diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-24 12:44:59 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-24 12:44:59 -0700 |
commit | 7c024e9534f9edd8d052380a1b40d376c8feb11b (patch) | |
tree | 521eeb9d1eaa851e254a372bd008a07ab1f5e574 /drivers/hid/hid-input.c | |
parent | 188e213dbc5758bbfb62f7ce0367c5c8de057f02 (diff) | |
parent | d8692ac012104ebffb343c0bcb4a2b8642c821a6 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (47 commits)
HID: fix mismerge in hid-lg
HID: hidraw: fix window in hidraw_release
HID: hid-sony: override usbhid_output_raw_report for Sixaxis
HID: add absolute axis resolution calculation
HID: force feedback support for Logitech RumblePad gamepad
HID: support STmicroelectronics and Sitronix with hid-stantuml driver
HID: magicmouse: Adjust major / minor axes to scale
HID: Fix for problems with eGalax/DWAV multi-touch-screen
HID: waltop: add support for Waltop Slim Tablet 12.1 inch
HID: add NOGET quirk for AXIS 295 Video Surveillance Joystick
HID: usbhid: remove unused hiddev_driver
HID: magicmouse: Use hid-input parsing rather than bypassing it
HID: trivial formatting fix
HID: Add support for Logitech Speed Force Wireless gaming wheel
HID: don't Send Feature Reports on Interrupt Endpoint
HID: 3m: Adjust major / minor axes to scale
HID: 3m: Correct touchscreen emulation
HID: 3m: Convert to MT slots
HID: 3m: Output proper orientation range
HID: 3m: Adjust to sequential MT HID protocol
...
Diffstat (limited to 'drivers/hid/hid-input.c')
-rw-r--r-- | drivers/hid/hid-input.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 6c03dcc5760..834ef47b76d 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -149,6 +149,83 @@ static int hidinput_setkeycode(struct input_dev *dev, } +/** + * hidinput_calc_abs_res - calculate an absolute axis resolution + * @field: the HID report field to calculate resolution for + * @code: axis code + * + * The formula is: + * (logical_maximum - logical_minimum) + * resolution = ---------------------------------------------------------- + * (physical_maximum - physical_minimum) * 10 ^ unit_exponent + * + * as seen in the HID specification v1.11 6.2.2.7 Global Items. + * + * Only exponent 1 length units are processed. Centimeters are converted to + * inches. Degrees are converted to radians. + */ +static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) +{ + __s32 unit_exponent = field->unit_exponent; + __s32 logical_extents = field->logical_maximum - + field->logical_minimum; + __s32 physical_extents = field->physical_maximum - + field->physical_minimum; + __s32 prev; + + /* Check if the extents are sane */ + if (logical_extents <= 0 || physical_extents <= 0) + return 0; + + /* + * Verify and convert units. + * See HID specification v1.11 6.2.2.7 Global Items for unit decoding + */ + if (code == ABS_X || code == ABS_Y || code == ABS_Z) { + if (field->unit == 0x11) { /* If centimeters */ + /* Convert to inches */ + prev = logical_extents; + logical_extents *= 254; + if (logical_extents < prev) + return 0; + unit_exponent += 2; + } else if (field->unit != 0x13) { /* If not inches */ + return 0; + } + } else if (code == ABS_RX || code == ABS_RY || code == ABS_RZ) { + if (field->unit == 0x14) { /* If degrees */ + /* Convert to radians */ + prev = logical_extents; + logical_extents *= 573; + if (logical_extents < prev) + return 0; + unit_exponent += 1; + } else if (field->unit != 0x12) { /* If not radians */ + return 0; + } + } else { + return 0; + } + + /* Apply negative unit exponent */ + for (; unit_exponent < 0; unit_exponent++) { + prev = logical_extents; + logical_extents *= 10; + if (logical_extents < prev) + return 0; + } + /* Apply positive unit exponent */ + for (; unit_exponent > 0; unit_exponent--) { + prev = physical_extents; + physical_extents *= 10; + if (physical_extents < prev) + return 0; + } + + /* Calculate resolution */ + return logical_extents / physical_extents; +} + static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, struct hid_usage *usage) { @@ -336,6 +413,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel map_key_clear(BTN_STYLUS); break; + case 0x46: /* TabletPick */ + map_key_clear(BTN_STYLUS2); + break; + default: goto unknown; } break; @@ -537,6 +618,9 @@ mapped: input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4); else input_set_abs_params(input, usage->code, a, b, 0, 0); + input_abs_set_res(input, usage->code, + hidinput_calc_abs_res(field, usage->code)); + /* use a larger default input buffer for MT devices */ if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0) input_set_events_per_packet(input, 60); @@ -659,6 +743,9 @@ void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { struct hid_input *hidinput; + if (hid->quirks & HID_QUIRK_NO_INPUT_SYNC) + return; + list_for_each_entry(hidinput, &hid->inputs, list) input_sync(hidinput->input); } |