diff options
Diffstat (limited to 'drivers/hid/hid-wiimote-modules.c')
-rw-r--r-- | drivers/hid/hid-wiimote-modules.c | 198 |
1 files changed, 198 insertions, 0 deletions
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 | |||
798 | enum wiimod_nunchuk_keys { | ||
799 | WIIMOD_NUNCHUK_KEY_C, | ||
800 | WIIMOD_NUNCHUK_KEY_Z, | ||
801 | WIIMOD_NUNCHUK_KEY_NUM, | ||
802 | }; | ||
803 | |||
804 | static const __u16 wiimod_nunchuk_map[] = { | ||
805 | BTN_C, /* WIIMOD_NUNCHUK_KEY_C */ | ||
806 | BTN_Z, /* WIIMOD_NUNCHUK_KEY_Z */ | ||
807 | }; | ||
808 | |||
809 | static 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 | |||
893 | static 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 | |||
906 | static 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 | |||
917 | static 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 | |||
964 | err_free: | ||
965 | input_free_device(wdata->extension.input); | ||
966 | wdata->extension.input = NULL; | ||
967 | return ret; | ||
968 | } | ||
969 | |||
970 | static 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 | |||
980 | static 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] = { | |||
1026 | const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = { | 1223 | const 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 | }; |