UART binding # runtime - linux

When does the console and UART binding happen in Linux,is it possible to unbind the UART from console and bind it to other module(GPS) at runtime.
My board is having a single UART,can i switch between console and GPS at runtime.if yes how do i do it? if no what is the hack which I need to do?

Yes you can. At run time you can unbind/bind any driver. You can find more information here:
https://lwn.net/Articles/143397/
You can find the correct driver for your the UART (and GPS probably, but I'm not sure. Never played with it) here:
cd /sys/class/tty/<your-device>/device/driver/
Then in these directories you have the sysfs files bind and unbind. The device ID to use to unbind the device from the driver is typically show in the driver directory.
The platform_device is not special at all, it behaves like any other driver. Typically the device id of a platform device it's its name (there is not a bus enumeration behind). Here an example with platform_device with my PC:
# ls /sys/bus/platform/devices/
alarmtimer gpio_ich iTCO_wdt platform-framebuffer.0 PNP0800:00 PNP0C14:00
coretemp.0 hp-wmi microcode PNP0003:00 PNP0C04:00 serial8250
Fixed MDIO bus.0 i8042 pcspkr PNP0103:00 PNP0C0C:00
# cd /sys/bus/platform/drivers/serial8250/
# ls
bind serial8250 uevent unbind

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.

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 I bind a driver with a USB device?

I am writing a USB device drive for linux. it's for a joystick.
every time plug it in, linux loads a hid driver. is there a way to tell Linux to load mine when I plug it in? or at least not load the default one?
I can echo the id in unbind of the default driver and echo it in bind of my driver; but I would like something more automatic..
thanks
Own USB driver taking precedence over usbhid
If you want to prevent binding to the usbhid driver, you can use its HID_QUIRK_IGNORE (= 4) setting. To stick with the example Karl Bielefeldt used, add
options usbhid quirks=0x15c2:0x0043:0x04
to some /etc/modprobe.d/*.conf file (and perhaps recreate your initramfs). That will tell hid-core to ignore that device. So usbhid will have a look at it but leave it for some other driver instead.
Own HID driver taking precedence over hid-generic
However, if your other driver is a HID driver not an USB driver, then you need usbhid to bind to the driver on the USB level, and you need your own HID driver to take precedence over hid-generic. This is the problem I'm facing my self, and for which I haven't found a solution yet, short of unbinding and rebinding the device later on.
Here's a thread with a fix for a similar problem. To summarize, you add something like the following to one of your /etc/udev/rules.d files:
SYSFS{idVendor}=="15c2", SYSFS{idProduct}=="0043", MODE="0666", PROGRAM="/bin/sh -c 'echo -n $id:1.0 >/sys/bus/usb/drivers/usbhid/unbind;\
echo -n $id:1.1 >/sys/bus/usb/drivers/usbhid/unbind'"
http://lwn.net/Articles/143397/ is very similar to the above answer, maybe some more details.

Forcing driver to device match

I have a piece of usb hardware, for which I know the driver.
However, the vendor id and product id do not match the VID, PID pair registered in the driver. Is there a way in linux to force a driver to be associated with a known device, that do not involve kernel module recompilation to add a PID / VID pair ?
Find the module in the sysfs tree. In this case it was in
/sys/bus/usb-serial/drivers/cp2101
In this directory, there is a new_id file entry that can be used to dynamically add VID PID pair like this :
echo VID PID >new_id
Here is a LWN entry about this feature
In case you want to make this change permanent and assign specific driver to device (VID, PID) you may find this answer useful.
For example create new file/etc/udev/rules.d/98-joystick.rules with content:
ACTION=="add", ATTRS{idVendor}=="1345", ATTRS{idProduct}=="6005", RUN+="/sbin/modprobe xpad" RUN+="/bin/sh -c 'echo 1345 6005 > /sys/bus/usb/drivers/xpad/new_id'"
Replace 1345 with your VID and 6005 with your PID.
Replace xpad with appropriate driver.
Run following command:
$ sudo udevadm control --reload
Unplug and plug your device back and check if the new driver is loaded.
Example shown here is for fixing driver issues with Speedlink Strike FX Gamepad (SL-6537-BK)
You don't need actually recompile the whole kernel, recompiling only relevant kernel module with updated match table will be enough, in case that this answer, does not work on your kernel.

Resources