diff options
-rw-r--r-- | drivers/hid/hid-logitech-hidpp.c | 701 |
1 files changed, 593 insertions, 108 deletions
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index bd2ab476c65e..2869bbff0899 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c | |||
@@ -15,13 +15,19 @@ | |||
15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
16 | 16 | ||
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/input.h> | ||
19 | #include <linux/usb.h> | ||
18 | #include <linux/hid.h> | 20 | #include <linux/hid.h> |
19 | #include <linux/module.h> | 21 | #include <linux/module.h> |
20 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
21 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
22 | #include <linux/kfifo.h> | 24 | #include <linux/kfifo.h> |
23 | #include <linux/input/mt.h> | 25 | #include <linux/input/mt.h> |
26 | #include <linux/workqueue.h> | ||
27 | #include <linux/atomic.h> | ||
28 | #include <linux/fixp-arith.h> | ||
24 | #include <asm/unaligned.h> | 29 | #include <asm/unaligned.h> |
30 | #include "usbhid/usbhid.h" | ||
25 | #include "hid-ids.h" | 31 | #include "hid-ids.h" |
26 | 32 | ||
27 | MODULE_LICENSE("GPL"); | 33 | MODULE_LICENSE("GPL"); |
@@ -773,6 +779,589 @@ static void hidpp_touchpad_raw_xy_event(struct hidpp_device *hidpp_dev, | |||
773 | } | 779 | } |
774 | } | 780 | } |
775 | 781 | ||
782 | /* -------------------------------------------------------------------------- */ | ||
783 | /* 0x8123: Force feedback support */ | ||
784 | /* -------------------------------------------------------------------------- */ | ||
785 | |||
786 | #define HIDPP_FF_GET_INFO 0x01 | ||
787 | #define HIDPP_FF_RESET_ALL 0x11 | ||
788 | #define HIDPP_FF_DOWNLOAD_EFFECT 0x21 | ||
789 | #define HIDPP_FF_SET_EFFECT_STATE 0x31 | ||
790 | #define HIDPP_FF_DESTROY_EFFECT 0x41 | ||
791 | #define HIDPP_FF_GET_APERTURE 0x51 | ||
792 | #define HIDPP_FF_SET_APERTURE 0x61 | ||
793 | #define HIDPP_FF_GET_GLOBAL_GAINS 0x71 | ||
794 | #define HIDPP_FF_SET_GLOBAL_GAINS 0x81 | ||
795 | |||
796 | #define HIDPP_FF_EFFECT_STATE_GET 0x00 | ||
797 | #define HIDPP_FF_EFFECT_STATE_STOP 0x01 | ||
798 | #define HIDPP_FF_EFFECT_STATE_PLAY 0x02 | ||
799 | #define HIDPP_FF_EFFECT_STATE_PAUSE 0x03 | ||
800 | |||
801 | #define HIDPP_FF_EFFECT_CONSTANT 0x00 | ||
802 | #define HIDPP_FF_EFFECT_PERIODIC_SINE 0x01 | ||
803 | #define HIDPP_FF_EFFECT_PERIODIC_SQUARE 0x02 | ||
804 | #define HIDPP_FF_EFFECT_PERIODIC_TRIANGLE 0x03 | ||
805 | #define HIDPP_FF_EFFECT_PERIODIC_SAWTOOTHUP 0x04 | ||
806 | #define HIDPP_FF_EFFECT_PERIODIC_SAWTOOTHDOWN 0x05 | ||
807 | #define HIDPP_FF_EFFECT_SPRING 0x06 | ||
808 | #define HIDPP_FF_EFFECT_DAMPER 0x07 | ||
809 | #define HIDPP_FF_EFFECT_FRICTION 0x08 | ||
810 | #define HIDPP_FF_EFFECT_INERTIA 0x09 | ||
811 | #define HIDPP_FF_EFFECT_RAMP 0x0A | ||
812 | |||
813 | #define HIDPP_FF_EFFECT_AUTOSTART 0x80 | ||
814 | |||
815 | #define HIDPP_FF_EFFECTID_NONE -1 | ||
816 | #define HIDPP_FF_EFFECTID_AUTOCENTER -2 | ||
817 | |||
818 | #define HIDPP_FF_MAX_PARAMS 20 | ||
819 | #define HIDPP_FF_RESERVED_SLOTS 1 | ||
820 | |||
821 | struct hidpp_ff_private_data { | ||
822 | struct hidpp_device *hidpp; | ||
823 | u8 feature_index; | ||
824 | u8 version; | ||
825 | u16 gain; | ||
826 | s16 range; | ||
827 | u8 slot_autocenter; | ||
828 | u8 num_effects; | ||
829 | int *effect_ids; | ||
830 | struct workqueue_struct *wq; | ||
831 | atomic_t workqueue_size; | ||
832 | }; | ||
833 | |||
834 | struct hidpp_ff_work_data { | ||
835 | struct work_struct work; | ||
836 | struct hidpp_ff_private_data *data; | ||
837 | int effect_id; | ||
838 | u8 command; | ||
839 | u8 params[HIDPP_FF_MAX_PARAMS]; | ||
840 | u8 size; | ||
841 | }; | ||
842 | |||
843 | static const signed short hiddpp_ff_effects[] = { | ||
844 | FF_CONSTANT, | ||
845 | FF_PERIODIC, | ||
846 | FF_SINE, | ||
847 | FF_SQUARE, | ||
848 | FF_SAW_UP, | ||
849 | FF_SAW_DOWN, | ||
850 | FF_TRIANGLE, | ||
851 | FF_SPRING, | ||
852 | FF_DAMPER, | ||
853 | FF_AUTOCENTER, | ||
854 | FF_GAIN, | ||
855 | -1 | ||
856 | }; | ||
857 | |||
858 | static const signed short hiddpp_ff_effects_v2[] = { | ||
859 | FF_RAMP, | ||
860 | FF_FRICTION, | ||
861 | FF_INERTIA, | ||
862 | -1 | ||
863 | }; | ||
864 | |||
865 | static const u8 HIDPP_FF_CONDITION_CMDS[] = { | ||
866 | HIDPP_FF_EFFECT_SPRING, | ||
867 | HIDPP_FF_EFFECT_FRICTION, | ||
868 | HIDPP_FF_EFFECT_DAMPER, | ||
869 | HIDPP_FF_EFFECT_INERTIA | ||
870 | }; | ||
871 | |||
872 | static const char *HIDPP_FF_CONDITION_NAMES[] = { | ||
873 | "spring", | ||
874 | "friction", | ||
875 | "damper", | ||
876 | "inertia" | ||
877 | }; | ||
878 | |||
879 | |||
880 | static u8 hidpp_ff_find_effect(struct hidpp_ff_private_data *data, int effect_id) | ||
881 | { | ||
882 | int i; | ||
883 | |||
884 | for (i = 0; i < data->num_effects; i++) | ||
885 | if (data->effect_ids[i] == effect_id) | ||
886 | return i+1; | ||
887 | |||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | static void hidpp_ff_work_handler(struct work_struct *w) | ||
892 | { | ||
893 | struct hidpp_ff_work_data *wd = container_of(w, struct hidpp_ff_work_data, work); | ||
894 | struct hidpp_ff_private_data *data = wd->data; | ||
895 | struct hidpp_report response; | ||
896 | u8 slot; | ||
897 | int ret; | ||
898 | |||
899 | /* add slot number if needed */ | ||
900 | switch (wd->effect_id) { | ||
901 | case HIDPP_FF_EFFECTID_AUTOCENTER: | ||
902 | wd->params[0] = data->slot_autocenter; | ||
903 | break; | ||
904 | case HIDPP_FF_EFFECTID_NONE: | ||
905 | /* leave slot as zero */ | ||
906 | break; | ||
907 | default: | ||
908 | /* find current slot for effect */ | ||
909 | wd->params[0] = hidpp_ff_find_effect(data, wd->effect_id); | ||
910 | break; | ||
911 | } | ||
912 | |||
913 | /* send command and wait for reply */ | ||
914 | ret = hidpp_send_fap_command_sync(data->hidpp, data->feature_index, | ||
915 | wd->command, wd->params, wd->size, &response); | ||
916 | |||
917 | if (ret) { | ||
918 | hid_err(data->hidpp->hid_dev, "Failed to send command to device!\n"); | ||
919 | goto out; | ||
920 | } | ||
921 | |||
922 | /* parse return data */ | ||
923 | switch (wd->command) { | ||
924 | case HIDPP_FF_DOWNLOAD_EFFECT: | ||
925 | slot = response.fap.params[0]; | ||
926 | if (slot > 0 && slot <= data->num_effects) { | ||
927 | if (wd->effect_id >= 0) | ||
928 | /* regular effect uploaded */ | ||
929 | data->effect_ids[slot-1] = wd->effect_id; | ||
930 | else if (wd->effect_id >= HIDPP_FF_EFFECTID_AUTOCENTER) | ||
931 | /* autocenter spring uploaded */ | ||
932 | data->slot_autocenter = slot; | ||
933 | } | ||
934 | break; | ||
935 | case HIDPP_FF_DESTROY_EFFECT: | ||
936 | if (wd->effect_id >= 0) | ||
937 | /* regular effect destroyed */ | ||
938 | data->effect_ids[wd->params[0]-1] = -1; | ||
939 | else if (wd->effect_id >= HIDPP_FF_EFFECTID_AUTOCENTER) | ||
940 | /* autocenter spring destoyed */ | ||
941 | data->slot_autocenter = 0; | ||
942 | break; | ||
943 | case HIDPP_FF_SET_GLOBAL_GAINS: | ||
944 | data->gain = (wd->params[0] << 8) + wd->params[1]; | ||
945 | break; | ||
946 | case HIDPP_FF_SET_APERTURE: | ||
947 | data->range = (wd->params[0] << 8) + wd->params[1]; | ||
948 | break; | ||
949 | default: | ||
950 | /* no action needed */ | ||
951 | break; | ||
952 | } | ||
953 | |||
954 | out: | ||
955 | atomic_dec(&data->workqueue_size); | ||
956 | kfree(wd); | ||
957 | } | ||
958 | |||
959 | static int hidpp_ff_queue_work(struct hidpp_ff_private_data *data, int effect_id, u8 command, u8 *params, u8 size) | ||
960 | { | ||
961 | struct hidpp_ff_work_data *wd = kzalloc(sizeof(*wd), GFP_KERNEL); | ||
962 | int s; | ||
963 | |||
964 | if (!wd) | ||
965 | return -ENOMEM; | ||
966 | |||
967 | INIT_WORK(&wd->work, hidpp_ff_work_handler); | ||
968 | |||
969 | wd->data = data; | ||
970 | wd->effect_id = effect_id; | ||
971 | wd->command = command; | ||
972 | wd->size = size; | ||
973 | memcpy(wd->params, params, size); | ||
974 | |||
975 | atomic_inc(&data->workqueue_size); | ||
976 | queue_work(data->wq, &wd->work); | ||
977 | |||
978 | /* warn about excessive queue size */ | ||
979 | s = atomic_read(&data->workqueue_size); | ||
980 | if (s >= 20 && s % 20 == 0) | ||
981 | hid_warn(data->hidpp->hid_dev, "Force feedback command queue contains %d commands, causing substantial delays!", s); | ||
982 | |||
983 | return 0; | ||
984 | } | ||
985 | |||
986 | static int hidpp_ff_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) | ||
987 | { | ||
988 | struct hidpp_ff_private_data *data = dev->ff->private; | ||
989 | u8 params[20]; | ||
990 | u8 size; | ||
991 | int force; | ||
992 | |||
993 | /* set common parameters */ | ||
994 | params[2] = effect->replay.length >> 8; | ||
995 | params[3] = effect->replay.length & 255; | ||
996 | params[4] = effect->replay.delay >> 8; | ||
997 | params[5] = effect->replay.delay & 255; | ||
998 | |||
999 | switch (effect->type) { | ||
1000 | case FF_CONSTANT: | ||
1001 | force = (effect->u.constant.level * fixp_sin16((effect->direction * 360) >> 16)) >> 15; | ||
1002 | params[1] = HIDPP_FF_EFFECT_CONSTANT; | ||
1003 | params[6] = force >> 8; | ||
1004 | params[7] = force & 255; | ||
1005 | params[8] = effect->u.constant.envelope.attack_level >> 7; | ||
1006 | params[9] = effect->u.constant.envelope.attack_length >> 8; | ||
1007 | params[10] = effect->u.constant.envelope.attack_length & 255; | ||
1008 | params[11] = effect->u.constant.envelope.fade_level >> 7; | ||
1009 | params[12] = effect->u.constant.envelope.fade_length >> 8; | ||
1010 | params[13] = effect->u.constant.envelope.fade_length & 255; | ||
1011 | size = 14; | ||
1012 | dbg_hid("Uploading constant force level=%d in dir %d = %d\n", | ||
1013 | effect->u.constant.level, | ||
1014 | effect->direction, force); | ||
1015 | dbg_hid(" envelope attack=(%d, %d ms) fade=(%d, %d ms)\n", | ||
1016 | effect->u.constant.envelope.attack_level, | ||
1017 | effect->u.constant.envelope.attack_length, | ||
1018 | effect->u.constant.envelope.fade_level, | ||
1019 | effect->u.constant.envelope.fade_length); | ||
1020 | break; | ||
1021 | case FF_PERIODIC: | ||
1022 | { | ||
1023 | switch (effect->u.periodic.waveform) { | ||
1024 | case FF_SINE: | ||
1025 | params[1] = HIDPP_FF_EFFECT_PERIODIC_SINE; | ||
1026 | break; | ||
1027 | case FF_SQUARE: | ||
1028 | params[1] = HIDPP_FF_EFFECT_PERIODIC_SQUARE; | ||
1029 | break; | ||
1030 | case FF_SAW_UP: | ||
1031 | params[1] = HIDPP_FF_EFFECT_PERIODIC_SAWTOOTHUP; | ||
1032 | break; | ||
1033 | case FF_SAW_DOWN: | ||
1034 | params[1] = HIDPP_FF_EFFECT_PERIODIC_SAWTOOTHDOWN; | ||
1035 | break; | ||
1036 | case FF_TRIANGLE: | ||
1037 | params[1] = HIDPP_FF_EFFECT_PERIODIC_TRIANGLE; | ||
1038 | break; | ||
1039 | default: | ||
1040 | hid_err(data->hidpp->hid_dev, "Unexpected periodic waveform type %i!\n", effect->u.periodic.waveform); | ||
1041 | return -EINVAL; | ||
1042 | } | ||
1043 | force = (effect->u.periodic.magnitude * fixp_sin16((effect->direction * 360) >> 16)) >> 15; | ||
1044 | params[6] = effect->u.periodic.magnitude >> 8; | ||
1045 | params[7] = effect->u.periodic.magnitude & 255; | ||
1046 | params[8] = effect->u.periodic.offset >> 8; | ||
1047 | params[9] = effect->u.periodic.offset & 255; | ||
1048 | params[10] = effect->u.periodic.period >> 8; | ||
1049 | params[11] = effect->u.periodic.period & 255; | ||
1050 | params[12] = effect->u.periodic.phase >> 8; | ||
1051 | params[13] = effect->u.periodic.phase & 255; | ||
1052 | params[14] = effect->u.periodic.envelope.attack_level >> 7; | ||
1053 | params[15] = effect->u.periodic.envelope.attack_length >> 8; | ||
1054 | params[16] = effect->u.periodic.envelope.attack_length & 255; | ||
1055 | params[17] = effect->u.periodic.envelope.fade_level >> 7; | ||
1056 | params[18] = effect->u.periodic.envelope.fade_length >> 8; | ||
1057 | params[19] = effect->u.periodic.envelope.fade_length & 255; | ||
1058 | size = 20; | ||
1059 | dbg_hid("Uploading periodic force mag=%d/dir=%d, offset=%d, period=%d ms, phase=%d\n", | ||
1060 | effect->u.periodic.magnitude, effect->direction, | ||
1061 | effect->u.periodic.offset, | ||
1062 | effect->u.periodic.period, | ||
1063 | effect->u.periodic.phase); | ||
1064 | dbg_hid(" envelope attack=(%d, %d ms) fade=(%d, %d ms)\n", | ||
1065 | effect->u.periodic.envelope.attack_level, | ||
1066 | effect->u.periodic.envelope.attack_length, | ||
1067 | effect->u.periodic.envelope.fade_level, | ||
1068 | effect->u.periodic.envelope.fade_length); | ||
1069 | break; | ||
1070 | } | ||
1071 | case FF_RAMP: | ||
1072 | params[1] = HIDPP_FF_EFFECT_RAMP; | ||
1073 | force = (effect->u.ramp.start_level * fixp_sin16((effect->direction * 360) >> 16)) >> 15; | ||
1074 | params[6] = force >> 8; | ||
1075 | params[7] = force & 255; | ||
1076 | force = (effect->u.ramp.end_level * fixp_sin16((effect->direction * 360) >> 16)) >> 15; | ||
1077 | params[8] = force >> 8; | ||
1078 | params[9] = force & 255; | ||
1079 | params[10] = effect->u.ramp.envelope.attack_level >> 7; | ||
1080 | params[11] = effect->u.ramp.envelope.attack_length >> 8; | ||
1081 | params[12] = effect->u.ramp.envelope.attack_length & 255; | ||
1082 | params[13] = effect->u.ramp.envelope.fade_level >> 7; | ||
1083 | params[14] = effect->u.ramp.envelope.fade_length >> 8; | ||
1084 | params[15] = effect->u.ramp.envelope.fade_length & 255; | ||
1085 | size = 16; | ||
1086 | dbg_hid("Uploading ramp force level=%d -> %d in dir %d = %d\n", | ||
1087 | effect->u.ramp.start_level, | ||
1088 | effect->u.ramp.end_level, | ||
1089 | effect->direction, force); | ||
1090 | dbg_hid(" envelope attack=(%d, %d ms) fade=(%d, %d ms)\n", | ||
1091 | effect->u.ramp.envelope.attack_level, | ||
1092 | effect->u.ramp.envelope.attack_length, | ||
1093 | effect->u.ramp.envelope.fade_level, | ||
1094 | effect->u.ramp.envelope.fade_length); | ||
1095 | break; | ||
1096 | case FF_FRICTION: | ||
1097 | case FF_INERTIA: | ||
1098 | case FF_SPRING: | ||
1099 | case FF_DAMPER: | ||
1100 | params[1] = HIDPP_FF_CONDITION_CMDS[effect->type - FF_SPRING]; | ||
1101 | params[6] = effect->u.condition[0].left_saturation >> 9; | ||
1102 | params[7] = (effect->u.condition[0].left_saturation >> 1) & 255; | ||
1103 | params[8] = effect->u.condition[0].left_coeff >> 8; | ||
1104 | params[9] = effect->u.condition[0].left_coeff & 255; | ||
1105 | params[10] = effect->u.condition[0].deadband >> 9; | ||
1106 | params[11] = (effect->u.condition[0].deadband >> 1) & 255; | ||
1107 | params[12] = effect->u.condition[0].center >> 8; | ||
1108 | params[13] = effect->u.condition[0].center & 255; | ||
1109 | params[14] = effect->u.condition[0].right_coeff >> 8; | ||
1110 | params[15] = effect->u.condition[0].right_coeff & 255; | ||
1111 | params[16] = effect->u.condition[0].right_saturation >> 9; | ||
1112 | params[17] = (effect->u.condition[0].right_saturation >> 1) & 255; | ||
1113 | size = 18; | ||
1114 | dbg_hid("Uploading %s force left coeff=%d, left sat=%d, right coeff=%d, right sat=%d\n", | ||
1115 | HIDPP_FF_CONDITION_NAMES[effect->type - FF_SPRING], | ||
1116 | effect->u.condition[0].left_coeff, | ||
1117 | effect->u.condition[0].left_saturation, | ||
1118 | effect->u.condition[0].right_coeff, | ||
1119 | effect->u.condition[0].right_saturation); | ||
1120 | dbg_hid(" deadband=%d, center=%d\n", | ||
1121 | effect->u.condition[0].deadband, | ||
1122 | effect->u.condition[0].center); | ||
1123 | break; | ||
1124 | default: | ||
1125 | hid_err(data->hidpp->hid_dev, "Unexpected force type %i!\n", effect->type); | ||
1126 | return -EINVAL; | ||
1127 | } | ||
1128 | |||
1129 | return hidpp_ff_queue_work(data, effect->id, HIDPP_FF_DOWNLOAD_EFFECT, params, size); | ||
1130 | } | ||
1131 | |||
1132 | static int hidpp_ff_playback(struct input_dev *dev, int effect_id, int value) | ||
1133 | { | ||
1134 | struct hidpp_ff_private_data *data = dev->ff->private; | ||
1135 | u8 params[2]; | ||
1136 | |||
1137 | params[1] = value ? HIDPP_FF_EFFECT_STATE_PLAY : HIDPP_FF_EFFECT_STATE_STOP; | ||
1138 | |||
1139 | dbg_hid("St%sing playback of effect %d.\n", value?"art":"opp", effect_id); | ||
1140 | |||
1141 | return hidpp_ff_queue_work(data, effect_id, HIDPP_FF_SET_EFFECT_STATE, params, ARRAY_SIZE(params)); | ||
1142 | } | ||
1143 | |||
1144 | static int hidpp_ff_erase_effect(struct input_dev *dev, int effect_id) | ||
1145 | { | ||
1146 | struct hidpp_ff_private_data *data = dev->ff->private; | ||
1147 | u8 slot = 0; | ||
1148 | |||
1149 | dbg_hid("Erasing effect %d.\n", effect_id); | ||
1150 | |||
1151 | return hidpp_ff_queue_work(data, effect_id, HIDPP_FF_DESTROY_EFFECT, &slot, 1); | ||
1152 | } | ||
1153 | |||
1154 | static void hidpp_ff_set_autocenter(struct input_dev *dev, u16 magnitude) | ||
1155 | { | ||
1156 | struct hidpp_ff_private_data *data = dev->ff->private; | ||
1157 | u8 params[18]; | ||
1158 | |||
1159 | dbg_hid("Setting autocenter to %d.\n", magnitude); | ||
1160 | |||
1161 | /* start a standard spring effect */ | ||
1162 | params[1] = HIDPP_FF_EFFECT_SPRING | HIDPP_FF_EFFECT_AUTOSTART; | ||
1163 | /* zero delay and duration */ | ||
1164 | params[2] = params[3] = params[4] = params[5] = 0; | ||
1165 | /* set coeff to 25% of saturation */ | ||
1166 | params[8] = params[14] = magnitude >> 11; | ||
1167 | params[9] = params[15] = (magnitude >> 3) & 255; | ||
1168 | params[6] = params[16] = magnitude >> 9; | ||
1169 | params[7] = params[17] = (magnitude >> 1) & 255; | ||
1170 | /* zero deadband and center */ | ||
1171 | params[10] = params[11] = params[12] = params[13] = 0; | ||
1172 | |||
1173 | hidpp_ff_queue_work(data, HIDPP_FF_EFFECTID_AUTOCENTER, HIDPP_FF_DOWNLOAD_EFFECT, params, ARRAY_SIZE(params)); | ||
1174 | } | ||
1175 | |||
1176 | static void hidpp_ff_set_gain(struct input_dev *dev, u16 gain) | ||
1177 | { | ||
1178 | struct hidpp_ff_private_data *data = dev->ff->private; | ||
1179 | u8 params[4]; | ||
1180 | |||
1181 | dbg_hid("Setting gain to %d.\n", gain); | ||
1182 | |||
1183 | params[0] = gain >> 8; | ||
1184 | params[1] = gain & 255; | ||
1185 | params[2] = 0; /* no boost */ | ||
1186 | params[3] = 0; | ||
1187 | |||
1188 | hidpp_ff_queue_work(data, HIDPP_FF_EFFECTID_NONE, HIDPP_FF_SET_GLOBAL_GAINS, params, ARRAY_SIZE(params)); | ||
1189 | } | ||
1190 | |||
1191 | static ssize_t hidpp_ff_range_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
1192 | { | ||
1193 | struct hid_device *hid = to_hid_device(dev); | ||
1194 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | ||
1195 | struct input_dev *idev = hidinput->input; | ||
1196 | struct hidpp_ff_private_data *data = idev->ff->private; | ||
1197 | |||
1198 | return scnprintf(buf, PAGE_SIZE, "%u\n", data->range); | ||
1199 | } | ||
1200 | |||
1201 | static ssize_t hidpp_ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | ||
1202 | { | ||
1203 | struct hid_device *hid = to_hid_device(dev); | ||
1204 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | ||
1205 | struct input_dev *idev = hidinput->input; | ||
1206 | struct hidpp_ff_private_data *data = idev->ff->private; | ||
1207 | u8 params[2]; | ||
1208 | int range = simple_strtoul(buf, NULL, 10); | ||
1209 | |||
1210 | range = clamp(range, 180, 900); | ||
1211 | |||
1212 | params[0] = range >> 8; | ||
1213 | params[1] = range & 0x00FF; | ||
1214 | |||
1215 | hidpp_ff_queue_work(data, -1, HIDPP_FF_SET_APERTURE, params, ARRAY_SIZE(params)); | ||
1216 | |||
1217 | return count; | ||
1218 | } | ||
1219 | |||
1220 | static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, hidpp_ff_range_show, hidpp_ff_range_store); | ||
1221 | |||
1222 | static void hidpp_ff_destroy(struct ff_device *ff) | ||
1223 | { | ||
1224 | struct hidpp_ff_private_data *data = ff->private; | ||
1225 | |||
1226 | kfree(data->effect_ids); | ||
1227 | } | ||
1228 | |||
1229 | int hidpp_ff_init(struct hidpp_device *hidpp, u8 feature_index) | ||
1230 | { | ||
1231 | struct hid_device *hid = hidpp->hid_dev; | ||
1232 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | ||
1233 | struct input_dev *dev = hidinput->input; | ||
1234 | const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor); | ||
1235 | const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice); | ||
1236 | struct ff_device *ff; | ||
1237 | struct hidpp_report response; | ||
1238 | struct hidpp_ff_private_data *data; | ||
1239 | int error, j, num_slots; | ||
1240 | u8 version; | ||
1241 | |||
1242 | if (!dev) { | ||
1243 | hid_err(hid, "Struct input_dev not set!\n"); | ||
1244 | return -EINVAL; | ||
1245 | } | ||
1246 | |||
1247 | /* Get firmware release */ | ||
1248 | version = bcdDevice & 255; | ||
1249 | |||
1250 | /* Set supported force feedback capabilities */ | ||
1251 | for (j = 0; hiddpp_ff_effects[j] >= 0; j++) | ||
1252 | set_bit(hiddpp_ff_effects[j], dev->ffbit); | ||
1253 | if (version > 1) | ||
1254 | for (j = 0; hiddpp_ff_effects_v2[j] >= 0; j++) | ||
1255 | set_bit(hiddpp_ff_effects_v2[j], dev->ffbit); | ||
1256 | |||
1257 | /* Read number of slots available in device */ | ||
1258 | error = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1259 | HIDPP_FF_GET_INFO, NULL, 0, &response); | ||
1260 | if (error) { | ||
1261 | if (error < 0) | ||
1262 | return error; | ||
1263 | hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", | ||
1264 | __func__, error); | ||
1265 | return -EPROTO; | ||
1266 | } | ||
1267 | |||
1268 | num_slots = response.fap.params[0] - HIDPP_FF_RESERVED_SLOTS; | ||
1269 | |||
1270 | error = input_ff_create(dev, num_slots); | ||
1271 | |||
1272 | if (error) { | ||
1273 | hid_err(dev, "Failed to create FF device!\n"); | ||
1274 | return error; | ||
1275 | } | ||
1276 | |||
1277 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
1278 | if (!data) | ||
1279 | return -ENOMEM; | ||
1280 | data->effect_ids = kcalloc(num_slots, sizeof(int), GFP_KERNEL); | ||
1281 | if (!data->effect_ids) { | ||
1282 | kfree(data); | ||
1283 | return -ENOMEM; | ||
1284 | } | ||
1285 | data->hidpp = hidpp; | ||
1286 | data->feature_index = feature_index; | ||
1287 | data->version = version; | ||
1288 | data->slot_autocenter = 0; | ||
1289 | data->num_effects = num_slots; | ||
1290 | for (j = 0; j < num_slots; j++) | ||
1291 | data->effect_ids[j] = -1; | ||
1292 | |||
1293 | ff = dev->ff; | ||
1294 | ff->private = data; | ||
1295 | |||
1296 | ff->upload = hidpp_ff_upload_effect; | ||
1297 | ff->erase = hidpp_ff_erase_effect; | ||
1298 | ff->playback = hidpp_ff_playback; | ||
1299 | ff->set_gain = hidpp_ff_set_gain; | ||
1300 | ff->set_autocenter = hidpp_ff_set_autocenter; | ||
1301 | ff->destroy = hidpp_ff_destroy; | ||
1302 | |||
1303 | |||
1304 | /* reset all forces */ | ||
1305 | error = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1306 | HIDPP_FF_RESET_ALL, NULL, 0, &response); | ||
1307 | |||
1308 | /* Read current Range */ | ||
1309 | error = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1310 | HIDPP_FF_GET_APERTURE, NULL, 0, &response); | ||
1311 | if (error) | ||
1312 | hid_warn(hidpp->hid_dev, "Failed to read range from device!\n"); | ||
1313 | data->range = error ? 900 : get_unaligned_be16(&response.fap.params[0]); | ||
1314 | |||
1315 | /* Create sysfs interface */ | ||
1316 | error = device_create_file(&(hidpp->hid_dev->dev), &dev_attr_range); | ||
1317 | if (error) | ||
1318 | hid_warn(hidpp->hid_dev, "Unable to create sysfs interface for \"range\", errno %d!\n", error); | ||
1319 | |||
1320 | /* Read the current gain values */ | ||
1321 | error = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1322 | HIDPP_FF_GET_GLOBAL_GAINS, NULL, 0, &response); | ||
1323 | if (error) | ||
1324 | hid_warn(hidpp->hid_dev, "Failed to read gain values from device!\n"); | ||
1325 | data->gain = error ? 0xffff : get_unaligned_be16(&response.fap.params[0]); | ||
1326 | /* ignore boost value at response.fap.params[2] */ | ||
1327 | |||
1328 | /* init the hardware command queue */ | ||
1329 | data->wq = create_singlethread_workqueue("hidpp-ff-sendqueue"); | ||
1330 | atomic_set(&data->workqueue_size, 0); | ||
1331 | |||
1332 | /* initialize with zero autocenter to get wheel in usable state */ | ||
1333 | hidpp_ff_set_autocenter(dev, 0); | ||
1334 | |||
1335 | hid_info(hid, "Force feeback support loaded (firmware release %d).\n", version); | ||
1336 | |||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1340 | int hidpp_ff_deinit(struct hid_device *hid) | ||
1341 | { | ||
1342 | struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); | ||
1343 | struct input_dev *dev = hidinput->input; | ||
1344 | struct hidpp_ff_private_data *data; | ||
1345 | |||
1346 | if (!dev) { | ||
1347 | hid_err(hid, "Struct input_dev not found!\n"); | ||
1348 | return -EINVAL; | ||
1349 | } | ||
1350 | |||
1351 | hid_info(hid, "Unloading HID++ force feedback.\n"); | ||
1352 | data = dev->ff->private; | ||
1353 | if (!data) { | ||
1354 | hid_err(hid, "Private data not found!\n"); | ||
1355 | return -EINVAL; | ||
1356 | } | ||
1357 | |||
1358 | destroy_workqueue(data->wq); | ||
1359 | device_remove_file(&hid->dev, &dev_attr_range); | ||
1360 | |||
1361 | return 0; | ||
1362 | } | ||
1363 | |||
1364 | |||
776 | /* ************************************************************************** */ | 1365 | /* ************************************************************************** */ |
777 | /* */ | 1366 | /* */ |
778 | /* Device Support */ | 1367 | /* Device Support */ |
@@ -1301,121 +1890,22 @@ static int k400_connect(struct hid_device *hdev, bool connected) | |||
1301 | 1890 | ||
1302 | #define HIDPP_PAGE_G920_FORCE_FEEDBACK 0x8123 | 1891 | #define HIDPP_PAGE_G920_FORCE_FEEDBACK 0x8123 |
1303 | 1892 | ||
1304 | /* Using session ID = 1 */ | ||
1305 | #define CMD_G920_FORCE_GET_APERTURE 0x51 | ||
1306 | #define CMD_G920_FORCE_SET_APERTURE 0x61 | ||
1307 | |||
1308 | struct g920_private_data { | ||
1309 | u8 force_feature; | ||
1310 | u16 range; | ||
1311 | }; | ||
1312 | |||
1313 | static ssize_t g920_range_show(struct device *dev, struct device_attribute *attr, | ||
1314 | char *buf) | ||
1315 | { | ||
1316 | struct hid_device *hid = to_hid_device(dev); | ||
1317 | struct hidpp_device *hidpp = hid_get_drvdata(hid); | ||
1318 | struct g920_private_data *pdata; | ||
1319 | |||
1320 | pdata = hidpp->private_data; | ||
1321 | if (!pdata) { | ||
1322 | hid_err(hid, "Private driver data not found!\n"); | ||
1323 | return -EINVAL; | ||
1324 | } | ||
1325 | |||
1326 | return scnprintf(buf, PAGE_SIZE, "%u\n", pdata->range); | ||
1327 | } | ||
1328 | |||
1329 | static ssize_t g920_range_store(struct device *dev, struct device_attribute *attr, | ||
1330 | const char *buf, size_t count) | ||
1331 | { | ||
1332 | struct hid_device *hid = to_hid_device(dev); | ||
1333 | struct hidpp_device *hidpp = hid_get_drvdata(hid); | ||
1334 | struct g920_private_data *pdata; | ||
1335 | struct hidpp_report response; | ||
1336 | u8 params[2]; | ||
1337 | int ret; | ||
1338 | u16 range = simple_strtoul(buf, NULL, 10); | ||
1339 | |||
1340 | pdata = hidpp->private_data; | ||
1341 | if (!pdata) { | ||
1342 | hid_err(hid, "Private driver data not found!\n"); | ||
1343 | return -EINVAL; | ||
1344 | } | ||
1345 | |||
1346 | if (range < 180) | ||
1347 | range = 180; | ||
1348 | else if (range > 900) | ||
1349 | range = 900; | ||
1350 | |||
1351 | params[0] = range >> 8; | ||
1352 | params[1] = range & 0x00FF; | ||
1353 | |||
1354 | ret = hidpp_send_fap_command_sync(hidpp, pdata->force_feature, | ||
1355 | CMD_G920_FORCE_SET_APERTURE, params, 2, &response); | ||
1356 | if (ret) | ||
1357 | return ret; | ||
1358 | |||
1359 | pdata->range = range; | ||
1360 | return count; | ||
1361 | } | ||
1362 | |||
1363 | static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, g920_range_show, g920_range_store); | ||
1364 | |||
1365 | static int g920_allocate(struct hid_device *hdev) | ||
1366 | { | ||
1367 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | ||
1368 | struct g920_private_data *pdata; | ||
1369 | |||
1370 | pdata = devm_kzalloc(&hdev->dev, sizeof(struct g920_private_data), | ||
1371 | GFP_KERNEL); | ||
1372 | if (!pdata) | ||
1373 | return -ENOMEM; | ||
1374 | |||
1375 | hidpp->private_data = pdata; | ||
1376 | |||
1377 | return 0; | ||
1378 | } | ||
1379 | |||
1380 | static int g920_get_config(struct hidpp_device *hidpp) | 1893 | static int g920_get_config(struct hidpp_device *hidpp) |
1381 | { | 1894 | { |
1382 | struct g920_private_data *pdata = hidpp->private_data; | ||
1383 | struct hidpp_report response; | ||
1384 | u8 feature_type; | 1895 | u8 feature_type; |
1385 | u8 feature_index; | 1896 | u8 feature_index; |
1386 | int ret; | 1897 | int ret; |
1387 | 1898 | ||
1388 | pdata = hidpp->private_data; | ||
1389 | if (!pdata) { | ||
1390 | hid_err(hidpp->hid_dev, "Private driver data not found!\n"); | ||
1391 | return -EINVAL; | ||
1392 | } | ||
1393 | |||
1394 | /* Find feature and store for later use */ | 1899 | /* Find feature and store for later use */ |
1395 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK, | 1900 | ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK, |
1396 | &feature_index, &feature_type); | 1901 | &feature_index, &feature_type); |
1397 | if (ret) | 1902 | if (ret) |
1398 | return ret; | 1903 | return ret; |
1399 | 1904 | ||
1400 | pdata->force_feature = feature_index; | 1905 | ret = hidpp_ff_init(hidpp, feature_index); |
1401 | |||
1402 | /* Read current Range */ | ||
1403 | ret = hidpp_send_fap_command_sync(hidpp, feature_index, | ||
1404 | CMD_G920_FORCE_GET_APERTURE, NULL, 0, &response); | ||
1405 | if (ret > 0) { | ||
1406 | hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n", | ||
1407 | __func__, ret); | ||
1408 | return -EPROTO; | ||
1409 | } | ||
1410 | if (ret) | ||
1411 | return ret; | ||
1412 | |||
1413 | pdata->range = get_unaligned_be16(&response.fap.params[0]); | ||
1414 | |||
1415 | /* Create sysfs interface */ | ||
1416 | ret = device_create_file(&(hidpp->hid_dev->dev), &dev_attr_range); | ||
1417 | if (ret) | 1906 | if (ret) |
1418 | hid_warn(hidpp->hid_dev, "Unable to create sysfs interface for \"range\", errno %d\n", ret); | 1907 | hid_warn(hidpp->hid_dev, "Unable to initialize force feedback support, errno %d\n", |
1908 | ret); | ||
1419 | 1909 | ||
1420 | return 0; | 1910 | return 0; |
1421 | } | 1911 | } |
@@ -1739,10 +2229,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
1739 | ret = k400_allocate(hdev); | 2229 | ret = k400_allocate(hdev); |
1740 | if (ret) | 2230 | if (ret) |
1741 | goto allocate_fail; | 2231 | goto allocate_fail; |
1742 | } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { | ||
1743 | ret = g920_allocate(hdev); | ||
1744 | if (ret) | ||
1745 | goto allocate_fail; | ||
1746 | } | 2232 | } |
1747 | 2233 | ||
1748 | INIT_WORK(&hidpp->work, delayed_work_cb); | 2234 | INIT_WORK(&hidpp->work, delayed_work_cb); |
@@ -1825,7 +2311,6 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
1825 | hid_hw_open_failed: | 2311 | hid_hw_open_failed: |
1826 | hid_device_io_stop(hdev); | 2312 | hid_device_io_stop(hdev); |
1827 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { | 2313 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { |
1828 | device_remove_file(&hdev->dev, &dev_attr_range); | ||
1829 | hid_hw_close(hdev); | 2314 | hid_hw_close(hdev); |
1830 | hid_hw_stop(hdev); | 2315 | hid_hw_stop(hdev); |
1831 | } | 2316 | } |
@@ -1843,7 +2328,7 @@ static void hidpp_remove(struct hid_device *hdev) | |||
1843 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); | 2328 | struct hidpp_device *hidpp = hid_get_drvdata(hdev); |
1844 | 2329 | ||
1845 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { | 2330 | if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) { |
1846 | device_remove_file(&hdev->dev, &dev_attr_range); | 2331 | hidpp_ff_deinit(hdev); |
1847 | hid_hw_close(hdev); | 2332 | hid_hw_close(hdev); |
1848 | } | 2333 | } |
1849 | hid_hw_stop(hdev); | 2334 | hid_hw_stop(hdev); |