diff options
Diffstat (limited to 'drivers/hid/hid-lenovo.c')
-rw-r--r-- | drivers/hid/hid-lenovo.c | 59 |
1 files changed, 56 insertions, 3 deletions
diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 4f59bffd0205..e4bc6cb6d7fa 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -37,6 +37,7 @@ struct lenovo_drvdata_tpkbd { }; struct lenovo_drvdata_cptkbd { + u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */ bool fn_lock; int sensitivity; }; @@ -146,10 +147,10 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev, switch (usage->hid & HID_USAGE) { case 0x0000: - hid_map_usage(hi, usage, bit, max, EV_REL, 0x06); + hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL); return 1; case 0x0001: - hid_map_usage(hi, usage, bit, max, EV_REL, 0x08); + hid_map_usage(hi, usage, bit, max, EV_REL, REL_WHEEL); return 1; default: return -1; @@ -207,9 +208,12 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev) struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock); - ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity); if (ret) hid_err(hdev, "Fn-lock setting failed: %d\n", ret); + + ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity); + if (ret) + hid_err(hdev, "Sensitivity setting failed: %d\n", ret); } static ssize_t attr_fn_lock_show_cptkbd(struct device *dev, @@ -313,6 +317,53 @@ static int lenovo_raw_event(struct hid_device *hdev, return 0; } +static int lenovo_event_cptkbd(struct hid_device *hdev, + struct hid_field *field, struct hid_usage *usage, __s32 value) +{ + struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + + /* "wheel" scroll events */ + if (usage->type == EV_REL && (usage->code == REL_WHEEL || + usage->code == REL_HWHEEL)) { + /* Scroll events disable middle-click event */ + cptkbd_data->middlebutton_state = 2; + return 0; + } + + /* Middle click events */ + if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) { + if (value == 1) { + cptkbd_data->middlebutton_state = 1; + } else if (value == 0) { + if (cptkbd_data->middlebutton_state == 1) { + /* No scrolling inbetween, send middle-click */ + input_event(field->hidinput->input, + EV_KEY, BTN_MIDDLE, 1); + input_sync(field->hidinput->input); + input_event(field->hidinput->input, + EV_KEY, BTN_MIDDLE, 0); + input_sync(field->hidinput->input); + } + cptkbd_data->middlebutton_state = 0; + } + return 1; + } + + return 0; +} + +static int lenovo_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + switch (hdev->product) { + case USB_DEVICE_ID_LENOVO_CUSBKBD: + case USB_DEVICE_ID_LENOVO_CBTKBD: + return lenovo_event_cptkbd(hdev, field, usage, value); + default: + return 0; + } +} + static int lenovo_features_set_tpkbd(struct hid_device *hdev) { struct hid_report *report; @@ -705,6 +756,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) hid_warn(hdev, "Failed to switch middle button: %d\n", ret); /* Set keyboard settings to known state */ + cptkbd_data->middlebutton_state = 0; cptkbd_data->fn_lock = true; cptkbd_data->sensitivity = 0x05; lenovo_features_set_cptkbd(hdev); @@ -832,6 +884,7 @@ static struct hid_driver lenovo_driver = { .probe = lenovo_probe, .remove = lenovo_remove, .raw_event = lenovo_raw_event, + .event = lenovo_event, .report_fixup = lenovo_report_fixup, }; module_hid_driver(lenovo_driver); |