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. Masonry 原理一

    Under the hood Auto Layout is a powerful and flexible way of organising and laying out your views. H ...

  2. Solr搜索引擎 — 通过mysql配置数据源

    一,准备数据库数据表结构 CREATE TABLE `app` ( `id` int(11) NOT NULL AUTO_INCREMENT, `app_name` varchar(255) NOT ...

  3. 【转载】Java下利用Jackson进行JSON解析和序列化

    参考资料: https://blog.csdn.net/sdut406/article/details/85647982 Java下常见的Json类库有Gson.JSON-lib和Jackson等,J ...

  4. 利用 Python 批量修改文件名

    开发的第一步,首先得熟悉脚本中使用的模块函数,废话不多说,开干! 1 函数介绍 1.1 os 模块 (1)os.lisdir() >>> import os >>> ...

  5. 腾讯云,体验域名注册解析与SSL证书

    体验域名注册解析与SSL证书 购买域名 任务时间:30min ~ 60min 在腾讯云上购买域名 首先需要在腾讯云上购买域名, 点击以下链接可以观看购买操作的指引 如何在腾讯云上购买域名 域名解析 域 ...

  6. RabbitMQ-linux安装rabbitmq(二)

    说明 本地装了个虚拟机模拟集群 所以记下安装步骤 安装Erlang 安装类库 yum -y install ncurses-devel yum -y install openssl-devel yum ...

  7. Ubuntu16.04再次装机记

    个人的吐槽 整个国庆假期(9天),基本上都在搭建PHP环境中耗费了. 是这样的——来大学报到前,想着大学里用个Dev-C++应该够了,于是把Ubuntu删了,腾出了100G的空间.到了CSU,加了团委 ...

  8. Spring @Conditional注解 详细讲解及示例

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/xcy1193068639/article/details/81491071 前言: @Conditi ...

  9. Hihocoder 1329(splay)

    Problem 平衡树 Splay 题目大意 维护一个数列,支持三种操作. 操作1:添加一个数x. 操作2:询问不超过x的最大的数. 操作三:删除大小在区间[a,b]内的数. 解题分析 和上一题相比, ...

  10. 所有在Linux系统下 arp -d $ip 命令只能清除一个IP地址的对应MAC地址缓存,可以使用组合命令操作。

    https://blog.csdn.net/u011641885/article/details/48175239 https://blog.csdn.net/zj0910/article/detai ...