Commit dbe79bbe9dcb22cb3651c46f18943477141ca452

Authored by John Youn
Committed by Sarah Sharp
1 parent ad73dff32e

USB 3.0 Hub Changes

Update the USB core to deal with USB 3.0 hubs.  These hubs have a slightly
different hub descriptor than USB 2.0 hubs, with a fixed (rather than
variable length) size.  Change the USB core's hub descriptor to have a
union for the last fields that differ.  Change the host controller drivers
that access those last fields (DeviceRemovable and PortPowerCtrlMask) to
use the union.

Translate the new version of the hub port status field into the old
version that khubd understands.  (Note: we need to fix it to translate the
roothub's port status once we stop converting it to USB 2.0 hub status
internally.)

Add new code to handle link state change status.  Send out new control
messages that are needed for USB 3.0 hubs, like Set Hub Depth.

This patch is a modified version of the original patch submitted by John
Youn.  It's updated to reflect the removal of the "bitmap" #define, and
change the hub descriptor accesses of a couple new host controller
drivers.

Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
Cc: Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
Cc: Tony Olech <tony.olech@elandigitalsystems.com>
Cc: "Robert P. J. Day" <rpjday@crashcourse.ca>
Cc: Max Vozeler <mvz@vozeler.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Cc: Rodolfo Giometti <giometti@linux.it>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Anton Vorontsov <avorontsov@mvista.com>
Cc: Sebastian Siewior <bigeasy@linutronix.de>
Cc: Lothar Wassmann <LW@KARO-electronics.de>
Cc: Olav Kongas <ok@artecdesign.ee>
Cc: Martin Fuzzey <mfuzzey@gmail.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: David Brownell <dbrownell@users.sourceforge.net>

Showing 17 changed files with 141 additions and 48 deletions Side-by-side Diff

drivers/staging/usbip/vhci_hcd.c
... ... @@ -255,8 +255,8 @@
255 255 desc->wHubCharacteristics = (__force __u16)
256 256 (__constant_cpu_to_le16(0x0001));
257 257 desc->bNbrPorts = VHCI_NPORTS;
258   - desc->DeviceRemovable[0] = 0xff;
259   - desc->DeviceRemovable[1] = 0xff;
  258 + desc->u.hs.DeviceRemovable[0] = 0xff;
  259 + desc->u.hs.DeviceRemovable[1] = 0xff;
260 260 }
261 261  
262 262 static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
drivers/usb/core/hub.c
... ... @@ -82,6 +82,10 @@
82 82 void **port_owners;
83 83 };
84 84  
  85 +static inline int hub_is_superspeed(struct usb_device *hdev)
  86 +{
  87 + return (hdev->descriptor.bDeviceProtocol == 3);
  88 +}
85 89  
86 90 /* Protect struct usb_device->state and ->children members
87 91 * Note: Both are also protected by ->dev.sem, except that ->state can
88 92  
89 93  
90 94  
... ... @@ -172,14 +176,23 @@
172 176 }
173 177  
174 178 /* USB 2.0 spec Section 11.24.4.5 */
175   -static int get_hub_descriptor(struct usb_device *hdev, void *data, int size)
  179 +static int get_hub_descriptor(struct usb_device *hdev, void *data)
176 180 {
177   - int i, ret;
  181 + int i, ret, size;
  182 + unsigned dtype;
178 183  
  184 + if (hub_is_superspeed(hdev)) {
  185 + dtype = USB_DT_SS_HUB;
  186 + size = USB_DT_SS_HUB_SIZE;
  187 + } else {
  188 + dtype = USB_DT_HUB;
  189 + size = sizeof(struct usb_hub_descriptor);
  190 + }
  191 +
179 192 for (i = 0; i < 3; i++) {
180 193 ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
181 194 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
182   - USB_DT_HUB << 8, 0, data, size,
  195 + dtype << 8, 0, data, size,
183 196 USB_CTRL_GET_TIMEOUT);
184 197 if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
185 198 return ret;
... ... @@ -365,6 +378,19 @@
365 378 } else {
366 379 *status = le16_to_cpu(hub->status->port.wPortStatus);
367 380 *change = le16_to_cpu(hub->status->port.wPortChange);
  381 +
  382 + if ((hub->hdev->parent != NULL) &&
  383 + hub_is_superspeed(hub->hdev)) {
  384 + /* Translate the USB 3 port status */
  385 + u16 tmp = *status & USB_SS_PORT_STAT_MASK;
  386 + if (*status & USB_SS_PORT_STAT_POWER)
  387 + tmp |= USB_PORT_STAT_POWER;
  388 + if ((*status & USB_SS_PORT_STAT_SPEED) ==
  389 + USB_PORT_STAT_SPEED_5GBPS)
  390 + tmp |= USB_PORT_STAT_SUPER_SPEED;
  391 + *status = tmp;
  392 + }
  393 +
368 394 ret = 0;
369 395 }
370 396 mutex_unlock(&hub->status_mutex);
... ... @@ -607,7 +633,7 @@
607 633 if (hdev->children[port1-1] && set_state)
608 634 usb_set_device_state(hdev->children[port1-1],
609 635 USB_STATE_NOTATTACHED);
610   - if (!hub->error)
  636 + if (!hub->error && !hub_is_superspeed(hub->hdev))
