From 8d18fba282120a4a8e4416d1202522ffae8cad58 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 15 Sep 2012 15:15:58 +0200 Subject: Input: Break out MT data Move all MT-related things to a separate place. This saves some bytes for non-mt input devices, and prepares for new MT features. Reviewed-and-tested-by: Benjamin Tissoires Tested-by: Ping Cheng Acked-by: Dmitry Torokhov Signed-off-by: Henrik Rydberg --- drivers/input/input.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/input/input.c') diff --git a/drivers/input/input.c b/drivers/input/input.c index 8921c6180c51..79a4a2ad74de 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -166,6 +166,7 @@ static void input_stop_autorepeat(struct input_dev *dev) static int input_handle_abs_event(struct input_dev *dev, unsigned int code, int *pval) { + struct input_mt *mt = dev->mt; bool is_mt_event; int *pold; @@ -174,8 +175,8 @@ static int input_handle_abs_event(struct input_dev *dev, * "Stage" the event; we'll flush it later, when we * get actual touch data. */ - if (*pval >= 0 && *pval < dev->mtsize) - dev->slot = *pval; + if (mt && *pval >= 0 && *pval < mt->num_slots) + mt->slot = *pval; return INPUT_IGNORE_EVENT; } @@ -184,9 +185,8 @@ static int input_handle_abs_event(struct input_dev *dev, if (!is_mt_event) { 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]; + } else if (mt) { + pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST]; } else { /* * Bypass filtering for multi-touch events when @@ -205,9 +205,9 @@ static int input_handle_abs_event(struct input_dev *dev, } /* Flush pending "slot" event */ - 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); + if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) { + input_abs_set_val(dev, ABS_MT_SLOT, mt->slot); + input_pass_event(dev, EV_ABS, ABS_MT_SLOT, mt->slot); } return INPUT_PASS_TO_HANDLERS; @@ -1751,8 +1751,8 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev) int i; unsigned int events; - if (dev->mtsize) { - mt_slots = dev->mtsize; + if (dev->mt) { + mt_slots = dev->mt->num_slots; } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, -- cgit From 7c75bf99271139ca7cb2d0cca3be11f1f7c59efd Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 1 Sep 2012 16:15:43 +0200 Subject: Input: Improve the events-per-packet estimate The events-per-packet estimate has so far been used by MT devices only. This patch adjusts the packet buffer size to also accomodate the KEY and MSC events. Keyboards normally send one or two keys at a time. MT devices normally send a number of button keys along with the MT information. The buffer size chosen here covers those cases, and matches the default buffer size in evdev. Since the input estimate is now preferred, remove the special input-mt estimate. Reviewed-and-tested-by: Ping Cheng Tested-by: Benjamin Tissoires Acked-by: Dmitry Torokhov Signed-off-by: Henrik Rydberg --- drivers/input/input.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/input/input.c') diff --git a/drivers/input/input.c b/drivers/input/input.c index 79a4a2ad74de..fb3a2c112deb 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1778,6 +1778,9 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev) if (test_bit(i, dev->relbit)) events++; + /* Make room for KEY and MSC events */ + events += 7; + return events; } @@ -1816,6 +1819,7 @@ int input_register_device(struct input_dev *dev) { static atomic_t input_no = ATOMIC_INIT(0); struct input_handler *handler; + unsigned int packet_size; const char *path; int error; @@ -1828,9 +1832,9 @@ int input_register_device(struct input_dev *dev) /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev); - if (!dev->hint_events_per_packet) - dev->hint_events_per_packet = - input_estimate_events_per_packet(dev); + packet_size = input_estimate_events_per_packet(dev); + if (dev->hint_events_per_packet < packet_size) + dev->hint_events_per_packet = packet_size; /* * If delay and period are pre-set by the driver, then autorepeating -- cgit From 0672120a2ee7c533dfec6db7c3e43450f439e5ff Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Fri, 10 Aug 2012 21:39:38 +0200 Subject: Input: Make sure we follow all EV_KEY events For some EV_KEY types, sending a larger-than-one value causes the input state to oscillate. This patch makes sure this cannot happen, clearing up the autorepeat bypass logic in the process. Tested-by: Benjamin Tissoires Tested-by: Ping Cheng Acked-by: Dmitry Torokhov Signed-off-by: Henrik Rydberg --- drivers/input/input.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/input/input.c') diff --git a/drivers/input/input.c b/drivers/input/input.c index fb3a2c112deb..f075fbbfb1e7 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -240,24 +240,30 @@ static void input_handle_event(struct input_dev *dev, break; case EV_KEY: - if (is_event_supported(code, dev->keybit, KEY_MAX) && - !!test_bit(code, dev->key) != value) { + if (is_event_supported(code, dev->keybit, KEY_MAX)) { + + /* auto-repeat bypasses state updates */ + if (value == 2) { + disposition = INPUT_PASS_TO_HANDLERS; + break; + } + + if (!!test_bit(code, dev->key) != !!value) { - if (value != 2) { __change_bit(code, dev->key); + disposition = INPUT_PASS_TO_HANDLERS; + if (value) input_start_autorepeat(dev, code); else input_stop_autorepeat(dev); } - - disposition = INPUT_PASS_TO_HANDLERS; } break; case EV_SW: if (is_event_supported(code, dev->swbit, SW_MAX) && - !!test_bit(code, dev->sw) != value) { + !!test_bit(code, dev->sw) != !!value) { __change_bit(code, dev->sw); disposition = INPUT_PASS_TO_HANDLERS; @@ -284,7 +290,7 @@ static void input_handle_event(struct input_dev *dev, case EV_LED: if (is_event_supported(code, dev->ledbit, LED_MAX) && - !!test_bit(code, dev->led) != value) { + !!test_bit(code, dev->led) != !!value) { __change_bit(code, dev->led); disposition = INPUT_PASS_TO_ALL; -- cgit From 352ac4bd018005cfa6f844433a98aa0b724fa8db Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Fri, 10 Aug 2012 21:36:15 +0200 Subject: Input: Move autorepeat to the event-passing phase Preparing to split event filtering and event passing, move the autorepeat function to the point where the event is actually passed. Tested-by: Benjamin Tissoires Tested-by: Ping Cheng Acked-by: Dmitry Torokhov Signed-off-by: Henrik Rydberg --- drivers/input/input.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'drivers/input/input.c') diff --git a/drivers/input/input.c b/drivers/input/input.c index f075fbbfb1e7..fbe522d0ead7 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -69,6 +69,22 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz) return value; } +static void input_start_autorepeat(struct input_dev *dev, int code) +{ + if (test_bit(EV_REP, dev->evbit) && + dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && + dev->timer.data) { + dev->repeat_key = code; + mod_timer(&dev->timer, + jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); + } +} + +static void input_stop_autorepeat(struct input_dev *dev) +{ + del_timer(&dev->timer); +} + /* * Pass event first through all filters and then, if event has not been * filtered out, through all open handles. This function is called with @@ -105,6 +121,15 @@ static void input_pass_event(struct input_dev *dev, } rcu_read_unlock(); + + /* trigger auto repeat for key events */ + if (type == EV_KEY && value != 2) { + if (value) + input_start_autorepeat(dev, code); + else + input_stop_autorepeat(dev); + } + } /* @@ -142,22 +167,6 @@ static void input_repeat_key(unsigned long data) spin_unlock_irqrestore(&dev->event_lock, flags); } -static void input_start_autorepeat(struct input_dev *dev, int code) -{ - if (test_bit(EV_REP, dev->evbit) && - dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && - dev->timer.data) { - dev->repeat_key = code; - mod_timer(&dev->timer, - jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); - } -} - -static void input_stop_autorepeat(struct input_dev *dev) -{ - del_timer(&dev->timer); -} - #define INPUT_IGNORE_EVENT 0 #define INPUT_PASS_TO_HANDLERS 1 #define INPUT_PASS_TO_DEVICE 2 @@ -252,11 +261,6 @@ static void input_handle_event(struct input_dev *dev, __change_bit(code, dev->key); disposition = INPUT_PASS_TO_HANDLERS; - - if (value) - input_start_autorepeat(dev, code); - else - input_stop_autorepeat(dev); } } break; -- cgit From 4369c64c79a22b98d3b7eff9d089196cd878a10a Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Sat, 15 Sep 2012 15:23:35 +0200 Subject: Input: Send events one packet at a time On heavy event loads, such as a multitouch driver, the irqsoff latency can be as high as 250 us. By accumulating a frame worth of data before passing it on, the latency can be dramatically reduced. As a side effect, the special EV_SYN handling can be removed, since the frame is now atomic. This patch adds the events() handler callback and uses it if it exists. The latency is improved by 50 us even without the callback. Cc: Daniel Kurtz Tested-by: Benjamin Tissoires Tested-by: Ping Cheng Tested-by: Sedat Dilek Acked-by: Dmitry Torokhov Signed-off-by: Henrik Rydberg --- drivers/input/input.c | 176 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 123 insertions(+), 53 deletions(-) (limited to 'drivers/input/input.c') diff --git a/drivers/input/input.c b/drivers/input/input.c index fbe522d0ead7..5244f3d05b12 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -47,6 +47,8 @@ static DEFINE_MUTEX(input_mutex); static struct input_handler *input_table[8]; +static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 }; + static inline int is_event_supported(unsigned int code, unsigned long *bm, unsigned int max) { @@ -90,46 +92,81 @@ static void input_stop_autorepeat(struct input_dev *dev) * filtered out, through all open handles. This function is called with * dev->event_lock held and interrupts disabled. */ -static void input_pass_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) +static unsigned int input_to_handler(struct input_handle *handle, + struct input_value *vals, unsigned int count) { - struct input_handler *handler; - struct input_handle *handle; + struct input_handler *handler = handle->handler; + struct input_value *end = vals; + struct input_value *v; - rcu_read_lock(); + for (v = vals; v != vals + count; v++) { + if (handler->filter && + handler->filter(handle, v->type, v->code, v->value)) + continue; + if (end != v) + *end = *v; + end++; + } - handle = rcu_dereference(dev->grab); - if (handle) - handle->handler->event(handle, type, code, value); - else { - bool filtered = false; + count = end - vals; + if (!count) + return 0; - list_for_each_entry_rcu(handle, &dev->h_list, d_node) { - if (!handle->open) - continue; + if (handler->events) + handler->events(handle, vals, count); + else if (handler->event) + for (v = vals; v != end; v++) + handler->event(handle, v->type, v->code, v->value); + + return count; +} + +/* + * Pass values first through all filters and then, if event has not been + * filtered out, through all open handles. This function is called with + * dev->event_lock held and interrupts disabled. + */ +static void input_pass_values(struct input_dev *dev, + struct input_value *vals, unsigned int count) +{ + struct input_handle *handle; + struct input_value *v; - handler = handle->handler; - if (!handler->filter) { - if (filtered) - break; + if (!count) + return; - handler->event(handle, type, code, value); + rcu_read_lock(); - } else if (handler->filter(handle, type, code, value)) - filtered = true; - } + handle = rcu_dereference(dev->grab); + if (handle) { + count = input_to_handler(handle, vals, count); + } else { + list_for_each_entry_rcu(handle, &dev->h_list, d_node) + if (handle->open) + count = input_to_handler(handle, vals, count); } rcu_read_unlock(); + add_input_randomness(vals->type, vals->code, vals->value); + /* trigger auto repeat for key events */ - if (type == EV_KEY && value != 2) { - if (value) - input_start_autorepeat(dev, code); - else - input_stop_autorepeat(dev); + for (v = vals; v != vals + count; v++) { + if (v->type == EV_KEY && v->value != 2) { + if (v->value) + input_start_autorepeat(dev, v->code); + else + input_stop_autorepeat(dev); + } } +} +static void input_pass_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) +{ + struct input_value vals[] = { { type, code, value } }; + + input_pass_values(dev, vals, ARRAY_SIZE(vals)); } /* @@ -146,18 +183,12 @@ static void input_repeat_key(unsigned long data) if (test_bit(dev->repeat_key, dev->key) && is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) { + struct input_value vals[] = { + { EV_KEY, dev->repeat_key, 2 }, + input_value_sync + }; - input_pass_event(dev, EV_KEY, dev->repeat_key, 2); - - if (dev->sync) { - /* - * Only send SYN_REPORT if we are not in a middle - * of driver parsing a new hardware packet. - * Otherwise assume that the driver will send - * SYN_REPORT once it's done. - */ - input_pass_event(dev, EV_SYN, SYN_REPORT, 1); - } + input_pass_values(dev, vals, ARRAY_SIZE(vals)); if (dev->rep[REP_PERIOD]) mod_timer(&dev->timer, jiffies + @@ -170,6 +201,8 @@ static void input_repeat_key(unsigned long data) #define INPUT_IGNORE_EVENT 0 #define INPUT_PASS_TO_HANDLERS 1 #define INPUT_PASS_TO_DEVICE 2 +#define INPUT_SLOT 4 +#define INPUT_FLUSH 8 #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) static int input_handle_abs_event(struct input_dev *dev, @@ -216,14 +249,14 @@ static int input_handle_abs_event(struct input_dev *dev, /* Flush pending "slot" event */ if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) { input_abs_set_val(dev, ABS_MT_SLOT, mt->slot); - input_pass_event(dev, EV_ABS, ABS_MT_SLOT, mt->slot); + return INPUT_PASS_TO_HANDLERS | INPUT_SLOT; } return INPUT_PASS_TO_HANDLERS; } -static void input_handle_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) +static int input_get_disposition(struct input_dev *dev, + unsigned int type, unsigned int code, int value) { int disposition = INPUT_IGNORE_EVENT; @@ -236,13 +269,9 @@ static void input_handle_event(struct input_dev *dev, break; case SYN_REPORT: - if (!dev->sync) { - dev->sync = true; - disposition = INPUT_PASS_TO_HANDLERS; - } + disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH; break; case SYN_MT_REPORT: - dev->sync = false; disposition = INPUT_PASS_TO_HANDLERS; break; } @@ -327,14 +356,48 @@ static void input_handle_event(struct input_dev *dev, break; } - if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) - dev->sync = false; + return disposition; +} + +static void input_handle_event(struct input_dev *dev, + unsigned int type, unsigned int code, int value) +{ + int disposition; + + disposition = input_get_disposition(dev, type, code, value); if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) dev->event(dev, type, code, value); - if (disposition & INPUT_PASS_TO_HANDLERS) - input_pass_event(dev, type, code, value); + if (!dev->vals) + return; + + if (disposition & INPUT_PASS_TO_HANDLERS) { + struct input_value *v; + + if (disposition & INPUT_SLOT) { + v = &dev->vals[dev->num_vals++]; + v->type = EV_ABS; + v->code = ABS_MT_SLOT; + v->value = dev->mt->slot; + } + + v = &dev->vals[dev->num_vals++]; + v->type = type; + v->code = code; + v->value = value; + } + + if (disposition & INPUT_FLUSH) { + if (dev->num_vals >= 2) + input_pass_values(dev, dev->vals, dev->num_vals); + dev->num_vals = 0; + } else if (dev->num_vals >= dev->max_vals - 2) { + dev->vals[dev->num_vals++] = input_value_sync; + input_pass_values(dev, dev->vals, dev->num_vals); + dev->num_vals = 0; + } + } /** @@ -362,7 +425,6 @@ void input_event(struct input_dev *dev, if (is_event_supported(type, dev->evbit, EV_MAX)) { spin_lock_irqsave(&dev->event_lock, flags); - add_input_randomness(type, code, value); input_handle_event(dev, type, code, value); spin_unlock_irqrestore(&dev->event_lock, flags); } @@ -841,10 +903,12 @@ int input_set_keycode(struct input_dev *dev, if (test_bit(EV_KEY, dev->evbit) && !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && __test_and_clear_bit(old_keycode, dev->key)) { + struct input_value vals[] = { + { EV_KEY, old_keycode, 0 }, + input_value_sync + }; - input_pass_event(dev, EV_KEY, old_keycode, 0); - if (dev->sync) - input_pass_event(dev, EV_SYN, SYN_REPORT, 1); + input_pass_values(dev, vals, ARRAY_SIZE(vals)); } out: @@ -1426,6 +1490,7 @@ static void input_dev_release(struct device *device) input_ff_destroy(dev); input_mt_destroy_slots(dev); kfree(dev->absinfo); + kfree(dev->vals); kfree(dev); module_put(THIS_MODULE); @@ -1846,6 +1911,11 @@ int input_register_device(struct input_dev *dev) if (dev->hint_events_per_packet < packet_size) dev->hint_events_per_packet = packet_size; + dev->max_vals = max(dev->hint_events_per_packet, packet_size) + 2; + dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL); + if (!dev->vals) + return -ENOMEM; + /* * If delay and period are pre-set by the driver, then autorepeating * is handled by the driver itself and we don't do it in input.c. -- cgit