Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dbe79bbe authored by John Youn's avatar John Youn Committed by Sarah Sharp
Browse files

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: default avatarJohn Youn <johnyoun@synopsys.com>
Signed-off-by: default avatarSarah 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>
parent ad73dff3
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -255,8 +255,8 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc)
	desc->wHubCharacteristics = (__force __u16)
		(__constant_cpu_to_le16(0x0001));
	desc->bNbrPorts = VHCI_NPORTS;
	desc->DeviceRemovable[0] = 0xff;
	desc->DeviceRemovable[1] = 0xff;
	desc->u.hs.DeviceRemovable[0] = 0xff;
	desc->u.hs.DeviceRemovable[1] = 0xff;
}

static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+65 −8
Original line number Diff line number Diff line
@@ -82,6 +82,10 @@ struct usb_hub {
	void			**port_owners;
};

static inline int hub_is_superspeed(struct usb_device *hdev)
{
	return (hdev->descriptor.bDeviceProtocol == 3);
}

/* Protect struct usb_device->state and ->children members
 * Note: Both are also protected by ->dev.sem, except that ->state can
@@ -172,14 +176,23 @@ static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
}

/* USB 2.0 spec Section 11.24.4.5 */
static int get_hub_descriptor(struct usb_device *hdev, void *data, int size)
static int get_hub_descriptor(struct usb_device *hdev, void *data)
{
	int i, ret;
	int i, ret, size;
	unsigned dtype;

	if (hub_is_superspeed(hdev)) {
		dtype = USB_DT_SS_HUB;
		size = USB_DT_SS_HUB_SIZE;
	} else {
		dtype = USB_DT_HUB;
		size = sizeof(struct usb_hub_descriptor);
	}

	for (i = 0; i < 3; i++) {
		ret = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
			USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
			USB_DT_HUB << 8, 0, data, size,
			dtype << 8, 0, data, size,
			USB_CTRL_GET_TIMEOUT);
		if (ret >= (USB_DT_HUB_NONVAR_SIZE + 2))
			return ret;
@@ -365,6 +378,19 @@ static int hub_port_status(struct usb_hub *hub, int port1,
	} else {
		*status = le16_to_cpu(hub->status->port.wPortStatus);
		*change = le16_to_cpu(hub->status->port.wPortChange);

		if ((hub->hdev->parent != NULL) &&
				hub_is_superspeed(hub->hdev)) {
			/* Translate the USB 3 port status */
			u16 tmp = *status & USB_SS_PORT_STAT_MASK;
			if (*status & USB_SS_PORT_STAT_POWER)
				tmp |= USB_PORT_STAT_POWER;
			if ((*status & USB_SS_PORT_STAT_SPEED) ==
					USB_PORT_STAT_SPEED_5GBPS)
				tmp |= USB_PORT_STAT_SUPER_SPEED;
			*status = tmp;
		}

		ret = 0;
	}
	mutex_unlock(&hub->status_mutex);
@@ -607,7 +633,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
	if (hdev->children[port1-1] && set_state)
		usb_set_device_state(hdev->children[port1-1],
				USB_STATE_NOTATTACHED);
	if (!hub->error)
	if (!hub->error && !hub_is_superspeed(hub->hdev))
		ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
	if (ret)
		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
@@ -795,6 +821,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
			clear_port_feature(hub->hdev, port1,
					USB_PORT_FEAT_C_ENABLE);
		}
		if (portchange & USB_PORT_STAT_C_LINK_STATE) {
			need_debounce_delay = true;
			clear_port_feature(hub->hdev, port1,
					USB_PORT_FEAT_C_PORT_LINK_STATE);
		}

		/* We can forget about a "removed" device when there's a
		 * physical disconnect or the connect status changes.
@@ -964,12 +995,23 @@ static int hub_configure(struct usb_hub *hub,
		goto fail;
	}

	if (hub_is_superspeed(hdev) && (hdev->parent != NULL)) {
		ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
				HUB_SET_DEPTH, USB_RT_HUB,
				hdev->level - 1, 0, NULL, 0,
				USB_CTRL_SET_TIMEOUT);

		if (ret < 0) {
			message = "can't set hub depth";
			goto fail;
		}
	}

	/* Request the entire hub descriptor.
	 * hub->descriptor can handle USB_MAXCHILDREN ports,
	 * but the hub can/will return fewer bytes here.
	 */
	ret = get_hub_descriptor(hdev, hub->descriptor,
			sizeof(*hub->descriptor));
	ret = get_hub_descriptor(hdev, hub->descriptor);
	if (ret < 0) {
		message = "can't read hub descriptor";
		goto fail;
@@ -991,12 +1033,14 @@ static int hub_configure(struct usb_hub *hub,

	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);

	if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
	/* FIXME for USB 3.0, skip for now */
	if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
			!(hub_is_superspeed(hdev))) {
		int	i;
		char	portstr [USB_MAXCHILDREN + 1];

		for (i = 0; i < hdev->maxchild; i++)
			portstr[i] = hub->descriptor->DeviceRemovable
			portstr[i] = hub->descriptor->u.hs.DeviceRemovable
				    [((i + 1) / 8)] & (1 << ((i + 1) % 8))
				? 'F' : 'R';
		portstr[hdev->maxchild] = 0;
@@ -2029,6 +2073,8 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
				udev->speed = USB_SPEED_HIGH;
			else if (portstatus & USB_PORT_STAT_LOW_SPEED)
				udev->speed = USB_SPEED_LOW;
			else if (portstatus & USB_PORT_STAT_SUPER_SPEED)
				udev->speed = USB_SPEED_SUPER;
			else
				udev->speed = USB_SPEED_FULL;
			return 0;
@@ -3430,6 +3476,17 @@ static void hub_events(void)
				clear_port_feature(hdev, i,
					USB_PORT_FEAT_C_RESET);
			}
			if (portchange & USB_PORT_STAT_C_LINK_STATE) {
				clear_port_feature(hub->hdev, i,
						USB_PORT_FEAT_C_PORT_LINK_STATE);
			}
			if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) {
				dev_warn(hub_dev,
					"config error on port %d\n",
					i);
				clear_port_feature(hub->hdev, i,
						USB_PORT_FEAT_C_PORT_CONFIG_ERROR);
			}

			if (connect_change)
				hub_port_connect_change(hub, i,
+2 −2
Original line number Diff line number Diff line
@@ -1593,8 +1593,8 @@ hub_descriptor (struct usb_hub_descriptor *desc)
	desc->bDescLength = 9;
	desc->wHubCharacteristics = cpu_to_le16(0x0001);
	desc->bNbrPorts = 1;
	desc->DeviceRemovable[0] = 0xff;
	desc->DeviceRemovable[1] = 0xff;
	desc->u.hs.DeviceRemovable[0] = 0xff;
	desc->u.hs.DeviceRemovable[1] = 0xff;
}

static int dummy_hub_control (
+2 −2
Original line number Diff line number Diff line
@@ -717,8 +717,8 @@ ehci_hub_descriptor (
	desc->bDescLength = 7 + 2 * temp;

	/* two bitmaps:  ports removable, and usb 1.0 legacy PortPwrCtrlMask */
	memset(&desc->DeviceRemovable[0], 0, temp);
	memset(&desc->DeviceRemovable[temp], 0xff, temp);
	memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
	memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);

	temp = 0x0008;			/* per-port overcurrent reporting */
	if (HCS_PPC (ehci->hcs_params))
+2 −2
Original line number Diff line number Diff line
@@ -1472,8 +1472,8 @@ static int get_hub_descriptor(struct usb_hcd *hcd,
		0x0010 |	/* No over current protection */
		0);

	desc->DeviceRemovable[0] = 1 << 1;
	desc->DeviceRemovable[1] = ~0;
	desc->u.hs.DeviceRemovable[0] = 1 << 1;
	desc->u.hs.DeviceRemovable[1] = ~0;
	return 0;
}

Loading