diff options
author | Dima Zavin <dima@android.com> | 2011-09-09 09:25:05 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:39:04 -0800 |
commit | ec2e6c72e4557774ee6913f5c4bb560236f56015 (patch) | |
tree | bbe10893bfe071ce7bed39f1e56b94930792869a /drivers/usb/otg | |
parent | 76a22ac439a4048bc6bd012253572bb571cc66d9 (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>
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r-- | drivers/usb/otg/otg_id.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/drivers/usb/otg/otg_id.c b/drivers/usb/otg/otg_id.c index ce22b4621308..8037edbf3141 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); } |