USB设备驱动开发-USBGadgetDriver_第1页
USB设备驱动开发-USBGadgetDriver_第2页
USB设备驱动开发-USBGadgetDriver_第3页
USB设备驱动开发-USBGadgetDriver_第4页
USB设备驱动开发-USBGadgetDriver_第5页
已阅读5页,还剩43页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、一、Linux USB Gadget Driver功能      为了与主机端驱动设备的USB Device Driver概念进行区别,将在外围器件中运行的驱动程序称为USB Gadget Driver。其中,Host端驱动设备的驱动程序是master或者client driver,设备端gadget driver是slave或者function driver。       Gadget Driver和USB Host端驱动程序类似,都是使用请求队列来对I/O包进行缓冲,这些

2、请求可以被提交和取消。它们的结构、消息和常量的定义也和USB技术规范第九章的内容一致。同时也是通过bind和unbind将driver与device建立关系。二、Linux USB Gadget Driver核心数据结构1 USB_Gadget对象struct usb_gadget /* readonly to gadget driver */const struct usb_gadget_ops *ops; /Gadget设备操作函数集struct usb_ep *ep0; /控制端点,只对setup包响应struct list_head ep_list;/将设备的所有端点连成链表,ep0不

3、在其中enum usb_device_speed speed;/高速、全速和低速unsigned is_dualspeed:1; /是否同时支持高速和全速unsigned is_otg:1; /是否支持OTG(On-To-Go)unsigned is_a_peripheral:1;unsigned b_hnp_enable:1;unsigned a_hnp_support:1;unsigned a_alt_hnp_support:1;const char *name; /器件名称struct device dev; /内核设备模型使用;2 Gadget器件操作函数集操作UDC硬件的API,但操

4、作端点的函数由端点操作函数集完成struct usb_gadget_ops int (*get_frame)(struct usb_gadget *);int (*wakeup)(struct usb_gadget *);int (*set_selfpowered) (struct usb_gadget *, int is_selfpowered);int (*vbus_session) (struct usb_gadget *, int is_active);int (*vbus_draw) (struct usb_gadget *, unsigned mA);int (*pullup) (

5、struct usb_gadget *, int is_on);int (*ioctl)(struct usb_gadget *, unsigned code, unsigned long param);3 USB Gadget driver对象struct usb_gadget_driver char *function; /驱动名称enum usb_device_speed speed; /USB设备速度类型int (*bind)(struct usb_gadget *); /将驱动和设备绑定,一般在驱动注册时调用void (*unbind)(struct usb_gadget *);/卸

6、载驱动时调用,rmmod时调用int (*setup)(struct usb_gadget *, const struct usb_ctrlrequest *); /处理ep0的控制请求,在中断中调用,不能睡眠void (*disconnect)(struct usb_gadget *); /可能在中断中调用不能睡眠void (*suspend)(struct usb_gadget *); /电源管理模式相关,设备挂起void (*resume)(struct usb_gadget *);/电源管理模式相关,设备恢复/* FIXME support safe rmmod */struct de

7、vice_driver driver; /内核设备管理使用;4 描述一个I/O请求struct usb_request void *buf; /数据缓存区unsigned length; /数据长度dma_addr_t dma; /与buf关联的DMA地址,DMA传输时使用unsigned no_interrupt:1;/当为true时,表示没有完成函数,则通过中断通知传输完成,这个由DMA控制器直接控制unsigned zero:1; /当输出的最后一个数据包不够长度是是否填充0unsigned short_not_ok:1; /当接收的数据不够指定长度时,是否报错void (*comple

8、te)(struct usb_ep *ep, struct usb_request *req);/请求完成函数void *context;/被completion回调函数使用struct list_head list; /被Gadget Driver使用,插入队列int status;/返回完成结果,0表示成功unsigned actual;/实际传输的数据长度;5 端点struct usb_ep void *driver_data;  /端点私有数据const char *name; /端点名称const struct usb_ep_ops *ops; /端点操作函数集struct

