x86下usb驱动framework

本文讲述的USB驱动,是基于X86架构下的PCI-USB总线下的USB设备驱动,侧重函数调用。架构如下:

x86下usb驱动framework

涉及的几个modules:

arch/x86/pci/legacy.c

drivers/usb/host/uhci-hcd.c

drivers/usb/core/usb.c

其中arch/x86/pci/legacy.c和drivers/usb/core/usb.c使用了subsys_initcall()来申明初始化的函数存放在initcall4这个段,结合makefile可知,drivers/下的先放,arch/x86/下的后放。

故在内核初始化时do_basic_setup时,首先调用的时drivers/下申明的函数,之后才是arch/x86/下的。对于本文来说,是先调用drivers/usb/core/usb.c中申明的usb_init()

drivers/usb/core/usb.c

x86下usb驱动framework

之后才调用arch/x86/pci/legacy.c下申明的pci_subsys_init()

arch/x86/pci/legacy.c

x86下usb驱动framework

drivers/usb/host/uhci-hcd.c中使用了module_init()来申明初始化函数,module_init()对应initcall6段,故它的初始化在另外两个之后。

我们按顺序来看,首先是drivers/usb/core/usb.c

drivers/usb/core/usb.c

x86下usb驱动framework

x86下usb驱动framework

1059行,注册一种总线类型usb bus。

drivers/usb/core/driver.c

x86下usb驱动framework

drivers/base/bus.c

x86下usb驱动framework

x86下usb驱动framework

注册完成后,会在’/sys/bus/’下创建对应总线类型的目录,这里为’/sys/bus/usb’

x86下usb驱动framework

并且在该目录下创建下列文件:

x86下usb驱动framework

1065行,调用usb_major_init()注册字符设备的设备号:主设备号180, 次设备号0-255。

且注册了字符设备chrdev, 可通过cat /proc/devices查看,见下面的图示。

drivers/usb/core/file.c

x86下usb驱动framework

include/linux/fs.h

x86下usb驱动framework

fs/char_dev.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

1068行,注册usb fs驱动,该驱动设置for_device为0,即不用于匹配usb device。

drivers/usb/core/devio.c

x86下usb驱动framework

include/linux/usb.h

x86下usb驱动framework

drivers/usb/core/driver.c

x86下usb驱动framework

1071行调用usb_devio_init()注册字符设备usb_devices,主设备号189,可通过cat /proc/devices查看。

/drivers/usb/core/devio.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

至此,我们已经创建了两个字符设备cdev,一个主设备号180(usb), 另一个主设备号189(usb_device), 这个信息可以通过/proc/devices导出到用户空间。

我们在/dev/下看到的字符设备文件,是通过mknod创建的。

x86下usb驱动framework

1074行调用usb_hub_init(),注册hub_driver,这个driver也不是用于usb device的(for_devices = 0),然后启动一个内核线程hub_thread. 这个hub thread用于处理hub 事件的,后面再讲。

drivers/usb/core/hub.c

x86下usb驱动framework

x86下usb驱动framework

1077行调用usb_register_device_driver()注册通用的usb设备驱动。

drivers/usb/core/generic.c

x86下usb驱动framework

drivers/usb/core/driver.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

在bus_add_driver()中,首先在/sys/bus/usb/drivers/下创建当前驱动的目录(kobject), 然后将驱动插入usb_bus_type的驱动链表klist_drivers中,并且尝试通过driver_attach()去匹配当前已经瓜子在usb_bus_type的devices链表klist_devices中的设备,如果有匹配的设备,则调用驱动的probe()函数。由于我们这个drivers/usb/core/usb.c是第一跑的,故此时还没有usb device挂在usb_bus_type的klist_devices上。

bus_add_driver()最后调用driver_create_file()在/sys/bus/usb/$(driver_name)/下创建uevent文件。

x86下usb驱动framework

x86下usb驱动framework

这个uevent文件,用于处理usb事件,比如插拔usb设备等(据说是在2.6版本之前使用的,2.6版本后不用了)。

当向这个文件写入”ADD”, “REMOVE”等,会触发内核广播netlink消息(<ACTION>@<DEVPATH>)给所有感兴趣的sock,调用/sbin/hotplug程序去处理事件.

内核调用hotplug的参数为: /sbin/hotplug usb

同时设置环境变量:

ACTION=

DEVPATH=/sys/bus/usb/drivers/usb

SUBSYSTEM=usb

SEQNUM=

