分类: LINUX
2013-10-11 14:30:43
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变量进行队列排队。