usb core



1.USB子系统的初始化-------------USB的开始 
static int __init usb_init(void)
{
    int retval;
    if ( nousb) {
        pr_info("%s: USB support disabled\n", usbcore_name);
        return 0;
    }
    retval = usb_debugfs_init();
    if (retval)
        goto out;
    usb_acpi_register();
    retval =  bus_register(&usb_bus_type); //注册USB总线,只有成功的将USB总线子系统注册到系统中,我们才可以向这个总线添加USB设备
    if (retval)
        goto bus_register_failed;
    retval =  bus_register_notifier(&usb_bus_type, &usb_bus_nb); //给USB总线注册一个通知链
    if (retval)
        goto bus_notifier_failed;
    retval =  usb_major_init(); //一个实际的总线也是一个设备,必须单独注册,因为USB是通过快速串行通信来读写数据,这里把它当作了字符设备来注册
    if (retval)
        goto major_init_failed;
    retval =  usb_register(&usbfs_driver); //usbfs相关的初始化
    if (retval)
        goto driver_register_failed;
    retval =  usb_devio_init(); //usbfs相关的初始化 --->  register_chrdev_region函数获得了设备usb_device对应的设备编号,设备usb_device对应的驱动当然就是usbfs_driver 
    if (retval)
        goto usb_devio_init_failed;
    retval =  usb_hub_init(); //hub的初始化
    if (retval)
        goto hub_init_failed;
    retval =  usb_register_device_driver(&usb_generic_driver, THIS_MODULE);  //注册USB device driver,是USB device driver而不是USB driver,前面说过,一个设备可以有多个接口,每个接口对应不同的驱动程序,这里所谓的device driver对应的是整个设备,而不是某个接口。 
    if (!retval)
        goto out;
    usb_hub_cleanup();
hub_init_failed:
    usb_devio_cleanup();
usb_devio_init_failed:
    usb_deregister(&usbfs_driver);
driver_register_failed:
    usb_major_cleanup();
major_init_failed:
    bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_notifier_failed:
    bus_unregister(&usb_bus_type);
bus_register_failed:
    usb_acpi_unregister();
    usb_debugfs_cleanup();
out:
    return retval;
}
1.
USB的设备驱动和接口驱动结构体 
include/linux/usb.h 
struct usb_device_driver { //USB device driver to usbcore   设备驱动                                                                
     const char *name;                                                                                                                                                                                             
     int (*probe) (struct usb_device *udev);                                                                
    void (*disconnect) (struct usb_device *udev);                                                                                                                                                        
     int (*suspend) (struct usb_device *udev, pm_message_t message);                                        
    int (*resume) (struct usb_device *udev, pm_message_t message);                                         
     struct usbdrv_wrap drvwrap;                                                                            
     unsigned int supports_autosuspend:1;                                                                   
 };
 #define to_usb_device_driver(d) container_of(d, struct usb_device_driver, drvwrap.driver)
drivers/usb/core/generic.c 这个函数定义了usb的设备驱动
struct usb_device_driver usb_generic_driver
drivers/usb/core/usb.c
 usb_init()----->
usb_register_device_driver(&usb_generic_driver, THIS_MODULE)注册了usb设备驱动
struct usb_driver { //USB interface driver to usbcore接口驱动 
     const char *name;
    int (*probe) (struct usb_interface *intf,
          const struct usb_device_id *id);
     void (*disconnect) (struct usb_interface *intf);
    int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
            void *buf);
     int (*suspend) (struct usb_interface *intf, pm_message_t message);
     int (*resume) (struct usb_interface *intf);
    int (*reset_resume)(struct usb_interface *intf);
     int (*pre_reset)(struct usb_interface *intf);
     int (*post_reset)(struct usb_interface *intf);
     const struct usb_device_id *id_table;
     struct usb_dynids dynids;
     struct usbdrv_wrap drvwrap;
     unsigned int no_dynamic_id:1;
     unsigned int supports_autosuspend:1;
     unsigned int disable_hub_initiated_lpm:1;
      unsigned int soft_unbind:1;
};
 #define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)
2.
drivers/usb/core/driver.c
usb_device_match()这个函数走两条路:
---->if (is_usb_device(dev))是不是usb设备
----->else if (is_usb_interface(dev)) 是不是usb接口
3.
设备的生命线(1) 
usb_device u盘的功能,当usb otg转接线接到开发板hub的时候,生命开始,拔出后生命结束。
首先当然是你将usb设备连接在hub的某个端口上,hub检测到有设备连接了进来,它会为设备分配一个struct usb_device结构的对象并初始化,并调用设备模型提供的接口将设备添加到usb总线的设备列表里,然后usb总线会遍历驱动列表里的每个驱动,调用自己的match函数看它们和你的设备或接口是否匹配。
hub检测到自己的某个端口有设备连接了进来后,它会调用core里的usb_alloc_dev函数为struct usb_device结构的对象申请内存,这个函数在drivers/usb/core/usb.c文件里定义。
当usb otg转接线接到开发板hub的时候函数的调用过程(检测到hub上的设备):
hub_port_connect_change(drivers/usb/core/hub.c) ----->usb_alloc_dev(drivers/usb/core/usb.c)
struct usb_device *usb_alloc_dev(struct usb_device *parent,struct usb_bus *bus, unsigned port1) ----->
{
  
 if (! usb_get_hcd(usb_hcd)) {
          kfree(dev);
          return NULL;
      }
      /* Root hubs aren't true devices, so don't allocate HCD resources */
 if (usb_hcd->driver->alloc_dev && parent &&
          !usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
           usb_put_hcd(bus_to_hcd(bus));
          kfree(dev);
          return NULL;
      } //这里的两个函数是hcd,主机控制器驱动里的,具体咱不讲,只要知道usb的世界里一个主机控制器对应着一条usb总线,主机控制器驱动用struct usb_hcd结构表示,一条总线用struct usb_bus结构表示,函数bus_to_hcd是为了获得总线对应的主机控制器驱动,也就是struct usb_hcd结构对象,函数usb_get_hcd只是将得到的这个usb_hcd结构对象的引用计数加1,因为总线上多了一个设备,设备在主机控制器的数据结构就得在,当然得为它增加引用计数。如果这俩函数没有很好的完成自己的任务,那整个usb_alloc_dev函数也就没有继续执行下去的必要了,将之前为struct usb_device结构对象申请的内存释放掉。
device_initialize(&dev->dev);
//device_initialize是设备模型里的函数,将struct usb_device结构里嵌入的那个struct device结构体初始化掉.
  dev->dev.bus = &usb_bus_type; //总线类型
  dev->dev.type = &usb_device_type; //设备类型
dev->state = USB_STATE_ATTACHED;  //将usb设备的状态设置为Attached,表示设备已经连接到usb接口上了,是hub检测到设备时的初始状态。
INIT_LIST_HEAD(&dev->ep0.urb_list); //端点0实在是太特殊了,struct usb_device里直接就有这么一个成员ep0,这行就将ep0的urb_list给初始化掉。
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;                          
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;  //分别初始化了端点0的描述符长度和描述符类型
usb_enable_endpoint(dev, &dev->ep0, false); 
}
 usb_new_device()---->device_add()将设备添加到usb_bus_type总线上
设备的生命线(2) 
(1)
设备的struct usb_device结构体已经准备好了,只是还不怎么饱满,hub接下来就会给它做做整容手术,往里边儿塞点什么,充实一些内容,比如:将设备的状态设置为Powered,也就是加电状态;因为此时还不知道设备支持的速度,于是将设备的speed成员暂时先设置为USB_SPEED_UNKNOWN;设备的级别level当然会被设置为hub的level加上1了;还有为设备能够从hub那里获得的电流赋值;为了保证通信畅通,hub还会为设备在总上选择一个独一无二的地址。
static void  hub_port_connect_change(struct usb_hub *hub, int port1,u16 portstatus, u16 portchange)

{
 usb_set_device_state(udev, USB_STATE_POWERED);
         udev->bus_mA = hub->mA_per_port;
        udev->level = hdev->level + 1;
        udev->wusb = hub_is_wusb(hub);
        /* Only USB 3.0 devices are connected to SuperSpeed hubs. */
        if (hub_is_superspeed(hub->hdev))
            udev->speed = USB_SPEED_SUPER;
        else
            udev->speed =  USB_SPEED_UNKNOWN;
        choose_devnum(udev);
        if (udev->devnum <= 0) {

            status = -ENOTCONN;    /* Don't retry */
            goto loop;

        }
        /* reset (non-USB 3.0 devices) and get descriptor */
        status =  hub_port_init(hub, udev, port1, i);   ----> usb_control_msg
        if (status < 0)

            goto loop;//设备现在已经处在了Powered状态。设备要想从Powered状态发展到下一个状态Default,必须收到一个复位信号并成功复位。那hub接下来的动作就很明显了,复位设备,复位成功后,设备就会进入Default状态

        usb_detect_quirks(udev);

        if (udev->quirks & USB_QUIRK_DELAY_INIT)
            msleep(1000);
}

(2)
hub使用core里定义的一个函数usb_control_msg,发送SET_ADDRESS请求给设备,设备就迈进Address。从default状态到Address