9、 list_head ep_list; /Gadget设备建立所有端点的链表unsigned maxpacket:16;/这个端点使用的最大包长度;6 端点操作函数集struct usb_ep_ops int (*enable) (struct usb_ep *ep,  const struct usb_endpoint_descriptor *desc);int (*disable) (struct usb_ep *ep);struct usb_request *(*alloc_request) (struct usb_ep *ep, gfp_t gfp_flags);void (

10、*free_request) (struct usb_ep *ep, struct usb_request *req);int (*queue) (struct usb_ep *ep, struct usb_request *req, gfp_t gfp_flags);int (*dequeue) (struct usb_ep *ep, struct usb_request *req);int (*set_halt) (struct usb_ep *ep, int value);int (*set_wedge) (struct usb_ep *ep);int (*fifo_status) (s

11、truct usb_ep *ep);void (*fifo_flush) (struct usb_ep *ep);7 字符串结构struct usb_gadget_strings u16 language; /* 0x0409 for en-us */struct usb_string *strings;struct usb_string u8 id; /索引const char *s;8 UDC驱动程序需要实现的上层调用接口int usb_gadget_register_driver(struct usb_gadget_driver *driver);int usb_gadget_unreg

12、ister_driver(struct usb_gadget_driver *driver);三、UDC驱动程序1 UDC层主要数据结构,以S3C2410为例,在driver/usb/gadget/s3c2410_udc.c和s3c2410_udc.h文件中。下面的结构基本上每个UDC驱动程序都会实现,但具体实现的细节又不太相同。但万变不离其宗,宗就是上面介绍的基本gadget驱动数据结构,基本上UDC驱动程序自己实现的数据结构都是都这些基本数据结构的二次封装。a 设备结构struct s3c2410_udc        

13、    spinlock_t lock;          struct s3c2410_ep epS3C2410_ENDPOINTS;          int address;           struct usb_gadget gadget;   &

14、#160;       struct usb_gadget_driver *driver;          struct s3c2410_request fifo_req;           u8 fifo_bufEP_FIFO_SIZE;         

15、;  u16 devstatus;           u32 port_status;          int ep0state;           unsigned got_irq : 1;        

16、60;  unsigned req_std : 1;           unsigned req_config : 1;           unsigned req_pending : 1;           u8 vbus;     

17、;   struct dentry *regs_info;程序中对这个结构的初始化:static struct s3c2410_udc memory = .gadget =            .ops = &s3c2410_ops,                   

18、0; .ep0 = &memory.ep0.ep,                    .name = gadget_name,                     .dev =  &#

19、160;                              .init_name = "gadget",               

20、;      ,/* control endpoint */.ep0 = /struct s3c2410_ep             .num = 0,            .ep = /struct usb_ep        

21、60;              .name = ep0name,                       .ops = &s3c2410_ep_ops,       

22、                .maxpacket = EP0_FIFO_SIZE,                              , 

23、             .dev = &memory,            ,/* first group of endpoints */.ep1 =                .num = 1, 

24、60;             .ep =                            .name = "ep1-bulk",     &#

25、160;                     .ops = &s3c2410_ep_ops,                        

26、0; .maxpacket = EP_FIFO_SIZE,                         ,               .dev = &memory,   

27、60;           .fifo_size = EP_FIFO_SIZE,               .bEndpointAddress = 1,               .bmAttributes = US

28、B_ENDPOINT_XFER_BULK,             ,.ep2 =                    .num = 2,             &#

29、160;    .ep =                              .name = "ep2-bulk",            &

30、#160;                .ops = &s3c2410_ep_ops,                             .maxpack

31、et = EP_FIFO_SIZE,                      ,                    .dev = &memory,   &#

32、160;                .fifo_size = EP_FIFO_SIZE,                    .bEndpointAddress = 2,       

33、             .bmAttributes = USB_ENDPOINT_XFER_BULK,             ,.ep3 =                 .num = 3, &

34、#160;              .ep =                           .name = "ep3-bulk",     

35、                      .ops = &s3c2410_ep_ops,                        &#

36、160;  .maxpacket = EP_FIFO_SIZE,                        ,                  .dev = &memory,&

37、#160;                 .fifo_size = EP_FIFO_SIZE,                  .bEndpointAddress = 3,        

38、;          .bmAttributes = USB_ENDPOINT_XFER_BULK,                         ,.ep4 =         

39、0;      .num = 4,               .ep =                            .name = &q

40、uot;ep4-bulk",                           .ops = &s3c2410_ep_ops,                &

41、#160;        .maxpacket = EP_FIFO_SIZE,                      ,               .dev = &m

42、emory,               .fifo_size = EP_FIFO_SIZE,               .bEndpointAddress = 4,            

43、0;   .bmAttributes = USB_ENDPOINT_XFER_BULK,             ;不同的UDC,自定义的数据结构不同。但一般都有这样一个数据结构来表示UDC设备,对usb_gadget设备对象进行封装,并包含设备的所有端点。b 端点结构struct s3c2410_ep struct list_head queue;unsigned long last_io; /* jiffies timestamp */struct u

