summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDima Zavin <dima@android.com>2011-10-09 02:33:41 +0100
committerAndy Green <andy.green@linaro.org>2011-10-09 02:33:41 +0100
commitff2565fe30320b507a68b3cd4d6aaa4c121d851a (patch)
treec967b496e3b86e23ca4e3b23eb65b028d38a64c8
parent8fab4ab032a69d1c97f0d5e441b9481e3178a17d (diff)
usb: otg_id: add suspend/resume interface
It is possible that while one driver has already suspended, another driver calls otg_id_notify() because it has not yet been suspended. It would then be possible for the suspended driver's detect callback to be called. This is undesirable. Introduce new otg_id_suspend/otg_id_resume functions that keep a suspended count, and if a notification happens while someone is suspended, that notification is deferred until all the drivers are resumed. If the notification happens before the last driver is suspended, that suspend will be aborted and once the final driver resumes through otg_id_resume, the notification will be delivered. Change-Id: I32fd32bec65e366e5f97a25c15255d94773b85b3 Signed-off-by: Dima Zavin <dima@android.com>
-rw-r--r--drivers/usb/otg/otg_id.c59
-rw-r--r--include/linux/usb/otg_id.h2
2 files changed, 61 insertions, 0 deletions
diff --git a/drivers/usb/otg/otg_id.c b/drivers/usb/otg/otg_id.c
index ce22b462130..8037edbf314 100644
--- a/drivers/usb/otg/otg_id.c
+++ b/drivers/usb/otg/otg_id.c
@@ -26,6 +26,8 @@ static struct plist_head otg_id_plist =
static struct otg_id_notifier_block *otg_id_active;
static bool otg_id_cancelling;
static bool otg_id_inited;
+static int otg_id_suspended;
+static bool otg_id_pending;
static void otg_id_cancel(void)
{
@@ -139,8 +141,65 @@ void otg_id_notify(void)
if (otg_id_cancelling)
goto out;
+ if (otg_id_suspended != 0) {
+ otg_id_pending = true;
+ goto out;
+ }
+
__otg_id_notify();
+out:
+ mutex_unlock(&otg_id_lock);
+}
+
+/**
+ * otg_id_suspend
+ *
+ * Mark the otg_id subsystem as going into suspend. From here on out,
+ * any notifications will be deferred until the last otg_id client resumes.
+ * If there is a pending notification when calling this function, it will
+ * return a negative errno and expects that the caller will abort suspend.
+ * Returs 0 on success.
+ */
+int otg_id_suspend(void)
+{
+ int ret = 0;
+
+ mutex_lock(&otg_id_lock);
+
+ /*
+ * if there's a pending notification, tell the caller to abort suspend
+ */
+ if (otg_id_suspended != 0 && otg_id_pending) {
+ pr_info("otg_id: pending notification, should abort suspend\n");
+ ret = -EBUSY;
+ goto out;
+ }
+ otg_id_suspended++;
+out:
+ mutex_unlock(&otg_id_lock);
+ return ret;
+}
+
+/**
+ * otg_id_resume
+ *
+ * Inform the otg_id subsystem that a client is resuming. If this is the
+ * last client to be resumed and there's a pending notification,
+ * otg_id_notify() is called.
+ */
+void otg_id_resume(void)
+{
+ mutex_lock(&otg_id_lock);
+ if (WARN(!otg_id_suspended, "unbalanced otg_id_resume\n"))
+ goto out;
+ if (--otg_id_suspended == 0) {
+ if (otg_id_pending) {
+ pr_info("otg_id: had pending notification\n");
+ otg_id_pending = false;
+ __otg_id_notify();
+ }
+ }
out:
mutex_unlock(&otg_id_lock);
}
diff --git a/include/linux/usb/otg_id.h b/include/linux/usb/otg_id.h
index 46a44637c11..f9f5189a73b 100644
--- a/include/linux/usb/otg_id.h
+++ b/include/linux/usb/otg_id.h
@@ -52,5 +52,7 @@ int otg_id_register_notifier(struct otg_id_notifier_block *otg_id_nb);
void otg_id_unregister_notifier(struct otg_id_notifier_block *otg_id_nb);
void otg_id_notify(void);
+int otg_id_suspend(void);
+void otg_id_resume(void);
#endif /* __LINUX_USB_OTG_ID_H */