自娛自樂3之Linux gadget驅動2(zero中的字符串描述符)

這個gadget驅動我會一部分一部分說(你可以對着zero.c看),最後給個完整的。

今天說的是字符串描述符,struct usb_gadget_strings我之前說是字符串描述符並不準確,

真正的描述符是struct usb_string_descriptor

上一篇說的結構體中有很多都包涵了struct usb_gadget_strings,它們是struct usb_function、struct usb_configuration、struct usb_composite_driver三世同堂

struct usb_composite_drive包涵struct usb_configuration包涵struct usb_function

而且zero.c f_souresink.c f_loopback.c(這個我不用就不看了)composite.c都有

string usb_string_descripter結構體,這篇文章就瞭解一下他們的關係

先看一下這幾個結構體

/* USB_DT_STRING: String descriptor */
struct usb_string_descriptor {
        __u8  bLength;//描述符長度
        __u8  bDescriptorType;//就是USB_DT_STRING  0x03

        __le16 wData[1];                /* UTF-16LE encoded */
} __attribute__ ((packed));


//這裏可以看出usb_gadget_strings包涵struct usb_string

//實例中的定義會看到

struct usb_gadget_strings {
        u16                     language;       /* 0x0409 for en-us */
        struct usb_string       *strings;
};

struct usb_string {
        u8                      id;
        const char              *s;
};

不過在驅動中我們大部分看到的是struct usb_string

先看zero.c

//首先定義

static const char longname[] = "Gadget gadget_transfer";

static char manufacturer[50];

/* default serial number takes at least two packets */
static char serial[] = "0123456789.0123456789.0123456789";

static struct usb_string strings_dev[] = {
    [STRING_MANUFACTURER_IDX].s = manufacturer,
    [STRING_PRODUCT_IDX].s = longname,
    [STRING_SERIAL_IDX].s = serial,
    {  }            /* end of list */
};

static struct usb_gadget_strings stringtab_dev = {
    .language    = 0x0409,    /* en-us */
    .strings    = strings_dev,//包涵struct usb_string
};

static struct usb_gadget_strings *dev_strings[] = {
    &stringtab_dev,
    NULL,
};

//沒什麼要解釋的吧

//在gadget_transfer_bind()中

    //各字符串描述符的引索
    id = usb_string_id(cdev);//這個東西之前有說過,就是cdev->next_string_id++返回,怕id衝突
    if (id < 0)
        return id;
    strings_dev[STRING_MANUFACTURER_IDX].id = id;
    device_desc.iManufacturer = id;

    id = usb_string_id(cdev);
    if (id < 0)
        return id;
    strings_dev[STRING_PRODUCT_IDX].id = id;
    device_desc.iProduct = id;

    id = usb_string_id(cdev);
    if (id < 0)
        return id;
    strings_dev[STRING_SERIAL_IDX].id = id;
    device_desc.iSerialNumber = id;

//manufacturer[50]下面賦值

    //本來下面這句就是給manufacturer賦值,可是非要整個init_utsname()
    //linux gadget的驅動都有這個,我們看一下吧
    /*
        .name = {
            .sysname        = UTS_SYSNAME,
            .nodename       = UTS_NODENAME,
            .release        = UTS_RELEASE,
            .version        = UTS_VERSION,
            .machine        = UTS_MACHINE,
            .domainname     = UTS_DOMAINNAME,
        },
        #ifndef UTS_SYSNAME//也有定義"uClinux"等
            #define UTS_SYSNAME "Linux"
        #endif

        #define UTS_RELEASE "3.2.0"//我的版本
    */
    snprintf
(manufacturer, sizeof manufacturer, "%s %s with %s",
        init_utsname()->sysname, init_utsname()->release,
        gadget->name);

//還有個靜態結構

static struct usb_composite_driver gadget_transfer_driver = {
    .name        = "gadget_transfer",
    .dev        = &device_desc,
    .strings    = dev_strings,
    .max_speed    = USB_SPEED_SUPER,
    .unbind        = gadget_transfer_unbind,
};//我們找到了爺爺usb_composite_driver

//f_sourecesink.c 我只用sink

