Commit c21c9fee authored by Benjamin Tissoires's avatar Benjamin Tissoires

Merge branch 'for-6.3/multitouch' into for-linus

Allow to pass quirks from i2c-hid to hid-multitouch (Allen Ballway &
Dmitry Torokhov)
parents 3ba2824c 03a86105
...@@ -71,6 +71,7 @@ MODULE_LICENSE("GPL"); ...@@ -71,6 +71,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_SEPARATE_APP_REPORT BIT(19) #define MT_QUIRK_SEPARATE_APP_REPORT BIT(19)
#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20) #define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
#define MT_QUIRK_DISABLE_WAKEUP BIT(21) #define MT_QUIRK_DISABLE_WAKEUP BIT(21)
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
#define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03 #define MT_INPUTMODE_TOUCHPAD 0x03
...@@ -1009,6 +1010,7 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, ...@@ -1009,6 +1010,7 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
struct mt_usages *slot) struct mt_usages *slot)
{ {
struct input_mt *mt = input->mt; struct input_mt *mt = input->mt;
struct hid_device *hdev = td->hdev;
__s32 quirks = app->quirks; __s32 quirks = app->quirks;
bool valid = true; bool valid = true;
bool confidence_state = true; bool confidence_state = true;
...@@ -1086,6 +1088,10 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, ...@@ -1086,6 +1088,10 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
int orientation = wide; int orientation = wide;
int max_azimuth; int max_azimuth;
int azimuth; int azimuth;
int x;
int y;
int cx;
int cy;
if (slot->a != DEFAULT_ZERO) { if (slot->a != DEFAULT_ZERO) {
/* /*
...@@ -1104,6 +1110,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, ...@@ -1104,6 +1110,9 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
if (azimuth > max_azimuth * 2) if (azimuth > max_azimuth * 2)
azimuth -= max_azimuth * 4; azimuth -= max_azimuth * 4;
orientation = -azimuth; orientation = -azimuth;
if (quirks & MT_QUIRK_ORIENTATION_INVERT)
orientation = -orientation;
} }
if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) { if (quirks & MT_QUIRK_TOUCH_SIZE_SCALING) {
...@@ -1115,10 +1124,23 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input, ...@@ -1115,10 +1124,23 @@ static int mt_process_slot(struct mt_device *td, struct input_dev *input,
minor = minor >> 1; minor = minor >> 1;
} }
input_event(input, EV_ABS, ABS_MT_POSITION_X, *slot->x); x = hdev->quirks & HID_QUIRK_X_INVERT ?
input_event(input, EV_ABS, ABS_MT_POSITION_Y, *slot->y); input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->x :
input_event(input, EV_ABS, ABS_MT_TOOL_X, *slot->cx); *slot->x;
input_event(input, EV_ABS, ABS_MT_TOOL_Y, *slot->cy); y = hdev->quirks & HID_QUIRK_Y_INVERT ?
input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->y :
*slot->y;
cx = hdev->quirks & HID_QUIRK_X_INVERT ?
input_abs_get_max(input, ABS_MT_POSITION_X) - *slot->cx :
*slot->cx;
cy = hdev->quirks & HID_QUIRK_Y_INVERT ?
input_abs_get_max(input, ABS_MT_POSITION_Y) - *slot->cy :
*slot->cy;
input_event(input, EV_ABS, ABS_MT_POSITION_X, x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, y);
input_event(input, EV_ABS, ABS_MT_TOOL_X, cx);
input_event(input, EV_ABS, ABS_MT_TOOL_Y, cy);
input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state); input_event(input, EV_ABS, ABS_MT_DISTANCE, !*slot->tip_state);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation); input_event(input, EV_ABS, ABS_MT_ORIENTATION, orientation);
input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p); input_event(input, EV_ABS, ABS_MT_PRESSURE, *slot->p);
...@@ -1735,6 +1757,15 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -1735,6 +1757,15 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
td->serial_maybe = true; td->serial_maybe = true;
/* Orientation is inverted if the X or Y axes are
* flipped, but normalized if both are inverted.
*/
if (hdev->quirks & (HID_QUIRK_X_INVERT | HID_QUIRK_Y_INVERT) &&
!((hdev->quirks & HID_QUIRK_X_INVERT)
&& (hdev->quirks & HID_QUIRK_Y_INVERT)))
td->mtclass.quirks = MT_QUIRK_ORIENTATION_INVERT;
/* This allows the driver to correctly support devices /* This allows the driver to correctly support devices
* that emit events over several HID messages. * that emit events over several HID messages.
*/ */
......
...@@ -1237,7 +1237,7 @@ EXPORT_SYMBOL_GPL(hid_quirks_exit); ...@@ -1237,7 +1237,7 @@ EXPORT_SYMBOL_GPL(hid_quirks_exit);
static unsigned long hid_gets_squirk(const struct hid_device *hdev) static unsigned long hid_gets_squirk(const struct hid_device *hdev)
{ {
const struct hid_device_id *bl_entry; const struct hid_device_id *bl_entry;
unsigned long quirks = 0; unsigned long quirks = hdev->initial_quirks;
if (hid_match_id(hdev, hid_ignore_list)) if (hid_match_id(hdev, hid_ignore_list))
quirks |= HID_QUIRK_IGNORE; quirks |= HID_QUIRK_IGNORE;
......
...@@ -1025,6 +1025,10 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops, ...@@ -1025,6 +1025,10 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID); hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID);
hid->product = le16_to_cpu(ihid->hdesc.wProductID); hid->product = le16_to_cpu(ihid->hdesc.wProductID);
hid->initial_quirks = quirks;
hid->initial_quirks |= i2c_hid_get_dmi_quirks(hid->vendor,
hid->product);
snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X",
client->name, (u16)hid->vendor, (u16)hid->product); client->name, (u16)hid->vendor, (u16)hid->product);
strscpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys)); strscpy(hid->phys, dev_name(&client->dev), sizeof(hid->phys));
...@@ -1038,8 +1042,6 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops, ...@@ -1038,8 +1042,6 @@ int i2c_hid_core_probe(struct i2c_client *client, struct i2chid_ops *ops,
goto err_mem_free; goto err_mem_free;
} }
hid->quirks |= quirks;
return 0; return 0;
err_mem_free: err_mem_free:
......
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/hid.h>
#include "i2c-hid.h" #include "i2c-hid.h"
#include "../hid-ids.h"
struct i2c_hid_desc_override { struct i2c_hid_desc_override {
...@@ -416,6 +418,28 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { ...@@ -416,6 +418,28 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
{ } /* Terminate list */ { } /* Terminate list */
}; };
static const struct hid_device_id i2c_hid_elan_flipped_quirks = {
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_ELAN, 0x2dcd),
HID_QUIRK_X_INVERT | HID_QUIRK_Y_INVERT
};
/*
* This list contains devices which have specific issues based on the system
* they're on and not just the device itself. The driver_data will have a
* specific hid device to match against.
*/
static const struct dmi_system_id i2c_hid_dmi_quirk_table[] = {
{
.ident = "DynaBook K50/FR",
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dynabook Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "dynabook K50/FR"),
},
.driver_data = (void *)&i2c_hid_elan_flipped_quirks,
},
{ } /* Terminate list */
};
struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
{ {
...@@ -450,3 +474,21 @@ char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, ...@@ -450,3 +474,21 @@ char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
*size = override->hid_report_desc_size; *size = override->hid_report_desc_size;
return override->hid_report_desc; return override->hid_report_desc;
} }
u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)
{
u32 quirks = 0;
const struct dmi_system_id *system_id =
dmi_first_match(i2c_hid_dmi_quirk_table);
if (system_id) {
const struct hid_device_id *device_id =
(struct hid_device_id *)(system_id->driver_data);
if (device_id && device_id->vendor == vendor &&
device_id->product == product)
quirks = device_id->driver_data;
}
return quirks;
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name); struct i2c_hid_desc *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name);
char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
unsigned int *size); unsigned int *size);
u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product);
#else #else
static inline struct i2c_hid_desc static inline struct i2c_hid_desc
*i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name) *i2c_hid_get_dmi_i2c_hid_desc_override(uint8_t *i2c_name)
...@@ -16,6 +17,8 @@ static inline struct i2c_hid_desc ...@@ -16,6 +17,8 @@ static inline struct i2c_hid_desc
static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name, static inline char *i2c_hid_get_dmi_hid_report_desc_override(uint8_t *i2c_name,
unsigned int *size) unsigned int *size)
{ return NULL; } { return NULL; }
static inline u32 i2c_hid_get_dmi_quirks(const u16 vendor, const u16 product)
{ return 0; }
#endif #endif
/** /**
......
...@@ -621,6 +621,7 @@ struct hid_device { /* device report descriptor */ ...@@ -621,6 +621,7 @@ struct hid_device { /* device report descriptor */
unsigned long status; /* see STAT flags above */ unsigned long status; /* see STAT flags above */
unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */ unsigned quirks; /* Various quirks the device can pull on us */
unsigned initial_quirks; /* Initial set of quirks supplied when creating device */
bool io_started; /* If IO has started */ bool io_started; /* If IO has started */
struct list_head inputs; /* The list of inputs */ struct list_head inputs; /* The list of inputs */
......
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