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)
{
return value;
}
+static void input_start_autorepeat(struct input_dev *dev, int code)
+{
+ if (test_bit(EV_REP, dev->evbit) &&
+ dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
+ dev->timer.data) {
+ dev->repeat_key = code;
+ mod_timer(&dev->timer,
+ jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
+ }
+}
+
+static void input_stop_autorepeat(struct input_dev *dev)
+{
+ del_timer(&dev->timer);
+}
+
/*
* 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)
+static unsigned int input_to_handler(struct input_handle *handle,
+ struct input_value *vals, unsigned int count)
+{
+ struct input_handler *handler = handle->handler;
+ struct input_value *end = vals;
+ struct input_value *v;
+
+ 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++;
+ }
+
+ count = end - vals;
+ if (!count)
+ return 0;
+
+ 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_handler *handler;
struct input_handle *handle;
+ struct input_value *v;
+
+ if (!count)
+ return;
rcu_read_lock();
handle = rcu_dereference(dev->grab);
- if (handle)
- 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;
+ 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);
+ }
- handler = handle->handler;
- if (!handler->filter) {
- if (filtered)
- break;
+ rcu_read_unlock();
- handler->event(handle, type, code, value);
+ add_input_randomness(vals->type, vals->code, vals->value);
- } else if (handler->filter(handle, type, code, value))
- filtered = true;
+ /* trigger auto repeat for key events */
+ 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);
}
}
+}
- rcu_read_unlock();
+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));
}
/*
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 +
spin_unlock_irqrestore(&dev->event_lock, flags);
}
-static void input_start_autorepeat(struct input_dev *dev, int code)
-{
- if (test_bit(EV_REP, dev->evbit) &&
- dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
- dev->timer.data) {
- dev->repeat_key = code;
- mod_timer(&dev->timer,
- jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
- }
-}
-
-static void input_stop_autorepeat(struct input_dev *dev)
-{
- del_timer(&dev->timer);
-}
-
#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,
unsigned int code, int *pval)
{
+ struct input_mt *mt = dev->mt;
bool is_mt_event;
int *pold;
* "Stage" the event; we'll flush it later, when we
* get actual touch data.
*/
- if (*pval >= 0 && *pval < dev->mtsize)
- dev->slot = *pval;
+ if (mt && *pval >= 0 && *pval < mt->num_slots)
+ mt->slot = *pval;
return INPUT_IGNORE_EVENT;
}
if (!is_mt_event) {
pold = &dev->absinfo[code].value;
- } else if (dev->mt) {
- struct input_mt_slot *mtslot = &dev->mt[dev->slot];
- pold = &mtslot->abs[code - ABS_MT_FIRST];
+ } else if (mt) {
+ pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
} else {
/*
* Bypass filtering for multi-touch events when
}
/* Flush pending "slot" event */
- if (is_mt_event && dev->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
- input_abs_set_val(dev, ABS_MT_SLOT, dev->slot);
- input_pass_event(dev, EV_ABS, ABS_MT_SLOT, dev->slot);
+ 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);
+ 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;
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;
}
break;
case EV_KEY:
- if (is_event_supported(code, dev->keybit, KEY_MAX) &&
- !!test_bit(code, dev->key) != value) {
+ if (is_event_supported(code, dev->keybit, KEY_MAX)) {
- if (value != 2) {
- __change_bit(code, dev->key);
- if (value)
- input_start_autorepeat(dev, code);
- else
- input_stop_autorepeat(dev);
+ /* auto-repeat bypasses state updates */
+ if (value == 2) {
+ disposition = INPUT_PASS_TO_HANDLERS;
+ break;
}
- disposition = INPUT_PASS_TO_HANDLERS;
+ if (!!test_bit(code, dev->key) != !!value) {
+
+ __change_bit(code, dev->key);
+ disposition = INPUT_PASS_TO_HANDLERS;
+ }
}
break;
case EV_SW:
if (is_event_supported(code, dev->swbit, SW_MAX) &&
- !!test_bit(code, dev->sw) != value) {
+ !!test_bit(code, dev->sw) != !!value) {
__change_bit(code, dev->sw);
disposition = INPUT_PASS_TO_HANDLERS;
case EV_LED:
if (is_event_supported(code, dev->ledbit, LED_MAX) &&
- !!test_bit(code, dev->led) != value) {
+ !!test_bit(code, dev->led) != !!value) {
__change_bit(code, dev->led);
disposition = INPUT_PASS_TO_ALL;
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;
+ }
+
}
/**
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);
}
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:
}
EXPORT_SYMBOL(input_set_keycode);
- #define MATCH_BIT(bit, max) \
- for (i = 0; i < BITS_TO_LONGS(max); i++) \
- if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \
- break; \
- if (i != BITS_TO_LONGS(max)) \
- continue;
-
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 = handler->id_table; id->flags || id->driver_info; id++) {
if (id->version != dev->id.version)
continue;
- MATCH_BIT(evbit, EV_MAX);
- MATCH_BIT(keybit, KEY_MAX);
- MATCH_BIT(relbit, REL_MAX);
- MATCH_BIT(absbit, ABS_MAX);
- MATCH_BIT(mscbit, MSC_MAX);
- MATCH_BIT(ledbit, LED_MAX);
- MATCH_BIT(sndbit, SND_MAX);
- MATCH_BIT(ffbit, FF_MAX);
- MATCH_BIT(swbit, SW_MAX);
+ if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX))
+ continue;
+
+ if (!bitmap_subset(id->keybit, dev->keybit, KEY_MAX))
+ continue;
+
+ if (!bitmap_subset(id->relbit, dev->relbit, REL_MAX))
+ continue;
+
+ if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX))
+ continue;
+
+ if (!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX))
+ continue;
+
+ if (!bitmap_subset(id->ledbit, dev->ledbit, LED_MAX))
+ continue;
+
+ if (!bitmap_subset(id->sndbit, dev->sndbit, SND_MAX))
+ continue;
+
+ if (!bitmap_subset(id->ffbit, dev->ffbit, FF_MAX))
+ continue;
+
+ if (!bitmap_subset(id->swbit, dev->swbit, SW_MAX))
+ continue;
if (!handler->match || handler->match(handler, dev))
return id;
input_ff_destroy(dev);
input_mt_destroy_slots(dev);
kfree(dev->absinfo);
+ kfree(dev->vals);
kfree(dev);
module_put(THIS_MODULE);
int i;
unsigned int events;
- if (dev->mtsize) {
- mt_slots = dev->mtsize;
+ if (dev->mt) {
+ mt_slots = dev->mt->num_slots;
} else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1,
if (test_bit(i, dev->relbit))
events++;
+ /* Make room for KEY and MSC events */
+ events += 7;
+
return events;
}
{
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handler *handler;
+ unsigned int packet_size;
const char *path;
int error;
/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev);
- if (!dev->hint_events_per_packet)
- dev->hint_events_per_packet =
- input_estimate_events_per_packet(dev);
+ packet_size = input_estimate_events_per_packet(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
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/slab.h>
-#include <asm/gpio.h>
-#include <plat/keypad.h>
-#include <plat/menelaus.h>
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <asm/io.h>
-#include <plat/mux.h>
+#include <linux/gpio.h>
+#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/keypad-omap.h>
#undef NEW_BOARD_LEARNING_MODE
static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
{
- struct omap_kp *omap_kp = dev_id;
-
/* disable keyboard interrupt and schedule for handling */
- if (cpu_is_omap24xx()) {
- int i;
-
- for (i = 0; i < omap_kp->rows; i++) {
- int gpio_irq = gpio_to_irq(row_gpios[i]);
- /*
- * The interrupt which we're currently handling should
- * be disabled _nosync() to avoid deadlocks waiting
- * for this handler to complete. All others should
- * be disabled the regular way for SMP safety.
- */
- if (gpio_irq == irq)
- disable_irq_nosync(gpio_irq);
- else
- disable_irq(gpio_irq);
- }
- } else
- /* disable keyboard interrupt and schedule for handling */
- omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
tasklet_schedule(&kp_tasklet);
{
int col = 0;
- /* read the keypad status */
- if (cpu_is_omap24xx()) {
- /* read the keypad status */
- for (col = 0; col < omap_kp->cols; col++) {
- set_col_gpio_val(omap_kp, ~(1 << col));
- state[col] = ~(get_row_gpio_val(omap_kp)) & 0xff;
- }
- set_col_gpio_val(omap_kp, 0);
-
- } else {
- /* disable keyboard interrupt and schedule for handling */
- omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ /* disable keyboard interrupt and schedule for handling */
+ omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- /* read the keypad status */
- omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
- for (col = 0; col < omap_kp->cols; col++) {
- omap_writew(~(1 << col) & 0xff,
- OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
+ /* read the keypad status */
+ omap_writew(0xff, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
+ for (col = 0; col < omap_kp->cols; col++) {
+ omap_writew(~(1 << col) & 0xff,
+ OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
- udelay(omap_kp->delay);
+ udelay(omap_kp->delay);
- state[col] = ~omap_readw(OMAP1_MPUIO_BASE +
- OMAP_MPUIO_KBR_LATCH) & 0xff;
- }
- omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
- udelay(2);
+ state[col] = ~omap_readw(OMAP1_MPUIO_BASE +
+ OMAP_MPUIO_KBR_LATCH) & 0xff;
}
+ omap_writew(0x00, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBC);
+ udelay(2);
}
static void omap_kp_tasklet(unsigned long data)
memcpy(keypad_state, new_state, sizeof(keypad_state));
if (key_down) {
- int delay = HZ / 20;
+ int delay = HZ / 20;
/* some key is pressed - keep irq disabled and use timer
* to poll the keypad */
if (spurious)
mod_timer(&omap_kp_data->timer, jiffies + delay);
} else {
/* enable interrupts */
- if (cpu_is_omap24xx()) {
- int i;
- for (i = 0; i < omap_kp_data->rows; i++)
- enable_irq(gpio_to_irq(row_gpios[i]));
- } else {
- omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- kp_cur_group = -1;
- }
+ omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ kp_cur_group = -1;
}
}
static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct omap_kp *omap_kp = dev_get_drvdata(dev);
int state;
if (sscanf(buf, "%u", &state) != 1)
mutex_lock(&kp_enable_mutex);
if (state != kp_enable) {
if (state)
- enable_irq(INT_KEYBOARD);
+ enable_irq(omap_kp->irq);
else
- disable_irq(INT_KEYBOARD);
+ disable_irq(omap_kp->irq);
kp_enable = state;
}
mutex_unlock(&kp_enable_mutex);
struct omap_kp *omap_kp;
struct input_dev *input_dev;
struct omap_kp_platform_data *pdata = pdev->dev.platform_data;
- int i, col_idx, row_idx, irq_idx, ret;
+ int i, col_idx, row_idx, ret;
unsigned int row_shift, keycodemax;
if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
omap_kp->input = input_dev;
/* Disable the interrupt for the MPUIO keyboard */
- if (!cpu_is_omap24xx())
- omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
if (pdata->delay)
omap_kp->delay = pdata->delay;
omap_kp->rows = pdata->rows;
omap_kp->cols = pdata->cols;
- if (cpu_is_omap24xx()) {
- /* Cols: outputs */
- for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) {
- if (gpio_request(col_gpios[col_idx], "omap_kp_col") < 0) {
- printk(KERN_ERR "Failed to request"
- "GPIO%d for keypad\n",
- col_gpios[col_idx]);
- goto err1;
- }
- gpio_direction_output(col_gpios[col_idx], 0);
- }
- /* Rows: inputs */
- for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) {
- if (gpio_request(row_gpios[row_idx], "omap_kp_row") < 0) {
- printk(KERN_ERR "Failed to request"
- "GPIO%d for keypad\n",
- row_gpios[row_idx]);
- goto err2;
- }
- gpio_direction_input(row_gpios[row_idx]);
- }
- } else {
- col_idx = 0;
- row_idx = 0;
- }
+ col_idx = 0;
+ row_idx = 0;
setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
/* scan current status and enable interrupt */
omap_kp_scan_keypad(omap_kp, keypad_state);
- if (!cpu_is_omap24xx()) {
- omap_kp->irq = platform_get_irq(pdev, 0);
- if (omap_kp->irq >= 0) {
- if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
- "omap-keypad", omap_kp) < 0)
- goto err4;
- }
- omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- } else {
- for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) {
- if (request_irq(gpio_to_irq(row_gpios[irq_idx]),
- omap_kp_interrupt,
- IRQF_TRIGGER_FALLING,
- "omap-keypad", omap_kp) < 0)
- goto err5;
- }
+ omap_kp->irq = platform_get_irq(pdev, 0);
+ if (omap_kp->irq >= 0) {
+ if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
+ "omap-keypad", omap_kp) < 0)
+ goto err4;
}
+ omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
return 0;
-err5:
- for (i = irq_idx - 1; i >= 0; i--)
- free_irq(row_gpios[i], omap_kp);
+
err4:
input_unregister_device(omap_kp->input);
input_dev = NULL;
err3:
device_remove_file(&pdev->dev, &dev_attr_enable);
err2:
- for (i = row_idx - 1; i >=0; i--)
+ for (i = row_idx - 1; i >= 0; i--)
gpio_free(row_gpios[i]);
- for (i = col_idx - 1; i >=0; i--)
-err1:
+ for (i = col_idx - 1; i >= 0; i--)
gpio_free(col_gpios[i]);
kfree(omap_kp);
/* disable keypad interrupt handling */
tasklet_disable(&kp_tasklet);
- if (cpu_is_omap24xx()) {
- int i;
- for (i = 0; i < omap_kp->cols; i++)
- gpio_free(col_gpios[i]);
- for (i = 0; i < omap_kp->rows; i++) {
- gpio_free(row_gpios[i]);
- free_irq(gpio_to_irq(row_gpios[i]), omap_kp);
- }
- } else {
- omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- free_irq(omap_kp->irq, omap_kp);
- }
+ omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ free_irq(omap_kp->irq, omap_kp);
del_timer_sync(&omap_kp->timer);
tasklet_kill(&kp_tasklet);
#include <linux/input/mt.h>
#include "../input-compat.h"
- static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+ static int uinput_dev_event(struct input_dev *dev,
+ unsigned int type, unsigned int code, int value)
{
struct uinput_device *udev = input_get_drvdata(dev);
}
/* Atomically allocate an ID for the given request. Returns 0 on success. */
- static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request)
+ static bool uinput_request_alloc_id(struct uinput_device *udev,
+ struct uinput_request *request)
{
- int id;
- int err = -1;
+ unsigned int id;
+ bool reserved = false;
spin_lock(&udev->requests_lock);
if (!udev->requests[id]) {
request->id = id;
udev->requests[id] = request;
- err = 0;
+ reserved = true;
break;
}
}
spin_unlock(&udev->requests_lock);
- return err;
+ return reserved;
}
- static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id)
+ static struct uinput_request *uinput_request_find(struct uinput_device *udev,
+ unsigned int id)
{
/* Find an input request, by ID. Returns NULL if the ID isn't valid. */
- if (id >= UINPUT_NUM_REQUESTS || id < 0)
+ if (id >= UINPUT_NUM_REQUESTS)
return NULL;
return udev->requests[id];
}
- static inline int uinput_request_reserve_slot(struct uinput_device *udev, struct uinput_request *request)
+ static int uinput_request_reserve_slot(struct uinput_device *udev,
+ struct uinput_request *request)
{
/* Allocate slot. If none are available right away, wait. */
return wait_event_interruptible(udev->requests_waitq,
- !uinput_request_alloc_id(udev, request));
+ uinput_request_alloc_id(udev, request));
}
- static void uinput_request_done(struct uinput_device *udev, struct uinput_request *request)
+ static void uinput_request_done(struct uinput_device *udev,
+ struct uinput_request *request)
{
/* Mark slot as available */
udev->requests[request->id] = NULL;
complete(&request->done);
}
- static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request)
+ static int uinput_request_send(struct uinput_device *udev,
+ struct uinput_request *request)
{
int retval;
- retval = uinput_request_reserve_slot(udev, request);
- if (retval)
- return retval;
-
retval = mutex_lock_interruptible(&udev->mutex);
if (retval)
return retval;
goto out;
}
- /* Tell our userspace app about this new request by queueing an input event */
+ init_completion(&request->done);
+
+ /*
+ * Tell our userspace application about this new request
+ * by queueing an input event.
+ */
uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
out:
return retval;
}
+ static int uinput_request_submit(struct uinput_device *udev,
+ struct uinput_request *request)
+ {
+ int error;
+
+ error = uinput_request_reserve_slot(udev, request);
+ if (error)
+ return error;
+
+ error = uinput_request_send(udev, request);
+ if (error) {
+ uinput_request_done(udev, request);
+ return error;
+ }
+
+ wait_for_completion(&request->done);
+ return request->retval;
+ }
+
/*
- * Fail all ouitstanding requests so handlers don't wait for the userspace
+ * Fail all outstanding requests so handlers don't wait for the userspace
* to finish processing them.
*/
static void uinput_flush_requests(struct uinput_device *udev)
return uinput_dev_event(dev, EV_FF, effect_id, value);
}
- static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
+ static int uinput_dev_upload_effect(struct input_dev *dev,
+ struct ff_effect *effect,
+ struct ff_effect *old)
{
struct uinput_device *udev = input_get_drvdata(dev);
struct uinput_request request;
- int retval;
/*
* uinput driver does not currently support periodic effects with
effect->u.periodic.waveform == FF_CUSTOM)
return -EINVAL;
- request.id = -1;
- init_completion(&request.done);
request.code = UI_FF_UPLOAD;
request.u.upload.effect = effect;
request.u.upload.old = old;
- retval = uinput_request_submit(udev, &request);
- if (!retval) {
- wait_for_completion(&request.done);
- retval = request.retval;
- }
-
- return retval;
+ return uinput_request_submit(udev, &request);
}
static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
{
struct uinput_device *udev = input_get_drvdata(dev);
struct uinput_request request;
- int retval;
if (!test_bit(EV_FF, dev->evbit))
return -ENOSYS;
- request.id = -1;
- init_completion(&request.done);
request.code = UI_FF_ERASE;
request.u.effect_id = effect_id;
- retval = uinput_request_submit(udev, &request);
- if (!retval) {
- wait_for_completion(&request.done);
- retval = request.retval;
- }
-
- return retval;
+ return uinput_request_submit(udev, &request);
}
static void uinput_destroy_device(struct uinput_device *udev)
return 0;
}
- static int uinput_setup_device(struct uinput_device *udev, const char __user *buffer, size_t count)
+ static int uinput_setup_device(struct uinput_device *udev,
+ const char __user *buffer, size_t count)
{
struct uinput_user_dev *user_dev;
struct input_dev *dev;
goto exit;
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
- input_mt_init_slots(dev, nslot);
+ input_mt_init_slots(dev, nslot, 0);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60);
}
return retval;
}
- static inline ssize_t uinput_inject_event(struct uinput_device *udev, const char __user *buffer, size_t count)
+ static ssize_t uinput_inject_event(struct uinput_device *udev,
+ const char __user *buffer, size_t count)
{
struct input_event ev;
return input_event_size();
}
- static ssize_t uinput_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+ static ssize_t uinput_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
struct uinput_device *udev = file->private_data;
int retval;
+ if (count == 0)
+ return 0;
+
retval = mutex_lock_interruptible(&udev->mutex);
if (retval)
return retval;
return retval;
}
- static ssize_t uinput_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+ static bool uinput_fetch_next_event(struct uinput_device *udev,
+ struct input_event *event)
{
- struct uinput_device *udev = file->private_data;
- int retval = 0;
+ bool have_event;
- if (udev->state != UIST_CREATED)
- return -ENODEV;
+ spin_lock_irq(&udev->dev->event_lock);
- if (udev->head == udev->tail && (file->f_flags & O_NONBLOCK))
- return -EAGAIN;
+ have_event = udev->head != udev->tail;
+ if (have_event) {
+ *event = udev->buff[udev->tail];
+ udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
+ }
- retval = wait_event_interruptible(udev->waitq,
- udev->head != udev->tail || udev->state != UIST_CREATED);
- if (retval)
- return retval;
+ spin_unlock_irq(&udev->dev->event_lock);
- retval = mutex_lock_interruptible(&udev->mutex);
- if (retval)
- return retval;
+ return have_event;
+ }
- if (udev->state != UIST_CREATED) {
- retval = -ENODEV;
- goto out;
- }
+ static ssize_t uinput_events_to_user(struct uinput_device *udev,
+ char __user *buffer, size_t count)
+ {
+ struct input_event event;
+ size_t read = 0;
- while (udev->head != udev->tail && retval + input_event_size() <= count) {
- if (input_event_to_user(buffer + retval, &udev->buff[udev->tail])) {
- retval = -EFAULT;
- goto out;
- }
- udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
- retval += input_event_size();
+ while (read + input_event_size() <= count &&
+ uinput_fetch_next_event(udev, &event)) {
+
+ if (input_event_to_user(buffer + read, &event))
+ return -EFAULT;
+
+ read += input_event_size();
}
- out:
- mutex_unlock(&udev->mutex);
+ return read;
+ }
+
+ static ssize_t uinput_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+ {
+ struct uinput_device *udev = file->private_data;
+ ssize_t retval;
+
+ if (count != 0 && count < input_event_size())
+ return -EINVAL;
+
+ do {
+ retval = mutex_lock_interruptible(&udev->mutex);
+ if (retval)
+ return retval;
+
+ if (udev->state != UIST_CREATED)
+ retval = -ENODEV;
+ else if (udev->head == udev->tail &&
+ (file->f_flags & O_NONBLOCK))
+ retval = -EAGAIN;
+ else
+ retval = uinput_events_to_user(udev, buffer, count);
+
+ mutex_unlock(&udev->mutex);
+
+ if (retval || count == 0)
+ break;
+
+ if (!(file->f_flags & O_NONBLOCK))
+ retval = wait_event_interruptible(udev->waitq,
+ udev->head != udev->tail ||
+ udev->state != UIST_CREATED);
+ } while (retval == 0);
return retval;
}
#ifdef CONFIG_COMPAT
struct uinput_ff_upload_compat {
- int request_id;
- int retval;
+ __u32 request_id;
+ __s32 retval;
struct ff_effect_compat effect;
struct ff_effect_compat old;
};
break;
req = uinput_request_find(udev, ff_up.request_id);
- if (!req || req->code != UI_FF_UPLOAD || !req->u.upload.effect) {
+ if (!req || req->code != UI_FF_UPLOAD ||
+ !req->u.upload.effect) {
retval = -EINVAL;
break;
}
}
#ifdef CONFIG_COMPAT
- static long uinput_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ static long uinput_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
{
return uinput_ioctl_handler(file, cmd, arg, compat_ptr(arg));
}
module_init(uinput_init);
module_exit(uinput_exit);
-
#define ABS_POS_BITS 13
/*
- * Any position values from the hardware above the following limits are
- * treated as "wrapped around negative" values that have been truncated to
- * the 13-bit reporting range of the hardware. These are just reasonable
- * guesses and can be adjusted if hardware is found that operates outside
- * of these parameters.
+ * These values should represent the absolute maximum value that will
+ * be reported for a positive position value. Some Synaptics firmware
+ * uses this value to indicate a finger near the edge of the touchpad
+ * whose precise position cannot be determined.
+ *
+ * At least one touchpad is known to report positions in excess of this
+ * value which are actually negative values truncated to the 13-bit
+ * reporting range. These values have never been observed to be lower
+ * than 8184 (i.e. -8), so we treat all values greater than 8176 as
+ * negative and any other value as positive.
*/
- #define X_MAX_POSITIVE (((1 << ABS_POS_BITS) + XMAX) / 2)
- #define Y_MAX_POSITIVE (((1 << ABS_POS_BITS) + YMAX) / 2)
+ #define X_MAX_POSITIVE 8176
+ #define Y_MAX_POSITIVE 8176
/*****************************************************************************
* Stuff we need even when we do not want native Synaptics support
hw->right = (buf[0] & 0x02) ? 1 : 0;
}
- /* Convert wrap-around values to negative */
+ /*
+ * Convert wrap-around values to negative. (X|Y)_MAX_POSITIVE
+ * is used by some firmware to indicate a finger at the edge of
+ * the touchpad whose precise position cannot be determined, so
+ * convert these values to the maximum axis value.
+ */
if (hw->x > X_MAX_POSITIVE)
hw->x -= 1 << ABS_POS_BITS;
+ else if (hw->x == X_MAX_POSITIVE)
+ hw->x = XMAX;
+
if (hw->y > Y_MAX_POSITIVE)
hw->y -= 1 << ABS_POS_BITS;
+ else if (hw->y == Y_MAX_POSITIVE)
+ hw->y = YMAX;
return 0;
}
input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
- input_mt_init_slots(dev, 2);
+ input_mt_init_slots(dev, 2, 0);
set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
ABS_MT_POSITION_Y);
/* Image sensors can report per-contact pressure */
} else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) {
/* Non-image sensors with AGM use semi-mt */
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
- input_mt_init_slots(dev, 2);
+ input_mt_init_slots(dev, 2, 0);
set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
ABS_MT_POSITION_Y);
}
input_report_abs(input, ABS_WHEEL, 0);
}
- if (data[2] | (data[3] & 0x01) | data[4]) {
+ if (data[2] | (data[3] & 0x01) | data[4] | data[5]) {
input_report_key(input, wacom->tool[1], 1);
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
} else {
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
- input_mt_init_slots(input_dev, features->touch_max);
+ input_mt_init_slots(input_dev, features->touch_max, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, 255, 0, 0);
case TABLETPC2FG:
if (features->device_type == BTN_TOOL_FINGER) {
- input_mt_init_slots(input_dev, features->touch_max);
+ input_mt_init_slots(input_dev, features->touch_max, 0);
input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
0, MT_TOOL_MAX, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
- input_mt_init_slots(input_dev, features->touch_max);
+ input_mt_init_slots(input_dev, features->touch_max, 0);
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
__set_bit(BTN_TOOL_TRIPLETAP,
#include <plat/adc.h>
#include <plat/regs-adc.h>
-#include <plat/ts.h>
+#include <linux/platform_data/touchscreen-s3c2410.h>
#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
return 0;
}
- static struct dev_pm_ops s3c_ts_pmops = {
+ static const struct dev_pm_ops s3c_ts_pmops = {
.suspend = s3c2410ts_suspend,
.resume = s3c2410ts_resume,
};
COMPATIBLE_IOCTL(TIOCSPTLCK)
COMPATIBLE_IOCTL(TIOCSERGETLSR)
COMPATIBLE_IOCTL(TIOCSIG)
+#ifdef TIOCSRS485
+COMPATIBLE_IOCTL(TIOCSRS485)
+#endif
+#ifdef TIOCGRS485
+COMPATIBLE_IOCTL(TIOCGRS485)
+#endif
#ifdef TCGETS2
COMPATIBLE_IOCTL(TCGETS2)
COMPATIBLE_IOCTL(TCSETS2)
COMPATIBLE_IOCTL(KDSKBSENT)
COMPATIBLE_IOCTL(KDGKBDIACR)
COMPATIBLE_IOCTL(KDSKBDIACR)
+ COMPATIBLE_IOCTL(KDGKBDIACRUC)
+ COMPATIBLE_IOCTL(KDSKBDIACRUC)
COMPATIBLE_IOCTL(KDKBDREP)
COMPATIBLE_IOCTL(KDGKBLED)
COMPATIBLE_IOCTL(KDGETLED)