Linux USB驱动分析

来源:互联网 发布:矩阵数据分析法案例 编辑:程序博客网 时间:2024/05/22 12:38

主机控制器的pci driver匹配device成功之后,会注册一条usb总线,并添加一个root hub device。usb core模块会添加hub的drvier。root hub device会与hub driver进行匹配。


主机控制器接口类型:

OHCI - USB1.1 + Apple火线等接口

UHCI - USB1.0 + USB1.1 (Intel主导,与OHCI不兼容)

EHCI - USB2.0 (Intel主导)

XHCI - USB3.0 (支持USB2.0 Low/Full/High, USB1.1 Low/Full,将替代EHCI/UHCI/OHCI)


usb/host/xhci.c/module_init(xhci_hcd_init)

xhci_hcd_init()

    /* Check compiler fields size */



/*********************************************

*

*    加载HCD驱动

*        添加root hub device

*

*********************************************/

usb/host/xhci-pci.c/module_init(xhci_pci_init)

    xhci_init_driver(&xhci_pci_hc_driver, xhci_pci_setup)

        *drv = xhci_hc_driver

        drv->reset = setup_fn

    pci_register_driver(&xhci_pci_driver)

        struct pci_driver xhci_pci_driver = {.name = (char *) "xhci_hcd", .id_table = pci_ids, ...}

        struct pci_device_id pci_ids[] = {

            {

                PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),

                .driver_data =    (unsigned long) &xhci_pci_hc_driver,
            },
        }

        xhci_pci_hc_driver = xhci_hc_driver

            struct hc_driver xhci_hc_driver = {
                .description =        "xhci-hcd",
                .product_desc =        "xHCI Host Controller",
                .hcd_priv_size =    sizeof(struct xhci_hcd *),
                .irq =            xhci_irq,
                .flags =        HCD_MEMORY | HCD_USB3 | HCD_SHARED,
                .reset =        NULL, /* set in xhci_init_driver() */
                .start =        xhci_run,

            }

/* usb/host/xhci-pci.c */

xhci_pci_probe(dev, id)

    driver = xhci_hc_driver

    /* 创建了一个struct usb_hcd并设置到pci设备driver_data里面 */

    usb_hcd_pci_probe(dev, id)  // dev=struct pci_dev

        driver = xhci_hc_driver

        hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev))

            /* 创建primary hcd */

            usb_create_shared_hcd(driver, dev, bus_name, NULL) // dev=struct device

                hcd = kzalloc(struct usb_hcd)

                dev_set_drvdata(dev, hcd)

                usb_bus_init(&hcd->self)

                hcd->driver = driver

        dev_set_drvdata(&dev->dev, hcd)

        device_wakeup_enable(hcd->self.controller)

        pci_dev_run_wake(dev)

    hcd = dev_get_drvdata(&dev->dev)

    xhci = hcd_to_xhci(hcd) /* xhci = hcd->hcd_priv */

    xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev, pci_name(dev), hcd) /* 创建shared hcd */

    xhci->shared_hcd->hcd_priv) = xhci

    usb_add_hcd(xhci->shared_hcd, dev->irq, IRQF_SHARED)

        usb_register_bus(&hcd->self)

            list_add (&bus->bus_list, &usb_bus_list)

        rhdev = usb_alloc_dev(NULL, &hcd->self, 0) /* 申请root hub设备内存 */

            dev = kzalloc(struct usb_device)

            dev->dev.bus = &usb_bus_type

            dev->dev.type = &usb_device_type

        hcd->self.root_hub = rhdev

        hcd->driver->reset(hcd)

            xhci_pci_setup()

        usb_hcd_request_irqs(hcd, irqnum, irqflags)

            request_irq(irqnum, &usb_hcd_irq, irqflags, hcd->irq_descr, hcd) /* 注册hcd中断处理函数 */

        hcd->driver->start(hcd)

            xhci_run()

        register_root_hub(hcd) /*注册root hub设备*/

            struct usb_device *usb_dev = hcd->self.root_hub

            usb_new_device (usb_dev)

                device_add(&udev->dev)



/*********************************************

*

*    加载usb core

*        添加hub interface driver

*        添加usb generic driver

*

*********************************************/