611 637 ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
612 638 if (ret)
613 639 dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
... ... @@ -795,6 +821,11 @@
795 821 clear_port_feature(hub->hdev, port1,
796 822 USB_PORT_FEAT_C_ENABLE);
797 823 }
  824 + if (portchange & USB_PORT_STAT_C_LINK_STATE) {
  825 + need_debounce_delay = true;
  826 + clear_port_feature(hub->hdev, port1,
  827 + USB_PORT_FEAT_C_PORT_LINK_STATE);
  828 + }
798 829  
799 830 /* We can forget about a "removed" device when there's a
800 831 * physical disconnect or the connect status changes.
801 832  
... ... @@ -964,12 +995,23 @@
964 995 goto fail;
965 996 }
966 997  
  998 + if (hub_is_superspeed(hdev) && (hdev->parent != NULL)) {
  999 + ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
  1000 + HUB_SET_DEPTH, USB_RT_HUB,
  1001 + hdev->level - 1, 0, NULL, 0,
  1002 + USB_CTRL_SET_TIMEOUT);
  1003 +
  1004 + if (ret < 0) {
  1005 + message = "can't set hub depth";
  1006 + goto fail;
  1007 + }
  1008 + }
  1009 +
967 1010 /* Request the entire hub descriptor.
968 1011 * hub->descriptor can handle USB_MAXCHILDREN ports,
969 1012 * but the hub can/will return fewer bytes here.
970 1013 */
971   - ret = get_hub_descriptor(hdev, hub->descriptor,
972   - sizeof(*hub->descriptor));
  1014 + ret = get_hub_descriptor(hdev, hub->descriptor);
973 1015 if (ret < 0) {
974 1016 message = "can't read hub descriptor";
975 1017 goto fail;
976 1018  
... ... @@ -991,12 +1033,14 @@
991 1033  
992 1034 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
993 1035  
994   - if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
  1036 + /* FIXME for USB 3.0, skip for now */
  1037 + if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
  1038 + !(hub_is_superspeed(hdev))) {
995 1039 int i;
996 1040 char portstr [USB_MAXCHILDREN + 1];
997 1041  
998 1042 for (i = 0; i < hdev->maxchild; i++)
999   - portstr[i] = hub->descriptor->DeviceRemovable
  1043 + portstr[i] = hub->descriptor->u.hs.DeviceRemovable
1000 1044 [((i + 1) / 8)] & (1 << ((i + 1) % 8))
1001 1045 ? 'F' : 'R';
1002 1046 portstr[hdev->maxchild] = 0;
... ... @@ -2029,6 +2073,8 @@
2029 2073 udev->speed = USB_SPEED_HIGH;
2030 2074 else if (portstatus & USB_PORT_STAT_LOW_SPEED)
2031 2075 udev->speed = USB_SPEED_LOW;
  2076 + else if (portstatus & USB_PORT_STAT_SUPER_SPEED)
  2077 + udev->speed = USB_SPEED_SUPER;
2032 2078 else
2033 2079 udev->speed = USB_SPEED_FULL;
2034 2080 return 0;
... ... @@ -3429,6 +3475,17 @@
3429 3475 i);
3430 3476 clear_port_feature(hdev, i,
3431 3477 USB_PORT_FEAT_C_RESET);
  3478 + }
  3479 + if (portchange & USB_PORT_STAT_C_LINK_STATE) {
  3480 + clear_port_feature(hub->hdev, i,
  3481 + USB_PORT_FEAT_C_PORT_LINK_STATE);
  3482 + }
  3483 + if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
  3484 + dev_warn(hub_dev,
  3485 + "config error on port %d\n",
  3486 + i);
  3487 + clear_port_feature(hub->hdev, i,
  3488 + USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
3432 3489 }
3433 3490  
3434 3491 if (connect_change)
drivers/usb/gadget/dummy_hcd.c
... ... @@ -1593,8 +1593,8 @@
1593 1593 desc->bDescLength = 9;
1594 1594 desc->wHubCharacteristics = cpu_to_le16(0x0001);
1595 1595 desc->bNbrPorts = 1;
1596   - desc->DeviceRemovable[0] = 0xff;
1597   - desc->DeviceRemovable[1] = 0xff;
  1596 + desc->u.hs.DeviceRemovable[0] = 0xff;
  1597 + desc->u.hs.DeviceRemovable[1] = 0xff;
