diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/usb/core/generic.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 81 | ||||
| -rw-r--r-- | drivers/usb/core/usb.h | 3 | 
3 files changed, 85 insertions, 1 deletions
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 20b095050a1..7b9e1ec718d 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)  		&& desc->bInterfaceProtocol == 1;  } -static int choose_configuration(struct usb_device *udev) +int choose_configuration(struct usb_device *udev)  {  	int i;  	int num_configs; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 65d9ea1e6d7..f725d9e62b5 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1399,6 +1399,87 @@ fail:  	return err;  } + +/** + * Similar to usb_disconnect() + * + * We share a lock (that we have) with device_del(), so we need to + * defer its call. + */ +int usb_deauthorize_device(struct usb_device *usb_dev) +{ +	unsigned cnt; +	usb_lock_device(usb_dev); +	if (usb_dev->authorized == 0) +		goto out_unauthorized; +	usb_dev->authorized = 0; +	usb_set_configuration(usb_dev, -1); +	usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); +	usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); +	usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); +	kfree(usb_dev->config); +	usb_dev->config = NULL; +	for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++) +		kfree(usb_dev->rawdescriptors[cnt]); +	usb_dev->descriptor.bNumConfigurations = 0; +	kfree(usb_dev->rawdescriptors); +out_unauthorized: +	usb_unlock_device(usb_dev); +	return 0; +} + + +int usb_authorize_device(struct usb_device *usb_dev) +{ +	int result = 0, c; +	usb_lock_device(usb_dev); +	if (usb_dev->authorized == 1) +		goto out_authorized; +	kfree(usb_dev->product); +	usb_dev->product = NULL; +	kfree(usb_dev->manufacturer); +	usb_dev->manufacturer = NULL; +	kfree(usb_dev->serial); +	usb_dev->serial = NULL; +	result = usb_autoresume_device(usb_dev); +	if (result < 0) { +		dev_err(&usb_dev->dev, +			"can't autoresume for authorization: %d\n", result); +		goto error_autoresume; +	} +	result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor)); +	if (result < 0) { +		dev_err(&usb_dev->dev, "can't re-read device descriptor for " +			"authorization: %d\n", result); +		goto error_device_descriptor; +	} +	usb_dev->authorized = 1; +	result = usb_configure_device(usb_dev); +	if (result < 0) +		goto error_configure; +	/* Choose and set the configuration.  This registers the interfaces +	 * with the driver core and lets interface drivers bind to them. +	 */ +	c = choose_configuration(usb_dev); +	if (c >= 0) { +		result = usb_set_configuration(usb_dev, c); +		if (result) { +			dev_err(&usb_dev->dev, +				"can't set config #%d, error %d\n", c, result); +			/* This need not be fatal.  The user can try to +			 * set other configurations. */ +		} +	} +	dev_info(&usb_dev->dev, "authorized to connect\n"); +error_configure: +error_device_descriptor: +error_autoresume: +out_authorized: +	usb_unlock_device(usb_dev);	// complements locktree +	return result; +} + +  static int hub_port_status(struct usb_hub *hub, int port1,  			       u16 *status, u16 *change)  { diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index cde6e52b84f..e22ec7f8eb1 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -15,12 +15,15 @@ extern void usb_disable_interface (struct usb_device *dev,  		struct usb_interface *intf);  extern void usb_release_interface_cache(struct kref *ref);  extern void usb_disable_device (struct usb_device *dev, int skip_ep0); +extern int usb_deauthorize_device (struct usb_device *); +extern int usb_authorize_device (struct usb_device *);  extern void usb_detect_quirks(struct usb_device *udev);  extern int usb_get_device_descriptor(struct usb_device *dev,  		unsigned int size);  extern char *usb_cache_string(struct usb_device *udev, int index);  extern int usb_set_configuration(struct usb_device *dev, int configuration); +extern int choose_configuration(struct usb_device *udev);  extern void usb_kick_khubd(struct usb_device *dev);  extern int usb_match_device(struct usb_device *dev,  |