windows上面对usb复合设备的识别需要下面条件。

如果设备满足下列要求,则总线驱动程序还会报告 USB\COMPOSITE 的兼容标识符:

  • 设备描述符的设备类字段 (bDeviceClass) 必须包含一个零值,或者设备描述符的类 (bDeviceClass)、子类 (bDeviceSubClass) 和协议 (bDeviceProtocol) 字段必须分别具有值 0xEF、0x02 和 0x01,如 USB 接口关联描述符中所述。

  • 设备必须具有多个接口。

  • 设备必须具有一个配置。“

引用自:http://msdn.microsoft.com/zh-cn/library/ff537109

下面是linux /driver/usb/gadget/mass_storage.c 中定义的设备描述符:

 static struct usb_device_descriptor msg_device_desc = {
.bLength = sizeof msg_device_desc,
.bDescriptorType = USB_DT_DEVICE, .bcdUSB = cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_PER_INTERFACE, /* Vendor and product id can be overridden by module parameters. */
.idVendor = cpu_to_le16(FSG_VENDOR_ID),
.idProduct = cpu_to_le16(FSG_PRODUCT_ID),
/* .bcdDevice = f(hardware) */
/* .iManufacturer = DYNAMIC */
/* .iProduct = DYNAMIC */
/* NO SERIAL NUMBER */
.bNumConfigurations = ,
};

其中:

.bDeviceClass = USB_CLASS_PER_INTERFACE,

即为0,
注意到其实mass storage类是被定义为:
#define USB_CLASS_MASS_STORAGE 8 
没有给.bDeviceClass 赋值为8,这样gadget 设备就会在windows上识别时获得 USB\COMPOSITE 的兼容标识符
 /*
* Device and/or Interface Class codes
* as found in bDeviceClass or bInterfaceClass
* and defined by www.usb.org documents
*/
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
#define USB_CLASS_PHYSICAL 5
#define USB_CLASS_STILL_IMAGE 6
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_CDC_DATA 0x0a
#define USB_CLASS_CSCID 0x0b /* chip+ smart card */
#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
#define USB_CLASS_MISC 0xef
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff #define USB_SUBCLASS_VENDOR_SPEC 0xff

上面那个结构体中:

.idVendor = cpu_to_le16(FSG_VENDOR_ID),

.idProduct = cpu_to_le16(FSG_PRODUCT_ID),

如果不做修改,windows会直接找到通用的mass sotrage驱动 ,而不会加载USB 通用父驱动程序 (Usbccgp.sys),就不会i识别成复合设备,而是直使用设备的第一个接口,设备管理器只看到一个设备。

widows的机制不是很了解

参考:http://msdn.microsoft.com/zh-cn/library/ff537109

我这里改成

.idVendor =             cpu_to_le16(0x022b),

.idProduct = cpu_to_le16(0x1234),

然后增加一个接口,即设备两个接口同时

static int fsg_add(struct usb_composite_dev *cdev,
struct usb_configuration *c,
struct fsg_common *common)
{
struct fsg_dev *fsg;
int rc; fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
if (unlikely(!fsg))
return -ENOMEM; fsg->function.name = FSG_DRIVER_DESC;
fsg->function.strings = fsg_strings_array;
fsg->function.bind = fsg_bind;
fsg->function.unbind = fsg_unbind;
fsg->function.setup = fsg_setup;
fsg->function.set_alt = fsg_set_alt;
fsg->function.disable = fsg_disable; fsg->common = common;
/* Our caller holds a reference to common structure so we
* don't have to be worry about it being freed until we return
* from this function. So instead of incrementing counter now
* and decrement in error recovery we increment it only when
* call to usb_add_function() was successful. */ rc = usb_add_function(c, &fsg->function);
if (unlikely(rc))
kfree(fsg);
else
fsg_common_get(fsg->common);
struct f_sourcesink *ss;
int status; ss = kzalloc(sizeof *ss, GFP_KERNEL);
if (!ss)
return -ENOMEM;
init_completion(&ss->gdt_completion);
ss->function.name = "source/sink"; //就是f_sourcesink.c中的接口,gadget zero中使用那个
ss->function.descriptors = fs_source_sink_descs;
ss->function.bind = sourcesink_bind;
ss->function.unbind = sourcesink_unbind;
ss->function.set_alt = sourcesink_set_alt;
ss->function.disable = sourcesink_disable; status = usb_add_function(c, &ss->function);
if (status)
kfree(ss);
return rc;
}

调用两次usb_add_function,给设备添加两个接口。

另外,在nuc900系列中,需要注意的是端点描述符里面

 static struct usb_endpoint_descriptor hs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(),
}; static struct usb_endpoint_descriptor hs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(),
};
.wMaxPacketSize = cpu_to_le16(),
每一个端点的maxpacketsize 加起来不能超过udc 控制器中定义的sram_data大小2048。
 
现在就是一个设备有两个不同功能的接口,可以同时工作,其中一个是标准的mass storage类设备,windows有相应驱动,不用管,令一个是之前用的gadget zero的接口,需要gadget zero的驱动。 
这里随便找一个usb驱动(只是先识别,并不能工作),修改一下.inf文件让它识别我的这个接口。
需要改一下vid pid就行了,
修改这两行为:
%USB\VID_022b&PID_1234.DeviceDesc%=SECBULK.Dev, USB\VID_022b&PID_1234&REV_0000&MI_01
USB\VID_022b&PID_1234.DeviceDesc="test device"
通常设备驱动的.inf 没有后面 &REV_0000&MI_01,这个应该就是指的第几个接口. .inf 文件不太了解,便用边查吧。
然后安装驱动,识别出来就是一个test device 一个 USB Mass Storage Device,两个接口。这样设备及可以作为mass storage设备有可用作test device设备。 
 
 