USB控制器和设备之间的传输数据结构由urb 
usb_control_msg用于发送control类数据,对于control类型,除发送正常数据外,还要发送一个setup transaction, request, requesttype指定请求包的类型和属性,data为要发送的数据,size为发送数据长度,timeout为发送超时时间。 
drivers/usb/core/message.c
usb_control_msg()----> usb_internal_control_msg()
usb-control_msg()
这个函数主要目的是创建一个控制urb,并把它发送给usb设备,然后等待它完成。urb是什么?忘了么,前面提到过的,你要想和你的usb通信,就得创建一个urb,并且为它赋好值,交给usb core,它会找到合适的host controller,从而进行具体的数据传输 .


struct usb_ctrlrequest {  
   __u8 bRequestType;  
   __u8 bRequest;  
   __le16 wValue;  
   __le16 wIndex;  
   __le16 wLength;  
} __attribute__ ((packed));  //描述了主机通过控制传输发送给设备的请求(Device Requests)


bRequestType
    D7     数据的传输方向:0表示从主机到设备; 1表示从设备到主机;
    D6~5   命令的类型:   0表示标准命令;    1表示类命令;      2表示厂商提供的命令; 3保留;
    D4~0   接收对象;     0表示设备;       1表示接口;       2表示端点;         3表示其他;
bRequest
    命令的序号(其实就是命令);所有的命令都是以不同编码值的方式传递给设备的,bRequest就表示USB命令的编码值
wValue, wIndex
    这两个字段对于不同的命令有不同的含义
wLength
    表示在完成命令控制传输的数据阶段,要求传输数据的字节长度。一般不论是输入还是输出都要求给出准确的数字。当命令不需要传输数据时,此字段设为0
bRequest
    命令的序号(其实就是命令);所有的命令都是以不同编码值的方式传递给设备的,bRequest就表示USB命令的编码值
bRequestType    bRequest   wValue   wIndex   wLength


80              6          100               0        12
80              6          200               0        9
80              6          300               0        FF
80              6          301             409      FF
80              6          302             409      FF
80              6          303             409      FF
100        表示获取设备描述符usb_device_descriptor
200        表示获取配置描述符usb_config_descriptor
300        表示获取字符描述符
301        iSerialNumber
302        iProduct
303        iManufacture

usb的transaction,包括一个Token包、一个Data包和一个Handshake包。

Token、Data和Handshake都属于四种PID类型中的。
1. Token包只包括SYNC、PID、地址域、CRC,并没有DATA字段,它的名字起的很形象,就是用来标记所在transaction里接下来动作的。
2. Out和Setup Token包,里面的地址域指明了接下来要接收Data包的端点,
3. In Token包,地址域指明了接下来哪个端点要发送Data包。
只有主机才有权利发送Token包,协议里就这么规定的

与Token包相比,Data包里没了地址域,多了Data字段,这个Data字段对于低速设备最大为8字节,对于全速设备最大为1023字节,对于高速设备最大为1024字节。,它就是躲在Token后边儿用来传输数据的。

Handshake包的成分,除了SYNC,它就只包含了一个PID,通过PID取不同的值来报告一个transaction的状态,比如数据已经成功接收了等。

控制传输的SETUP transaction一般来说也有三个阶段,就是主机向设备发送Setup Token包、然后发送Data0包,如果一切顺利,设备回应ACK Handshake包表示OK,为什么加上一般?如果中间的那个Data0包由于某种不可知因素被损坏了,设备就什么都不会回应,这时就成俩阶段了。SETUP transaction之后,接下来如果控制传输有DATA transaction的话,那就Data0、Data1这样交叉的发送数据包,前面说过这是为了实现data toggle。最后是STATUS transaction,向主机汇报前面SETUP和DATA阶段的结果,比如表示主机下达的命令已经完成了,或者主机下达的命令没有完成,或者设备正忙着那没功夫去理会主机的那些命令。


经过SETUP、DATA、STATUS这三个transaction阶段,一个完整的控制传输完成了。主机接下来可以规划下一次的控制传输。

requests都在Setup包里发送是有问题的,因为Setup包本身并没有数据字段,严格来说它们应该都是在SETUP transaction阶段里Setup包后的Data0包里发送的。
设备的生命线(3) 
 
usb_control_msg()---->
usb_internal_control_msg()
这个函数粗看过去,可以概括为一个中心,三个基本点,以一个struct urb结构体为中心,以usb_alloc_urb、usb_fill_control_urb、usb_start_wait_urb三个函数为基本点。
一个中心:struct urb结构体,就是咱们前面多次提到又多次飘过,只闻其名不见其形的传说中的urb,全称usb request block,站在咱们的角度看,usb通信靠的就是它这张脸。
第一个基本点:usb_alloc_urb函数,创建一个urb,struct urb结构体只能使用它来创建,它是urb在usb世界里的独家代理。
第二个基本点:usb_fill_control_urb函数,初始化一个控制urb,urb被创建之后,使用之前必须要正确的初始化。
第三个基本点:usb_start_wait_urb函数,将urb提交给咱们的usb core,以便分配给特定的主机控制器驱动进行处理,然后默默的等待处理结果,或者超时.
usb_control_msg()---->usb_internal_control_msg()----->usb_submit_urb(给控制器提交urb)
include/linux/usb.h
结构体struct urb{}
724780844.jpg
 
include/linux/kref.h
kref_init初始化,kref_get将引用计数加1,kref_put调用kref_sub将引用计数减一并判断是不是为0,为0的话就调用参数里release函数指针指向的函数把对象销毁掉.
drivers/usb/core/urb.c
usb_init_urb、usb_get_urb、usb_free_urb这三个函数分别调用了前面看到的struct kref结构的三个操作函数来进行引用计数的初始化、加1、减一。什么叫封装?这就叫封装.
usb_free_urb里给kref_put传递的那个函数urb_destroy,它也在urb.c里定义
static void urb_destroy(struct kref *kref)  
{  
   struct urb *urb = to_urb(kref);  
      
   if (urb->transfer_flags & URB_FREE_BUFFER)  
         kfree(urb->transfer_buffer);  
      
     kfree(urb);  
}  
这个urb_destroy首先调用了to_urb,实际上就是一个container_of来获得引用计数关联的那个urb,然后使用kfree将它销毁
先了解下使用urb来完成一次完整的usb通信都要经历哪些阶段,首先,驱动程序发现自己有与usb设备通信的需要,于是创建一个urb,并指定它的目的地是设备上的哪个端点,然后提交给usb core,usb core将它修修补补的做些美化之后再移交给主机控制器的驱动程序HCD,HCD会去解析这个urb,了解它的目的是什么,并与usb设备进行相应的交流,在交流结束,urb的目的达到之后,HCD再把这个urb的所有权移交回驱动程序。
struct urb 结构体中的成员 use_count,表示usb core将urb移交给HCD,办理移交手续的时候,use_count加1,在HCD重新将urb的所有权移交回驱动程序的时候,use_count减1.
driver/usb/core/urb.c
void  usb_kill_urb( struct  urb *urb) 
在同步方式下对应的urb取消函数接口为:
void usb_kill_urb(struct urb *urb)
usb_kill_urb提交取消urb申请后,会一直等待urb取消完成才会退出,里面的等待也是通过等待队列实现的
int  usb_unlink_urb( struct  urb *urb) 
如果想取消之前提交的urb,可以用usb_unlink_urb来实现:
int usb_unlink_urb(struct urb *urb);
取消urb时,程序不会阻塞,属于异步方式
设备的生命线(4) 
struct urb {
/* 私有的:只能由USB 核心和主机控制器访问的字段 */
struct kref kref; /*urb 引用计数 */
void *hcpriv; /* 主机控制器私有数据 */
atomic_t use_count; /* 并发传输计数 */
u8 reject; /* 传输将失败*/
int unlink; /* unlink 错误码 */
 /* 公共的: 可以被驱动使用的字段 */
 struct list_head urb_list; /* 链表头*/
struct usb_anchor *anchor;
 struct usb_device *dev; /* 关联的USB 设备 */
 struct usb_host_endpoint *ep;
unsigned int pipe; /* 管道信息 */
 int status; /* URB 的当前状态 */
 unsigned int transfer_flags; /* URB_SHORT_NOT_OK | ...*/
 void *transfer_buffer; /* 发送数据到设备或从设备接收数据的缓冲区 */
 dma_addr_t transfer_dma; /*用来以DMA 方式向设备传输数据的缓冲区 */
 int transfer_buffer_length;/*transfer_buffer 或transfer_dma 指向缓冲区的大小 */
 
