2010-11-01 15:38:55

by Tanya Brokhman

[permalink] [raw]
Subject: [PATCH v4 1/3] usb: USB3.0 ch11 definitions

Adding hub SuperSpeed usb definitions as defined by ch10 of the USB3.0
spec.

Signed-off-by: tlinder <[email protected]>
---
include/linux/usb/ch11.h | 47 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/usb/hcd.h | 4 +++
2 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h
index 119194c..10ec069 100644
--- a/include/linux/usb/ch11.h
+++ b/include/linux/usb/ch11.h
@@ -28,6 +28,13 @@
#define HUB_STOP_TT 11

/*
+ * Hub class additional requests defined by USB 3.0 spec
+ * See USB 3.0 spec Table 10-6
+ */
+#define HUB_SET_DEPTH 12
+#define HUB_GET_PORT_ERR_COUNT 13
+
+/*
* Hub Class feature numbers
* See USB 2.0 spec Table 11-17
*/
@@ -56,6 +63,20 @@
#define USB_PORT_FEAT_C_PORT_L1 23

/*
+ * Port feature selectors added by USB 3.0 spec.
+ * See USB 3.0 spec Table 10-7
+ */
+#define USB_PORT_FEAT_LINK_STATE 5
+#define USB_PORT_FEAT_U1_TIMEOUT 23
+#define USB_PORT_FEAT_U2_TIMEOUT 24
+#define USB_PORT_FEAT_C_LINK_STATE 25
+#define USB_PORT_FEAT_C_CONFIG_ERR 26
+#define USB_PORT_FEAT_REMOTE_WAKE_MASK 27
+#define USB_PORT_FEAT_BH_PORT_RESET 28
+#define USB_PORT_FEAT_C_BH_PORT_RESET 29
+#define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT 30
+
+/*
* Hub Status and Hub Change results
* See USB 2.0 spec Table 11-19 and Table 11-20
*/
@@ -84,6 +105,32 @@ struct usb_port_status {
#define USB_PORT_STAT_SUPER_SPEED 0x8000 /* Linux-internal */

/*
+ * Additions to wPortStatus bit field from USB 3.0
+ * See USB 3.0 spec Table 10-10
+ */
+#define USB_PORT_STAT_LINK_STATE 0x01e0
+#define USB_SS_PORT_STAT_POWER 0x0200
+#define USB_PORT_STAT_SPEED_5GBPS 0x0000
+/* Valid only if port is enabled */
+
+/*
+ * Definitions for PORT_LINK_STATE values
+ * (bits 5-8) in wPortStatus
+ */
+#define USB_SS_PORT_LS_U0 0x0000
+#define USB_SS_PORT_LS_U1 0x0020
+#define USB_SS_PORT_LS_U2 0x0040
+#define USB_SS_PORT_LS_U3 0x0060
+#define USB_SS_PORT_LS_SS_DISABLED 0x0080
+#define USB_SS_PORT_LS_RX_DETECT 0x00a0
+#define USB_SS_PORT_LS_SS_INACTIVE 0x00c0
+#define USB_SS_PORT_LS_POLLING 0x00e0
+#define USB_SS_PORT_LS_RECOVERY 0x0100
+#define USB_SS_PORT_LS_HOT_RESET 0x0120
+#define USB_SS_PORT_LS_COMP_MOD 0x0140
+#define USB_SS_PORT_LS_LOOPBACK 0x0160
+
+/*
* wPortChange bit field
* See USB 2.0 spec Table 11-22
* Bits 0 to 4 shown, bits 5 to 15 are reserved
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 3b571f1..d7738de 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -469,6 +469,10 @@ extern void usb_ep0_reinit(struct usb_device *);

/*-------------------------------------------------------------------------*/

+/* class requests from USB 3.0 hub spec, table 10-5 */
+#define SetHubDepth (0x3000 | HUB_SET_DEPTH)
+#define GetPortErrorCount (0x8000 | HUB_GET_PORT_ERR_COUNT)
+
/*
* Generic bandwidth allocation constants/support
*/
--
1.6.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.


2010-11-01 15:39:12

by Tanya Brokhman

[permalink] [raw]
Subject: [PATCH v4 2/3] usb: dummy_hcd code simplification

Take handling of the control requests out from dummy_timer to a different
function.

Signed-off-by: Tatyana Brokhman <[email protected]>
---
drivers/usb/gadget/dummy_hcd.c | 251 +++++++++++++++++++++------------------
1 files changed, 135 insertions(+), 116 deletions(-)

diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index dc65462..ef34c4d 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -1195,6 +1195,139 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
#define Ep_InRequest (Ep_Request | USB_DIR_IN)

+
+/**
+ * handle_control_request() - handles all control transfers
+ * @dum: pointer to dummy (the_controller)
+ * @urb: the urb request to handle
+ * @setup: pointer to the setup data for a USB device control
+ * request
+ * @status: pointer to request handling status
+ *
+ * Return 0 - if the request was handled
+ * 1 - if the request wasn't handles
+ * error code on error
+ */
+static int handle_control_request(struct dummy *dum, struct urb *urb,
+ struct usb_ctrlrequest *setup,
+ int *status)
+{
+ struct dummy_ep *ep2;
+ int ret_val = 1;
+ unsigned w_index;
+ unsigned w_value;
+
+ w_index = le16_to_cpu(setup->wIndex);
+ w_value = le16_to_cpu(setup->wValue);
+ switch (setup->bRequest) {
+ case USB_REQ_SET_ADDRESS:
+ if (setup->bRequestType != Dev_Request)
+ break;
+ dum->address = w_value;
+ *status = 0;
+ dev_dbg(udc_dev(dum), "set_address = %d\n",
+ w_value);
+ ret_val = 0;
+ break;
+ case USB_REQ_SET_FEATURE:
+ if (setup->bRequestType == Dev_Request) {
+ ret_val = 0;
+ switch (w_value) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ break;
+ case USB_DEVICE_B_HNP_ENABLE:
+ dum->gadget.b_hnp_enable = 1;
+ break;
+ case USB_DEVICE_A_HNP_SUPPORT:
+ dum->gadget.a_hnp_support = 1;
+ break;
+ case USB_DEVICE_A_ALT_HNP_SUPPORT:
+ dum->gadget.a_alt_hnp_support = 1;
+ break;
+ default:
+ ret_val = -EOPNOTSUPP;
+ }
+ if (ret_val == 0) {
+ dum->devstatus |= (1 << w_value);
+ *status = 0;
+ }
+ } else if (setup->bRequestType == Ep_Request) {
+ /* endpoint halt */
+ ep2 = find_endpoint(dum, w_index);
+ if (!ep2 || ep2->ep.name == ep0name) {
+ ret_val = -EOPNOTSUPP;
+ break;
+ }
+ ep2->halted = 1;
+ ret_val = 0;
+ *status = 0;
+ }
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ if (setup->bRequestType == Dev_Request) {
+ ret_val = 0;
+ switch (w_value) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ w_value = USB_DEVICE_REMOTE_WAKEUP;
+ break;
+ default:
+ ret_val = -EOPNOTSUPP;
+ break;
+ }
+ if (ret_val == 0) {
+ dum->devstatus &= ~(1 << w_value);
+ *status = 0;
+ }
+ } else if (setup->bRequestType == Ep_Request) {
+ /* endpoint halt */
+ ep2 = find_endpoint(dum, w_index);
+ if (!ep2) {
+ ret_val = -EOPNOTSUPP;
+ break;
+ }
+ if (!ep2->wedged)
+ ep2->halted = 0;
+ ret_val = 0;
+ *status = 0;
+ }
+ break;
+ case USB_REQ_GET_STATUS:
+ if (setup->bRequestType == Dev_InRequest
+ || setup->bRequestType == Intf_InRequest
+ || setup->bRequestType == Ep_InRequest) {
+ char *buf;
+ /*
+ * device: remote wakeup, selfpowered
+ * interface: nothing
+ * endpoint: halt
+ */
+ buf = (char *)urb->transfer_buffer;
+ if (urb->transfer_buffer_length > 0) {
+ if (setup->bRequestType == Ep_InRequest) {
+ ep2 = find_endpoint(dum, w_index);
+ if (!ep2) {
+ ret_val = -EOPNOTSUPP;
+ break;
+ }
+ buf[0] = ep2->halted;
+ } else if (setup->bRequestType ==
+ Dev_InRequest) {
+ buf[0] = (u8)dum->devstatus;
+ } else
+ buf[0] = 0;
+ }
+ if (urb->transfer_buffer_length > 1)
+ buf[1] = 0;
+ urb->actual_length = min_t(u32, 2,
+ urb->transfer_buffer_length);
+ ret_val = 0;
+ *status = 0;
+ }
+ break;
+ }
+ return ret_val;
+}
+
/* drive both sides of the transfers; looks like irq handlers to
* both drivers except the callbacks aren't in_irq().
*/
@@ -1297,14 +1430,8 @@ restart:
if (ep == &dum->ep [0] && ep->setup_stage) {
struct usb_ctrlrequest setup;
int value = 1;
- struct dummy_ep *ep2;
- unsigned w_index;
- unsigned w_value;

setup = *(struct usb_ctrlrequest*) urb->setup_packet;
- w_index = le16_to_cpu(setup.wIndex);
- w_value = le16_to_cpu(setup.wValue);
-
/* paranoia, in case of stale queued data */
list_for_each_entry (req, &ep->queue, queue) {
list_del_init (&req->queue);
@@ -1326,117 +1453,9 @@ restart:
ep->last_io = jiffies;
ep->setup_stage = 0;
ep->halted = 0;
- switch (setup.bRequest) {
- case USB_REQ_SET_ADDRESS:
- if (setup.bRequestType != Dev_Request)
- break;
- dum->address = w_value;
- status = 0;
- dev_dbg (udc_dev(dum), "set_address = %d\n",
- w_value);
- value = 0;
- break;
- case USB_REQ_SET_FEATURE:
- if (setup.bRequestType == Dev_Request) {
- value = 0;
- switch (w_value) {
- case USB_DEVICE_REMOTE_WAKEUP:
- break;
- case USB_DEVICE_B_HNP_ENABLE:
- dum->gadget.b_hnp_enable = 1;
- break;
- case USB_DEVICE_A_HNP_SUPPORT:
- dum->gadget.a_hnp_support = 1;
- break;
- case USB_DEVICE_A_ALT_HNP_SUPPORT:
- dum->gadget.a_alt_hnp_support
- = 1;
- break;
- default:
- value = -EOPNOTSUPP;
- }
- if (value == 0) {
- dum->devstatus |=
- (1 << w_value);
- status = 0;
- }

- } else if (setup.bRequestType == Ep_Request) {
- // endpoint halt
- ep2 = find_endpoint (dum, w_index);
- if (!ep2 || ep2->ep.name == ep0name) {
- value = -EOPNOTSUPP;
- break;
- }
- ep2->halted = 1;
- value = 0;
- status = 0;
- }
- break;
- case USB_REQ_CLEAR_FEATURE:
- if (setup.bRequestType == Dev_Request) {
- switch (w_value) {
- case USB_DEVICE_REMOTE_WAKEUP:
- dum->devstatus &= ~(1 <<
- USB_DEVICE_REMOTE_WAKEUP);
- value = 0;
- status = 0;
- break;
- default:
- value = -EOPNOTSUPP;
- break;
- }
- } else if (setup.bRequestType == Ep_Request) {
- // endpoint halt
- ep2 = find_endpoint (dum, w_index);
- if (!ep2) {
- value = -EOPNOTSUPP;
- break;
- }
- if (!ep2->wedged)
- ep2->halted = 0;
- value = 0;
- status = 0;
- }
- break;
- case USB_REQ_GET_STATUS:
- if (setup.bRequestType == Dev_InRequest
- || setup.bRequestType
- == Intf_InRequest
- || setup.bRequestType
- == Ep_InRequest
- ) {
- char *buf;
-
- // device: remote wakeup, selfpowered
- // interface: nothing
- // endpoint: halt
- buf = (char *)urb->transfer_buffer;
- if (urb->transfer_buffer_length > 0) {
- if (setup.bRequestType ==
- Ep_InRequest) {
- ep2 = find_endpoint (dum, w_index);
- if (!ep2) {
- value = -EOPNOTSUPP;
- break;
- }
- buf [0] = ep2->halted;
- } else if (setup.bRequestType ==
- Dev_InRequest) {
- buf [0] = (u8)
- dum->devstatus;
- } else
- buf [0] = 0;
- }
- if (urb->transfer_buffer_length > 1)
- buf [1] = 0;
- urb->actual_length = min_t(u32, 2,
- urb->transfer_buffer_length);
- value = 0;
- status = 0;
- }
- break;
- }
+ value = handle_control_request(dum, urb, &setup,
+ &status);

/* gadget driver handles all other requests. block
* until setup() returns; no reentrancy issues etc.
--
1.6.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.

2010-11-01 15:39:25

by Tanya Brokhman

[permalink] [raw]
Subject: [PATCH v4 3/3] usb: Adding SuperSpeed support to dummy_hcd

USB 3.0 hub includes 2 hubs - HS and SS ones.
Thus, when dummy_hcd enabled it will register 2 root hubs (SS and HS).

Signed-off-by: Tatyana Brokhman <[email protected]>
---
drivers/usb/gadget/dummy_hcd.c | 501 ++++++++++++++++++++++++++++++++++++++--
1 files changed, 487 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index ef34c4d..71e1eaf 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -5,6 +5,7 @@
*
* Copyright (C) 2003 David Brownell
* Copyright (C) 2003-2005 Alan Stern
+ * Copyright (C) 2010 Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -61,10 +62,13 @@

#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */

-static const char driver_name [] = "dummy_hcd";
-static const char driver_desc [] = "USB Host+Gadget Emulator";
+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 gadget_name[] = "dummy_udc";
+static const char ss_gadget_name[] = "ss_dummy_udc";

MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_AUTHOR ("David Brownell");
@@ -220,6 +224,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 +264,97 @@ 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_SUPER_SPEED);
+ 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 +435,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;
+ max = le16_to_cpu(desc->wMaxPacketSize) ;
+ /*
+ * For HS/FS devices only bits 0..9 of the wMaxPacketSize represent the
+ * maximum packet size
+ */
+ if (dum->gadget.speed < USB_SPEED_SUPER)
+ max &= 0x3ff;

/* drivers must not request bad settings, since lower levels
* (hardware or its drivers) may not check. some endpoints
@@ -361,6 +459,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 +481,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 +502,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;
@@ -750,16 +854,22 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
int
usb_gadget_register_driver (struct usb_gadget_driver *driver)
{
- struct dummy *dum = the_controller;
+ struct dummy *dum;
int retval, i;

+ if (!driver->bind || !driver->setup
+ || driver->speed == USB_SPEED_UNKNOWN)
+ return -EINVAL;
+
+ if (driver->speed == USB_SPEED_SUPER)
+ dum = the_ss_controller;
+ else
+ dum = the_controller;
+
if (!dum)
return -EINVAL;
if (dum->driver)
return -EBUSY;
- if (!driver->bind || !driver->setup
- || driver->speed == USB_SPEED_UNKNOWN)
- return -EINVAL;

/*
* SLAVE side init ... the layer above hardware, which
@@ -787,7 +897,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
}

dum->gadget.ep0 = &dum->ep [0].ep;
- dum->ep [0].ep.maxpacket = 64;
list_del_init (&dum->ep [0].ep.ep_list);
INIT_LIST_HEAD(&dum->fifo_req.queue);

@@ -806,6 +915,11 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
/* khubd will enumerate this in a while */
spin_lock_irq (&dum->lock);
dum->pullup = 1;
+ dum->gadget.speed = driver->speed;;
+ if (driver->speed == USB_SPEED_SUPER)
+ dum->ep[0].ep.maxpacket = 9;
+ else
+ dum->ep[0].ep.maxpacket = 64;
set_link_state (dum);
spin_unlock_irq (&dum->lock);

@@ -817,12 +931,20 @@ EXPORT_SYMBOL (usb_gadget_register_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",
@@ -897,6 +1019,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);
@@ -946,6 +1096,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
@@ -1244,6 +1405,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;
}
@@ -1270,6 +1449,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;
@@ -1350,6 +1547,9 @@ static void dummy_timer (unsigned long _dum)
case USB_SPEED_HIGH:
total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
break;
+ case USB_SPEED_SUPER:
+ total = 400 << 20; /* 400MB = 400*(2^20) bytes */
+ break;
default:
dev_err (dummy_dev(dum), "bogus device speed\n");
return;
@@ -1595,7 +1795,168 @@ hub_descriptor (struct usb_hub_descriptor *desc)
desc->bitmap [1] = 0xff;
}

