Forcing driver to device match - linux

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.

Related

Why do I have multiple product and vendor id's?

GOAL:
I am trying to connect 4 RFID readers to a Pi and I need to differentiate each one's port.
WHAT I'VE DONE:
I entered lsusb into terminal with nothing but one reader plugged in. It returns :
Bus 001 Device 004: ID 0c27:232a RFIDeas, Inc
This is my reader.
So my Vendor ID should be 0c27 and my Product ID should be 232a
Now I need the serial # because all of my readers show the same Vendor and Product IDs.
My device is on port ttyACM0, so in terminal I search for the serial attribute as well as verify my product ID and vendor ID by putting:
udevadm info --name=ttyACM0 --attribute-walk | grep -i "serial" -e "product" -e "vendor"
This returns:
ATTRS{idProduct}=="232a"
ATTRS{idVendor}=="0c27"
ATTRS{product}=="USB Serial"
ATTRS{idProduct}=="9514"
ATTRS{idVendor}=="0424"
ATTRS{idProduct}=="0002"
ATTRS{idVendor}=="1d6b"
ATTRS{product}=="DWC OTG Controller"
ATTRS{serial}=="3f980000.usb"
PROBLEM:
3 Product IDs and 3 Vendor IDs return. While only one serial # returns.
QUESTIONS:
Why does this return 3 Product IDs and 3 Vendor IDs when there is only one device connected?
Which ones am I supposed to use in my udev rules to make a persistent device name?
If I am leaving something out please let me know so I can update the question.
EDIT:
I have successfully created a udev rule using the first mentioned product ID and vendor ID:
SUBSYSTEM=="tty", ATTRS{idVendor}=="0c27", ATTRS{idProduct}=="232a", SYMLINK+="reader1"
This creates a working udev rule, BUT when I add the serial # ATTRS{serial}=="3f980000.usb" it stops working. I need a unique identifier.
While from your perspective you just plugged one device into your computer, the Linux kernel has a more complicated view of what is happening. The kernel keeps track of a hierarchy of devices, each with its own attributes, drivers, and child devices. The root of the hierarchy is usually some kind of root device representing your CPU, which is then connected (perhaps indirectly) to a USB controller device, which is connected to a "root hub", which is then connected to the physical USB device you plugged in, which in turn might have child devices for each function/interface that the USB device exposes.
You can run man udevadm to learn more about what the command does. It says:
-a, --attribute-walk
Print all sysfs properties of the specified device that can be used
in udev rules to match the specified device. It prints all devices
along the chain, up to the root of sysfs that can be used in udev
rules.
So there is this chain of devices, starting with ttyACM0 (a function of your USB device), and going up to the physical USB device, then the root hub, and then the USB controller, until it reaches the root of the heirarchy. The --attribute-walk option walks up that chain and prints out attributes of each of the devices along the way.
You are piping the output of that command into grep so you are not seeing the full output, and that it probably why you are confused. The full output of the command is actually very informative: it prints out a nice paragraph explaining what it does, and there are helpful sentences to make it clear when it switches from printing the attributes of one device to printing that of its parent. Here is some of the output I get when examining a USB device on my Raspberry Pi:
$ udevadm info --name=sda2 --attribute-walk
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2':
KERNEL=="sda2"
SUBSYSTEM=="block"
[snip]
looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/0:0:0:0/block/sda':
KERNELS=="sda"
SUBSYSTEMS=="block"
[snip]
looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0':
KERNELS=="target0:0:0"
SUBSYSTEMS=="scsi"
[snip]
looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0':
KERNELS=="1-1.2.1:1.0"
SUBSYSTEMS=="usb"
[snip]
looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1':
KERNELS=="1-1.2.1"
SUBSYSTEMS=="usb"
[snip]
[... and so on, up to the root device]
Unfortunately, from the output of your udevadm command, it looks like your RFID adapter does not have a USB serial number, so distinguishing it from other devices of the same model might by tricky. To confirm it doesn't have a serial number, I recommend that you run lsusb -v -d 0c27:232a | grep iSerial. If the number after iSerial is 0, it means there is no serial number.
I recommend looking at the symbolic links that Linux creates for you in /dev/serial/by-id; maybe those symbolic links will have enough detail in their names so that you don't need to create a new udev rule. (Hint: run ls -lR /dev/serial/by-id.)
If you still need more help finding or creating stable symbolic links, I think you should plug in all four RFID readers and then post the full output from each of these commands:
ls -lR /dev/serial/by-id
ls /dev/ttyACM*
udevadm info --name=ttyACM0 --attribute-walk
I was able to create a udev rule by putting in the following:
SUBSYSTEM=="tty", ATTRS{idVendor}=="1d6b", ATTRS{idProduct}=="0002", ATTRS{serial}=="3f980000.usb", SYMLINK+="reader1"
The reason for multiple Product and Vendor IDs is explained by David Grayson's answer quoted below. This is what lead me to the solution.
While from your perspective you just plugged one device into your computer, the Linux kernel has a more complicated view of what is happening. The kernel keeps track of a hierarchy of devices, each with its own attributes, drivers, and child devices. The root of the hierarchy is usually some kind of root device representing your CPU, which is then connected (perhaps indirectly) to a USB controller device, which is connected to a "root hub", which is then connected to the physical USB device you plugged in, which in turn might have child devices for each function/interface that the USB device exposes.
You can run man udevadm to learn more about what the command does. It says:
-a, --attribute-walk
Print all sysfs properties of the specified device that can be used
in udev rules to match the specified device. It prints all devices
along the chain, up to the root of sysfs that can be used in udev
rules.
So there is this chain of devices, starting with ttyACM0 (a function of your USB device), and going up to the physical USB device, then the root hub, and then the USB controller, until it reaches the root of the heirarchy. The --attribute-walk option walks up that chain and prints out attributes of each of the devices along the way.
You are piping the output of that command into grep so you are not seeing the full output, and that it probably why you are confused. The full output of the command is actually very informative: it prints out a nice paragraph explaining what it does, and there are helpful sentences to make it clear when it switches from printing the attributes of one device to printing that of its parent. Here is some of the output I get when examining a USB device on my Raspberry Pi:
$ udevadm info --name=sda2 --attribute-walk
Udevadm info starts with the device specified by the devpath and then walks up the chain of parent devices. It prints for every device found, all possible attributes in the udev rules key format. A rule to match, can be composed by the attributes of the device and the attributes from one single parent device.
looking at device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda2': KERNEL=="sda2" SUBSYSTEM=="block" [snip]
looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0/0:0:0:0/block/sda': KERNELS=="sda" SUBSYSTEMS=="block" [snip]
looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0/host0/target0:0:0': KERNELS=="target0:0:0" SUBSYSTEMS=="scsi" [snip]
looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1/1-1.2.1:1.0': KERNELS=="1-1.2.1:1.0" SUBSYSTEMS=="usb" [snip]
looking at parent device '/devices/platform/soc/3f980000.usb/usb1/1-1/1-1.2/1-1.2.1': KERNELS=="1-1.2.1" SUBSYSTEMS=="usb" [snip]
[... and so on, up to the root device]"

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.

UART binding # runtime

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

how to make /dev/mmcblk0

I'm trying to adapt an existing SD/MMC card driver to our SD controller hardware. I'm using Synopsys' dw_mmc code (in linux3.3) as a reference. I have a long way to go but at least it's compiled ok and the platform device and platform driver seems to have been registered. My question is how to make the /dev/mmcblk0 file appear in the system? I named our new device ald_sd and I can see ald_sd.0 under /sys/devices/platform. under /dev, I tried 'mknod mmcblk0 179 0' and I see mmcblk0 under /dev. Then I tried 'mount /dev/mmcblk0 /mnt/sd' (after making /mnt/sd) and it gives me message 'mount: mounting /dev/mmcblk0 on /mnt/sd failed: No such device or address'.
Please help. Thank you!
Chan
It's been several months since I sloved this problem. long story short, when the kernel reads the super block of the SD card, then the block access is ok. usually we make /dev/sd0 using mknod command.(not mmcblock0). (mmcblock0 file is made somewhere different maybe /sys.. I don't remember). Also beware, you can mis-type mknod like mkdir or mkdev, then you can have 'No such device or address' message too. Just for your information.

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.

Resources