How to load and unload linux drivers that are built into kernel - linux

I want to load and unload linux drivers in the device terminal,and I have two options but I do not want to do the first one
Build driver as a module
CONFIG_DRIVER = m
and I can use rmmod and modprobe to unload and load device driver.
Build device driver into kernel itself
CONFIG_DRIVER = Y
I want to follow the 2nd option but I do not know how to unload and load the device driver, can the open source community please help me out here !

It's easy as that. You find a device and driver which you want to unbind. For example, on my Intel Minnownboard (v1) I have PCH UDC controller (a PCI device):
% lspci -nk
...
02:02.4 0c03: 8086:8808 (rev 02)
Subsystem: 1cc8:0001
Kernel driver in use: pch_udc
Now I know necessary bits:
bus on which the device is located: PCI
device name: 0000:02:02.4 (note that lspci gives reduced PCI address, i.e. without domain or i.o.w. BDF, while driver expects domain:BDF)
driver name: pch_udc
Take altogether we can unbind the device:
% echo 0000:02:02.4 > /sys/bus/pci/drivers/pch_udc/unbind
[ 3042.531872] configfs-gadget 0000:02:02.4: unregistering UDC driver [g1]
[ 3042.540979] udc 0000:02:02.4: releasing '0000:02:02.4'
You may bind it again. Simple use bind node in the same folder.
The feature appeared more than 15 years ago and here is the article on LWN that explains it.

Related

Raspberry Pi Zero USB device emulation

I know that the Raspberry Pi Zero supports OTG and USB Peripheral protocols, and there's a lot of cool built in peripherals shown here: https://learn.adafruit.com/turning-your-raspberry-pi-zero-into-a-usb-gadget?view=all#other-modules
The problem is that I need to emulate a USB Peripheral device that does not appear on this list. I have a vendor ID and product ID for the device, and I'm trying to figure out how exactly to go about doing this. Do I need to modify the OTG USB drivers in the Raspbian kernel? Do I have to completely build my own kernel? Or is there a better option I don't even realize?
Thanks in advance!!
Do I need to modify the OTG USB drivers in the Raspbian kernel?
The answer to your first question is "it depends", but if your device
doesn't do anything too unusual this could be a No: you need not
modify source code for kernel modules nor the kernel.
You're fortunate that Raspbian supports a modern kernel with ConfigFS support. Once you are set up with dtoverlay=dwc2, you can open up a FunctionFS bulk endpoint as root like so:
modprobe libcomposite
modprobe usb_f_fs
cd /sys/kernel/config/usb_gadget
mkdir -p myperipheral; cd myperipheral
echo 0x1234 > idVendor # put actual vendor ID here
echo 0xabcd > idProduct # put actual product ID here
mkdir configs/c.1
mkdir configs/c.1/strings/0x409
echo "My Peripheral" > configs/c.1/strings/0x409/configuration
mkdir functions/ffs.my_func_name
ln -s functions/ffs.my_func_name configs/c.1/
mkdir -p /tmp/mount_point
mount my_func_name -t functionfs /tmp/mount_point
# compile ffs-test from source, then copy and run it from /tmp/mount_point
ls /sys/class/udc > UDC
If you need to emulate the other device more closely, it's up to you to set bcdDevice, bcdUSB, serial number, manufacturer, product string, max power, os_desc, and possibly other fields.
AFAIK FunctionFS does not support isochronous endpoints, interrupt transfers, nor out-of-the-ordinary control transfers. If you require this, you may need to start looking into extending existing gadget modules, with source code here.
Update: When I got home to test this, I encountered a severe caveat with Raspbian. It'll initially fail to create ffs.my_func_name because usb_f_fs is not enabled by default. Although you need not modify any kernel modules, you must recompile with an alternate configuration. make menuconfig -> Device Drivers -> USB support -> USB Gadget Support -> USB functions configurable through configfs / Function filesystem (FunctionFS) + some other modules to test. After uploading a new kernel/modules, I tested the above script on Raspbian 8. I would also recommend setting USB Gadget Drivers / Function Filesystem to (M) in case you resort to the simpler g_ffs legacy module in lieu of ConfigFS.

MCP23017 I2C Device driver probe function is not called

