static int usb_parse_configuration(struct device *ddev, int cfgidx,
struct usb_host_config *config, unsigned char *buffer, int size)
{
unsigned char *buffer0 = buffer;
int cfgno;
int nintf, nintf_orig;
int i, j, n;
struct usb_interface_cache *intfc;
unsigned char *buffer2;
int size2;
struct usb_descriptor_header *header;
int len, retval;
u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
unsigned iad_num = 0;
//复制配置信息的前9字节(也就是配置描述符)
//到dev->config[cfgidx]->desc中
memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
//检测描述符的类型及长度是否正确
if (config->desc.bDescriptorType != USB_DT_CONFIG || config->desc.bLength < USB_DT_CONFIG_SIZE)
{
dev_err(ddev, "invalid descriptor for config index %d: "
"type = 0x%X, length = %d\n", cfgidx,
config->desc.bDescriptorType, config->desc.bLength);
return -EINVAL;
}
//取得配置中的配置值
cfgno = config->desc.bConfigurationValue;
//buffer指向接口描述符部分的起始位置
buffer += config->desc.bLength;
//计算配置信息除去配置描述符后的大小
size -= config->desc.bLength;
//取得该配置的接口数
nintf = nintf_orig = config->desc.bNumInterfaces;
//检测接口数目是否超过上限
if (nintf > USB_MAXINTERFACES)
{
dev_warn(ddev, "config %d has too many interfaces: %d, "
"using maximum allowed: %d\n",
cfgno, nintf, USB_MAXINTERFACES);
nintf = USB_MAXINTERFACES;
}
/* Go through the descriptors, checking their length and counting the
* number of altsettings for each interface */
//n用于保存接口数
n = 0;
//历遍接口
for ((buffer2 = buffer, size2 = size) ; size2 > 0 ; (buffer2 += header->bLength, size2 -= header->bLength))
{
if (size2 < sizeof(struct usb_descriptor_header))
{
dev_warn(ddev, "config %d descriptor has %d excess " "byte%s, ignoring\n",cfgno, size2, plural(size2));
break;
}
//将buffer2,也就是配置描述符的第10字节起格式化成描述符头结构保存在header中
header = (struct usb_descriptor_header *) buffer2;
//检测接口描述符的长度是否超过最大长度或过小
if ((header->bLength > size2) || (header->bLength < 2))
{
dev_warn(ddev, "config %d has an invalid descriptor " "of length %d, skipping remainder of the config\n",cfgno, header->bLength);
break;
}
//检测接口描述符的类型是否为接口
if (header->bDescriptorType == USB_DT_INTERFACE)
{
struct usb_interface_descriptor *d;
int inum;
//将header,也就是配置描述符的第10字节起格式化成接口描述符结构保存在d中
d = (struct usb_interface_descriptor *) header;
//检测接口描述符的长度是否过短
if (d->bLength < USB_DT_INTERFACE_SIZE)
{
dev_warn(ddev, "config %d has an invalid "
"interface descriptor of length %d, "
"skipping\n", cfgno, d->bLength);
continue;
}
//取得接口描述符的接口号
inum = d->bInterfaceNumber;
//接口描述符数目是否大于配置描述符中规定的数目
if (inum >= nintf_orig)
dev_warn(ddev, "config %d has an invalid "
"interface number: %d but max is %d\n",cfgno, inum, nintf_orig - 1);
/* Have we already encountered this interface?
* Count its altsettings */
//inums记录当前接口的接口号
//nalts记录接口号的重复次数
//历遍接口号数组
for (i = 0; i < n; ++i)
{
//检测接口号是否等于当前接口的接口号
if (inums[i] == inum)
break;
}
//i<n说明有相同接口号的接口,则增加交互号数组中对应的值
if (i < n)
{
if (nalts[i] < 255)
++nalts[i];
}
//没有相同接口号,则在交互号数组中占一个对应接口号的位置
else if (n < USB_MAXINTERFACES)
{
inums[n] = inum;
nalts[n] = 1;
//接口数目计数器自加1
++n;
}
}
//检测接口描述符的类型是否为接口联合
else if (header->bDescriptorType == USB_DT_INTERFACE_ASSOCIATION)
{
if (iad_num == USB_MAXIADS)
{
dev_warn(ddev, "found more Interface "
"Association Descriptors "
"than allocated for in "
"configuration %d\n", cfgno);
}
else
{
config->intf_assoc[iad_num] =(struct usb_interface_assoc_descriptor *)header;
iad_num++;
}
}
//检测接口描述符的类型是否为设备或者配置
else if (header->bDescriptorType == USB_DT_DEVICE || header->bDescriptorType == USB_DT_CONFIG)
dev_warn(ddev, "config %d contains an unexpected "
"descriptor of type 0x%X, skipping\n",
cfgno, header->bDescriptorType);
} /* for ((buffer2 = buffer, size2 = size); ...) */
//计算除去配置描述符的长度
size = buffer2 - buffer;
//计算剩下的配置信息长度
config->desc.wTotalLength = cpu_to_le16(buffer2 - buffer0);
if (n != nintf)
dev_warn(ddev, "config %d has %d interface%s, different from "
"the descriptor's value: %d\n",
cfgno, n, plural(n), nintf_orig);
else if (n == 0)
dev_warn(ddev, "config %d has no interfaces?\n", cfgno);
//设置接口数
config->desc.bNumInterfaces = nintf = n;
/* Check for missing interface numbers */
//历遍接口
for (i = 0; i < nintf; ++i)
{
//历遍接口号数组
for (j = 0; j < nintf; ++j)
{
if (inums[j] == i)
break;
}
//检测是否有占用了接口号数组却没有接口号
if (j >= nintf)
dev_warn(ddev, "config %d has no interface number " "%d\n", cfgno, i);
}
/* Allocate the usb_interface_caches and altsetting arrays */
//历遍接口
for (i = 0; i < nintf; ++i)
{
//取得交互数
j = nalts[i];
//检测是否超过最大交互数
if (j > USB_MAXALTSETTING)
{
dev_warn(ddev, "too many alternate settings for "
"config %d interface %d: %d, "
"using maximum allowed: %d\n",
cfgno, inums[i], j, USB_MAXALTSETTING);
nalts[i] = j = USB_MAXALTSETTING;
}
//计算交互数组结构与接口结构一共需要的空间
len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;
//分配接口结构
config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL);
if (!intfc)
return -ENOMEM;
kref_init(&intfc->ref);
}
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the first interface descriptor */
//保存接口描述符起始位置到config中
config->extra = buffer;
//寻找下一个接口描述符,返回偏移量
i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,USB_DT_INTERFACE, &n);
//设置距离下一个接口描述符的偏移量
config->extralen = i;
if (n > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",n, plural(n), "configuration");
//移动到下一个描述符的起始位置
buffer += i;
//计算描述符的剩余大小
size -= i;
/* Parse all the interface/altsetting descriptors */
while (size > 0)
{
//分析接口描述符
retval = usb_parse_interface(ddev, cfgno, config,buffer, size, inums, nalts);
if (retval < 0)
return retval;
//移动到下一个描述符的起始位置
buffer += retval;
//计算配置信息的剩余大小
size -= retval;
}
/* Check for missing altsettings */
//检测是否有缺失的交互配置
for (i = 0; i < nintf; ++i)
{
intfc = config->intf_cache[i];
for (j = 0; j < intfc->num_altsetting; ++j)
{
for (n = 0; n < intfc->num_altsetting; ++n)
{
if (intfc->altsetting[n].desc.bAlternateSetting == j)
break;
}
if (n >= intfc->num_altsetting)
dev_warn(ddev, "config %d interface %d has no ""altsetting %d\n", cfgno, inums[i], j);
}
}
return 0;
}
|