Skip to contentSkip to conversation

usb: Adding SuperSpeed support to dummy_hcd

PATCH Superseded Tatyana Brokhman 4 participants 10 messages Mar 23, 2011 – Apr 28, 2011

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH v8 1/5 usb: Adding SuperSpeed support to dummy_hcd

This patch adds SS support to the dummy hcd module. It may be used to test SS device when no (SS) HW is available.
USB 3.0 hub includes 2 hubs - HS and SS ones.
This patch adds support for a SS hub in the dummy_hcd module. Thus, when dummy_hcd enabled it will register 2 root hubs (SS and HS).

drivers/usb/gadget/dummy_hcd.c +511 -8
index 3214ca3..4f4db96 100644
@@ -62,9 +62,12 @@
 #define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
 
 static const char	driver_name [] = "dummy_hcd";
+static const char	ss_driver_name[] = "ss_dummy_hcd";
 static const char	driver_desc [] = "USB Host+Gadget Emulator";
+static const char	ss_driver_desc[] = "SS USB Host+Gadget Emulator";
 
 static const char	gadget_name [] = "dummy_udc";
+static const char	ss_gadget_name[] = "ss_dummy_udc";
 
 MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_AUTHOR ("David Brownell");
@@ -220,6 +223,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
 }
 
 static struct dummy			*the_controller;
+static struct dummy			*the_ss_controller;
 
 /*-------------------------------------------------------------------------*/
 
@@ -259,10 +263,94 @@ stop_activity (struct dummy *dum)
 	/* driver now does any non-usb quiescing necessary */
 }
 
-/* caller must hold lock */
+/**
+ * set_ss_link_state() - Sets the current state of the SuperSpeed link
+ * @dum: pointer to the dummy_hcd structure to update the link
+ *     state for
+ *
+ * This function updates the port_status according to the link
+ * state. The old status is saved befor updating.
+ * Note: this function should be called only for SuperSpeed
+ * master and the caller must hold the lock.
+ */
+static void
+set_ss_link_state(struct dummy *dum)
+{
+	dum->active = 0;
+	if ((dum->port_status & USB_SS_PORT_STAT_POWER) == 0)
+		dum->port_status = 0;
+
+	/* UDC suspend must cause a disconnect */
+	else if (!dum->pullup || dum->udc_suspended) {
+		dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
+					USB_PORT_STAT_ENABLE);
+		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
+			dum->port_status |=
+					(USB_PORT_STAT_C_CONNECTION << 16);
+	} else {
+		/* device is connected and not suspended */
+		dum->port_status |= (USB_PORT_STAT_CONNECTION |
+				     USB_PORT_STAT_SPEED_5GBPS) ;
+		if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
+			dum->port_status |=
+				(USB_PORT_STAT_C_CONNECTION << 16);
+		if ((dum->port_status & USB_PORT_STAT_ENABLE) == 1 &&
+		    (dum->port_status & USB_SS_PORT_LS_U0) == 1 &&
+		    dum->rh_state != DUMMY_RH_SUSPENDED)
+			dum->active = 1;
+	}
+
+
+	if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
+		dum->resuming = 0;
+
+	/* if !connected or reset */
+	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+			(dum->port_status & USB_PORT_STAT_RESET) != 0) {
+		/*
+		 * We're connected and not reseted (reset occured now),
+		 * and driver attached - disconnect!
+		 */
+		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+		    (dum->old_status & USB_PORT_STAT_RESET) == 0 &&
+		    dum->driver) {
+			stop_activity(dum);
+			spin_unlock(&dum->lock);
+			dum->driver->disconnect(&dum->gadget);
+			spin_lock(&dum->lock);
+		}
+	} else if (dum->active != dum->old_active) {
+		if (dum->old_active && dum->driver->suspend) {
+			spin_unlock(&dum->lock);
+			dum->driver->suspend(&dum->gadget);
+			spin_lock(&dum->lock);
+		} else if (!dum->old_active &&  dum->driver->resume) {
+			spin_unlock(&dum->lock);
+			dum->driver->resume(&dum->gadget);
+			spin_lock(&dum->lock);
+		}
+	}
+
+	dum->old_status = dum->port_status;
+	dum->old_active = dum->active;
+}
+
+/**
+ * set_link_state() - Sets the current state of the link
+ * @dum: pointer to the dummy_hcd structure to update the link
+ *     state for
+ *
+ * This function updates the port_status according to the link
+ * state. The old status is saved befor updating.
+ * Note: caller must hold the lock.
+ */
 static void
 set_link_state (struct dummy *dum)
 {
+	if (dum == the_ss_controller) {
+		set_ss_link_state(dum);
+		return;
+	}
 	dum->active = 0;
 	if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
 		dum->port_status = 0;
@@ -343,7 +431,13 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 	dum = ep_to_dummy (ep);
 	if (!dum->driver || !is_enabled (dum))
 		return -ESHUTDOWN;
-	max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff;
+
+	/*
+	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
+	 * maximum packet size.
+	 * For SS devices the wMaxPacketSize is limited by 1024.
+	 */
+	max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
 
 	/* drivers must not request bad settings, since lower levels
 	 * (hardware or its drivers) may not check.  some endpoints
@@ -361,6 +455,10 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 		}
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
+			if (max == 1024)
+				break;
+			goto done;
 		case USB_SPEED_HIGH:
 			if (max == 512)
 				break;
@@ -379,6 +477,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 		/* real hardware might not handle all packet sizes */
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
 		case USB_SPEED_HIGH:
 			if (max <= 1024)
 				break;
@@ -399,6 +498,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 		/* real hardware might not handle all packet sizes */
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
 		case USB_SPEED_HIGH:
 			if (max <= 1024)
 				break;
@@ -751,9 +851,14 @@ int
 usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
-	struct dummy	*dum = the_controller;
+	struct dummy	*dum;
 	int		retval, i;
 
+	if (driver->speed == USB_SPEED_SUPER)
+		dum = the_ss_controller;
+	else
+		dum = the_controller;
+
 	if (!dum)
 		return -EINVAL;
 	if (dum->driver)
@@ -787,7 +892,11 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	}
 
 	dum->gadget.ep0 = &dum->ep [0].ep;
-	dum->ep [0].ep.maxpacket = 64;
+	dum->gadget.speed = driver->speed;
+	if (driver->speed == USB_SPEED_SUPER)
+		dum->ep[0].ep.maxpacket = 9;
+	else
+		dum->ep[0].ep.maxpacket = 64;
 	list_del_init (&dum->ep [0].ep.ep_list);
 	INIT_LIST_HEAD(&dum->fifo_req.queue);
 
@@ -817,12 +926,20 @@ EXPORT_SYMBOL(usb_gadget_probe_driver);
 int
 usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 {
-	struct dummy	*dum = the_controller;
+	struct dummy	*dum ;
 	unsigned long	flags;
 
+	if (!driver || !driver->unbind)
+		return -EINVAL;
+
+	if (driver->speed == USB_SPEED_SUPER)
+		dum = the_ss_controller;
+	else
+		dum = the_controller;
+
 	if (!dum)
 		return -ENODEV;
-	if (!driver || driver != dum->driver || !driver->unbind)
+	if (driver != dum->driver)
 		return -EINVAL;
 
 	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
@@ -899,6 +1016,34 @@ static int dummy_udc_probe (struct platform_device *pdev)
 	return rc;
 }
 
