diff options
-rw-r--r-- | drivers/hid/Kconfig | 9 | ||||
-rw-r--r-- | drivers/hid/Makefile | 3 | ||||
-rw-r--r-- | drivers/hid/hid-wiimote-core.c | 23 | ||||
-rw-r--r-- | drivers/hid/hid-wiimote-ext.c | 130 | ||||
-rw-r--r-- | drivers/hid/hid-wiimote.h | 17 |
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 | ||
626 | config 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 | |||
626 | config HID_ZEROPLUS | 635 | config 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 | |||
26 | endif | 26 | endif |
27 | 27 | ||
28 | hid-wiimote-y := hid-wiimote-core.o | 28 | hid-wiimote-y := hid-wiimote-core.o |
29 | ifdef CONFIG_HID_WIIMOTE_EXT | ||
30 | hid-wiimote-y += hid-wiimote-ext.o | ||
31 | endif | ||
29 | 32 | ||
30 | obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o | 33 | obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o |
31 | obj-$(CONFIG_HID_ACRUX) += hid-axff.o | 34 | obj-$(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) | |||
201 | static __u8 select_drm(struct wiimote_data *wdata) | 201 | static __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 | ||
1146 | static void wiimote_destroy(struct wiimote_data *wdata) | 1156 | static 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 | |||
19 | struct 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 | |||
30 | enum wiiext_type { | ||
31 | WIIEXT_NONE, /* placeholder */ | ||
32 | WIIEXT_CLASSIC, /* Nintendo classic controller */ | ||
33 | WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */ | ||
34 | }; | ||
35 | |||
36 | static 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 */ | ||
43 | static 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 | */ | ||
56 | void 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 | */ | ||
79 | bool 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 */ | ||
88 | int 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 */ | ||
108 | void 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, | |||
118 | extern ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset, | 119 | extern 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 | |||
124 | extern int wiiext_init(struct wiimote_data *wdata); | ||
125 | extern void wiiext_deinit(struct wiimote_data *wdata); | ||
126 | extern void wiiext_event(struct wiimote_data *wdata, bool plugged); | ||
127 | extern bool wiiext_active(struct wiimote_data *wdata); | ||
128 | |||
129 | #else | ||
130 | |||
131 | static inline int wiiext_init(void *u) { return 0; } | ||
132 | static inline void wiiext_deinit(void *u) { } | ||
133 | static inline void wiiext_event(void *u, bool p) { } | ||
134 | static 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 */ |
122 | static inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd, | 139 | static inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd, |
123 | __u32 opt) | 140 | __u32 opt) |