usb: usbtest: support usb2 extension descriptor test
authorHuang Rui <ray.huang@amd.com>
Wed, 30 Oct 2013 03:27:38 +0000 (11:27 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 30 Oct 2013 16:52:14 +0000 (09:52 -0700)
In Test 9 of usbtest module, it is used for performing chapter 9 tests N
times.

USB2.0 Extension descriptor is one of the generic device-level capbility
descriptors which added in section 9.6.2.1 of USB 3.0 spec.

This patch adds to support getting usb2.0 extension descriptor test
scenario for USB 3.0.

Signed-off-by: Huang Rui <ray.huang@amd.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/misc/usbtest.c

index e7235d5cce857a8f1229bebde8b930b51e1dcbdb..1c78e747f72b3ce63b99dabc1ccd7a2e3af5cf1b 100644 (file)
@@ -606,6 +606,28 @@ static int is_good_config(struct usbtest_dev *tdev, int len)
        return 0;
 }
 
+static int is_good_ext(struct usbtest_dev *tdev, u8 *buf)
+{
+       struct usb_ext_cap_descriptor *ext;
+       u32 attr;
+
+       ext = (struct usb_ext_cap_descriptor *) buf;
+
+       if (ext->bLength != USB_DT_USB_EXT_CAP_SIZE) {
+               ERROR(tdev, "bogus usb 2.0 extension descriptor length\n");
+               return 0;
+       }
+
+       attr = le32_to_cpu(ext->bmAttributes);
+       /* bits[1:4] is used and others are reserved */
+       if (attr & ~0x1e) {     /* reserved == 0 */
+               ERROR(tdev, "reserved bits set\n");
+               return 0;
+       }
+
+       return 1;
+}
+
 /* sanity test for standard requests working with usb_control_mesg() and some
  * of the utility functions which use it.
  *
@@ -694,12 +716,67 @@ static int ch9_postconfig(struct usbtest_dev *dev)
         * 3.0 spec
         */
        if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0300) {
+               struct usb_bos_descriptor *bos = NULL;
+               struct usb_dev_cap_header *header = NULL;
+               unsigned total, num, length;
+               u8 *buf;
+
                retval = usb_get_descriptor(udev, USB_DT_BOS, 0, dev->buf,
                                sizeof(*udev->bos->desc));
                if (retval != sizeof(*udev->bos->desc)) {
                        dev_err(&iface->dev, "bos descriptor --> %d\n", retval);
                        return (retval < 0) ? retval : -EDOM;
                }
+
+               bos = (struct usb_bos_descriptor *)dev->buf;
+               total = le16_to_cpu(bos->wTotalLength);
+               num = bos->bNumDeviceCaps;
+
+               if (total > TBUF_SIZE)
+                       total = TBUF_SIZE;
+
+               /*
+                * get generic device-level capability descriptors [9.6.2]
+                * in USB 3.0 spec
+                */
+               retval = usb_get_descriptor(udev, USB_DT_BOS, 0, dev->buf,
+                               total);
+               if (retval != total) {
+                       dev_err(&iface->dev, "bos descriptor set --> %d\n",
+                                       retval);
+                       return (retval < 0) ? retval : -EDOM;
+               }
+
+               length = sizeof(*udev->bos->desc);
+               buf = dev->buf;
+               for (i = 0; i < num; i++) {
+                       buf += length;
+                       if (buf + sizeof(struct usb_dev_cap_header) >
+                                       dev->buf + total)
+                               break;
+
+                       header = (struct usb_dev_cap_header *)buf;
+                       length = header->bLength;
+
+                       if (header->bDescriptorType !=
+                                       USB_DT_DEVICE_CAPABILITY) {
+                               dev_warn(&udev->dev, "not device capability descriptor, skip\n");
+                               continue;
+                       }
+
+                       switch (header->bDevCapabilityType) {
+                       case USB_CAP_TYPE_EXT:
+                               if (buf + USB_DT_USB_EXT_CAP_SIZE >
+                                               dev->buf + total ||
+                                               !is_good_ext(dev, buf)) {
+                                       dev_err(&iface->dev, "bogus usb 2.0 extension descriptor\n");
+                                       return -EDOM;
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
        }
 
        /* there's always [9.4.3] at least one config descriptor [9.6.3] */