@@ -40,8 +40,9 @@ MODULE_PARM_DESC(disable_raw_mode,
40
40
#define HIDPP_REPORT_LONG_LENGTH 20
41
41
42
42
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
43
+ #define HIDPP_QUIRK_CLASS_M560 BIT(1)
43
44
44
- /* bits 1 ..20 are reserved for classes */
45
+ /* bits 2 ..20 are reserved for classes */
45
46
#define HIDPP_QUIRK_DELAYED_INIT BIT(21)
46
47
#define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22)
47
48
#define HIDPP_QUIRK_MULTI_INPUT BIT(23)
@@ -941,6 +942,207 @@ static int wtp_connect(struct hid_device *hdev, bool connected)
941
942
true, true);
942
943
}
943
944
945
+ /* ------------------------------------------------------------------------- */
946
+ /* Logitech M560 devices */
947
+ /* ------------------------------------------------------------------------- */
948
+
949
+ /*
950
+ * Logitech M560 protocol overview
951
+ *
952
+ * The Logitech M560 mouse, is designed for windows 8. When the middle and/or
953
+ * the sides buttons are pressed, it sends some keyboard keys events
954
+ * instead of buttons ones.
955
+ * To complicate things further, the middle button keys sequence
956
+ * is different from the odd press and the even press.
957
+ *
958
+ * forward button -> Super_R
959
+ * backward button -> Super_L+'d' (press only)
960
+ * middle button -> 1st time: Alt_L+SuperL+XF86TouchpadOff (press only)
961
+ * 2nd time: left-click (press only)
962
+ * NB: press-only means that when the button is pressed, the
963
+ * KeyPress/ButtonPress and KeyRelease/ButtonRelease events are generated
964
+ * together sequentially; instead when the button is released, no event is
965
+ * generated !
966
+ *
967
+ * With the command
968
+ * 10<xx>0a 3500af03 (where <xx> is the mouse id),
969
+ * the mouse reacts differently:
970
+ * - it never sends a keyboard key event
971
+ * - for the three mouse button it sends:
972
+ * middle button press 11<xx>0a 3500af00...
973
+ * side 1 button (forward) press 11<xx>0a 3500b000...
974
+ * side 2 button (backward) press 11<xx>0a 3500ae00...
975
+ * middle/side1/side2 button release 11<xx>0a 35000000...
976
+ */
977
+
978
+ static const u8 m560_config_parameter [] = {0x00 , 0xaf , 0x03 };
979
+
980
+ struct m560_private_data {
981
+ struct input_dev * input ;
982
+ };
983
+
984
+ /* how buttons are mapped in the report */
985
+ #define M560_MOUSE_BTN_LEFT 0x01
986
+ #define M560_MOUSE_BTN_RIGHT 0x02
987
+ #define M560_MOUSE_BTN_WHEEL_LEFT 0x08
988
+ #define M560_MOUSE_BTN_WHEEL_RIGHT 0x10
989
+
990
+ #define M560_SUB_ID 0x0a
991
+ #define M560_BUTTON_MODE_REGISTER 0x35
992
+
993
+ static int m560_send_config_command (struct hid_device * hdev , bool connected )
994
+ {
995
+ struct hidpp_report response ;
996
+ struct hidpp_device * hidpp_dev ;
997
+
998
+ hidpp_dev = hid_get_drvdata (hdev );
999
+
1000
+ if (!connected )
1001
+ return - ENODEV ;
1002
+
1003
+ return hidpp_send_rap_command_sync (
1004
+ hidpp_dev ,
1005
+ REPORT_ID_HIDPP_SHORT ,
1006
+ M560_SUB_ID ,
1007
+ M560_BUTTON_MODE_REGISTER ,
1008
+ (u8 * )m560_config_parameter ,
1009
+ sizeof (m560_config_parameter ),
1010
+ & response
1011
+ );
1012
+ }
1013
+
1014
+ static int m560_allocate (struct hid_device * hdev )
1015
+ {
1016
+ struct hidpp_device * hidpp = hid_get_drvdata (hdev );
1017
+ struct m560_private_data * d ;
1018
+
1019
+ d = devm_kzalloc (& hdev -> dev , sizeof (struct m560_private_data ),
1020
+ GFP_KERNEL );
1021
+ if (!d )
1022
+ return - ENOMEM ;
1023
+
1024
+ hidpp -> private_data = d ;
1025
+
1026
+ return 0 ;
1027
+ };
1028
+
1029
+ static int m560_raw_event (struct hid_device * hdev , u8 * data , int size )
1030
+ {
1031
+ struct hidpp_device * hidpp = hid_get_drvdata (hdev );
1032
+ struct m560_private_data * mydata = hidpp -> private_data ;
1033
+
1034
+ /* sanity check */
1035
+ if (!mydata || !mydata -> input ) {
1036
+ hid_err (hdev , "error in parameter\n" );
1037
+ return - EINVAL ;
1038
+ }
1039
+
1040
+ if (size < 7 ) {
1041
+ hid_err (hdev , "error in report\n" );
1042
+ return 0 ;
1043
+ }
1044
+
1045
+ if (data [0 ] == REPORT_ID_HIDPP_LONG &&
1046
+ data [2 ] == M560_SUB_ID && data [6 ] == 0x00 ) {
1047
+ /*
1048
+ * m560 mouse report for middle, forward and backward button
1049
+ *
1050
+ * data[0] = 0x11
1051
+ * data[1] = device-id
1052
+ * data[2] = 0x0a
1053
+ * data[5] = 0xaf -> middle
1054
+ * 0xb0 -> forward
1055
+ * 0xae -> backward
1056
+ * 0x00 -> release all
1057
+ * data[6] = 0x00
1058
+ */
1059
+
1060
+ switch (data [5 ]) {
1061
+ case 0xaf :
1062
+ input_report_key (mydata -> input , BTN_MIDDLE , 1 );
1063
+ break ;
1064
+ case 0xb0 :
1065
+ input_report_key (mydata -> input , BTN_FORWARD , 1 );
1066
+ break ;
1067
+ case 0xae :
1068
+ input_report_key (mydata -> input , BTN_BACK , 1 );
1069
+ break ;
1070
+ case 0x00 :
1071
+ input_report_key (mydata -> input , BTN_BACK , 0 );
1072
+ input_report_key (mydata -> input , BTN_FORWARD , 0 );
1073
+ input_report_key (mydata -> input , BTN_MIDDLE , 0 );
1074
+ break ;
1075
+ default :
1076
+ hid_err (hdev , "error in report\n" );
1077
+ return 0 ;
1078
+ }
1079
+ input_sync (mydata -> input );
1080
+
1081
+ } else if (data [0 ] == 0x02 ) {
1082
+ /*
1083
+ * Logitech M560 mouse report
1084
+ *
1085
+ * data[0] = type (0x02)
1086
+ * data[1..2] = buttons
1087
+ * data[3..5] = xy
1088
+ * data[6] = wheel
1089
+ */
1090
+
1091
+ int v ;
1092
+
1093
+ input_report_key (mydata -> input , BTN_LEFT ,
1094
+ !!(data [1 ] & M560_MOUSE_BTN_LEFT ));
1095
+ input_report_key (mydata -> input , BTN_RIGHT ,
1096
+ !!(data [1 ] & M560_MOUSE_BTN_RIGHT ));
1097
+
1098
+ if (data [1 ] & M560_MOUSE_BTN_WHEEL_LEFT )
1099
+ input_report_rel (mydata -> input , REL_HWHEEL , -1 );
1100
+ else if (data [1 ] & M560_MOUSE_BTN_WHEEL_RIGHT )
1101
+ input_report_rel (mydata -> input , REL_HWHEEL , 1 );
1102
+
1103
+ v = hid_snto32 (hid_field_extract (hdev , data + 3 , 0 , 12 ), 12 );
1104
+ input_report_rel (mydata -> input , REL_X , v );
1105
+
1106
+ v = hid_snto32 (hid_field_extract (hdev , data + 3 , 12 , 12 ), 12 );
1107
+ input_report_rel (mydata -> input , REL_Y , v );
1108
+
1109
+ v = hid_snto32 (data [6 ], 8 );
1110
+ input_report_rel (mydata -> input , REL_WHEEL , v );
1111
+
1112
+ input_sync (mydata -> input );
1113
+ }
1114
+
1115
+ return 1 ;
1116
+ }
1117
+
1118
+ static void m560_populate_input (struct hidpp_device * hidpp ,
1119
+ struct input_dev * input_dev , bool origin_is_hid_core )
1120
+ {
1121
+ struct m560_private_data * mydata = hidpp -> private_data ;
1122
+
1123
+ mydata -> input = input_dev ;
1124
+
1125
+ __set_bit (EV_KEY , mydata -> input -> evbit );
1126
+ __set_bit (BTN_MIDDLE , mydata -> input -> keybit );
1127
+ __set_bit (BTN_RIGHT , mydata -> input -> keybit );
1128
+ __set_bit (BTN_LEFT , mydata -> input -> keybit );
1129
+ __set_bit (BTN_BACK , mydata -> input -> keybit );
1130
+ __set_bit (BTN_FORWARD , mydata -> input -> keybit );
1131
+
1132
+ __set_bit (EV_REL , mydata -> input -> evbit );
1133
+ __set_bit (REL_X , mydata -> input -> relbit );
1134
+ __set_bit (REL_Y , mydata -> input -> relbit );
1135
+ __set_bit (REL_WHEEL , mydata -> input -> relbit );
1136
+ __set_bit (REL_HWHEEL , mydata -> input -> relbit );
1137
+ }
1138
+
1139
+ static int m560_input_mapping (struct hid_device * hdev , struct hid_input * hi ,
1140
+ struct hid_field * field , struct hid_usage * usage ,
1141
+ unsigned long * * bit , int * max )
1142
+ {
1143
+ return -1 ;
1144
+ }
1145
+
944
1146
/* -------------------------------------------------------------------------- */
945
1147
/* Generic HID++ devices */
946
1148
/* -------------------------------------------------------------------------- */
@@ -953,6 +1155,9 @@ static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
953
1155
954
1156
if (hidpp -> quirks & HIDPP_QUIRK_CLASS_WTP )
955
1157
return wtp_input_mapping (hdev , hi , field , usage , bit , max );
1158
+ else if (hidpp -> quirks & HIDPP_QUIRK_CLASS_M560 &&
1159
+ field -> application != HID_GD_MOUSE )
1160
+ return m560_input_mapping (hdev , hi , field , usage , bit , max );
956
1161
957
1162
return 0 ;
958
1163
}
@@ -962,6 +1167,8 @@ static void hidpp_populate_input(struct hidpp_device *hidpp,
962
1167
{
963
1168
if (hidpp -> quirks & HIDPP_QUIRK_CLASS_WTP )
964
1169
wtp_populate_input (hidpp , input , origin_is_hid_core );
1170
+ else if (hidpp -> quirks & HIDPP_QUIRK_CLASS_M560 )
1171
+ m560_populate_input (hidpp , input , origin_is_hid_core );
965
1172
}
966
1173
967
1174
static void hidpp_input_configured (struct hid_device * hdev ,
@@ -1049,6 +1256,8 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
1049
1256
1050
1257
if (hidpp -> quirks & HIDPP_QUIRK_CLASS_WTP )
1051
1258
return wtp_raw_event (hdev , data , size );
1259
+ else if (hidpp -> quirks & HIDPP_QUIRK_CLASS_M560 )
1260
+ return m560_raw_event (hdev , data , size );
1052
1261
1053
1262
return 0 ;
1054
1263
}
@@ -1126,6 +1335,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
1126
1335
ret = wtp_connect (hdev , connected );
1127
1336
if (ret )
1128
1337
return ;
1338
+ } else if (hidpp -> quirks & HIDPP_QUIRK_CLASS_M560 ) {
1339
+ ret = m560_send_config_command (hdev , connected );
1340
+ if (ret )
1341
+ return ;
1129
1342
}
1130
1343
1131
1344
if (!connected || hidpp -> delayed_input )
@@ -1201,7 +1414,11 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
1201
1414
if (hidpp -> quirks & HIDPP_QUIRK_CLASS_WTP ) {
1202
1415
ret = wtp_allocate (hdev , id );
1203
1416
if (ret )
1204
- goto wtp_allocate_fail ;
1417
+ goto allocate_fail ;
1418
+ } else if (hidpp -> quirks & HIDPP_QUIRK_CLASS_M560 ) {
1419
+ ret = m560_allocate (hdev );
1420
+ if (ret )
1421
+ goto allocate_fail ;
1205
1422
}
1206
1423
1207
1424
INIT_WORK (& hidpp -> work , delayed_work_cb );
@@ -1268,7 +1485,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
1268
1485
hid_parse_fail :
1269
1486
cancel_work_sync (& hidpp -> work );
1270
1487
mutex_destroy (& hidpp -> send_mutex );
1271
- wtp_allocate_fail :
1488
+ allocate_fail :
1272
1489
hid_set_drvdata (hdev , NULL );
1273
1490
return ret ;
1274
1491
}
@@ -1301,6 +1518,10 @@ static const struct hid_device_id hidpp_devices[] = {
1301
1518
USB_VENDOR_ID_LOGITECH , 0x4102 ),
1302
1519
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_MULTI_INPUT |
1303
1520
HIDPP_QUIRK_CLASS_WTP },
1521
+ { /* Mouse logitech M560 */
1522
+ HID_DEVICE (BUS_USB , HID_GROUP_LOGITECH_DJ_DEVICE ,
1523
+ USB_VENDOR_ID_LOGITECH , 0x402d ),
1524
+ .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
1304
1525
1305
1526
{ HID_DEVICE (BUS_USB , HID_GROUP_LOGITECH_DJ_DEVICE ,
1306
1527
USB_VENDOR_ID_LOGITECH , HID_ANY_ID )},
0 commit comments