Commit | Line | Data |
---|---|---|
cb99221b DH |
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; | |
479901ba DH |
22 | struct input_dev *input; |
23 | struct input_dev *mp_input; | |
cb99221b DH |
24 | |
25 | atomic_t opened; | |
26 | atomic_t mp_opened; | |
27 | bool plugged; | |
b17b57a5 | 28 | bool mp_plugged; |
cb99221b DH |
29 | bool motionp; |
30 | __u8 ext_type; | |
3155a09f | 31 | __u16 calib[4][3]; |
cb99221b DH |
32 | }; |
33 | ||
34 | enum wiiext_type { | |
35 | WIIEXT_NONE, /* placeholder */ | |
36 | WIIEXT_CLASSIC, /* Nintendo classic controller */ | |
37 | WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */ | |
5ad67fbc | 38 | WIIEXT_BALANCE_BOARD, /* Nintendo balance board controller */ |
cb99221b DH |
39 | }; |
40 | ||
a5353501 DH |
41 | enum wiiext_keys { |
42 | WIIEXT_KEY_C, | |
43 | WIIEXT_KEY_Z, | |
5906215b DH |
44 | WIIEXT_KEY_A, |
45 | WIIEXT_KEY_B, | |
46 | WIIEXT_KEY_X, | |
47 | WIIEXT_KEY_Y, | |
48 | WIIEXT_KEY_ZL, | |
49 | WIIEXT_KEY_ZR, | |
50 | WIIEXT_KEY_PLUS, | |
51 | WIIEXT_KEY_MINUS, | |
52 | WIIEXT_KEY_HOME, | |
53 | WIIEXT_KEY_LEFT, | |
54 | WIIEXT_KEY_RIGHT, | |
55 | WIIEXT_KEY_UP, | |
56 | WIIEXT_KEY_DOWN, | |
57 | WIIEXT_KEY_LT, | |
58 | WIIEXT_KEY_RT, | |
a5353501 DH |
59 | WIIEXT_KEY_COUNT |
60 | }; | |
61 | ||
62 | static __u16 wiiext_keymap[] = { | |
63 | BTN_C, /* WIIEXT_KEY_C */ | |
64 | BTN_Z, /* WIIEXT_KEY_Z */ | |
5906215b DH |
65 | BTN_A, /* WIIEXT_KEY_A */ |
66 | BTN_B, /* WIIEXT_KEY_B */ | |
67 | BTN_X, /* WIIEXT_KEY_X */ | |
68 | BTN_Y, /* WIIEXT_KEY_Y */ | |
69 | BTN_TL2, /* WIIEXT_KEY_ZL */ | |
70 | BTN_TR2, /* WIIEXT_KEY_ZR */ | |
71 | KEY_NEXT, /* WIIEXT_KEY_PLUS */ | |
72 | KEY_PREVIOUS, /* WIIEXT_KEY_MINUS */ | |
73 | BTN_MODE, /* WIIEXT_KEY_HOME */ | |
74 | KEY_LEFT, /* WIIEXT_KEY_LEFT */ | |
75 | KEY_RIGHT, /* WIIEXT_KEY_RIGHT */ | |
76 | KEY_UP, /* WIIEXT_KEY_UP */ | |
77 | KEY_DOWN, /* WIIEXT_KEY_DOWN */ | |
78 | BTN_TL, /* WIIEXT_KEY_LT */ | |
79 | BTN_TR, /* WIIEXT_KEY_RT */ | |
a5353501 DH |
80 | }; |
81 | ||
e39fe251 | 82 | /* disable all extensions */ |
82fb1b39 DH |
83 | static void ext_disable(struct wiimote_ext *ext) |
84 | { | |
85 | unsigned long flags; | |
492ba955 DH |
86 | __u8 wmem = 0x55; |
87 | ||
88 | if (!wiimote_cmd_acquire(ext->wdata)) { | |
89 | wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem)); | |
90 | wiimote_cmd_release(ext->wdata); | |
91 | } | |
82fb1b39 DH |
92 | |
93 | spin_lock_irqsave(&ext->wdata->state.lock, flags); | |
94 | ext->motionp = false; | |
95 | ext->ext_type = WIIEXT_NONE; | |
492ba955 | 96 | wiiproto_req_drm(ext->wdata, WIIPROTO_REQ_NULL); |
82fb1b39 DH |
97 | spin_unlock_irqrestore(&ext->wdata->state.lock, flags); |
98 | } | |
99 | ||
100 | static bool motionp_read(struct wiimote_ext *ext) | |
101 | { | |
492ba955 DH |
102 | __u8 rmem[2], wmem; |
103 | ssize_t ret; | |
104 | bool avail = false; | |
105 | ||
479901ba DH |
106 | if (!atomic_read(&ext->mp_opened)) |
107 | return false; | |
108 | ||
492ba955 DH |
109 | if (wiimote_cmd_acquire(ext->wdata)) |
110 | return false; | |
111 | ||
112 | /* initialize motion plus */ | |
113 | wmem = 0x55; | |
114 | ret = wiimote_cmd_write(ext->wdata, 0xa600f0, &wmem, sizeof(wmem)); | |
115 | if (ret) | |
116 | goto error; | |
117 | ||
118 | /* read motion plus ID */ | |
119 | ret = wiimote_cmd_read(ext->wdata, 0xa600fe, rmem, 2); | |
120 | if (ret == 2 || rmem[1] == 0x5) | |
121 | avail = true; | |
122 | ||
123 | error: | |
124 | wiimote_cmd_release(ext->wdata); | |
125 | return avail; | |
82fb1b39 DH |
126 | } |
127 | ||
128 | static __u8 ext_read(struct wiimote_ext *ext) | |
129 | { | |
492ba955 | 130 | ssize_t ret; |
3155a09f | 131 | __u8 buf[24], i, j, offs = 0; |
492ba955 DH |
132 | __u8 rmem[2], wmem; |
133 | __u8 type = WIIEXT_NONE; | |
134 | ||
479901ba | 135 | if (!ext->plugged || !atomic_read(&ext->opened)) |
492ba955 DH |
136 | return WIIEXT_NONE; |
137 | ||
138 | if (wiimote_cmd_acquire(ext->wdata)) | |
139 | return WIIEXT_NONE; | |
140 | ||
141 | /* initialize extension */ | |
142 | wmem = 0x55; | |
143 | ret = wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem)); | |
144 | if (!ret) { | |
145 | /* disable encryption */ | |
146 | wmem = 0x0; | |
147 | wiimote_cmd_write(ext->wdata, 0xa400fb, &wmem, sizeof(wmem)); | |
148 | } | |
149 | ||
150 | /* read extension ID */ | |
151 | ret = wiimote_cmd_read(ext->wdata, 0xa400fe, rmem, 2); | |
152 | if (ret == 2) { | |
153 | if (rmem[0] == 0 && rmem[1] == 0) | |
154 | type = WIIEXT_NUNCHUCK; | |
155 | else if (rmem[0] == 0x01 && rmem[1] == 0x01) | |
156 | type = WIIEXT_CLASSIC; | |
5ad67fbc DH |
157 | else if (rmem[0] == 0x04 && rmem[1] == 0x02) |
158 | type = WIIEXT_BALANCE_BOARD; | |
492ba955 DH |
159 | } |
160 | ||
3155a09f FE |
161 | /* get balance board calibration data */ |
162 | if (type == WIIEXT_BALANCE_BOARD) { | |
163 | ret = wiimote_cmd_read(ext->wdata, 0xa40024, buf, 12); | |
164 | ret += wiimote_cmd_read(ext->wdata, 0xa40024 + 12, | |
165 | buf + 12, 12); | |
166 | ||
167 | if (ret != 24) { | |
168 | type = WIIEXT_NONE; | |
169 | } else { | |
170 | for (i = 0; i < 3; i++) { | |
171 | for (j = 0; j < 4; j++) { | |
172 | ext->calib[j][i] = buf[offs]; | |
173 | ext->calib[j][i] <<= 8; | |
174 | ext->calib[j][i] |= buf[offs + 1]; | |
175 | offs += 2; | |
176 | } | |
177 | } | |
178 | } | |
179 | } | |
180 | ||
492ba955 DH |
181 | wiimote_cmd_release(ext->wdata); |
182 | ||
183 | return type; | |
82fb1b39 DH |
184 | } |
185 | ||
186 | static void ext_enable(struct wiimote_ext *ext, bool motionp, __u8 ext_type) | |
187 | { | |
188 | unsigned long flags; | |
492ba955 DH |
189 | __u8 wmem; |
190 | int ret; | |
191 | ||
192 | if (motionp) { | |
193 | if (wiimote_cmd_acquire(ext->wdata)) | |
194 | return; | |
195 | ||
196 | if (ext_type == WIIEXT_CLASSIC) | |
197 | wmem = 0x07; | |
198 | else if (ext_type == WIIEXT_NUNCHUCK) | |
199 | wmem = 0x05; | |
200 | else | |
201 | wmem = 0x04; | |
202 | ||
203 | ret = wiimote_cmd_write(ext->wdata, 0xa600fe, &wmem, sizeof(wmem)); | |
204 | wiimote_cmd_release(ext->wdata); | |
205 | if (ret) | |
206 | return; | |
207 | } | |
82fb1b39 DH |
208 | |
209 | spin_lock_irqsave(&ext->wdata->state.lock, flags); | |
210 | ext->motionp = motionp; | |
211 | ext->ext_type = ext_type; | |
492ba955 | 212 | wiiproto_req_drm(ext->wdata, WIIPROTO_REQ_NULL); |
82fb1b39 DH |
213 | spin_unlock_irqrestore(&ext->wdata->state.lock, flags); |
214 | } | |
215 | ||
cb99221b DH |
216 | static void wiiext_worker(struct work_struct *work) |
217 | { | |
218 | struct wiimote_ext *ext = container_of(work, struct wiimote_ext, | |
219 | worker); | |
82fb1b39 DH |
220 | bool motionp; |
221 | __u8 ext_type; | |
222 | ||
223 | ext_disable(ext); | |
224 | motionp = motionp_read(ext); | |
225 | ext_type = ext_read(ext); | |
226 | ext_enable(ext, motionp, ext_type); | |
cb99221b DH |
227 | } |
228 | ||
229 | /* schedule work only once, otherwise mark for reschedule */ | |
230 | static void wiiext_schedule(struct wiimote_ext *ext) | |
231 | { | |
3b07e9ca | 232 | schedule_work(&ext->worker); |
cb99221b DH |
233 | } |
234 | ||
235 | /* | |
236 | * Reacts on extension port events | |
237 | * Whenever the driver gets an event from the wiimote that an extension has been | |
238 | * plugged or unplugged, this funtion shall be called. It checks what extensions | |
239 | * are connected and initializes and activates them. | |
240 | * This can be called in atomic context. The initialization is done in a | |
241 | * separate worker thread. The state.lock spinlock must be held by the caller. | |
242 | */ | |
243 | void wiiext_event(struct wiimote_data *wdata, bool plugged) | |
244 | { | |
245 | if (!wdata->ext) | |
246 | return; | |
247 | ||
248 | if (wdata->ext->plugged == plugged) | |
249 | return; | |
250 | ||
251 | wdata->ext->plugged = plugged; | |
b17b57a5 DH |
252 | |
253 | if (!plugged) | |
254 | wdata->ext->mp_plugged = false; | |
255 | ||
cb99221b DH |
256 | /* |
257 | * We need to call wiiext_schedule(wdata->ext) here, however, the | |
258 | * extension initialization logic is not fully understood and so | |
259 | * automatic initialization is not supported, yet. | |
260 | */ | |
261 | } | |
262 | ||
263 | /* | |
264 | * Returns true if the current DRM mode should contain extension data and false | |
265 | * if there is no interest in extension data. | |
266 | * All supported extensions send 6 byte extension data so any DRM that contains | |
267 | * extension bytes is fine. | |
268 | * The caller must hold the state.lock spinlock. | |
269 | */ | |
270 | bool wiiext_active(struct wiimote_data *wdata) | |
271 | { | |
272 | if (!wdata->ext) | |
273 | return false; | |
274 | ||
275 | return wdata->ext->motionp || wdata->ext->ext_type; | |
276 | } | |
277 | ||
0b6815d7 DH |
278 | static void handler_motionp(struct wiimote_ext *ext, const __u8 *payload) |
279 | { | |
b17b57a5 DH |
280 | __s32 x, y, z; |
281 | bool plugged; | |
282 | ||
283 | /* | 8 7 6 5 4 3 | 2 | 1 | | |
284 | * -----+------------------------------+-----+-----+ | |
285 | * 1 | Yaw Speed <7:0> | | |
286 | * 2 | Roll Speed <7:0> | | |
287 | * 3 | Pitch Speed <7:0> | | |
288 | * -----+------------------------------+-----+-----+ | |
289 | * 4 | Yaw Speed <13:8> | Yaw |Pitch| | |
290 | * -----+------------------------------+-----+-----+ | |
291 | * 5 | Roll Speed <13:8> |Roll | Ext | | |
292 | * -----+------------------------------+-----+-----+ | |
293 | * 6 | Pitch Speed <13:8> | 1 | 0 | | |
294 | * -----+------------------------------+-----+-----+ | |
295 | * The single bits Yaw, Roll, Pitch in the lower right corner specify | |
296 | * whether the wiimote is rotating fast (0) or slow (1). Speed for slow | |
297 | * roation is 440 deg/s and for fast rotation 2000 deg/s. To get a | |
298 | * linear scale we multiply by 2000/440 = ~4.5454 which is 18 for fast | |
299 | * and 9 for slow. | |
300 | * If the wiimote is not rotating the sensor reports 2^13 = 8192. | |
301 | * Ext specifies whether an extension is connected to the motionp. | |
302 | */ | |
303 | ||
304 | x = payload[0]; | |
305 | y = payload[1]; | |
306 | z = payload[2]; | |
307 | ||
308 | x |= (((__u16)payload[3]) << 6) & 0xff00; | |
309 | y |= (((__u16)payload[4]) << 6) & 0xff00; | |
310 | z |= (((__u16)payload[5]) << 6) & 0xff00; | |
311 | ||
312 | x -= 8192; | |
313 | y -= 8192; | |
314 | z -= 8192; | |
315 | ||
316 | if (!(payload[3] & 0x02)) | |
317 | x *= 18; | |
318 | else | |
319 | x *= 9; | |
320 | if (!(payload[4] & 0x02)) | |
321 | y *= 18; | |
322 | else | |
323 | y *= 9; | |
324 | if (!(payload[3] & 0x01)) | |
325 | z *= 18; | |
326 | else | |
327 | z *= 9; | |
328 | ||
329 | input_report_abs(ext->mp_input, ABS_RX, x); | |
330 | input_report_abs(ext->mp_input, ABS_RY, y); | |
331 | input_report_abs(ext->mp_input, ABS_RZ, z); | |
332 | input_sync(ext->mp_input); | |
333 | ||
334 | plugged = payload[5] & 0x01; | |
335 | if (plugged != ext->mp_plugged) | |
336 | ext->mp_plugged = plugged; | |
0b6815d7 DH |
337 | } |
338 | ||
339 | static void handler_nunchuck(struct wiimote_ext *ext, const __u8 *payload) | |
340 | { | |
a5353501 DH |
341 | __s16 x, y, z, bx, by; |
342 | ||
343 | /* Byte | 8 7 | 6 5 | 4 3 | 2 | 1 | | |
344 | * -----+----------+---------+---------+----+-----+ | |
345 | * 1 | Button X <7:0> | | |
346 | * 2 | Button Y <7:0> | | |
347 | * -----+----------+---------+---------+----+-----+ | |
348 | * 3 | Speed X <9:2> | | |
349 | * 4 | Speed Y <9:2> | | |
350 | * 5 | Speed Z <9:2> | | |
351 | * -----+----------+---------+---------+----+-----+ | |
352 | * 6 | Z <1:0> | Y <1:0> | X <1:0> | BC | BZ | | |
353 | * -----+----------+---------+---------+----+-----+ | |
354 | * Button X/Y is the analog stick. Speed X, Y and Z are the | |
355 | * accelerometer data in the same format as the wiimote's accelerometer. | |
356 | * The 6th byte contains the LSBs of the accelerometer data. | |
357 | * BC and BZ are the C and Z buttons: 0 means pressed | |
358 | * | |
359 | * If reported interleaved with motionp, then the layout changes. The | |
360 | * 5th and 6th byte changes to: | |
361 | * -----+-----------------------------------+-----+ | |
362 | * 5 | Speed Z <9:3> | EXT | | |
363 | * -----+--------+-----+-----+----+----+----+-----+ | |
364 | * 6 |Z <2:1> |Y <1>|X <1>| BC | BZ | 0 | 0 | | |
365 | * -----+--------+-----+-----+----+----+----+-----+ | |
366 | * All three accelerometer values lose their LSB. The other data is | |
367 | * still available but slightly moved. | |
368 | * | |
369 | * Center data for button values is 128. Center value for accelerometer | |
370 | * values it 512 / 0x200 | |
371 | */ | |
372 | ||
373 | bx = payload[0]; | |
374 | by = payload[1]; | |
375 | bx -= 128; | |
376 | by -= 128; | |
377 | ||
378 | x = payload[2] << 2; | |
379 | y = payload[3] << 2; | |
380 | z = payload[4] << 2; | |
381 | ||
382 | if (ext->motionp) { | |
383 | x |= (payload[5] >> 3) & 0x02; | |
384 | y |= (payload[5] >> 4) & 0x02; | |
385 | z &= ~0x4; | |
386 | z |= (payload[5] >> 5) & 0x06; | |
387 | } else { | |
388 | x |= (payload[5] >> 2) & 0x03; | |
389 | y |= (payload[5] >> 4) & 0x03; | |
390 | z |= (payload[5] >> 6) & 0x03; | |
391 | } | |
392 | ||
393 | x -= 0x200; | |
394 | y -= 0x200; | |
395 | z -= 0x200; | |
396 | ||
397 | input_report_abs(ext->input, ABS_HAT0X, bx); | |
398 | input_report_abs(ext->input, ABS_HAT0Y, by); | |
399 | ||
400 | input_report_abs(ext->input, ABS_RX, x); | |
401 | input_report_abs(ext->input, ABS_RY, y); | |
402 | input_report_abs(ext->input, ABS_RZ, z); | |
403 | ||
404 | if (ext->motionp) { | |
405 | input_report_key(ext->input, | |
406 | wiiext_keymap[WIIEXT_KEY_Z], !!(payload[5] & 0x04)); | |
407 | input_report_key(ext->input, | |
408 | wiiext_keymap[WIIEXT_KEY_C], !!(payload[5] & 0x08)); | |
409 | } else { | |
410 | input_report_key(ext->input, | |
411 | wiiext_keymap[WIIEXT_KEY_Z], !!(payload[5] & 0x01)); | |
412 | input_report_key(ext->input, | |
413 | wiiext_keymap[WIIEXT_KEY_C], !!(payload[5] & 0x02)); | |
414 | } | |
415 | ||
416 | input_sync(ext->input); | |
0b6815d7 DH |
417 | } |
418 | ||
419 | static void handler_classic(struct wiimote_ext *ext, const __u8 *payload) | |
420 | { | |
5906215b DH |
421 | __s8 rx, ry, lx, ly, lt, rt; |
422 | ||
423 | /* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | | |
424 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ | |
425 | * 1 | RX <5:4> | LX <5:0> | | |
426 | * 2 | RX <3:2> | LY <5:0> | | |
427 | * -----+-----+-----+-----+-----------------------------+ | |
428 | * 3 |RX<1>| LT <5:4> | RY <5:1> | | |
429 | * -----+-----+-----------+-----------------------------+ | |
430 | * 4 | LT <3:1> | RT <5:1> | | |
431 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ | |
432 | * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | 1 | | |
433 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ | |
434 | * 6 | BZL | BB | BY | BA | BX | BZR | BDL | BDU | | |
435 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ | |
436 | * All buttons are 0 if pressed | |
437 | * RX and RY are right analog stick | |
438 | * LX and LY are left analog stick | |
439 | * LT is left trigger, RT is right trigger | |
440 | * BLT is 0 if left trigger is fully pressed | |
441 | * BRT is 0 if right trigger is fully pressed | |
442 | * BDR, BDD, BDL, BDU form the D-Pad with right, down, left, up buttons | |
443 | * BZL is left Z button and BZR is right Z button | |
444 | * B-, BH, B+ are +, HOME and - buttons | |
445 | * BB, BY, BA, BX are A, B, X, Y buttons | |
446 | * LSB of RX, RY, LT, and RT are not transmitted and always 0. | |
447 | * | |
448 | * With motionp enabled it changes slightly to this: | |
449 | * Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | | |
450 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ | |
451 | * 1 | RX <4:3> | LX <5:1> | BDU | | |
452 | * 2 | RX <2:1> | LY <5:1> | BDL | | |
453 | * -----+-----+-----+-----+-----------------------+-----+ | |
454 | * 3 |RX<0>| LT <4:3> | RY <4:0> | | |
455 | * -----+-----+-----------+-----------------------------+ | |
456 | * 4 | LT <2:0> | RT <4:0> | | |
457 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ | |
458 | * 5 | BDR | BDD | BLT | B- | BH | B+ | BRT | EXT | | |
459 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ | |
460 | * 6 | BZL | BB | BY | BA | BX | BZR | 0 | 0 | | |
461 | * -----+-----+-----+-----+-----+-----+-----+-----+-----+ | |
462 | * Only the LSBs of LX and LY are lost. BDU and BDL are moved, the rest | |
463 | * is the same as before. | |
464 | */ | |
465 | ||
466 | if (ext->motionp) { | |
467 | lx = payload[0] & 0x3e; | |
468 | ly = payload[0] & 0x3e; | |
469 | } else { | |
470 | lx = payload[0] & 0x3f; | |
471 | ly = payload[0] & 0x3f; | |
472 | } | |
473 | ||
474 | rx = (payload[0] >> 3) & 0x14; | |
475 | rx |= (payload[1] >> 5) & 0x06; | |
476 | rx |= (payload[2] >> 7) & 0x01; | |
477 | ry = payload[2] & 0x1f; | |
478 | ||
479 | rt = payload[3] & 0x1f; | |
480 | lt = (payload[2] >> 2) & 0x18; | |
481 | lt |= (payload[3] >> 5) & 0x07; | |
482 | ||
483 | rx <<= 1; | |
484 | ry <<= 1; | |
485 | rt <<= 1; | |
486 | lt <<= 1; | |
487 | ||
488 | input_report_abs(ext->input, ABS_HAT1X, lx - 0x20); | |
489 | input_report_abs(ext->input, ABS_HAT1Y, ly - 0x20); | |
490 | input_report_abs(ext->input, ABS_HAT2X, rx - 0x20); | |
491 | input_report_abs(ext->input, ABS_HAT2Y, ry - 0x20); | |
492 | input_report_abs(ext->input, ABS_HAT3X, rt - 0x20); | |
493 | input_report_abs(ext->input, ABS_HAT3Y, lt - 0x20); | |
494 | ||
495 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_RIGHT], | |
496 | !!(payload[4] & 0x80)); | |
497 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_DOWN], | |
498 | !!(payload[4] & 0x40)); | |
499 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_LT], | |
500 | !!(payload[4] & 0x20)); | |
501 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_MINUS], | |
502 | !!(payload[4] & 0x10)); | |
503 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_HOME], | |
504 | !!(payload[4] & 0x08)); | |
505 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_PLUS], | |
506 | !!(payload[4] & 0x04)); | |
507 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_RT], | |
508 | !!(payload[4] & 0x02)); | |
509 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_ZL], | |
510 | !!(payload[5] & 0x80)); | |
511 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_B], | |
512 | !!(payload[5] & 0x40)); | |
513 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_Y], | |
514 | !!(payload[5] & 0x20)); | |
515 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_A], | |
516 | !!(payload[5] & 0x10)); | |
517 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_X], | |
518 | !!(payload[5] & 0x08)); | |
519 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_ZR], | |
520 | !!(payload[5] & 0x04)); | |
521 | ||
522 | if (ext->motionp) { | |
523 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_UP], | |
524 | !!(payload[0] & 0x01)); | |
525 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_LEFT], | |
526 | !!(payload[1] & 0x01)); | |
527 | } else { | |
528 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_UP], | |
529 | !!(payload[5] & 0x01)); | |
530 | input_report_key(ext->input, wiiext_keymap[WIIEXT_KEY_LEFT], | |
531 | !!(payload[5] & 0x02)); | |
532 | } | |
533 | ||
534 | input_sync(ext->input); | |
0b6815d7 DH |
535 | } |
536 | ||
5ad67fbc DH |
537 | static void handler_balance_board(struct wiimote_ext *ext, const __u8 *payload) |
538 | { | |
3155a09f FE |
539 | __s32 val[4], tmp; |
540 | unsigned int i; | |
5ad67fbc DH |
541 | |
542 | /* Byte | 8 7 6 5 4 3 2 1 | | |
543 | * -----+--------------------------+ | |
544 | * 1 | Top Right <15:8> | | |
545 | * 2 | Top Right <7:0> | | |
546 | * -----+--------------------------+ | |
547 | * 3 | Bottom Right <15:8> | | |
548 | * 4 | Bottom Right <7:0> | | |
549 | * -----+--------------------------+ | |
550 | * 5 | Top Left <15:8> | | |
551 | * 6 | Top Left <7:0> | | |
552 | * -----+--------------------------+ | |
553 | * 7 | Bottom Left <15:8> | | |
554 | * 8 | Bottom Left <7:0> | | |
555 | * -----+--------------------------+ | |
556 | * | |
557 | * These values represent the weight-measurements of the Wii-balance | |
558 | * board with 16bit precision. | |
559 | * | |
560 | * The balance-board is never reported interleaved with motionp. | |
561 | */ | |
562 | ||
563 | val[0] = payload[0]; | |
564 | val[0] <<= 8; | |
565 | val[0] |= payload[1]; | |
566 | ||
567 | val[1] = payload[2]; | |
568 | val[1] <<= 8; | |
569 | val[1] |= payload[3]; | |
570 | ||
571 | val[2] = payload[4]; | |
572 | val[2] <<= 8; | |
573 | val[2] |= payload[5]; | |
574 | ||
575 | val[3] = payload[6]; | |
576 | val[3] <<= 8; | |
577 | val[3] |= payload[7]; | |
578 | ||
3155a09f FE |
579 | /* apply calibration data */ |
580 | for (i = 0; i < 4; i++) { | |
581 | if (val[i] < ext->calib[i][1]) { | |
582 | tmp = val[i] - ext->calib[i][0]; | |
583 | tmp *= 1700; | |
584 | tmp /= ext->calib[i][1] - ext->calib[i][0]; | |
585 | } else { | |
586 | tmp = val[i] - ext->calib[i][1]; | |
587 | tmp *= 1700; | |
a2f6e4e0 FE |
588 | tmp /= ext->calib[i][2] - ext->calib[i][1]; |
589 | tmp += 1700; | |
3155a09f FE |
590 | } |
591 | val[i] = tmp; | |
592 | } | |
593 | ||
5ad67fbc DH |
594 | input_report_abs(ext->input, ABS_HAT0X, val[0]); |
595 | input_report_abs(ext->input, ABS_HAT0Y, val[1]); | |
596 | input_report_abs(ext->input, ABS_HAT1X, val[2]); | |
597 | input_report_abs(ext->input, ABS_HAT1Y, val[3]); | |
598 | ||
599 | input_sync(ext->input); | |
600 | } | |
601 | ||
0b6815d7 DH |
602 | /* call this with state.lock spinlock held */ |
603 | void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload) | |
604 | { | |
605 | struct wiimote_ext *ext = wdata->ext; | |
606 | ||
607 | if (!ext) | |
608 | return; | |
609 | ||
610 | if (ext->motionp && (payload[5] & 0x02)) { | |
611 | handler_motionp(ext, payload); | |
612 | } else if (ext->ext_type == WIIEXT_NUNCHUCK) { | |
613 | handler_nunchuck(ext, payload); | |
614 | } else if (ext->ext_type == WIIEXT_CLASSIC) { | |
615 | handler_classic(ext, payload); | |
5ad67fbc DH |
616 | } else if (ext->ext_type == WIIEXT_BALANCE_BOARD) { |
617 | handler_balance_board(ext, payload); | |
0b6815d7 DH |
618 | } |
619 | } | |
620 | ||
c1e51398 DH |
621 | static ssize_t wiiext_show(struct device *dev, struct device_attribute *attr, |
622 | char *buf) | |
623 | { | |
624 | struct wiimote_data *wdata = dev_to_wii(dev); | |
625 | __u8 type = WIIEXT_NONE; | |
626 | bool motionp = false; | |
627 | unsigned long flags; | |
628 | ||
629 | spin_lock_irqsave(&wdata->state.lock, flags); | |
630 | if (wdata->ext) { | |
631 | motionp = wdata->ext->motionp; | |
632 | type = wdata->ext->ext_type; | |
633 | } | |
634 | spin_unlock_irqrestore(&wdata->state.lock, flags); | |
635 | ||
636 | if (type == WIIEXT_NUNCHUCK) { | |
637 | if (motionp) | |
638 | return sprintf(buf, "motionp+nunchuck\n"); | |
639 | else | |
640 | return sprintf(buf, "nunchuck\n"); | |
641 | } else if (type == WIIEXT_CLASSIC) { | |
642 | if (motionp) | |
643 | return sprintf(buf, "motionp+classic\n"); | |
644 | else | |
645 | return sprintf(buf, "classic\n"); | |
5ad67fbc DH |
646 | } else if (type == WIIEXT_BALANCE_BOARD) { |
647 | if (motionp) | |
648 | return sprintf(buf, "motionp+balanceboard\n"); | |
649 | else | |
650 | return sprintf(buf, "balanceboard\n"); | |
c1e51398 DH |
651 | } else { |
652 | if (motionp) | |
653 | return sprintf(buf, "motionp\n"); | |
654 | else | |
655 | return sprintf(buf, "none\n"); | |
656 | } | |
657 | } | |
658 | ||
659 | static DEVICE_ATTR(extension, S_IRUGO, wiiext_show, NULL); | |
660 | ||
479901ba DH |
661 | static int wiiext_input_open(struct input_dev *dev) |
662 | { | |
663 | struct wiimote_ext *ext = input_get_drvdata(dev); | |
664 | int ret; | |
665 | ||
666 | ret = hid_hw_open(ext->wdata->hdev); | |
667 | if (ret) | |
668 | return ret; | |
669 | ||
670 | atomic_inc(&ext->opened); | |
671 | wiiext_schedule(ext); | |
672 | ||
673 | return 0; | |
674 | } | |
675 | ||
676 | static void wiiext_input_close(struct input_dev *dev) | |
677 | { | |
678 | struct wiimote_ext *ext = input_get_drvdata(dev); | |
679 | ||
680 | atomic_dec(&ext->opened); | |
681 | wiiext_schedule(ext); | |
682 | hid_hw_close(ext->wdata->hdev); | |
683 | } | |
684 | ||
685 | static int wiiext_mp_open(struct input_dev *dev) | |
686 | { | |
687 | struct wiimote_ext *ext = input_get_drvdata(dev); | |
688 | int ret; | |
689 | ||
690 | ret = hid_hw_open(ext->wdata->hdev); | |
691 | if (ret) | |
692 | return ret; | |
693 | ||
694 | atomic_inc(&ext->mp_opened); | |
695 | wiiext_schedule(ext); | |
696 | ||
697 | return 0; | |
698 | } | |
699 | ||
700 | static void wiiext_mp_close(struct input_dev *dev) | |
701 | { | |
702 | struct wiimote_ext *ext = input_get_drvdata(dev); | |
703 | ||
704 | atomic_dec(&ext->mp_opened); | |
705 | wiiext_schedule(ext); | |
706 | hid_hw_close(ext->wdata->hdev); | |
707 | } | |
708 | ||
cb99221b DH |
709 | /* Initializes the extension driver of a wiimote */ |
710 | int wiiext_init(struct wiimote_data *wdata) | |
711 | { | |
712 | struct wiimote_ext *ext; | |
713 | unsigned long flags; | |
a5353501 | 714 | int ret, i; |
cb99221b DH |
715 | |
716 | ext = kzalloc(sizeof(*ext), GFP_KERNEL); | |
717 | if (!ext) | |
718 | return -ENOMEM; | |
719 | ||
720 | ext->wdata = wdata; | |
721 | INIT_WORK(&ext->worker, wiiext_worker); | |
722 | ||
479901ba DH |
723 | ext->input = input_allocate_device(); |
724 | if (!ext->input) { | |
725 | ret = -ENOMEM; | |
726 | goto err_input; | |
727 | } | |
728 | ||
729 | input_set_drvdata(ext->input, ext); | |
730 | ext->input->open = wiiext_input_open; | |
731 | ext->input->close = wiiext_input_close; | |
732 | ext->input->dev.parent = &wdata->hdev->dev; | |
733 | ext->input->id.bustype = wdata->hdev->bus; | |
734 | ext->input->id.vendor = wdata->hdev->vendor; | |
735 | ext->input->id.product = wdata->hdev->product; | |
736 | ext->input->id.version = wdata->hdev->version; | |
737 | ext->input->name = WIIMOTE_NAME " Extension"; | |
738 | ||
a5353501 DH |
739 | set_bit(EV_KEY, ext->input->evbit); |
740 | for (i = 0; i < WIIEXT_KEY_COUNT; ++i) | |
741 | set_bit(wiiext_keymap[i], ext->input->keybit); | |
742 | ||
743 | set_bit(EV_ABS, ext->input->evbit); | |
744 | set_bit(ABS_HAT0X, ext->input->absbit); | |
745 | set_bit(ABS_HAT0Y, ext->input->absbit); | |
5906215b DH |
746 | set_bit(ABS_HAT1X, ext->input->absbit); |
747 | set_bit(ABS_HAT1Y, ext->input->absbit); | |
748 | set_bit(ABS_HAT2X, ext->input->absbit); | |
749 | set_bit(ABS_HAT2Y, ext->input->absbit); | |
750 | set_bit(ABS_HAT3X, ext->input->absbit); | |
751 | set_bit(ABS_HAT3Y, ext->input->absbit); | |
a5353501 DH |
752 | input_set_abs_params(ext->input, ABS_HAT0X, -120, 120, 2, 4); |
753 | input_set_abs_params(ext->input, ABS_HAT0Y, -120, 120, 2, 4); | |
5906215b DH |
754 | input_set_abs_params(ext->input, ABS_HAT1X, -30, 30, 1, 1); |
755 | input_set_abs_params(ext->input, ABS_HAT1Y, -30, 30, 1, 1); | |
756 | input_set_abs_params(ext->input, ABS_HAT2X, -30, 30, 1, 1); | |
757 | input_set_abs_params(ext->input, ABS_HAT2Y, -30, 30, 1, 1); | |
758 | input_set_abs_params(ext->input, ABS_HAT3X, -30, 30, 1, 1); | |
759 | input_set_abs_params(ext->input, ABS_HAT3Y, -30, 30, 1, 1); | |
a5353501 DH |
760 | set_bit(ABS_RX, ext->input->absbit); |
761 | set_bit(ABS_RY, ext->input->absbit); | |
762 | set_bit(ABS_RZ, ext->input->absbit); | |
763 | input_set_abs_params(ext->input, ABS_RX, -500, 500, 2, 4); | |
764 | input_set_abs_params(ext->input, ABS_RY, -500, 500, 2, 4); | |
765 | input_set_abs_params(ext->input, ABS_RZ, -500, 500, 2, 4); | |
766 | ||
479901ba DH |
767 | ret = input_register_device(ext->input); |
768 | if (ret) { | |
769 | input_free_device(ext->input); | |
770 | goto err_input; | |
771 | } | |
772 | ||
773 | ext->mp_input = input_allocate_device(); | |
774 | if (!ext->mp_input) { | |
775 | ret = -ENOMEM; | |
776 | goto err_mp; | |
777 | } | |
778 | ||
779 | input_set_drvdata(ext->mp_input, ext); | |
780 | ext->mp_input->open = wiiext_mp_open; | |
781 | ext->mp_input->close = wiiext_mp_close; | |
782 | ext->mp_input->dev.parent = &wdata->hdev->dev; | |
783 | ext->mp_input->id.bustype = wdata->hdev->bus; | |
784 | ext->mp_input->id.vendor = wdata->hdev->vendor; | |
785 | ext->mp_input->id.product = wdata->hdev->product; | |
786 | ext->mp_input->id.version = wdata->hdev->version; | |
787 | ext->mp_input->name = WIIMOTE_NAME " Motion+"; | |
788 | ||
b17b57a5 DH |
789 | set_bit(EV_ABS, ext->mp_input->evbit); |
790 | set_bit(ABS_RX, ext->mp_input->absbit); | |
791 | set_bit(ABS_RY, ext->mp_input->absbit); | |
792 | set_bit(ABS_RZ, ext->mp_input->absbit); | |
793 | input_set_abs_params(ext->mp_input, ABS_RX, -160000, 160000, 4, 8); | |
794 | input_set_abs_params(ext->mp_input, ABS_RY, -160000, 160000, 4, 8); | |
795 | input_set_abs_params(ext->mp_input, ABS_RZ, -160000, 160000, 4, 8); | |
796 | ||
479901ba DH |
797 | ret = input_register_device(ext->mp_input); |
798 | if (ret) { | |
799 | input_free_device(ext->mp_input); | |
800 | goto err_mp; | |
801 | } | |
802 | ||
c1e51398 DH |
803 | ret = device_create_file(&wdata->hdev->dev, &dev_attr_extension); |
804 | if (ret) | |
479901ba | 805 | goto err_dev; |
c1e51398 | 806 | |
cb99221b DH |
807 | spin_lock_irqsave(&wdata->state.lock, flags); |
808 | wdata->ext = ext; | |
809 | spin_unlock_irqrestore(&wdata->state.lock, flags); | |
810 | ||
811 | return 0; | |
c1e51398 | 812 | |
479901ba DH |
813 | err_dev: |
814 | input_unregister_device(ext->mp_input); | |
815 | err_mp: | |
816 | input_unregister_device(ext->input); | |
817 | err_input: | |
c1e51398 DH |
818 | kfree(ext); |
819 | return ret; | |
cb99221b DH |
820 | } |
821 | ||
822 | /* Deinitializes the extension driver of a wiimote */ | |
823 | void wiiext_deinit(struct wiimote_data *wdata) | |
824 | { | |
825 | struct wiimote_ext *ext = wdata->ext; | |
826 | unsigned long flags; | |
827 | ||
828 | if (!ext) | |
829 | return; | |
830 | ||
831 | /* | |
832 | * We first unset wdata->ext to avoid further input from the wiimote | |
833 | * core. The worker thread does not access this pointer so it is not | |
834 | * affected by this. | |
835 | * We kill the worker after this so it does not get respawned during | |
836 | * deinitialization. | |
837 | */ | |
838 | ||
839 | spin_lock_irqsave(&wdata->state.lock, flags); | |
840 | wdata->ext = NULL; | |
841 | spin_unlock_irqrestore(&wdata->state.lock, flags); | |
842 | ||
c1e51398 | 843 | device_remove_file(&wdata->hdev->dev, &dev_attr_extension); |
479901ba DH |
844 | input_unregister_device(ext->mp_input); |
845 | input_unregister_device(ext->input); | |
c1e51398 | 846 | |
cb99221b DH |
847 | cancel_work_sync(&ext->worker); |
848 | kfree(ext); | |
849 | } |