HOME=/

PATH= /sbin:/bin:/usr/sbin:/usr/bin

最后,总结一下/sys这个路径的含义:

x86下usb驱动framework

至此,我们将完了drivers/usb/core/usb.c的初始化函数usb_init()

接下去是arch/x86/pci/legacy.c

arch/x86/pci/legacy.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

arch/x86/pci/common.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

drivers/pci/probe.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

通过上述调用栈, pci_subsys_init()最终调用了pci_scan_single_device()来扫描pci总线上的设备,以确定某个pci设备是否存在。

pci_scan_single_device()调用pci_scan_device()通过读取vendor_id来判断是否存在对应的pci设备,如果存在,则分配pci_dev内存, 并设置pci_dev的bus type为pci_bus_type。

drivers/pci/probe.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

这个pci_bus_type是在drivers/pci/pci-driver.c中注册的。pci_driver_init使用postcore_initcall()声明,故其存放在initcall2, 更早的时候被调用。

x86下usb驱动framework

pci_bus_type被注册后,系统中就有/sys/bus/pci, /sys/bus/pci/drivers/, /sys/bus/pci/<pci_driver>等文件或目录了,具体的,在usb_bus_type注册的时候讲过了。

pci_scan_single_device()调用pci_scan_device()扫描到设备后,调用pci_device_add()向pci总线注册设备。

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

pci_device_add()通过device_initialize()设置pci_dev的kobj.kset为devices_kset,这个devices_kset为所有pci_dev的“始祖”,这个devices_kset对应的目录为/sys/devices

drivers/base/core.c

x86下usb驱动framework

x86下usb驱动framework

最后,调用device_add(),添加这个pci设备。

drivers/base/core.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

device_add()调用kobject_add()在/sys/devices/创建pci设备对应的目录,并且在该设备目录下创建uevent等文件或目录。

x86下usb驱动framework

x86下usb驱动framework

添加完kobject后,调用bus_add_device()将设备挂到pci_bus_type的klist_devices上。

drivers/base/bus.c

x86下usb驱动framework

x86下usb驱动framework

device_add()最后调用bus_probe_device()去关联驱动和其对应的设备。

drivers/base/bus.c

x86下usb驱动framework

x86下usb驱动framework

drivers/base/dd.c

x86下usb驱动framework

x86下usb驱动framework

通过上述调用栈,在device_attach()中,通过bus_for_each_drv()遍历pci_bus_type上的所有的驱动,找到pci_dev匹配的驱动,并调用这个驱动的probe函数。由于此时,我们的usb hcd驱动还没有注册,所以,这里device_attach()什么也不做。

drivers/base/bus.c

x86下usb驱动framework

x86下usb驱动framework

到此,pci也初始化部分也讲完了,来看最后一个。

最后一个是drivers/usb/host/uhci-hcd.c

drivers/usb/host/uhci-pci.c

x86下usb驱动framework

hcd_name为”uhci_hcd”

drivers/usb/host/uhci-hcd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

include/linux/pci.h

x86下usb驱动framework

drivers/pci/pci-driver.c

x86下usb驱动framework

drivers/base/driver.c

x86下usb驱动framework

x86下usb驱动framework

drivers/base/bus.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

bus_add_driver()调用kobject_init_and_add()在/sys/bus/pci/drivers/下创建了该驱动对应的目录(uhci_hcd)。

x86下usb驱动framework

然后将驱动挂到pci_bus_type的klist_drivers上,并调用driver_attach()去找该驱动匹配的pci设备。

drivers/base/dd.c

x86下usb驱动framework

drivers/base/bus.c

x86下usb驱动framework

x86下usb驱动framework

由于之前PCI驱动已经将扫描到的PCI设备挂到了pci_bus_type的klist_devices上了。故这里klist_devices上有dev, __driver_attach()会被调用。

drivers/base/dd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

driver_match_device()调用pci_bus_type的match函数,即pci_bus_match().

drivers/base/base.h

x86下usb驱动framework

drivers/pci/pci-driver.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

drivers/pci/pci.h

x86下usb驱动framework

通过匹配pci驱动的id_table中的vendor,device,subvendor,subdevice和pci总线扫描出来的设备上的vendor,device,subvendor,subdevice是否一致来判断该驱动和该device是否match。

当当前device是pci-usb-bridge时,且是该驱动支持的厂商设备时,match返回1,即match。

uhci_pci_driver是个通用driver,匹配any_id。

