summaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-input.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid/hid-input.c')
-rw-r--r--drivers/hid/hid-input.c97
1 files changed, 62 insertions, 35 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d917c0d5368..21b196c394b 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
@@ -208,7 +207,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,17 +228,29 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
case ABS_X:
case ABS_Y:
case ABS_Z:
- if (field->unit == 0x11) { /* If centimeters */
+ 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 & 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;
@@ -281,8 +292,9 @@ static __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);
#ifdef CONFIG_HID_BATTERY_STRENGTH
static enum power_supply_property hidinput_battery_props[] = {
@@ -299,6 +311,9 @@ 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 },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
@@ -502,9 +517,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:
@@ -1146,6 +1166,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
@@ -1157,7 +1209,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);
@@ -1188,33 +1239,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++)