+static int dummy_ss_udc_probe(struct platform_device *pdev)
+{
+	struct dummy	*dum = the_ss_controller;
+	int		rc;
+
+	dum->gadget.name = gadget_name;
+	dum->gadget.ops = &dummy_ops;
+	dum->gadget.is_dualspeed = 1;
+
+	/* maybe claim OTG support, though we won't complete HNP */
+	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
+
+	dev_set_name(&dum->gadget.dev, "ss_gadget");
+	dum->gadget.dev.parent = &pdev->dev;
+	dum->gadget.dev.release = dummy_gadget_release;
+	rc = device_register(&dum->gadget.dev);
+	if (rc < 0)
+		return rc;
+
+	usb_get_hcd(dummy_to_hcd(dum));
+
+	platform_set_drvdata(pdev, dum);
+	rc = device_create_file(&dum->gadget.dev, &dev_attr_function);
+	if (rc < 0)
+		device_unregister(&dum->gadget.dev);
+	return rc;
+}
+
 static int dummy_udc_remove (struct platform_device *pdev)
 {
 	struct dummy	*dum = platform_get_drvdata (pdev);
@@ -948,6 +1093,17 @@ static struct platform_driver dummy_udc_driver = {
 	},
 };
 
+static struct platform_driver dummy_ss_udc_driver = {
+	.probe		= dummy_ss_udc_probe,
+	.remove		= dummy_udc_remove,
+	.suspend	= dummy_udc_suspend,
+	.resume		= dummy_udc_resume,
+	.driver		= {
+		.name	= (char *) ss_gadget_name,
+		.owner	= THIS_MODULE,
+	},
+};
+
 /*-------------------------------------------------------------------------*/
 
 /* MASTER/HOST SIDE DRIVER
@@ -1161,6 +1317,21 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
 		tmp *= 8 /* applies to entire frame */;
 		limit += limit * tmp;
 	}
+	if (dum->gadget.speed == USB_SPEED_SUPER) {
+		switch (ep->desc->bmAttributes & 0x03) {
+		case USB_ENDPOINT_XFER_ISOC:
+			/* Sec. 4.4.8.2 USB3.0 Spec */
+			limit = 3 * 16 * 1024 * 8;
+			break;
+		case USB_ENDPOINT_XFER_INT:
+			/* Sec. 4.4.7.2 USB3.0 Spec */
+			limit = 3 * 1024 * 8;
+			break;
+		case USB_ENDPOINT_XFER_BULK:
+		default:
+			break;
+		}
+	}
 	return limit;
 }
 
@@ -1246,6 +1417,24 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
 			case USB_DEVICE_A_ALT_HNP_SUPPORT:
 				dum->gadget.a_alt_hnp_support = 1;
 				break;
+			case USB_DEVICE_U1_ENABLE:
+				if (dum->gadget.speed == USB_SPEED_SUPER)
+					w_value = USB_DEV_STAT_U1_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_U2_ENABLE:
+				if (dum->gadget.speed == USB_SPEED_SUPER)
+					w_value = USB_DEV_STAT_U2_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_LTM_ENABLE:
+				if (dum->gadget.speed == USB_SPEED_SUPER)
+					w_value = USB_DEV_STAT_LTM_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
 			default:
 				ret_val = -EOPNOTSUPP;
 			}
@@ -1272,6 +1461,24 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
 			case USB_DEVICE_REMOTE_WAKEUP:
 				w_value = USB_DEVICE_REMOTE_WAKEUP;
 				break;
+			case USB_DEVICE_U1_ENABLE:
+				if (dum->gadget.speed == USB_SPEED_SUPER)
+					w_value = USB_DEV_STAT_U1_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_U2_ENABLE:
+				if (dum->gadget.speed == USB_SPEED_SUPER)
+					w_value = USB_DEV_STAT_U2_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_LTM_ENABLE:
+				if (dum->gadget.speed == USB_SPEED_SUPER)
+					w_value = USB_DEV_STAT_LTM_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
 			default:
 				ret_val = -EOPNOTSUPP;
 				break;
@@ -1352,6 +1559,10 @@ static void dummy_timer (unsigned long _dum)
 	case USB_SPEED_HIGH:
 		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
 		break;
+	case USB_SPEED_SUPER:
+		/* Bus speed is 500000 bytes/ms, so use a little less */
+		total = 490000;
+		break;
 	default:
 		dev_err (dummy_dev(dum), "bogus device speed\n");
 		return;
@@ -1597,7 +1808,184 @@ hub_descriptor (struct usb_hub_descriptor *desc)
 	desc->u.hs.DeviceRemovable[1] = 0xff;
 }
 
