Finding the Kernel Driver(s)
The victim device
Bus 010 Device 002: ID 046d:c01e Logitech, Inc. MX518 Optical Mouse
Bus 010 Device 003: ID 051d:0002 American Power Conversion Uninterruptible Power Supply
We're going to try to find out what driver is used for the APC UPS. Note that there are two answers to this question: The driver that the kernel would use, and the driver that is currently in use. Userspace can instruct the kernel to use a different driver (and in the case of my APC UPS,
Method 1: Using usbutils (easy)
usbutils package (on Debian, at least) includes a script called
usb-devices. If you run it, it outputs information about the devices on the system, including which driver is used:
T: Bus=10 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#= 3 Spd=1.5 MxCh= 0
D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=051d ProdID=0002 Rev=01.06
S: Manufacturer=American Power Conversion
S: Product=Back-UPS RS 1500 FW:8.g9 .D USB FW:g9
C: #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr=24mA
I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=00 Driver=usbfs
Note that this lists the current driver, not the default one. There isn't a way to find the default one.
Method 2: Using debugfs (requires root)
If you have debugfs mounted, the kernel maintains a file in the same format as
usb-devices prints out at
/sys/kernel/debug/usb/devices; you can view with
less, etc. Note that debugfs interfaces are not stable, so different kernel versions may print in a different format, or be missing the file entirely.
Once again, this only shows the current driver, not the default.
Method 3: Using only basic utilities to read /sys directly (best for scripting or recovery)
You can get the information out of
/sys, thought its more painful than
/sys interfaces should be reasonably stable, so if you're writing a shell script, this is probably how you want to do it.
lsusb seems to count devices from 1,
/sys from 0. So, let's say we wonder what driver the APC UPS is using. Its bus 10, device 3, but subtract one to get the sysfs name: 10-2.
$ cd /sys/bus/usb/devices/10-2
10-2:1.0 bDeviceClass bMaxPower descriptors ep_00 maxchild remove urbnum
authorized bDeviceProtocol bNumConfigurations dev idProduct power serial version
avoid_reset_quirk bDeviceSubClass bNumInterfaces devnum idVendor product speed
bcdDevice bmAttributes busnum devpath ltm_capable quirks subsystem
bConfigurationValue bMaxPacketSize0 configuration driver manufacturer removable uevent
We can be sure this is the right device by
cating a few of the files:
$ cat idVendor idProduct manufacturer product
American Power Conversion
Back-UPS RS 1500 FW:8.g9 .D USB FW:g9
If you look in 10-2:1.0 (
:1 is the "configuration",
.0 the interface—a single USB device can do multiple things, and have multiple drivers;
lsusb -v will show these), there is a modalias file and a driver symlink:
$ cat 10-2\:1.0/modalias
$ readlink driver
So, the current driver is
usbfs. You can find the default driver by asking
modinfo about the modalias:
$ /sbin/modinfo `cat 10-2\:1.0/modalias`
description: USB HID core driver
author: Jiri Kosina
author: Vojtech Pavlik
author: Andreas Gal
vermagic: 3.6-trunk-amd64 SMP mod_unload modversions
parm: mousepoll:Polling interval of mice (uint)
parm: ignoreled:Autosuspend with active leds (uint)
parm: quirks:Add/modify USB HID quirks by specifying quirks=vendorID:productID:quirks where vendorID, productID, and quirks are all in 0x-prefixed hex (array of charp)
So, the APC UPS defaults to the
hid driver, which is indeed correct. And its currently using usbfs, which is correct since
usbhid-ups is monitoring it.
What about userspace (usbfs) drivers?
When the driver is
usbfs, it basically means a userspace (non-kernel) program is functioning as the driver. Finding which program it is requires root (unless the program is running as your user) and is fairly easy: whichever program has the device file open.
We know that our "victim" device is bus 10, device 3. So the device file is
/dev/bus/usb/010/003 (at least on a modern Debian), and
lsof provides the answer:
# lsof /dev/bus/usb/010/003
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
usbhid-up 4951 nut 4u CHR 189,1154 0t0 8332 /dev/bus/usb/010/003
And indeed, its
usbhid-ups as expected (lsof truncated the command name to make the layout fit, if you need the full name, you can use
ps 4951 to get it, or probably some lsof output formatting options).