-static int dummy_hub_control (
+/**
+ * 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:
+ 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,
@@ -1709,7 +2070,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 */
@@ -1892,6 +2257,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;
@@ -1912,6 +2298,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;
@@ -1923,6 +2329,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;
@@ -1964,10 +2381,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)
{
@@ -1979,34 +2409,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;
}
@@ -2015,8 +2484,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);
--
1.6.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.

2010-11-01 15:56:07

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v4 1/3] usb: USB3.0 ch11 definitions

On Mon, Nov 01, 2010 at 05:38:04PM +0200, Tatyana Brokhman wrote:
> Adding hub SuperSpeed usb definitions as defined by ch10 of the USB3.0
> spec.
>
> Signed-off-by: tlinder <[email protected]>

Please use your real name here.

thanks,

greg k-h

2010-11-15 10:52:08

by Meena Jain

[permalink] [raw]
Subject: Re: [PATCH v4 3/3] usb: Adding SuperSpeed support to dummy_hcd

Hi Tanya!

I have doubt regarding the below changes done in
usb_gadget_register_driver() w.r.t superspeed.

> dum->gadget.ep0 = &dum->ep [0].ep;
> - dum->ep [0].ep.maxpacket = 64;
> list_del_init (&dum->ep [0].ep.ep_list);
> INIT_LIST_HEAD(&dum->fifo_req.queue);
>
> @@ -806,6 +915,11 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
> /* khubd will enumerate this in a while */
> spin_lock_irq (&dum->lock);
> dum->pullup = 1;
> + dum->gadget.speed = driver->speed;;
> + if (driver->speed == USB_SPEED_SUPER)
> + dum->ep[0].ep.maxpacket = 9;
> + else
> + dum->ep[0].ep.maxpacket = 64;
> set_link_state (dum);
> spin_unlock_irq (&dum->lock);

