这个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驱动还没讲完!
下期再见!