USB Core 九

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

 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 += 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 = 0;
	//统计记录一下这个配置里每个接口所拥有的设置数目
	 for ((buffer2 = buffer, size2 = size);//这个循环里使用的是buffer2 和size2, buffer 和size 的两个替身
 	size2 > 0;
 	(buffer2 += header->bLength, size2 -= header->bLength)) {
/*
 struct usb_descriptor_header {
	 __u8 bLength;
	 __u8 bDescriptorType;
 } __attribute__ ((packed));
*/
	 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;
	 }

 	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 theconfig\n",
 	cfgno, header->bLength);
	 break;
	 }

 	if (header->bDescriptorType == USB_DT_INTERFACE) {
 	struct usb_interface_descriptor *d;
 	int inum;

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

 /* 
  n 记录的是接口的数目,数组inums 里的每一项都表示一
个接口号,数组nalts 里的每一项记录的是每个接口拥有的设置数目,inums 和nalts 两
个数组里的元素是一一对应的,inums[0]就对应nalts[0],inums[1]就对应nalts[1]。发送GET_DESCRIPTOR 请求时,设备并不一定会按照接
口1,接口2 这样的顺序循规蹈矩的返回数据. 
*/
 	for (i = 0; i < n; ++i) {
	 if (inums[i] == inum)
	 break;
	 }
	 if (i < n) {

	 	if (nalts[i] < 255)
		 ++nalts[i];
		 } else if (n < USB_MAXINTERFACES) {
		 inums[n] = inum;
		 nalts[n] = 1;
		 ++n;
		 }

	 } 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;//buffer 的最后边儿可能会有些垃圾数据,为了去除这些洋垃圾,这里需要将size和配置描述符里的那个wTotalLength 修正一下
 	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->extra = buffer;
	 i = find_next_descriptor(buffer, size, USB_DT_INTERFACE,
	 USB_DT_INTERFACE, &n);//调用find_next_descriptor()在buffer 里寻找配置描述符后面跟着的第一个接口描述符。

	 config->extralen = i;
	 if (n > 0)
	 dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
	 n, plural(n), "configuration");
	 buffer += i;//根据find_next_descriptor 的结果修正buffer 和size。
	 size -= i;

 /* Parse all the interface/altsetting descriptors */
/*
  如果size 大于0,就说明配置描述符后面找到了一个接口描述符,根据这个接口描述符的长度,已经可以解析出一个
  完整的接口描述符了,但是仍然没到乐观的时候,这个接口描述符后面还会跟着一群端点描述符,再然后还会有其它的接口描述符
*/
	 while (size > 0){
		 retval = usb_parse_interface(ddev, cfgno, config,
		 buffer, size, inums, nalts);//暂时只需要知道它返回的时候,buffer 的位置已经在下一个接口描述符那里了
 		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;
 }


 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值