usb设备驱动程序usb gadget driver(4)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
USB设备驱动程序-USB Gadget Driver(4) 
Gadget 功能层Gadget功能层完成USB设备的具体功能,其表现的形式各不相同,如键盘、鼠标、存储和网卡等等。
功能层不仅涉及到Gadget驱动相关的内容,还涉及到其功能相关的内核子系统。
如存储还涉及到内核存储子系统,网卡还涉及到网络驱动子系统。
因此,Gadget功能的代码非常复杂。
这里以zero.c为例,这个模块只是简单地将接收的数据回显回去。
一、数据结构首先需要实现
usb_composite_driver函数集:static struct
usb_composite_driver zero_driver =
{ .name =
"zero", .dev =
&device_desc, .strings =
dev_strings, .bind =
zero_bind, .unbind =
zero_unbind, .suspend =
zero_suspend, .resume =
zero_resume, }; 二、主要函数这个模块的实现就是这么简单:static int __init init(void)
{ return
usb_composite_register(&zero_driver); }
module_init(init); static void __exit cleanup(void)
{ usb_composite_unregister(&zero_driver);
} Bind函数是功能层需要实现与设备层关联的重要函数:static int __init zero_bind(struct usb_composite_dev *cdev) { int gcnum;
struct usb_gadget *gadget = cdev->gadget; //Gadget设备
int id; /* Allocate string descriptor numbers ... note that string * contents can be overridden by the composite_dev glue.
*/ /*分配字符串描述符的id,并赋值给设备描述符中字符串索引*/ id = usb_string_id(cdev); strings_dev[STRING_MANUFACTURER_IDX].id = id; device_desc.iManufacturer = id; id =
usb_string_id(cdev); i
strings_dev[STRING_PRODUCT_IDX].id = id;
device_desc.iProduct = id; id =
usb_string_id(cdev);
strings_dev[STRING_SERIAL_IDX].id = id;
device_desc.iSerialNumber = id; /*设置挂起后,设备自动恢复的定时器*/
setup_timer(&autoresume_timer, zero_autoresume, (unsigned long) cdev); /*核心代码,实现
功能*/ if (loopdefault)
{ loopback_add(cdev, autoresume != 0); //数据简单回显功能
if (!gadget_is_sh(gadget))
sourcesink_add(cdev, autoresume != 0); } else
{ sourcesink_add(cdev, autoresume != 0); if
(!gadget_is_sh(gadget))
loopback_add(cdev, autoresume != 0); } /*初始化设备描述符*/ gcnum =
usb_gadget_controller_number(gadget); if (gcnum >= 0)
device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
else { device_desc.bcdDevice = cpu_to_le16(0x9999); } return 0; } /*增加数据简单回显功能*/ int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume) { int id;
/*获取字符串描述符id索引*/
id = usb_string_id(cdev);
strings_loopback[0].id = id;
loopback_intf.iInterface = id;
loopback_driver.iConfiguration = id;
/* support autoresume for remote wakeup testing */
if (autoresume)
sourcesink_driver.bmAttributes |=
USB_CONFIG_ATT_WAKEUP;
/* support OTG systems */ if (gadget_is_otg(cdev->gadget))
{
loopback_driver.descriptors = otg_desc;
loopback_driver.bmAttributes |=
USB_CONFIG_ATT_WAKEUP;
} return
usb_add_config(cdev, &loopback_driver); //增加一个配置} /*loopback配置*/ static struct usb_configuration loopback_driver = { .label = "loopback", .strings = loopback_strings, .bind = loopback_bind_config, .bC onfigurationValue =
2, .bmAttributes =
USB_CONFIG_ATT_SELFPOWER,
/* .iConfiguration = DYNAMIC */ }; 将增加配置的
usb_add_config函数中会调用其bind函数,即
loopback_bind_config函数,来分配这个配置所需要的资源。
struct f_loopback { struct
usb_function function; struct usb_ep *in_ep; struct usb_ep *out_ep; }; static int __init loopback_bind_config(struct usb_configuration *c)
{ struct f_loopback *loop; int status; loop =
kzalloc(sizeof *loop, GFP_KERNEL); //分配一个loop结构
if (!loop)
return -ENOMEM; /*初始化一个功能*/
loop-> = "loopback";
loop->function.descriptors = fs_loopback_descs;
loop->function.bind = loopback_bind;
loop->function.unbind = loopback_unbind;
loop->function.set_alt = loopback_set_alt;
loop->function.disable = loopback_disable;
status = usb_add_function(c, &loop->function); //加入这个功能if (status)
kfree(loop); return status; } 在usb_add_function函数中,又会调用这个功能的bind函数,即loopback_bind函数:static int __init
loopback_bind(struct usb_configuration *c, struct usb_function *f) { struct usb_composite_dev *cdev = c->cdev; struct
f_loopback *loop = func_to_loop(f);
int id; /* allocate interface ID(s) */ id = usb_interface_id(c, f); //分配一个接口id
if (id < 0) return id; loopback_intf.bInterfaceNumber = id; /* allocate endpoints */
/*返回一个输入端点*/
loop->in_ep = usb_ep_autoconfig(cdev->gadget,
&fs_loop_source_desc); if (!loop->in_ep)
{ autoco nf_fail:
ERROR(cdev, "%s: can't autoconfigure on %s\n", f->name, cdev->gadget->name);
return -ENODEV; }
loop->in_ep->driver_data = cdev; /* claim */
/*返回一个输出端点,返回合适的端点*/
loop->out_ep = usb_ep_autoconfig(cdev->gadget,
&fs_loop_sink_desc); if
(!loop->out_ep)
goto autoconf_fail;
loop->out_ep->driver_data = cdev; /* claim */
/* support high speed hardware */
if (gadget_is_dualspeed(c->cdev->gadget))
{
hs_loop_source_desc.bEndpointAddress =
fs_loop_source_desc.bEndpointAddress;
hs_loop_sink_desc.bEndpointAddress =
fs_loop_sink_desc.bEndpointAddress;
f->hs_descriptors =
hs_loopback_descs; }
DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",f->name, loop->in_ep->name,
loop->out_ep->name); return 0; } 功能的实现Loopback_set_alt函数将在设备层的setup函数中被调用,控制通信设置接口。
static int
loopback_set_alt(struct usb_function *f, unsigned intf, unsigned
alt) { struct f_loopback *loop = func_to_loop(f); struct
usb_composite_dev *cdev = f->config->cdev;
/* we know alt is zero */ if
(loop->in_ep->driver_data)
disable_loopback(loop); return enable_loopback(cdev, loop); //开启功能} static int enable_loopback(struct usb_composite_dev *cdev, struct
f_loopback *loop) { int result = 0; const struct
usb_endpoint_descriptor *src, *sink;
struct usb_ep *ep; struct
usb_request *req; unsigned i; /*选择端点描述符*/ src =
ep_choose(cdev->gadget, &hs_loop_source_desc,
&fs_loop_source_desc); sink = ep_choose(cdev->gadget, &hs_loop_sink_desc,
&fs_loop_sink_desc); /* one endpoint writes data back IN to the host */
/*输入输出端点使能*/ ep = loop->in_ep; result =
usb_ep_enable(ep, src); if (result
< 0)
return result; ep->driver_data = loop; /* one endpoint just reads OUT packets */ ep =
loop->out_ep; result =
usb_ep_enable(ep, sink); if (result < 0)
{ fa il0:
ep = loop->in_ep;
usb_ep_disable(ep);
ep->driver_data = NULL;
return result; }
ep->driver_data = loop; /* allocate a bunch of read buffers and queue them all at once.
* we buffer at most 'qlen' transfers; fewer if any need more
* than 'buflen' bytes each. */
/*qlen=32,分配32个请求,将这个请求放入输出端点队列,等待接收数据*/ for (i = 0; i
< qlen && result == 0; i++)
{
req = alloc_ep_req(ep);
if (req)
{
req->complete = loopback_complete; result = usb_ep_queue(ep, req, GFP_ATOMIC);
if (result)
ERROR(cdev, "%s queue req --> %d\n", ep->name, result);
}
else
{
usb_ep_disable(ep);
ep->driver_data = NULL;
result = -ENOMEM;
goto
fail0;
} }
DBG(cdev, "%s enabled\n", loop->);
return result; } /*接收到数据之后,将调用这个完成函数*/ static void loopback_complete(struct usb_ep *ep, struct usb_request *req) { struct
f_loopback *loop = ep->driver_data;
struct usb_composite_dev *cdev =
loop->function.config->cdev;
int status = req->status; switch (status) { case 0: /* normal completion? */
if (ep == loop->out_ep) { //将接收到的数据放入输入端点,返回给主机
/* loop this OUT packet back IN to the host */
req->zero = (req->actual < req->length);
req->length = req->actual;
status = usb_ep_queue(loop->in_ep, req, GFP_ATOMIC);
if (status == 0)
return;
/* "should never get here" */
ERROR(cdev, "can't loop %s to %s: %d\n", ep->name,
loop->in_ep->name,status);
}
/* queue the buffer for some later OUT packet */
req->length = buflen; //将输入端点完成的申请,重新放入输出队列,等待接收新的数据
status = usb_ep_queue(loop->out_ep, req, GFP_ATOMIC); if (status == 0)
return; /* "should
never get here" */
/* FALLTHROUGH */ default: ERROR(cdev, "%s loop complete --> %d, %d/%d\n",
ep->name, status, req->actual, req->length);
/* FALLTHROUGH */
/* NOTE: since this driver doesn't maintain an explicit record * of requests it submitted (just maintains qlen count), we
* rely on the hardware driver to clean up on disconnect or
* endpoint disable.
*/ case -ECONNABORTED: /* hardware forced ep reset */ case
-ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
free_ep_req(ep, req);
return; } }。