aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-wiimote-modules.c
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/hid/hid-wiimote-modules.c
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/hid/hid-wiimote-modules.c')
-rw-r--r--drivers/hid/hid-wiimote-modules.c211
1 files changed, 211 insertions, 0 deletions
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};