Linux gadget驅動分析3------復合設備驅動


 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 中定義的設備描述符:

 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,

即為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設備。 
image
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM