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等;
完成了这个功能以后,USB主机端系统就会设别出我们是一个什么样的设备。
. 实现数据交互功能
即如何实现向硬件控制器的端点发出读、写请求来完成数据交互;
. 具体功能的实现如:如何实现一个usb net驱动,或是一个usb storage驱动。
接下来以zero.c为例,说明这3个方面是如何实现的。
1、zero设备介绍
作为一个简单的 gadget 驱动,zero 的功能基于两个 BULK 端点实现了简单的输入输出功能, 它可以用作写新的 gadget 驱动的一个实例。
两个 BULK 端点为一个 IN 端点, 一个 OUT端点。基于这两个(由底层提供的)端点,g_zero 驱动实现了两个 configuration。 第一个 configuration 提供了 sink/source功能:两个端点一个负责输入,一个负责输出,其中输出的内容根据设置可以是全0,也可以是按照某种算法生成的数据。另一个 configuration 提供了 loopback 接口, IN 端点负责把从 OUT 端点收到的数据反馈给 Host.
2、zero设备注册、注销
static int __init init(void)
{
return usb_gadget_register_driver(&zero_driver);
}
module_init(init);
static struct usb_gadget_driver zero_driver = {
#ifdef CONFIG_USB_GADGET_DUALSPEE
.speed = USB_SPEED_HIGH,
#else
.speed = USB_SPEED_FULL,
#endif
.function = (char *) longname,
.bind = zero_bind,
.unbind = __exit_p(zero_unbind),
.setup = zero_setup,
.disconnect = zero_disconnect,
.suspend = zero_suspend,
.resume = zero_resume,
.driver = {
.name = (char *) shortname,
.owner = THIS_MODULE,
},
};
构建一个usb_gadget_driver,调用usb_gadget_register_driver注册函数即可注册一个usb gadget驱动。需要注意的是,目前S3C2410主机控制器只能注册一个gadget功能驱动。这主要是由协议决定的。参考s3c2410_udc.c中的这段代码
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{……
if (udc->driver)//如果已经注册过了
return -EBUSY;
……
}
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请求
另外,通过usb_ep_autoconfig函数,可以分配到名为EP_IN_NAME、EP_OUT_NAME两个端点。后面可以对两个端点发起数据传输请求,和USB 主机端的urb请求非常相似,大家可以和urb对照一些。
发起数据请求大致有以下几步:
struct usb_request *req;
req = alloc_ep_req(ep, buflen);//分配请求,数据传输的方向由ep本身决定
req->complete = source_sink_complete; //请求完成后的处理函数
status = usb_ep_queue(ep, req, GFP_ATOMIC);//递交请求
free_ep_req(ep, req);//释放请求,通常在请求处理函数complete中调用
. 通常在bind和unbind函数中注册具体的功能驱动
如果为了实现某个特定功能需要在设备端注册字符、块、网络设备驱动的话,选择的场
合通常是bind中注册,unbind中卸载。如ether.c文件中:
static int __init
eth_bind (struct usb_gadget *gadget)
{
……
status = register_netdev (dev->net); //注册网卡驱动
……
}
static void /* __init_or_exit */
eth_unbind (struct usb_gadget *gadget)
{
……
unregister_netdev (dev->net); //注销网卡驱动
……
}
这也让我们对在设备端实现一个字符、块、网络驱动的结构有了一些了解。
总结
本文对gadget的驱动结构做了简要的介绍。下一篇将介绍如何编写一个简单的gadget驱动及应用测试程序。
“本文由www.5idzw.comhttp://www.5idzw.com提供”
,USB gadget设备驱动解析(3)