-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 05/22/10 18:30, Henrik Rydberg wrote: > 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. > Sorry, about taking so long to look at this patch. This looks like a good step forward and it looks good to me. Acked-by: Rafi Rubin <rafi@xxxxxxxxxxxxxx> > Signed-off-by: Henrik Rydberg <rydberg@xxxxxxxxxxx> > --- > Revision 5 incorporates the following changes: > - Rename the slot event to ABS_MT_SLOT to keep all MT-related events > in the same namespace. > - Move the MT slot event list to input.h so that it can be read > by userspace. > > drivers/input/input.c | 105 +++++++++++++++++++++++++++++++++++++------------ > include/linux/input.h | 44 ++++++++++++++++++++ > 2 files changed, 123 insertions(+), 26 deletions(-) > > diff --git a/drivers/input/input.c b/drivers/input/input.c > index 9c79bd5..9b6d474 100644 > --- a/drivers/input/input.c > +++ b/drivers/input/input.c > @@ -33,24 +33,9 @@ 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 unsigned int input_mt_abs_map_init_data[] __initdata = > + MT_SLOT_ABS_EVENTS; > +static unsigned char input_mt_abs_map[ABS_CNT]; > > static LIST_HEAD(input_dev_list); > static LIST_HEAD(input_handler_list); > @@ -181,6 +166,26 @@ 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 void input_mt_handle_abs_event(struct input_dev *dev, > + unsigned int code, int value) > +{ > + if (dev->mt) { > + struct input_mt_slot *mtslot = &dev->mt[dev->slot]; > + unsigned int mtcode = input_mt_abs_map[code] - 1; > + int old = mtslot->abs[mtcode]; > + value = input_defuzz_abs_event(value, old, dev->absfuzz[code]); > + if (value == old) > + return; > + mtslot->abs[mtcode] = value; > + } > + dev->sync = 0; > + if (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); > + } > + input_pass_event(dev, EV_ABS, code, value); > +} > + > static void input_handle_event(struct input_dev *dev, > unsigned int type, unsigned int code, int value) > { > @@ -235,11 +240,17 @@ static void input_handle_event(struct input_dev *dev, > case EV_ABS: > if (is_event_supported(code, dev->absbit, ABS_MAX)) { > > - if (test_bit(code, input_abs_bypass)) { > - disposition = INPUT_PASS_TO_HANDLERS; > + if (code == ABS_MT_SLOT) { > + if (value >= 0 && value < dev->mtsize) > + dev->slot = value; > break; > } > > + if (input_mt_abs_map[code]) { > + input_mt_handle_abs_event(dev, code, value); > + return; > + } > + > value = input_defuzz_abs_event(value, > dev->abs[code], dev->absfuzz[code]); > > @@ -1278,6 +1289,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); > @@ -1518,6 +1530,46 @@ 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 > + * @max_slots: maximum number of slots supported 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, int max_slots) > +{ > + struct input_mt_slot *mt; > + > + if (max_slots <= 0) > + return 0; > + mt = kzalloc(max_slots * sizeof(struct input_mt_slot), GFP_KERNEL); > + if (!mt) > + return -ENOMEM; > + > + dev->mt = mt; > + dev->mtsize = max_slots; > + input_set_abs_params(dev, ABS_MT_SLOT, 0, max_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 > * @type: type of the event (EV_KEY, EV_REL, etc...) > @@ -1926,19 +1978,20 @@ static const struct file_operations input_fops = { > .open = input_open_file, > }; > > -static void __init input_init_abs_bypass(void) > +static void __init input_mt_init_maps(void) > { > - const unsigned int *p; > - > - for (p = input_abs_bypass_init_data; *p; p++) > - input_abs_bypass[BIT_WORD(*p)] |= BIT_MASK(*p); > + int i; > + BUILD_BUG_ON(MT_ABS_SIZE != (typeof(input_mt_abs_map[0]))MT_ABS_SIZE); > + BUILD_BUG_ON(ARRAY_SIZE(input_mt_abs_map_init_data) > MT_ABS_SIZE); > + for (i = 0; i < ARRAY_SIZE(input_mt_abs_map_init_data); i++) > + input_mt_abs_map[input_mt_abs_map_init_data[i]] = i + 1; > } > > static int __init input_init(void) > { > int err; > > - input_init_abs_bypass(); > + input_mt_init_maps(); > > err = class_register(&input_class); > if (err) { > diff --git a/include/linux/input.h b/include/linux/input.h > index 7ed2251..bea6958 100644 > --- a/include/linux/input.h > +++ b/include/linux/input.h > @@ -694,6 +694,7 @@ struct input_absinfo { > #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 */ > @@ -814,6 +815,24 @@ struct input_absinfo { > #define MT_TOOL_PEN 1 > > /* > + * MT slot event lists > + */ > + > +#define MT_SLOT_ABS_EVENTS { \ > + 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, \ > +} > + > +/* > * Values describing the status of a force-feedback effect > */ > #define FF_STATUS_STOPPED 0x00 > @@ -1080,6 +1099,9 @@ 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: array of MT slots > + * @mtsize: number of allocated MT slots > + * @slot: current MT slot > * @key: reflects current state of device's keys/buttons > * @led: reflects current state of device's LEDs > * @snd: reflects current state of sound effects > @@ -1157,6 +1179,10 @@ struct input_dev { > int abs[ABS_MAX + 1]; > 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)]; > @@ -1405,6 +1431,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); > > static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat) > @@ -1484,5 +1515,18 @@ 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 *)); > > +#define MT_ABS_SIZE 11 > + > +/** > + * struct input_mt_slot - represents the state of an input MT slot > + * @abs: current values of ABS_MT axes for this slot > + */ > +struct input_mt_slot { > + int abs[MT_ABS_SIZE]; > +}; > + > +int input_mt_create_slots(struct input_dev *dev, int max_slots); > +void input_mt_destroy_slots(struct input_dev *dev); > + > #endif > #endif -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAkwXCKwACgkQwuRiAT9o608AfwCfT15rbveKL/kCROKk5E7xg81L zrYAoK8edxq+1HeBDBcHiuP2rDoy4Oi/ =J6e0 -----END PGP SIGNATURE----- -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html