44、sb_gadget *gadget;struct s3c2410_udc *dev;const struct usb_endpoint_descriptor *desc;struct usb_ep ep; /封装的struct usb_ep结构u8 num;unsigned short fifo_size;u8 bEndpointAddress;u8 bmAttributes;unsigned halted : 1;unsigned already_seen : 1;unsigned setup_stage : 1;对usb_ep结构进行封装,并有一个queue队列来对该端口上的request

45、进行排队。c Request结构struct s3c2410_request struct list_head queue; /* ep's requests */struct usb_request req;对usb_request进行封装,queue变量进行队列排队。1 UDC驱动是作为platform driver向platform子系统注册的,因此UDC驱动首先就需要实现struct platform_driver结构中的函数成员:struct platform_driver         

46、60;  int (*probe)(struct platform_device *); /驱动和设备绑定           int (*remove)(struct platform_device *); /支持热插拔的设备移除           void (*shutdown)(struct platform_device *); /设备关闭   &

47、#160;       int (*suspend)(struct platform_device *, pm_message_t state); /电源管理相关,挂起设备           int (*resume)(struct platform_device *); /电源管理相关,恢复设备           struct de

48、vice_driver driver;          struct platform_device_id *id_table; /驱动和设备匹配信息;在下面的源码分析中以s3c2410_udc.c文件为例:static struct platform_driver udc_driver_2410 =           .driver =       &

49、#160;                   .name = "s3c2410-usbgadget",                        

50、0; .owner = THIS_MODULE,          ,        .probe = s3c2410_udc_probe,        .remove = s3c2410_udc_remove,        .suspend = s3c2410_udc_suspend,

51、0;       .resume = s3c2410_udc_resume,;其中以s3c2410_udc_probe和s3c2410_udc_remove函数最为重要,s3c2410_udc_probe函数实现驱动和设备的匹配绑定,并分配资源;而s3c2410_udc_remove函数实现资源的释放。static int s3c2410_udc_probe(struct platform_device *pdev)        struct s3c2410_ud

52、c *udc = &memory; /s3c2410的UDC设备,在其中对usb_gadget设备对象和端点等进行了初始化       struct device *dev = &pdev->dev;       int retval;      int irq;     /获取总线时钟并使能      

53、usb_bus_clock = clk_get(NULL, "usb-bus-gadget");        clk_enable(usb_bus_clock);     /获取设备时钟并使能      udc_clock = clk_get(NULL, "usb-device");       clk_enable(udc_clock

54、);      mdelay(10);       spin_lock_init (&udc->lock); /初始化设备的自旋锁       udc_info = pdev->dev.platform_data;        rsrc_start = S3C2410_PA_USBDEV; /s3c2410 UDC端口起始地址 