1598 1598 }
1599 1599  
1600 1600 static int dummy_hub_control (
drivers/usb/host/ehci-hub.c
... ... @@ -717,8 +717,8 @@
717 717 desc->bDescLength = 7 + 2 * temp;
718 718  
719 719 /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
720   - memset(&desc->DeviceRemovable[0], 0, temp);
721   - memset(&desc->DeviceRemovable[temp], 0xff, temp);
  720 + memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
  721 + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
722 722  
723 723 temp = 0x0008; /* per-port overcurrent reporting */
724 724 if (HCS_PPC (ehci->hcs_params))
drivers/usb/host/imx21-hcd.c
... ... @@ -1472,8 +1472,8 @@
1472 1472 0x0010 | /* No over current protection */
1473 1473 0);
1474 1474  
1475   - desc->DeviceRemovable[0] = 1 << 1;
1476   - desc->DeviceRemovable[1] = ~0;
  1475 + desc->u.hs.DeviceRemovable[0] = 1 << 1;
  1476 + desc->u.hs.DeviceRemovable[1] = ~0;
1477 1477 return 0;
1478 1478 }
1479 1479  
drivers/usb/host/isp116x-hcd.c
... ... @@ -952,8 +952,8 @@
952 952 desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) & 0x1f));
953 953 desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff);
954 954 /* ports removable, and legacy PortPwrCtrlMask */
955   - desc->DeviceRemovable[0] = 0;
956   - desc->DeviceRemovable[1] = ~0;
  955 + desc->u.hs.DeviceRemovable[0] = 0;
  956 + desc->u.hs.DeviceRemovable[1] = ~0;
957 957 }
958 958  
959 959 /* Perform reset of a given port.
drivers/usb/host/isp1362-hcd.c
... ... @@ -1553,8 +1553,8 @@
1553 1553 DBG(0, "%s: hubcharacteristics = %02x\n", __func__, cpu_to_le16((reg >> 8) & 0x1f));
1554 1554 desc->bPwrOn2PwrGood = (reg >> 24) & 0xff;
1555 1555 /* ports removable, and legacy PortPwrCtrlMask */
1556   - desc->DeviceRemovable[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
1557   - desc->DeviceRemovable[1] = ~0;
  1556 + desc->u.hs.DeviceRemovable[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
  1557 + desc->u.hs.DeviceRemovable[1] = ~0;
1558 1558  
1559 1559 DBG(3, "%s: exit\n", __func__);
1560 1560 }
drivers/usb/host/isp1760-hcd.c
... ... @@ -1752,8 +1752,8 @@
1752 1752 desc->bDescLength = 7 + 2 * temp;
1753 1753  
1754 1754 /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
1755   - memset(&desc->DeviceRemovable[0], 0, temp);
1756   - memset(&desc->DeviceRemovable[temp], 0xff, temp);
  1755 + memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
  1756 + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
1757 1757  
1758 1758 /* per-port overcurrent reporting */
1759 1759 temp = 0x0008;
drivers/usb/host/ohci-hub.c
... ... @@ -582,13 +582,14 @@
582 582  
583 583 /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
584 584 rh = roothub_b (ohci);
585   - memset(desc->DeviceRemovable, 0xff, sizeof(desc->DeviceRemovable));
586   - desc->DeviceRemovable[0] = rh & RH_B_DR;
  585 + memset(desc->u.hs.DeviceRemovable, 0xff,
  586 + sizeof(desc->u.hs.DeviceRemovable));
  587 + desc->u.hs.DeviceRemovable[0] = rh & RH_B_DR;
587 588 if (ohci->num_ports > 7) {
588   - desc->DeviceRemovable[1] = (rh & RH_B_DR) >> 8;
589   - desc->DeviceRemovable[2] = 0xff;
  589 + desc->u.hs.DeviceRemovable[1] = (rh & RH_B_DR) >> 8;
  590 + desc->u.hs.DeviceRemovable[2] = 0xff;
590 591 } else
591   - desc->DeviceRemovable[1] = 0xff;
  592 + desc->u.hs.DeviceRemovable[1] = 0xff;
592 593 }
593 594  
594 595 /*-------------------------------------------------------------------------*/
drivers/usb/host/oxu210hp-hcd.c
... ... @@ -452,8 +452,8 @@
452 452 desc->bDescLength = 7 + 2 * temp;
453 453  
454 454 /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
455   - memset(&desc->DeviceRemovable[0], 0, temp);
456   - memset(&desc->DeviceRemovable[temp], 0xff, temp);
  455 + memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
  456 + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
