aboutsummaryrefslogtreecommitdiff
path: root/drivers/input/serio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/serio')
-rw-r--r--drivers/input/serio/Kconfig2
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h14
-rw-r--r--drivers/input/serio/i8042.c62
-rw-r--r--drivers/input/serio/libps2.c136
-rw-r--r--drivers/input/serio/serio.c149
-rw-r--r--drivers/input/serio/serio_raw.c1
-rw-r--r--drivers/input/serio/serport.c2
7 files changed, 247 insertions, 119 deletions
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index b3710733b36..98acf170252 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -175,7 +175,7 @@ config SERIO_RAW
allocating minor 1 (that historically corresponds to /dev/psaux)
first. To bind this driver to a serio port use sysfs interface:
- echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver
+ echo -n "serio_raw" > /sys/bus/serio/devices/serioX/drvctl
To compile this driver as a module, choose M here: the
module will be called serio_raw.
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 0487ecbb8a4..03877c84e6f 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -131,12 +131,26 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
},
},
{
+ .ident = "Fujitsu-Siemens Lifebook T3010",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T3010"),
+ },
+ },
+ {
.ident = "Toshiba P10",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"),
},
},
+ {
+ .ident = "Alienware Sentia",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Sentia"),
+ },
+ },
{ }
};
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 5900de3c3f4..708a1d3beab 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -100,7 +100,7 @@ struct i8042_port {
static struct i8042_port i8042_ports[I8042_NUM_PORTS] = {
{
.disable = I8042_CTR_KBDDIS,
- .irqen = I8042_CTR_KBDINT,
+ .irqen = I8042_CTR_KBDINT,
.mux = -1,
.name = "KBD",
},
@@ -191,41 +191,45 @@ static int i8042_flush(void)
static int i8042_command(unsigned char *param, int command)
{
unsigned long flags;
- int retval = 0, i = 0;
+ int i, retval, auxerr = 0;
if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
return -1;
spin_lock_irqsave(&i8042_lock, flags);
- retval = i8042_wait_write();
- if (!retval) {
- dbg("%02x -> i8042 (command)", command & 0xff);
- i8042_write_command(command & 0xff);
+ if ((retval = i8042_wait_write()))
+ goto out;
+
+ dbg("%02x -> i8042 (command)", command & 0xff);
+ i8042_write_command(command & 0xff);
+
+ for (i = 0; i < ((command >> 12) & 0xf); i++) {
+ if ((retval = i8042_wait_write()))
+ goto out;
+ dbg("%02x -> i8042 (parameter)", param[i]);
+ i8042_write_data(param[i]);
}
- if (!retval)
- for (i = 0; i < ((command >> 12) & 0xf); i++) {
- if ((retval = i8042_wait_write())) break;
- dbg("%02x -> i8042 (parameter)", param[i]);
- i8042_write_data(param[i]);
- }
+ for (i = 0; i < ((command >> 8) & 0xf); i++) {
+ if ((retval = i8042_wait_read()))
+ goto out;
- if (!retval)
- for (i = 0; i < ((command >> 8) & 0xf); i++) {
- if ((retval = i8042_wait_read())) break;
- if (i8042_read_status() & I8042_STR_AUXDATA)
- param[i] = ~i8042_read_data();
- else
- param[i] = i8042_read_data();
- dbg("%02x <- i8042 (return)", param[i]);
+ if (command == I8042_CMD_AUX_LOOP &&
+ !(i8042_read_status() & I8042_STR_AUXDATA)) {
+ retval = auxerr = -1;
+ goto out;
}
- spin_unlock_irqrestore(&i8042_lock, flags);
+ param[i] = i8042_read_data();
+ dbg("%02x <- i8042 (return)", param[i]);
+ }
if (retval)
- dbg(" -- i8042 (timeout)");
+ dbg(" -- i8042 (%s)", auxerr ? "auxerr" : "timeout");
+ out:
+ spin_unlock_irqrestore(&i8042_lock, flags);
return retval;
}
@@ -396,7 +400,7 @@ static void i8042_stop(struct serio *serio)
struct i8042_port *port = serio->port_data;
port->exists = 0;
- synchronize_kernel();
+ synchronize_sched();
port->serio = NULL;
}
@@ -507,17 +511,17 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version)
*/
param = 0xf0;
- if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x0f)
+ if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xf0)
return -1;
param = mode ? 0x56 : 0xf6;
- if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != (mode ? 0xa9 : 0x09))
+ if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != (mode ? 0x56 : 0xf6))
return -1;
param = mode ? 0xa4 : 0xa5;
- if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == (mode ? 0x5b : 0x5a))
+ if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param == (mode ? 0xa4 : 0xa5))
return -1;
if (mux_version)
- *mux_version = ~param;
+ *mux_version = param;
return 0;
}
@@ -619,7 +623,7 @@ static int __init i8042_check_aux(void)
*/
param = 0x5a;
- if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0xa5) {
+ if (i8042_command(&param, I8042_CMD_AUX_LOOP) || param != 0x5a) {
/*
* External connection test - filters out AT-soldered PS/2 i8042's
@@ -630,7 +634,7 @@ static int __init i8042_check_aux(void)
*/
if (i8042_command(&param, I8042_CMD_AUX_TEST)
- || (param && param != 0xfa && param != 0xff))
+ || (param && param != 0xfa && param != 0xff))
return -1;
}
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index c978657068c..d4c990f7c85 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ps2_init);
EXPORT_SYMBOL(ps2_sendbyte);
+EXPORT_SYMBOL(ps2_drain);
EXPORT_SYMBOL(ps2_command);
EXPORT_SYMBOL(ps2_schedule_command);
EXPORT_SYMBOL(ps2_handle_ack);
@@ -45,11 +46,11 @@ struct ps2work {
/*
- * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge.
- * It doesn't handle retransmission, though it could - because when there would
- * be need for retransmissions, the mouse has to be replaced anyway.
+ * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
+ * It doesn't handle retransmission, though it could - because if there
+ * is a need for retransmissions device has to be replaced anyway.
*
- * ps2_sendbyte() can only be called from a process context
+ * ps2_sendbyte() can only be called from a process context.
*/
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
@@ -72,6 +73,91 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
}
/*
+ * ps2_drain() waits for device to transmit requested number of bytes
+ * and discards them.
+ */
+
+void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
+{
+ if (maxbytes > sizeof(ps2dev->cmdbuf)) {
+ WARN_ON(1);
+ maxbytes = sizeof(ps2dev->cmdbuf);
+ }
+
+ down(&ps2dev->cmd_sem);
+
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = PS2_FLAG_CMD;
+ ps2dev->cmdcnt = maxbytes;
+ serio_continue_rx(ps2dev->serio);
+
+ wait_event_timeout(ps2dev->wait,
+ !(ps2dev->flags & PS2_FLAG_CMD),
+ msecs_to_jiffies(timeout));
+ up(&ps2dev->cmd_sem);
+}
+
+/*
+ * ps2_is_keyboard_id() checks received ID byte against the list of
+ * known keyboard IDs.
+ */
+
+static inline int ps2_is_keyboard_id(char id_byte)
+{
+ static char keyboard_ids[] = {
+ 0xab, /* Regular keyboards */
+ 0xac, /* NCD Sun keyboard */
+ 0x2b, /* Trust keyboard, translated */
+ 0x5d, /* Trust keyboard */
+ 0x60, /* NMB SGI keyboard, translated */
+ 0x47, /* NMB SGI keyboard */
+ };
+
+ return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
+}
+
+/*
+ * ps2_adjust_timeout() is called after receiving 1st byte of command
+ * response and tries to reduce remaining timeout to speed up command
+ * completion.
+ */
+
+static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
+{
+ switch (command) {
+ case PS2_CMD_RESET_BAT:
+ /*
+ * Device has sent the first response byte after
+ * reset command, reset is thus done, so we can
+ * shorten the timeout.
+ * The next byte will come soon (keyboard) or not
+ * at all (mouse).
+ */
+ if (timeout > msecs_to_jiffies(100))
+ timeout = msecs_to_jiffies(100);
+ break;
+
+ case PS2_CMD_GETID:
+ /*
+ * If device behind the port is not a keyboard there
+ * won't be 2nd byte of ID response.
+ */
+ if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = ps2dev->cmdcnt = 0;
+ serio_continue_rx(ps2dev->serio);
+ timeout = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return timeout;
+}
+
+/*
* ps2_command() sends a command and its parameters to the mouse,
* then waits for the response and puts it in the param array.
*
@@ -86,6 +172,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
int rc = -1;
int i;
+ if (receive > sizeof(ps2dev->cmdbuf)) {
+ WARN_ON(1);
+ return -1;
+ }
+
down(&ps2dev->cmd_sem);
serio_pause_rx(ps2dev->serio);
@@ -101,10 +192,9 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
* ACKing the reset command, and so it can take a long
* time before the ACK arrrives.
*/
- if (command & 0xff)
- if (ps2_sendbyte(ps2dev, command & 0xff,
- command == PS2_CMD_RESET_BAT ? 1000 : 200))
- goto out;
+ if (ps2_sendbyte(ps2dev, command & 0xff,
+ command == PS2_CMD_RESET_BAT ? 1000 : 200))
+ goto out;
for (i = 0; i < send; i++)
if (ps2_sendbyte(ps2dev, param[i], 200))
@@ -120,33 +210,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
if (ps2dev->cmdcnt && timeout > 0) {
- if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) {
- /*
- * Device has sent the first response byte
- * after a reset command, reset is thus done,
- * shorten the timeout. The next byte will come
- * soon (keyboard) or not at all (mouse).
- */
- timeout = msecs_to_jiffies(100);
- }
-
- if (command == PS2_CMD_GETID &&
- ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */
- ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */
- ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */
- ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */
- ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */
- ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */
- /*
- * Device behind the port is not a keyboard
- * so we don't need to wait for the 2nd byte
- * of ID response.
- */
- serio_pause_rx(ps2dev->serio);
- ps2dev->flags = ps2dev->cmdcnt = 0;
- serio_continue_rx(ps2dev->serio);
- }
-
+ timeout = ps2_adjust_timeout(ps2dev, command, timeout);
wait_event_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_CMD), timeout);
}
@@ -160,7 +224,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
rc = 0;
-out:
+ out:
serio_pause_rx(ps2dev->serio);
ps2dev->flags = 0;
serio_continue_rx(ps2dev->serio);
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 0beacb77ee1..edd15db1771 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -31,10 +31,9 @@
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/wait.h>
-#include <linux/completion.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
+#include <linux/kthread.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
@@ -43,6 +42,7 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_child_port);
EXPORT_SYMBOL(__serio_unregister_port_delayed);
EXPORT_SYMBOL(__serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver);
@@ -68,6 +68,37 @@ static void serio_destroy_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio);
+static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
+{
+ int retval;
+
+ down(&serio->drv_sem);
+ retval = drv->connect(serio, drv);
+ up(&serio->drv_sem);
+
+ return retval;
+}
+
+static int serio_reconnect_driver(struct serio *serio)
+{
+ int retval = -1;
+
+ down(&serio->drv_sem);
+ if (serio->drv && serio->drv->reconnect)
+ retval = serio->drv->reconnect(serio);
+ up(&serio->drv_sem);
+
+ return retval;
+}
+
+static void serio_disconnect_driver(struct serio *serio)
+{
+ down(&serio->drv_sem);
+ if (serio->drv)
+ serio->drv->disconnect(serio);
+ up(&serio->drv_sem);
+}
+
static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
{
while (ids->type || ids->proto) {
@@ -91,7 +122,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
if (serio_match_port(drv->id_table, serio)) {
serio->dev.driver = &drv->driver;
- if (drv->connect(serio, drv)) {
+ if (serio_connect_driver(serio, drv)) {
serio->dev.driver = NULL;
goto out;
}
@@ -138,8 +169,7 @@ struct serio_event {
static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */
static LIST_HEAD(serio_event_list);
static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
-static DECLARE_COMPLETION(serio_exited);
-static int serio_pid;
+static struct task_struct *serio_task;
static void serio_queue_event(void *object, struct module *owner,
enum serio_event_type event_type)
@@ -150,12 +180,12 @@ static void serio_queue_event(void *object, struct module *owner,
spin_lock_irqsave(&serio_event_lock, flags);
/*
- * Scan event list for the other events for the same serio port,
+ * Scan event list for the other events for the same serio port,
* starting with the most recent one. If event is the same we
* do not need add new one. If event is of different type we
* need to add this event and should not look further because
* we need to preseve sequence of distinct events.
- */
+ */
list_for_each_entry_reverse(event, &serio_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
@@ -337,20 +367,15 @@ static struct serio *serio_get_pending_child(struct serio *parent)
static int serio_thread(void *nothing)
{
- lock_kernel();
- daemonize("kseriod");
- allow_signal(SIGTERM);
-
do {
serio_handle_events();
- wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
- try_to_freeze(PF_FREEZE);
- } while (!signal_pending(current));
+ wait_event_interruptible(serio_wait,
+ kthread_should_stop() || !list_empty(&serio_event_list));
+ try_to_freeze();
+ } while (!kthread_should_stop());
printk(KERN_DEBUG "serio: kseriod exiting\n");
-
- unlock_kernel();
- complete_and_exit(&serio_exited, 0);
+ return 0;
}
@@ -358,31 +383,39 @@ static int serio_thread(void *nothing)
* Serio port operations
*/
-static ssize_t serio_show_description(struct device *dev, char *buf)
+static ssize_t serio_show_description(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%s\n", serio->name);
}
-static ssize_t serio_show_id_type(struct device *dev, char *buf)
+static ssize_t serio_show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct serio *serio = to_serio_port(dev);
+
+ return sprintf(buf, "serio:ty%02Xpr%02Xid%02Xex%02X\n",
+ serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
+}
+
+static ssize_t serio_show_id_type(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%02x\n", serio->id.type);
}
-static ssize_t serio_show_id_proto(struct device *dev, char *buf)
+static ssize_t serio_show_id_proto(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%02x\n", serio->id.proto);
}
-static ssize_t serio_show_id_id(struct device *dev, char *buf)
+static ssize_t serio_show_id_id(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%02x\n", serio->id.id);
}
-static ssize_t serio_show_id_extra(struct device *dev, char *buf)
+static ssize_t serio_show_id_extra(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%02x\n", serio->id.extra);
@@ -406,7 +439,7 @@ static struct attribute_group serio_id_attr_group = {
.attrs = serio_device_id_attrs,
};
-static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count)
+static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct serio *serio = to_serio_port(dev);
struct device_driver *drv;
@@ -437,13 +470,13 @@ static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t c
return retval;
}
-static ssize_t serio_show_bind_mode(struct device *dev, char *buf)
+static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf)
{
struct serio *serio = to_serio_port(dev);
return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto");
}
-static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t count)
+static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct serio *serio = to_serio_port(dev);
int retval;
@@ -462,6 +495,7 @@ static ssize_t serio_set_bind_mode(struct device *dev, const char *buf, size_t c
static struct device_attribute serio_device_attrs[] = {
__ATTR(description, S_IRUGO, serio_show_description, NULL),
+ __ATTR(modalias, S_IRUGO, serio_show_modalias, NULL),
__ATTR(drvctl, S_IWUSR, NULL, serio_rebind_driver),
__ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode),
__ATTR_NULL
@@ -557,7 +591,7 @@ static void serio_destroy_port(struct serio *serio)
static void serio_reconnect_port(struct serio *serio)
{
do {
- if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+ if (serio_reconnect_driver(serio)) {
serio_disconnect_port(serio);
serio_find_driver(serio);
/* Ok, old children are now gone, we are done */
@@ -630,6 +664,19 @@ void serio_unregister_port(struct serio *serio)
}
/*
+ * Safely unregisters child port if one is present.
+ */
+void serio_unregister_child_port(struct serio *serio)
+{
+ down(&serio_sem);
+ if (serio->child) {
+ serio_disconnect_port(serio->child);
+ serio_destroy_port(serio->child);
+ }
+ up(&serio_sem);
+}
+
+/*
* Submits register request to kseriod for subsequent execution.
* Can be used when it is not obvious whether the serio_sem is
* taken or not and when delayed execution is feasible.
@@ -686,15 +733,14 @@ static int serio_driver_probe(struct device *dev)
struct serio *serio = to_serio_port(dev);
struct serio_driver *drv = to_serio_driver(dev->driver);
- return drv->connect(serio, drv);
+ return serio_connect_driver(serio, drv);
}
static int serio_driver_remove(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- struct serio_driver *drv = to_serio_driver(dev->driver);
- drv->disconnect(serio);
+ serio_disconnect_driver(serio);
return 0;
}
@@ -730,11 +776,9 @@ start_over:
static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
{
- down(&serio->drv_sem);
serio_pause_rx(serio);
serio->drv = drv;
serio_continue_rx(serio);
- up(&serio->drv_sem);
}
static int serio_bus_match(struct device *dev, struct device_driver *drv)
@@ -750,36 +794,37 @@ static int serio_bus_match(struct device *dev, struct device_driver *drv)
#ifdef CONFIG_HOTPLUG
-#define PUT_ENVP(fmt, val) \
-do { \
- envp[i++] = buffer; \
- length += snprintf(buffer, buffer_size - length, fmt, val); \
- if (buffer_size - length <= 0 || i >= num_envp) \
- return -ENOMEM; \
- length++; \
- buffer += length; \
-} while (0)
+#define SERIO_ADD_HOTPLUG_VAR(fmt, val...) \
+ do { \
+ int err = add_hotplug_env_var(envp, num_envp, &i, \
+ buffer, buffer_size, &len, \
+ fmt, val); \
+ if (err) \
+ return err; \
+ } while (0)
+
static int serio_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
{
struct serio *serio;
int i = 0;
- int length = 0;
+ int len = 0;
if (!dev)
return -ENODEV;
serio = to_serio_port(dev);
- PUT_ENVP("SERIO_TYPE=%02x", serio->id.type);
- PUT_ENVP("SERIO_PROTO=%02x", serio->id.proto);
- PUT_ENVP("SERIO_ID=%02x", serio->id.id);
- PUT_ENVP("SERIO_EXTRA=%02x", serio->id.extra);
-
+ SERIO_ADD_HOTPLUG_VAR("SERIO_TYPE=%02x", serio->id.type);
+ SERIO_ADD_HOTPLUG_VAR("SERIO_PROTO=%02x", serio->id.proto);
+ SERIO_ADD_HOTPLUG_VAR("SERIO_ID=%02x", serio->id.id);
+ SERIO_ADD_HOTPLUG_VAR("SERIO_EXTRA=%02x", serio->id.extra);
+ SERIO_ADD_HOTPLUG_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
+ serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
envp[i] = NULL;
return 0;
}
-#undef PUT_ENVP
+#undef SERIO_ADD_HOTPLUG_VAR
#else
@@ -794,7 +839,7 @@ static int serio_resume(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+ if (serio_reconnect_driver(serio)) {
/*
* Driver re-probing can take a while, so better let kseriod
* deal with it.
@@ -848,9 +893,10 @@ irqreturn_t serio_interrupt(struct serio *serio,
static int __init serio_init(void)
{
- if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) {
+ serio_task = kthread_run(serio_thread, NULL, "kseriod");
+ if (IS_ERR(serio_task)) {
printk(KERN_ERR "serio: Failed to start kseriod\n");
- return -1;
+ return PTR_ERR(serio_task);
}
serio_bus.dev_attrs = serio_device_attrs;
@@ -866,8 +912,7 @@ static int __init serio_init(void)
static void __exit serio_exit(void)
{
bus_unregister(&serio_bus);
- kill_proc(serio_pid, SIGTERM, 1);
- wait_for_completion(&serio_exited);
+ kthread_stop(serio_task);
}
module_init(serio_init);
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index d914e7e93db..47e08de18d0 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -299,6 +299,7 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
serio_raw->dev.minor = PSMOUSE_MINOR;
serio_raw->dev.name = serio_raw->name;
+ serio_raw->dev.dev = &serio->dev;
serio_raw->dev.fops = &serio_raw_fops;
err = misc_register(&serio_raw->dev);
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index f6b85222ba3..79ca3846915 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -257,7 +257,7 @@ static int __init serport_init(void)
static void __exit serport_exit(void)
{
- tty_register_ldisc(N_MOUSE, NULL);
+ tty_unregister_ldisc(N_MOUSE);
}
module_init(serport_init);