55、;      rsrc_len = S3C24XX_SZ_USBDEV; /s3c2410端口地址长度       if (!request_mem_region(rsrc_start, rsrc_len, gadget_name) /申请端口资源                   return -EBUS

56、Y;     base_addr = ioremap(rsrc_start, rsrc_len); /端口映射      if (!base_addr)                  retval = -ENOMEM;          

57、0;      goto err_mem;             device_initialize(&udc->gadget.dev); /初始化device设备对象      udc->gadget.dev.parent = &pdev->dev; /当前UDC设备的父设备对象是platform_device    u

58、dc->gadget.dev.dma_mask = pdev->dev.dma_mask;       the_controller = udc;    platform_set_drvdata(pdev, udc); /驱动和设备绑定,在platform_device结构中保存udc设备对象/*重新初始化设备*/s3c2410_udc_disable(udc);s3c2410_udc_reinit(udc);/* irq setup after old hardware state is c

59、leaned up */*申请中断,并绑定中断函数,中断函数是UDC功能驱动的入口函数*/retval = request_irq(IRQ_USBD, s3c2410_udc_irq, IRQF_DISABLED, gadget_name, udc);if (udc_info && udc_info->vbus_pin > 0)           retval = gpio_request(udc_info->vbus_pin, "udc vbus"

60、);                    irq = gpio_to_irq(udc_info->vbus_pin);                    retval = request_irq(irq, s

61、3c2410_udc_vbus_irq, IRQF_DISABLED | IRQF_TRIGGER_RISING| IRQF_TRIGGER_FALLING | IRQF_SHARED,gadget_name, udc);                         else        &#

62、160;           udc->vbus = 1;      if (s3c2410_udc_debugfs_root) /创建虚拟文件debugfs          udc->regs_info = debugfs_create_file("registers", S_IRUGO, s3c2410_udc

63、_debugfs_root,udc, &s3c2410_udc_debugfs_fops);          if (!udc->regs_info)                      dev_warn(dev, "debugfs file creation fai

64、ledn");dev_dbg(dev, "probe okn");return 0;err_gpio_claim:                   if (udc_info && udc_info->vbus_pin > 0)           

65、   gpio_free(udc_info->vbus_pin);err_int:        free_irq(IRQ_USBD, udc);err_map:          iounmap(base_addr);err_mem:          release_mem_region(rsrc_start, rsr

66、c_len);return retval;从s3c2410_udc_probe函数可以看出,probe函数主要完成的就是将platform_device设备对象和UDC设备对象建立关系,UDC设备和驱动的一些初始化工作,并申请驱动所需的资源,若端口区间、中断号等,并将中断函数和中断号绑定。这个中断处理函数非常重要,对这个设备的所有操作都将从中断函数入口。static int s3c2410_udc_remove(struct platform_device *pdev)          

67、60;  struct s3c2410_udc *udc = platform_get_drvdata(pdev); /获取UDC设备对象,在probe函数中绑定的             unsigned int irq;            if (udc->driver) /设备的驱动usb_gadget_driver对象,说明设备正在使用&#

68、160;                      return -EBUSY;          debugfs_remove(udc->regs_info); /移除debugfs文件系统中建立的文件       

69、60;  if (udc_info && udc_info->vbus_pin > 0)                           irq = gpio_to_irq(udc_info->vbus_pin);       &#

70、160;                  free_irq(irq, udc);                              

71、; free_irq(IRQ_USBD, udc); /释放中断           /*释放端口资源*/           iounmap(base_addr);           release_mem_region(rsrc_start, rsrc_len);  

72、60;       /*解除绑定*/           platform_set_drvdata(pdev, NULL);          /*释放时钟*/            if (!IS_ERR(udc_clock) &

73、& udc_clock != NULL)                               clk_disable(udc_clock);             

74、;                  clk_put(udc_clock);                              ud

75、c_clock = NULL;                          if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL)              

76、                   clk_disable(usb_bus_clock);                           &#

77、160;     clk_put(usb_bus_clock);                                  usb_bus_clock = NULL;    

78、0;                 dev_dbg(&pdev->dev, "%s: remove okn", _func_);          return 0;可以看出,remove函数基本上是probe函数的逆操作,将probe函数中申请的资源释放掉。2 UDC驱动程序还需要为上层实现usb_gadget_regi

79、ster_driver和usb_gadget_unregister_driver两个gadget driver注册接口,这两个函数将实现gadget driver和udc driver绑定。int usb_gadget_register_driver(struct usb_gadget_driver *driver)          struct s3c2410_udc *udc = the_controller; /UDC设备对象      

80、     int retval;         /* Sanity checks */          if (!udc)                      retur

81、n -ENODEV;        /*UDC设备只能绑定一个gadget driver对象*/         if (udc->driver)                   return -EBUSY;    &#

82、160;    /*检查gadget driver是否实现了绑定函数、setup函数。同时低速设备也不支持gadget driver*/        if (!driver->bind | !driver->setup| driver->speed < USB_SPEED_FULL)                

83、0;   printk(KERN_ERR "Invalid driver: bind %p setup %p speed %dn",driver->bind, driver->setup, driver->speed);                    return -EINVAL;     &

84、#160;            /支持卸载的话,还需要实现unbind函数         #if defined(MODULE)                   if (!driver->unbind)   

85、;                                printk(KERN_ERR "Invalid driver: no unbind methodn");        &

86、#160;                          return -EINVAL;                      &#

87、160;      #endif         /* Hook the driver */        /*将gadget driver和udc设备绑定*/           udc->driver = driver;      

88、;     udc->gadget.dev.driver = &driver->driver;           /* Bind the driver */           if (retval = device_add(&udc->gadget.dev) != 0) /完成gadget设备在内核中的注册 &

89、#160;                       printk(KERN_ERR "Error in device_add() : %dn",retval);                &#

90、160;       goto register_error;                     if (retval = driver->bind (&udc->gadget) != 0) /gadget驱动绑定函数       &

91、#160;            device_del(&udc->gadget.dev);                     goto register_error;         &#

92、160;        /* Enable udc */         /使能UDC设备         s3c2410_udc_enable(udc);          return 0;       &

93、#160; register_error:                   udc->driver = NULL;                   udc->gadget.dev.driver = NULL; 

94、                  return retval; /*gadget 驱动注销函数*/int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)             struct s3c2410_udc *u

