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; } |