blob: ecc7b7b9b17186e6b58544e5867972c1d5890167 [file] [log] [blame]
David Herrmanncb992212011-11-17 14:12:01 +01001/*
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;
David Herrmann479901b2011-11-17 14:12:05 +010022 struct input_dev *input;
23 struct input_dev *mp_input;
David Herrmanncb992212011-11-17 14:12:01 +010024
25 atomic_t opened;
26 atomic_t mp_opened;
27 bool plugged;
28 bool motionp;
29 __u8 ext_type;
30};
31
32enum wiiext_type {
33 WIIEXT_NONE, /* placeholder */
34 WIIEXT_CLASSIC, /* Nintendo classic controller */
35 WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */
36};
37
David Herrmann82fb1b32011-11-17 14:12:02 +010038/* diable all extensions */
39static void ext_disable(struct wiimote_ext *ext)
40{
41 unsigned long flags;
David Herrmann492ba952011-11-17 14:12:03 +010042 __u8 wmem = 0x55;
43
44 if (!wiimote_cmd_acquire(ext->wdata)) {
45 wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem));
46 wiimote_cmd_release(ext->wdata);
47 }
David Herrmann82fb1b32011-11-17 14:12:02 +010048
49 spin_lock_irqsave(&ext->wdata->state.lock, flags);
50 ext->motionp = false;
51 ext->ext_type = WIIEXT_NONE;
David Herrmann492ba952011-11-17 14:12:03 +010052 wiiproto_req_drm(ext->wdata, WIIPROTO_REQ_NULL);
David Herrmann82fb1b32011-11-17 14:12:02 +010053 spin_unlock_irqrestore(&ext->wdata->state.lock, flags);
54}
55
56static bool motionp_read(struct wiimote_ext *ext)
57{
David Herrmann492ba952011-11-17 14:12:03 +010058 __u8 rmem[2], wmem;
59 ssize_t ret;
60 bool avail = false;
61
David Herrmann479901b2011-11-17 14:12:05 +010062 if (!atomic_read(&ext->mp_opened))
63 return false;
64
David Herrmann492ba952011-11-17 14:12:03 +010065 if (wiimote_cmd_acquire(ext->wdata))
66 return false;
67
68 /* initialize motion plus */
69 wmem = 0x55;
70 ret = wiimote_cmd_write(ext->wdata, 0xa600f0, &wmem, sizeof(wmem));
71 if (ret)
72 goto error;
73
74 /* read motion plus ID */
75 ret = wiimote_cmd_read(ext->wdata, 0xa600fe, rmem, 2);
76 if (ret == 2 || rmem[1] == 0x5)
77 avail = true;
78
79error:
80 wiimote_cmd_release(ext->wdata);
81 return avail;
David Herrmann82fb1b32011-11-17 14:12:02 +010082}
83
84static __u8 ext_read(struct wiimote_ext *ext)
85{
David Herrmann492ba952011-11-17 14:12:03 +010086 ssize_t ret;
87 __u8 rmem[2], wmem;
88 __u8 type = WIIEXT_NONE;
89
David Herrmann479901b2011-11-17 14:12:05 +010090 if (!ext->plugged || !atomic_read(&ext->opened))
David Herrmann492ba952011-11-17 14:12:03 +010091 return WIIEXT_NONE;
92
93 if (wiimote_cmd_acquire(ext->wdata))
94 return WIIEXT_NONE;
95
96 /* initialize extension */
97 wmem = 0x55;
98 ret = wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem));
99 if (!ret) {
100 /* disable encryption */
101 wmem = 0x0;
102 wiimote_cmd_write(ext->wdata, 0xa400fb, &wmem, sizeof(wmem));
103 }
104
105 /* read extension ID */
106 ret = wiimote_cmd_read(ext->wdata, 0xa400fe, rmem, 2);
107 if (ret == 2) {
108 if (rmem[0] == 0 && rmem[1] == 0)
109 type = WIIEXT_NUNCHUCK;
110 else if (rmem[0] == 0x01 && rmem[1] == 0x01)
111 type = WIIEXT_CLASSIC;
112 }
113
114 wiimote_cmd_release(ext->wdata);
115
116 return type;
David Herrmann82fb1b32011-11-17 14:12:02 +0100117}
118
119static void ext_enable(struct wiimote_ext *ext, bool motionp, __u8 ext_type)
120{
121 unsigned long flags;
David Herrmann492ba952011-11-17 14:12:03 +0100122 __u8 wmem;
123 int ret;
124
125 if (motionp) {
126 if (wiimote_cmd_acquire(ext->wdata))
127 return;
128
129 if (ext_type == WIIEXT_CLASSIC)
130 wmem = 0x07;
131 else if (ext_type == WIIEXT_NUNCHUCK)
132 wmem = 0x05;
133 else
134 wmem = 0x04;
135
136 ret = wiimote_cmd_write(ext->wdata, 0xa600fe, &wmem, sizeof(wmem));
137 wiimote_cmd_release(ext->wdata);
138 if (ret)
139 return;
140 }
David Herrmann82fb1b32011-11-17 14:12:02 +0100141
142 spin_lock_irqsave(&ext->wdata->state.lock, flags);
143 ext->motionp = motionp;
144 ext->ext_type = ext_type;
David Herrmann492ba952011-11-17 14:12:03 +0100145 wiiproto_req_drm(ext->wdata, WIIPROTO_REQ_NULL);
David Herrmann82fb1b32011-11-17 14:12:02 +0100146 spin_unlock_irqrestore(&ext->wdata->state.lock, flags);
147}
148
David Herrmanncb992212011-11-17 14:12:01 +0100149static void wiiext_worker(struct work_struct *work)
150{
151 struct wiimote_ext *ext = container_of(work, struct wiimote_ext,
152 worker);
David Herrmann82fb1b32011-11-17 14:12:02 +0100153 bool motionp;
154 __u8 ext_type;
155
156 ext_disable(ext);
157 motionp = motionp_read(ext);
158 ext_type = ext_read(ext);
159 ext_enable(ext, motionp, ext_type);
David Herrmanncb992212011-11-17 14:12:01 +0100160}
161
162/* schedule work only once, otherwise mark for reschedule */
163static void wiiext_schedule(struct wiimote_ext *ext)
164{
165 queue_work(system_nrt_wq, &ext->worker);
166}
167
168/*
169 * Reacts on extension port events
170 * Whenever the driver gets an event from the wiimote that an extension has been
171 * plugged or unplugged, this funtion shall be called. It checks what extensions
172 * are connected and initializes and activates them.
173 * This can be called in atomic context. The initialization is done in a
174 * separate worker thread. The state.lock spinlock must be held by the caller.
175 */
176void wiiext_event(struct wiimote_data *wdata, bool plugged)
177{
178 if (!wdata->ext)
179 return;
180
181 if (wdata->ext->plugged == plugged)
182 return;
183
184 wdata->ext->plugged = plugged;
185 /*
186 * We need to call wiiext_schedule(wdata->ext) here, however, the
187 * extension initialization logic is not fully understood and so
188 * automatic initialization is not supported, yet.
189 */
190}
191
192/*
193 * Returns true if the current DRM mode should contain extension data and false
194 * if there is no interest in extension data.
195 * All supported extensions send 6 byte extension data so any DRM that contains
196 * extension bytes is fine.
197 * The caller must hold the state.lock spinlock.
198 */
199bool wiiext_active(struct wiimote_data *wdata)
200{
201 if (!wdata->ext)
202 return false;
203
204 return wdata->ext->motionp || wdata->ext->ext_type;
205}
206
David Herrmann0b6815d2011-11-17 14:12:06 +0100207static void handler_motionp(struct wiimote_ext *ext, const __u8 *payload)
208{
209}
210
211static void handler_nunchuck(struct wiimote_ext *ext, const __u8 *payload)
212{
213}
214
215static void handler_classic(struct wiimote_ext *ext, const __u8 *payload)
216{
217}
218
219/* call this with state.lock spinlock held */
220void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload)
221{
222 struct wiimote_ext *ext = wdata->ext;
223
224 if (!ext)
225 return;
226
227 if (ext->motionp && (payload[5] & 0x02)) {
228 handler_motionp(ext, payload);
229 } else if (ext->ext_type == WIIEXT_NUNCHUCK) {
230 handler_nunchuck(ext, payload);
231 } else if (ext->ext_type == WIIEXT_CLASSIC) {
232 handler_classic(ext, payload);
233 }
234}
235
David Herrmannc1e51392011-11-17 14:12:04 +0100236static ssize_t wiiext_show(struct device *dev, struct device_attribute *attr,
237 char *buf)
238{
239 struct wiimote_data *wdata = dev_to_wii(dev);
240 __u8 type = WIIEXT_NONE;
241 bool motionp = false;
242 unsigned long flags;
243
244 spin_lock_irqsave(&wdata->state.lock, flags);
245 if (wdata->ext) {
246 motionp = wdata->ext->motionp;
247 type = wdata->ext->ext_type;
248 }
249 spin_unlock_irqrestore(&wdata->state.lock, flags);
250
251 if (type == WIIEXT_NUNCHUCK) {
252 if (motionp)
253 return sprintf(buf, "motionp+nunchuck\n");
254 else
255 return sprintf(buf, "nunchuck\n");
256 } else if (type == WIIEXT_CLASSIC) {
257 if (motionp)
258 return sprintf(buf, "motionp+classic\n");
259 else
260 return sprintf(buf, "classic\n");
261 } else {
262 if (motionp)
263 return sprintf(buf, "motionp\n");
264 else
265 return sprintf(buf, "none\n");
266 }
267}
268
269static DEVICE_ATTR(extension, S_IRUGO, wiiext_show, NULL);
270
David Herrmann479901b2011-11-17 14:12:05 +0100271static int wiiext_input_open(struct input_dev *dev)
272{
273 struct wiimote_ext *ext = input_get_drvdata(dev);
274 int ret;
275
276 ret = hid_hw_open(ext->wdata->hdev);
277 if (ret)
278 return ret;
279
280 atomic_inc(&ext->opened);
281 wiiext_schedule(ext);
282
283 return 0;
284}
285
286static void wiiext_input_close(struct input_dev *dev)
287{
288 struct wiimote_ext *ext = input_get_drvdata(dev);
289
290 atomic_dec(&ext->opened);
291 wiiext_schedule(ext);
292 hid_hw_close(ext->wdata->hdev);
293}
294
295static int wiiext_mp_open(struct input_dev *dev)
296{
297 struct wiimote_ext *ext = input_get_drvdata(dev);
298 int ret;
299
300 ret = hid_hw_open(ext->wdata->hdev);
301 if (ret)
302 return ret;
303
304 atomic_inc(&ext->mp_opened);
305 wiiext_schedule(ext);
306
307 return 0;
308}
309
310static void wiiext_mp_close(struct input_dev *dev)
311{
312 struct wiimote_ext *ext = input_get_drvdata(dev);
313
314 atomic_dec(&ext->mp_opened);
315 wiiext_schedule(ext);
316 hid_hw_close(ext->wdata->hdev);
317}
318
David Herrmanncb992212011-11-17 14:12:01 +0100319/* Initializes the extension driver of a wiimote */
320int wiiext_init(struct wiimote_data *wdata)
321{
322 struct wiimote_ext *ext;
323 unsigned long flags;
David Herrmannc1e51392011-11-17 14:12:04 +0100324 int ret;
David Herrmanncb992212011-11-17 14:12:01 +0100325
326 ext = kzalloc(sizeof(*ext), GFP_KERNEL);
327 if (!ext)
328 return -ENOMEM;
329
330 ext->wdata = wdata;
331 INIT_WORK(&ext->worker, wiiext_worker);
332
David Herrmann479901b2011-11-17 14:12:05 +0100333 ext->input = input_allocate_device();
334 if (!ext->input) {
335 ret = -ENOMEM;
336 goto err_input;
337 }
338
339 input_set_drvdata(ext->input, ext);
340 ext->input->open = wiiext_input_open;
341 ext->input->close = wiiext_input_close;
342 ext->input->dev.parent = &wdata->hdev->dev;
343 ext->input->id.bustype = wdata->hdev->bus;
344 ext->input->id.vendor = wdata->hdev->vendor;
345 ext->input->id.product = wdata->hdev->product;
346 ext->input->id.version = wdata->hdev->version;
347 ext->input->name = WIIMOTE_NAME " Extension";
348
349 ret = input_register_device(ext->input);
350 if (ret) {
351 input_free_device(ext->input);
352 goto err_input;
353 }
354
355 ext->mp_input = input_allocate_device();
356 if (!ext->mp_input) {
357 ret = -ENOMEM;
358 goto err_mp;
359 }
360
361 input_set_drvdata(ext->mp_input, ext);
362 ext->mp_input->open = wiiext_mp_open;
363 ext->mp_input->close = wiiext_mp_close;
364 ext->mp_input->dev.parent = &wdata->hdev->dev;
365 ext->mp_input->id.bustype = wdata->hdev->bus;
366 ext->mp_input->id.vendor = wdata->hdev->vendor;
367 ext->mp_input->id.product = wdata->hdev->product;
368 ext->mp_input->id.version = wdata->hdev->version;
369 ext->mp_input->name = WIIMOTE_NAME " Motion+";
370
371 ret = input_register_device(ext->mp_input);
372 if (ret) {
373 input_free_device(ext->mp_input);
374 goto err_mp;
375 }
376
David Herrmannc1e51392011-11-17 14:12:04 +0100377 ret = device_create_file(&wdata->hdev->dev, &dev_attr_extension);
378 if (ret)
David Herrmann479901b2011-11-17 14:12:05 +0100379 goto err_dev;
David Herrmannc1e51392011-11-17 14:12:04 +0100380
David Herrmanncb992212011-11-17 14:12:01 +0100381 spin_lock_irqsave(&wdata->state.lock, flags);
382 wdata->ext = ext;
383 spin_unlock_irqrestore(&wdata->state.lock, flags);
384
385 return 0;
David Herrmannc1e51392011-11-17 14:12:04 +0100386
David Herrmann479901b2011-11-17 14:12:05 +0100387err_dev:
388 input_unregister_device(ext->mp_input);
389err_mp:
390 input_unregister_device(ext->input);
391err_input:
David Herrmannc1e51392011-11-17 14:12:04 +0100392 kfree(ext);
393 return ret;
David Herrmanncb992212011-11-17 14:12:01 +0100394}
395
396/* Deinitializes the extension driver of a wiimote */
397void wiiext_deinit(struct wiimote_data *wdata)
398{
399 struct wiimote_ext *ext = wdata->ext;
400 unsigned long flags;
401
402 if (!ext)
403 return;
404
405 /*
406 * We first unset wdata->ext to avoid further input from the wiimote
407 * core. The worker thread does not access this pointer so it is not
408 * affected by this.
409 * We kill the worker after this so it does not get respawned during
410 * deinitialization.
411 */
412
413 spin_lock_irqsave(&wdata->state.lock, flags);
414 wdata->ext = NULL;
415 spin_unlock_irqrestore(&wdata->state.lock, flags);
416
David Herrmannc1e51392011-11-17 14:12:04 +0100417 device_remove_file(&wdata->hdev->dev, &dev_attr_extension);
David Herrmann479901b2011-11-17 14:12:05 +0100418 input_unregister_device(ext->mp_input);
419 input_unregister_device(ext->input);
David Herrmannc1e51392011-11-17 14:12:04 +0100420
David Herrmanncb992212011-11-17 14:12:01 +0100421 cancel_work_sync(&ext->worker);
422 kfree(ext);
423}