How to find device driver associated with a device file? - linux

ls -l /dev
command lists the device files, and the associated information like major number, minor number.
cat proc/devices
command helps me to find the device name associated with a major number.
So for a node, I have found the major number, device name.
I understood how to auto create a device file, by populating the class information under /sys/class => By installing the device driver module, i can find the device file created.
I cant trace back from device file to the corresponding module.
In essence,how to find the Device driver/module associated with the device file, with these information?

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]"

How does Linux determine a device class?

Linux newbie question.
Just wondering how Linux determines which device class a device is? Specifically, when I plug a barcode scanner in how does it know it is an ttyACM device? I have a scanner that works with my Linux OS but the new model isn't recognized so I'm wondering if I can alter a file somewhere in the system that tells it to recognize the scanner as ttyACM0 and use the existing drivers.
USB devices (I assume your scanner is USB) are identified by vendorId and productId (two 16bit integers), each driver fill an array with the list of supported vendor/prods id (creating a relation vendor:prod->driver), I guess at compile time all the id in the array are merged together in a list which then is used for a lookup search when a device is plugged in.
Usually you can see vendor and product id of the attached device with dmesg command right after the device is plugged in (or with lsusb).
For ttyACM see acm_ids[] in drivers/usb/class/cdc-acm.c
Careful playing around with device drivers, even being ttyACM a terminal interface only if the interface tty->hardware is implemented poorly some command may break the hardware.
Perhaps this question should be in Unix & Linux stackexchange

How is the Hardware address mapped to eth0/eth1 on a Linux(Ubuntu) machine.?

What goes behind the hood when i add a new NIC card to my Ubuntu machine.?
Which program/module is responsible for mapping the HardWare address of the device to a name(eth0/eth1). Where are this mappings(HWaddress1-eth0, HWaddress2-eth1) actually stored.?
As far as I know the kernel itself will name the nics depending on the order they are connected to the bus. This behavior is very similar to SCSI/SATA naming.
Take a look at the output of
lspci
You should find the corresponding network card there. The first column e.g. 0000:00:03.0 contains the following information:
0000 : PCI domain (each domain can contain up to 256 PCI buses)
00 : the bus number the device is attached to
03 : the device number
.0 : PCI device function
(source: http://prefetch.net/articles/linuxpci.html)
under /sys/bus/pci(_express)/devices/ you will find links that match to the lspci output. When you enter the folder of your network card, there are lots of files and folders.
You can do a find and grep
cd /sys/bus/.../devices/0000:00:03.0/
someuser#somemachine:/sys/bus/pci/devices/0000:00:03.0$ find -type f -exec grep 'ethX' /dev/null {} \; 2>/dev/null
where ethX is your device name to get an output like
./virtio0/net/ethX/uevent:INTERFACE=eth0
(in my case a virtual machine with a virtio device)
Since this information is derived from the running kernel I bet you will also find the hardware-address there.
Happy grepping!

How to create an event# device for a virtual input device (/dev/input/js3) in linux kernel module?

i am writing a linux kernel module which takes N of real /dev/input/js# devices and proxifies them as a single /dev/input/js3 device. Currently my module is creating /dev/input/js3 just fine, jstest is happy with it, but not the real applications. I guess (strace'd) it is so because i have no matching pair of /dev/input/event# for my virtual js3 device. How do i create one from my module?
Here is my module's source, which probably has numerous of issues, but mostly working: https://github.com/iamtakingiteasy/unijoy/blob/master/unijoy.c
Here is an example, you can use
1. class_create to create the class specified for the device,
2. device_create to create the device node
3. cdev_init to initialize and
4. cdev_add to add the device to the /dev list
For example you can refer the below link :Create a device node in kernel module

Find which drive corresponds to which USB mass storage device in Linux

I have several USB mass storage flash drives connected to a Ubuntu Linux computer (Ubuntu 10.04.1, kernel 2.6.32-25-386), and I need to tell them apart programatically (from bash if possible, but I'm not afraid of compiling either) - I need to find which block device corresponds to which physical device (e.g. /dev/sdb1 -> device in USB port 1; in my case, one device ~ one volume).
In other words, I know that I have three hardware devices plugged into USB ports; each of them shows up in the system as a USB mass storage device (as seen with lsusb), is created as a block device (/dev/sdb1) and automounted by UUID (/media/1234-5678).
USB device block device mountpoint
USB device in port 2.2 <-> /dev/sdb1 <-> /media/1234-5678
I'm not trying to find the relationship between block device and mountpoint; I'm trying to find the relationship between block device and USB device, is there a way?
Why? There will be some writes on the disks, with unpredictable time of completion. I need to give the operator some indication like "you can now remove the disk in port 2 (which is second from the left)". I have found which physical port corresponds to which port number on that specific machine, and finding block devices from mountpoints is simple; now I'm stuck mapping the logical USB ports to block devices.
I can see the disks with lsusb :
Bus 001 Device 058: ID 067b:2517 Prolific Technology, Inc. Mass Storage Device
Bus 001 Device 060: ID 067b:2517 Prolific Technology, Inc. Mass Storage Device
Bus 001 Device 061: ID 067b:2517 Prolific Technology, Inc. Mass Storage Device
and I can see them mounted (by their UUID):
/dev/sdb1 on /media/BC88-15C4 type vfat
/dev/sdc1 on /media/AE54-65AA type vfat
/dev/sdd1 on /media/58D2-FED1 type vfat
Now, all the drives are the same model from the same manufacturer, so I can't distinguish them by that, and I can't guarantee they'll be plugged in a particular order.
I have found /sys/bus/usb/devices (a list of USB devices), but it seems to be the same data that I get from lsusb - I don't see a mapping to disks there.
There's also /sys/block/sdb and /sys/block/sdb/sdb1 (the block device and its first partition; similarly for sdc and sdd), but again, I see no mapping to devices.
I'm not sure in which kernel version this was implemented, but the /sys/block/* entries are symlinks to the devices.
In other words, /sys/block/sdb symlinks to a different directory, and its name contains the USB device ID.
$ file /sys/block/sdb
/sys/block/sdb: symbolic link to `../devices/pci0000:00/0000:00:02.1/usb1/1-1/1-1.1/1-1.1:1.0/host31/target31:0:0/31:0:0:0/block/sdb'
USB version and port here---^^^^^
The 1-1.1 is the interesting part, denoting usb1-port 1.device 1. When plugged into a hub, another level is added: 1-2.3.1, denoting usb1-port 2.port 3.device 1.
Pseudocode:
get partition name # e.g. /dev/sdb1
get disk name # that would be /dev/sdb
get your basename # sdb
see where /sys/block/$your_basename points to # e.g. ../devices/blah/blah/1-2.1/blah
get the longest substring matching "\d-\d+(.\d+)*" # e.g. 1-2.1
that is the device id you want
/sys/bus/usb/devices/$device_id/ has all kinds of information about it
the ID corresponds to hardware USB ports
Working example script in bash.
I use the path:
/sys/bus/usb/drivers/usb-storage/4-1:1.0/host4/target4:0:0/4:0:0:0/block/sda
so you can see usb bus 4, port 1 is connected with a usb storage /dev/sda
Can't you use disk labels?
http://ubuntuforums.org/showthread.php?t=322973
Here is how I do it.
lsusb -v shows all the devices disks get an iserial number take note of them
ls -l /dev/disk | grep [iserial]
Everything in /dev/disk is a symlink so follow the symlink to see the device.

Resources