/* usb/core/usb.c */

usb_init()

    bus_register(&usb_bus_type)

        bus->p = priv

        bus->p->drivers_autoprobe = 1

        bus->p->devices_kset = kset_create_and_add("devices", NULL, &priv->subsys.kobj)

        bus->p->drivers_kset = kset_create_and_add("drivers", NULL, &priv->subsys.kobj)

    usb_hub_init()

        usb_register(&hub_driver) /* usb interface driver */

            usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)

                new_driver->drvwrap.for_devices = 0 /* interface driver */

                new_driver->drvwrap.driver.bus = &usb_bus_type

                new_driver->drvwrap.driver.probe = usb_probe_interface

                driver_register(&new_driver->drvwrap.driver)  /* base/driver.c */

                    struct usb_driver hub_driver = {.name = "hub", .probe = hub_probe, ..}

                    driver_find(drv->name, drv->bus)

                    bus_add_driver(drv)

                        driver_attach(drv)

                            bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)

                                __driver_attach()

                                    driver_match_device(drv, dev)

                                        drv->bus->match(dev, drv)

                                           usb_device_match()

                                             

                                    driver_probe_device(drv, dev)

                    driver_add_groups(drv, drv->groups)

                    kobject_uevent(&drv->p->kobj, KOBJ_ADD)

        hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0)

    usb_register_device_driver(&usb_generic_driver, THIS_MODULE)

        new_udriver->drvwrap.for_devices = 1 /* device driver */

        new_udriver->drvwrap.driver.bus = &usb_bus_type

        new_udriver->drvwrap.driver.probe = usb_probe_device

        driver_register(&new_udriver->drvwrap.driver)

            struct usb_device_driver usb_generic_driver = {.name = "usb", .probe = generic_probe, ..}

            driver_find(drv->name, drv->bus)

            bus_add_driver(drv)

                driver_attach(drv)

                    bus_for_each_dev(drv->bus, NULL, drv, __driver_attach)

                        __driver_attach()

                            driver_match_device(drv, dev)

                                drv->bus->match(dev, drv)

                                    usb_device_match()

                                        is_usb_device(dev) && !is_usb_device_driver(drv)

                                        return 1 /* root hub device */

                                    driver_probe_device(drv, dev)

                                        really_probe(dev, drv)

                                            dev->bus->probe?dev->bus->probe(dev)

                                            drv->probe?drv->probe(dev)

                                                usb_probe_device()

                                                    udriver->probe(udev)

                                                        generic_probe()

            driver_add_groups(drv, drv->groups)

            kobject_uevent(&drv->p->kobj, KOBJ_ADD)


generic_probe()

    usb_choose_configuration(udev)

    usb_set_configuration(udev, c)

        device_add(&intf->dev)




/*  */

hub_probe()


/* HCD中断处理 */

usb_hcd_irq()

    hcd->driver->irq(hcd)

        xhci_irq()

            xhci_handle_event(xhci)


uhci_hcd_init()

    pci_register_driver()

        uhci_pci_driver.probe() -> usb_hcd_pci_probe()

            usb_add_hcd()

                usb_register_bus() /* 一个usb主控制器对应一条usb总线 */

                usb_alloc_dev() /* 给root hub分配空间 */

                usb_hcd_request_irqs() /* 注册中断 */

                register_root_hub() /* 注册root hub到总线 */

                    usb_new_device()

                        device_add()


/* usb/core/usb.c */

__init usb_init()

    bus_register(&usb_bus_type)

    usb_hub_init()

        usb_register(&hub_driver)

        kthread_run(hub_thread) /* 监视hub设备插拔 */

    usb_register_device_driver(&usb_generic_driver)

        /* usb/core/generic.c */

        struct usb_device_driver usb_generic_driver = {

            .name = "usb", 

            .probe = generic_probe,

            ...

        }

    usb_generic_driver.probe() -> generic_probe()

       


/* usb/serial/usb-serial.c */

__init usb_serial_init()

    bus_register(&usb_serial_bus_type)

    tty_register_driver(usb_serial_tty_driver)

    usb_register(&usb_serial_driver)


