diff options
author | Ville Syrjala <syrjala@sci.fi> | 2008-07-03 10:45:37 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-07-30 00:41:38 -0400 |
commit | d6505ab9cd5672f99adeba86696499c2651a6e73 (patch) | |
tree | 489b60d35903a16fdc0bb0d3590e24c0ecc0fa68 /drivers/input/misc/ati_remote2.c | |
parent | 1971b9d56fce9d8903e623b953c5e2fffe3a878e (diff) |
Input: ati_remote2 - add autosuspend support
Signed-off-by: Ville Syrjala <syrjala@sci.fi>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/misc/ati_remote2.c')
-rw-r--r-- | drivers/input/misc/ati_remote2.c | 133 |
1 files changed, 127 insertions, 6 deletions
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index f4918b9bb94..3c9988dc0e9 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c | |||
@@ -45,6 +45,13 @@ static struct usb_device_id ati_remote2_id_table[] = { | |||
45 | }; | 45 | }; |
46 | MODULE_DEVICE_TABLE(usb, ati_remote2_id_table); | 46 | MODULE_DEVICE_TABLE(usb, ati_remote2_id_table); |
47 | 47 | ||
48 | static DEFINE_MUTEX(ati_remote2_mutex); | ||
49 | |||
50 | enum { | ||
51 | ATI_REMOTE2_OPENED = 0x1, | ||
52 | ATI_REMOTE2_SUSPENDED = 0x2, | ||
53 | }; | ||
54 | |||
48 | enum { | 55 | enum { |
49 | ATI_REMOTE2_AUX1, | 56 | ATI_REMOTE2_AUX1, |
50 | ATI_REMOTE2_AUX2, | 57 | ATI_REMOTE2_AUX2, |
@@ -124,46 +131,103 @@ struct ati_remote2 { | |||
124 | 131 | ||
125 | /* Each mode (AUX1-AUX4 and PC) can have an independent keymap. */ | 132 | /* Each mode (AUX1-AUX4 and PC) can have an independent keymap. */ |
126 | u16 keycode[ATI_REMOTE2_MODES][ARRAY_SIZE(ati_remote2_key_table)]; | 133 | u16 keycode[ATI_REMOTE2_MODES][ARRAY_SIZE(ati_remote2_key_table)]; |
134 | |||
135 | unsigned int flags; | ||
127 | }; | 136 | }; |
128 | 137 | ||
129 | static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id); | 138 | static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id); |
130 | static void ati_remote2_disconnect(struct usb_interface *interface); | 139 | static void ati_remote2_disconnect(struct usb_interface *interface); |
140 | static int ati_remote2_suspend(struct usb_interface *interface, pm_message_t message); | ||
141 | static int ati_remote2_resume(struct usb_interface *interface); | ||
131 | 142 | ||
132 | static struct usb_driver ati_remote2_driver = { | 143 | static struct usb_driver ati_remote2_driver = { |
133 | .name = "ati_remote2", | 144 | .name = "ati_remote2", |
134 | .probe = ati_remote2_probe, | 145 | .probe = ati_remote2_probe, |
135 | .disconnect = ati_remote2_disconnect, | 146 | .disconnect = ati_remote2_disconnect, |
136 | .id_table = ati_remote2_id_table, | 147 | .id_table = ati_remote2_id_table, |
148 | .suspend = ati_remote2_suspend, | ||
149 | .resume = ati_remote2_resume, | ||
150 | .supports_autosuspend = 1, | ||
137 | }; | 151 | }; |
138 | 152 | ||
139 | static int ati_remote2_open(struct input_dev *idev) | 153 | static int ati_remote2_submit_urbs(struct ati_remote2 *ar2) |
140 | { | 154 | { |
141 | struct ati_remote2 *ar2 = input_get_drvdata(idev); | ||
142 | int r; | 155 | int r; |
143 | 156 | ||
144 | r = usb_submit_urb(ar2->urb[0], GFP_KERNEL); | 157 | r = usb_submit_urb(ar2->urb[0], GFP_KERNEL); |
145 | if (r) { | 158 | if (r) { |
146 | dev_err(&ar2->intf[0]->dev, | 159 | dev_err(&ar2->intf[0]->dev, |
147 | "%s: usb_submit_urb() = %d\n", __func__, r); | 160 | "%s(): usb_submit_urb() = %d\n", __func__, r); |
148 | return r; | 161 | return r; |
149 | } | 162 | } |
150 | r = usb_submit_urb(ar2->urb[1], GFP_KERNEL); | 163 | r = usb_submit_urb(ar2->urb[1], GFP_KERNEL); |
151 | if (r) { | 164 | if (r) { |
152 | usb_kill_urb(ar2->urb[0]); | 165 | usb_kill_urb(ar2->urb[0]); |
153 | dev_err(&ar2->intf[1]->dev, | 166 | dev_err(&ar2->intf[1]->dev, |
154 | "%s: usb_submit_urb() = %d\n", __func__, r); | 167 | "%s(): usb_submit_urb() = %d\n", __func__, r); |
155 | return r; | 168 | return r; |
156 | } | 169 | } |
157 | 170 | ||
158 | return 0; | 171 | return 0; |
159 | } | 172 | } |
160 | 173 | ||
174 | static void ati_remote2_kill_urbs(struct ati_remote2 *ar2) | ||
175 | { | ||
176 | usb_kill_urb(ar2->urb[1]); | ||
177 | usb_kill_urb(ar2->urb[0]); | ||
178 | } | ||
179 | |||
180 | static int ati_remote2_open(struct input_dev *idev) | ||
181 | { | ||
182 | struct ati_remote2 *ar2 = input_get_drvdata(idev); | ||
183 | int r; | ||
184 | |||
185 | dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); | ||
186 | |||
187 | r = usb_autopm_get_interface(ar2->intf[0]); | ||
188 | if (r) { | ||
189 | dev_err(&ar2->intf[0]->dev, | ||
190 | "%s(): usb_autopm_get_interface() = %d\n", __func__, r); | ||
191 | goto fail1; | ||
192 | } | ||
193 | |||
194 | mutex_lock(&ati_remote2_mutex); | ||
195 | |||
196 | if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) { | ||
197 | r = ati_remote2_submit_urbs(ar2); | ||
198 | if (r) | ||
199 | goto fail2; | ||
200 | } | ||
201 | |||
202 | ar2->flags |= ATI_REMOTE2_OPENED; | ||
203 | |||
204 | mutex_unlock(&ati_remote2_mutex); | ||
205 | |||
206 | usb_autopm_put_interface(ar2->intf[0]); | ||
207 | |||
208 | return 0; | ||
209 | |||
210 | fail2: | ||
211 | mutex_unlock(&ati_remote2_mutex); | ||
212 | usb_autopm_put_interface(ar2->intf[0]); | ||
213 | fail1: | ||
214 | return r; | ||
215 | } | ||
216 | |||
161 | static void ati_remote2_close(struct input_dev *idev) | 217 | static void ati_remote2_close(struct input_dev *idev) |
162 | { | 218 | { |
163 | struct ati_remote2 *ar2 = input_get_drvdata(idev); | 219 | struct ati_remote2 *ar2 = input_get_drvdata(idev); |
164 | 220 | ||
165 | usb_kill_urb(ar2->urb[0]); | 221 | dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); |
166 | usb_kill_urb(ar2->urb[1]); | 222 | |
223 | mutex_lock(&ati_remote2_mutex); | ||
224 | |||
225 | if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) | ||
226 | ati_remote2_kill_urbs(ar2); | ||
227 | |||
228 | ar2->flags &= ~ATI_REMOTE2_OPENED; | ||
229 | |||
230 | mutex_unlock(&ati_remote2_mutex); | ||
167 | } | 231 | } |
168 | 232 | ||
169 | static void ati_remote2_input_mouse(struct ati_remote2 *ar2) | 233 | static void ati_remote2_input_mouse(struct ati_remote2 *ar2) |
@@ -288,6 +352,7 @@ static void ati_remote2_complete_mouse(struct urb *urb) | |||
288 | 352 | ||
289 | switch (urb->status) { | 353 | switch (urb->status) { |
290 | case 0: | 354 | case 0: |
355 | usb_mark_last_busy(ar2->udev); | ||
291 | ati_remote2_input_mouse(ar2); | 356 | ati_remote2_input_mouse(ar2); |
292 | break; | 357 | break; |
293 | case -ENOENT: | 358 | case -ENOENT: |
@@ -298,6 +363,7 @@ static void ati_remote2_complete_mouse(struct urb *urb) | |||
298 | "%s(): urb status = %d\n", __func__, urb->status); | 363 | "%s(): urb status = %d\n", __func__, urb->status); |
299 | return; | 364 | return; |
300 | default: | 365 | default: |
366 | usb_mark_last_busy(ar2->udev); | ||
301 | dev_err(&ar2->intf[0]->dev, | 367 | dev_err(&ar2->intf[0]->dev, |
302 | "%s(): urb status = %d\n", __func__, urb->status); | 368 | "%s(): urb status = %d\n", __func__, urb->status); |
303 | } | 369 | } |
@@ -315,6 +381,7 @@ static void ati_remote2_complete_key(struct urb *urb) | |||
315 | 381 | ||
316 | switch (urb->status) { | 382 | switch (urb->status) { |
317 | case 0: | 383 | case 0: |
384 | usb_mark_last_busy(ar2->udev); | ||
318 | ati_remote2_input_key(ar2); | 385 | ati_remote2_input_key(ar2); |
319 | break; | 386 | break; |
320 | case -ENOENT: | 387 | case -ENOENT: |
@@ -325,6 +392,7 @@ static void ati_remote2_complete_key(struct urb *urb) | |||
325 | "%s(): urb status = %d\n", __func__, urb->status); | 392 | "%s(): urb status = %d\n", __func__, urb->status); |
326 | return; | 393 | return; |
327 | default: | 394 | default: |
395 | usb_mark_last_busy(ar2->udev); | ||
328 | dev_err(&ar2->intf[1]->dev, | 396 | dev_err(&ar2->intf[1]->dev, |
329 | "%s(): urb status = %d\n", __func__, urb->status); | 397 | "%s(): urb status = %d\n", __func__, urb->status); |
330 | } | 398 | } |
@@ -562,6 +630,8 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d | |||
562 | 630 | ||
563 | usb_set_intfdata(interface, ar2); | 631 | usb_set_intfdata(interface, ar2); |
564 | 632 | ||
633 | interface->needs_remote_wakeup = 1; | ||
634 | |||
565 | return 0; | 635 | return 0; |
566 | 636 | ||
567 | fail2: | 637 | fail2: |
@@ -594,6 +664,57 @@ static void ati_remote2_disconnect(struct usb_interface *interface) | |||
594 | kfree(ar2); | 664 | kfree(ar2); |
595 | } | 665 | } |
596 | 666 | ||
667 | static int ati_remote2_suspend(struct usb_interface *interface, | ||
668 | pm_message_t message) | ||
669 | { | ||
670 | struct ati_remote2 *ar2; | ||
671 | struct usb_host_interface *alt = interface->cur_altsetting; | ||
672 | |||
673 | if (alt->desc.bInterfaceNumber) | ||
674 | return 0; | ||
675 | |||
676 | ar2 = usb_get_intfdata(interface); | ||
677 | |||
678 | dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); | ||
679 | |||
680 | mutex_lock(&ati_remote2_mutex); | ||
681 | |||
682 | if (ar2->flags & ATI_REMOTE2_OPENED) | ||
683 | ati_remote2_kill_urbs(ar2); | ||
684 | |||
685 | ar2->flags |= ATI_REMOTE2_SUSPENDED; | ||
686 | |||
687 | mutex_unlock(&ati_remote2_mutex); | ||
688 | |||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | static int ati_remote2_resume(struct usb_interface *interface) | ||
693 | { | ||
694 | struct ati_remote2 *ar2; | ||
695 | struct usb_host_interface *alt = interface->cur_altsetting; | ||
696 | int r = 0; | ||
697 | |||
698 | if (alt->desc.bInterfaceNumber) | ||
699 | return 0; | ||
700 | |||
701 | ar2 = usb_get_intfdata(interface); | ||
702 | |||
703 | dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__); | ||
704 | |||
705 | mutex_lock(&ati_remote2_mutex); | ||
706 | |||
707 | if (ar2->flags & ATI_REMOTE2_OPENED) | ||
708 | r = ati_remote2_submit_urbs(ar2); | ||
709 | |||
710 | if (!r) | ||
711 | ar2->flags &= ~ATI_REMOTE2_SUSPENDED; | ||
712 | |||
713 | mutex_unlock(&ati_remote2_mutex); | ||
714 | |||
715 | return r; | ||
716 | } | ||
717 | |||
597 | static int __init ati_remote2_init(void) | 718 | static int __init ati_remote2_init(void) |
598 | { | 719 | { |
599 | int r; | 720 | int r; |