usb: emul: hub: Report the actual device speed of the emulation device
authorBin Meng <bmeng.cn@gmail.com>
Sun, 1 Oct 2017 13:19:41 +0000 (06:19 -0700)
committerMarek Vasut <marex@denx.de>
Sun, 1 Oct 2017 14:32:51 +0000 (16:32 +0200)
At present the usb hub emulator always reports its downstream port
speed as full speed. Actually it is high speed for sandbox-flash,
and low speed for sandbox-keyb. We can determine the device speed
by checking its device descriptor bcdUSB field, and do the proper
hub port status report based on that.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
drivers/usb/emul/sandbox_hub.c

index 8ed7a0f43456510e4c1008dac9b57b9c90ba9c18..9a0f47b81c4d041b2d13b1329e3d2a0928e0a281 100644 (file)
@@ -121,9 +121,12 @@ struct sandbox_hub_priv {
        int change[SANDBOX_NUM_PORTS];
 };
 
-static struct udevice *hub_find_device(struct udevice *hub, int port)
+static struct udevice *hub_find_device(struct udevice *hub, int port,
+                                      enum usb_device_speed *speed)
 {
        struct udevice *dev;
+       struct usb_generic_descriptor **gen_desc;
+       struct usb_device_descriptor **dev_desc;
 
        for (device_find_first_child(hub, &dev);
             dev;
@@ -131,8 +134,27 @@ static struct udevice *hub_find_device(struct udevice *hub, int port)
                struct sandbox_hub_platdata *plat;
 
                plat = dev_get_parent_platdata(dev);
-               if (plat->port == port)
+               if (plat->port == port) {
+                       gen_desc = plat->plat.desc_list;
+                       gen_desc = usb_emul_find_descriptor(gen_desc,
+                                                           USB_DT_DEVICE, 0);
+                       dev_desc = (struct usb_device_descriptor **)gen_desc;
+
+                       switch (le16_to_cpu((*dev_desc)->bcdUSB)) {
+                       case 0x0100:
+                               *speed = USB_SPEED_LOW;
+                               break;
+                       case 0x0101:
+                               *speed = USB_SPEED_FULL;
+                               break;
+                       case 0x0200:
+                       default:
+                               *speed = USB_SPEED_HIGH;
+                               break;
+                       }
+
                        return dev;
+               }
        }
 
        return NULL;
@@ -146,7 +168,8 @@ static int clrset_post_state(struct udevice *hub, int port, int clear, int set)
        int ret = 0;
 
        if ((clear | set) & USB_PORT_STAT_POWER) {
-               struct udevice *dev = hub_find_device(hub, port);
+               enum usb_device_speed speed;
+               struct udevice *dev = hub_find_device(hub, port, &speed);
 
                if (dev) {
                        if (set & USB_PORT_STAT_POWER) {
@@ -156,6 +179,10 @@ static int clrset_post_state(struct udevice *hub, int port, int clear, int set)
                                if (!ret) {
                                        set |= USB_PORT_STAT_CONNECTION |
                                                USB_PORT_STAT_ENABLE;
+                                       if (speed == USB_SPEED_LOW)
+                                               set |= USB_PORT_STAT_LOW_SPEED;
+                                       else if (speed == USB_SPEED_HIGH)
+                                               set |= USB_PORT_STAT_HIGH_SPEED;
                                }
 
                        } else if (clear & USB_PORT_STAT_POWER) {