457 457  
458 458 temp = 0x0008; /* per-port overcurrent reporting */
459 459 if (HCS_PPC(oxu->hcs_params))
drivers/usb/host/r8a66597-hcd.c
... ... @@ -2150,8 +2150,9 @@
2150 2150 desc->bDescLength = 9;
2151 2151 desc->bPwrOn2PwrGood = 0;
2152 2152 desc->wHubCharacteristics = cpu_to_le16(0x0011);
2153   - desc->DeviceRemovable[0] = ((1 << r8a66597->max_root_hub) - 1) << 1;
2154   - desc->DeviceRemovable[1] = ~0;
  2153 + desc->u.hs.DeviceRemovable[0] =
  2154 + ((1 << r8a66597->max_root_hub) - 1) << 1;
  2155 + desc->u.hs.DeviceRemovable[1] = ~0;
2155 2156 }
2156 2157  
2157 2158 static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
drivers/usb/host/sl811-hcd.c
... ... @@ -1112,8 +1112,8 @@
1112 1112 desc->wHubCharacteristics = cpu_to_le16(temp);
1113 1113  
1114 1114 /* ports removable, and legacy PortPwrCtrlMask */
1115   - desc->DeviceRemovable[0] = 0 << 1;
1116   - desc->DeviceRemovable[1] = ~0;
  1115 + desc->u.hs.DeviceRemovable[0] = 0 << 1;
  1116 + desc->u.hs.DeviceRemovable[1] = ~0;
1117 1117 }
1118 1118  
1119 1119 static void
drivers/usb/host/u132-hcd.c
... ... @@ -2604,13 +2604,14 @@
2604 2604 retval = u132_read_pcimem(u132, roothub.b, &rh_b);
2605 2605 if (retval)
2606 2606 return retval;
2607   - memset(desc->DeviceRemovable, 0xff, sizeof(desc->DeviceRemovable));
2608   - desc->DeviceRemovable[0] = rh_b & RH_B_DR;
  2607 + memset(desc->u.hs.DeviceRemovable, 0xff,
  2608 + sizeof(desc->u.hs.DeviceRemovable));
  2609 + desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR;
2609 2610 if (u132->num_ports > 7) {
2610   - desc->DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8;
2611   - desc->DeviceRemovable[2] = 0xff;
  2611 + desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8;
  2612 + desc->u.hs.DeviceRemovable[2] = 0xff;
2612 2613 } else
2613   - desc->DeviceRemovable[1] = 0xff;
  2614 + desc->u.hs.DeviceRemovable[1] = 0xff;
2614 2615 return 0;
2615 2616 }
2616 2617  
drivers/usb/host/xhci-hub.c
... ... @@ -45,8 +45,8 @@
45 45 temp = 1 + (ports / 8);
46 46 desc->bDescLength = 7 + 2 * temp;
47 47  
48   - memset(&desc->DeviceRemovable[0], 0, temp);
49   - memset(&desc->DeviceRemovable[temp], 0xff, temp);
  48 + memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
  49 + memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
50 50  
51 51 /* Ugh, these should be #defines, FIXME */
52 52 /* Using table 11-13 in USB 2.0 spec. */
drivers/usb/musb/musb_virthub.c
... ... @@ -305,8 +305,8 @@
305 305 desc->bHubContrCurrent = 0;
306 306  
307 307 /* workaround bogus struct definition */
308   - desc->DeviceRemovable[0] = 0x02; /* port 1 */
309   - desc->DeviceRemovable[1] = 0xff;
  308 + desc->u.hs.DeviceRemovable[0] = 0x02; /* port 1 */
  309 + desc->u.hs.DeviceRemovable[1] = 0xff;
310 310 }
311 311 break;
312 312 case GetHubStatus:
drivers/usb/wusbcore/rh.c
... ... @@ -184,8 +184,8 @@
184 184 descr->bPwrOn2PwrGood = 0;
185 185 descr->bHubContrCurrent = 0;
186 186 /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
187   - memset(&descr->DeviceRemovable[0], 0, temp);
188   - memset(&descr->DeviceRemovable[temp], 0xff, temp);
  187 + memset(&descr->u.hs.DeviceRemovable[0], 0, temp);
  188 + memset(&descr->u.hs.DeviceRemovable[temp], 0xff, temp);