-static int dummy_hub_control (
+static inline void
+ss_hub_descriptor(struct usb_hub_descriptor *desc)
+{
+	memset(desc, 0, sizeof *desc);
+	desc->bDescriptorType = 0x2a;
+	desc->bDescLength = 12;
+	desc->wHubCharacteristics = cpu_to_le16(0x0001);
+	desc->bNbrPorts = 1;
+	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
+	desc->u.ss.DeviceRemovable = 0xffff;
+}
+
+/**
+ * dummy_ss_hub_control() - handles the control requests of the dummy (ss hub)
+ * master.
+ * @hcd: pointer to the hcd to handle
+ * @typeReq: type of the request
+ * @wValue: wValue of the request
+ * @wIndex: wIndex of the request
+ * @buf: buffer for reply in case of an IN request
+ * @wLength: wLength of the request
+ *
+ * Return int - 0 on success, error code otherwise
+ *
+ * This function handles the control requests of the dummy (ss
+ * hub) master. All control requests that are part of the
+ * enumeration are handled by the dummy_timer
+ * Note: this function is used only for the SS root hub
+ */
+static int dummy_ss_hub_control(
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength)
+{
+	struct dummy		*dum;
+	int		retval = 0;
+	unsigned long	flags;
+
+	if (!HCD_HW_ACCESSIBLE(hcd))
+		return -ETIMEDOUT;
+
+	dum = hcd_to_dummy(hcd);
+	spin_lock_irqsave(&dum->lock, flags);
+	switch (typeReq) {
+	case ClearHubFeature:
+		break;
+	case ClearPortFeature:
+		switch (wValue) {
+		case USB_PORT_FEAT_POWER:
+			if (dum->port_status & USB_SS_PORT_STAT_POWER)
+				dev_dbg(dummy_dev(dum), "power-off\n");
+			/* FALLS THROUGH */
+		default:
+			dum->port_status &= ~(1 << wValue);
+			set_link_state(dum);
+		}
+		break;
+	case GetHubDescriptor:
+		ss_hub_descriptor((struct usb_hub_descriptor *) buf);
+		break;
+	case GetHubStatus:
+		/*
+		 * We report that no change occured in the hub status
+		 * (power and overcurent conditions)
+		 */
+		*(__le32 *) buf = cpu_to_le32 (0);
+		break;
+	case GetPortStatus:
+		/* We have only one port */
+		if (wIndex != 1)
+			retval = -EPIPE;
+
+		/*
+		 * whoever resets or resumes must GetPortStatus to
+		 * complete it!!
+		 */
+		/* TODO: add support for suspend/resume */
+		if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
+			time_after_eq(jiffies, dum->re_timeout)) {
+			dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
+			dum->port_status &= ~USB_PORT_STAT_RESET;
+		}
+		if (dum->pullup)
+			dum->port_status |= USB_PORT_STAT_ENABLE;
+
+		set_link_state(dum);
+
+		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
+		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
+		break;
+	case SetHubFeature:
+		retval = -EPIPE;
+		break;
+	case SetPortFeature:
+		switch (wValue) {
+		case USB_PORT_FEAT_LINK_STATE:
+			/*
+			 * Since this is dummy we don't have an actual link so
+			 * there is nothing to do for the SET_LINK_STATE cmd
+			 */
+			break;
+		case USB_PORT_FEAT_U1_TIMEOUT:
+		case USB_PORT_FEAT_U2_TIMEOUT:
+			/* TODO: add suspend/resume support! */
+			break;
+		case USB_PORT_FEAT_POWER:
+			dum->port_status |= USB_SS_PORT_STAT_POWER;
+			set_link_state(dum);
+			break;
+		case USB_PORT_FEAT_BH_PORT_RESET:
+		case USB_PORT_FEAT_RESET:
+			/* if it's already enabled, disable */
+			dum->port_status = 0;
+			dum->port_status = (USB_SS_PORT_STAT_POWER |
+					       USB_PORT_STAT_CONNECTION |
+					       USB_PORT_STAT_RESET);
+			/*
+			 * We want to reset device status. All but the
+			 * Self powered feature
+			 */
+			dum->devstatus &= 0x0000 |
+				(1 << USB_DEVICE_SELF_POWERED);
+			/*
+			 * FIXME: what is the correct reset signaling interval?
+			 * Is it still 50msec as for HS?
+			 */
+			dum->re_timeout = jiffies + msecs_to_jiffies(50);
+			/* FALLS THROUGH */
+		default:
+			if ((dum->port_status &
+			     USB_SS_PORT_STAT_POWER) != 0) {
+				dum->port_status |= (1 << wValue);
+				set_link_state(dum);
+			}
+		}
+		break;
+	case GetPortErrorCount:
+		/* We'll always return 0 since this is a dummy hub */
+		*(__le32 *) buf = cpu_to_le32 (0);
+		break;
+	case SetHubDepth:
+		break;
+	default:
+		dev_dbg(dummy_dev(dum),
+			"hub control req%04x v%04x i%04x l%d\n",
+			typeReq, wValue, wIndex, wLength);
+		/* "protocol stall" on error */
+		retval = -EPIPE;
+	}
+	spin_unlock_irqrestore(&dum->lock, flags);
+
+	if ((dum->port_status & PORT_C_MASK) != 0)
+		usb_hcd_poll_rh_status(hcd);
+	return retval;
+}
+
+
+/**
+ * dummy_hub_control() - handles the control requests of the dummy (hs hub)
+ * master.
+ * @hcd: pointer to the hcd to handle
+ * @typeReq: type of the request
+ * @wValue: wValue of the request
+ * @wIndex: wIndex of the request
+ * @buf: buffer for reply in case of an IN request
+ * @wLength: wLength of the request
+ *
+ * Return int - 0 on success, error code otherwise
+ *
+ * This function handles the control requests of the dummy (hs
+ * hub) master. All control requests that are part of the
+ * enumeration are handled by the dummy_timer
+ * Note: this function is used only for the HS root hub
+ */
+static int dummy_hub_control(
 	struct usb_hcd	*hcd,
 	u16		typeReq,
 	u16		wValue,
@@ -1711,7 +2099,11 @@ static int dummy_hub_control (
 			dum->port_status &= ~(USB_PORT_STAT_ENABLE
 					| USB_PORT_STAT_LOW_SPEED
 					| USB_PORT_STAT_HIGH_SPEED);
-			dum->devstatus = 0;
+			/*
+			 * We want to reset device status. All but the
+			 * Self powered feature
+			 */
+			dum->devstatus &= (1 << USB_DEVICE_SELF_POWERED);
 			/* 50msec reset signaling */
 			dum->re_timeout = jiffies + msecs_to_jiffies(50);
 			/* FALLS THROUGH */
@@ -1788,6 +2180,9 @@ show_urb (char *buf, size_t size, struct urb *urb)
 		 case USB_SPEED_LOW:	s = "ls"; break;
 		 case USB_SPEED_FULL:	s = "fs"; break;
 		 case USB_SPEED_HIGH:	s = "hs"; break;
+		 case USB_SPEED_SUPER:
+			 s = "ss";
+			 break;
 		 default:		s = "?"; break;
 		 }; s; }),
 		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
@@ -1894,6 +2289,27 @@ static const struct hc_driver dummy_hcd = {
 	.bus_resume =		dummy_bus_resume,
 };
 
+static const struct hc_driver dummy_ss_hcd = {
+	.description =		(char *) ss_driver_name,
+	.product_desc =		"Dummy SS host controller",
+	.hcd_priv_size =	sizeof(struct dummy),
+
+	.flags =		HCD_USB3,
+
+	.start =		dummy_start,
+	.stop =			dummy_stop,
+
+	.urb_enqueue =		dummy_urb_enqueue,
+	.urb_dequeue =		dummy_urb_dequeue,
+
+	.get_frame_number =	dummy_h_get_frame,
+
+	.hub_status_data =	dummy_hub_status,
+	.hub_control =		dummy_ss_hub_control,
+	.bus_suspend =		dummy_bus_suspend,
+	.bus_resume =		dummy_bus_resume,
+};
+
 static int dummy_hcd_probe(struct platform_device *pdev)
 {
 	struct usb_hcd		*hcd;
@@ -1914,6 +2330,26 @@ static int dummy_hcd_probe(struct platform_device *pdev)
 	return retval;
 }
 
+static int dummy_hcd_probe_ss(struct platform_device *pdev)
+{
+	struct usb_hcd		*hcd;
+	int			retval;
+
+	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", ss_driver_desc);
+
+	hcd = usb_create_hcd(&dummy_ss_hcd, &pdev->dev, dev_name(&pdev->dev));
+	if (!hcd)
+		return -ENOMEM;
+	the_ss_controller = hcd_to_dummy(hcd);
+
+	retval = usb_add_hcd(hcd, 0, 0);
+	if (retval != 0) {
+		usb_put_hcd(hcd);
+		the_ss_controller = NULL;
+	}
+	return retval;
+}
+
 static int dummy_hcd_remove (struct platform_device *pdev)
 {
 	struct usb_hcd		*hcd;
@@ -1925,6 +2361,17 @@ static int dummy_hcd_remove (struct platform_device *pdev)
 	return 0;
 }
 
