Merge branch 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/dtor/input

* 'for-linus' of master.kernel.org:/pub/scm/linux/kernel/git/dtor/input: (24 commits)
  Input: ati_remote - use msec instead of jiffies
  Input: ati_remote - add missing input_sync()
  Input: ati_remote - relax permissions sysfs module parameters
  Input: ati_remote - make filter time a module parameter
  Input: atkbd - restore repeat rate when resuming
  Input: trackpoint - activate protocol when resuming
  Input: logips2pp - fix button mapping for MX300
  Input: keyboard - change to use kzalloc
  Input: serio/gameport - check whether driver core calls succeeded
  Input: spaceball - make 4000FLX Lefty work
  Input: keyboard - simplify emulate_raw() implementation
  Input: keyboard - remove static variable and clean up initialization
  Input: hiddev - use standard list implementation
  Input: add missing handler->start() call
  Input: HID - fix potential out-of-bound array access
  Input: fix list iteration in input_release_device()
  Input: iforce - add Trust Force Feedback Race Master support
  Input: iforce - check array bounds before accessing elements
  Input: libps2 - warn instead of oopsing when passed bad arguments
  Input: fm801-gp - fix use after free
  ...
This commit is contained in:
Linus Torvalds 2006-08-06 09:12:49 -07:00
commit 6e1e63259b
17 changed files with 508 additions and 307 deletions

View File

@ -107,7 +107,6 @@ const int NR_TYPES = ARRAY_SIZE(max_vals);
struct kbd_struct kbd_table[MAX_NR_CONSOLES]; struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct kbd_struct *kbd = kbd_table; static struct kbd_struct *kbd = kbd_table;
static struct kbd_struct kbd0;
int spawnpid, spawnsig; int spawnpid, spawnsig;
@ -223,13 +222,13 @@ static void kd_nosound(unsigned long ignored)
{ {
struct list_head *node; struct list_head *node;
list_for_each(node,&kbd_handler.h_list) { list_for_each(node, &kbd_handler.h_list) {
struct input_handle *handle = to_handle_h(node); struct input_handle *handle = to_handle_h(node);
if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(EV_SND, handle->dev->evbit)) {
if (test_bit(SND_TONE, handle->dev->sndbit)) if (test_bit(SND_TONE, handle->dev->sndbit))
input_event(handle->dev, EV_SND, SND_TONE, 0); input_inject_event(handle, EV_SND, SND_TONE, 0);
if (test_bit(SND_BELL, handle->dev->sndbit)) if (test_bit(SND_BELL, handle->dev->sndbit))
input_event(handle->dev, EV_SND, SND_BELL, 0); input_inject_event(handle, EV_SND, SND_BELL, 0);
} }
} }
} }
@ -247,11 +246,11 @@ void kd_mksound(unsigned int hz, unsigned int ticks)
struct input_handle *handle = to_handle_h(node); struct input_handle *handle = to_handle_h(node);
if (test_bit(EV_SND, handle->dev->evbit)) { if (test_bit(EV_SND, handle->dev->evbit)) {
if (test_bit(SND_TONE, handle->dev->sndbit)) { if (test_bit(SND_TONE, handle->dev->sndbit)) {
input_event(handle->dev, EV_SND, SND_TONE, hz); input_inject_event(handle, EV_SND, SND_TONE, hz);
break; break;
} }
if (test_bit(SND_BELL, handle->dev->sndbit)) { if (test_bit(SND_BELL, handle->dev->sndbit)) {
input_event(handle->dev, EV_SND, SND_BELL, 1); input_inject_event(handle, EV_SND, SND_BELL, 1);
break; break;
} }
} }
@ -272,15 +271,15 @@ int kbd_rate(struct kbd_repeat *rep)
unsigned int d = 0; unsigned int d = 0;
unsigned int p = 0; unsigned int p = 0;
list_for_each(node,&kbd_handler.h_list) { list_for_each(node, &kbd_handler.h_list) {
struct input_handle *handle = to_handle_h(node); struct input_handle *handle = to_handle_h(node);
struct input_dev *dev = handle->dev; struct input_dev *dev = handle->dev;
if (test_bit(EV_REP, dev->evbit)) { if (test_bit(EV_REP, dev->evbit)) {
if (rep->delay > 0) if (rep->delay > 0)
input_event(dev, EV_REP, REP_DELAY, rep->delay); input_inject_event(handle, EV_REP, REP_DELAY, rep->delay);
if (rep->period > 0) if (rep->period > 0)
input_event(dev, EV_REP, REP_PERIOD, rep->period); input_inject_event(handle, EV_REP, REP_PERIOD, rep->period);
d = dev->rep[REP_DELAY]; d = dev->rep[REP_DELAY];
p = dev->rep[REP_PERIOD]; p = dev->rep[REP_PERIOD];
} }
@ -988,7 +987,7 @@ static inline unsigned char getleds(void)
* interrupt routines for this thing allows us to easily mask * interrupt routines for this thing allows us to easily mask
* this when we don't want any of the above to happen. * this when we don't want any of the above to happen.
* This allows for easy and efficient race-condition prevention * This allows for easy and efficient race-condition prevention
* for kbd_refresh_leds => input_event(dev, EV_LED, ...) => ... * for kbd_start => input_inject_event(dev, EV_LED, ...) => ...
*/ */
static void kbd_bh(unsigned long dummy) static void kbd_bh(unsigned long dummy)
@ -998,11 +997,11 @@ static void kbd_bh(unsigned long dummy)
if (leds != ledstate) { if (leds != ledstate) {
list_for_each(node, &kbd_handler.h_list) { list_for_each(node, &kbd_handler.h_list) {
struct input_handle * handle = to_handle_h(node); struct input_handle *handle = to_handle_h(node);
input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01)); input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02)); input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04)); input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
input_sync(handle->dev); input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
} }
} }
@ -1011,23 +1010,6 @@ static void kbd_bh(unsigned long dummy)
DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0); DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
/*
* This allows a newly plugged keyboard to pick the LED state.
*/
static void kbd_refresh_leds(struct input_handle *handle)
{
unsigned char leds = ledstate;
tasklet_disable(&keyboard_tasklet);
if (leds != 0xff) {
input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01));
input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02));
input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04));
input_sync(handle->dev);
}
tasklet_enable(&keyboard_tasklet);
}
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\ #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\ defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\ defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
@ -1043,7 +1025,7 @@ static const unsigned short x86_keycodes[256] =
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92, 80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,
284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339, 284,285,309, 0,312, 91,327,328,329,331,333,335,336,337,338,339,
367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349, 367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355, 360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
103,104,105,275,287,279,306,106,274,107,294,364,358,363,362,361, 103,104,105,275,287,279,306,106,274,107,294,364,358,363,362,361,
@ -1065,38 +1047,55 @@ extern void sun_do_break(void);
static int emulate_raw(struct vc_data *vc, unsigned int keycode, static int emulate_raw(struct vc_data *vc, unsigned int keycode,
unsigned char up_flag) unsigned char up_flag)
{ {
if (keycode > 255 || !x86_keycodes[keycode]) int code;
return -1;
switch (keycode) { switch (keycode) {
case KEY_PAUSE: case KEY_PAUSE:
put_queue(vc, 0xe1); put_queue(vc, 0xe1);
put_queue(vc, 0x1d | up_flag); put_queue(vc, 0x1d | up_flag);
put_queue(vc, 0x45 | up_flag); put_queue(vc, 0x45 | up_flag);
return 0; break;
case KEY_HANGEUL: case KEY_HANGEUL:
if (!up_flag) if (!up_flag)
put_queue(vc, 0xf2); put_queue(vc, 0xf2);
return 0; break;
case KEY_HANJA: case KEY_HANJA:
if (!up_flag) if (!up_flag)
put_queue(vc, 0xf1); put_queue(vc, 0xf1);
return 0; break;
}
if (keycode == KEY_SYSRQ && sysrq_alt) { case KEY_SYSRQ:
put_queue(vc, 0x54 | up_flag); /*
return 0; * Real AT keyboards (that's what we're trying
} * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
* pressing PrtSc/SysRq alone, but simply 0x54
* when pressing Alt+PrtSc/SysRq.
*/
if (sysrq_alt) {
put_queue(vc, 0x54 | up_flag);
} else {
put_queue(vc, 0xe0);
put_queue(vc, 0x2a | up_flag);
put_queue(vc, 0xe0);
put_queue(vc, 0x37 | up_flag);
}
break;
if (x86_keycodes[keycode] & 0x100) default:
put_queue(vc, 0xe0); if (keycode > 255)
return -1;
put_queue(vc, (x86_keycodes[keycode] & 0x7f) | up_flag); code = x86_keycodes[keycode];
if (!code)
return -1;
if (keycode == KEY_SYSRQ) { if (code & 0x100)
put_queue(vc, 0xe0); put_queue(vc, 0xe0);
put_queue(vc, 0x37 | up_flag); put_queue(vc, (code & 0x7f) | up_flag);
break;
} }
return 0; return 0;
@ -1298,16 +1297,15 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit)) if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
return NULL; return NULL;
if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
return NULL; return NULL;
memset(handle, 0, sizeof(struct input_handle));
handle->dev = dev; handle->dev = dev;
handle->handler = handler; handle->handler = handler;
handle->name = "kbd"; handle->name = "kbd";
input_open_device(handle); input_open_device(handle);
kbd_refresh_leds(handle);
return handle; return handle;
} }
@ -1318,6 +1316,24 @@ static void kbd_disconnect(struct input_handle *handle)
kfree(handle); kfree(handle);
} }
/*
* Start keyboard handler on the new keyboard by refreshing LED state to
* match the rest of the system.
*/
static void kbd_start(struct input_handle *handle)
{
unsigned char leds = ledstate;
tasklet_disable(&keyboard_tasklet);
if (leds != 0xff) {
input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
}
tasklet_enable(&keyboard_tasklet);
}
static struct input_device_id kbd_ids[] = { static struct input_device_id kbd_ids[] = {
{ {
.flags = INPUT_DEVICE_ID_MATCH_EVBIT, .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
@ -1338,6 +1354,7 @@ static struct input_handler kbd_handler = {
.event = kbd_event, .event = kbd_event,
.connect = kbd_connect, .connect = kbd_connect,
.disconnect = kbd_disconnect, .disconnect = kbd_disconnect,
.start = kbd_start,
.name = "kbd", .name = "kbd",
.id_table = kbd_ids, .id_table = kbd_ids,
}; };
@ -1346,15 +1363,15 @@ int __init kbd_init(void)
{ {
int i; int i;
kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; for (i = 0; i < MAX_NR_CONSOLES; i++) {
kbd0.ledmode = LED_SHOW_FLAGS; kbd_table[i].ledflagstate = KBD_DEFLEDS;
kbd0.lockstate = KBD_DEFLOCK; kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
kbd0.slockstate = 0; kbd_table[i].ledmode = LED_SHOW_FLAGS;
kbd0.modeflags = KBD_DEFMODE; kbd_table[i].lockstate = KBD_DEFLOCK;
kbd0.kbdmode = VC_XLATE; kbd_table[i].slockstate = 0;
kbd_table[i].modeflags = KBD_DEFMODE;
for (i = 0 ; i < MAX_NR_CONSOLES ; i++) kbd_table[i].kbdmode = VC_XLATE;
kbd_table[i] = kbd0; }
input_register_handler(&kbd_handler); input_register_handler(&kbd_handler);

View File

@ -127,14 +127,10 @@ static int evdev_open(struct inode * inode, struct file * file)
{ {
struct evdev_list *list; struct evdev_list *list;
int i = iminor(inode) - EVDEV_MINOR_BASE; int i = iminor(inode) - EVDEV_MINOR_BASE;
int accept_err;
if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist) if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
return -ENODEV; return -ENODEV;
if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file)))
return accept_err;
if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL))) if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
@ -260,7 +256,7 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
if (evdev_event_from_user(buffer + retval, &event)) if (evdev_event_from_user(buffer + retval, &event))
return -EFAULT; return -EFAULT;
input_event(list->evdev->handle.dev, event.type, event.code, event.value); input_inject_event(&list->evdev->handle, event.type, event.code, event.value);
retval += evdev_event_size(); retval += evdev_event_size();
} }
@ -428,8 +424,8 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
if (get_user(v, ip + 1)) if (get_user(v, ip + 1))
return -EFAULT; return -EFAULT;
input_event(dev, EV_REP, REP_DELAY, u); input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
input_event(dev, EV_REP, REP_PERIOD, v); input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
return 0; return 0;

