自娱自乐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驱动还没讲完!

下期再见!

你可能感兴趣的:(自娱自乐3之Linux gadget驱动2(zero中的字符串描述符))