Re: [PATCH] usbcore: get BOS descriptor set

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Andiry,

Are you getting the BOS descriptor in order to implement link power
management?  That was next on my todo list, and I want to make sure I'm
not duplicating your efforts. :)

Sarah Sharp

On Wed, Jul 13, 2011 at 03:43:40PM +0800, Andiry Xu wrote:
> This commit gets BOS(Binary Device Object Store) descriptor set for Super
> Speed devices and High Speed devices which support BOS descriptor.
> 
> BOS descriptor is used to report additional USB device-level capabilities
> that are not reported via the Device descriptor. By getting BOS descriptor
> set, driver can check device's device-level capability such as LPM
> capability.
> 
> Signed-off-by: Andiry Xu <andiry.xu@xxxxxxx>
> ---
>  drivers/usb/core/hub.c     |    3 +
>  drivers/usb/core/message.c |  143 ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/usb/core/usb.c     |    1 +
>  drivers/usb/core/usb.h     |    2 +
>  include/linux/usb.h        |   13 ++++
>  5 files changed, 162 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 90ae175..4ca6bb2 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -3041,6 +3041,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
>  		goto fail;
>  	}
>  
> +	if (udev->wusb == 0 && udev->descriptor.bcdUSB >= 0x0210)
> +		retval = usb_get_bos_descriptor(udev);
> +
>  	retval = 0;
>  	/* notify HCD that we have a device connected and addressed */
>  	if (hcd->driver->update_device)
> diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
> index 5701e85..cc54e57 100644
> --- a/drivers/usb/core/message.c
> +++ b/drivers/usb/core/message.c
> @@ -916,6 +916,149 @@ int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
>  	return ret;
>  }
>  
> +void usb_release_bos_descriptor(struct usb_device *dev)
> +{
> +	if (dev->bos) {
> +		kfree(dev->bos->ext_cap_desc);
> +		kfree(dev->bos->ss_cap_desc);
> +		kfree(dev->bos->ss_id_desc);
> +		kfree(dev->bos);
> +		dev->bos = NULL;
> +	}
> +}
> +
> +/* 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;
> +	unsigned char *buffer, *header;
> +	int length, total_len, num, i;
> +	int ret;
> +
> +	bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL);
> +	if (!bos)
> +		return -ENOMEM;
> +
> +	/* Get BOS descriptor */
> +	ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE);
> +	if (ret < USB_DT_BOS_SIZE) {
> +		dev_err(ddev, "unable to get BOS descriptor\n");
> +		goto err1;
> +	}
> +
> +	dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL);
> +	if (!dev->bos) {
> +		ret = -ENOMEM;
> +		goto err1;
> +	}
> +	memcpy(&dev->bos->desc, bos, USB_DT_BOS_SIZE);
> +
> +	length = (int)le16_to_cpu(bos->bLength);
> +	total_len = (int)le16_to_cpu(bos->wTotalLength);
> +	num = (int)le16_to_cpu(bos->bNumDeviceCaps);
> +
> +	/* Now let's get the whole BOS descriptor set */
> +	buffer = kzalloc(total_len, GFP_KERNEL);
> +	if (!buffer) {
> +		ret = -ENOMEM;
> +		goto err2;
> +	}
> +
> +	ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len);
> +	if (ret < total_len) {
> +		dev_err(ddev, "unable to get BOS descriptor set\n");
> +		goto err3;
> +	}
> +
> +	header = buffer;
> +
> +	for (i = 0; i < num; i++) {
> +		if (total_len < length)
> +			break;
> +		total_len -= length;
> +
> +		header += length;
> +		cap = (struct usb_dev_cap_header *)header;
> +		length = (int)le16_to_cpu(cap->bLength);
> +
> +		if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
> +			dev_warn(ddev, "descriptor type invalid, skip\n");
> +			continue;
> +		}
> +
> +		switch (cap->bDevCapabilityType) {
> +		case USB_CAP_TYPE_WIRELESS_USB:
> +			/* Wireless USB cap descriptor is handled by wusb */
> +			break;
> +		case USB_CAP_TYPE_EXT:
> +			if (dev->bos->ext_cap_desc)
> +				break;
> +			dev->bos->ext_cap_desc =
> +				kzalloc(sizeof(struct usb_ext_cap_descriptor),
> +						GFP_KERNEL);
> +			if (!dev->bos->ext_cap_desc) {
> +				ret = -ENOMEM;
> +				goto err4;
> +			}
> +			memcpy(dev->bos->ext_cap_desc,
> +				(struct usb_ext_cap_descriptor *)header,
> +				USB_DT_USB_EXT_CAP_SIZE);
> +			break;
> +		case USB_SS_CAP_TYPE:
> +			if (dev->bos->ss_cap_desc)
> +				break;
> +			dev->bos->ss_cap_desc =
> +				kzalloc(sizeof(struct usb_ss_cap_descriptor),
> +						GFP_KERNEL);
> +			if (!dev->bos->ss_cap_desc) {
> +				ret = -ENOMEM;
> +				goto err4;
> +			}
> +			memcpy(dev->bos->ss_cap_desc,
> +				(struct usb_ss_cap_descriptor *)header,
> +				USB_DT_USB_SS_CAP_SIZE);
> +			break;
> +		case CONTAINER_ID_TYPE:
> +			if (dev->bos->ss_id_desc)
> +				break;
> +			dev->bos->ss_id_desc =
> +			kzalloc(sizeof(struct usb_ss_container_id_descriptor),
> +						GFP_KERNEL);
> +			if (!dev->bos->ss_id_desc) {
> +				ret = -ENOMEM;
> +				goto err4;
> +			}
> +			memcpy(dev->bos->ss_id_desc,
> +				(struct usb_ss_container_id_descriptor *)header,
> +				USB_DT_USB_SS_CONTN_ID_SIZE);
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +
> +	kfree(bos);
> +	kfree(buffer);
> +
> +	return 0;
> +
> +err4:
> +	kfree(dev->bos->ext_cap_desc);
> +	kfree(dev->bos->ss_cap_desc);
> +	kfree(dev->bos->ss_id_desc);
> +err3:
> +	kfree(buffer);
> +err2:
> +	kfree(dev->bos);
> +	dev->bos = NULL;
> +err1:
> +	kfree(bos);
> +
> +	return ret;
> +}
> +
>  /**
>   * usb_get_status - issues a GET_STATUS call
>   * @dev: the device whose status is being checked
> diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
> index 8706fc9..73cd900 100644
> --- a/drivers/usb/core/usb.c
> +++ b/drivers/usb/core/usb.c
> @@ -225,6 +225,7 @@ static void usb_release_dev(struct device *dev)
>  	hcd = bus_to_hcd(udev->bus);
>  
>  	usb_destroy_configuration(udev);
> +	usb_release_bos_descriptor(udev);
>  	usb_put_hcd(hcd);
>  	kfree(udev->product);
>  	kfree(udev->manufacturer);
> diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
> index d44d4b7..0d023cd 100644
> --- a/drivers/usb/core/usb.h
> +++ b/drivers/usb/core/usb.h
> @@ -28,6 +28,8 @@ extern int usb_remove_device(struct usb_device *udev);
>  
>  extern int usb_get_device_descriptor(struct usb_device *dev,
>  		unsigned int size);
> +extern int usb_get_bos_descriptor(struct usb_device *dev);
> +extern void usb_release_bos_descriptor(struct usb_device *dev);
>  extern char *usb_cache_string(struct usb_device *udev, int index);
>  extern int usb_set_configuration(struct usb_device *dev, int configuration);
>  extern int usb_choose_configuration(struct usb_device *udev);
> diff --git a/include/linux/usb.h b/include/linux/usb.h
> index 73c7df4..5b87377 100644
> --- a/include/linux/usb.h
> +++ b/include/linux/usb.h
> @@ -292,6 +292,17 @@ struct usb_host_config {
>  	int extralen;
>  };
>  
> +/* USB2.0 and USB3.0 device BOS descriptor set */
> +struct usb_host_bos {
> +	struct usb_bos_descriptor	desc;
> +
> +	/* wireless cap descriptor is handled by wusb */
> +	struct usb_ext_cap_descriptor	*ext_cap_desc;
> +	struct usb_ss_cap_descriptor	*ss_cap_desc;
> +	struct usb_ss_container_id_descriptor	*ss_id_desc;
> +
> +};
> +
>  int __usb_get_extra_descriptor(char *buffer, unsigned size,
>  	unsigned char type, void **ptr);
>  #define usb_get_extra_descriptor(ifpoint, type, ptr) \
> @@ -381,6 +392,7 @@ struct usb_tt;
>   * @ep0: endpoint 0 data (default control pipe)
>   * @dev: generic device interface
>   * @descriptor: USB device descriptor
> + * @bos: USB device BOS descriptor set
>   * @config: all of the device's configs
>   * @actconfig: the active configuration
>   * @ep_in: array of IN endpoints
> @@ -442,6 +454,7 @@ struct usb_device {
>  	struct device dev;
>  
>  	struct usb_device_descriptor descriptor;
> +	struct usb_host_bos *bos;
>  	struct usb_host_config *config;
>  
>  	struct usb_host_config *actconfig;
> -- 
> 1.7.1
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux