打印

USB从设备驱动 转

[复制链接]
2249|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
无语凝咽|  楼主 | 2010-1-19 21:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 无语凝咽 于 2010-1-19 21:19 编辑

最近在做Linux下USB从设备的驱动,程序写的差不多了,做一个整理小结。欢迎交流,如有错误请指正,谢谢!--Jason
一、USB从设备驱动介绍
USB总线上主要有三类设备:主控制器(Host Controller, such as EHCI、UHCI、OHCI)、集线器(hub)和设备(device)。Host controller(HC)负责总线的管理,是总线的指挥官,总线上一切传输都是由HC发起的,支持OTG的Device也能发起传输;Hub是总线的节点,用来扩展总线上可接入设备的数量,对于驱动来说是透明的;Device就是各种各样的设备了,每个设备都有自己的功能,比如U盘、USB摄像头等等。


Linux下主机端USB设备的驱动(device driver)编写的资料有很多,LDD3中有相应的介绍。主要是通过内核中USB core这个模块与设备交互。本文只介绍运行Linux的嵌入式USB设备驱动的编写。因为Host端已经使用了device driver一词,为了避免混淆,使用USB gadget driver一次表示从设备驱动。In USB protocol interactions, the device driver is the master (or client driver) and the gadget driver is the slave (or function driver).
Linux USB gadget driver API定义了一个通用的gadget driver的接口,gadget driver通过API与底层USB controller driver通信。该API屏蔽了底层硬件的不同,使gadget driver注重功能的实现,尽量与硬件无关。Slave端系统的架构如下图所示:

其中,gadgetfs提供给用户空间程序直接与USB device controller交互的能力。
二、相关资料
USB gadget API Layer的相关资料:
1. http://www.linux-usb.org/gadget/
2. 内核中/KernelDoc/gadget/目录下的文档
3.最重要的就是/include/linux/usb_gadget.h文件,该文件中有gadget API接口数据结构和方法的详细定义及注释。
Gadget Driver的例子:
4. 内核/drivers/usb/gadget/目录下有一些gadget driver的例子,zero.c为最简单的例子,file_storage.c是存储设备的gadget driver。

相关帖子

沙发
无语凝咽|  楼主 | 2010-1-19 21:20 | 只看该作者
三、gadget API

要了解gadget API,只需要理解头文件(usb_gadget.h)中几个重要的数据结构就可以了。详细的字段介绍看h文件注释。

(1)

struct usb_gadget {

const struct usb_gadget_ops *ops;

struct usb_ep                *ep0;


struct list_head              ep_list;

enum usb_device_speed        speed;

unsigned                is_dualspeed:1;

unsigned                is_otg:1;

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;

};

该结构表示一个USB device controller(UDC),在udc driver中初始化,它对gadget driver是只读的。

(2)

struct usb_gadget_driver {

char               *function;

enum usb_device_speed speed;

int                  (*bind)(struct usb_gadget *);

void               (*unbind)(struct usb_gadget *);

int                  (*setup)(struct usb_gadget *,

const struct usb_ctrlrequest *);

void               (*disconnect)(struct usb_gadget *);

void               (*suspend)(struct usb_gadget *);

void               (*resume)(struct usb_gadget *);

struct device_driver       driver;

};

这个结构表示我们的gadget驱动,其中的函数需要在gadget driver中实现,是编码的重点之一。具体实现可参考zero.c文件,下面简单介绍一下各个函数的功能:

Bind中主要执行gadget driver的初始化,它会被usb_gadget_register_driver函数调用,而usb_gadget_register_driver一般在模块初始化时调用。usb_gadget_register_driver执行完之后,device可以被主机探测到。

Unbind与bind相反,被usb_gadget_unregister_driver调用。

Setup处理主机发过来的request,例如读decriptors,配置configuration等。因此,setup函数中一般包含switch,case语句。

Disconnect在设备与主机断开时被调用。

(3)

struct usb_request {

void               *buf;

unsigned         length;

dma_addr_t           dma;

unsigned         no_interrupt:1;

unsigned         zero:1;

unsigned         short_not_ok:1;

void               (*complete)(struct usb_ep *ep,

struct usb_request *req);

void               *context;

struct list_head       list;

int                  status;

unsigned         actual;

};

usb_request 表示一个传输的请求,与host端的urb很相似。它有一个complete字段,指定当request完成时的回调函数。

(4)

struct usb_ep {

void               *driver_data;

const char             *name;

const struct usb_ep_ops       *ops;

struct list_head       ep_list;

unsigned         maxpacket:16;

};

struct usb_ep 表示一个端点(EP),usb_gadget中有所有EP的list。

(5)

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);

void *(*alloc_buffer) (struct usb_ep *ep, unsigned bytes,

dma_addr_t *dma, gfp_t gfp_flags);

void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma,

unsigned bytes);

// NOTE:  on 2.6, drivers may also use dma_map() and

// dma_sync_single_*() to directly manage dma overhead.

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 (*fifo_status) (struct usb_ep *ep);

void (*fifo_flush) (struct usb_ep *ep);

};

struct usb_ep_ops表示端点的操作,其中queue函数将一个usb_request提交给某个EndPoint,是进行数据传输的关键函数。

四、总结

本文是自己对学习使用Gadget API的一些总结,记录下来以防时间一长就忘记了。

使用特权

评论回复
板凳
gongtengxinyi| | 2010-1-20 11:43 | 只看该作者
http://www.linux-usb.org/gadget/全英文的,没有中文的吗

使用特权

评论回复
地板
亦正亦邪| | 2010-1-20 11:55 | 只看该作者
了解了gadget API,多谢分享

使用特权

评论回复
5
Massif123| | 2010-1-20 13:09 | 只看该作者
谢谢分享

使用特权

评论回复
6
LPC300| | 2010-1-20 20:34 | 只看该作者
发现这个更简洁先,入门的人可以先看这个,然后看我发的那个!学习驱动就是先不 管事什么 ,先认识它在干什么就行!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

88

主题

399

帖子

1

粉丝