95、dc = the_controller;             if (!udc)                        return -ENODEV;       &#

96、160;     /*驱动必须和注册时的驱动是一致的,同时实现了unbind函数*/             if (!driver | driver != udc->driver | !driver->unbind)                 

97、60;      return -EINVAL;             dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'n", driver->);             /*调用

98、gadget driver实现的unbind函数*/             driver->unbind(&udc->gadget);             device_del(&udc->gadget.dev); /和register函数中的device_add对应   

99、60;         udc->driver = NULL;/这个很重要,这里说明gadget驱动注销之后,才能移除udc设备             /* Disable udc */             /*关闭设备*/   

100、0;           s3c2410_udc_disable(udc);               return 0;  3 中断函数中断处理函数是UDC驱动层的核心函数,由于UDC是从设备,主机端是控制端,所有的操作都是主机端发起的,所以中断处理函数是UDC驱动层的核心函数。static irqreturn_t s3c2410_udc_ir

101、q(int dummy, void *_dev)              struct s3c2410_udc *dev = _dev; /UDC设备对象              int usb_status;          

102、60;   int usbd_status;              int pwr_reg;              int ep0csr;              int i;&#

103、160;             u32 idx;             unsigned long flags;             spin_lock_irqsave(&dev->lock, flags); 

104、;             /* Driver connected ? */             if (!dev->driver) /还没有和驱动绑定,清除中断               

105、0;                            /* Clear interrupts */                   

106、;                      udc_write(udc_read(S3C2410_UDC_USB_INT_REG), S3C2410_UDC_USB_INT_REG);                 

107、                         udc_write(udc_read(S3C2410_UDC_EP_INT_REG),S3C2410_UDC_EP_INT_REG);              

108、0;                 /* Save index */              idx = udc_read(S3C2410_UDC_INDEX_REG); /这是哪个端点产生中断的索引号         

109、60;     /* Read status registers */             usb_status = udc_read(S3C2410_UDC_USB_INT_REG); /UDC设备状态              usbd_status = udc_read(S3C2410_UDC_EP

110、_INT_REG); /UDC产生中断的端点状态               pwr_reg = udc_read(S3C2410_UDC_PWR_REG);                udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_IND

111、EX_REG);               ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);              dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02xn", usb_s

112、tatus, usbd_status, pwr_reg, ep0csr);                           /*                 &#

113、160; 开始中断的实际处理,这里的中断只有两种类型:                   1. UDC设备中断: 重置、挂起和恢复                   2. 端点中断    

114、0;           */                /* UDC设备RESET操作处理 */              if (usb_status & S3C2410_UDC_USBINT_RESET

115、) /Reset中断                                  /* two kind of reset :           

116、60;                       * - reset start -> pwr reg = 8                      

117、;             * - reset end -> pwr reg = 0                                

118、60;  */                                  dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %xn", ep0csr, pwr_reg);  

119、                                 dev->gadget.speed = USB_SPEED_UNKNOWN;           

120、                        udc_write(0x00, S3C2410_UDC_INDEX_REG);                    &#

121、160;              udc_write(dev->ep0.ep.maxpacket & 0x7ff) >> 3, S3C2410_UDC_MAXP_REG);                      

122、60;            dev->address = 0;                                   dev-&

123、gt;ep0state = EP0_IDLE;                                    dev->gadget.speed = USB_SPEED_FULL;    

124、0;                                /* clear interrupt */               

125、                     udc_write(S3C2410_UDC_USBINT_RESET, S3C2410_UDC_USB_INT_REG);                   

126、0;                udc_write(idx, S3C2410_UDC_INDEX_REG);                            &

127、#160;        spin_unlock_irqrestore(&dev->lock, flags);                                  

128、; return IRQ_HANDLED;                              /* UDC设备RESUME操作处理 */               if

129、(usb_status & S3C2410_UDC_USBINT_RESUME) /Resume中断                                         

130、      dprintk(DEBUG_NORMAL, "USB resumen");                                     

131、          /* clear interrupt */                                               udc_write(S3C2410_UDC_USBINT_RESUME, S3C24

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论