* [RFC/PATCH v2 1/2] usb:dummy_hcd: connect/disconnect test support
[not found] <1308731945-7601-1-git-send-email-tlinder@codeaurora.org>
@ 2011-06-22 8:39 ` Tatyana Brokhman
2011-06-22 9:52 ` Sebastian Andrzej Siewior
2011-06-22 8:39 ` [RFC/PATCH v2 2/2] usb:g_zero: bulk in/out unittest support Tatyana Brokhman
1 sibling, 1 reply; 4+ messages in thread
From: Tatyana Brokhman @ 2011-06-22 8:39 UTC (permalink / raw)
To: balbi; +Cc: linux-usb, linux-arm-msm, ablay, Tatyana Brokhman, open list
This implementation adds a new proprietary device control requests (to be
handled by the dummy_hcd) that initiates a connect/disconnect sequence.
The bRequest value of the new control request is 0x52.
It is used by the user-space Unit testing application.
Signed-off-by: Tatyana Linder <tlinder@codeaurora.org>
---
drivers/usb/gadget/dummy_hcd.c | 53 ++++++++++++++++++++++++++++++++++++++++
1 files changed, 53 insertions(+), 0 deletions(-)
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 1916360..5925fe6 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -61,6 +61,10 @@
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
+/* Proprietary requests: values for the bRequest field of a SETUP packet. */
+/* TESTING: Connect/disconnect the device */
+#define USB_TEST_REQ_CONN_DISCON 0x52
+
static const char driver_name [] = "dummy_hcd";
static const char driver_desc [] = "USB Host+Gadget Emulator";
@@ -179,6 +183,7 @@ struct dummy_hcd {
unsigned active:1;
unsigned old_active:1;
unsigned resuming:1;
+ struct work_struct conn_disc_work;
};
struct dummy {
@@ -1337,6 +1342,42 @@ 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)
+#define Dev_Test_Request (USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define Dev_Test_OutRequest (Dev_Test_Request | USB_DIR_OUT)
+
+/**
+ * dummy_hcd_conn_disc_work() - performs a disconnect/connect sequence.
+ * @data: pointer to the scheduled work_struct
+ */
+static void dummy_hcd_conn_disc_work(struct work_struct *data)
+{
+ struct dummy_hcd *dum_hcd =
+ container_of(data, struct dummy_hcd, conn_disc_work);
+ int ret_val;
+
+ if (!dum_hcd->dum->driver) {
+ dev_err(dummy_dev(dum_hcd),
+ "dummy_hcd_conn_disc_work called without connected "
+ "device\n");
+ return;
+ }
+
+ dev_info(dummy_dev(dum_hcd), "disconnecting device...\n");
+ ret_val = dummy_pullup(&dum_hcd->dum->gadget, 0);
+ if (ret_val) {
+ dev_err(dummy_dev(dum_hcd), "%s: couldn't disconnect --> %d\n",
+ __func__, ret_val);
+ return;
+ }
+
+ /* We have to let the hub task to update the device disconnect state */
+ msleep_interruptible(1000);
+ dev_info(dummy_dev(dum_hcd), "re-connecting device...\n");
+ ret_val = dummy_pullup(&dum_hcd->dum->gadget, 1);
+ if (ret_val)
+ dev_err(dummy_dev(dum_hcd), "%s: couldn't re-connect --> %d\n",
+ __func__, ret_val);
+}
/**
* handle_control_request() - handles all control transfers
@@ -1509,6 +1550,12 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
*status = 0;
}
break;
+ case USB_TEST_REQ_CONN_DISCON:
+ if (setup->bRequestType == Dev_Test_OutRequest) {
+ schedule_work(&dum_hcd->conn_disc_work);
+ ret_val = 0;
+ }
+ break;
}
return ret_val;
}
@@ -2224,6 +2271,8 @@ static int dummy_setup(struct usb_hcd *hcd)
if (usb_hcd_is_primary_hcd(hcd)) {
the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
the_controller.hs_hcd->dum = &the_controller;
+ INIT_WORK(&the_controller.hs_hcd->conn_disc_work,
+ dummy_hcd_conn_disc_work);
/*
* Mark the first roothub as being USB 2.0.
* The USB 3.0 roothub will be registered later by
@@ -2234,6 +2283,8 @@ static int dummy_setup(struct usb_hcd *hcd)
} else {
the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
the_controller.ss_hcd->dum = &the_controller;
+ INIT_WORK(&the_controller.ss_hcd->conn_disc_work,
+ dummy_hcd_conn_disc_work);
hcd->speed = HCD_USB3;
hcd->self.root_hub->speed = USB_SPEED_SUPER;
}
@@ -2341,10 +2392,12 @@ static int dummy_hcd_remove(struct platform_device *pdev)
if (dum->ss_hcd) {
usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
+ cancel_work_sync(&dum->ss_hcd->conn_disc_work);
}
usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
+ cancel_work_sync(&dum->hs_hcd->conn_disc_work);
the_controller.hs_hcd = NULL;
the_controller.ss_hcd = NULL;
--
1.7.0.4
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply related [flat|nested] 4+ messages in thread* [RFC/PATCH v2 2/2] usb:g_zero: bulk in/out unittest support
[not found] <1308731945-7601-1-git-send-email-tlinder@codeaurora.org>
2011-06-22 8:39 ` [RFC/PATCH v2 1/2] usb:dummy_hcd: connect/disconnect test support Tatyana Brokhman
@ 2011-06-22 8:39 ` Tatyana Brokhman
1 sibling, 0 replies; 4+ messages in thread
From: Tatyana Brokhman @ 2011-06-22 8:39 UTC (permalink / raw)
To: balbi; +Cc: linux-usb, linux-arm-msm, ablay, Tatyana Brokhman, open list
This commit adds a new vendor specific request to be handled by the
g_zero module in it's sourcesink configuration. The purpose if this
request is to update the length of the BULK transfer to a given value.
The bRequest value of the new control request is 0x5e.
It is used by the user-space Unit testing application for bulk in/out
tests.
The sourcesink_setup function was moved to be ->setup() of the function
and not the configuration.
Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
---
drivers/usb/gadget/f_sourcesink.c | 145 +++++++++++++++++++------------------
1 files changed, 75 insertions(+), 70 deletions(-)
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index caf2f95..ff8840d 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -385,6 +385,80 @@ fail:
return result;
}
+static int sourcesink_setup(struct usb_function *f,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct f_sourcesink *ss = func_to_ss(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct usb_request *req = f->config->cdev->req;
+ int retval = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ switch (ctrl->bRequest) {
+ /*
+ * These are the same vendor-specific requests supported by
+ * Intel's USB 2.0 compliance test devices. We exceed that
+ * device spec by allowing multiple-packet requests.
+ *
+ * NOTE: the Control-OUT data stays in req->buf ... better
+ * would be copying it into a scratch buffer, so that other
+ * requests may safely intervene.
+ */
+ case 0x5b: /* control WRITE test -- fill the buffer */
+ if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
+ goto unknown;
+ if (w_value || w_index)
+ break;
+ /* just read that many bytes into the buffer */
+ if (w_length > req->length)
+ break;
+ retval = w_length;
+ break;
+ case 0x5c: /* control READ test -- return the buffer */
+ if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
+ goto unknown;
+ if (w_value || w_index)
+ break;
+ /* expect those bytes are still in the buffer; send back */
+ if (w_length > req->length)
+ break;
+ retval = w_length;
+ break;
+
+ case 0x5e:
+ /*
+ * Change bulk ep buffer size. buflen is the length of
+ * the BULK transfer (req->length=buflen). Defined in g_zero.h
+ */
+ disable_source_sink(ss);
+ buflen = w_value;
+ retval = enable_source_sink(cdev, ss);
+ break;
+ default:
+unknown:
+ VDBG(cdev, "unknown control req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ }
+
+ /* respond with data transfer or status phase? */
+ if (retval >= 0) {
+ VDBG(cdev, "source/sink req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ req->zero = 0;
+ req->length = retval;
+ retval = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ if (retval < 0)
+ ERROR(cdev, "source/sinkc response, err %d\n", retval);
+ }
+
+ /* device either stalls (value < 0) or reports success */
+ return retval;
+}
+
static int sourcesink_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
@@ -421,6 +495,7 @@ static int __init sourcesink_bind_config(struct usb_configuration *c)
ss->function.unbind = sourcesink_unbind;
ss->function.set_alt = sourcesink_set_alt;
ss->function.disable = sourcesink_disable;
+ ss->function.setup = sourcesink_setup;
status = usb_add_function(c, &ss->function);
if (status)
@@ -428,79 +503,9 @@ static int __init sourcesink_bind_config(struct usb_configuration *c)
return status;
}
-static int sourcesink_setup(struct usb_configuration *c,
- const struct usb_ctrlrequest *ctrl)
-{
- struct usb_request *req = c->cdev->req;
- int value = -EOPNOTSUPP;
- u16 w_index = le16_to_cpu(ctrl->wIndex);
- u16 w_value = le16_to_cpu(ctrl->wValue);
- u16 w_length = le16_to_cpu(ctrl->wLength);
-
- /* composite driver infrastructure handles everything except
- * the two control test requests.
- */
- switch (ctrl->bRequest) {
-
- /*
- * These are the same vendor-specific requests supported by
- * Intel's USB 2.0 compliance test devices. We exceed that
- * device spec by allowing multiple-packet requests.
- *
- * NOTE: the Control-OUT data stays in req->buf ... better
- * would be copying it into a scratch buffer, so that other
- * requests may safely intervene.
- */
- case 0x5b: /* control WRITE test -- fill the buffer */
- if (ctrl->bRequestType != (USB_DIR_OUT|USB_TYPE_VENDOR))
- goto unknown;
- if (w_value || w_index)
- break;
- /* just read that many bytes into the buffer */
- if (w_length > req->length)
- break;
- value = w_length;
- break;
- case 0x5c: /* control READ test -- return the buffer */
- if (ctrl->bRequestType != (USB_DIR_IN|USB_TYPE_VENDOR))
- goto unknown;
- if (w_value || w_index)
- break;
- /* expect those bytes are still in the buffer; send back */
- if (w_length > req->length)
- break;
- value = w_length;
- break;
-
- default:
-unknown:
- VDBG(c->cdev,
- "unknown control req%02x.%02x v%04x i%04x l%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
- }
-
- /* respond with data transfer or status phase? */
- if (value >= 0) {
- VDBG(c->cdev, "source/sink req%02x.%02x v%04x i%04x l%d\n",
- ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
- req->zero = 0;
- req->length = value;
- value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC);
- if (value < 0)
- ERROR(c->cdev, "source/sinkc response, err %d\n",
- value);
- }
-
- /* device either stalls (value < 0) or reports success */
- return value;
-}
-
static struct usb_configuration sourcesink_driver = {
.label = "source/sink",
.strings = sourcesink_strings,
- .setup = sourcesink_setup,
.bConfigurationValue = 3,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
/* .iConfiguration = DYNAMIC */
--
1.7.0.4
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply related [flat|nested] 4+ messages in thread