drivers/usb/host/uhci-pci.c

x86下usb驱动framework

include/linux/pci.h

x86下usb驱动framework

驱动和设备匹配后,由于该设备之前是没有对应的驱动的,即dev->driver为NULL, 所以__driver_attach()调用driver_probe_device()函数。

drivers/base/dd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

really_probe()调用driver_sysfs_add()在驱动目录下创建一个link,link到对应的设备文件。

并在设备文件目录下创建一个link,link到这个驱动。

x86下usb驱动framework

然后,调用pci_bus_type的probe函数,即pci_device_probe().

drivers/pci/pci-driver.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

最终,调用pci驱动的probe()函数,我们这里,即usb_hcd_pci_probe()

drivers/usb/host/uhci-hcd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

drivers/usb/host/uhci-pci.c

x86下usb驱动framework

drivers/usb/core/hcd-pci.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

189行的id->driver_data为uhci_driver,定义如下:

drivers/usb/core/hcd-pci.c

x86下usb驱动framework

x86下usb驱动framework

212行调用usb_create_hcd()创建hcd(host control device).

drivers/usb/core/hcd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

hcd的结构为struct usb_hcd + struct uhci_hcd. dev->p-driver_data = hcd;  hcd->driver为id_table中的driver_data, 即uhci_pci_ids[0].driver_data.

x86下usb驱动framework

249行将pci-usb-bridge的io资源注册到系统中。

275行调用usb_add_hcd(hcd, hcd_irq, IRQF_SHARED)注册这个hcd,hcd是作为usb总线的。, 其中hcd_irq为pci中断号。

再往下将之前,先来介绍下linux kernel对usb的管理结构,如下图:

 

x86下usb驱动framework

所有的usb设备都是挂载virtual Root Hub下的,hub可以级联。而virtual Root Hub是属于Host Controller的。上面说的root hub就是上图中的virtual Root Hub, 它是第一个usb device.

drivers/usb/core/hcd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

2627行,注册hcd为usb_bus, 总线号为1. 并调用usb_notifier_list上的notify函数发送USB_BUS_ADD信息。

drivers/usb/core/hcd.c

x86下usb驱动framework

x86下usb驱动framework

drivers/usb/core/notify.c

x86下usb驱动framework

这个usb_notifier_list为driver/usb/core/usb.c中通过usb_devio_init()注册的。

driver/usb/core/usb.c

 

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

2630行调用usb_alloc_dev()申请usb_device内存,这个usb_device是用作virtual Root Hub的。

drivers/usb/core/usb.c

x86下usb驱动framework

x86下usb驱动framework

这个usb_device将会设置kobject的parent为’/sys/devices’, 由于pci-usb-bridge是作为pci设备的,故在pci目录下:

x86下usb驱动framework

另外,这个usb_device将会被挂载到usb_bus_type的klist_devices上。

x86下usb驱动framework

并且设置usb_device的devpath.对于virtual Root Hub, 其为’0’,对于它的child,则为port号,再低一层级则为port1.port2

2670行调用id_table[].driver_data.reset()即uhci_pci_init()。

drivers/usb/host/uhci-pci.c

x86下usb驱动framework

uhci_pci_init()调用uhci_count_ports(),向uhci->io_addr发送port status get命令,来判断这个端口是否可用,通过这样的方式来获取port的数目,该数目就是virtual Root Hub的port数目,它决定了virtual Root Hub下面可以挂多少usb_device.

2689行,调用usb_hcd_request_irqs()来设置中断处理程序usb_hcd_irq()。

drivers/usb/core/hcd.c

x86下usb驱动framework

x86下usb驱动framework

include/linux/interrupt.h

x86下usb驱动framework

drivers/usb/core/hcd.c

x86下usb驱动framework

这里的hcd->driver->irq为uhci_irq()。

drivers/usb/host/uhci-hcd.c

x86下usb驱动framework

中断程序先不将,后面合适的时候再来将。

2695行调用hcd->driver->start(),即uhci_start()。

drivers/usb/host/uhci-hcd.c

x86下usb驱动framework

uhci_start()给hcd做一些初始化配置,比如queue, dma pool等, 之后,调用configure_hc设置host controller寄存器,比如配置SOF,frame_number,设置framd dma物理地址等。

configure_hc之后又调用start_rh让host controller run起来。

drivers/usb/host/uhci_hcd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

2702行调用register_root_hub()注册usb virtual Root Hub.

drivers/usb/core/hcd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