189 189 return 0;
190 190 }
191 191  
include/linux/usb/ch11.h
... ... @@ -26,6 +26,7 @@
26 26 #define HUB_RESET_TT 9
27 27 #define HUB_GET_TT_STATE 10
28 28 #define HUB_STOP_TT 11
  29 +#define HUB_SET_DEPTH 12
29 30  
30 31 /*
31 32 * Hub class additional requests defined by USB 3.0 spec
... ... @@ -61,6 +62,12 @@
61 62 #define USB_PORT_FEAT_TEST 21
62 63 #define USB_PORT_FEAT_INDICATOR 22
63 64 #define USB_PORT_FEAT_C_PORT_L1 23
  65 +#define USB_PORT_FEAT_C_PORT_LINK_STATE 25
  66 +#define USB_PORT_FEAT_C_PORT_CONFIG_ERROR 26
  67 +#define USB_PORT_FEAT_PORT_REMOTE_WAKE_MASK 27
  68 +#define USB_PORT_FEAT_BH_PORT_RESET 28
  69 +#define USB_PORT_FEAT_C_BH_PORT_RESET 29
  70 +#define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT 30
64 71  
65 72 /*
66 73 * Port feature selectors added by USB 3.0 spec.
67 74  
... ... @@ -110,8 +117,14 @@
110 117 */
111 118 #define USB_PORT_STAT_LINK_STATE 0x01e0
112 119 #define USB_SS_PORT_STAT_POWER 0x0200
  120 +#define USB_SS_PORT_STAT_SPEED 0x1c00
113 121 #define USB_PORT_STAT_SPEED_5GBPS 0x0000
114 122 /* Valid only if port is enabled */
  123 +/* Bits that are the same from USB 2.0 */
  124 +#define USB_SS_PORT_STAT_MASK (USB_PORT_STAT_CONNECTION | \
  125 + USB_PORT_STAT_ENABLE | \
  126 + USB_PORT_STAT_OVERCURRENT | \
  127 + USB_PORT_STAT_RESET)
115 128  
116 129 /*
117 130 * Definitions for PORT_LINK_STATE values
... ... @@ -141,6 +154,13 @@
141 154 #define USB_PORT_STAT_C_OVERCURRENT 0x0008
142 155 #define USB_PORT_STAT_C_RESET 0x0010
143 156 #define USB_PORT_STAT_C_L1 0x0020
  157 +/*
  158 + * USB 3.0 wPortChange bit fields
  159 + * See USB 3.0 spec Table 10-11
  160 + */
  161 +#define USB_PORT_STAT_C_BH_RESET 0x0020
  162 +#define USB_PORT_STAT_C_LINK_STATE 0x0040
  163 +#define USB_PORT_STAT_C_CONFIG_ERROR 0x0080
144 164  
145 165 /*
146 166 * wHubCharacteristics (masks)
147 167  
... ... @@ -175,7 +195,9 @@
175 195 */
176 196  
177 197 #define USB_DT_HUB (USB_TYPE_CLASS | 0x09)
  198 +#define USB_DT_SS_HUB (USB_TYPE_CLASS | 0x0a)
178 199 #define USB_DT_HUB_NONVAR_SIZE 7
  200 +#define USB_DT_SS_HUB_SIZE 12
179 201  
180 202 struct usb_hub_descriptor {
181 203 __u8 bDescLength;
182 204  
... ... @@ -184,11 +206,22 @@
184 206 __le16 wHubCharacteristics;
185 207 __u8 bPwrOn2PwrGood;
186 208 __u8 bHubContrCurrent;
187   - /* add 1 bit for hub status change; round to bytes */
188   - __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];
189   - __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];
190   -} __attribute__ ((packed));
191 209  
  210 + /* 2.0 and 3.0 hubs differ here */
  211 + union {
  212 + struct {
  213 + /* add 1 bit for hub status change; round to bytes */
  214 + __u8 DeviceRemovable[(USB_MAXCHILDREN + 1 + 7) / 8];
  215 + __u8 PortPwrCtrlMask[(USB_MAXCHILDREN + 1 + 7) / 8];
  216 + } __attribute__ ((packed)) hs;
  217 +
  218 + struct {
  219 + __u8 bHubHdrDecLat;
  220 + __u16 wHubDelay;
  221 + __u16 DeviceRemovable;
  222 + } __attribute__ ((packed)) ss;
  223 + } u;
  224 +} __attribute__ ((packed));
192 225  
193 226 /* port indicator status selectors, tables 11-7 and 11-25 */
194 227 #define HUB_LED_AUTO 0