diff options
-rw-r--r-- | drivers/hid/hid-wiimote-core.c | 26 | ||||
-rw-r--r-- | drivers/hid/hid-wiimote-modules.c | 211 | ||||
-rw-r--r-- | drivers/hid/hid-wiimote.h | 9 |
3 files changed, 246 insertions, 0 deletions
diff --git a/drivers/hid/hid-wiimote-core.c b/drivers/hid/hid-wiimote-core.c index 836611e3e37e..90ea5a2565d4 100644 --- a/drivers/hid/hid-wiimote-core.c +++ b/drivers/hid/hid-wiimote-core.c | |||
@@ -202,6 +202,14 @@ static __u8 select_drm(struct wiimote_data *wdata) | |||
202 | ext = (wdata->state.flags & WIIPROTO_FLAG_EXT_USED) || | 202 | ext = (wdata->state.flags & WIIPROTO_FLAG_EXT_USED) || |
203 | (wdata->state.flags & WIIPROTO_FLAG_MP_USED); | 203 | (wdata->state.flags & WIIPROTO_FLAG_MP_USED); |
204 | 204 | ||
205 | /* some 3rd-party balance-boards are hard-coded to KEE, *sigh* */ | ||
206 | if (wdata->state.devtype == WIIMOTE_DEV_BALANCE_BOARD) { | ||
207 | if (ext) | ||
208 | return WIIPROTO_REQ_DRM_KEE; | ||
209 | else | ||
210 | return WIIPROTO_REQ_DRM_K; | ||
211 | } | ||
212 | |||
205 | if (ir == WIIPROTO_FLAG_IR_BASIC) { | 213 | if (ir == WIIPROTO_FLAG_IR_BASIC) { |
206 | if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) { | 214 | if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) { |
207 | if (ext) | 215 | if (ext) |
@@ -436,6 +444,9 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem) | |||
436 | rmem[3] == 0xff && rmem[4] == 0xff && rmem[5] == 0xff) | 444 | rmem[3] == 0xff && rmem[4] == 0xff && rmem[5] == 0xff) |
437 | return WIIMOTE_EXT_NONE; | 445 | return WIIMOTE_EXT_NONE; |
438 | 446 | ||
447 | if (rmem[4] == 0x04 && rmem[5] == 0x02) | ||
448 | return WIIMOTE_EXT_BALANCE_BOARD; | ||
449 | |||
439 | return WIIMOTE_EXT_UNKNOWN; | 450 | return WIIMOTE_EXT_UNKNOWN; |
440 | } | 451 | } |
441 | 452 | ||
@@ -570,6 +581,11 @@ static const __u8 * const wiimote_devtype_mods[WIIMOTE_DEV_NUM] = { | |||
570 | WIIMOD_IR, | 581 | WIIMOD_IR, |
571 | WIIMOD_NULL, | 582 | WIIMOD_NULL, |
572 | }, | 583 | }, |
584 | [WIIMOTE_DEV_BALANCE_BOARD] = (const __u8[]) { | ||
585 | WIIMOD_BATTERY, | ||
586 | WIIMOD_LED1, | ||
587 | WIIMOD_NULL, | ||
588 | }, | ||
573 | }; | 589 | }; |
574 | 590 | ||
575 | static void wiimote_modules_load(struct wiimote_data *wdata, | 591 | static void wiimote_modules_load(struct wiimote_data *wdata, |
@@ -753,6 +769,7 @@ static const char *wiimote_devtype_names[WIIMOTE_DEV_NUM] = { | |||
753 | [WIIMOTE_DEV_GENERIC] = "Generic", | 769 | [WIIMOTE_DEV_GENERIC] = "Generic", |
754 | [WIIMOTE_DEV_GEN10] = "Nintendo Wii Remote (Gen 1)", | 770 | [WIIMOTE_DEV_GEN10] = "Nintendo Wii Remote (Gen 1)", |
755 | [WIIMOTE_DEV_GEN20] = "Nintendo Wii Remote Plus (Gen 2)", | 771 | [WIIMOTE_DEV_GEN20] = "Nintendo Wii Remote Plus (Gen 2)", |
772 | [WIIMOTE_DEV_BALANCE_BOARD] = "Nintendo Wii Balance Board", | ||
756 | }; | 773 | }; |
757 | 774 | ||
758 | /* Try to guess the device type based on all collected information. We | 775 | /* Try to guess the device type based on all collected information. We |
@@ -770,12 +787,20 @@ static void wiimote_init_set_type(struct wiimote_data *wdata, | |||
770 | product = wdata->hdev->product; | 787 | product = wdata->hdev->product; |
771 | name = wdata->hdev->name; | 788 | name = wdata->hdev->name; |
772 | 789 | ||
790 | if (exttype == WIIMOTE_EXT_BALANCE_BOARD) { | ||
791 | devtype = WIIMOTE_DEV_BALANCE_BOARD; | ||
792 | goto done; | ||
793 | } | ||
794 | |||
773 | if (!strcmp(name, "Nintendo RVL-CNT-01")) { | 795 | if (!strcmp(name, "Nintendo RVL-CNT-01")) { |
774 | devtype = WIIMOTE_DEV_GEN10; | 796 | devtype = WIIMOTE_DEV_GEN10; |
775 | goto done; | 797 | goto done; |
776 | } else if (!strcmp(name, "Nintendo RVL-CNT-01-TR")) { | 798 | } else if (!strcmp(name, "Nintendo RVL-CNT-01-TR")) { |
777 | devtype = WIIMOTE_DEV_GEN20; | 799 | devtype = WIIMOTE_DEV_GEN20; |
778 | goto done; | 800 | goto done; |
801 | } else if (!strcmp(name, "Nintendo RVL-WBC-01")) { | ||
802 | devtype = WIIMOTE_DEV_BALANCE_BOARD; | ||
803 | goto done; | ||
779 | } | 804 | } |
780 | 805 | ||
781 | if (vendor == USB_VENDOR_ID_NINTENDO) { | 806 | if (vendor == USB_VENDOR_ID_NINTENDO) { |
@@ -1009,6 +1034,7 @@ out_release: | |||
1009 | static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = { | 1034 | static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = { |
1010 | [WIIMOTE_EXT_NONE] = "None", | 1035 | [WIIMOTE_EXT_NONE] = "None", |
1011 | [WIIMOTE_EXT_UNKNOWN] = "Unknown", | 1036 | [WIIMOTE_EXT_UNKNOWN] = "Unknown", |
1037 | [WIIMOTE_EXT_BALANCE_BOARD] = "Nintendo Wii Balance Board", | ||
1012 | }; | 1038 | }; |
1013 | 1039 | ||
1014 | /* | 1040 | /* |
diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c index d3eef771b00b..6239cd87f1ed 100644 --- a/drivers/hid/hid-wiimote-modules.c +++ b/drivers/hid/hid-wiimote-modules.c | |||
@@ -789,6 +789,216 @@ static const struct wiimod_ops wiimod_ir = { | |||
789 | }; | 789 | }; |
790 | 790 | ||
791 | /* | 791 | /* |
792 | * Balance Board Extension | ||
793 | * The Nintendo Wii Balance Board provides four hardware weight sensor plus a | ||
794 | * single push button. No other peripherals are available. However, the | ||
795 | * balance-board data is sent via a standard Wii Remote extension. All other | ||
796 | * data for non-present hardware is zeroed out. | ||
797 | * Some 3rd party devices react allergic if we try to access normal Wii Remote | ||
798 | * hardware, so this extension module should be the only module that is loaded | ||
799 | * on balance boards. | ||
800 | * The balance board needs 8 bytes extension data instead of basic 6 bytes so | ||
801 | * it needs the WIIMOD_FLAG_EXT8 flag. | ||
802 | */ | ||
803 | |||
804 | static void wiimod_bboard_in_keys(struct wiimote_data *wdata, const __u8 *keys) | ||
805 | { | ||
806 | input_report_key(wdata->extension.input, BTN_A, | ||
807 | !!(keys[1] & 0x08)); | ||
808 | input_sync(wdata->extension.input); | ||
809 | } | ||
810 | |||
811 | static void wiimod_bboard_in_ext(struct wiimote_data *wdata, | ||
812 | const __u8 *ext) | ||
813 | { | ||
814 | __s32 val[4], tmp, div; | ||
815 | unsigned int i; | ||
816 | struct wiimote_state *s = &wdata->state; | ||
817 | |||
818 | /* | ||
819 | * Balance board data layout: | ||
820 | * | ||
821 | * Byte | 8 7 6 5 4 3 2 1 | | ||
822 | * -----+--------------------------+ | ||
823 | * 1 | Top Right <15:8> | | ||
824 | * 2 | Top Right <7:0> | | ||
825 | * -----+--------------------------+ | ||
826 | * 3 | Bottom Right <15:8> | | ||
827 | * 4 | Bottom Right <7:0> | | ||
828 | * -----+--------------------------+ | ||
829 | * 5 | Top Left <15:8> | | ||
830 | * 6 | Top Left <7:0> | | ||
831 | * -----+--------------------------+ | ||
832 | * 7 | Bottom Left <15:8> | | ||
833 | * 8 | Bottom Left <7:0> | | ||
834 | * -----+--------------------------+ | ||
835 | * | ||
836 | * These values represent the weight-measurements of the Wii-balance | ||
837 | * board with 16bit precision. | ||
838 | * | ||
839 | * The balance-board is never reported interleaved with motionp. | ||
840 | */ | ||
841 | |||
842 | val[0] = ext[0]; | ||
843 | val[0] <<= 8; | ||
844 | val[0] |= ext[1]; | ||
845 | |||
846 | val[1] = ext[2]; | ||
847 | val[1] <<= 8; | ||
848 | val[1] |= ext[3]; | ||
849 | |||
850 | val[2] = ext[4]; | ||
851 | val[2] <<= 8; | ||
852 | val[2] |= ext[5]; | ||
853 | |||
854 | val[3] = ext[6]; | ||
855 | val[3] <<= 8; | ||
856 | val[3] |= ext[7]; | ||
857 | |||
858 | /* apply calibration data */ | ||
859 | for (i = 0; i < 4; i++) { | ||
860 | if (val[i] <= s->calib_bboard[i][0]) { | ||
861 | tmp = 0; | ||
862 | } else if (val[i] < s->calib_bboard[i][1]) { | ||
863 | tmp = val[i] - s->calib_bboard[i][0]; | ||
864 | tmp *= 1700; | ||
865 | div = s->calib_bboard[i][1] - s->calib_bboard[i][0]; | ||
866 | tmp /= div ? div : 1; | ||
867 | } else { | ||
868 | tmp = val[i] - s->calib_bboard[i][1]; | ||
869 | tmp *= 1700; | ||
870 | div = s->calib_bboard[i][2] - s->calib_bboard[i][1]; | ||
871 | tmp /= div ? div : 1; | ||
872 | tmp += 1700; | ||
873 | } | ||
874 | val[i] = tmp; | ||
875 | } | ||
876 | |||
877 | input_report_abs(wdata->extension.input, ABS_HAT0X, val[0]); | ||
878 | input_report_abs(wdata->extension.input, ABS_HAT0Y, val[1]); | ||
879 | input_report_abs(wdata->extension.input, ABS_HAT1X, val[2]); | ||
880 | input_report_abs(wdata->extension.input, ABS_HAT1Y, val[3]); | ||
881 | input_sync(wdata->extension.input); | ||
882 | } | ||
883 | |||
884 | static int wiimod_bboard_open(struct input_dev *dev) | ||
885 | { | ||
886 | struct wiimote_data *wdata = input_get_drvdata(dev); | ||
887 | unsigned long flags; | ||
888 | |||
889 | spin_lock_irqsave(&wdata->state.lock, flags); | ||
890 | wdata->state.flags |= WIIPROTO_FLAG_EXT_USED; | ||
891 | wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); | ||
892 | spin_unlock_irqrestore(&wdata->state.lock, flags); | ||
893 | |||
894 | return 0; | ||
895 | } | ||
896 | |||
897 | static void wiimod_bboard_close(struct input_dev *dev) | ||
898 | { | ||
899 | struct wiimote_data *wdata = input_get_drvdata(dev); | ||
900 | unsigned long flags; | ||
901 | |||
902 | spin_lock_irqsave(&wdata->state.lock, flags); | ||
903 | wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED; | ||
904 | wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL); | ||
905 | spin_unlock_irqrestore(&wdata->state.lock, flags); | ||
906 | } | ||
907 | |||
908 | static int wiimod_bboard_probe(const struct wiimod_ops *ops, | ||
909 | struct wiimote_data *wdata) | ||
910 | { | ||
911 | int ret, i, j; | ||
912 | __u8 buf[24], offs; | ||
913 | |||
914 | wiimote_cmd_acquire_noint(wdata); | ||
915 | |||
916 | ret = wiimote_cmd_read(wdata, 0xa40024, buf, 12); | ||
917 | if (ret != 12) { | ||
918 | wiimote_cmd_release(wdata); | ||
919 | return ret < 0 ? ret : -EIO; | ||
920 | } | ||
921 | ret = wiimote_cmd_read(wdata, 0xa40024 + 12, buf + 12, 12); | ||
922 | if (ret != 12) { | ||
923 | wiimote_cmd_release(wdata); | ||
924 | return ret < 0 ? ret : -EIO; | ||
925 | } | ||
926 | |||
927 | wiimote_cmd_release(wdata); | ||
928 | |||
929 | offs = 0; | ||
930 | for (i = 0; i < 3; ++i) { | ||
931 | for (j = 0; j < 4; ++j) { | ||
932 | wdata->state.calib_bboard[j][i] = buf[offs]; | ||
933 | wdata->state.calib_bboard[j][i] <<= 8; | ||
934 | wdata->state.calib_bboard[j][i] |= buf[offs + 1]; | ||
935 | offs += 2; | ||
936 | } | ||
937 | } | ||
938 | |||
939 | wdata->extension.input = input_allocate_device(); | ||
940 | if (!wdata->extension.input) | ||
941 | return -ENOMEM; | ||
942 | |||
943 | input_set_drvdata(wdata->extension.input, wdata); | ||
944 | wdata->extension.input->open = wiimod_bboard_open; | ||
945 | wdata->extension.input->close = wiimod_bboard_close; | ||
946 | wdata->extension.input->dev.parent = &wdata->hdev->dev; | ||
947 | wdata->extension.input->id.bustype = wdata->hdev->bus; | ||
948 | wdata->extension.input->id.vendor = wdata->hdev->vendor; | ||
949 | wdata->extension.input->id.product = wdata->hdev->product; | ||
950 | wdata->extension.input->id.version = wdata->hdev->version; | ||
951 | wdata->extension.input->name = WIIMOTE_NAME " Balance Board"; | ||
952 | |||
953 | set_bit(EV_KEY, wdata->extension.input->evbit); | ||
954 | set_bit(BTN_A, wdata->extension.input->keybit); | ||
955 | |||
956 | set_bit(EV_ABS, wdata->extension.input->evbit); | ||
957 | set_bit(ABS_HAT0X, wdata->extension.input->absbit); | ||
958 | set_bit(ABS_HAT0Y, wdata->extension.input->absbit); | ||
959 | set_bit(ABS_HAT1X, wdata->extension.input->absbit); | ||
960 | set_bit(ABS_HAT1Y, wdata->extension.input->absbit); | ||
961 | input_set_abs_params(wdata->extension.input, | ||
962 | ABS_HAT0X, 0, 65535, 2, 4); | ||
963 | input_set_abs_params(wdata->extension.input, | ||
964 | ABS_HAT0Y, 0, 65535, 2, 4); | ||
965 | input_set_abs_params(wdata->extension.input, | ||
966 | ABS_HAT1X, 0, 65535, 2, 4); | ||
967 | input_set_abs_params(wdata->extension.input, | ||
968 | ABS_HAT1Y, 0, 65535, 2, 4); | ||
969 | |||
970 | ret = input_register_device(wdata->extension.input); | ||
971 | if (ret) | ||
972 | goto err_free; | ||
973 | |||
974 | return 0; | ||
975 | |||
976 | err_free: | ||
977 | input_free_device(wdata->extension.input); | ||
978 | wdata->extension.input = NULL; | ||
979 | return ret; | ||
980 | } | ||
981 | |||
982 | static void wiimod_bboard_remove(const struct wiimod_ops *ops, | ||
983 | struct wiimote_data *wdata) | ||
984 | { | ||
985 | if (!wdata->extension.input) | ||
986 | return; | ||
987 | |||
988 | input_unregister_device(wdata->extension.input); | ||
989 | wdata->extension.input = NULL; | ||
990 | } | ||
991 | |||
992 | static const struct wiimod_ops wiimod_bboard = { | ||
993 | .flags = WIIMOD_FLAG_EXT8, | ||
994 | .arg = 0, | ||
995 | .probe = wiimod_bboard_probe, | ||
996 | .remove = wiimod_bboard_remove, | ||
997 | .in_keys = wiimod_bboard_in_keys, | ||
998 | .in_ext = wiimod_bboard_in_ext, | ||
999 | }; | ||
1000 | |||
1001 | /* | ||
792 | * Motion Plus | 1002 | * Motion Plus |
793 | */ | 1003 | */ |
794 | 1004 | ||
@@ -816,4 +1026,5 @@ const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = { | |||
816 | const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = { | 1026 | const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = { |
817 | [WIIMOTE_EXT_NONE] = &wiimod_dummy, | 1027 | [WIIMOTE_EXT_NONE] = &wiimod_dummy, |
818 | [WIIMOTE_EXT_UNKNOWN] = &wiimod_dummy, | 1028 | [WIIMOTE_EXT_UNKNOWN] = &wiimod_dummy, |
1029 | [WIIMOTE_EXT_BALANCE_BOARD] = &wiimod_bboard, | ||
819 | }; | 1030 | }; |
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h index 0afc9f9a9bd6..8d314ae429b6 100644 --- a/drivers/hid/hid-wiimote.h +++ b/drivers/hid/hid-wiimote.h | |||
@@ -73,12 +73,14 @@ enum wiimote_devtype { | |||
73 | WIIMOTE_DEV_GENERIC, | 73 | WIIMOTE_DEV_GENERIC, |
74 | WIIMOTE_DEV_GEN10, | 74 | WIIMOTE_DEV_GEN10, |
75 | WIIMOTE_DEV_GEN20, | 75 | WIIMOTE_DEV_GEN20, |
76 | WIIMOTE_DEV_BALANCE_BOARD, | ||
76 | WIIMOTE_DEV_NUM, | 77 | WIIMOTE_DEV_NUM, |
77 | }; | 78 | }; |
78 | 79 | ||
79 | enum wiimote_exttype { | 80 | enum wiimote_exttype { |
80 | WIIMOTE_EXT_NONE, | 81 | WIIMOTE_EXT_NONE, |
81 | WIIMOTE_EXT_UNKNOWN, | 82 | WIIMOTE_EXT_UNKNOWN, |
83 | WIIMOTE_EXT_BALANCE_BOARD, | ||
82 | WIIMOTE_EXT_NUM, | 84 | WIIMOTE_EXT_NUM, |
83 | }; | 85 | }; |
84 | 86 | ||
@@ -123,6 +125,9 @@ struct wiimote_state { | |||
123 | __u8 cmd_err; | 125 | __u8 cmd_err; |
124 | __u8 *cmd_read_buf; | 126 | __u8 *cmd_read_buf; |
125 | __u8 cmd_read_size; | 127 | __u8 cmd_read_size; |
128 | |||
129 | /* calibration data */ | ||
130 | __u16 calib_bboard[4][3]; | ||
126 | }; | 131 | }; |
127 | 132 | ||
128 | struct wiimote_data { | 133 | struct wiimote_data { |
@@ -136,6 +141,10 @@ struct wiimote_data { | |||
136 | struct wiimote_ext *ext; | 141 | struct wiimote_ext *ext; |
137 | struct wiimote_debug *debug; | 142 | struct wiimote_debug *debug; |
138 | 143 | ||
144 | union { | ||
145 | struct input_dev *input; | ||
146 | } extension; | ||
147 | |||
139 | struct wiimote_queue queue; | 148 | struct wiimote_queue queue; |
140 | struct wiimote_state state; | 149 | struct wiimote_state state; |
141 | struct work_struct init_worker; | 150 | struct work_struct init_worker; |