register_root_hub()首先获取virtual root hub的设备描述符(device descriptor), 然后调用usb_new_device()。

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

usb_new_device()调用usb_enumerate_device()获取这个virtual root hub的配置描述符(config descriptor), 接口描述符(interface descriptor), 端点描述符(ep descriptor), 并解析描述符,写入udev->config.

virtual root hub作为第一个usb device,其描述符是固定的,如下:

drivers/usb/core/hcd.c

设备描述符

x86下usb驱动framework

配置描述符 + 接口描述符 + endpoint描述符

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

之后调用device_add()将这个hcd设备添加到系统中(可以通过/sys/devices/来查询), 这个device_add()将触发hcd关联的bus type上匹配的驱动的probe()。

从前面的代码,我们直到hcd的bus type为usb_bus_type,我们先来分析它的match函数。

drivers/usb/core/driver.c

x86下usb驱动framework

x86下usb驱动framework

drivers/usb/core/usb.h

x86下usb驱动framework

所以,对于usb device而言,只要有驱动的for_devices为1的,就可以match。

在讲解drivers/usb/core/usb.c的初始化函数时,我们知道有且只有usb generic的驱动设置了这个。故usb generic驱动的probe()将被调用来处理hcd device。

drivers/usb/core/generic.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

generic_probe()调用usb_choose_configuration()从usb设备的多个配置描述符中选择一个合适的。然后调用usb_set_configuration()**设备的选中的配置描述符的配置。

drivers/usb/core/message.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

同时,创建这个设备的interface, 以及interface下的endpoint.

interface object的命名为<busno>-<parent_devpath>.<config_index>.<interfacenumber>,比如1-0:1.0

endpoint的命令为ep_<endpointaddr>.

x86下usb驱动framework

这里两种device,我们分开介绍:usb_if_device和usb_ep_device。

先介绍usb_if_device.

drivers/usb/core/message.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

首先给root hub创建了interface device, 注意上述中的dev.type为usb_if_device_type.当调用device_add()添加该设备时,

drivers/base/core.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

drivers/base/bus.c

x86下usb驱动framework

添加interface device会触发usb bus驱动匹配。我们来看usb bus type的match函数。

drivers/base/dd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

drivers/base/base.h

x86下usb驱动framework

drv->bus->match为usb_bus_type的match。

drivers/usb/core/driver.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

由于当前添加的是interface,故走788行分支。

drivers/usb/core/driver.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

usb_bus_type.match,遍历所有注册的usb_driver,调用usb_match_device()匹配root hub中的设备描述符,即匹配usb11_rh_dev_descriptor[].

然后调用usb_match_one_id_intf()匹配root_hub中的一个interface描述符。

这里会匹配上hub_driver。我们来看hub_driver。

drivers/usb/core/hub.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

匹配root hub设备描述符时,id为hub_driver的hub_id_table[2],match_flag为USB_DEVICE_ID_MATCH_INT_CLASS,device_class为USB_CLASS_HUB(9), 不会命中任何if branch,最后返回1. 然后去匹配interface.

匹配interface描述符时,id为同一个id,为hub_driver的hub_id_table[2],match_flag为USB_DEVICE_ID_MATCH_INT_CLASS,interfaceclass为USB_CLASS_HUB(9)。root hub 对应的interface描述符的值为:

x86下usb驱动framework

x86下usb驱动framework

所以,root hub的interface这个usb device会匹配hub_driver这个usb_driver,匹配的id为hub_driver的hub_id_table[2]。

匹配之后,调用driver_probe_device(), 第一个参数为hub_driver的device_driver, 第二个参数为root hub的interface.

drivers/base/dd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

usb_bus_type没有probe函数,故这里直接调用了usb_driver的device_driver的probe()函数。

对于hub_driver而言,其device_driver的probe函数为:usb_probe_interface

drivers/usb/core/hub.c

x86下usb驱动framework

include/linux/usb.h

x86下usb驱动framework

drivers/usb/core/driver.c

x86下usb驱动framework

usb_probe_interface()最终去调用usb_driver的probe()。

drivers/usb/core/driver.c

x86下usb驱动framework

x86下usb驱动framework

即,最终调用了hub_driver的probe函数hub_probe().

drivers/usb/core/hub.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

hub_probe分配usb_hub设备内存,然后调用hub_configure(), 参数2endpoint为root hub设备的endpoint, 不再是root hub的ep0了。