View File

@ -106,10 +106,10 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device
gp->gameport = port; gp->gameport = port;
gp->res_port = request_region(port->io, 0x10, "FM801 GP"); gp->res_port = request_region(port->io, 0x10, "FM801 GP");
if (!gp->res_port) { if (!gp->res_port) {
kfree(gp);
gameport_free_port(port);
printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n", printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n",
port->io, port->io + 0x0f); port->io, port->io + 0x0f);
gameport_free_port(port);
kfree(gp);
return -EBUSY; return -EBUSY;
} }

View File

@ -53,6 +53,7 @@ static LIST_HEAD(gameport_list);
static struct bus_type gameport_bus; static struct bus_type gameport_bus;
static void gameport_add_driver(struct gameport_driver *drv);
static void gameport_add_port(struct gameport *gameport); static void gameport_add_port(struct gameport *gameport);
static void gameport_destroy_port(struct gameport *gameport); static void gameport_destroy_port(struct gameport *gameport);
static void gameport_reconnect_port(struct gameport *gameport); static void gameport_reconnect_port(struct gameport *gameport);
@ -211,8 +212,14 @@ static void gameport_release_driver(struct gameport *gameport)
static void gameport_find_driver(struct gameport *gameport) static void gameport_find_driver(struct gameport *gameport)
{ {
int error;
down_write(&gameport_bus.subsys.rwsem); down_write(&gameport_bus.subsys.rwsem);
device_attach(&gameport->dev); error = device_attach(&gameport->dev);
if (error < 0)
printk(KERN_WARNING
"gameport: device_attach() failed for %s (%s), error: %d\n",
gameport->phys, gameport->name, error);
up_write(&gameport_bus.subsys.rwsem); up_write(&gameport_bus.subsys.rwsem);
} }
@ -316,7 +323,6 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
spin_unlock_irqrestore(&gameport_event_lock, flags); spin_unlock_irqrestore(&gameport_event_lock, flags);
} }
static struct gameport_event *gameport_get_event(void) static struct gameport_event *gameport_get_event(void)
{ {
struct gameport_event *event; struct gameport_event *event;
@ -342,7 +348,6 @@ static struct gameport_event *gameport_get_event(void)
static void gameport_handle_event(void) static void gameport_handle_event(void)
{ {
struct gameport_event *event; struct gameport_event *event;
struct gameport_driver *gameport_drv;
mutex_lock(&gameport_mutex); mutex_lock(&gameport_mutex);
@ -369,8 +374,7 @@ static void gameport_handle_event(void)
break; break;
case GAMEPORT_REGISTER_DRIVER: case GAMEPORT_REGISTER_DRIVER:
gameport_drv = event->object; gameport_add_driver(event->object);
driver_register(&gameport_drv->driver);
break; break;
default: default:
@ -532,6 +536,7 @@ static void gameport_init_port(struct gameport *gameport)
if (gameport->parent) if (gameport->parent)
gameport->dev.parent = &gameport->parent->dev; gameport->dev.parent = &gameport->parent->dev;
INIT_LIST_HEAD(&gameport->node);
spin_lock_init(&gameport->timer_lock); spin_lock_init(&gameport->timer_lock);
init_timer(&gameport->poll_timer); init_timer(&gameport->poll_timer);
gameport->poll_timer.function = gameport_run_poll_handler; gameport->poll_timer.function = gameport_run_poll_handler;
@ -544,6 +549,8 @@ static void gameport_init_port(struct gameport *gameport)
*/ */
static void gameport_add_port(struct gameport *gameport) static void gameport_add_port(struct gameport *gameport)
{ {
int error;
if (gameport->parent) if (gameport->parent)
gameport->parent->child = gameport; gameport->parent->child = gameport;
@ -558,8 +565,13 @@ static void gameport_add_port(struct gameport *gameport)
printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n", printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n",
gameport->name, gameport->phys, gameport->speed); gameport->name, gameport->phys, gameport->speed);
device_add(&gameport->dev); error = device_add(&gameport->dev);
gameport->registered = 1; if (error)
printk(KERN_ERR
"gameport: device_add() failed for %s (%s), error: %d\n",
gameport->phys, gameport->name, error);
else
gameport->registered = 1;
} }
/* /*
@ -583,10 +595,11 @@ static void gameport_destroy_port(struct gameport *gameport)
if (gameport->registered) { if (gameport->registered) {
device_del(&gameport->dev); device_del(&gameport->dev);
list_del_init(&gameport->node);
gameport->registered = 0; gameport->registered = 0;
} }
list_del_init(&gameport->node);
gameport_remove_pending_events(gameport); gameport_remove_pending_events(gameport);
put_device(&gameport->dev); put_device(&gameport->dev);
} }
@ -704,11 +717,22 @@ static int gameport_driver_remove(struct device *dev)
} }
static struct bus_type gameport_bus = { static struct bus_type gameport_bus = {
.name = "gameport", .name = "gameport",
.probe = gameport_driver_probe, .probe = gameport_driver_probe,
.remove = gameport_driver_remove, .remove = gameport_driver_remove,
}; };
static void gameport_add_driver(struct gameport_driver *drv)
{
int error;
error = driver_register(&drv->driver);
if (error)
printk(KERN_ERR
"gameport: driver_register() failed for %s, error: %d\n",
drv->driver.name, error);
}
void __gameport_register_driver(struct gameport_driver *drv, struct module *owner) void __gameport_register_driver(struct gameport_driver *drv, struct module *owner)
{ {
drv->driver.bus = &gameport_bus; drv->driver.bus = &gameport_bus;
@ -778,16 +802,24 @@ void gameport_close(struct gameport *gameport)
static int __init gameport_init(void) static int __init gameport_init(void)
{ {
gameport_task = kthread_run(gameport_thread, NULL, "kgameportd"); int error;
if (IS_ERR(gameport_task)) {
printk(KERN_ERR "gameport: Failed to start kgameportd\n");
return PTR_ERR(gameport_task);
}
gameport_bus.dev_attrs = gameport_device_attrs; gameport_bus.dev_attrs = gameport_device_attrs;
gameport_bus.drv_attrs = gameport_driver_attrs; gameport_bus.drv_attrs = gameport_driver_attrs;
gameport_bus.match = gameport_bus_match; gameport_bus.match = gameport_bus_match;
bus_register(&gameport_bus); error = bus_register(&gameport_bus);
if (error) {
printk(KERN_ERR "gameport: failed to register gameport bus, error: %d\n", error);
return error;
}
gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
if (IS_ERR(gameport_task)) {
bus_unregister(&gameport_bus);
error = PTR_ERR(gameport_task);
printk(KERN_ERR "gameport: Failed to start kgameportd, error: %d\n", error);
return error;
}
return 0; return 0;
} }

View File

@ -35,6 +35,16 @@ static LIST_HEAD(input_handler_list);
static struct input_handler *input_table[8]; static struct input_handler *input_table[8];
/**
* input_event() - report new input event
* @handle: device that generated the event
* @type: type of the event
* @code: event code
* @value: value of the event
*
* This function should be used by drivers implementing various input devices
* See also input_inject_event()
*/
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{ {
struct input_handle *handle; struct input_handle *handle;
@ -183,6 +193,23 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
} }
EXPORT_SYMBOL(input_event); EXPORT_SYMBOL(input_event);
/**
* input_inject_event() - send input event from input handler
* @handle: input handle to send event through
* @type: type of the event
* @code: event code
* @value: value of the event
*
* Similar to input_event() but will ignore event if device is "grabbed" and handle
* injecting event is not the one that owns the device.
*/
void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
if (!handle->dev->grab || handle->dev->grab == handle)
input_event(handle->dev, type, code, value);
}
EXPORT_SYMBOL(input_inject_event);
static void input_repeat_key(unsigned long data) static void input_repeat_key(unsigned long data)
{ {
struct input_dev *dev = (void *) data; struct input_dev *dev = (void *) data;
@ -197,15 +224,6 @@ static void input_repeat_key(unsigned long data)
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD])); mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD]));
} }
int input_accept_process(struct input_handle *handle, struct file *file)
{
if (handle->dev->accept)
return handle->dev->accept(handle->dev, file);
return 0;
}
EXPORT_SYMBOL(input_accept_process);
int input_grab_device(struct input_handle *handle) int input_grab_device(struct input_handle *handle)
{ {
if (handle->dev->grab) if (handle->dev->grab)
@ -218,8 +236,15 @@ EXPORT_SYMBOL(input_grab_device);
void input_release_device(struct input_handle *handle) void input_release_device(struct input_handle *handle)
{ {
if (handle->dev->grab == handle) struct input_dev *dev = handle->dev;
handle->dev->grab = NULL;
if (dev->grab == handle) {
dev->grab = NULL;
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->handler->start)
handle->handler->start(handle);
}
} }
EXPORT_SYMBOL(input_release_device); EXPORT_SYMBOL(input_release_device);
@ -963,8 +988,11 @@ int input_register_device(struct input_dev *dev)
list_for_each_entry(handler, &input_handler_list, node) list_for_each_entry(handler, &input_handler_list, node)
if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
if ((id = input_match_device(handler->id_table, dev))) if ((id = input_match_device(handler->id_table, dev)))
if ((handle = handler->connect(handler, dev, id))) if ((handle = handler->connect(handler, dev, id))) {
input_link_handle(handle); input_link_handle(handle);
if (handler->start)
handler->start(handle);
}
input_wakeup_procfs_readers(); input_wakeup_procfs_readers();
@ -1028,8 +1056,11 @@ void input_register_handler(struct input_handler *handler)
list_for_each_entry(dev, &input_dev_list, node) list_for_each_entry(dev, &input_dev_list, node)
if (!handler->blacklist || !input_match_device(handler->blacklist, dev)) if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
if ((id = input_match_device(handler->id_table, dev))) if ((id = input_match_device(handler->id_table, dev)))
if ((handle = handler->connect(handler, dev, id))) if ((handle = handler->connect(handler, dev, id))) {
input_link_handle(handle); input_link_handle(handle);
if (handler->start)
handler->start(handle);
}
input_wakeup_procfs_readers(); input_wakeup_procfs_readers();
} }