+static int dummy_ss_hcd_remove(struct platform_device *pdev)
+{
+	struct usb_hcd		*hcd;
+
+	hcd = platform_get_drvdata(pdev);
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
+	the_ss_controller = NULL;
+	return 0;
+}
+
 static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
 {
 	struct usb_hcd		*hcd;
@@ -1966,10 +2413,23 @@ static struct platform_driver dummy_hcd_driver = {
 	},
 };
 
+static struct platform_driver dummy_ss_hcd_driver = {
+	.probe		= dummy_hcd_probe_ss,
+	.remove		= dummy_ss_hcd_remove,
+	.suspend	= dummy_hcd_suspend,
+	.resume		= dummy_hcd_resume,
+	.driver		= {
+		.name	= (char *) ss_driver_name,
+		.owner	= THIS_MODULE,
+	},
+};
+
 /*-------------------------------------------------------------------------*/
 
 static struct platform_device *the_udc_pdev;
+static struct platform_device *the_ss_udc_pdev;
 static struct platform_device *the_hcd_pdev;
+static struct platform_device *the_ss_hcd_pdev;
 
 static int __init init (void)
 {
@@ -1981,34 +2441,73 @@ static int __init init (void)
 	the_hcd_pdev = platform_device_alloc(driver_name, -1);
 	if (!the_hcd_pdev)
 		return retval;
+
+	the_ss_hcd_pdev = platform_device_alloc(ss_driver_name, -1);
+	if (!the_ss_hcd_pdev)
+		goto err_alloc_ss_hcd;
+
 	the_udc_pdev = platform_device_alloc(gadget_name, -1);
 	if (!the_udc_pdev)
 		goto err_alloc_udc;
 
+	the_ss_udc_pdev = platform_device_alloc(ss_gadget_name, -1);
+	if (!the_ss_udc_pdev)
+		goto err_alloc_ss_udc;
+
 	retval = platform_driver_register(&dummy_hcd_driver);
 	if (retval < 0)
 		goto err_register_hcd_driver;
+
+	retval = platform_driver_register(&dummy_ss_hcd_driver);
+	if (retval < 0)
+		goto err_register_ss_hcd_driver;
+
 	retval = platform_driver_register(&dummy_udc_driver);
 	if (retval < 0)
 		goto err_register_udc_driver;
 
+	retval = platform_driver_register(&dummy_ss_udc_driver);
+	if (retval < 0)
+		goto err_register_ss_udc_driver;
+
 	retval = platform_device_add(the_hcd_pdev);
 	if (retval < 0)
 		goto err_add_hcd;
+
+	retval = platform_device_add(the_ss_hcd_pdev);
+	if (retval < 0)
+		goto err_add_ss_hcd;
+
 	retval = platform_device_add(the_udc_pdev);
 	if (retval < 0)
 		goto err_add_udc;
+
+	retval = platform_device_add(the_ss_udc_pdev);
+	if (retval < 0)
+		goto err_add_ss_udc;
 	return retval;
 
+err_add_ss_udc:
+	platform_device_unregister(the_udc_pdev);
 err_add_udc:
+	platform_device_del(the_ss_hcd_pdev);
+err_add_ss_hcd:
 	platform_device_del(the_hcd_pdev);
 err_add_hcd:
+	platform_driver_unregister(&dummy_ss_udc_driver);
+err_register_ss_udc_driver:
 	platform_driver_unregister(&dummy_udc_driver);
 err_register_udc_driver:
+	platform_driver_unregister(&dummy_ss_hcd_driver);
+err_register_ss_hcd_driver:
 	platform_driver_unregister(&dummy_hcd_driver);
 err_register_hcd_driver:
+	platform_device_put(the_ss_udc_pdev);
+err_alloc_ss_udc:
 	platform_device_put(the_udc_pdev);
 err_alloc_udc:
+	platform_device_put(the_ss_hcd_pdev);
+err_alloc_ss_hcd:
 	platform_device_put(the_hcd_pdev);
 	return retval;
 }
@@ -2017,8 +2516,12 @@ module_init (init);
 static void __exit cleanup (void)
 {
 	platform_device_unregister(the_udc_pdev);
+	platform_device_unregister(the_ss_udc_pdev);
 	platform_device_unregister(the_hcd_pdev);
+	platform_device_unregister(the_ss_hcd_pdev);
 	platform_driver_unregister(&dummy_udc_driver);
+	platform_driver_unregister(&dummy_ss_udc_driver);
 	platform_driver_unregister(&dummy_hcd_driver);
+	platform_driver_unregister(&dummy_ss_hcd_driver);
 }
 module_exit (cleanup);
Signature · 4 lines
1.7.3.3
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
#1 lore raw

Hi,

Quoted 7 lines · Tatyana Brokhman

This patch adds SS support to the dummy hcd module. It may be used to test SS device when no (SS) HW is available.
USB 3.0 hub includes 2 hubs - HS and SS ones.
This patch adds support for a SS hub in the dummy_hcd module. Thus, when dummy_hcd enabled it will register 2 root hubs (SS and HS).

missing tear line.

Quoted 18 lines
drivers/usb/gadget/dummy_hcd.c +3 -0
index 3214ca3..4f4db96 100644
@@ -62,9 +62,12 @@
 #define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
 
 static const char	driver_name [] = "dummy_hcd";
+static const char	ss_driver_name[] = "ss_dummy_hcd";
 static const char	driver_desc [] = "USB Host+Gadget Emulator";
+static const char	ss_driver_desc[] = "SS USB Host+Gadget Emulator";
 
 static const char	gadget_name [] = "dummy_udc";
+static const char	ss_gadget_name[] = "ss_dummy_udc";
 
 MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_AUTHOR ("David Brownell");

drivers/usb/gadget/dummy_hcd.c static inline struct dummy *gadget_dev_to_dummy (struct device *dev) · line 226

Quoted 4 lines
drivers/usb/gadget/dummy_hcd.c +1 -0
@@ -220,6 +223,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
 }
 
 static struct dummy			*the_controller;
+static struct dummy			*the_ss_controller;

the only thing I don't like, is why you splitted the ss controller to a separate controller. Why don't you use the same ? From SW perspective, we can treat SS and HS/FS/LS controllers as one unit.

Signature · 5 lines
balbi
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#2 lore raw

Hi

Quoted 5 lines

Review static inline struct dummy *gadget_dev_to_dummy

Quoted 4 lines

MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_AUTHOR ("David Brownell");

(quoted diff) +0 -0
@@ -220,6 +223,7 @@ static inline struct dummy *gadget_dev_to_dummy

(struct device *dev)

Quoted 9 lines

drivers/usb/gadget/dummy_hcd.c static inline struct dummy *gadget_dev_to_dummy (struct device *dev) · line 226

Quoted 4 lines
drivers/usb/gadget/dummy_hcd.c +1 -0
 }
 
 static struct dummy			*the_controller;
+static struct dummy			*the_ss_controller;