I am using the following I2C/GPIO Device driver to access the MCP23017 GPIOs. With the insmod command I am able to load the driver and its listed in /proc/modules. I have two MCP23017 chips connected to my Raspberry Pi. Both are detected at addresses 0x20 and 0x21. The initcall to the driver registers the driver. I checked this by printing out a message. But the driver probe function is not called. The devices are not opened/ cannot be located elsewhere.
How is the probe function called?
Should the probe be done manually to locate the devices?
Is the probe call similar to the open call?
I tried this echo mcp23017 0x20 > new_device to manually create a new device with the address. But it didnt work. I got the followin message: Driver 'mcp23s08' is already registered, aborting...
Any help would be appreciated.
probe() function is called when driver is matched with your device description in Device Tree. Matching happens when compatible field of your driver found in Device Tree (for your driver it's "microchip,mcp23017" string).
Apparently you don't have your device (MCP23017) described in Device Tree, that's why probe() is not called. You can load corresponding Device Tree Overlay to overcome this issue. The one you pointed out in your comment seems to be correct. Read more about loading overlays in Raspberry Pi ecosystem here.
You can try to load your overlay like described in that article:
$ sudo dtoverlay mcp23017.dtbo
Or you can try to use Capemgr for this purpose. Personally I didn't try any of those, so you should look which works for you best.
Update
Replying to your questions in comments.
But when I try the i2cdetect command it shows UU.
See man i2cdetect. So "UU" means that i2cdetect skipped probing because device at the address you specified is already used by driver. I guess it what you intended, so it's ok.
With a rmmod mcp23017 command I see the device still under devices but i2cdetect shows 0x20
So you unloaded the driver and now i2cdetect shows you that there is some device on 0x20 address. I guess it's correct behavior. Also if you want to get rid completely of your device -- try to unload DT overlay along with driver.
Also I have connected two MCP23017 chips. But I can see only the device at 0x20 under devices. The I2C chip at 0x21 is still not detected, though the driver says it supports up to 8 chips
I can see two possible causes to this issue.
DT overlay only has description for device with 0x20 address, but missing description for device with 0x21 address. If this is the case, you should find sources for your DT overlay, add description for rest of your devices, compile that modified DT overlay and then load it instead of pre-built one.
All devices may be configured for using 0x20 address. See section 1.4
Hardware Address Decoder in MCP23017 datasheet for details. Check A0, A1, A2 pins on your chips.

Linux PCI Driver calls init, but not probe

I'm developing a driver for an FPGA-board connected to my machine via an PCIe expansion slot, and everything works great if the board is powered on prior to the PC. However, if I book up my computer first and then the FPGA board, I get the rather unusual behavior of the device being recognized and loading my module (I see the "init" function called in my syslog), however the "probe" function is never called.
I think this is due to an invalid BAR0. Output from dmesg when I power on the board:
[ 71.287587] pci 0000:3b:00.0: [0ae5:0001] type 00 class 0x000000
[ 71.287613] pci 0000:3b:00.0: reg 0x10: [mem 0x00000000-0x0000ffff]
[ 71.287821] pci 0000:3b:00.0: System wakeup disabled by ACPI
[ 71.328537] my_driver:
[ 71.328537] ****************************************************************
[ 71.328542] my_driver: init debug=2
That first reg should be something like 0xb4000000-0xb400ffff but instead it's coming up as 0. (Like I said, it works perfectly if it's powered on before the computer).
Is there an additional step required to get it to allocate this block? Or somehow to indicate to the kernel that it needs to do this?
The solution wound up being a manual call to pci_assign_resource ( http://lxr.free-electrons.com/source/drivers/pci/setup-res.c#L283 ).
Calling this right before pci_enable_device caused the OS, rather than the BIOS, to allocate the required BAR's and now it all works!
I do still have to manually trigger a PCI bus rescan ( echo 1 > /sys/bus/pci/rescan ).
Your PCI device must be powered up prior to the BIOS PCI enumeration phase.
On enumeration phase, the BIOS tries to read the ID of the PCI devices that might be connected.
If it reads invalid ID (0xfffff) it skips that PCI device.
I don't have a reference, but AFAIK, you have about a second before you must populate the configuration space of the PCI.
Are you sure you register the PCI driver and don't return non-zero from mod_init? Please try to manually bind the device to your driver:
echo -n "0000:3b:00.0" > /sys/bus/pci/drivers/my_driver/bind
Unallocated BAR should not be an issue when loading the driver.
As for the BAR being 0 and HotPlug: find out what is your platform and if and how HotPlug is supported. You need to have the right HotPlug driver in the kernel for this sort of thing to work. BARs are allocated by the kernel (or initially firmware/BIOS) so you can't set them to anything meaningful from the FPGA side - there you can only set the size. Kernel has to do the rescanning and reassignment after device appears. I vaguely recall that there should be some reservation going on during boot, otherwise kernel will not have to space to give to your devices' BAR and it will not reassign the windows on bridges below your device as they can be actively used by other devs. Other option is to just do the BAR programming yourself from the driver. It ain't that hard but you would probably don't want to ship this kind of hacks to customers. Also, even though your device does seem to come up fine, make sure you don't have HP disabled in FW/BIOS.

Which drivers are used by usb mouse in linux kernel?

I read from LDD3 chapter 14 about hotplug drivers.I need to write a usb mouse driver which load when I plug the hardware. Now, doing some experiment I come to know that there is a driver named "hid-generic" which is called when plug-unplug.
[ 6654.232046] usb 3-1: new low-speed USB device number 3 using uhci_hcd
[ 6654.462061] usb 3-1: New USB device found, idVendor=093a, idProduct=2510
[ 6654.462067] usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 6654.462071] usb 3-1: Product: USB OPTICAL MOUSE
[ 6654.462074] usb 3-1: Manufacturer: PIXART
[ 6654.489316] input: PIXART USB OPTICAL MOUSE as /devices/pci0000:00/0000:00:1d.1/usb3/3-1/3-1:1.0/input/input12
[ 6654.489445] hid-generic 0003:093A:2510.0004: input,hidraw0: USB HID v1.10 Mouse [PIXART USB OPTICAL MOUSE] on usb-0000:00:1d.1-1/input0
Also lsmod shows,
Module Size Used by
hid_generic 12541 0
usbhid 47259 0
hid 105241 2 hid_generic,usbhid
psmouse 102541 0
My doubts are as follows,
1) To make my module load (hotplug) when this mouse plugs in, I have to disable these 3 drivers in kernel and build whole kernel with my driver with vendor and device ID in id_table. Right?
2) I also read about USB core drivers and USB device drivers. So these HID drivers are core drivers or device drivers?
3) Which are core drivers and device driver in case of USB mouse? And where can I find them in kernel source?
Thanks,
Sunil.
I'll try to answer your questions one by one :
1) To make my module load (hotplug) when this mouse plugs in, I have to disable these 3 drivers in kernel and build whole kernel with my driver with vendor and device ID in id_table. Right?
Yes, but there are some additional things you need to take care of. First understand how a particular module(driver) gets loaded. The key to this is MODULE_DEVICE_TABLE(usb, &my_id_table); Whenever a particular module is "installed" (using make modules_install), an entry, according to the id table passed in MODULE_DEVICE_TABLE gets created in /lib/modules/<your_kernel>/modules.usbmap and /lib/modules/<your_kernel>/modules.dep file(search for the string "usbhid" in the files). Whenever a new usb device is detected, the kernel reads these files to find the matching parameters. If it is found, the following module is loaded from the corresponding path found in /lib/modules/<your_kernel>/modules.dep which holds the info. about the path where the driver is located and also its dependencies.
So, now even if you unload(rmmod) usbhid from the kernel, it will be loaded again when you re-insert your mouse. To avoid this from happening you need to modify those files, i.e. remove the entries from the files. To do so, "move" the usbhid driver from its original path(generally located at /lib/modules/<your_kernel>/kernel/drivers/hid/usbhid/usbhid.ko to a safe place. Now rebuild the dependencies such that the entries would be removed from the dependency files.
Now you need to create entries of your driver. Just install your driver and you are good to go!
So, to summarize :
$ sudo rmmod usbhid # Unload the usb mouse driver
$ cd /lib/modules/$(uname -r)/ # Move to your current kernel
$ vim modules.usbmap # Check for the "usbhid" string
$ vim modules.dep # Check for "usbhid.ko:" string
$ sudo mv kernel/drivers/hid/usbhid/usbhid.ko ~/Desktop # Take backup of your current
usb mouse driver
$ sudo depmod -a # Rebuild the dependency files
Now check the dependency files for the string "usbhid" again. It shouldn't be there!
$ cd /path/to/your/driver
$ sudo make modules_install # Install your driver into /lib/modules/$(uname -r)/extra
$ sudo depmod -a # Rebuild the dependency files
After this step, search for the string corresponding to your module in the dependency files, and it should be there! From this moment on, whenever you insert the mouse(or from boot itself) your driver will be loaded, instead of the original.
Once your are done playing with your driver, you may copy back the original usbhid file to its original destination and rebuild the dependency files (sudo depmod -a)
Now I also see that you are trying to use vendor and device id to match your device, in which case, the driver would work only for your mouse. The recommended way is to use class ids, which makes your driver work for any usb mouse.
2) I also read about USB core drivers and USB device drivers. So these HID drivers are core drivers or device drivers?
usbhid is basically a "device driver". The classification of drivers could be briefed out as : core drivers, host controller drivers and device drivers :
Device Drivers : This is the software used to control the devices. For example usb mouse, pci based ethernet card, usb pendrive, i2c based accelerometer.
Host Controller Drivers : This is the software written to control the bus controller. For example USB Host Controllers(EHCI, UHCI, OHCI, etc.), PCI Host Controller, I2C Masters, etc.
Core Drivers : These actually glues up the above discussed drivers. Examples are USB core, PCI core, etc. Core drivers provides helper routines(APIs) such that the device and host-controller driver could make use of them(concept of module stacking!). These are the ones, which bind the correct device to its driver. There are many other services provided by the core drivers.
Example code for USB Device Driver :
http://lxr.free-electrons.com/source/drivers/hid/usbhid/usbmouse.c
You may find the USB Host Controller Drivers under :
http://lxr.free-electrons.com/source/drivers/usb/host/
USB Core resides here : http://lxr.free-electrons.com/source/drivers/usb/core/
I think this also answers your third question!
Hope this helped.
The device driver is usbhid.
To prevent it from attaching to your device, add a HID_QUIRK_IGNORE entry to drivers/hid/usbhid/hid-quirks.c, or use the quirks parameter of the usbhid module.