 int actual_length; /* URB 结束后,发送或接收数据的实际长度 */
 unsigned char *setup_packet; /* 指向控制URB 的设置数据包的指针*/
 dma_addr_t setup_dma; /*控制URB 的设置数据包的DMA 缓冲区*/
 int start_frame; /*等时传输中用于设置或返回初始帧*/
 int number_of_packets; /*等时传输中等时缓冲区数量 */
 int interval; /* URB 被轮询到的时间间隔(对中断和等时urb 有效) */
 int error_count; /* 等时传输错误数量 */
 void *context; /* completion 函数上下文 */
 usb_complete_t complete; /* 当URB 被完全传输或发生错误时,被调用 */
 /*单个URB 一次可定义多个等时传输时,描述各个等时传输 */
 struct usb_iso_packet_descriptor iso_frame_desc[0];
};
设备的生命线(5) 
第一个基本点,usb_alloc_urb函数,创建urb的专用函数,为一个urb申请内存并做初始化,在drviers/usb/core/urb.c里定义。
void usb_free_urb(struct urb *urb)
usb_free_urb更潇洒,只调用kref_put将urb的引用计数减一,减了之后如果变为0,也就是没人再用它了,就调用urb_destroy将它销毁掉。
第二个基本点,usb_fill_control_urb函数,初始化刚才创建的控制urb,你要想使用urb进行usb传输,不是光为它申请点内存就够的,你得为它初始化,充实点实实在在的内容。
usb_fill_control_urb(include/linux/usb.h)
控制传输usb_fill_control_urb(include/linux/usb.h),批量传输有usb_fill_bulk_urb,对于中断传输有usb_fill_int_urb
drivers/usb/core/message.c 
usb_control_msg()----->usb_internal_control_msg()---->usb_fill_control_urb()
usb_internal_control_msg()
usb_alloc_urb()分配结构体  struct  urb
usb_fill_control_urb()填充控制传输结构体struct urb
}
结束处理函数 usb_api_blocking_completion,可以看一下当这次控制传输已经完成,设备地址已经设置好
static void usb_api_blocking_completion(struct urb *urb)
第三个基本点,usb_start_wait_urb函数,将前面历经千辛万苦创建和初始化的urb提交给咱们的usb core,让它移交给特定的主机控制器驱动进行处理,然后望眼欲穿的等待HCD回馈的结果,如果等待的时间超过了预期的限度,它不会再等,不会去变成望夫石.
结构体struct completion,completion是内核里一个比较简单的同步机制, 一个线程可以通过它来通知另外一个线程某件事情已经做完了.
先定义一个struct completion结构体,然后使用init_completion去初始化.
用来通知已经完成了的函数也不只一个,
void complete(struct completion *c);
void complete_all(struct completion *c);
complete只通知一个等候的线程,complete_all可以通知所有等候的线程
void wait_for_completion(struct completion *);  
int wait_for_completion_interruptible(struct completion *x);  
unsigned long wait_for_completion_timeout(struct completion *x,unsigned long timeout);  
long wait_for_completion_interruptible_timeout(struct completion *x, unsigned long timeout);
设备的生命线(6) 
drivers/usb/core/urb.c
int  usb_submit_urb(struct urb *urb, gfp_t mem_flags)对urb做些前期处理后扔给HCD
{
 max = usb_endpoint_maxp(&ep->desc);//从端点描述符中获取(struct usb_endpoint_descriptor)获得端点的wMaxPacketSize
usb_hcd_submit_urb()//将urb扔给HCD,然后就进入HCD
}
等时传输 usb_control_msg()----->usb_internal_control_msg()----->usb_submit_urb(给控制器提交urb)
批量传输 usb_bulk_msg()---->usb_alloc_urb()--->usb_fill_bulk_urb()--->usb_start_wait_urb()--->usb_submit_urb()
中断传输 usb_interrupt_msg()--->usb_bulk_msg()---->usb_alloc_urb()--->usb_fill_bulk_urb()--->usb_start_wait_urb()--->usb_submit_urb()
设备的生命线(7) 
  
一个主机控制器就会连出一条usb总线,主机控制器驱动用struct usb_hcd结构表示,一条总线用struct usb_bus结构表示
include/linux/usb/hcd.h
struct  usb_hcd{
  struct usb_bus      self;       /* hcd is-a bus */  
}
include/linux/usb.h
struct  usb_bus {
   struct device *controller;  /* host/master side hardware */
   int busnum;         /* Bus number (in order of reg) *
   const char *bus_name;       /* stable id (PCI slot_name etc) */
   u8 uses_dma;            /* Does the host controller use DMA? */
   int devnum_next;        /* Next open device number in* round-robin allocation */
    struct list_head bus_list;  /* list of busses */
    int bandwidth_allocated;
     int bandwidth_int_reqs;
     int bandwidth_isoc_reqs;
      
}
drivers/usb/dwc2/hcd.cint dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)--->
retval = usb_add_hcd(hcd, irq, IRQF_SHARED)--->
static int usb_register_bus(struct usb_bus *bus)--->   // usb_register_bus函数是每个主机控制器驱动在probe里调用的,向usb core注册一条总线,也可以说是注册一个主机控制器  
设备的生命线(8) 
在Linux内核中,用usb_hcd结构体描述USB主机控制器驱动,它包含USB主机控制器的“家务”信息、硬件资源、状态描述和用于操作主机控制器的hc_driver等.
struct usb_hcd
  {
    /* 管理“家务” */
    struct usb_bus self;
    const char *product_desc; /* 产品/厂商字符串 */
    char irq_descr[24]; /* 驱动 + 总线 # */
    struct timer_list rh_timer; /* 根Hub轮询 */
    struct urb *status_urb; /* 目前的状态urb */
   /* 硬件信息/状态 */
   const struct hc_driver *driver; /* 硬件特定的钩子函数 */
   /* 需要维护的标志 */
   unsigned long flags;
   #define HCD_FLAG_HW_ACCESSIBLE  0x00000001
   #define HCD_FLAG_SAW_IRQ        0x00000002
   unsigned rh_registered: 1; /* 根Hub注册? */
   /* 下一个标志的采用只是“权益之计”,当所有HCDs支持新的根Hub轮询机制后将移除 */
   unsigned uses_new_polling: 1;
   unsigned poll_rh: 1; /* 轮询根Hub状态? */
   unsigned poll_pending: 1; /* 状态已经改变? */
   int irq; /* 被分配的irq */
   void _ _iomem *regs; /* 设备内存和I/O */
   u64 rsrc_start; /* 内存和I/O资源开始位置 */
   u64 rsrc_len; /* 内存和I/O资源长度 */
   unsigned power_budget; /* mA, 0 = 无限制 */
   #define HCD_BUFFER_POOLS        4
   struct dma_pool *pool[HCD_BUFFER_POOLS];
   int state;
   #define _ _ACTIVE                0x01
   #define _ _SUSPEND               0x04
   #define _ _TRANSIENT             0x80
   #define HC_STATE_HALT           0
   #define HC_STATE_RUNNING        (_ _ACTIVE)
   #define HC_STATE_QUIESCING   (_ _SUSPEND|_ _TRANSIENT|_ _ACTIVE)
   #define HC_STATE_RESUMING       (_ _SUSPEND|_ _TRANSIENT)
   #define HC_STATE_SUSPENDED      (_ _SUSPEND)
   #define HC_IS_RUNNING(state) ((state) & _ _ACTIVE)
   #define HC_IS_SUSPENDED(state) ((state) & _ _SUSPEND)
   /* 主机控制器驱动的私有数据 */
   unsigned long hcd_priv[0]_ _attribute_ _((aligned(sizeof(unsigned long))));
 };

