summaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/evdev.c10
-rw-r--r--drivers/input/gameport/fm801-gp.c4
-rw-r--r--drivers/input/gameport/gameport.c66
-rw-r--r--drivers/input/input.c57
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c19
-rw-r--r--drivers/input/joystick/spaceball.c2
-rw-r--r--drivers/input/keyboard/atkbd.c103
-rw-r--r--drivers/input/misc/wistron_btns.c4
-rw-r--r--drivers/input/mouse/logips2pp.c3
-rw-r--r--drivers/input/mouse/psmouse-base.c7
-rw-r--r--drivers/input/mouse/trackpoint.c52
-rw-r--r--drivers/input/serio/libps2.c5
-rw-r--r--drivers/input/serio/serio.c65
13 files changed, 262 insertions, 135 deletions
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index a29d5ceb00cf..4bf48188cc91 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -127,14 +127,10 @@ static int evdev_open(struct inode * inode, struct file * file)
{
struct evdev_list *list;
int i = iminor(inode) - EVDEV_MINOR_BASE;
- int accept_err;
if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
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)))
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))
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();
}
@@ -428,8 +424,8 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
if (get_user(v, ip + 1))
return -EFAULT;
- input_event(dev, EV_REP, REP_DELAY, u);
- input_event(dev, EV_REP, REP_PERIOD, v);
+ input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
+ input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
return 0;
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index 47e93daa0fa7..90de5afe03c2 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -106,10 +106,10 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device
gp->gameport = port;
gp->res_port = request_region(port->io, 0x10, "FM801 GP");
if (!gp->res_port) {
- kfree(gp);
- gameport_free_port(port);
printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n",
port->io, port->io + 0x0f);
+ gameport_free_port(port);
+ kfree(gp);
return -EBUSY;
}
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 36644bff379d..3f47ae55c6f3 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -53,6 +53,7 @@ static LIST_HEAD(gameport_list);
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_destroy_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)
{
+ int error;
+
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);
}
@@ -316,7 +323,6 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
spin_unlock_irqrestore(&gameport_event_lock, flags);
}
-
static struct gameport_event *gameport_get_event(void)
{
struct gameport_event *event;
@@ -342,7 +348,6 @@ static struct gameport_event *gameport_get_event(void)
static void gameport_handle_event(void)
{
struct gameport_event *event;
- struct gameport_driver *gameport_drv;
mutex_lock(&gameport_mutex);
@@ -369,8 +374,7 @@ static void gameport_handle_event(void)
break;
case GAMEPORT_REGISTER_DRIVER:
- gameport_drv = event->object;
- driver_register(&gameport_drv->driver);
+ gameport_add_driver(event->object);
break;
default:
@@ -532,6 +536,7 @@ static void gameport_init_port(struct gameport *gameport)
if (gameport->parent)
gameport->dev.parent = &gameport->parent->dev;
+ INIT_LIST_HEAD(&gameport->node);
spin_lock_init(&gameport->timer_lock);
init_timer(&gameport->poll_timer);
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)
{
+ int error;
+
if (gameport->parent)
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",
gameport->name, gameport->phys, gameport->speed);
- device_add(&gameport->dev);
- gameport->registered = 1;
+ error = device_add(&gameport->dev);
+ 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) {
device_del(&gameport->dev);
- list_del_init(&gameport->node);
gameport->registered = 0;
}
+ list_del_init(&gameport->node);
+
gameport_remove_pending_events(gameport);
put_device(&gameport->dev);
}
@@ -704,11 +717,22 @@ static int gameport_driver_remove(struct device *dev)
}
static struct bus_type gameport_bus = {
- .name = "gameport",
- .probe = gameport_driver_probe,
- .remove = gameport_driver_remove,
+ .name = "gameport",
+ .probe = gameport_driver_probe,
+ .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)
{
drv->driver.bus = &gameport_bus;
@@ -778,16 +802,24 @@ void gameport_close(struct gameport *gameport)
static int __init gameport_init(void)
{
- gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
- if (IS_ERR(gameport_task)) {
- printk(KERN_ERR "gameport: Failed to start kgameportd\n");
- return PTR_ERR(gameport_task);
- }
+ int error;
gameport_bus.dev_attrs = gameport_device_attrs;
gameport_bus.drv_attrs = gameport_driver_attrs;
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;
}
diff --git a/drivers/input/input.c b/drivers/input/input.c
index a90486f5e491..9cb4b9a54f01 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -35,6 +35,16 @@ static LIST_HEAD(input_handler_list);
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)
{
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);
+/**
+ * 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)
{
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]));
}
-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)
{
if (handle->dev->grab)
@@ -218,8 +236,15 @@ EXPORT_SYMBOL(input_grab_device);
void input_release_device(struct input_handle *handle)
{
- if (handle->dev->grab == handle)
- handle->dev->grab = NULL;
+ struct input_dev *dev = handle->dev;
+
+ 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);
@@ -963,8 +988,11 @@ int input_register_device(struct input_dev *dev)
list_for_each_entry(handler, &input_handler_list, node)
if (!handler->blacklist || !input_match_device(handler->blacklist, 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);
+ if (handler->start)
+ handler->start(handle);
+ }
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)
if (!handler->blacklist || !input_match_device(handler->blacklist, 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);
+ if (handler->start)
+ handler->start(handle);
+ }
input_wakeup_procfs_readers();
}
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 6d99e3c37884..b4914e7231f8 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -79,6 +79,7 @@ static struct iforce_device iforce_device[] = {
{ 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, "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 }
};
@@ -222,22 +223,22 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id)
int err = 0;
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)
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))
- 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))
- 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 */
core_effect->flags[0] = 0;
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index 75eb5ca59992..7a19ee052972 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -50,7 +50,7 @@ MODULE_LICENSE("GPL");
*/
#define SPACEBALL_MAX_LENGTH 128
-#define SPACEBALL_MAX_ID 8
+#define SPACEBALL_MAX_ID 9
#define SPACEBALL_1003 1
#define SPACEBALL_2003B 3
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index ce1f10e8984b..a86afd0a5ef1 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -482,13 +482,7 @@ out:
return IRQ_HANDLED;
}
-/*
- * atkbd_event_work() is used to complete processing of events that
- * can not be processed by input_event() which is often called from
- * interrupt context.
- */
-
-static void atkbd_event_work(void *data)
+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,
@@ -496,41 +490,64 @@ static void atkbd_event_work(void *data)
const short delay[4] =
{ 250, 500, 750, 1000 };
- struct atkbd *atkbd = data;
+ 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(delay) - 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];
- int i, j;
- mutex_lock(&atkbd->event_mutex);
+ 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 (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) {
- 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);
- ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS);
-
- 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);
- ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
- }
+ 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;
}
- 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);
- }
+ return 0;
+}
+
+/*
+ * atkbd_event_work() is used to complete processing of events that
+ * can not be processed by input_event() which is often called from
+ * interrupt context.
+ */
+
+static void atkbd_event_work(void *data)
+{
+ struct atkbd *atkbd = data;
+
+ mutex_lock(&atkbd->event_mutex);
+
+ if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
+ atkbd_set_leds(atkbd);
+
+ if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
+ atkbd_set_repeat_rate(atkbd);
mutex_unlock(&atkbd->event_mutex);
}
@@ -975,7 +992,6 @@ static int atkbd_reconnect(struct serio *serio)
{
struct atkbd *atkbd = serio_get_drvdata(serio);
struct serio_driver *drv = serio->drv;
- unsigned char param[1];
if (!atkbd || !drv) {
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);
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))
return -1;
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);
- 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);
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index ccf0faeee5c1..de0f46dd9692 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -94,7 +94,7 @@ static void call_bios(struct regs *regs)
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 };
ssize_t offset;
@@ -343,7 +343,7 @@ static struct key_entry keymap_aopen_1559as[] = {
* a list of buttons and their key codes (reported when loading this module
* 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,
.ident = "Fujitsu-Siemens Amilo Pro V2000",
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 2f0d28840810..54b696cfe1e3 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -238,8 +238,7 @@ static struct ps2pp_info *get_model_info(unsigned char model)
{ 100, PS2PP_KIND_MX, /* MX510 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
- { 111, PS2PP_KIND_MX, /* MX300 */
- PS2PP_WHEEL | PS2PP_EXTRA_BTN | PS2PP_TASK_BTN },
+ { 111, PS2PP_KIND_MX, PS2PP_WHEEL | PS2PP_SIDE_BTN }, /* MX300 reports task button as side */
{ 112, PS2PP_KIND_MX, /* MX500 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 8bc9f51ae6c2..343afa38f4c2 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -485,13 +485,6 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
param[0] = 40;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
- param[0] = 200;
- ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
- param[0] = 200;
- ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
- param[0] = 60;
- ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
-
if (set_properties) {
set_bit(BTN_MIDDLE, psmouse->dev->keybit);
set_bit(REL_WHEEL, psmouse->dev->relbit);
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 6d9ec9ab1b90..ae5871a0e060 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -183,21 +183,26 @@ static struct attribute_group trackpoint_attr_group = {
.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);
- psmouse->private = NULL;
+ if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
+ 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)
{
- unsigned char toggle;
struct trackpoint_data *tp = psmouse->private;
-
- if (!tp)
- return -1;
+ unsigned char toggle;
/* Disable features that may make device unusable with this driver */
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;
}
+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)
{
struct trackpoint_data *priv;
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char firmware_id;
unsigned char button_info;
- unsigned char param[2];
-
- param[0] = param[1] = 0;
- if (ps2_command(ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
- return -1;
-
- if (param[0] != TP_MAGIC_IDENT)
+ if (trackpoint_start_protocol(psmouse, &firmware_id))
return -1;
if (!set_properties)
return 0;
- firmware_id = param[1];
-
if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n");
button_info = 0;
@@ -296,7 +312,7 @@ int trackpoint_detect(struct psmouse *psmouse, int set_properties)
psmouse->vendor = "IBM";
psmouse->name = "TrackPoint";
- psmouse->reconnect = trackpoint_sync;
+ psmouse->reconnect = trackpoint_reconnect;
psmouse->disconnect = trackpoint_disconnect;
trackpoint_defaults(priv);
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 61a6f977846f..ed202f2f251a 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -177,6 +177,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
return -1;
}
+ if (send && !param) {
+ WARN_ON(1);
+ return -1;
+ }
+
mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING);
serio_pause_rx(ps2dev->serio);
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 6521034bc933..3e76ad71c9a0 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -62,6 +62,7 @@ static LIST_HEAD(serio_list);
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_destroy_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)
{
+ int error;
+
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);
}
@@ -272,7 +279,6 @@ static struct serio_event *serio_get_event(void)
static void serio_handle_event(void)
{
struct serio_event *event;
- struct serio_driver *serio_drv;
mutex_lock(&serio_mutex);
@@ -304,8 +310,7 @@ static void serio_handle_event(void)
break;
case SERIO_REGISTER_DRIVER:
- serio_drv = event->object;
- driver_register(&serio_drv->driver);
+ serio_add_driver(event->object);
break;
default:
@@ -525,6 +530,7 @@ static void serio_init_port(struct serio *serio)
__module_get(THIS_MODULE);
+ INIT_LIST_HEAD(&serio->node);
spin_lock_init(&serio->lock);
mutex_init(&serio->drv_mutex);
device_initialize(&serio->dev);
@@ -542,6 +548,8 @@ static void serio_init_port(struct serio *serio)
*/
static void serio_add_port(struct serio *serio)
{
+ int error;
+
if (serio->parent) {
serio_pause_rx(serio->parent);
serio->parent->child = serio;
@@ -551,9 +559,19 @@ static void serio_add_port(struct serio *serio)
list_add_tail(&serio->node, &serio_list);
if (serio->start)
serio->start(serio);
- device_add(&serio->dev);
- sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
- serio->registered = 1;
+ error = device_add(&serio->dev);
+ if (error)
+ 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) {
sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
device_del(&serio->dev);
- list_del_init(&serio->node);
serio->registered = 0;
}
+ list_del_init(&serio->node);
serio_remove_pending_events(serio);
put_device(&serio->dev);
}
@@ -756,6 +774,17 @@ static struct bus_type serio_bus = {
.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)
{
drv->driver.bus = &serio_bus;
@@ -903,18 +932,26 @@ irqreturn_t serio_interrupt(struct serio *serio,
static int __init serio_init(void)
{
- serio_task = kthread_run(serio_thread, NULL, "kseriod");
- if (IS_ERR(serio_task)) {
- printk(KERN_ERR "serio: Failed to start kseriod\n");
- return PTR_ERR(serio_task);
- }
+ int error;
serio_bus.dev_attrs = serio_device_attrs;
serio_bus.drv_attrs = serio_driver_attrs;
serio_bus.match = serio_bus_match;
serio_bus.uevent = serio_uevent;
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;
}
OpenPOWER on IntegriCloud