View File

@ -79,6 +79,7 @@ static struct iforce_device iforce_device[] = {
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //? { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0004, "Gullemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //? { 0x06f8, 0x0004, "Gullemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //?
{ 0x06d6, 0x29bc, "Trust Force Feedback Race Master", btn_wheel, abs_wheel, ff_iforce },
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
}; };
@ -222,22 +223,22 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id)
int err = 0; int err = 0;
struct iforce_core_effect* core_effect; struct iforce_core_effect* core_effect;
/* Check who is trying to erase this effect */
if (iforce->core_effects[effect_id].owner != current->pid) {
printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, iforce->core_effects[effect_id].owner);
return -EACCES;
}
if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX)
return -EINVAL; return -EINVAL;
core_effect = iforce->core_effects + effect_id; core_effect = &iforce->core_effects[effect_id];
/* Check who is trying to erase this effect */
if (core_effect->owner != current->pid) {
printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, core_effect->owner);
return -EACCES;
}
if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); err = release_resource(&core_effect->mod1_chunk);
if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); err = release_resource(&core_effect->mod2_chunk);
/*TODO: remember to change that if more FF_MOD* bits are added */ /*TODO: remember to change that if more FF_MOD* bits are added */
core_effect->flags[0] = 0; core_effect->flags[0] = 0;

