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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.