USB gadget设备驱动解析(3)
时间:2016-12-29作者:华清远见
Linux USB 设备端驱动有两部分组成。一部分是USB 设备控制器(USB Device Controller, UDC)驱动、另一部分是硬件无关的功能驱动(如:鼠标、u盘、usb串口、usb网络等);也可以分为3层的,分别是:Controller Drivers、Gadget Drivers、Upper Layers,大概意思都差不多。 一、控制器(USB Device Controller, UDC)驱动 Gadget 框架提出了一套标准 API, 在底层, USB 设备控制器驱动则实现这一套 API, 不同的 UDC需要不同的驱动, 甚至基于同样的 UDC 的不同板子也需要进行代码修改。这一层是硬件相关层。
Linux 标准内核里支持各种主流 SOC 的 udc 驱动,如:S3C2410、PXA270等。你可以通过内核直接配置支持。你也可以通过修改它们获取更高的效率。如:s3c2410_uda.c 中并没有利用到控制器的dma功能,你可以根据需要修改它。 下面给出在UDC驱动中涉及到的一些关键数据结构及API,参考s3c2410_uda.c 1.关键的数据结构及API gadget api 提供了usb device controller 驱动和上层gadget驱动交互的接口。下面列出一些关键的数据结构。
struct usb_gadget {//代表一个UDC设备
struct usb_gadget_driver {//代表一个gadget设备driver,如:file_storage.c中的fsg_driver
/* FIXME support safe rmmod */
struct usb_gadget_ops {//代表设备的操作集
struct usb_ep {//代表一个端点
struct usb_request {//表示一个传输的请求,这与usb host端的urb类似
上述结构中具体每项的含义可以参考//tali.admingilde.org/linux-docbook/gadget/ 在//tali.admingilde.org/linux-docbook/gadget/re02.html中 Name struct usb_request — describes one i/o request Synopsis
struct usb_request { Members buf Buffer used for data. Always provide this; some controllers only use PIO, or don't use DMA for some endpoints. length Length of that data dma DMA address corresponding to 'buf'. If you don't set this field, and the usb controller needs one, it is responsible for mapping and unmapping the buffer. no_interrupt If true, hints that no completion irq is needed. Helpful sometimes with deep request queues that are handled directly by DMA controllers. zero If true, when writing data, makes the last packet be “short” by adding a zero length packet as needed; short_not_ok When reading data, makes short packets be treated as errors (queue stops advancing till cleanup). complete Function called when request completes, so this request and its buffer may be re-used. Reads terminate with a short packet, or when the buffer fills, whichever comes first. When writes terminate, some data bytes will usually still be in flight (often in a hardware fifo). Errors (for reads or writes) stop the queue from advancing until the completion function returns, so that any transfers invalidated by the error may first be dequeued. context For use by the completion callback list For use by the gadget driver. status Reports completion code, zero or a negative errno. Normally, faults block the transfer queue from advancing until the completion callback returns. Code “-ESHUTDOWN” indicates completion caused by device disconnect, or when the driver disabled the endpoint. actual Reports bytes transferred to/from the buffer. For reads (OUT transfers) this may be less than the requested length. If the short_not_ok flag is set, short reads are treated as errors even when status otherwise indicates successful completion. Note that for writes (IN transfers) some data bytes may still reside in a device-side FIFO when the request is reported as complete. Description These are allocated/freed through the endpoint they're used with. The hardware's driver can add extra per-request data to the memory it returns,whichoften avoids separate memory allocations (potential failures), later when the request is queued. Request flags affect request handling, such as whether a zero length packet is written (the “zero” flag), whether a short read should be treated as anerror (blocking request queue advance, the “short_not_ok” flag), or hinting that an interrupt is not required (the “no_interrupt” flag, for use with deeprequest queues). Bulk endpoints can use any size buffers, and can also be used for interrupt transfers. interrupt-only endpoints can be much less functional. 2、为USB gadget功能驱动提供的注册、注销函数 EXPORT_SYMBOL(usb_gadget_unregister_driver); //注销一个USB gadget功能驱动 EXPORT_SYMBOL(usb_gadget_register_driver);//注册一个USB gadget功能驱动 二、USB gadget功能驱动 如果内核已经支持了SOC的UDC驱动,很多时候,我们可以只关心这部分代码的编写。那么我们如何编写出一个类似usb 功能驱动呢? usb 功能驱动应该至少要实现如下功能:
. 实现USB协议中端点0部分和具体功能相关的部分(UDC驱动无法帮我们完成的部分)。如:USB_REQ_GET_DESCRIPTOR、USB_REQ_GET_CONFIGURATION等; 1、zero设备介绍
作为一个简单的 gadget 驱动,zero 的功能基于两个 BULK 端点实现了简单的输入输出功能, 它可以用作写新的 gadget 驱动的一个实例。
2、zero设备注册、注销
static struct usb_gadget_driver zero_driver = { 构建一个usb_gadget_driver,调用usb_gadget_register_driver注册函数即可注册一个usb gadget驱动。需要注意的是,目前S3C2410主机控制器只能注册一个gadget功能驱动。这主要是由协议决定的。参考s3c2410_udc.c中的这段代码
int usb_gadget_register_driver(struct usb_gadget_driver *driver) 3、usb_gadget_driver结构 事实上我们的工作就是构建这个usb_gadget_driver结构。那么这个结构这样和我们上面要实现的3个目标联系起来呢。 . Setup (zero_setup) 处理host端发来的request,如:处理host端发来的get_descriptor请求。 在这实现了前面提到的必须要实现的第一个功能。 . bind (zero_bind)
绑定dev与driver,在gadget driver,注册驱动时被usb_gadget_register_driver调用,绑定之后driver才能处理setup请求
struct usb_request *req; . 通常在bind和unbind函数中注册具体的功能驱动
如果为了实现某个特定功能需要在设备端注册字符、块、网络设备驱动的话,选择的场
这也让我们对在设备端实现一个字符、块、网络驱动的结构有了一些了解。 总结 本文对gadget的驱动结构做了简要的介绍。下一篇将介绍如何编写一个简单的gadget驱动及应用测试程序。
相关资讯
发表评论
|