linux usb 驱动程序开发,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变量进行队列排队。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值