From 7957e9c4d175cc065f4277211fcb7d784fcee860 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 2 Aug 2010 19:33:51 -0700 Subject: [PATCH 01/10] Input: add static inline accessors for ABS properties In preparation for dynamically allocated ABS axis, introduce a number of static inline access helpers. This should make the transition less painful. Signed-off-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/include/linux/input.h b/include/linux/input.h index 339d043ccb53..4a5531161de1 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1469,6 +1469,36 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); } +#define INPUT_GENERATE_ABS_ACCESSORS(_suffix, _item) \ +static inline int input_abs_get_##_suffix(struct input_dev *dev, \ + unsigned int axis) \ +{ \ + return dev->abs##_item[axis]; \ +} \ + \ +static inline void input_abs_set_##_suffix(struct input_dev *dev, \ + unsigned int axis, int val) \ +{ \ + dev->abs##_item[axis] = val; \ +} + +INPUT_GENERATE_ABS_ACCESSORS(min, min) +INPUT_GENERATE_ABS_ACCESSORS(max, max) +INPUT_GENERATE_ABS_ACCESSORS(fuzz, fuzz) +INPUT_GENERATE_ABS_ACCESSORS(flat, flat) +INPUT_GENERATE_ABS_ACCESSORS(res, res) + +static inline int input_abs_get_val(struct input_dev *dev, unsigned int axis) +{ + return dev->abs[axis]; +} + +static inline void input_abs_set_val(struct input_dev *dev, + unsigned int axis, int val) +{ + dev->abs[axis] = val; +} + int input_get_keycode(struct input_dev *dev, unsigned int scancode, unsigned int *keycode); int input_set_keycode(struct input_dev *dev, From 987a6c0298260b7aa40702b349282554d6180e4b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 2 Aug 2010 20:15:17 -0700 Subject: [PATCH 02/10] Input: switch to input_abs_*() access functions Change all call sites in drivers/input to not access the ABS axis information directly anymore. Make them use the access helpers instead. Also use input_set_abs_params() when possible. Did some code refactoring as I was on it. Signed-off-by: Daniel Mack Cc: Dmitry Torokhov Signed-off-by: Dmitry Torokhov --- drivers/hid/hid-wacom.c | 49 ++++++++++++++--------------- drivers/input/evdev.c | 26 +++++++-------- drivers/input/input.c | 4 +-- drivers/input/joydev.c | 31 +++++++++--------- drivers/input/joystick/a3d.c | 3 +- drivers/input/joystick/adi.c | 2 +- drivers/input/joystick/amijoy.c | 4 +-- drivers/input/joystick/gf2k.c | 20 ++++++------ drivers/input/joystick/interact.c | 14 +++------ drivers/input/joystick/sidewinder.c | 18 ++++++----- drivers/input/keyboard/hil_kbd.c | 21 +++++++------ drivers/input/misc/uinput.c | 29 ++++++++++------- drivers/input/mouse/pc110pad.c | 4 +-- drivers/input/mouse/synaptics.c | 4 +-- drivers/input/mousedev.c | 44 +++++++++++++++----------- drivers/input/tablet/aiptek.c | 15 ++++----- drivers/input/tablet/wacom_wac.c | 4 +-- 17 files changed, 153 insertions(+), 139 deletions(-) diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 1e051f1171e4..1c4b4ca19195 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -230,7 +230,7 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, input_report_key(input, BTN_RIGHT, 0); input_report_key(input, BTN_MIDDLE, 0); input_report_abs(input, ABS_DISTANCE, - input->absmax[ABS_DISTANCE]); + input_abs_get_max(input, ABS_DISTANCE)); } else { input_report_key(input, BTN_TOUCH, 0); input_report_key(input, BTN_STYLUS, 0); @@ -383,38 +383,37 @@ static int wacom_probe(struct hid_device *hdev, /* Basics */ input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL); - input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | - BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE); - input->relbit[0] |= BIT(REL_WHEEL); - set_bit(BTN_TOOL_PEN, input->keybit); - set_bit(BTN_TOUCH, input->keybit); - set_bit(BTN_STYLUS, input->keybit); - set_bit(BTN_STYLUS2, input->keybit); - set_bit(BTN_LEFT, input->keybit); - set_bit(BTN_RIGHT, input->keybit); - set_bit(BTN_MIDDLE, input->keybit); + + __set_bit(REL_WHEEL, input->relbit); + + __set_bit(BTN_TOOL_PEN, input->keybit); + __set_bit(BTN_TOUCH, input->keybit); + __set_bit(BTN_STYLUS, input->keybit); + __set_bit(BTN_STYLUS2, input->keybit); + __set_bit(BTN_LEFT, input->keybit); + __set_bit(BTN_RIGHT, input->keybit); + __set_bit(BTN_MIDDLE, input->keybit); /* Pad */ input->evbit[0] |= BIT(EV_MSC); - input->mscbit[0] |= BIT(MSC_SERIAL); - set_bit(BTN_0, input->keybit); - set_bit(BTN_1, input->keybit); - set_bit(BTN_TOOL_FINGER, input->keybit); + + __set_bit(MSC_SERIAL, input->mscbit); + + __set_bit(BTN_0, input->keybit); + __set_bit(BTN_1, input->keybit); + __set_bit(BTN_TOOL_FINGER, input->keybit); /* Distance, rubber and mouse */ - input->absbit[0] |= BIT(ABS_DISTANCE); - set_bit(BTN_TOOL_RUBBER, input->keybit); - set_bit(BTN_TOOL_MOUSE, input->keybit); + __set_bit(BTN_TOOL_RUBBER, input->keybit); + __set_bit(BTN_TOOL_MOUSE, input->keybit); - input->absmax[ABS_PRESSURE] = 511; - input->absmax[ABS_DISTANCE] = 32; - - input->absmax[ABS_X] = 16704; - input->absmax[ABS_Y] = 12064; - input->absfuzz[ABS_X] = 4; - input->absfuzz[ABS_Y] = 4; + input_set_abs_params(input, ABS_X, 0, 16704, 4, 0); + input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0); + input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0); return 0; + err_free: kfree(wdata); return ret; diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 054edf346e0b..9807c8ff6a84 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -650,12 +650,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, t = _IOC_NR(cmd) & ABS_MAX; - abs.value = dev->abs[t]; - abs.minimum = dev->absmin[t]; - abs.maximum = dev->absmax[t]; - abs.fuzz = dev->absfuzz[t]; - abs.flat = dev->absflat[t]; - abs.resolution = dev->absres[t]; + abs.value = input_abs_get_val(dev, t); + abs.minimum = input_abs_get_min(dev, t); + abs.maximum = input_abs_get_max(dev, t); + abs.fuzz = input_abs_get_fuzz(dev, t); + abs.flat = input_abs_get_flat(dev, t); + abs.resolution = input_abs_get_res(dev, t); if (copy_to_user(p, &abs, min_t(size_t, _IOC_SIZE(cmd), @@ -702,13 +702,13 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, */ spin_lock_irq(&dev->event_lock); - dev->abs[t] = abs.value; - dev->absmin[t] = abs.minimum; - dev->absmax[t] = abs.maximum; - dev->absfuzz[t] = abs.fuzz; - dev->absflat[t] = abs.flat; - dev->absres[t] = _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ? - 0 : abs.resolution; + input_abs_set_val(dev, t, abs.value); + input_abs_set_min(dev, t, abs.minimum); + input_abs_set_max(dev, t, abs.maximum); + input_abs_set_fuzz(dev, t, abs.fuzz); + input_abs_set_flat(dev, t, abs.flat); + input_abs_set_res(dev, t, _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ? + 0 : abs.resolution); spin_unlock_irq(&dev->event_lock); diff --git a/drivers/input/input.c b/drivers/input/input.c index e1243b4b32a5..7259adb8619d 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -204,8 +204,8 @@ static int input_handle_abs_event(struct input_dev *dev, } /* Flush pending "slot" event */ - if (is_mt_event && dev->slot != dev->abs[ABS_MT_SLOT]) { - dev->abs[ABS_MT_SLOT] = dev->slot; + if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) { + input_abs_set_val(dev, ABS_MT_SLOT, dev->slot); input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot); } diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 63834585c283..d85bd8a7967d 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -530,7 +530,7 @@ static int joydev_ioctl_common(struct joydev *joydev, { struct input_dev *dev = joydev->handle.dev; size_t len; - int i, j; + int i; const char *name; /* Process fixed-sized commands. */ @@ -562,12 +562,11 @@ static int joydev_ioctl_common(struct joydev *joydev, case JSIOCSCORR: if (copy_from_user(joydev->corr, argp, sizeof(joydev->corr[0]) * joydev->nabs)) - return -EFAULT; + return -EFAULT; for (i = 0; i < joydev->nabs; i++) { - j = joydev->abspam[i]; - joydev->abs[i] = joydev_correct(dev->abs[j], - &joydev->corr[i]); + int val = input_abs_get_val(dev, joydev->abspam[i]); + joydev->abs[i] = joydev_correct(val, &joydev->corr[i]); } return 0; @@ -848,25 +847,27 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, for (i = 0; i < joydev->nabs; i++) { j = joydev->abspam[i]; - if (dev->absmax[j] == dev->absmin[j]) { + if (input_abs_get_max(dev, j) == input_abs_get_min(dev, j)) { joydev->corr[i].type = JS_CORR_NONE; - joydev->abs[i] = dev->abs[j]; + joydev->abs[i] = input_abs_get_val(dev, j); continue; } joydev->corr[i].type = JS_CORR_BROKEN; - joydev->corr[i].prec = dev->absfuzz[j]; - joydev->corr[i].coef[0] = - (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; - joydev->corr[i].coef[1] = - (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; + joydev->corr[i].prec = input_abs_get_fuzz(dev, j); - t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]; + t = (input_abs_get_max(dev, j) + input_abs_get_min(dev, j)) / 2; + joydev->corr[i].coef[0] = t - input_abs_get_flat(dev, j); + joydev->corr[i].coef[1] = t + input_abs_get_flat(dev, j); + + t = (input_abs_get_max(dev, j) - input_abs_get_min(dev, j)) / 2 + - 2 * input_abs_get_flat(dev, j); if (t) { joydev->corr[i].coef[2] = (1 << 29) / t; joydev->corr[i].coef[3] = (1 << 29) / t; - joydev->abs[i] = joydev_correct(dev->abs[j], - joydev->corr + i); + joydev->abs[i] = + joydev_correct(input_abs_get_val(dev, j), + joydev->corr + i); } } diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index 6489f4010c4f..d259b41354b8 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c @@ -342,7 +342,8 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv) for (i = 0; i < 4; i++) { if (i < 2) - input_set_abs_params(input_dev, axes[i], 48, input_dev->abs[axes[i]] * 2 - 48, 0, 8); + input_set_abs_params(input_dev, axes[i], + 48, input_abs_get_val(input_dev, axes[i]) * 2 - 48, 0, 8); else input_set_abs_params(input_dev, axes[i], 2, 253, 0, 0); input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c index 89c4c084d4ad..b992fbf91f2f 100644 --- a/drivers/input/joystick/adi.c +++ b/drivers/input/joystick/adi.c @@ -452,7 +452,7 @@ static void adi_init_center(struct adi *adi) for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) { t = adi->abs[i]; - x = adi->dev->abs[t]; + x = input_abs_get_val(adi->dev, t); if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) x = i < adi->axes10 ? 512 : 128; diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c index 05022f07ec77..e90694fe0d5c 100644 --- a/drivers/input/joystick/amijoy.c +++ b/drivers/input/joystick/amijoy.c @@ -139,8 +139,8 @@ static int __init amijoy_init(void) amijoy_dev[i]->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); for (j = 0; j < 2; j++) { - amijoy_dev[i]->absmin[ABS_X + j] = -1; - amijoy_dev[i]->absmax[ABS_X + j] = 1; + XXinput_set_abs_params(amijoy_dev[i], ABS_X + j, + -1, 1, 0, 0); } err = input_register_device(amijoy_dev[i]); diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c index 45ac70eae0aa..0536b1b2f018 100644 --- a/drivers/input/joystick/gf2k.c +++ b/drivers/input/joystick/gf2k.c @@ -318,11 +318,8 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) for (i = 0; i < gf2k_axes[gf2k->id]; i++) set_bit(gf2k_abs[i], input_dev->absbit); - for (i = 0; i < gf2k_hats[gf2k->id]; i++) { - set_bit(ABS_HAT0X + i, input_dev->absbit); - input_dev->absmin[ABS_HAT0X + i] = -1; - input_dev->absmax[ABS_HAT0X + i] = 1; - } + for (i = 0; i < gf2k_hats[gf2k->id]; i++) + input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); for (i = 0; i < gf2k_joys[gf2k->id]; i++) set_bit(gf2k_btn_joy[i], input_dev->keybit); @@ -334,11 +331,14 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) gf2k_read(gf2k, data); for (i = 0; i < gf2k_axes[gf2k->id]; i++) { - input_dev->absmax[gf2k_abs[i]] = (i < 2) ? input_dev->abs[gf2k_abs[i]] * 2 - 32 : - input_dev->abs[gf2k_abs[0]] + input_dev->abs[gf2k_abs[1]] - 32; - input_dev->absmin[gf2k_abs[i]] = 32; - input_dev->absfuzz[gf2k_abs[i]] = 8; - input_dev->absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0; + int max = i < 2 ? + input_abs_get_val(input_dev, gf2k_abs[i]) * 2 : + input_abs_get_val(input_dev, gf2k_abs[0]) + + input_abs_get_val(input_dev, gf2k_abs[1]); + int flat = i < 2 ? 24 : 0; + + input_set_abs_params(input_dev, gf2k_abs[i], + 32, max - 32, 8, flat); } err = input_register_device(gf2k->dev); diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c index 2478289aeeea..16fb19d1ca25 100644 --- a/drivers/input/joystick/interact.c +++ b/drivers/input/joystick/interact.c @@ -270,18 +270,14 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) { - set_bit(t, input_dev->absbit); - if (i < interact_type[interact->type].b8) { - input_dev->absmin[t] = 0; - input_dev->absmax[t] = 255; - } else { - input_dev->absmin[t] = -1; - input_dev->absmax[t] = 1; - } + if (i < interact_type[interact->type].b8) + input_set_abs_params(input_dev, t, 0, 255, 0, 0); + else + input_set_abs_params(input_dev, t, -1, 1, 0, 0); } for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++) - set_bit(t, input_dev->keybit); + __set_bit(t, input_dev->keybit); err = input_register_device(interact->dev); if (err) diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index ca13a6bec33e..b8d86115644b 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -761,17 +761,21 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); for (j = 0; (bits = sw_bit[sw->type][j]); j++) { + int min, max, fuzz, flat; + code = sw_abs[sw->type][j]; - set_bit(code, input_dev->absbit); - input_dev->absmax[code] = (1 << bits) - 1; - input_dev->absmin[code] = (bits == 1) ? -1 : 0; - input_dev->absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0; - if (code != ABS_THROTTLE) - input_dev->absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0; + min = bits == 1 ? -1 : 0; + max = (1 << bits) - 1; + fuzz = (bits >> 1) >= 2 ? 1 << ((bits >> 1) - 2) : 0; + flat = code == ABS_THROTTLE || bits < 5 ? + 0 : 1 << (bits - 5); + + input_set_abs_params(input_dev, code, + min, max, fuzz, flat); } for (j = 0; (code = sw_btn[sw->type][j]); j++) - set_bit(code, input_dev->keybit); + __set_bit(code, input_dev->keybit); dbg("%s%s [%d-bit id %d data %d]\n", sw->name, comment, m, l, k); diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c index c83f4b2ec7d3..ddd5afd301d4 100644 --- a/drivers/input/keyboard/hil_kbd.c +++ b/drivers/input/keyboard/hil_kbd.c @@ -232,15 +232,16 @@ static void hil_dev_handle_ptr_events(struct hil_dev *ptr) if (absdev) { val = lo + (hi << 8); #ifdef TABLET_AUTOADJUST - if (val < dev->absmin[ABS_X + i]) - dev->absmin[ABS_X + i] = val; - if (val > dev->absmax[ABS_X + i]) - dev->absmax[ABS_X + i] = val; + if (val < input_abs_min(dev, ABS_X + i)) + input_abs_set_min(dev, ABS_X + i, val); + if (val > input_abs_max(dev, ABS_X + i)) + XXinput_abs_set_max(dev, ABS_X + i, val); #endif - if (i%3) val = dev->absmax[ABS_X + i] - val; + if (i % 3) + val = input_abs_max(dev, ABS_X + i) - val; input_report_abs(dev, ABS_X + i, val); } else { - val = (int) (((int8_t)lo) | ((int8_t)hi << 8)); + val = (int) (((int8_t) lo) | ((int8_t) hi << 8)); if (i % 3) val *= -1; input_report_rel(dev, REL_X + i, val); @@ -387,9 +388,11 @@ static void hil_dev_pointer_setup(struct hil_dev *ptr) #ifdef TABLET_AUTOADJUST for (i = 0; i < ABS_MAX; i++) { - int diff = input_dev->absmax[ABS_X + i] / 10; - input_dev->absmin[ABS_X + i] += diff; - input_dev->absmax[ABS_X + i] -= diff; + int diff = input_abs_max(input_dev, ABS_X + i) / 10; + input_abs_set_min(input_dev, ABS_X + i, + input_abs_min(input_dev, ABS_X + i) + diff) + XXinput_abs_set_max(input_dev, ABS_X + i, + input_abs_max(input_dev, ABS_X + i) - diff) } #endif diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index b71eb55f2dbc..bb53fd33cd1c 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -304,21 +304,25 @@ static int uinput_validate_absbits(struct input_dev *dev) if (!test_bit(cnt, dev->absbit)) continue; - if ((dev->absmax[cnt] <= dev->absmin[cnt])) { + if (input_abs_get_max(dev, cnt) <= input_abs_get_min(dev, cnt)) { printk(KERN_DEBUG "%s: invalid abs[%02x] min:%d max:%d\n", UINPUT_NAME, cnt, - dev->absmin[cnt], dev->absmax[cnt]); + input_abs_get_min(dev, cnt), + input_abs_get_max(dev, cnt)); retval = -EINVAL; break; } - if (dev->absflat[cnt] > (dev->absmax[cnt] - dev->absmin[cnt])) { + if (input_abs_get_flat(dev, cnt) > + input_abs_get_max(dev, cnt) - input_abs_get_min(dev, cnt)) { printk(KERN_DEBUG - "%s: absflat[%02x] out of range: %d " + "%s: abs_flat #%02x out of range: %d " "(min:%d/max:%d)\n", - UINPUT_NAME, cnt, dev->absflat[cnt], - dev->absmin[cnt], dev->absmax[cnt]); + UINPUT_NAME, cnt, + input_abs_get_flat(dev, cnt), + input_abs_get_min(dev, cnt), + input_abs_get_max(dev, cnt)); retval = -EINVAL; break; } @@ -343,7 +347,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu struct uinput_user_dev *user_dev; struct input_dev *dev; char *name; - int size; + int i, size; int retval; if (count != sizeof(struct uinput_user_dev)) @@ -387,11 +391,12 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu dev->id.product = user_dev->id.product; dev->id.version = user_dev->id.version; - size = sizeof(int) * ABS_CNT; - memcpy(dev->absmax, user_dev->absmax, size); - memcpy(dev->absmin, user_dev->absmin, size); - memcpy(dev->absfuzz, user_dev->absfuzz, size); - memcpy(dev->absflat, user_dev->absflat, size); + for (i = 0; i < ABS_CNT; i++) { + input_abs_set_max(dev, i, user_dev->absmax[i]); + input_abs_set_min(dev, i, user_dev->absmin[i]); + input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]); + input_abs_set_flat(dev, i, user_dev->absflat[i]); + } /* check if absmin/absmax/absfuzz/absflat are filled as * told in Documentation/input/input-programming.txt */ diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c index 3941f97cfa60..7b02b652e267 100644 --- a/drivers/input/mouse/pc110pad.c +++ b/drivers/input/mouse/pc110pad.c @@ -145,8 +145,8 @@ static int __init pc110pad_init(void) pc110pad_dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y); pc110pad_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - pc110pad_dev->absmax[ABS_X] = 0x1ff; - pc110pad_dev->absmax[ABS_Y] = 0x0ff; + input_abs_set_max(pc110pad_dev, ABS_X, 0x1ff); + input_abs_set_max(pc110pad_dev, ABS_Y, 0x0ff); pc110pad_dev->open = pc110pad_open; pc110pad_dev->close = pc110pad_close; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 85a1e1460996..2bf93432b8c0 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -629,8 +629,8 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) __clear_bit(REL_X, dev->relbit); __clear_bit(REL_Y, dev->relbit); - dev->absres[ABS_X] = priv->x_res; - dev->absres[ABS_Y] = priv->y_res; + input_abs_set_res(dev, ABS_X, priv->x_res); + input_abs_set_res(dev, ABS_Y, priv->y_res); if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { /* Clickpads report only left button */ diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index d8f68f77007b..83c24cca234a 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -22,6 +22,7 @@ #include #include #include +#include #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX #include #endif @@ -134,11 +135,14 @@ static void mousedev_touchpad_event(struct input_dev *dev, switch (code) { case ABS_X: + fx(0) = value; if (mousedev->touch && mousedev->pkt_count >= 2) { - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; + size = input_abs_get_min(dev, ABS_X) - + input_abs_get_max(dev, ABS_X); if (size == 0) size = 256 * 2; + tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size; tmp += mousedev->frac_dx; mousedev->packet.dx = tmp / FRACTION_DENOM; @@ -150,10 +154,12 @@ static void mousedev_touchpad_event(struct input_dev *dev, case ABS_Y: fy(0) = value; if (mousedev->touch && mousedev->pkt_count >= 2) { - /* use X size to keep the same scale */ - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; + /* use X size for ABS_Y to keep the same scale */ + size = input_abs_get_min(dev, ABS_X) - + input_abs_get_max(dev, ABS_X); if (size == 0) size = 256 * 2; + tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size; tmp += mousedev->frac_dy; mousedev->packet.dy = tmp / FRACTION_DENOM; @@ -167,33 +173,35 @@ static void mousedev_touchpad_event(struct input_dev *dev, static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) { - int size; + int min, max, size; switch (code) { case ABS_X: - size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; + min = input_abs_get_min(dev, ABS_X); + max = input_abs_get_max(dev, ABS_X); + + size = max - min; if (size == 0) size = xres ? : 1; - if (value > dev->absmax[ABS_X]) - value = dev->absmax[ABS_X]; - if (value < dev->absmin[ABS_X]) - value = dev->absmin[ABS_X]; - mousedev->packet.x = - ((value - dev->absmin[ABS_X]) * xres) / size; + + clamp(value, min, max); + + mousedev->packet.x = ((value - min) * xres) / size; mousedev->packet.abs_event = 1; break; case ABS_Y: - size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; + min = input_abs_get_min(dev, ABS_Y); + max = input_abs_get_max(dev, ABS_Y); + + size = max - min; if (size == 0) size = yres ? : 1; - if (value > dev->absmax[ABS_Y]) - value = dev->absmax[ABS_Y]; - if (value < dev->absmin[ABS_Y]) - value = dev->absmin[ABS_Y]; - mousedev->packet.y = yres - - ((value - dev->absmin[ABS_Y]) * yres) / size; + + clamp(value, min, max); + + mousedev->packet.y = yres - ((value - min) * yres) / size; mousedev->packet.abs_event = 1; break; } diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 51b80b08d467..57b25b84d1fc 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -987,20 +987,17 @@ static int aiptek_program_tablet(struct aiptek *aiptek) /* Query getXextension */ if ((ret = aiptek_query(aiptek, 0x01, 0x00)) < 0) return ret; - aiptek->inputdev->absmin[ABS_X] = 0; - aiptek->inputdev->absmax[ABS_X] = ret - 1; + input_set_abs_params(aiptek->inputdev, ABS_X, 0, ret - 1, 0, 0); /* Query getYextension */ if ((ret = aiptek_query(aiptek, 0x01, 0x01)) < 0) return ret; - aiptek->inputdev->absmin[ABS_Y] = 0; - aiptek->inputdev->absmax[ABS_Y] = ret - 1; + input_set_abs_params(aiptek->inputdev, ABS_Y, 0, ret - 1, 0, 0); /* Query getPressureLevels */ if ((ret = aiptek_query(aiptek, 0x08, 0x00)) < 0) return ret; - aiptek->inputdev->absmin[ABS_PRESSURE] = 0; - aiptek->inputdev->absmax[ABS_PRESSURE] = ret - 1; + input_set_abs_params(aiptek->inputdev, ABS_PRESSURE, 0, ret - 1, 0, 0); /* Depending on whether we are in absolute or relative mode, we will * do a switchToTablet(absolute) or switchToMouse(relative) command. @@ -1054,8 +1051,8 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr struct aiptek *aiptek = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%dx%d\n", - aiptek->inputdev->absmax[ABS_X] + 1, - aiptek->inputdev->absmax[ABS_Y] + 1); + input_abs_get_max(aiptek->inputdev, ABS_X) + 1, + input_abs_get_max(aiptek->inputdev, ABS_Y) + 1); } /* These structs define the sysfs files, param #1 is the name of the @@ -1843,7 +1840,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) for (i = 0; i < ARRAY_SIZE(speeds); ++i) { aiptek->curSetting.programmableDelay = speeds[i]; (void)aiptek_program_tablet(aiptek); - if (aiptek->inputdev->absmax[ABS_X] > 0) { + if (input_abs_get_max(aiptek->inputdev, ABS_X) > 0) { dev_info(&intf->dev, "Aiptek using %d ms programming speed\n", aiptek->curSetting.programmableDelay); diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 555ef26e206d..87427d02e761 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -686,10 +686,10 @@ static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx) * protocol. */ if (wacom->last_finger != finger) { - if (x == input->abs[ABS_X]) + if (x == input_abs_get_val(input, ABS_X)) x++; - if (y == input->abs[ABS_Y]) + if (y == input_abs_get_val(input, ABS_Y)) y++; } From d31b2865a4e8a9dd02f39e56c8fadb824c5e187b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 2 Aug 2010 20:18:21 -0700 Subject: [PATCH 03/10] Input: dynamically allocate ABS information As all callers are now changed to only use the input_abs_*() access helpers, switching over to dynamically allocated ABS information is easy. This reduces size of struct input_dev from 3152 to 1640 on 64 bit architectures. Signed-off-by: Daniel Mack Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 21 ++++------------ drivers/input/input.c | 42 +++++++++++++++++++++++++++++-- include/linux/input.h | 57 ++++++++++++++----------------------------- 3 files changed, 63 insertions(+), 57 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 9807c8ff6a84..08f48c03eec4 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -649,13 +649,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { t = _IOC_NR(cmd) & ABS_MAX; - - abs.value = input_abs_get_val(dev, t); - abs.minimum = input_abs_get_min(dev, t); - abs.maximum = input_abs_get_max(dev, t); - abs.fuzz = input_abs_get_fuzz(dev, t); - abs.flat = input_abs_get_flat(dev, t); - abs.resolution = input_abs_get_res(dev, t); + abs = dev->absinfo[t]; if (copy_to_user(p, &abs, min_t(size_t, _IOC_SIZE(cmd), @@ -691,6 +685,9 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, sizeof(struct input_absinfo)))) return -EFAULT; + if (_IOC_SIZE(cmd) < sizeof(struct input_absinfo)) + abs.resolution = 0; + /* We can't change number of reserved MT slots */ if (t == ABS_MT_SLOT) return -EINVAL; @@ -701,15 +698,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, * of event. */ spin_lock_irq(&dev->event_lock); - - input_abs_set_val(dev, t, abs.value); - input_abs_set_min(dev, t, abs.minimum); - input_abs_set_max(dev, t, abs.maximum); - input_abs_set_fuzz(dev, t, abs.fuzz); - input_abs_set_flat(dev, t, abs.flat); - input_abs_set_res(dev, t, _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ? - 0 : abs.resolution); - + dev->absinfo[t] = abs; spin_unlock_irq(&dev->event_lock); return 0; diff --git a/drivers/input/input.c b/drivers/input/input.c index 7259adb8619d..a9b025f4147a 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -182,7 +182,7 @@ static int input_handle_abs_event(struct input_dev *dev, is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST; if (!is_mt_event) { - pold = &dev->abs[code]; + pold = &dev->absinfo[code].value; } else if (dev->mt) { struct input_mt_slot *mtslot = &dev->mt[dev->slot]; pold = &mtslot->abs[code - ABS_MT_FIRST]; @@ -196,7 +196,7 @@ static int input_handle_abs_event(struct input_dev *dev, if (pold) { *pval = input_defuzz_abs_event(*pval, *pold, - dev->absfuzz[code]); + dev->absinfo[code].fuzz); if (*pold == *pval) return INPUT_IGNORE_EVENT; @@ -390,6 +390,43 @@ void input_inject_event(struct input_handle *handle, } EXPORT_SYMBOL(input_inject_event); +/** + * input_alloc_absinfo - allocates array of input_absinfo structs + * @dev: the input device emitting absolute events + * + * If the absinfo struct the caller asked for is already allocated, this + * functions will not do anything. + */ +void input_alloc_absinfo(struct input_dev *dev) +{ + if (!dev->absinfo) + dev->absinfo = kcalloc(ABS_CNT, sizeof(struct input_absinfo), + GFP_KERNEL); + + WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__); +} +EXPORT_SYMBOL(input_alloc_absinfo); + +void input_set_abs_params(struct input_dev *dev, unsigned int axis, + int min, int max, int fuzz, int flat) +{ + struct input_absinfo *absinfo; + + input_alloc_absinfo(dev); + if (!dev->absinfo) + return; + + absinfo = &dev->absinfo[axis]; + absinfo->minimum = min; + absinfo->maximum = max; + absinfo->fuzz = fuzz; + absinfo->flat = flat; + + dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); +} +EXPORT_SYMBOL(input_set_abs_params); + + /** * input_grab_device - grabs device for exclusive use * @handle: input handle that wants to own the device @@ -1308,6 +1345,7 @@ static void input_dev_release(struct device *device) input_ff_destroy(dev); input_mt_destroy_slots(dev); + kfree(dev->absinfo); kfree(dev); module_put(THIS_MODULE); diff --git a/include/linux/input.h b/include/linux/input.h index 4a5531161de1..896a92227bc4 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -776,6 +776,7 @@ struct input_absinfo { #define REP_DELAY 0x00 #define REP_PERIOD 0x01 #define REP_MAX 0x01 +#define REP_CNT (REP_MAX+1) /* * Sounds @@ -1099,21 +1100,18 @@ struct input_mt_slot { * @repeat_key: stores key code of the last key pressed; used to implement * software autorepeat * @timer: timer for software autorepeat - * @abs: current values for reports from absolute axes * @rep: current values for autorepeat parameters (delay, rate) * @mt: pointer to array of struct input_mt_slot holding current values * of tracked contacts * @mtsize: number of MT slots the device uses * @slot: MT slot currently being transmitted + * @absinfo: array of &struct absinfo elements holding information + * about absolute axes (current value, min, max, flat, fuzz, + * resolution) * @key: reflects current state of device's keys/buttons * @led: reflects current state of device's LEDs * @snd: reflects current state of sound effects * @sw: reflects current state of device's switches - * @absmax: maximum values for events coming from absolute axes - * @absmin: minimum values for events coming from absolute axes - * @absfuzz: describes noisiness for axes - * @absflat: size of the center flat position (used by joydev) - * @absres: resolution used for events coming form absolute axes * @open: this method is called when the very first user calls * input_open_device(). The driver must prepare the device * to start generating events (start polling thread, @@ -1180,24 +1178,19 @@ struct input_dev { unsigned int repeat_key; struct timer_list timer; - int abs[ABS_CNT]; - int rep[REP_MAX + 1]; + int rep[REP_CNT]; struct input_mt_slot *mt; int mtsize; int slot; + struct input_absinfo *absinfo; + unsigned long key[BITS_TO_LONGS(KEY_CNT)]; unsigned long led[BITS_TO_LONGS(LED_CNT)]; unsigned long snd[BITS_TO_LONGS(SND_CNT)]; unsigned long sw[BITS_TO_LONGS(SW_CNT)]; - int absmax[ABS_CNT]; - int absmin[ABS_CNT]; - int absfuzz[ABS_CNT]; - int absflat[ABS_CNT]; - int absres[ABS_CNT]; - int (*open)(struct input_dev *dev); void (*close)(struct input_dev *dev); int (*flush)(struct input_dev *dev, struct file *file); @@ -1459,45 +1452,31 @@ static inline void input_set_events_per_packet(struct input_dev *dev, int n_even dev->hint_events_per_packet = n_events; } -static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat) -{ - dev->absmin[axis] = min; - dev->absmax[axis] = max; - dev->absfuzz[axis] = fuzz; - dev->absflat[axis] = flat; - - dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis); -} +void input_alloc_absinfo(struct input_dev *dev); +void input_set_abs_params(struct input_dev *dev, unsigned int axis, + int min, int max, int fuzz, int flat); #define INPUT_GENERATE_ABS_ACCESSORS(_suffix, _item) \ static inline int input_abs_get_##_suffix(struct input_dev *dev, \ unsigned int axis) \ { \ - return dev->abs##_item[axis]; \ + return dev->absinfo ? dev->absinfo[axis]._item : 0; \ } \ \ static inline void input_abs_set_##_suffix(struct input_dev *dev, \ unsigned int axis, int val) \ { \ - dev->abs##_item[axis] = val; \ + input_alloc_absinfo(dev); \ + if (dev->absinfo) \ + dev->absinfo[axis]._item = val; \ } -INPUT_GENERATE_ABS_ACCESSORS(min, min) -INPUT_GENERATE_ABS_ACCESSORS(max, max) +INPUT_GENERATE_ABS_ACCESSORS(val, value) +INPUT_GENERATE_ABS_ACCESSORS(min, minimum) +INPUT_GENERATE_ABS_ACCESSORS(max, maximum) INPUT_GENERATE_ABS_ACCESSORS(fuzz, fuzz) INPUT_GENERATE_ABS_ACCESSORS(flat, flat) -INPUT_GENERATE_ABS_ACCESSORS(res, res) - -static inline int input_abs_get_val(struct input_dev *dev, unsigned int axis) -{ - return dev->abs[axis]; -} - -static inline void input_abs_set_val(struct input_dev *dev, - unsigned int axis, int val) -{ - dev->abs[axis] = val; -} +INPUT_GENERATE_ABS_ACCESSORS(res, resolution) int input_get_keycode(struct input_dev *dev, unsigned int scancode, unsigned int *keycode); From 448cd1664a573e69f54bfd32f3bb7220212b6cf5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 2 Aug 2010 20:29:10 -0700 Subject: [PATCH 04/10] Input: evdev - rearrange ioctl handling Split ioctl handling into 3 separate sections: fixed-length ioctls, variable-length ioctls and multi-number variable length handlers. This reduces identation and makes the code a bit clearer. Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 157 ++++++++++++++++++++++-------------------- 1 file changed, 81 insertions(+), 76 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 08f48c03eec4..c908c5f83645 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -492,13 +492,15 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) } #define OLD_KEY_MAX 0x1ff -static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode) +static int handle_eviocgbit(struct input_dev *dev, + unsigned int type, unsigned int size, + void __user *p, int compat_mode) { static unsigned long keymax_warn_time; unsigned long *bits; int len; - switch (_IOC_NR(cmd) & EV_MAX) { + switch (type) { case 0: bits = dev->evbit; len = EV_MAX; break; case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; @@ -517,7 +519,7 @@ static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len' * should be in bytes, not in bits. */ - if ((_IOC_NR(cmd) & EV_MAX) == EV_KEY && _IOC_SIZE(cmd) == OLD_KEY_MAX) { + if (type == EV_KEY && size == OLD_KEY_MAX) { len = OLD_KEY_MAX; if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) printk(KERN_WARNING @@ -528,7 +530,7 @@ static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); } - return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); + return bits_to_user(bits, len, size, p, compat_mode); } #undef OLD_KEY_MAX @@ -542,8 +544,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, struct ff_effect effect; int __user *ip = (int __user *)p; unsigned int i, t, u, v; + unsigned int size; int error; + /* First we check for fixed-length commands */ switch (cmd) { case EVIOCGVERSION: @@ -610,101 +614,102 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, return evdev_grab(evdev, client); else return evdev_ungrab(evdev, client); + } - default: + size = _IOC_SIZE(cmd); - if (_IOC_TYPE(cmd) != 'E') - return -EINVAL; + /* Now check variable-length commands */ +#define EVIOC_MASK_SIZE(nr) ((nr) & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) - if (_IOC_DIR(cmd) == _IOC_READ) { + switch (EVIOC_MASK_SIZE(cmd)) { - if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) - return handle_eviocgbit(dev, cmd, p, compat_mode); + case EVIOCGKEY(0): + return bits_to_user(dev->key, KEY_MAX, size, p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) - return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), - p, compat_mode); + case EVIOCGLED(0): + return bits_to_user(dev->led, LED_MAX, size, p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) - return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), - p, compat_mode); + case EVIOCGSND(0): + return bits_to_user(dev->snd, SND_MAX, size, p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) - return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), - p, compat_mode); + case EVIOCGSW(0): + return bits_to_user(dev->sw, SW_MAX, size, p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) - return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), - p, compat_mode); + case EVIOCGNAME(0): + return str_to_user(dev->name, size, p); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) - return str_to_user(dev->name, _IOC_SIZE(cmd), p); + case EVIOCGPHYS(0): + return str_to_user(dev->phys, size, p); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) - return str_to_user(dev->phys, _IOC_SIZE(cmd), p); + case EVIOCGUNIQ(0): + return str_to_user(dev->uniq, size, p); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) - return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); + case EVIOC_MASK_SIZE(EVIOCSFF): + if (input_ff_effect_from_user(p, size, &effect)) + return -EFAULT; - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { + error = input_ff_upload(dev, &effect, file); - t = _IOC_NR(cmd) & ABS_MAX; - abs = dev->absinfo[t]; + if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) + return -EFAULT; - if (copy_to_user(p, &abs, min_t(size_t, - _IOC_SIZE(cmd), - sizeof(struct input_absinfo)))) - return -EFAULT; + return error; + } - return 0; - } + /* Multi-number variable-length handlers */ + if (_IOC_TYPE(cmd) != 'E') + return -EINVAL; - } + if (_IOC_DIR(cmd) == _IOC_READ) { - if (_IOC_DIR(cmd) == _IOC_WRITE) { + if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) + return handle_eviocgbit(dev, + _IOC_NR(cmd) & EV_MAX, size, + p, compat_mode); - if (_IOC_NR(cmd) == _IOC_NR(EVIOCSFF)) { + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { - if (input_ff_effect_from_user(p, _IOC_SIZE(cmd), &effect)) - return -EFAULT; + t = _IOC_NR(cmd) & ABS_MAX; + abs = dev->absinfo[t]; - error = input_ff_upload(dev, &effect, file); + if (copy_to_user(p, &abs, min_t(size_t, + size, sizeof(struct input_absinfo)))) + return -EFAULT; - if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) - return -EFAULT; - - return error; - } - - if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { - - t = _IOC_NR(cmd) & ABS_MAX; - - if (copy_from_user(&abs, p, min_t(size_t, - _IOC_SIZE(cmd), - sizeof(struct input_absinfo)))) - return -EFAULT; - - if (_IOC_SIZE(cmd) < sizeof(struct input_absinfo)) - abs.resolution = 0; - - /* We can't change number of reserved MT slots */ - if (t == ABS_MT_SLOT) - return -EINVAL; - - /* - * Take event lock to ensure that we are not - * changing device parameters in the middle - * of event. - */ - spin_lock_irq(&dev->event_lock); - dev->absinfo[t] = abs; - spin_unlock_irq(&dev->event_lock); - - return 0; - } + return 0; } } + + if (_IOC_DIR(cmd) == _IOC_READ) { + + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { + + t = _IOC_NR(cmd) & ABS_MAX; + + if (copy_from_user(&abs, p, min_t(size_t, + size, sizeof(struct input_absinfo)))) + return -EFAULT; + + if (size < sizeof(struct input_absinfo)) + abs.resolution = 0; + + /* We can't change number of reserved MT slots */ + if (t == ABS_MT_SLOT) + return -EINVAL; + + /* + * Take event lock to ensure that we are not + * changing device parameters in the middle + * of event. + */ + spin_lock_irq(&dev->event_lock); + dev->absinfo[t] = abs; + spin_unlock_irq(&dev->event_lock); + + return 0; + } + } + return -EINVAL; } From 173bdd746b128241d3d6d202142820692e7dd530 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Tue, 3 Aug 2010 19:44:40 -0700 Subject: [PATCH 05/10] Input: gpio_keys - add hooks to enable/disable device Allow platform code to specify callbcks that will be invoked when input device is opened or closed, allowing, for example, to enable the device. Signed-off-by: Shubhrajyoti D Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 22 ++++++++++++++++++++++ include/linux/gpio_keys.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index a9fd147f2ba7..6069abe31e42 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -39,6 +39,8 @@ struct gpio_keys_drvdata { struct input_dev *input; struct mutex disable_lock; unsigned int n_buttons; + int (*enable)(struct device *dev); + void (*disable)(struct device *dev); struct gpio_button_data data[0]; }; @@ -423,6 +425,21 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev, return error; } +static int gpio_keys_open(struct input_dev *input) +{ + struct gpio_keys_drvdata *ddata = input_get_drvdata(input); + + return ddata->enable ? ddata->enable(input->dev.parent) : 0; +} + +static void gpio_keys_close(struct input_dev *input) +{ + struct gpio_keys_drvdata *ddata = input_get_drvdata(input); + + if (ddata->disable) + ddata->disable(input->dev.parent); +} + static int __devinit gpio_keys_probe(struct platform_device *pdev) { struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; @@ -444,13 +461,18 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) ddata->input = input; ddata->n_buttons = pdata->nbuttons; + ddata->enable = pdata->enable; + ddata->disable = pdata->disable; mutex_init(&ddata->disable_lock); platform_set_drvdata(pdev, ddata); + input_set_drvdata(input, ddata); input->name = pdev->name; input->phys = "gpio-keys/input0"; input->dev.parent = &pdev->dev; + input->open = gpio_keys_open; + input->close = gpio_keys_close; input->id.bustype = BUS_HOST; input->id.vendor = 0x0001; diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index cd0b3f30f48e..ce73a30113b4 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -17,6 +17,8 @@ struct gpio_keys_platform_data { struct gpio_keys_button *buttons; int nbuttons; unsigned int rep:1; /* enable input subsystem auto repeat */ + int (*enable)(struct device *dev); + void (*disable)(struct device *dev); }; #endif From 7be3c13425ddeed8427cfaad65c9123c2c8ca331 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Thu, 5 Aug 2010 10:05:55 -0700 Subject: [PATCH 06/10] Input: adxl34x - do not mark device as disabled on startup Do not mark device as desabled on startup - otherwise user must reset disable sysfs hook before the driver delivers any data. Signed-off-by: Michael Hennerich Signed-off-by: Dmitry Torokhov --- drivers/input/misc/adxl34x.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index e2ca01708080..de5900d50788 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -724,7 +724,6 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq, pdata = &ac->pdata; ac->input = input_dev; - ac->disabled = true; ac->dev = dev; ac->irq = irq; ac->bops = bops; From 7f29f17b57255b6395046805a98bc663ded63fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Piel?= Date: Thu, 5 Aug 2010 23:51:49 -0700 Subject: [PATCH 07/10] Input: elantech - discard the first 2 positions on some firmwares MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the Dell/Ubuntu driver, what was previously observed as "jumpy cursor" corresponds to the hardware sending incorrect data for the first two reports of a one touch finger. So let's use the same workaround as in the other driver. Also, detect another firmware version with the same behaviour, as in the other driver. Signed-off-by: Éric Piel Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 21 ++++++++++----------- drivers/input/mouse/elantech.h | 7 ++++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index b18862b2a70e..bd5b91da169e 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -185,7 +185,6 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) struct elantech_data *etd = psmouse->private; unsigned char *packet = psmouse->packet; int fingers; - static int old_fingers; if (etd->fw_version < 0x020000) { /* @@ -203,10 +202,13 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) } if (etd->jumpy_cursor) { - /* Discard packets that are likely to have bogus coordinates */ - if (fingers > old_fingers) { + if (fingers != 1) { + etd->single_finger_reports = 0; + } else if (etd->single_finger_reports < 2) { + /* Discard first 2 reports of one finger, bogus */ + etd->single_finger_reports++; elantech_debug("discarding packet\n"); - goto discard_packet_v1; + return; } } @@ -238,9 +240,6 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) } input_sync(dev); - - discard_packet_v1: - old_fingers = fingers; } /* @@ -733,13 +732,13 @@ int elantech_init(struct psmouse *psmouse) etd->capabilities = param[0]; /* - * This firmware seems to suffer from misreporting coordinates when + * This firmware suffers from misreporting coordinates when * a touch action starts causing the mouse cursor or scrolled page * to jump. Enable a workaround. */ - if (etd->fw_version == 0x020022) { - pr_info("firmware version 2.0.34 detected, enabling jumpy cursor workaround\n"); - etd->jumpy_cursor = 1; + if (etd->fw_version == 0x020022 || etd->fw_version == 0x020600) { + pr_info("firmware version 2.0.34/2.6.0 detected, enabling jumpy cursor workaround\n"); + etd->jumpy_cursor = true; } if (elantech_set_absolute_mode(psmouse)) { diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index ac57bde1bb9f..aa4aac5d2198 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -100,10 +100,11 @@ struct elantech_data { unsigned char reg_26; unsigned char debug; unsigned char capabilities; - unsigned char paritycheck; - unsigned char jumpy_cursor; + bool paritycheck; + bool jumpy_cursor; unsigned char hw_version; - unsigned int fw_version; + unsigned int fw_version; + unsigned int single_finger_reports; unsigned char parity[256]; }; From 22462d9fcf5b29184716aca486058943b2d6995f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Piel?= Date: Thu, 5 Aug 2010 23:51:49 -0700 Subject: [PATCH 08/10] Input: elantech - report position also with 3 fingers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 6-byte protocol supports reporting the position when three fingers are pressed, exactly like when one finger is pressed. Report this. In addition, it is also distinguishes between 3 and 4 fingers pressed. Signed-off-by: Éric Piel Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index bd5b91da169e..48311204ba51 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -257,6 +257,14 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) input_report_key(dev, BTN_TOUCH, fingers != 0); switch (fingers) { + case 3: + /* + * Same as one finger, except report of more than 3 fingers: + * byte 3: n4 . w1 w0 . . . . + */ + if (packet[3] & 0x80) + fingers = 4; + /* pass through... */ case 1: /* * byte 1: . . . . . x10 x9 x8 @@ -309,6 +317,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2); input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3); + input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4); input_report_key(dev, BTN_LEFT, packet[0] & 0x01); input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); @@ -466,6 +475,7 @@ static void elantech_set_input_params(struct psmouse *psmouse) break; case 2: + __set_bit(BTN_TOOL_QUADTAP, dev->keybit); input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0); input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0); input_set_abs_params(dev, ABS_HAT0X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0); From f1b50760a7e3d69ef5d62f294e51300dd206ea05 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 9 Aug 2010 10:06:47 -0700 Subject: [PATCH 09/10] Input: cy8ctmg100_ts - signedness bug "ret" should be signed here or the error handling doesn't work. Signed-off-by: Dan Carpenter Acked-by: Alan Cox Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/cy8ctmg110_ts.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index 4eb7df0b7f87..5ec0946938fe 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -75,7 +75,7 @@ static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg, unsigned char len, unsigned char *value) { struct i2c_client *client = tsc->client; - unsigned int ret; + int ret; unsigned char i2c_data[6]; BUG_ON(len > 5); @@ -86,7 +86,7 @@ static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg, ret = i2c_master_send(client, i2c_data, len + 1); if (ret != 1) { dev_err(&client->dev, "i2c write data cmd failed\n"); - return ret; + return ret ? ret : -EIO; } return 0; @@ -96,7 +96,7 @@ static int cy8ctmg110_read_regs(struct cy8ctmg110 *tsc, unsigned char *data, unsigned char len, unsigned char cmd) { struct i2c_client *client = tsc->client; - unsigned int ret; + int ret; struct i2c_msg msg[2] = { /* first write slave position to i2c devices */ { client->addr, 0, 1, &cmd }, From 6ac8a99b906b01eaceef0057dbee4a225a32c423 Mon Sep 17 00:00:00 2001 From: Christoph Fritz Date: Mon, 9 Aug 2010 10:08:10 -0700 Subject: [PATCH 10/10] Input: xpad - add USB-ID for PL-3601 Xbox 360 pad This patch adds USB Vendor and Product ID for Pelican PL-3601 'TSZ' Wired Xbox 360 Controller to the device table. Signed-off-by: Christoph Fritz Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index c41d012c88dc..97c5587fd5d9 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -148,6 +148,7 @@ static const struct xpad_device { { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0006, "Pelican 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, + { 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },