aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/hid-logitech-hidpp.c133
1 files changed, 133 insertions, 0 deletions
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 81d1bc0feebb..452e5d5d6be7 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -33,6 +33,11 @@ module_param(disable_raw_mode, bool, 0644);
33MODULE_PARM_DESC(disable_raw_mode, 33MODULE_PARM_DESC(disable_raw_mode,
34 "Disable Raw mode reporting for touchpads and keep firmware gestures."); 34 "Disable Raw mode reporting for touchpads and keep firmware gestures.");
35 35
36static bool disable_tap_to_click;
37module_param(disable_tap_to_click, bool, 0644);
38MODULE_PARM_DESC(disable_tap_to_click,
39 "Disable Tap-To-Click mode reporting for touchpads (only on the K400 currently).");
40
36#define REPORT_ID_HIDPP_SHORT 0x10 41#define REPORT_ID_HIDPP_SHORT 0x10
37#define REPORT_ID_HIDPP_LONG 0x11 42#define REPORT_ID_HIDPP_LONG 0x11
38 43
@@ -41,6 +46,7 @@ MODULE_PARM_DESC(disable_raw_mode,
41 46
42#define HIDPP_QUIRK_CLASS_WTP BIT(0) 47#define HIDPP_QUIRK_CLASS_WTP BIT(0)
43#define HIDPP_QUIRK_CLASS_M560 BIT(1) 48#define HIDPP_QUIRK_CLASS_M560 BIT(1)
49#define HIDPP_QUIRK_CLASS_K400 BIT(2)
44 50
45/* bits 2..20 are reserved for classes */ 51/* bits 2..20 are reserved for classes */
46#define HIDPP_QUIRK_CONNECT_EVENTS BIT(21) 52#define HIDPP_QUIRK_CONNECT_EVENTS BIT(21)
@@ -557,6 +563,52 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp)
557} 563}
558 564
559/* -------------------------------------------------------------------------- */ 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
573struct 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 */
584static 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
611/* -------------------------------------------------------------------------- */
560/* 0x6100: TouchPadRawXY */ 612/* 0x6100: TouchPadRawXY */
561/* -------------------------------------------------------------------------- */ 613/* -------------------------------------------------------------------------- */
562 614
@@ -1136,6 +1188,75 @@ static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi,
1136 return -1; 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
1205struct k400_private_data {
1206 u8 feature_index;
1207};
1208
1209static 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
1232static 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
1247static 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/* Generic HID++ devices */ 1261/* Generic HID++ devices */
1141/* -------------------------------------------------------------------------- */ 1262/* -------------------------------------------------------------------------- */
@@ -1332,6 +1453,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
1332 ret = m560_send_config_command(hdev, connected); 1453 ret = m560_send_config_command(hdev, connected);
1333 if (ret) 1454 if (ret)
1334 return; 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 if (!connected || hidpp->delayed_input) 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 ret = m560_allocate(hdev); 1541 ret = m560_allocate(hdev);
1417 if (ret) 1542 if (ret)
1418 goto allocate_fail; 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 INIT_WORK(&hidpp->work, delayed_work_cb); 1550 INIT_WORK(&hidpp->work, delayed_work_cb);
@@ -1510,6 +1639,10 @@ static const struct hid_device_id hidpp_devices[] = {
1510 HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, 1639 HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
1511 USB_VENDOR_ID_LOGITECH, 0x402d), 1640 USB_VENDOR_ID_LOGITECH, 0x402d),
1512 .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, 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 { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, 1647 { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
1515 USB_VENDOR_ID_LOGITECH, HID_ANY_ID)}, 1648 USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},