static void button_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1);
+ input_sync(&button_dev);
}
static int __init button_init(void)
which upon every interrupt from the button checks its state and reports it
via the
- input_report_btn()
+ input_report_key()
call to the input system. There is no need to check whether the interrupt
routine isn't reporting two same value events (press, press for example) to
the input system, because the input_report_* functions check that
themselves.
+Then there is the
+
+ input_sync()
+
+call to tell those who receive the events that we've sent a complete report.
+This doesn't seem important in the one button case, but is quite important
+for for example mouse movement, where you don't want the X and Y values
+to be interpreted separately, because that'd result in a different movement.
+
1.2 dev->open() and dev->close()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
struct input_handle *handle = dev->handle;
-/*
- * Wake up the device if it is sleeping.
- */
if (dev->pm_dev)
pm_access(dev->pm_dev);
-/*
- * Filter non-events, and bad input values out.
- */
-
if (type > EV_MAX || !test_bit(type, dev->evbit))
return;
switch (type) {
+ case EV_SYN:
+ switch (code) {
+ case SYN_CONFIG:
+ if (dev->event) dev->event(dev, type, code, value);
+ break;
+
+ case SYN_REPORT:
+ if (dev->sync) return;
+ dev->sync = 1;
+ break;
+ }
+ break;
+
case EV_KEY:
if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value)
break;
}
-/*
- * Distribute the event to handler modules.
- */
+ if (type != EV_SYN)
+ dev->sync = 0;
while (handle) {
if (handle->open)
{
struct input_dev *dev = (void *) data;
input_event(dev, EV_KEY, dev->repeat_key, 2);
+ input_sync(dev);
mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]);
}
struct input_handle *handle;
struct input_device_id *id;
+/*
+ * Add the EV_SYN capability.
+ */
+
+ set_bit(EV_SYN, dev->evbit);
+
/*
* Initialize repeat timer to default values.
*/
input_report_key(dev, BTN_LEFT, data[3] & 2);
input_report_key(dev, BTN_MIDDLE, data[3] & 4);
+ input_sync(dev);
+
a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
input_report_key(dev, BTN_TOP, data[8] & 4);
input_report_key(dev, BTN_PINKIE, data[7] & 1);
+ input_sync(dev);
+
return;
}
}
for (i = 63; i < adi->buttons; i++)
input_report_key(dev, *key++, adi_get_bits(adi, 1));
+
+ input_sync(dev);
return 0;
}
input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1));
data = ~(data ^ (data << 1));
input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1));
+
+ input_sync(amijoy_dev + i);
}
}
input_report_abs(dev, analog_hats[j++],
((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1));
}
+
+ input_sync(dev);
}
/*
for (j = 0; cobra_btn[j]; j++)
input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j));
+ input_sync(dev);
+
}
mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
break;
}
+ input_sync(dev);
+
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
}
for (j = 0; j < 10; j++)
input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
+
+ input_sync(dev + i);
}
}
}
if (s & gc->pads[GC_SNES])
for (j = 0; j < 8; j++)
input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
+
+ input_sync(dev + i);
}
}
if (s & gc->pads[GC_MULTI2])
input_report_key(dev + i, BTN_THUMB, s & data[5]);
+
+ input_sync(dev + i);
}
}
input_report_key(dev + i, BTN_THUMBL, ~data[0] & 0x04);
input_report_key(dev + i, BTN_THUMBR, ~data[0] & 0x02);
+ input_sync(dev + i);
case GC_PSX_NEGCON:
case GC_PSX_ANALOG:
input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
+ input_sync(dev + i);
+
break;
case GC_PSX_NORMAL:
input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
+ input_sync(dev + i);
+
break;
}
}
for (i = 0; i < gf2k_pads[gf2k->id]; i++)
input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1);
+
+ input_sync(dev);
}
/*
}
+
+ input_sync(dev);
}
mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
input_report_abs(dev, ABS_X, grip->xaxes[slot]);
input_report_abs(dev, ABS_Y, grip->yaxes[slot]);
+ /* Tell the receiver of the events to process them */
+
+ input_sync(dev);
+
grip->dirty[slot] = 0;
}
input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1);
}
+ input_sync(dev);
+
mod_timer(&guillemot->timer, jiffies + GUILLEMOT_REFRESH_TIME);
}
}
}
+ input_sync(dev);
+
break;
case 0x02: /* status report */
input_report_key(dev, BTN_DEAD, data[0] & 0x02);
+ input_sync(dev);
/* Check if an effect was just started or stopped */
i = data[1] & 0x7f;
}
}
+ input_sync(dev);
+
mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
}
for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1);
break;
}
+
+ input_sync(dev);
}
static void magellan_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
input_report_key(dev, BTN_BASE4, !GB(38,1));
input_report_key(dev, BTN_BASE5, !GB(37,1));
+ input_sync(dev);
+
return 0;
case SW_ID_GP:
for (j = 0; j < 10; j++)
input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
+
+ input_sync(dev + i);
}
return 0;
for (j = 0; j < 9; j++)
input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1));
+ input_sync(dev);
+
return 0;
case SW_ID_FSP:
input_report_key(dev, BTN_MODE, GB(38,1));
input_report_key(dev, BTN_SELECT, GB(39,1));
+ input_sync(dev);
+
return 0;
case SW_ID_FFW:
for (j = 0; j < 8; j++)
input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1));
+ input_sync(dev);
+
return 0;
}
printk(KERN_ERR "spaceball: Bad command. [%s]\n", spaceball->data + 1);
break;
}
+
+ input_sync(dev);
}
/*
printk("]\n");
break;
}
+
+ input_sync(dev);
}
static void spaceorb_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6));
input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F));
+ input_sync(dev);
+
return;
}
((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1));
l += tmdc->btnc[j][k];
}
+
+ input_sync(dev);
}
tmdc->bads += bad;
input_report_key(dev, BTN_THUMB2, (data2 & TGFX_THUMB2 ));
input_report_key(dev, BTN_TOP, (data2 & TGFX_TOP ));
input_report_key(dev, BTN_TOP2, (data2 & TGFX_TOP2 ));
+
+ input_sync(dev);
}
mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
input_report_abs(dev, ABS_X, -abs_x);
input_report_abs(dev, ABS_Y, +abs_y);
+
+ input_sync(dev);
}
return;
input_report_key(dev, BTN_THUMB, (data[3] >> 1) & 1);
input_report_key(dev, BTN_TOP, (data[3] >> 2) & 1);
input_report_key(dev, BTN_TOP2, (data[3] >> 3) & 1);
- return;
+ break;
case 3: /* XY-axis info->data */
input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5)));
input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
- return;
+ break;
case 5: /* Throttle, spinner, hat info->data */
input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0));
input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0));
input_report_rel(dev, REL_DIAL, (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5));
- return;
+ break;
}
+ input_sync(dev);
}
/*
struct input_handle *handle;
for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
-
input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01));
input_event(handle->dev, EV_LED, LED_NUML, !!(led & 0x02));
input_event(handle->dev, EV_LED, LED_CAPSL, !!(led & 0x04));
-
+ input_sync(handle->dev);
}
}
if (scancode == KEY_CAPS) { /* CapsLock is a toggle switch key on Amiga */
input_report_key(&amikbd_dev, scancode, 1);
input_report_key(&amikbd_dev, scancode, 0);
+ input_sync(&amikbd_dev);
return;
}
input_report_key(&amikbd_dev, scancode, down);
+ input_sync(&amikbd_dev);
return;
}
break;
default:
input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release);
+ input_sync(&atkbd->dev);
}
atkbd->release = 0;
}
}
+ input_sync(dev);
+
memcpy(kbd->old, kbd->new, 8);
}
else if (data == 0xe7) /* end of init sequence */
printk(KERN_INFO "input: %s on %s\n", nkbd_name, serio->phys);
+
+ input_sync(&nkbd->dev);
}
void nkbd_connect(struct serio *serio, struct serio_dev *dev)
break;
default:
input_report_key(&ps2serkbd->dev, ps2serkbd->keycode[code], !ps2serkbd->release);
+ input_sync(&ps2serkbd->dev);
}
ps2serkbd->release = 0;
default:
if (sunkbd->keycode[data & SUNKBD_KEY]) {
input_report_key(&sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE));
+ input_sync(&sunkbd->dev);
} else {
printk(KERN_WARNING "sunkbd.c: Unknown key (scancode %#x) %s.\n",
data & SUNKBD_KEY, data & SUNKBD_RELEASE ? "released" : "pressed");
if (xtkbd->keycode[data & XTKBD_KEY]) {
input_report_key(&xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE));
+ input_sync(&xtkbd->dev);
} else {
printk(KERN_WARNING "xtkbd.c: Unknown key (scancode %#x) %s.\n",
data & XTKBD_KEY, data & XTKBD_RELEASE ? "released" : "pressed");
input_report_key(&amimouse_dev, BTN_LEFT, ciaa.pra & 0x40);
input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
input_report_key(&amimouse_dev, BTN_RIGHT, potgor & 0x0400);
+
+ input_sync(&amimouse_dev);
}
static int amimouse_open(struct input_dev *dev)
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
+
+ input_sync(&inport_dev);
}
#ifndef MODULE
input_report_key(&logibm_dev, BTN_RIGHT, buttons & 1);
input_report_key(&logibm_dev, BTN_MIDDLE, buttons & 2);
input_report_key(&logibm_dev, BTN_LEFT, buttons & 4);
+ input_sync(&logibm_dev);
+
outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
}
input_report_rel(dev, REL_X, relx);
input_report_rel(dev, REL_Y, rely);
input_report_rel(dev, REL_WHEEL, relz);
+ input_sync(dev);
}
pc110pad_data[1] | ((pc110pad_data[0] << 3) & 0x80) | ((pc110pad_data[0] << 1) & 0x100));
input_report_abs(&pc110pad_dev, ABS_Y,
pc110pad_data[2] | ((pc110pad_data[0] << 4) & 0x80));
+ input_sync(&pc110pad_dev);
pc110pad_count = 0;
}
static int pc110pad_open(struct input_dev *dev)
{
- unsigned long flags;
-
if (pc110pad_used++)
return 0;
input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0);
input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0);
+ input_sync(dev);
}
/*
input_report_key(&rpcmouse_dev, BTN_LEFT, b & 0x10);
input_report_key(&rpcmouse_dev, BTN_MIDDLE, b & 0x20);
input_report_key(&rpcmouse_dev, BTN_RIGHT, b & 0x40);
+
+ input_sync(&rpcmouse_dev);
}
static int __init rpcmouse_init(void)
break;
}
+ input_sync(dev);
+
if (++sermouse->count == (5 - ((sermouse->type == SERIO_SUN) << 1)))
sermouse->count = 0;
}
break;
}
+ input_sync(dev);
+
sermouse->count++;
}
struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
struct mousedev **mousedev = mousedevs;
struct mousedev_list *list;
- int index, size;
+ int index, size, wake;
while (*mousedev) {
+ wake = 0;
list = (*mousedev)->list;
while (list) {
switch (type) {
case 2: return;
}
break;
- }
-
- list->ready = 1;
-
- kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ case EV_SYN:
+ switch (code) {
+ case SYN_REPORT:
+ list->ready = 1;
+ kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ wake = 1;
+ break;
+ }
+ }
list = list->next;
}
-
- wake_up_interruptible(&((*mousedev)->wait));
+ if (wake)
+ wake_up_interruptible(&((*mousedev)->wait));
mousedev++;
}
}
input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10) * 4);
input_report_abs(dev, ABS_Y, 3072 - simple_strtoul(gunze->data + 6, NULL, 10) * 3);
input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
+ input_sync(dev);
}
static void gunze_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
struct input_dev *dev = (struct input_dev *) dev_id;
input_report_key(dev, KEY_ENTER, down);
+ input_sync(dev);
}
static void npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
*/
input_report_key(dev, KEY_SUSPEND, 1);
input_report_key(dev, KEY_SUSPEND, down);
+ input_sync(dev);
}
#ifdef CONFIG_PM
/* Send a non input event elsewhere */
break;
}
+
+ input_sync(dev);
}
/*
else
printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode,
up_flag ? "released" : "pressed");
+
+ input_sync(&adbhid[id]->input);
}
static void
((data[2]&0x7f) < 64 ? (data[2]&0x7f) : (data[2]&0x7f)-128 ));
input_report_rel(&adbhid[id]->input, REL_Y,
((data[1]&0x7f) < 64 ? (data[1]&0x7f) : (data[1]&0x7f)-128 ));
+
+ input_sync(&adbhid[id]->input);
}
static void
}
break;
}
+
+ input_sync(&adbhid[id]->input);
}
static struct adb_request led_request;
input_report_key(&emumousebtn,
keycode == mouse_button2_keycode ? BTN_MIDDLE : BTN_RIGHT,
down);
+ input_sync(&emumousebtn);
return 1;
}
mouse_last_keycode = down ? keycode : 0;
input_report_key(dev, BTN_STYLUS2, data[5] & 0x10);
}
+ input_sync(dev);
+
}
struct aiptek_features aiptek_features[] = {
for (n = 0; n < report->maxfield; n++)
hid_input_field(hid, report->field[n], data);
+ if (hid->claimed & HID_CLAIMED_INPUT)
+ hidinput_report_event(hid, report);
+
return 0;
}
input_event(input, usage->type, usage->code, 0);
}
+void hidinput_report_event(struct hid_device *hid, struct hid_report *report)
+{
+ input_sync(&hid->input);
+}
+
static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct hid_device *hid = dev->private;
/* We ignore a few input applications that are not widely used */
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001))
extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
+extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
extern int hidinput_connect(struct hid_device *);
extern void hidinput_disconnect(struct hid_device *);
#else
#define IS_INPUT_APPLICATION(a) (0)
static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { }
+static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { }
static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; }
static inline void hidinput_disconnect(struct hid_device *hid) { }
#endif
/* handle updates to device state */
input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01);
input_report_rel(&pm->input, REL_DIAL, pm->data[1]);
+ input_sync(&pm->input);
}
/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */
}
}
+ input_sync(&kbd->dev);
+
memcpy(kbd->old, kbd->new, 8);
}
kbd->dev.name = kbd->name;
kbd->dev.phys = kbd->phys;
- kbd->dev.id.bus = BUS_USB;
+ kbd->dev.id.bustype = BUS_USB;
kbd->dev.id.vendor = dev->descriptor.idVendor;
kbd->dev.id.product = dev->descriptor.idProduct;
kbd->dev.id.version = dev->descriptor.bcdDevice;
input_report_rel(dev, REL_X, data[1]);
input_report_rel(dev, REL_Y, data[2]);
input_report_rel(dev, REL_WHEEL, data[3]);
+
+ input_sync(dev);
}
static int usb_mouse_open(struct input_dev *dev)
mouse->dev.name = mouse->name;
mouse->dev.phys = mouse->phys;
- mouse->dev.id.bus = BUS_USB;
+ mouse->dev.id.bustype = BUS_USB;
mouse->dev.id.vendor = dev->descriptor.idVendor;
mouse->dev.id.product = dev->descriptor.idProduct;
mouse->dev.id.version = dev->descriptor.bcdDevice;
}
input_event(dev, EV_MSC, MSC_SERIAL, 0);
+ input_sync(dev);
}
static void wacom_graphire_irq(struct urb *urb)
input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
input_event(dev, EV_MSC, MSC_SERIAL, data[1] & 0x01);
+
+ input_sync(dev);
}
static void wacom_intuos_irq(struct urb *urb)
}
input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+
+ input_sync(dev);
}
#define WACOM_INTUOS_TOOLS (BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS))
/* "analog" buttons black, white */
input_report_key(dev, BTN_C, data[8]);
input_report_key(dev, BTN_Z, data[9]);
+
+ input_sync(dev);
}
static void xpad_irq_in(struct urb *urb)
*/
struct input_devinfo {
- uint16_t bustype;
- uint16_t vendor;
- uint16_t product;
- uint16_t version;
+ __u16 bustype;
+ __u16 vendor;
+ __u16 product;
+ __u16 version;
};
#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
* Event types
*/
-#define EV_RST 0x00
+#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
+/*
+ * Synchronization events.
+ */
+
+#define SYN_REPORT 0
+#define SYN_CONFIG 1
+
/*
* Keys and buttons
*/
struct pm_dev *pm_dev;
int state;
+ int sync;
+
int abs[ABS_MAX + 1];
int rep[REP_MAX + 1];
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+#define input_sync(a) input_event(a, EV_SYN, SYN_REPORT, 0)
#define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c))
#define input_report_rel(a,b,c) input_event(a, EV_REL, b, c)
#define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c)