static struct usb_string strings_sourcesink[] = {
    [0].s = "source and sink data",
    {  }            /* end of list */
};

static struct usb_gadget_strings stringtab_sourcesink = {
    .language    = 0x0409,    /* en-us */
    .strings    = strings_sourcesink,
};

static struct usb_gadget_strings *sourcesink_strings[] = {
    &stringtab_sourcesink,
    NULL,
};

static struct usb_configuration sourcesink_driver = {
    .label        = "source/sink",
    .strings    = sourcesink_strings,
    .setup        = sourcesink_setup,
    .bConfigurationValue = 3,
    .bmAttributes    = USB_CONFIG_ATT_SELFPOWER,
    /* .iConfiguration = DYNAMIC */
};//我們找到了爸爸struct usb_configuration

probe時會加入cdev中

usb_add_config(cdev, &sourcesink_driver, sourcesink_bind_config);

list_add_tail(&config->list, &cdev->configs);//下面會見到查找列表


還差兒子struct usb_function

    ss->function.name = "source/sink";
    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);

很可惜這是個不爭氣的孩子,沒有給string賦值

//composite.c 

struct usb_composite_dev中的這幾位,下面會賦值

       u8                         manufacturer_override;

       u8                         product_override;

       u8                         serial_override;


static char *iManufacturer;
module_param(iManufacturer, charp, 0);
MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");

static char *iProduct;
module_param(iProduct, charp, 0);
MODULE_PARM_DESC(iProduct, "USB Product string");

static char *iSerialNumber;
module_param(iSerialNumber, charp, 0);
MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");

//上面的可以裝載時賦值
static char composite_manufacturer[50];

在static int composite_bind(struct usb_gadget *gadget)中

//有個全局的tatic struct usb_composite_driver *composite;

//在int usb_composite_probe(struct usb_composite_driver *driver,
//                   int (*bind)(struct usb_composite_dev *cdev))中

//composite =driver,對我們來說就是zero中的struct usb_composite_driver

    cdev->desc = *composite->dev;

/*

cdev->desc對我們來說就是zero中的

static struct usb_device_descriptor device_desc = {
    .bLength =        sizeof device_desc,
    .bDescriptorType =    USB_DT_DEVICE,

    .bcdUSB =        cpu_to_le16(0x0200),
    .bDeviceClass =        USB_CLASS_VENDOR_SPEC,

    .idVendor =        cpu_to_le16(DRIVER_VENDOR_NUM),//我們有賦值
    .idProduct =        cpu_to_le16(DRIVER_PRODUCT_NUM),
    .bNumConfigurations =    2,
};

*/


    /* string overrides */
    if (iManufacturer || !cdev->desc.iManufacturer) {//只要iMonufacturer指定就會用

/*

對於struct usb_composite_driver它裏面也有

       const char                            *iProduct;//產品

       const char                            *iManufacturer;//廠商信息

zero並沒有指定,下面會看到composite->iManufacturer和

composite->iProduct判斷

*/

        if (!iManufacturer && !composite->iManufacturer &&
            !*composite_manufacturer)//如果這幾個都沒有指定
            snprintf(composite_manufacturer,
                 sizeof composite_manufacturer,
                 "%s %s with %s",
                 init_utsname()->sysname,
                 init_utsname()->release,
                 gadget->name);//這個和zero中的一樣

/*
static u8 override_id(struct usb_composite_dev *cdev, u8 *desc)
{
    if (!*desc) {//如果不是0,就是已分配過id
        int ret = usb_string_id(cdev);//這個已說過
        if (unlikely(ret < 0))
            WARNING(cdev, "failed to override string ID\n");//出錯最後返回就是0
        else
            *desc = ret;
    }

    return *desc;
}

*/       

           cdev->manufacturer_override =
            override_id(cdev, &cdev->desc.iManufacturer);
    }
//下面邏輯和上面差不多,不贅述了
    if (iProduct || (!cdev->desc.iProduct && composite->iProduct))
        cdev->product_override =
            override_id(cdev, &cdev->desc.iProduct);

    if (iSerialNumber)
        cdev->serial_override =
            override_id(cdev, &cdev->desc.iSerialNumber);


