Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 323415
b: refs/heads/master
c: 4369c64
h: refs/heads/master
i:
  323413: 2068bea
  323411: 86b7a99
  323407: 4fcf249
v: v3
  • Loading branch information
Henrik Rydberg committed Sep 19, 2012
1 parent 32ed2f2 commit b0807c3
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 57 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 352ac4bd018005cfa6f844433a98aa0b724fa8db
refs/heads/master: 4369c64c79a22b98d3b7eff9d089196cd878a10a
176 changes: 123 additions & 53 deletions trunk/drivers/input/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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));
}

/*
Expand All @@ -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 +
Expand All @@ -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,
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
}

}

/**
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down
24 changes: 21 additions & 3 deletions trunk/include/linux/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,18 @@ struct ff_effect {
#include <linux/timer.h>
#include <linux/mod_devicetable.h>

/**
* struct input_value - input value representation
* @type: type of value (EV_KEY, EV_ABS, etc)
* @code: the value code
* @value: the value
*/
struct input_value {
__u16 type;
__u16 code;
__s32 value;
};

/**
* struct input_dev - represents an input device
* @name: name of the device
Expand Down Expand Up @@ -1240,7 +1252,6 @@ struct ff_effect {
* last user closes the device
* @going_away: marks devices that are in a middle of unregistering and
* causes input_open_device*() fail with -ENODEV.
* @sync: set to %true when there were no new events since last EV_SYN
* @dev: driver model's view of this device
* @h_list: list of input handles associated with the device. When
* accessing the list dev->mutex must be held
Expand Down Expand Up @@ -1305,12 +1316,14 @@ struct input_dev {
unsigned int users;
bool going_away;

bool sync;

struct device dev;

struct list_head h_list;
struct list_head node;

unsigned int num_vals;
unsigned int max_vals;
struct input_value *vals;
};
#define to_input_dev(d) container_of(d, struct input_dev, dev)

Expand Down Expand Up @@ -1371,6 +1384,9 @@ struct input_handle;
* @event: event handler. This method is being called by input core with
* interrupts disabled and dev->event_lock spinlock held and so
* it may not sleep
* @events: event sequence handler. This method is being called by
* input core with interrupts disabled and dev->event_lock
* spinlock held and so it may not sleep
* @filter: similar to @event; separates normal event handlers from
* "filters".
* @match: called after comparing device's id with handler's id_table
Expand Down Expand Up @@ -1407,6 +1423,8 @@ struct input_handler {
void *private;

void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
void (*events)(struct input_handle *handle,
const struct input_value *vals, unsigned int count);
bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
bool (*match)(struct input_handler *handler, struct input_dev *dev);
int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
Expand Down

0 comments on commit b0807c3

Please sign in to comment.