From: Amit Blay <ablay@codeaurora.org>
To: greg@kroah.com
Cc: linux-usb@vger.kernel.org, linux-arm-msm@vger.kernel.org,
balbi@ti.com, tlinder@codeaurora.org,
Amit Blay <ablay@codeaurora.org>
Subject: [RFC/PATCH 3/3] usb:gadget: SuperSpeed function power management testing support
Date: Sun, 3 Jul 2011 17:29:33 +0300 [thread overview]
Message-ID: <1309703373-22476-4-git-send-email-ablay@codeaurora.org> (raw)
In-Reply-To: <1309703373-22476-1-git-send-email-ablay@codeaurora.org>
1. Fix dummy_hcd to let the function handle GET_STATUS(Interface) request.
2. Fix a bug in f_loopback Gadget which updated the bmAttribute of
f_sourcesink instead of f_loopback.
3. Update f_sourcesink Gadget to support function suspend & wakeup.
This is done by adding get_status() & func_suspend() handlers.
The current status of the function is controlable via debug FS:
(wakeup capable, wakeup enabled, suspended).
Signed-off-by: Amit Blay <ablay@codeaurora.org>
---
drivers/usb/gadget/dummy_hcd.c | 3 +-
drivers/usb/gadget/f_loopback.c | 2 +-
drivers/usb/gadget/f_sourcesink.c | 162 +++++++++++++++++++++++++++++++++++++
3 files changed, 165 insertions(+), 2 deletions(-)
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index e755a9d..7f6a2d8 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -1496,7 +1496,8 @@ static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
Dev_InRequest) {
buf[0] = (u8)dum->devstatus;
} else
- buf[0] = 0;
+ /* Let the function handle this */
+ break;
}
if (urb->transfer_buffer_length > 1)
buf[1] = 0;
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index ca660d4..75bac6d 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -427,7 +427,7 @@ int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume)
/* support autoresume for remote wakeup testing */
if (autoresume)
- sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+ loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
/* support OTG systems */
if (gadget_is_otg(cdev->gadget)) {
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index 5247f07..5c5da19 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -59,6 +59,12 @@ struct f_sourcesink {
struct usb_ep *in_ep;
struct usb_ep *out_ep;
+
+ /* Function Power Management */
+ bool func_suspended;
+ bool func_wakeup_capable;
+ bool func_wakeup_enabled;
+ struct device dev;
};
static inline struct f_sourcesink *func_to_ss(struct usb_function *f)
@@ -191,6 +197,79 @@ static struct usb_gadget_strings *sourcesink_strings[] = {
NULL,
};
+/*************************** DEVICE ATTRIBUTES ***************************/
+
+static ssize_t f_sourcesink_show_func_suspend(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct f_sourcesink *ss = container_of(dev, struct f_sourcesink,
+ dev);
+ return sprintf(buf, "%d\n", ss->func_suspended);
+}
+
+static ssize_t f_sourcesink_show_func_wakeup_enabled(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct f_sourcesink *ss = container_of(dev, struct f_sourcesink,
+ dev);
+ return sprintf(buf, "%d\n", ss->func_wakeup_enabled);
+}
+
+static ssize_t f_sourcesink_show_func_wakeup_capable(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct f_sourcesink *ss = container_of(dev, struct f_sourcesink,
+ dev);
+ return sprintf(buf, "%d\n", ss->func_wakeup_capable);
+}
+
+static ssize_t f_sourcesink_store_func_wakeup_capable(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct f_sourcesink *ss = container_of(dev, struct f_sourcesink, dev);
+ unsigned long func_wakeup_capable;
+
+ /* Allows changing function wakeup capable field from the file system */
+ if (strict_strtoul(buf, 2, &func_wakeup_capable))
+ return -EINVAL;
+ ss->func_wakeup_capable = (bool)func_wakeup_capable;
+ return count;
+}
+
+static ssize_t f_sourcesink_store_func_wakeup_trigger(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct f_sourcesink *ss = container_of(dev, struct f_sourcesink, dev);
+
+ /* Allows trigerring function wakeup from the file system */
+ if (!ss->func_wakeup_capable || !ss->func_wakeup_enabled)
+ return -EINVAL;
+
+ if (usb_gadget_wakeup(ss->function.config->cdev->gadget,
+ source_sink_intf.bInterfaceNumber) < 0)
+ return -EINVAL;
+ return count;
+}
+
+static DEVICE_ATTR(func_suspend, 0444, f_sourcesink_show_func_suspend, NULL);
+static DEVICE_ATTR(func_wakeup_enabled, 0444,
+ f_sourcesink_show_func_wakeup_enabled, NULL);
+static DEVICE_ATTR(func_wakeup_capable, 0666,
+ f_sourcesink_show_func_wakeup_capable,
+ f_sourcesink_store_func_wakeup_capable);
+static DEVICE_ATTR(func_wakeup_trigger, 0666, NULL,
+ f_sourcesink_store_func_wakeup_trigger);
+
+/*-------------------------------------------------------------------------*/
+
+static void sourcesink_release(struct device *dev)
+{
+ /* Nothing needs to be done */
+}
+
/*-------------------------------------------------------------------------*/
static int __init
@@ -199,6 +278,7 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
struct usb_composite_dev *cdev = c->cdev;
struct f_sourcesink *ss = func_to_ss(f);
int id;
+ int result = 0;
/* allocate interface ID(s) */
id = usb_interface_id(c, f);
@@ -243,12 +323,66 @@ autoconf_fail:
(gadget_is_superspeed(c->cdev->gadget) ? "super" :
(gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
f->name, ss->in_ep->name, ss->out_ep->name);
+
+ ss->dev.parent = &cdev->gadget->dev;
+ ss->dev.release = sourcesink_release;
+ dev_set_name(&ss->dev, "sourcesink");
+
+ result = device_register(&ss->dev);
+ if (result) {
+ ERROR(cdev, "failed to register: %d\n", result);
+ goto err_device_register;
+ }
+
+ result = device_create_file(&ss->dev, &dev_attr_func_suspend);
+ if (result) {
+ ERROR(cdev, "device_create_file failed\n", result);
+ goto err_func_suspend_file;
+ }
+
+ result = device_create_file(&ss->dev, &dev_attr_func_wakeup_enabled);
+ if (result) {
+ ERROR(cdev, "device_create_file failed\n", result);
+ goto err_func_wake_enabled_file;
+ }
+
+ result = device_create_file(&ss->dev, &dev_attr_func_wakeup_capable);
+ if (result) {
+ ERROR(cdev, "device_create_file failed\n", result);
+ goto err_func_wake_capable_file;
+ }
+
+ result = device_create_file(&ss->dev, &dev_attr_func_wakeup_trigger);
+ if (result) {
+ ERROR(cdev, "device_create_file failed\n", result);
+ goto err_func_wake_trigger_file;
+ }
+
return 0;
+
+err_func_wake_trigger_file:
+ device_remove_file(&ss->dev, &dev_attr_func_wakeup_capable);
+err_func_wake_capable_file:
+ device_remove_file(&ss->dev, &dev_attr_func_wakeup_enabled);
+err_func_wake_enabled_file:
+ device_remove_file(&ss->dev, &dev_attr_func_suspend);
+err_func_suspend_file:
+ device_unregister(&ss->dev);
+err_device_register:
+ return -ENODEV;
}
static void
sourcesink_unbind(struct usb_configuration *c, struct usb_function *f)
{
+ struct f_sourcesink *ss = func_to_ss(f);
+
+ device_remove_file(&ss->dev, &dev_attr_func_suspend);
+ device_remove_file(&ss->dev, &dev_attr_func_wakeup_capable);
+ device_remove_file(&ss->dev, &dev_attr_func_wakeup_enabled);
+ device_remove_file(&ss->dev, &dev_attr_func_wakeup_trigger);
+ device_unregister(&ss->dev);
+
kfree(func_to_ss(f));
}
@@ -383,6 +517,32 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in)
return status;
}
+static int sourcesink_func_suspend(struct usb_function *f,
+ u8 suspend_opt)
+{
+ struct f_sourcesink *ss = func_to_ss(f);
+ struct usb_composite_dev *cdev;
+
+ cdev = ss->function.config->cdev;
+
+ /* Parse suspend options */
+ ss->func_suspended = suspend_opt & USB_INTR_FUNC_SUSPEND_SUSP;
+ ss->func_wakeup_enabled = suspend_opt & USB_INTR_FUNC_SUSPEND_RWAKE_EN;
+
+ return 1;
+}
+
+static int sourcesink_get_status(struct usb_function *f)
+{
+ struct f_sourcesink *ss = func_to_ss(f);
+ struct usb_composite_dev *cdev;
+
+ cdev = ss->function.config->cdev;
+
+ return ss->func_wakeup_capable << USB_INTR_STAT_RWAKE_CAP
+ | (ss->func_wakeup_enabled << USB_INTR_STAT_RWAKE_EN);
+}
+
static void disable_source_sink(struct f_sourcesink *ss)
{
struct usb_composite_dev *cdev;
@@ -474,6 +634,8 @@ 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.func_suspend = sourcesink_func_suspend;
+ ss->function.get_status = sourcesink_get_status;
status = usb_add_function(c, &ss->function);
if (status)
--
1.7.3.3
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
next prev parent reply other threads:[~2011-07-03 14:30 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-07-03 14:29 [PATCH 0/3] usb:gadget: Add SuperSpeed Function Power Management Amit Blay
[not found] ` <1309703373-22476-1-git-send-email-ablay-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2011-07-03 14:29 ` [RFC/PATCH 1/3] usb: Add SuperSpeed support to g_zero gadget Amit Blay
[not found] ` <1309703373-22476-2-git-send-email-ablay-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2011-07-08 10:58 ` Felipe Balbi
2011-07-03 14:29 ` [RFC/PATCH 2/3] usb:gadget: Add SuperSpeed function power management Amit Blay
[not found] ` <1309703373-22476-3-git-send-email-ablay-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2011-07-27 14:34 ` Felipe Balbi
2011-07-28 16:15 ` Amit Blay
2011-07-29 4:51 ` Felipe Balbi
[not found] ` <20110729045136.GA9069-UiBtZHVXSwEVvW8u9ZQWYwjfymiNCTlR@public.gmane.org>
2011-07-29 7:41 ` Amit Blay
2011-07-28 16:15 ` Amit Blay
2011-07-03 14:29 ` Amit Blay [this message]
[not found] ` <1309703373-22476-4-git-send-email-ablay-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2011-07-27 14:37 ` [RFC/PATCH 3/3] usb:gadget: SuperSpeed function power management testing support Felipe Balbi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1309703373-22476-4-git-send-email-ablay@codeaurora.org \
--to=ablay@codeaurora.org \
--cc=balbi@ti.com \
--cc=greg@kroah.com \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=tlinder@codeaurora.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox