From f8e86d054686d9090549476ea2394aa04c614a93 Mon Sep 17 00:00:00 2001 From: Ingo Ruhnke Date: Mon, 29 Oct 2012 14:29:30 +0100 Subject: HID: fix incorrect handling of devices with high button count Button names for USB gamepads are currently assigned incorrectly, as the evdev code assigned to buttons is "BTN_GAMEPAD + code", which on devices with more then 16 buttons bleeds over into button names reserved for graphic tablets (BTN_TOOL_PEN, etc.). This causes problems further down the line as the device are now no longer detected as joystick. This patch fixes that by assigning buttons outside the range to BTN_TRIGGER_HAPPY (as is already the case for USB joysticks). Furthermore this patch corrects the assignment to BTN_TRIGGER_HAPPY, as currently the first button over 16 is assigned to BTN_TRIGGER_HAPPY17 (i.e. BTN_TRIGGER_HAPPY+0x10) not BTN_TRIGGER_HAPPY. Signed-off-by: Ingo Ruhnke Acked-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/hid/hid-input.c') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d917c0d53685..10248cf548fc 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -502,9 +502,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel if (code <= 0xf) code += BTN_JOYSTICK; else - code += BTN_TRIGGER_HAPPY; + code += BTN_TRIGGER_HAPPY - 0x10; + break; + case HID_GD_GAMEPAD: + if (code <= 0xf) + code += BTN_GAMEPAD; + else + code += BTN_TRIGGER_HAPPY - 0x10; break; - case HID_GD_GAMEPAD: code += BTN_GAMEPAD; break; default: switch (field->physical) { case HID_GD_MOUSE: -- cgit v1.2.2 From 37cf6e6fc34e2fca4e7c565697e7cd5c317bc316 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 14 Nov 2012 16:59:13 +0100 Subject: HID: export hidinput_calc_abs_res Exporting the function allows us to calculate the resolution in third party drivers like hid-multitouch. This patch also complete the function with additional valid axes. Signed-off-by: Benjamin Tissoires Acked-by: Jiri Kosina Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/hid/hid-input.c') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d917c0d53685..d1ec571bdb3b 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -208,7 +208,7 @@ static int hidinput_setkeycode(struct input_dev *dev, * Only exponent 1 length units are processed. Centimeters and inches are * converted to millimeters. Degrees are converted to radians. */ -static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) +__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) { __s32 unit_exponent = field->unit_exponent; __s32 logical_extents = field->logical_maximum - @@ -229,6 +229,12 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) case ABS_X: case ABS_Y: case ABS_Z: + case ABS_MT_POSITION_X: + case ABS_MT_POSITION_Y: + case ABS_MT_TOOL_X: + case ABS_MT_TOOL_Y: + case ABS_MT_TOUCH_MAJOR: + case ABS_MT_TOUCH_MINOR: if (field->unit == 0x11) { /* If centimeters */ /* Convert to millimeters */ unit_exponent += 1; @@ -283,6 +289,7 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) /* Calculate resolution */ return logical_extents / physical_extents; } +EXPORT_SYMBOL_GPL(hidinput_calc_abs_res); #ifdef CONFIG_HID_BATTERY_STRENGTH static enum power_supply_property hidinput_battery_props[] = { -- cgit v1.2.2 From ccdd699411b77c463022ebac311eb4a06ca56db4 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 14 Nov 2012 16:59:14 +0100 Subject: HID: round return value of hidinput_calc_abs_res hidinput_calc_abs_res should return the closest int in the division instead of the floor. On a device with a logical_max of 3008 and a physical_max of 255mm, previous implementation gave a resolution of 11 instead of 12. With 11, user-space computes a physical size of 273.5mm and the round_closest results gives 250.6mm. The old implementation introduced an error of 2cm in this example. Signed-off-by: Benjamin Tissoires Acked-by: Jiri Kosina Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid/hid-input.c') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d1ec571bdb3b..1b0adc3f7803 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -287,7 +287,7 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) } /* Calculate resolution */ - return logical_extents / physical_extents; + return DIV_ROUND_CLOSEST(logical_extents, physical_extents); } EXPORT_SYMBOL_GPL(hidinput_calc_abs_res); -- cgit v1.2.2 From 774638386826621c984ab6994439f474709cac5e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 14 Nov 2012 16:59:15 +0100 Subject: HID: fix unit exponent parsing HID spec details special values for the HID field unit exponent. Basically, the range [0x8..0xf] correspond to [-8..-1], so this is a standard two's complement on a half-byte. Signed-off-by: Benjamin Tissoires Acked-by: Jiri Kosina Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/hid/hid-input.c') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 1b0adc3f7803..007a9433bfa7 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -192,7 +192,6 @@ static int hidinput_setkeycode(struct input_dev *dev, return -EINVAL; } - /** * hidinput_calc_abs_res - calculate an absolute axis resolution * @field: the HID report field to calculate resolution for @@ -235,17 +234,23 @@ __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) case ABS_MT_TOOL_Y: case ABS_MT_TOUCH_MAJOR: case ABS_MT_TOUCH_MINOR: - if (field->unit == 0x11) { /* If centimeters */ + if (field->unit & 0xffffff00) /* Not a length */ + return 0; + unit_exponent += hid_snto32(field->unit >> 4, 4) - 1; + switch (field->unit & 0xf) { + case 0x1: /* If centimeters */ /* Convert to millimeters */ unit_exponent += 1; - } else if (field->unit == 0x13) { /* If inches */ + break; + case 0x3: /* If inches */ /* Convert to millimeters */ prev = physical_extents; physical_extents *= 254; if (physical_extents < prev) return 0; unit_exponent -= 1; - } else { + break; + default: return 0; } break; -- cgit v1.2.2 From 4cc8541782140e9ccbece5c8ac367fbf659b16d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ortwin=20Gl=C3=BCck?= Date: Sun, 25 Nov 2012 15:08:34 +0100 Subject: HID: add battery quirk for Apple 2009_ISO keyboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support battery capacity on another Apple wireless keyboard. Signed-off-by: Ortwin Glück Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/hid/hid-input.c') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 10248cf548fc..0887b52f804b 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -298,6 +298,9 @@ static enum power_supply_property hidinput_battery_props[] = { #define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */ 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 }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, -- cgit v1.2.2 From ae751fa82dd8e5a79932d6b55742e7e298afd733 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 23 Nov 2012 16:31:24 +0100 Subject: HID: hid-input: factorize hid_input allocation This just refactors the allocation of hid_input. No semantic changes. Signed-off-by: Benjamin Tissoires Reviewed-by: Henrik Rydberg Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 61 +++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 27 deletions(-) (limited to 'drivers/hid/hid-input.c') diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 0887b52f804b..97c08c5d0973 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1154,6 +1154,38 @@ static void report_features(struct hid_device *hid) } } +static struct hid_input *hidinput_allocate(struct hid_device *hid) +{ + struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); + struct input_dev *input_dev = input_allocate_device(); + if (!hidinput || !input_dev) { + kfree(hidinput); + input_free_device(input_dev); + hid_err(hid, "Out of memory during hid input probe\n"); + return NULL; + } + + input_set_drvdata(input_dev, hid); + input_dev->event = hid->ll_driver->hidinput_input_event; + input_dev->open = hidinput_open; + input_dev->close = hidinput_close; + input_dev->setkeycode = hidinput_setkeycode; + input_dev->getkeycode = hidinput_getkeycode; + + input_dev->name = hid->name; + input_dev->phys = hid->phys; + input_dev->uniq = hid->uniq; + input_dev->id.bustype = hid->bus; + input_dev->id.vendor = hid->vendor; + input_dev->id.product = hid->product; + input_dev->id.version = hid->version; + input_dev->dev.parent = hid->dev.parent; + hidinput->input = input_dev; + list_add_tail(&hidinput->list, &hid->inputs); + + return hidinput; +} + /* * Register the input device; print a message. * Configure the input layer interface @@ -1165,7 +1197,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) struct hid_driver *drv = hid->driver; struct hid_report *report; struct hid_input *hidinput = NULL; - struct input_dev *input_dev; int i, j, k; INIT_LIST_HEAD(&hid->inputs); @@ -1196,33 +1227,9 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) continue; if (!hidinput) { - hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!hidinput || !input_dev) { - kfree(hidinput); - input_free_device(input_dev); - hid_err(hid, "Out of memory during hid input probe\n"); + hidinput = hidinput_allocate(hid); + if (!hidinput) goto out_unwind; - } - - input_set_drvdata(input_dev, hid); - input_dev->event = - hid->ll_driver->hidinput_input_event; - input_dev->open = hidinput_open; - input_dev->close = hidinput_close; - input_dev->setkeycode = hidinput_setkeycode; - input_dev->getkeycode = hidinput_getkeycode; - - input_dev->name = hid->name; - input_dev->phys = hid->phys; - input_dev->uniq = hid->uniq; - input_dev->id.bustype = hid->bus; - input_dev->id.vendor = hid->vendor; - input_dev->id.product = hid->product; - input_dev->id.version = hid->version; - input_dev->dev.parent = hid->dev.parent; - hidinput->input = input_dev; - list_add_tail(&hidinput->list, &hid->inputs); } for (i = 0; i < report->maxfield; i++) -- cgit v1.2.2