How can you check whether your kernel supports GPIO on your hardware?

My aim is to control the GPIO pins in Peppermint 4 Linux (Kernel version 3.8.0) on an Intel motherboard (NM70 chipset with C1037U processor).
How can you check whether your kernel supports GPIO on your hardware?
Background
Motherboard: Intel with NM70 chipset
Processor: C1037U processor
OS: Peppermint 4 Linux
Kernel version: 3.8.0
GPIO interface: sysfs
I'm attempting to use the sysfs interface, which allows GPIO pins to be accessed from userspace through the filesystem.
I’ve successfully followed the "Alternate Build Method: The Old-Fashioned Debian Way" section of https://help.ubuntu.com/community/Kernel/Compile to recompile the kernel in order to expose GPIO access in user space and to turn on debug mode for GPIO:
Once the new kernel was compiled, I was able to see the GPIO folder in /sys/class/gpio for the first time. Then, in theory, it should be a case of being able to turn GPIO ports ON/OFF by writing to the filesystem. This approach is outlined at http://falsinsoft.blogspot.co.uk/2012/11/access-gpio-from-linux-user-space.html.
When attempting to export pins 0 to 255 by
echo XX > /sys/class/gpio/export
for XX from 0 to 255, I get the following error message
echo: write error: No such device
When attempting to export pins outside the range 0 to 255 by
echo XX > /sys/class/gpio/export
I get the following error message
echo: write error: Invalid argument
The tutorial suggests this could be because the GPIO ports are reserved for another program and that, if so, the debug file (/sys/kernel/debug/gpio) would be able to show where they are reserved.
However, /sys/kernel/debug/gpio is empty.
I can see and control the GPIO pins in the BIOS (change pins to be input or output HIGH/LOW).
Related questions
Under what conditions would /sys/kernel/debug/gpio be empty?
writing to /sys/class/gpio/export failing

Resources