diff options
Diffstat (limited to 'drivers/usb/core/config.c')
| -rw-r--r-- | drivers/usb/core/config.c | 32 | 
1 files changed, 27 insertions, 5 deletions
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index da8acd980fc6..c821b4b9647e 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -555,6 +555,9 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,  	unsigned iad_num = 0;  	memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE); +	nintf = nintf_orig = config->desc.bNumInterfaces; +	config->desc.bNumInterfaces = 0;	// Adjusted later +  	if (config->desc.bDescriptorType != USB_DT_CONFIG ||  	    config->desc.bLength < USB_DT_CONFIG_SIZE ||  	    config->desc.bLength > size) { @@ -568,7 +571,6 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,  	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", @@ -905,14 +907,25 @@ void usb_release_bos_descriptor(struct usb_device *dev)  	}  } +static const __u8 bos_desc_len[256] = { +	[USB_CAP_TYPE_WIRELESS_USB] = USB_DT_USB_WIRELESS_CAP_SIZE, +	[USB_CAP_TYPE_EXT]          = USB_DT_USB_EXT_CAP_SIZE, +	[USB_SS_CAP_TYPE]           = USB_DT_USB_SS_CAP_SIZE, +	[USB_SSP_CAP_TYPE]          = USB_DT_USB_SSP_CAP_SIZE(1), +	[CONTAINER_ID_TYPE]         = USB_DT_USB_SS_CONTN_ID_SIZE, +	[USB_PTM_CAP_TYPE]          = USB_DT_USB_PTM_ID_SIZE, +}; +  /* Get BOS descriptor set */  int usb_get_bos_descriptor(struct usb_device *dev)  {  	struct device *ddev = &dev->dev;  	struct usb_bos_descriptor *bos;  	struct usb_dev_cap_header *cap; +	struct usb_ssp_cap_descriptor *ssp_cap;  	unsigned char *buffer; -	int length, total_len, num, i; +	int length, total_len, num, i, ssac; +	__u8 cap_type;  	int ret;  	bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL); @@ -965,7 +978,13 @@ int usb_get_bos_descriptor(struct usb_device *dev)  			dev->bos->desc->bNumDeviceCaps = i;  			break;  		} +		cap_type = cap->bDevCapabilityType;  		length = cap->bLength; +		if (bos_desc_len[cap_type] && length < bos_desc_len[cap_type]) { +			dev->bos->desc->bNumDeviceCaps = i; +			break; +		} +  		total_len -= length;  		if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) { @@ -973,7 +992,7 @@ int usb_get_bos_descriptor(struct usb_device *dev)  			continue;  		} -		switch (cap->bDevCapabilityType) { +		switch (cap_type) {  		case USB_CAP_TYPE_WIRELESS_USB:  			/* Wireless USB cap descriptor is handled by wusb */  			break; @@ -986,8 +1005,11 @@ int usb_get_bos_descriptor(struct usb_device *dev)  				(struct usb_ss_cap_descriptor *)buffer;  			break;  		case USB_SSP_CAP_TYPE: -			dev->bos->ssp_cap = -				(struct usb_ssp_cap_descriptor *)buffer; +			ssp_cap = (struct usb_ssp_cap_descriptor *)buffer; +			ssac = (le32_to_cpu(ssp_cap->bmAttributes) & +				USB_SSP_SUBLINK_SPEED_ATTRIBS); +			if (length >= USB_DT_USB_SSP_CAP_SIZE(ssac)) +				dev->bos->ssp_cap = ssp_cap;  			break;  		case CONTAINER_ID_TYPE:  			dev->bos->ss_id =  |