zoukankan      html  css  js  c++  java
  • usb gadge驱动设计之我是zero

    此处将以zero.c为例进行讲解。

    第一次接触zero.c驱动的时候,是因为某项目需要,提供一种usb字符设备,希望能够通过字符设备打开,读取和发送文件。当时能想到的就是zero.c文件,本打算按照zero驱动的编写方式,自己编写一个字符驱动,但后来为了节省工作时间,直接修改zero驱动,增加了字符设备的注册和操作函数。

    zero.c驱动提供了丰富的功能接口,既包含自收自发的loopback(回环功能),又包含了主从通信的source link功能。该两功分别绑定各自的配置,配置在实际使用的过程中,是不同共存的,只能切换操作,当然,如果你足够厉害,将两功能汇总到一个配置里面,也不是不可能的事。该两种功能的具体实现会在下面详细介绍。

    zero.c驱动功能上主要是实现了两个bulk端点,in和out,根据选定的配置,in和out针对性就不同了。但是如果你要是想和host端主机通信,source link功能必然是完美的选择,因为loopback顾明思意,就是采用的回环功能。

     在介绍zero.c驱动过的实现之前,先介绍下zero中相关的变量和函数。

    variable : //该驱动涉及到的变量和结构体。
     ||     autoresume          
     ||     autoresume_interval_
     ||     autoresume_step_ms  
     ||     autoresume_timer      //表示zero设备与resume操作相关。||     dev_strings           //设备字符串描述符
     ||     device_desc           //设备描述符,唯一
     ||     func_inst_lb          //loopback功能实例   此处特别的重要
     ||     func_inst_ss          //source link功能实例,也特别的重要。
     ||     func_lb               //loopback接口,又称功能
     ||     func_ss               //source link接口,又称功能
     ||     gzero_options         //涉及到zero设备中packet和bulk_buf长度等||     longname              //产品名称||     loopdefault           //是否支持loopback功能通过该变量判定,为0表示选择source link功能。
     ||     max_autoresume        //最长的自动恢复时间,与定时器设置相关
     ||     otg_desc              //关于otg功能的
     ||     otg_descriptor       
     ||     serial                /Serial 变量存储的是设备序列号,对于一个非正式设备,显得不是那么重要,随便填充一下
     ||     sourcesink_driver     //基本上后缀命名的driver表示是usb config
     ||     strings_dev           //字符串描述符
     ||     stringtab_dev         //gadget字符串描述符,包括字符串描述符,以及支持的语种。默认是英文。
     ||     zero_driver           //usb_composite_driver
    
     function                       
       ||     cleanup             //卸载驱动函数。 
       ||     init                //驱动注册函数。
       ||     ss_config_setup     //枚举响应函数,只有source link功能支持。
       ||     zero_autoresum      //定时器调用函数
       ||     zero_bind           //没有绑定,就没有各种配置和接口的实现,也就没有驱动和设备的绑定
       ||     zero_resume         //个人认为主要是省电模式采用,设备处于空闲时,进入挂起状态,被唤醒后自动回复正常状态
        || zero_suspend           //设备挂起。

    || zero_unbind //是否功能和功能实例。

    之所以介绍zero驱动的相关变量、结构体和函数主要是为了对驱动整体框架有所了解。在分析该驱动的过程中,我们主要关注那些点,以及这些是怎么封装的,这样会对我们改zero驱动会有很大的帮助。

    1=======模块的注册和卸载。此处不用多讲,我的另一篇文章linux usb gadget框架概述已经较为详细的介绍了驱动的注册过程。

    403 static __refdata struct usb_composite_driver zero_driver = {
    404     .name       = "zero",
    405     .dev        = &device_desc,
    406     .strings    = dev_strings,
    407     .max_speed  = USB_SPEED_SUPER, //此处还支持usb3.0?没有测试过。
    408     .bind       = zero_bind,
    409     .unbind     = zero_unbind,
    410     .suspend    = zero_suspend,
    411     .resume     = zero_resume,
    412 }; 
    413    
    414 MODULE_AUTHOR("David Brownell");
    415 MODULE_LICENSE("GPL");
    416    
    417 static int __init init(void)
    418 {  
    419     return usb_composite_probe(&zero_driver);
    420 }
      421 module_init(init);
      422    
      423 static void __exit cleanup(void)
      424 {  
      425     usb_composite_unregister(&zero_driver);
      426 }                                                                                                                   
      427 module_exit(cleanup);

    2=====填充设备描述符。

      112 static struct usb_device_descriptor device_desc = {
      113     .bLength =      sizeof device_desc,
      114     .bDescriptorType =  USB_DT_DEVICE,//描述符类型,此处表示设备描述符,非接口描述符
      115                                     
      116     .bcdUSB =       cpu_to_le16(0x0200),
      117     .bDeviceClass =     USB_CLASS_VENDOR_SPEC, //#define USB_CLASS_VENDOR_SPEC   0xff 表示产商自定义类设备
      118                                     
      119     .idVendor =     cpu_to_le16(DRIVER_VENDOR_NUM),
      120     .idProduct =        cpu_to_le16(DRIVER_PRODUCT_NUM),
      121     .bNumConfigurations =   2,      //介绍该设备有几个配置,此处写的两个,真好是loopback和source link两个配置。
      122 }; 

    3=====填充字符描述符。基本上usb_gadget_strings都是这个德行,封装三层,最后填充到zero_driver的.strings = dev_strings,中去。

    150 static struct usb_string strings_dev[] = {
    151     [USB_GADGET_MANUFACTURER_IDX].s = "",
    152     [USB_GADGET_PRODUCT_IDX].s = longname,
    153     [USB_GADGET_SERIAL_IDX].s = serial,
    154     [USB_GZERO_SS_DESC].s   = "source and sink data",
    155     [USB_GZERO_LB_DESC].s   = "loop input to output",
    156     {  }            /* end of list */
    157 };      
    158         
    159 static struct usb_gadget_strings stringtab_dev = {
    160     .language   = 0x0409,   /* en-us */
    161     .strings    = strings_dev,
    162 };      
    163         
    164 static struct usb_gadget_strings *dev_strings[] = {
    165     &stringtab_dev,
    166     NULL,
    167 }; 

     ==========填充配置描述符。loopback_driver&sourcesink_driver

      242 static struct usb_configuration sourcesink_driver = {
      243     .label                  = "source/sink",  //标签在主机枚举的时候获取,如果主机是window,可以在管理/设备管理器中找到
      244     .setup                  = ss_config_setup, //setup主要是响应枚举过程中控制请求某些特效的操作。
      245     .bConfigurationValue    = 3, //当使用SetConfiguration和GetConfiguration请求时所指定的配置索引值。这个在响应枚举过程是十分重要的。
      246     .bmAttributes           = USB_CONFIG_ATT_SELFPOWER,    //自供电                                                         
      247     /* .iConfiguration      = DYNAMIC */
      248 };  
      220 static struct usb_configuration loopback_driver = {
      221     .label          = "loopback",
      222     .bConfigurationValue = 2,    
      223     .bmAttributes   = USB_CONFIG_ATT_SELFPOWER,
      224     /* .iConfiguration = DYNAMIC */                                                                                 
      225 };  

     ==========填充接口描述符。func_ss&func_lb

    该接口的实现挺有技巧的,下面详细讲述之。

    227 static struct usb_function *func_ss; 
      228 static struct usb_function_instance *func_inst_ss; //视乎编写一个gadget驱动的通用方法需要填充一个功能实例。
      269 static struct usb_function *func_lb;
      270 static struct usb_function_instance *func_inst_lb; 

    //首先,填充usb_function_instance 这个结构体。
     func_inst_ss = usb_get_function_instance("SourceSink");  
     func_inst_lb = usb_get_function_instance("Loopback");

    38 struct usb_function_instance *usb_get_function_instance(const char *name) //此处是怎么通过字符串得到的功能实例呢?
    39 {
    40 struct usb_function_instance *fi;
    41 int ret;
    42
    43 fi = try_get_usb_function_instance(name);
    44 if (!IS_ERR(fi))
    45 return fi;
    46 ret = PTR_ERR(fi);
    47 if (ret != -ENOENT)
    48 return fi;
    49 ret = request_module("usbfunc:%s", name);
    50 if (ret < 0)
    51 return ERR_PTR(ret);
    52 return try_get_usb_function_instance(name); //关键在于这个函数。
    53 }

    11 static struct usb_function_instance *try_get_usb_function_instance(const char *name)
    12 {
    13 struct usb_function_driver *fd;
    14 struct usb_function_instance *fi;
    15
    16 fi = ERR_PTR(-ENOENT);
    17 mutex_lock(&func_lock);
    18 list_for_each_entry(fd, &func_list, list) {  //便利所有的功能链表,通过功能链表获取功能驱动,那功能驱动从哪里来的?那就设计到每个功能驱动的注册了。
    19
    20 if (strcmp(name, fd->name))
    21 continue;
    22
    23 if (!try_module_get(fd->mod)) {
    24 fi = ERR_PTR(-EBUSY);
    25 break;
    26 }
    27 fi = fd->alloc_inst();  //功能实例是在这里生成的。
    28 if (IS_ERR(fi))
    29 module_put(fd->mod);
    30 else
    31 fi->fd = fd;
    32 break;
    33 }
    34 mutex_unlock(&func_lock);
    35 return fi;
    36 }

    那现在问题的关键点是在于找到usb_function_driver这个结构体,驱动肯定是需要调用注册函数进行注册的,功能驱动肯定是在各自功能实现文件里。

    f_sourcesink.c f_loopback.c 

    usb_function_register(&SourceSinkusb_func); 
     90 int usb_function_register(struct usb_function_driver *newf)
     91 {          
     92     struct usb_function_driver *fd;
     93     int ret;
     94            
     95     ret = -EEXIST;
     96            
     97     mutex_lock(&func_lock);
     98     list_for_each_entry(fd, &func_list, list) { 
     99         if (!strcmp(fd->name, newf->name))                                                                            
    100             goto out;
    101     }      
    102     ret = 0;
    103     list_add_tail(&newf->list, &func_list); //从该函数可以看出,该注册函数正好是讲功能实例结构体中的链表加入全局链表func_list中,这样通过list_for_entry就可以获取实例了
    104 out: 

    105 mutex_unlock(&func_lock);

    106 return ret; 107 }

    那SourceSinkusb_func这个变量从哪里来呢?用ag搜索了整个内核目录都没有找到,这个时候不得不好好分析linux中宏定义的厉害了。

    1224 DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst,                                                             
    1225         source_sink_alloc_func);
    
    489 #define DECLARE_USB_FUNCTION(_name, _inst_alloc, _func_alloc)       
    490     static struct usb_function_driver _name ## usb_func = {       //这个地方就不用过多的介绍了吧。
    491         .name = __stringify(_name),             
    492         .mod  = THIS_MODULE,                    
    493         .alloc_inst = _inst_alloc,                        //所以在try_get_usb_function_instance函数中其实才是真正的开始对功能实例进行初始化。
    494         .alloc_func = _func_alloc,                        //usb_get_function其实也是调用的该函数实现得功能的初始化。
    495     };                              
    496     MODULE_ALIAS("usbfunc:"__stringify(_name));
    下面在再来看一下alloc_func做了哪些操作。
    865 static struct usb_function *source_sink_alloc_func(
     866         struct usb_function_instance *fi)                                                                            
     867 {                            
     868     struct f_sourcesink     *ss;
     869     struct f_ss_opts    *ss_opts;
     870                              
     871     ss = kzalloc(sizeof(*ss), GFP_KERNEL);
     872     if (!ss)                 
     873         return NULL;         
     874                              
     875     ss_opts =  container_of(fi, struct f_ss_opts, func_inst);
     876                              
     877     mutex_lock(&ss_opts->lock);
     878     ss_opts->refcnt++;       
     879     mutex_unlock(&ss_opts->lock);
     880                              
     881     pattern = ss_opts->pattern;
     882     isoc_interval = ss_opts->isoc_interval;
     883     isoc_maxpacket = ss_opts->isoc_maxpacket;
     884     isoc_mult = ss_opts->isoc_mult;
     885     isoc_maxburst = ss_opts->isoc_maxburst;
     886     buflen = ss_opts->bulk_buflen;
     887                              
     888     ss->function.name = "source/sink"; //填充功能名称
     889     ss->function.bind = sourcesink_bind;//主要实现了设备和驱动的绑定,已经端点的初始化的操作
     890     ss->function.set_alt = sourcesink_set_alt;//这个会根据配置中功能的先后顺序,将某个功能配置为0
     891     ss->function.get_alt = sourcesink_get_alt;
     892     ss->function.disable = sourcesink_disable;
     893     ss->function.setup = sourcesink_setup;
     894     ss->function.strings = sourcesink_strings;
     895                             
     896     ss->function.free_func = sourcesink_free_func;
     897                             
     898     return &ss->function;   
     899 }

     ==========填充端点描述符。 //端点描述符有两种一个是支持全是一种是支持高速,主要针对host端是否支持来定,在bind函数中,将其加入function中。

    97 static struct usb_endpoint_descriptor fs_source_desc = { 
      98     .bLength =      USB_DT_ENDPOINT_SIZE,
      99     .bDescriptorType =  USB_DT_ENDPOINT,
     100                   
     101     .bEndpointAddress = USB_DIR_IN,
     102     .bmAttributes =     USB_ENDPOINT_XFER_BULK,
     103 };                
     104                   
     105 static struct usb_endpoint_descriptor fs_sink_desc = {
     106     .bLength =      USB_DT_ENDPOINT_SIZE,
     107     .bDescriptorType =  USB_DT_ENDPOINT,
     108                   
     109     .bEndpointAddress = USB_DIR_OUT,
     110     .bmAttributes =     USB_ENDPOINT_XFER_BULK,
     111 };                
     113 static struct usb_endpoint_descriptor fs_iso_source_desc = {
     114     .bLength =      USB_DT_ENDPOINT_SIZE,
     115     .bDescriptorType =  USB_DT_ENDPOINT,
     116                    
     117     .bEndpointAddress = USB_DIR_IN,
     118     .bmAttributes =     USB_ENDPOINT_XFER_ISOC,
     119     .wMaxPacketSize =   cpu_to_le16(1023),
     120     .bInterval =        4,
     121 };                 
     122                    
     123 static struct usb_endpoint_descriptor fs_iso_sink_desc = {
     124     .bLength =      USB_DT_ENDPOINT_SIZE,
     125     .bDescriptorType =  USB_DT_ENDPOINT,
     126                    
     127     .bEndpointAddress = USB_DIR_OUT,
     128     .bmAttributes =     USB_ENDPOINT_XFER_ISOC,
     129     .wMaxPacketSize =   cpu_to_le16(1023),
     130     .bInterval =        4,
     131 };
     133 static struct usb_descriptor_header *fs_source_sink_descs[] = {
     134     (struct usb_descriptor_header *) &source_sink_intf_alt0,  //在枚举过程中,都是通过usb_descriptor_header指针获取的。
     135     (struct usb_descriptor_header *) &fs_sink_desc,
     136     (struct usb_descriptor_header *) &fs_source_desc,
     137     (struct usb_descriptor_header *) &source_sink_intf_alt1,
     138 #define FS_ALT_IFC_1_OFFSET 3
     139     (struct usb_descriptor_header *) &fs_sink_desc,
     140     (struct usb_descriptor_header *) &fs_source_desc,
     141     (struct usb_descriptor_header *) &fs_iso_sink_desc,
     142     (struct usb_descriptor_header *) &fs_iso_source_desc,
     143     NULL,         
     144 }; 

     至此,从驱动注册,各种配置描述符的初始化和实现已经讲完,是不是感觉什么也没讲明白,那是因为你不熟悉gadaget驱动的注册和枚举响应过程,下面将花大量的篇幅介绍gadget设备的枚举过程。

    枚举过程主要分为如下几个步骤:

     要了解gadget驱动的枚举过程,就必须了解usb设备的中断响应。要了解usb的中断响应就必须知道usb控制的注册过程,因为中断的注册实在控制器的注册中完成的。

    下面将花少量篇幅介绍下udc的注册过程,以omap_udc.c为例进行讲解。

    194 static struct platform_device udc_device = {
    195 .name = "omap_udc",
    196 .id = -1,
    197 .dev = {
    198 .dma_mask = &udc_dmamask,
    199 .coherent_dma_mask = 0xffffffff,
    200 },
    201 .num_resources = ARRAY_SIZE(udc_resources),
    202 .resource = udc_resources,
    203 };

     114 static const char driver_name[] = "omap_udc"//此处是平台设备能够注册成功的关键,平台设备一般在板级信息中注册。
    3026 static struct platform_driver udc_driver = {
    3027     .probe      = omap_udc_probe,
    3028     .remove     = omap_udc_remove,
    3029     .suspend    = omap_udc_suspend,
    3030     .resume     = omap_udc_resume,
    3031     .driver     = {         
    3032         .owner  = THIS_MODULE,
    3033         .name   = (char *) driver_name,                                                                              
    3034     },                      
    3035 }; 
    一当内核查找到平台设备和驱动设备中名称匹配,就会加重驱动,调用驱动probe函数
    2731 static int omap_udc_probe(struct platform_device *pdev)
    2732 {           
    2733     int         status = -ENODEV;
    2734     int         hmc;
    2735     struct usb_phy      *xceiv = NULL;
    2736     const char      *type = NULL;
    2737     struct omap_usb_config  *config = pdev->dev.platform_data;
    2738     struct clk      *dc_clk = NULL;
    2739     struct clk      *hhc_clk = NULL;
    2740             
    2741     if (cpu_is_omap7xx())
    2742         use_dma = 0;
    2743             
    2744     /* NOTE:  "knows" the order of the resources! */
    2745     if (!request_mem_region(pdev->resource[0].start,
    2746             pdev->resource[0].end - pdev->resource[0].start + 1,
    2747             driver_name)) {
    2748         DBG("request_mem_region failed
    ");
    2749         return -EBUSY; 
    2750     }                
    
    。。。。。。。。。。。
    2879     /* USB "non-iso" IRQ (PIO for all but ep0) */
    2880     status = request_irq(pdev->resource[2].start, omap_udc_pio_irq,   //最关键的函数,一当host发起任何从设备相关的操作,都会调用该函数。
    2881             0, "omap_udc pio", udc);
    2882     if (status != 0) { 
    2883         ERR("can't get irq %d, err %d
    ",
    2884             (int) pdev->resource[2].start, status);
    2885         goto cleanup2; 
    2886     } 
    1819 static irqreturn_t omap_udc_irq(int irq, void *_udc)
      1820 {   
      1821     struct omap_udc *udc = _udc;
      1822     u16     irq_src;
      1823     irqreturn_t status = IRQ_NONE;
      1824     unsigned long   flags;
      1825     
      1826     spin_lock_irqsave(&udc->lock, flags);
      1827     irq_src = omap_readw(UDC_IRQ_SRC);
      1828     
      1829     /* Device state change (usb ch9 stuff) */
      1830     if (irq_src & UDC_DS_CHG) {
      1831         devstate_irq(_udc, irq_src);
      1832         status = IRQ_HANDLED;
      1833         irq_src &= ~UDC_DS_CHG;
      1834     }   
      1835     
      1836     /* EP0 control transfers */
      1837     if (irq_src & (UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX)) {//针对枚举过程,中断源肯定是控制端点0发送过来的。
      1838         ep0_irq(_udc, irq_src);//如果是控制端点,则调用端点0中断函数响应中断。
      1839         status = IRQ_HANDLED;
      1840         irq_src &= ~(UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX);
      1841     }

    //这个地方不对这个中断函数进行多讲,主要介绍其枚举响应分支。

      1667         default:                                     
      1668 delegate:                                            
      1669             /* activate the ep0out fifo right away */
      1670             if (!udc->ep0_in && w_length) {          
      1671                 omap_writew(0, UDC_EP_NUM);          
      1672                 omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
      1673             }                                       
      1674                                                     
      1675             /* gadget drivers see class/vendor specific requests,
      1676             ┊* {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION},
      1677             ┊* and more          
      1678             ┊*/               
      1679             VDBG("SETUP %02x.%02x v%04x i%04x l%04x
    ",
      1680                 u.r.bRequestType, u.r.bRequest,     
      1681                 w_value, w_index, w_length);        
      1682                          
      1683 #undef  w_value               
      1684 #undef  w_index               
      1685 #undef  w_length              
      1686                          
      1687             /* The gadget driver may return an error here,
      1688             ┊* causing an immediate protocol stall. 
      1689             ┊*                
      1690             ┊* Else it must issue a response, either queueing a
      1691             ┊* response buffer for the DATA stage, or halting ep0
      1692             ┊* (causing a protocol stall, not a real halt).  A
      1693             ┊* zero length buffer means no DATA stage.
      1694             ┊*                
      1695             ┊* It's fine to issue that response after the setup()
      1696             ┊* call returns, and this IRQ was handled.
      1697             ┊*/               
      1698             udc->ep0_setup = 1;  
      1699             spin_unlock(&udc->lock);                
      1700             status = udc->driver->setup(&udc->gadget, &u.r); 这个函数可不是zero.c中那个setup函数,而是composite.c中的setup函数。下面我们具体分析之。

    =======枚举过程的关键性函数。

    在介绍该函数时,先介绍下至关重要的一个结构体,usb_request,该结构体就是数据发送和接受的载体,类似于网络中的skb.

      90 struct usb_request {              
      91     void            *buf;            //需要传输的数据都会在此填充。
      92     unsigned        length;          //buf长度
      93     dma_addr_t      dma;             //与dma操作相关的
      94                                   
      95     struct scatterlist  *sg;         //视乎是分散聚集表鄙人不是很明白。
      96     unsigned        num_sgs;         //如上
      97     unsigned        num_mapped_sgs;  //如上
      98                                   
      99     unsigned        stream_id:16;    //The stream id, when USB3.0 bulk streams are being used
     100     unsigned        no_interrupt:1;  //If true, hints that no completion irq is needed. Helpful sometimes with deep request queues that are handled directly by DMA controllers.
     101     unsigned        zero:1;          //是否是0包。     
     102     unsigned        short_not_ok:1;  //对于0包,判定该报是否允许其为错包
     103                                   
     104     void            (*complete)(struct usb_ep *ep,  //包发送完成后,会调用该函数。
     105                     struct usb_request *req);
     106     void            *context;         //很简单
     107     struct list_head    list;         //同一类型的usb_request    
     108                                   
     109     int         status;               //当前状态,Reports completion code, zero or a negative errno.
     110     unsigned        actual;          //实际传输包的长度。
     111 };  
    1227 composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
    1228 {         
    1229     struct usb_composite_dev    *cdev = get_gadget_data(gadget);
    1230     struct usb_request      *req = cdev->req; //所有的数据传输都是靠usb_request函数完成的。
    1231     int             value = -EOPNOTSUPP;
    1232     int             status = 0;
    1233     u16             w_index = le16_to_cpu(ctrl->wIndex);
    1234     u8              intf = w_index & 0xFF;
    1235     u16             w_value = le16_to_cpu(ctrl->wValue);
    1236     u16             w_length = le16_to_cpu(ctrl->wLength);
    1237     struct usb_function     *f = NULL;
    1238     u8              endp;
    1239           
    1240     /* partial re-init of the response message; the function or the
    1241     ┊* gadget might need to intercept e.g. a control-OUT completion
    1242     ┊* when we delegate to it.
    1243     ┊*/   
    1244     req->zero = 0;
    1245     req->complete = composite_setup_complete;
    1246     req->length = 0;
    1247     gadget->ep0->driver_data = cdev;
    1248           
    1249     switch (ctrl->bRequest) {
    1251     /* we handle all standard USB descriptors */
    1252     case USB_REQ_GET_DESCRIPTOR:
    1253         if (ctrl->bRequestType != USB_DIR_IN)
    1254             goto unknown;
    1255         switch (w_value >> 8) {
    1256             
    1257         case USB_DT_DEVICE:   //设备描述符
    1258             cdev->desc.bNumConfigurations =
    1259                 count_configs(cdev, USB_DT_DEVICE);
    1260             cdev->desc.bMaxPacketSize0 =
    1261                 cdev->gadget->ep0->maxpacket;
    1262             if (gadget_is_superspeed(gadget)) {
    1263                 if (gadget->speed >= USB_SPEED_SUPER) {
    1264                     cdev->desc.bcdUSB = cpu_to_le16(0x0300);
    1265                     cdev->desc.bMaxPacketSize0 = 9;
    1266                 } else {
    1267                     cdev->desc.bcdUSB = cpu_to_le16(0x0210);
    1268                 }
    1269             }
    1270             
    1271             value = min(w_length, (u16) sizeof cdev->desc);
    1272             memcpy(req->buf, &cdev->desc, value);
    1273             break;
    1274         case USB_DT_DEVICE_QUALIFIER:   //the structure is used by USB client drivers to retrieve a USB-defined device qualifier descriptor.
    1275             if (!gadget_is_dualspeed(gadget) ||
    1276             ┊   gadget->speed >= USB_SPEED_SUPER)                                                                    
    1277                 break;
    1278             device_qual(cdev);
    1279             value = min_t(int, w_length,
    1280                 sizeof(struct usb_qualifier_descriptor));
    1281             break;
    1282         case USB_DT_OTHER_SPEED_CONFIG:
    1283             if (!gadget_is_dualspeed(gadget) ||
    1284             ┊   gadget->speed >= USB_SPEED_SUPER)
    1285                 break;
    1286             /* FALLTHROUGH */
    1287         case USB_DT_CONFIG:  //配置描述符
    1288             value = config_desc(cdev, w_value);
    1289             if (value >= 0)
    1290                 value = min(w_length, (u16) value);
    1291             break;
    1292         case USB_DT_STRING:  //字符串描述符
    1293             value = get_string(cdev, req->buf,
    1294                     w_index, w_value & 0xff);
    1295             if (value >= 0)
    1296                 value = min(w_length, (u16) value);
    1297             break;
    1298         case USB_DT_BOS:
    1299             if (gadget_is_superspeed(gadget)) {
    1300                 value = bos_desc(cdev);
    1301                 value = min(w_length, (u16) value);
    1302             }
    1303             break;                                                                                                   
    1304         }   
    1305         break;
    1306             1307     /* any number of configs can work */
    1308     case USB_REQ_SET_CONFIGURATION:
    1309         if (ctrl->bRequestType != 0)
    1310             goto unknown;
    1311         if (gadget_is_otg(gadget)) {
    1312             if (gadget->a_hnp_support)
    1313                 DBG(cdev, "HNP available
    ");
    1314             else if (gadget->a_alt_hnp_support)
    1315                 DBG(cdev, "HNP on another port
    ");
    1316             else
    1317                 VDBG(cdev, "HNP inactive
    ");
    1318         } 
    1319         spin_lock(&cdev->lock);
    1320         value = set_config(cdev, ctrl, w_value);
    1321         spin_unlock(&cdev->lock);
    1322         break;
    1323     case USB_REQ_GET_CONFIGURATION:
    1324         if (ctrl->bRequestType != USB_DIR_IN)
    1325             goto unknown;
    1326         if (cdev->config)
    1327             *(u8 *)req->buf = cdev->config->bConfigurationValue;
    1328         else
    1329             *(u8 *)req->buf = 0;
    1330         value = min(w_length, (u16) 1);
    1331         break;
    1333     /* function drivers must handle get/set altsetting; if there's
    1334     ┊* no get() method, we know only altsetting zero works.
    1335     ┊*/    
    1336     case USB_REQ_SET_INTERFACE:   //配置接口
    1337         if (ctrl->bRequestType != USB_RECIP_INTERFACE)
    1338             goto unknown;
    1339         if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
    1340             break;
    1341         f = cdev->config->interface[intf];
    1342         if (!f)
    1343             break;
    1344         if (w_value && !f->set_alt)
    1345             break;
    1346         value = f->set_alt(f, w_index, w_value); //设置当前接口为第一个接口0,在上文中有提及该函数的作用
    1347         if (value == USB_GADGET_DELAYED_STATUS) {
    1348             DBG(cdev,
    1349"%s: interface %d (%s) requested delayed status
    ",
    1350                     __func__, intf, f->name);
    1351             cdev->delayed_status++;
    1352             DBG(cdev, "delayed_status count %d
    ",
    1353                     cdev->delayed_status);
    1354         }  
    1355         break;                                                                                                       
    1356     case USB_REQ_GET_INTERFACE:
    1357         if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
    1358             goto unknown;
    1359         if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
    1360             break;
    1361         f = cdev->config->interface[intf];
    1356     case USB_REQ_GET_INTERFACE:
    1357         if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
    1358             goto unknown;
    1359         if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
    1360             break;
    1361         f = cdev->config->interface[intf];
    1362         if (!f)
    1363             break;
    1364         /* lots of interfaces only need altsetting zero... */
    1365         value = f->get_alt ? f->get_alt(f, w_index) : 0;
    1366         if (value < 0)
    1367             break;
    1368         *((u8 *)req->buf) = value;
    1369         value = min(w_length, (u16) 1);
    1370         break;
    1371             
    1372     /*      
    1373     ┊* USB 3.0 additions:
    1374     ┊* Function driver should handle get_status request. If such cb
    1375     ┊* wasn't supplied we respond with default value = 0
    1376     ┊* Note: function driver should supply such cb only for the first
    1377     ┊* interface of the function
    1378     ┊*/     
    1379     case USB_REQ_GET_STATUS:
    1380         if (!gadget_is_superspeed(gadget))
    1381             goto unknown;                                                                                            
    1382         if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
    1383             goto unknown;
    1384         value = 2;  /* This is the length of the get_status reply */
    1384         value = 2;  /* This is the length of the get_status reply */
    1385         put_unaligned_le16(0, req->buf);
    1386         if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
    1387             break;
    1388         f = cdev->config->interface[intf];
    1389         if (!f)
    1390             break;
    1391         status = f->get_status ? f->get_status(f) : 0;
    1392         if (status < 0)
    1393             break;
    1394         put_unaligned_le16(status & 0x0000ffff, req->buf);
    1395         break;
    1396     /*      
    1397     ┊* Function drivers should handle SetFeature/ClearFeature
    1398     ┊* (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
    1399     ┊* only for the first interface of the function
    1400     ┊*/     
    1401     case USB_REQ_CLEAR_FEATURE:
    1402     case USB_REQ_SET_FEATURE:
    1403         if (!gadget_is_superspeed(gadget))
    1404             goto unknown;
    1405         if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
    1406             goto unknown;
    1407         switch (w_value) {
    1408         case USB_INTRF_FUNC_SUSPEND:
    1409             if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)                                                      
    1410                 break;
    1411             f = cdev->config->interface[intf];
    1412             if (!f)
    1409             if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
    1410                 break;
    1411             f = cdev->config->interface[intf];
    1412             if (!f)
    1413                 break;
    1414             value = 0;
    1415             if (f->func_suspend)
    1416                 value = f->func_suspend(f, w_index >> 8);
    1417             if (value < 0) {
    1418                 ERROR(cdev,
    1419                 ┊   ┊ "func_suspend() returned error %d
    ",
    1420                 ┊   ┊ value);
    1421                 value = 0;
    1422             }
    1423             break;
    1424         }  
    1425         break;
    1426     default:
    1427 unknown:     //倘若枚举过程中发送了无法识别的请求。
    1428         VDBG(cdev,
    1429             "non-core control req%02x.%02x v%04x i%04x l%d
    ",
    1430             ctrl->bRequestType, ctrl->bRequest,
    1431             w_value, w_index, w_length);
    1432            
    1433         /* functions always handle their interfaces and endpoints...
    1434         ┊* punt other recipients (other, WUSB, ...) to the current                                                   
    1435         ┊* configuration code.
    1436         ┊* 
    1437         ┊* REVISIT it could make sense to let the composite device
    1435         ┊* configuration code.
    1436         ┊*  
    1437         ┊* REVISIT it could make sense to let the composite device
    1438         ┊* take such requests too, if that's ever needed:  to work
    1439         ┊* in config 0, etc.
    1440         ┊*/ 
    1441         switch (ctrl->bRequestType & USB_RECIP_MASK) {
    1442         case USB_RECIP_INTERFACE:
    1443             if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
    1444                 break;
    1445             f = cdev->config->interface[intf];
    1446             break;
    1447             
    1448         case USB_RECIP_ENDPOINT:
    1449             endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
    1450             list_for_each_entry(f, &cdev->config->functions, list) {
    1451                 if (test_bit(endp, f->endpoints))
    1452                     break;
    1453             }
    1454             if (&f->list == &cdev->config->functions)
    1455                 f = NULL;
    1456             break;
    1457         }   
    1458             
    1459         if (f && f->setup)
    1460             value = f->setup(f, ctrl);    //当时在分析该代码时候,很不明白function中为啥还设置setup函数,至少zero驱动中source sink只是简单的处理了下。                                                                                      
    1461         else {
    1462             struct usb_configuration    *c;
    1463            
    1464             c = cdev->config;
    1465             if (!c)
    1466                 goto done;
    1467            
    1468             /* try current config's setup */
    1469             if (c->setup) {
    1470                 value = c->setup(c, ctrl);
    1471                 goto done;
    1472             }
    1473            
    1474             /* try the only function in the current config */
    1475             if (!list_is_singular(&c->functions))
    1476                 goto done;
    1477             f = list_first_entry(&c->functions, struct usb_function,
    1478                     ┊   ┊list);
    1479             if (f->setup)
    1480                 value = f->setup(f, ctrl);
    1481         }  
    1482            
    1483         goto done;
    1484     }      
    1485    //其实在每一个case语句里面,都对req进行了填充。并调用发送函数usb_eq_queue,做好执行回馈函数。        
    1486     /* respond with data transfer before status phase? */                                                            
    1487     if (value >= 0 && value != USB_GADGET_DELAYED_STATUS) {
    1488         req->length = value;
    1489         req->zero = value < w_length;
    1490         value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);//将封装好的数据,发送到udc指定的fifo中返回给主机,并调用回调函数composite_setup_complete
    1491         if (value < 0) {
    1492             DBG(cdev, "ep_queue --> %d
    ", value);
    1493             req->status = 0;
    1494             composite_setup_complete(gadget->ep0, req);//complete响应函数1495         }  
    1496     } else if (value == USB_GADGET_DELAYED_STATUS && w_length != 0) {
    1497         WARN(cdev,
    1498             "%s: Delayed status not supported for w_length != 0",
    1499             __func__);
    1500     }      
    1501            
    1502 done:      
    1503     /* device either stalls (value < 0) or reports success */
    1504     if (value < 0) {
    1505         printk("control error %d req%02x.%02x v%04x i%04x l%d
    ", value,
    1506                 ctrl->bRequestType, ctrl->bRequest,
    1507                 w_value, w_index, w_length);
    1508     }      
    1509     return value;
    1510 } 
    usb_ep_queue实际调用的是udc中实现的queue函数。
    1116 static struct usb_ep_ops omap_ep_ops = {
    1117     .enable     = omap_ep_enable,
    1118     .disable    = omap_ep_disable,
    1119                   
    1120     .alloc_request  = omap_alloc_request,
    1121     .free_request   = omap_free_request,
    1122                   
    1123     .queue      = omap_ep_queue,//该函数的作用主要是讲req写入
    到对应的端点中的queue队列中去。
    1002         list_add_tail(&req->queue, &ep->queue);

     下面好好分析下填充好了req后,是怎样通过omap_ep_queue函数发送的。

    omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
     869 {                         
     870     struct omap_ep  *ep = container_of(_ep, struct omap_ep, ep);
     871     struct omap_req *req = container_of(_req, struct omap_req, req);
     872     struct omap_udc *udc; 
     873     unsigned long   flags;
     874     int     is_iso = 0;   
     875                           
     876     /* catch various bogus parameters */
     877     if (!_req || !req->req.complete || !req->req.buf  //毋庸置疑,为了代码的严谨性,对req进行相关判定是必然的。
     878             || !list_empty(&req->queue)) {
     879         DBG("%s, bad params
    ", __func__);                                                                           
     880         return -EINVAL;   
     881     }                     882     if (!_ep || (!ep->ep.desc && ep->bEndpointAddress)) {//这个时候端点描述符显得尤为重要。
     883         DBG("%s, bad ep
    ", __func__);
     884         return -EINVAL;   
     885     }                     
     886     if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
     887         if (req->req.length > ep->ep.maxpacket)
     888             return -EMSGSIZE;
     889         is_iso = 1;       
     890     }                     
     891                           
     892     /* this isn't bogus, but OMAP DMA isn't the only hardware to
     893     ┊* have a hard time with partial packet reads...  reject it.
     894     ┊*/                   
     895     if (use_dma           
     896             && ep->has_dma
     897             && ep->bEndpointAddress != 0
     898             && (ep->bEndpointAddress & USB_DIR_IN) == 0
     899             && (req->req.length % ep->ep.maxpacket) != 0) {
     900         DBG("%s, no partial packet OUT reads
    ", __func__);
     901         return -EMSGSIZE; 
     902     }                     
     903                           
     904     udc = ep->udc;       //获取ucd控制器实例,这个时候就是req和udc结合高潮来临的节奏。
     905     if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
     906         return -ESHUTDOWN;                                                                                           
     907                           
     908     if (use_dma && ep->has_dma)//dma支持吗?
     909         usb_gadget_map_request(&udc->gadget, &req->req,
    909         usb_gadget_map_request(&udc->gadget, &req->req,
     910                 (ep->bEndpointAddress & USB_DIR_IN));
     911                          
     912     VDBG("%s queue req %p, len %d buf %p
    ",
     913         ep->ep.name, _req, _req->length, _req->buf);
     914                          
     915     spin_lock_irqsave(&udc->lock, flags);
     916                          
     917     req->req.status = -EINPROGRESS;
     918     req->req.actual = 0; 
     919                          
     920     /* maybe kickstart non-iso i/o queues */
     921     if (is_iso) {        
     922         u16 w;           
     923                          
     924         w = omap_readw(UDC_IRQ_EN);
     925         w |= UDC_SOF_IE; 
     926         omap_writew(w, UDC_IRQ_EN);
     927     } else if (list_empty(&ep->queue) && !ep->stopped && !ep->ackwait) {
     928         int is_in;       
     929                          
     930         if (ep->bEndpointAddress == 0) {  //若是控制端点0
     931             if (!udc->ep0_pending || !list_empty(&ep->queue)) {
     932                 spin_unlock_irqrestore(&udc->lock, flags);
     933                 return -EL2HLT;
     934             }                                                                                                        
     935                          
     936             /* empty DATA stage? */
     937             is_in = udc->ep0_in;
    938             if (!req->req.length) {  //对于端点0,并且或者req数据长度为0,显然,不用进行回复,直接调用done函数表示完成传输。
     939                          
     940                 /* chip became CONFIGURED or ADDRESSED
     941                 ┊* earlier; drivers may already have queued
     942                 ┊* requests to non-control endpoints
     943                 ┊*/      
     944                 if (udc->ep0_set_config) {
     945                     u16 irq_en = omap_readw(UDC_IRQ_EN);
     946                          
     947                     irq_en |= UDC_DS_CHG_IE | UDC_EP0_IE;
     948                     if (!udc->ep0_reset_config)
     949                         irq_en |= UDC_EPN_RX_IE
     950                             | UDC_EPN_TX_IE;
     951                     omap_writew(irq_en, UDC_IRQ_EN); //是能udc中断
     952                 }        
     953                          
     954                 /* STATUS for zero length DATA stages is
     955                 ┊* always an IN ... even for IN transfers,
     956                 ┊* a weird case which seem to stall OMAP.
     957                 ┊*/      
     958                 omap_writew(UDC_EP_SEL | UDC_EP_DIR,
     959                         UDC_EP_NUM);
     960                 omap_writew(UDC_CLR_EP, UDC_CTRL);
     961                 omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);//设置fifo使能
     962                 omap_writew(UDC_EP_DIR, UDC_EP_NUM);//配置端点放向和号
     963                                                                                                                      
     964                 /* cleanup */
     965                 udc->ep0_pending = 0; //将控制端点0设置为非挂起状态,即空闲状态。
     966                 done(ep, req, 0);967                 req = NULL;
     968                           
     969             /* non-empty DATA stage */
     970             } else if (is_in) {
     971                 omap_writew(UDC_EP_SEL | UDC_EP_DIR,
     972                         UDC_EP_NUM);
     973             } else {      
     974                 if (udc->ep0_setup) //若端点处理建立状态则说明该端点中数据还没发送完成,即需要发送请求。则将req加入控制器队列queue中。
     975                     goto irq_wait;
     976                 omap_writew(UDC_EP_SEL, UDC_EP_NUM);
     977             }             
     978         } else {          
     979             is_in = ep->bEndpointAddress & USB_DIR_IN;
     980             if (!ep->has_dma)
     981                 use_ep(ep, UDC_EP_SEL);
     982             /* if ISO: SOF IRQs must be enabled/disabled! */
     983         }                 
     984                           
     985         if (ep->has_dma)  
     986             (is_in ? next_in_dma : next_out_dma)(ep, req);
     987         else if (req) {   
     988             if ((is_in ? write_fifo : read_fifo)(ep, req) == 1) //若是in则调用write_fifo,将req写入队列中,若是out,则调用read函数,并释放req
     989                 req = NULL;                                                                                         
     990             deselect_ep();
     991             if (!is_in) { 992                 omap_writew(UDC_SET_FIFO_EN, UDC_CTRL);
     993                 ep->ackwait = 1 + ep->double_buf;
     994             }            
     995             /* IN: 6 wait states before it'll tx */
     996         }                
     997     }                    
     998                          
     999 irq_wait:                
    1000     /* irq handler advances the queue */
    1001     if (req != NULL)     
    1002         list_add_tail(&req->queue, &ep->queue);//将usb加入队列中,等待中断处理,处理完后就调用中断回调函数,done
    1003     spin_unlock_irqrestore(&udc->lock, flags);
    1004                          
    1005     return 0;            
    1006 } 

    自此,枚举过程已经讲完,如果成功的话,会返回0值,小于0值,那就得调用composite_setup_complete,表明枚举过程失败了。

     讲完枚举过程,这里还讲下usb_request的传输过程。当时开发项目时,主要用到loopback功能,主要是对ep_in和out的包进行拦截,后并进行处理。

    looback功能很按照字面意思很简单,就是普通的回复,即收到的req转给发出的req。

    host和gadge之间的通信主要依靠中断,在gadget端,进行数据通信时,收到bulk处理指令后都会调用各自端点实现的complete函数,对于loopback来说,关键的处理函数如下:

    此处针对omap_udc.c控制器简单的介绍下:

    omap_udc_pio_irq-->write_fifo/read_fifo--->done->req.complete; //看起来很简单,其实是花费笔者较长时间才弄明白的。

    246 static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
    247 {  
    248     struct f_loopback   *loop = ep->driver_data;
    249     struct usb_composite_dev *cdev = loop->function.config->cdev;
    250     int         status = req->status;
    251    
    252     switch (status) {
    253    
    254     case 0:             /* normal completion? */
    255         if (ep == loop->out_ep) { //如果host端发送过来的out_ep,则需要将包转发给ep_in端点。
    256             /* loop this OUT packet back IN to the host */
    257             req->zero = (req->actual < req->length);
    258             req->length = req->actual;
    259             status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC);//转发很简单,直接把收到的转到另外一个端点即可,对于需要通过loopback功能
    //将req->buf中的包进行某些处理的,可以增加字符操作接口,对buf进行处理后再发送
    //给对应得端点。
    260 if (status == 0) 261 return; 262 263 /* "should never get here" */ 264 ERROR(cdev, "can't loop %s to %s: %d ", 265 ep->name, loop->in_ep->name, 266 status); 267 } 268 269 /* queue the buffer for some later OUT packet */ 270 req->length = buflen; 271 status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC); //很显然,如果是in_ep端点的话,需要将out_ep中包发出。 272 if (status == 0) 273 return; 274 275 /* "should never get here" */ 276 /* FALLTHROUGH */ 277 278 default: 279 ERROR(cdev, "%s loop complete --> %d, %d/%d ", ep->name, 280 status, req->actual, req->length); 281 /* FALLTHROUGH */ 282 283 /* NOTE: since this driver doesn't maintain an explicit record 284 ┊* of requests it submitted (just maintains qlen count), we 285 ┊* rely on the hardware driver to clean up on disconnect or 286 ┊* endpoint disable. 287 ┊*/ 288 case -ECONNABORTED: /* hardware forced ep reset */ 289 case -ECONNRESET: /* request dequeued */ 290 case -ESHUTDOWN: /* disconnect from host */ 291 free_ep_req(ep, req); 292 return; 293 } 294 }
  • 相关阅读:
    smary里Js正则表达式不正常
    php7下对微信支付退款申请通知的解密处理
    apache下设置deflate/gzip
    从大表里随机取若干行的效率问题
    Ecshop、Discuz! 等开源产品的局限
    mysql实现ORACLE的connect by prior父子递归查询
    SQL计算字符串里的子字符串出现个数
    UCENTER同步登录工作原理和配置要点
    云服务器:西部数码VS阿里云
    用ftp命令实现主机文件批量更新
  • 原文地址:https://www.cnblogs.com/haoxing990/p/8860419.html
Copyright © 2011-2022 走看看