@@ -33,6 +33,11 @@ module_param(disable_raw_mode, bool, 0644);
33
33
MODULE_PARM_DESC (disable_raw_mode ,
34
34
"Disable Raw mode reporting for touchpads and keep firmware gestures." );
35
35
36
+ static bool disable_tap_to_click ;
37
+ module_param (disable_tap_to_click , bool , 0644 );
38
+ MODULE_PARM_DESC (disable_tap_to_click ,
39
+ "Disable Tap-To-Click mode reporting for touchpads (only on the K400 currently)." );
40
+
36
41
#define REPORT_ID_HIDPP_SHORT 0x10
37
42
#define REPORT_ID_HIDPP_LONG 0x11
38
43
@@ -41,6 +46,7 @@ MODULE_PARM_DESC(disable_raw_mode,
41
46
42
47
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
43
48
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
49
+ #define HIDPP_QUIRK_CLASS_K400 BIT(2)
44
50
45
51
/* bits 2..20 are reserved for classes */
46
52
#define HIDPP_QUIRK_CONNECT_EVENTS BIT(21)
@@ -556,6 +562,52 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp)
556
562
return name ;
557
563
}
558
564
565
+ /* -------------------------------------------------------------------------- */
566
+ /* 0x6010: Touchpad FW items */
567
+ /* -------------------------------------------------------------------------- */
568
+
569
+ #define HIDPP_PAGE_TOUCHPAD_FW_ITEMS 0x6010
570
+
571
+ #define CMD_TOUCHPAD_FW_ITEMS_SET 0x10
572
+
573
+ struct hidpp_touchpad_fw_items {
574
+ uint8_t presence ;
575
+ uint8_t desired_state ;
576
+ uint8_t state ;
577
+ uint8_t persistent ;
578
+ };
579
+
580
+ /**
581
+ * send a set state command to the device by reading the current items->state
582
+ * field. items is then filled with the current state.
583
+ */
584
+ static int hidpp_touchpad_fw_items_set (struct hidpp_device * hidpp ,
585
+ u8 feature_index ,
586
+ struct hidpp_touchpad_fw_items * items )
587
+ {
588
+ struct hidpp_report response ;
589
+ int ret ;
590
+ u8 * params = (u8 * )response .fap .params ;
591
+
592
+ ret = hidpp_send_fap_command_sync (hidpp , feature_index ,
593
+ CMD_TOUCHPAD_FW_ITEMS_SET , & items -> state , 1 , & response );
594
+
595
+ if (ret > 0 ) {
596
+ hid_err (hidpp -> hid_dev , "%s: received protocol error 0x%02x\n" ,
597
+ __func__ , ret );
598
+ return - EPROTO ;
599
+ }
600
+ if (ret )
601
+ return ret ;
602
+
603
+ items -> presence = params [0 ];
604
+ items -> desired_state = params [1 ];
605
+ items -> state = params [2 ];
606
+ items -> persistent = params [3 ];
607
+
608
+ return 0 ;
609
+ }
610
+
559
611
/* -------------------------------------------------------------------------- */
560
612
/* 0x6100: TouchPadRawXY */
561
613
/* -------------------------------------------------------------------------- */
@@ -1136,6 +1188,75 @@ static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi,
1136
1188
return -1 ;
1137
1189
}
1138
1190
1191
+ /* ------------------------------------------------------------------------- */
1192
+ /* Logitech K400 devices */
1193
+ /* ------------------------------------------------------------------------- */
1194
+
1195
+ /*
1196
+ * The Logitech K400 keyboard has an embedded touchpad which is seen
1197
+ * as a mouse from the OS point of view. There is a hardware shortcut to disable
1198
+ * tap-to-click but the setting is not remembered accross reset, annoying some
1199
+ * users.
1200
+ *
1201
+ * We can toggle this feature from the host by using the feature 0x6010:
1202
+ * Touchpad FW items
1203
+ */
1204
+
1205
+ struct k400_private_data {
1206
+ u8 feature_index ;
1207
+ };
1208
+
1209
+ static int k400_disable_tap_to_click (struct hidpp_device * hidpp )
1210
+ {
1211
+ struct k400_private_data * k400 = hidpp -> private_data ;
1212
+ struct hidpp_touchpad_fw_items items = {};
1213
+ int ret ;
1214
+ u8 feature_type ;
1215
+
1216
+ if (!k400 -> feature_index ) {
1217
+ ret = hidpp_root_get_feature (hidpp ,
1218
+ HIDPP_PAGE_TOUCHPAD_FW_ITEMS ,
1219
+ & k400 -> feature_index , & feature_type );
1220
+ if (ret )
1221
+ /* means that the device is not powered up */
1222
+ return ret ;
1223
+ }
1224
+
1225
+ ret = hidpp_touchpad_fw_items_set (hidpp , k400 -> feature_index , & items );
1226
+ if (ret )
1227
+ return ret ;
1228
+
1229
+ return 0 ;
1230
+ }
1231
+
1232
+ static int k400_allocate (struct hid_device * hdev )
1233
+ {
1234
+ struct hidpp_device * hidpp = hid_get_drvdata (hdev );
1235
+ struct k400_private_data * k400 ;
1236
+
1237
+ k400 = devm_kzalloc (& hdev -> dev , sizeof (struct k400_private_data ),
1238
+ GFP_KERNEL );
1239
+ if (!k400 )
1240
+ return - ENOMEM ;
1241
+
1242
+ hidpp -> private_data = k400 ;
1243
+
1244
+ return 0 ;
1245
+ };
1246
+
1247
+ static int k400_connect (struct hid_device * hdev , bool connected )
1248
+ {
1249
+ struct hidpp_device * hidpp = hid_get_drvdata (hdev );
1250
+
1251
+ if (!connected )
1252
+ return 0 ;
1253
+
1254
+ if (!disable_tap_to_click )
1255
+ return 0 ;
1256
+
1257
+ return k400_disable_tap_to_click (hidpp );
1258
+ }
1259
+
1139
1260
/* -------------------------------------------------------------------------- */
1140
1261
/* Generic HID++ devices */
1141
1262
/* -------------------------------------------------------------------------- */
@@ -1332,6 +1453,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
1332
1453
ret = m560_send_config_command (hdev , connected );
1333
1454
if (ret )
1334
1455
return ;
1456
+ } else if (hidpp -> quirks & HIDPP_QUIRK_CLASS_K400 ) {
1457
+ ret = k400_connect (hdev , connected );
1458
+ if (ret )
1459
+ return ;
1335
1460
}
1336
1461
1337
1462
if (!connected || hidpp -> delayed_input )
@@ -1416,6 +1541,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
1416
1541
ret = m560_allocate (hdev );
1417
1542
if (ret )
1418
1543
goto allocate_fail ;
1544
+ } else if (hidpp -> quirks & HIDPP_QUIRK_CLASS_K400 ) {
1545
+ ret = k400_allocate (hdev );
1546
+ if (ret )
1547
+ goto allocate_fail ;
1419
1548
}
1420
1549
1421
1550
INIT_WORK (& hidpp -> work , delayed_work_cb );
@@ -1510,6 +1639,10 @@ static const struct hid_device_id hidpp_devices[] = {
1510
1639
HID_DEVICE (BUS_USB , HID_GROUP_LOGITECH_DJ_DEVICE ,
1511
1640
USB_VENDOR_ID_LOGITECH , 0x402d ),
1512
1641
.driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 },
1642
+ { /* Keyboard logitech K400 */
1643
+ HID_DEVICE (BUS_USB , HID_GROUP_LOGITECH_DJ_DEVICE ,
1644
+ USB_VENDOR_ID_LOGITECH , 0x4024 ),
1645
+ .driver_data = HIDPP_QUIRK_CONNECT_EVENTS | HIDPP_QUIRK_CLASS_K400 },
1513
1646
1514
1647
{ HID_DEVICE (BUS_USB , HID_GROUP_LOGITECH_DJ_DEVICE ,
1515
1648
USB_VENDOR_ID_LOGITECH , HID_ANY_ID )},
0 commit comments