hcd->self代表的实际的物理总线。一个usb设备分为device和interface两个层面。 usb_register_device_driver注册的是device层面的驱动,能匹配所有的usb设备,root_hub设备与正常插入的usb设备都要先与这个usb_device_driver匹配,然后进入generic_probe函数中添加对应的intf->dev,再与intf driver匹配进入root_hub设备的hub_probe函数或着usb设备的xxx_probe函数。usb_register_driver注册的是interface层面的驱动,与usb device具体功能相关。



Linux设备模型的基础结构体是kobject和kset,kset相当于文件夹,kobject相当于文件。总线kset包含了两个kset——driver kset和device kset。加载driver时,driver总是先把自己注册到某一个bus,即把driver的kobject加入到bus的driver kset中,形成层次关联。而当系统检测到device时,也会先判断device属于哪个总线,然后遍历总线下的所有driver,匹配该设备,一般根据设备的pid和vid,去匹配driver的pid和vid。


USB子系统属于典型的Linux设备模型。USB设备首先插入HUB上面,HUB再通知USB主控制器有设备插入。这里USB主控制器,HUB,USB设备都作为设备挂载到USB bus上。相应的,USB主控制器driver、HUB driver、USB device driver也要挂载到USB bus上。一条USB总线对应一个USB主控制器,USB主控制器类型有UHCI、OHCI、ECHI。一般这些主控制器是PCI接口或者platform设备,driver先加载PCI驱动或者platform驱动,然后再添加USB总线。USB主控制器通常集成了一个root hub,USB主控制器驱动好以后,会把root hub作为一个设备添加到usb总线的设备队列,并查找对应driver。

uhci_hcd_init()

    pci_register_driver()

        uhci_pci_driver.probe() -> usb_hcd_pci_probe()

            usb_add_hcd()

                usb_register_bus() /* 一个usb主控制器对应一条usb总线 */

                usb_alloc_dev() /* 给root hub分配空间 */

                usb_hcd_request_irqs() /* 注册中断 */

                register_root_hub() /* 注册root hub到总线 */

                    usb_new_device()

                        device_add()


主控制器发现了root hub接口后,调用hub_probe函数开始配置root hub。

http://www.cnblogs.com/image-eye/archive/2012/02/02/2336035.html
1.  通过接口描述符获得当前接口描述符,通过分析当前的接口描述符的bInterfaceSubClass成员是不是hub类成员,是不是只有一个端口,这个端口是不是中断端口,来判断是否是一个hub设备,如果通不过这些验证,表示不是hub设备,退出
2.  通过1的验证,可以证明是hub设备了,才给hub设备分配控制(struct usb_hub),并初始化hub结构体,即struct usb_hub是在这里被初始化的。
3.  配置root hub,分配用于urb传输的缓存和DMA地址(两者是关联的),hub状态空间,hub描述符空间,分配完后,通过向设备发送请求,获得设备的描述符,通过描述符得到hub的各种参数,用这些参数配置usb_hub中的usb_device结构体。
4.  获取hub跟host连接的管道,及管道端点的大小,这个管道是中断传输的,端点大小不能大于刚刚分配的缓冲区的大小
5.  申请一个urb空间,用于准备传输urb请求数据。
6.  填充hub的urb数据,包括管道,缓存,缓存长度,中断处理函数等,这个是最重要的,经过在这里的配置,当hub端口有中断信号(即有设备插入或拔开)时,就会调用这里已经配置好的中断函数,来唤醒hub守护进程,进程得到执行,开始解析端口的状态---urb是需要请求的时候才会创建的,urb创建完,提交给主机后,就被系统释放了。
7.  通过设备接口属性,使能hub 上行端口的power-on
8.  把刚刚申请的urb发送给主机,如果一切正常,主机就会定时来询问hub是否有中断,如果就进行中断传输,发送的urb请求是把hub的各种数据报给主控制器,让主控制器知道。
9.  到此,hub就开始正常工作了,随时等候中断信号,并跟主控制器报告。


usb系统在usb_init时启动了一个内核线程——hub的守护线程。设备插入usb接口时,这个守护线程通过中断方式通知主控制器,主控制器再调用hub的probe函数来解析我们的设备。