usb_hcd中的hc_driver成员非常重要,它包含具体的用于操作主机控制器的钩子函数
struct hc_driver
  {
    const char *description; /* "ehci-hcd" 等 */
    const char *product_desc; /* 产品/厂商字符串 */
    size_t hcd_priv_size; /* 私有数据的大小 */
    /* 中断处理函数 */
  irqreturn_t(*irq)(struct usb_hcd *hcd, struct pt_regs *regs);  
   int flags;
   #define HCD_MEMORY      0x0001      /* HC寄存器使用的内存和I/O */
   #define HCD_USB11       0x0010          /* USB 1.1 */
   #define HCD_USB2        0x0020          /* USB 2.0 */
   /* 被调用以初始化HCD和根Hub */
   int(*reset)(struct usb_hcd *hcd);
   int(*start)(struct usb_hcd *hcd);
   /* 挂起Hub后,进入D3(etc)前被调用 */
   int(*suspend)(struct usb_hcd *hcd, pm_message_t message);
   /* 在进入D0(etc)后,恢复Hub前调用 */
   int(*resume)(struct usb_hcd *hcd);
   /* 使HCD停止写内存和进行I/O操作 */
   void(*stop)(struct usb_hcd *hcd);
   /* 返回目前的帧数 */
   int(*get_frame_number)(struct usb_hcd *hcd);
   /* 管理I/O请求和设备状态 */
   int(*urb_enqueue)(struct usb_hcd *hcd, struct usb_host_endpoint *ep, struct
     urb *urb, gfp_t mem_flags);
   int(*urb_dequeue)(struct usb_hcd *hcd, struct urb *urb);
   /* 释放endpoint资源 */
   void(*endpoint_disable)(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
   /* 根Hub支持 */
   int(*hub_status_data)(struct usb_hcd *hcd, char *buf);
   int(*hub_control)(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
     char *buf, u16 wLength);
   int(*bus_suspend)(struct usb_hcd*);
   int(*bus_resume)(struct usb_hcd*);
   int(*start_port_reset)(struct usb_hcd *, unsigned port_num);
   void(*hub_irq_enable)(struct usb_hcd*);
 };




drivers/usb/core/hcd.c
static void hcd_release(struct kref *kref)
struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd)
void usb_put_hcd (struct usb_hcd *hcd)     kref引用计数的增加和减少接口 
include/linux/usb/hcd.h   struct usb_hcd 
include/linux/usb.h   struct usb_bus
具体的主机控制器驱动程序快速的走一下,就UHCI吧,都在host目录下的uhci-族文件里,首先它是个pci设备,要使用pci_register_driver注册一个struct pci_driver结构体uhci_pci_driver,uhci_pci_driver里又有个熟悉的probe,在这个probe里,它调用usb_create_hcd来创建一个usb_hcd,初始化里面的self,还将这个self里的controller设定为描述主机控制器的那个pci_dev里的struct device结构体,从而将usb_hcd、usb_bus和pci_dev,甚至设备模型都连接起来了。
drivers/usb/host/uhci-hcd.c
static int __init uhci_hcd_init(void)----->
retval = pci_register_driver(&PCI_DRIVER);   ---->   #define PCI_DRIVER      uhci_pci_driver 
int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)------>drivers/usb/core/hcd-pci.c
struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,struct device *dev, const char *bus_name)---->drivers/usb/core/hcd.c 
结构体struct hc_driver {
const char  *description;   /* "ehci-hcd" etc */
const char  *product_desc;  /* product/vendor string */
size_t      hcd_priv_size;  /* size of private data */
}
drivers/staging/dwc2/hcd.c
root hub和host controller
主机控制器的驱动结构体
2724 static struct hc_driver dwc2_hc_driver = {                                                                 
2725     .description = "dwc2_hsotg",                                                                           
2726     .product_desc = "DWC OTG Controller",                                                                  
2727     .hcd_priv_size = sizeof(struct wrapper_priv_data),                                                     
2728                                                                                                            
2729     .irq = _dwc2_hcd_irq,                                                                                  
2730     .flags = HCD_MEMORY | HCD_USB2,                                                                        
2731                                                                                                            
2732     .start = _dwc2_hcd_start,                                                                              
2733     .stop = _dwc2_hcd_stop,                                                                                
2734     .urb_enqueue = _dwc2_hcd_urb_enqueue,                                                                  
2735     .urb_dequeue = _dwc2_hcd_urb_dequeue,                                                                  
2736     .endpoint_disable = _dwc2_hcd_endpoint_disable,                                                        
2737     .endpoint_reset = _dwc2_hcd_endpoint_reset,                                                            
2738     .get_frame_number = _dwc2_hcd_get_frame_number,                                                        
2739                                                                                                            
2740     .hub_status_data = _dwc2_hcd_hub_status_data,                                                          
2741     .hub_control = _dwc2_hcd_hub_control,                                                                  
2742     .clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,                                        
2743                                                                                                            
2744     .bus_suspend = _dwc2_hcd_suspend,                                                                      
2745     .bus_resume = _dwc2_hcd_resume,                                                                        
2746 }; 
drivers/staging/dwc2/hcd.c
int  dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) 
{
hcd =  usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev));//创建一个属于自己的usb_hcd
   retval =  usb_add_hcd(hcd, irq, IRQF_SHARED); //将这个刚刚创建的usb_hcd注册到usb组织里
}
drivers/usb/core/hcd.c
int  usb_add_hcd(struct usb_hcd *hcd,unsigned int irqnum, unsigned long irqflags)
{
if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) 
hcd->self.root_hub = rhdev; //struct usb_device结构体准备妥当之后,就要赋给struct usb_bus的root_hub元素
if ((retval = register_root_hub(hcd)) != 0)----->retval = usb_new_device (usb_dev); 将root hub送给无所不能的设备模型,去寻找它命中的驱动
//register_root_hub()在最后就会将struct usb_hcd的rh_registered设置为1,表示root hub已经找到组织并加入到革命队伍里了
}
usb_alloc_dev()来为root hub准备一个struct usb_device结构体
drivers/usb/core/hcd.c
/* usb 2.0 root hub device descriptor */                                                                   
static const u8 usb2_rh_dev_descriptor [18] =
/* Configuration descriptors for our root hubs */
static const u8 fs_rh_config_descriptor [] =
static const u8 hs_rh_config_descriptor [] =
static const u8 ss_rh_config_descriptor[] =
CPU也需要跟各种外设配合交流,它需要访问外设里的那些寄存器或者内存。现在差别就出来了,主要是空间的差别,一些CPU芯片有两个空间,即I/O空间和内存空间,提供有专门访问外设I/O端口的指令,而另外一些只有一个空间,即内存空间。外设的I/O端口可以映射在I/O空间也可以映射到内存空间,CPU通过访问这两个空间来访问外设,I/O空间有I/O空间访问的接口,内存空间有内存空间访问的接口.
主机控制器的DMA池的创建接口
drivers/usb/core/buffer.c
int hcd_buffer_create(struct usb_hcd *hcd)
void hcd_buffer_destroy(struct usb_hcd *hcd) //hcd_buffer_destroy - deallocate buffer pools
每个DMA池子都要找到四个函数,一个用来创建,一个用来销毁,一个用来取内存,一个用来放内存.
hcd_buffer_create  <-----> dma_pool_create()
hcd_buffer_destroy()    <------>    dma_pool_destroy()
hcd_buffer_alloc()  <------>   dma_pool_alloc()
hcd_buffer_free()   <--------> dma_pool_free()

设备的生命线(9)

int usb_submit_urb(struct urb *urb, gfp_t mem_flags)--->
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)  drivers/usb/core/hcd.c  将提交过来的urb指派给合适的主机控制器驱动程序  
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags){          bus_to_hcd(urb->dev->bus) // 获得struct usb_bus结构体对应的struct usb_hcd结构体  
           usb_get_urb(urb);  //  增加urb的引用计数                                                                          
           atomic_inc(&urb->use_count);  // 将urb的use_count也增加1,表示urb已经被HCD接受了,正在被处理着            status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);  // 将urb扔给具体的主机控制器驱动程序 ,设备可以进入addres状态
}
 hcd_to_bus ()

设备的生命线(10) 

drivers/usb/core/message.c
int  usb_get_device_descriptor(struct usb_device *dev, unsigned int size)//获得设备的设备描述符   --->
int  usb_get_descriptor(struct usb_device *dev, unsigned char type,unsigned char index, void *buf, int size) //不管你想获得哪种描述符都是要通过usb_get_descriptor()  --------->
result = usb_control_msg(
dev,
usb_rcvctrlpipe(dev, 0),                                             
USB_REQ_GET_DESCRIPTOR, 
USB_DIR_IN,  //GET_DESCRIPTOR请求的数据传输方向很明显是device-to-host的, bRequestType只能为0x80                                       
(type << 8) + index, //wValue的高位字节表示描述符的类型,低位字节表示描述符的序号
0, //wIndex对于字符串描述符应该设置为使用语言的ID,对于其它的描述符应该设置为0
buf, 
size,   //wLength,就是描述符的长度                                                     
USB_CTRL_GET_TIMEOUT  //5s的超时时间
);
{
for (i = 0; i < 3; ++i) //3次获得描述符,确保能获得设备描述符
if (result <= 0 && result != -ETIMEDOUT) 
if (result > 1 && ((u8 *)buf)[1] != type) //用来判断获得描述符是不是请求的类型就可以了
}
drivers/usb/core/config.c
int usb_get_configuration(struct usb_device *dev)--->
{
int ncfg = dev->descriptor.bNumConfigurations;//获得设备配置描述符的数目
if (ncfg > USB_MAXCONFIG)//一个设备最多只能支持8种配置拥有8个配置描述符
length = ncfg * sizeof(struct usb_host_config);
dev->config = kzalloc(length, GFP_KERNEL);//struct usb_device里的config表示的是设备拥有的所有配置,你设备有多少个配置就为它准备多大的空间
dev->rawdescriptors = kzalloc(length, GFP_KERNEL);//rawdescriptors,这是个字符指针数组里的每一项都指向一个使用GET_DESCRIPTOR请求去获取配置描述符时所得到的结果
desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);//准备一个大小为USB_DT_CONFIG_SIZE的缓冲区,第一次发送GET_DESCRIPTOR请求要用的
for (; cfgno < ncfg; cfgno++) {//for循环,获取每一个配置的那些描述符
{
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,desc, USB_DT_CONFIG_SIZE) //以USB_DT_CONFIG为参数,向设备发送GET_DESCRIPTOR请求. USB_DT_CONFIG_SIZE只表示配置描述符本身的大小,并不表示GET_DESCRIPTOR请求返回结果的大小(设备并不单单返回一个配置描述符了事,而是一股脑儿的将这个配置下面的所有接口描述符,端点描述,还有class-或vendor-specific描述符都返回了给你).  配置描述符里有这样一个的字段wTotalLength,它里面记录总长度(配置下面的所有接口描述符,端点描述,还有class-或vendor-specific描述符)
else if (result < 4) //然后对返回的结果进行检验,判断结果是不是小于4么?在配置描述符中,里面的3,4字节就是wTotalLength,只要得到前4个字节,就已经完成任务能够获得总长度了。
length = max((int) le16_to_cpu(desc-> wTotalLength), USB_DT_CONFIG_SIZE);
bigbuffer = kmalloc(length, GFP_KERNEL);
 result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length);  //首先发送USB_DT_CONFIG_SIZE个字节的请求过去,获得这个配置描述符的内容,从而获得那个总长度wTotalLength,然后以这个长度再请求一次,这样就可以获得一个配置下面所有的描述符内容