View File

@ -50,7 +50,7 @@ MODULE_LICENSE("GPL");
*/ */
#define SPACEBALL_MAX_LENGTH 128 #define SPACEBALL_MAX_LENGTH 128
#define SPACEBALL_MAX_ID 8 #define SPACEBALL_MAX_ID 9
#define SPACEBALL_1003 1 #define SPACEBALL_1003 1
#define SPACEBALL_2003B 3 #define SPACEBALL_2003B 3

View File

@ -482,6 +482,55 @@ out:
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int atkbd_set_repeat_rate(struct atkbd *atkbd)
{
const short period[32] =
{ 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125,
133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
const short delay[4] =
{ 250, 500, 750, 1000 };
struct input_dev *dev = atkbd->dev;
unsigned char param;
int i = 0, j = 0;
while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])
i++;
dev->rep[REP_PERIOD] = period[i];
while (j < ARRAY_SIZE(period) - 1 && delay[j] < dev->rep[REP_DELAY])
j++;
dev->rep[REP_DELAY] = delay[j];
param = i | (j << 5);
return ps2_command(&atkbd->ps2dev, &param, ATKBD_CMD_SETREP);
}
static int atkbd_set_leds(struct atkbd *atkbd)
{
struct input_dev *dev = atkbd->dev;
unsigned char param[2];
param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
| (test_bit(LED_NUML, dev->led) ? 2 : 0)
| (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
return -1;
if (atkbd->extra) {
param[0] = 0;
param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
| (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
| (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
| (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
| (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS))
return -1;
}
return 0;
}
/* /*
* atkbd_event_work() is used to complete processing of events that * atkbd_event_work() is used to complete processing of events that
* can not be processed by input_event() which is often called from * can not be processed by input_event() which is often called from
@ -490,47 +539,15 @@ out:
static void atkbd_event_work(void *data) static void atkbd_event_work(void *data)
{ {
const short period[32] =
{ 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125,
133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
const short delay[4] =
{ 250, 500, 750, 1000 };
struct atkbd *atkbd = data; struct atkbd *atkbd = data;
struct input_dev *dev = atkbd->dev;
unsigned char param[2];
int i, j;
mutex_lock(&atkbd->event_mutex); mutex_lock(&atkbd->event_mutex);
if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) { if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) atkbd_set_leds(atkbd);
| (test_bit(LED_NUML, dev->led) ? 2 : 0)
| (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS);
if (atkbd->extra) { if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
param[0] = 0; atkbd_set_repeat_rate(atkbd);
param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
| (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
| (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
| (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
| (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
}
}
if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) {
i = j = 0;
while (i < 31 && period[i] < dev->rep[REP_PERIOD])
i++;
while (j < 3 && delay[j] < dev->rep[REP_DELAY])
j++;
dev->rep[REP_PERIOD] = period[i];
dev->rep[REP_DELAY] = delay[j];
param[0] = i | (j << 5);
ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP);
}
mutex_unlock(&atkbd->event_mutex); mutex_unlock(&atkbd->event_mutex);
} }
@ -975,7 +992,6 @@ static int atkbd_reconnect(struct serio *serio)
{ {
struct atkbd *atkbd = serio_get_drvdata(serio); struct atkbd *atkbd = serio_get_drvdata(serio);
struct serio_driver *drv = serio->drv; struct serio_driver *drv = serio->drv;
unsigned char param[1];
if (!atkbd || !drv) { if (!atkbd || !drv) {
printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
@ -985,10 +1001,6 @@ static int atkbd_reconnect(struct serio *serio)
atkbd_disable(atkbd); atkbd_disable(atkbd);
if (atkbd->write) { if (atkbd->write) {
param[0] = (test_bit(LED_SCROLLL, atkbd->dev->led) ? 1 : 0)
| (test_bit(LED_NUML, atkbd->dev->led) ? 2 : 0)
| (test_bit(LED_CAPSL, atkbd->dev->led) ? 4 : 0);
if (atkbd_probe(atkbd)) if (atkbd_probe(atkbd))
return -1; return -1;
if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
@ -996,8 +1008,13 @@ static int atkbd_reconnect(struct serio *serio)
atkbd_activate(atkbd); atkbd_activate(atkbd);
if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS)) /*
return -1; * Restore repeat rate and LEDs (that were reset by atkbd_activate)
* to pre-resume state
*/
if (!atkbd->softrepeat)
atkbd_set_repeat_rate(atkbd);
atkbd_set_leds(atkbd);
} }
atkbd_enable(atkbd); atkbd_enable(atkbd);

View File

@ -94,7 +94,7 @@ static void call_bios(struct regs *regs)
static ssize_t __init locate_wistron_bios(void __iomem *base) static ssize_t __init locate_wistron_bios(void __iomem *base)
{ {
static const unsigned char __initdata signature[] = static unsigned char __initdata signature[] =
{ 0x42, 0x21, 0x55, 0x30 }; { 0x42, 0x21, 0x55, 0x30 };
ssize_t offset; ssize_t offset;
@ -259,11 +259,11 @@ static int __init dmi_matched(struct dmi_system_id *dmi)
return 1; return 1;
} }
static struct key_entry keymap_empty[] = { static struct key_entry keymap_empty[] __initdata = {
{ KE_END, 0 } { KE_END, 0 }
}; };
static struct key_entry keymap_fs_amilo_pro_v2000[] = { static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
{ KE_KEY, 0x01, KEY_HELP }, { KE_KEY, 0x01, KEY_HELP },
{ KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x11, KEY_PROG1 },
{ KE_KEY, 0x12, KEY_PROG2 }, { KE_KEY, 0x12, KEY_PROG2 },
@ -273,7 +273,7 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] = {
{ KE_END, 0 } { KE_END, 0 }
}; };
static struct key_entry keymap_fujitsu_n3510[] = { static struct key_entry keymap_fujitsu_n3510[] __initdata = {
{ KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x11, KEY_PROG1 },
{ KE_KEY, 0x12, KEY_PROG2 }, { KE_KEY, 0x12, KEY_PROG2 },
{ KE_KEY, 0x36, KEY_WWW }, { KE_KEY, 0x36, KEY_WWW },
@ -285,7 +285,7 @@ static struct key_entry keymap_fujitsu_n3510[] = {
{ KE_END, 0 } { KE_END, 0 }
}; };
static struct key_entry keymap_wistron_ms2111[] = { static struct key_entry keymap_wistron_ms2111[] __initdata = {
{ KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x11, KEY_PROG1 },
{ KE_KEY, 0x12, KEY_PROG2 }, { KE_KEY, 0x12, KEY_PROG2 },
{ KE_KEY, 0x13, KEY_PROG3 }, { KE_KEY, 0x13, KEY_PROG3 },
@ -294,7 +294,7 @@ static struct key_entry keymap_wistron_ms2111[] = {
{ KE_END, 0 } { KE_END, 0 }
}; };
static struct key_entry keymap_wistron_ms2141[] = { static struct key_entry keymap_wistron_ms2141[] __initdata = {
{ KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x11, KEY_PROG1 },
{ KE_KEY, 0x12, KEY_PROG2 }, { KE_KEY, 0x12, KEY_PROG2 },
{ KE_WIFI, 0x30, 0 }, { KE_WIFI, 0x30, 0 },
@ -307,7 +307,7 @@ static struct key_entry keymap_wistron_ms2141[] = {
{ KE_END, 0 } { KE_END, 0 }
}; };
static struct key_entry keymap_acer_aspire_1500[] = { static struct key_entry keymap_acer_aspire_1500[] __initdata = {
{ KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x11, KEY_PROG1 },
{ KE_KEY, 0x12, KEY_PROG2 }, { KE_KEY, 0x12, KEY_PROG2 },
{ KE_WIFI, 0x30, 0 }, { KE_WIFI, 0x30, 0 },
@ -317,7 +317,7 @@ static struct key_entry keymap_acer_aspire_1500[] = {
{ KE_END, 0 } { KE_END, 0 }
}; };
static struct key_entry keymap_acer_travelmate_240[] = { static struct key_entry keymap_acer_travelmate_240[] __initdata = {
{ KE_KEY, 0x31, KEY_MAIL }, { KE_KEY, 0x31, KEY_MAIL },
{ KE_KEY, 0x36, KEY_WWW }, { KE_KEY, 0x36, KEY_WWW },
{ KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x11, KEY_PROG1 },
@ -327,7 +327,7 @@ static struct key_entry keymap_acer_travelmate_240[] = {
{ KE_END, 0 } { KE_END, 0 }
}; };
static struct key_entry keymap_aopen_1559as[] = { static struct key_entry keymap_aopen_1559as[] __initdata = {
{ KE_KEY, 0x01, KEY_HELP }, { KE_KEY, 0x01, KEY_HELP },
{ KE_KEY, 0x06, KEY_PROG3 }, { KE_KEY, 0x06, KEY_PROG3 },
{ KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x11, KEY_PROG1 },
@ -343,7 +343,7 @@ static struct key_entry keymap_aopen_1559as[] = {
* a list of buttons and their key codes (reported when loading this module * a list of buttons and their key codes (reported when loading this module
* with force=1) and the output of dmidecode to $MODULE_AUTHOR. * with force=1) and the output of dmidecode to $MODULE_AUTHOR.
*/ */
static struct dmi_system_id dmi_ids[] = { static struct dmi_system_id dmi_ids[] __initdata = {
{ {
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Fujitsu-Siemens Amilo Pro V2000", .ident = "Fujitsu-Siemens Amilo Pro V2000",

View File

@ -238,8 +238,7 @@ static struct ps2pp_info *get_model_info(unsigned char model)
{ 100, PS2PP_KIND_MX, /* MX510 */ { 100, PS2PP_KIND_MX, /* MX510 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
{ 111, PS2PP_KIND_MX, /* MX300 */ { 111, PS2PP_KIND_MX, PS2PP_WHEEL | PS2PP_SIDE_BTN }, /* MX300 reports task button as side */
PS2PP_WHEEL | PS2PP_EXTRA_BTN | PS2PP_TASK_BTN },
{ 112, PS2PP_KIND_MX, /* MX500 */ { 112, PS2PP_KIND_MX, /* MX500 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },

View File

@ -183,21 +183,26 @@ static struct attribute_group trackpoint_attr_group = {
.attrs = trackpoint_attrs, .attrs = trackpoint_attrs,
}; };
static void trackpoint_disconnect(struct psmouse *psmouse) static int trackpoint_start_protocol(struct psmouse *psmouse, unsigned char *firmware_id)
{ {
sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group); unsigned char param[2] = { 0 };
kfree(psmouse->private); if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
psmouse->private = NULL; return -1;
if (param[0] != TP_MAGIC_IDENT)
return -1;
if (firmware_id)
*firmware_id = param[1];
return 0;
} }
static int trackpoint_sync(struct psmouse *psmouse) static int trackpoint_sync(struct psmouse *psmouse)
{ {
unsigned char toggle;
struct trackpoint_data *tp = psmouse->private; struct trackpoint_data *tp = psmouse->private;
unsigned char toggle;
if (!tp)
return -1;
/* Disable features that may make device unusable with this driver */ /* Disable features that may make device unusable with this driver */
trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle); trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle);
@ -263,27 +268,38 @@ static void trackpoint_defaults(struct trackpoint_data *tp)
tp->ext_dev = TP_DEF_EXT_DEV; tp->ext_dev = TP_DEF_EXT_DEV;
} }
static void trackpoint_disconnect(struct psmouse *psmouse)
{
sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group);
kfree(psmouse->private);
psmouse->private = NULL;
}
static int trackpoint_reconnect(struct psmouse *psmouse)
{
if (trackpoint_start_protocol(psmouse, NULL))
return -1;
if (trackpoint_sync(psmouse))
return -1;
return 0;
}
int trackpoint_detect(struct psmouse *psmouse, int set_properties) int trackpoint_detect(struct psmouse *psmouse, int set_properties)
{ {
struct trackpoint_data *priv; struct trackpoint_data *priv;
struct ps2dev *ps2dev = &psmouse->ps2dev; struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char firmware_id; unsigned char firmware_id;
unsigned char button_info; unsigned char button_info;
unsigned char param[2];
param[0] = param[1] = 0; if (trackpoint_start_protocol(psmouse, &firmware_id))
if (ps2_command(ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
return -1;
if (param[0] != TP_MAGIC_IDENT)
return -1; return -1;
if (!set_properties) if (!set_properties)
return 0; return 0;
firmware_id = param[1];
if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) { if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n"); printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n");
button_info = 0; button_info = 0;
@ -296,7 +312,7 @@ int trackpoint_detect(struct psmouse *psmouse, int set_properties)
psmouse->vendor = "IBM"; psmouse->vendor = "IBM";
psmouse->name = "TrackPoint"; psmouse->name = "TrackPoint";
psmouse->reconnect = trackpoint_sync; psmouse->reconnect = trackpoint_reconnect;
psmouse->disconnect = trackpoint_disconnect; psmouse->disconnect = trackpoint_disconnect;
trackpoint_defaults(priv); trackpoint_defaults(priv);

View File

@ -177,6 +177,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
return -1; return -1;
} }
if (send && !param) {
WARN_ON(1);
return -1;
}
mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING); mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING);
serio_pause_rx(ps2dev->serio); serio_pause_rx(ps2dev->serio);

View File

@ -62,6 +62,7 @@ static LIST_HEAD(serio_list);
static struct bus_type serio_bus; static struct bus_type serio_bus;
static void serio_add_driver(struct serio_driver *drv);
static void serio_add_port(struct serio *serio); static void serio_add_port(struct serio *serio);
static void serio_destroy_port(struct serio *serio); static void serio_destroy_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio); static void serio_reconnect_port(struct serio *serio);
@ -140,8 +141,14 @@ static void serio_release_driver(struct serio *serio)
static void serio_find_driver(struct serio *serio) static void serio_find_driver(struct serio *serio)
{ {
int error;
down_write(&serio_bus.subsys.rwsem); down_write(&serio_bus.subsys.rwsem);
device_attach(&serio->dev); error = device_attach(&serio->dev);
if (error < 0)
printk(KERN_WARNING
"serio: device_attach() failed for %s (%s), error: %d\n",
serio->phys, serio->name, error);
up_write(&serio_bus.subsys.rwsem); up_write(&serio_bus.subsys.rwsem);
} }
@ -272,7 +279,6 @@ static struct serio_event *serio_get_event(void)
static void serio_handle_event(void) static void serio_handle_event(void)
{ {
struct serio_event *event; struct serio_event *event;
struct serio_driver *serio_drv;
mutex_lock(&serio_mutex); mutex_lock(&serio_mutex);
@ -304,8 +310,7 @@ static void serio_handle_event(void)
break; break;
case SERIO_REGISTER_DRIVER: case SERIO_REGISTER_DRIVER:
serio_drv = event->object; serio_add_driver(event->object);
driver_register(&serio_drv->driver);
break; break;
default: default:
@ -525,6 +530,7 @@ static void serio_init_port(struct serio *serio)
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
INIT_LIST_HEAD(&serio->node);
spin_lock_init(&serio->lock); spin_lock_init(&serio->lock);
mutex_init(&serio->drv_mutex); mutex_init(&serio->drv_mutex);
device_initialize(&serio->dev); device_initialize(&serio->dev);
@ -542,6 +548,8 @@ static void serio_init_port(struct serio *serio)
*/ */
static void serio_add_port(struct serio *serio) static void serio_add_port(struct serio *serio)
{ {
int error;
if (serio->parent) { if (serio->parent) {
serio_pause_rx(serio->parent); serio_pause_rx(serio->parent);
serio->parent->child = serio; serio->parent->child = serio;
@ -551,9 +559,19 @@ static void serio_add_port(struct serio *serio)
list_add_tail(&serio->node, &serio_list); list_add_tail(&serio->node, &serio_list);
if (serio->start) if (serio->start)
serio->start(serio); serio->start(serio);
device_add(&serio->dev); error = device_add(&serio->dev);
sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group); if (error)
serio->registered = 1; printk(KERN_ERR
"serio: device_add() failed for %s (%s), error: %d\n",
serio->phys, serio->name, error);
else {
serio->registered = 1;
error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
if (error)
printk(KERN_ERR
"serio: sysfs_create_group() failed for %s (%s), error: %d\n",
serio->phys, serio->name, error);
}
} }
/* /*
@ -583,10 +601,10 @@ static void serio_destroy_port(struct serio *serio)
if (serio->registered) { if (serio->registered) {
sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group); sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
device_del(&serio->dev); device_del(&serio->dev);
list_del_init(&serio->node);
serio->registered = 0; serio->registered = 0;
} }
list_del_init(&serio->node);
serio_remove_pending_events(serio); serio_remove_pending_events(serio);
put_device(&serio->dev); put_device(&serio->dev);
} }
@ -756,6 +774,17 @@ static struct bus_type serio_bus = {
.remove = serio_driver_remove, .remove = serio_driver_remove,
}; };
static void serio_add_driver(struct serio_driver *drv)
{
int error;
error = driver_register(&drv->driver);
if (error)
printk(KERN_ERR
"serio: driver_register() failed for %s, error: %d\n",
drv->driver.name, error);
}
void __serio_register_driver(struct serio_driver *drv, struct module *owner) void __serio_register_driver(struct serio_driver *drv, struct module *owner)
{ {
drv->driver.bus = &serio_bus; drv->driver.bus = &serio_bus;
@ -903,18 +932,26 @@ irqreturn_t serio_interrupt(struct serio *serio,
static int __init serio_init(void) static int __init serio_init(void)
{ {
serio_task = kthread_run(serio_thread, NULL, "kseriod"); int error;
if (IS_ERR(serio_task)) {
printk(KERN_ERR "serio: Failed to start kseriod\n");
return PTR_ERR(serio_task);
}
serio_bus.dev_attrs = serio_device_attrs; serio_bus.dev_attrs = serio_device_attrs;
serio_bus.drv_attrs = serio_driver_attrs; serio_bus.drv_attrs = serio_driver_attrs;
serio_bus.match = serio_bus_match; serio_bus.match = serio_bus_match;
serio_bus.uevent = serio_uevent; serio_bus.uevent = serio_uevent;
serio_bus.resume = serio_resume; serio_bus.resume = serio_resume;
bus_register(&serio_bus); error = bus_register(&serio_bus);
if (error) {
printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error);
return error;
}
serio_task = kthread_run(serio_thread, NULL, "kseriod");
if (IS_ERR(serio_task)) {
bus_unregister(&serio_bus);
error = PTR_ERR(serio_task);
printk(KERN_ERR "serio: Failed to start kseriod, error: %d\n", error);
return error;
}
return 0; return 0;
} }

View File

@ -111,14 +111,28 @@
#define NAME_BUFSIZE 80 /* size of product name, path buffers */ #define NAME_BUFSIZE 80 /* size of product name, path buffers */
#define DATA_BUFSIZE 63 /* size of URB data buffers */ #define DATA_BUFSIZE 63 /* size of URB data buffers */
/*
* Duplicate event filtering time.
* Sequential, identical KIND_FILTERED inputs with less than
* FILTER_TIME milliseconds between them are considered as repeat
* events. The hardware generates 5 events for the first keypress
* and we have to take this into account for an accurate repeat
* behaviour.
*/
#define FILTER_TIME 60 /* msec */
static unsigned long channel_mask; static unsigned long channel_mask;
module_param(channel_mask, ulong, 0444); module_param(channel_mask, ulong, 0644);
MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore"); MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
static int debug; static int debug;
module_param(debug, int, 0444); module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Enable extra debug messages and information"); MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
static int repeat_filter = FILTER_TIME;
module_param(repeat_filter, int, 0644);
MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0) #define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
#undef err #undef err
#define err(format, arg...) printk(KERN_ERR format , ## arg) #define err(format, arg...) printk(KERN_ERR format , ## arg)
@ -143,18 +157,6 @@ MODULE_DEVICE_TABLE(usb, ati_remote_table);
static char init1[] = { 0x01, 0x00, 0x20, 0x14 }; static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 }; static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
/* Acceleration curve for directional control pad */
static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
/* Duplicate event filtering time.
* Sequential, identical KIND_FILTERED inputs with less than
* FILTER_TIME jiffies between them are considered as repeat
* events. The hardware generates 5 events for the first keypress
* and we have to take this into account for an accurate repeat
* behaviour.
*/
#define FILTER_TIME 60 /* msec */
struct ati_remote { struct ati_remote {
struct input_dev *idev; struct input_dev *idev;
struct usb_device *udev; struct usb_device *udev;
@ -411,6 +413,43 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
return -1; return -1;
} }
/*
* ati_remote_compute_accel
*
* Implements acceleration curve for directional control pad
* If elapsed time since last event is > 1/4 second, user "stopped",
* so reset acceleration. Otherwise, user is probably holding the control
* pad down, so we increase acceleration, ramping up over two seconds to
* a maximum speed.
*/
static int ati_remote_compute_accel(struct ati_remote *ati_remote)
{
static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
unsigned long now = jiffies;
int acc;
if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) {
acc = 1;
ati_remote->acc_jiffies = now;
}
else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125)))
acc = accel[0];
else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250)))
acc = accel[1];
else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500)))
acc = accel[2];
else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000)))
acc = accel[3];
else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500)))
acc = accel[4];
else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000)))
acc = accel[5];
else
acc = accel[6];
return acc;
}
/* /*
* ati_remote_report_input * ati_remote_report_input
*/ */
@ -464,9 +503,9 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
if (ati_remote_tbl[index].kind == KIND_FILTERED) { if (ati_remote_tbl[index].kind == KIND_FILTERED) {
/* Filter duplicate events which happen "too close" together. */ /* Filter duplicate events which happen "too close" together. */
if ((ati_remote->old_data[0] == data[1]) && if (ati_remote->old_data[0] == data[1] &&
(ati_remote->old_data[1] == data[2]) && ati_remote->old_data[1] == data[2] &&
time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(FILTER_TIME))) { time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(repeat_filter))) {
ati_remote->repeat_count++; ati_remote->repeat_count++;
} else { } else {
ati_remote->repeat_count = 0; ati_remote->repeat_count = 0;
@ -476,75 +515,61 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
ati_remote->old_data[1] = data[2]; ati_remote->old_data[1] = data[2];
ati_remote->old_jiffies = jiffies; ati_remote->old_jiffies = jiffies;
if ((ati_remote->repeat_count > 0) if (ati_remote->repeat_count > 0 &&
&& (ati_remote->repeat_count < 5)) ati_remote->repeat_count < 5)
return; return;
input_regs(dev, regs); input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type, input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, 1); ati_remote_tbl[index].code, 1);
input_sync(dev);
input_event(dev, ati_remote_tbl[index].type, input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, 0); ati_remote_tbl[index].code, 0);
input_sync(dev); input_sync(dev);
return; } else {
}
/* /*
* Other event kinds are from the directional control pad, and have an * Other event kinds are from the directional control pad, and have an
* acceleration factor applied to them. Without this acceleration, the * acceleration factor applied to them. Without this acceleration, the
* control pad is mostly unusable. * control pad is mostly unusable.
* */
* If elapsed time since last event is > 1/4 second, user "stopped", acc = ati_remote_compute_accel(ati_remote);
* so reset acceleration. Otherwise, user is probably holding the control
* pad down, so we increase acceleration, ramping up over two seconds to
* a maximum speed. The acceleration curve is #defined above.
*/
if (time_after(jiffies, ati_remote->old_jiffies + (HZ >> 2))) {
acc = 1;
ati_remote->acc_jiffies = jiffies;
}
else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 3))) acc = accel[0];
else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 2))) acc = accel[1];
else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 1))) acc = accel[2];
else if (time_before(jiffies, ati_remote->acc_jiffies + HZ)) acc = accel[3];
else if (time_before(jiffies, ati_remote->acc_jiffies + HZ+(HZ>>1))) acc = accel[4];
else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ << 1))) acc = accel[5];
else acc = accel[6];
input_regs(dev, regs); input_regs(dev, regs);
switch (ati_remote_tbl[index].kind) { switch (ati_remote_tbl[index].kind) {
case KIND_ACCEL: case KIND_ACCEL:
input_event(dev, ati_remote_tbl[index].type, input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, ati_remote_tbl[index].code,
ati_remote_tbl[index].value * acc); ati_remote_tbl[index].value * acc);
break; break;
case KIND_LU: case KIND_LU:
input_report_rel(dev, REL_X, -acc); input_report_rel(dev, REL_X, -acc);
input_report_rel(dev, REL_Y, -acc); input_report_rel(dev, REL_Y, -acc);
break; break;
case KIND_RU: case KIND_RU:
input_report_rel(dev, REL_X, acc); input_report_rel(dev, REL_X, acc);
input_report_rel(dev, REL_Y, -acc); input_report_rel(dev, REL_Y, -acc);
break; break;
case KIND_LD: case KIND_LD:
input_report_rel(dev, REL_X, -acc); input_report_rel(dev, REL_X, -acc);
input_report_rel(dev, REL_Y, acc); input_report_rel(dev, REL_Y, acc);
break; break;
case KIND_RD: case KIND_RD:
input_report_rel(dev, REL_X, acc); input_report_rel(dev, REL_X, acc);
input_report_rel(dev, REL_Y, acc); input_report_rel(dev, REL_Y, acc);
break; break;
default: default:
dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n", dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
ati_remote_tbl[index].kind); ati_remote_tbl[index].kind);
} }
input_sync(dev); input_sync(dev);
ati_remote->old_jiffies = jiffies; ati_remote->old_jiffies = jiffies;
ati_remote->old_data[0] = data[1]; ati_remote->old_data[0] = data[1];
ati_remote->old_data[1] = data[2]; ati_remote->old_data[1] = data[2];
}
} }
/* /*

View File

@ -607,7 +607,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
} }
if (usage->hat_min < usage->hat_max || usage->hat_dir) { if (usage->type == EV_ABS &&
(usage->hat_min < usage->hat_max || usage->hat_dir)) {
int i; int i;
for (i = usage->code; i < usage->code + 2 && i <= max; i++) { for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
input_set_abs_params(input, i, -1, 1, 0, 0); input_set_abs_params(input, i, -1, 1, 0, 0);

View File

@ -49,7 +49,7 @@ struct hiddev {
int open; int open;
wait_queue_head_t wait; wait_queue_head_t wait;
struct hid_device *hid; struct hid_device *hid;
struct hiddev_list *list; struct list_head list;
}; };
struct hiddev_list { struct hiddev_list {
@ -59,7 +59,7 @@ struct hiddev_list {
unsigned flags; unsigned flags;
struct fasync_struct *fasync; struct fasync_struct *fasync;
struct hiddev *hiddev; struct hiddev *hiddev;
struct hiddev_list *next; struct list_head node;
}; };
static struct hiddev *hiddev_table[HIDDEV_MINORS]; static struct hiddev *hiddev_table[HIDDEV_MINORS];
@ -73,12 +73,15 @@ static struct hiddev *hiddev_table[HIDDEV_MINORS];
static struct hid_report * static struct hid_report *
hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
{ {
unsigned flags = rinfo->report_id & ~HID_REPORT_ID_MASK; unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK;
unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK;
struct hid_report_enum *report_enum; struct hid_report_enum *report_enum;
struct hid_report *report;
struct list_head *list; struct list_head *list;
if (rinfo->report_type < HID_REPORT_TYPE_MIN || if (rinfo->report_type < HID_REPORT_TYPE_MIN ||
rinfo->report_type > HID_REPORT_TYPE_MAX) return NULL; rinfo->report_type > HID_REPORT_TYPE_MAX)
return NULL;
report_enum = hid->report_enum + report_enum = hid->report_enum +
(rinfo->report_type - HID_REPORT_TYPE_MIN); (rinfo->report_type - HID_REPORT_TYPE_MIN);
@ -88,21 +91,25 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
break; break;
case HID_REPORT_ID_FIRST: case HID_REPORT_ID_FIRST:
list = report_enum->report_list.next; if (list_empty(&report_enum->report_list))
if (list == &report_enum->report_list)
return NULL; return NULL;
rinfo->report_id = ((struct hid_report *) list)->id;
list = report_enum->report_list.next;
report = list_entry(list, struct hid_report, list);
rinfo->report_id = report->id;
break; break;
case HID_REPORT_ID_NEXT: case HID_REPORT_ID_NEXT:
list = (struct list_head *) report = report_enum->report_id_hash[rid];
report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK]; if (!report)
if (list == NULL)
return NULL; return NULL;
list = list->next;
list = report->list.next;
if (list == &report_enum->report_list) if (list == &report_enum->report_list)
return NULL; return NULL;
rinfo->report_id = ((struct hid_report *) list)->id;
report = list_entry(list, struct hid_report, list);
rinfo->report_id = report->id;
break; break;
default: default:
@ -125,12 +132,13 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
struct hid_field *field; struct hid_field *field;
if (uref->report_type < HID_REPORT_TYPE_MIN || if (uref->report_type < HID_REPORT_TYPE_MIN ||
uref->report_type > HID_REPORT_TYPE_MAX) return NULL; uref->report_type > HID_REPORT_TYPE_MAX)
return NULL;
report_enum = hid->report_enum + report_enum = hid->report_enum +
(uref->report_type - HID_REPORT_TYPE_MIN); (uref->report_type - HID_REPORT_TYPE_MIN);
list_for_each_entry(report, &report_enum->report_list, list) list_for_each_entry(report, &report_enum->report_list, list) {
for (i = 0; i < report->maxfield; i++) { for (i = 0; i < report->maxfield; i++) {
field = report->field[i]; field = report->field[i];
for (j = 0; j < field->maxusage; j++) { for (j = 0; j < field->maxusage; j++) {
@ -142,6 +150,7 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
} }
} }
} }
}
return NULL; return NULL;
} }
@ -150,9 +159,9 @@ static void hiddev_send_event(struct hid_device *hid,
struct hiddev_usage_ref *uref) struct hiddev_usage_ref *uref)
{ {
struct hiddev *hiddev = hid->hiddev; struct hiddev *hiddev = hid->hiddev;
struct hiddev_list *list = hiddev->list; struct hiddev_list *list;
while (list) { list_for_each_entry(list, &hiddev->list, node) {
if (uref->field_index != HID_FIELD_INDEX_NONE || if (uref->field_index != HID_FIELD_INDEX_NONE ||
(list->flags & HIDDEV_FLAG_REPORT) != 0) { (list->flags & HIDDEV_FLAG_REPORT) != 0) {
list->buffer[list->head] = *uref; list->buffer[list->head] = *uref;
@ -160,8 +169,6 @@ static void hiddev_send_event(struct hid_device *hid,
(HIDDEV_BUFFER_SIZE - 1); (HIDDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN); kill_fasync(&list->fasync, SIGIO, POLL_IN);
} }
list = list->next;
} }
wake_up_interruptible(&hiddev->wait); wake_up_interruptible(&hiddev->wait);
@ -180,7 +187,7 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
uref.report_type = uref.report_type =
(type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
uref.report_id = field->report->id; uref.report_id = field->report->id;
uref.field_index = field->index; uref.field_index = field->index;
uref.usage_index = (usage - field->usage); uref.usage_index = (usage - field->usage);
@ -200,7 +207,7 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
uref.report_type = uref.report_type =
(type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
uref.report_id = report->id; uref.report_id = report->id;
uref.field_index = HID_FIELD_INDEX_NONE; uref.field_index = HID_FIELD_INDEX_NONE;
@ -213,7 +220,9 @@ static int hiddev_fasync(int fd, struct file *file, int on)
{ {
int retval; int retval;
struct hiddev_list *list = file->private_data; struct hiddev_list *list = file->private_data;
retval = fasync_helper(fd, file, on, &list->fasync); retval = fasync_helper(fd, file, on, &list->fasync);
return retval < 0 ? retval : 0; return retval < 0 ? retval : 0;
} }
@ -224,14 +233,9 @@ static int hiddev_fasync(int fd, struct file *file, int on)
static int hiddev_release(struct inode * inode, struct file * file) static int hiddev_release(struct inode * inode, struct file * file)
{ {
struct hiddev_list *list = file->private_data; struct hiddev_list *list = file->private_data;
struct hiddev_list **listptr;
listptr = &list->hiddev->list;
hiddev_fasync(-1, file, 0); hiddev_fasync(-1, file, 0);
list_del(&list->node);
while (*listptr && (*listptr != list))
listptr = &((*listptr)->next);
*listptr = (*listptr)->next;
if (!--list->hiddev->open) { if (!--list->hiddev->open) {
if (list->hiddev->exist) if (list->hiddev->exist)
@ -248,7 +252,8 @@ static int hiddev_release(struct inode * inode, struct file * file)
/* /*
* open file op * open file op
*/ */
static int hiddev_open(struct inode * inode, struct file * file) { static int hiddev_open(struct inode *inode, struct file *file)
{
struct hiddev_list *list; struct hiddev_list *list;
int i = iminor(inode) - HIDDEV_MINOR_BASE; int i = iminor(inode) - HIDDEV_MINOR_BASE;
@ -260,9 +265,7 @@ static int hiddev_open(struct inode * inode, struct file * file) {
return -ENOMEM; return -ENOMEM;
list->hiddev = hiddev_table[i]; list->hiddev = hiddev_table[i];
list->next = hiddev_table[i]->list; list_add_tail(&list->node, &hiddev_table[i]->list);
hiddev_table[i]->list = list;
file->private_data = list; file->private_data = list;
if (!list->hiddev->open++) if (!list->hiddev->open++)
@ -362,6 +365,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
static unsigned int hiddev_poll(struct file *file, poll_table *wait) static unsigned int hiddev_poll(struct file *file, poll_table *wait)
{ {
struct hiddev_list *list = file->private_data; struct hiddev_list *list = file->private_data;
poll_wait(file, &list->hiddev->wait, wait); poll_wait(file, &list->hiddev->wait, wait);
if (list->head != list->tail) if (list->head != list->tail)
return POLLIN | POLLRDNORM; return POLLIN | POLLRDNORM;
@ -382,7 +386,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct hiddev_collection_info cinfo; struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo; struct hiddev_report_info rinfo;
struct hiddev_field_info finfo; struct hiddev_field_info finfo;
struct hiddev_usage_ref_multi *uref_multi=NULL; struct hiddev_usage_ref_multi *uref_multi = NULL;
struct hiddev_usage_ref *uref; struct hiddev_usage_ref *uref;
struct hiddev_devinfo dinfo; struct hiddev_devinfo dinfo;
struct hid_report *report; struct hid_report *report;
@ -764,15 +768,15 @@ int hiddev_connect(struct hid_device *hid)
} }
init_waitqueue_head(&hiddev->wait); init_waitqueue_head(&hiddev->wait);
INIT_LIST_HEAD(&hiddev->list);
hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
hiddev->hid = hid; hiddev->hid = hid;
hiddev->exist = 1; hiddev->exist = 1;
hid->minor = hid->intf->minor; hid->minor = hid->intf->minor;
hid->hiddev = hiddev; hid->hiddev = hiddev;
hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
return 0; return 0;
} }

View File

@ -893,7 +893,6 @@ struct input_dev {
int (*open)(struct input_dev *dev); int (*open)(struct input_dev *dev);
void (*close)(struct input_dev *dev); void (*close)(struct input_dev *dev);
int (*accept)(struct input_dev *dev, struct file *file);
int (*flush)(struct input_dev *dev, struct file *file); int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);
@ -961,6 +960,26 @@ struct input_dev {
struct input_handle; struct input_handle;
/**
* struct input_handler - implements one of interfaces for input devices
* @private: driver-specific data
* @event: event handler
* @connect: called when attaching a handler to an input device
* @disconnect: disconnects a handler from input device
* @start: starts handler for given handle. This function is called by
* input core right after connect() method and also when a process
* that "grabbed" a device releases it
* @fops: file operations this driver implements
* @minor: beginning of range of 32 minors for devices this driver
* can provide
* @name: name of the handler, to be shown in /proc/bus/input/handlers
* @id_table: pointer to a table of input_device_ids this driver can
* handle
* @blacklist: prointer to a table of input_device_ids this driver should
* ignore even if they match @id_table
* @h_list: list of input handles associated with the handler
* @node: for placing the driver onto input_handler_list
*/
struct input_handler { struct input_handler {
void *private; void *private;
@ -968,6 +987,7 @@ struct input_handler {
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id); struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);
void (*disconnect)(struct input_handle *handle); void (*disconnect)(struct input_handle *handle);
void (*start)(struct input_handle *handle);
const struct file_operations *fops; const struct file_operations *fops;
int minor; int minor;
@ -1030,10 +1050,10 @@ void input_release_device(struct input_handle *);
int input_open_device(struct input_handle *); int input_open_device(struct input_handle *);
void input_close_device(struct input_handle *); void input_close_device(struct input_handle *);
int input_accept_process(struct input_handle *handle, struct file *file);
int input_flush_device(struct input_handle* handle, struct file* file); int input_flush_device(struct input_handle* handle, struct file* file);
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value);
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)
{ {