the only thing I don't like, is why you splitted the ss controller to a separate controller. Why don't you use the same ? From SW perspective, we can treat SS and HS/FS/LS controllers as one unit.

Actually I'm not sure about that... Because SS controller handles things a bit differently than HS/FS/LS. For example look at set_ss_link_state(), the port status is reported differently than for HS/FS/LS devices. It could be done, I mean spare the the_ss_controller variable and use the_controller, and we did that at first, but later on we decided to go back to this implementation since the code got too complex. Since dummy_hcd.c is used for debugging purposes we decided that simplicity is the better approach here.

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

#3 lore raw
Quoted 17 lines · Tanya Brokhman

Hi

Quoted 5 lines

Review static inline struct dummy *gadget_dev_to_dummy

Quoted 4 lines

MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_AUTHOR ("David Brownell");

(quoted diff) +0 -0
@@ -220,6 +223,7 @@ static inline struct dummy *gadget_dev_to_dummy

(struct device *dev)

Quoted 9 lines

drivers/usb/gadget/dummy_hcd.c static inline struct dummy *gadget_dev_to_dummy (struct device *dev) · line 226

Quoted 4 lines
drivers/usb/gadget/dummy_hcd.c +1 -0
 }
 
 static struct dummy			*the_controller;
+static struct dummy			*the_ss_controller;

the only thing I don't like, is why you splitted the ss controller to a separate controller. Why don't you use the same ? From SW perspective, we can treat SS and HS/FS/LS controllers as one unit.

Quoted 8 lines

Actually I'm not sure about that... Because SS controller handles things a bit differently than HS/FS/LS. For example look at set_ss_link_state(), the port status is reported differently than for HS/FS/LS devices. It could be done, I mean spare the the_ss_controller variable and use the_controller, and we did that at first, but later on we decided to go back to this implementation since the code got too complex. Since dummy_hcd.c is used for debugging purposes we decided that simplicity is the better approach here.

you can have two different functions and decide which one to call by checking gadget->speed.

Signature · 1 line
balbi
#4 lore raw

PATCH 1/1 usb: merge the two dummy_hcds into one

This patch merges the two HCDs so there is one for both.

---
 drivers/usb/gadget/dummy_hcd.c |  353 ++++++++++++----------------------------
 1 files changed, 102 insertions(+), 251 deletions(-)
drivers/usb/gadget/dummy_hcd.c +102 -251
index 634c4ec..db44183 100644
@@ -62,12 +62,9 @@
 #define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */
 
 static const char	driver_name [] = "dummy_hcd";
-static const char	ss_driver_name[] = "ss_dummy_hcd";
 static const char	driver_desc [] = "USB Host+Gadget Emulator";
-static const char	ss_driver_desc[] = "SS USB Host+Gadget Emulator";
 
 static const char	gadget_name [] = "dummy_udc";
-static const char	ss_gadget_name[] = "ss_dummy_udc";
 
 MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_AUTHOR ("David Brownell");
@@ -223,7 +220,6 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
 }
 
 static struct dummy			*the_controller;
-static struct dummy			*the_ss_controller;
 
 /*-------------------------------------------------------------------------*/
 
@@ -263,8 +259,73 @@ stop_activity (struct dummy *dum)
 	/* driver now does any non-usb quiescing necessary */
 }
 
+
 /**
- * set_ss_link_state() - Sets the current state of the SuperSpeed link
+ * set_link_state_usb2() - Sets the current state of the link
+ * @dum: pointer to the dummy_hcd structure to update the link
+ *     state for
+ *
+ * This function updates the port_status according to the link
+ * state. The old status is saved befor updating.
+ * Note: caller must hold the lock.
+ */
+static void set_link_state_usb2(struct dummy *dum)
+{
+	dum->active = 0;
+	if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
+		dum->port_status = 0;
+
+	/* UDC suspend must cause a disconnect */
+	else if (!dum->pullup || dum->udc_suspended) {
+		dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
+					USB_PORT_STAT_ENABLE |
+					USB_PORT_STAT_LOW_SPEED |
+					USB_PORT_STAT_HIGH_SPEED |
+					USB_PORT_STAT_SUSPEND);
+		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
+			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+	} else {
+		dum->port_status |= USB_PORT_STAT_CONNECTION;
+		if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
+			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+		if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
+			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+		else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+				dum->rh_state != DUMMY_RH_SUSPENDED)
+			dum->active = 1;
+	}
+
+	if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
+		dum->resuming = 0;
+
+	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+			(dum->port_status & USB_PORT_STAT_RESET) != 0) {
+		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+				(dum->old_status & USB_PORT_STAT_RESET) == 0 &&
+				dum->driver) {
+			stop_activity (dum);
+			spin_unlock (&dum->lock);
+			dum->driver->disconnect (&dum->gadget);
+			spin_lock (&dum->lock);
+		}
+	} else if (dum->active != dum->old_active) {
+		if (dum->old_active && dum->driver->suspend) {
+			spin_unlock (&dum->lock);
+			dum->driver->suspend (&dum->gadget);
+			spin_lock (&dum->lock);
+		} else if (!dum->old_active && dum->driver->resume) {
+			spin_unlock (&dum->lock);
+			dum->driver->resume (&dum->gadget);
+			spin_lock (&dum->lock);
+		}
+	}
+
+	dum->old_status = dum->port_status;
+	dum->old_active = dum->active;
+}
+
+/**
+ * set_link_state_usb3() - Sets the current state of the SuperSpeed link
  * @dum: pointer to the dummy_hcd structure to update the link
  *     state for
  *
@@ -273,8 +334,7 @@ stop_activity (struct dummy *dum)
  * Note: this function should be called only for SuperSpeed
  * master and the caller must hold the lock.
  */
-static void
-set_ss_link_state(struct dummy *dum)
+static void set_link_state_usb3(struct dummy *dum)
 {
 	dum->active = 0;
 	if ((dum->port_status & USB_SS_PORT_STAT_POWER) == 0)
@@ -335,73 +395,14 @@ set_ss_link_state(struct dummy *dum)
 	dum->old_active = dum->active;
 }
 