dev->rawdescriptors[cfgno] = bigbuffer;//现在可以获得这个配置相关的所有描述符了。然后是对返回结果的检验,再然后就是将得到的那一堆数据的地址赋给rawdescriptors数组里的指针.
result = usb_parse_configuration(dev, cfgno, &dev->config[cfgno], bigbuffer, length);//对前面GET_DESCRIPTOR请求获得的那堆数据做处理

设备的生命线(11) 
GET_DESCRIPTOR请求取到了包含一个配置里所有相关描述符内容的一堆数据,这些数据是raw的,即原始的,所有数据不管是配置描述符、接口描述符还是端点描述符都彼此的挤在一起,所以得想办法将它们给分开,丁是丁卯是卯的,于是用到usb_parse_configuration()。 
使用GET_DESCRIPTOR请求时,得到的数据并不是杂乱无序的,而是有规可循的,一般来说,配置描述符后面跟的是第一个接口的接口描述符,接着是这个接口里第一个端点的端点描述符,如果有class-和vendor-specific描述符的话,会紧跟在对应的标准描述符后面,不管接口有多少端点有多少都是按照这个规律顺序排列。当然有些厂商会特立独行一些,非要先返回第二个接口然后再返回第一个接口,但配置描述符后面总归先是接口描述符再是端点描述符
static int usb_parse_configuration(struct usb_device *dev, int cfgidx, struct usb_host_config *config, unsigned char *buffer, int size)
{
 unsigned char *buffer0 = buffer;  // buffer里保存的就是GET_DESCRIPTOR请求获得的那堆数据,要解析这些数据,不可避免的要对buffer指针进行操作,这里先将它备份一下.
 memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);                                            
     if (config->desc.bDescriptorType != USB_DT_CONFIG ||                                          
          config->desc.bLength < USB_DT_CONFIG_SIZE ||                                              
         config->desc.bLength > size) {                                                            
         dev_err(ddev, "invalid descriptor for config index %d: "                                  
             "type = 0x%X, length = %d\n", cfgidx,                                                 
             config->desc.bDescriptorType, config->desc.bLength);                                  
         return -EINVAL;                                                                           
     } //config是参数里传递过来的,是设备struct usb_device结构体里的struct usb_host_config结构体数组config中的一员。不出意外的话buffer的前USB_DT_CONFIG_SIZE个字节对应的就是配置描述符,然后做些检验,看看这USB_DT_CONFIG_SIZE字节的内容究竟是不是正如我们所期待的那样是个配置描述符.
  
nintf = nintf_orig = config->desc.bNumInterfaces; //获得这个配置所拥有的接口数目,对这个数目是有个USB_MAXINTERFACES这样的限制的.
header = (struct usb_descriptor_header *) buffer2;//把buffer2指针转化为struct usb_descriptor_header的结构体指针,然后就可以使用‘->’来取出bLength和bDescriptorType
d = (struct usb_interface_descriptor *) header;  //上面转化为struct usb_descriptor_header结构体指针和这里转化为struct usb_interface_descriptor结构体指针,它就不再仅仅是一个地址,而是代表了不同的含义
if (d->bLength < USB_DT_INTERFACE_SIZE) //bDescriptorType等于USB_DT_INTERFACE并不说明它就一定是接口描述符了,它的bLength还必须要等于USB_DT_INTERFACE_SIZE。bLength和bDescriptorType一起才能决定一个描述符
size = buffer2 - buffer;
config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0); // buffer的最后边儿可能会有些垃圾数据,为了去除这些洋垃圾,这里需要将size和配置描述符里的那个wTotalLength修正一下。 
  /* Allocate the usb_interface_caches and altsetting arrays */  
 for (i = 0; i < nintf; ++i) {  
        j = nalts[i];  
        if (j > USB_MAXALTSETTING) {  
            dev_warn(ddev, "too many alternate settings for "  
                "config %d interface %d: %d, "  
                "using maximum allowed: %d\n",  
                cfgno, inums[i], j, USB_MAXALTSETTING);  
            nalts[i] = j = USB_MAXALTSETTING;  
        }    
        len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;  
        config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL);  
        if (!intfc)  
            return -ENOMEM;  
        kref_init(&intfc->ref);  
} //for循环,struct usb_interface_caches.
一个接口最多可以有128个设置,根据每个接口拥有的设置数目为对应的intf_cache数组项申请内存
   config->extra = buffer;  
    i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,  
        USB_DT_INTERFACE, &n); / / 在buffer里寻找配置描述符后面跟着的第一个接口描述符 
    config->extralen = i;  
    if (n > 0)  
        dev_dbg(ddev, "skipped %d descriptor%s after %s\n",  
            n, plural(n), "configuration");  
    buffer += i;  
    size -= i; 
/* Parse all the interface/altsetting descriptors */  
    while (size > 0) {  
        retval =  usb_parse_interface(ddev, cfgno, config,  
            buffer, size, inums, nalts);  
        if (retval < 0)  
            return retval;  
  
        buffer += retval;  
        size -= retval;  
    }//while循环,如果size大于0,就说明配置描述符后面找到了一个接口描述符,根据这个接口描述符的长度,已经可以解析出一个完整的接口描述符了,但是仍然没到乐观的时候,这个接口描述符后面还会跟着一群端点描述符,再然后还会有其它的接口描述符。usb_parse_interface进行解析接口描述符,它返回的时候,buffer的位置已经在下一个接口描述符那里了,还是那个理儿,对buffer地址本身来说是按值传递的,对这个位置和长度进行下调整以适应新形势。那么这个while循环的意思就很明显了,对buffer一段一段的解析,直到再也找不到接口描述符了
}
}
}
static int find_next_descriptor(unsigned char *buffer, int size,int dt1, int dt2, int *num_skipped)
比如你指定dt1为USB_DT_INTERFACE,dt2为USB_DT_ENDPOINT时,只要能够找到接口描述符或端点描述符中的一个,这个函数就返回.
i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,USB_DT_INTERFACE, &n);
只需要寻找下一个接口描述符,所以dt1和dt2都设置为USB_DT_INTERFACE 
static int usb_parse_interface(struct device *ddev, int cfgno, struct usb_host_config *config, unsigned char *buffer, int size, u8 inums[], u8 nalts[])
{
    
 /* Check for duplicate altsetting entries */  
    asnum = d->bAlternateSetting;  
    for ((i = 0, alt = &intfc->altsetting[0]);  
          i < intfc->num_altsetting;  
         (++i, ++alt)) {  
        if (alt->desc.bAlternateSetting == asnum) {  
            dev_warn(ddev, "Duplicate descriptor for config %d "  
                "interface %d altsetting %d, skipping\n",  
                cfgno, inum, asnum);  
            goto skip_to_next_interface_descriptor;  
        }  
    }
++intfc->num_altsetting;  //获得这个接口描述符对应的设置编号,然后根据这个编号从接口的cache里搜索看这个设置是不是已经遇到过了,如果已经遇到过,就没必要再对这个接口描述符进行处理,直接跳到最后,否则意味着发现了一个新的设置,要将它添加到cache里,并cache里的设置数目num_altsetting加1。要记住,设置是用struct usb_host_interface结构来表示的,一个接口描述符就对应一个设置
 /* Skip over any Class Specific or Vendor Specific descriptors; 
     * find the first endpoint or interface descriptor */  
    alt->extra = buffer;  
    i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,  
        USB_DT_INTERFACE, &n);  
    alt->extralen = i;  
    if (n > 0)  
        dev_dbg(ddev, "skipped %d descriptor%s after %s\n",  
            n, plural(n), "interface");  
    buffer += i;  
    size -= i; //现在buffer开头儿的那个接口描述符已经理清了,要解析它后面的那些数据了。先把位置赋给这个刚解析出来的接口描述符的extra,然后再从这个位置开始去寻找下一个距离最近的一个接口描述符或端点描述符。如果这个接口描述符后面还跟有class-或vendor-specific描述符,则find_next_descriptor的返回值会大于0,buffer的位置和size也要进行相应的调整,来指向新找到的接口描述符或端点描述符。这里find_next_descriptor的dt1参数和dt2参数就不再一样了,因为如果一个接口只用到端点0,它的接口描述符后边儿是不会跟有端点描述符的。
 /* Allocate space for the right(?) number of endpoints */  
    num_ep = num_ep_orig = alt->desc.bNumEndpoints;  
    alt->desc.bNumEndpoints = 0;     /* Use as a counter */  
    if (num_ep > USB_MAXENDPOINTS) {  
        dev_warn(ddev, "too many endpoints for config %d interface %d "  
            "altsetting %d: %d, using maximum allowed: %d\n",  
            cfgno, inum, asnum, num_ep, USB_MAXENDPOINTS);  
        num_ep = USB_MAXENDPOINTS;  
    }  
  
    if (num_ep > 0) {  
        /* Can't allocate 0 bytes */  
        len = sizeof(struct usb_host_endpoint) * num_ep;  
        alt->endpoint = kzalloc(len, GFP_KERNEL);  
        if (!alt->endpoint)  
            return -ENOMEM;  
    }  //#define USB_MAXENDPOINTS    30  端点数最大是30
