/* Fill in the USB 3.0 roothub descriptor */ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, struct usb_hub_descriptor *desc) { int ports; u16 port_removable; u32 portsc; unsigned int i; ports = xhci->num_usb3_ports; xhci_common_hub_descriptor(xhci, desc, ports); desc->bDescriptorType = USB_DT_SS_HUB; desc->bDescLength = USB_DT_SS_HUB_SIZE; /* header decode latency should be zero for roothubs, * see section 4.23.5.2. */ desc->u.ss.bHubHdrDecLat = 0; desc->u.ss.wHubDelay = 0; port_removable = 0; /* bit 0 is reserved, bit 1 is for port 1, etc. */ for (i = 0; i < ports; i++) { portsc = xhci_readl(xhci, xhci->usb3_ports[i]); if (portsc & PORT_DEV_REMOVE) port_removable |= 1 << (i + 1); } memset(&desc->u.ss.DeviceRemovable, (__force __u16) cpu_to_le16(port_removable), sizeof(__u16)); }
/* Fill in the USB 2.0 roothub descriptor */ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, struct usb_hub_descriptor *desc) { int ports; u16 temp; __u8 port_removable[(USB_MAXCHILDREN + 1 + 7) / 8]; u32 portsc; unsigned int i; ports = xhci->num_usb2_ports; xhci_common_hub_descriptor(xhci, desc, ports); desc->bDescriptorType = USB_DT_HUB; temp = 1 + (ports / 8); desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp; /* The Device Removable bits are reported on a byte granularity. * If the port doesn't exist within that byte, the bit is set to 0. */ memset(port_removable, 0, sizeof(port_removable)); for (i = 0; i < ports; i++) { portsc = readl(xhci->usb2_ports[i]); /* If a device is removable, PORTSC reports a 0, same as in the * hub descriptor DeviceRemovable bits. */ if (portsc & PORT_DEV_REMOVE) /* This math is hairy because bit 0 of DeviceRemovable * is reserved, and bit 1 is for port 1, etc. */ port_removable[(i + 1) / 8] |= 1 << ((i + 1) % 8); } /* ch11.h defines a hub descriptor that has room for USB_MAXCHILDREN * ports on it. The USB 2.0 specification says that there are two * variable length fields at the end of the hub descriptor: * DeviceRemovable and PortPwrCtrlMask. But since we can have less than * USB_MAXCHILDREN ports, we may need to use the DeviceRemovable array * to set PortPwrCtrlMask bits. PortPwrCtrlMask must always be set to * 0xFF, so we initialize the both arrays (DeviceRemovable and * PortPwrCtrlMask) to 0xFF. Then we set the DeviceRemovable for each * set of ports that actually exist. */ memset(desc->u.hs.DeviceRemovable, 0xff, sizeof(desc->u.hs.DeviceRemovable)); memset(desc->u.hs.PortPwrCtrlMask, 0xff, sizeof(desc->u.hs.PortPwrCtrlMask)); for (i = 0; i < (ports + 1 + 7) / 8; i++) memset(&desc->u.hs.DeviceRemovable[i], port_removable[i], sizeof(__u8)); }