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/input.c | 135 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 92 insertions(+), 43 deletions(-) (limited to 'drivers/input/input.c') diff --git a/drivers/input/input.c b/drivers/input/input.c index a3d5485154e..54109c33e36 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"); -- cgit v1.2.3-70-g09d2