2 * Copyright (C) 2011 Google, Inc.
5 * Colin Cross <ccross@android.com>
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 #include <linux/kernel.h>
19 #include <linux/mutex.h>
20 #include <linux/notifier.h>
21 #include <linux/usb/otg_id.h>
23 static DEFINE_MUTEX(otg_id_lock
);
24 static struct plist_head otg_id_plist
=
25 PLIST_HEAD_INIT(otg_id_plist
);
26 static struct otg_id_notifier_block
*otg_id_active
;
27 static bool otg_id_cancelling
;
28 static bool otg_id_inited
;
29 static int otg_id_suspended
;
30 static bool otg_id_pending
;
32 static void otg_id_cancel(void)
35 otg_id_cancelling
= true;
36 mutex_unlock(&otg_id_lock
);
38 otg_id_active
->cancel(otg_id_active
);
40 mutex_lock(&otg_id_lock
);
41 otg_id_cancelling
= false;
45 static void __otg_id_notify(void)
48 struct otg_id_notifier_block
*otg_id_nb
;
49 bool proxy_wait
= false;
50 if (plist_head_empty(&otg_id_plist
))
53 plist_for_each_entry(otg_id_nb
, &otg_id_plist
, p
) {
55 if (otg_id_nb
->proxy_wait
)
56 ret
= otg_id_nb
->proxy_wait(otg_id_nb
);
58 ret
= otg_id_nb
->detect(otg_id_nb
);
60 if (ret
== OTG_ID_HANDLED
) {
61 otg_id_active
= otg_id_nb
;
64 if (ret
== OTG_ID_PROXY_WAIT
)
69 WARN(1, "otg id event not handled");
75 mutex_lock(&otg_id_lock
);
80 mutex_unlock(&otg_id_lock
);
83 late_initcall(otg_id_init
);
86 * otg_id_register_notifier
87 * @otg_id_nb: notifier block containing priority and callback function
89 * Register a notifier that will be called on any USB cable state change.
90 * The priority determines the order the callback will be called in, a higher
91 * number will be called first. A callback function needs to determine the
92 * type of USB cable that is connected. If it can determine the type, it
93 * should notify the appropriate drivers (for example, call an otg notifier
94 * with USB_EVENT_VBUS), and return OTG_ID_HANDLED. Once a callback has
95 * returned OTG_ID_HANDLED, it is responsible for calling otg_id_notify() when
96 * the detected USB cable is disconnected.
98 int otg_id_register_notifier(struct otg_id_notifier_block
*otg_id_nb
)
100 plist_node_init(&otg_id_nb
->p
, otg_id_nb
->priority
);
102 mutex_lock(&otg_id_lock
);
103 plist_add(&otg_id_nb
->p
, &otg_id_plist
);
110 mutex_unlock(&otg_id_lock
);
115 void otg_id_unregister_notifier(struct otg_id_notifier_block
*otg_id_nb
)
117 mutex_lock(&otg_id_lock
);
119 plist_del(&otg_id_nb
->p
, &otg_id_plist
);
121 if (otg_id_inited
&& (otg_id_active
== otg_id_nb
)) {
126 mutex_unlock(&otg_id_lock
);
132 * Notify listeners on any USB cable state change.
134 * A driver may only call otg_id_notify if it returned OTG_ID_HANDLED the last
135 * time it's notifier was called, and it's cancel function has not been called.
137 void otg_id_notify(void)
139 mutex_lock(&otg_id_lock
);
141 if (otg_id_cancelling
)
144 if (otg_id_suspended
!= 0) {
145 otg_id_pending
= true;
151 mutex_unlock(&otg_id_lock
);
157 * Mark the otg_id subsystem as going into suspend. From here on out,
158 * any notifications will be deferred until the last otg_id client resumes.
159 * If there is a pending notification when calling this function, it will
160 * return a negative errno and expects that the caller will abort suspend.
161 * Returs 0 on success.
163 int otg_id_suspend(void)
167 mutex_lock(&otg_id_lock
);
170 * if there's a pending notification, tell the caller to abort suspend
172 if (otg_id_suspended
!= 0 && otg_id_pending
) {
173 pr_info("otg_id: pending notification, should abort suspend\n");
180 mutex_unlock(&otg_id_lock
);
187 * Inform the otg_id subsystem that a client is resuming. If this is the
188 * last client to be resumed and there's a pending notification,
189 * otg_id_notify() is called.
191 void otg_id_resume(void)
193 mutex_lock(&otg_id_lock
);
194 if (WARN(!otg_id_suspended
, "unbalanced otg_id_resume\n"))
196 if (--otg_id_suspended
== 0) {
197 if (otg_id_pending
) {
198 pr_info("otg_id: had pending notification\n");
199 otg_id_pending
= false;
204 mutex_unlock(&otg_id_lock
);