windows上面對usb複合設備的識別須要下面條件。html
「linux
若是設備知足下列要求,則總線驅動程序還會報告 USB\COMPOSITE
的兼容標識符:windows
設備描述符的設備類字段 (bDeviceClass) 必須包含一個零值,或者設備描述符的類 (bDeviceClass)、子類 (bDeviceSubClass) 和協議 (bDeviceProtocol) 字段必須分別具備值 0xEF、0x02 和 0x01,如 USB 接口關聯描述符中所述。this
設備必須具備多個接口。spa
設備必須具備一個配置。「code
引用自:http://msdn.microsoft.com/zh-cn/library/ff537109htm
下面是linux /driver/usb/gadget/mass_storage.c 中定義的設備描述符:blog
1 static struct usb_device_descriptor msg_device_desc = { 2 .bLength = sizeof msg_device_desc, 3 .bDescriptorType = USB_DT_DEVICE, 4 5 .bcdUSB = cpu_to_le16(0x0200), 6 .bDeviceClass = USB_CLASS_PER_INTERFACE, 7 8 /* Vendor and product id can be overridden by module parameters. */ 9 .idVendor = cpu_to_le16(FSG_VENDOR_ID), 10 .idProduct = cpu_to_le16(FSG_PRODUCT_ID), 11 /* .bcdDevice = f(hardware) */ 12 /* .iManufacturer = DYNAMIC */ 13 /* .iProduct = DYNAMIC */ 14 /* NO SERIAL NUMBER */ 15 .bNumConfigurations = 1, 16 };
其中:接口
.bDeviceClass = USB_CLASS_PER_INTERFACE,ip
即爲0,
注意到其實mass storage類是被定義爲:
#define USB_CLASS_MASS_STORAGE 8
沒有給.bDeviceClass 賦值爲8,這樣gadget 設備就會在windows上識別時得到 的兼容標識符USB\COMPOSITE
1 /* 2 * Device and/or Interface Class codes 3 * as found in bDeviceClass or bInterfaceClass 4 * and defined by www.usb.org documents 5 */ 6 #define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */ 7 #define USB_CLASS_AUDIO 1 8 #define USB_CLASS_COMM 2 9 #define USB_CLASS_HID 3 10 #define USB_CLASS_PHYSICAL 5 11 #define USB_CLASS_STILL_IMAGE 6 12 #define USB_CLASS_PRINTER 7 13 #define USB_CLASS_MASS_STORAGE 8 14 #define USB_CLASS_HUB 9 15 #define USB_CLASS_CDC_DATA 0x0a 16 #define USB_CLASS_CSCID 0x0b /* chip+ smart card */ 17 #define USB_CLASS_CONTENT_SEC 0x0d /* content security */ 18 #define USB_CLASS_VIDEO 0x0e 19 #define USB_CLASS_WIRELESS_CONTROLLER 0xe0 20 #define USB_CLASS_MISC 0xef 21 #define USB_CLASS_APP_SPEC 0xfe 22 #define USB_CLASS_VENDOR_SPEC 0xff 23 24 #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系列中,須要注意的是端點描述符裏面
1 static struct usb_endpoint_descriptor hs_source_desc = { 2 .bLength = USB_DT_ENDPOINT_SIZE, 3 .bDescriptorType = USB_DT_ENDPOINT, 4 5 .bmAttributes = USB_ENDPOINT_XFER_BULK, 6 .wMaxPacketSize = cpu_to_le16(512), 7 }; 8 9 static struct usb_endpoint_descriptor hs_sink_desc = { 10 .bLength = USB_DT_ENDPOINT_SIZE, 11 .bDescriptorType = USB_DT_ENDPOINT, 12 13 .bmAttributes = USB_ENDPOINT_XFER_BULK, 14 .wMaxPacketSize = cpu_to_le16(512), 15 }; 16 .wMaxPacketSize = cpu_to_le16(512),
每個端點的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設備。