From e529fea919872c6568bbda7873c64ac5d807ee83 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Wed, 17 Dec 2014 00:23:51 +0100 Subject: HID: logitech-hidpp: separate HID++ from WTP processing Previously wtp_raw_event would be called through hidpp_raw_hidpp_event (for the touchpad report) and hidpp_raw_event (for the mouse report). This patch removes one calling surface, making a clearer distinction between "generic HID++ processing" (matching internal reports) and device-specific event processing. Suggested-by: Benjamin Tissoires Signed-off-by: Peter Wu Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 2f420c0..6a5fe97 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -924,7 +924,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, /* * If the mutex is locked then we have a pending answer from a - * previoulsly sent command + * previously sent command. */ if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { /* @@ -955,9 +955,6 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, return 1; } - if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) - return wtp_raw_event(hidpp->hid_dev, data, size); - return 0; } @@ -965,7 +962,9 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { struct hidpp_device *hidpp = hid_get_drvdata(hdev); + int ret = 0; + /* Generic HID++ processing. */ switch (data[0]) { case REPORT_ID_HIDPP_LONG: if (size != HIDPP_REPORT_LONG_LENGTH) { @@ -973,16 +972,23 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, size); return 1; } - return hidpp_raw_hidpp_event(hidpp, data, size); + ret = hidpp_raw_hidpp_event(hidpp, data, size); + break; case REPORT_ID_HIDPP_SHORT: if (size != HIDPP_REPORT_SHORT_LENGTH) { hid_err(hdev, "received hid++ report of bad size (%d)", size); return 1; } - return hidpp_raw_hidpp_event(hidpp, data, size); + ret = hidpp_raw_hidpp_event(hidpp, data, size); + break; } + /* If no report is available for further processing, skip calling + * raw_event of subclasses. */ + if (ret != 0) + return ret; + if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) return wtp_raw_event(hdev, data, size); -- cgit v0.10.2 From e3cb0acd23258cf5e1a7ea270c98805eff01dcc5 Mon Sep 17 00:00:00 2001 From: Jamie Lentin Date: Tue, 16 Dec 2014 21:26:45 +0000 Subject: HID: lenovo: Add sensitivity control to compact keyboards The trackpoint sensitivity can also be controlled, expose this via sysfs. Signed-off-by: Jamie Lentin Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 4c55f4d..0f35a76 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -38,6 +38,7 @@ struct lenovo_drvdata_tpkbd { struct lenovo_drvdata_cptkbd { bool fn_lock; + int sensitivity; }; #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) @@ -145,6 +146,7 @@ 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); } @@ -179,13 +181,50 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev, return count; } +static ssize_t attr_sensitivity_show_cptkbd(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + + return snprintf(buf, PAGE_SIZE, "%u\n", + cptkbd_data->sensitivity); +} + +static ssize_t attr_sensitivity_store_cptkbd(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev); + int value; + + if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) + return -EINVAL; + + cptkbd_data->sensitivity = value; + lenovo_features_set_cptkbd(hdev); + + return count; +} + + static struct device_attribute dev_attr_fn_lock_cptkbd = __ATTR(fn_lock, S_IWUSR | S_IRUGO, attr_fn_lock_show_cptkbd, attr_fn_lock_store_cptkbd); +static struct device_attribute dev_attr_sensitivity_cptkbd = + __ATTR(sensitivity, S_IWUSR | S_IRUGO, + attr_sensitivity_show_cptkbd, + attr_sensitivity_store_cptkbd); + + static struct attribute *lenovo_attributes_cptkbd[] = { &dev_attr_fn_lock_cptkbd.attr, + &dev_attr_sensitivity_cptkbd.attr, NULL }; @@ -594,8 +633,9 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) if (ret) hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret); - /* Turn Fn-Lock on by default */ + /* Set keyboard settings to known state */ cptkbd_data->fn_lock = true; + cptkbd_data->sensitivity = 0x05; lenovo_features_set_cptkbd(hdev); ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd); -- cgit v0.10.2 From 94eefa27132358434735060c6bbdf61c669bb0ab Mon Sep 17 00:00:00 2001 From: Jamie Lentin Date: Tue, 16 Dec 2014 21:26:46 +0000 Subject: HID: lenovo: Use native middle-button mode for compact keyboards By default the middle button is in a compatibility mode, and generates standard wheel events when dragging with the middle trackpoint button. Unfortunately this is buggy: * The middle button comes up before starting wheel events, causing a middle click on whatever the mouse cursor was sitting on * The USB keyboard always generates the "native" horizontal wheel event, regardless of mode. Instead, enable the "native" mode the Windows driver uses, and add support for the custom events this generates. This fixes the USB keyboard wheel events, and the middle-click up event comes after the wheel events. Signed-off-by: Jamie Lentin Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 0f35a76..c4c3f09 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -92,6 +92,38 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev, case 0x00fa: /* Fn-Esc: Fn-lock toggle */ map_key_clear(KEY_FN_ESC); return 1; + case 0x00fb: /* Middle mouse button (in native mode) */ + map_key_clear(BTN_MIDDLE); + return 1; + } + } + + /* Compatibility middle/wheel mappings should be ignored */ + if (usage->hid == HID_GD_WHEEL) + return -1; + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON && + (usage->hid & HID_USAGE) == 0x003) + return -1; + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER && + (usage->hid & HID_USAGE) == 0x238) + return -1; + + /* Map wheel emulation reports: 0xffa1 = USB, 0xff10 = BT */ + if ((usage->hid & HID_USAGE_PAGE) == 0xff100000 || + (usage->hid & HID_USAGE_PAGE) == 0xffa10000) { + field->flags |= HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_VARIABLE; + field->logical_minimum = -127; + field->logical_maximum = 127; + + switch (usage->hid & HID_USAGE) { + case 0x0000: + hid_map_usage(hi, usage, bit, max, EV_REL, 0x06); + return 1; + case 0x0001: + hid_map_usage(hi, usage, bit, max, EV_REL, 0x08); + return 1; + default: + return -1; } } @@ -633,6 +665,11 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev) if (ret) hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret); + /* Switch middle button to native mode */ + ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01); + if (ret) + hid_warn(hdev, "Failed to switch middle button: %d\n", ret); + /* Set keyboard settings to known state */ cptkbd_data->fn_lock = true; cptkbd_data->sensitivity = 0x05; -- cgit v0.10.2 From bf159447537ed234afb569f91f5fd8c54ffa4c36 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 16 Dec 2014 17:06:01 -0500 Subject: HID: logitech-hidpp: bail out if wtp_connect fails If wtp_connect() fails, that means most of the time that the device has been disconnected. Subsequent attempts to contact the device will fail too, so it's simpler to bail out earlier. Signed-off-by: Benjamin Tissoires Reviewed-by: Peter Wu Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 6a5fe97..e1f3aca 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -862,24 +862,24 @@ static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id) return 0; }; -static void wtp_connect(struct hid_device *hdev, bool connected) +static int wtp_connect(struct hid_device *hdev, bool connected) { struct hidpp_device *hidpp = hid_get_drvdata(hdev); struct wtp_data *wd = hidpp->private_data; int ret; if (!connected) - return; + return 0; if (!wd->x_size) { ret = wtp_get_config(hidpp); if (ret) { hid_err(hdev, "Can not get wtp config: %d\n", ret); - return; + return ret; } } - hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index, + return hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index, true, true); } @@ -1063,8 +1063,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) struct input_dev *input; char *name, *devm_name; - if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) - wtp_connect(hdev, connected); + if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) { + ret = wtp_connect(hdev, connected); + if (ret) + return; + } if (!connected || hidpp->delayed_input) return; -- cgit v0.10.2 From e39f2d5956999c05c85814787a113ffadbcd4b26 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Fri, 12 Dec 2014 10:17:26 -0800 Subject: HID: rmi: Scan the report descriptor to determine if the device is suitable for the hid-rmi driver On composite HID devices there may be multiple HID devices on separate interfaces, but hid-rmi should only bind to the touchpad. The previous version simply checked that the interface protocol was set to mouse. Unfortuately, it is not always the case that the touchpad has the mouse interface protocol set. This patch takes a different approach and scans the report descriptor looking for the Generic Desktop Pointer usage and the Vendor Specific Top Level Collection needed by the hid-rmi driver to interface with the device. Signed-off-by: Andrew Duggan Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c3d0ac1..81665b4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -698,6 +698,7 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage) static void hid_scan_collection(struct hid_parser *parser, unsigned type) { struct hid_device *hid = parser->device; + int i; if (((parser->global.usage_page << 16) == HID_UP_SENSOR) && type == HID_COLLECTION_PHYSICAL) @@ -707,6 +708,14 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; + + if ((parser->global.usage_page << 16) == HID_UP_GENDESK) + for (i = 0; i < parser->local.usage_index; i++) + if (parser->local.usage[i] == HID_GD_POINTER) + parser->scan_flags |= HID_SCAN_FLAG_GD_POINTER; + + if ((parser->global.usage_page << 16) >= HID_UP_MSVENDOR) + parser->scan_flags |= HID_SCAN_FLAG_VENDOR_SPECIFIC; } static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) @@ -792,11 +801,14 @@ static int hid_scan_report(struct hid_device *hid) hid->group = HID_GROUP_WACOM; break; case USB_VENDOR_ID_SYNAPTICS: - if ((hid->group == HID_GROUP_GENERIC) && - (hid->bus != BUS_USB || hid->type == HID_TYPE_USBMOUSE)) - /* hid-rmi should only bind to the mouse interface of - * composite USB devices */ - hid->group = HID_GROUP_RMI; + if (hid->group == HID_GROUP_GENERIC) + if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC) + && (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER)) + /* + * hid-rmi should take care of them, + * not hid-generic + */ + hid->group = HID_GROUP_RMI; break; } diff --git a/include/linux/hid.h b/include/linux/hid.h index 06c4607..efc7787 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -574,7 +574,9 @@ static inline void hid_set_drvdata(struct hid_device *hdev, void *data) #define HID_GLOBAL_STACK_SIZE 4 #define HID_COLLECTION_STACK_SIZE 4 -#define HID_SCAN_FLAG_MT_WIN_8 0x00000001 +#define HID_SCAN_FLAG_MT_WIN_8 BIT(0) +#define HID_SCAN_FLAG_VENDOR_SPECIFIC BIT(1) +#define HID_SCAN_FLAG_GD_POINTER BIT(2) struct hid_parser { struct hid_global global; -- cgit v0.10.2 From b1ac9487c824a212f3b5bb80df5ac578243b0e21 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 11 Dec 2014 17:39:59 -0500 Subject: HID: logitech-hidpp: prefix the name with "Logitech" Current names are reported as "K750", "M705", and it can be misleading for the users when they look at their input device list. Prefixing the names with "Logitech " makes things better. Signed-off-by: Benjamin Tissoires Reviewed-by: Peter Wu Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index e1f3aca..7efbd8b 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -282,6 +282,33 @@ static inline bool hidpp_report_is_connect_event(struct hidpp_report *report) (report->rap.sub_id == 0x41); } +/** + * hidpp_prefix_name() prefixes the current given name with "Logitech ". + */ +static void hidpp_prefix_name(char **name, int name_length) +{ +#define PREFIX_LENGTH 9 /* "Logitech " */ + + int new_length; + char *new_name; + + if (name_length > PREFIX_LENGTH && + strncmp(*name, "Logitech ", PREFIX_LENGTH) == 0) + /* The prefix has is already in the name */ + return; + + new_length = PREFIX_LENGTH + name_length; + new_name = kzalloc(new_length, GFP_KERNEL); + if (!new_name) + return; + + snprintf(new_name, new_length, "Logitech %s", *name); + + kfree(*name); + + *name = new_name; +} + /* -------------------------------------------------------------------------- */ /* HIDP++ 1.0 commands */ /* -------------------------------------------------------------------------- */ @@ -321,6 +348,10 @@ static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev) return NULL; memcpy(name, &response.rap.params[2], len); + + /* include the terminating '\0' */ + hidpp_prefix_name(&name, len + 1); + return name; } @@ -498,6 +529,9 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp) index += ret; } + /* include the terminating '\0' */ + hidpp_prefix_name(&name, __name_length + 1); + return name; } -- cgit v0.10.2 From f677bb150c2f7b96ebcd377cd722e9d2649e9400 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Tue, 16 Dec 2014 01:50:14 +0100 Subject: HID: logitech-hidpp: detect HID++ 2.0 errors too Devices speaking HID++ 2.0 report a different error code (0xff). Detect these errors too to avoid 5 second delays when the device reports an error. Caught by... well, a bug in the QEMU emulation of this receiver. Renamed fap to rap for HID++ 1.0 errors because it is more logical, it has no functional difference. Signed-off-by: Peter Wu Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 7efbd8b..cf57955 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -105,6 +105,7 @@ struct hidpp_device { }; +/* HID++ 1.0 error codes */ #define HIDPP_ERROR 0x8f #define HIDPP_ERROR_SUCCESS 0x00 #define HIDPP_ERROR_INVALID_SUBID 0x01 @@ -119,6 +120,8 @@ struct hidpp_device { #define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a #define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b #define HIDPP_ERROR_WRONG_PIN_CODE 0x0c +/* HID++ 2.0 error codes */ +#define HIDPP20_ERROR 0xff static void hidpp_connect_event(struct hidpp_device *hidpp_dev); @@ -192,9 +195,16 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp, } if (response->report_id == REPORT_ID_HIDPP_SHORT && - response->fap.feature_index == HIDPP_ERROR) { + response->rap.sub_id == HIDPP_ERROR) { + ret = response->rap.params[1]; + dbg_hid("%s:got hidpp error %02X\n", __func__, ret); + goto exit; + } + + if (response->report_id == REPORT_ID_HIDPP_LONG && + response->fap.feature_index == HIDPP20_ERROR) { ret = response->fap.params[1]; - dbg_hid("__hidpp_send_report got hidpp error %02X\n", ret); + dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); goto exit; } @@ -271,7 +281,8 @@ static inline bool hidpp_match_answer(struct hidpp_report *question, static inline bool hidpp_match_error(struct hidpp_report *question, struct hidpp_report *answer) { - return (answer->fap.feature_index == HIDPP_ERROR) && + return ((answer->rap.sub_id == HIDPP_ERROR) || + (answer->fap.feature_index == HIDPP20_ERROR)) && (answer->fap.funcindex_clientid == question->fap.feature_index) && (answer->fap.params[0] == question->fap.funcindex_clientid); } -- cgit v0.10.2 From 2f43de605e700f5aa5cad15e19f8ffe54b1d4c86 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Fri, 19 Dec 2014 14:45:41 -0800 Subject: HID: rmi: Support non rmi devices by passing events to hid-input Allowing hid-rmi to bind to non rmi devices allows us to support composite USB devices which contain several HID devices one of which is a HID touchpad. Since all of the devices have the same VID and PID we can add the device to the hid_have_special_driver list and have hid-rmi handle all of the devices. Then hid-rmi's probe can look for the rmi specific HID report IDs and decide if it should handle the device as a rmi device or simply report that the events needs additional processing. Signed-off-by: Andrew Duggan Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index b51200f..018f80f 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -33,6 +33,9 @@ #define RMI_READ_DATA_PENDING BIT(1) #define RMI_STARTED BIT(2) +/* device flags */ +#define RMI_DEVICE BIT(0) + enum rmi_mode_type { RMI_MODE_OFF = 0, RMI_MODE_ATTN_REPORTS = 1, @@ -118,6 +121,8 @@ struct rmi_data { struct work_struct reset_work; struct hid_device *hdev; + + unsigned long device_flags; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -452,9 +457,23 @@ static int rmi_raw_event(struct hid_device *hdev, return rmi_read_data_event(hdev, data, size); case RMI_ATTN_REPORT_ID: return rmi_input_event(hdev, data, size); - case RMI_MOUSE_REPORT_ID: + default: + return 1; + } + + return 0; +} + +static int rmi_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + + if ((data->device_flags & RMI_DEVICE) && + (field->application == HID_GD_POINTER || + field->application == HID_GD_MOUSE)) { rmi_schedule_reset(hdev); - break; + return 1; } return 0; @@ -856,6 +875,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) if (ret) return; + if (!(data->device_flags & RMI_DEVICE)) + return; + /* Allow incoming hid reports */ hid_device_io_start(hdev); @@ -914,8 +936,33 @@ static int rmi_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - /* we want to make HID ignore the advertised HID collection */ - return -1; + struct rmi_data *data = hid_get_drvdata(hdev); + + /* + * we want to make HID ignore the advertised HID collection + * for RMI deivces + */ + if (data->device_flags & RMI_DEVICE) + return -1; + + return 0; +} + +static int rmi_check_valid_report_id(struct hid_device *hdev, unsigned type, + unsigned id, struct hid_report **report) +{ + int i; + + *report = hdev->report_enum[type].report_id_hash[id]; + if (*report) { + for (i = 0; i < (*report)->maxfield; i++) { + unsigned app = (*report)->field[i]->application; + if ((app & HID_USAGE_PAGE) >= HID_UP_MSVENDOR) + return 1; + } + } + + return 0; } static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -925,6 +972,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) size_t alloc_size; struct hid_report *input_report; struct hid_report *output_report; + struct hid_report *feature_report; data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL); if (!data) @@ -943,27 +991,35 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } - input_report = hdev->report_enum[HID_INPUT_REPORT] - .report_id_hash[RMI_ATTN_REPORT_ID]; - if (!input_report) { - hid_err(hdev, "device does not have expected input report\n"); - ret = -ENODEV; - return ret; + /* + * Check for the RMI specific report ids. If they are misisng + * simply return and let the events be processed by hid-input + */ + if (!rmi_check_valid_report_id(hdev, HID_FEATURE_REPORT, + RMI_SET_RMI_MODE_REPORT_ID, &feature_report)) { + hid_dbg(hdev, "device does not have set mode feature report\n"); + goto start; + } + + if (!rmi_check_valid_report_id(hdev, HID_INPUT_REPORT, + RMI_ATTN_REPORT_ID, &input_report)) { + hid_dbg(hdev, "device does not have attention input report\n"); + goto start; } data->input_report_size = (input_report->size >> 3) + 1 /* report id */; - output_report = hdev->report_enum[HID_OUTPUT_REPORT] - .report_id_hash[RMI_WRITE_REPORT_ID]; - if (!output_report) { - hid_err(hdev, "device does not have expected output report\n"); - ret = -ENODEV; - return ret; + if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT, + RMI_WRITE_REPORT_ID, &output_report)) { + hid_dbg(hdev, + "device does not have rmi write output report\n"); + goto start; } data->output_report_size = (output_report->size >> 3) + 1 /* report id */; + data->device_flags |= RMI_DEVICE; alloc_size = data->output_report_size + data->input_report_size; data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); @@ -978,13 +1034,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) mutex_init(&data->page_mutex); +start: ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { hid_err(hdev, "hw start failed\n"); return ret; } - if (!test_bit(RMI_STARTED, &data->flags)) + if ((data->device_flags & RMI_DEVICE) && + !test_bit(RMI_STARTED, &data->flags)) /* * The device maybe in the bootloader if rmi_input_configured * failed to find F11 in the PDT. Print an error, but don't @@ -1017,6 +1075,7 @@ static struct hid_driver rmi_driver = { .id_table = rmi_id, .probe = rmi_probe, .remove = rmi_remove, + .event = rmi_event, .raw_event = rmi_raw_event, .input_mapping = rmi_input_mapping, .input_configured = rmi_input_configured, -- cgit v0.10.2 From fc38a8a66e1bda87da13e8eb549dd87ddd86f3b8 Mon Sep 17 00:00:00 2001 From: Huang Bo Date: Wed, 26 Nov 2014 18:21:03 +0800 Subject: HID: add BETOP game controller force feedback support Adds force feedback support for BETOP USB game controllers. These devices are mass produced in China. Signed-off-by: Huang Bo Signed-off-by: Jiri Kosina diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 230b6f8..c33d98e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -146,6 +146,16 @@ config HID_BELKIN ---help--- Support for Belkin Flip KVM and Wireless keyboard. +config HID_BETOP_FF + tristate "Betop Production Inc. force feedback support" + depends on USB_HID + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you want to enable force feedback support for devices by + BETOP Production Ltd. + Currently the following devices are known to be supported: + - BETOP 2185 PC & BFM MODE + config HID_CHERRY tristate "Cherry Cymotion keyboard" if EXPERT depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index debd15b..3a27d14 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o obj-$(CONFIG_HID_AUREAL) += hid-aureal.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o +obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CP2112) += hid-cp2112.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c3d0ac1..9b1442a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1757,6 +1757,10 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7460f34..ac20ba0 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -189,6 +189,11 @@ #define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 +#define USB_VENDOR_ID_BETOP_2185BFM 0x11c2 +#define USB_VENDOR_ID_BETOP_2185PC 0x11c0 +#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380 +#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc + #define USB_VENDOR_ID_BTC 0x046e #define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 #define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 -- cgit v0.10.2 From 52cd7785f3cdd2724f4efb5b21dbc75d6f9ccef4 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 22 Dec 2014 14:58:13 +0100 Subject: HID: betop: add drivers/hid/hid-betopff.c Commit fc38a8a66e ("HID: add BETOP game controller force feedback support") is missing the actual addition of drivers/hid/hid-betopff.c due to my mistake (I forgot to add the file after fixing conflicts). Fixes: fc38a8a66e1b ("HID: add BETOP game controller force feedback support") Reported-by: kbuild test robot Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-betopff.c b/drivers/hid/hid-betopff.c new file mode 100644 index 0000000..69cfc8d --- /dev/null +++ b/drivers/hid/hid-betopff.c @@ -0,0 +1,160 @@ +/* + * Force feedback support for Betop based devices + * + * The devices are distributed under various names and the same USB device ID + * can be used in both adapters and actual game controllers. + * + * 0x11c2:0x2208 "BTP2185 BFM mode Joystick" + * - tested with BTP2185 BFM Mode. + * + * 0x11C0:0x5506 "BTP2185 PC mode Joystick" + * - tested with BTP2185 PC Mode. + * + * 0x8380:0x1850 "BTP2185 V2 PC mode USB Gamepad" + * - tested with BTP2185 PC Mode with another version. + * + * 0x20bc:0x5500 "BTP2185 V2 BFM mode Joystick" + * - tested with BTP2171s. + * Copyright (c) 2014 Huang Bo + */ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + + +#include +#include +#include +#include + +#include "hid-ids.h" + +struct betopff_device { + struct hid_report *report; +}; + +static int hid_betopff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct betopff_device *betopff = data; + __u16 left, right; + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + + betopff->report->field[2]->value[0] = left / 256; + betopff->report->field[3]->value[0] = right / 256; + + hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT); + + return 0; +} + +static int betopff_init(struct hid_device *hid) +{ + struct betopff_device *betopff; + struct hid_report *report; + struct hid_input *hidinput = + list_first_entry(&hid->inputs, struct hid_input, list); + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + int field_count = 0; + int error; + int i, j; + + if (list_empty(report_list)) { + hid_err(hid, "no output reports found\n"); + return -ENODEV; + } + + report = list_first_entry(report_list, struct hid_report, list); + /* + * Actually there are 4 fields for 4 Bytes as below: + * ----------------------------------------- + * Byte0 Byte1 Byte2 Byte3 + * 0x00 0x00 left_motor right_motor + * ----------------------------------------- + * Do init them with default value. + */ + for (i = 0; i < report->maxfield; i++) { + for (j = 0; j < report->field[i]->report_count; j++) { + report->field[i]->value[j] = 0x00; + field_count++; + } + } + + if (field_count < 4) { + hid_err(hid, "not enough fields in the report: %d\n", + field_count); + return -ENODEV; + } + + betopff = kzalloc(sizeof(*betopff), GFP_KERNEL); + if (!betopff) + return -ENOMEM; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, betopff, hid_betopff_play); + if (error) { + kfree(betopff); + return error; + } + + betopff->report = report; + hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT); + + hid_info(hid, "Force feedback for betop devices by huangbo \n"); + + return 0; +} + +static int betop_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int ret; + + if (id->driver_data) + hdev->quirks |= HID_QUIRK_MULTI_INPUT; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + goto err; + } + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto err; + } + + betopff_init(hdev); + + return 0; +err: + return ret; +} + +static const struct hid_device_id betop_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) }, + { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) }, + { } +}; +MODULE_DEVICE_TABLE(hid, betop_devices); + +static struct hid_driver betop_driver = { + .name = "betop", + .id_table = betop_devices, + .probe = betop_probe, +}; +module_hid_driver(betop_driver); + +MODULE_LICENSE("GPL"); -- cgit v0.10.2 From d97a552210320d3bec8ee22b8ccdb1d6d189482a Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 5 Jan 2015 16:32:12 -0500 Subject: HID: wacom: use WACOM_*_FIELD macros in wacom_usage_mapping() We introduced nice macros in wacom_wac.c to check whether a field is a pen or a touch one. wacom_usage_mapping() still uses it's own tests, which are not in sync with the wacom_wac tests (.application is not checked). That means that some legitimate fields might be filtered out from the usage mapping, and thus will not be used properly while receiving the events. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 6542029..f01ab3a 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -173,10 +173,8 @@ static void wacom_usage_mapping(struct hid_device *hdev, { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_features *features = &wacom->wacom_wac.features; - bool finger = (field->logical == HID_DG_FINGER) || - (field->physical == HID_DG_FINGER); - bool pen = (field->logical == HID_DG_STYLUS) || - (field->physical == HID_DG_STYLUS); + bool finger = WACOM_FINGER_FIELD(field); + bool pen = WACOM_PEN_FIELD(field); /* * Requiring Stylus Usage will ignore boot mouse diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index ac7447c..596a6fb5 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -15,7 +15,6 @@ #include "wacom_wac.h" #include "wacom.h" #include -#include /* resolution for penabled devices */ #define WACOM_PL_RES 20 @@ -1514,13 +1513,6 @@ static void wacom_wac_finger_report(struct hid_device *hdev, wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(hdev); } -#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ - ((f)->physical == HID_DG_STYLUS) || \ - ((f)->application == HID_DG_PEN)) -#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ - ((f)->physical == HID_DG_FINGER) || \ - ((f)->application == HID_DG_TOUCHSCREEN)) - void wacom_wac_usage_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage) { diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index bfad815..7436f2b 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -10,6 +10,7 @@ #define WACOM_WAC_H #include +#include /* maximum packet length for USB devices */ #define WACOM_PKGLEN_MAX 68 @@ -71,6 +72,13 @@ #define WACOM_QUIRK_MONITOR 0x0008 #define WACOM_QUIRK_BATTERY 0x0010 +#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ + ((f)->physical == HID_DG_STYLUS) || \ + ((f)->application == HID_DG_PEN)) +#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ + ((f)->physical == HID_DG_FINGER) || \ + ((f)->application == HID_DG_TOUCHSCREEN)) + enum { PENPARTNER = 0, GRAPHIRE, -- cgit v0.10.2 From 61e9e7e40a93cfb4a70180beefbbb5bd0c860aeb Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 5 Jan 2015 16:32:13 -0500 Subject: HID: wacom: add support of the Pen of the Bamboo Pad Bamboo Pads are using the generic processing but their report descriptors differ from the ISDv* line. The pen fields are marked with the .physical as Digitizer_Pen, which makes also sense. Add this field to the checks and enable for free Bamboo Pads. Reported-by: Josep Sanchez Ferreres Signed-off-by: Benjamin Tissoires Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 7436f2b..7afd929 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -74,6 +74,7 @@ #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ ((f)->physical == HID_DG_STYLUS) || \ + ((f)->physical == HID_DG_PEN) || \ ((f)->application == HID_DG_PEN)) #define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ ((f)->physical == HID_DG_FINGER) || \ -- cgit v0.10.2 From 6ce901eb61aa30ba8565c62049ee80c90728ef14 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 29 Dec 2014 15:21:26 +0100 Subject: HID: input: fix confusion on conflicting mappings On an PC-101/103/104 keyboard (American layout) the 'Enter' key and its neighbours look like this: +---+ +---+ +-------+ | 1 | | 2 | | 5 | +---+ +---+ +-------+ +---+ +-----------+ | 3 | | 4 | +---+ +-----------+ On a PC-102/105 keyboard (European layout) it looks like this: +---+ +---+ +-------+ | 1 | | 2 | | | +---+ +---+ +-+ 4 | +---+ +---+ | | | 3 | | 5 | | | +---+ +---+ +-----+ (Note that the number of keys is the same, but key '5' is moved down and the shape of key '4' is changed. Keys '1' to '3' are exactly the same.) The keys 1-4 report the same scan-code in HID in both layouts, even though the keysym they produce is usually different depending on the XKB-keymap used by user-space. However, key '5' (US 'backslash'/'pipe') reports 0x31 for the upper layout and 0x32 for the lower layout, as defined by the HID spec. This is highly confusing as the linux-input API uses a single keycode for both. So far, this was never a problem as there never has been a keyboard with both of those keys present at the same time. It would have to look something like this: +---+ +---+ +-------+ | 1 | | 2 | | x31 | +---+ +---+ +-------+ +---+ +---+ +-----+ | 3 | |x32| | 4 | +---+ +---+ +-----+ HID can represent such a keyboard, but the linux-input API cannot. Furthermore, any user-space mapping would be confused by this and, luckily, no-one ever produced such hardware. Now, the HID input layer fixed this mess by mapping both 0x31 and 0x32 to the same keycode (KEY_BACKSLASH==0x2b). As only one of both physical keys is present on a hardware, this works just fine. Lets introduce hardware-vendors into this: ------------------------------------------ Unfortunately, it seems way to expensive to produce a different device for American and European layouts. Therefore, hardware-vendors put both keys, (0x31 and 0x32) on the same keyboard, but only one of them is hooked up to the physical button, the other one is 'dead'. This means, they can use the same hardware, with a different button-layout and automatically produce the correct HID events for American *and* European layouts. This is unproblematic for normal keyboards, as the 'dead' key will never report any KEY-DOWN events. But RollOver keyboards send the whole matrix on each key-event, allowing n-key roll-over mode. This means, we get a 0x31 and 0x32 event on each key-press. One of them will always be 0, the other reports the real state. As we map both to the same keycode, we will get spurious key-events, even though the real key-state never changed. The easiest way would be to blacklist 'dead' keys and never handle those. We could simply read the 'country' tag of USB devices and blacklist either key according to the layout. But... hardware vendors... want the same device for all countries and thus many of them set 'country' to 0 for all devices. Meh.. So we have to deal with this properly. As we cannot know which of the keys is 'dead', we either need a heuristic and track those keys, or we simply make use of our value-tracking for HID fields. We simply ignore HID events for absolute data if the data didn't change. As HID tracks events on the HID level, we haven't done the keycode translation, yet. Therefore, the 'dead' key is tracked independently of the real key, therefore, any events on it will be ignored. This patch simply discards any HID events for absolute data if it didn't change compared to the last report. We need to ignore relative and buffered-byte reports for obvious reasons. But those cannot be affected by this bug, so we're fine. Preferably, we'd do this filtering on the HID-core level. But this might break a lot of custom drivers, if they do not follow the HID specs. Therefore, we do this late in hid-input just before we inject it into the input layer (which does the exact same filtering, but on the keycode level). If this turns out to break some devices, we might have to limit filtering to EV_KEY events. But lets try to do the Right Thing first, and properly filter any absolute data that didn't change. This patch is tagged for 'stable' as it fixes a lot of n-key RollOver hardware. We might wanna wait with backporting for a while, before we know it doesn't break anything else, though. Cc: Reported-by: Adam Goode Reported-by: Fredrik Hallenberg Tested-by: Fredrik Hallenberg Signed-off-by: David Herrmann Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index e0a0f06..84b6899 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1101,6 +1101,22 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; } + /* + * Ignore reports for absolute data if the data didn't change. This is + * not only an optimization but also fixes 'dead' key reports. Some + * RollOver implementations for localized keys (like BACKSLASH/PIPE; HID + * 0x31 and 0x32) report multiple keys, even though a localized keyboard + * can only have one of them physically available. The 'dead' keys + * report constant 0. As all map to the same keycode, they'd confuse + * the input layer. If we filter the 'dead' keys on the HID level, we + * skip the keycode translation and only forward real events. + */ + if (!(field->flags & (HID_MAIN_ITEM_RELATIVE | + HID_MAIN_ITEM_BUFFERED_BYTE)) && + usage->usage_index < field->maxusage && + value == field->value[usage->usage_index]) + return; + /* report the usage code as scancode if the key status has changed */ if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) input_event(input, EV_MSC, MSC_SCAN, usage->hid); -- cgit v0.10.2 From 79bc33bd60ac3d5ab3bd1918fba95234ac9d510e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 6 Jan 2015 09:09:13 +0100 Subject: HID: fix Kconfig text Signed-off-by: Geert Uytterhoeven Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 230b6f8..303b295 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -388,7 +388,7 @@ config HID_LOGITECH_HIDPP Say Y if you want support for Logitech devices relying on the HID++ specification. Such devices are the various Logitech Touchpads (T650, T651, TK820), some mice (Zone Touch mouse), or even keyboards (Solar - Keayboard). + Keyboard). config LOGITECH_FF bool "Logitech force feedback support" -- cgit v0.10.2 From cbd366bea2b8513bc0fc1c9e8832cb0ab221d6d5 Mon Sep 17 00:00:00 2001 From: Ross Skaliotis Date: Sat, 20 Dec 2014 19:01:35 -0500 Subject: HID: apple: fix battery support for the 2009 ANSI wireless keyboard Enabled quirks necessary for correct battery capacity reporting. Cleaned up surrounding style. Signed-off-by: Ross Skaliotis Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index e0a0f06..146da43 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -306,10 +306,13 @@ static enum power_supply_property hidinput_battery_props[] = { static const struct hid_device_id hid_battery_quirks[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), - HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), + HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), -- cgit v0.10.2 From 8e7b341037db1835ee6eea64663013cbfcf33575 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 6 Jan 2015 22:34:19 +0100 Subject: HID: fixup the conflicting keyboard mappings quirk The ignore check that got added in 6ce901eb61 ("HID: input: fix confusion on conflicting mappings") needs to properly check for VARIABLE reports as well (ARRAY reports should be ignored), otherwise legitimate keyboards might break. Cc: Fixes: 6ce901eb61 ("HID: input: fix confusion on conflicting mappings") Reported-by: Fredrik Hallenberg Reported-by: David Herrmann Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 84b6899..a758900 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1113,6 +1113,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct */ if (!(field->flags & (HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_BUFFERED_BYTE)) && + (field->flags & HID_MAIN_ITEM_VARIABLE) && usage->usage_index < field->maxusage && value == field->value[usage->usage_index]) return; -- cgit v0.10.2 From 5e7e9e90b5867a3754159a8ce524299d930fbac8 Mon Sep 17 00:00:00 2001 From: Alan Wu Date: Tue, 6 Jan 2015 18:32:51 -0800 Subject: HID: microsoft: add support for Japanese Surface Type Cover 3 Based on code for the US Surface Type Cover 3 from commit be3b16341d5cd8cf2a64fcc7a604a8efe6599ff0 ("HID: add support for MS Surface Pro 3 Type Cover"): Signed-off-by: Alan Wu Tested-by: Karlis Dreizis Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c3d0ac1..0cea5a0 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -704,7 +704,8 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) hid->group = HID_GROUP_SENSOR_HUB; if (hid->vendor == USB_VENDOR_ID_MICROSOFT && - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 && + (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP) && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; } @@ -1860,6 +1861,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7460f34..95ee91b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -653,6 +653,7 @@ #define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 #define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc +#define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd #define USB_VENDOR_ID_MOJO 0x8282 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index cacda43..fbaea6e 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -276,6 +276,8 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_DUPLICATE_USAGES }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP), + .driver_data = MS_HIDINPUT }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), .driver_data = MS_PRESENTER }, diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index dc89be9..6591b5d 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -80,6 +80,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, -- cgit v0.10.2 From 005b3f574a0a53f476a62da5c861c1c9bf8177b7 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 8 Jan 2015 14:37:12 -0500 Subject: HID: logitech-hidpp: store the name of the device in struct hidpp If a disconnect occurs while getting the actual name of the device (which can take several HID transactions), the name of the device will be the hid name, provided by the Unifying Receiver. This means that in some cases, the user space will see a different name that what it usually sees when there is no disconnect. We should store the name of the device in the struct hidpp. That way, if a disconnect occurs while we are accessing the name, hidpp_connect_event() can fail, and the input node is not created. The input node will be created only if we have a connection which lasts long enough to retrieve all the requested information: name, protocol, and specific configuration. Reviewed-by: Peter Wu Tested-by: Peter Wu Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index cf57955..acb632d 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -89,6 +89,7 @@ struct hidpp_device { struct hid_device *hid_dev; struct mutex send_mutex; void *send_receive_buf; + char *name; /* will never be NULL and should not be freed */ wait_queue_head_t wait; bool answer_available; u8 protocol_major; @@ -1080,6 +1081,7 @@ static void hidpp_input_close(struct input_dev *dev) static struct input_dev *hidpp_allocate_input(struct hid_device *hdev) { struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev); + struct hidpp_device *hidpp = hid_get_drvdata(hdev); if (!input_dev) return NULL; @@ -1088,7 +1090,7 @@ static struct input_dev *hidpp_allocate_input(struct hid_device *hdev) input_dev->open = hidpp_input_open; input_dev->close = hidpp_input_close; - input_dev->name = hdev->name; + input_dev->name = hidpp->name; input_dev->phys = hdev->phys; input_dev->uniq = hdev->uniq; input_dev->id.bustype = hdev->bus; @@ -1130,22 +1132,28 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) hid_info(hdev, "HID++ %u.%u device connected.\n", hidpp->protocol_major, hidpp->protocol_minor); + if (!hidpp->name || hidpp->name == hdev->name) { + name = hidpp_get_device_name(hidpp); + if (!name) { + hid_err(hdev, + "unable to retrieve the name of the device"); + return; + } + + devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name); + kfree(name); + if (!devm_name) + return; + + hidpp->name = devm_name; + } + input = hidpp_allocate_input(hdev); if (!input) { hid_err(hdev, "cannot allocate new input device: %d\n", ret); return; } - name = hidpp_get_device_name(hidpp); - if (!name) { - hid_err(hdev, "unable to retrieve the name of the device"); - } else { - devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name); - if (devm_name) - input->name = devm_name; - kfree(name); - } - hidpp_populate_input(hidpp, input, false); ret = input_register_device(input); @@ -1168,6 +1176,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) return -ENOMEM; hidpp->hid_dev = hdev; + hidpp->name = hdev->name; hid_set_drvdata(hdev, hidpp); hidpp->quirks = id->driver_data; -- cgit v0.10.2 From b8aed6ea39a70a9b9b8de9df8655ac36719b4d3b Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Thu, 8 Jan 2015 14:51:36 -0800 Subject: HID: rmi: Use hid_report_len to compute the size of reports Now that hid_report_len is in hid.h we can use this function instead of duplicating the code which computes it. Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 018f80f..6270d2c 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -1007,7 +1007,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) goto start; } - data->input_report_size = (input_report->size >> 3) + 1 /* report id */; + data->input_report_size = hid_report_len(input_report); if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT, RMI_WRITE_REPORT_ID, &output_report)) { @@ -1016,8 +1016,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) goto start; } - data->output_report_size = (output_report->size >> 3) - + 1 /* report id */; + data->output_report_size = hid_report_len(output_report); data->device_flags |= RMI_DEVICE; alloc_size = data->output_report_size + data->input_report_size; -- cgit v0.10.2 From 79364d87af239e2029aeba3b82bd79c355b9bb86 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Thu, 8 Jan 2015 14:51:34 -0800 Subject: HID: rmi: Support touchpads with external buttons The external buttons on HID touchpads are connected as pass through devices and button events are not reported in the rmi registers. As a result on these devices we need to allow the HID generic desktop button events to be processed by hid-input. Unfortunately, there is no way to query the touchpad to determine that it has pass through buttons so the RMI_DEVICE_HAS_PHYS_BUTTONS should be set manually when adding the device to rmi_id[]. Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 6270d2c..4bf43c8 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -35,6 +35,7 @@ /* device flags */ #define RMI_DEVICE BIT(0) +#define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) enum rmi_mode_type { RMI_MODE_OFF = 0, @@ -472,6 +473,15 @@ static int rmi_event(struct hid_device *hdev, struct hid_field *field, if ((data->device_flags & RMI_DEVICE) && (field->application == HID_GD_POINTER || field->application == HID_GD_MOUSE)) { + if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) { + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) + return 0; + + if ((usage->hid == HID_GD_X || usage->hid == HID_GD_Y) + && !value) + return 1; + } + rmi_schedule_reset(hdev); return 1; } @@ -942,8 +952,13 @@ static int rmi_input_mapping(struct hid_device *hdev, * we want to make HID ignore the advertised HID collection * for RMI deivces */ - if (data->device_flags & RMI_DEVICE) + if (data->device_flags & RMI_DEVICE) { + if ((data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) && + ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)) + return 0; + return -1; + } return 0; } @@ -991,6 +1006,9 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } + if (id->driver_data) + data->device_flags = id->driver_data; + /* * Check for the RMI specific report ids. If they are misisng * simply return and let the events be processed by hid-input -- cgit v0.10.2 From e9287099ba6539bccb20cd791269186f3ae28b85 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Thu, 8 Jan 2015 14:51:35 -0800 Subject: HID: rmi: Add support for the touchpad in the Razer Blade 14 laptop Have hid-rmi handle all of the Razer Blade HID devices that are part of the composite USB device. This will allow hid-rmi to operate the touchpad in rmi mode while passing events from the other devices to hid-input. Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 81665b4..ef718f9 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1982,6 +1982,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) }, { } }; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7460f34..7d0912d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -767,6 +767,9 @@ #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008 +#define USB_VENDOR_ID_RAZER 0x1532 +#define USB_DEVICE_ID_RAZER_BLADE_14 0x011D + #define USB_VENDOR_ID_REALTEK 0x0bda #define USB_DEVICE_ID_REALTEK_READER 0x0152 diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 4bf43c8..49d4fe4 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -1082,6 +1082,8 @@ static void rmi_remove(struct hid_device *hdev) } static const struct hid_device_id rmi_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14), + .driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) }, { } }; -- cgit v0.10.2 From 373a5356dfb75ea7140f8d37cf26eb6a62910617 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Fri, 9 Jan 2015 11:04:50 -0800 Subject: HID: wacom: process invalid Cintiq and Intuos data in wacom_intuos_inout() Users may use unsupported tools on Cintiq or Intuos. When invalid tools or data are detected, they should be ignored. That is, no event from those tools should be reported. Consolidating that code in wacom_intuos_inout simplifies the logic and make it easier for future code change. Signed-off-by: Ping Cheng Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 596a6fb5..5276689 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -534,9 +534,24 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) return 1; } + /* + * don't report events for invalid data + */ /* older I4 styli don't work with new Cintiqs */ - if (!((wacom->id[idx] >> 20) & 0x01) && - (features->type == WACOM_21UX2)) + if ((!((wacom->id[idx] >> 20) & 0x01) && + (features->type == WACOM_21UX2)) || + /* Only large Intuos support Lense Cursor */ + (wacom->tool[idx] == BTN_TOOL_LENS && + (features->type == INTUOS3 || + features->type == INTUOS3S || + features->type == INTUOS4 || + features->type == INTUOS4S || + features->type == INTUOS5 || + features->type == INTUOS5S || + features->type == INTUOSPM || + features->type == INTUOSPS)) || + /* Cintiq doesn't send data when RDY bit isn't set */ + (features->type == CINTIQ && !(data[1] & 0x40))) return 1; /* Range Report */ @@ -553,6 +568,10 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) if (features->quirks & WACOM_QUIRK_MULTI_INPUT) wacom->shared->stylus_in_proximity = false; + /* don't report exit if we don't know the ID */ + if (!wacom->id[idx]) + return 1; + /* * Reset all states otherwise we lose the initial states * when in-prox next time @@ -585,6 +604,11 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) wacom->id[idx] = 0; return 2; } + + /* don't report other events if we don't know the ID */ + if (!wacom->id[idx]) + return 1; + return 0; } @@ -842,28 +866,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) if (result) return result - 1; - /* don't proceed if we don't know the ID */ - if (!wacom->id[idx]) - return 0; - - /* Only large Intuos support Lense Cursor */ - if (wacom->tool[idx] == BTN_TOOL_LENS && - (features->type == INTUOS3 || - features->type == INTUOS3S || - features->type == INTUOS4 || - features->type == INTUOS4S || - features->type == INTUOS5 || - features->type == INTUOS5S || - features->type == INTUOSPM || - features->type == INTUOSPS)) { - - return 0; - } - - /* Cintiq doesn't send data when RDY bit isn't set */ - if (features->type == CINTIQ && !(data[1] & 0x40)) - return 0; - if (features->type >= INTUOS3S) { input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1)); input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1)); -- cgit v0.10.2 From b3bd7ef397a6031f5398c76a9a0b0695a38f6587 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Fri, 9 Jan 2015 11:05:13 -0800 Subject: HID: wacom: peport In Range event according to the spec Some Cintiq and Intuos tablets report In Range event. This event is sent before valid data is reported when tool enters proximity; or before out of proximity event is reported when tool exits. While entering proximity, In Range means a pen is detected. This information can be used for palm/touch rejection on both pen and touch enabled devices. While exiting, it means the tool has reached its maximum detectable distance. Signed-off-by: Ping Cheng Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 5276689..a4ba8ca 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -443,9 +443,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) /* Enter report */ if ((data[1] & 0xfc) == 0xc0) { - if (features->quirks & WACOM_QUIRK_MULTI_INPUT) - wacom->shared->stylus_in_proximity = true; - /* serial number of the tool */ wacom->serial[idx] = ((data[3] & 0x0f) << 28) + (data[4] << 20) + (data[5] << 12) + @@ -554,19 +551,22 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) (features->type == CINTIQ && !(data[1] & 0x40))) return 1; - /* Range Report */ - if ((data[1] & 0xfe) == 0x20) { + if (features->quirks & WACOM_QUIRK_MULTI_INPUT) + wacom->shared->stylus_in_proximity = true; + + /* in Range while exiting */ + if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) { input_report_key(input, BTN_TOUCH, 0); input_report_abs(input, ABS_PRESSURE, 0); input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max); - if (features->quirks & WACOM_QUIRK_MULTI_INPUT) - wacom->shared->stylus_in_proximity = true; + return 2; } /* Exit report */ if ((data[1] & 0xfe) == 0x80) { if (features->quirks & WACOM_QUIRK_MULTI_INPUT) wacom->shared->stylus_in_proximity = false; + wacom->reporting_data = false; /* don't report exit if we don't know the ID */ if (!wacom->id[idx]) @@ -952,6 +952,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */ input_report_key(input, wacom->tool[idx], 1); input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + wacom->reporting_data = true; return 1; } diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 7afd929..72e78cc 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -189,6 +189,7 @@ struct wacom_wac { int tool[2]; int id[2]; __u32 serial[2]; + bool reporting_data; struct wacom_features features; struct wacom_shared *shared; struct input_dev *input; -- cgit v0.10.2 From fcf80e597c5182edbcbe8322f8e4dfbf5b5d5d64 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jan 2015 02:03:25 -0500 Subject: HID: hid-lg4ff: fix sysfs attribute permission There is no reason to set the range attribute executable to the user and group, and writable to the group. Fix the permission to 0644. Signed-off-by: Vivien Didelot Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 7835717..4b668bf 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -52,7 +52,8 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range); static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); -static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IROTH, lg4ff_range_show, lg4ff_range_store); +static DEVICE_ATTR(range, S_IRUGO | S_IWUSR, lg4ff_range_show, + lg4ff_range_store); struct lg4ff_device_entry { __u32 product_id; -- cgit v0.10.2 From 2f1cec3250e38609bf9252db52dbbe61603c04a7 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 19 Jan 2015 02:03:26 -0500 Subject: HID: hid-lg4ff: use DEVICE_ATTR_RW macro Use the DEVICE_ATTR_RW macro to reduce boiler plate and move the attribute declaration to get rid of function signatures. Signed-off-by: Vivien Didelot Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 4b668bf..db0dd9b 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -49,11 +49,6 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range); -static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf); -static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); - -static DEVICE_ATTR(range, S_IRUGO | S_IWUSR, lg4ff_range_show, - lg4ff_range_store); struct lg4ff_device_entry { __u32 product_id; @@ -417,7 +412,8 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n } /* Read current range and display it in terminal */ -static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t range_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct hid_device *hid = to_hid_device(dev); struct lg4ff_device_entry *entry; @@ -442,7 +438,8 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att /* Set range to user specified value, call appropriate function * according to the type of the wheel */ -static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t range_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct hid_device *hid = to_hid_device(dev); struct lg4ff_device_entry *entry; @@ -473,6 +470,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at return count; } +static DEVICE_ATTR_RW(range); #ifdef CONFIG_LEDS_CLASS static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) -- cgit v0.10.2 From a8c8316b11594e616df641b4b19ec9da732f93df Mon Sep 17 00:00:00 2001 From: Kristian Evensen Date: Tue, 20 Jan 2015 17:55:03 +0100 Subject: HID: do not bind to Microchip Pick16F1454 The Microchip Pick16F1454 is exported as a HID device and is used by for example the Yepkit YKUSH three-port switchable USB hub. However, it is not an actual HID-device. On the Yepkit, it is used to power up/down the ports on the hub. The HID driver should ignore this device. Signed-off-by: Kristian Evensen Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 8b63879..77afffc 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2328,6 +2328,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454) }, { HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) }, { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) }, { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 9243359..8df4744 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -638,6 +638,7 @@ #define USB_DEVICE_ID_PICKIT2 0x0033 #define USB_DEVICE_ID_PICOLCD 0xc002 #define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002 +#define USB_DEVICE_ID_PICK16F1454 0x0042 #define USB_VENDOR_ID_MICROSOFT 0x045e #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b -- cgit v0.10.2 From 86312e4b78647d9fa62cf2293c50161cc0421d30 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Wed, 21 Jan 2015 14:07:10 +0100 Subject: HID: Use Kbuild idiom in Makefiles Use -$(CONFIG_FOO) syntax to build multipart objects with optional parts, since all the config options are bool. Also, delete the obvious comments in the usbhid Makefile. Signed-off-by: Michal Marek Signed-off-by: Jiri Kosina diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index debd15b..11a3708 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -2,10 +2,7 @@ # Makefile for the HID driver # hid-y := hid-core.o hid-input.o - -ifdef CONFIG_DEBUG_FS - hid-objs += hid-debug.o -endif +hid-$(CONFIG_DEBUG_FS) += hid-debug.o obj-$(CONFIG_HID) += hid.o obj-$(CONFIG_UHID) += uhid.o @@ -15,23 +12,13 @@ obj-$(CONFIG_HID_GENERIC) += hid-generic.o hid-$(CONFIG_HIDRAW) += hidraw.o hid-logitech-y := hid-lg.o -ifdef CONFIG_LOGITECH_FF - hid-logitech-y += hid-lgff.o -endif -ifdef CONFIG_LOGIRUMBLEPAD2_FF - hid-logitech-y += hid-lg2ff.o -endif -ifdef CONFIG_LOGIG940_FF - hid-logitech-y += hid-lg3ff.o -endif -ifdef CONFIG_LOGIWHEELS_FF - hid-logitech-y += hid-lg4ff.o -endif +hid-logitech-$(CONFIG_LOGITECH_FF) += hid-lgff.o +hid-logitech-$(CONFIG_LOGIRUMBLEPAD2_FF) += hid-lg2ff.o +hid-logitech-$(CONFIG_LOGIG940_FF) += hid-lg3ff.o +hid-logitech-$(CONFIG_LOGIWHEELS_FF) += hid-lg4ff.o hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o -ifdef CONFIG_DEBUG_FS - hid-wiimote-y += hid-wiimote-debug.o -endif +hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_ACRUX) += hid-axff.o @@ -76,24 +63,12 @@ obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o hid-picolcd-y += hid-picolcd_core.o -ifdef CONFIG_HID_PICOLCD_FB -hid-picolcd-y += hid-picolcd_fb.o -endif -ifdef CONFIG_HID_PICOLCD_BACKLIGHT -hid-picolcd-y += hid-picolcd_backlight.o -endif -ifdef CONFIG_HID_PICOLCD_LCD -hid-picolcd-y += hid-picolcd_lcd.o -endif -ifdef CONFIG_HID_PICOLCD_LEDS -hid-picolcd-y += hid-picolcd_leds.o -endif -ifdef CONFIG_HID_PICOLCD_CIR -hid-picolcd-y += hid-picolcd_cir.o -endif -ifdef CONFIG_DEBUG_FS -hid-picolcd-y += hid-picolcd_debugfs.o -endif +hid-picolcd-$(CONFIG_HID_PICOLCD_FB) += hid-picolcd_fb.o +hid-picolcd-$(CONFIG_HID_PICOLCD_BACKLIGHT) += hid-picolcd_backlight.o +hid-picolcd-$(CONFIG_HID_PICOLCD_LCD) += hid-picolcd_lcd.o +hid-picolcd-$(CONFIG_HID_PICOLCD_LEDS) += hid-picolcd_leds.o +hid-picolcd-$(CONFIG_HID_PICOLCD_CIR) += hid-picolcd_cir.o +hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o obj-$(CONFIG_HID_PRIMAX) += hid-primax.o diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile index db3cf31..890f291 100644 --- a/drivers/hid/usbhid/Makefile +++ b/drivers/hid/usbhid/Makefile @@ -2,17 +2,9 @@ # Makefile for the USB input drivers # -# Multipart objects. usbhid-y := hid-core.o hid-quirks.o - -# Optional parts of multipart objects. - -ifeq ($(CONFIG_USB_HIDDEV),y) - usbhid-y += hiddev.o -endif -ifeq ($(CONFIG_HID_PID),y) - usbhid-y += hid-pidff.o -endif +usbhid-$(CONFIG_USB_HIDDEV) += hiddev.o +usbhid-$(CONFIG_HID_PID) += hid-pidff.o obj-$(CONFIG_USB_HID) += usbhid.o obj-$(CONFIG_USB_KBD) += usbkbd.o -- cgit v0.10.2 From 33e5df0e0e32027866e9fb00451952998fc957f2 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 22 Jan 2015 15:53:28 -0800 Subject: HID: wacom: Report ABS_MISC event for Cintiq Companion Hybrid It appears that the Cintiq Companion Hybrid does not send an ABS_MISC event to userspace when any of its ExpressKeys are pressed. This is not strictly necessary now that the pad exists on its own device, but should be fixed for consistency's sake. Traditionally both the stylus and pad shared the same device node, and xf86-input-wacom would use ABS_MISC for disambiguation. Not sending this causes the Hybrid to behave incorrectly with xf86-input-wacom beginning with its 8f44f3 commit. Signed-off-by: Jason Gerecke Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index a4ba8ca..f886149 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -783,6 +783,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) input_report_key(input, BTN_7, (data[4] & 0x40)); /* Left */ input_report_key(input, BTN_8, (data[4] & 0x80)); /* Down */ input_report_key(input, BTN_0, (data[3] & 0x01)); /* Center */ + + if (data[4] | (data[3] & 0x01)) { + input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); + } else { + input_report_abs(input, ABS_MISC, 0); + } } else if (features->type >= INTUOS5S && features->type <= INTUOSPL) { int i; -- cgit v0.10.2 From 3458e4c0e5f8783ae699e1205062d1fdd2a48cca Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 25 Jan 2015 15:47:47 +0100 Subject: HID: hyperv: match wait_for_completion_timeout return type The return type of wait_for_completion_timeout is unsigned long not int. This patch fixes up the declarations only. Patch was compile tested only for x86_64_defconfig + CONFIG_X86_VSMP=y CONFIG_HYPERV=m, CONFIG_HID_HYPERV_MOUSE=m Signed-off-by: Nicholas Mc Guire Signed-off-by: K. Y. Srinivasan Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index 31fad64..6039f07 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -381,7 +381,7 @@ static void mousevsc_on_channel_callback(void *context) static int mousevsc_connect_to_vsp(struct hv_device *device) { int ret = 0; - int t; + unsigned long t; struct mousevsc_dev *input_dev = hv_get_drvdata(device); struct mousevsc_prt_msg *request; struct mousevsc_prt_msg *response; -- cgit v0.10.2 From afd700d933963d07391e3e3dfbfbc05e905960ef Mon Sep 17 00:00:00 2001 From: Jim Keir Date: Fri, 23 Jan 2015 17:21:12 +0000 Subject: HID: pidff: Fix initialisation forMicrosoft Sidewinder FF Pro 2 The FF2 driver (usbhid/hid-pidff.c) sends commands to the stick during ff_init. However, this is called inside a block where driver_input_lock is locked, so the results of these initial commands are discarded. This behavior is the "killer", without this nothing else works. ff_init issues commands using "hid_hw_request". This eventually goes to hid_input_report, which returns -EBUSY because driver_input_lock is locked. The change is to delay the ff_init call in hid-core.c until after this lock has been released. Calling hid_device_io_start() releases the lock so the device can be configured. We also need to call hid_device_io_stop() on exit for the lock to remain locked while ending the init of the drivers. [ benjamin.tissoires@redhat.com: imrpoved the changelog a lot ] Signed-off-by: Jim Keir Reviewed-by: Benjamin.tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 10b6167..0b531c6 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c @@ -1252,6 +1252,8 @@ int hid_pidff_init(struct hid_device *hid) pidff->hid = hid; + hid_device_io_start(hid); + pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff); pidff_find_reports(hid, HID_FEATURE_REPORT, pidff); @@ -1315,9 +1317,13 @@ int hid_pidff_init(struct hid_device *hid) hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula \n"); + hid_device_io_stop(hid); + return 0; fail: + hid_device_io_stop(hid); + kfree(pidff); return error; } -- cgit v0.10.2 From 9b61aa864ab6c2e12e463559eb83cf83cbd06889 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Wed, 28 Jan 2015 09:42:59 -0800 Subject: HID: wacom: make sure touch arbitration is applied consistently stylus_in_proximity is used to make sure no touch event is sent while pen is in proximity. touch_down is used to make sure a touch up event is sent when pen comes into proximity while touch is down. Two touch routines didn't store touch_down. One touch routine forgot to check stylus_in_proximity before sending touch events. This patch fixes those issues. Signed-off-by: Ping Cheng Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index f886149..6d490f60 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1042,7 +1042,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) for (i = 0; i < contacts_to_send; i++) { int offset = (WACOM_BYTES_PER_24HDT_PACKET * i) + 1; - bool touch = data[offset] & 0x1 && !wacom->shared->stylus_in_proximity; + bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity; int slot = input_mt_get_slot_by_key(input, data[offset + 1]); if (slot < 0) @@ -1072,6 +1072,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) if (wacom->num_contacts_left <= 0) wacom->num_contacts_left = 0; + wacom->shared->touch_down = (wacom->num_contacts_left > 0); return 1; } @@ -1100,7 +1101,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom) for (i = 0; i < contacts_to_send; i++) { int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3; - bool touch = data[offset] & 0x1; + bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity; int id = get_unaligned_le16(&data[offset + 1]); int slot = input_mt_get_slot_by_key(input, id); @@ -1122,6 +1123,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom) if (wacom->num_contacts_left < 0) wacom->num_contacts_left = 0; + wacom->shared->touch_down = (wacom->num_contacts_left > 0); return 1; } -- cgit v0.10.2 From a2f71c6c878e664cce4591fc1de36dce2bf44d8d Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 27 Jan 2015 13:29:36 -0800 Subject: HID: wacom: consolidate input capability settings for pen and touch After PAD moved to its own interface, there were duplicated statements in wacom_setup_pentouch_input_capabilities. Merge them together to reduce future maintenance effort. Signed-off-by: Ping Cheng Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 6d490f60..d239d82 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2089,32 +2089,17 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, wacom_abs_set_axis(input_dev, wacom_wac); switch (features->type) { - case WACOM_MO: - case WACOM_G4: - /* fall through */ - - case GRAPHIRE: - input_set_capability(input_dev, EV_REL, REL_WHEEL); - - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); - __set_bit(BTN_MIDDLE, input_dev->keybit); - - __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_TOOL_MOUSE, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); - __set_bit(BTN_STYLUS2, input_dev->keybit); - - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - break; - case GRAPHIRE_BT: __clear_bit(ABS_MISC, input_dev->absbit); + + case WACOM_MO: + case WACOM_G4: input_set_abs_params(input_dev, ABS_DISTANCE, 0, features->distance_max, 0, 0); + /* fall through */ + case GRAPHIRE: input_set_capability(input_dev, EV_REL, REL_WHEEL); __set_bit(BTN_LEFT, input_dev->keybit); @@ -2131,30 +2116,13 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, break; case WACOM_24HD: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0); - /* fall through */ - case DTK: - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - wacom_setup_cintiq(wacom_wac); - break; - case WACOM_22HD: case WACOM_21UX2: case WACOM_BEE: case CINTIQ: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - wacom_setup_cintiq(wacom_wac); - break; - case WACOM_13HD: + case CINTIQ_HYBRID: input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_abs_set_res(input_dev, ABS_Z, 287); __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); @@ -2164,6 +2132,10 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, case INTUOS3: case INTUOS3L: case INTUOS3S: + case INTUOS4: + case INTUOS4WL: + case INTUOS4L: + case INTUOS4S: input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); input_abs_set_res(input_dev, ABS_Z, 287); /* fall through */ @@ -2202,17 +2174,6 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, } break; - case INTUOS4: - case INTUOS4WL: - case INTUOS4L: - case INTUOS4S: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - wacom_setup_intuos(wacom_wac); - - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - break; - case WACOM_24HDT: if (features->device_type == BTN_TOOL_FINGER) { input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0); @@ -2308,14 +2269,6 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, 0, 0); } break; - - case CINTIQ_HYBRID: - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - wacom_setup_cintiq(wacom_wac); - break; } return 0; } -- cgit v0.10.2 From 500d4160abe9a2e88b12e319c13ae3ebd1e18108 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 27 Jan 2015 13:30:03 -0800 Subject: HID: wacom: add support for Cintiq 27QHD and 27QHD touch These devices have accelerometers. To report accelerometer coordinates, a new property, INPUT_PROP_ACCELEROMETER, is added. Signed-off-by: Ping Cheng Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index f01ab3a..f0568a7 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -403,6 +403,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev, else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) { return wacom_set_device_mode(hdev, 18, 3, 2); } + else if (features->type == WACOM_27QHDT) { + return wacom_set_device_mode(hdev, 131, 3, 2); + } } else if (features->device_type == BTN_TOOL_PEN) { if (features->type <= BAMBOO_PT && features->type != WIRELESS) { return wacom_set_device_mode(hdev, 2, 2, 2); diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index d239d82..1a65079 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -656,6 +656,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) data[0] != WACOM_REPORT_INTUOSREAD && data[0] != WACOM_REPORT_INTUOSWRITE && data[0] != WACOM_REPORT_INTUOSPAD && + data[0] != WACOM_REPORT_CINTIQ && + data[0] != WACOM_REPORT_CINTIQPAD && data[0] != WACOM_REPORT_INTUOS5PAD) { dev_dbg(input->dev.parent, "%s: received unknown report #%d\n", __func__, data[0]); @@ -667,7 +669,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) idx = data[1] & 0x01; /* pad packets. Works as a second tool and is always in prox */ - if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) { + if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD || + data[0] == WACOM_REPORT_CINTIQPAD) { input = wacom->pad_input; if (features->type >= INTUOS4S && features->type <= INTUOS4L) { input_report_key(input, BTN_0, (data[2] & 0x01)); @@ -767,6 +770,14 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) } else { input_report_abs(input, ABS_MISC, 0); } + } else if (features->type == WACOM_27QHD) { + input_report_key(input, KEY_PROG1, data[2] & 0x01); + input_report_key(input, KEY_PROG2, data[2] & 0x02); + input_report_key(input, KEY_PROG3, data[2] & 0x04); + + input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4])); + input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6])); + input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8])); } else if (features->type == CINTIQ_HYBRID) { /* * Do not send hardware buttons under Android. They @@ -1027,8 +1038,20 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) struct input_dev *input = wacom->input; unsigned char *data = wacom->data; int i; - int current_num_contacts = data[61]; + int current_num_contacts = 0; int contacts_to_send = 0; + int num_contacts_left = 4; /* maximum contacts per packet */ + int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET; + int y_offset = 2; + + if (wacom->features.type == WACOM_27QHDT) { + current_num_contacts = data[63]; + num_contacts_left = 10; + byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET; + y_offset = 0; + } else { + current_num_contacts = data[61]; + } /* * First packet resets the counter since only the first @@ -1037,11 +1060,10 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) if (current_num_contacts) wacom->num_contacts_left = current_num_contacts; - /* There are at most 4 contacts per packet */ - contacts_to_send = min(4, wacom->num_contacts_left); + contacts_to_send = min(num_contacts_left, wacom->num_contacts_left); for (i = 0; i < contacts_to_send; i++) { - int offset = (WACOM_BYTES_PER_24HDT_PACKET * i) + 1; + int offset = (byte_per_packet * i) + 1; bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity; int slot = input_mt_get_slot_by_key(input, data[offset + 1]); @@ -1052,18 +1074,23 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) if (touch) { int t_x = get_unaligned_le16(&data[offset + 2]); - int c_x = get_unaligned_le16(&data[offset + 4]); - int t_y = get_unaligned_le16(&data[offset + 6]); - int c_y = get_unaligned_le16(&data[offset + 8]); - int w = get_unaligned_le16(&data[offset + 10]); - int h = get_unaligned_le16(&data[offset + 12]); + int t_y = get_unaligned_le16(&data[offset + 4 + y_offset]); input_report_abs(input, ABS_MT_POSITION_X, t_x); input_report_abs(input, ABS_MT_POSITION_Y, t_y); - input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h)); - input_report_abs(input, ABS_MT_WIDTH_MAJOR, min(w, h) + int_dist(t_x, t_y, c_x, c_y)); - input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h)); - input_report_abs(input, ABS_MT_ORIENTATION, w > h); + + if (wacom->features.type != WACOM_27QHDT) { + int c_x = get_unaligned_le16(&data[offset + 4]); + int c_y = get_unaligned_le16(&data[offset + 8]); + int w = get_unaligned_le16(&data[offset + 10]); + int h = get_unaligned_le16(&data[offset + 12]); + + input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h)); + input_report_abs(input, ABS_MT_WIDTH_MAJOR, + min(w, h) + int_dist(t_x, t_y, c_x, c_y)); + input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h)); + input_report_abs(input, ABS_MT_ORIENTATION, w > h); + } } } input_mt_report_pointer_emulation(input, true); @@ -1894,6 +1921,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) case WACOM_21UX2: case WACOM_22HD: case WACOM_24HD: + case WACOM_27QHD: case DTK: case CINTIQ_HYBRID: sync = wacom_intuos_irq(wacom_wac); @@ -1904,6 +1932,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) break; case WACOM_24HDT: + case WACOM_27QHDT: sync = wacom_24hdt_irq(wacom_wac); break; @@ -2115,6 +2144,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, __set_bit(INPUT_PROP_POINTER, input_dev->propbit); break; + case WACOM_27QHD: case WACOM_24HD: case DTK: case WACOM_22HD: @@ -2183,6 +2213,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, } /* fall through */ + case WACOM_27QHDT: case MTSCREEN: case MTTPC: case MTTPC_B: @@ -2330,6 +2361,19 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0); break; + case WACOM_27QHD: + __set_bit(KEY_PROG1, input_dev->keybit); + __set_bit(KEY_PROG2, input_dev->keybit); + __set_bit(KEY_PROG3, input_dev->keybit); + input_set_abs_params(input_dev, ABS_X, -2048, 2048, 0, 0); + input_abs_set_res(input_dev, ABS_X, 1024); /* points/g */ + input_set_abs_params(input_dev, ABS_Y, -2048, 2048, 0, 0); + input_abs_set_res(input_dev, ABS_Y, 1024); + input_set_abs_params(input_dev, ABS_Z, -2048, 2048, 0, 0); + input_abs_set_res(input_dev, ABS_Z, 1024); + __set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit); + break; + case DTK: for (i = 0; i < 6; i++) __set_bit(BTN_0 + i, input_dev->keybit); @@ -2680,6 +2724,18 @@ static const struct wacom_features wacom_features_0xF6 = { "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; +static const struct wacom_features wacom_features_0x32A = + { "Wacom Cintiq 27QHD", 119740, 67520, 2047, + 63, WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; +static const struct wacom_features wacom_features_0x32B = + { "Wacom Cintiq 27QHD touch", 119740, 67520, 2047, 63, + WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, + .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32C }; +static const struct wacom_features wacom_features_0x32C = + { "Wacom Cintiq 27QHD touch", .type = WACOM_27QHDT, + .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32B, .touch_max = 10 }; static const struct wacom_features wacom_features_0x3F = { "Wacom Cintiq 21UX", 87200, 65600, 1023, 63, CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; @@ -3046,6 +3102,9 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x315) }, { USB_DEVICE_WACOM(0x317) }, { USB_DEVICE_WACOM(0x323) }, + { USB_DEVICE_WACOM(0x32A) }, + { USB_DEVICE_WACOM(0x32B) }, + { USB_DEVICE_WACOM(0x32C) }, { USB_DEVICE_WACOM(0x32F) }, { USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x4004) }, diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 72e78cc..021ee1c 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -13,7 +13,7 @@ #include /* maximum packet length for USB devices */ -#define WACOM_PKGLEN_MAX 68 +#define WACOM_PKGLEN_MAX 192 #define WACOM_NAME_MAX 64 @@ -37,6 +37,7 @@ /* wacom data size per MT contact */ #define WACOM_BYTES_PER_MT_PACKET 11 #define WACOM_BYTES_PER_24HDT_PACKET 14 +#define WACOM_BYTES_PER_QHDTHID_PACKET 6 /* device IDs */ #define STYLUS_DEVICE_ID 0x02 @@ -58,6 +59,8 @@ #define WACOM_REPORT_TPCMT 13 #define WACOM_REPORT_TPCMT2 3 #define WACOM_REPORT_TPCHID 15 +#define WACOM_REPORT_CINTIQ 16 +#define WACOM_REPORT_CINTIQPAD 17 #define WACOM_REPORT_TPCST 16 #define WACOM_REPORT_DTUS 17 #define WACOM_REPORT_TPC1FGE 18 @@ -109,6 +112,7 @@ enum { WACOM_22HD, DTK, WACOM_24HD, + WACOM_27QHD, CINTIQ_HYBRID, CINTIQ, WACOM_BEE, @@ -117,6 +121,7 @@ enum { WIRELESS, BAMBOO_PT, WACOM_24HDT, + WACOM_27QHDT, TABLETPC, /* add new TPC below */ TABLETPCE, TABLETPC2FG, diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h index a1d7e93..b0a8130 100644 --- a/include/uapi/linux/input.h +++ b/include/uapi/linux/input.h @@ -166,6 +166,7 @@ struct input_keymap_entry { #define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */ #define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */ #define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */ +#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */ #define INPUT_PROP_MAX 0x1f #define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) -- cgit v0.10.2