根据端点数为接口描述符里的endpoint数组申请内存 
  /* Parse all the endpoint descriptors */  
    n = 0;  
    while (size > 0) {  
        if (((struct usb_descriptor_header *) buffer)->bDescriptorType  
             == USB_DT_INTERFACE)  
            break;  
        retval = usb_parse_endpoint(ddev, cfgno, inum, asnum, alt,  
            num_ep, buffer, size);  
        if (retval < 0)  
            return retval;  
        ++n;  
  
        buffer += retval;  
        size -= retval;  
    } //先判断一下前面找到的是接口描述符还是端点描述符,如果是接口描述符就中断这个while循环,返回与下一个接口描述符的距离。否则说明在buffer当前的位置上待着的是一个端点描述符,因此就要迎来另一个函数usb_parse_endpoint对面紧接着的数据进行解析。usb_parse_endpoint()返回的时候,buffer的位置已经在下一个端点描述符那里了,调整buffer的位置长度,这个while循环的也很明显了,对buffer一段一段的解析,直到遇到下一个接口描述符或者已经走到buffer结尾
}
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,  int asnum, struct usb_host_interface *ifp, int num_ep, unsigned char *buffer, int size)   
{
d = (struct usb_endpoint_descriptor *) buffer;  
buffer += d->bLength;  
size -= d->bLength;//buffer开头儿只能是一个端点描述符,所以这里将地址转化为struct usb_endpoint_descriptor结构体指针,然后调整buffer的位置和size。
endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];                                           
++ifp->desc.bNumEndpoints;
memcpy(&endpoint->desc, d, n);  //endpoint数组在usb_parse_interface()已经申请好内存了的。bNumEndpoints是被当成了一个计数器,发现一个端点描述符,它就加1,并把找到的端点描述符copy到设置的endpoint数组里。
INIT_LIST_HEAD(&endpoint->urb_list); //初始化端点的urb队列urb_list
 i = 0;      /* i = min, j = max, n = default */  
 j = 255;  
    if ( usb_endpoint_xfer_int(d)) { 
   } else if  (usb_endpoint_xfer_isoc(d))   
第一个就是,i,j,n分别表示什么。那么n表示的就是bInterval的一个默认值。i和j的默认值分别为0和255,也就是说合法的范围默认是0~255,对于批量端点和控制端点,bInterval对你我来说并没有太大的用处,不过协议里还是规定了,这个范围只能为0~255。对于中断端点和等时端点,bInterval表演的舞台就很大了,如何判断端点是中断的还是等时的。这涉及到两个函数usb_endpoint_xfer_int和usb_endpoint_xfer_isoc
usb_endpoint_xfer_bulk和usb_endpoint_xfer_control,用来判断批量端点和控制端点的。
endpoint->extra = buffer;  
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,USB_DT_INTERFACE, &n);//接着在buffer里寻找下一个端点描述符或者接口描述符
}
总结:
经过usb_parse_configuration、usb_parse_interface和usb_parse_endpoint这三个函数一步一营的层层推进,通过GET_DESCRIPTOR请求所获得那堆数据现在已经解析的清清白白。
设备的那个struct usb_device结构体在出生的时候就带有usb_bus_type和usb_device_type这样的胎记,Linux设备模型根据总线类型usb_bus_type将设备添加到usb总线的那条有名的设备链表里,然后去轮询usb总线的另外一条有名的驱动链表,针对每个找到的驱动去调用usb总线的match函数,也就是usb_device_match(),去为设备寻找另一个匹配的驱动。match函数会根据设备的自身条件和类型usb_device_type安排设备走设备那条路,从而匹配到那个对所有usb_device_type类型的设备都来者不拒的花心大萝卜,usb世界里唯一的那个usb设备驱动(不是usb接口驱动)struct device_driver结构体对象usb_generic_driver。
drivers/usb/core/usb.c
static int __init usb_init(void)
{
retval = usb_register_device_driver(& usb_generic_driver, THIS_MODULE);
}
驱动的生命线(一) 
drivers/usb/core/usb.c
static int __init  usb_init(void)
{
retval =  usb_register_device_driver(& usb_generic_driver, THIS_MODULE);// usb_register_device_driver函数将usb_generic_driver注册给系统 
}
int usb_register_device_driver(struct usb_device_driver *new_udriver,struct module *owner)
{
retval =  driver_register(&new_udriver->drvwrap.driver); //调用设备模型的函数driver_register将usb_generic_driver添加到usb总线的那条驱动链表里
}
usb_generic_driver和usb设备匹配成功后,就会调用new_udriver->drvwrap.driver.probe = usb_probe_device;指定的probe函数usb_probe_device()
drivers/usb/core/driver.c
static int  usb_probe_device(struct device *dev)
{
 
if (!udriver->supports_autosuspend)  //supports_autosuspend前面都提到过那么一下,现在将那两个片断给回顾一下。每个struct usb_driver或struct usb_device_driver里都有一个supports_autosuspend。提到supports_autosuspend时说如果它为0就不再允许绑定到这个驱动的接口。所有的usb设备都是绑定到usb_generic_driver上面的,usb_generic_driver的supports_autosuspend字段是为1的,也就是说允许设备autosuspend。
    if (!error)
         error = udriver->probe(udev); 
//drivers/usb/core/generic.c
static int generic_probe(struct usb_device *udev)
}
drivers/usb/core/generic.c
static int generic_probe(struct usb_device *udev)
{
c = usb_choose_configuration(udev); //
从设备可能的众多配置中选择一个合适的,然后去配置设备,从而让设备进入期待已久的Configured状态。先看看是怎么选择一个配置的,调用的是generic.c里的usb_choose_configuration函数。
}
驱动的生命线(二) 
  
drivers/usb/core/message.c
int usb_set_configuration(struct usb_device *dev, int configuration) 
第一阶段:
int i, ret;
    struct usb_host_config *cp = NULL;
    struct usb_interface **new_interfaces = NULL;
    struct usb_hcd *hcd = bus_to_hcd(dev->bus);
    int n, nintf;
//configuration是choose_configuration()那里返回回来的,找到合意的配置的话,就返回那个配置的bConfigurationValue值,没有找到称心的配置的话,就返回-1,所以这里的configuration值就可能有两种情况,或者为-1,或者为配置的bConfigurationValue值。
    if (dev->authorized == 0 || configuration == -1)
        configuration = 0;//当configuration为-1时这里为啥又要把它改为0?要知道configuration这个值是要在后面发送SET_CONFIGURATION请求时用的,关于SET_CONFIGURATION请求,spec里说,这个值必须为0或者与配置描述符的bConfigurationValue一致,如果为0,则设备收到SET_CONFIGURATION请求后,仍然会待在Address状态。这里当configuration为-1也就是没有发现满意的配置时,设备不能进入Configured,所以要把configuration的值改为0,以便满足SET_CONFIGURATION请求的要求。
    else {
        for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
            if (dev->config[i].desc.bConfigurationValue ==
                    configuration) {
                cp = &dev->config[i];
                break;
            }
        }
    }//如果configuration值为0或大于0的值,就从设备struct usb_device结构体的config数组里将相应配置的描述信息,也就是struct usb_host_config结构体给取出来.
    if ((!cp && configuration != 0))
        return -EINVAL;
    if (cp && configuration == 0)
        dev_warn(&dev->dev, "config 0 descriptor??\n");  //如果没有拿到配置的内容,configuration值就必须为0了,让设备待在Address那儿别动
过了if就为它使用的那些接口都准备一个struct usb_interface结构体。new_interfaces是开头儿就定义好的一个struct usb_interface结构体指针数组,数组的每一项都指向了一个struct usb_interface结构体,所以这里申请内存也要分两步走,先申请指针数组的,再申请每一项的。
驱动的生命线(三) 
drivers/usb/core/message.c
int  usb_set_configuration(struct usb_device *dev, int configuration)
{
if (dev->state != USB_STATE_ADDRESS)
        usb_disable_device(dev, 1); //如果已经在Configured状态了,就得做些清理工作,退回到Address状态.
if (ret < 0 && cp) {
        /*
         * All the old state is gone, so what else can we do?
         * The device is probably useless now anyway.
         */
        usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
        for (i = 0; i < nintf; ++i) {
            usb_disable_interface(dev, cp->interface[i], true);
            put_device(&cp->interface[i]->dev);
            cp->interface[i] = NULL;
        }
        cp = NULL;
    }
     dev->actconfig = cp;
     mutex_unlock(hcd->bandwidth_mutex); //将激活的那个配置的地址赋给actconfig。如果cp为空,重新设置设备的状态为Address,并将之前准备的那些struct usb_interface结构体和new_interfaces释放掉,然后返回。
if (!cp) {
        usb_set_device_state(dev, USB_STATE_ADDRESS);
        /* Leave LPM disabled while the device is unconfigured. */
        usb_autosuspend_device(dev);
        return ret;
    }
    usb_set_device_state(dev, USB_STATE_CONFIGURED); //cp有三种可能为空,一是参数configuration为-1,一是参数configuration为0,且从设备的config数组里拿出来的就为空,一是SET_CONFIGURATION请求出了问题。设置设备的状态为Configured。
}
void  usb_disable_device(struct usb_device *dev, int skip_ep0)
{
usb_disable_device函数的清理工作主要有两部分,一是将设备里所有端点给disable掉,一是将设备当前配置使用的每个接口都从系统里给unregister掉,也就是将接口和它对应的驱动给分开。
if (dev->actconfig) {  actconfig表示的是设备当前激活的配置,只有它不为空时才有接下来清理的必要。
        /*
         * FIXME: In order to avoid self-deadlock involving the
         * bandwidth_mutex, we have to mark all the interfaces
         * before unregistering any of them.
         */
        for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
            dev->actconfig->interface[i]->unregistering = 1;
        for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
            struct usb_interface    *interface;
            /* remove this interface if it has been registered */
            interface = dev->actconfig->interface[i];
            if (!device_is_registered(&interface->dev))
                continue;
            dev_dbg(&dev->dev, "unregistering interface %s\n",
                dev_name(&interface->dev));
             remove_intf_ep_devs(interface); //将这个配置的每个接口从设备模型的体系中删除掉
            device_del(&interface->dev); //将它们和对应的接口驱动分开
        }  //for循环就是将这个配置的每个接口从设备模型的体系中删除掉,将它们和对应的接口驱动分开,没有驱动了,这些接口也就丧失了能力,当然也就什么作用都发挥不了了,这也是名字里那个disable的真正含意所在
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
            put_device(&dev->actconfig->interface[i]->dev);
            dev->actconfig->interface[i] = NULL;
        }// 将actconfig的interface数组置为空,然后再将actconfig置为空,它指向设备struct usb_device结构的config数组里的其中一项,当前被激活的是哪一个配置,它就指向config数组里的哪一项,你这里只是不想让设备当前激活任何一个配置而已,没必要将actconfig指向的那个配置给释放掉吧.