hub_configure通过get_hub_descriptor获取hub descriptor, hub descriptor定义如下:

drivers/usb/host/uhci-hub.c

x86下usb驱动framework

之后,根据hub descriptor的bNbrPorts申请usb_port内存。

接着调用usb_get_status(),获取hub device status,hub device status的值如下:

drivers/usb/core/hcd.c

x86下usb驱动framework

x86下usb驱动framework

然后,调用hub_hub_status() -> get_hub_status()获取hub status, 如下:

drivers/usb/host/uhci_hub.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

之后,给hub申请urb, 并设置pipe为endpoint descriptor描述的address。

再调用usb_hub_create_port_device(),创建hub下的usb_port设备。

最后调用hub_activate(hub, HUB_INIT)。

drivers/usb/core/hub.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

hub_active()调用hub_port_status,通过pci  io addr + req去获取硬件hub上指定的Port的状态信息,如下(266行):

drivers/usb/host/uhci_hub.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

portstatus & USB_PORT_STAT_CONNECTION== 1表示当前port1上有设备连着。

1166行设置port change位,标识当前hub哪个port状态发生了变化。

当usb接口上连接了usb设备,则port信息会变化。

以ast2500evt为例,来看一下port 寄存器的定义。

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

最后,hub_active()进入INIT3阶段时,调用usb_submit_urb(),递交了一个之前设置好的urb(usb request block)

//hub_configure()

x86下usb驱动framework

x86下usb驱动framework

//hub_active()

x86下usb驱动framework

drivers/usb/core/urb.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

drivers/usb/core/hcd.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

usb_submit_urb()最终调用rh_queue_status()。

rh_queue_status()调用usb_hcd_link_urb_to_ep()将usb挂到ep urb_list上。

x86下usb驱动framework

然后将hcd的status_urb指向这个urb。

hub_active()最后调用kick_khubd()。

drivers/usb/core/hub.c

x86下usb驱动framework

kick_khubd()将当前hub添加到hub_event_list(572行),并唤醒等待队列khubd_wait。

这个等待队列会将hub thread唤醒。

我们接着来看这个hub thread.

drivers/usb/core/hub.c

x86下usb驱动framework

x86下usb驱动framework

hub_thread为这个hub thread的内核线程的入口函数。

hub_thread刚运行时,hub_event_list为空,hub_events()会马上返回,然后这个线程就sleep在这个等待队列khubd_wait上。当hub_active()唤醒这个khubd_wait后,hub_event_list不为空,hub_thread又循环回到hub_events()处理。

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

hub_events循环扫描hub的所有ports,如果Port连接状态改变了,即portchange & USB_PORT_STAT_C_CONNECTION, 则先清除这个register对应的bit,并设置connect_change为1.

之后,再调用hub_port_connect_change()来处理当前port的连接状态的变化。

drivers/usb/core/hub.c

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

x86下usb驱动framework

hub_port_connect_change()申请usb_device内存(udev),这个udev代表了连接在hub port上的usb设备,然后调用hub_port_init(), hub_port_init()去reset外设(USB外设),并获取该usb外设的设备描述符。

最后hub_port_connect_change()调用usb_new_device()注册这个udev。

这个udev再usb_alloc_dev时,有如下设置:

x86下usb驱动framework

即该udev会被挂到usb_bus_type的device_klist上,且type为usb_device_type。

于是,当调用usb_new_device()注册该udev设备时,会触发以下actions:

遍历usb_bus_type的drivers_klist上的驱动;

调用其match函数,匹配驱动和注册的设备udev;

如果驱动匹配设备udev,则调用驱动的probe()函数。

总之,usb_new_device()会查找系统中注册的usb驱动程序,找到设备对应的驱动程序后,调用驱动程序的probe()函数。

drivers/usb/core/hub.c

x86下usb驱动framework

x86下usb驱动framework

至此,我们的这部分的也结束了。

以上部分,我们讲解了对于pci-usb bridge架构下,系统如何检测usb设备连入,以及查找对应的驱动,并调用驱动的probe()函数。接下去,那就是驱动程序做的事了。

有个问题,既然usb是标准规范的,为什么要查找usb外设驱动?难道不是一个驱动就能搞定的吗?

答:usb外设有各种设备,比如打印机,摄像头,鼠标,键盘等。这些设备有各自不同的feature和要求,比如有只有input的或只有output的,或要求大吞吐的,或要求同步的,每种设备的电气或配置要求有差异。故需要特别的驱动。