上面這一大堆就是初始化賦值,下面看usb請求,請求我不細說了,就是主機發獲得字符串描述符請求時

調用int get_string(struct usb_composite_dev *cdev,  void *buf, u16 language, int id)

static int get_string(struct usb_composite_dev *cdev,
        void *buf, u16 language, int id)
{
    struct usb_configuration    *c;
    struct usb_function        *f;
    int                len;
    const char            *str;

    /* Yes, not only is USB's I18N support probably more than most
     * folk will ever care about ... also, it's all supported here.
     * (Except for UTF8 support for Unicode's "Astral Planes".)
     */

    /* 0 == report all available language codes *///這裏寫的很清楚,0返回所有支持語言codes
    if (id == 0) {
        struct usb_string_descriptor    *s = buf;//字符串描述符,這個buf就是usb_request中的buf,我們就就是要給它賦值
        struct usb_gadget_strings    **sp;

        memset(s, 0, 256);
        s->bDescriptorType = USB_DT_STRING;//開始就說了
//下面直到list_for_each_entry結束,我們看到了上面說的包涵關係

/*

唯一要說的就是void collect_langs(struct usb_gadget_strings **sp, __le16 *buf)

不貼代碼了,就是獲得struct usb_gadget_strings的language id並與buf中比較

如果沒有相同的就記錄下來,裏面有個126限制下面也有,應該是指buf的最大長度

*/

        sp = composite->strings;//就是zero中的dev_strings
        if (sp)
            collect_langs(sp, s->wData);

        list_for_each_entry(c, &cdev->configs, list) {
            sp = c->strings;
            if (sp)
                collect_langs(sp, s->wData);

            list_for_each_entry(f, &c->functions, list) {
                sp = f->strings;
                if (sp)
                    collect_langs(sp, s->wData);
            }
        }

        for (len = 0; len <= 126 && s->wData[len]; len++)
            continue;
        if (!len)
            return -EINVAL;

        s->bLength = 2 * (len + 1);//這個其實就是2 * len + 2,前面*2是應爲wData是le16就是16位,+2是bLength和bDescriptorType
        return s->bLength;
    }

    /* Otherwise, look up and return a specified string.  First
     * check if the string has not been overridden.
     */
    if (cdev->manufacturer_override == id)
        str = iManufacturer ?: composite->iManufacturer ?:
            composite_manufacturer;
    else if (cdev->product_override == id)
        str = iProduct ?: composite->iProduct;
    else if (cdev->serial_override == id)
        str = iSerialNumber;
    else
        str = NULL;
    if (str) {
        struct usb_gadget_strings strings = {
            .language = language,
            .strings  = &(struct usb_string) { 0xff, str }
        };
        return usb_gadget_get_string(&strings, 0xff, buf);

//usb_gadget_get_string

//linux解釋fill out a string descriptor,不用說了吧,不過你看一下代碼會發現,它又判斷了id == 0,在這有點多餘
    }

//上面一段就是先用轉載是指定的strings,下面不看也知道,肯定是查三世同堂的strings

    /* String IDs are device-scoped, so we look up each string
     * table we're told about.  These lookups are infrequent;
     * simpler-is-better here.
     */

//和上面統計語言ID邏輯一樣,就是用了lookup_string

/*

static int lookup_string(
    struct usb_gadget_strings    **sp,
    void                *buf,
    u16                language,
    int                id
)

也會調用usb_gadget_get_string,不過調用之前會判斷一下

是否和指定language相同

*/

    if (composite->strings) {
        len = lookup_string(composite->strings, buf, language, id);
        if (len > 0)
            return len;
    }
    list_for_each_entry(c, &cdev->configs, list) {
        if (c->strings) {
            len = lookup_string(c->strings, buf, language, id);
            if (len > 0)
                return len;
        }
        list_for_each_entry(f, &c->functions, list) {
            if (!f->strings)
                continue;
            len = lookup_string(f->strings, buf, language, id);
            if (len > 0)
                return len;
        }
    }
    return -EINVAL;
}


好了字符串描述符講完了,當然我們的gadget驅動還沒講完!

下期再見!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章