Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 265018
b: refs/heads/master
c: 3148bf0
h: refs/heads/master
v: v3
  • Loading branch information
Andiry Xu authored and Greg Kroah-Hartman committed Sep 26, 2011
1 parent e904356 commit ec8e99e
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5023829969f56b78a16da94f34c605bbbb344018
refs/heads/master: 3148bf041d169a083aa31bd69bedd5bfb7ffe215
103 changes: 103 additions & 0 deletions trunk/drivers/usb/core/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -755,3 +755,106 @@ int usb_get_configuration(struct usb_device *dev)
dev_err(ddev, "out of memory\n");
return result;
}

void usb_release_bos_descriptor(struct usb_device *dev)
{
if (dev->bos) {
kfree(dev->bos->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;
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");
if (ret >= 0)
ret = -ENOMSG;
kfree(bos);
return ret;
}

length = bos->bLength;
total_len = le16_to_cpu(bos->wTotalLength);
num = bos->bNumDeviceCaps;
kfree(bos);
if (total_len < length)
return -EINVAL;

dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL);
if (!dev->bos)
return -ENOMEM;

/* Now let's get the whole BOS descriptor set */
buffer = kzalloc(total_len, GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
goto err;
}
dev->bos->desc = (struct usb_bos_descriptor *)buffer;

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");
if (ret >= 0)
ret = -ENOMSG;
goto err;
}
total_len -= length;

for (i = 0; i < num; i++) {
buffer += length;
cap = (struct usb_dev_cap_header *)buffer;
length = cap->bLength;

if (total_len < length)
break;
total_len -= length;

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:
dev->bos->ext_cap =
(struct usb_ext_cap_descriptor *)buffer;
break;
case USB_SS_CAP_TYPE:
dev->bos->ss_cap =
(struct usb_ss_cap_descriptor *)buffer;
break;
case CONTAINER_ID_TYPE:
dev->bos->ss_id =
(struct usb_ss_container_id_descriptor *)buffer;
break;
default:
break;
}
}

return 0;

err:
usb_release_bos_descriptor(dev);
return ret;
}
3 changes: 3 additions & 0 deletions trunk/drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -3083,6 +3083,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}

if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201)
usb_get_bos_descriptor(udev);

retval = 0;
/* notify HCD that we have a device connected and addressed */
if (hcd->driver->update_device)
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/usb/core/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions trunk/drivers/usb/core/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 12 additions & 0 deletions trunk/include/linux/usb.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,16 @@ 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;
struct usb_ss_cap_descriptor *ss_cap;
struct usb_ss_container_id_descriptor *ss_id;
};

int __usb_get_extra_descriptor(char *buffer, unsigned size,
unsigned char type, void **ptr);
#define usb_get_extra_descriptor(ifpoint, type, ptr) \
Expand Down Expand Up @@ -381,6 +391,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
Expand Down Expand Up @@ -442,6 +453,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;
Expand Down

0 comments on commit ec8e99e

Please sign in to comment.