操作系统: debian 7.4(linux 3.2.54)
硬件: 一个无线鼠标、一个有线鼠标
从淘宝上花了15块钱买了个无线鼠标,很好奇它的驱动程序是如何执行的。
首先执行下面命令来捕获uevent事件:
sudo udevadm monitor
然后插入和移除再插入无线鼠标的nano接收器(为了完整的查看信息才操作这么多次),可以在控制台下查看到下面的信息:
$ sudo udevadm monitor monitor will print the received events for: UDEV - the event which udev sends out after rule processing KERNEL - the kernel uevent KERNEL[22375.667072] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1 (usb)KERNEL[22375.667421] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0 (usb)KERNEL[22375.667470] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0006 (hid)KERNEL[22375.668613] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9 (input)KERNEL[22375.668769] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9/mouse0 (input)KERNEL[22375.668899] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9/event0 (input)KERNEL[22375.669151] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0006/hidraw/hidraw0 (hidraw)UDEV [22375.693845] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1 (usb)UDEV [22375.701112] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0 (usb)UDEV [22375.714647] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9 (input)UDEV [22375.716553] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9/mouse0 (input)UDEV [22375.719153] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0006 (hid)UDEV [22375.719712] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0006/hidraw/hidraw0 (hidraw)UDEV [22375.729434] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9/event0 (input)KERNEL[22456.752414] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9/mouse0 (input)UDEV [22456.752961] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9/mouse0 (input)KERNEL[22456.776217] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9/event0 (input)UDEV [22456.776626] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9/event0 (input)KERNEL[22456.785326] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9 (input)KERNEL[22456.785501] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0006/hidraw/hidraw0 (hidraw)KERNEL[22456.785523] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0006 (hid)KERNEL[22456.785541] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0 (usb)KERNEL[22456.785616] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1 (usb)UDEV [22456.786670] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9 (input)UDEV [22456.786699] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0006/hidraw/hidraw0 (hidraw)UDEV [22456.786842] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0006 (hid)UDEV [22456.786940] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0 (usb)UDEV [22456.794130] remove /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1 (usb)KERNEL[22562.038737] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1 (usb)KERNEL[22562.039577] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0 (usb)KERNEL[22562.039748] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0007 (hid)KERNEL[22562.040809] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input10 (input)KERNEL[22562.040953] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input10/mouse0 (input)KERNEL[22562.041206] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input10/event0 (input)KERNEL[22562.041400] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0007/hidraw/hidraw0 (hidraw)UDEV [22562.070879] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1 (usb)UDEV [22562.077647] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0 (usb)UDEV [22562.084927] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0007 (hid)UDEV [22562.086144] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/0003:1D57:0016.0007/hidraw/hidraw0 (hidraw)UDEV [22562.089305] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input10 (input)UDEV [22562.089350] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input10/mouse0 (input)UDEV [22562.089384] add /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input10/event0 (input)
输出信息中add对应行是插入时候产生的uevent,remove对应行是移除nano接收器时产生的uevent。
最后一次插入时在/sys文件夹下添加了很多目录,可以用下面命令查看:
$ cat /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input10/mouse0/device/id/vendor 1d57 $ cat /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input10/mouse0/device/id/product 0016
这与lsusb命令获取的信息一致:
$ lsusb Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 001 Device 002: ID 1a40:0101 Terminus Technology Inc. 4-Port HUB Bus 001 Device 010: ID 1d57:0016 Xenta Bus 002 Device 002: ID 046d:c05a Logitech, Inc. Optical Mouse M90 Bus 003 Device 002: ID 413c:2003 Dell Computer Corp. Keyboard Bus 001 Device 007: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode) $ lsusb -s 001:010 -v Bus 001 Device 010: ID 1d57:0016 Xenta Couldn‘t open device, some information will be missingDevice Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 8 idVendor 0x1d57 Xenta idProduct 0x0016 bcdDevice 11.10 iManufacturer 1 iProduct 2 iSerial 0 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 34 bNumInterfaces 1 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xa0 (Bus Powered) Remote Wakeup MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 1 Boot Interface Subclass bInterfaceProtocol 2 Mouse iInterface 0 HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.10 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 65 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0008 1x 8 bytes bInterval 2
这个nano接收器的vendorID和productID分别是0x1d57和0x0016。
执行dmesg查看插入nano接收器的输入信息:
dmesg | tail -n 15 [22375.556155] usb 1-1.1: new full-speed USB device number 9 using ehci_hcd [22375.666762] usb 1-1.1: New USB device found, idVendor=1d57, idProduct=0016 [22375.666769] usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [22375.666773] usb 1-1.1: Product: HID Wireless Mouse [22375.666777] usb 1-1.1: Manufacturer: HID Wireless Mouse [22375.668566] input: HID Wireless Mouse HID Wireless Mouse as /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input9 [22375.668979] generic-usb 0003:1D57:0016.0006: input,hidraw0: USB HID v1.10 Mouse [HID Wireless Mouse HID Wireless Mouse] on usb-0000:00:1d.7-1.1/input0 [22456.751805] usb 1-1.1: USB disconnect, device number 9 [22561.928127] usb 1-1.1: new full-speed USB device number 10 using ehci_hcd [22562.038482] usb 1-1.1: New USB device found, idVendor=1d57, idProduct=0016 [22562.038489] usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [22562.038493] usb 1-1.1: Product: HID Wireless Mouse [22562.038497] usb 1-1.1: Manufacturer: HID Wireless Mouse [22562.040767] input: HID Wireless Mouse HID Wireless Mouse as /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1.1/1-1.1:1.0/input/input10 [22562.041276] generic-usb 0003:1D57:0016.0007: input,hidraw0: USB HID v1.10 Mouse [HID Wireless Mouse HID Wireless Mouse] on usb-0000:00:1d.7-1.1/input0
只有最后7行输出信息与最后一次插入nano接收器有关。
下面获取当前linux的内核源码,我使用的是debian 7.4,使用下面命令查看内核信息:
[email protected]:~/soft/mini2440/linux-2.6.32.2$ uname -a Linux debian 3.2.0-4-686-pae #1 SMP Debian 3.2.54-2 i686 GNU/Linux
当前内核版本是linux 3.2.54, 因为我已经下载了3.2.57的内核,就直接使用该版本的内核源代码(这两个版本源码差别很小,我只是查看源代码,所以就不想重新下载了)。
如果没有内核源代码,可以参考我的博文《编译debian内核》下载内核源码。
内核源代码下载后,执行解压缩,然后进入该文件夹.
鼠标属于hid(human interface device),而nano接收器使用了usb口,所以其对应驱动所在位置很可能是在drivers/hid或者drivers/usb下。
为了确保能找到所有相关代码,我在drivers文件夹执行搜索:
$ find drivers/ -name ‘*.[ch]‘ -exec grep -rnHi ‘full-speed‘ {} \; | grep USB drivers/usb/usb-common.c:23: [USB_SPEED_FULL] = "full-speed",
可以看到该行源代码位于usb_speed_string。在vim下执行"make cscope"、"cs add cscope.out"、"cs f s usb_speed_string"可以搜索到所有使用usb_speed_string的代码。
其中最可能相关联的是hub_port_init函数中调用usb_speed_string的代码。
而hub_port_init又被hub_port_connect_change函数所调用。
当前情况下是将nano接收器插入到usb口,确实满足port连接状况改变的情况。
继续查找信息,使用下面命令:
$ find drivers/ -name ‘*.[ch]‘ -exec grep -rnHi ‘idVendor=‘ {} \; drivers/usb/core/hub.c:1783: dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
该行代码位于annouce_device函数,annouce_device函数内容如下:
1 static void announce_device(struct usb_device *udev) 1782 { 1783 dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n", 1784 le16_to_cpu(udev->descriptor.idVendor), 1785 le16_to_cpu(udev->descriptor.idProduct)); 1786 dev_info(&udev->dev, 1787 "New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n", 1788 udev->descriptor.iManufacturer, 1789 udev->descriptor.iProduct, 1790 udev->descriptor.iSerialNumber); 1791 show_string(udev, "Product", udev->product); 1792 show_string(udev, "Manufacturer", udev->manufacturer); 1793 show_string(udev, "SerialNumber", udev->serial); 1794 }
而annouce_device被usb_new_device调用,usb_new_device又被hub_port_connect_change函数所调用。
倒数第二行的输出信息中不容易用grep搜索到,直接搜索最后一行输出信息中的"generic-usb":
$ find drivers/ -name ‘*.[ch]‘ -exec grep -rnHi ‘generic-usb‘ {} \; drivers/hid/usbhid/hid-core.c:1477: .name = "generic-usb",
这行输出信息很可能是初始化hid(对应于hid_init函数)时得到的输出信息。
稍微整理一下代码的执行流程(参考《essential linux device drivers》)。
usb代码架构中包含有三个重要的组成部分:usbcore, usb host controller driver, usb client driver.
其中usb host controller driver是比较靠近内核的一部分功能,此处不需要考虑。
usbcore中创建了一个khubd线程(位于usb_hub_init函数中)监控端口(port)的状态,当端口(port)状态改变时,会调用hub_port_connect_change函数。
hub_port_connect_change中调用hub_port_init对port进行初始化(包括获取设备描述符,这样能得到所有该设备相关信息),
然后调用usb_new_device调用device_add添加新的usb设备(此处即nano接收器)。
device_add添加该设备(nano接收器)时,主要是创建设备和sysfs文件夹以及添加相应的设备驱动,
中间经过漫长的调用(具体执行过程比较复杂,我还没有好好分析)后会执行hid_bus_match对总线匹配,
匹配成功后执行hid_device_probe->hid_hw_start->hid_connect输出信息。
我手中还有个有线鼠标,插入该鼠标得到的输出信息如下:
[ 7029.876038] usb 2-2: new low-speed USB device number 3 using uhci_hcd [ 7030.051078] usb 2-2: New USB device found, idVendor=046d, idProduct=c05a [ 7030.051085] usb 2-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0 [ 7030.051090] usb 2-2: Product: USB Optical Mouse [ 7030.051093] usb 2-2: Manufacturer: Logitech [ 7030.067358] input: Logitech USB Optical Mouse as /devices/pci0000:00/0000:00:1d.0/usb2/2-2/2-2:1.0/input/input7 [ 7030.067521] generic-usb 0003:046D:C05A.0004: input,hidraw0: USB HID v1.11 Mouse [Logitech USB Optical Mouse] on usb-0000:00:1d.0-2/input0
从输出信息上看,二者输出信息是相当类似的,其驱动执行过程也应该大致相似。
在写博客之前,我猜想无线鼠标可能会用到和有线鼠标不同的驱动程序,但是从整个分析过程看来二者用的驱动程序基本上是差不多的(都是用到usbcore和usbhid)。
linux下无线鼠标驱动执行流程