Here, we are setting the ep[0].ep.maxpacket size as 9 or 64 depending
upon speed. As per the patch, ep maxpacket size information is being
updated after the driver->bind function is called i.e. after below
code

retval = driver->bind(&dum->gadget);

Earlier this information was being updating before the bind function called.

Due to this, we are getting wrong packet size as "0xffff" instead of
64 (in case of high speed) inside the bind function which is causing
enumeration problem while loading the existing file_storage gadget
driver.

IMO, the above code should be placed before bind function call.

Please confirm.

Thanks and Regards,

Meetu



On Mon, Nov 1, 2010 at 9:08 PM, Tatyana Brokhman <[email protected]> wrote:
> USB 3.0 hub includes 2 hubs - HS and SS ones.
> Thus, when dummy_hcd enabled it will register 2 root hubs (SS and HS).
>
> Signed-off-by: Tatyana Brokhman <[email protected]>
> ---
> ?drivers/usb/gadget/dummy_hcd.c | ?501 ++++++++++++++++++++++++++++++++++++++--
> ?1 files changed, 487 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
> index ef34c4d..71e1eaf 100644
> --- a/drivers/usb/gadget/dummy_hcd.c
> +++ b/drivers/usb/gadget/dummy_hcd.c
> @@ -5,6 +5,7 @@
> ?*
> ?* Copyright (C) 2003 David Brownell
> ?* Copyright (C) 2003-2005 Alan Stern
> + * Copyright (C) 2010 Code Aurora Forum. All rights reserved.
> ?*
> ?* This program is free software; you can redistribute it and/or modify
> ?* it under the terms of the GNU General Public License as published by
> @@ -61,10 +62,13 @@
>
> ?#define POWER_BUDGET ? 500 ? ? /* in mA; use 8 for low-power port testing */
>
> -static const char ? ? ?driver_name [] = "dummy_hcd";
> -static const char ? ? ?driver_desc [] = "USB Host+Gadget Emulator";
> +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 ? ? ?gadget_name[] = "dummy_udc";
> +static const char ? ? ?ss_gadget_name[] = "ss_dummy_udc";
>
> ?MODULE_DESCRIPTION (DRIVER_DESC);
> ?MODULE_AUTHOR ("David Brownell");
> @@ -220,6 +224,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 +264,97 @@ 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_SUPER_SPEED);
> + ? ? ? ? ? ? ? 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 +435,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;
> + ? ? ? max = le16_to_cpu(desc->wMaxPacketSize) ;
> + ? ? ? /*
> + ? ? ? ?* For HS/FS devices only bits 0..9 of the wMaxPacketSize represent the
> + ? ? ? ?* maximum packet size
> + ? ? ? ?*/
> + ? ? ? if (dum->gadget.speed < USB_SPEED_SUPER)
> + ? ? ? ? ? ? ? max &= 0x3ff;
>
> ? ? ? ?/* drivers must not request bad settings, since lower levels
> ? ? ? ? * (hardware or its drivers) may not check. ?some endpoints
> @@ -361,6 +459,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 +481,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 +502,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;
> @@ -750,16 +854,22 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
> ?int
> ?usb_gadget_register_driver (struct usb_gadget_driver *driver)
> ?{
> - ? ? ? struct dummy ? ?*dum = the_controller;
> + ? ? ? struct dummy ? ?*dum;
> ? ? ? ?int ? ? ? ? ? ? retval, i;
>
> + ? ? ? if (!driver->bind || !driver->setup
> + ? ? ? ? ? ? ? ? ? ? ? || driver->speed == USB_SPEED_UNKNOWN)
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? if (driver->speed == USB_SPEED_SUPER)
> + ? ? ? ? ? ? ? dum = the_ss_controller;
> + ? ? ? else
> + ? ? ? ? ? ? ? dum = the_controller;
> +
> ? ? ? ?if (!dum)
> ? ? ? ? ? ? ? ?return -EINVAL;
> ? ? ? ?if (dum->driver)
> ? ? ? ? ? ? ? ?return -EBUSY;
> - ? ? ? if (!driver->bind || !driver->setup
> - ? ? ? ? ? ? ? ? ? ? ? || driver->speed == USB_SPEED_UNKNOWN)
> - ? ? ? ? ? ? ? return -EINVAL;
>
> ? ? ? ?/*
> ? ? ? ? * SLAVE side init ... the layer above hardware, which
> @@ -787,7 +897,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
> ? ? ? ?}
>
> ? ? ? ?dum->gadget.ep0 = &dum->ep [0].ep;
> - ? ? ? dum->ep [0].ep.maxpacket = 64;
> ? ? ? ?list_del_init (&dum->ep [0].ep.ep_list);
> ? ? ? ?INIT_LIST_HEAD(&dum->fifo_req.queue);
>
> @@ -806,6 +915,11 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
> ? ? ? ?/* khubd will enumerate this in a while */
> ? ? ? ?spin_lock_irq (&dum->lock);
> ? ? ? ?dum->pullup = 1;
> + ? ? ? dum->gadget.speed = driver->speed;;
> + ? ? ? if (driver->speed == USB_SPEED_SUPER)
> + ? ? ? ? ? ? ? dum->ep[0].ep.maxpacket = 9;
> + ? ? ? else
> + ? ? ? ? ? ? ? dum->ep[0].ep.maxpacket = 64;
> ? ? ? ?set_link_state (dum);
> ? ? ? ?spin_unlock_irq (&dum->lock);
>
> @@ -817,12 +931,20 @@ EXPORT_SYMBOL (usb_gadget_register_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",
> @@ -897,6 +1019,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);
> @@ -946,6 +1096,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
> @@ -1244,6 +1405,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;
> ? ? ? ? ? ? ? ? ? ? ? ?}
> @@ -1270,6 +1449,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;
> @@ -1350,6 +1547,9 @@ static void dummy_timer (unsigned long _dum)
> ? ? ? ?case USB_SPEED_HIGH:
> ? ? ? ? ? ? ? ?total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
> ? ? ? ? ? ? ? ?break;
> + ? ? ? case USB_SPEED_SUPER:
> + ? ? ? ? ? ? ? total = 400 << 20; /* 400MB = 400*(2^20) bytes */
> + ? ? ? ? ? ? ? break;
> ? ? ? ?default:
> ? ? ? ? ? ? ? ?dev_err (dummy_dev(dum), "bogus device speed\n");
> ? ? ? ? ? ? ? ?return;
> @@ -1595,7 +1795,168 @@ hub_descriptor (struct usb_hub_descriptor *desc)
> ? ? ? ?desc->bitmap [1] = 0xff;
> ?}
>
> -static int dummy_hub_control (
> +/**
> + * 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:
> + ? ? ? ? ? ? ? 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,
> @@ -1709,7 +2070,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 */
> @@ -1892,6 +2257,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;
> @@ -1912,6 +2298,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;
> @@ -1923,6 +2329,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;
> @@ -1964,10 +2381,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)
> ?{
> @@ -1979,34 +2409,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;
> ?}
> @@ -2015,8 +2484,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);
> --
> 1.6.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.
> --
> 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
>

