操作系统: debian 7.4(linux 3.2.54)

硬件: 一个无线鼠标、一个有线鼠标、usb集线器。

从淘宝上花了15块钱买了个无线鼠标,很好奇它的驱动程序是如何执行的。

首先将usb集线器插入到pc的usb口,然后将无线鼠标插入到usb集线器的一个usb口上。

执行下面命令来捕获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:/::1d./usb1/-/-1.1/-1.1:1.0/input/input10/mouse0/device/id/vendor
1d57
$ cat /sys/devices/pci0000:/::1d./usb1/-/-1.1/-1.1:1.0/input/input10/mouse0/device/id/product

这与lsusb命令获取的信息一致:

$ lsusb
Bus Device : ID 1d6b: Linux Foundation 2.0 root hub
Bus Device : ID 1d6b: Linux Foundation 1.1 root hub
Bus Device : ID 1d6b: Linux Foundation 1.1 root hub
Bus Device : ID 1d6b: Linux Foundation 1.1 root hub
Bus Device : ID 1d6b: Linux Foundation 1.1 root hub
Bus Device : ID 1a40: Terminus Technology Inc. -Port HUB
Bus 001 Device 010: ID 1d57:0016 Xenta
Bus Device : ID 046d:c05a Logitech, Inc. Optical Mouse M90
Bus Device : ID 413c: Dell Computer Corp. Keyboard
Bus Device : ID 0a12: 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 missing
Device 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
[22375.556155] usb -1.1: new full-speed USB device number using ehci_hcd
[22375.666762] usb -1.1: New USB device found, idVendor=1d57, idProduct=
[22375.666769] usb -1.1: New USB device strings: Mfr=, Product=, SerialNumber=
[22375.666773] usb -1.1: Product: HID Wireless Mouse
[22375.666777] usb -1.1: Manufacturer: HID Wireless Mouse
[22375.668566] input: HID Wireless Mouse HID Wireless Mouse as /devices/pci0000:/::1d./usb1/-/-1.1/-1.1:1.0/input/input9
[22375.668979] generic-usb :1D57:0016.0006: input,hidraw0: USB HID v1. Mouse [HID Wireless Mouse HID Wireless Mouse] on usb-::1d.-1.1/input0
[22456.751805] usb -1.1: USB disconnect, device number
[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,使用下面命令查看内核信息:

host@debian:~/soft/mini2440/linux-2.6.32.2$ uname -a
Linux debian 3.2.---pae # SMP Debian 3.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:: [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:: dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",

该行代码位于annouce_device函数,annouce_device函数内容如下:

 static void announce_device(struct usb_device *udev)
{
dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
dev_info(&udev->dev,
"New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
udev->descriptor.iManufacturer,
udev->descriptor.iProduct,
udev->descriptor.iSerialNumber);
show_string(udev, "Product", udev->product);
show_string(udev, "Manufacturer", udev->manufacturer);
show_string(udev, "SerialNumber", udev->serial);
}

而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:: .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 -: new low-speed USB device number  using uhci_hcd
[ 7030.051078] usb -: New USB device found, idVendor=046d, idProduct=c05a
[ 7030.051085] usb -: New USB device strings: Mfr=, Product=, SerialNumber=
[ 7030.051090] usb -: Product: USB Optical Mouse
[ 7030.051093] usb -: Manufacturer: Logitech
[ 7030.067358] input: Logitech USB Optical Mouse as /devices/pci0000:/::1d./usb2/-/-:1.0/input/input7
[ 7030.067521] generic-usb :046D:C05A.: input,hidraw0: USB HID v1. Mouse [Logitech USB Optical Mouse] on usb-::1d.-/input0

从输出信息上看,二者输出信息是相当类似的,其驱动执行过程也应该大致相似。

在写博客之前,我猜想无线鼠标可能会用到和有线鼠标不同的驱动程序,但是从整个分析过程看来二者用的驱动程序基本上是差不多的(都是用到usbcore和usbhid)。

linux下无线鼠标驱动执行流程的更多相关文章

  1. debian下使用dynamic printk分析usb转串口驱动执行流程

    看了一篇文章<debug by printing>,文中提到了多种通过printk来调试驱动的方法,其中最有用的就是"Dynamic debugging". “Dyna ...

  2. 转载-Linux下svn搭建配置流程

    Linux下svn搭建配置流程     一.    源文件编译安装.源文件共两个,为: 1.   下载subversion源文件 subversion-1.6.1.tar.gz http://d136 ...

  3. cron Linux下的定时执行工具

    说明:测试平台  Ubuntu 16.04.4 LTS cron是一个Linux下的定时执行工具,可以在无需人工干预的情况下运行作业.所以,在Linux中,周期性执行的任务一般由cron这个守护进程来 ...

  4. 【驱动】linux下I2C驱动架构全面分析

    I2C 概述 I2C是philips提出的外设总线. I2C只有两条线,一条串行数据线:SDA,一条是时钟线SCL ,使用SCL,SDA这两根信号线就实现了设备之间的数据交互,它方便了工程师的布线. ...

  5. linux下I2C驱动架构全面分析【转】

    本文转载自:http://blog.csdn.net/wangpengqi/article/details/17711165 I2C 概述 I2C是philips提出的外设总线. I2C只有两条线,一 ...

  6. 如何用javac 和java 编译运行整个Java工程 (转载)【转】在Linux下编译与执行Java程序

    如何用javac 和java 编译运行整个Java工程 (转载)  http://blog.csdn.net/huagong_adu/article/details/6929817 [转]在Linux ...

  7. php 运行linux命令 与 linux下命令行执行php

    1.php运行linux命令 exec函数:string exec(string command, string [array], int [return_var]);  执行函数后不输出结果,返回最 ...

  8. Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析

    源: Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析

  9. Linux下用freetds执行SQL Server的sql语句和存储过程

    Linux下用freetds执行SQL Server的sql语句和存储过程 http://www.linuxidc.com/Linux/2012-06/61617.htm freetds相关 http ...

随机推荐

  1. 对象序列和反序列化Xml

    1. XmlArray和XmlArrayItem XmlArray和XmlArrayItem是不同的,XmlArray是指这个数组叫什么,XmlArrayItem 值数组的每个元素叫什么. <X ...

  2. 了解MVC框架开发

    版权声明:本文为博主原创文章,未经博主允许不得转载. 前言:本篇文章我们浅谈下MVC各个部分,模型(model)-视图(view)-控制器(controller), 以及路由. 对于使用MVC的好处大 ...

  3. url中带有加号的处理方法

    最近项目中出现了一个问题,图片的路径正确,但是转成URL之后无法找到... 找了各种原因之后,最后注意到URL中的图片名称和本地路径名称有点不一样,如下图 1.URL图片 2.本地路径 上网查了一下发 ...

  4. Swing实现右下角消息框

    package com.ui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; impo ...

  5. ICloneable接口 Clone 深拷贝 浅拷贝

    需要字段本身也实现了深拷贝Clone.应用场景不多,意义不大. 1. 隐含式地要求其子类和引用类也要实现ICloneable接口,如果引用层次比较深类似一个网状或树形接口,增加复杂性. 2. 考虑给s ...

  6. 转载:SQL 字符串操作函数

    http://www.cnblogs.com/jiajiayuan/archive/2011/06/16/2082488.html 以下所有例子均Studnet表为例:  计算字符串长度len()用来 ...

  7. [转]maven2中snapshot快照库和release发布库的区别和作用

    Post by 铁木箱子 in 技术杂谈 on 2010-08-03 17:17 [转载声明] 转载时必须标注:本文来源于铁木箱子的博客http://www.mzone.cc[原文地址] 原文永久地址 ...

  8. JAVA card 应用开发(六) 个人化数据的线路安全和数据安全

    卡片个人化数据的线路安全和数据安全 说明:下面理论,基于GP2.2规范. 一.线路安全 1. 概念:线路安全.就是对于数据不保密.但要保证数据的完整性和防止被篡改. 2. 方法:在原有的数据基础上.加 ...

  9. TortoiseSVN与VisualSVN Server搭建SVN版本控制系统(转)

    地址:http://www.cnblogs.com/xing901022/p/4399382.html

  10. python语言特性-------python2.7教程学习【廖雪峰版】(一)

    开始学习廖雪峰的py2.7教程: 2017年6月5日12:54:28 笔记: 廖雪峰python2.7教程1.用任何编程语言来开发程序,都是为了让计算机干活.  2.Python是一种相当高级的语言. ...