Linux gadget驱动分析3------复合设备驱动的更多相关文章

  1. Linux I2C驱动分析(三)----i2c_dev驱动和应用层分析 【转】

    本文转载自:http://blog.chinaunix.net/uid-21558711-id-3959287.html 分类: LINUX 原文地址:Linux I2C驱动分析(三)----i2c_ ...

  2. linuxok6410的I2C驱动分析---用户态驱动

    3  i2c-dev 3.1 概述 之前在介绍I2C子系统时,提到过使用i2c-dev.c文件在应用程序中实现我们的I2C从设备驱动.不过,它实现的是一个虚拟,临时的i2c_client,随着设备文件 ...

  3. tiny4412 串口驱动分析六 --- TTY驱动架构

    转载: http://www.linuxidc.com/Linux/2013-11/92639.htm 参考: http://blog.csdn.net/lamdoc/article/details/ ...

  4. linux驱动基础系列--Linux下Spi接口Wifi驱动分析

    前言 本文纯粹的纸上谈兵,我并未在实际开发过程中遇到需要编写或调试这类驱动的时候,本文仅仅是根据源码分析后的记录!基于内核版本:2.6.35.6 .主要是想对spi接口的wifi驱动框架有一个整体的把 ...

  5. Linux spi驱动分析(二)----SPI核心(bus、device_driver和device)

    一.spi总线注册 这里所说的SPI核心,就是指/drivers/spi/目录下spi.c文件中提供给其他文件的函数,首先看下spi核心的初始化函数spi_init(void).程序如下: 点击(此处 ...

  6. Linux gadget驱动分析1------驱动加载过程

    为了解决一个问题,简单看了一遍linux gadget驱动的加载流程.做一下记录. 使用的内核为linux 2.6.35 硬件为芯唐NUC950. gadget是在UDC驱动上面的一层,如果要编写ga ...

  7. s3c6410 linux gadget hid驱动

    s3c6410 linux gadget hid驱动调了我一个多星期了今天终于搞定了,来跟大家分享下. 上一个星期纠结了一个星期的寄存器,试了N次,不管把3.1和3.7的hid驱动移植过来也是一样的情 ...

  8. linux的串口驱动分析

    1.串口驱动中的数据结构 • UART驱动程序结构:struct uart_driver  驱动 • UART端口结构: struct uart_port  串口 • UART相关操作函数结构: st ...

  9. linux内核SPI总线驱动分析(一)(转)

    linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...

  10. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

随机推荐

  1. Java入门第37课——猜字母游戏之设计数据结构

    问题        有猜字母游戏,其游戏规则为:程序随机产生5个按照一定顺序排列的字符作为猜测的结果,由玩家来猜测此字符串.玩家可以猜测多次,每猜测一次,则由系统提示结果.如果猜测的完全正确,则游戏结 ...

  2. 08Java Server Pages 语法

    Java Server Pages 语法 基础语法 注释 <!--   -->可以在客户端通过源代码看到:<%--   --%>在客户端通过查看源代码看不到. <!--浏 ...

  3. HDU多校Round 7

    Solved:2 rank:293 J. Sequense 不知道自己写的什么东西 以后整数分块直接用 n / (n / i)表示一个块内相同n / i的最大i #include <bits/s ...

  4. A3. JVM 类加载器

    [概述] 虚拟机设计团队把类加载阶段中的 “通过一个类的全限定名来获取描述此类的二进制字节流” 这个动作放到 Java 虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类.实现这个动作的代码 ...

  5. maven deploy时报错

    Failed to execute goal org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy (default-deploy) on p ...

  6. C++中重载,重写,隐藏的区别

    重载: 重载是指在同一个作用域下,函数的函数名相同,但是函数参数的个数,或者参数的类型,参数的顺序不同.这时函数之间就构成了重载关系,这里需要注意的是,如果函数的参数列表完全相同,仅仅是返回值类型不同 ...

  7. [luogu3573 POI2014] RAJ-Rally (拓扑排序 权值线段树)

    传送门 Solution 在DAG中我们可以\(O(n)\)预处理\(Ds(u)\)表示从u表示以s为起点的最长路\(Dt(u)\)表示以u为终点的最长路,那么经过\((u,v)\)的最长路即为\(D ...

  8. Java:冒泡排序 | 二分查找

    2018-10-29 20:16:46 冒泡排序 例子(对数字排序): 假设有这样一组数字:32, 8, 128, 2, 64 现在对其进行冒泡排序(*表示下次比较的开始数字): 32>8? t ...

  9. 移动端placeholder不能垂直居中解决方案

    1.问题描述 问题如图:手机端placeholder文字偏上,垂直方向不居中,input光标显示偏上解决IE下不支持placeholder属性 2.解决方案 css .phoneNumber inpu ...

  10. 挂载本地file到容器中

    -v /Us……/cts/fffen:/usr/local/src -v 标记 将本地主机的目录 到 目标容器的路径下 在容器中查看:ls  发现已经存在py文件 运行python fenci.py ...