diff options
Diffstat (limited to 'drivers/input/input.c')
| -rw-r--r-- | drivers/input/input.c | 90 | 
1 files changed, 72 insertions, 18 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index 86cb2d2196f..41168d5f8c1 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -87,12 +87,14 @@ static int input_defuzz_abs_event(int value, int old_val, int fuzz)  }  /* - * Pass event through all open handles. This function is called with + * Pass event 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_event(struct input_dev *dev,  			     unsigned int type, unsigned int code, int value)  { +	struct input_handler *handler;  	struct input_handle *handle;  	rcu_read_lock(); @@ -100,11 +102,25 @@ static void input_pass_event(struct input_dev *dev,  	handle = rcu_dereference(dev->grab);  	if (handle)  		handle->handler->event(handle, type, code, value); -	else -		list_for_each_entry_rcu(handle, &dev->h_list, d_node) -			if (handle->open) -				handle->handler->event(handle, -							type, code, value); +	else { +		bool filtered = false; + +		list_for_each_entry_rcu(handle, &dev->h_list, d_node) { +			if (!handle->open) +				continue; + +			handler = handle->handler; +			if (!handler->filter) { +				if (filtered) +					break; + +				handler->event(handle, type, code, value); + +			} else if (handler->filter(handle, type, code, value)) +				filtered = true; +		} +	} +  	rcu_read_unlock();  } @@ -615,12 +631,12 @@ static int input_default_setkeycode(struct input_dev *dev,  		}  	} -	clear_bit(old_keycode, dev->keybit); -	set_bit(keycode, dev->keybit); +	__clear_bit(old_keycode, dev->keybit); +	__set_bit(keycode, dev->keybit);  	for (i = 0; i < dev->keycodemax; i++) {  		if (input_fetch_keycode(dev, i) == old_keycode) { -			set_bit(old_keycode, dev->keybit); +			__set_bit(old_keycode, dev->keybit);  			break; /* Setting the bit twice is useless, so break */  		}  	} @@ -678,6 +694,9 @@ int input_set_keycode(struct input_dev *dev, int scancode, int keycode)  	if (retval)  		goto out; +	/* Make sure KEY_RESERVED did not get enabled. */ +	__clear_bit(KEY_RESERVED, dev->keybit); +  	/*  	 * Simulate keyup event if keycode is not present  	 * in the keymap anymore @@ -705,12 +724,13 @@ EXPORT_SYMBOL(input_set_keycode);  		if (i != BITS_TO_LONGS(max)) \  			continue; -static const struct input_device_id *input_match_device(const struct input_device_id *id, +static const struct input_device_id *input_match_device(struct input_handler *handler,  							struct input_dev *dev)  { +	const struct input_device_id *id;  	int i; -	for (; id->flags || id->driver_info; id++) { +	for (id = handler->id_table; id->flags || id->driver_info; id++) {  		if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)  			if (id->bustype != dev->id.bustype) @@ -738,7 +758,8 @@ static const struct input_device_id *input_match_device(const struct input_devic  		MATCH_BIT(ffbit,  FF_MAX);  		MATCH_BIT(swbit,  SW_MAX); -		return id; +		if (!handler->match || handler->match(handler, dev)) +			return id;  	}  	return NULL; @@ -749,10 +770,7 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han  	const struct input_device_id *id;  	int error; -	if (handler->blacklist && input_match_device(handler->blacklist, dev)) -		return -ENODEV; - -	id = input_match_device(handler->id_table, dev); +	id = input_match_device(handler, dev);  	if (!id)  		return -ENODEV; @@ -988,6 +1006,8 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v)  	union input_seq_state *state = (union input_seq_state *)&seq->private;  	seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name); +	if (handler->filter) +		seq_puts(seq, " (filter)");  	if (handler->fops)  		seq_printf(seq, " Minor=%d", handler->minor);  	seq_putc(seq, '\n'); @@ -1551,6 +1571,25 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int  }  EXPORT_SYMBOL(input_set_capability); +#define INPUT_CLEANSE_BITMASK(dev, type, bits)				\ +	do {								\ +		if (!test_bit(EV_##type, dev->evbit))			\ +			memset(dev->bits##bit, 0,			\ +				sizeof(dev->bits##bit));		\ +	} while (0) + +static void input_cleanse_bitmasks(struct input_dev *dev) +{ +	INPUT_CLEANSE_BITMASK(dev, KEY, key); +	INPUT_CLEANSE_BITMASK(dev, REL, rel); +	INPUT_CLEANSE_BITMASK(dev, ABS, abs); +	INPUT_CLEANSE_BITMASK(dev, MSC, msc); +	INPUT_CLEANSE_BITMASK(dev, LED, led); +	INPUT_CLEANSE_BITMASK(dev, SND, snd); +	INPUT_CLEANSE_BITMASK(dev, FF, ff); +	INPUT_CLEANSE_BITMASK(dev, SW, sw); +} +  /**   * input_register_device - register device with input core   * @dev: device to be registered @@ -1570,13 +1609,19 @@ int input_register_device(struct input_dev *dev)  	const char *path;  	int error; +	/* Every input device generates EV_SYN/SYN_REPORT events. */  	__set_bit(EV_SYN, dev->evbit); +	/* KEY_RESERVED is not supposed to be transmitted to userspace. */ +	__clear_bit(KEY_RESERVED, dev->keybit); + +	/* Make sure that bitmasks not mentioned in dev->evbit are clean. */ +	input_cleanse_bitmasks(dev); +  	/*  	 * 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.  	 */ -  	init_timer(&dev->timer);  	if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {  		dev->timer.data = (long) dev; @@ -1776,7 +1821,16 @@ int input_register_handle(struct input_handle *handle)  	error = mutex_lock_interruptible(&dev->mutex);  	if (error)  		return error; -	list_add_tail_rcu(&handle->d_node, &dev->h_list); + +	/* +	 * Filters go to the head of the list, normal handlers +	 * to the tail. +	 */ +	if (handler->filter) +		list_add_rcu(&handle->d_node, &dev->h_list); +	else +		list_add_tail_rcu(&handle->d_node, &dev->h_list); +  	mutex_unlock(&dev->mutex);  	/*  |