2010-11-15 13:40:53

by Tanya Brokhman

[permalink] [raw]
Subject: RE: [PATCH v4 3/3] usb: Adding SuperSpeed support to dummy_hcd

Hi Meetu,

Thank you for your input. You're right in your observation.
I'll upload a fixed patch soon.

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



-----Original Message-----
From: [email protected]
[mailto:[email protected]] On Behalf Of Meena Jain
Sent: Monday, November 15, 2010 12:52 PM
To: Tatyana Brokhman
Cc: [email protected]; [email protected]; David
Brownell; Greg Kroah-Hartman; Alan Stern; [email protected]
Subject: Re: [PATCH v4 3/3] usb: Adding SuperSpeed support to dummy_hcd

Hi Tanya!

I have doubt regarding the below changes done in
usb_gadget_register_driver() w.r.t superspeed.

> dum->gadget.ep0 = &dum->ep [0].ep;
> - dum->ep [0].ep.maxpacket = 64;
> list_del_init (&dum->ep [0].ep.ep_list);
> INIT_LIST_HEAD(&dum->fifo_req.queue);
>
> @@ -806,6 +915,11 @@ usb_gadget_register_driver (struct usb_gadget_driver
*driver)
> /* khubd will enumerate this in a while */
> spin_lock_irq (&dum->lock);
> dum->pullup = 1;
> + dum->gadget.speed = driver->speed;;
> + if (driver->speed == USB_SPEED_SUPER)
> + dum->ep[0].ep.maxpacket = 9;
> + else
> + dum->ep[0].ep.maxpacket = 64;
> set_link_state (dum);
> spin_unlock_irq (&dum->lock);

