aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-wiimote-ext.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/hid-wiimote-ext.c')
-rw-r--r--drivers/hid/hid-wiimote-ext.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c
index 0a1805c9b0e5..bc85bf29062e 100644
--- a/drivers/hid/hid-wiimote-ext.c
+++ b/drivers/hid/hid-wiimote-ext.c
@@ -28,12 +28,14 @@ struct wiimote_ext {
28 bool mp_plugged; 28 bool mp_plugged;
29 bool motionp; 29 bool motionp;
30 __u8 ext_type; 30 __u8 ext_type;
31 __u16 calib[4][3];
31}; 32};
32 33
33enum wiiext_type { 34enum wiiext_type {
34 WIIEXT_NONE, /* placeholder */ 35 WIIEXT_NONE, /* placeholder */
35 WIIEXT_CLASSIC, /* Nintendo classic controller */ 36 WIIEXT_CLASSIC, /* Nintendo classic controller */
36 WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */ 37 WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */
38 WIIEXT_BALANCE_BOARD, /* Nintendo balance board controller */
37}; 39};
38 40
39enum wiiext_keys { 41enum wiiext_keys {
@@ -126,6 +128,7 @@ error:
126static __u8 ext_read(struct wiimote_ext *ext) 128static __u8 ext_read(struct wiimote_ext *ext)
127{ 129{
128 ssize_t ret; 130 ssize_t ret;
131 __u8 buf[24], i, j, offs = 0;
129 __u8 rmem[2], wmem; 132 __u8 rmem[2], wmem;
130 __u8 type = WIIEXT_NONE; 133 __u8 type = WIIEXT_NONE;
131 134
@@ -151,6 +154,28 @@ static __u8 ext_read(struct wiimote_ext *ext)
151 type = WIIEXT_NUNCHUCK; 154 type = WIIEXT_NUNCHUCK;
152 else if (rmem[0] == 0x01 && rmem[1] == 0x01) 155 else if (rmem[0] == 0x01 && rmem[1] == 0x01)
153 type = WIIEXT_CLASSIC; 156 type = WIIEXT_CLASSIC;
157 else if (rmem[0] == 0x04 && rmem[1] == 0x02)
158 type = WIIEXT_BALANCE_BOARD;
159 }
160
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 }
154 } 179 }
155 180
156 wiimote_cmd_release(ext->wdata); 181 wiimote_cmd_release(ext->wdata);
@@ -509,6 +534,71 @@ static void handler_classic(struct wiimote_ext *ext, const __u8 *payload)
509 input_sync(ext->input); 534 input_sync(ext->input);
510} 535}
511 536
537static void handler_balance_board(struct wiimote_ext *ext, const __u8 *payload)
538{
539 __s32 val[4], tmp;
540 unsigned int i;
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
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;
588 tmp /= ext->calib[i][2] - ext->calib[i][1];
589 tmp += 1700;
590 }
591 val[i] = tmp;
592 }
593
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
512/* call this with state.lock spinlock held */ 602/* call this with state.lock spinlock held */
513void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload) 603void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload)
514{ 604{
@@ -523,6 +613,8 @@ void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload)
523 handler_nunchuck(ext, payload); 613 handler_nunchuck(ext, payload);
524 } else if (ext->ext_type == WIIEXT_CLASSIC) { 614 } else if (ext->ext_type == WIIEXT_CLASSIC) {
525 handler_classic(ext, payload); 615 handler_classic(ext, payload);
616 } else if (ext->ext_type == WIIEXT_BALANCE_BOARD) {
617 handler_balance_board(ext, payload);
526 } 618 }
527} 619}
528 620
@@ -551,6 +643,11 @@ static ssize_t wiiext_show(struct device *dev, struct device_attribute *attr,
551 return sprintf(buf, "motionp+classic\n"); 643 return sprintf(buf, "motionp+classic\n");
552 else 644 else
553 return sprintf(buf, "classic\n"); 645 return sprintf(buf, "classic\n");
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");
554 } else { 651 } else {
555 if (motionp) 652 if (motionp)
556 return sprintf(buf, "motionp\n"); 653 return sprintf(buf, "motionp\n");