开启辅助访问
 找回密码
 立即注册

USB设备驱动开发-USB Gadget Driver(1)

woaieb 回答数0 浏览数427
USB设备驱动开发-USB Gadget Driver(一)

一、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变量进行队列排队。
当贝投影