Here, we are setting the ep[0].ep.maxpacket size as 9 or 64 depending
upon speed. As per the patch, ep maxpacket size information is being
updated after the driver->bind function is called i.e. after below
code

retval = driver->bind(&dum->gadget);

Earlier this information was being updating before the bind function called.

Due to this, we are getting wrong packet size as "0xffff" instead of
64 (in case of high speed) inside the bind function which is causing
enumeration problem while loading the existing file_storage gadget
driver.

IMO, the above code should be placed before bind function call.

Please confirm.

Thanks and Regards,

Meetu



On Mon, Nov 1, 2010 at 9:08 PM, Tatyana Brokhman <[email protected]>
wrote:
> USB 3.0 hub includes 2 hubs - HS and SS ones.
> Thus, when dummy_hcd enabled it will register 2 root hubs (SS and HS).
>
> Signed-off-by: Tatyana Brokhman <[email protected]>
> ---
> ?drivers/usb/gadget/dummy_hcd.c | ?501
++++++++++++++++++++++++++++++++++++++--
> ?1 files changed, 487 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/usb/gadget/dummy_hcd.c
b/drivers/usb/gadget/dummy_hcd.c
> index ef34c4d..71e1eaf 100644
> --- a/drivers/usb/gadget/dummy_hcd.c
> +++ b/drivers/usb/gadget/dummy_hcd.c
> @@ -5,6 +5,7 @@
> ?*
> ?* Copyright (C) 2003 David Brownell
> ?* Copyright (C) 2003-2005 Alan Stern
> + * Copyright (C) 2010 Code Aurora Forum. All rights reserved.
> ?*
> ?* This program is free software; you can redistribute it and/or modify
> ?* it under the terms of the GNU General Public License as published by
> @@ -61,10 +62,13 @@
>
> ?#define POWER_BUDGET ? 500 ? ? /* in mA; use 8 for low-power port testing
*/
>
> -static const char ? ? ?driver_name [] = "dummy_hcd";
> -static const char ? ? ?driver_desc [] = "USB Host+Gadget Emulator";
> +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 ? ? ?gadget_name[] = "dummy_udc";
> +static const char ? ? ?ss_gadget_name[] = "ss_dummy_udc";
>
> ?MODULE_DESCRIPTION (DRIVER_DESC);
> ?MODULE_AUTHOR ("David Brownell");
> @@ -220,6 +224,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 +264,97 @@ 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_SUPER_SPEED);
> + ? ? ? ? ? ? ? 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 +435,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;
> + ? ? ? max = le16_to_cpu(desc->wMaxPacketSize) ;
> + ? ? ? /*
> + ? ? ? ?* For HS/FS devices only bits 0..9 of the wMaxPacketSize
represent the
> + ? ? ? ?* maximum packet size
> + ? ? ? ?*/
> + ? ? ? if (dum->gadget.speed < USB_SPEED_SUPER)
> + ? ? ? ? ? ? ? max &= 0x3ff;
>
> ? ? ? ?/* drivers must not request bad settings, since lower levels
> ? ? ? ? * (hardware or its drivers) may not check. ?some endpoints
> @@ -361,6 +459,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 +481,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 +502,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;
> @@ -750,16 +854,22 @@ static DEVICE_ATTR (function, S_IRUGO,
show_function, NULL);
> ?int
> ?usb_gadget_register_driver (struct usb_gadget_driver *driver)
> ?{
> - ? ? ? struct dummy ? ?*dum = the_controller;
> + ? ? ? struct dummy ? ?*dum;
> ? ? ? ?int ? ? ? ? ? ? retval, i;
>
> + ? ? ? if (!driver->bind || !driver->setup
> + ? ? ? ? ? ? ? ? ? ? ? || driver->speed == USB_SPEED_UNKNOWN)
> + ? ? ? ? ? ? ? return -EINVAL;
> +
> + ? ? ? if (driver->speed == USB_SPEED_SUPER)
> + ? ? ? ? ? ? ? dum = the_ss_controller;
> + ? ? ? else
> + ? ? ? ? ? ? ? dum = the_controller;
> +
> ? ? ? ?if (!dum)
> ? ? ? ? ? ? ? ?return -EINVAL;
> ? ? ? ?if (dum->driver)
> ? ? ? ? ? ? ? ?return -EBUSY;
> - ? ? ? if (!driver->bind || !driver->setup
> - ? ? ? ? ? ? ? ? ? ? ? || driver->speed == USB_SPEED_UNKNOWN)
> - ? ? ? ? ? ? ? return -EINVAL;
>
> ? ? ? ?/*
> ? ? ? ? * SLAVE side init ... the layer above hardware, which
> @@ -787,7 +897,6 @@ usb_gadget_register_driver (struct usb_gadget_driver
*driver)
> ? ? ? ?}
>
> ? ? ? ?dum->gadget.ep0 = &dum->ep [0].ep;
> - ? ? ? dum->ep [0].ep.maxpacket = 64;
> ? ? ? ?list_del_init (&dum->ep [0].ep.ep_list);
> ? ? ? ?INIT_LIST_HEAD(&dum->fifo_req.queue);
>
> @@ -806,6 +915,11 @@ usb_gadget_register_driver (struct usb_gadget_driver
*driver)
> ? ? ? ?/* khubd will enumerate this in a while */
> ? ? ? ?spin_lock_irq (&dum->lock);
> ? ? ? ?dum->pullup = 1;
> + ? ? ? dum->gadget.speed = driver->speed;;
> + ? ? ? if (driver->speed == USB_SPEED_SUPER)
> + ? ? ? ? ? ? ? dum->ep[0].ep.maxpacket = 9;
> + ? ? ? else
> + ? ? ? ? ? ? ? dum->ep[0].ep.maxpacket = 64;
> ? ? ? ?set_link_state (dum);
> ? ? ? ?spin_unlock_irq (&dum->lock);
>
> @@ -817,12 +931,20 @@ EXPORT_SYMBOL (usb_gadget_register_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",
> @@ -897,6 +1019,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);
> @@ -946,6 +1096,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
> @@ -1244,6 +1405,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;
> ? ? ? ? ? ? ? ? ? ? ? ?}
> @@ -1270,6 +1449,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;
> @@ -1350,6 +1547,9 @@ static void dummy_timer (unsigned long _dum)
> ? ? ? ?case USB_SPEED_HIGH:
> ? ? ? ? ? ? ? ?total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
> ? ? ? ? ? ? ? ?break;
> + ? ? ? case USB_SPEED_SUPER:
> + ? ? ? ? ? ? ? total = 400 << 20; /* 400MB = 400*(2^20) bytes */
> + ? ? ? ? ? ? ? break;
> ? ? ? ?default:
> ? ? ? ? ? ? ? ?dev_err (dummy_dev(dum), "bogus device speed\n");
> ? ? ? ? ? ? ? ?return;
> @@ -1595,7 +1795,168 @@ hub_descriptor (struct usb_hub_descriptor *desc)
> ? ? ? ?desc->bitmap [1] = 0xff;
> ?}
>
> -static int dummy_hub_control (
> +/**
> + * 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:
> + ? ? ? ? ? ? ? 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,
> @@ -1709,7 +2070,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 */
> @@ -1892,6 +2257,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;
> @@ -1912,6 +2298,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;
> @@ -1923,6 +2329,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;
> @@ -1964,10 +2381,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)
> ?{
> @@ -1979,34 +2409,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;
> ?}
> @@ -2015,8 +2484,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);
> --
> 1.6.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.
> --
> 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
>