blob: ceec0cef326826b9b072d671dc43334940cb27c7 [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;
David Herrmannb17b57a2011-11-17 14:12:07 +010028 bool mp_plugged;
David Herrmanncb992212011-11-17 14:12:01 +010029 bool motionp;
30 __u8 ext_type;
31};
32
33enum wiiext_type {
34 WIIEXT_NONE, /* placeholder */
35 WIIEXT_CLASSIC, /* Nintendo classic controller */
36 WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */
37};
38
David Herrmann82fb1b32011-11-17 14:12:02 +010039/* diable all extensions */
40static void ext_disable(struct wiimote_ext *ext)
41{
42 unsigned long flags;
David Herrmann492ba952011-11-17 14:12:03 +010043 __u8 wmem = 0x55;
44
45 if (!wiimote_cmd_acquire(ext->wdata)) {
46 wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem));
47 wiimote_cmd_release(ext->wdata);
48 }
David Herrmann82fb1b32011-11-17 14:12:02 +010049
50 spin_lock_irqsave(&ext->wdata->state.lock, flags);
51 ext->motionp = false;
52 ext->ext_type = WIIEXT_NONE;
David Herrmann492ba952011-11-17 14:12:03 +010053 wiiproto_req_drm(ext->wdata, WIIPROTO_REQ_NULL);
David Herrmann82fb1b32011-11-17 14:12:02 +010054 spin_unlock_irqrestore(&ext->wdata->state.lock, flags);
55}
56
57static bool motionp_read(struct wiimote_ext *ext)
58{
David Herrmann492ba952011-11-17 14:12:03 +010059 __u8 rmem[2], wmem;
60 ssize_t ret;
61 bool avail = false;
62
David Herrmann479901b2011-11-17 14:12:05 +010063 if (!atomic_read(&ext->mp_opened))
64 return false;
65
David Herrmann492ba952011-11-17 14:12:03 +010066 if (wiimote_cmd_acquire(ext->wdata))
67 return false;
68
69 /* initialize motion plus */
70 wmem = 0x55;
71 ret = wiimote_cmd_write(ext->wdata, 0xa600f0, &wmem, sizeof(wmem));
72 if (ret)
73 goto error;
74
75 /* read motion plus ID */
76 ret = wiimote_cmd_read(ext->wdata, 0xa600fe, rmem, 2);
77 if (ret == 2 || rmem[1] == 0x5)
78 avail = true;
79
80error:
81 wiimote_cmd_release(ext->wdata);
82 return avail;
David Herrmann82fb1b32011-11-17 14:12:02 +010083}
84
85static __u8 ext_read(struct wiimote_ext *ext)
86{
David Herrmann492ba952011-11-17 14:12:03 +010087 ssize_t ret;
88 __u8 rmem[2], wmem;
89 __u8 type = WIIEXT_NONE;
90
David Herrmann479901b2011-11-17 14:12:05 +010091 if (!ext->plugged || !atomic_read(&ext->opened))
David Herrmann492ba952011-11-17 14:12:03 +010092 return WIIEXT_NONE;
93
94 if (wiimote_cmd_acquire(ext->wdata))
95 return WIIEXT_NONE;
96
97 /* initialize extension */
98 wmem = 0x55;
99 ret = wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem));
100 if (!ret) {
101 /* disable encryption */
102 wmem = 0x0;
103 wiimote_cmd_write(ext->wdata, 0xa400fb, &wmem, sizeof(wmem));
104 }
105
106 /* read extension ID */
107 ret = wiimote_cmd_read(ext->wdata, 0xa400fe, rmem, 2);
108 if (ret == 2) {
109 if (rmem[0] == 0 && rmem[1] == 0)
110 type = WIIEXT_NUNCHUCK;
111 else if (rmem[0] == 0x01 && rmem[1] == 0x01)
112 type = WIIEXT_CLASSIC;
113 }
114
115 wiimote_cmd_release(ext->wdata);
116
117 return type;
David Herrmann82fb1b32011-11-17 14:12:02 +0100118}
119
120static void ext_enable(struct wiimote_ext *ext, bool motionp, __u8 ext_type)
121{
122 unsigned long flags;
David Herrmann492ba952011-11-17 14:12:03 +0100123 __u8 wmem;
124 int ret;
125
126 if (motionp) {
127 if (wiimote_cmd_acquire(ext->wdata))
128 return;
129
130 if (ext_type == WIIEXT_CLASSIC)
131 wmem = 0x07;
132 else if (ext_type == WIIEXT_NUNCHUCK)
133 wmem = 0x05;
134 else
135 wmem = 0x04;
136
137 ret = wiimote_cmd_write(ext->wdata, 0xa600fe, &wmem, sizeof(wmem));
138 wiimote_cmd_release(ext->wdata);
139 if (ret)
140 return;
141 }
David Herrmann82fb1b32011-11-17 14:12:02 +0100142
143 spin_lock_irqsave(&ext->wdata->state.lock, flags);
144 ext->motionp = motionp;
145 ext->ext_type = ext_type;
David Herrmann492ba952011-11-17 14:12:03 +0100146 wiiproto_req_drm(ext->wdata, WIIPROTO_REQ_NULL);
David Herrmann82fb1b32011-11-17 14:12:02 +0100147 spin_unlock_irqrestore(&ext->wdata->state.lock, flags);
148}
149
David Herrmanncb992212011-11-17 14:12:01 +0100150static void wiiext_worker(struct work_struct *work)
151{
152 struct wiimote_ext *ext = container_of(work, struct wiimote_ext,
153 worker);
David Herrmann82fb1b32011-11-17 14:12:02 +0100154 bool motionp;
155 __u8 ext_type;
156
157 ext_disable(ext);
158 motionp = motionp_read(ext);
159 ext_type = ext_read(ext);
160 ext_enable(ext, motionp, ext_type);
David Herrmanncb992212011-11-17 14:12:01 +0100161}
162
163/* schedule work only once, otherwise mark for reschedule */
164static void wiiext_schedule(struct wiimote_ext *ext)
165{
166 queue_work(system_nrt_wq, &ext->worker);
167}
168
169/*
170 * Reacts on extension port events
171 * Whenever the driver gets an event from the wiimote that an extension has been
172 * plugged or unplugged, this funtion shall be called. It checks what extensions
173 * are connected and initializes and activates them.
174 * This can be called in atomic context. The initialization is done in a
175 * separate worker thread. The state.lock spinlock must be held by the caller.
176 */
177void wiiext_event(struct wiimote_data *wdata, bool plugged)
178{
179 if (!wdata->ext)
180 return;
181
182 if (wdata->ext->plugged == plugged)
183 return;
184
185 wdata->ext->plugged = plugged;
David Herrmannb17b57a2011-11-17 14:12:07 +0100186
187 if (!plugged)
188 wdata->ext->mp_plugged = false;
189
David Herrmanncb992212011-11-17 14:12:01 +0100190 /*
191 * We need to call wiiext_schedule(wdata->ext) here, however, the
192 * extension initialization logic is not fully understood and so
193 * automatic initialization is not supported, yet.
194 */
195}
196
197/*
198 * Returns true if the current DRM mode should contain extension data and false
199 * if there is no interest in extension data.
200 * All supported extensions send 6 byte extension data so any DRM that contains
201 * extension bytes is fine.
202 * The caller must hold the state.lock spinlock.
203 */
204bool wiiext_active(struct wiimote_data *wdata)
205{
206 if (!wdata->ext)
207 return false;
208
209 return wdata->ext->motionp || wdata->ext->ext_type;
210}
211
David Herrmann0b6815d2011-11-17 14:12:06 +0100212static void handler_motionp(struct wiimote_ext *ext, const __u8 *payload)
213{
David Herrmannb17b57a2011-11-17 14:12:07 +0100214 __s32 x, y, z;
215 bool plugged;
216
217 /* | 8 7 6 5 4 3 | 2 | 1 |
218 * -----+------------------------------+-----+-----+
219 * 1 | Yaw Speed <7:0> |
220 * 2 | Roll Speed <7:0> |
221 * 3 | Pitch Speed <7:0> |
222 * -----+------------------------------+-----+-----+
223 * 4 | Yaw Speed <13:8> | Yaw |Pitch|
224 * -----+------------------------------+-----+-----+
225 * 5 | Roll Speed <13:8> |Roll | Ext |
226 * -----+------------------------------+-----+-----+
227 * 6 | Pitch Speed <13:8> | 1 | 0 |
228 * -----+------------------------------+-----+-----+
229 * The single bits Yaw, Roll, Pitch in the lower right corner specify
230 * whether the wiimote is rotating fast (0) or slow (1). Speed for slow
231 * roation is 440 deg/s and for fast rotation 2000 deg/s. To get a
232 * linear scale we multiply by 2000/440 = ~4.5454 which is 18 for fast
233 * and 9 for slow.
234 * If the wiimote is not rotating the sensor reports 2^13 = 8192.
235 * Ext specifies whether an extension is connected to the motionp.
236 */
237
238 x = payload[0];
239 y = payload[1];
240 z = payload[2];
241
242 x |= (((__u16)payload[3]) << 6) & 0xff00;
243 y |= (((__u16)payload[4]) << 6) & 0xff00;
244 z |= (((__u16)payload[5]) << 6) & 0xff00;
245
246 x -= 8192;
247 y -= 8192;
248 z -= 8192;
249
250 if (!(payload[3] & 0x02))
251 x *= 18;
252 else
253 x *= 9;
254 if (!(payload[4] & 0x02))
255 y *= 18;
256 else
257 y *= 9;
258 if (!(payload[3] & 0x01))
259 z *= 18;
260 else
261 z *= 9;
262
263 input_report_abs(ext->mp_input, ABS_RX, x);
264 input_report_abs(ext->mp_input, ABS_RY, y);
265 input_report_abs(ext->mp_input, ABS_RZ, z);
266 input_sync(ext->mp_input);
267
268 plugged = payload[5] & 0x01;
269 if (plugged != ext->mp_plugged)
270 ext->mp_plugged = plugged;
David Herrmann0b6815d2011-11-17 14:12:06 +0100271}
272
273static void handler_nunchuck(struct wiimote_ext *ext, const __u8 *payload)
274{
275}
276
277static void handler_classic(struct wiimote_ext *ext, const __u8 *payload)
278{
279}
280
281/* call this with state.lock spinlock held */
282void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload)
283{
284 struct wiimote_ext *ext = wdata->ext;
285
286 if (!ext)
287 return;
288
289 if (ext->motionp && (payload[5] & 0x02)) {
290 handler_motionp(ext, payload);
291 } else if (ext->ext_type == WIIEXT_NUNCHUCK) {
292 handler_nunchuck(ext, payload);
293 } else if (ext->ext_type == WIIEXT_CLASSIC) {
294 handler_classic(ext, payload);
295 }
296}
297
David Herrmannc1e51392011-11-17 14:12:04 +0100298static ssize_t wiiext_show(struct device *dev, struct device_attribute *attr,
299 char *buf)
300{
301 struct wiimote_data *wdata = dev_to_wii(dev);
302 __u8 type = WIIEXT_NONE;
303 bool motionp = false;
304 unsigned long flags;
305
306 spin_lock_irqsave(&wdata->state.lock, flags);
307 if (wdata->ext) {
308 motionp = wdata->ext->motionp;
309 type = wdata->ext->ext_type;
310 }
311 spin_unlock_irqrestore(&wdata->state.lock, flags);
312
313 if (type == WIIEXT_NUNCHUCK) {
314 if (motionp)
315 return sprintf(buf, "motionp+nunchuck\n");
316 else
317 return sprintf(buf, "nunchuck\n");
318 } else if (type == WIIEXT_CLASSIC) {
319 if (motionp)
320 return sprintf(buf, "motionp+classic\n");
321 else
322 return sprintf(buf, "classic\n");
323 } else {
324 if (motionp)
325 return sprintf(buf, "motionp\n");
326 else
327 return sprintf(buf, "none\n");
328 }
329}
330
331static DEVICE_ATTR(extension, S_IRUGO, wiiext_show, NULL);
332
David Herrmann479901b2011-11-17 14:12:05 +0100333static int wiiext_input_open(struct input_dev *dev)
334{
335 struct wiimote_ext *ext = input_get_drvdata(dev);
336 int ret;
337
338 ret = hid_hw_open(ext->wdata->hdev);
339 if (ret)
340 return ret;
341
342 atomic_inc(&ext->opened);
343 wiiext_schedule(ext);
344
345 return 0;
346}
347
348static void wiiext_input_close(struct input_dev *dev)
349{
350 struct wiimote_ext *ext = input_get_drvdata(dev);
351
352 atomic_dec(&ext->opened);
353 wiiext_schedule(ext);
354 hid_hw_close(ext->wdata->hdev);
355}
356
357static int wiiext_mp_open(struct input_dev *dev)
358{
359 struct wiimote_ext *ext = input_get_drvdata(dev);
360 int ret;
361
362 ret = hid_hw_open(ext->wdata->hdev);
363 if (ret)
364 return ret;
365
366 atomic_inc(&ext->mp_opened);
367 wiiext_schedule(ext);
368
369 return 0;
370}
371
372static void wiiext_mp_close(struct input_dev *dev)
373{
374 struct wiimote_ext *ext = input_get_drvdata(dev);
375
376 atomic_dec(&ext->mp_opened);
377 wiiext_schedule(ext);
378 hid_hw_close(ext->wdata->hdev);
379}
380
David Herrmanncb992212011-11-17 14:12:01 +0100381/* Initializes the extension driver of a wiimote */
382int wiiext_init(struct wiimote_data *wdata)
383{
384 struct wiimote_ext *ext;
385 unsigned long flags;
David Herrmannc1e51392011-11-17 14:12:04 +0100386 int ret;
David Herrmanncb992212011-11-17 14:12:01 +0100387
388 ext = kzalloc(sizeof(*ext), GFP_KERNEL);
389 if (!ext)
390 return -ENOMEM;
391
392 ext->wdata = wdata;
393 INIT_WORK(&ext->worker, wiiext_worker);
394
David Herrmann479901b2011-11-17 14:12:05 +0100395 ext->input = input_allocate_device();
396 if (!ext->input) {
397 ret = -ENOMEM;
398 goto err_input;
399 }
400
401 input_set_drvdata(ext->input, ext);
402 ext->input->open = wiiext_input_open;
403 ext->input->close = wiiext_input_close;
404 ext->input->dev.parent = &wdata->hdev->dev;
405 ext->input->id.bustype = wdata->hdev->bus;
406 ext->input->id.vendor = wdata->hdev->vendor;
407 ext->input->id.product = wdata->hdev->product;
408 ext->input->id.version = wdata->hdev->version;
409 ext->input->name = WIIMOTE_NAME " Extension";
410
411 ret = input_register_device(ext->input);
412 if (ret) {
413 input_free_device(ext->input);
414 goto err_input;
415 }
416
417 ext->mp_input = input_allocate_device();
418 if (!ext->mp_input) {
419 ret = -ENOMEM;
420 goto err_mp;
421 }
422
423 input_set_drvdata(ext->mp_input, ext);
424 ext->mp_input->open = wiiext_mp_open;
425 ext->mp_input->close = wiiext_mp_close;
426 ext->mp_input->dev.parent = &wdata->hdev->dev;
427 ext->mp_input->id.bustype = wdata->hdev->bus;
428 ext->mp_input->id.vendor = wdata->hdev->vendor;
429 ext->mp_input->id.product = wdata->hdev->product;
430 ext->mp_input->id.version = wdata->hdev->version;
431 ext->mp_input->name = WIIMOTE_NAME " Motion+";
432
David Herrmannb17b57a2011-11-17 14:12:07 +0100433 set_bit(EV_ABS, ext->mp_input->evbit);
434 set_bit(ABS_RX, ext->mp_input->absbit);
435 set_bit(ABS_RY, ext->mp_input->absbit);
436 set_bit(ABS_RZ, ext->mp_input->absbit);
437 input_set_abs_params(ext->mp_input, ABS_RX, -160000, 160000, 4, 8);
438 input_set_abs_params(ext->mp_input, ABS_RY, -160000, 160000, 4, 8);
439 input_set_abs_params(ext->mp_input, ABS_RZ, -160000, 160000, 4, 8);
440
David Herrmann479901b2011-11-17 14:12:05 +0100441 ret = input_register_device(ext->mp_input);
442 if (ret) {
443 input_free_device(ext->mp_input);
444 goto err_mp;
445 }
446
David Herrmannc1e51392011-11-17 14:12:04 +0100447 ret = device_create_file(&wdata->hdev->dev, &dev_attr_extension);
448 if (ret)
David Herrmann479901b2011-11-17 14:12:05 +0100449 goto err_dev;
David Herrmannc1e51392011-11-17 14:12:04 +0100450
David Herrmanncb992212011-11-17 14:12:01 +0100451 spin_lock_irqsave(&wdata->state.lock, flags);
452 wdata->ext = ext;
453 spin_unlock_irqrestore(&wdata->state.lock, flags);
454
455 return 0;
David Herrmannc1e51392011-11-17 14:12:04 +0100456
David Herrmann479901b2011-11-17 14:12:05 +0100457err_dev:
458 input_unregister_device(ext->mp_input);
459err_mp:
460 input_unregister_device(ext->input);
461err_input:
David Herrmannc1e51392011-11-17 14:12:04 +0100462 kfree(ext);
463 return ret;
David Herrmanncb992212011-11-17 14:12:01 +0100464}
465
466/* Deinitializes the extension driver of a wiimote */
467void wiiext_deinit(struct wiimote_data *wdata)
468{
469 struct wiimote_ext *ext = wdata->ext;
470 unsigned long flags;
471
472 if (!ext)
473 return;
474
475 /*
476 * We first unset wdata->ext to avoid further input from the wiimote
477 * core. The worker thread does not access this pointer so it is not
478 * affected by this.
479 * We kill the worker after this so it does not get respawned during
480 * deinitialization.
481 */
482
483 spin_lock_irqsave(&wdata->state.lock, flags);
484 wdata->ext = NULL;
485 spin_unlock_irqrestore(&wdata->state.lock, flags);
486
David Herrmannc1e51392011-11-17 14:12:04 +0100487 device_remove_file(&wdata->hdev->dev, &dev_attr_extension);
David Herrmann479901b2011-11-17 14:12:05 +0100488 input_unregister_device(ext->mp_input);
489 input_unregister_device(ext->input);
David Herrmannc1e51392011-11-17 14:12:04 +0100490
David Herrmanncb992212011-11-17 14:12:01 +0100491 cancel_work_sync(&ext->worker);
492 kfree(ext);
493}