在设备生命线那里取配置描述符的,解析返回的那堆数据时,只是把每个配置里的cache数组,也就是intf_cache数组给初始化了,并没有为interface数组充实任何的内容,这里做清理工作的目的就是要恢复原状,当然要将它置为空了,usb_set_configuration函数里第二个高潮阶段之后不是还有个第三个阶段么,就在那里,你那时激活了哪个配置,就为哪个配置的interface数组动手术,填点东西。
if (hcd->driver->check_bandwidth) {
        /* First pass: Cancel URBs, leave endpoint pointers intact. */
        for (i = skip_ep0; i < 16; ++i) {
            usb_disable_endpoint(dev, i, false);
            usb_disable_endpoint(dev, i + USB_DIR_IN, false);
        }   // 第一部分的清理工作。这个部分主要就是为每个端点调用了usb_disable_endpoint函数,将挂在它们上面的urb给取消掉。能调用到usb_disable_device这个函数,一般来说设备的状态要发生变化了,设备的状态都改变了,那设备的那些端点的状态要不要改变?还有挂在它们上面的那些urb需不需要给取消掉?设备从Configured回到Address,在Address的时候,你只能通过缺省管道也就是端点0对应的管道与设备进行通信的,但是在Configured的时候,设备的所有端点都是能够使用的,它们上面可能已经挂了一些urb正在处理或者将要处理,那么你这时让设备要从Configured变到Address,是不是应该先将这些urb给取消掉?
        /* Remove endpoints from the host controller internal state */
        mutex_lock(hcd->bandwidth_mutex);
        usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
        mutex_unlock(hcd->bandwidth_mutex);
        /* Second pass: remove endpoint pointers */
    }
    for (i = skip_ep0; i < 16; ++i) {  //skip_ep0: 0 to disable endpoint 0, 1 to skip it 如果是1端口0不用做清理工作
        usb_disable_endpoint(dev, i, true);
        usb_disable_endpoint(dev, i + USB_DIR_IN, true);
    }
//从Configured回到Address,这个过程中,其它端点是从能够使用变成了不能使用,但端点0却是一直都很强势,虽说是设备发生了状态的变化,但在这两个状态里它都是要正常使用的,所以就没必要disable它了。
什么时候需要disable端点0?目前版本的内核里两种情况,一是设备要断开的时候,一是设备从Default进化到Address的时候,虽说不管是Default还是Address,端点0都是需要能够正常使用的,但因为地址发生改变了,毫无疑问,你需要将挂在它上面的urb清除掉。
 void  usb_ep0_reinit(struct usb_device *udev)                                                               
 {                                                                                                          
     usb_disable_endpoint(udev, 0 + USB_DIR_IN, true);                                                      
     usb_disable_endpoint(udev, 0 + USB_DIR_OUT, true);                                                     
     usb_enable_endpoint(udev, &udev->ep0, true);                                                           
 } //这个函数里只对端点0调用了usb_disable_endpoint(),但是端点0接下来还是要使用的,不然你就取不到设备那些描述符了,所以接着重新将ep0赋给ep_in[0]和ep_out[0]。
void  usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr, bool reset_hardware)
{
unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
    struct usb_host_endpoint *ep;
    if (!dev)
        return;
    if (usb_endpoint_out(epaddr)) {
        ep = dev->ep_out[epnum];
        if (reset_hardware)
            dev->ep_out[epnum] = NULL;
    } else {
        ep = dev->ep_in[epnum];
        if (reset_hardware)
            dev->ep_in[epnum] = NULL;   // 这个函数先获得端点号和端点的方向,然后从ep_in或ep_out两个数组里取出端点的struct usb_host_endpoint结构体,并将数组里的对应项置为空,要注意的是这里同样不是释放掉数组里对应项的内存而是置为空。这两个数组里的ep_in[0]和ep_out[0]是早就被赋值了.
    }
    if (ep) {
        ep->enabled = 0;
        usb_hcd_flush_endpoint(dev, ep);
        if (reset_hardware)
            usb_hcd_disable_endpoint(dev, ep);
    }
}
}
1887 void  usb_hcd_disable_endpoint(struct usb_device *udev,                                                     
1888         struct usb_host_endpoint *ep)                                                                      
1889 {                                                                                                          
1890     struct usb_hcd      *hcd;                                                                              
1891                                                                                                            
1892     might_sleep();                                                                                         
1893     hcd = bus_to_hcd(udev->bus);                                                                           
1894     if (hcd->driver->endpoint_disable)                                                                     
1895         hcd->driver->endpoint_disable(hcd, ep);                                                            
1896 } 
驱动的生命线(四) 
  drivers/usb/core/message.c
usb_set_configuration 
{
 * Initialize the new interface structures and the
 * hc/hcd/usbcore interface/endpoint state.
 */
for (i = 0; i < nintf; ++i) {//intf就是配置里接口的数目,那for循环对配置里的每个接口做处理 
struct usb_interface_cache *intfc;
struct usb_interface *intf;
struct usb_host_interface *alt;
cp->interface[i] = intf = new_interfaces[i];
intfc = cp->intf_cache[i];
intf->altsetting = intfc->altsetting;
intf->num_altsetting = intfc->num_altsetting;
kref_get(&intfc->ref);
 //cp里的两个数组interface和intf_cache,一个是没有初始化的,一个是已经动过手术很饱满的。拿intf_cache的内容去充实它。
alt =  usb_altnum_to_altsetting(intf, 0);
/* No altsetting 0?  We'll assume the first altsetting.
 * We could use a GetInterface call, but if a device is
 * so non-compliant that it doesn't have altsetting 0
 * then I wouldn't trust its reply anyway.
 */
if (!alt)
alt = &intf->altsetting[0];
intf->intf_assoc =
find_iad(dev, cp, alt->desc.bInterfaceNumber);
intf->cur_altsetting = alt;
usb_enable_interface(dev, intf, true);
intf->dev.parent = &dev->dev;
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;  // 接口所属的总线类型仍然为usb_bus_type 
intf->dev.type = &usb_if_device_type;  // 设备类型变为usb_if_device_type 
intf->dev.groups = usb_interface_groups;
intf->dev.dma_mask = dev->dev.dma_mask;
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
intf->minor = -1;
device_initialize(&intf->dev); // 初始化接口 
pm_runtime_no_callbacks(&intf->dev);
dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);
}
kfree(new_interfaces)//;for循环结束了,new_interfaces的历史使命也就结束了。这里的kfree释放的只是new_interfaces指针数组的内存,而不包括它里面各个指针所指向的内存,至于那些数据,都已经在前面被赋给配置里的interface数组了。
/* Now that all the interfaces are set up, register them
 * to trigger binding of drivers to interfaces.  probe()
 * routines may install different altsettings and may
 * claim() any interfaces not yet bound.  Many class drivers
 * need that: CDC, audio, video, etc.
 */