https://www.cnblogs.com/image-eye/archive/2012/02/04/2338271.html

Hub正常工作后,主控制器就会定时询问hub是否有中断产生,当hub端口上有一个设备插入或拔除,hub就向主控制器发送urb请求,即把hub端口的变化状况告诉主控制器,这是通过urb请求来完成的,主机在处理完了这个urb后,就会调用urb所提供的完成函数,来调用hub的中断函数,即hub_irq。
Hub_irq是hub的中断处理函数,处理程序首先判断主控制器处理urb的结果状态,如果状态是OK的,则继续处理。
1.扫描hub的所有端口,确定是哪个端口发生了变化。端口是用位图来表示的,一个long型数据可以表示32个hub端口(每位表示一个端口),有多少个端口,就用多少位表示,而8位用一个字节表示,因此,最后的使用的位都是转化成了字节的的,比如一个hub有18个端口,则需要用18位来表示,但是一个字节只有8位,因此,需要用3个字节才能表示完。
2.调用kick_khubd函数,把当前hub加入到hub驱动队列hub_event_list中,然后唤醒hub守护进程wake_up(khubd_wait),开始解析hub发生的事情了。
3.hub_thread被唤醒后,将得到执行,hub_events也将得到执行
4.hub_events是分析hub事件的主函数,hub分析的相关内容都在这里执行。这个函数是一个大的死循环。
5.Hub_events处理流程
5.1先从hub_event_list中取出此次处理的hub节点,并把hub节点从原来的队列中删除,使之独立于任何链表,因为我们处理完事件后,hub结构体就要删除,因此不能保留在任何队列中。hub可以是根hub,也可以是接到根hub上的子hub,只是,不论是什么hub,都使用同样的守护进程了。
5.2.通过宏转换,找到hub节点对以的hub结构体,进而得到hub结构体对应的usb结构体,以及hub接口结构体usb_intfdev,得到这三个结构体是这个函数处理的关键。
5.3.锁住当前的hub树,因为hub只有一个守护进程,所有的hub都使用这个守护进程,而守护进程每次只能服务一个hub,因此,只要有一个hub在使用这个守护进程,就需要锁住,以防止其他hub的使用。
5.4.按位检索hub每个端口是否正在执行reset或resume操作,注意是从1开始检索的,位0表示整个hub的情况,如果当前端口正在执行reset或resume操作,则跳过对这端口的检查,否则,测试这个端口是否有状态改变,如果没有状态改变,也跳过此端口。
5.5.如果端口有状态改变,则判断端口是发生了什么状态的改变,有以下的状态
#define USB_PORT_STAT_C_CONNECTION    0x0001
#define USB_PORT_STAT_C_ENABLE              0x0002
#define USB_PORT_STAT_C_SUSPEND           0x0004
#define USB_PORT_STAT_C_OVERCURRENT  0x0008
#define USB_PORT_STAT_C_RESET         0x0010
5.6.确定有状态改变后,就开始对有改变的端口的状态进行进一步的处理,此时的处理,就要根据刚刚分析得到的各种状态,分开进行处理。
5.7.首先要确定端口是否还有设备,如果有,则要把设备删除,原因是,hub端口上有两种状态发生转换,1为端口从无设备到有设备的状态,此时设备还在认证中,因此端口不应该有设备,2是端口从有到无设备的转换,此时检测到还有设备,表示设备还没有被移除,因此,需要直接把设备disable掉。
5.8.把设备disable掉的动作,需要进行反弹的检查,一个设备至少需要100ms的时间,才能表示此状态是稳定的,因此,等100ms后再判断端口是否是disable了,就可以判断了
5.9.判断设备状态为无设备插入时,需要检测是否是端口电源被disable掉了,如果是,则需要开启端口电源,如果电源是开启的,则表示设备有误,结束判断,返回上层。
5.10.经过上面的判断,能执行到这里,表示端口是有设备插入了,此时,就需要要分析端口的状态了,对端口的分析,可以尝试4次,主要是为了排除各种干扰。
5.11.为即将到来的设备分配空间(struct usb_device),对这个即将到来的设备的设备结构体设置状态为连接状态,速度为未知,电源为hub分配给的,这些都是默认状态。
5.12.准备为设备分配地址,此时是子系统软件的操作,就是查看总线上128位位图中,哪位为0的,就选择出来,查找的方式是从上次记录的下一位开始查找,如果超过128了还没有找到,就接着从0开始查找,即如果频繁的拔插usb设备,即使只有一个设备,则每次插入,设备地址都会增加1,直到到达128后,从0接着开始,此时的设备地址,还不是设备的真实地址,因为还没有发送给设备。
5.13.复位设备,通过对设备的复位来达到使能设备的目的,此时,如果复位成功,则设备的状态将成为USB_STATE_DEFAULT状态,主控制器就可以通过控制端口获得设备的描述符符,通过对设备描述符的解析,可以得到设备的速度,从而可以根据速度猜测控制端口的空间大小。
5.14.得到控制端点的大小后,就开始准备往控制端点发送urb请求,获得设备的真正的设备描述符。
5.15.获得设备描述符时分两种模式,新模式和旧模式,每种模式最多试两次,每次可以最多读三回端口。对于新模式,需要分配一个64字节的空间,用于接收从设备返回的设备描述符。通过获得的设备描述符来判断端口的类别是不是确实是设备类别的,如果是,则只需要读取一次端口,就可以判断是设备描述符了,把描述符中记录的端口的空间大小给刚刚申请的空间的对应字节赋值了。
5.16.复位设备,准备给设备设置刚刚系统选择好,但还没有设置的那个地址,这个设置可以最多尝试设置两次,之间要停留200ms。
5.17.一旦设置成功,就要把设备的状态转变为地址状态(USB_STATE_ADDRESS),同时把控制端口0给disable掉,这样,这个端口上的urb链表都被清除了。
5.18.如果新的模式能走到这里,就表明新模式成功的获得了设备描述符了,因此旧模式就不要试了,而旧模式是分两次来获得设备的描述符的,第一次是发送要求获得8字节的urb请求,经过这个请求得到的数据,就可以知道设备的端口大小到达是多大,再按照获得的端口大小,获得端口的真实的设备描述符。
5.19.接下来,就要开始把这个设备加入设备模式中去了(usb_new_device)。
5.20.首先,要获得设备的配置描述符,注意,只有设备才有配置,接口,端口都是没有配置的,接口有设置。设备有多少个配置,就要分配多少个配置的空间,用于接收,而有多少个配置,已经在设备描述符中获得了,这时只需要从设备中读取就可以。
5.21.设置配置描述符指针,同样有多少个配置多少个这样的指针
5.22.一个配置描述符有9个字节,此时需要分配出这个空间,用于接收从设备中读回的配置描述符。
5.23.循环读取设备中的配置描述符,并把读回的数据放在设备结构体中的相应位置,之后,从配置中获得接口数,接口设置,以及接口下面的端点,通通都是在这里分析的,好长的几个函数。
5.24.接着,把设备添加到设备模型中去,这部分工作由设备模型完成,主要包括完成了设备链表的添加,和查找设备驱动程序的,此处是设备的驱动,usb系统只有一个设备驱动,而且是系统已经做好的,当设备里的接口被添加时,我们的编写的驱动,就是在这里被调用,用来判断驱动是否符合设备的了。
5.25.扫描设备的所有配置,选择最优的当前配置,再用选中的这个配置去设置设备。
5.26.到此,设备的配置,设置,什么都配置妥当了,系统就可以正常的使用设备了。


/* usb/core/usb.c */

__init usb_init()

    bus_register(&usb_bus_type)

    usb_hub_init()

        usb_register(&hub_driver)

        kthread_run(hub_thread) /* 监视hub设备插拔 */

    usb_register_device_driver(&usb_generic_driver)

        /* usb/core/generic.c */

        struct usb_device_driver usb_generic_driver = {

            .name = "usb", 

            .probe = generic_probe,

            ...

        }

    usb_generic_driver.probe() -> generic_probe()

       


/* usb/serial/usb-serial.c */

__init usb_serial_init()

    bus_register(&usb_serial_bus_type)

    tty_register_driver(usb_serial_tty_driver)

    usb_register(&usb_serial_driver)



  hub_probe                                   

原创粉丝点击