Commit 79084494 authored by Jiri Kosina's avatar Jiri Kosina

Merge branches 'for-4.16/hid-quirks-cleanup/asus',...

Merge branches 'for-4.16/hid-quirks-cleanup/asus', 'for-4.16/hid-quirks-cleanup/elecom', 'for-4.16/hid-quirks-cleanup/ish', 'for-4.16/hid-quirks-cleanup/multitouch', 'for-4.16/hid-quirks-cleanup/pixart', 'for-4.16/hid-quirks-cleanup/rmi', 'for-4.16/hid-quirks-cleanup/sony' and 'for-4.16/hid-quirks-cleanup/toshiba' into for-linus

Pull assorted device driver fixes (ASUS, Elecom, Intel-ISH, Multitouch, PixArt, RMI,
Sony and Toshiba) based on top the hid-quirks revamp.
...@@ -269,10 +269,11 @@ ABS_MT_ORIENTATION ...@@ -269,10 +269,11 @@ ABS_MT_ORIENTATION
The orientation of the touching ellipse. The value should describe a signed The orientation of the touching ellipse. The value should describe a signed
quarter of a revolution clockwise around the touch center. The signed value quarter of a revolution clockwise around the touch center. The signed value
range is arbitrary, but zero should be returned for an ellipse aligned with range is arbitrary, but zero should be returned for an ellipse aligned with
the Y axis of the surface, a negative value when the ellipse is turned to the Y axis (north) of the surface, a negative value when the ellipse is
the left, and a positive value when the ellipse is turned to the turned to the left, and a positive value when the ellipse is turned to the
right. When completely aligned with the X axis, the range max should be right. When aligned with the X axis in the positive direction, the range
returned. max should be returned; when aligned with the X axis in the negative
direction, the range -max should be returned.
Touch ellipsis are symmetrical by default. For devices capable of true 360 Touch ellipsis are symmetrical by default. For devices capable of true 360
degree orientation, the reported orientation must exceed the range max to degree orientation, the reported orientation must exceed the range max to
......
...@@ -280,6 +280,7 @@ config HID_ELECOM ...@@ -280,6 +280,7 @@ config HID_ELECOM
---help--- ---help---
Support for ELECOM devices: Support for ELECOM devices:
- BM084 Bluetooth Mouse - BM084 Bluetooth Mouse
- EX-G Trackball (Wired and wireless)
- DEFT Trackball (Wired and wireless) - DEFT Trackball (Wired and wireless)
- HUGE Trackball (Wired and wireless) - HUGE Trackball (Wired and wireless)
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
* any later version. * any later version.
*/ */
#include <linux/dmi.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
...@@ -119,6 +120,24 @@ static const struct asus_touchpad_info asus_t100ta_tp = { ...@@ -119,6 +120,24 @@ static const struct asus_touchpad_info asus_t100ta_tp = {
.max_contacts = 5, .max_contacts = 5,
}; };
static const struct asus_touchpad_info asus_t100ha_tp = {
.max_x = 2640,
.max_y = 1320,
.res_x = 30, /* units/mm */
.res_y = 29, /* units/mm */
.contact_size = 5,
.max_contacts = 5,
};
static const struct asus_touchpad_info asus_t200ta_tp = {
.max_x = 3120,
.max_y = 1716,
.res_x = 30, /* units/mm */
.res_y = 28, /* units/mm */
.contact_size = 5,
.max_contacts = 5,
};
static const struct asus_touchpad_info asus_t100chi_tp = { static const struct asus_touchpad_info asus_t100chi_tp = {
.max_x = 2640, .max_x = 2640,
.max_y = 1320, .max_y = 1320,
...@@ -606,7 +625,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -606,7 +625,17 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) { if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) {
drvdata->quirks = QUIRK_SKIP_INPUT_MAPPING; drvdata->quirks = QUIRK_SKIP_INPUT_MAPPING;
drvdata->tp = &asus_t100ta_tp; /*
* The T100HA uses the same USB-ids as the T100TAF and
* the T200TA uses the same USB-ids as the T100TA, while
* both have different max x/y values as the T100TA[F].
*/
if (dmi_match(DMI_PRODUCT_NAME, "T100HAN"))
drvdata->tp = &asus_t100ha_tp;
else if (dmi_match(DMI_PRODUCT_NAME, "T200TA"))
drvdata->tp = &asus_t200ta_tp;
else
drvdata->tp = &asus_t100ta_tp;
} }
} }
...@@ -686,9 +715,10 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -686,9 +715,10 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
hid_info(hdev, "Fixing up Asus notebook report descriptor\n"); hid_info(hdev, "Fixing up Asus notebook report descriptor\n");
rdesc[55] = 0xdd; rdesc[55] = 0xdd;
} }
/* For the T100TA keyboard dock */ /* For the T100TA/T200TA keyboard dock */
if (drvdata->quirks & QUIRK_T100_KEYBOARD && if (drvdata->quirks & QUIRK_T100_KEYBOARD &&
*rsize == 76 && rdesc[73] == 0x81 && rdesc[74] == 0x01) { (*rsize == 76 || *rsize == 101) &&
rdesc[73] == 0x81 && rdesc[74] == 0x01) {
hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n"); hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n");
rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT; rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT;
} }
...@@ -751,7 +781,10 @@ static const struct hid_device_id asus_devices[] = { ...@@ -751,7 +781,10 @@ static const struct hid_device_id asus_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD }, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD), USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD),
QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD),
QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) }, { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) },
......
/* /*
* HID driver for ELECOM devices. * HID driver for ELECOM devices:
* - BM084 Bluetooth Mouse
* - EX-G Trackball (Wired and wireless)
* - DEFT Trackball (Wired and wireless)
* - HUGE Trackball (Wired and wireless)
*
* Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com> * Copyright (c) 2010 Richard Nauber <Richard.Nauber@gmail.com>
* Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com> * Copyright (c) 2016 Yuxuan Shui <yshuiv7@gmail.com>
* Copyright (c) 2017 Diego Elio Pettenò <flameeyes@flameeyes.eu> * Copyright (c) 2017 Diego Elio Pettenò <flameeyes@flameeyes.eu>
* Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org> * Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org>
* Copyright (c) 2017 Tomasz Kramkowski <tk@the-tk.com>
*/ */
/* /*
...@@ -19,6 +25,34 @@ ...@@ -19,6 +25,34 @@
#include "hid-ids.h" #include "hid-ids.h"
/*
* Certain ELECOM mice misreport their button count meaning that they only work
* correctly with the ELECOM mouse assistant software which is unavailable for
* Linux. A four extra INPUT reports and a FEATURE report are described by the
* report descriptor but it does not appear that these enable software to
* control what the extra buttons map to. The only simple and straightforward
* solution seems to involve fixing up the report descriptor.
*
* Report descriptor format:
* Positions 13, 15, 21 and 31 store the button bit count, button usage minimum,
* button usage maximum and padding bit count respectively.
*/
#define MOUSE_BUTTONS_MAX 8
static void mouse_button_fixup(struct hid_device *hdev,
__u8 *rdesc, unsigned int rsize,
int nbuttons)
{
if (rsize < 32 || rdesc[12] != 0x95 ||
rdesc[14] != 0x75 || rdesc[15] != 0x01 ||
rdesc[20] != 0x29 || rdesc[30] != 0x75)
return;
hid_info(hdev, "Fixing up Elecom mouse button count\n");
nbuttons = clamp(nbuttons, 0, MOUSE_BUTTONS_MAX);
rdesc[13] = nbuttons;
rdesc[21] = nbuttons;
rdesc[31] = MOUSE_BUTTONS_MAX - nbuttons;
}
static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
{ {
...@@ -31,45 +65,15 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -31,45 +65,15 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[47] = 0x00; rdesc[47] = 0x00;
} }
break; break;
case USB_DEVICE_ID_ELECOM_EX_G_WIRED:
case USB_DEVICE_ID_ELECOM_EX_G_WIRELESS:
mouse_button_fixup(hdev, rdesc, *rsize, 6);
break;
case USB_DEVICE_ID_ELECOM_DEFT_WIRED: case USB_DEVICE_ID_ELECOM_DEFT_WIRED:
case USB_DEVICE_ID_ELECOM_DEFT_WIRELESS: case USB_DEVICE_ID_ELECOM_DEFT_WIRELESS:
case USB_DEVICE_ID_ELECOM_HUGE_WIRED: case USB_DEVICE_ID_ELECOM_HUGE_WIRED:
case USB_DEVICE_ID_ELECOM_HUGE_WIRELESS: case USB_DEVICE_ID_ELECOM_HUGE_WIRELESS:
/* The DEFT/HUGE trackball has eight buttons, but its descriptor mouse_button_fixup(hdev, rdesc, *rsize, 8);
* only reports five, disabling the three Fn buttons on the top
* of the mouse.
*
* Apply the following diff to the descriptor:
*
* Collection (Physical), Collection (Physical),
* Report ID (1), Report ID (1),
* Report Count (5), -> Report Count (8),
* Report Size (1), Report Size (1),
* Usage Page (Button), Usage Page (Button),
* Usage Minimum (01h), Usage Minimum (01h),
* Usage Maximum (05h), -> Usage Maximum (08h),
* Logical Minimum (0), Logical Minimum (0),
* Logical Maximum (1), Logical Maximum (1),
* Input (Variable), Input (Variable),
* Report Count (1), -> Report Count (0),
* Report Size (3), Report Size (3),
* Input (Constant), Input (Constant),
* Report Size (16), Report Size (16),
* Report Count (2), Report Count (2),
* Usage Page (Desktop), Usage Page (Desktop),
* Usage (X), Usage (X),
* Usage (Y), Usage (Y),
* Logical Minimum (-32768), Logical Minimum (-32768),
* Logical Maximum (32767), Logical Maximum (32767),
* Input (Variable, Relative), Input (Variable, Relative),
* End Collection, End Collection,
*/
if (*rsize == 213 && rdesc[13] == 5 && rdesc[21] == 5) {
hid_info(hdev, "Fixing up Elecom DEFT/HUGE Fn buttons\n");
rdesc[13] = 8; /* Button/Variable Report Count */
rdesc[21] = 8; /* Button/Variable Usage Maximum */
rdesc[29] = 0; /* Button/Constant Report Count */
}
break; break;
} }
return rdesc; return rdesc;
...@@ -77,6 +81,8 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -77,6 +81,8 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc,
static const struct hid_device_id elecom_devices[] = { static const struct hid_device_id elecom_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) },
......
...@@ -178,7 +178,8 @@ ...@@ -178,7 +178,8 @@
#define USB_VENDOR_ID_ASUSTEK 0x0b05 #define USB_VENDOR_ID_ASUSTEK 0x0b05
#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726 #define USB_DEVICE_ID_ASUSTEK_LCM 0x1726
#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b #define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b
#define USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD 0x17e0 #define USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD 0x17e0
#define USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD 0x1807
#define USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD 0x8502 #define USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD 0x8502
#define USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD 0x184a #define USB_DEVICE_ID_ASUSTEK_T304_KEYBOARD 0x184a
#define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585 #define USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD 0x8585
...@@ -370,6 +371,8 @@ ...@@ -370,6 +371,8 @@
#define USB_VENDOR_ID_ELECOM 0x056e #define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061 #define USB_DEVICE_ID_ELECOM_BM084 0x0061
#define USB_DEVICE_ID_ELECOM_EX_G_WIRED 0x00fb
#define USB_DEVICE_ID_ELECOM_EX_G_WIRELESS 0x00fc
#define USB_DEVICE_ID_ELECOM_DEFT_WIRED 0x00fe #define USB_DEVICE_ID_ELECOM_DEFT_WIRED 0x00fe
#define USB_DEVICE_ID_ELECOM_DEFT_WIRELESS 0x00ff #define USB_DEVICE_ID_ELECOM_DEFT_WIRELESS 0x00ff
#define USB_DEVICE_ID_ELECOM_HUGE_WIRED 0x010c #define USB_DEVICE_ID_ELECOM_HUGE_WIRED 0x010c
...@@ -535,6 +538,7 @@ ...@@ -535,6 +538,7 @@
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A 0x0a4a #define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A 0x0a4a
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a #define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a #define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a
#define USB_VENDOR_ID_HUION 0x256c #define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e #define USB_DEVICE_ID_HUION_TABLET 0x006e
...@@ -1156,6 +1160,7 @@ ...@@ -1156,6 +1160,7 @@
#define USB_VENDOR_ID_PRIMAX 0x0461 #define USB_VENDOR_ID_PRIMAX 0x0461
#define USB_DEVICE_ID_PRIMAX_MOUSE_4D22 0x4d22 #define USB_DEVICE_ID_PRIMAX_MOUSE_4D22 0x4d22
#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 #define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05
#define USB_DEVICE_ID_PRIMAX_REZEL 0x4e72
#define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */ #define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */
......
...@@ -85,11 +85,12 @@ MODULE_LICENSE("GPL"); ...@@ -85,11 +85,12 @@ MODULE_LICENSE("GPL");
#define MT_IO_FLAGS_PENDING_SLOTS 2 #define MT_IO_FLAGS_PENDING_SLOTS 2
struct mt_slot { struct mt_slot {
__s32 x, y, cx, cy, p, w, h; __s32 x, y, cx, cy, p, w, h, a;
__s32 contactid; /* the device ContactID assigned to this slot */ __s32 contactid; /* the device ContactID assigned to this slot */
bool touch_state; /* is the touch valid? */ bool touch_state; /* is the touch valid? */
bool inrange_state; /* is the finger in proximity of the sensor? */ bool inrange_state; /* is the finger in proximity of the sensor? */
bool confidence_state; /* is the touch made by a finger? */ bool confidence_state; /* is the touch made by a finger? */
bool has_azimuth; /* the contact reports azimuth */
}; };
struct mt_class { struct mt_class {
...@@ -119,6 +120,10 @@ struct mt_device { ...@@ -119,6 +120,10 @@ struct mt_device {
unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */
int cc_index; /* contact count field index in the report */ int cc_index; /* contact count field index in the report */
int cc_value_index; /* contact count value index in the field */ int cc_value_index; /* contact count value index in the field */
int scantime_index; /* scantime field index in the report */
int scantime_val_index; /* scantime value index in the field */
int prev_scantime; /* scantime reported in the previous packet */
int left_button_state; /* left button state */
unsigned last_slot_field; /* the last field of a slot */ unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */ unsigned mt_report_id; /* the report ID of the multitouch device */
unsigned long initial_quirks; /* initial quirks state */ unsigned long initial_quirks; /* initial quirks state */
...@@ -582,8 +587,15 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -582,8 +587,15 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if (!(cls->quirks & MT_QUIRK_NO_AREA)) { if (!(cls->quirks & MT_QUIRK_NO_AREA)) {
set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
cls->sn_height); cls->sn_height);
input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0); /*
* Only set ABS_MT_ORIENTATION if it is not
* already set by the HID_DG_AZIMUTH usage.
*/
if (!test_bit(ABS_MT_ORIENTATION,
hi->input->absbit))
input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0);
} }
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
return 1; return 1;
...@@ -599,6 +611,12 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -599,6 +611,12 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
EV_MSC, MSC_TIMESTAMP); EV_MSC, MSC_TIMESTAMP);
input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP); input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP);
mt_store_field(usage, td, hi); mt_store_field(usage, td, hi);
/* Ignore if indexes are out of bounds. */
if (field->index >= field->report->maxfield ||
usage->usage_index >= field->report_count)
return 1;
td->scantime_index = field->index;
td->scantime_val_index = usage->usage_index;
return 1; return 1;
case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTCOUNT:
/* Ignore if indexes are out of bounds. */ /* Ignore if indexes are out of bounds. */
...@@ -608,6 +626,21 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -608,6 +626,21 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
td->cc_index = field->index; td->cc_index = field->index;
td->cc_value_index = usage->usage_index; td->cc_value_index = usage->usage_index;
return 1; return 1;
case HID_DG_AZIMUTH:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_ORIENTATION);
/*
* Azimuth has the range of [0, MAX) representing a full
* revolution. Set ABS_MT_ORIENTATION to a quarter of
* MAX according the definition of ABS_MT_ORIENTATION
*/
input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
-field->logical_maximum / 4,
field->logical_maximum / 4,
cls->sn_move ?
field->logical_maximum / cls->sn_move : 0, 0);
mt_store_field(usage, td, hi);
return 1;
case HID_DG_CONTACTMAX: case HID_DG_CONTACTMAX:
/* we don't set td->last_slot_field as contactcount and /* we don't set td->last_slot_field as contactcount and
* contact max are global to the report */ * contact max are global to the report */
...@@ -700,6 +733,10 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) ...@@ -700,6 +733,10 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
int wide = (s->w > s->h); int wide = (s->w > s->h);
int major = max(s->w, s->h); int major = max(s->w, s->h);
int minor = min(s->w, s->h); int minor = min(s->w, s->h);
int orientation = wide;
if (s->has_azimuth)
orientation = s->a;
/* /*
* divided by two to match visual scale of touch * divided by two to match visual scale of touch
...@@ -716,7 +753,8 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) ...@@ -716,7 +753,8 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy); input_event(input, EV_ABS, ABS_MT_TOOL_Y, s->cy);
input_event(input, EV_ABS, ABS_MT_DISTANCE, input_event(input, EV_ABS, ABS_MT_DISTANCE,
!s->touch_state); !s->touch_state);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide); input_event(input, EV_ABS, ABS_MT_ORIENTATION,
orientation);
input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p); input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
...@@ -734,10 +772,16 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) ...@@ -734,10 +772,16 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
*/ */
static void mt_sync_frame(struct mt_device *td, struct input_dev *input) static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
{ {
__s32 cls = td->mtclass.name;
if (cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL)
input_event(input, EV_KEY, BTN_LEFT, td->left_button_state);
input_mt_sync_frame(input); input_mt_sync_frame(input);
input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp); input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp);
input_sync(input); input_sync(input);
td->num_received = 0; td->num_received = 0;
td->left_button_state = 0;
if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags)) if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags))
set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags); set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags);
else else
...@@ -778,9 +822,11 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field, ...@@ -778,9 +822,11 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
} }
static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value) struct hid_usage *usage, __s32 value,
bool first_packet)
{ {
struct mt_device *td = hid_get_drvdata(hid); struct mt_device *td = hid_get_drvdata(hid);
__s32 cls = td->mtclass.name;
__s32 quirks = td->mtclass.quirks; __s32 quirks = td->mtclass.quirks;
struct input_dev *input = field->hidinput->input; struct input_dev *input = field->hidinput->input;
...@@ -832,11 +878,49 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, ...@@ -832,11 +878,49 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
break; break;
case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTCOUNT:
break; break;
case HID_DG_AZIMUTH:
/*
* Azimuth is counter-clockwise and ranges from [0, MAX)
* (a full revolution). Convert it to clockwise ranging
* [-MAX/2, MAX/2].
*
* Note that ABS_MT_ORIENTATION require us to report
* the limit of [-MAX/4, MAX/4], but the value can go
* out of range to [-MAX/2, MAX/2] to report an upside
* down ellipsis.
*/
if (value > field->logical_maximum / 2)
value -= field->logical_maximum;
td->curdata.a = -value;
td->curdata.has_azimuth = true;
break;
case HID_DG_TOUCH: case HID_DG_TOUCH:
/* do nothing */ /* do nothing */
break; break;
default: default:
/*
* For Win8 PTP touchpads we should only look at
* non finger/touch events in the first_packet of
* a (possible) multi-packet frame.
*/
if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
!first_packet)
return;
/*
* For Win8 PTP touchpads we map both the clickpad click
* and any "external" left buttons to BTN_LEFT if a
* device claims to have both we need to report 1 for
* BTN_LEFT if either is pressed, so we or all values
* together and report the result in mt_sync_frame().
*/
if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
usage->type == EV_KEY && usage->code == BTN_LEFT) {
td->left_button_state |= value;
return;
}
if (usage->type) if (usage->type)
input_event(input, usage->type, usage->code, input_event(input, usage->type, usage->code,
value); value);
...@@ -855,9 +939,11 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, ...@@ -855,9 +939,11 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
static void mt_touch_report(struct hid_device *hid, struct hid_report *report) static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
{ {
struct mt_device *td = hid_get_drvdata(hid); struct mt_device *td = hid_get_drvdata(hid);
__s32 cls = td->mtclass.name;
struct hid_field *field; struct hid_field *field;
bool first_packet;
unsigned count; unsigned count;
int r, n; int r, n, scantime = 0;
/* sticky fingers release in progress, abort */ /* sticky fingers release in progress, abort */
if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags)) if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
...@@ -867,13 +953,31 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) ...@@ -867,13 +953,31 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
* Includes multi-packet support where subsequent * Includes multi-packet support where subsequent
* packets are sent with zero contactcount. * packets are sent with zero contactcount.
*/ */
if (td->scantime_index >= 0) {
field = report->field[td->scantime_index];
scantime = field->value[td->scantime_val_index];
}
if (td->cc_index >= 0) { if (td->cc_index >= 0) {
struct hid_field *field = report->field[td->cc_index]; struct hid_field *field = report->field[td->cc_index];
int value = field->value[td->cc_value_index]; int value = field->value[td->cc_value_index];
if (value)
/*
* For Win8 PTPs the first packet (td->num_received == 0) may
* have a contactcount of 0 if there only is a button event.
* We double check that this is not a continuation packet
* of a possible multi-packet frame be checking that the
* timestamp has changed.
*/
if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) &&
td->num_received == 0 && td->prev_scantime != scantime)
td->num_expected = value;
/* A non 0 contact count always indicates a first packet */
else if (value)
td->num_expected = value; td->num_expected = value;
} }
td->prev_scantime = scantime;
first_packet = td->num_received == 0;
for (r = 0; r < report->maxfield; r++) { for (r = 0; r < report->maxfield; r++) {
field = report->field[r]; field = report->field[r];
count = field->report_count; count = field->report_count;
...@@ -883,7 +987,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) ...@@ -883,7 +987,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
for (n = 0; n < count; n++) for (n = 0; n < count; n++)
mt_process_mt_event(hid, field, &field->usage[n], mt_process_mt_event(hid, field, &field->usage[n],
field->value[n]); field->value[n], first_packet);
} }
if (td->num_received >= td->num_expected) if (td->num_received >= td->num_expected)
...@@ -1329,6 +1433,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1329,6 +1433,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->maxcontact_report_id = -1; td->maxcontact_report_id = -1;
td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
td->cc_index = -1; td->cc_index = -1;
td->scantime_index = -1;
td->mt_report_id = -1; td->mt_report_id = -1;
hid_set_drvdata(hdev, td); hid_set_drvdata(hdev, td);
...@@ -1649,14 +1754,6 @@ static const struct hid_device_id mt_devices[] = { ...@@ -1649,14 +1754,6 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, MT_USB_DEVICE(USB_VENDOR_ID_TURBOX,
USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
/* Panasonic panels */
{ .driver_data = MT_CLS_PANASONIC,
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
USB_DEVICE_ID_PANABOARD_UBT780) },
{ .driver_data = MT_CLS_PANASONIC,
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
USB_DEVICE_ID_PANABOARD_UBT880) },
/* Novatek Panel */ /* Novatek Panel */
{ .driver_data = MT_CLS_NSMU, { .driver_data = MT_CLS_NSMU,
MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK,
...@@ -1667,6 +1764,14 @@ static const struct hid_device_id mt_devices[] = { ...@@ -1667,6 +1764,14 @@ static const struct hid_device_id mt_devices[] = {
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
USB_VENDOR_ID_NTRIG, 0x1b05) }, USB_VENDOR_ID_NTRIG, 0x1b05) },
/* Panasonic panels */
{ .driver_data = MT_CLS_PANASONIC,
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
USB_DEVICE_ID_PANABOARD_UBT780) },
{ .driver_data = MT_CLS_PANASONIC,
MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC,
USB_DEVICE_ID_PANABOARD_UBT880) },
/* PixArt optical touch screen */ /* PixArt optical touch screen */
{ .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER,
MT_USB_DEVICE(USB_VENDOR_ID_PIXART, MT_USB_DEVICE(USB_VENDOR_ID_PIXART,
......
...@@ -90,6 +90,7 @@ static const struct hid_device_id hid_quirks[] = { ...@@ -90,6 +90,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
...@@ -284,7 +285,6 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -284,7 +285,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) }, { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) }, { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD) },
...@@ -335,6 +335,8 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -335,6 +335,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
#endif #endif
#if IS_ENABLED(CONFIG_HID_ELECOM) #if IS_ENABLED(CONFIG_HID_ELECOM)
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_EX_G_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_DEFT_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_HUGE_WIRED) },
...@@ -561,6 +563,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -561,6 +563,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
#if IS_ENABLED(CONFIG_HID_RMI) #if IS_ENABLED(CONFIG_HID_RMI)
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) }, { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_REZEL) },
#endif #endif
#if IS_ENABLED(CONFIG_HID_ROCCAT) #if IS_ENABLED(CONFIG_HID_ROCCAT)
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) }, { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
...@@ -730,7 +733,6 @@ static const struct hid_device_id hid_ignore_list[] = { ...@@ -730,7 +733,6 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) }, { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) }, { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
...@@ -998,6 +1000,17 @@ bool hid_ignore(struct hid_device *hdev) ...@@ -998,6 +1000,17 @@ bool hid_ignore(struct hid_device *hdev)
strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0) strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0)
return true; return true;
break; break;
case USB_VENDOR_ID_ELAN:
/*
* Many Elan devices have a product id of 0x0401 and are handled
* by the elan_i2c input driver. But the ACPI HID ELAN0800 dev
* is not (and cannot be) handled by that driver ->
* Ignore all 0x0401 devs except for the ELAN0800 dev.
*/
if (hdev->product == 0x0401 &&
strncmp(hdev->name, "ELAN0800", 8) != 0)
return true;
break;
} }
if (hdev->type == HID_TYPE_USBMOUSE && if (hdev->type == HID_TYPE_USBMOUSE &&
......
...@@ -731,6 +731,7 @@ static const struct hid_device_id rmi_id[] = { ...@@ -731,6 +731,7 @@ static const struct hid_device_id rmi_id[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14), { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14),
.driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS }, .driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_REZEL) },
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) },
{ } { }
}; };
......
...@@ -473,6 +473,7 @@ struct motion_output_report_02 { ...@@ -473,6 +473,7 @@ struct motion_output_report_02 {
#define DS4_FEATURE_REPORT_0x02_SIZE 37 #define DS4_FEATURE_REPORT_0x02_SIZE 37
#define DS4_FEATURE_REPORT_0x05_SIZE 41 #define DS4_FEATURE_REPORT_0x05_SIZE 41
#define DS4_FEATURE_REPORT_0x81_SIZE 7 #define DS4_FEATURE_REPORT_0x81_SIZE 7
#define DS4_FEATURE_REPORT_0xA3_SIZE 49
#define DS4_INPUT_REPORT_0x11_SIZE 78 #define DS4_INPUT_REPORT_0x11_SIZE 78
#define DS4_OUTPUT_REPORT_0x05_SIZE 32 #define DS4_OUTPUT_REPORT_0x05_SIZE 32
#define DS4_OUTPUT_REPORT_0x11_SIZE 78 #define DS4_OUTPUT_REPORT_0x11_SIZE 78
...@@ -544,6 +545,8 @@ struct sony_sc { ...@@ -544,6 +545,8 @@ struct sony_sc {
struct power_supply *battery; struct power_supply *battery;
struct power_supply_desc battery_desc; struct power_supply_desc battery_desc;
int device_id; int device_id;
unsigned fw_version;
unsigned hw_version;
u8 *output_report_dmabuf; u8 *output_report_dmabuf;
#ifdef CONFIG_SONY_FF #ifdef CONFIG_SONY_FF
...@@ -627,6 +630,29 @@ static ssize_t ds4_store_poll_interval(struct device *dev, ...@@ -627,6 +630,29 @@ static ssize_t ds4_store_poll_interval(struct device *dev,
static DEVICE_ATTR(bt_poll_interval, 0644, ds4_show_poll_interval, static DEVICE_ATTR(bt_poll_interval, 0644, ds4_show_poll_interval,
ds4_store_poll_interval); ds4_store_poll_interval);
static ssize_t sony_show_firmware_version(struct device *dev,
struct device_attribute
*attr, char *buf)
{
struct hid_device *hdev = to_hid_device(dev);
struct sony_sc *sc = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "0x%04x\n", sc->fw_version);
}
static DEVICE_ATTR(firmware_version, 0444, sony_show_firmware_version, NULL);
static ssize_t sony_show_hardware_version(struct device *dev,
struct device_attribute
*attr, char *buf)
{
struct hid_device *hdev = to_hid_device(dev);
struct sony_sc *sc = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "0x%04x\n", sc->hw_version);
}
static DEVICE_ATTR(hardware_version, 0444, sony_show_hardware_version, NULL);
static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc, static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc,
unsigned int *rsize) unsigned int *rsize)
...@@ -1646,6 +1672,31 @@ static void dualshock4_calibration_work(struct work_struct *work) ...@@ -1646,6 +1672,31 @@ static void dualshock4_calibration_work(struct work_struct *work)
spin_unlock_irqrestore(&sc->lock, flags); spin_unlock_irqrestore(&sc->lock, flags);
} }
static int dualshock4_get_version_info(struct sony_sc *sc)
{
u8 *buf;
int ret;
buf = kmalloc(DS4_FEATURE_REPORT_0xA3_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = hid_hw_raw_request(sc->hdev, 0xA3, buf,
DS4_FEATURE_REPORT_0xA3_SIZE,
HID_FEATURE_REPORT,
HID_REQ_GET_REPORT);
if (ret < 0) {
kfree(buf);
return ret;
}
sc->hw_version = get_unaligned_le16(&buf[35]);
sc->fw_version = get_unaligned_le16(&buf[41]);
kfree(buf);
return 0;
}
static void sixaxis_set_leds_from_id(struct sony_sc *sc) static void sixaxis_set_leds_from_id(struct sony_sc *sc)
{ {
static const u8 sixaxis_leds[10][4] = { static const u8 sixaxis_leds[10][4] = {
...@@ -2619,6 +2670,28 @@ static int sony_input_configured(struct hid_device *hdev, ...@@ -2619,6 +2670,28 @@ static int sony_input_configured(struct hid_device *hdev,
goto err_stop; goto err_stop;
} }
ret = dualshock4_get_version_info(sc);
if (ret < 0) {
hid_err(sc->hdev, "Failed to get version data from Dualshock 4\n");
goto err_stop;
}
ret = device_create_file(&sc->hdev->dev, &dev_attr_firmware_version);
if (ret) {
/* Make zero for cleanup reasons of sysfs entries. */
sc->fw_version = 0;
sc->hw_version = 0;
hid_err(sc->hdev, "can't create sysfs firmware_version attribute err: %d\n", ret);
goto err_stop;
}
ret = device_create_file(&sc->hdev->dev, &dev_attr_hardware_version);
if (ret) {
sc->hw_version = 0;
hid_err(sc->hdev, "can't create sysfs hardware_version attribute err: %d\n", ret);
goto err_stop;
}
/* /*
* The Dualshock 4 touchpad supports 2 touches and has a * The Dualshock 4 touchpad supports 2 touches and has a
* resolution of 1920x942 (44.86 dots/mm). * resolution of 1920x942 (44.86 dots/mm).
...@@ -2695,6 +2768,10 @@ static int sony_input_configured(struct hid_device *hdev, ...@@ -2695,6 +2768,10 @@ static int sony_input_configured(struct hid_device *hdev,
*/ */
if (sc->ds4_bt_poll_interval) if (sc->ds4_bt_poll_interval)
device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval);
if (sc->fw_version)
device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version);
if (sc->hw_version)
device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version);
if (sc->quirks & SONY_LED_SUPPORT) if (sc->quirks & SONY_LED_SUPPORT)
sony_leds_remove(sc); sony_leds_remove(sc);
if (sc->quirks & SONY_BATTERY_SUPPORT) if (sc->quirks & SONY_BATTERY_SUPPORT)
...@@ -2796,6 +2873,12 @@ static void sony_remove(struct hid_device *hdev) ...@@ -2796,6 +2873,12 @@ static void sony_remove(struct hid_device *hdev)
if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) if (sc->quirks & DUALSHOCK4_CONTROLLER_BT)
device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval);
if (sc->fw_version)
device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version);
if (sc->hw_version)
device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version);
sony_cancel_work_sync(sc); sony_cancel_work_sync(sc);
kfree(sc->output_report_dmabuf); kfree(sc->output_report_dmabuf);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#define SPT_Ax_DEVICE_ID 0x9D35 #define SPT_Ax_DEVICE_ID 0x9D35
#define CNL_Ax_DEVICE_ID 0x9DFC #define CNL_Ax_DEVICE_ID 0x9DFC
#define GLK_Ax_DEVICE_ID 0x31A2 #define GLK_Ax_DEVICE_ID 0x31A2
#define CNL_H_DEVICE_ID 0xA37C
#define REVISION_ID_CHT_A0 0x6 #define REVISION_ID_CHT_A0 0x6
#define REVISION_ID_CHT_Ax_SI 0x0 #define REVISION_ID_CHT_Ax_SI 0x0
......
...@@ -37,6 +37,7 @@ static const struct pci_device_id ish_pci_tbl[] = { ...@@ -37,6 +37,7 @@ static const struct pci_device_id ish_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_Ax_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_Ax_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_Ax_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_Ax_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, GLK_Ax_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, GLK_Ax_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_H_DEVICE_ID)},
{0, } {0, }
}; };
MODULE_DEVICE_TABLE(pci, ish_pci_tbl); MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
......
...@@ -281,6 +281,7 @@ struct hid_item { ...@@ -281,6 +281,7 @@ struct hid_item {
#define HID_DG_DEVICECONFIG 0x000d000e #define HID_DG_DEVICECONFIG 0x000d000e
#define HID_DG_DEVICESETTINGS 0x000d0023 #define HID_DG_DEVICESETTINGS 0x000d0023
#define HID_DG_AZIMUTH 0x000d003f
#define HID_DG_CONFIDENCE 0x000d0047 #define HID_DG_CONFIDENCE 0x000d0047
#define HID_DG_WIDTH 0x000d0048 #define HID_DG_WIDTH 0x000d0048
#define HID_DG_HEIGHT 0x000d0049 #define HID_DG_HEIGHT 0x000d0049
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment