diff options
Diffstat (limited to 'drivers/input/input.c')
| -rw-r--r-- | drivers/input/input.c | 182 | 
1 files changed, 125 insertions, 57 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index 9c79bd56b51..e1243b4b32a 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)  { @@ -196,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;  		} @@ -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: @@ -298,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); @@ -528,12 +547,30 @@ void input_close_device(struct input_handle *handle)  EXPORT_SYMBOL(input_close_device);  /* + * Simulate keyup events for all keys that are marked as pressed. + * The function must be called with dev->event_lock held. + */ +static void input_dev_release_keys(struct input_dev *dev) +{ +	int code; + +	if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { +		for (code = 0; code <= KEY_MAX; code++) { +			if (is_event_supported(code, dev->keybit, KEY_MAX) && +			    __test_and_clear_bit(code, dev->key)) { +				input_pass_event(dev, EV_KEY, code, 0); +			} +		} +		input_pass_event(dev, EV_SYN, SYN_REPORT, 1); +	} +} + +/*   * Prepare device for unregistering   */  static void input_disconnect_device(struct input_dev *dev)  {  	struct input_handle *handle; -	int code;  	/*  	 * Mark device as going away. Note that we take dev->mutex here @@ -552,15 +589,7 @@ static void input_disconnect_device(struct input_dev *dev)  	 * generate events even after we done here but they will not  	 * reach any handlers.  	 */ -	if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { -		for (code = 0; code <= KEY_MAX; code++) { -			if (is_event_supported(code, dev->keybit, KEY_MAX) && -			    __test_and_clear_bit(code, dev->key)) { -				input_pass_event(dev, EV_KEY, code, 0); -			} -		} -		input_pass_event(dev, EV_SYN, SYN_REPORT, 1); -	} +	input_dev_release_keys(dev);  	list_for_each_entry(handle, &dev->h_list, d_node)  		handle->open = 0; @@ -684,7 +713,7 @@ int input_set_keycode(struct input_dev *dev,  		      unsigned int scancode, unsigned int keycode)  {  	unsigned long flags; -	int old_keycode; +	unsigned int old_keycode;  	int retval;  	if (keycode > KEY_MAX) @@ -1278,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); @@ -1433,6 +1463,15 @@ static int input_dev_resume(struct device *dev)  	mutex_lock(&input_dev->mutex);  	input_dev_reset(input_dev, true); + +	/* +	 * Keys that have been pressed at suspend time are unlikely +	 * to be still pressed when we resume. +	 */ +	spin_lock_irq(&input_dev->event_lock); +	input_dev_release_keys(input_dev); +	spin_unlock_irq(&input_dev->event_lock); +  	mutex_unlock(&input_dev->mutex);  	return 0; @@ -1518,6 +1557,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   * @type: type of the event (EV_KEY, EV_REL, etc...) @@ -1926,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");  | 