-/**
- * set_link_state() - Sets the current state of the link
- * @dum: pointer to the dummy_hcd structure to update the link
- *     state for
- *
- * This function updates the port_status according to the link
- * state. The old status is saved befor updating.
- * Note: caller must hold the lock.
- */
-static void
-set_link_state (struct dummy *dum)
+static void set_link_state(struct dummy *dum)
 {
-	if (dum == the_ss_controller) {
-		set_ss_link_state(dum);
-		return;
-	}
-	dum->active = 0;
-	if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
-		dum->port_status = 0;
-
-	/* UDC suspend must cause a disconnect */
-	else if (!dum->pullup || dum->udc_suspended) {
-		dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
-					USB_PORT_STAT_ENABLE |
-					USB_PORT_STAT_LOW_SPEED |
-					USB_PORT_STAT_HIGH_SPEED |
-					USB_PORT_STAT_SUSPEND);
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
-			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
-	} else {
-		dum->port_status |= USB_PORT_STAT_CONNECTION;
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
-			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
-		if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
-			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
-		else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
-				dum->rh_state != DUMMY_RH_SUSPENDED)
-			dum->active = 1;
-	}
-
-	if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
-		dum->resuming = 0;
-
-	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
-			(dum->port_status & USB_PORT_STAT_RESET) != 0) {
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
-				(dum->old_status & USB_PORT_STAT_RESET) == 0 &&
-				dum->driver) {
-			stop_activity (dum);
-			spin_unlock (&dum->lock);
-			dum->driver->disconnect (&dum->gadget);
-			spin_lock (&dum->lock);
-		}
-	} else if (dum->active != dum->old_active) {
-		if (dum->old_active && dum->driver->suspend) {
-			spin_unlock (&dum->lock);
-			dum->driver->suspend (&dum->gadget);
-			spin_lock (&dum->lock);
-		} else if (!dum->old_active && dum->driver->resume) {
-			spin_unlock (&dum->lock);
-			dum->driver->resume (&dum->gadget);
-			spin_lock (&dum->lock);
-		}
-	}
+	struct usb_hcd	*hcd = dummy_to_hcd(dum);
 
