aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-05-05 17:12:59 -0400
committerJiri Kosina <jkosina@suse.cz>2013-06-03 05:07:03 -0400
commitb6ee67b37c02790ba9bd170ee1fe0d2cd2941001 (patch)
treed0e40e6d68175340473c789f43f663a36270cb85
parentf1d4bed45b553dda2be402e427d8d708c4dca85d (diff)
HID: wiimote: add Nunchuk support
This moves the nunchuk parser over to an extension module. This allows to make use of hotplugged Nunchuks instead of the old static parser. Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--drivers/hid/hid-wiimote-core.c6
-rw-r--r--drivers/hid/hid-wiimote-modules.c198
-rw-r--r--drivers/hid/hid-wiimote.h1
3 files changed, 205 insertions, 0 deletions
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c
index 90ea5a2565d4..dedf3c84e243 100644
--- a/drivers/hid/hid-wiimote-core.c
+++ b/drivers/hid/hid-wiimote-core.c
@@ -444,6 +444,8 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
444 rmem[3] == 0xff && rmem[4] == 0xff && rmem[5] == 0xff) 444 rmem[3] == 0xff && rmem[4] == 0xff && rmem[5] == 0xff)
445 return WIIMOTE_EXT_NONE; 445 return WIIMOTE_EXT_NONE;
446 446
447 if (rmem[4] == 0x00 && rmem[5] == 0x00)
448 return WIIMOTE_EXT_NUNCHUK;
447 if (rmem[4] == 0x04 && rmem[5] == 0x02) 449 if (rmem[4] == 0x04 && rmem[5] == 0x02)
448 return WIIMOTE_EXT_BALANCE_BOARD; 450 return WIIMOTE_EXT_BALANCE_BOARD;
449 451
@@ -478,6 +480,9 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype)
478 480
479 /* map MP with correct pass-through mode */ 481 /* map MP with correct pass-through mode */
480 switch (exttype) { 482 switch (exttype) {
483 case WIIMOTE_EXT_NUNCHUK:
484 wmem = 0x05;
485 break;
481 default: 486 default:
482 wmem = 0x04; 487 wmem = 0x04;
483 break; 488 break;
@@ -1034,6 +1039,7 @@ out_release:
1034static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = { 1039static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = {
1035 [WIIMOTE_EXT_NONE] = "None", 1040 [WIIMOTE_EXT_NONE] = "None",
1036 [WIIMOTE_EXT_UNKNOWN] = "Unknown", 1041 [WIIMOTE_EXT_UNKNOWN] = "Unknown",
1042 [WIIMOTE_EXT_NUNCHUK] = "Nintendo Wii Nunchuk",
1037 [WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board", 1043 [WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board",
1038}; 1044};
1039 1045
diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index 6239cd87f1ed..e4bcc098bdfd 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -789,6 +789,203 @@ static const struct wiimod_ops wiimod_ir = {
789}; 789};
790 790
791/* 791/*
792 * Nunchuk Extension
793 * The Nintendo Wii Nunchuk was the first official extension published by
794 * Nintendo. It provides two additional keys and a separate accelerometer. It
795 * can be hotplugged to standard Wii Remotes.
796 */
797
798enum wiimod_nunchuk_keys {
799 WIIMOD_NUNCHUK_KEY_C,
800 WIIMOD_NUNCHUK_KEY_Z,
801 WIIMOD_NUNCHUK_KEY_NUM,
802};
803
804static const __u16 wiimod_nunchuk_map[] = {
805 BTN_C, /* WIIMOD_NUNCHUK_KEY_C */
806 BTN_Z, /* WIIMOD_NUNCHUK_KEY_Z */
807};
808
809static void wiimod_nunchuk_in_ext(struct wiimote_data *wdata, const __u8 *ext)
810{
811 __s16 x, y, z, bx, by;
812
813 /* Byte | 8 7 | 6 5 | 4 3 | 2 | 1 |
814 * -----+----------+---------+---------+----+-----+
815 * 1 | Button X <7:0> |
816 * 2 | Button Y <7:0> |
817 * -----+----------+---------+---------+----+-----+
818 * 3 | Speed X <9:2> |
819 * 4 | Speed Y <9:2> |
820 * 5 | Speed Z <9:2> |
821 * -----+----------+---------+---------+----+-----+
822 * 6 | Z <1:0> | Y <1:0> | X <1:0> | BC | BZ |
823 * -----+----------+---------+---------+----+-----+
824 * Button X/Y is the analog stick. Speed X, Y and Z are the
825 * accelerometer data in the same format as the wiimote's accelerometer.
826 * The 6th byte contains the LSBs of the accelerometer data.
827 * BC and BZ are the C and Z buttons: 0 means pressed
828 *
829 * If reported interleaved with motionp, then the layout changes. The
830 * 5th and 6th byte changes to:
831 * -----+-----------------------------------+-----+
832 * 5 | Speed Z <9:3> | EXT |
833 * -----+--------+-----+-----+----+----+----+-----+
834 * 6 |Z <2:1> |Y <1>|X <1>| BC | BZ | 0 | 0 |
835 * -----+--------+-----+-----+----+----+----+-----+
836 * All three accelerometer values lose their LSB. The other data is
837 * still available but slightly moved.
838 *
839 * Center data for button values is 128. Center value for accelerometer
840 * values it 512 / 0x200
841 */
842
843 bx = ext[0];
844 by = ext[1];
845 bx -= 128;
846 by -= 128;
847
848 x = ext[2] << 2;
849 y = ext[3] << 2;
850 z = ext[4] << 2;
851
852 if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
853 x |= (ext[5] >> 3) & 0x02;
854 y |= (ext[5] >> 4) & 0x02;
855 z &= ~0x4;
856 z |= (ext[5] >> 5) & 0x06;
857 } else {
858 x |= (ext[5] >> 2) & 0x03;
859 y |= (ext[5] >> 4) & 0x03;
860 z |= (ext[5] >> 6) & 0x03;
861 }
862
863 x -= 0x200;
864 y -= 0x200;
865 z -= 0x200;
866
867 input_report_abs(wdata->extension.input, ABS_HAT0X, bx);
868 input_report_abs(wdata->extension.input, ABS_HAT0Y, by);
869
870 input_report_abs(wdata->extension.input, ABS_RX, x);
871 input_report_abs(wdata->extension.input, ABS_RY, y);
872 input_report_abs(wdata->extension.input, ABS_RZ, z);
873
874 if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
875 input_report_key(wdata->extension.input,
876 wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_Z],
877 !(ext[5] & 0x04));
878 input_report_key(wdata->extension.input,
879 wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_C],
880 !(ext[5] & 0x08));
881 } else {
882 input_report_key(wdata->extension.input,
883 wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_Z],
884 !(ext[5] & 0x01));
885 input_report_key(wdata->extension.input,
886 wiimod_nunchuk_map[WIIMOD_NUNCHUK_KEY_C],
887 !(ext[5] & 0x02));
888 }
889
890 input_sync(wdata->extension.input);
891}
892
893static int wiimod_nunchuk_open(struct input_dev *dev)
894{
895 struct wiimote_data *wdata = input_get_drvdata(dev);
896 unsigned long flags;
897
898 spin_lock_irqsave(&wdata->state.lock, flags);
899 wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
900 wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
901 spin_unlock_irqrestore(&wdata->state.lock, flags);
902
903 return 0;
904}
905
906static void wiimod_nunchuk_close(struct input_dev *dev)
907{
908 struct wiimote_data *wdata = input_get_drvdata(dev);
909 unsigned long flags;
910
911 spin_lock_irqsave(&wdata->state.lock, flags);
912 wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
913 wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
914 spin_unlock_irqrestore(&wdata->state.lock, flags);
915}
916
917static int wiimod_nunchuk_probe(const struct wiimod_ops *ops,
918 struct wiimote_data *wdata)
919{
920 int ret, i;
921
922 wdata->extension.input = input_allocate_device();
923 if (!wdata->extension.input)
924 return -ENOMEM;
925
926 input_set_drvdata(wdata->extension.input, wdata);
927 wdata->extension.input->open = wiimod_nunchuk_open;
928 wdata->extension.input->close = wiimod_nunchuk_close;
929 wdata->extension.input->dev.parent = &wdata->hdev->dev;
930 wdata->extension.input->id.bustype = wdata->hdev->bus;
931 wdata->extension.input->id.vendor = wdata->hdev->vendor;
932 wdata->extension.input->id.product = wdata->hdev->product;
933 wdata->extension.input->id.version = wdata->hdev->version;
934 wdata->extension.input->name = WIIMOTE_NAME " Nunchuk";
935
936 set_bit(EV_KEY, wdata->extension.input->evbit);
937 for (i = 0; i < WIIMOD_NUNCHUK_KEY_NUM; ++i)
938 set_bit(wiimod_nunchuk_map[i],
939 wdata->extension.input->keybit);
940
941 set_bit(EV_ABS, wdata->extension.input->evbit);
942 set_bit(ABS_HAT0X, wdata->extension.input->absbit);
943 set_bit(ABS_HAT0Y, wdata->extension.input->absbit);
944 input_set_abs_params(wdata->extension.input,
945 ABS_HAT0X, -120, 120, 2, 4);
946 input_set_abs_params(wdata->extension.input,
947 ABS_HAT0Y, -120, 120, 2, 4);
948 set_bit(ABS_RX, wdata->extension.input->absbit);
949 set_bit(ABS_RY, wdata->extension.input->absbit);
950 set_bit(ABS_RZ, wdata->extension.input->absbit);
951 input_set_abs_params(wdata->extension.input,
952 ABS_RX, -500, 500, 2, 4);
953 input_set_abs_params(wdata->extension.input,
954 ABS_RY, -500, 500, 2, 4);
955 input_set_abs_params(wdata->extension.input,
956 ABS_RZ, -500, 500, 2, 4);
957
958 ret = input_register_device(wdata->extension.input);
959 if (ret)
960 goto err_free;
961
962 return 0;
963
964err_free:
965 input_free_device(wdata->extension.input);
966 wdata->extension.input = NULL;
967 return ret;
968}
969
970static void wiimod_nunchuk_remove(const struct wiimod_ops *ops,
971 struct wiimote_data *wdata)
972{
973 if (!wdata->extension.input)
974 return;
975
976 input_unregister_device(wdata->extension.input);
977 wdata->extension.input = NULL;
978}
979
980static const struct wiimod_ops wiimod_nunchuk = {
981 .flags = 0,
982 .arg = 0,
983 .probe = wiimod_nunchuk_probe,
984 .remove = wiimod_nunchuk_remove,
985 .in_ext = wiimod_nunchuk_in_ext,
986};
987
988/*
792 * Balance Board Extension 989 * Balance Board Extension
793 * The Nintendo Wii Balance Board provides four hardware weight sensor plus a 990 * The Nintendo Wii Balance Board provides four hardware weight sensor plus a
794 * single push button. No other peripherals are available. However, the 991 * single push button. No other peripherals are available. However, the
@@ -1026,5 +1223,6 @@ const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = {
1026const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = { 1223const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = {
1027 [WIIMOTE_EXT_NONE] = &wiimod_dummy, 1224 [WIIMOTE_EXT_NONE] = &wiimod_dummy,
1028 [WIIMOTE_EXT_UNKNOWN] = &wiimod_dummy, 1225 [WIIMOTE_EXT_UNKNOWN] = &wiimod_dummy,
1226 [WIIMOTE_EXT_NUNCHUK] = &wiimod_nunchuk,
1029 [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard, 1227 [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard,
1030}; 1228};
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index 8d314ae429b6..3414e4cdc4ff 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -80,6 +80,7 @@ enum wiimote_devtype {
80enum wiimote_exttype { 80enum wiimote_exttype {
81 WIIMOTE_EXT_NONE, 81 WIIMOTE_EXT_NONE,
82 WIIMOTE_EXT_UNKNOWN, 82 WIIMOTE_EXT_UNKNOWN,
83 WIIMOTE_EXT_NUNCHUK,
83 WIIMOTE_EXT_BALANCE_BOARD, 84 WIIMOTE_EXT_BALANCE_BOARD,
84 WIIMOTE_EXT_NUM, 85 WIIMOTE_EXT_NUM,
85}; 86};