diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
| -rw-r--r-- | drivers/usb/core/hub.c | 27 | 
1 files changed, 21 insertions, 6 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 9dca59ef18b3..b8bb20d7acdb 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -362,7 +362,8 @@ static void usb_set_lpm_parameters(struct usb_device *udev)  }  /* USB 2.0 spec Section 11.24.4.5 */ -static int get_hub_descriptor(struct usb_device *hdev, void *data) +static int get_hub_descriptor(struct usb_device *hdev, +		struct usb_hub_descriptor *desc)  {  	int i, ret, size;  	unsigned dtype; @@ -378,10 +379,18 @@ static int get_hub_descriptor(struct usb_device *hdev, void *data)  	for (i = 0; i < 3; i++) {  		ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),  			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, -			dtype << 8, 0, data, size, +			dtype << 8, 0, desc, size,  			USB_CTRL_GET_TIMEOUT); -		if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2)) +		if (hub_is_superspeed(hdev)) { +			if (ret == size) +				return ret; +		} else if (ret >= USB_DT_HUB_NONVAR_SIZE + 2) { +			/* Make sure we have the DeviceRemovable field. */ +			size = USB_DT_HUB_NONVAR_SIZE + desc->bNbrPorts / 8 + 1; +			if (ret < size) +				return -EMSGSIZE;  			return ret; +		}  	}  	return -EINVAL;  } @@ -1313,7 +1322,7 @@ static int hub_configure(struct usb_hub *hub,  	}  	mutex_init(&hub->status_mutex); -	hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); +	hub->descriptor = kzalloc(sizeof(*hub->descriptor), GFP_KERNEL);  	if (!hub->descriptor) {  		ret = -ENOMEM;  		goto fail; @@ -1321,13 +1330,19 @@ static int hub_configure(struct usb_hub *hub,  	/* Request the entire hub descriptor.  	 * hub->descriptor can handle USB_MAXCHILDREN ports, -	 * but the hub can/will return fewer bytes here. +	 * but a (non-SS) hub can/will return fewer bytes here.  	 */  	ret = get_hub_descriptor(hdev, hub->descriptor);  	if (ret < 0) {  		message = "can't read hub descriptor";  		goto fail; -	} else if (hub->descriptor->bNbrPorts > USB_MAXCHILDREN) { +	} + +	maxchild = USB_MAXCHILDREN; +	if (hub_is_superspeed(hdev)) +		maxchild = min_t(unsigned, maxchild, USB_SS_MAXPORTS); + +	if (hub->descriptor->bNbrPorts > maxchild) {  		message = "hub has too many ports!";  		ret = -ENODEV;  		goto fail;  |