-	dum->old_status = dum->port_status;
-	dum->old_active = dum->active;
+	if (hcd->speed == HCD_USB3)
+		set_link_state_usb3(dum);
+	else
+		set_link_state_usb2(dum);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -851,14 +852,9 @@ int
 usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 {
-	struct dummy	*dum;
+	struct dummy	*dum = the_controller;
 	int		retval, i;
 
-	if (driver->speed == USB_SPEED_SUPER)
-		dum = the_ss_controller;
-	else
-		dum = the_controller;
-
 	if (!dum)
 		return -EINVAL;
 	if (dum->driver)
@@ -926,17 +922,12 @@ EXPORT_SYMBOL(usb_gadget_probe_driver);
 int
 usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 {
-	struct dummy	*dum ;
+	struct dummy	*dum = the_controller;
 	unsigned long	flags;
 
 	if (!driver || !driver->unbind)
 		return -EINVAL;
 
-	if (driver->speed == USB_SPEED_SUPER)
-		dum = the_ss_controller;
-	else
-		dum = the_controller;
-
 	if (!dum)
 		return -ENODEV;
 	if (driver != dum->driver)
@@ -1018,34 +1009,6 @@ static int dummy_udc_probe (struct platform_device *pdev)
 	return rc;
 }
 
-static int dummy_ss_udc_probe(struct platform_device *pdev)
-{
-	struct dummy	*dum = the_ss_controller;
-	int		rc;
-
-	dum->gadget.name = gadget_name;
-	dum->gadget.ops = &dummy_ops;
-	dum->gadget.is_dualspeed = 1;
-
-	/* maybe claim OTG support, though we won't complete HNP */
-	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
-
-	dev_set_name(&dum->gadget.dev, "ss_gadget");
-	dum->gadget.dev.parent = &pdev->dev;
-	dum->gadget.dev.release = dummy_gadget_release;
-	rc = device_register(&dum->gadget.dev);
-	if (rc < 0)
-		return rc;
-
-	usb_get_hcd(dummy_to_hcd(dum));
-
-	platform_set_drvdata(pdev, dum);
-	rc = device_create_file(&dum->gadget.dev, &dev_attr_function);
-	if (rc < 0)
-		device_unregister(&dum->gadget.dev);
-	return rc;
-}
-
 static int dummy_udc_remove (struct platform_device *pdev)
 {
 	struct dummy	*dum = platform_get_drvdata (pdev);
@@ -1095,17 +1058,6 @@ static struct platform_driver dummy_udc_driver = {
 	},
 };
 
-static struct platform_driver dummy_ss_udc_driver = {
-	.probe		= dummy_ss_udc_probe,
-	.remove		= dummy_udc_remove,
-	.suspend	= dummy_udc_suspend,
-	.resume		= dummy_udc_resume,
-	.driver		= {
-		.name	= (char *) ss_gadget_name,
-		.owner	= THIS_MODULE,
-	},
-};
-
 /*-------------------------------------------------------------------------*/
 
 /* MASTER/HOST SIDE DRIVER
@@ -1823,7 +1775,7 @@ ss_hub_descriptor(struct usb_hub_descriptor *desc)
 }
 
 /**
- * dummy_ss_hub_control() - handles the control requests of the dummy (ss hub)
+ * dummy_hub_control_usb3() - handles the control requests of the dummy (ss hub)
  * master.
  * @hcd: pointer to the hcd to handle
  * @typeReq: type of the request
@@ -1839,7 +1791,7 @@ ss_hub_descriptor(struct usb_hub_descriptor *desc)
  * enumeration are handled by the dummy_timer
  * Note: this function is used only for the SS root hub
  */
-static int dummy_ss_hub_control(
+static int dummy_hub_control_usb3(
 	struct usb_hcd	*hcd,
 	u16		typeReq,
 	u16		wValue,
@@ -1867,7 +1819,7 @@ static int dummy_ss_hub_control(
 			/* FALLS THROUGH */
 		default:
 			dum->port_status &= ~(1 << wValue);
-			set_link_state(dum);
+			set_link_state_usb3(dum);
 		}
 		break;
 	case GetHubDescriptor:
@@ -1898,7 +1850,7 @@ static int dummy_ss_hub_control(
 		if (dum->pullup)
 			dum->port_status |= USB_PORT_STAT_ENABLE;
 
-		set_link_state(dum);
+		set_link_state_usb3(dum);
 
 		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
 		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
@@ -1920,7 +1872,7 @@ static int dummy_ss_hub_control(
 			break;
 		case USB_PORT_FEAT_POWER:
 			dum->port_status |= USB_SS_PORT_STAT_POWER;
-			set_link_state(dum);
+			set_link_state_usb3(dum);
 			break;
 		case USB_PORT_FEAT_BH_PORT_RESET:
 		case USB_PORT_FEAT_RESET:
@@ -1933,8 +1885,7 @@ static int dummy_ss_hub_control(
 			 * We want to reset device status. All but the
 			 * Self powered feature
 			 */
-			dum->devstatus &= 0x0000 |
-				(1 << USB_DEVICE_SELF_POWERED);
+			dum->devstatus &= (1 << USB_DEVICE_SELF_POWERED);
 			/*
 			 * FIXME: what is the correct reset signaling interval?
 			 * Is it still 50msec as for HS?
@@ -1945,7 +1896,7 @@ static int dummy_ss_hub_control(
 			if ((dum->port_status &
 			     USB_SS_PORT_STAT_POWER) != 0) {
 				dum->port_status |= (1 << wValue);
-				set_link_state(dum);
+				set_link_state_usb3(dum);
 			}
 		}
 		break;
@@ -1969,9 +1920,8 @@ static int dummy_ss_hub_control(
 	return retval;
 }
 
-
 /**
- * dummy_hub_control() - handles the control requests of the dummy (hs hub)
+ * dummy_hub_control_usb2() - handles the control requests of the dummy (hs hub)
  * master.
  * @hcd: pointer to the hcd to handle
  * @typeReq: type of the request
@@ -1987,7 +1937,7 @@ static int dummy_ss_hub_control(
  * enumeration are handled by the dummy_timer
  * Note: this function is used only for the HS root hub
  */
-static int dummy_hub_control(
+static int dummy_hub_control_usb2(
 	struct usb_hcd	*hcd,
 	u16		typeReq,
 	u16		wValue,
@@ -2023,7 +1973,7 @@ static int dummy_hub_control(
 			/* FALLS THROUGH */
 		default:
 			dum->port_status &= ~(1 << wValue);
-			set_link_state (dum);
+			set_link_state_usb2(dum);
 		}
 		break;
 	case GetHubDescriptor:
@@ -2069,7 +2019,7 @@ static int dummy_hub_control(
 				}
 			}
 		}
-		set_link_state (dum);
+		set_link_state_usb2(dum);
 		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
 		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
 		break;
@@ -2085,7 +2035,7 @@ static int dummy_hub_control(
 				/* HNP would happen here; for now we
 				 * assume b_bus_req is always true.
 				 */
-				set_link_state (dum);
+				set_link_state_usb2(dum);
 				if (((1 << USB_DEVICE_B_HNP_ENABLE)
 						& dum->devstatus) != 0)
 					dev_dbg (dummy_dev(dum),
@@ -2094,7 +2044,7 @@ static int dummy_hub_control(
 			break;
 		case USB_PORT_FEAT_POWER:
 			dum->port_status |= USB_PORT_STAT_POWER;
-			set_link_state (dum);
+			set_link_state_usb2(dum);
 			break;
 		case USB_PORT_FEAT_RESET:
 			/* if it's already enabled, disable */
@@ -2112,7 +2062,7 @@ static int dummy_hub_control(
 		default:
 			if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
 				dum->port_status |= (1 << wValue);
-				set_link_state (dum);
+				set_link_state_usb2(dum);
 			}
 		}
 		break;
@@ -2132,6 +2082,17 @@ static int dummy_hub_control(
 	return retval;
 }
 
+static int dummy_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+		u16 wIndex, char *buf, u16 wLength)
+{
+	if (hcd->speed == HCD_USB3)
+		return dummy_hub_control_usb3(hcd, typeReq, wValue, wIndex, buf,
+			wLength);
+
+	return dummy_hub_control_usb2(hcd, typeReq, wValue, wIndex, buf,
+			wLength);
+}
+
 static int dummy_bus_suspend (struct usb_hcd *hcd)
 {
 	struct dummy *dum = hcd_to_dummy (hcd);
@@ -2182,9 +2143,7 @@ show_urb (char *buf, size_t size, struct urb *urb)
 		 case USB_SPEED_LOW:	s = "ls"; break;
 		 case USB_SPEED_FULL:	s = "fs"; break;
 		 case USB_SPEED_HIGH:	s = "hs"; break;
-		 case USB_SPEED_SUPER:
-			 s = "ss";
-			 break;
+		 case USB_SPEED_SUPER:	s = "ss"; break;
 		 default:		s = "?"; break;
 		 }; s; }),
 		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
@@ -2275,7 +2234,7 @@ static const struct hc_driver dummy_hcd = {
 	.product_desc =		"Dummy host controller",
 	.hcd_priv_size =	sizeof(struct dummy),
 
-	.flags =		HCD_USB2,
+	.flags =		HCD_USB3,
 
 	.start =		dummy_start,
 	.stop =			dummy_stop,
@@ -2291,27 +2250,6 @@ static const struct hc_driver dummy_hcd = {
 	.bus_resume =		dummy_bus_resume,
 };
 
-static const struct hc_driver dummy_ss_hcd = {
-	.description =		(char *) ss_driver_name,
-	.product_desc =		"Dummy SS host controller",
-	.hcd_priv_size =	sizeof(struct dummy),
-
-	.flags =		HCD_USB3,
-
-	.start =		dummy_start,
-	.stop =			dummy_stop,
-
-	.urb_enqueue =		dummy_urb_enqueue,
-	.urb_dequeue =		dummy_urb_dequeue,
-
-	.get_frame_number =	dummy_h_get_frame,
-
-	.hub_status_data =	dummy_hub_status,
-	.hub_control =		dummy_ss_hub_control,
-	.bus_suspend =		dummy_bus_suspend,
-	.bus_resume =		dummy_bus_resume,
-};
-
 static int dummy_hcd_probe(struct platform_device *pdev)
 {
 	struct usb_hcd		*hcd;
@@ -2332,26 +2270,6 @@ static int dummy_hcd_probe(struct platform_device *pdev)
 	return retval;
 }
 
-static int dummy_hcd_probe_ss(struct platform_device *pdev)
-{
-	struct usb_hcd		*hcd;
-	int			retval;
-
-	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", ss_driver_desc);
-
-	hcd = usb_create_hcd(&dummy_ss_hcd, &pdev->dev, dev_name(&pdev->dev));
-	if (!hcd)
-		return -ENOMEM;
-	the_ss_controller = hcd_to_dummy(hcd);
-
-	retval = usb_add_hcd(hcd, 0, 0);
-	if (retval != 0) {
-		usb_put_hcd(hcd);
-		the_ss_controller = NULL;
-	}
-	return retval;
-}
-
 static int dummy_hcd_remove (struct platform_device *pdev)
 {
 	struct usb_hcd		*hcd;
@@ -2363,17 +2281,6 @@ static int dummy_hcd_remove (struct platform_device *pdev)
 	return 0;
 }
 
-static int dummy_ss_hcd_remove(struct platform_device *pdev)
-{
-	struct usb_hcd		*hcd;
-
-	hcd = platform_get_drvdata(pdev);
-	usb_remove_hcd(hcd);
-	usb_put_hcd(hcd);
-	the_ss_controller = NULL;
-	return 0;
-}
-
 static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
 {
 	struct usb_hcd		*hcd;
@@ -2415,23 +2322,10 @@ static struct platform_driver dummy_hcd_driver = {
 	},
 };
 
-static struct platform_driver dummy_ss_hcd_driver = {
-	.probe		= dummy_hcd_probe_ss,
-	.remove		= dummy_ss_hcd_remove,
-	.suspend	= dummy_hcd_suspend,
-	.resume		= dummy_hcd_resume,
-	.driver		= {
-		.name	= (char *) ss_driver_name,
-		.owner	= THIS_MODULE,
-	},
-};
-
 /*-------------------------------------------------------------------------*/
 
 static struct platform_device *the_udc_pdev;
-static struct platform_device *the_ss_udc_pdev;
 static struct platform_device *the_hcd_pdev;
-static struct platform_device *the_ss_hcd_pdev;
 
 static int __init init (void)
 {
@@ -2443,73 +2337,34 @@ static int __init init (void)
 	the_hcd_pdev = platform_device_alloc(driver_name, -1);
 	if (!the_hcd_pdev)
 		return retval;
-
-	the_ss_hcd_pdev = platform_device_alloc(ss_driver_name, -1);
-	if (!the_ss_hcd_pdev)
-		goto err_alloc_ss_hcd;
-
 	the_udc_pdev = platform_device_alloc(gadget_name, -1);
 	if (!the_udc_pdev)
 		goto err_alloc_udc;
 
-	the_ss_udc_pdev = platform_device_alloc(ss_gadget_name, -1);
-	if (!the_ss_udc_pdev)
-		goto err_alloc_ss_udc;
-
 	retval = platform_driver_register(&dummy_hcd_driver);
 	if (retval < 0)
 		goto err_register_hcd_driver;
-
-	retval = platform_driver_register(&dummy_ss_hcd_driver);
-	if (retval < 0)
-		goto err_register_ss_hcd_driver;
-
 	retval = platform_driver_register(&dummy_udc_driver);
 	if (retval < 0)
 		goto err_register_udc_driver;
 
-	retval = platform_driver_register(&dummy_ss_udc_driver);
-	if (retval < 0)
-		goto err_register_ss_udc_driver;
-
 	retval = platform_device_add(the_hcd_pdev);
 	if (retval < 0)
 		goto err_add_hcd;
-
-	retval = platform_device_add(the_ss_hcd_pdev);
-	if (retval < 0)
-		goto err_add_ss_hcd;
-
 	retval = platform_device_add(the_udc_pdev);
 	if (retval < 0)
 		goto err_add_udc;
-
-	retval = platform_device_add(the_ss_udc_pdev);
-	if (retval < 0)
-		goto err_add_ss_udc;
 	return retval;
 
-err_add_ss_udc:
-	platform_device_unregister(the_udc_pdev);
 err_add_udc:
-	platform_device_del(the_ss_hcd_pdev);
-err_add_ss_hcd:
 	platform_device_del(the_hcd_pdev);
 err_add_hcd:
-	platform_driver_unregister(&dummy_ss_udc_driver);
-err_register_ss_udc_driver:
 	platform_driver_unregister(&dummy_udc_driver);
 err_register_udc_driver:
-	platform_driver_unregister(&dummy_ss_hcd_driver);
-err_register_ss_hcd_driver:
 	platform_driver_unregister(&dummy_hcd_driver);
 err_register_hcd_driver:
-	platform_device_put(the_ss_udc_pdev);
-err_alloc_ss_udc:
 	platform_device_put(the_udc_pdev);
 err_alloc_udc:
-	platform_device_put(the_ss_hcd_pdev);
-err_alloc_ss_hcd:
 	platform_device_put(the_hcd_pdev);
 	return retval;
 }
@@ -2518,12 +2373,8 @@ module_init (init);
 static void __exit cleanup (void)
 {
 	platform_device_unregister(the_udc_pdev);
-	platform_device_unregister(the_ss_udc_pdev);
 	platform_device_unregister(the_hcd_pdev);
-	platform_device_unregister(the_ss_hcd_pdev);
 	platform_driver_unregister(&dummy_udc_driver);
-	platform_driver_unregister(&dummy_ss_udc_driver);
 	platform_driver_unregister(&dummy_hcd_driver);
-	platform_driver_unregister(&dummy_ss_hcd_driver);
 }
 module_exit (cleanup);
Signature · 6 lines
1.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#5 lore raw

Re: [PATCH] usb: merge the two dummy_hcds into one

Quoted 1 line · Sebastian Andrzej Siewior

This patch merges the two HCDs so there is one for both.

It is too premature for this.

In fact, the support for USB-3 HCDs is currently in flux. Sarah Sharp has submitted a whole bunch of patches to allow for the creation of primary and secondary HCDs, representing the USB-2 and USB-3 root hubs of an xHCI controller. dummy-hcd should use the same mechanism.

This will means creating only one host-side platform device, and then creating two usb_hcd structures below it. Tanya's design should be based on Sarah's work.

Alan Stern

#6 lore raw

Re: [PATCH] usb: merge the two dummy_hcds into one

Quoted 4 lines · * Alan Stern | 2011-04-14 11:45:34 [-0400]:

In fact, the support for USB-3 HCDs is currently in flux. Sarah Sharp has submitted a whole bunch of patches to allow for the creation of primary and secondary HCDs, representing the USB-2 and USB-3 root hubs of an xHCI controller. dummy-hcd should use the same mechanism.

Yeah, after I merged those two I've seen that I can't assign USB2 and USB3 at the same time so I looked what xhci is doing in this case.

Quoted 3 lines

This will means creating only one host-side platform device, and then creating two usb_hcd structures below it. Tanya's design should be based on Sarah's work.

Yes, it makes sense.

Quoted 1 line

Alan Stern

Sebastian

#7 lore raw

RE: [PATCH] usb: merge the two dummy_hcds into one

In reply to Alan Stern
Quoted 6 lines · Sebastian Andrzej Siewior
Quoted 2 lines

This patch merges the two HCDs so there is one for both.

It is too premature for this.

Quoted 9 lines

In fact, the support for USB-3 HCDs is currently in flux. Sarah Sharp has submitted a whole bunch of patches to allow for the creation of primary and secondary HCDs, representing the USB-2 and USB-3 root hubs of an xHCI controller. dummy-hcd should use the same mechanism.

This will means creating only one host-side platform device, and then creating two usb_hcd structures below it. Tanya's design should be based on Sarah's work.

Hi Alan

Thank you for your inputs. I'm not familiar with Sarah's work you mentioned. I'll have to look into that. Could you please point me to where I can find this code? Has it been merged into linux-next yet or just posted on the mailing list?

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum

#8 lore raw

Re: [PATCH] usb: merge the two dummy_hcds into one

Quoted 6 lines · Tanya Brokhman
Quoted 4 lines

This will means creating only one host-side platform device, and then creating two usb_hcd structures below it. Tanya's design should be based on Sarah's work.

Hi Alan

Hi Tanya,

Quoted 4 lines

Thank you for your inputs. I'm not familiar with Sarah's work you mentioned. I'll have to look into that. Could you please point me to where I can find this code? Has it been merged into linux-next yet or just posted on the mailing list?

Please take a look at xhci_pci_probe() where usb_create_shared_hcd() is used. It was introduced by

commit f6ff0ac878eb420011fa2448851dd48c3a7e7b31

Author: Sarah Sharp <[email protected]>
Date:   Thu Dec 16 11:21:10 2010 -0800

xhci: Register second xHCI roothub.

in v2.6.39-rc1.

Sebastian

#9 lore raw

RE: [PATCH] usb: merge the two dummy_hcds into one

Quoted 5 lines

Please take a look at xhci_pci_probe() where usb_create_shared_hcd() is used. It was introduced by

commit f6ff0ac878eb420011fa2448851dd48c3a7e7b31

Quoted 8 lines
Author: Sarah Sharp <[email protected]>
Date:   Thu Dec 16 11:21:10 2010 -0800

xhci: Register second xHCI roothub.

in v2.6.39-rc1.

Sebastian

Thanks Sebastian. I'm on it.

Best regards,
Tanya Brokhman
Consultant for Qualcomm Innovation Center, Inc. Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum