一、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包进行缓冲,这些请求可以被提交和取消。它们的结构、消息和常量的定义也和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不在其中 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,但操作端点的函数由端点操作函数集完成 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) (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 *);//卸载驱动时调用,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 device_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; //当输出的最后一个数据包不够长度是是否填充0 unsigned short_not_ok:1; //当接收的数据不够指定长度时,是否报错 void (*complete)(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 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 (*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) (struct 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_unregister_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 { spinlock_t lock; struct s3c2410_ep ep[S3C2410_ENDPOINTS]; int address; struct usb_gadget gadget; struct usb_gadget_driver *driver; struct s3c2410_request fifo_req; u8 fifo_buf[EP_FIFO_SIZE]; u16 devstatus; u32 port_status; int ep0state; unsigned got_irq : 1; unsigned req_std : 1; unsigned req_config : 1; unsigned req_pending : 1; u8 vbus; struct dentry *regs_info; }; 程序中对这个结构的初始化: static struct s3c2410_udc memory = { .gadget = { .ops = &s3c2410_ops, .ep0 = &memory.ep[0].ep, .name = gadget_name, .dev = { .init_name = "gadget", }, }, /* control endpoint */ .ep[0] = { //struct s3c2410_ep .num = 0, .ep = {//struct usb_ep .name = ep0name, .ops = &s3c2410_ep_ops, .maxpacket = EP0_FIFO_SIZE, }, .dev = &memory, }, /* first group of endpoints */ .ep[1] = { .num = 1, .ep = { .name = "ep1-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, .bEndpointAddress = 1, .bmAttributes = USB_ENDPOINT_XFER_BULK, }, .ep[2] = { .num = 2, .ep = { .name = "ep2-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, .bEndpointAddress = 2, .bmAttributes = USB_ENDPOINT_XFER_BULK, }, .ep[3] = { .num = 3, .ep = { .name = "ep3-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, .bEndpointAddress = 3, .bmAttributes = USB_ENDPOINT_XFER_BULK, }, .ep[4] = { .num = 4, .ep = { .name = "ep4-bulk", .ops = &s3c2410_ep_ops, .maxpacket = EP_FIFO_SIZE, }, .dev = &memory, .fifo_size = EP_FIFO_SIZE, .bEndpointAddress = 4, .bmAttributes = USB_ENDPOINT_XFER_BULK, } }; 不同的UDC,自定义的数据结构不同。但一般都有这样一个数据结构来表示UDC设备,对usb_gadget设备对象进行封装,并包含设备的所有端点。 b. 端点结构 struct s3c2410_ep { struct list_head queue; unsigned long last_io; /* jiffies timestamp */ struct usb_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进行排队。 c. Request结构 struct s3c2410_request { struct list_head queue; /* ep's requests */ struct usb_request req; }; 对usb_request进行封装,queue变量进行队列排队。
|