for (i = 0; i < nintf; ++i) {
struct usb_interface *intf = cp->interface[i];
dev_dbg(&dev->dev,
"adding %s (config #%d, interface %d)\n",
dev_name(&intf->dev), configuration,
intf->cur_altsetting->desc.bInterfaceNumber);
device_enable_async_suspend(&intf->dev);
ret =  device_add(&intf->dev);
if (ret != 0) {
dev_err(&dev->dev, "device_add(%s) --> %d\n",
dev_name(&intf->dev), ret);
continue;
}
create_intf_ep_devs(intf);
}
usb_autosuspend_device(dev); // 这个for循环结束,usb_set_configuration()的三个阶段也就算结束了,设备和大美女usb_generic_driver上上下下忙活了这么久也都很累了,接下来就该接口和接口驱动去忙活了。
这个for循环将前面那个for循环准备好的每个接口送给设备模型,Linux设备模型会根据总线类型usb_bus_type将接口添加到usb总线的那条有名的设备链表里,然后去轮询usb总线的另外一条有名的驱动链表,针对每个找到的驱动去调用usb总线的match函数,也就是usb_device_match,去为接口寻找另一个匹配的半圆。你说这个时候设备和接口两条路它应该走哪条?它的类型已经设置成usb_if_device_type了,设备那条路把门儿的根本就不会让它进,所以它必须得去走接口那条路。
}
int  usb_set_interface(struct usb_device *dev, int interface, int alternate)
{
   iface = usb_ifnum_to_if(dev, interface);   //因为某些厂商有特殊的癖好,导致了struct usb_host_config结构里的数组interface并不一定是按照接口号的顺序存储的,你必须使用usb_ifnum_to_if 来获得指定接口号对应的struct usb_interface结构体
  
    alt = usb_altnum_to_altsetting(iface, alternate); //接口里的altsetting数组也不一定是按照设置编号来顺序存储的,你必须使用usb_altnum_to_altsetting()来获得接口里的指定设置
}
struct usb_host_interface * usb_altnum_to_altsetting(const struct usb_interface *intf,unsigned int altnum)
{
}
void  usb_enable_interface(struct usb_device *dev,struct usb_interface *intf, bool reset_eps)  {
struct usb_host_interface *alt = intf->cur_altsetting;                                       
     int i;                                                                                       
                                                                                                  
     for (i = 0; i < alt->desc.bNumEndpoints; ++i)                                                
          usb_enable_endpoint(dev, &alt->endpoint[i], reset_eps); //轮询前面获得的那个接口设置使用到的每个端点,调用message.c里的usb_enable_endpoint()将它们统统enable。 
}
void  usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep,
bool reset_ep)
{
int epnum = usb_endpoint_num(&ep->desc);
int is_out = usb_endpoint_dir_out(&ep->desc);
int is_control = usb_endpoint_xfer_control(&ep->desc);
if (reset_ep)
usb_hcd_reset_endpoint(dev, ep);
if (is_out || is_control)
dev->ep_out[epnum] = ep;
if (!is_out || is_control)
dev->ep_in[epnum] = ep;
ep->enabled = 1;
}
字符串描述符 
字符串描述符,地位仅次于设备/配置/接口/端点四大描述符,那四大设备必须得支持,而字符串描述符对设备来说则是可选的
char * usb_cache_string(struct usb_device *udev, int index) //获 得一个字符串描述符 
{
char *buf;
char *smallbuf = NULL;
int len;
if (index <= 0)
return NULL;
buf = kmalloc(MAX_USB_STRING_SIZE, GFP_NOIO);
if (buf) {
len =  usb_string(udev, index, buf, MAX_USB_STRING_SIZE);
if (len > 0) {
smallbuf = kmalloc(++len, GFP_NOIO);
if (!smallbuf)
return buf;
memcpy(smallbuf, buf, len);
}
kfree(buf);
}
return smallbuf;
}
接口驱动 usb_generic_driver在自己的生命线里,以一己之力将设备的各个接口送给了linux的设备模型,让usb总线的match函数,也就是usb_device_match,在自己的那条驱动链表里为它们寻找一个合适的接口驱动程序。现在让咱们轻声的问一句,这些接口驱动都从哪里来?()
insmod,modprobe,rmmod。你insmod或modprobe驱动的时候,经过一个曲折的过程,会调用到你驱动里的那个xxx_init函数,进而去调用usb_register()将你的驱动提交给设备模型,添加到usb总线的驱动链表里。你rmmod驱动时候,同样经过一个曲折的过程之后,调用到你驱动里的那个xxx_cleanup函数,进而调用usb_deregister()将你的驱动从usb总线的驱动链表里删除掉。现在就看看include/linux/usb.h里定义的usb_register函数
#define THIS_MODULE (&__this_module)是一个struct module变量,代表当前模块,与那个著名的current有几分相似,可以通过THIS_MODULE宏来引用模块的struct module结构,比如使用THIS_MODULE->state可以获得当前模块的状态。struct usb_driver结构里的owner设置为THIS_MODULE了吧,这个owner指针指向的就是你的模块自己
drivers/usb/core/driver.c   //注册每个接口驱动
int  usb_register_driver(struct usb_driver *new_driver, struct module *owner, const char *mod_name)                                                                
{
int retval = 0;                                                                              
                                                                                                   
      if (usb_disabled())                                                                          
          return -ENODEV;                                                                          
                                                                                                   
      new_driver->drvwrap.for_devices = 0;                                                         
      new_driver->drvwrap.driver.name = (char *) new_driver->name;                                 
      new_driver->drvwrap.driver.bus = &usb_bus_type;                                              
      new_driver->drvwrap.driver.probe =  usb_probe_interface; //接口驱动和接口设备匹配后调用                                     
      new_driver->drvwrap.driver.remove = usb_unbind_interface;                                    
      new_driver->drvwrap.driver.owner =  owner;                                                    
      new_driver->drvwrap.driver.mod_name = mod_name;                                              
      spin_lock_init(&new_driver->dynids.lock);                                                    
      INIT_LIST_HEAD(&new_driver->dynids.list);                                                    
                                                                                                   
      retval =  driver_register(&new_driver->drvwrap.driver);                                       
      if (retval)                                                                                  
          goto out;                                                                                
                                                                                                   
      retval = usb_create_newid_files(new_driver);                                                 
      if (retval)                                                                                  
          goto out_newid;                                                                          
                                                                                                   
      pr_info("%s: registered new interface driver %s\n",                                          
              usbcore_name, new_driver->name);                                                     
                                                                                                   
  out:                                                                                             
      return retval;                                                                               
                                                                                                   
  out_newid:                                                                                       
      driver_unregister(&new_driver->drvwrap.driver);
  
      printk(KERN_ERR "%s: error %d registering interface "
              "   driver %s\n",
              usbcore_name, retval, new_driver->name);
      goto out;
//这函数和前面见过的usb_register_device_driver长的很相,for_devices在742行设置成了0,有了这行,match里的那个is_usb_device_driver把门儿的才不会把它当成设备驱动放过去。driver_register(&new_driver->drvwrap.driver)将你的驱动提交给设备模型,从而添加到usb总线的驱动链表里,从此之后,接口和接口驱动就可以通过usb总线的match函数匹配
}                                                                 
还是那个match 
usb总线的那个match函数usb_device_match()开始到现在,遇到了设备,遇到了设备驱动,遇到了接口,也遇到了接口驱动,期间还多次遇到usb_device_match()。
每个设备也都有一条共同之路,与hub初恋,失身于usb_generic_driver,嫁给了接口驱动,被usb总线保养。设备没有真正自由过,刚开始时在Default状态动弹不得,稍后步入Address,无论外头风光多好,都得与usb_generic_driver长厢厮守,没得选择,终于达到了Configured,又必须为自己的接口殚精竭虑,以便usb_device_match()能够为它们找一个好人家。
drivers/usb/core/driver.c 
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
}
USB整个流程总结 
(1) 
drivers/usb/core/usb.c 
usb_init  usb子系统的初始化 
(2) 
注册usb 设备驱动 
usb_init{
usb_register_device_driver(& usb_generic_driver, THIS_MODULE)
}
(3) 
当usb插入hub口的时候调用下面的接口 ,注册usb device 
static void hub_port_connect_change(struct usb_hub *hub, int port1,u16 portstatus, u16 portchange) ---->
{
分配一个usb_device设备
struct usb_device * usb_alloc_dev(struct usb_device *parent,struct usb_bus *bus, unsigned port1)----->
{
   dev->dev.bus = & usb_bus_type; //usb设备的总线类型
   dev->dev.type = & usb_device_type; //usb设备的类型
}
int  usb_new_device(struct usb_device *udev) --> err =  device_add(&udev->dev); //添加usb设备
}
(4) 
usb device 注册到usb_bus_tpye总线后,调用usb_device_match去匹配usb_bus_tpye上面的usb设备驱动 
static int usb_device_match(struct device *dev, struct device_driver *drv)
{  //判断是设备还是接口 
static inline int  is_usb_device(const struct device *dev)                                         
 {                                                                                                 
     return dev->type == &usb_device_type;                                                         
 }                                                                                                 
                                                                                                   
 static inline int  is_usb_interface(const struct device *dev)                                      
 {                                                                                                 
     return dev->type == &usb_if_device_type;                                                      
 } 
}
 usb_device_match----->(设备/接口) 
--->设备---->generic_probe()--->usb_set_configuration()设置配置 
--->接口---->usb_probe_interface()----->error = driver->probe(intf, id);自己驱动的probe 
比如: drivers/usb/storage/usb.c 
 static struct  usb_driver usb_storage_driver = {
     .name =     "usb-storage",
     .probe =     storage_probe,
}
drivers/usb/core/hub.c 
static struct  usb_driver hub_driver = {
     .name =     "hub",
     .probe =     hub_probe,
}
(5) 
经过usb_device_match判断后,是设备驱动,然后调用usb_probe_device 
static int  usb_probe_device(struct device *dev)
{
      if (!error)                                                                                  
      error = udriver->probe(udev);  //这里调用的是generic_probe 
// struct  usb_device_driver usb_generic_driver = {
     .name = "usb",
     .probe =  generic_probe;
 }; 
}
(6)  
static int generic_probe(struct usb_device *udev) 
{
 err =  usb_set_configuration(udev, c); 
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux技术芯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值