這個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驅動還沒講完!
下期再見!