aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-05-05 17:12:58 -0400
committerJiri Kosina <jkosina@suse.cz>2013-06-03 05:07:03 -0400
commitf1d4bed45b553dda2be402e427d8d708c4dca85d (patch)
tree182ad53d5c28f5f1e3e8696f16e36c7ea61cef58 /drivers
parent4148b6bf8a4a4d6e533329775370ccf49778c061 (diff)
HID: wiimote: add Balance Board support
This adds Nintendo Wii Balance Board support to the new HOTPLUG capable wiimote core. It is mostly copied from the old extension. This also adds Balance Board device detection. Whenever we find a device that supports the balance-board extension, we assume that it is a real balance board and disable unsupported hardward like accelerometer, IR, rumble and more. Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hid/hid-wiimote-core.c26
-rw-r--r--drivers/hid/hid-wiimote-modules.c211
-rw-r--r--drivers/hid/hid-wiimote.h9
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
575static void wiimote_modules_load(struct wiimote_data *wdata, 591static 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:
1009static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = { 1034static 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
804static 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
811static 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
884static 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
897static 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
908static 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
976err_free:
977 input_free_device(wdata->extension.input);
978 wdata->extension.input = NULL;
979 return ret;
980}
981
982static 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
992static 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] = {
816const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = { 1026const 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
79enum wiimote_exttype { 80enum 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
128struct wiimote_data { 133struct 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;