aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@googlemail.com>2011-11-17 08:12:01 -0500
committerJiri Kosina <jkosina@suse.cz>2011-11-22 17:08:28 -0500
commitcb99221ba74bb16576a9c3b7e49357b6b12ff3ea (patch)
tree3aee851b0643491ba0208b022c92335e0e9550dd /drivers/hid
parentfad8c0e34323eb7789f93750258a2cf02dc6cf69 (diff)
HID: wiimote: Add extension support stub
The wiimote supports several extensions. This adds a separate source file which handles all extensions and can be disabled at compile-time. The driver reacts on "plug"-events on the extension port and starts a worker which initializes or deinitializes the extensions. Currently, the initialization logic is not fully understood and we can only detect and enable all extensions when all extensions are deactivated. Therefore, we need to disable all extensions, then detect and activate them again to react on "plug"-events. However, deactivating extensions will generate a new "plug"-event and we will never leave that loop. Hence, we only support extensions if they are plugged before the wiimote is connected (or before the ext-input device is opened). In the future we may support full extension hotplug support, but reverse-engineering this may take a while. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/Kconfig9
-rw-r--r--drivers/hid/Makefile3
-rw-r--r--drivers/hid/hid-wiimote-core.c23
-rw-r--r--drivers/hid/hid-wiimote-ext.c130
-rw-r--r--drivers/hid/hid-wiimote.h17
5 files changed, 178 insertions, 4 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 22a4a051f221..7a0c6f956d3e 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -623,6 +623,15 @@ config HID_WIIMOTE
623 ---help--- 623 ---help---
624 Support for the Nintendo Wii Remote bluetooth device. 624 Support for the Nintendo Wii Remote bluetooth device.
625 625
626config HID_WIIMOTE_EXT
627 bool "Nintendo Wii Remote Extension support"
628 depends on HID_WIIMOTE
629 default HID_WIIMOTE
630 ---help---
631 Support for extension controllers of the Nintendo Wii Remote. Say yes
632 here if you want to use the Nintendo Motion+, Nunchuck or Classic
633 extension controllers with your Wii Remote.
634
626config HID_ZEROPLUS 635config HID_ZEROPLUS
627 tristate "Zeroplus based game controller support" 636 tristate "Zeroplus based game controller support"
628 depends on USB_HID 637 depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 96d33adb258a..5fab4e632eab 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -26,6 +26,9 @@ ifdef CONFIG_LOGIWHEELS_FF
26endif 26endif
27 27
28hid-wiimote-y := hid-wiimote-core.o 28hid-wiimote-y := hid-wiimote-core.o
29ifdef CONFIG_HID_WIIMOTE_EXT
30 hid-wiimote-y += hid-wiimote-ext.o
31endif
29 32
30obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o 33obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
31obj-$(CONFIG_HID_ACRUX) += hid-axff.o 34obj-$(CONFIG_HID_ACRUX) += hid-axff.o
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index f7f8b7ff7dec..2ca8bfd350ad 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -201,6 +201,7 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
201static __u8 select_drm(struct wiimote_data *wdata) 201static __u8 select_drm(struct wiimote_data *wdata)
202{ 202{
203 __u8 ir = wdata->state.flags & WIIPROTO_FLAGS_IR; 203 __u8 ir = wdata->state.flags & WIIPROTO_FLAGS_IR;
204 bool ext = wiiext_active(wdata);
204 205
205 if (ir == WIIPROTO_FLAG_IR_BASIC) { 206 if (ir == WIIPROTO_FLAG_IR_BASIC) {
206 if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) 207 if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
@@ -212,10 +213,17 @@ static __u8 select_drm(struct wiimote_data *wdata)
212 } else if (ir == WIIPROTO_FLAG_IR_FULL) { 213 } else if (ir == WIIPROTO_FLAG_IR_FULL) {
213 return WIIPROTO_REQ_DRM_SKAI1; 214 return WIIPROTO_REQ_DRM_SKAI1;
214 } else { 215 } else {
215 if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) 216 if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) {
216 return WIIPROTO_REQ_DRM_KA; 217 if (ext)
217 else 218 return WIIPROTO_REQ_DRM_KAE;
218 return WIIPROTO_REQ_DRM_K; 219 else
220 return WIIPROTO_REQ_DRM_KA;
221 } else {
222 if (ext)
223 return WIIPROTO_REQ_DRM_KE;
224 else
225 return WIIPROTO_REQ_DRM_K;
226 }
219 } 227 }
220} 228}
221 229
@@ -795,6 +803,8 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
795 /* on status reports the drm is reset so we need to resend the drm */ 803 /* on status reports the drm is reset so we need to resend the drm */
796 wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); 804 wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
797 805
806 wiiext_event(wdata, payload[2] & 0x02);
807
798 if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_SREQ, 0)) { 808 if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_SREQ, 0)) {
799 wdata->state.cmd_battery = payload[5]; 809 wdata->state.cmd_battery = payload[5];
800 wiimote_cmd_complete(wdata); 810 wiimote_cmd_complete(wdata);
@@ -1145,6 +1155,7 @@ err:
1145 1155
1146static void wiimote_destroy(struct wiimote_data *wdata) 1156static void wiimote_destroy(struct wiimote_data *wdata)
1147{ 1157{
1158 wiiext_deinit(wdata);
1148 wiimote_leds_destroy(wdata); 1159 wiimote_leds_destroy(wdata);
1149 1160
1150 power_supply_unregister(&wdata->battery); 1161 power_supply_unregister(&wdata->battery);
@@ -1216,6 +1227,10 @@ static int wiimote_hid_probe(struct hid_device *hdev,
1216 if (ret) 1227 if (ret)
1217 goto err_free; 1228 goto err_free;
1218 1229
1230 ret = wiiext_init(wdata);
1231 if (ret)
1232 goto err_free;
1233
1219 hid_info(hdev, "New device registered\n"); 1234 hid_info(hdev, "New device registered\n");
1220 1235
1221 /* by default set led1 after device initialization */ 1236 /* by default set led1 after device initialization */
diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c
new file mode 100644
index 000000000000..fa9c67722aca
--- /dev/null
+++ b/drivers/hid/hid-wiimote-ext.c
@@ -0,0 +1,130 @@
1/*
2 * HID driver for Nintendo Wiimote extension devices
3 * Copyright (c) 2011 David Herrmann
4 */
5
6/*
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 */
12
13#include <linux/atomic.h>
14#include <linux/module.h>
15#include <linux/spinlock.h>
16#include <linux/workqueue.h>
17#include "hid-wiimote.h"
18
19struct wiimote_ext {
20 struct wiimote_data *wdata;
21 struct work_struct worker;
22
23 atomic_t opened;
24 atomic_t mp_opened;
25 bool plugged;
26 bool motionp;
27 __u8 ext_type;
28};
29
30enum wiiext_type {
31 WIIEXT_NONE, /* placeholder */
32 WIIEXT_CLASSIC, /* Nintendo classic controller */
33 WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */
34};
35
36static void wiiext_worker(struct work_struct *work)
37{
38 struct wiimote_ext *ext = container_of(work, struct wiimote_ext,
39 worker);
40}
41
42/* schedule work only once, otherwise mark for reschedule */
43static void wiiext_schedule(struct wiimote_ext *ext)
44{
45 queue_work(system_nrt_wq, &ext->worker);
46}
47
48/*
49 * Reacts on extension port events
50 * Whenever the driver gets an event from the wiimote that an extension has been
51 * plugged or unplugged, this funtion shall be called. It checks what extensions
52 * are connected and initializes and activates them.
53 * This can be called in atomic context. The initialization is done in a
54 * separate worker thread. The state.lock spinlock must be held by the caller.
55 */
56void wiiext_event(struct wiimote_data *wdata, bool plugged)
57{
58 if (!wdata->ext)
59 return;
60
61 if (wdata->ext->plugged == plugged)
62 return;
63
64 wdata->ext->plugged = plugged;
65 /*
66 * We need to call wiiext_schedule(wdata->ext) here, however, the
67 * extension initialization logic is not fully understood and so
68 * automatic initialization is not supported, yet.
69 */
70}
71
72/*
73 * Returns true if the current DRM mode should contain extension data and false
74 * if there is no interest in extension data.
75 * All supported extensions send 6 byte extension data so any DRM that contains
76 * extension bytes is fine.
77 * The caller must hold the state.lock spinlock.
78 */
79bool wiiext_active(struct wiimote_data *wdata)
80{
81 if (!wdata->ext)
82 return false;
83
84 return wdata->ext->motionp || wdata->ext->ext_type;
85}
86
87/* Initializes the extension driver of a wiimote */
88int wiiext_init(struct wiimote_data *wdata)
89{
90 struct wiimote_ext *ext;
91 unsigned long flags;
92
93 ext = kzalloc(sizeof(*ext), GFP_KERNEL);
94 if (!ext)
95 return -ENOMEM;
96
97 ext->wdata = wdata;
98 INIT_WORK(&ext->worker, wiiext_worker);
99
100 spin_lock_irqsave(&wdata->state.lock, flags);
101 wdata->ext = ext;
102 spin_unlock_irqrestore(&wdata->state.lock, flags);
103
104 return 0;
105}
106
107/* Deinitializes the extension driver of a wiimote */
108void wiiext_deinit(struct wiimote_data *wdata)
109{
110 struct wiimote_ext *ext = wdata->ext;
111 unsigned long flags;
112
113 if (!ext)
114 return;
115
116 /*
117 * We first unset wdata->ext to avoid further input from the wiimote
118 * core. The worker thread does not access this pointer so it is not
119 * affected by this.
120 * We kill the worker after this so it does not get respawned during
121 * deinitialization.
122 */
123
124 spin_lock_irqsave(&wdata->state.lock, flags);
125 wdata->ext = NULL;
126 spin_unlock_irqrestore(&wdata->state.lock, flags);
127
128 cancel_work_sync(&ext->worker);
129 kfree(ext);
130}
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index 865740d3a3fe..abbfab8f60b7 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -73,6 +73,7 @@ struct wiimote_data {
73 struct input_dev *accel; 73 struct input_dev *accel;
74 struct input_dev *ir; 74 struct input_dev *ir;
75 struct power_supply battery; 75 struct power_supply battery;
76 struct wiimote_ext *ext;
76 77
77 spinlock_t qlock; 78 spinlock_t qlock;
78 __u8 head; 79 __u8 head;
@@ -118,6 +119,22 @@ extern int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
118extern ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset, 119extern ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset,
119 __u8 *rmem, __u8 size); 120 __u8 *rmem, __u8 size);
120 121
122#ifdef CONFIG_HID_WIIMOTE_EXT
123
124extern int wiiext_init(struct wiimote_data *wdata);
125extern void wiiext_deinit(struct wiimote_data *wdata);
126extern void wiiext_event(struct wiimote_data *wdata, bool plugged);
127extern bool wiiext_active(struct wiimote_data *wdata);
128
129#else
130
131static inline int wiiext_init(void *u) { return 0; }
132static inline void wiiext_deinit(void *u) { }
133static inline void wiiext_event(void *u, bool p) { }
134static inline bool wiiext_active(void *u) { return false; }
135
136#endif
137
121/* requires the state.lock spinlock to be held */ 138/* requires the state.lock spinlock to be held */
122static inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd, 139static inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd,
123 __u32 opt) 140 __u32 opt)