FROM:http://blog.chinaunix.net/uid-14518381-id-3942425.html

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,

.bConfigurationValue = 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->function.name = "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) {

autoconf_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) {

fail0:

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->function.name);

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;

}

}

USB设备驱动程序-USB Gadget Driver(四)相关推荐

  1. USB协议与Windows USB设备驱动程序笔记

    USB概述 USB主控制器负责数据处理,USB根集线器(ROOT HUB)提供一个连接USB主控制器与USB设备之间的接口和通路.USB集线器(USB HUB)可以对原有的USB端口在数量上进行扩展. ...

  2. 转-用Driver Studio工具包开发WDM型的USB设备驱动程序

    前文所提及的WDM驱动程序开发方法,笔者都曾尝试过.个人认为用DriverStudio开发工具包来开发USB驱动程序行之有效.其中的Driver Wizard是创建WDM驱动程序框架的一个很好的工具, ...

  3. usb扫描枪驱动下载 wince_wince下USB设备驱动程序

    随着USB设备的不断增加,我们这些开发人员也就多了对USB设备进行驱动程序开发的工作.但是对于很多初学者来说,存在以下三个困难: 一是对WinCE的驱动程序结构了解得太少,没办法得心应手的专注于驱动程 ...

  4. 嵌入式linux查看usb设备驱动程序,嵌入式Linux下USB驱动程序的设计

    嵌入式Linux下USB驱动程序的设计 usb概念:  USB(Universal Serial Bus)即通用串行总线,是一种全新的双向同步传输的支持热插拔的数据传输总线,其目的是为了提供一种兼容不 ...

  5. 开发WDM型USB设备驱动程序(一)

    摘要 本文介绍WDM型USB设备驱动程序的基本概念.结构和特性,并说明了利用Driverworks进行开发的方法. 关键词 WDM:USB设备驱动程序:Driverworks 导言 通用串行总线USB ...

  6. USB设备驱动程序导读(4)

            在上次了解了所有USBD接口函数以后,我们已经有了很多基础知识了,回顾USB样例的文件夹结构,我们还能记得USB/CLASS/COMMON这个文件夹下是存放所公共部分的源程序,它是微软 ...

  7. USB设备驱动程序导读(9)

            以Bot.c文件中的BOT_DataTransfer()函数为例,在这个函数中,读写操作全部是调用了IssueBulkTransfer()函数,这个函数是由USBD提供的接口并且被us ...

  8. 【远程访问与设备重定向】上海道宁为您助您远程共享USB设备与USB设备重定向到远程会话

    USB over Network用于 通过LAN或Internet 与远程USB设备进行通信 远程USB设备可供多个用户共享 当您连接远程共享USB设备时 它们会被识别为 直接连接到本地计算机 USB ...

  9. 【USB笔记】 USB设备请求USB Device Requests

    USB笔记 USB设备请求USB Device Requests 所有USB设备都会响应主机向设备默认控制管道(Control Pipe)上发送的请求(requests). 这些请求是使用控制传输(c ...

最新文章

  1. Linux控制Bash输出的格式与颜色
  2. 在ctex环境下利用Metapost作图
  3. 每日一皮:发现程序员经常熬夜有三个弊端!
  4. Longest Palindromic Substring Part II
  5. python数字排序 循环_【python-leetcode448-循环排序】找到所有数组中消失的数字
  6. StringUtils 中 isEmpty 和 isBlank 的区别
  7. python实现中文繁体字与简体字转换
  8. java dem数据格式解析_【转载】DEM数据的介绍,获取,处理
  9. git difftool 使用 p4merge,DiffMerge 或者 Beyond Compare 4
  10. 什么是人工智能(AI)数据平台?
  11. fullcalendar实现日程增、删、改、查
  12. FastDB 磁盘和无盘模式
  13. 分块矩阵的逆矩阵的公式记忆方法
  14. html5取消backspace后退功能,js屏蔽退格键(backspace或者叫后退键与F5)
  15. Java面试基础(二)
  16. 分裂基 c语言算法,分裂基快速傅里叶变换 - osc_v8jmwk6w的个人空间 - OSCHINA - 中文开源技术交流社区...
  17. SoviChart数据可视化:条形图(Bar chart)
  18. 什么情况下我可以认为我就是我最大的骄傲
  19. 多文件断点续传,上传视频自动转MP4和截图,图片格式转换
  20. 那是计算机房吗英语否定回答,【微课+教材+听力+知识点】PEP四年级英语下册 Unit 1...

热门文章

  1. PS~了解PS的第一步,基本操作
  2. 块级元素中设置行书HTML,书法元素在平面设计中的运用.docx
  3. 程序员薪酬榜来了!这9类程序员上榜:AI第1 全栈第3,你排第几?
  4. YOLOv5-Lite:NCNN+Int8部署和量化,树莓派也可实时
  5. 什么是内存屏障?具有什么作用?
  6. 乐千业:税务筹划对企业的经营到底有多重要呢
  7. 赵小楼《天道》《遥远的救世主》深度解析(77)叶、冯、刘三人用了丁元英,就用了他的一切,没有能力的时候还谈什么缘,攀缘没有对错,起码得先活着
  8. 单基因gsea_零代码5分+的单基因综合分析
  9. 手机端别用谷歌了,好用到爆的小众浏览器你确定不试试
  10. oracle SQL先按字母排序再按数字排序