From 63a6404d8ae693e71ab27c4f9c4032aa29113e92 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Thu, 10 Jun 2010 12:05:24 -0700 Subject: Input: evdev - use driver hint to compute size of event buffer Some devices, in particular MT devices, produce a lot of data. This may lead to overflowing of the event queues in evdev driver, which by default are fairly small. Let the drivers hint the average number of events per packet generated by the device, and use that information when computing the buffer size evdev should use for the device. Signed-off-by: Henrik Rydberg Acked-by: Chase Douglas Signed-off-by: Dmitry Torokhov --- include/linux/input.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'include/linux/input.h') diff --git a/include/linux/input.h b/include/linux/input.h index 6fcc9101beeb..cc524c8b6703 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1063,6 +1063,10 @@ struct ff_effect { * @sndbit: bitmap of sound effects supported by the device * @ffbit: bitmap of force feedback effects supported by the device * @swbit: bitmap of switches present on the device + * @hint_events_per_packet: average number of events generated by the + * device in a packet (between EV_SYN/SYN_REPORT events). Used by + * event handlers to estimate size of the buffer needed to hold + * events. * @keycodemax: size of keycode table * @keycodesize: size of elements in keycode table * @keycode: map of scancodes to keycodes for this device @@ -1140,6 +1144,8 @@ struct input_dev { unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; + unsigned int hint_events_per_packet; + unsigned int keycodemax; unsigned int keycodesize; void *keycode; @@ -1408,6 +1414,21 @@ static inline void input_mt_sync(struct input_dev *dev) void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code); +/** + * input_set_events_per_packet - tell handlers about the driver event rate + * @dev: the input device used by the driver + * @n_events: the average number of events between calls to input_sync() + * + * If the event rate sent from a device is unusually large, use this + * function to set the expected event rate. This will allow handlers + * to set up an appropriate buffer size for the event stream, in order + * to minimize information loss. + */ +static inline void input_set_events_per_packet(struct input_dev *dev, int n_events) +{ + 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; -- cgit v1.2.3 From 40d007e7df1dab17bf1ecf91e718218354d963d7 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Thu, 15 Jul 2010 23:10:10 -0700 Subject: Input: introduce MT event slots With the rapidly increasing number of intelligent multi-contact and multi-user devices, the need to send digested, filtered information from a set of different sources within the same device is imminent. This patch adds the concept of slots to the MT protocol. The slots enumerate a set of identified sources, such that all MT events can be passed independently and selectively per identified source. The protocol works like this: Instead of sending a SYN_MT_REPORT event immediately after the contact data, one sends an ABS_MT_SLOT event immediately before the contact data. The input core will only emit events for slots with modified MT events. It is assumed that the same slot is used for the duration of an initiated contact. Acked-by: Ping Cheng Acked-by: Chase Douglas Acked-by: Rafi Rubin Signed-off-by: Henrik Rydberg Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 4 ++ drivers/input/input.c | 135 ++++++++++++++++++++++++++++++++++---------------- include/linux/input.h | 33 ++++++++++++ 3 files changed, 129 insertions(+), 43 deletions(-) (limited to 'include/linux/input.h') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index cd323254ca6f..fc5afbd78625 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -686,6 +686,10 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, sizeof(struct input_absinfo)))) return -EFAULT; + /* 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 diff --git a/drivers/input/input.c b/drivers/input/input.c index a3d5485154e7..54109c33e36c 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -33,25 +33,6 @@ MODULE_LICENSE("GPL"); #define INPUT_DEVICES 256 -/* - * EV_ABS events which should not be cached are listed here. - */ -static unsigned int input_abs_bypass_init_data[] __initdata = { - ABS_MT_TOUCH_MAJOR, - ABS_MT_TOUCH_MINOR, - ABS_MT_WIDTH_MAJOR, - ABS_MT_WIDTH_MINOR, - ABS_MT_ORIENTATION, - ABS_MT_POSITION_X, - ABS_MT_POSITION_Y, - ABS_MT_TOOL_TYPE, - ABS_MT_BLOB_ID, - ABS_MT_TRACKING_ID, - ABS_MT_PRESSURE, - 0 -}; -static unsigned long input_abs_bypass[BITS_TO_LONGS(ABS_CNT)]; - static LIST_HEAD(input_dev_list); static LIST_HEAD(input_handler_list); @@ -181,6 +162,56 @@ static void input_stop_autorepeat(struct input_dev *dev) #define INPUT_PASS_TO_DEVICE 2 #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) +static int input_handle_abs_event(struct input_dev *dev, + unsigned int code, int *pval) +{ + bool is_mt_event; + int *pold; + + if (code == ABS_MT_SLOT) { + /* + * "Stage" the event; we'll flush it later, when we + * get actiual touch data. + */ + if (*pval >= 0 && *pval < dev->mtsize) + dev->slot = *pval; + + return INPUT_IGNORE_EVENT; + } + + is_mt_event = code >= ABS_MT_FIRST && code <= ABS_MT_LAST; + + if (!is_mt_event) { + pold = &dev->abs[code]; + } else if (dev->mt) { + struct input_mt_slot *mtslot = &dev->mt[dev->slot]; + pold = &mtslot->abs[code - ABS_MT_FIRST]; + } else { + /* + * Bypass filtering for multitouch events when + * not employing slots. + */ + pold = NULL; + } + + if (pold) { + *pval = input_defuzz_abs_event(*pval, *pold, + dev->absfuzz[code]); + if (*pold == *pval) + return INPUT_IGNORE_EVENT; + + *pold = *pval; + } + + /* Flush pending "slot" event */ + if (is_mt_event && dev->slot != dev->abs[ABS_MT_SLOT]) { + dev->abs[ABS_MT_SLOT] = dev->slot; + input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot); + } + + return INPUT_PASS_TO_HANDLERS; +} + static void input_handle_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { @@ -233,21 +264,9 @@ static void input_handle_event(struct input_dev *dev, break; case EV_ABS: - if (is_event_supported(code, dev->absbit, ABS_MAX)) { - - if (test_bit(code, input_abs_bypass)) { - disposition = INPUT_PASS_TO_HANDLERS; - break; - } + if (is_event_supported(code, dev->absbit, ABS_MAX)) + disposition = input_handle_abs_event(dev, code, &value); - value = input_defuzz_abs_event(value, - dev->abs[code], dev->absfuzz[code]); - - if (dev->abs[code] != value) { - dev->abs[code] = value; - disposition = INPUT_PASS_TO_HANDLERS; - } - } break; case EV_REL: @@ -1288,6 +1307,7 @@ static void input_dev_release(struct device *device) struct input_dev *dev = to_input_dev(device); input_ff_destroy(dev); + input_mt_destroy_slots(dev); kfree(dev); module_put(THIS_MODULE); @@ -1536,6 +1556,45 @@ void input_free_device(struct input_dev *dev) } EXPORT_SYMBOL(input_free_device); +/** + * input_mt_create_slots() - create MT input slots + * @dev: input device supporting MT events and finger tracking + * @num_slots: number of slots used by the device + * + * This function allocates all necessary memory for MT slot handling + * in the input device, and adds ABS_MT_SLOT to the device capabilities. + */ +int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots) +{ + if (!num_slots) + return 0; + + dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL); + if (!dev->mt) + return -ENOMEM; + + dev->mtsize = num_slots; + input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0); + + return 0; +} +EXPORT_SYMBOL(input_mt_create_slots); + +/** + * input_mt_destroy_slots() - frees the MT slots of the input device + * @dev: input device with allocated MT slots + * + * This function is only needed in error path as the input core will + * automatically free the MT slots when the device is destroyed. + */ +void input_mt_destroy_slots(struct input_dev *dev) +{ + kfree(dev->mt); + dev->mt = NULL; + dev->mtsize = 0; +} +EXPORT_SYMBOL(input_mt_destroy_slots); + /** * input_set_capability - mark device as capable of a certain event * @dev: device that is capable of emitting or accepting event @@ -1945,20 +2004,10 @@ static const struct file_operations input_fops = { .open = input_open_file, }; -static void __init input_init_abs_bypass(void) -{ - const unsigned int *p; - - for (p = input_abs_bypass_init_data; *p; p++) - input_abs_bypass[BIT_WORD(*p)] |= BIT_MASK(*p); -} - static int __init input_init(void) { int err; - input_init_abs_bypass(); - err = class_register(&input_class); if (err) { printk(KERN_ERR "input: unable to register input_dev class\n"); diff --git a/include/linux/input.h b/include/linux/input.h index cc524c8b6703..a14de64ed16a 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -691,9 +691,12 @@ struct input_absinfo { #define ABS_TILT_X 0x1a #define ABS_TILT_Y 0x1b #define ABS_TOOL_WIDTH 0x1c + #define ABS_VOLUME 0x20 + #define ABS_MISC 0x28 +#define ABS_MT_SLOT 0x2f /* MT slot being modified */ #define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ #define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ #define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ @@ -706,6 +709,12 @@ struct input_absinfo { #define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ #define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ +#ifdef __KERNEL__ +/* Implementation details, userspace should not care about these */ +#define ABS_MT_FIRST ABS_MT_TOUCH_MAJOR +#define ABS_MT_LAST ABS_MT_PRESSURE +#endif + #define ABS_MAX 0x3f #define ABS_CNT (ABS_MAX+1) @@ -1047,6 +1056,14 @@ struct ff_effect { #include #include +/** + * struct input_mt_slot - represents the state of an input MT slot + * @abs: holds current values of ABS_MT axes for this slot + */ +struct input_mt_slot { + int abs[ABS_MT_LAST - ABS_MT_FIRST + 1]; +}; + /** * struct input_dev - represents an input device * @name: name of the device @@ -1085,6 +1102,10 @@ struct ff_effect { * @sync: set to 1 when there were no new events since last EV_SYNC * @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 * @key: reflects current state of device's keys/buttons * @led: reflects current state of device's LEDs * @snd: reflects current state of sound effects @@ -1164,6 +1185,10 @@ struct input_dev { int abs[ABS_CNT]; int rep[REP_MAX + 1]; + struct input_mt_slot *mt; + int mtsize; + int slot; + unsigned long key[BITS_TO_LONGS(KEY_CNT)]; unsigned long led[BITS_TO_LONGS(LED_CNT)]; unsigned long snd[BITS_TO_LONGS(SND_CNT)]; @@ -1412,6 +1437,11 @@ static inline void input_mt_sync(struct input_dev *dev) input_event(dev, EV_SYN, SYN_MT_REPORT, 0); } +static inline void input_mt_slot(struct input_dev *dev, int slot) +{ + input_event(dev, EV_ABS, ABS_MT_SLOT, slot); +} + void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code); /** @@ -1506,5 +1536,8 @@ int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file); int input_ff_create_memless(struct input_dev *dev, void *data, int (*play_effect)(struct input_dev *, void *, struct ff_effect *)); +int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots); +void input_mt_destroy_slots(struct input_dev *dev); + #endif #endif -- cgit v1.2.3 From 20da92de8ec3c1d4ba7e5aca322d38b6ce634932 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 15 Jul 2010 23:27:36 -0700 Subject: Input: change input handlers to use bool when possible Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 6 +++--- drivers/input/input.c | 6 +++--- drivers/input/joydev.c | 7 +++---- drivers/input/mousedev.c | 6 +++--- include/linux/input.h | 6 +++--- 5 files changed, 15 insertions(+), 16 deletions(-) (limited to 'include/linux/input.h') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index fc5afbd78625..70c0eb52ca96 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -24,7 +24,6 @@ #include "input-compat.h" struct evdev { - int exist; int open; int minor; struct input_handle handle; @@ -34,6 +33,7 @@ struct evdev { spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; + bool exist; }; struct evdev_client { @@ -793,7 +793,7 @@ static void evdev_remove_chrdev(struct evdev *evdev) static void evdev_mark_dead(struct evdev *evdev) { mutex_lock(&evdev->mutex); - evdev->exist = 0; + evdev->exist = false; mutex_unlock(&evdev->mutex); } @@ -842,7 +842,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, init_waitqueue_head(&evdev->wait); dev_set_name(&evdev->dev, "event%d", minor); - evdev->exist = 1; + evdev->exist = true; evdev->minor = minor; evdev->handle.dev = input_get_device(dev); diff --git a/drivers/input/input.c b/drivers/input/input.c index 54109c33e36c..e1243b4b32a5 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -227,12 +227,12 @@ static void input_handle_event(struct input_dev *dev, case SYN_REPORT: if (!dev->sync) { - dev->sync = 1; + dev->sync = true; disposition = INPUT_PASS_TO_HANDLERS; } break; case SYN_MT_REPORT: - dev->sync = 0; + dev->sync = false; disposition = INPUT_PASS_TO_HANDLERS; break; } @@ -317,7 +317,7 @@ static void input_handle_event(struct input_dev *dev, } if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) - dev->sync = 0; + dev->sync = false; if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) dev->event(dev, type, code, value); diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 34157bb97ed6..63834585c283 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -37,7 +37,6 @@ MODULE_LICENSE("GPL"); #define JOYDEV_BUFFER_SIZE 64 struct joydev { - int exist; int open; int minor; struct input_handle handle; @@ -46,6 +45,7 @@ struct joydev { spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; + bool exist; struct js_corr corr[ABS_CNT]; struct JS_DATA_SAVE_TYPE glue; @@ -760,7 +760,7 @@ static void joydev_remove_chrdev(struct joydev *joydev) static void joydev_mark_dead(struct joydev *joydev) { mutex_lock(&joydev->mutex); - joydev->exist = 0; + joydev->exist = false; mutex_unlock(&joydev->mutex); } @@ -817,10 +817,9 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, init_waitqueue_head(&joydev->wait); dev_set_name(&joydev->dev, "js%d", minor); - joydev->exist = 1; + joydev->exist = true; joydev->minor = minor; - joydev->exist = 1; joydev->handle.dev = input_get_device(dev); joydev->handle.name = dev_name(&joydev->dev); joydev->handle.handler = handler; diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index f34b22bce4ff..d7a7a2fce745 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -57,7 +57,6 @@ struct mousedev_hw_data { }; struct mousedev { - int exist; int open; int minor; struct input_handle handle; @@ -66,6 +65,7 @@ struct mousedev { spinlock_t client_lock; /* protects client_list */ struct mutex mutex; struct device dev; + bool exist; struct list_head mixdev_node; int mixdev_open; @@ -802,7 +802,7 @@ static void mousedev_remove_chrdev(struct mousedev *mousedev) static void mousedev_mark_dead(struct mousedev *mousedev) { mutex_lock(&mousedev->mutex); - mousedev->exist = 0; + mousedev->exist = false; mutex_unlock(&mousedev->mutex); } @@ -862,7 +862,7 @@ static struct mousedev *mousedev_create(struct input_dev *dev, dev_set_name(&mousedev->dev, "mouse%d", minor); mousedev->minor = minor; - mousedev->exist = 1; + mousedev->exist = true; mousedev->handle.dev = input_get_device(dev); mousedev->handle.name = dev_name(&mousedev->dev); mousedev->handle.handler = handler; diff --git a/include/linux/input.h b/include/linux/input.h index a14de64ed16a..339d043ccb53 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1099,7 +1099,6 @@ struct input_mt_slot { * @repeat_key: stores key code of the last key pressed; used to implement * software autorepeat * @timer: timer for software autorepeat - * @sync: set to 1 when there were no new events since last EV_SYNC * @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 @@ -1144,6 +1143,7 @@ struct input_mt_slot { * last user closes the device * @going_away: marks devices that are in a middle of unregistering and * causes input_open_device*() fail with -ENODEV. + * @sync: set to %true when there were no new events since last EV_SYN * @dev: driver model's view of this device * @h_list: list of input handles associated with the device. When * accessing the list dev->mutex must be held @@ -1180,8 +1180,6 @@ struct input_dev { unsigned int repeat_key; struct timer_list timer; - int sync; - int abs[ABS_CNT]; int rep[REP_MAX + 1]; @@ -1213,6 +1211,8 @@ struct input_dev { unsigned int users; bool going_away; + bool sync; + struct device dev; struct list_head h_list; -- cgit v1.2.3 From 7957e9c4d175cc065f4277211fcb7d784fcee860 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 2 Aug 2010 19:33:51 -0700 Subject: 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(+) (limited to 'include/linux/input.h') 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, -- cgit v1.2.3 From d31b2865a4e8a9dd02f39e56c8fadb824c5e187b Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 2 Aug 2010 20:18:21 -0700 Subject: 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(-) (limited to 'include/linux/input.h') 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); -- cgit v1.2.3