Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1945826
  • 博文数量: 1000
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 7921
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-20 09:23
个人简介

storage R&D guy.

文章分类

全部博文(1000)

文章存档

2019年(5)

2017年(47)

2016年(38)

2015年(539)

2014年(193)

2013年(178)

分类: LINUX

2015-05-17 21:02:52

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

阅读(782) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~