From a87191add6c0c7509e4bf353635fc592d9143fe2 Mon Sep 17 00:00:00 2001 From: Adam Kropelin Date: Wed, 19 May 2004 04:13:58 +0200 Subject: input: Add 64-bit compatible ioctls for hiddev. --- drivers/usb/input/hiddev.c | 2 +- fs/compat_ioctl.c | 2 ++ include/linux/compat_ioctl.h | 17 +++++++++++++++++ include/linux/hiddev.h | 8 +++++++- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index b3f06af2c852..f649444a924c 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -642,7 +642,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd goto inval; if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (uref_multi->num_values >= HID_MAX_USAGES || + if (uref_multi->num_values >= HID_MAX_MULTI_USAGES || uref->usage_index >= field->maxusage || (uref->usage_index + uref_multi->num_values) >= field->maxusage) goto inval; diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 56ef9138e9cc..110d8f8b3088 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -114,6 +114,8 @@ #include #include +#include + #undef INCLUDES #endif diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h index 72787d3af70d..ff8d6778cb22 100644 --- a/include/linux/compat_ioctl.h +++ b/include/linux/compat_ioctl.h @@ -720,3 +720,20 @@ COMPATIBLE_IOCTL(SIOCSIWRETRY) COMPATIBLE_IOCTL(SIOCGIWRETRY) COMPATIBLE_IOCTL(SIOCSIWPOWER) COMPATIBLE_IOCTL(SIOCGIWPOWER) +/* hiddev */ +COMPATIBLE_IOCTL(HIDIOCGVERSION) +COMPATIBLE_IOCTL(HIDIOCAPPLICATION) +COMPATIBLE_IOCTL(HIDIOCGDEVINFO) +COMPATIBLE_IOCTL(HIDIOCGSTRING) +COMPATIBLE_IOCTL(HIDIOCINITREPORT) +COMPATIBLE_IOCTL(HIDIOCGREPORT) +COMPATIBLE_IOCTL(HIDIOCSREPORT) +COMPATIBLE_IOCTL(HIDIOCGREPORTINFO) +COMPATIBLE_IOCTL(HIDIOCGFIELDINFO) +COMPATIBLE_IOCTL(HIDIOCGUSAGE) +COMPATIBLE_IOCTL(HIDIOCSUSAGE) +COMPATIBLE_IOCTL(HIDIOCGUCODE) +COMPATIBLE_IOCTL(HIDIOCGFLAG) +COMPATIBLE_IOCTL(HIDIOCSFLAG) +COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINDEX) +COMPATIBLE_IOCTL(HIDIOCGCOLLECTIONINFO) diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h index 75c1fa0d2189..2065224aaf62 100644 --- a/include/linux/hiddev.h +++ b/include/linux/hiddev.h @@ -128,10 +128,11 @@ struct hiddev_usage_ref { /* hiddev_usage_ref_multi is used for sending multiple bytes to a control. * It really manifests itself as setting the value of consecutive usages */ +#define HID_MAX_MULTI_USAGES 1024 struct hiddev_usage_ref_multi { struct hiddev_usage_ref uref; __u32 num_values; - __s32 values[HID_MAX_USAGES]; + __s32 values[HID_MAX_MULTI_USAGES]; }; /* FIELD_INDEX_NONE is returned in read() data from the kernel when flags @@ -213,6 +214,11 @@ struct hiddev_usage_ref_multi { */ #ifdef CONFIG_USB_HIDDEV +struct hid_device; +struct hid_usage; +struct hid_field; +struct hid_report; + int hiddev_connect(struct hid_device *); void hiddev_disconnect(struct hid_device *); void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, -- cgit v1.2.3 From 01cb4053d08e10d2b75053148a88fd5135f928c2 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Fri, 28 May 2004 20:19:29 +0200 Subject: Cset exclude: dtor_core@ameritech.net|ChangeSet|20040510063935|25419 --- drivers/input/serio/i8042.c | 141 +++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 92 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index e92157cfd608..e9d8dabd1da7 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -2,7 +2,6 @@ * i8042 keyboard and mouse controller driver for Linux * * Copyright (c) 1999-2002 Vojtech Pavlik - * Copyright (c) 2004 Dmitry Torokhov */ /* @@ -75,14 +74,6 @@ struct i8042_values { unsigned char *phys; }; -#define I8042_QUEUE_LEN 64 -struct { - unsigned char str[I8042_QUEUE_LEN]; - unsigned char data[I8042_QUEUE_LEN]; - unsigned int read_pos; - unsigned int write_pos; -} i8042_buf; - static struct serio i8042_kbd_port; static struct serio i8042_aux_port; static unsigned char i8042_initial_ctr; @@ -91,7 +82,7 @@ static unsigned char i8042_mux_open; static unsigned char i8042_mux_present; static unsigned char i8042_sysdev_initialized; static struct pm_dev *i8042_pm_dev; -static struct timer_list i8042_timer; +struct timer_list i8042_timer; /* * Shared IRQ's require a device pointer, but this driver doesn't support @@ -383,108 +374,76 @@ static char i8042_mux_short[4][16]; static char i8042_mux_phys[4][32]; /* - * i8042_handle_data() is the most important function in this driver - - * it processes data received by i8042_interrupt and sends it to the - * upper layers. + * i8042_interrupt() is the most important function in this driver - + * it handles the interrupts from the i8042, and sends incoming bytes + * to the upper layers. */ -static void i8042_handle_data(unsigned long notused) +static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; unsigned char str, data = 0; unsigned int dfl; + int ret; - /* - * No locking it required on i8042_buf as the tasklet is guaranteed - * to be serialized and if write_pos changes while comparing it with - * read_pos another run will be scheduled by i8042_interrupt. - */ - while (i8042_buf.read_pos != i8042_buf.write_pos) { - - str = i8042_buf.str[i8042_buf.read_pos]; - data = i8042_buf.data[i8042_buf.read_pos]; - - i8042_buf.read_pos++; - i8042_buf.read_pos %= I8042_QUEUE_LEN; - - dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | - ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); - - if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) { - - if (str & I8042_STR_MUXERR) { - switch (data) { - case 0xfd: - case 0xfe: dfl = SERIO_TIMEOUT; break; - case 0xff: dfl = SERIO_PARITY; break; - } - data = 0xfe; - } else dfl = 0; - - dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)", - data, (str >> 6), irq, - dfl & SERIO_PARITY ? ", bad parity" : "", - dfl & SERIO_TIMEOUT ? ", timeout" : ""); - - serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, NULL); - } else { + mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); - dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", - data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, - dfl & SERIO_PARITY ? ", bad parity" : "", - dfl & SERIO_TIMEOUT ? ", timeout" : ""); + spin_lock_irqsave(&i8042_lock, flags); + str = i8042_read_status(); + if (str & I8042_STR_OBF) + data = i8042_read_data(); + spin_unlock_irqrestore(&i8042_lock, flags); - if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) - serio_interrupt(&i8042_aux_port, data, dfl, NULL); - else if (i8042_kbd_values.exists) - serio_interrupt(&i8042_kbd_port, data, dfl, NULL); - } + if (~str & I8042_STR_OBF) { + if (irq) dbg("Interrupt %d, without any data", irq); + ret = 0; + goto out; } -} - -DECLARE_TASKLET(i8042_tasklet, i8042_handle_data, 0); - -/* - * i8042_interrupt() handles the interrupts from i8042 and schedules - * i8042_handle_data to process and pass received bytes to the upper - * layers. - */ - -static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - unsigned char str; - unsigned int n_bytes = 0; - mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); - - spin_lock_irqsave(&i8042_lock, flags); + dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | + ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); - while ((str = i8042_read_status()) & I8042_STR_OBF) { + if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) { - n_bytes++; + if (str & I8042_STR_MUXERR) { + switch (data) { + case 0xfd: + case 0xfe: dfl = SERIO_TIMEOUT; break; + case 0xff: dfl = SERIO_PARITY; break; + } + data = 0xfe; + } else dfl = 0; - i8042_buf.str[i8042_buf.write_pos] = str; - i8042_buf.data[i8042_buf.write_pos] = i8042_read_data(); + dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)", + data, (str >> 6), irq, + dfl & SERIO_PARITY ? ", bad parity" : "", + dfl & SERIO_TIMEOUT ? ", timeout" : ""); - i8042_buf.write_pos++; - i8042_buf.write_pos %= I8042_QUEUE_LEN; + serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs); - if (unlikely(i8042_buf.write_pos == i8042_buf.read_pos)) - printk(KERN_WARNING "i8042.c: ring buffer full\n"); + goto irq_ret; } - spin_unlock_irqrestore(&i8042_lock, flags); + dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", + data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, + dfl & SERIO_PARITY ? ", bad parity" : "", + dfl & SERIO_TIMEOUT ? ", timeout" : ""); - if (unlikely(n_bytes == 0)) { - if (irq) dbg("Interrupt %d, without any data", irq); - return IRQ_NONE; + if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { + serio_interrupt(&i8042_aux_port, data, dfl, regs); + goto irq_ret; } - tasklet_schedule(&i8042_tasklet); + if (!i8042_kbd_values.exists) + goto irq_ret; - return IRQ_HANDLED; -} + serio_interrupt(&i8042_kbd_port, data, dfl, regs); +irq_ret: + ret = 1; +out: + return IRQ_RETVAL(ret); +} /* * i8042_enable_mux_mode checks whether the controller has an active @@ -1058,9 +1017,7 @@ void __exit i8042_exit(void) for (i = 0; i < 4; i++) if (i8042_mux_values[i].exists) serio_unregister_port(i8042_mux_port + i); - del_timer_sync(&i8042_timer); - tasklet_kill(&i8042_tasklet); i8042_platform_exit(); } -- cgit v1.2.3 From 29af30fb4b0f0308f3c6d7ff088f264ffc6e5b4b Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Fri, 28 May 2004 22:24:08 +0200 Subject: input: An attempt at fixing locking in i8042.c and serio.c --- drivers/input/serio/i8042.c | 4 +++ drivers/input/serio/serio.c | 64 ++++++++++++++++++++++++++++++++++++++------- include/linux/serio.h | 2 +- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index e9d8dabd1da7..758c0e8acd64 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -95,6 +95,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs); /* * The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to * be ready for reading values from it / writing values to it. + * Called always with i8042_lock held. */ static int i8042_wait_read(void) @@ -677,6 +678,7 @@ static void i8042_timer_func(unsigned long data) static int i8042_controller_init(void) { + unsigned long flags; /* * Test the i8042. We need to know if it thinks it's working correctly @@ -723,12 +725,14 @@ static int i8042_controller_init(void) * Handle keylock. */ + spin_lock_irqsave(&i8042_lock, flags); if (~i8042_read_status() & I8042_STR_KEYLOCK) { if (i8042_unlock) i8042_ctr |= I8042_CTR_IGNKEYLOCK; else printk(KERN_WARNING "i8042.c: Warning: Keylock active.\n"); } + spin_unlock_irqrestore(&i8042_lock, flags); /* * If the chip is configured into nontranslated mode by the BIOS, don't diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 6f003197b62c..3414e0bc3cf1 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -67,12 +67,18 @@ struct serio_event { struct list_head node; }; -static DECLARE_MUTEX(serio_sem); + +spinlock_t serio_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list and serio->dev */ +static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_dev_list */ static LIST_HEAD(serio_list); static LIST_HEAD(serio_dev_list); static LIST_HEAD(serio_event_list); static int serio_pid; +/* + * serio_find_dev() must be called with serio_sem down. + */ + static void serio_find_dev(struct serio *serio) { struct serio_dev *dev; @@ -96,22 +102,42 @@ static DECLARE_COMPLETION(serio_exited); static void serio_invalidate_pending_events(struct serio *serio) { struct serio_event *event; + unsigned long flags; + + spin_lock_irqsave(&serio_lock, flags); list_for_each_entry(event, &serio_event_list, node) if (event->serio == serio) event->serio = NULL; + + spin_unlock_irqrestore(&serio_lock, flags); } void serio_handle_events(void) { - struct list_head *node, *next; + struct list_head *node; struct serio_event *event; + unsigned long flags; + + + while (1) { + + spin_lock_irqsave(&serio_lock, flags); + + if (list_empty(&serio_event_list)) { + spin_unlock_irqrestore(&serio_lock, flags); + break; + } - list_for_each_safe(node, next, &serio_event_list) { + node = serio_event_list.next; event = container_of(node, struct serio_event, node); + list_del_init(node); + + spin_unlock_irqrestore(&serio_lock, flags); down(&serio_sem); - if (event->serio == NULL) + + if (event->serio == NULL) /*!!!*/ goto event_done; switch (event->type) { @@ -139,7 +165,6 @@ void serio_handle_events(void) } event_done: up(&serio_sem); - list_del_init(node); kfree(event); } } @@ -178,12 +203,18 @@ static void serio_queue_event(struct serio *serio, int event_type) void serio_rescan(struct serio *serio) { + unsigned long flags; + spin_lock_irqsave(&serio_lock, flags); serio_queue_event(serio, SERIO_RESCAN); + spin_unlock_irqrestore(&serio_lock, flags); } void serio_reconnect(struct serio *serio) { + unsigned long flags; + spin_lock_irqsave(&serio_lock, flags); serio_queue_event(serio, SERIO_RECONNECT); + spin_unlock_irqrestore(&serio_lock, flags); } irqreturn_t serio_interrupt(struct serio *serio, @@ -191,17 +222,22 @@ irqreturn_t serio_interrupt(struct serio *serio, { irqreturn_t ret = IRQ_NONE; + spin_lock_irq(&serio_lock); + if (serio->dev && serio->dev->interrupt) { ret = serio->dev->interrupt(serio, data, flags, regs); } else { if (!flags) { - if ((serio->type == SERIO_8042 || - serio->type == SERIO_8042_XL) && (data != 0xaa)) - return ret; - serio_rescan(serio); - ret = IRQ_HANDLED; + if ((serio->type != SERIO_8042 && + serio->type != SERIO_8042_XL) || (data == 0xaa)) { + serio_queue_event(serio, SERIO_RESCAN); + ret = IRQ_HANDLED; + } } } + + spin_unlock_irq(&serio_lock); + return ret; } @@ -292,7 +328,11 @@ void serio_unregister_device(struct serio_dev *dev) /* called from serio_dev->connect/disconnect methods under serio_sem */ int serio_open(struct serio *serio, struct serio_dev *dev) { + unsigned long flags; + + spin_lock_irqsave(&serio_lock, flags); serio->dev = dev; + spin_unlock_irqrestore(&serio_lock, flags); if (serio->open && serio->open(serio)) { serio->dev = NULL; return -1; @@ -303,9 +343,13 @@ int serio_open(struct serio *serio, struct serio_dev *dev) /* called from serio_dev->connect/disconnect methods under serio_sem */ void serio_close(struct serio *serio) { + unsigned long flags; + if (serio->close) serio->close(serio); + spin_lock_irqsave(&serio_lock, flags); serio->dev = NULL; + spin_unlock_irqrestore(&serio_lock, flags); } static int __init serio_init(void) diff --git a/include/linux/serio.h b/include/linux/serio.h index 28f62471af10..037e9f7bc052 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -36,7 +36,7 @@ struct serio { int (*open)(struct serio *); void (*close)(struct serio *); - struct serio_dev *dev; + struct serio_dev *dev; /* Accessed from interrupt, writes must be protected by serio_lock */ struct list_head node; }; -- cgit v1.2.3 From bd5c02e5bba69ae6f1298c22f757141408036907 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sat, 29 May 2004 02:57:43 +0200 Subject: input: Fix an oops in poll() on uinput. Thanks to Dmitry Torokhov for suggesting the fix. --- drivers/input/misc/uinput.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 2e097dc66449..482472f9f09d 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -279,6 +279,9 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait) { struct uinput_device *udev = file->private_data; + if (!test_bit(UIST_CREATED, &(udev->state))) + return -ENODEV; + poll_wait(file, &udev->waitq, wait); if (udev->head != udev->tail) -- cgit v1.2.3 From 7d2a5db98c9398e2d184bbf7a20ec3abb4c409a7 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sun, 30 May 2004 20:57:22 +0200 Subject: input: Make atomicity and exclusive access to variables explicit in atkbd.c, using bitops. Signed-off-by: Vojtech Pavlik --- drivers/input/keyboard/atkbd.c | 131 +++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 43 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 026fc13ead0b..9077df06168d 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -164,34 +164,48 @@ static unsigned char atkbd_scroll_keys[5][2] = { { ATKBD_SCR_CLICK, 0x60 }, }; +#define ATKBD_FLAG_ACK 0 /* Waiting for ACK/NAK */ +#define ATKBD_FLAG_CMD 1 /* Waiting for command to finish */ +#define ATKBD_FLAG_CMD1 2 /* First byte of command response */ +#define ATKBD_FLAG_ID 3 /* First byte is not keyboard ID */ +#define ATKBD_FLAG_ENABLED 4 /* Waining for init to finish */ + /* * The atkbd control structure */ struct atkbd { - unsigned char keycode[512]; - struct input_dev dev; - struct serio *serio; + /* Written only during init */ char name[64]; char phys[32]; - unsigned short id; + struct serio *serio; + struct input_dev dev; + unsigned char set; - unsigned int translated:1; - unsigned int extra:1; - unsigned int write:1; + unsigned short id; + unsigned char keycode[512]; + unsigned char translated; + unsigned char extra; + unsigned char write; + + /* Protected by FLAG_ACK */ + unsigned char nak; + /* Protected by FLAG_CMD */ unsigned char cmdbuf[4]; unsigned char cmdcnt; - volatile signed char ack; - unsigned char emul; - unsigned int resend:1; - unsigned int release:1; - unsigned int bat_xl:1; - unsigned int enabled:1; + /* Accessed only from interrupt */ + unsigned char emul; + unsigned char resend; + unsigned char release; + unsigned char bat_xl; unsigned int last; unsigned long time; + + /* Flags */ + unsigned long flags; }; static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) @@ -224,7 +238,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, #if !defined(__i386__) && !defined (__x86_64__) if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { - printk("atkbd.c: frame/parity error: %02x\n", flags); + printk(KERN_WARNING "atkbd.c: frame/parity error: %02x\n", flags); serio_write(serio, ATKBD_CMD_RESEND); atkbd->resend = 1; goto out; @@ -234,22 +248,36 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, atkbd->resend = 0; #endif - if (!atkbd->ack) + if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags)) switch (code) { case ATKBD_RET_ACK: - atkbd->ack = 1; + atkbd->nak = 0; + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); goto out; case ATKBD_RET_NAK: - atkbd->ack = -1; + atkbd->nak = 1; + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); goto out; } - if (atkbd->cmdcnt) { - atkbd->cmdbuf[--atkbd->cmdcnt] = code; + if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) { + + atkbd->cmdcnt--; + atkbd->cmdbuf[atkbd->cmdcnt] = code; + + if (atkbd->cmdcnt == 1) { + if (code != 0xab && code != 0xac) + clear_bit(ATKBD_FLAG_ID, &atkbd->flags); + clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + } + + if (!atkbd->cmdcnt) + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + goto out; } - if (!atkbd->enabled) + if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags)) goto out; if (atkbd->translated) { @@ -270,6 +298,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, switch (code) { case ATKBD_RET_BAT: + clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); serio_rescan(atkbd->serio); goto out; case ATKBD_RET_EMUL0: @@ -376,18 +405,19 @@ out: static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) { - int timeout = 20000; /* 200 msec */ - atkbd->ack = 0; + int timeout = 200000; /* 200 msec */ #ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte); #endif + + set_bit(ATKBD_FLAG_ACK, &atkbd->flags); if (serio_write(atkbd->serio, byte)) return -1; + while (test_bit(ATKBD_FLAG_ACK, &atkbd->flags) && timeout--) udelay(1); + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); - while (!atkbd->ack && timeout--) udelay(10); - - return -(atkbd->ack <= 0); + return -atkbd->nak; } /* @@ -411,40 +441,52 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) for (i = 0; i < receive; i++) atkbd->cmdbuf[(receive - 1) - i] = param[i]; + if (receive) { + set_bit(ATKBD_FLAG_CMD, &atkbd->flags); + set_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + set_bit(ATKBD_FLAG_ID, &atkbd->flags); + } + if (command & 0xff) - if (atkbd_sendbyte(atkbd, command & 0xff)) - return (atkbd->cmdcnt = 0) - 1; + if (atkbd_sendbyte(atkbd, command & 0xff)) { + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + return -1; + } for (i = 0; i < send; i++) - if (atkbd_sendbyte(atkbd, param[i])) - return (atkbd->cmdcnt = 0) - 1; + if (atkbd_sendbyte(atkbd, param[i])) { + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + return -1; + } - while (atkbd->cmdcnt && timeout--) { + while (test_bit(ATKBD_FLAG_CMD, &atkbd->flags) && timeout--) { - if (atkbd->cmdcnt == 1 && - command == ATKBD_CMD_RESET_BAT && timeout > 100000) - timeout = 100000; + if (!test_bit(ATKBD_FLAG_CMD1, &atkbd->flags)) { + + if (command == ATKBD_CMD_RESET_BAT && timeout > 100000) + timeout = 100000; - if (atkbd->cmdcnt == 1 && command == ATKBD_CMD_GETID && - atkbd->cmdbuf[1] != 0xab && atkbd->cmdbuf[1] != 0xac) { - atkbd->cmdcnt = 0; - break; + if (command == ATKBD_CMD_GETID && !test_bit(ATKBD_FLAG_ID, &atkbd->flags)) { + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + atkbd->cmdcnt = 0; + break; + } } udelay(1); } + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + if (param) for (i = 0; i < receive; i++) param[i] = atkbd->cmdbuf[(receive - 1) - i]; if (command == ATKBD_CMD_RESET_BAT && atkbd->cmdcnt == 1) - atkbd->cmdcnt = 0; + return 0; - if (atkbd->cmdcnt) { - atkbd->cmdcnt = 0; + if (atkbd->cmdcnt) return -1; - } return 0; } @@ -672,6 +714,7 @@ static void atkbd_cleanup(struct serio *serio) static void atkbd_disconnect(struct serio *serio) { struct atkbd *atkbd = serio->private; + clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); input_unregister_device(&atkbd->dev); serio_close(serio); kfree(atkbd); @@ -719,7 +762,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) atkbd->dev.rep[REP_PERIOD] = 33; } - atkbd->ack = 1; atkbd->serio = serio; init_input_dev(&atkbd->dev); @@ -754,7 +796,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) atkbd->id = 0xab00; } - atkbd->enabled = 1; if (atkbd->extra) { atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); @@ -797,6 +838,8 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) input_register_device(&atkbd->dev); + set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys); } @@ -832,6 +875,8 @@ static int atkbd_reconnect(struct serio *serio) return -1; } + set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + return 0; } -- cgit v1.2.3 From 34a39d46671ea7bb261ec138168e25ef6c794125 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Mon, 31 May 2004 16:27:40 +0200 Subject: input: Return 0 from uinput poll if device isn't yet created. Signed-off-by: Vojtech Pavlik --- drivers/input/misc/uinput.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 482472f9f09d..f90fdbe51702 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -280,7 +280,7 @@ static unsigned int uinput_poll(struct file *file, poll_table *wait) struct uinput_device *udev = file->private_data; if (!test_bit(UIST_CREATED, &(udev->state))) - return -ENODEV; + return 0; poll_wait(file, &udev->waitq, wait); -- cgit v1.2.3 From 77606ab3b3ff99b557f9e75ba3976a4ebf5f4df8 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Mon, 31 May 2004 19:11:41 +0200 Subject: input: Explicit variable access rules for psmouse.c, using bitops. --- drivers/input/keyboard/atkbd.c | 2 +- drivers/input/mouse/psmouse-base.c | 127 +++++++++++++++++++++++-------------- drivers/input/mouse/psmouse.h | 9 ++- 3 files changed, 86 insertions(+), 52 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 9077df06168d..b4960be7661b 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -435,7 +435,7 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) atkbd->cmdcnt = receive; if (command == ATKBD_CMD_RESET_BAT) - timeout = 2000000; /* 2 sec */ + timeout = 4000000; /* 4 sec */ if (receive && param) for (i = 0; i < receive; i++) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 0b382672407b..4d85232f7d8a 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -142,34 +142,45 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n", flags & SERIO_TIMEOUT ? " timeout" : "", flags & SERIO_PARITY ? " bad parity" : ""); - if (psmouse->acking) { - psmouse->ack = -1; - psmouse->acking = 0; - } - psmouse->pktcnt = 0; + psmouse->nak = 1; + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); goto out; } - if (psmouse->acking) { + if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) switch (data) { case PSMOUSE_RET_ACK: - psmouse->ack = 1; + psmouse->nak = 0; + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + goto out; break; case PSMOUSE_RET_NAK: - psmouse->ack = -1; - break; + psmouse->nak = 1; + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + goto out; default: - psmouse->ack = 1; /* Workaround for mice which don't ACK the Get ID command */ - if (psmouse->cmdcnt) - psmouse->cmdbuf[--psmouse->cmdcnt] = data; - break; + psmouse->nak = 0; /* Workaround for mice which don't ACK the Get ID command */ + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + if (!test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) + goto out; + } - psmouse->acking = 0; - goto out; - } - if (psmouse->cmdcnt) { - psmouse->cmdbuf[--psmouse->cmdcnt] = data; + if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) { + + psmouse->cmdcnt--; + psmouse->cmdbuf[psmouse->cmdcnt] = data; + + if (psmouse->cmdcnt == 1) { + if (data != 0xab && data != 0xac) + clear_bit(PSMOUSE_FLAG_ID, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); + } + + if (!psmouse->cmdcnt) + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + goto out; } @@ -242,18 +253,15 @@ out: static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte) { - int timeout = 10000; /* 100 msec */ - psmouse->ack = 0; - psmouse->acking = 1; + int timeout = 200000; /* 200 msec */ - if (serio_write(psmouse->serio, byte)) { - psmouse->acking = 0; + set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + if (serio_write(psmouse->serio, byte)) return -1; - } - - while (!psmouse->ack && timeout--) udelay(10); + while (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags) && timeout--) udelay(1); + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); - return -(psmouse->ack <= 0); + return -psmouse->nak; } /* @@ -271,46 +279,62 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) psmouse->cmdcnt = receive; if (command == PSMOUSE_CMD_RESET_BAT) - timeout = 4000000; /* 4 sec */ + timeout = 4000000; /* 4 sec */ - /* initialize cmdbuf with preset values from param */ - if (receive) - for (i = 0; i < receive; i++) - psmouse->cmdbuf[(receive - 1) - i] = param[i]; + if (receive && param) + for (i = 0; i < receive; i++) + psmouse->cmdbuf[(receive - 1) - i] = param[i]; + + if (receive) { + set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); + set_bit(PSMOUSE_FLAG_ID, &psmouse->flags); + } if (command & 0xff) - if (psmouse_sendbyte(psmouse, command & 0xff)) - return (psmouse->cmdcnt = 0) - 1; + if (psmouse_sendbyte(psmouse, command & 0xff)) { + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + return -1; + } for (i = 0; i < send; i++) - if (psmouse_sendbyte(psmouse, param[i])) - return (psmouse->cmdcnt = 0) - 1; + if (psmouse_sendbyte(psmouse, param[i])) { + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + return -1; + } - while (psmouse->cmdcnt && timeout--) { + while (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags) && timeout--) { - if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_RESET_BAT && - timeout > 100000) /* do not run in a endless loop */ - timeout = 100000; /* 1 sec */ + if (!test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags)) { + + if (command == PSMOUSE_CMD_RESET_BAT && timeout > 100000) + timeout = 100000; - if (psmouse->cmdcnt == 1 && command == PSMOUSE_CMD_GETID && - psmouse->cmdbuf[1] != 0xab && psmouse->cmdbuf[1] != 0xac) { - psmouse->cmdcnt = 0; - break; + if (command == PSMOUSE_CMD_GETID && !test_bit(PSMOUSE_FLAG_ID, &psmouse->flags)) { + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + psmouse->cmdcnt = 0; + break; + } } udelay(1); } - for (i = 0; i < receive; i++) - param[i] = psmouse->cmdbuf[(receive - 1) - i]; + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + + if (param) + for (i = 0; i < receive; i++) + param[i] = psmouse->cmdbuf[(receive - 1) - i]; + + if (command == PSMOUSE_CMD_RESET_BAT && psmouse->cmdcnt == 1) + return 0; if (psmouse->cmdcnt) - return (psmouse->cmdcnt = 0) - 1; + return -1; return 0; } - /* * psmouse_sliced_command() sends an extended PS/2 command to the mouse * using sliced syntax, understood by advanced devices, such as Logitech @@ -735,7 +759,12 @@ static int psmouse_reconnect(struct serio *serio) } psmouse->state = PSMOUSE_CMD_MODE; - psmouse->acking = psmouse->cmdcnt = psmouse->pktcnt = psmouse->out_of_sync = 0; + + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + + psmouse->pktcnt = psmouse->out_of_sync = 0; + if (psmouse->reconnect) { if (psmouse->reconnect(psmouse)) return -1; diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 47fbc48f66e5..09095ea6fa3b 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -22,6 +22,11 @@ #define PSMOUSE_ACTIVATED 1 #define PSMOUSE_IGNORE 2 +#define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */ +#define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */ +#define PSMOUSE_FLAG_CMD1 2 /* First byte of command response */ +#define PSMOUSE_FLAG_ID 3 /* First byte is not keyboard ID */ + /* psmouse protocol handler return codes */ typedef enum { PSMOUSE_BAD_DATA, @@ -54,11 +59,11 @@ struct psmouse { unsigned long last; unsigned long out_of_sync; unsigned char state; - char acking; - volatile char ack; + unsigned char nak; char error; char devname[64]; char phys[32]; + unsigned long flags; psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); int (*reconnect)(struct psmouse *psmouse); -- cgit v1.2.3 From d8c514cfa12b180f41bae49374a4de7e894287a7 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Mon, 31 May 2004 19:49:05 +0200 Subject: input: Add reporting of raw scancodes to atkbd.c Signed-off-by: Vojtech Pavlik --- drivers/input/keyboard/atkbd.c | 8 +++++--- include/linux/input.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index b4960be7661b..d5a63adf0343 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -280,6 +280,8 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags)) goto out; + input_event(&atkbd->dev, EV_MSC, MSC_RAW, code); + if (atkbd->translated) { if (atkbd->emul || @@ -753,9 +755,10 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) } if (atkbd->write) { - atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP) | BIT(EV_MSC); atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); - } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); + atkbd->dev.mscbit[0] = BIT(MSC_RAW); if (!atkbd_softrepeat) { atkbd->dev.rep[REP_DELAY] = 250; @@ -796,7 +799,6 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) atkbd->id = 0xab00; } - if (atkbd->extra) { atkbd->dev.ledbit[0] |= BIT(LED_COMPOSE) | BIT(LED_SUSPEND) | BIT(LED_SLEEP) | BIT(LED_MUTE) | BIT(LED_MISC); sprintf(atkbd->name, "AT Set 2 Extra keyboard"); diff --git a/include/linux/input.h b/include/linux/input.h index b7a30bb6412e..2fa58351bd4f 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -527,6 +527,7 @@ struct input_absinfo { #define MSC_SERIAL 0x00 #define MSC_PULSELED 0x01 #define MSC_GESTURE 0x02 +#define MSC_RAW 0x03 #define MSC_MAX 0x07 /* -- cgit v1.2.3 From 2f3617d6274e31d882cfe47bb31a97dad5464d54 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Mon, 31 May 2004 20:25:29 +0200 Subject: input: Use raw events generated by atkbd in keyboard.c to implement true rawmode for PS/2 keyboards. Signed-off-by: Vojtech Pavlik --- drivers/char/keyboard.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 010bff6e1449..a815b9760258 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -942,6 +942,8 @@ void kbd_refresh_leds(struct input_handle *handle) #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SH_MPC1211) +#define HW_RAW(dev) (((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) + static unsigned short x86_keycodes[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -1008,6 +1010,8 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, #else +#define HW_RAW(dev) 0 + #warning "Cannot generate rawmode keyboard for your architecture yet." static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) @@ -1020,7 +1024,15 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char u } #endif -void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) +void kbd_rawcode(unsigned char data) +{ + struct vc_data *vc = vc_cons[fg_console].d; + kbd = kbd_table + fg_console; + if (kbd->kbdmode == VC_RAW) + put_queue(vc, data); +} + +void kbd_keycode(unsigned int keycode, int down, int hw_raw, struct pt_regs *regs) { struct vc_data *vc = vc_cons[fg_console].d; unsigned short keysym, *key_map; @@ -1054,7 +1066,7 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) return; #endif /* CONFIG_MAC_EMUMOUSEBTN */ - if ((raw_mode = (kbd->kbdmode == VC_RAW))) + if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw) if (emulate_raw(vc, keycode, !down << 7)) if (keycode < BTN_MISC) printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode); @@ -1149,11 +1161,12 @@ void kbd_keycode(unsigned int keycode, int down, struct pt_regs *regs) } static void kbd_event(struct input_handle *handle, unsigned int event_type, - unsigned int keycode, int down) + unsigned int event_code, int value) { - if (event_type != EV_KEY) - return; - kbd_keycode(keycode, down, handle->dev->regs); + if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev)) + kbd_rawcode(value); + if (event_type == EV_KEY) + kbd_keycode(event_code, value, HW_RAW(handle->dev), handle->dev->regs); tasklet_schedule(&keyboard_tasklet); do_poke_blanked_console = 1; schedule_console_callback(); -- cgit v1.2.3 From 4419b97101e71f9a0021cefdcfdd90c00238f3ed Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 2 Jun 2004 02:56:24 -0500 Subject: Cset exclude: dtor_core@ameritech.net|ChangeSet|20040510063935|25419 --- drivers/input/serio/i8042.c | 141 +++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 92 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index e92157cfd608..e9d8dabd1da7 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -2,7 +2,6 @@ * i8042 keyboard and mouse controller driver for Linux * * Copyright (c) 1999-2002 Vojtech Pavlik - * Copyright (c) 2004 Dmitry Torokhov */ /* @@ -75,14 +74,6 @@ struct i8042_values { unsigned char *phys; }; -#define I8042_QUEUE_LEN 64 -struct { - unsigned char str[I8042_QUEUE_LEN]; - unsigned char data[I8042_QUEUE_LEN]; - unsigned int read_pos; - unsigned int write_pos; -} i8042_buf; - static struct serio i8042_kbd_port; static struct serio i8042_aux_port; static unsigned char i8042_initial_ctr; @@ -91,7 +82,7 @@ static unsigned char i8042_mux_open; static unsigned char i8042_mux_present; static unsigned char i8042_sysdev_initialized; static struct pm_dev *i8042_pm_dev; -static struct timer_list i8042_timer; +struct timer_list i8042_timer; /* * Shared IRQ's require a device pointer, but this driver doesn't support @@ -383,108 +374,76 @@ static char i8042_mux_short[4][16]; static char i8042_mux_phys[4][32]; /* - * i8042_handle_data() is the most important function in this driver - - * it processes data received by i8042_interrupt and sends it to the - * upper layers. + * i8042_interrupt() is the most important function in this driver - + * it handles the interrupts from the i8042, and sends incoming bytes + * to the upper layers. */ -static void i8042_handle_data(unsigned long notused) +static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; unsigned char str, data = 0; unsigned int dfl; + int ret; - /* - * No locking it required on i8042_buf as the tasklet is guaranteed - * to be serialized and if write_pos changes while comparing it with - * read_pos another run will be scheduled by i8042_interrupt. - */ - while (i8042_buf.read_pos != i8042_buf.write_pos) { - - str = i8042_buf.str[i8042_buf.read_pos]; - data = i8042_buf.data[i8042_buf.read_pos]; - - i8042_buf.read_pos++; - i8042_buf.read_pos %= I8042_QUEUE_LEN; - - dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | - ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); - - if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) { - - if (str & I8042_STR_MUXERR) { - switch (data) { - case 0xfd: - case 0xfe: dfl = SERIO_TIMEOUT; break; - case 0xff: dfl = SERIO_PARITY; break; - } - data = 0xfe; - } else dfl = 0; - - dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)", - data, (str >> 6), irq, - dfl & SERIO_PARITY ? ", bad parity" : "", - dfl & SERIO_TIMEOUT ? ", timeout" : ""); - - serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, NULL); - } else { + mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); - dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", - data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, - dfl & SERIO_PARITY ? ", bad parity" : "", - dfl & SERIO_TIMEOUT ? ", timeout" : ""); + spin_lock_irqsave(&i8042_lock, flags); + str = i8042_read_status(); + if (str & I8042_STR_OBF) + data = i8042_read_data(); + spin_unlock_irqrestore(&i8042_lock, flags); - if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) - serio_interrupt(&i8042_aux_port, data, dfl, NULL); - else if (i8042_kbd_values.exists) - serio_interrupt(&i8042_kbd_port, data, dfl, NULL); - } + if (~str & I8042_STR_OBF) { + if (irq) dbg("Interrupt %d, without any data", irq); + ret = 0; + goto out; } -} - -DECLARE_TASKLET(i8042_tasklet, i8042_handle_data, 0); - -/* - * i8042_interrupt() handles the interrupts from i8042 and schedules - * i8042_handle_data to process and pass received bytes to the upper - * layers. - */ - -static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - unsigned char str; - unsigned int n_bytes = 0; - mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); - - spin_lock_irqsave(&i8042_lock, flags); + dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | + ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); - while ((str = i8042_read_status()) & I8042_STR_OBF) { + if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) { - n_bytes++; + if (str & I8042_STR_MUXERR) { + switch (data) { + case 0xfd: + case 0xfe: dfl = SERIO_TIMEOUT; break; + case 0xff: dfl = SERIO_PARITY; break; + } + data = 0xfe; + } else dfl = 0; - i8042_buf.str[i8042_buf.write_pos] = str; - i8042_buf.data[i8042_buf.write_pos] = i8042_read_data(); + dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)", + data, (str >> 6), irq, + dfl & SERIO_PARITY ? ", bad parity" : "", + dfl & SERIO_TIMEOUT ? ", timeout" : ""); - i8042_buf.write_pos++; - i8042_buf.write_pos %= I8042_QUEUE_LEN; + serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs); - if (unlikely(i8042_buf.write_pos == i8042_buf.read_pos)) - printk(KERN_WARNING "i8042.c: ring buffer full\n"); + goto irq_ret; } - spin_unlock_irqrestore(&i8042_lock, flags); + dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", + data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, + dfl & SERIO_PARITY ? ", bad parity" : "", + dfl & SERIO_TIMEOUT ? ", timeout" : ""); - if (unlikely(n_bytes == 0)) { - if (irq) dbg("Interrupt %d, without any data", irq); - return IRQ_NONE; + if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { + serio_interrupt(&i8042_aux_port, data, dfl, regs); + goto irq_ret; } - tasklet_schedule(&i8042_tasklet); + if (!i8042_kbd_values.exists) + goto irq_ret; - return IRQ_HANDLED; -} + serio_interrupt(&i8042_kbd_port, data, dfl, regs); +irq_ret: + ret = 1; +out: + return IRQ_RETVAL(ret); +} /* * i8042_enable_mux_mode checks whether the controller has an active @@ -1058,9 +1017,7 @@ void __exit i8042_exit(void) for (i = 0; i < 4; i++) if (i8042_mux_values[i].exists) serio_unregister_port(i8042_mux_port + i); - del_timer_sync(&i8042_timer); - tasklet_kill(&i8042_tasklet); i8042_platform_exit(); } -- cgit v1.2.3 From 0a30246c88bb498cff431c9fcb97f7c935af6554 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 2 Jun 2004 03:00:58 -0500 Subject: Input: logips2pp - do not call get_model_info 2 times Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/logips2pp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 0063af0379d6..6af1455fd97b 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -277,7 +277,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) protocol = PSMOUSE_PS2TPP; } - } else if (get_model_info(model) != NULL) { + } else if (model_info != NULL) { param[0] = param[1] = param[2] = 0; ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ -- cgit v1.2.3 From ecb88b25be3865f89144bc7418e2c8b7ef16d9e1 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Wed, 2 Jun 2004 13:37:24 +0200 Subject: input: Fixes in serio locking. We need per-serio lock for passthrough ports, some locks were missing, and spin_lock_irq was wishful thinking in serio_interrupt. There is no guarantee that serio_interrupt won't be called twice at the same time. Signed-off-by: Vojtech Pavlik --- drivers/input/serio/serio.c | 55 ++++++++++++++++++++++++--------------------- include/linux/serio.h | 3 +++ 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 3414e0bc3cf1..f02014498246 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -68,8 +68,8 @@ struct serio_event { }; -spinlock_t serio_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list and serio->dev */ -static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_dev_list */ +spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list */ +static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_dev_list */ static LIST_HEAD(serio_list); static LIST_HEAD(serio_dev_list); static LIST_HEAD(serio_event_list); @@ -104,13 +104,13 @@ static void serio_invalidate_pending_events(struct serio *serio) struct serio_event *event; unsigned long flags; - spin_lock_irqsave(&serio_lock, flags); + spin_lock_irqsave(&serio_event_lock, flags); list_for_each_entry(event, &serio_event_list, node) if (event->serio == serio) event->serio = NULL; - spin_unlock_irqrestore(&serio_lock, flags); + spin_unlock_irqrestore(&serio_event_lock, flags); } void serio_handle_events(void) @@ -119,13 +119,13 @@ void serio_handle_events(void) struct serio_event *event; unsigned long flags; - + while (1) { - spin_lock_irqsave(&serio_lock, flags); - + spin_lock_irqsave(&serio_event_lock, flags); + if (list_empty(&serio_event_list)) { - spin_unlock_irqrestore(&serio_lock, flags); + spin_unlock_irqrestore(&serio_event_lock, flags); break; } @@ -133,7 +133,7 @@ void serio_handle_events(void) event = container_of(node, struct serio_event, node); list_del_init(node); - spin_unlock_irqrestore(&serio_lock, flags); + spin_unlock_irqrestore(&serio_event_lock, flags); down(&serio_sem); @@ -190,8 +190,11 @@ static int serio_thread(void *nothing) static void serio_queue_event(struct serio *serio, int event_type) { + unsigned long flags; struct serio_event *event; + spin_lock_irqsave(&serio_event_lock, flags); + if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { event->type = event_type; event->serio = serio; @@ -199,44 +202,41 @@ static void serio_queue_event(struct serio *serio, int event_type) list_add_tail(&event->node, &serio_event_list); wake_up(&serio_wait); } + + spin_unlock_irqrestore(&serio_event_lock, flags); } void serio_rescan(struct serio *serio) { - unsigned long flags; - spin_lock_irqsave(&serio_lock, flags); serio_queue_event(serio, SERIO_RESCAN); - spin_unlock_irqrestore(&serio_lock, flags); } void serio_reconnect(struct serio *serio) { - unsigned long flags; - spin_lock_irqsave(&serio_lock, flags); serio_queue_event(serio, SERIO_RECONNECT); - spin_unlock_irqrestore(&serio_lock, flags); } irqreturn_t serio_interrupt(struct serio *serio, - unsigned char data, unsigned int flags, struct pt_regs *regs) + unsigned char data, unsigned int dfl, struct pt_regs *regs) { + unsigned long flags; irqreturn_t ret = IRQ_NONE; - spin_lock_irq(&serio_lock); + spin_lock_irqsave(&serio->lock, flags); if (serio->dev && serio->dev->interrupt) { - ret = serio->dev->interrupt(serio, data, flags, regs); + ret = serio->dev->interrupt(serio, data, dfl, regs); } else { - if (!flags) { + if (!dfl) { if ((serio->type != SERIO_8042 && serio->type != SERIO_8042_XL) || (data == 0xaa)) { - serio_queue_event(serio, SERIO_RESCAN); + serio_rescan(serio); ret = IRQ_HANDLED; } } } - - spin_unlock_irq(&serio_lock); + + spin_unlock_irqrestore(&serio->lock, flags); return ret; } @@ -265,6 +265,7 @@ void serio_register_port_delayed(struct serio *serio) */ void __serio_register_port(struct serio *serio) { + spin_lock_init(&serio->lock); list_add_tail(&serio->node, &serio_list); serio_find_dev(serio); } @@ -330,11 +331,13 @@ int serio_open(struct serio *serio, struct serio_dev *dev) { unsigned long flags; - spin_lock_irqsave(&serio_lock, flags); + spin_lock_irqsave(&serio->lock, flags); serio->dev = dev; - spin_unlock_irqrestore(&serio_lock, flags); + spin_unlock_irqrestore(&serio->lock, flags); if (serio->open && serio->open(serio)) { + spin_lock_irqsave(&serio->lock, flags); serio->dev = NULL; + spin_unlock_irqrestore(&serio->lock, flags); return -1; } return 0; @@ -347,9 +350,9 @@ void serio_close(struct serio *serio) if (serio->close) serio->close(serio); - spin_lock_irqsave(&serio_lock, flags); + spin_lock_irqsave(&serio->lock, flags); serio->dev = NULL; - spin_unlock_irqrestore(&serio_lock, flags); + spin_unlock_irqrestore(&serio->lock, flags); } static int __init serio_init(void) diff --git a/include/linux/serio.h b/include/linux/serio.h index 037e9f7bc052..cd833f823512 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -17,6 +17,7 @@ #ifdef __KERNEL__ #include +#include struct serio { void *private; @@ -32,6 +33,8 @@ struct serio { unsigned long type; unsigned long event; + spinlock_t lock; + int (*write)(struct serio *, unsigned char); int (*open)(struct serio *); void (*close)(struct serio *); -- cgit v1.2.3 From c362c06ac0c3b448180770e25ad5fa19ab0059ad Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Wed, 2 Jun 2004 17:44:20 +0200 Subject: input: Disable the AUX LoopBack command in i8042.c on Compaq ProLiant 8-way Xeon ProFusion systems, as it causes crashes and reboots on these machines. DMI data is used for determining if the workaround should be enabled. Signed-off-by: Vojtech Pavlik --- arch/i386/kernel/dmi_scan.c | 31 +++++++++++++++++++++++++++++++ drivers/input/serio/i8042.c | 14 +++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c index 6c20ebe9934f..5447b12ffb22 100644 --- a/arch/i386/kernel/dmi_scan.c +++ b/arch/i386/kernel/dmi_scan.c @@ -15,6 +15,9 @@ unsigned long dmi_broken; EXPORT_SYMBOL(dmi_broken); +unsigned int i8042_dmi_noloop = 0; +EXPORT_SYMBOL(i8042_dmi_noloop); + int is_sony_vaio_laptop; int is_unsafe_smbus; int es7000_plat = 0; @@ -400,6 +403,17 @@ static __init int sony_vaio_laptop(struct dmi_blacklist *d) return 0; } +/* + * Several HP Proliant (and maybe other OSB4/ProFusion) systems + * shouldn't use the AUX LoopBack command, or they crash or reboot. + */ + +static __init int set_8042_noloop(struct dmi_blacklist *d) +{ + i8042_dmi_noloop = 1; + return 0; +} + /* * This bios swaps the APM minute reporting bytes over (Many sony laptops * have this problem). @@ -875,6 +889,23 @@ static __initdata struct dmi_blacklist dmi_blacklist[]={ NO_MATCH, NO_MATCH, } }, + /* + * Several HP Proliant (and maybe other OSB4/ProFusion) systems + * can't use i8042 in mux mode, or they crash or reboot. + */ + + { set_8042_noloop, "Compaq Proliant 8500", { + MATCH(DMI_SYS_VENDOR, "Compaq"), + MATCH(DMI_PRODUCT_NAME , "ProLiant"), + MATCH(DMI_PRODUCT_VERSION, "8500"), + NO_MATCH }}, + + { set_8042_noloop, "Compaq Proliant DL760", { + MATCH(DMI_SYS_VENDOR, "Compaq"), + MATCH(DMI_PRODUCT_NAME , "ProLiant"), + MATCH(DMI_PRODUCT_VERSION, "DL760"), + NO_MATCH }}, + #ifdef CONFIG_ACPI_BOOT /* * If your system is blacklisted here, but you find that acpi=force diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index efe3c289baf9..b2ac4f3b9122 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -1,7 +1,7 @@ /* * i8042 keyboard and mouse controller driver for Linux * - * Copyright (c) 1999-2002 Vojtech Pavlik + * Copyright (c) 1999-2004 Vojtech Pavlik */ /* @@ -52,6 +52,8 @@ static unsigned int i8042_dumbkbd; module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); +static unsigned int i8042_noloop; + __obsolete_setup("i8042_noaux"); __obsolete_setup("i8042_nomux"); __obsolete_setup("i8042_unlock"); @@ -154,6 +156,9 @@ static int i8042_command(unsigned char *param, int command) unsigned long flags; int retval = 0, i = 0; + if (i8042_noloop && command == I8042_CMD_AUX_LOOP) + return -1; + spin_lock_irqsave(&i8042_lock, flags); retval = i8042_wait_write(); @@ -955,6 +960,13 @@ int __init i8042_init(void) if (i8042_dumbkbd) i8042_kbd_port.write = NULL; +#ifdef __i386__ + if (i8042_dmi_noloop) { + printk(KERN_INFO "i8042.c: AUX LoopBack command disabled by DMI.\n"); + i8042_noloop = 1; + } +#endif + if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) { if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values)) for (i = 0; i < 4; i++) { -- cgit v1.2.3 From cdc6f1975143c89c7a31b1ed1aec1be6522624a1 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Wed, 2 Jun 2004 19:46:14 +0200 Subject: input: Make atkbd.c's atkbd_command() function immune to keys being pressed and scancodes coming from the keyboard while it's executing. Signed-off-by: Vojtech Pavlik --- drivers/input/keyboard/atkbd.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index d5a63adf0343..ba7fa98c892d 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -252,6 +252,11 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, switch (code) { case ATKBD_RET_ACK: atkbd->nak = 0; + if (atkbd->cmdcnt) { + set_bit(ATKBD_FLAG_CMD, &atkbd->flags); + set_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + set_bit(ATKBD_FLAG_ID, &atkbd->flags); + } clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); goto out; case ATKBD_RET_NAK: @@ -414,6 +419,7 @@ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) #endif set_bit(ATKBD_FLAG_ACK, &atkbd->flags); + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); if (serio_write(atkbd->serio, byte)) return -1; while (test_bit(ATKBD_FLAG_ACK, &atkbd->flags) && timeout--) udelay(1); @@ -443,23 +449,13 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) for (i = 0; i < receive; i++) atkbd->cmdbuf[(receive - 1) - i] = param[i]; - if (receive) { - set_bit(ATKBD_FLAG_CMD, &atkbd->flags); - set_bit(ATKBD_FLAG_CMD1, &atkbd->flags); - set_bit(ATKBD_FLAG_ID, &atkbd->flags); - } - if (command & 0xff) - if (atkbd_sendbyte(atkbd, command & 0xff)) { - clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + if (atkbd_sendbyte(atkbd, command & 0xff)) return -1; - } for (i = 0; i < send; i++) - if (atkbd_sendbyte(atkbd, param[i])) { - clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + if (atkbd_sendbyte(atkbd, param[i])) return -1; - } while (test_bit(ATKBD_FLAG_CMD, &atkbd->flags) && timeout--) { -- cgit v1.2.3 From 5b138907cf228781587ed6e78f398a3691304cb2 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Wed, 2 Jun 2004 20:09:25 +0200 Subject: input: More locking improvements (and a fix) for serio. This merges both my and Dmitry's changes. Signed-off-by: Vojtech Pavlik --- drivers/input/serio/serio.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index f02014498246..c810919d255d 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -68,8 +68,8 @@ struct serio_event { }; -spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list */ -static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_dev_list */ +static spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list */ +static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_dev_list */ static LIST_HEAD(serio_list); static LIST_HEAD(serio_dev_list); static LIST_HEAD(serio_event_list); @@ -99,16 +99,21 @@ static void serio_find_dev(struct serio *serio) static DECLARE_WAIT_QUEUE_HEAD(serio_wait); static DECLARE_COMPLETION(serio_exited); -static void serio_invalidate_pending_events(struct serio *serio) +static void serio_remove_pending_events(struct serio *serio) { + struct list_head *node, *next; struct serio_event *event; unsigned long flags; spin_lock_irqsave(&serio_event_lock, flags); - list_for_each_entry(event, &serio_event_list, node) - if (event->serio == serio) - event->serio = NULL; + list_for_each_safe(node, next, &serio_event_list) { + event = container_of(node, struct serio_event, node); + if (event->serio == serio) { + list_del_init(node); + kfree(event); + } + } spin_unlock_irqrestore(&serio_event_lock, flags); } @@ -137,9 +142,6 @@ void serio_handle_events(void) down(&serio_sem); - if (event->serio == NULL) /*!!!*/ - goto event_done; - switch (event->type) { case SERIO_REGISTER_PORT : __serio_register_port(event->serio); @@ -163,7 +165,7 @@ void serio_handle_events(void) default: break; } -event_done: + up(&serio_sem); kfree(event); } @@ -224,7 +226,7 @@ irqreturn_t serio_interrupt(struct serio *serio, spin_lock_irqsave(&serio->lock, flags); - if (serio->dev && serio->dev->interrupt) { + if (likely(serio->dev)) { ret = serio->dev->interrupt(serio, data, dfl, regs); } else { if (!dfl) { @@ -294,7 +296,7 @@ void serio_unregister_port_delayed(struct serio *serio) */ void __serio_unregister_port(struct serio *serio) { - serio_invalidate_pending_events(serio); + serio_remove_pending_events(serio); list_del_init(&serio->node); if (serio->dev && serio->dev->disconnect) serio->dev->disconnect(serio); -- cgit v1.2.3 From 71aadd50e03949ee5d40b918b57cb2b5014bb238 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Wed, 2 Jun 2004 20:30:53 +0200 Subject: input: Add a missong dmi_noloop declaration in i8042.c Signed-off-by: Vojtech Pavlik --- drivers/input/serio/i8042.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index b8ebbf04cdfc..39b67e177f1f 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -53,6 +53,7 @@ module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); static unsigned int i8042_noloop; +extern unsigned int i8042_dmi_noloop; __obsolete_setup("i8042_noaux"); __obsolete_setup("i8042_nomux"); -- cgit v1.2.3 From 8f93db5bbbbd6caf1fb7ea3bb1c9085c5b615949 Mon Sep 17 00:00:00 2001 From: William Lee Irwin III Date: Fri, 4 Jun 2004 11:18:00 +0200 Subject: input: Move CONFIG_USB_HIDDEV a little lower in hiddev.h, to fix compilation breakage when it is not defined. Signed-off-by: Vojtech Pavlik --- include/linux/hiddev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h index 2065224aaf62..695423da423e 100644 --- a/include/linux/hiddev.h +++ b/include/linux/hiddev.h @@ -213,12 +213,12 @@ struct hiddev_usage_ref_multi { * In-kernel definitions. */ -#ifdef CONFIG_USB_HIDDEV struct hid_device; struct hid_usage; struct hid_field; struct hid_report; +#ifdef CONFIG_USB_HIDDEV int hiddev_connect(struct hid_device *); void hiddev_disconnect(struct hid_device *); void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, -- cgit v1.2.3 From fadb62b670d6896f865f7dbfc464893d75e46716 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 6 Jun 2004 01:34:24 -0500 Subject: Input: mousedev - better handle button presses when under load Signed-off-by: Dmitry Torokhov --- drivers/input/mousedev.c | 152 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 104 insertions(+), 48 deletions(-) diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 53d5d5e87539..f13118fc3bab 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -50,6 +50,7 @@ MODULE_PARM_DESC(yres, "Vertical screen resolution"); struct mousedev_motion { int dx, dy, dz; + unsigned long buttons; }; struct mousedev { @@ -62,21 +63,31 @@ struct mousedev { struct input_handle handle; struct mousedev_motion packet; - unsigned long buttons; unsigned int pkt_count; int old_x[4], old_y[4]; unsigned int touch; }; +enum mousedev_emul { + MOUSEDEV_EMUL_PS2, + MOUSEDEV_EMUL_IMPS, + MOUSEDEV_EMUL_EXPS +} __attribute__ ((packed)); + +#define PACKET_QUEUE_LEN 16 struct mousedev_list { struct fasync_struct *fasync; struct mousedev *mousedev; struct list_head node; - int dx, dy, dz; - unsigned long buttons; + + struct mousedev_motion packets[PACKET_QUEUE_LEN]; + unsigned int head, tail; + spinlock_t packet_lock; + signed char ps2[6]; unsigned char ready, buffer, bufsiz; - unsigned char mode, imexseq, impsseq; + unsigned char imexseq, impsseq; + enum mousedev_emul mode; }; #define MOUSEDEV_SEQ_LEN 6 @@ -165,24 +176,40 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int } if (value) { - set_bit(index, &mousedev->buttons); - set_bit(index, &mousedev_mix.buttons); + set_bit(index, &mousedev->packet.buttons); + set_bit(index, &mousedev_mix.packet.buttons); } else { - clear_bit(index, &mousedev->buttons); - clear_bit(index, &mousedev_mix.buttons); + clear_bit(index, &mousedev->packet.buttons); + clear_bit(index, &mousedev_mix.packet.buttons); } } static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet) { struct mousedev_list *list; + struct mousedev_motion *p; + unsigned long flags; list_for_each_entry(list, &mousedev->list, node) { - list->dx += packet->dx; - list->dy += packet->dy; - list->dz += packet->dz; - list->buttons = mousedev->buttons; + spin_lock_irqsave(&list->packet_lock, flags); + + p = &list->packets[list->head]; + if (list->ready && p->buttons != packet->buttons) { + unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN; + if (new_head != list->tail) { + p = &list->packets[list->head = new_head]; + memset(p, 0, sizeof(struct mousedev_motion)); + } + } + + p->dx += packet->dx; + p->dy += packet->dy; + p->dz += packet->dz; + p->buttons = mousedev->packet.buttons; + list->ready = 1; + + spin_unlock_irqrestore(&list->packet_lock, flags); kill_fasync(&list->fasync, SIGIO, POLL_IN); } @@ -237,7 +264,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig mousedev_notify_readers(mousedev, &mousedev->packet); mousedev_notify_readers(&mousedev_mix, &mousedev->packet); - memset(&mousedev->packet, 0, sizeof(struct mousedev_motion)); + mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; } break; } @@ -322,6 +349,7 @@ static int mousedev_open(struct inode * inode, struct file * file) return -ENOMEM; memset(list, 0, sizeof(struct mousedev_list)); + spin_lock_init(&list->packet_lock); list->mousedev = mousedev_table[i]; list_add_tail(&list->node, &mousedev_table[i]->list); file->private_data = list; @@ -341,32 +369,56 @@ static int mousedev_open(struct inode * inode, struct file * file) return 0; } -static void mousedev_packet(struct mousedev_list *list, unsigned char off) +static inline int mousedev_limit_delta(int delta, int limit) { - list->ps2[off] = 0x08 | ((list->dx < 0) << 4) | ((list->dy < 0) << 5) | (list->buttons & 0x07); - list->ps2[off + 1] = (list->dx > 127 ? 127 : (list->dx < -127 ? -127 : list->dx)); - list->ps2[off + 2] = (list->dy > 127 ? 127 : (list->dy < -127 ? -127 : list->dy)); - list->dx -= list->ps2[off + 1]; - list->dy -= list->ps2[off + 2]; - list->bufsiz = off + 3; - - if (list->mode == 2) { - list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz)); - list->dz -= list->ps2[off + 3]; - list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1); - list->bufsiz++; - } else { - list->ps2[off] |= ((list->buttons & 0x10) >> 3) | ((list->buttons & 0x08) >> 1); + return delta > limit ? limit : (delta < -limit ? -limit : delta); +} + +static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) +{ + struct mousedev_motion *p; + unsigned long flags; + + spin_lock_irqsave(&list->packet_lock, flags); + p = &list->packets[list->tail]; + + ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); + ps2_data[1] = mousedev_limit_delta(p->dx, 127); + ps2_data[2] = mousedev_limit_delta(p->dy, 127); + p->dx -= ps2_data[1]; + p->dy -= ps2_data[2]; + + switch (list->mode) { + case MOUSEDEV_EMUL_EXPS: + ps2_data[3] = mousedev_limit_delta(p->dz, 127); + p->dz -= ps2_data[3]; + ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); + list->bufsiz = 4; + break; + + case MOUSEDEV_EMUL_IMPS: + ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); + ps2_data[3] = mousedev_limit_delta(p->dz, 127); + p->dz -= ps2_data[3]; + list->bufsiz = 4; + break; + + case MOUSEDEV_EMUL_PS2: + default: + ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); + p->dz = 0; + list->bufsiz = 3; + break; } - if (list->mode == 1) { - list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz)); - list->dz -= list->ps2[off + 3]; - list->bufsiz++; + if (!p->dx && !p->dy && !p->dz) { + if (list->tail != list->head) + list->tail = (list->tail + 1) % PACKET_QUEUE_LEN; + if (list->tail == list->head) + list->ready = 0; } - if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0; - list->buffer = list->bufsiz; + spin_unlock_irqrestore(&list->packet_lock, flags); } @@ -384,31 +436,31 @@ static ssize_t mousedev_write(struct file * file, const char * buffer, size_t co if (c == mousedev_imex_seq[list->imexseq]) { if (++list->imexseq == MOUSEDEV_SEQ_LEN) { list->imexseq = 0; - list->mode = 2; + list->mode = MOUSEDEV_EMUL_EXPS; } } else list->imexseq = 0; if (c == mousedev_imps_seq[list->impsseq]) { if (++list->impsseq == MOUSEDEV_SEQ_LEN) { list->impsseq = 0; - list->mode = 1; + list->mode = MOUSEDEV_EMUL_IMPS; } } else list->impsseq = 0; list->ps2[0] = 0xfa; - list->bufsiz = 1; switch (c) { case 0xeb: /* Poll */ - mousedev_packet(list, 1); + mousedev_packet(list, &list->ps2[1]); + list->bufsiz++; /* account for leading ACK */ break; case 0xf2: /* Get ID */ switch (list->mode) { - case 0: list->ps2[1] = 0; break; - case 1: list->ps2[1] = 3; break; - case 2: list->ps2[1] = 4; break; + case MOUSEDEV_EMUL_PS2: list->ps2[1] = 0; break; + case MOUSEDEV_EMUL_IMPS: list->ps2[1] = 3; break; + case MOUSEDEV_EMUL_EXPS: list->ps2[1] = 4; break; } list->bufsiz = 2; break; @@ -419,13 +471,15 @@ static ssize_t mousedev_write(struct file * file, const char * buffer, size_t co break; case 0xff: /* Reset */ - list->impsseq = 0; - list->imexseq = 0; - list->mode = 0; - list->ps2[1] = 0xaa; - list->ps2[2] = 0x00; + list->impsseq = list->imexseq = 0; + list->mode = MOUSEDEV_EMUL_PS2; + list->ps2[1] = 0xaa; list->ps2[2] = 0x00; list->bufsiz = 3; break; + + default: + list->bufsiz = 1; + break; } list->buffer = list->bufsiz; @@ -451,8 +505,10 @@ static ssize_t mousedev_read(struct file * file, char * buffer, size_t count, lo if (retval) return retval; - if (!list->buffer && list->ready) - mousedev_packet(list, 0); + if (!list->buffer && list->ready) { + mousedev_packet(list, list->ps2); + list->buffer = list->bufsiz; + } if (count > list->buffer) count = list->buffer; -- cgit v1.2.3 From 9c99b2b0df7c48dc247110e47ef4126b7649df1a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sun, 6 Jun 2004 01:37:05 -0500 Subject: Input: mousedev - implement tapping for touchpads working in absolute mode, such as Synaptics Signed-off-by: Dmitry Torokhov --- Documentation/kernel-parameters.txt | 6 ++++++ drivers/input/mouse/Kconfig | 2 -- drivers/input/mousedev.c | 38 ++++++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index c26a38ac54b7..50a8947b37e1 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -652,6 +652,12 @@ running once the system is up. mga= [HW,DRM] + mousedev.tap_time= + [MOUSE] Maximum time between finger touching and + leaving touchpad surface for touch to be considered + a tap and be reported as a left button click (for + touchpads working in absolute mode only). + Format: mousedev.xres= [MOUSE] Horizontal screen resolution, used for devices reporting absolute coordinates, such as tablets mousedev.yres= [MOUSE] Vertical screen resolution, used for devices diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 17db090dc6f6..8af7826fe71b 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -30,8 +30,6 @@ config MOUSE_PS2 and a new verion of GPM at: http://www.geocities.com/dt_or/gpm/gpm.html to take advantage of the advanced features of the touchpad. - If you do not want install specialized drivers but want tapping - working please use option psmouse.proto=imps. If unsure, say Y. diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index f13118fc3bab..4dc1f5ea1ac2 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -48,6 +48,10 @@ static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; module_param(yres, uint, 0); MODULE_PARM_DESC(yres, "Vertical screen resolution"); +static unsigned tap_time = 200; +module_param(tap_time, uint, 0); +MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); + struct mousedev_motion { int dx, dy, dz; unsigned long buttons; @@ -65,7 +69,7 @@ struct mousedev { struct mousedev_motion packet; unsigned int pkt_count; int old_x[4], old_y[4]; - unsigned int touch; + unsigned long touch; }; enum mousedev_emul { @@ -216,6 +220,30 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_m wake_up_interruptible(&mousedev->wait); } +static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) +{ + if (!value) { + if (mousedev->touch && + !time_after(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) { + /* + * Toggle left button to emulate tap. + * We rely on the fact that mousedev_mix always has 0 + * motion packet so we won't mess current position. + */ + set_bit(0, &mousedev->packet.buttons); + set_bit(0, &mousedev_mix.packet.buttons); + mousedev_notify_readers(mousedev, &mousedev_mix.packet); + mousedev_notify_readers(&mousedev_mix, &mousedev_mix.packet); + clear_bit(0, &mousedev->packet.buttons); + clear_bit(0, &mousedev_mix.packet.buttons); + } + mousedev->touch = mousedev->pkt_count = 0; + } + else + if (!mousedev->touch) + mousedev->touch = jiffies; +} + static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { struct mousedev *mousedev = handle->private; @@ -239,12 +267,8 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig case EV_KEY: if (value != 2) { - if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) { - /* Handle touchpad data */ - mousedev->touch = value; - if (!mousedev->touch) - mousedev->pkt_count = 0; - } + if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) + mousedev_touchpad_touch(mousedev, value); else mousedev_key_event(mousedev, code, value); } -- cgit v1.2.3 From 7daff91b8710b968dff4fdafe55690ab29f05f6d Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sun, 6 Jun 2004 15:08:20 +0200 Subject: input: Make hardware rawmode optional for AT-keyboards, and check for rawmode bits in keyboard.c Signed-off-by: Vojtech Pavlik --- drivers/char/keyboard.c | 3 ++- drivers/input/keyboard/atkbd.c | 16 ++++++++++++++-- include/linux/input.h | 1 + 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index a815b9760258..52efa77cf2d6 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -942,7 +942,8 @@ void kbd_refresh_leds(struct input_handle *handle) #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC32) || defined(CONFIG_SPARC64) || defined(CONFIG_PARISC) || defined(CONFIG_SH_MPC1211) -#define HW_RAW(dev) (((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) +#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\ + ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001)) static unsigned short x86_keycodes[256] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index ba7fa98c892d..67dfd159b4f0 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -47,6 +47,10 @@ static int atkbd_softrepeat; module_param_named(softrepeat, atkbd_softrepeat, bool, 0); MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); +static int atkbd_softraw = 1; +module_param_named(softraw, atkbd_softraw, bool, 0); +MODULE_PARM_DESC(softraw, "Use software generated rawmode"); + static int atkbd_scroll; module_param_named(scroll, atkbd_scroll, bool, 0); MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); @@ -336,6 +340,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, code |= (atkbd->set != 3) ? 0x80 : 0x100; } + if (atkbd->keycode[code] != ATKBD_KEY_NULL) + input_event(&atkbd->dev, EV_MSC, MSC_SCAN, code); + switch (atkbd->keycode[code]) { case ATKBD_KEY_NULL: break; @@ -750,16 +757,21 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) return; } + if (!atkbd->write) + atkbd_softrepeat = 1; + if (atkbd_softrepeat) + atkbd_softraw = 1; + if (atkbd->write) { atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP) | BIT(EV_MSC); atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); } else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_MSC); - atkbd->dev.mscbit[0] = BIT(MSC_RAW); + atkbd->dev.mscbit[0] = atkbd_softraw ? BIT(MSC_SCAN) : BIT(MSC_RAW) | BIT(MSC_SCAN); if (!atkbd_softrepeat) { atkbd->dev.rep[REP_DELAY] = 250; atkbd->dev.rep[REP_PERIOD] = 33; - } + } else atkbd_softraw = 1; atkbd->serio = serio; diff --git a/include/linux/input.h b/include/linux/input.h index 2fa58351bd4f..43cb25e228d5 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -528,6 +528,7 @@ struct input_absinfo { #define MSC_PULSELED 0x01 #define MSC_GESTURE 0x02 #define MSC_RAW 0x03 +#define MSC_SCAN 0x04 #define MSC_MAX 0x07 /* -- cgit v1.2.3 From ccbcf7710752fee44a9b23376c6d01b475685618 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sun, 6 Jun 2004 15:09:31 +0200 Subject: input: Add a missing extern i8042_dmi_loop. Signed-off-by: Vojtech Pavlik --- drivers/input/serio/i8042.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index b8ebbf04cdfc..07d78215b159 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -52,6 +52,7 @@ static unsigned int i8042_dumbkbd; module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); +extern unsigned int i8042_dmi_noloop; static unsigned int i8042_noloop; __obsolete_setup("i8042_noaux"); -- cgit v1.2.3 From 79a9b4b6e100e531d0f0d9389cab98d1c25ca981 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 6 Jun 2004 15:37:43 +0200 Subject: input: Fix boundary checks for GUSAGE/SUSAGE in hiddev. Signed-off-by: Vojtech Pavlik --- drivers/usb/input/hiddev.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index de4879935c52..00baecedc76f 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -638,16 +638,22 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd goto inval; field = report->field[uref->field_index]; - if (uref->usage_index >= field->maxusage) - goto inval; - if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) { - if (uref_multi->num_values >= HID_MAX_MULTI_USAGES || - uref->usage_index >= field->maxusage || - (uref->usage_index + uref_multi->num_values) >= field->maxusage) + if (cmd == HIDIOCGCOLLECTIONINDEX) { + if (uref->usage_index >= field->maxusage) goto inval; + } else if (uref->usage_index >= field->report_count) + goto inval; + + else if ((cmd == HIDIOCGUSAGES || + cmd == HIDIOCSUSAGES) && + (uref->usage_index + uref_multi->num_values >= + field->report_count || + uref->usage_index + uref_multi->num_values < + uref->usage_index)) + goto inval; + } - } switch (cmd) { case HIDIOCGUSAGE: -- cgit v1.2.3 From bc2d9f690cb2408cd3d3b7438da1af5aabba1de8 Mon Sep 17 00:00:00 2001 From: Andrew Zabolotny Date: Sun, 6 Jun 2004 15:56:42 +0200 Subject: input: From: Andrew Zabolotny - Implement the 'raw' touchscreen protocol for backward compatibility (/dev/input/ts[0-7] now speaks the protocol of the old /dev/h3600_ts, and the /dev/input/tsraw[0-7] speaks the protocol of the old /dev/h3600_tsraw device). - Support the ioctls for setting the calibration parameters. The default calibration matrix is computed from the xres,yres parameters (duplicate the old behaviour), however this is not enough for a good translation from touchscreen space to screen space. - Fixed a old bug in tsdev: on a pen motion event X1,Y1 -> X2,Y2 the driver would output three events with coordinates: X1,Y1, X2,Y1, X2,Y2. This happened not only with coordinates, but with pressure too. - Update James's email address - Remove mention of Transvirtual Technologies: they no longer exist. Signed-off-by: Vojtech Pavlik --- drivers/input/tsdev.c | 291 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 186 insertions(+), 105 deletions(-) diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 7958ae8578ca..79dcf9a2b299 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -3,9 +3,17 @@ * * Copyright (c) 2001 "Crazy" james Simmons * - * Input driver to Touchscreen device driver module. + * Compaq touchscreen protocol driver. The protocol emulated by this driver + * is obsolete; for new programs use the tslib library which can read directly + * from evdev and perform dejittering, variance filtering and calibration - + * all in user space, not at kernel level. The meaning of this driver is + * to allow usage of newer input drivers with old applications that use the + * old /dev/h3600_ts and /dev/h3600_tsraw devices. * - * Sponsored by Transvirtual Technology + * 09-Apr-2004: Andrew Zabolotny + * Fixed to actually work, not just output random numbers. + * Added support for both h3600_ts and h3600_tsraw protocol + * emulation. */ /* @@ -24,11 +32,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to . + * e-mail - mail your message to . */ #define TSDEV_MINOR_BASE 128 #define TSDEV_MINORS 32 +/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ +#define TSDEV_MINOR_MASK 15 #define TSDEV_BUFFER_SIZE 64 #include @@ -52,48 +62,84 @@ #define CONFIG_INPUT_TSDEV_SCREEN_Y 320 #endif +/* This driver emulates both protocols of the old h3600_ts and h3600_tsraw + * devices. The first one must output X/Y data in 'cooked' format, e.g. + * filtered, dejittered and calibrated. Second device just outputs raw + * data received from the hardware. + * + * This driver doesn't support filtering and dejittering; it supports only + * calibration. Filtering and dejittering must be done in the low-level + * driver, if needed, because it may gain additional benefits from knowing + * the low-level details, the nature of noise and so on. + * + * The driver precomputes a calibration matrix given the initial xres and + * yres values (quite innacurate for most touchscreens) that will result + * in a more or less expected range of output values. The driver supports + * the TS_SET_CAL ioctl, which will replace the calibration matrix with a + * new one, supposedly generated from the values taken from the raw device. + */ + MODULE_AUTHOR("James Simmons "); MODULE_DESCRIPTION("Input driver to touchscreen converter"); MODULE_LICENSE("GPL"); static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; module_param(xres, uint, 0); -MODULE_PARM_DESC(xres, "Horizontal screen resolution"); +MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)"); static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; module_param(yres, uint, 0); -MODULE_PARM_DESC(yres, "Vertical screen resolution"); +MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)"); + +/* From Compaq's Touch Screen Specification version 0.2 (draft) */ +struct ts_event { + short pressure; + short x; + short y; + short millisecs; +}; + +struct ts_calibration { + int xscale; + int xtrans; + int yscale; + int ytrans; + int xyswap; +}; struct tsdev { int exist; int open; int minor; - char name[16]; + char name[8]; wait_queue_head_t wait; struct list_head list; struct input_handle handle; + int x, y, pressure; + struct ts_calibration cal; }; -/* From Compaq's Touch Screen Specification version 0.2 (draft) */ -typedef struct { - short pressure; - short x; - short y; - short millisecs; -} TS_EVENT; - struct tsdev_list { struct fasync_struct *fasync; struct list_head node; struct tsdev *tsdev; int head, tail; - int oldx, oldy, pendown; - TS_EVENT event[TSDEV_BUFFER_SIZE]; + struct ts_event event[TSDEV_BUFFER_SIZE]; + int raw; }; +/* The following ioctl codes are defined ONLY for backward compatibility. + * Don't use tsdev for new developement; use the tslib library instead. + * Touchscreen calibration is a fully userspace task. + */ +/* Use 'f' as magic number */ +#define IOC_H3600_TS_MAGIC 'f' +#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) +#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) + static struct input_handler tsdev_handler; -static struct tsdev *tsdev_table[TSDEV_MINORS]; +static struct tsdev *tsdev_table[TSDEV_MINORS/2]; static int tsdev_fasync(int fd, struct file *file, int on) { @@ -109,13 +155,16 @@ static int tsdev_open(struct inode *inode, struct file *file) int i = iminor(inode) - TSDEV_MINOR_BASE; struct tsdev_list *list; - if (i >= TSDEV_MINORS || !tsdev_table[i]) + if (i >= TSDEV_MINORS || !tsdev_table[i & TSDEV_MINOR_MASK]) return -ENODEV; if (!(list = kmalloc(sizeof(struct tsdev_list), GFP_KERNEL))) return -ENOMEM; memset(list, 0, sizeof(struct tsdev_list)); + list->raw = (i >= TSDEV_MINORS/2) ? 1 : 0; + + i &= TSDEV_MINOR_MASK; list->tsdev = tsdev_table[i]; list_add_tail(&list->node, &tsdev_table[i]->list); file->private_data = list; @@ -169,11 +218,13 @@ static ssize_t tsdev_read(struct file *file, char *buffer, size_t count, if (!list->tsdev->exist) return -ENODEV; - while (list->head != list->tail && retval + sizeof(TS_EVENT) <= count) { - if (copy_to_user (buffer + retval, list->event + list->tail, sizeof(TS_EVENT))) + while (list->head != list->tail && + retval + sizeof (struct ts_event) <= count) { + if (copy_to_user (buffer + retval, list->event + list->tail, + sizeof (struct ts_event))) return -EFAULT; list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1); - retval += sizeof(TS_EVENT); + retval += sizeof (struct ts_event); } return retval; @@ -193,22 +244,27 @@ static unsigned int tsdev_poll(struct file *file, poll_table * wait) static int tsdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { -/* struct tsdev_list *list = file->private_data; - struct tsdev *evdev = list->tsdev; - struct input_dev *dev = tsdev->handle.dev; - int retval; - + struct tsdev *tsdev = list->tsdev; + int retval = 0; + switch (cmd) { - case HHEHE: - return 0; - case hjff: - return 0; - default: - return 0; + case TS_GET_CAL: + if (copy_to_user ((void *)arg, &tsdev->cal, + sizeof (struct ts_calibration))) + retval = -EFAULT; + break; + case TS_SET_CAL: + if (copy_from_user (&tsdev->cal, (void *)arg, + sizeof (struct ts_calibration))) + retval = -EFAULT; + break; + default: + retval = -EINVAL; + break; } -*/ - return -EINVAL; + + return retval; } struct file_operations tsdev_fops = { @@ -227,82 +283,85 @@ static void tsdev_event(struct input_handle *handle, unsigned int type, struct tsdev *tsdev = handle->private; struct tsdev_list *list; struct timeval time; - int size; - list_for_each_entry(list, &tsdev->list, node) { - switch (type) { - case EV_ABS: - switch (code) { - case ABS_X: - if (!list->pendown) - return; - size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; - if (size > 0) - list->oldx = ((value - handle->dev->absmin[ABS_X]) * xres / size); - else - list->oldx = ((value - handle->dev->absmin[ABS_X])); - break; - case ABS_Y: - if (!list->pendown) - return; - size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; - if (size > 0) - list->oldy = ((value - handle->dev->absmin[ABS_Y]) * yres / size); - else - list->oldy = ((value - handle->dev->absmin[ABS_Y])); - break; - case ABS_PRESSURE: - list->pendown = ((value > handle->dev-> absmin[ABS_PRESSURE])) ? - value - handle->dev->absmin[ABS_PRESSURE] : 0; - break; - } + switch (type) { + case EV_ABS: + switch (code) { + case ABS_X: + tsdev->x = value; + break; + case ABS_Y: + tsdev->y = value; + break; + case ABS_PRESSURE: + if (value > handle->dev->absmax[ABS_PRESSURE]) + value = handle->dev->absmax[ABS_PRESSURE]; + value -= handle->dev->absmin[ABS_PRESSURE]; + if (value < 0) + value = 0; + tsdev->pressure = value; + break; + } + break; + + case EV_REL: + switch (code) { + case REL_X: + tsdev->x += value; + if (tsdev->x < 0) + tsdev->x = 0; + else if (tsdev->x > xres) + tsdev->x = xres; break; + case REL_Y: + tsdev->y += value; + if (tsdev->y < 0) + tsdev->y = 0; + else if (tsdev->y > yres) + tsdev->y = yres; + break; + } + break; - case EV_REL: - switch (code) { - case REL_X: - if (!list->pendown) - return; - list->oldx += value; - if (list->oldx < 0) - list->oldx = 0; - else if (list->oldx > xres) - list->oldx = xres; + case EV_KEY: + if (code == BTN_TOUCH || code == BTN_MOUSE) { + switch (value) { + case 0: + tsdev->pressure = 0; break; - case REL_Y: - if (!list->pendown) - return; - list->oldy += value; - if (list->oldy < 0) - list->oldy = 0; - else if (list->oldy > xres) - list->oldy = xres; + case 1: + if (!tsdev->pressure) + tsdev->pressure = 1; break; } - break; - - case EV_KEY: - if (code == BTN_TOUCH || code == BTN_MOUSE) { - switch (value) { - case 0: - list->pendown = 0; - break; - case 1: - if (!list->pendown) - list->pendown = 1; - break; - case 2: - return; - } - } else - return; - break; } + break; + } + + if (type != EV_SYN || code != SYN_REPORT) + return; + + list_for_each_entry(list, &tsdev->list, node) { + int x, y, tmp; + do_gettimeofday(&time); list->event[list->head].millisecs = time.tv_usec / 100; - list->event[list->head].pressure = list->pendown; - list->event[list->head].x = list->oldx; - list->event[list->head].y = list->oldy; + list->event[list->head].pressure = tsdev->pressure; + + x = tsdev->x; + y = tsdev->y; + + /* Calibration */ + if (!list->raw) { + x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; + y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; + if (tsdev->cal.xyswap) { + tmp = x; x = y; y = tmp; + } + } + + list->event[list->head].x = x; + list->event[list->head].y = y; list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1); kill_fasync(&list->fasync, SIGIO, POLL_IN); } @@ -314,11 +373,11 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, struct input_device_id *id) { struct tsdev *tsdev; - int minor; + int minor, delta; - for (minor = 0; minor < TSDEV_MINORS && tsdev_table[minor]; + for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor]; minor++); - if (minor == TSDEV_MINORS) { + if (minor >= TSDEV_MINORS/2) { printk(KERN_ERR "tsdev: You have way too many touchscreens\n"); return NULL; @@ -340,10 +399,25 @@ static struct input_handle *tsdev_connect(struct input_handler *handler, tsdev->handle.handler = handler; tsdev->handle.private = tsdev; + /* Precompute the rough calibration matrix */ + delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; + if (delta == 0) + delta = 1; + tsdev->cal.xscale = (xres << 8) / delta; + tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8); + + delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1; + if (delta == 0) + delta = 1; + tsdev->cal.yscale = (yres << 8) / delta; + tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); + tsdev_table[minor] = tsdev; - + devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor); + devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor + TSDEV_MINORS/2), + S_IFCHR|S_IRUGO|S_IWUSR, "input/tsraw%d", minor); class_simple_device_add(input_class, MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor), dev->dev, "ts%d", minor); @@ -362,6 +436,7 @@ static void tsdev_disconnect(struct input_handle *handle) wake_up_interruptible(&tsdev->wait); } else tsdev_free(tsdev); + devfs_remove("input/tsraw%d", tsdev->minor); } static struct input_device_id tsdev_ids[] = { @@ -379,6 +454,12 @@ static struct input_device_id tsdev_ids[] = { .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, },/* A tablet like device, at least touch detection, two absolute axes */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT(EV_ABS) }, + .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, + },/* A tablet like device with several gradations of pressure */ + {},/* Terminating entry */ }; -- cgit v1.2.3 From 8f10a98a3ea09154d8e34d5485b0824a770bc354 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Mon, 7 Jun 2004 00:13:56 +0200 Subject: input: Remove OSB4/Profusion hack in i8042, as it's handled by DMI blacklist now. Signed-off-by: Vojtech Pavlik --- drivers/input/serio/i8042.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 07d78215b159..b1b3ed2d11b1 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -481,17 +481,8 @@ static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param != 0xa9) return -1; param = 0xa4; - if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b) { - -/* - * Do another loop test with the 0x5a value. Doing anything else upsets - * Profusion/ServerWorks OSB4 chipsets. - */ - - param = 0x5a; - i8042_command(¶m, I8042_CMD_AUX_LOOP); + if (i8042_command(¶m, I8042_CMD_AUX_LOOP) || param == 0x5b) return -1; - } if (mux_version) *mux_version = ~param; -- cgit v1.2.3 From 214b78050b3a8933f6550ff75af78bd34e8d4024 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sat, 12 Jun 2004 17:55:01 +0200 Subject: Input: rearrangements and cleanups in serio.c Signed-off-by: Vojtech Pavlik --- drivers/input/serio/serio.c | 191 +++++++++++++++++++++++--------------------- 1 file changed, 102 insertions(+), 89 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index c810919d255d..01148d4499fc 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -1,11 +1,9 @@ -/* - * $Id: serio.c,v 1.15 2002/01/22 21:12:03 vojtech Exp $ - * - * Copyright (c) 1999-2001 Vojtech Pavlik - */ - /* * The Serio abstraction module + * + * Copyright (c) 1999-2004 Vojtech Pavlik + * Copyright (c) 2004 Dmitry Torokhov + * Copyright (c) 2003 Daniele Bellucci */ /* @@ -26,10 +24,6 @@ * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - * - * Changes: - * 20 Jul. 2003 Daniele Bellucci - * Minor cleanups. */ #include @@ -61,23 +55,11 @@ EXPORT_SYMBOL(serio_close); EXPORT_SYMBOL(serio_rescan); EXPORT_SYMBOL(serio_reconnect); -struct serio_event { - int type; - struct serio *serio; - struct list_head node; -}; - - -static spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED; /* protects serio_event_list */ static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_dev_list */ static LIST_HEAD(serio_list); static LIST_HEAD(serio_dev_list); -static LIST_HEAD(serio_event_list); -static int serio_pid; -/* - * serio_find_dev() must be called with serio_sem down. - */ +/* serio_find_dev() must be called with serio_sem down. */ static void serio_find_dev(struct serio *serio) { @@ -91,54 +73,74 @@ static void serio_find_dev(struct serio *serio) } } -#define SERIO_RESCAN 1 -#define SERIO_RECONNECT 2 -#define SERIO_REGISTER_PORT 3 -#define SERIO_UNREGISTER_PORT 4 +/* + * Serio event processing. + */ +struct serio_event { + int type; + struct serio *serio; + struct list_head node; +}; + +enum serio_event_type { + SERIO_RESCAN, + SERIO_RECONNECT, + SERIO_REGISTER_PORT, + SERIO_UNREGISTER_PORT, +}; + +static spinlock_t serio_event_lock = SPIN_LOCK_UNLOCKED; /* 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 void serio_remove_pending_events(struct serio *serio) +static void serio_queue_event(struct serio *serio, int event_type) { - struct list_head *node, *next; - struct serio_event *event; unsigned long flags; + struct serio_event *event; spin_lock_irqsave(&serio_event_lock, flags); - list_for_each_safe(node, next, &serio_event_list) { - event = container_of(node, struct serio_event, node); - if (event->serio == serio) { - list_del_init(node); - kfree(event); - } + if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { + event->type = event_type; + event->serio = serio; + + list_add_tail(&event->node, &serio_event_list); + wake_up(&serio_wait); } spin_unlock_irqrestore(&serio_event_lock, flags); } -void serio_handle_events(void) +static struct serio_event *serio_get_event(void) { - struct list_head *node; struct serio_event *event; + struct list_head *node; unsigned long flags; + spin_lock_irqsave(&serio_event_lock, flags); - while (1) { + if (list_empty(&serio_event_list)) { + spin_unlock_irqrestore(&serio_event_lock, flags); + return NULL; + } - spin_lock_irqsave(&serio_event_lock, flags); + node = serio_event_list.next; + event = container_of(node, struct serio_event, node); + list_del_init(node); - if (list_empty(&serio_event_list)) { - spin_unlock_irqrestore(&serio_event_lock, flags); - break; - } + spin_unlock_irqrestore(&serio_event_lock, flags); - node = serio_event_list.next; - event = container_of(node, struct serio_event, node); - list_del_init(node); + return event; +} - spin_unlock_irqrestore(&serio_event_lock, flags); +static void serio_handle_events(void) +{ + struct serio_event *event; + + while ((event = serio_get_event())) { down(&serio_sem); @@ -171,6 +173,26 @@ void serio_handle_events(void) } } +static void serio_remove_pending_events(struct serio *serio) +{ + struct list_head *node, *next; + struct serio_event *event; + unsigned long flags; + + spin_lock_irqsave(&serio_event_lock, flags); + + list_for_each_safe(node, next, &serio_event_list) { + event = container_of(node, struct serio_event, node); + if (event->serio == serio) { + list_del_init(node); + kfree(event); + } + } + + spin_unlock_irqrestore(&serio_event_lock, flags); +} + + static int serio_thread(void *nothing) { lock_kernel(); @@ -190,23 +212,10 @@ static int serio_thread(void *nothing) complete_and_exit(&serio_exited, 0); } -static void serio_queue_event(struct serio *serio, int event_type) -{ - unsigned long flags; - struct serio_event *event; - - spin_lock_irqsave(&serio_event_lock, flags); - - if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) { - event->type = event_type; - event->serio = serio; - - list_add_tail(&event->node, &serio_event_list); - wake_up(&serio_wait); - } - spin_unlock_irqrestore(&serio_event_lock, flags); -} +/* + * Serio port operations + */ void serio_rescan(struct serio *serio) { @@ -218,31 +227,6 @@ void serio_reconnect(struct serio *serio) serio_queue_event(serio, SERIO_RECONNECT); } -irqreturn_t serio_interrupt(struct serio *serio, - unsigned char data, unsigned int dfl, struct pt_regs *regs) -{ - unsigned long flags; - irqreturn_t ret = IRQ_NONE; - - spin_lock_irqsave(&serio->lock, flags); - - if (likely(serio->dev)) { - ret = serio->dev->interrupt(serio, data, dfl, regs); - } else { - if (!dfl) { - if ((serio->type != SERIO_8042 && - serio->type != SERIO_8042_XL) || (data == 0xaa)) { - serio_rescan(serio); - ret = IRQ_HANDLED; - } - } - } - - spin_unlock_irqrestore(&serio->lock, flags); - - return ret; -} - void serio_register_port(struct serio *serio) { down(&serio_sem); @@ -302,6 +286,10 @@ void __serio_unregister_port(struct serio *serio) serio->dev->disconnect(serio); } +/* + * Serio device operations + */ + void serio_register_device(struct serio_dev *dev) { struct serio *serio; @@ -357,6 +345,31 @@ void serio_close(struct serio *serio) spin_unlock_irqrestore(&serio->lock, flags); } +irqreturn_t serio_interrupt(struct serio *serio, + unsigned char data, unsigned int dfl, struct pt_regs *regs) +{ + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + + spin_lock_irqsave(&serio->lock, flags); + + if (likely(serio->dev)) { + ret = serio->dev->interrupt(serio, data, dfl, regs); + } else { + if (!dfl) { + if ((serio->type != SERIO_8042 && + serio->type != SERIO_8042_XL) || (data == 0xaa)) { + serio_rescan(serio); + ret = IRQ_HANDLED; + } + } + } + + spin_unlock_irqrestore(&serio->lock, flags); + + return ret; +} + static int __init serio_init(void) { int pid; -- cgit v1.2.3 From 700faee4db8a54c61476ab5d1b8039d7fa6873e9 Mon Sep 17 00:00:00 2001 From: Zinx Verituse Date: Thu, 17 Jun 2004 12:38:07 +0200 Subject: input: Fix bad struct hidinput initialization in hid-tmff.c Signed-off-by: Vojtech Pavlik --- drivers/usb/input/hid-tmff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c index 8fd0e489e734..8f6a0a6f94a9 100644 --- a/drivers/usb/input/hid-tmff.c +++ b/drivers/usb/input/hid-tmff.c @@ -110,7 +110,7 @@ int hid_tmff_init(struct hid_device *hid) { struct tmff_device *private; struct list_head *pos; - struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list); + struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL); if (!private) -- cgit v1.2.3 From d2460be416cf7314eaeb73dbf4f1e1832b86176f Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Mon, 21 Jun 2004 11:48:47 +0200 Subject: input: Remove an extra dmi_noloop declaration in i8042.c Signed-off-by: Vojtech Pavlik --- drivers/input/serio/i8042.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 36da15b1bf5b..6f4df27d0214 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -52,9 +52,10 @@ static unsigned int i8042_dumbkbd; module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); +#ifdef __i386__ extern unsigned int i8042_dmi_noloop; +#endif static unsigned int i8042_noloop; -extern unsigned int i8042_dmi_noloop; __obsolete_setup("i8042_noaux"); __obsolete_setup("i8042_nomux"); -- cgit v1.2.3 From fce5a558fca5fd4c7ce2af4770222d22b251a589 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 21 Jun 2004 12:35:20 +0200 Subject: input: Enhancements/fixes for PSX pad support: * Adds support for more than one controller. Previously more than one controller was initialized and the docs said they worked, but only one was actually read. * Removes unnecessary detection on initialization. This allows the module to be initialized without controllers plugged in (hot swapping controllers works). This removes a warning if the user has an unrecognized controller plugged in, but the only unrecognized controller I have been able to find information about online is the PSX mouse, which I've never actually seen. * Adds a GC_DDR option value to have direction presses register as buttons instead of axes. Allows the module to be used for Dance Dance Revolution emulators like Stepmania. * Adds psx_* to documentation. Signed-off-by: Vojtech Pavlik --- Documentation/input/joystick-parport.txt | 13 ++- drivers/input/joystick/gamecon.c | 194 ++++++++++++++++--------------- 2 files changed, 113 insertions(+), 94 deletions(-) diff --git a/Documentation/input/joystick-parport.txt b/Documentation/input/joystick-parport.txt index b8d92c008a7d..88a011c9f985 100644 --- a/Documentation/input/joystick-parport.txt +++ b/Documentation/input/joystick-parport.txt @@ -335,6 +335,7 @@ controller (compatible with DirectPadPro): * Analog PSX Pad (red mode) * Analog PSX Pad (green mode) * PSX Rumble Pad + * PSX DDR Pad 2.4 Sega ~~~~~~~~ @@ -452,14 +453,22 @@ uses the following kernel/module command line: 5 | Multisystem 2-button joystick 6 | N64 pad 7 | Sony PSX controller + 8 | Sony PSX DDR controller - The exact type of the PSX controller type is autoprobed, so you must have -your controller plugged in before initializing. + The exact type of the PSX controller type is autoprobed when used so +hot swapping should work (but is not recomended). Should you want to use more than one of parallel ports at once, you can use gamecon.map2 and gamecon.map3 as additional command line parameters for two more parallel ports. + There are two options specific to PSX driver portion. gamecon.psx_delay sets +the command delay when talking to the controllers. The default of 25 should +work but you can try lowering it for better performace. If your pads don't +respond try raising it untill they work. Setting the type to 8 allows the +driver to be used with Dance Dance Revolution or similar games. Arrow keys are +registered as key presses instead of X and Y axes. + 3.2 db9.c ~~~~~~~~~ Apart from making an interface, there is nothing difficult on using the diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 555fb362ba31..a1fd6e31044d 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -1,17 +1,14 @@ /* - * $Id: gamecon.c,v 1.22 2002/07/01 15:42:25 vojtech Exp $ + * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux * - * Copyright (c) 1999-2001 Vojtech Pavlik + * Copyright (c) 1999-2004 Vojtech Pavlik + * Copyright (c) 2004 Peter Nelson * * Based on the work of: * Andree Borrmann John Dahlstrom * David Kuder Nathan Hand */ -/* - * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux - */ - /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -72,8 +69,9 @@ __obsolete_setup("gc_3="); #define GC_MULTI2 5 #define GC_N64 6 #define GC_PSX 7 +#define GC_DDR 8 -#define GC_MAX 7 +#define GC_MAX 8 #define GC_REFRESH_TIME HZ/100 @@ -91,7 +89,8 @@ static struct gc *gc_base[3]; static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", - "Multisystem 2-button joystick", "N64 controller", "PSX controller" }; + "Multisystem 2-button joystick", "N64 controller", "PSX controller" + "PSX DDR controller" }; /* * N64 support. */ @@ -237,7 +236,7 @@ static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data) #define GC_PSX_RUMBLE 7 /* Rumble in Red mode */ #define GC_PSX_CLOCK 0x04 /* Pin 4 */ -#define GC_PSX_COMMAND 0x01 /* Pin 1 */ +#define GC_PSX_COMMAND 0x01 /* Pin 2 */ #define GC_PSX_POWER 0xf8 /* Pins 5-9 */ #define GC_PSX_SELECT 0x02 /* Pin 3 */ @@ -253,25 +252,29 @@ __obsolete_setup("gc_psx_delay="); static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y }; static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR }; +static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 }; /* * gc_psx_command() writes 8bit command and reads 8bit data from * the psx pad. */ -static int gc_psx_command(struct gc *gc, int b) +static void gc_psx_command(struct gc *gc, int b, unsigned char data[GC_PSX_LENGTH]) { - int i, cmd, data = 0; + int i, j, cmd, read; + for (i = 0; i < 5; i++) + data[i] = 0; for (i = 0; i < 8; i++, b >>= 1) { cmd = (b & 1) ? GC_PSX_COMMAND : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_POWER); udelay(gc_psx_delay); - data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0; + read = parport_read_status(gc->pd->port) ^ 0x80; + for (j = 0; j < 5; j++) + data[j] |= (read & gc_status_bit[j] & gc->pads[GC_PSX]) ? (1 << i) : 0; parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); udelay(gc_psx_delay); } - return data; } /* @@ -279,30 +282,39 @@ static int gc_psx_command(struct gc *gc, int b) * device identifier code. */ -static int gc_psx_read_packet(struct gc *gc, unsigned char *data) +static void gc_psx_read_packet(struct gc *gc, unsigned char data[5][GC_PSX_LENGTH], unsigned char id[5]) { - int i, id; + int i, j, max_len = 0; unsigned long flags; + unsigned char data2[5]; parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */ - udelay(gc_psx_delay * 2); + udelay(gc_psx_delay); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ - udelay(gc_psx_delay * 2); + udelay(gc_psx_delay); local_irq_save(flags); - gc_psx_command(gc, 0x01); /* Access pad */ - id = gc_psx_command(gc, 0x42); /* Get device id */ - if (gc_psx_command(gc, 0) == 0x5a) { /* Okay? */ - for (i = 0; i < GC_PSX_LEN(id) * 2; i++) - data[i] = gc_psx_command(gc, 0); - } else id = 0; + gc_psx_command(gc, 0x01, data2); /* Access pad */ + gc_psx_command(gc, 0x42, id); /* Get device ids */ + gc_psx_command(gc, 0, data2); /* Dump status */ + + for (i =0; i < 5; i++) /* Find the longest pad */ + if((gc_status_bit[i] & gc->pads[GC_PSX]) && (GC_PSX_LEN(id[i]) > max_len)) + max_len = GC_PSX_LEN(id[i]); + + for (i = 0; i < max_len * 2; i++) { /* Read in all the data */ + gc_psx_command(gc, 0, data2); + for (j = 0; j < 5; j++) + data[j][i] = data2[j]; + } local_irq_restore(flags); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); - return GC_PSX_ID(id); + for(i = 0; i < 5; i++) /* Set id's to the real value */ + id[i] = GC_PSX_ID(id[i]); } /* @@ -316,6 +328,7 @@ static void gc_timer(unsigned long private) struct gc *gc = (void *) private; struct input_dev *dev = gc->dev; unsigned char data[GC_MAX_LENGTH]; + unsigned char data_psx[5][GC_PSX_LENGTH]; int i, j, s; /* @@ -412,53 +425,72 @@ static void gc_timer(unsigned long private) * PSX controllers */ - if (gc->pads[GC_PSX]) { + if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) { - for (i = 0; i < 5; i++) - if (gc->pads[GC_PSX] & gc_status_bit[i]) - break; + gc_psx_read_packet(gc, data_psx, data); - switch (gc_psx_read_packet(gc, data)) { + for (i = 0; i < 5; i++) { + switch (data[i]) { - case GC_PSX_RUMBLE: + case GC_PSX_RUMBLE: - input_report_key(dev + i, BTN_THUMBL, ~data[0] & 0x04); - input_report_key(dev + i, BTN_THUMBR, ~data[0] & 0x02); - input_sync(dev + i); + input_report_key(dev + i, BTN_THUMBL, ~data_psx[i][0] & 0x04); + input_report_key(dev + i, BTN_THUMBR, ~data_psx[i][0] & 0x02); - case GC_PSX_NEGCON: - case GC_PSX_ANALOG: + case GC_PSX_NEGCON: + case GC_PSX_ANALOG: - for (j = 0; j < 4; j++) - input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]); + if(gc->pads[GC_DDR] & gc_status_bit[i]) { + for(j = 0; j < 4; j++) + input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + } else { + for (j = 0; j < 4; j++) + input_report_abs(dev + i, gc_psx_abs[j+2], data_psx[i][j + 2]); - input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80)); - input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10)); + input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); + } - for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data[0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(dev + i); - break; + break; - case GC_PSX_NORMAL: + case GC_PSX_NORMAL: + if(gc->pads[GC_DDR] & gc_status_bit[i]) { + for(j = 0; j < 4; j++) + input_report_key(dev + i, gc_psx_ddr_btn[j], ~data_psx[i][0] & (0x10 << j)); + } else { + input_report_abs(dev + i, ABS_X, 128 + !(data_psx[i][0] & 0x20) * 127 - !(data_psx[i][0] & 0x80) * 128); + input_report_abs(dev + i, ABS_Y, 128 + !(data_psx[i][0] & 0x40) * 127 - !(data_psx[i][0] & 0x10) * 128); - input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128); - input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128); + /* for some reason if the extra axes are left unset they drift */ + /* for (j = 0; j < 4; j++) + input_report_abs(dev + i, gc_psx_abs[j+2], 128); + * This needs to be debugged properly, + * maybe fuzz processing needs to be done in input_sync() + * --vojtech + */ + } - for (j = 0; j < 8; j++) - input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j)); + for (j = 0; j < 8; j++) + input_report_key(dev + i, gc_psx_btn[j], ~data_psx[i][1] & (1 << j)); - input_report_key(dev + i, BTN_START, ~data[0] & 0x08); - input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01); + input_report_key(dev + i, BTN_START, ~data_psx[i][0] & 0x08); + input_report_key(dev + i, BTN_SELECT, ~data_psx[i][0] & 0x01); - input_sync(dev + i); + input_sync(dev + i); - break; + break; + + case 0: /* not a pad, ignore */ + break; + } } } @@ -490,8 +522,7 @@ static struct gc __init *gc_probe(int *config, int nargs) { struct gc *gc; struct parport *pp; - int i, j, psx; - unsigned char data[32]; + int i, j; if (config[0] < 0) return NULL; @@ -588,43 +619,22 @@ static struct gc __init *gc_probe(int *config, int nargs) break; case GC_PSX: - - psx = gc_psx_read_packet(gc, data); - - switch(psx) { - case GC_PSX_NEGCON: - case GC_PSX_NORMAL: - case GC_PSX_ANALOG: - case GC_PSX_RUMBLE: - - for (j = 0; j < 6; j++) { - psx = gc_psx_abs[j]; - set_bit(psx, gc->dev[i].absbit); - if (j < 4) { - gc->dev[i].absmin[psx] = 4; - gc->dev[i].absmax[psx] = 252; - gc->dev[i].absflat[psx] = 2; - } else { - gc->dev[i].absmin[psx] = -1; - gc->dev[i].absmax[psx] = 1; - } - } - - for (j = 0; j < 12; j++) - set_bit(gc_psx_btn[j], gc->dev[i].keybit); - - break; - - case 0: - gc->pads[GC_PSX] &= ~gc_status_bit[i]; - printk(KERN_ERR "gamecon.c: No PSX controller found.\n"); - break; - - default: - gc->pads[GC_PSX] &= ~gc_status_bit[i]; - printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x," - " please report to .\n", psx); + case GC_DDR: + if(config[i + 1] == GC_DDR) { + for (j = 0; j < 4; j++) + set_bit(gc_psx_ddr_btn[j], gc->dev[i].keybit); + } else { + for (j = 0; j < 6; j++) { + set_bit(gc_psx_abs[j], gc->dev[i].absbit); + gc->dev[i].absmin[gc_psx_abs[j]] = 4; + gc->dev[i].absmax[gc_psx_abs[j]] = 252; + gc->dev[i].absflat[gc_psx_abs[j]] = 2; + } } + + for (j = 0; j < 12; j++) + set_bit(gc_psx_btn[j], gc->dev[i].keybit); + break; } -- cgit v1.2.3 From 20c48df4f0c78f4ee1e7b186d7e99eb3dd72e9ab Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Tue, 22 Jun 2004 00:31:56 +0200 Subject: input: when probing for ImExPS/2 mice, the ImPS/2 sequence needs to be sent first, but the result should be ignored. Signed-off-by: Vojtech Pavlik --- drivers/input/mouse/psmouse-base.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 4d85232f7d8a..97f3e795001e 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -418,6 +418,8 @@ static int im_explorer_detect(struct psmouse *psmouse) { unsigned char param[2]; + intellimouse_detect(psmouse); + param[0] = 200; psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); param[0] = 200; -- cgit v1.2.3 From d1b0ad5ab4adf1c1a4aa36b1e3923c1622e8c2b7 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Wed, 23 Jun 2004 12:06:20 +0200 Subject: input: Fix array overflows in keyboard.c when KEY_MAX > keycode > NR_KEYS > 128. Signed-off-by: Vojtech Pavlik --- drivers/char/keyboard.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 52efa77cf2d6..dc008cd71386 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -124,7 +124,7 @@ int shift_state = 0; */ static struct input_handler kbd_handler; -static unsigned long key_down[256/BITS_PER_LONG]; /* keyboard key bitmap */ +static unsigned long key_down[NBITS(KEY_MAX)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static int dead_key_next; static int npadch = -1; /* -1 or number assembled on pad */ @@ -143,7 +143,7 @@ static struct ledptr { /* Simple translation table for the SysRq keys */ #ifdef CONFIG_MAGIC_SYSRQ -unsigned char kbd_sysrq_xlate[128] = +unsigned char kbd_sysrq_xlate[KEY_MAX] = "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ @@ -1133,6 +1133,9 @@ void kbd_keycode(unsigned int keycode, int down, int hw_raw, struct pt_regs *reg return; } + if (keycode > NR_KEYS) + return; + keysym = key_map[keycode]; type = KTYP(keysym); -- cgit v1.2.3 From 9283deedc8e29eb15a2e58b7c0dbcead7df936f9 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Wed, 23 Jun 2004 23:58:19 +0200 Subject: input: Add Dell SB Live! PCI ID to the emu10k1-gp driver. Reported-by: Francisco Moraes Signed-off-by: Vojtech Pavlik --- drivers/input/gameport/emu10k1-gp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index 89d469378de8..99d649109197 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -50,8 +50,10 @@ struct emu { }; static struct pci_device_id emu_tbl[] = { + { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ + { 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */ { 0, } }; -- cgit v1.2.3 From f163d52fd532906ec60e23f456f048e52a987cf7 Mon Sep 17 00:00:00 2001 From: James Courtier-Dutton Date: Thu, 24 Jun 2004 02:19:54 +0200 Subject: input: Add Audigy LS PCI ID to emu10k1-gp.c Signed-off-by: Vojtech Pavlik --- drivers/input/gameport/emu10k1-gp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c index 99d649109197..1c478a7a7bd0 100644 --- a/drivers/input/gameport/emu10k1-gp.c +++ b/drivers/input/gameport/emu10k1-gp.c @@ -54,6 +54,7 @@ static struct pci_device_id emu_tbl[] = { { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live gameport */ { 0x1102, 0x7003, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy gameport */ { 0x1102, 0x7004, PCI_ANY_ID, PCI_ANY_ID }, /* Dell SB Live */ + { 0x1102, 0x7005, PCI_ANY_ID, PCI_ANY_ID }, /* Audigy LS gameport */ { 0, } }; -- cgit v1.2.3 From 1757fd9195e75f2dd76a14a383f987366d1e5007 Mon Sep 17 00:00:00 2001 From: Carsten Rietzschel Date: Thu, 24 Jun 2004 19:44:37 +0200 Subject: input: Add CodeMercs IOWarrior to hid-core device blacklist. Signed-off-by: Vojtech Pavlik --- drivers/usb/input/hid-core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index ff0010d953fa..40b578818889 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1430,6 +1430,11 @@ void hid_init_reports(struct hid_device *hid) #define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 #define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 +#define USB_VENDOR_ID_CODEMERCS 0x07c0 +#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500 +#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501 + + static struct hid_blacklist { __u16 idVendor; __u16 idProduct; @@ -1444,20 +1449,20 @@ static struct hid_blacklist { { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE }, - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE }, -- cgit v1.2.3 From c256c1a3b4ca8bf7867de095f65e07ae356660da Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Thu, 24 Jun 2004 21:55:29 +0200 Subject: input: Fix Peter Nelson's e-mail address in gamecon.c Signed-off-by: Vojtech Pavlik --- drivers/input/joystick/gamecon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index a1fd6e31044d..46326b701743 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -2,7 +2,7 @@ * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux * * Copyright (c) 1999-2004 Vojtech Pavlik - * Copyright (c) 2004 Peter Nelson + * Copyright (c) 2004 Peter Nelson * * Based on the work of: * Andree Borrmann John Dahlstrom -- cgit v1.2.3 From cac8e9e5789cd82e603d1ee93a44f05561bcc39c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jun 2004 15:25:59 -0500 Subject: Input: make connect and disconnect methods mandatory for serio drivers since that's where serio_{open|close} are called from to actually bind driver to a port. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 01148d4499fc..b130e0d3191f 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -68,8 +68,7 @@ static void serio_find_dev(struct serio *serio) list_for_each_entry(dev, &serio_dev_list, node) { if (serio->dev) break; - if (dev->connect) - dev->connect(serio, dev); + dev->connect(serio, dev); } } @@ -160,7 +159,7 @@ static void serio_handle_events(void) /* reconnect failed - fall through to rescan */ case SERIO_RESCAN : - if (event->serio->dev && event->serio->dev->disconnect) + if (event->serio->dev) event->serio->dev->disconnect(event->serio); serio_find_dev(event->serio); break; @@ -282,7 +281,7 @@ void __serio_unregister_port(struct serio *serio) { serio_remove_pending_events(serio); list_del_init(&serio->node); - if (serio->dev && serio->dev->disconnect) + if (serio->dev) serio->dev->disconnect(serio); } @@ -296,7 +295,7 @@ void serio_register_device(struct serio_dev *dev) down(&serio_sem); list_add_tail(&dev->node, &serio_dev_list); list_for_each_entry(serio, &serio_list, node) - if (!serio->dev && dev->connect) + if (!serio->dev) dev->connect(serio, dev); up(&serio_sem); } @@ -309,7 +308,7 @@ void serio_unregister_device(struct serio_dev *dev) list_del_init(&dev->node); list_for_each_entry(serio, &serio_list, node) { - if (serio->dev == dev && dev->disconnect) + if (serio->dev == dev) dev->disconnect(serio); serio_find_dev(serio); } -- cgit v1.2.3 From 7990a353f46a91cd9d5948d9b14826e1e08e975d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jun 2004 15:26:36 -0500 Subject: Input: rename serio->driver to serio->port_data in preparation to sysfs integration Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 4 ++-- drivers/input/serio/ambakmi.c | 22 +++++++++++----------- drivers/input/serio/gscps2.c | 8 ++++---- drivers/input/serio/i8042.c | 14 +++++++------- drivers/input/serio/maceps2.c | 36 ++++++++++++++++++------------------ drivers/input/serio/pcips2.c | 8 ++++---- drivers/input/serio/sa1111ps2.c | 8 ++++---- drivers/input/serio/serport.c | 6 +++--- drivers/serial/sunsu.c | 8 ++++---- drivers/serial/sunzilog.c | 8 ++++---- include/linux/serio.h | 2 +- 11 files changed, 62 insertions(+), 62 deletions(-) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 2bd152fe02bc..11542272632d 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -214,7 +214,7 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode) ****************************************************************************/ static int synaptics_pt_write(struct serio *port, unsigned char c) { - struct psmouse *parent = port->driver; + struct psmouse *parent = port->port_data; char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ if (psmouse_sliced_command(parent, c)) @@ -273,7 +273,7 @@ static void synaptics_pt_create(struct psmouse *psmouse) port->serio.name = "Synaptics pass-through"; port->serio.phys = "synaptics-pt/serio0"; port->serio.write = synaptics_pt_write; - port->serio.driver = psmouse; + port->serio.port_data = psmouse; port->activate = synaptics_pt_activate; } diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 6a780c10fc73..5d7879dfef13 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -54,7 +54,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) static int amba_kmi_write(struct serio *io, unsigned char val) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; unsigned int timeleft = 10000; /* timeout in 100ms */ while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--) @@ -68,7 +68,7 @@ static int amba_kmi_write(struct serio *io, unsigned char val) static int amba_kmi_open(struct serio *io) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; unsigned int divisor; int ret; @@ -105,7 +105,7 @@ static int amba_kmi_open(struct serio *io) static void amba_kmi_close(struct serio *io) { - struct amba_kmi_port *kmi = io->driver; + struct amba_kmi_port *kmi = io->port_data; writeb(0, KMICR); @@ -131,15 +131,15 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) memset(kmi, 0, sizeof(struct amba_kmi_port)); - kmi->io.type = SERIO_8042; - kmi->io.write = amba_kmi_write; - kmi->io.open = amba_kmi_open; - kmi->io.close = amba_kmi_close; - kmi->io.name = dev->dev.bus_id; - kmi->io.phys = dev->dev.bus_id; - kmi->io.driver = kmi; + kmi->io.type = SERIO_8042; + kmi->io.write = amba_kmi_write; + kmi->io.open = amba_kmi_open; + kmi->io.close = amba_kmi_close; + kmi->io.name = dev->dev.bus_id; + kmi->io.phys = dev->dev.bus_id; + kmi->io.port_data = kmi; - kmi->base = ioremap(dev->res.start, KMI_SIZE); + kmi->base = ioremap(dev->res.start, KMI_SIZE); if (!kmi->base) { ret = -ENOMEM; goto out; diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 48a0ad587160..f649e0aa5777 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -288,7 +288,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) static int gscps2_write(struct serio *port, unsigned char data) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; if (!gscps2_writeb_output(ps2port, data)) { printk(KERN_DEBUG PFX "sending byte %#x failed.\n", data); @@ -304,7 +304,7 @@ static int gscps2_write(struct serio *port, unsigned char data) static int gscps2_open(struct serio *port) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; gscps2_reset(ps2port); @@ -319,7 +319,7 @@ static int gscps2_open(struct serio *port) static void gscps2_close(struct serio *port) { - struct gscps2port *ps2port = port->driver; + struct gscps2port *ps2port = port->port_data; gscps2_enable(ps2port, DISABLE); } @@ -372,7 +372,7 @@ static int __init gscps2_probe(struct parisc_device *dev) (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" ); memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port)); - ps2port->port.driver = ps2port; + ps2port->port.port_data = ps2port; ps2port->port.name = ps2port->name; ps2port->port.phys = dev->dev.bus_id; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 6f4df27d0214..843327c323ce 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -223,7 +223,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c) static int i8042_aux_write(struct serio *port, unsigned char c) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; int retval; /* @@ -251,7 +251,7 @@ static int i8042_aux_write(struct serio *port, unsigned char c) static int i8042_activate_port(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; i8042_flush(); @@ -279,7 +279,7 @@ static int i8042_activate_port(struct serio *port) static int i8042_open(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; if (values->mux != -1) if (i8042_mux_open++) @@ -318,7 +318,7 @@ irq_fail: static void i8042_close(struct serio *port) { - struct i8042_values *values = port->driver; + struct i8042_values *values = port->port_data; if (values->mux != -1) if (--i8042_mux_open) @@ -353,7 +353,7 @@ static struct serio i8042_kbd_port = .write = i8042_kbd_write, .open = i8042_open, .close = i8042_close, - .driver = &i8042_kbd_values, + .port_data = &i8042_kbd_values, .name = "i8042 Kbd Port", .phys = I8042_KBD_PHYS_DESC, }; @@ -371,7 +371,7 @@ static struct serio i8042_aux_port = .write = i8042_aux_write, .open = i8042_open, .close = i8042_close, - .driver = &i8042_aux_values, + .port_data = &i8042_aux_values, .name = "i8042 Aux Port", .phys = I8042_AUX_PHYS_DESC, }; @@ -941,7 +941,7 @@ static void __init i8042_init_mux_values(struct i8042_values *values, struct ser sprintf(i8042_mux_short[index], "AUX%d", index); port->name = i8042_mux_names[index]; port->phys = i8042_mux_phys[index]; - port->driver = values; + port->port_data = values; values->name = i8042_mux_short[index]; values->mux = index; } diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index c7db1de49cfc..bab997a7fcf6 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -54,7 +54,7 @@ struct maceps2_data { static int maceps2_write(struct serio *dev, unsigned char val) { - struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; unsigned int timeout = MACE_PS2_TIMEOUT; do { @@ -72,7 +72,7 @@ static irqreturn_t maceps2_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct serio *dev = dev_id; - struct mace_ps2port *port = ((struct maceps2_data *)dev->driver)->port; + struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; unsigned int byte; if (mace_read(port->status) & PS2_STATUS_RX_FULL) { @@ -85,7 +85,7 @@ static irqreturn_t maceps2_interrupt(int irq, void *dev_id, static int maceps2_open(struct serio *dev) { - struct maceps2_data *data = (struct maceps2_data *)dev->driver; + struct maceps2_data *data = (struct maceps2_data *)dev->port_data; if (request_irq(data->irq, maceps2_interrupt, 0, "PS/2 port", dev)) { printk(KERN_ERR "Could not allocate PS/2 IRQ\n"); @@ -106,7 +106,7 @@ static int maceps2_open(struct serio *dev) static void maceps2_close(struct serio *dev) { - struct maceps2_data *data = (struct maceps2_data *)dev->driver; + struct maceps2_data *data = (struct maceps2_data *)dev->port_data; mace_write(PS2_CONTROL_TX_CLOCK_DISABLE | PS2_CONTROL_RESET, data->port->control); @@ -118,24 +118,24 @@ static struct maceps2_data port0_data, port1_data; static struct serio maceps2_port0 = { - .type = SERIO_8042, - .open = maceps2_open, - .close = maceps2_close, - .write = maceps2_write, - .name = "MACE PS/2 port0", - .phys = "mace/serio0", - .driver = &port0_data, + .type = SERIO_8042, + .open = maceps2_open, + .close = maceps2_close, + .write = maceps2_write, + .name = "MACE PS/2 port0", + .phys = "mace/serio0", + .port_data = &port0_data, }; static struct serio maceps2_port1 = { - .type = SERIO_8042, - .open = maceps2_open, - .close = maceps2_close, - .write = maceps2_write, - .name = "MACE PS/2 port1", - .phys = "mace/serio1", - .driver = &port1_data, + .type = SERIO_8042, + .open = maceps2_open, + .close = maceps2_close, + .write = maceps2_write, + .name = "MACE PS/2 port1", + .phys = "mace/serio1", + .port_data = &port1_data, }; static int __init maceps2_init(void) diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 2b4acac9439c..ab67c0713aec 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -45,7 +45,7 @@ struct pcips2_data { static int pcips2_write(struct serio *io, unsigned char val) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; unsigned int stat; do { @@ -101,7 +101,7 @@ static void pcips2_flush_input(struct pcips2_data *ps2if) static int pcips2_open(struct serio *io) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; int ret, val = 0; outb(PS2_CTRL_ENABLE, ps2if->base); @@ -119,7 +119,7 @@ static int pcips2_open(struct serio *io) static void pcips2_close(struct serio *io) { - struct pcips2_data *ps2if = io->driver; + struct pcips2_data *ps2if = io->port_data; outb(0, ps2if->base); @@ -155,7 +155,7 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i ps2if->io.close = pcips2_close; ps2if->io.name = pci_name(dev); ps2if->io.phys = dev->dev.bus_id; - ps2if->io.driver = ps2if; + ps2if->io.port_data = ps2if; ps2if->dev = dev; ps2if->base = pci_resource_start(dev, 0); diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 9beb7575c365..3867206c9496 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -95,7 +95,7 @@ static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs) */ static int ps2_write(struct serio *io, unsigned char val) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; unsigned long flags; unsigned int head; @@ -122,7 +122,7 @@ static int ps2_write(struct serio *io, unsigned char val) static int ps2_open(struct serio *io) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; int ret; sa1111_enable_device(ps2if->dev); @@ -154,7 +154,7 @@ static int ps2_open(struct serio *io) static void ps2_close(struct serio *io) { - struct ps2if *ps2if = io->driver; + struct ps2if *ps2if = io->port_data; sa1111_writel(0, ps2if->base + SA1111_PS2CR); @@ -247,7 +247,7 @@ static int ps2_probe(struct sa1111_dev *dev) ps2if->io.close = ps2_close; ps2if->io.name = dev->dev.bus_id; ps2if->io.phys = dev->dev.bus_id; - ps2if->io.driver = ps2if; + ps2if->io.port_data = ps2if; ps2if->dev = dev; sa1111_set_drvdata(dev, ps2if); diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 19e269249a29..175ef49ca1f9 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -44,13 +44,13 @@ char serport_name[] = "Serial port"; static int serport_serio_write(struct serio *serio, unsigned char data) { - struct serport *serport = serio->driver; + struct serport *serport = serio->port_data; return -(serport->tty->driver->write(serport->tty, 0, &data, 1) != 1); } static void serport_serio_close(struct serio *serio) { - struct serport *serport = serio->driver; + struct serport *serport = serio->port_data; serport->serio.type = 0; wake_up_interruptible(&serport->wait); @@ -83,7 +83,7 @@ static int serport_ldisc_open(struct tty_struct *tty) serport->serio.type = SERIO_RS232; serport->serio.write = serport_serio_write; serport->serio.close = serport_serio_close; - serport->serio.driver = serport; + serport->serio.port_data = serport; init_waitqueue_head(&serport->wait); diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index d72a7aaf280a..80605126b4b6 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -994,7 +994,7 @@ static spinlock_t sunsu_serio_lock = SPIN_LOCK_UNLOCKED; static int sunsu_serio_write(struct serio *serio, unsigned char ch) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; int lsr; @@ -1014,7 +1014,7 @@ static int sunsu_serio_write(struct serio *serio, unsigned char ch) static int sunsu_serio_open(struct serio *serio) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; int ret; @@ -1031,7 +1031,7 @@ static int sunsu_serio_open(struct serio *serio) static void sunsu_serio_close(struct serio *serio) { - struct uart_sunsu_port *up = serio->driver; + struct uart_sunsu_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunsu_serio_lock, flags); @@ -1311,7 +1311,7 @@ static int __init sunsu_kbd_ms_init(void) #ifdef CONFIG_SERIO memset(&up->serio, 0, sizeof(up->serio)); - up->serio.driver = up; + up->serio.port_data = up; up->serio.type = SERIO_RS232; if (up->su_type == SU_PORT_KBD) { diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index b38c02593836..8071e33729f6 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1295,7 +1295,7 @@ static spinlock_t sunzilog_serio_lock = SPIN_LOCK_UNLOCKED; static int sunzilog_serio_write(struct serio *serio, unsigned char ch) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunzilog_serio_lock, flags); @@ -1309,7 +1309,7 @@ static int sunzilog_serio_write(struct serio *serio, unsigned char ch) static int sunzilog_serio_open(struct serio *serio) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; int ret; @@ -1326,7 +1326,7 @@ static int sunzilog_serio_open(struct serio *serio) static void sunzilog_serio_close(struct serio *serio) { - struct uart_sunzilog_port *up = serio->driver; + struct uart_sunzilog_port *up = serio->port_data; unsigned long flags; spin_lock_irqsave(&sunzilog_serio_lock, flags); @@ -1549,7 +1549,7 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe #ifdef CONFIG_SERIO memset(&up->serio, 0, sizeof(up->serio)); - up->serio.driver = up; + up->serio.port_data = up; up->serio.type = SERIO_RS232; if (channel == KEYBOARD_LINE) { diff --git a/include/linux/serio.h b/include/linux/serio.h index d6959dec83d8..8308b1a82688 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -21,7 +21,7 @@ struct serio { void *private; - void *driver; + void *port_data; char *name; char *phys; -- cgit v1.2.3 From 0669ebea301b3bc16cb5a0305febba1d04240da2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jun 2004 15:27:11 -0500 Subject: Input: more renames in serio in preparations to sysfs integration - serio_dev -> serio_driver - serio_[un]register_device -> serio_[un]register_driver Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/iforce/iforce-main.c | 4 +- drivers/input/joystick/iforce/iforce-serio.c | 6 +-- drivers/input/joystick/iforce/iforce.h | 2 +- drivers/input/joystick/magellan.c | 10 ++-- drivers/input/joystick/spaceball.c | 10 ++-- drivers/input/joystick/spaceorb.c | 10 ++-- drivers/input/joystick/stinger.c | 10 ++-- drivers/input/joystick/twidjoy.c | 10 ++-- drivers/input/joystick/warrior.c | 10 ++-- drivers/input/keyboard/atkbd.c | 14 +++--- drivers/input/keyboard/lkkbd.c | 10 ++-- drivers/input/keyboard/newtonkbd.c | 10 ++-- drivers/input/keyboard/sunkbd.c | 10 ++-- drivers/input/keyboard/xtkbd.c | 10 ++-- drivers/input/mouse/psmouse-base.c | 14 +++--- drivers/input/mouse/sermouse.c | 10 ++-- drivers/input/mouse/synaptics.c | 2 +- drivers/input/mouse/vsxxxaa.c | 10 ++-- drivers/input/serio/serio.c | 72 ++++++++++++++-------------- drivers/input/serio/serport.c | 2 +- drivers/input/touchscreen/gunze.c | 10 ++-- drivers/input/touchscreen/h3600_ts_input.c | 10 ++-- include/linux/serio.h | 22 ++++----- 23 files changed, 139 insertions(+), 139 deletions(-) diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c index 71cb7db75a63..cf815c7ee68d 100644 --- a/drivers/input/joystick/iforce/iforce-main.c +++ b/drivers/input/joystick/iforce/iforce-main.c @@ -524,7 +524,7 @@ static int __init iforce_init(void) usb_register(&iforce_usb_driver); #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_register_device(&iforce_serio_dev); + serio_register_driver(&iforce_serio_drv); #endif return 0; } @@ -535,7 +535,7 @@ static void __exit iforce_exit(void) usb_deregister(&iforce_usb_driver); #endif #ifdef CONFIG_JOYSTICK_IFORCE_232 - serio_unregister_device(&iforce_serio_dev); + serio_unregister_driver(&iforce_serio_drv); #endif } diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 0665b5460050..196a62b85661 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -124,7 +124,7 @@ out: return IRQ_HANDLED; } -static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) +static void iforce_serio_connect(struct serio *serio, struct serio_driver *drv) { struct iforce *iforce; if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) @@ -137,7 +137,7 @@ static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) iforce->serio = serio; serio->private = iforce; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(iforce); return; } @@ -158,7 +158,7 @@ static void iforce_serio_disconnect(struct serio *serio) kfree(iforce); } -struct serio_dev iforce_serio_dev = { +struct serio_driver iforce_serio_drv = { .write_wakeup = iforce_serio_write_wakeup, .interrupt = iforce_serio_irq, .connect = iforce_serio_connect, diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h index a8586abf530e..bce247bc300b 100644 --- a/drivers/input/joystick/iforce/iforce.h +++ b/drivers/input/joystick/iforce/iforce.h @@ -187,5 +187,5 @@ int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); /* Public variables */ -extern struct serio_dev iforce_serio_dev; +extern struct serio_driver iforce_serio_drv; extern struct usb_driver iforce_usb_driver; diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index f326299b4193..ba2b6f846d7c 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c @@ -146,7 +146,7 @@ static void magellan_disconnect(struct serio *serio) * it as an input device. */ -static void magellan_connect(struct serio *serio, struct serio_dev *dev) +static void magellan_connect(struct serio *serio, struct serio_driver *drv) { struct magellan *magellan; int i, t; @@ -184,7 +184,7 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev) serio->private = magellan; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(magellan); return; } @@ -199,7 +199,7 @@ static void magellan_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev magellan_dev = { +static struct serio_driver magellan_drv = { .interrupt = magellan_interrupt, .connect = magellan_connect, .disconnect = magellan_disconnect, @@ -211,13 +211,13 @@ static struct serio_dev magellan_dev = { int __init magellan_init(void) { - serio_register_device(&magellan_dev); + serio_register_driver(&magellan_drv); return 0; } void __exit magellan_exit(void) { - serio_unregister_device(&magellan_dev); + serio_unregister_driver(&magellan_drv); } module_init(magellan_init); diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index eb5b6f76c1f3..6f50c1e1dd81 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -201,7 +201,7 @@ static void spaceball_disconnect(struct serio *serio) * it as an input device. */ -static void spaceball_connect(struct serio *serio, struct serio_dev *dev) +static void spaceball_connect(struct serio *serio, struct serio_driver *drv) { struct spaceball *spaceball; int i, t, id; @@ -254,7 +254,7 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) serio->private = spaceball; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(spaceball); return; } @@ -269,7 +269,7 @@ static void spaceball_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev spaceball_dev = { +static struct serio_driver spaceball_drv = { .interrupt = spaceball_interrupt, .connect = spaceball_connect, .disconnect = spaceball_disconnect, @@ -281,13 +281,13 @@ static struct serio_dev spaceball_dev = { int __init spaceball_init(void) { - serio_register_device(&spaceball_dev); + serio_register_driver(&spaceball_drv); return 0; } void __exit spaceball_exit(void) { - serio_unregister_device(&spaceball_dev); + serio_unregister_driver(&spaceball_drv); } module_init(spaceball_init); diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index 00da66c4b489..7078ea8df46c 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c @@ -162,7 +162,7 @@ static void spaceorb_disconnect(struct serio *serio) * it as an input device. */ -static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) +static void spaceorb_connect(struct serio *serio, struct serio_driver *drv) { struct spaceorb *spaceorb; int i, t; @@ -201,7 +201,7 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) serio->private = spaceorb; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(spaceorb); return; } @@ -213,7 +213,7 @@ static void spaceorb_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev spaceorb_dev = { +static struct serio_driver spaceorb_drv = { .interrupt = spaceorb_interrupt, .connect = spaceorb_connect, .disconnect = spaceorb_disconnect, @@ -225,13 +225,13 @@ static struct serio_dev spaceorb_dev = { int __init spaceorb_init(void) { - serio_register_device(&spaceorb_dev); + serio_register_driver(&spaceorb_drv); return 0; } void __exit spaceorb_exit(void) { - serio_unregister_device(&spaceorb_dev); + serio_unregister_driver(&spaceorb_drv); } module_init(spaceorb_init); diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index ce9be4563135..10d17a17d241 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c @@ -134,7 +134,7 @@ static void stinger_disconnect(struct serio *serio) * it as an input device. */ -static void stinger_connect(struct serio *serio, struct serio_dev *dev) +static void stinger_connect(struct serio *serio, struct serio_driver *drv) { struct stinger *stinger; int i; @@ -172,7 +172,7 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev) stinger->dev.private = stinger; serio->private = stinger; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(stinger); return; } @@ -187,7 +187,7 @@ static void stinger_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev stinger_dev = { +static struct serio_driver stinger_drv = { .interrupt = stinger_interrupt, .connect = stinger_connect, .disconnect = stinger_disconnect, @@ -199,13 +199,13 @@ static struct serio_dev stinger_dev = { int __init stinger_init(void) { - serio_register_device(&stinger_dev); + serio_register_driver(&stinger_drv); return 0; } void __exit stinger_exit(void) { - serio_unregister_device(&stinger_dev); + serio_unregister_driver(&stinger_drv); } module_init(stinger_init); diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index eb5c935a678e..f8be506086e3 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c @@ -187,7 +187,7 @@ static void twidjoy_disconnect(struct serio *serio) * it as an input device. */ -static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) +static void twidjoy_connect(struct serio *serio, struct serio_driver *drv) { struct twidjoy_button_spec *bp; struct twidjoy *twidjoy; @@ -232,7 +232,7 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) twidjoy->dev.private = twidjoy; serio->private = twidjoy; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(twidjoy); return; } @@ -246,7 +246,7 @@ static void twidjoy_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev twidjoy_dev = { +static struct serio_driver twidjoy_drv = { .interrupt = twidjoy_interrupt, .connect = twidjoy_connect, .disconnect = twidjoy_disconnect, @@ -258,13 +258,13 @@ static struct serio_dev twidjoy_dev = { int __init twidjoy_init(void) { - serio_register_device(&twidjoy_dev); + serio_register_driver(&twidjoy_drv); return 0; } void __exit twidjoy_exit(void) { - serio_unregister_device(&twidjoy_dev); + serio_unregister_driver(&twidjoy_drv); } module_init(twidjoy_init); diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index 32ec90e81d4a..6b29897f47fd 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c @@ -139,7 +139,7 @@ static void warrior_disconnect(struct serio *serio) * it as an input device. */ -static void warrior_connect(struct serio *serio, struct serio_dev *dev) +static void warrior_connect(struct serio *serio, struct serio_driver *drv) { struct warrior *warrior; int i; @@ -185,7 +185,7 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev) serio->private = warrior; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(warrior); return; } @@ -199,7 +199,7 @@ static void warrior_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev warrior_dev = { +static struct serio_driver warrior_drv = { .interrupt = warrior_interrupt, .connect = warrior_connect, .disconnect = warrior_disconnect, @@ -211,13 +211,13 @@ static struct serio_dev warrior_dev = { int __init warrior_init(void) { - serio_register_device(&warrior_dev); + serio_register_driver(&warrior_drv); return 0; } void __exit warrior_exit(void) { - serio_unregister_device(&warrior_dev); + serio_unregister_driver(&warrior_drv); } module_init(warrior_init); diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 34802b852e3e..ea74e7eee690 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -732,7 +732,7 @@ static void atkbd_disconnect(struct serio *serio) * to the input module. */ -static void atkbd_connect(struct serio *serio, struct serio_dev *dev) +static void atkbd_connect(struct serio *serio, struct serio_driver *drv) { struct atkbd *atkbd; int i; @@ -785,7 +785,7 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) serio->private = atkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(atkbd); return; } @@ -861,10 +861,10 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev) static int atkbd_reconnect(struct serio *serio) { struct atkbd *atkbd = serio->private; - struct serio_dev *dev = serio->dev; + struct serio_driver *drv = serio->drv; unsigned char param[1]; - if (!dev) { + if (!drv) { printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } @@ -890,7 +890,7 @@ static int atkbd_reconnect(struct serio *serio) return 0; } -static struct serio_dev atkbd_dev = { +static struct serio_driver atkbd_drv = { .interrupt = atkbd_interrupt, .connect = atkbd_connect, .reconnect = atkbd_reconnect, @@ -900,13 +900,13 @@ static struct serio_dev atkbd_dev = { int __init atkbd_init(void) { - serio_register_device(&atkbd_dev); + serio_register_driver(&atkbd_drv); return 0; } void __exit atkbd_exit(void) { - serio_unregister_device(&atkbd_dev); + serio_unregister_driver(&atkbd_drv); } module_init(atkbd_init); diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index 8dc51e2966e4..fc875611f985 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -622,7 +622,7 @@ lkkbd_reinit (void *data) * lkkbd_connect() probes for a LK keyboard and fills the necessary structures. */ static void -lkkbd_connect (struct serio *serio, struct serio_dev *dev) +lkkbd_connect (struct serio *serio, struct serio_driver *drv) { struct lkkbd *lk; int i; @@ -665,7 +665,7 @@ lkkbd_connect (struct serio *serio, struct serio_dev *dev) serio->private = lk; - if (serio_open (serio, dev)) { + if (serio_open (serio, drv)) { kfree (lk); return; } @@ -703,7 +703,7 @@ lkkbd_disconnect (struct serio *serio) kfree (lk); } -static struct serio_dev lkkbd_dev = { +static struct serio_driver lkkbd_drv = { .connect = lkkbd_connect, .disconnect = lkkbd_disconnect, .interrupt = lkkbd_interrupt, @@ -715,14 +715,14 @@ static struct serio_dev lkkbd_dev = { int __init lkkbd_init (void) { - serio_register_device (&lkkbd_dev); + serio_register_driver(&lkkbd_drv); return 0; } void __exit lkkbd_exit (void) { - serio_unregister_device (&lkkbd_dev); + serio_unregister_driver(&lkkbd_drv); } module_init (lkkbd_init); diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c index dc47acb0a4f7..1b6cefb51e66 100644 --- a/drivers/input/keyboard/newtonkbd.c +++ b/drivers/input/keyboard/newtonkbd.c @@ -82,7 +82,7 @@ irqreturn_t nkbd_interrupt(struct serio *serio, } -void nkbd_connect(struct serio *serio, struct serio_dev *dev) +void nkbd_connect(struct serio *serio, struct serio_driver *drv) { struct nkbd *nkbd; int i; @@ -106,7 +106,7 @@ void nkbd_connect(struct serio *serio, struct serio_dev *dev) nkbd->dev.private = nkbd; serio->private = nkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(nkbd); return; } @@ -138,7 +138,7 @@ void nkbd_disconnect(struct serio *serio) kfree(nkbd); } -struct serio_dev nkbd_dev = { +struct serio_driver nkbd_drv = { .interrupt = nkbd_interrupt, .connect = nkbd_connect, .disconnect = nkbd_disconnect @@ -146,13 +146,13 @@ struct serio_dev nkbd_dev = { int __init nkbd_init(void) { - serio_register_device(&nkbd_dev); + serio_register_driver(&nkbd_drv); return 0; } void __exit nkbd_exit(void) { - serio_unregister_device(&nkbd_dev); + serio_unregister_driver(&nkbd_drv); } module_init(nkbd_init); diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 1bb8a57e28dc..9db172d19583 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -221,7 +221,7 @@ static void sunkbd_reinit(void *data) * sunkbd_connect() probes for a Sun keyboard and fills the necessary structures. */ -static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) +static void sunkbd_connect(struct serio *serio, struct serio_driver *drv) { struct sunkbd *sunkbd; int i; @@ -257,7 +257,7 @@ static void sunkbd_connect(struct serio *serio, struct serio_dev *dev) serio->private = sunkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(sunkbd); return; } @@ -301,7 +301,7 @@ static void sunkbd_disconnect(struct serio *serio) kfree(sunkbd); } -static struct serio_dev sunkbd_dev = { +static struct serio_driver sunkbd_drv = { .interrupt = sunkbd_interrupt, .connect = sunkbd_connect, .disconnect = sunkbd_disconnect @@ -313,13 +313,13 @@ static struct serio_dev sunkbd_dev = { int __init sunkbd_init(void) { - serio_register_device(&sunkbd_dev); + serio_register_driver(&sunkbd_drv); return 0; } void __exit sunkbd_exit(void) { - serio_unregister_device(&sunkbd_dev); + serio_unregister_driver(&sunkbd_drv); } module_init(sunkbd_init); diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index 56adfa1cceb8..5542f29cf6c7 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -86,7 +86,7 @@ irqreturn_t xtkbd_interrupt(struct serio *serio, return IRQ_HANDLED; } -void xtkbd_connect(struct serio *serio, struct serio_dev *dev) +void xtkbd_connect(struct serio *serio, struct serio_driver *drv) { struct xtkbd *xtkbd; int i; @@ -111,7 +111,7 @@ void xtkbd_connect(struct serio *serio, struct serio_dev *dev) serio->private = xtkbd; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(xtkbd); return; } @@ -143,7 +143,7 @@ void xtkbd_disconnect(struct serio *serio) kfree(xtkbd); } -struct serio_dev xtkbd_dev = { +struct serio_driver xtkbd_drv = { .interrupt = xtkbd_interrupt, .connect = xtkbd_connect, .disconnect = xtkbd_disconnect @@ -151,13 +151,13 @@ struct serio_dev xtkbd_dev = { int __init xtkbd_init(void) { - serio_register_device(&xtkbd_dev); + serio_register_driver(&xtkbd_drv); return 0; } void __exit xtkbd_exit(void) { - serio_unregister_device(&xtkbd_dev); + serio_unregister_driver(&xtkbd_drv); } module_init(xtkbd_init); diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 97f3e795001e..0587e92bb4cc 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -678,7 +678,7 @@ static void psmouse_disconnect(struct serio *serio) * psmouse_connect() is a callback from the serio module when * an unhandled serio port is found. */ -static void psmouse_connect(struct serio *serio, struct serio_dev *dev) +static void psmouse_connect(struct serio *serio, struct serio_driver *drv) { struct psmouse *psmouse; @@ -700,7 +700,7 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) psmouse->dev.private = psmouse; serio->private = psmouse; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(psmouse); serio->private = NULL; return; @@ -753,9 +753,9 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev) static int psmouse_reconnect(struct serio *serio) { struct psmouse *psmouse = serio->private; - struct serio_dev *dev = serio->dev; + struct serio_driver *drv = serio->drv; - if (!dev || !psmouse) { + if (!drv || !psmouse) { printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } @@ -793,7 +793,7 @@ static int psmouse_reconnect(struct serio *serio) } -static struct serio_dev psmouse_dev = { +static struct serio_driver psmouse_drv = { .interrupt = psmouse_interrupt, .connect = psmouse_connect, .reconnect = psmouse_reconnect, @@ -818,13 +818,13 @@ static inline void psmouse_parse_proto(void) int __init psmouse_init(void) { psmouse_parse_proto(); - serio_register_device(&psmouse_dev); + serio_register_driver(&psmouse_drv); return 0; } void __exit psmouse_exit(void) { - serio_unregister_device(&psmouse_dev); + serio_unregister_driver(&psmouse_drv); } module_init(psmouse_init); diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index 9c97a0a40c4d..d0e4176344d6 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c @@ -237,7 +237,7 @@ static void sermouse_disconnect(struct serio *serio) * an unhandled serio port is found. */ -static void sermouse_connect(struct serio *serio, struct serio_dev *dev) +static void sermouse_connect(struct serio *serio, struct serio_driver *drv) { struct sermouse *sermouse; unsigned char c; @@ -279,7 +279,7 @@ static void sermouse_connect(struct serio *serio, struct serio_dev *dev) sermouse->dev.id.product = c; sermouse->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(sermouse); return; } @@ -289,7 +289,7 @@ static void sermouse_connect(struct serio *serio, struct serio_dev *dev) printk(KERN_INFO "input: %s on %s\n", sermouse_protocols[sermouse->type], serio->phys); } -static struct serio_dev sermouse_dev = { +static struct serio_driver sermouse_drv = { .interrupt = sermouse_interrupt, .connect = sermouse_connect, .disconnect = sermouse_disconnect @@ -297,13 +297,13 @@ static struct serio_dev sermouse_dev = { int __init sermouse_init(void) { - serio_register_device(&sermouse_dev); + serio_register_driver(&sermouse_drv); return 0; } void __exit sermouse_exit(void) { - serio_unregister_device(&sermouse_dev); + serio_unregister_driver(&sermouse_drv); } module_init(sermouse_init); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 11542272632d..c1c970998a45 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -470,7 +470,7 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (psmouse->ptport && psmouse->ptport->serio.dev && synaptics_is_pt_packet(psmouse->packet)) + if (psmouse->ptport && psmouse->ptport->serio.drv && synaptics_is_pt_packet(psmouse->packet)) synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); else synaptics_process_packet(psmouse); diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index c26d907e8bb9..29acfe06f74f 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -482,7 +482,7 @@ vsxxxaa_disconnect (struct serio *serio) } static void -vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) +vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) { struct vsxxxaa *mouse; @@ -524,7 +524,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) mouse->dev.id.bustype = BUS_RS232; mouse->serio = serio; - if (serio_open (serio, dev)) { + if (serio_open (serio, drv)) { kfree (mouse); return; } @@ -540,7 +540,7 @@ vsxxxaa_connect (struct serio *serio, struct serio_dev *dev) printk (KERN_INFO "input: %s on %s\n", mouse->name, mouse->phys); } -static struct serio_dev vsxxxaa_dev = { +static struct serio_driver vsxxxaa_drv = { .connect = vsxxxaa_connect, .interrupt = vsxxxaa_interrupt, .disconnect = vsxxxaa_disconnect, @@ -549,14 +549,14 @@ static struct serio_dev vsxxxaa_dev = { int __init vsxxxaa_init (void) { - serio_register_device (&vsxxxaa_dev); + serio_register_driver(&vsxxxaa_drv); return 0; } void __exit vsxxxaa_exit (void) { - serio_unregister_device (&vsxxxaa_dev); + serio_unregister_driver(&vsxxxaa_drv); } module_init (vsxxxaa_init); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index b130e0d3191f..7a369ec9f114 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -48,27 +48,27 @@ EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_port_delayed); EXPORT_SYMBOL(__serio_unregister_port); -EXPORT_SYMBOL(serio_register_device); -EXPORT_SYMBOL(serio_unregister_device); +EXPORT_SYMBOL(serio_register_driver); +EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); EXPORT_SYMBOL(serio_close); EXPORT_SYMBOL(serio_rescan); EXPORT_SYMBOL(serio_reconnect); -static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_dev_list */ +static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_diriver_list */ static LIST_HEAD(serio_list); -static LIST_HEAD(serio_dev_list); +static LIST_HEAD(serio_driver_list); -/* serio_find_dev() must be called with serio_sem down. */ +/* serio_find_driver() must be called with serio_sem down. */ -static void serio_find_dev(struct serio *serio) +static void serio_find_driver(struct serio *serio) { - struct serio_dev *dev; + struct serio_driver *drv; - list_for_each_entry(dev, &serio_dev_list, node) { - if (serio->dev) + list_for_each_entry(drv, &serio_driver_list, node) { + if (serio->drv) break; - dev->connect(serio, dev); + drv->connect(serio, drv); } } @@ -153,15 +153,15 @@ static void serio_handle_events(void) break; case SERIO_RECONNECT : - if (event->serio->dev && event->serio->dev->reconnect) - if (event->serio->dev->reconnect(event->serio) == 0) + if (event->serio->drv && event->serio->drv->reconnect) + if (event->serio->drv->reconnect(event->serio) == 0) break; /* reconnect failed - fall through to rescan */ case SERIO_RESCAN : - if (event->serio->dev) - event->serio->dev->disconnect(event->serio); - serio_find_dev(event->serio); + if (event->serio->drv) + event->serio->drv->disconnect(event->serio); + serio_find_driver(event->serio); break; default: break; @@ -252,7 +252,7 @@ void __serio_register_port(struct serio *serio) { spin_lock_init(&serio->lock); list_add_tail(&serio->node, &serio_list); - serio_find_dev(serio); + serio_find_driver(serio); } void serio_unregister_port(struct serio *serio) @@ -281,58 +281,58 @@ void __serio_unregister_port(struct serio *serio) { serio_remove_pending_events(serio); list_del_init(&serio->node); - if (serio->dev) - serio->dev->disconnect(serio); + if (serio->drv) + serio->drv->disconnect(serio); } /* - * Serio device operations + * Serio driver operations */ -void serio_register_device(struct serio_dev *dev) +void serio_register_driver(struct serio_driver *drv) { struct serio *serio; down(&serio_sem); - list_add_tail(&dev->node, &serio_dev_list); + list_add_tail(&drv->node, &serio_driver_list); list_for_each_entry(serio, &serio_list, node) - if (!serio->dev) - dev->connect(serio, dev); + if (!serio->drv) + drv->connect(serio, drv); up(&serio_sem); } -void serio_unregister_device(struct serio_dev *dev) +void serio_unregister_driver(struct serio_driver *drv) { struct serio *serio; down(&serio_sem); - list_del_init(&dev->node); + list_del_init(&drv->node); list_for_each_entry(serio, &serio_list, node) { - if (serio->dev == dev) - dev->disconnect(serio); - serio_find_dev(serio); + if (serio->drv == drv) + drv->disconnect(serio); + serio_find_driver(serio); } up(&serio_sem); } -/* called from serio_dev->connect/disconnect methods under serio_sem */ -int serio_open(struct serio *serio, struct serio_dev *dev) +/* called from serio_driver->connect/disconnect methods under serio_sem */ +int serio_open(struct serio *serio, struct serio_driver *drv) { unsigned long flags; spin_lock_irqsave(&serio->lock, flags); - serio->dev = dev; + serio->drv = drv; spin_unlock_irqrestore(&serio->lock, flags); if (serio->open && serio->open(serio)) { spin_lock_irqsave(&serio->lock, flags); - serio->dev = NULL; + serio->drv = NULL; spin_unlock_irqrestore(&serio->lock, flags); return -1; } return 0; } -/* called from serio_dev->connect/disconnect methods under serio_sem */ +/* called from serio_driver->connect/disconnect methods under serio_sem */ void serio_close(struct serio *serio) { unsigned long flags; @@ -340,7 +340,7 @@ void serio_close(struct serio *serio) if (serio->close) serio->close(serio); spin_lock_irqsave(&serio->lock, flags); - serio->dev = NULL; + serio->drv = NULL; spin_unlock_irqrestore(&serio->lock, flags); } @@ -352,8 +352,8 @@ irqreturn_t serio_interrupt(struct serio *serio, spin_lock_irqsave(&serio->lock, flags); - if (likely(serio->dev)) { - ret = serio->dev->interrupt(serio, data, dfl, regs); + if (likely(serio->drv)) { + ret = serio->drv->interrupt(serio, data, dfl, regs); } else { if (!dfl) { if ((serio->type != SERIO_8042 && diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 175ef49ca1f9..f808ed55b6b5 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -170,7 +170,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty) { struct serport *sp = (struct serport *) tty->disc_data; - serio_dev_write_wakeup(&sp->serio); + serio_drv_write_wakeup(&sp->serio); } /* diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index 77591498016a..ca00633d4b64 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -111,7 +111,7 @@ static void gunze_disconnect(struct serio *serio) * and if yes, registers it as an input device. */ -static void gunze_connect(struct serio *serio, struct serio_dev *dev) +static void gunze_connect(struct serio *serio, struct serio_driver *drv) { struct gunze *gunze; @@ -142,7 +142,7 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev) gunze->dev.id.product = 0x0051; gunze->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { kfree(gunze); return; } @@ -156,7 +156,7 @@ static void gunze_connect(struct serio *serio, struct serio_dev *dev) * The serio device structure. */ -static struct serio_dev gunze_dev = { +static struct serio_driver gunze_drv = { .interrupt = gunze_interrupt, .connect = gunze_connect, .disconnect = gunze_disconnect, @@ -168,13 +168,13 @@ static struct serio_dev gunze_dev = { int __init gunze_init(void) { - serio_register_device(&gunze_dev); + serio_register_driver(&gunze_drv); return 0; } void __exit gunze_exit(void) { - serio_unregister_device(&gunze_dev); + serio_unregister_driver(&gunze_drv); } module_init(gunze_init); diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 7b4c16d6fb54..514816c3f1e7 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -373,7 +373,7 @@ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data, * new serio device. It looks whether it was registered as a H3600 touchscreen * and if yes, registers it as an input device. */ -static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) +static void h3600ts_connect(struct serio *serio, struct serio_driver *drv) { struct h3600_dev *ts; @@ -441,7 +441,7 @@ static void h3600ts_connect(struct serio *serio, struct serio_dev *dev) ts->dev.id.product = 0x0666; /* FIXME !!! We can ask the hardware */ ts->dev.id.version = 0x0100; - if (serio_open(serio, dev)) { + if (serio_open(serio, drv)) { free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts); free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts); kfree(ts); @@ -478,7 +478,7 @@ static void h3600ts_disconnect(struct serio *serio) * The serio device structure. */ -static struct serio_dev h3600ts_dev = { +static struct serio_driver h3600ts_drv = { .interrupt = h3600ts_interrupt, .connect = h3600ts_connect, .disconnect = h3600ts_disconnect, @@ -490,13 +490,13 @@ static struct serio_dev h3600ts_dev = { static int __init h3600ts_init(void) { - serio_register_device(&h3600ts_dev); + serio_register_driver(&h3600ts_drv); return 0; } static void __exit h3600ts_exit(void) { - serio_unregister_device(&h3600ts_dev); + serio_unregister_driver(&h3600ts_drv); } module_init(h3600ts_init); diff --git a/include/linux/serio.h b/include/linux/serio.h index 8308b1a82688..be0ce4360d8b 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -39,19 +39,19 @@ struct serio { int (*open)(struct serio *); void (*close)(struct serio *); - struct serio_dev *dev; /* Accessed from interrupt, writes must be protected by serio_lock */ + struct serio_driver *drv; /* Accessed from interrupt, writes must be protected by serio_lock */ struct list_head node; }; -struct serio_dev { +struct serio_driver { void *private; char *name; void (*write_wakeup)(struct serio *); irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int, struct pt_regs *); - void (*connect)(struct serio *, struct serio_dev *dev); + void (*connect)(struct serio *, struct serio_driver *drv); int (*reconnect)(struct serio *); void (*disconnect)(struct serio *); void (*cleanup)(struct serio *); @@ -59,7 +59,7 @@ struct serio_dev { struct list_head node; }; -int serio_open(struct serio *serio, struct serio_dev *dev); +int serio_open(struct serio *serio, struct serio_driver *drv); void serio_close(struct serio *serio); void serio_rescan(struct serio *serio); void serio_reconnect(struct serio *serio); @@ -71,8 +71,8 @@ void __serio_register_port(struct serio *serio); void serio_unregister_port(struct serio *serio); void serio_unregister_port_delayed(struct serio *serio); void __serio_unregister_port(struct serio *serio); -void serio_register_device(struct serio_dev *dev); -void serio_unregister_device(struct serio_dev *dev); +void serio_register_driver(struct serio_driver *drv); +void serio_unregister_driver(struct serio_driver *drv); static __inline__ int serio_write(struct serio *serio, unsigned char data) { @@ -82,16 +82,16 @@ static __inline__ int serio_write(struct serio *serio, unsigned char data) return -1; } -static __inline__ void serio_dev_write_wakeup(struct serio *serio) +static __inline__ void serio_drv_write_wakeup(struct serio *serio) { - if (serio->dev && serio->dev->write_wakeup) - serio->dev->write_wakeup(serio); + if (serio->drv && serio->drv->write_wakeup) + serio->drv->write_wakeup(serio); } static __inline__ void serio_cleanup(struct serio *serio) { - if (serio->dev && serio->dev->cleanup) - serio->dev->cleanup(serio); + if (serio->drv && serio->drv->cleanup) + serio->drv->cleanup(serio); } #endif -- cgit v1.2.3 From 7d9f1d2fa7222853f08de43019696916122e039f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jun 2004 15:27:46 -0500 Subject: Input: switch to dynamic (heap) serio port allocation in preparation to sysfs integration. By having all data structures dynamically allocated serio driver modules can be unloaded without waiting for the last reference to the port to be dropped. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 12 +-- drivers/input/mouse/psmouse.h | 3 +- drivers/input/mouse/synaptics.c | 33 +++--- drivers/input/serio/ambakmi.c | 39 ++++--- drivers/input/serio/ct82c710.c | 62 ++++++----- drivers/input/serio/gscps2.c | 55 ++++++---- drivers/input/serio/i8042.c | 208 ++++++++++++++++++++----------------- drivers/input/serio/i8042.h | 7 ++ drivers/input/serio/maceps2.c | 69 ++++++------ drivers/input/serio/parkbd.c | 47 ++++++--- drivers/input/serio/pcips2.c | 32 +++--- drivers/input/serio/q40kbd.c | 109 +++++++++++++------ drivers/input/serio/rpckbd.c | 38 +++++-- drivers/input/serio/sa1111ps2.c | 34 +++--- drivers/input/serio/serio.c | 1 + drivers/input/serio/serport.c | 45 ++++---- drivers/serial/sunsu.c | 83 ++++++++------- drivers/serial/sunzilog.c | 60 +++++++---- include/linux/serio.h | 5 +- 19 files changed, 566 insertions(+), 376 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 0587e92bb4cc..c11298d3482b 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -659,7 +659,7 @@ static void psmouse_disconnect(struct serio *serio) if (psmouse->ptport) { if (psmouse->ptport->deactivate) psmouse->ptport->deactivate(psmouse); - __serio_unregister_port(&psmouse->ptport->serio); /* we have serio_sem */ + __serio_unregister_port(psmouse->ptport->serio); /* we have serio_sem */ kfree(psmouse->ptport); psmouse->ptport = NULL; } @@ -740,8 +740,8 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_initialize(psmouse); if (psmouse->ptport) { - printk(KERN_INFO "serio: %s port at %s\n", psmouse->ptport->serio.name, psmouse->phys); - __serio_register_port(&psmouse->ptport->serio); /* we have serio_sem */ + printk(KERN_INFO "serio: %s port at %s\n", psmouse->ptport->serio->name, psmouse->phys); + __serio_register_port(psmouse->ptport->serio); /* we have serio_sem */ if (psmouse->ptport->activate) psmouse->ptport->activate(psmouse); } @@ -780,9 +780,9 @@ static int psmouse_reconnect(struct serio *serio) psmouse_initialize(psmouse); if (psmouse->ptport) { - if (psmouse_reconnect(&psmouse->ptport->serio)) { - __serio_unregister_port(&psmouse->ptport->serio); - __serio_register_port(&psmouse->ptport->serio); + if (psmouse_reconnect(psmouse->ptport->serio)) { + __serio_unregister_port(psmouse->ptport->serio); + __serio_register_port(psmouse->ptport->serio); if (psmouse->ptport->activate) psmouse->ptport->activate(psmouse); } diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 09095ea6fa3b..73cc16ef8ba9 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -37,7 +37,8 @@ typedef enum { struct psmouse; struct psmouse_ptport { - struct serio serio; + struct serio *serio; + struct psmouse *parent; void (*activate)(struct psmouse *parent); void (*deactivate)(struct psmouse *parent); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index c1c970998a45..955f5c394015 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -214,12 +214,12 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode) ****************************************************************************/ static int synaptics_pt_write(struct serio *port, unsigned char c) { - struct psmouse *parent = port->port_data; + struct psmouse_ptport *ptport = port->port_data; char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ - if (psmouse_sliced_command(parent, c)) + if (psmouse_sliced_command(ptport->parent, c)) return -1; - if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE)) + if (psmouse_command(ptport->parent, &rate_param, PSMOUSE_CMD_SETRATE)) return -1; return 0; } @@ -248,7 +248,7 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet static void synaptics_pt_activate(struct psmouse *psmouse) { - struct psmouse *child = psmouse->ptport->serio.private; + struct psmouse *child = psmouse->ptport->serio->private; /* adjust the touchpad to child's choice of protocol */ if (child && child->type >= PSMOUSE_GENPS) { @@ -260,22 +260,29 @@ static void synaptics_pt_activate(struct psmouse *psmouse) static void synaptics_pt_create(struct psmouse *psmouse) { struct psmouse_ptport *port; + struct serio *serio; - psmouse->ptport = port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL); - if (!port) { + port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL); + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!port || !serio) { printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); return; } memset(port, 0, sizeof(struct psmouse_ptport)); + memset(serio, 0, sizeof(struct serio)); - port->serio.type = SERIO_PS_PSTHRU; - port->serio.name = "Synaptics pass-through"; - port->serio.phys = "synaptics-pt/serio0"; - port->serio.write = synaptics_pt_write; - port->serio.port_data = psmouse; + serio->type = SERIO_PS_PSTHRU; + strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); + strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); + serio->write = synaptics_pt_write; + serio->port_data = port; + port->serio = serio; + port->parent = psmouse; port->activate = synaptics_pt_activate; + + psmouse->ptport = port; } /***************************************************************************** @@ -470,8 +477,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (psmouse->ptport && psmouse->ptport->serio.drv && synaptics_is_pt_packet(psmouse->packet)) - synaptics_pass_pt_packet(&psmouse->ptport->serio, psmouse->packet); + if (psmouse->ptport && psmouse->ptport->serio->drv && synaptics_is_pt_packet(psmouse->packet)) + synaptics_pass_pt_packet(psmouse->ptport->serio, psmouse->packet); else synaptics_process_packet(psmouse); diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 5d7879dfef13..4b793b640ec6 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -29,7 +29,7 @@ #define KMI_BASE (kmi->base) struct amba_kmi_port { - struct serio io; + struct serio *io; struct clk *clk; unsigned char *base; unsigned int irq; @@ -44,7 +44,7 @@ static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs) int handled = IRQ_NONE; while (status & KMIIR_RXINTR) { - serio_interrupt(&kmi->io, readb(KMIDATA), 0, regs); + serio_interrupt(kmi->io, readb(KMIDATA), 0, regs); status = readb(KMIIR); handled = IRQ_HANDLED; } @@ -117,6 +117,7 @@ static void amba_kmi_close(struct serio *io) static int amba_kmi_probe(struct amba_device *dev, void *id) { struct amba_kmi_port *kmi; + struct serio *io; int ret; ret = amba_request_regions(dev, NULL); @@ -124,22 +125,25 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) return ret; kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL); - if (!kmi) { + io = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!kmi || !io) { ret = -ENOMEM; goto out; } memset(kmi, 0, sizeof(struct amba_kmi_port)); - - kmi->io.type = SERIO_8042; - kmi->io.write = amba_kmi_write; - kmi->io.open = amba_kmi_open; - kmi->io.close = amba_kmi_close; - kmi->io.name = dev->dev.bus_id; - kmi->io.phys = dev->dev.bus_id; - kmi->io.port_data = kmi; - - kmi->base = ioremap(dev->res.start, KMI_SIZE); + memset(io, 0, sizeof(struct serio)); + + io->type = SERIO_8042; + io->write = amba_kmi_write; + io->open = amba_kmi_open; + io->close = amba_kmi_close; + strlcpy(io->name, dev->dev.bus_id, sizeof(io->name)); + strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys)); + io->port_data = kmi; + + kmi->io = io; + kmi->base = ioremap(dev->res.start, KMI_SIZE); if (!kmi->base) { ret = -ENOMEM; goto out; @@ -154,13 +158,14 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) kmi->irq = dev->irq[0]; amba_set_drvdata(dev, kmi); - serio_register_port(&kmi->io); + serio_register_port(kmi->io); return 0; unmap: iounmap(kmi->base); out: kfree(kmi); + kfree(io); amba_release_regions(dev); return ret; } @@ -171,7 +176,7 @@ static int amba_kmi_remove(struct amba_device *dev) amba_set_drvdata(dev, NULL); - serio_unregister_port(&kmi->io); + serio_unregister_port(kmi->io); clk_put(kmi->clk); iounmap(kmi->base); kfree(kmi); @@ -184,7 +189,7 @@ static int amba_kmi_resume(struct amba_device *dev) struct amba_kmi_port *kmi = amba_get_drvdata(dev); /* kick the serio layer to rescan this port */ - serio_rescan(&kmi->io); + serio_reconnect(kmi->io); return 0; } @@ -214,7 +219,7 @@ static int __init amba_kmi_init(void) static void __exit amba_kmi_exit(void) { - return amba_driver_unregister(&ambakmi_driver); + amba_driver_unregister(&ambakmi_driver); } module_init(amba_kmi_init); diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index 2234ff39dca1..abacb6fb4de6 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -43,9 +43,6 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("82C710 C&T mouse port chip driver"); MODULE_LICENSE("GPL"); -static char ct82c710_name[] = "C&T 82c710 mouse port"; -static char ct82c710_phys[16]; - /* * ct82c710 interface */ @@ -61,10 +58,20 @@ static char ct82c710_phys[16]; #define CT82C710_IRQ 12 +static struct serio *ct82c710_port; static int ct82c710_data; static int ct82c710_status; -static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs); + +/* + * Interrupt handler for the 82C710 mouse port. A character + * is waiting in the 82C710. + */ + +static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) +{ + return serio_interrupt(ct82c710_port, inb(ct82c710_data), 0, regs); +} /* * Wait for device to send output char and flush any input char. @@ -139,26 +146,6 @@ static int ct82c710_write(struct serio *port, unsigned char c) return 0; } -static struct serio ct82c710_port = -{ - .type = SERIO_8042, - .name = ct82c710_name, - .phys = ct82c710_phys, - .write = ct82c710_write, - .open = ct82c710_open, - .close = ct82c710_close, -}; - -/* - * Interrupt handler for the 82C710 mouse port. A character - * is waiting in the 82C710. - */ - -static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) -{ - return serio_interrupt(&ct82c710_port, inb(ct82c710_data), 0, regs); -} - /* * See if we can find a 82C710 device. Read mouse address. */ @@ -183,6 +170,24 @@ static int __init ct82c710_probe(void) return 0; } +static struct serio * __init ct82c710_allocate_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->open = ct82c710_open; + serio->close = ct82c710_close; + serio->write = ct82c710_write; + strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "isa%04x/serio0", ct82c710_data); + } + + return serio; +} + int __init ct82c710_init(void) { if (ct82c710_probe()) @@ -191,9 +196,12 @@ int __init ct82c710_init(void) if (request_region(ct82c710_data, 2, "ct82c710")) return -EBUSY; - sprintf(ct82c710_phys, "isa%04x/serio0", ct82c710_data); + if (!(ct82c710_port = ct82c710_allocate_port())) { + release_region(ct82c710_data, 2); + return -ENOMEM; + } - serio_register_port(&ct82c710_port); + serio_register_port(ct82c710_port); printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n", ct82c710_data, CT82C710_IRQ); @@ -203,7 +211,7 @@ int __init ct82c710_init(void) void __exit ct82c710_exit(void) { - serio_unregister_port(&ct82c710_port); + serio_unregister_port(ct82c710_port); release_region(ct82c710_data, 2); } diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index f649e0aa5777..ee91428be054 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -91,7 +91,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs); struct gscps2port { struct list_head node; struct parisc_device *padev; - struct serio port; + struct serio *port; spinlock_t lock; char *addr; u8 act, append; /* position in buffer[] */ @@ -100,7 +100,6 @@ struct gscps2port { u8 str; } buffer[BUFFER_SIZE+1]; int id; - char name[32]; }; /* @@ -272,7 +271,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs) rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) | ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 ); - serio_interrupt(&ps2port->port, data, rxflags, regs); + serio_interrupt(ps2port->port, data, rxflags, regs); } /* while() */ @@ -343,7 +342,8 @@ static struct serio gscps2_serio_port = static int __init gscps2_probe(struct parisc_device *dev) { - struct gscps2port *ps2port; + struct gscps2port *ps2port; + struct serio *serio; unsigned long hpa = dev->hpa; int ret; @@ -355,34 +355,44 @@ static int __init gscps2_probe(struct parisc_device *dev) hpa += GSC_DINO_OFFSET; ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL); - if (!ps2port) - return -ENOMEM; + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2port || !serio) { + ret = -ENOMEM; + goto fail_nomem; + } dev_set_drvdata(&dev->dev, ps2port); memset(ps2port, 0, sizeof(struct gscps2port)); + memset(serio, 0, sizeof(struct serio)); + ps2port->port = serio; ps2port->padev = dev; ps2port->addr = ioremap(hpa, GSC_STATUS + 4); spin_lock_init(&ps2port->lock); gscps2_reset(ps2port); - ps2port->id = readb(ps2port->addr+GSC_ID) & 0x0f; - snprintf(ps2port->name, sizeof(ps2port->name)-1, "%s %s", - gscps2_serio_port.name, - (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse" ); - - memcpy(&ps2port->port, &gscps2_serio_port, sizeof(gscps2_serio_port)); - ps2port->port.port_data = ps2port; - ps2port->port.name = ps2port->name; - ps2port->port.phys = dev->dev.bus_id; + ps2port->id = readb(ps2port->addr + GSC_ID) & 0x0f; + + snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s", + (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse"); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->idbus = BUS_GSC; + serio->idvendor = PCI_VENDOR_ID_HP; + serio->idproduct = 0x0001; + serio->idversion = 0x0010; + serio->type = SERIO_8042; + serio->write = gscps2_write; + serio->open = gscps2_open; + serio->close = gscps2_close; + serio->port_data = ps2port; list_add_tail(&ps2port->node, &ps2port_list); ret = -EBUSY; - if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->name, ps2port)) + if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port)) goto fail_miserably; - if ( (ps2port->id != GSC_ID_KEYBOARD) && (ps2port->id != GSC_ID_MOUSE) ) { + if (ps2port->id != GSC_ID_KEYBOARD && ps2port->id != GSC_ID_MOUSE) { printk(KERN_WARNING PFX "Unsupported PS/2 port at 0x%08lx (id=%d) ignored\n", hpa, ps2port->id); ret = -ENODEV; @@ -395,12 +405,12 @@ static int __init gscps2_probe(struct parisc_device *dev) #endif printk(KERN_INFO "serio: %s port at 0x%p irq %d @ %s\n", - ps2port->name, + ps2port->port->name, ps2port->addr, ps2port->padev->irq, - ps2port->port.phys); + ps2port->port->phys); - serio_register_port(&ps2port->port); + serio_register_port(ps2port->port); return 0; @@ -411,7 +421,10 @@ fail_miserably: list_del(&ps2port->node); iounmap(ps2port->addr); release_mem_region(dev->hpa, GSC_STATUS + 4); + +fail_nomem: kfree(ps2port); + kfree(serio); return ret; } @@ -424,7 +437,7 @@ static int __devexit gscps2_remove(struct parisc_device *dev) { struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); - serio_unregister_port(&ps2port->port); + serio_unregister_port(ps2port->port); free_irq(dev->irq, ps2port); gscps2_flush(ps2port); list_del(&ps2port->node); diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 843327c323ce..aaf7384fa5f9 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -75,19 +75,35 @@ struct i8042_values { unsigned char irqen; unsigned char exists; signed char mux; - unsigned char *name; - unsigned char *phys; + char name[8]; }; -static struct serio i8042_kbd_port; -static struct serio i8042_aux_port; +static struct i8042_values i8042_kbd_values = { + .disable = I8042_CTR_KBDDIS, + .irqen = I8042_CTR_KBDINT, + .mux = -1, + .name = "KBD", +}; + +static struct i8042_values i8042_aux_values = { + .disable = I8042_CTR_AUXDIS, + .irqen = I8042_CTR_AUXINT, + .mux = -1, + .name = "AUX", +}; + +static struct i8042_values i8042_mux_values[I8042_NUM_MUX_PORTS]; + +static struct serio *i8042_kbd_port; +static struct serio *i8042_aux_port; +static struct serio *i8042_mux_port[I8042_NUM_MUX_PORTS]; static unsigned char i8042_initial_ctr; static unsigned char i8042_ctr; static unsigned char i8042_mux_open; static unsigned char i8042_mux_present; static unsigned char i8042_sysdev_initialized; static struct pm_dev *i8042_pm_dev; -struct timer_list i8042_timer; +static struct timer_list i8042_timer; /* * Shared IRQ's require a device pointer, but this driver doesn't support @@ -336,52 +352,6 @@ static void i8042_close(struct serio *port) i8042_flush(); } -/* - * Structures for registering the devices in the serio.c module. - */ - -static struct i8042_values i8042_kbd_values = { - .irqen = I8042_CTR_KBDINT, - .disable = I8042_CTR_KBDDIS, - .name = "KBD", - .mux = -1, -}; - -static struct serio i8042_kbd_port = -{ - .type = SERIO_8042_XL, - .write = i8042_kbd_write, - .open = i8042_open, - .close = i8042_close, - .port_data = &i8042_kbd_values, - .name = "i8042 Kbd Port", - .phys = I8042_KBD_PHYS_DESC, -}; - -static struct i8042_values i8042_aux_values = { - .irqen = I8042_CTR_AUXINT, - .disable = I8042_CTR_AUXDIS, - .name = "AUX", - .mux = -1, -}; - -static struct serio i8042_aux_port = -{ - .type = SERIO_8042, - .write = i8042_aux_write, - .open = i8042_open, - .close = i8042_close, - .port_data = &i8042_aux_values, - .name = "i8042 Aux Port", - .phys = I8042_AUX_PHYS_DESC, -}; - -static struct i8042_values i8042_mux_values[4]; -static struct serio i8042_mux_port[4]; -static char i8042_mux_names[4][32]; -static char i8042_mux_short[4][16]; -static char i8042_mux_phys[4][32]; - /* * i8042_interrupt() is the most important function in this driver - * it handles the interrupts from the i8042, and sends incoming bytes @@ -428,7 +398,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); - serio_interrupt(i8042_mux_port + ((str >> 6) & 3), data, dfl, regs); + serio_interrupt(i8042_mux_port[(str >> 6) & 3], data, dfl, regs); goto irq_ret; } @@ -439,14 +409,14 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) dfl & SERIO_TIMEOUT ? ", timeout" : ""); if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { - serio_interrupt(&i8042_aux_port, data, dfl, regs); + serio_interrupt(i8042_aux_port, data, dfl, regs); goto irq_ret; } if (!i8042_kbd_values.exists) goto irq_ret; - serio_interrupt(&i8042_kbd_port, data, dfl, regs); + serio_interrupt(i8042_kbd_port, data, dfl, regs); irq_ret: ret = 1; @@ -639,8 +609,10 @@ static int __init i8042_check_aux(struct i8042_values *values) * registers it, and reports to the user. */ -static int __init i8042_port_register(struct i8042_values *values, struct serio *port) +static int __init i8042_port_register(struct serio *port) { + struct i8042_values *values = port->port_data; + values->exists = 1; i8042_ctr &= ~values->disable; @@ -748,10 +720,8 @@ static int i8042_controller_init(void) * BIOSes. */ - if (i8042_direct) { + if (i8042_direct) i8042_ctr &= ~I8042_CTR_XLATE; - i8042_kbd_port.type = SERIO_8042; - } /* * Write CTR back. @@ -805,14 +775,14 @@ void i8042_controller_cleanup(void) */ if (i8042_kbd_values.exists) - serio_cleanup(&i8042_kbd_port); + serio_cleanup(i8042_kbd_port); if (i8042_aux_values.exists) - serio_cleanup(&i8042_aux_port); + serio_cleanup(i8042_aux_port); - for (i = 0; i < 4; i++) + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) if (i8042_mux_values[i].exists) - serio_cleanup(i8042_mux_port + i); + serio_cleanup(i8042_mux_port[i]); i8042_controller_reset(); } @@ -854,15 +824,15 @@ static int i8042_controller_resume(void) * Reconnect anything that was connected to the ports. */ - if (i8042_kbd_values.exists && i8042_activate_port(&i8042_kbd_port) == 0) - serio_reconnect(&i8042_kbd_port); + if (i8042_kbd_values.exists && i8042_activate_port(i8042_kbd_port) == 0) + serio_reconnect(i8042_kbd_port); - if (i8042_aux_values.exists && i8042_activate_port(&i8042_aux_port) == 0) - serio_reconnect(&i8042_aux_port); + if (i8042_aux_values.exists && i8042_activate_port(i8042_aux_port) == 0) + serio_reconnect(i8042_aux_port); - for (i = 0; i < 4; i++) - if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port + i) == 0) - serio_reconnect(i8042_mux_port + i); + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) + if (i8042_mux_values[i].exists && i8042_activate_port(i8042_mux_port[i]) == 0) + serio_reconnect(i8042_mux_port[i]); /* * Restart timer (for polling "stuck" data) */ @@ -932,18 +902,66 @@ static int i8042_pm_callback(struct pm_dev *dev, pm_request_t request, void *dum return 0; } -static void __init i8042_init_mux_values(struct i8042_values *values, struct serio *port, int index) +static struct serio * __init i8042_allocate_kbd_port(void) { - memcpy(port, &i8042_aux_port, sizeof(struct serio)); - memcpy(values, &i8042_aux_values, sizeof(struct i8042_values)); - sprintf(i8042_mux_names[index], "i8042 Aux-%d Port", index); - sprintf(i8042_mux_phys[index], I8042_MUX_PHYS_DESC, index + 1); - sprintf(i8042_mux_short[index], "AUX%d", index); - port->name = i8042_mux_names[index]; - port->phys = i8042_mux_phys[index]; - port->port_data = values; - values->name = i8042_mux_short[index]; - values->mux = index; + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = i8042_direct ? SERIO_8042 : SERIO_8042_XL, + serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write, + serio->open = i8042_open, + serio->close = i8042_close, + serio->port_data = &i8042_kbd_values, + strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); + } + + return serio; +} + +static struct serio * __init i8042_allocate_aux_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->port_data = &i8042_aux_values, + strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); + strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); + } + + return serio; +} + +static struct serio * __init i8042_allocate_mux_port(int index) +{ + struct serio *serio; + struct i8042_values *values = &i8042_mux_values[index]; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + *values = i8042_aux_values; + snprintf(values->name, sizeof(values->name), "AUX%d", index); + values->mux = index; + + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = i8042_aux_write; + serio->open = i8042_open; + serio->close = i8042_close; + serio->port_data = values; + snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); + snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); + } + + return serio; } int __init i8042_init(void) @@ -964,9 +982,6 @@ int __init i8042_init(void) if (i8042_controller_init()) return -ENODEV; - if (i8042_dumbkbd) - i8042_kbd_port.write = NULL; - #ifdef __i386__ if (i8042_dmi_noloop) { printk(KERN_INFO "i8042.c: AUX LoopBack command disabled by DMI.\n"); @@ -976,15 +991,21 @@ int __init i8042_init(void) if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) { if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values)) - for (i = 0; i < 4; i++) { - i8042_init_mux_values(i8042_mux_values + i, i8042_mux_port + i, i); - i8042_port_register(i8042_mux_values + i, i8042_mux_port + i); + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { + i8042_mux_port[i] = i8042_allocate_mux_port(i); + if (i8042_mux_port[i]) + i8042_port_register(i8042_mux_port[i]); } - else - i8042_port_register(&i8042_aux_values, &i8042_aux_port); + else { + i8042_aux_port = i8042_allocate_aux_port(); + if (i8042_aux_port) + i8042_port_register(i8042_aux_port); + } } - i8042_port_register(&i8042_kbd_values, &i8042_kbd_port); + i8042_kbd_port = i8042_allocate_kbd_port(); + if (i8042_kbd_port) + i8042_port_register(i8042_kbd_port); mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); @@ -1019,14 +1040,15 @@ void __exit i8042_exit(void) i8042_controller_cleanup(); if (i8042_kbd_values.exists) - serio_unregister_port(&i8042_kbd_port); + serio_unregister_port(i8042_kbd_port); if (i8042_aux_values.exists) - serio_unregister_port(&i8042_aux_port); + serio_unregister_port(i8042_aux_port); - for (i = 0; i < 4; i++) + for (i = 0; i < I8042_NUM_MUX_PORTS; i++) if (i8042_mux_values[i].exists) - serio_unregister_port(i8042_mux_port + i); + serio_unregister_port(i8042_mux_port[i]); + del_timer_sync(&i8042_timer); i8042_platform_exit(); diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index f0f637483233..cea24034d5be 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h @@ -103,6 +103,13 @@ #define I8042_BUFFER_SIZE 32 +/* + * Number of AUX ports on controllers supporting active multiplexing + * specification + */ + +#define I8042_NUM_MUX_PORTS 4 + /* * Debug. */ diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index bab997a7fcf6..e71e05535bae 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -46,12 +46,14 @@ MODULE_LICENSE("GPL"); #define PS2_CONTROL_RX_CLOCK_ENABLE BIT(4) /* pause reception if set to 0 */ #define PS2_CONTROL_RESET BIT(5) /* reset */ - struct maceps2_data { struct mace_ps2port *port; int irq; }; +static struct maceps2_data port_data[2]; +static struct serio *maceps2_port[2]; + static int maceps2_write(struct serio *dev, unsigned char val) { struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; @@ -68,8 +70,7 @@ static int maceps2_write(struct serio *dev, unsigned char val) return -1; } -static irqreturn_t maceps2_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t maceps2_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct serio *dev = dev_id; struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port; @@ -114,46 +115,52 @@ static void maceps2_close(struct serio *dev) free_irq(data->irq, dev); } -static struct maceps2_data port0_data, port1_data; -static struct serio maceps2_port0 = +static struct serio * __init maceps2_allocate_port(int idx) { - .type = SERIO_8042, - .open = maceps2_open, - .close = maceps2_close, - .write = maceps2_write, - .name = "MACE PS/2 port0", - .phys = "mace/serio0", - .port_data = &port0_data, -}; + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = maceps2_write; + serio->open = maceps2_open; + serio->close = maceps2_close; + snprintf(serio->name, sizeof(serio->name), "MACE PS/2 port%d", idx); + snprintf(serio->phys, sizeof(serio->phys), "mace/serio%d", idx); + serio->port_data = &port_data[idx]; + } + + return serio; +} -static struct serio maceps2_port1 = -{ - .type = SERIO_8042, - .open = maceps2_open, - .close = maceps2_close, - .write = maceps2_write, - .name = "MACE PS/2 port1", - .phys = "mace/serio1", - .port_data = &port1_data, -}; static int __init maceps2_init(void) { - port0_data.port = &mace->perif.ps2.keyb; - port0_data.irq = MACEISA_KEYB_IRQ; - port1_data.port = &mace->perif.ps2.mouse; - port1_data.irq = MACEISA_MOUSE_IRQ; - serio_register_port(&maceps2_port0); - serio_register_port(&maceps2_port1); + port_data[0].port = &mace->perif.ps2.keyb; + port_data[0].irq = MACEISA_KEYB_IRQ; + port_data[1].port = &mace->perif.ps2.mouse; + port_data[1].irq = MACEISA_MOUSE_IRQ; + + maceps2_port[0] = maceps2_allocate_port(0); + maceps2_port[1] = maceps2_allocate_port(1); + if (!maceps2_port[0] || !maceps2_port[1]) { + kfree(maceps2_port[0]); + kfree(maceps2_port[1]); + return -ENOMEM; + } + + serio_register_port(maceps2_port[0]); + serio_register_port(maceps2_port[1]); return 0; } static void __exit maceps2_exit(void) { - serio_unregister_port(&maceps2_port0); - serio_unregister_port(&maceps2_port1); + serio_unregister_port(maceps2_port[0]); + serio_unregister_port(maceps2_port[1]); } module_init(maceps2_init); diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c index 5f25b21bed21..07cc9c3b05fe 100644 --- a/drivers/input/serio/parkbd.c +++ b/drivers/input/serio/parkbd.c @@ -53,9 +53,7 @@ static int parkbd_writing; static unsigned long parkbd_start; static struct pardevice *parkbd_dev; - -static char parkbd_name[] = "PARKBD AT/XT keyboard adapter"; -static char parkbd_phys[32]; +static struct serio *parkbd_port; static int parkbd_readlines(void) { @@ -86,13 +84,6 @@ static int parkbd_write(struct serio *port, unsigned char c) return 0; } -static struct serio parkbd_port = -{ - .write = parkbd_write, - .name = parkbd_name, - .phys = parkbd_phys, -}; - static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -125,7 +116,7 @@ static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++; if (parkbd_counter == parkbd_mode + 10) - serio_interrupt(&parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); + serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs); } parkbd_last = jiffies; @@ -163,16 +154,38 @@ static int parkbd_getport(void) return 0; } +static struct serio * __init parkbd_allocate_serio(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + serio->type = parkbd_mode; + serio->write = parkbd_write, + strlcpy(serio->name, "PARKBD AT/XT keyboard adapter", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", parkbd_dev->port->name); + } + + return serio; +} int __init parkbd_init(void) { - if (parkbd_getport()) return -1; - parkbd_writelines(3); - parkbd_port.type = parkbd_mode; + int err; + + err = parkbd_getport(); + if (err) + return err; - sprintf(parkbd_phys, "%s/serio0", parkbd_dev->port->name); + parkbd_port = parkbd_allocate_serio(); + if (!parkbd_port) { + parport_release(parkbd_dev); + return -ENOMEM; + } + + parkbd_writelines(3); - serio_register_port(&parkbd_port); + serio_register_port(parkbd_port); printk(KERN_INFO "serio: PARKBD %s adapter on %s\n", parkbd_mode ? "AT" : "XT", parkbd_dev->port->name); @@ -183,7 +196,7 @@ int __init parkbd_init(void) void __exit parkbd_exit(void) { parport_release(parkbd_dev); - serio_unregister_port(&parkbd_port); + serio_unregister_port(parkbd_port); parport_unregister_device(parkbd_dev); } diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index ab67c0713aec..cc1f19129294 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -38,7 +38,7 @@ #define PS2_STAT_TXEMPTY (1<<7) struct pcips2_data { - struct serio io; + struct serio *io; unsigned int base; struct pci_dev *dev; }; @@ -80,7 +80,7 @@ static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs) if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; - serio_interrupt(&ps2if->io, scancode, flag, regs); + serio_interrupt(ps2if->io, scancode, flag, regs); } while (1); return IRQ_RETVAL(handled); } @@ -129,6 +129,7 @@ static void pcips2_close(struct serio *io) static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct pcips2_data *ps2if; + struct serio *serio; int ret; ret = pci_enable_device(dev); @@ -142,29 +143,34 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i } ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL); - if (!ps2if) { + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { ret = -ENOMEM; goto release; } memset(ps2if, 0, sizeof(struct pcips2_data)); - - ps2if->io.type = SERIO_8042; - ps2if->io.write = pcips2_write; - ps2if->io.open = pcips2_open; - ps2if->io.close = pcips2_close; - ps2if->io.name = pci_name(dev); - ps2if->io.phys = dev->dev.bus_id; - ps2if->io.port_data = ps2if; + memset(serio, 0, sizeof(struct serio)); + + serio->type = SERIO_8042; + serio->write = pcips2_write; + serio->open = pcips2_open; + serio->close = pcips2_close; + strlcpy(serio->name, pci_name(dev), sizeof(serio->name)); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->port_data = ps2if; + ps2if->io = serio; ps2if->dev = dev; ps2if->base = pci_resource_start(dev, 0); pci_set_drvdata(dev, ps2if); - serio_register_port(&ps2if->io); + serio_register_port(ps2if->io); return 0; release: + kfree(ps2if); + kfree(serio); release_region(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); disable: @@ -176,7 +182,7 @@ static void __devexit pcips2_remove(struct pci_dev *dev) { struct pcips2_data *ps2if = pci_get_drvdata(dev); - serio_unregister_port(&ps2if->io); + serio_unregister_port(ps2if->io); release_region(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); pci_set_drvdata(dev, NULL); diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 7f4a2628726a..85d1e1ea64ec 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -47,43 +47,98 @@ MODULE_AUTHOR("Vojtech Pavlik "); MODULE_DESCRIPTION("Q40 PS/2 keyboard controller driver"); MODULE_LICENSE("GPL"); -static struct serio q40kbd_port = -{ - .type = SERIO_8042, - .name = "Q40 kbd port", - .phys = "Q40", - .write = NULL, -}; - -static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, - struct pt_regs *regs) +spinlock_t q40kbd_lock = SPIN_LOCK_UNLOCKED; +static struct serio *q40kbd_port; + +static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + unsigned long flags; + + spin_lock_irqsave(&q40kbd_lock, flags); + if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)) - serio_interrupt(&q40kbd_port, master_inb(KEYCODE_REG), 0, regs); + serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs); master_outb(-1, KEYBOARD_UNLOCK_REG); + + spin_unlock_irqrestore(&q40kbd_lock, flags); + return IRQ_HANDLED; } -static int __init q40kbd_init(void) +/* + * q40kbd_flush() flushes all data that may be in the keyboard buffers + */ + +static void q40kbd_flush(void) { - int maxread = 100; + int maxread = 100; + unsigned long flags; - if (!MACH_IS_Q40) - return -EIO; + spin_lock_irqsave(&q40kbd_lock, flags); + + while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) + master_inb(KEYCODE_REG); + + spin_unlock_irqrestore(&q40kbd_lock, flags); +} + +/* + * q40kbd_open() is called when a port is open by the higher layer. + * It allocates the interrupt and enables in in the chip. + */ + +static int q40kbd_open(struct serio *port) +{ + q40kbd_flush(); + + if (request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL)) { + printk(KERN_ERR "q40kbd.c: Can't get irq %d.\n", Q40_IRQ_KEYBOARD); + return -1; + } - /* allocate the IRQ */ - request_irq(Q40_IRQ_KEYBOARD, q40kbd_interrupt, 0, "q40kbd", NULL); + /* off we go */ + master_outb(-1, KEYBOARD_UNLOCK_REG); + master_outb(1, KEY_IRQ_ENABLE_REG); - /* flush any pending input */ - while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))) - master_inb(KEYCODE_REG); + return 0; +} + +static void q40kbd_close(struct serio *port) +{ + master_outb(0, KEY_IRQ_ENABLE_REG); + master_outb(-1, KEYBOARD_UNLOCK_REG); + free_irq(Q40_IRQ_KEYBOARD, NULL); - /* off we go */ - master_outb(-1,KEYBOARD_UNLOCK_REG); - master_outb(1,KEY_IRQ_ENABLE_REG); + q40kbd_flush(); +} - serio_register_port(&q40kbd_port); +static struct serio * __init q40kbd_allocate_port(void) +{ + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->open = q40kbd_open; + serio->close = q40kbd_close; + strlcpy(serio->name, "Q40 Kbd Port", sizeof(serio->name)); + strlcpy(serio->phys, "Q40", sizeof(serio->phys)); + } + + return serio; +} + +static int __init q40kbd_init(void) +{ + if (!MACH_IS_Q40) + return -EIO; + + if (!(q40kbd_port = q40kbd_allocate_port())) + return -ENOMEM; + + serio_register_port(q40kbd_port); printk(KERN_INFO "serio: Q40 kbd registered\n"); return 0; @@ -91,11 +146,7 @@ static int __init q40kbd_init(void) static void __exit q40kbd_exit(void) { - master_outb(0,KEY_IRQ_ENABLE_REG); - master_outb(-1,KEYBOARD_UNLOCK_REG); - - serio_unregister_port(&q40kbd_port); - free_irq(Q40_IRQ_KEYBOARD, NULL); + serio_unregister_port(q40kbd_port); } module_init(q40kbd_init); diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index a2e4be7ae74c..a31e760c43a5 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -44,6 +44,8 @@ MODULE_AUTHOR("Vojtech Pavlik, Russell King"); MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); MODULE_LICENSE("GPL"); +static struct serio *rpckbd_port; + static int rpckbd_write(struct serio *port, unsigned char val) { while (!(iomd_readb(IOMD_KCTRL) & (1 << 7))) @@ -101,25 +103,41 @@ static void rpckbd_close(struct serio *port) free_irq(IRQ_KEYBOARDTX, port); } -static struct serio rpckbd_port = +/* + * Allocate and initialize serio structure for subsequent registration + * with serio core. + */ + +static struct serio * __init rpckbd_allocate_port(void) { - .type = SERIO_8042, - .open = rpckbd_open, - .close = rpckbd_close, - .write = rpckbd_write, - .name = "RiscPC PS/2 kbd port", - .phys = "rpckbd/serio0", -}; + struct serio *serio; + + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(struct serio)); + serio->type = SERIO_8042; + serio->write = rpckbd_write; + serio->open = rpckbd_open; + serio->close = rpckbd_close; + strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name)); + strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys)); + } + + return serio; +} static int __init rpckbd_init(void) { - serio_register_port(&rpckbd_port); + if (!(rpckbd_port = rpckbd_allocate_port())) + return -ENOMEM; + + serio_register_port(rpckbd_port); return 0; } static void __exit rpckbd_exit(void) { - serio_unregister_port(&rpckbd_port); + serio_unregister_port(rpckbd_port); } module_init(rpckbd_init); diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 3867206c9496..345c2da2ed43 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -26,7 +26,7 @@ #include struct ps2if { - struct serio io; + struct serio *io; struct sa1111_dev *dev; unsigned long base; unsigned int open; @@ -59,7 +59,7 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs) if (hweight8(scancode) & 1) flag ^= SERIO_PARITY; - serio_interrupt(&ps2if->io, scancode, flag, regs); + serio_interrupt(ps2if->io, scancode, flag, regs); status = sa1111_readl(ps2if->base + SA1111_PS2STAT); } @@ -232,22 +232,27 @@ static int __init ps2_test(struct ps2if *ps2if) static int ps2_probe(struct sa1111_dev *dev) { struct ps2if *ps2if; + struct serio *serio; int ret; ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL); - if (!ps2if) { - return -ENOMEM; + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (!ps2if || !serio) { + ret = -ENOMEM; + goto free; } memset(ps2if, 0, sizeof(struct ps2if)); - - ps2if->io.type = SERIO_8042; - ps2if->io.write = ps2_write; - ps2if->io.open = ps2_open; - ps2if->io.close = ps2_close; - ps2if->io.name = dev->dev.bus_id; - ps2if->io.phys = dev->dev.bus_id; - ps2if->io.port_data = ps2if; + memset(serio, 0, sizeof(struct serio)); + + serio->type = SERIO_8042; + serio->write = ps2_write; + serio->open = ps2_open; + serio->close = ps2_close; + strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name)); + strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); + serio->port_data = ps2if; + ps2if->io = serio; ps2if->dev = dev; sa1111_set_drvdata(dev, ps2if); @@ -292,7 +297,7 @@ static int ps2_probe(struct sa1111_dev *dev) ps2_clear_input(ps2if); sa1111_disable_device(ps2if->dev); - serio_register_port(&ps2if->io); + serio_register_port(ps2if->io); return 0; out: @@ -302,6 +307,7 @@ static int ps2_probe(struct sa1111_dev *dev) free: sa1111_set_drvdata(dev, NULL); kfree(ps2if); + kfree(serio); return ret; } @@ -312,7 +318,7 @@ static int ps2_remove(struct sa1111_dev *dev) { struct ps2if *ps2if = sa1111_get_drvdata(dev); - serio_unregister_port(&ps2if->io); + serio_unregister_port(ps2if->io); release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1); sa1111_set_drvdata(dev, NULL); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 7a369ec9f114..d606a6ac86fe 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -283,6 +283,7 @@ void __serio_unregister_port(struct serio *serio) list_del_init(&serio->node); if (serio->drv) serio->drv->disconnect(serio); + kfree(serio); } /* diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index f808ed55b6b5..5582ee8227d5 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -31,13 +31,10 @@ MODULE_ALIAS_LDISC(N_MOUSE); struct serport { struct tty_struct *tty; wait_queue_head_t wait; - struct serio serio; + struct serio *serio; unsigned long flags; - char phys[32]; }; -char serport_name[] = "Serial port"; - /* * Callback functions from the serio code. */ @@ -52,7 +49,7 @@ static void serport_serio_close(struct serio *serio) { struct serport *serport = serio->port_data; - serport->serio.type = 0; + serport->serio->type = 0; wake_up_interruptible(&serport->wait); } @@ -64,26 +61,30 @@ static void serport_serio_close(struct serio *serio) static int serport_ldisc_open(struct tty_struct *tty) { struct serport *serport; + struct serio *serio; char name[64]; serport = kmalloc(sizeof(struct serport), GFP_KERNEL); - if (unlikely(!serport)) + serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (unlikely(!serport || !serio)) { + kfree(serport); + kfree(serio); return -ENOMEM; - memset(serport, 0, sizeof(struct serport)); + } + memset(serport, 0, sizeof(struct serport)); + serport->serio = serio; set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); serport->tty = tty; tty->disc_data = serport; - snprintf(serport->phys, sizeof(serport->phys), "%s/serio0", tty_name(tty, name)); - - serport->serio.name = serport_name; - serport->serio.phys = serport->phys; - - serport->serio.type = SERIO_RS232; - serport->serio.write = serport_serio_write; - serport->serio.close = serport_serio_close; - serport->serio.port_data = serport; + memset(serio, 0, sizeof(struct serio)); + strlcpy(serio->name, "Serial port", sizeof(serio->name)); + snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty, name)); + serio->type = SERIO_RS232; + serio->write = serport_serio_write; + serio->close = serport_serio_close; + serio->port_data = serport; init_waitqueue_head(&serport->wait); @@ -114,7 +115,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c struct serport *serport = (struct serport*) tty->disc_data; int i; for (i = 0; i < count; i++) - serio_interrupt(&serport->serio, cp[i], 0, NULL); + serio_interrupt(serport->serio, cp[i], 0, NULL); } /* @@ -142,10 +143,10 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, u if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) return -EBUSY; - serio_register_port(&serport->serio); + serio_register_port(serport->serio); printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty, name)); - wait_event_interruptible(serport->wait, !serport->serio.type); - serio_unregister_port(&serport->serio); + wait_event_interruptible(serport->wait, !serport->serio->type); + serio_unregister_port(serport->serio); clear_bit(SERPORT_BUSY, &serport->flags); @@ -161,7 +162,7 @@ static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsi struct serport *serport = (struct serport*) tty->disc_data; if (cmd == SPIOCSTYPE) - return get_user(serport->serio.type, (unsigned long __user *) arg); + return get_user(serport->serio->type, (unsigned long __user *) arg); return -EINVAL; } @@ -170,7 +171,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty) { struct serport *sp = (struct serport *) tty->disc_data; - serio_drv_write_wakeup(&sp->serio); + serio_drv_write_wakeup(sp->serio); } /* diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 80605126b4b6..f6e9484999a7 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -98,7 +98,7 @@ struct uart_sunsu_port { unsigned int irq; #ifdef CONFIG_SERIO - struct serio serio; + struct serio *serio; int serio_open; #endif }; @@ -520,7 +520,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg /* Stop-A is handled by drivers/char/keyboard.c now. */ if (up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif } else if (up->su_type == SU_PORT_MS) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -534,7 +534,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg case 0: #ifdef CONFIG_SERIO - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif break; }; @@ -1284,54 +1284,58 @@ static struct uart_driver sunsu_reg = { .major = TTY_MAJOR, }; -static int __init sunsu_kbd_ms_init(void) +static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel) { - struct uart_sunsu_port *up; - int i; + struct serio *serio; - for (i = 0, up = sunsu_ports; i < 2; i++, up++) { - up->port.line = i; - up->port.type = PORT_UNKNOWN; - up->port.uartclk = (SU_BASE_BAUD * 16); + up->port.line = channel; + up->port.type = PORT_UNKNOWN; + up->port.uartclk = (SU_BASE_BAUD * 16); - if (up->su_type == SU_PORT_KBD) - up->cflag = B1200 | CS8 | CLOCAL | CREAD; - else - up->cflag = B4800 | CS8 | CLOCAL | CREAD; + if (up->su_type == SU_PORT_KBD) + up->cflag = B1200 | CS8 | CLOCAL | CREAD; + else + up->cflag = B4800 | CS8 | CLOCAL | CREAD; - sunsu_autoconfig(up); - if (up->port.type == PORT_UNKNOWN) - continue; + sunsu_autoconfig(up); + if (up->port.type == PORT_UNKNOWN) + return -1; - printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", - i, - up->port.membase, __irq_itoa(up->irq), - sunsu_type(&up->port)); + printk(KERN_INFO "su%d at 0x%p (irq = %s) is a %s\n", + channel, + up->port.membase, __irq_itoa(up->irq), + sunsu_type(&up->port)); #ifdef CONFIG_SERIO - memset(&up->serio, 0, sizeof(up->serio)); + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { + memset(serio, 0, sizeof(serio)); - up->serio.port_data = up; + serio->port_data = up; - up->serio.type = SERIO_RS232; + serio->type = SERIO_RS232; if (up->su_type == SU_PORT_KBD) { - up->serio.type |= SERIO_SUNKBD; - up->serio.name = "sukbd"; + serio->type |= SERIO_SUNKBD; + strlcpy(serio->name, "sukbd", sizeof(serio->name)); } else { - up->serio.type |= (SERIO_SUN | (1 << 16)); - up->serio.name = "sums"; + serio->type |= (SERIO_SUN | (1 << 16)); + strlcpy(serio->name, "sums", sizeof(serio->name)); } - up->serio.phys = (i == 0 ? "su/serio0" : "su/serio1"); + strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"), + sizeof(serio->phys)); - up->serio.write = sunsu_serio_write; - up->serio.open = sunsu_serio_open; - up->serio.close = sunsu_serio_close; + serio->write = sunsu_serio_write; + serio->open = sunsu_serio_open; + serio->close = sunsu_serio_close; - serio_register_port(&up->serio); + serio_register_port(serio); + } else { + printk(KERN_WARNING "su%d: not enough memory for serio port\n", + channel); + } #endif - sunsu_startup(&up->port); - } + sunsu_startup(&up->port); return 0; } @@ -1680,10 +1684,12 @@ static int __init sunsu_probe(void) if (scan.msx != -1 && scan.kbx != -1) { sunsu_ports[0].su_type = SU_PORT_MS; sunsu_ports[0].port_node = scan.msnode; + sunsu_kbd_ms_init(&sunsu_ports[0], 0); + sunsu_ports[1].su_type = SU_PORT_KBD; sunsu_ports[1].port_node = scan.kbnode; + sunsu_kbd_ms_init(&sunsu_ports[1], 1); - sunsu_kbd_ms_init(); return 0; } @@ -1715,7 +1721,10 @@ static void __exit sunsu_exit(void) if (up->su_type == SU_PORT_MS || up->su_type == SU_PORT_KBD) { #ifdef CONFIG_SERIO - serio_unregister_port(&up->serio); + if (up->serio) { + serio_unregister_port(up->serio); + up->serio = NULL; + } #endif } else if (up->port.type != PORT_UNKNOWN) { uart_remove_one_port(&sunsu_reg, &up->port); diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 8071e33729f6..e5989624731d 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -107,7 +107,7 @@ struct uart_sunzilog_port { unsigned char prev_status; #ifdef CONFIG_SERIO - struct serio serio; + struct serio *serio; int serio_open; #endif }; @@ -291,7 +291,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, /* Stop-A is handled by drivers/char/keyboard.c now. */ #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif } else if (ZS_IS_MOUSE(up)) { int ret = suncore_mouse_baud_detection(ch, is_break); @@ -306,7 +306,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up, case 0: #ifdef CONFIG_SERIO if (up->serio_open) - serio_interrupt(&up->serio, ch, 0, regs); + serio_interrupt(up->serio, ch, 0, regs); #endif break; }; @@ -1529,6 +1529,7 @@ static void __init sunzilog_prepare(void) static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) { int baud, brg; + struct serio *serio; if (channel == KEYBOARD_LINE) { up->flags |= SUNZILOG_FLAG_CONS_KEYB; @@ -1547,26 +1548,34 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe sunzilog_convert_to_zs(up, up->cflag, 0, brg); #ifdef CONFIG_SERIO - memset(&up->serio, 0, sizeof(up->serio)); + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); + if (serio) { - up->serio.port_data = up; + memset(serio, 0, sizeof(serio)); - up->serio.type = SERIO_RS232; - if (channel == KEYBOARD_LINE) { - up->serio.type |= SERIO_SUNKBD; - up->serio.name = "zskbd"; - } else { - up->serio.type |= (SERIO_SUN | (1 << 16)); - up->serio.name = "zsms"; - } - up->serio.phys = (channel == KEYBOARD_LINE ? - "zs/serio0" : "zs/serio1"); + serio->port_data = up; - up->serio.write = sunzilog_serio_write; - up->serio.open = sunzilog_serio_open; - up->serio.close = sunzilog_serio_close; + serio->type = SERIO_RS232; + if (channel == KEYBOARD_LINE) { + serio->type |= SERIO_SUNKBD; + strlcpy(serio->name, "zskbd", sizeof(serio->name)); + } else { + serio->type |= (SERIO_SUN | (1 << 16)); + strlcpy(serio->name, "zsms", sizeof(serio->name)); + } + strlcpy(serio->phys, + (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), + sizeof(serio->phys)); + + serio->write = sunzilog_serio_write; + serio->open = sunzilog_serio_open; + serio->close = sunzilog_serio_close; - serio_register_port(&up->serio); + serio_register_port(serio); + } else { + printk(KERN_WARNING "zs%d: not enough memory for serio port\n", + channel); + } #endif sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); @@ -1732,10 +1741,15 @@ static void __exit sunzilog_exit(void) for (i = 0; i < NUM_CHANNELS; i++) { struct uart_sunzilog_port *up = &sunzilog_port_table[i]; - if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) - continue; - - uart_remove_one_port(&sunzilog_reg, &up->port); + if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) { +#ifdef CONFIG_SERIO + if (up->serio) { + serio_unregister_port(up->serio); + up->serio = NULL; + } +#endif + } else + uart_remove_one_port(&sunzilog_reg, &up->port); } uart_unregister_driver(&sunzilog_reg); diff --git a/include/linux/serio.h b/include/linux/serio.h index be0ce4360d8b..65f2a95879e4 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -22,8 +22,9 @@ struct serio { void *private; void *port_data; - char *name; - char *phys; + + char name[32]; + char phys[32]; unsigned short idbus; unsigned short idvendor; -- cgit v1.2.3 From d537c384b56daf106ccbd94b1be365df8fb8541e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jun 2004 15:28:21 -0500 Subject: Input: allow serio drivers to create children ports and register these ports for them in serio core to avoid having recursion in connect methods. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 75 ++++++++----- drivers/input/mouse/psmouse.h | 16 +-- drivers/input/mouse/synaptics.c | 27 ++--- drivers/input/serio/serio.c | 215 ++++++++++++++++++++++++++++--------- include/linux/serio.h | 4 +- 5 files changed, 231 insertions(+), 106 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index c11298d3482b..be99f5edcd3a 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -652,16 +652,15 @@ static void psmouse_cleanup(struct serio *serio) static void psmouse_disconnect(struct serio *serio) { - struct psmouse *psmouse = serio->private; + struct psmouse *psmouse, *parent; + psmouse = serio->private; psmouse->state = PSMOUSE_CMD_MODE; - if (psmouse->ptport) { - if (psmouse->ptport->deactivate) - psmouse->ptport->deactivate(psmouse); - __serio_unregister_port(psmouse->ptport->serio); /* we have serio_sem */ - kfree(psmouse->ptport); - psmouse->ptport = NULL; + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { + parent = serio->parent->private; + if (parent->pt_deactivate) + parent->pt_deactivate(parent); } if (psmouse->disconnect) @@ -680,14 +679,17 @@ static void psmouse_disconnect(struct serio *serio) */ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) { - struct psmouse *psmouse; + struct psmouse *psmouse, *parent = NULL; if ((serio->type & SERIO_TYPE) != SERIO_8042 && (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU) return; + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) + parent = serio->parent->private; + if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) - return; + goto out; memset(psmouse, 0, sizeof(struct psmouse)); @@ -703,14 +705,14 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) if (serio_open(serio, drv)) { kfree(psmouse); serio->private = NULL; - return; + goto out; } if (psmouse_probe(psmouse) < 0) { serio_close(serio); kfree(psmouse); serio->private = NULL; - return; + goto out; } psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); @@ -739,20 +741,36 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse_initialize(psmouse); - if (psmouse->ptport) { - printk(KERN_INFO "serio: %s port at %s\n", psmouse->ptport->serio->name, psmouse->phys); - __serio_register_port(psmouse->ptport->serio); /* we have serio_sem */ - if (psmouse->ptport->activate) - psmouse->ptport->activate(psmouse); - } + if (parent && parent->pt_activate) + parent->pt_activate(parent); - psmouse_activate(psmouse); + /* + * OK, the device is ready, we just need to activate it (turn the + * stream mode on). But if mouse has a pass-through port we don't + * want to do it yet to not disturb child detection. + * The child will activate this port when it's ready. + */ + + if (serio->child) { + /* + * Nothing to be done here, serio core will detect that + * the driver set serio->child and will register it for us. + */ + printk(KERN_INFO "serio: %s port at %s\n", serio->child->name, psmouse->phys); + } else + psmouse_activate(psmouse); + +out: + /* If this is a pass-through port the parent awaits to be activated */ + if (parent) + psmouse_activate(parent); } static int psmouse_reconnect(struct serio *serio) { struct psmouse *psmouse = serio->private; + struct psmouse *parent = NULL; struct serio_driver *drv = serio->drv; if (!drv || !psmouse) { @@ -779,16 +797,19 @@ static int psmouse_reconnect(struct serio *serio) */ psmouse_initialize(psmouse); - if (psmouse->ptport) { - if (psmouse_reconnect(psmouse->ptport->serio)) { - __serio_unregister_port(psmouse->ptport->serio); - __serio_register_port(psmouse->ptport->serio); - if (psmouse->ptport->activate) - psmouse->ptport->activate(psmouse); - } - } + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) + parent = serio->parent->private; + + if (parent && parent->pt_activate) + parent->pt_activate(parent); + + if (!serio->child) + psmouse_activate(psmouse); + + /* If this is a pass-through port the parent waits to be activated */ + if (parent) + psmouse_activate(parent); - psmouse_activate(psmouse); return 0; } diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 73cc16ef8ba9..56f143453fab 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -34,21 +34,10 @@ typedef enum { PSMOUSE_FULL_PACKET } psmouse_ret_t; -struct psmouse; - -struct psmouse_ptport { - struct serio *serio; - struct psmouse *parent; - - void (*activate)(struct psmouse *parent); - void (*deactivate)(struct psmouse *parent); -}; - struct psmouse { void *private; struct input_dev dev; struct serio *serio; - struct psmouse_ptport *ptport; char *vendor; char *name; unsigned char cmdbuf[8]; @@ -66,9 +55,12 @@ struct psmouse { char phys[32]; unsigned long flags; - psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); + psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); int (*reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); + + void (*pt_activate)(struct psmouse *psmouse); + void (*pt_deactivate)(struct psmouse *psmouse); }; #define PSMOUSE_PS2 1 diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 955f5c394015..764642f41071 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -212,14 +212,14 @@ static int synaptics_set_mode(struct psmouse *psmouse, int mode) /***************************************************************************** * Synaptics pass-through PS/2 port support ****************************************************************************/ -static int synaptics_pt_write(struct serio *port, unsigned char c) +static int synaptics_pt_write(struct serio *serio, unsigned char c) { - struct psmouse_ptport *ptport = port->port_data; + struct psmouse *parent = serio->parent->private; char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ - if (psmouse_sliced_command(ptport->parent, c)) + if (psmouse_sliced_command(parent, c)) return -1; - if (psmouse_command(ptport->parent, &rate_param, PSMOUSE_CMD_SETRATE)) + if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE)) return -1; return 0; } @@ -248,7 +248,7 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet static void synaptics_pt_activate(struct psmouse *psmouse) { - struct psmouse *child = psmouse->ptport->serio->private; + struct psmouse *child = psmouse->serio->child->private; /* adjust the touchpad to child's choice of protocol */ if (child && child->type >= PSMOUSE_GENPS) { @@ -259,30 +259,25 @@ static void synaptics_pt_activate(struct psmouse *psmouse) static void synaptics_pt_create(struct psmouse *psmouse) { - struct psmouse_ptport *port; struct serio *serio; - port = kmalloc(sizeof(struct psmouse_ptport), GFP_KERNEL); serio = kmalloc(sizeof(struct serio), GFP_KERNEL); - if (!port || !serio) { + if (!serio) { printk(KERN_ERR "synaptics: not enough memory to allocate pass-through port\n"); return; } - memset(port, 0, sizeof(struct psmouse_ptport)); memset(serio, 0, sizeof(struct serio)); serio->type = SERIO_PS_PSTHRU; strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); serio->write = synaptics_pt_write; - serio->port_data = port; + serio->parent = psmouse->serio; - port->serio = serio; - port->parent = psmouse; - port->activate = synaptics_pt_activate; + psmouse->pt_activate = synaptics_pt_activate; - psmouse->ptport = port; + psmouse->serio->child = serio; } /***************************************************************************** @@ -477,8 +472,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (psmouse->ptport && psmouse->ptport->serio->drv && synaptics_is_pt_packet(psmouse->packet)) - synaptics_pass_pt_packet(psmouse->ptport->serio, psmouse->packet); + if (psmouse->serio->child && psmouse->serio->child->drv && synaptics_is_pt_packet(psmouse->packet)) + synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet); else synaptics_process_packet(psmouse); diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index d606a6ac86fe..7666843a6023 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -44,10 +44,8 @@ MODULE_LICENSE("GPL"); EXPORT_SYMBOL(serio_interrupt); EXPORT_SYMBOL(serio_register_port); EXPORT_SYMBOL(serio_register_port_delayed); -EXPORT_SYMBOL(__serio_register_port); EXPORT_SYMBOL(serio_unregister_port); EXPORT_SYMBOL(serio_unregister_port_delayed); -EXPORT_SYMBOL(__serio_unregister_port); EXPORT_SYMBOL(serio_register_driver); EXPORT_SYMBOL(serio_unregister_driver); EXPORT_SYMBOL(serio_open); @@ -59,17 +57,28 @@ static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_diriver_list * static LIST_HEAD(serio_list); static LIST_HEAD(serio_driver_list); -/* serio_find_driver() must be called with serio_sem down. */ +static void serio_find_driver(struct serio *serio); +static void serio_create_port(struct serio *serio); +static void serio_destroy_port(struct serio *serio); +static void serio_connect_port(struct serio *serio, struct serio_driver *drv); +static void serio_reconnect_port(struct serio *serio); +static void serio_disconnect_port(struct serio *serio); + +static int serio_bind_driver(struct serio *serio, struct serio_driver *drv) +{ + drv->connect(serio, drv); + return serio->drv != NULL; +} + +/* serio_find_driver() must be called with serio_sem down. */ static void serio_find_driver(struct serio *serio) { struct serio_driver *drv; - list_for_each_entry(drv, &serio_driver_list, node) { - if (serio->drv) + list_for_each_entry(drv, &serio_driver_list, node) + if (serio_bind_driver(serio, drv)) break; - drv->connect(serio, drv); - } } /* @@ -145,23 +154,22 @@ static void serio_handle_events(void) switch (event->type) { case SERIO_REGISTER_PORT : - __serio_register_port(event->serio); + serio_create_port(event->serio); + serio_connect_port(event->serio, NULL); break; case SERIO_UNREGISTER_PORT : - __serio_unregister_port(event->serio); + serio_disconnect_port(event->serio); + serio_destroy_port(event->serio); break; case SERIO_RECONNECT : - if (event->serio->drv && event->serio->drv->reconnect) - if (event->serio->drv->reconnect(event->serio) == 0) - break; - /* reconnect failed - fall through to rescan */ + serio_reconnect_port(event->serio); + break; case SERIO_RESCAN : - if (event->serio->drv) - event->serio->drv->disconnect(event->serio); - serio_find_driver(event->serio); + serio_disconnect_port(event->serio); + serio_connect_port(event->serio, NULL); break; default: break; @@ -216,6 +224,118 @@ static int serio_thread(void *nothing) * Serio port operations */ +static void serio_create_port(struct serio *serio) +{ + spin_lock_init(&serio->lock); + list_add_tail(&serio->node, &serio_list); +} + +/* + * serio_destroy_port() completes deregistration process and removes + * port from the system + */ +static void serio_destroy_port(struct serio *serio) +{ + struct serio_driver *drv = serio->drv; + unsigned long flags; + + serio_remove_pending_events(serio); + list_del_init(&serio->node); + + if (drv) + drv->disconnect(serio); + + if (serio->parent) { + spin_lock_irqsave(&serio->parent->lock, flags); + serio->parent->child = NULL; + spin_unlock_irqrestore(&serio->parent->lock, flags); + } + + kfree(serio); +} + +/* + * serio_connect_port() tries to bind the port and possible all its + * children to appropriate drivers. If driver passed in the function will not + * try otehr drivers when binding parent port. + */ +static void serio_connect_port(struct serio *serio, struct serio_driver *drv) +{ + WARN_ON(serio->drv); + WARN_ON(serio->child); + + if (drv) + serio_bind_driver(serio, drv); + else + serio_find_driver(serio); + + /* Ok, now bind children, if any */ + while (serio->child) { + serio = serio->child; + + WARN_ON(serio->drv); + WARN_ON(serio->child); + + serio_create_port(serio); + + /* + * With children we just _prefer_ passed in driver, + * but we will try other options in case preferred + * is not the one + */ + if (!drv || !serio_bind_driver(serio, drv)) + serio_find_driver(serio); + } +} + +/* + * + */ +static void serio_reconnect_port(struct serio *serio) +{ + do { + if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + /* Ok, old children are now gone, we are done */ + break; + } + serio = serio->child; + } while (serio); +} + +/* + * serio_disconnect_port() unbinds a port from its driver. As a side effect + * all child ports are unbound and destroyed. + */ +static void serio_disconnect_port(struct serio *serio) +{ + struct serio_driver *drv = serio->drv; + struct serio *s; + + if (serio->child) { + /* + * Children ports should be disconnected and destroyed + * first, staring with the leaf one, since we don't want + * to do recursion + */ + do { + s = serio->child; + } while (s->child); + + while (s != serio) { + s = s->parent; + serio_destroy_port(s->child); + } + } + + /* + * Ok, no children left, now disconnect this port + */ + if (drv) + drv->disconnect(serio); +} + void serio_rescan(struct serio *serio) { serio_queue_event(serio, SERIO_RESCAN); @@ -229,7 +349,8 @@ void serio_reconnect(struct serio *serio) void serio_register_port(struct serio *serio) { down(&serio_sem); - __serio_register_port(serio); + serio_create_port(serio); + serio_connect_port(serio, NULL); up(&serio_sem); } @@ -243,22 +364,11 @@ void serio_register_port_delayed(struct serio *serio) serio_queue_event(serio, SERIO_REGISTER_PORT); } -/* - * Should only be called directly if serio_sem has already been taken, - * for example when unregistering a serio from other input device's - * connect() function. - */ -void __serio_register_port(struct serio *serio) -{ - spin_lock_init(&serio->lock); - list_add_tail(&serio->node, &serio_list); - serio_find_driver(serio); -} - void serio_unregister_port(struct serio *serio) { down(&serio_sem); - __serio_unregister_port(serio); + serio_disconnect_port(serio); + serio_destroy_port(serio); up(&serio_sem); } @@ -272,32 +382,33 @@ void serio_unregister_port_delayed(struct serio *serio) serio_queue_event(serio, SERIO_UNREGISTER_PORT); } -/* - * Should only be called directly if serio_sem has already been taken, - * for example when unregistering a serio from other input device's - * disconnect() function. - */ -void __serio_unregister_port(struct serio *serio) -{ - serio_remove_pending_events(serio); - list_del_init(&serio->node); - if (serio->drv) - serio->drv->disconnect(serio); - kfree(serio); -} /* * Serio driver operations */ + void serio_register_driver(struct serio_driver *drv) { struct serio *serio; + down(&serio_sem); + list_add_tail(&drv->node, &serio_driver_list); - list_for_each_entry(serio, &serio_list, node) - if (!serio->drv) - drv->connect(serio, drv); + +start_over: + list_for_each_entry(serio, &serio_list, node) { + if (!serio->drv) { + serio_connect_port(serio, drv); + /* + * if new child appeared then the list is changed, + * we need to start over + */ + if (serio->child) + goto start_over; + } + } + up(&serio_sem); } @@ -306,13 +417,19 @@ void serio_unregister_driver(struct serio_driver *drv) struct serio *serio; down(&serio_sem); + list_del_init(&drv->node); +start_over: list_for_each_entry(serio, &serio_list, node) { - if (serio->drv == drv) - drv->disconnect(serio); - serio_find_driver(serio); + if (serio->drv == drv) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + /* we could've deleted some ports, restart */ + goto start_over; + } } + up(&serio_sem); } diff --git a/include/linux/serio.h b/include/linux/serio.h index 65f2a95879e4..751772999c22 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -40,6 +40,8 @@ struct serio { int (*open)(struct serio *); void (*close)(struct serio *); + struct serio *parent, *child; + struct serio_driver *drv; /* Accessed from interrupt, writes must be protected by serio_lock */ struct list_head node; @@ -68,10 +70,8 @@ irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned in void serio_register_port(struct serio *serio); void serio_register_port_delayed(struct serio *serio); -void __serio_register_port(struct serio *serio); void serio_unregister_port(struct serio *serio); void serio_unregister_port_delayed(struct serio *serio); -void __serio_unregister_port(struct serio *serio); void serio_register_driver(struct serio_driver *drv); void serio_unregister_driver(struct serio_driver *drv); -- cgit v1.2.3 From 5821dbd4e1560b9464f2c8e15db73352cb5692a5 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jun 2004 15:28:53 -0500 Subject: Input: serio sysfs integration Signed-off-by: Dmitry Torokhov --- drivers/Makefile | 2 +- drivers/input/joystick/iforce/iforce-serio.c | 12 ++-- drivers/input/joystick/magellan.c | 14 +++-- drivers/input/joystick/spaceball.c | 14 +++-- drivers/input/joystick/spaceorb.c | 14 +++-- drivers/input/joystick/stinger.c | 14 +++-- drivers/input/joystick/twidjoy.c | 10 +++- drivers/input/joystick/warrior.c | 14 +++-- drivers/input/keyboard/atkbd.c | 18 ++++-- drivers/input/keyboard/lkkbd.c | 14 +++-- drivers/input/keyboard/newtonkbd.c | 14 +++-- drivers/input/keyboard/sunkbd.c | 14 +++-- drivers/input/keyboard/xtkbd.c | 14 +++-- drivers/input/mouse/psmouse-base.c | 18 ++++-- drivers/input/mouse/sermouse.c | 14 +++-- drivers/input/mouse/vsxxxaa.c | 14 +++-- drivers/input/serio/serio.c | 85 ++++++++++++++++++++++++---- drivers/input/touchscreen/gunze.c | 14 +++-- drivers/input/touchscreen/h3600_ts_input.c | 14 +++-- include/linux/serio.h | 9 ++- 20 files changed, 253 insertions(+), 83 deletions(-) diff --git a/drivers/Makefile b/drivers/Makefile index c767329e931c..456e89df13e4 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -37,9 +37,9 @@ obj-$(CONFIG_PARIDE) += block/paride/ obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_USB) += usb/ obj-$(CONFIG_USB_GADGET) += usb/gadget/ +obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_GAMEPORT) += input/gameport/ -obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_PHONE) += telephony/ diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c index 196a62b85661..9422407c2acb 100644 --- a/drivers/input/joystick/iforce/iforce-serio.c +++ b/drivers/input/joystick/iforce/iforce-serio.c @@ -159,8 +159,12 @@ static void iforce_serio_disconnect(struct serio *serio) } struct serio_driver iforce_serio_drv = { - .write_wakeup = iforce_serio_write_wakeup, - .interrupt = iforce_serio_irq, - .connect = iforce_serio_connect, - .disconnect = iforce_serio_disconnect, + .driver = { + .name = "iforce", + }, + .description = "RS232 I-Force joysticks and wheels driver", + .write_wakeup = iforce_serio_write_wakeup, + .interrupt = iforce_serio_irq, + .connect = iforce_serio_connect, + .disconnect = iforce_serio_disconnect, }; diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c index ba2b6f846d7c..2b303bac57ae 100644 --- a/drivers/input/joystick/magellan.c +++ b/drivers/input/joystick/magellan.c @@ -35,8 +35,10 @@ #include #include +#define DRIVER_DESC "Magellan and SpaceMouse 6dof controller driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Magellan and SpaceMouse 6dof controller driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -200,9 +202,13 @@ static void magellan_connect(struct serio *serio, struct serio_driver *drv) */ static struct serio_driver magellan_drv = { - .interrupt = magellan_interrupt, - .connect = magellan_connect, - .disconnect = magellan_disconnect, + .driver = { + .name = "magellan", + }, + .description = DRIVER_DESC, + .interrupt = magellan_interrupt, + .connect = magellan_connect, + .disconnect = magellan_disconnect, }; /* diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c index 6f50c1e1dd81..40412528ef9d 100644 --- a/drivers/input/joystick/spaceball.c +++ b/drivers/input/joystick/spaceball.c @@ -39,8 +39,10 @@ #include #include +#define DRIVER_DESC "SpaceTec SpaceBall 2003/3003/4000 FLX driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("SpaceTec SpaceBall 2003/3003/4000 FLX driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -270,9 +272,13 @@ static void spaceball_connect(struct serio *serio, struct serio_driver *drv) */ static struct serio_driver spaceball_drv = { - .interrupt = spaceball_interrupt, - .connect = spaceball_connect, - .disconnect = spaceball_disconnect, + .driver = { + .name = "spaceball", + }, + .description = DRIVER_DESC, + .interrupt = spaceball_interrupt, + .connect = spaceball_connect, + .disconnect = spaceball_disconnect, }; /* diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c index 7078ea8df46c..c20091a6ecb5 100644 --- a/drivers/input/joystick/spaceorb.c +++ b/drivers/input/joystick/spaceorb.c @@ -38,8 +38,10 @@ #include #include +#define DRIVER_DESC "SpaceTec SpaceOrb 360 and Avenger 6dof controller driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("SpaceTec SpaceOrb 360 and Avenger 6dof controller driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -214,9 +216,13 @@ static void spaceorb_connect(struct serio *serio, struct serio_driver *drv) */ static struct serio_driver spaceorb_drv = { - .interrupt = spaceorb_interrupt, - .connect = spaceorb_connect, - .disconnect = spaceorb_disconnect, + .driver = { + .name = "spaceorb", + }, + .description = DRIVER_DESC, + .interrupt = spaceorb_interrupt, + .connect = spaceorb_connect, + .disconnect = spaceorb_disconnect, }; /* diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c index 10d17a17d241..580e32375f30 100644 --- a/drivers/input/joystick/stinger.c +++ b/drivers/input/joystick/stinger.c @@ -36,8 +36,10 @@ #include #include +#define DRIVER_DESC "Gravis Stinger gamepad driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Gravis Stinger gamepad driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -188,9 +190,13 @@ static void stinger_connect(struct serio *serio, struct serio_driver *drv) */ static struct serio_driver stinger_drv = { - .interrupt = stinger_interrupt, - .connect = stinger_connect, - .disconnect = stinger_disconnect, + .driver = { + .name = "stinger", + }, + .description = DRIVER_DESC, + .interrupt = stinger_interrupt, + .connect = stinger_connect, + .disconnect = stinger_disconnect, }; /* diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c index f8be506086e3..909b6b54aae5 100644 --- a/drivers/input/joystick/twidjoy.c +++ b/drivers/input/joystick/twidjoy.c @@ -247,9 +247,13 @@ static void twidjoy_connect(struct serio *serio, struct serio_driver *drv) */ static struct serio_driver twidjoy_drv = { - .interrupt = twidjoy_interrupt, - .connect = twidjoy_connect, - .disconnect = twidjoy_disconnect, + .driver = { + .name = "twidjoy", + }, + .description = DRIVER_DESC, + .interrupt = twidjoy_interrupt, + .connect = twidjoy_connect, + .disconnect = twidjoy_disconnect, }; /* diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c index 6b29897f47fd..5f19b2a51f27 100644 --- a/drivers/input/joystick/warrior.c +++ b/drivers/input/joystick/warrior.c @@ -35,8 +35,10 @@ #include #include +#define DRIVER_DESC "Logitech WingMan Warrior joystick driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Logitech WingMan Warrior joystick driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -200,9 +202,13 @@ static void warrior_connect(struct serio *serio, struct serio_driver *drv) */ static struct serio_driver warrior_drv = { - .interrupt = warrior_interrupt, - .connect = warrior_connect, - .disconnect = warrior_disconnect, + .driver = { + .name = "warrior", + }, + .description = DRIVER_DESC, + .interrupt = warrior_interrupt, + .connect = warrior_connect, + .disconnect = warrior_disconnect, }; /* diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index ea74e7eee690..8b7291cd59bd 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -27,8 +27,10 @@ #include #include +#define DRIVER_DESC "AT and PS/2 keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("AT and PS/2 keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static int atkbd_set = 2; @@ -891,11 +893,15 @@ static int atkbd_reconnect(struct serio *serio) } static struct serio_driver atkbd_drv = { - .interrupt = atkbd_interrupt, - .connect = atkbd_connect, - .reconnect = atkbd_reconnect, - .disconnect = atkbd_disconnect, - .cleanup = atkbd_cleanup, + .driver = { + .name = "atkbd", + }, + .description = DRIVER_DESC, + .interrupt = atkbd_interrupt, + .connect = atkbd_connect, + .reconnect = atkbd_reconnect, + .disconnect = atkbd_disconnect, + .cleanup = atkbd_cleanup, }; int __init atkbd_init(void) diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c index fc875611f985..a04cf3efd3c3 100644 --- a/drivers/input/keyboard/lkkbd.c +++ b/drivers/input/keyboard/lkkbd.c @@ -76,8 +76,10 @@ #include #include +#define DRIVER_DESC "LK keyboard driver" + MODULE_AUTHOR ("Jan-Benedict Glaw "); -MODULE_DESCRIPTION ("LK keyboard driver"); +MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); /* @@ -704,9 +706,13 @@ lkkbd_disconnect (struct serio *serio) } static struct serio_driver lkkbd_drv = { - .connect = lkkbd_connect, - .disconnect = lkkbd_disconnect, - .interrupt = lkkbd_interrupt, + .driver = { + .name = "lkkbd", + }, + .description = DRIVER_DESC, + .connect = lkkbd_connect, + .disconnect = lkkbd_disconnect, + .interrupt = lkkbd_interrupt, }; /* diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c index 1b6cefb51e66..caa92dd8bbe4 100644 --- a/drivers/input/keyboard/newtonkbd.c +++ b/drivers/input/keyboard/newtonkbd.c @@ -32,8 +32,10 @@ #include #include +#define DRIVER_DESC "Newton keyboard driver" + MODULE_AUTHOR("Justin Cormack "); -MODULE_DESCRIPTION("Newton keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); #define NKBD_KEY 0x7f @@ -139,9 +141,13 @@ void nkbd_disconnect(struct serio *serio) } struct serio_driver nkbd_drv = { - .interrupt = nkbd_interrupt, - .connect = nkbd_connect, - .disconnect = nkbd_disconnect + .driver = { + .name = "newtonkbd", + }, + .description = DRIVER_DESC, + .interrupt = nkbd_interrupt, + .connect = nkbd_connect, + .disconnect = nkbd_disconnect, }; int __init nkbd_init(void) diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c index 9db172d19583..4513d90575f8 100644 --- a/drivers/input/keyboard/sunkbd.c +++ b/drivers/input/keyboard/sunkbd.c @@ -37,8 +37,10 @@ #include #include +#define DRIVER_DESC "Sun keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Sun keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static unsigned char sunkbd_keycode[128] = { @@ -302,9 +304,13 @@ static void sunkbd_disconnect(struct serio *serio) } static struct serio_driver sunkbd_drv = { - .interrupt = sunkbd_interrupt, - .connect = sunkbd_connect, - .disconnect = sunkbd_disconnect + .driver = { + .name = "sunkbd", + }, + .description = DRIVER_DESC, + .interrupt = sunkbd_interrupt, + .connect = sunkbd_connect, + .disconnect = sunkbd_disconnect, }; /* diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c index 5542f29cf6c7..eb8a9b72be0b 100644 --- a/drivers/input/keyboard/xtkbd.c +++ b/drivers/input/keyboard/xtkbd.c @@ -34,8 +34,10 @@ #include #include +#define DRIVER_DESC "XT keyboard driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("XT keyboard driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); #define XTKBD_EMUL0 0xe0 @@ -144,9 +146,13 @@ void xtkbd_disconnect(struct serio *serio) } struct serio_driver xtkbd_drv = { - .interrupt = xtkbd_interrupt, - .connect = xtkbd_connect, - .disconnect = xtkbd_disconnect + .driver = { + .name = "xtkbd", + }, + .description = DRIVER_DESC, + .interrupt = xtkbd_interrupt, + .connect = xtkbd_connect, + .disconnect = xtkbd_disconnect, }; int __init xtkbd_init(void) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index be99f5edcd3a..346ec46126f7 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -22,8 +22,10 @@ #include "synaptics.h" #include "logips2pp.h" +#define DRIVER_DESC "PS/2 mouse driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("PS/2 mouse driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static char *psmouse_proto; @@ -815,11 +817,15 @@ static int psmouse_reconnect(struct serio *serio) static struct serio_driver psmouse_drv = { - .interrupt = psmouse_interrupt, - .connect = psmouse_connect, - .reconnect = psmouse_reconnect, - .disconnect = psmouse_disconnect, - .cleanup = psmouse_cleanup, + .driver = { + .name = "psmouse", + }, + .description = DRIVER_DESC, + .interrupt = psmouse_interrupt, + .connect = psmouse_connect, + .reconnect = psmouse_reconnect, + .disconnect = psmouse_disconnect, + .cleanup = psmouse_cleanup, }; static inline void psmouse_parse_proto(void) diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c index d0e4176344d6..e1db6e078c0b 100644 --- a/drivers/input/mouse/sermouse.c +++ b/drivers/input/mouse/sermouse.c @@ -37,8 +37,10 @@ #include #include +#define DRIVER_DESC "Serial mouse driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Serial mouse driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse", @@ -290,9 +292,13 @@ static void sermouse_connect(struct serio *serio, struct serio_driver *drv) } static struct serio_driver sermouse_drv = { - .interrupt = sermouse_interrupt, - .connect = sermouse_connect, - .disconnect = sermouse_disconnect + .driver = { + .name = "sermouse", + }, + .description = DRIVER_DESC, + .interrupt = sermouse_interrupt, + .connect = sermouse_connect, + .disconnect = sermouse_disconnect, }; int __init sermouse_init(void) diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c index 29acfe06f74f..3845ca458f80 100644 --- a/drivers/input/mouse/vsxxxaa.c +++ b/drivers/input/mouse/vsxxxaa.c @@ -82,8 +82,10 @@ #include #include +#define DRIVER_DESC "Serial DEC VSXXX-AA/GA mouse / DEC tablet driver" + MODULE_AUTHOR ("Jan-Benedict Glaw "); -MODULE_DESCRIPTION ("Serial DEC VSXXX-AA/GA mouse / DEC tablet driver"); +MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE ("GPL"); #undef VSXXXAA_DEBUG @@ -541,9 +543,13 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv) } static struct serio_driver vsxxxaa_drv = { - .connect = vsxxxaa_connect, - .interrupt = vsxxxaa_interrupt, - .disconnect = vsxxxaa_disconnect, + .driver = { + .name = "vsxxxaa", + }, + .description = DRIVER_DESC, + .connect = vsxxxaa_connect, + .interrupt = vsxxxaa_interrupt, + .disconnect = vsxxxaa_disconnect, }; int __init diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 7666843a6023..9761c53edb6b 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -56,6 +56,11 @@ EXPORT_SYMBOL(serio_reconnect); static DECLARE_MUTEX(serio_sem); /* protects serio_list and serio_diriver_list */ static LIST_HEAD(serio_list); static LIST_HEAD(serio_driver_list); +static unsigned int serio_no; + +struct bus_type serio_bus = { + .name = "serio", +}; static void serio_find_driver(struct serio *serio); static void serio_create_port(struct serio *serio); @@ -66,9 +71,19 @@ static void serio_disconnect_port(struct serio *serio); static int serio_bind_driver(struct serio *serio, struct serio_driver *drv) { + get_driver(&drv->driver); + drv->connect(serio, drv); + if (serio->drv) { + down_write(&serio_bus.subsys.rwsem); + serio->dev.driver = &drv->driver; + device_bind_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + return 1; + } - return serio->drv != NULL; + put_driver(&drv->driver); + return 0; } /* serio_find_driver() must be called with serio_sem down. */ @@ -224,10 +239,41 @@ static int serio_thread(void *nothing) * Serio port operations */ +static ssize_t serio_show_description(struct device *dev, char *buf) +{ + struct serio *serio = to_serio_port(dev); + return sprintf(buf, "%s\n", serio->name); +} +static DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL); + +static ssize_t serio_show_driver(struct device *dev, char *buf) +{ + return sprintf(buf, "%s\n", dev->driver ? dev->driver->name : "(none)"); +} +static DEVICE_ATTR(driver, S_IRUGO, serio_show_driver, NULL); + +static void serio_release_port(struct device *dev) +{ + struct serio *serio = to_serio_port(dev); + + kfree(serio); + module_put(THIS_MODULE); +} + static void serio_create_port(struct serio *serio) { + try_module_get(THIS_MODULE); + spin_lock_init(&serio->lock); list_add_tail(&serio->node, &serio_list); + snprintf(serio->dev.bus_id, sizeof(serio->dev.bus_id), "serio%d", serio_no++); + serio->dev.bus = &serio_bus; + serio->dev.release = serio_release_port; + if (serio->parent) + serio->dev.parent = &serio->parent->dev; + device_register(&serio->dev); + device_create_file(&serio->dev, &dev_attr_description); + device_create_file(&serio->dev, &dev_attr_driver); } /* @@ -242,8 +288,13 @@ static void serio_destroy_port(struct serio *serio) serio_remove_pending_events(serio); list_del_init(&serio->node); - if (drv) + if (drv) { drv->disconnect(serio); + down_write(&serio_bus.subsys.rwsem); + device_release_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + put_driver(&drv->driver); + } if (serio->parent) { spin_lock_irqsave(&serio->parent->lock, flags); @@ -251,7 +302,7 @@ static void serio_destroy_port(struct serio *serio) spin_unlock_irqrestore(&serio->parent->lock, flags); } - kfree(serio); + device_unregister(&serio->dev); } /* @@ -332,8 +383,13 @@ static void serio_disconnect_port(struct serio *serio) /* * Ok, no children left, now disconnect this port */ - if (drv) + if (drv) { drv->disconnect(serio); + down_write(&serio_bus.subsys.rwsem); + device_release_driver(&serio->dev); + up_write(&serio_bus.subsys.rwsem); + put_driver(&drv->driver); + } } void serio_rescan(struct serio *serio) @@ -387,6 +443,12 @@ void serio_unregister_port_delayed(struct serio *serio) * Serio driver operations */ +static ssize_t serio_driver_show_description(struct device_driver *drv, char *buf) +{ + struct serio_driver *driver = to_serio_driver(drv); + return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); +} +static DRIVER_ATTR(description, S_IRUGO, serio_driver_show_description, NULL); void serio_register_driver(struct serio_driver *drv) { @@ -396,6 +458,10 @@ void serio_register_driver(struct serio_driver *drv) list_add_tail(&drv->node, &serio_driver_list); + drv->driver.bus = &serio_bus; + driver_register(&drv->driver); + driver_create_file(&drv->driver, &driver_attr_description); + start_over: list_for_each_entry(serio, &serio_list, node) { if (!serio->drv) { @@ -430,6 +496,8 @@ start_over: } } + driver_unregister(&drv->driver); + up(&serio_sem); } @@ -489,22 +557,19 @@ irqreturn_t serio_interrupt(struct serio *serio, static int __init serio_init(void) { - int pid; - - pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL); - - if (!pid) { + if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) { printk(KERN_WARNING "serio: Failed to start kseriod\n"); return -1; } - serio_pid = pid; + bus_register(&serio_bus); return 0; } static void __exit serio_exit(void) { + bus_unregister(&serio_bus); kill_proc(serio_pid, SIGTERM, 1); wait_for_completion(&serio_exited); } diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index ca00633d4b64..e5e38dd4a191 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -36,8 +36,10 @@ #include #include +#define DRIVER_DESC "Gunze AHL-51S touchscreen driver" + MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Gunze AHL-51S touchscreen driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -157,9 +159,13 @@ static void gunze_connect(struct serio *serio, struct serio_driver *drv) */ static struct serio_driver gunze_drv = { - .interrupt = gunze_interrupt, - .connect = gunze_connect, - .disconnect = gunze_disconnect, + .driver = { + .name = "gunze", + }, + .description = DRIVER_DESC, + .interrupt = gunze_interrupt, + .connect = gunze_connect, + .disconnect = gunze_disconnect, }; /* diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 514816c3f1e7..5d719671cda2 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -45,8 +45,10 @@ #include #include +#define DRIVER_DESC "H3600 touchscreen driver" + MODULE_AUTHOR("James Simmons "); -MODULE_DESCRIPTION("H3600 touchscreen driver"); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); /* @@ -479,9 +481,13 @@ static void h3600ts_disconnect(struct serio *serio) */ static struct serio_driver h3600ts_drv = { - .interrupt = h3600ts_interrupt, - .connect = h3600ts_connect, - .disconnect = h3600ts_disconnect, + .driver = { + .name = "h3600ts", + }, + .description = DRIVER_DESC, + .interrupt = h3600ts_interrupt, + .connect = h3600ts_connect, + .disconnect = h3600ts_disconnect, }; /* diff --git a/include/linux/serio.h b/include/linux/serio.h index 751772999c22..50beac56ae2e 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -18,6 +18,7 @@ #include #include +#include struct serio { void *private; @@ -44,12 +45,15 @@ struct serio { struct serio_driver *drv; /* Accessed from interrupt, writes must be protected by serio_lock */ + struct device dev; + struct list_head node; }; +#define to_serio_port(d) container_of(d, struct serio, dev) struct serio_driver { void *private; - char *name; + char *description; void (*write_wakeup)(struct serio *); irqreturn_t (*interrupt)(struct serio *, unsigned char, @@ -59,8 +63,11 @@ struct serio_driver { void (*disconnect)(struct serio *); void (*cleanup)(struct serio *); + struct device_driver driver; + struct list_head node; }; +#define to_serio_driver(d) container_of(d, struct serio_driver, driver) int serio_open(struct serio *serio, struct serio_driver *drv); void serio_close(struct serio *serio); -- cgit v1.2.3 From 514c2a8ffd3dec820e57d3f90fd6638a78ada16c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jun 2004 15:29:39 -0500 Subject: Input: allow users manually rebind serio ports, like this: echo -n "psmouse" > /sys/bus/serio/devices/serio0/driver echo -n "atkbd" > /sys/bus/serio/devices/serio1/driver echo -n "none" > /sys/bus/serio/devices/serio1/driver echo -n "reconnect" > /sys/bus/serio/devices/serio1/driver echo -n "rescan" > /sys/bus/serio/devices/serio1/driver Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 9761c53edb6b..7bbadc8dd1a2 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -250,7 +250,39 @@ static ssize_t serio_show_driver(struct device *dev, char *buf) { return sprintf(buf, "%s\n", dev->driver ? dev->driver->name : "(none)"); } -static DEVICE_ATTR(driver, S_IRUGO, serio_show_driver, NULL); + +static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t count) +{ + struct serio *serio = to_serio_port(dev); + struct device_driver *drv; + struct kobject *k; + int retval; + + retval = down_interruptible(&serio_sem); + if (retval) + return retval; + + retval = count; + if (!strncmp(buf, "none", count)) { + serio_disconnect_port(serio); + } else if (!strncmp(buf, "reconnect", count)) { + serio_reconnect_port(serio); + } else if (!strncmp(buf, "rescan", count)) { + serio_disconnect_port(serio); + serio_connect_port(serio, NULL); + } else if ((k = kset_find_obj(&serio_bus.drivers, buf)) != NULL) { + drv = container_of(k, struct device_driver, kobj); + serio_disconnect_port(serio); + serio_connect_port(serio, to_serio_driver(drv)); + } else { + retval = -EINVAL; + } + + up(&serio_sem); + + return retval; +} +static DEVICE_ATTR(driver, S_IWUSR | S_IRUGO, serio_show_driver, serio_rebind_driver); static void serio_release_port(struct device *dev) { -- cgit v1.2.3 From 876311cd2c75b1b08c9032e23a595df78c2fdd79 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jun 2004 15:30:19 -0500 Subject: Input: allow marking some drivers (that don't do HW autodetection) as manual bind only. Such drivers will only be bound to a serio port if user requests it by echoing driver name into port's sysfs driver attribute. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 9 +++++++-- include/linux/serio.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 7bbadc8dd1a2..63b246dfa5a0 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -92,8 +92,9 @@ static void serio_find_driver(struct serio *serio) struct serio_driver *drv; list_for_each_entry(drv, &serio_driver_list, node) - if (serio_bind_driver(serio, drv)) - break; + if (!drv->manual_bind) + if (serio_bind_driver(serio, drv)) + break; } /* @@ -494,6 +495,9 @@ void serio_register_driver(struct serio_driver *drv) driver_register(&drv->driver); driver_create_file(&drv->driver, &driver_attr_description); + if (drv->manual_bind) + goto out; + start_over: list_for_each_entry(serio, &serio_list, node) { if (!serio->drv) { @@ -507,6 +511,7 @@ start_over: } } +out: up(&serio_sem); } diff --git a/include/linux/serio.h b/include/linux/serio.h index 50beac56ae2e..38c4e59aae0f 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -55,6 +55,8 @@ struct serio_driver { void *private; char *description; + int manual_bind; + void (*write_wakeup)(struct serio *); irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int, struct pt_regs *); -- cgit v1.2.3 From b9a20b83c6b170863c872ba6aa59cb75fd05dd74 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jun 2004 15:31:03 -0500 Subject: Input: Add serio_raw driver that binds to serio ports and provides unobstructed access to the underlying serio port via a char device. The driver tries to register char device 10,1 (/dev/psaux) first and if it fails goes for dynamically allocated minor. To bind use sysfs interface: echo -n "serio_raw" > /sys/bus/serio/devices/serioX/driver Signed-off-by: Dmitry Torokhov --- drivers/input/serio/Kconfig | 16 ++ drivers/input/serio/Makefile | 1 + drivers/input/serio/serio_raw.c | 390 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 407 insertions(+) create mode 100644 drivers/input/serio/serio_raw.c diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index cd74954bd472..31fe603e9d12 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -130,3 +130,19 @@ config SERIO_MACEPS2 To compile this driver as a module, choose M here: the module will be called maceps2. + +config SERIO_RAW + tristate "Raw access to serio ports" + depends on SERIO + help + Say Y here if you want to have raw access to serio ports, such as + AUX ports on i8042 keyboard controller. Each serio port that is + bound to this driver will be accessible via a char device with + major 10 and dynamically allocated minor. The driver will try + 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 + + To compile this driver as a module, choose M here: the + module will be called serio_raw. diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile index a47dec2556e8..cf52b6141363 100644 --- a/drivers/input/serio/Makefile +++ b/drivers/input/serio/Makefile @@ -17,3 +17,4 @@ obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o +obj-$(CONFIG_SERIO_RAW) += serio_raw.o diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c new file mode 100644 index 000000000000..f4b78bbd5cfe --- /dev/null +++ b/drivers/input/serio/serio_raw.c @@ -0,0 +1,390 @@ +/* + * Raw serio device providing access to a raw byte stream from underlying + * serio port. Closely emulates behavior of pre-2.6 /dev/psaux device + * + * Copyright (c) 2004 Dmitry Torokhov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_DESC "Raw serio driver" + +MODULE_AUTHOR("Dmitry Torokhov "); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +#define SERIO_RAW_QUEUE_LEN 64 +struct serio_raw { + unsigned char queue[SERIO_RAW_QUEUE_LEN]; + unsigned int tail, head; + + char name[16]; + unsigned int refcnt; + struct serio *serio; + struct miscdevice dev; + wait_queue_head_t wait; + struct list_head list; + struct list_head node; +}; + +struct serio_raw_list { + struct fasync_struct *fasync; + struct serio_raw *serio_raw; + struct list_head node; +}; + +static DECLARE_MUTEX(serio_raw_sem); +static LIST_HEAD(serio_raw_list); +static unsigned int serio_raw_no; + +/********************************************************************* + * Interface with userspace (file operations) * + *********************************************************************/ + +static int serio_raw_fasync(int fd, struct file *file, int on) +{ + struct serio_raw_list *list = file->private_data; + int retval; + + retval = fasync_helper(fd, file, on, &list->fasync); + return retval < 0 ? retval : 0; +} + +static struct serio_raw *serio_raw_locate(int minor) +{ + struct serio_raw *serio_raw; + + list_for_each_entry(serio_raw, &serio_raw_list, node) { + if (serio_raw->dev.minor == minor) + return serio_raw; + } + + return NULL; +} + +static int serio_raw_open(struct inode *inode, struct file *file) +{ + struct serio_raw *serio_raw; + struct serio_raw_list *list; + int retval = 0; + + retval = down_interruptible(&serio_raw_sem); + if (retval) + return retval; + + if (!(serio_raw = serio_raw_locate(iminor(inode)))) { + retval = -ENODEV; + goto out; + } + + if (!serio_raw->serio) { + retval = -ENODEV; + goto out; + } + + if (!(list = kmalloc(sizeof(struct serio_raw_list), GFP_KERNEL))) { + retval = -ENOMEM; + goto out; + } + + memset(list, 0, sizeof(struct serio_raw_list)); + list->serio_raw = serio_raw; + file->private_data = list; + + serio_raw->refcnt++; + list_add_tail(&list->node, &serio_raw->list); + +out: + up(&serio_raw_sem); + return retval; +} + +static int serio_raw_cleanup(struct serio_raw *serio_raw) +{ + if (--serio_raw->refcnt == 0) { + misc_deregister(&serio_raw->dev); + list_del_init(&serio_raw->node); + kfree(serio_raw); + + return 1; + } + + return 0; +} + +static int serio_raw_release(struct inode *inode, struct file *file) +{ + struct serio_raw_list *list = file->private_data; + struct serio_raw *serio_raw = list->serio_raw; + + down(&serio_raw_sem); + + serio_raw_fasync(-1, file, 0); + serio_raw_cleanup(serio_raw); + + up(&serio_raw_sem); + return 0; +} + +static int serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c) +{ + unsigned long flags; + int empty; + + spin_lock_irqsave(&serio_raw->serio->lock, flags); + + empty = serio_raw->head == serio_raw->tail; + if (!empty) { + *c = serio_raw->queue[serio_raw->tail]; + serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN; + } + + spin_unlock_irqrestore(&serio_raw->serio->lock, flags); + + return !empty; +} + +static ssize_t serio_raw_read(struct file *file, char *buffer, size_t count, loff_t *ppos) +{ + struct serio_raw_list *list = file->private_data; + struct serio_raw *serio_raw = list->serio_raw; + char c; + ssize_t retval = 0; + + if (!serio_raw->serio) + return -ENODEV; + + if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK)) + return -EAGAIN; + + retval = wait_event_interruptible(list->serio_raw->wait, + serio_raw->head != serio_raw->tail || !serio_raw->serio); + if (retval) + return retval; + + if (!serio_raw->serio) + return -ENODEV; + + while (retval < count && serio_raw_fetch_byte(serio_raw, &c)) { + if (put_user(c, buffer++)) + return -EFAULT; + retval++; + } + + return retval; +} + +static ssize_t serio_raw_write(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + struct serio_raw_list *list = file->private_data; + ssize_t written = 0; + int retval; + unsigned char c; + + retval = down_interruptible(&serio_raw_sem); + if (retval) + return retval; + + if (!list->serio_raw->serio) { + retval = -ENODEV; + goto out; + } + + if (count > 32) + count = 32; + + while (count--) { + if (get_user(c, buffer++)) { + retval = -EFAULT; + goto out; + } + if (serio_write(list->serio_raw->serio, c)) { + retval = -EIO; + goto out; + } + written++; + }; + +out: + up(&serio_raw_sem); + return written; +} + +static unsigned int serio_raw_poll(struct file *file, poll_table *wait) +{ + struct serio_raw_list *list = file->private_data; + + poll_wait(file, &list->serio_raw->wait, wait); + + if (list->serio_raw->head != list->serio_raw->tail) + return POLLIN | POLLRDNORM; + + return 0; +} + +struct file_operations serio_raw_fops = { + .owner = THIS_MODULE, + .open = serio_raw_open, + .release = serio_raw_release, + .read = serio_raw_read, + .write = serio_raw_write, + .poll = serio_raw_poll, + .fasync = serio_raw_fasync, +}; + + +/********************************************************************* + * Interface with serio port * + *********************************************************************/ + +static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data, + unsigned int dfl, struct pt_regs *regs) +{ + struct serio_raw *serio_raw = serio->private; + struct serio_raw_list *list; + unsigned int head = serio_raw->head; + + /* we are holding serio->lock here so we are prootected */ + serio_raw->queue[head] = data; + head = (head + 1) % SERIO_RAW_QUEUE_LEN; + if (likely(head != serio_raw->tail)) { + serio_raw->head = head; + list_for_each_entry(list, &serio_raw->list, node) + kill_fasync(&list->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&serio_raw->wait); + } + + return IRQ_HANDLED; +} + +static void serio_raw_connect(struct serio *serio, struct serio_driver *drv) +{ + struct serio_raw *serio_raw; + int err; + + if ((serio->type & SERIO_TYPE) != SERIO_8042) + return; + + if (!(serio_raw = kmalloc(sizeof(struct serio_raw), GFP_KERNEL))) { + printk(KERN_ERR "serio_raw.c: can't allocate memory for a device\n"); + return; + } + + down(&serio_raw_sem); + + memset(serio_raw, 0, sizeof(struct serio_raw)); + snprintf(serio_raw->name, sizeof(serio_raw->name), "serio_raw%d", serio_raw_no++); + serio_raw->refcnt = 1; + serio_raw->serio = serio; + INIT_LIST_HEAD(&serio_raw->list); + init_waitqueue_head(&serio_raw->wait); + + serio->private = serio_raw; + if (serio_open(serio, drv)) + goto out_free; + + list_add_tail(&serio_raw->node, &serio_raw_list); + + serio_raw->dev.minor = PSMOUSE_MINOR; + serio_raw->dev.name = serio_raw->name; + serio_raw->dev.fops = &serio_raw_fops; + + err = misc_register(&serio_raw->dev); + if (err) { + serio_raw->dev.minor = MISC_DYNAMIC_MINOR; + err = misc_register(&serio_raw->dev); + } + + if (err) { + printk(KERN_INFO "serio_raw: failed to register raw access device for %s\n", + serio->phys); + goto out_close; + } + + printk(KERN_INFO "serio_raw: raw access enabled on %s (%s, minor %d)\n", + serio->phys, serio_raw->name, serio_raw->dev.minor); + goto out; + +out_close: + serio_close(serio); + list_del_init(&serio_raw->node); +out_free: + serio->private = NULL; + kfree(serio_raw); +out: + up(&serio_raw_sem); +} + +static int serio_raw_reconnect(struct serio *serio) +{ + struct serio_raw *serio_raw = serio->private; + struct serio_driver *drv = serio->drv; + + if (!drv || !serio_raw) { + printk(KERN_DEBUG "serio_raw: reconnect request, but serio is disconnected, ignoring...\n"); + return -1; + } + + /* + * Nothing needs to be done here, we just need this method to + * keep the same device. + */ + return 0; +} + +static void serio_raw_disconnect(struct serio *serio) +{ + struct serio_raw *serio_raw; + + down(&serio_raw_sem); + + serio_raw = serio->private; + + serio_close(serio); + serio->private = NULL; + + serio_raw->serio = NULL; + if (!serio_raw_cleanup(serio_raw)) + wake_up_interruptible(&serio_raw->wait); + + up(&serio_raw_sem); +} + +static struct serio_driver serio_raw_drv = { + .driver = { + .name = "serio_raw", + }, + .description = DRIVER_DESC, + .interrupt = serio_raw_interrupt, + .connect = serio_raw_connect, + .reconnect = serio_raw_reconnect, + .disconnect = serio_raw_disconnect, + .manual_bind = 1, +}; + +int __init serio_raw_init(void) +{ + serio_register_driver(&serio_raw_drv); + return 0; +} + +void __exit serio_raw_exit(void) +{ + serio_unregister_driver(&serio_raw_drv); +} + +module_init(serio_raw_init); +module_exit(serio_raw_exit); -- cgit v1.2.3 From 71b3cd2d568a1d5ec00e403c2b98d131888aacad Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 28 Jun 2004 15:36:29 -0500 Subject: Input: link serio ports to their parent devices in ambakmi, gscps2, pcips2 and sa1111ps2 drivers Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ambakmi.c | 1 + drivers/input/serio/gscps2.c | 1 + drivers/input/serio/pcips2.c | 1 + drivers/input/serio/sa1111ps2.c | 1 + 4 files changed, 4 insertions(+) diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 4b793b640ec6..4b3b5135f5c1 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -141,6 +141,7 @@ static int amba_kmi_probe(struct amba_device *dev, void *id) strlcpy(io->name, dev->dev.bus_id, sizeof(io->name)); strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys)); io->port_data = kmi; + io->dev.parent = &dev->dev; kmi->io = io; kmi->base = ioremap(dev->res.start, KMI_SIZE); diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index ee91428be054..5395467f2eb2 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -385,6 +385,7 @@ static int __init gscps2_probe(struct parisc_device *dev) serio->open = gscps2_open; serio->close = gscps2_close; serio->port_data = ps2port; + serio->dev.parent = &dev->dev; list_add_tail(&ps2port->node, &ps2port_list); diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index cc1f19129294..610f94a18348 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -159,6 +159,7 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i strlcpy(serio->name, pci_name(dev), sizeof(serio->name)); strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); serio->port_data = ps2if; + serio->dev.parent = &dev->dev; ps2if->io = serio; ps2if->dev = dev; ps2if->base = pci_resource_start(dev, 0); diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c index 345c2da2ed43..62937f5b3e57 100644 --- a/drivers/input/serio/sa1111ps2.c +++ b/drivers/input/serio/sa1111ps2.c @@ -252,6 +252,7 @@ static int ps2_probe(struct sa1111_dev *dev) strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name)); strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys)); serio->port_data = ps2if; + serio->dev.parent = &dev->dev; ps2if->io = serio; ps2if->dev = dev; sa1111_set_drvdata(dev, ps2if); -- cgit v1.2.3 From 10f4f052905cd201c47e2b876ebb8b606d0c3298 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Tue, 29 Jun 2004 13:48:40 +0200 Subject: input: Fix Kconfig so that the joydump module can be compiled. Reported-by: Matthieu Castet Signed-off-by: Vojtech Pavlik --- drivers/input/joystick/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 7d506f1f742f..d2903255ef7f 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -247,7 +247,7 @@ config JOYSTICK_AMIGA To compile this driver as a module, choose M here: the module will be called amijoy. -config INPUT_JOYDUMP +config JOYSTICK_JOYDUMP tristate "Gameport data dumper" depends on INPUT && INPUT_JOYSTICK help -- cgit v1.2.3 From b1c088a57fd388a7106c25c17e69180fe7d176fd Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Tue, 29 Jun 2004 15:59:04 +0200 Subject: input: Move Compaq ProLiant DMI handling (ServerWorks/OSB workaround) to i8042.c. Signed-off-by: Vojtech Pavlik --- drivers/input/serio/i8042-io.h | 31 +++++++++++++++++++++++++++++++ drivers/input/serio/i8042.c | 12 ++---------- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h index 9b36485fc605..83a1691a2238 100644 --- a/drivers/input/serio/i8042-io.h +++ b/drivers/input/serio/i8042-io.h @@ -63,6 +63,31 @@ static inline void i8042_write_command(int val) return; } +#if defined(__i386__) + +#include + +static struct dmi_system_id __initdata i8042_dmi_table[] = { + { + .ident = "Compaq Proliant 8500", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), + DMI_MATCH(DMI_PRODUCT_VERSION, "8500"), + }, + }, + { + .ident = "Compaq Proliant DL760", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), + DMI_MATCH(DMI_PRODUCT_NAME , "ProLiant"), + DMI_MATCH(DMI_PRODUCT_VERSION, "DL760"), + }, + }, + { } +}; +#endif + static inline int i8042_platform_init(void) { /* @@ -77,6 +102,12 @@ static inline int i8042_platform_init(void) #if !defined(__i386__) && !defined(__x86_64__) i8042_reset = 1; #endif + +#if defined(__i386__) + if (dmi_check_system(i8042_dmi_table)) + i8042_noloop = 1; +#endif + return 0; } diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 6f4df27d0214..075324215d89 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -52,10 +52,9 @@ static unsigned int i8042_dumbkbd; module_param_named(dumbkbd, i8042_dumbkbd, bool, 0); MODULE_PARM_DESC(dumbkbd, "Pretend that controller can only read data from keyboard"); -#ifdef __i386__ -extern unsigned int i8042_dmi_noloop; -#endif static unsigned int i8042_noloop; +module_param_named(noloop, i8042_noloop, bool, 0); +MODULE_PARM_DESC(dumbkbd, "Disable the AUX Loopback command while probing for the AUX port"); __obsolete_setup("i8042_noaux"); __obsolete_setup("i8042_nomux"); @@ -967,13 +966,6 @@ int __init i8042_init(void) if (i8042_dumbkbd) i8042_kbd_port.write = NULL; -#ifdef __i386__ - if (i8042_dmi_noloop) { - printk(KERN_INFO "i8042.c: AUX LoopBack command disabled by DMI.\n"); - i8042_noloop = 1; - } -#endif - if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) { if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values)) for (i = 0; i < 4; i++) { -- cgit v1.2.3 From 7c5241b33d8f95a9c5ce29522e0a98a7e2dcc699 Mon Sep 17 00:00:00 2001 From: Adam Kropelin Date: Mon, 5 Jul 2004 17:38:52 +0200 Subject: This patch fixes another disconnect oops in hiddev. hid-core calls hiddev_disconnect() when the underlying device goes away (hot unplug or system shutdown). Normally, hiddev_disconnect() will clean up nicely and return to hid-core who then frees the hid structure. However, if the corresponding hiddev node is open at disconnect time, hiddev delays the majority of disconnect work until the device is closed via hiddev_release(). hiddev_release() calls hiddev_cleanup() which proceeds to dereference the hid struct which hid-core freed back when the hardware was disconnected. Oops. To solve this, we change hiddev_disconnect() to deregister the hiddev minor and invalidate its table entry immediately and delay only the freeing of the hiddev structure itself. We're protected against future operations on the fd since the major fops check hiddev->exists. There may still be an ordering of events that causes a problem but I can no longer reproduce any manually. There are enough different subsystems and object lifetimes interacting here that I may have screwed something else up; review is certainly welcome. Signed-off-by: Adam Kropelin Signed-off-by: Vojtech Pavlik --- drivers/usb/input/hiddev.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index dc4a309dafb7..29f4c8e9a7d2 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -226,16 +226,6 @@ static int hiddev_fasync(int fd, struct file *file, int on) return retval < 0 ? retval : 0; } -/* - * De-allocate a hiddev structure - */ -static struct usb_class_driver hiddev_class; -static void hiddev_cleanup(struct hiddev *hiddev) -{ - hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; - usb_deregister_dev(hiddev->hid->intf, &hiddev_class); - kfree(hiddev); -} /* * release file op @@ -256,7 +246,7 @@ static int hiddev_release(struct inode * inode, struct file * file) if (list->hiddev->exist) hid_close(list->hiddev->hid); else - hiddev_cleanup(list->hiddev); + kfree(list->hiddev); } kfree(list); @@ -804,17 +794,21 @@ int hiddev_connect(struct hid_device *hid) * This is where hid.c calls us to disconnect a hiddev device from the * corresponding hid device (usually because the usb device has disconnected) */ +static struct usb_class_driver hiddev_class; void hiddev_disconnect(struct hid_device *hid) { struct hiddev *hiddev = hid->hiddev; hiddev->exist = 0; + hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; + usb_deregister_dev(hiddev->hid->intf, &hiddev_class); + if (hiddev->open) { hid_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { - hiddev_cleanup(hiddev); + kfree(hiddev); } } -- cgit v1.2.3 From 1428ddf3c9d0025b3cda5d45d792bff07424ba13 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 12:34:23 -0500 Subject: Input: move input/serio closer to the top of drivers/Makefile so serio_bus is available early Signed-off-by: Dmitry Torokhov --- drivers/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/Makefile b/drivers/Makefile index dfd1aa5c1c46..541ea3063acb 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -15,6 +15,9 @@ obj-$(CONFIG_PNP) += pnp/ # char/ comes before serial/ etc so that the VT console is the boot-time # default. obj-y += char/ +# we also need input/serio early so serio bus is initialized by the time +# serial drivers start registering their serio ports +obj-$(CONFIG_SERIO) += input/serio/ obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ block/ misc/ net/ media/ @@ -37,7 +40,6 @@ obj-$(CONFIG_PARIDE) += block/paride/ obj-$(CONFIG_TC) += tc/ obj-$(CONFIG_USB) += usb/ obj-$(CONFIG_USB_GADGET) += usb/gadget/ -obj-$(CONFIG_SERIO) += input/serio/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_I2O) += message/ -- cgit v1.2.3 From f8011d31d9ea14725fc5380ea02b2ce5169772e0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 12:35:13 -0500 Subject: Input: rearrange code in sunzilog so it registers its serio ports only after hardware was fully initialized and with interrupts tuned back on, otherwise it deadlocks. Signed-off-by: Dmitry Torokhov --- drivers/serial/sunzilog.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index e5989624731d..48398d136401 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -1529,7 +1529,6 @@ static void __init sunzilog_prepare(void) static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel) { int baud, brg; - struct serio *serio; if (channel == KEYBOARD_LINE) { up->flags |= SUNZILOG_FLAG_CONS_KEYB; @@ -1546,8 +1545,15 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe up->curregs[R15] = BRKIE; brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR); sunzilog_convert_to_zs(up, up->cflag, 0, brg); + sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); + __sunzilog_startup(up); +} #ifdef CONFIG_SERIO +static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel) +{ + struct serio *serio; + up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL); if (serio) { @@ -1576,11 +1582,8 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe printk(KERN_WARNING "zs%d: not enough memory for serio port\n", channel); } -#endif - - sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS); - __sunzilog_startup(up); } +#endif static void __init sunzilog_init_hw(void) { @@ -1624,6 +1627,11 @@ static void __init sunzilog_init_hw(void) } spin_unlock_irqrestore(&up->port.lock, flags); + +#ifdef CONFIG_SERIO + if (i == KEYBOARD_LINE || i == MOUSE_LINE) + sunzilog_register_serio(up, i); +#endif } } -- cgit v1.2.3 From a3938700fbea1f2b3d4baf92e8e98af452c25154 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 12:36:34 -0500 Subject: Input: workaround for i8042 active multiplexing controllers losing track of where data is coming from. Also sprinkled some "likely"s in i8042 interrupt handler. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 60 +++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 2b754afc7851..693f1ac44acd 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -362,6 +362,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) unsigned long flags; unsigned char str, data = 0; unsigned int dfl; + unsigned int aux_idx; int ret; mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); @@ -378,44 +379,67 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs) goto out; } - dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | - ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); - - if (i8042_mux_values[0].exists && (str & I8042_STR_AUXDATA)) { + if (i8042_mux_present && (str & I8042_STR_AUXDATA)) { + static unsigned long last_transmit; + static unsigned char last_str; + dfl = 0; if (str & I8042_STR_MUXERR) { + dbg("MUX error, status is %02x, data is %02x", str, data); switch (data) { + default: +/* + * When MUXERR condition is signalled the data register can only contain + * 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately + * it is not always the case. Some KBC just get confused which port the + * data came from and signal error leaving the data intact. They _do not_ + * revert to legacy mode (actually I've never seen KBC reverting to legacy + * mode yet, when we see one we'll add proper handling). + * Anyway, we will assume that the data came from the same serio last byte + * was transmitted (if transmission happened not too long ago). + */ + if (time_before(jiffies, last_transmit + HZ/10)) { + str = last_str; + break; + } + /* fall through - report timeout */ case 0xfd: - case 0xfe: dfl = SERIO_TIMEOUT; break; - case 0xff: dfl = SERIO_PARITY; break; + case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break; + case 0xff: dfl = SERIO_PARITY; data = 0xfe; break; } - data = 0xfe; - } else dfl = 0; + } + + aux_idx = (str >> 6) & 3; dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)", - data, (str >> 6), irq, + data, aux_idx, irq, dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); - serio_interrupt(i8042_mux_port[(str >> 6) & 3], data, dfl, regs); + if (likely(i8042_mux_values[aux_idx].exists)) + serio_interrupt(i8042_mux_port[aux_idx], data, dfl, regs); + last_str = str; + last_transmit = jiffies; goto irq_ret; } + dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) | + ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0); + dbg("%02x <- i8042 (interrupt, %s, %d%s%s)", data, (str & I8042_STR_AUXDATA) ? "aux" : "kbd", irq, dfl & SERIO_PARITY ? ", bad parity" : "", dfl & SERIO_TIMEOUT ? ", timeout" : ""); - if (i8042_aux_values.exists && (str & I8042_STR_AUXDATA)) { - serio_interrupt(i8042_aux_port, data, dfl, regs); - goto irq_ret; - } - if (!i8042_kbd_values.exists) - goto irq_ret; - - serio_interrupt(i8042_kbd_port, data, dfl, regs); + if (str & I8042_STR_AUXDATA) { + if (likely(i8042_aux_values.exists)) + serio_interrupt(i8042_aux_port, data, dfl, regs); + } else { + if (likely(i8042_kbd_values.exists)) + serio_interrupt(i8042_kbd_port, data, dfl, regs); + } irq_ret: ret = 1; -- cgit v1.2.3 From 91cac0b07f62e91da154f1abb576b19ec6d14253 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 12:37:24 -0500 Subject: Input: add serio_pause_rx and serio_continue_rx so drivers can protect their critical sections from port's interrupt handler Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 18 ++++++++---------- include/linux/serio.h | 21 +++++++++++++++++++-- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 63b246dfa5a0..36de6c228355 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -541,15 +541,14 @@ start_over: /* called from serio_driver->connect/disconnect methods under serio_sem */ int serio_open(struct serio *serio, struct serio_driver *drv) { - unsigned long flags; - - spin_lock_irqsave(&serio->lock, flags); + serio_pause_rx(serio); serio->drv = drv; - spin_unlock_irqrestore(&serio->lock, flags); + serio_continue_rx(serio); + if (serio->open && serio->open(serio)) { - spin_lock_irqsave(&serio->lock, flags); + serio_pause_rx(serio); serio->drv = NULL; - spin_unlock_irqrestore(&serio->lock, flags); + serio_continue_rx(serio); return -1; } return 0; @@ -558,13 +557,12 @@ int serio_open(struct serio *serio, struct serio_driver *drv) /* called from serio_driver->connect/disconnect methods under serio_sem */ void serio_close(struct serio *serio) { - unsigned long flags; - if (serio->close) serio->close(serio); - spin_lock_irqsave(&serio->lock, flags); + + serio_pause_rx(serio); serio->drv = NULL; - spin_unlock_irqrestore(&serio->lock, flags); + serio_continue_rx(serio); } irqreturn_t serio_interrupt(struct serio *serio, diff --git a/include/linux/serio.h b/include/linux/serio.h index 38c4e59aae0f..d925fba4f96c 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -35,7 +35,7 @@ struct serio { unsigned long type; unsigned long event; - spinlock_t lock; + spinlock_t lock; /* protects critical sections from port's interrupt handler */ int (*write)(struct serio *, unsigned char); int (*open)(struct serio *); @@ -43,7 +43,7 @@ struct serio { struct serio *parent, *child; - struct serio_driver *drv; /* Accessed from interrupt, writes must be protected by serio_lock */ + struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock */ struct device dev; @@ -81,6 +81,7 @@ void serio_register_port(struct serio *serio); void serio_register_port_delayed(struct serio *serio); void serio_unregister_port(struct serio *serio); void serio_unregister_port_delayed(struct serio *serio); + void serio_register_driver(struct serio_driver *drv); void serio_unregister_driver(struct serio_driver *drv); @@ -104,6 +105,22 @@ static __inline__ void serio_cleanup(struct serio *serio) serio->drv->cleanup(serio); } + +/* + * Use the following fucntions to protect critical sections in + * driver code from port's interrupt handler + */ +static __inline__ void serio_pause_rx(struct serio *serio) +{ + spin_lock_irq(&serio->lock); +} + +static __inline__ void serio_continue_rx(struct serio *serio) +{ + spin_unlock_irq(&serio->lock); +} + + #endif /* -- cgit v1.2.3 From a45857d153327ccdc26e31b0b7f84a0bd6dc9e0f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 12:38:32 -0500 Subject: Input: when changing psmouse state (activated, ignore) use srio_pause_rx/ serio_continue_rx so it will not fight with the interrupt handler Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 346ec46126f7..58298f9d3e42 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -308,7 +308,7 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) while (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags) && timeout--) { if (!test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags)) { - + if (command == PSMOUSE_CMD_RESET_BAT && timeout > 100000) timeout = 100000; @@ -625,6 +625,21 @@ static void psmouse_initialize(struct psmouse *psmouse) psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM); } +/* + * psmouse_set_state() sets new psmouse state and resets all flags and + * counters while holding serio lock so fighting with interrupt handler + * is not a concern. + */ + +static void psmouse_set_state(struct psmouse *psmouse, unsigned char new_state) +{ + serio_pause_rx(psmouse->serio); + psmouse->state = new_state; + psmouse->pktcnt = psmouse->cmdcnt = psmouse->out_of_sync = 0; + psmouse->flags = 0; + serio_continue_rx(psmouse->serio); +} + /* * psmouse_activate() enables the mouse so that we get motion reports from it. */ @@ -634,7 +649,7 @@ static void psmouse_activate(struct psmouse *psmouse) if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys); - psmouse->state = PSMOUSE_ACTIVATED; + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); } /* @@ -657,7 +672,7 @@ static void psmouse_disconnect(struct serio *serio) struct psmouse *psmouse, *parent; psmouse = serio->private; - psmouse->state = PSMOUSE_CMD_MODE; + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { parent = serio->parent->private; @@ -668,7 +683,7 @@ static void psmouse_disconnect(struct serio *serio) if (psmouse->disconnect) psmouse->disconnect(psmouse); - psmouse->state = PSMOUSE_IGNORE; + psmouse_set_state(psmouse, PSMOUSE_IGNORE); input_unregister_device(&psmouse->dev); serio_close(serio); @@ -699,9 +714,9 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - psmouse->state = PSMOUSE_CMD_MODE; psmouse->serio = serio; psmouse->dev.private = psmouse; + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); serio->private = psmouse; if (serio_open(serio, drv)) { @@ -780,12 +795,7 @@ static int psmouse_reconnect(struct serio *serio) return -1; } - psmouse->state = PSMOUSE_CMD_MODE; - - clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); - clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); - - psmouse->pktcnt = psmouse->out_of_sync = 0; + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); if (psmouse->reconnect) { if (psmouse->reconnect(psmouse)) -- cgit v1.2.3 From 0edcd2c4dacaa8745b291fdccc2e886279e8bc85 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 12:39:18 -0500 Subject: Input: do not call protocol handler in psmouse unless mouse is filly initialized - helps when USB Legacy emulation gets in our way and starts generating junk data stream while psmouse is detecting hardware Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 13 ++++++++++--- drivers/input/mouse/psmouse.h | 14 ++++++++------ 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 58298f9d3e42..d49a9882f3c8 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -186,6 +186,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, goto out; } + if (psmouse->state == PSMOUSE_INITIALIZING) + goto out; + if (psmouse->state == PSMOUSE_ACTIVATED && psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", @@ -631,7 +634,7 @@ static void psmouse_initialize(struct psmouse *psmouse) * is not a concern. */ -static void psmouse_set_state(struct psmouse *psmouse, unsigned char new_state) +static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) { serio_pause_rx(psmouse->serio); psmouse->state = new_state; @@ -716,7 +719,7 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); psmouse->serio = serio; psmouse->dev.private = psmouse; - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); serio->private = psmouse; if (serio_open(serio, drv)) { @@ -756,6 +759,8 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); if (parent && parent->pt_activate) @@ -795,7 +800,7 @@ static int psmouse_reconnect(struct serio *serio) return -1; } - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); if (psmouse->reconnect) { if (psmouse->reconnect(psmouse)) @@ -807,6 +812,8 @@ static int psmouse_reconnect(struct serio *serio) /* ok, the device type (and capabilities) match the old one, * we can continue using it, complete intialization */ + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + psmouse_initialize(psmouse); if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 56f143453fab..936f6f1e55f6 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -17,16 +17,18 @@ #define PSMOUSE_RET_ACK 0xfa #define PSMOUSE_RET_NAK 0xfe -/* psmouse states */ -#define PSMOUSE_CMD_MODE 0 -#define PSMOUSE_ACTIVATED 1 -#define PSMOUSE_IGNORE 2 - #define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */ #define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */ #define PSMOUSE_FLAG_CMD1 2 /* First byte of command response */ #define PSMOUSE_FLAG_ID 3 /* First byte is not keyboard ID */ +enum psmouse_state { + PSMOUSE_IGNORE, + PSMOUSE_INITIALIZING, + PSMOUSE_CMD_MODE, + PSMOUSE_ACTIVATED, +}; + /* psmouse protocol handler return codes */ typedef enum { PSMOUSE_BAD_DATA, @@ -48,7 +50,7 @@ struct psmouse { unsigned char model; unsigned long last; unsigned long out_of_sync; - unsigned char state; + enum psmouse_state state; unsigned char nak; char error; char devname[64]; -- cgit v1.2.3 From 233b7dfd64605a55b22e7cc45a4a0211aaa46806 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 12:41:37 -0500 Subject: Input: synaptics - do not try to process packets from slave device as if they were coming form the touchpad itself if pass-through port is disconnected, just pass them to serio core and it will attempt to bind proper driver to the port Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 764642f41071..101b8094720a 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -233,17 +233,14 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet { struct psmouse *child = ptport->private; - if (child) { - if (child->state == PSMOUSE_ACTIVATED) { - serio_interrupt(ptport, packet[1], 0, NULL); - serio_interrupt(ptport, packet[4], 0, NULL); - serio_interrupt(ptport, packet[5], 0, NULL); - if (child->type >= PSMOUSE_GENPS) - serio_interrupt(ptport, packet[2], 0, NULL); - } else if (child->state != PSMOUSE_IGNORE) { - serio_interrupt(ptport, packet[1], 0, NULL); - } - } + if (child && child->state == PSMOUSE_ACTIVATED) { + serio_interrupt(ptport, packet[1], 0, NULL); + serio_interrupt(ptport, packet[4], 0, NULL); + serio_interrupt(ptport, packet[5], 0, NULL); + if (child->type >= PSMOUSE_GENPS) + serio_interrupt(ptport, packet[2], 0, NULL); + } else + serio_interrupt(ptport, packet[1], 0, NULL); } static void synaptics_pt_activate(struct psmouse *psmouse) @@ -472,9 +469,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r if (unlikely(priv->pkt_type == SYN_NEWABS)) priv->pkt_type = synaptics_detect_pkt_type(psmouse); - if (psmouse->serio->child && psmouse->serio->child->drv && synaptics_is_pt_packet(psmouse->packet)) - synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet); - else + if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { + if (psmouse->serio->child) + synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet); + } else synaptics_process_packet(psmouse); return PSMOUSE_FULL_PACKET; -- cgit v1.2.3 From b73aa034f1c44fd03446237fa9de02ca200b729b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 12:44:37 -0500 Subject: Input: rearrange activation/children probe sequence in psmouse so reconnect on children ports works even after parent port is fully activated: - when connecting/reconnecting a port always activate it - when connecting/reconnecting a pass-throgh port deactivate parent first and activate it after connect is done Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 55 +++++++++++++++++++++++++------------- drivers/input/mouse/psmouse.h | 1 + 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index d49a9882f3c8..49bd78714d46 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -655,6 +655,21 @@ static void psmouse_activate(struct psmouse *psmouse) psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); } + +/* + * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion + * reports from it unless we explicitely request it. + */ + +static void psmouse_deactivate(struct psmouse *psmouse) +{ + if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE)) + printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", psmouse->serio->phys); + + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); +} + + /* * psmouse_cleanup() resets the mouse into power-on state. */ @@ -705,8 +720,14 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU) return; - if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) + /* + * If this is a pass-through port deactivate parent so the device + * connected to this port can be successfully identified + */ + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { parent = serio->parent->private; + psmouse_deactivate(parent); + } if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) goto out; @@ -766,21 +787,15 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) if (parent && parent->pt_activate) parent->pt_activate(parent); - /* - * OK, the device is ready, we just need to activate it (turn the - * stream mode on). But if mouse has a pass-through port we don't - * want to do it yet to not disturb child detection. - * The child will activate this port when it's ready. - */ - if (serio->child) { /* * Nothing to be done here, serio core will detect that * the driver set serio->child and will register it for us. */ printk(KERN_INFO "serio: %s port at %s\n", serio->child->name, psmouse->phys); - } else - psmouse_activate(psmouse); + } + + psmouse_activate(psmouse); out: /* If this is a pass-through port the parent awaits to be activated */ @@ -794,20 +809,26 @@ static int psmouse_reconnect(struct serio *serio) struct psmouse *psmouse = serio->private; struct psmouse *parent = NULL; struct serio_driver *drv = serio->drv; + int rc = -1; if (!drv || !psmouse) { printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); return -1; } + if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) { + parent = serio->parent->private; + psmouse_deactivate(parent); + } + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); if (psmouse->reconnect) { if (psmouse->reconnect(psmouse)) - return -1; + goto out; } else if (psmouse_probe(psmouse) < 0 || psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0)) - return -1; + goto out; /* ok, the device type (and capabilities) match the old one, * we can continue using it, complete intialization @@ -816,20 +837,18 @@ static int psmouse_reconnect(struct serio *serio) psmouse_initialize(psmouse); - if (serio->parent && (serio->type & SERIO_TYPE) == SERIO_PS_PSTHRU) - parent = serio->parent->private; - if (parent && parent->pt_activate) parent->pt_activate(parent); - if (!serio->child) - psmouse_activate(psmouse); + psmouse_activate(psmouse); + rc = 0; +out: /* If this is a pass-through port the parent waits to be activated */ if (parent) psmouse_activate(parent); - return 0; + return rc; } diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 936f6f1e55f6..ffad466db1c8 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -9,6 +9,7 @@ #define PSMOUSE_CMD_GETID 0x02f2 #define PSMOUSE_CMD_SETRATE 0x10f3 #define PSMOUSE_CMD_ENABLE 0x00f4 +#define PSMOUSE_CMD_DISABLE 0x00f5 #define PSMOUSE_CMD_RESET_DIS 0x00f6 #define PSMOUSE_CMD_RESET_BAT 0x02ff -- cgit v1.2.3 From 375ae9a2acbf9251166a35348287fc3da91aa305 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 12:48:22 -0500 Subject: Input: drop __attribute__ ((packed)) from mousedev_emul Signed-off-by: Dmitry Torokhov --- drivers/input/mousedev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 97be073d16a4..7aeed6fcfc5a 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -76,7 +76,7 @@ enum mousedev_emul { MOUSEDEV_EMUL_PS2, MOUSEDEV_EMUL_IMPS, MOUSEDEV_EMUL_EXPS -} __attribute__ ((packed)); +}; #define PACKET_QUEUE_LEN 16 struct mousedev_list { -- cgit v1.2.3 From f4f36a0dcbf1415ba74ac91fb96540fed0a64b3b Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 13:14:44 -0500 Subject: Input: make i8042 a platform device instead of system device so its serio ports have proper parent Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 60 +++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 693f1ac44acd..ac2780bd9a84 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -100,9 +101,9 @@ static unsigned char i8042_initial_ctr; static unsigned char i8042_ctr; static unsigned char i8042_mux_open; static unsigned char i8042_mux_present; -static unsigned char i8042_sysdev_initialized; static struct pm_dev *i8042_pm_dev; static struct timer_list i8042_timer; +static struct platform_device *i8042_platform_device; /* * Shared IRQ's require a device pointer, but this driver doesn't support @@ -878,7 +879,7 @@ static int i8042_notify_sys(struct notifier_block *this, unsigned long code, return NOTIFY_DONE; } -static struct notifier_block i8042_notifier= +static struct notifier_block i8042_notifier = { i8042_notify_sys, NULL, @@ -888,25 +889,27 @@ static struct notifier_block i8042_notifier= /* * Suspend/resume handlers for the new PM scheme (driver model) */ -static int i8042_suspend(struct sys_device *dev, u32 state) +static int i8042_suspend(struct device *dev, u32 state, u32 level) { - return i8042_controller_suspend(); + return level == SUSPEND_DISABLE ? i8042_controller_suspend() : 0; } -static int i8042_resume(struct sys_device *dev) +static int i8042_resume(struct device *dev, u32 level) { - return i8042_controller_resume(); + return level == RESUME_ENABLE ? i8042_controller_resume() : 0; } -static struct sysdev_class kbc_sysclass = { - set_kset_name("i8042"), - .suspend = i8042_suspend, - .resume = i8042_resume, -}; +static void i8042_shutdown(struct device *dev) +{ + i8042_controller_cleanup(); +} -static struct sys_device device_i8042 = { - .id = 0, - .cls = &kbc_sysclass, +static struct device_driver i8042_driver = { + .name = "i8042", + .bus = &platform_bus_type, + .suspend = i8042_suspend, + .resume = i8042_resume, + .shutdown = i8042_shutdown, }; /* @@ -937,6 +940,7 @@ static struct serio * __init i8042_allocate_kbd_port(void) serio->open = i8042_open, serio->close = i8042_close, serio->port_data = &i8042_kbd_values, + serio->dev.parent = &i8042_platform_device->dev; strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name)); strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys)); } @@ -956,6 +960,7 @@ static struct serio * __init i8042_allocate_aux_port(void) serio->open = i8042_open; serio->close = i8042_close; serio->port_data = &i8042_aux_values, + serio->dev.parent = &i8042_platform_device->dev; strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name)); strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys)); } @@ -980,6 +985,7 @@ static struct serio * __init i8042_allocate_mux_port(int index) serio->open = i8042_open; serio->close = i8042_close; serio->port_data = values; + serio->dev.parent = &i8042_platform_device->dev; snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index); snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1); } @@ -990,6 +996,7 @@ static struct serio * __init i8042_allocate_mux_port(int index) int __init i8042_init(void) { int i; + int err; dbg_init(); @@ -1005,6 +1012,16 @@ int __init i8042_init(void) if (i8042_controller_init()) return -ENODEV; + err = driver_register(&i8042_driver); + if (err) + return err; + + i8042_platform_device = platform_device_register_simple("i8042", -1, NULL, 0); + if (IS_ERR(i8042_platform_device)) { + driver_unregister(&i8042_driver); + return PTR_ERR(i8042_platform_device); + } + if (!i8042_noaux && !i8042_check_aux(&i8042_aux_values)) { if (!i8042_nomux && !i8042_check_mux(&i8042_aux_values)) for (i = 0; i < I8042_NUM_MUX_PORTS; i++) { @@ -1025,13 +1042,6 @@ int __init i8042_init(void) mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD); - if (sysdev_class_register(&kbc_sysclass) == 0) { - if (sysdev_register(&device_i8042) == 0) - i8042_sysdev_initialized = 1; - else - sysdev_class_unregister(&kbc_sysclass); - } - i8042_pm_dev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, i8042_pm_callback); register_reboot_notifier(&i8042_notifier); @@ -1048,11 +1058,6 @@ void __exit i8042_exit(void) if (i8042_pm_dev) pm_unregister(i8042_pm_dev); - if (i8042_sysdev_initialized) { - sysdev_unregister(&device_i8042); - sysdev_class_unregister(&kbc_sysclass); - } - i8042_controller_cleanup(); if (i8042_kbd_values.exists) @@ -1067,6 +1072,9 @@ void __exit i8042_exit(void) del_timer_sync(&i8042_timer); + platform_device_unregister(i8042_platform_device); + driver_unregister(&i8042_driver); + i8042_platform_exit(); } -- cgit v1.2.3 From fe8bc20230475ed2ae5ddfe69489eeab576e6465 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 13:15:36 -0500 Subject: Input: integrate ct82c710, maceps2, q40kbd and rpckbd with sysfs as platform devices so their serio ports have proper parents Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ct82c710.c | 50 +++++++++++++++++++++++------------------- drivers/input/serio/maceps2.c | 19 +++++++++++----- drivers/input/serio/q40kbd.c | 18 +++++++++++---- drivers/input/serio/rpckbd.c | 20 ++++++++++++----- 4 files changed, 71 insertions(+), 36 deletions(-) diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c index abacb6fb4de6..ee785460b78f 100644 --- a/drivers/input/serio/ct82c710.c +++ b/drivers/input/serio/ct82c710.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -58,10 +59,12 @@ MODULE_LICENSE("GPL"); #define CT82C710_IRQ 12 -static struct serio *ct82c710_port; -static int ct82c710_data; -static int ct82c710_status; +#define CT82C710_DATA ct82c710_iores.start +#define CT82C710_STATUS (ct82c710_iores.start + 1) +static struct serio *ct82c710_port; +static struct platform_device *ct82c710_device; +static struct resource ct82c710_iores; /* * Interrupt handler for the 82C710 mouse port. A character @@ -70,7 +73,7 @@ static int ct82c710_status; static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs) { - return serio_interrupt(ct82c710_port, inb(ct82c710_data), 0, regs); + return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0, regs); } /* @@ -81,10 +84,10 @@ static int ct82c170_wait(void) { int timeout = 60000; - while ((inb(ct82c710_status) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) + while ((inb(CT82C710_STATUS) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE)) != (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) { - if (inb_p(ct82c710_status) & CT82C710_RX_FULL) inb_p(ct82c710_data); + if (inb_p(CT82C710_STATUS) & CT82C710_RX_FULL) inb_p(CT82C710_DATA); udelay(1); timeout--; @@ -98,7 +101,7 @@ static void ct82c710_close(struct serio *serio) if (ct82c170_wait()) printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); - outb_p(inb_p(ct82c710_status) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), ct82c710_status); + outb_p(inb_p(CT82C710_STATUS) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), CT82C710_STATUS); if (ct82c170_wait()) printk(KERN_WARNING "ct82c710.c: Device busy in close()\n"); @@ -113,21 +116,21 @@ static int ct82c710_open(struct serio *serio) if (request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL)) return -1; - status = inb_p(ct82c710_status); + status = inb_p(CT82C710_STATUS); status |= (CT82C710_ENABLE | CT82C710_RESET); - outb_p(status, ct82c710_status); + outb_p(status, CT82C710_STATUS); status &= ~(CT82C710_RESET); - outb_p(status, ct82c710_status); + outb_p(status, CT82C710_STATUS); status |= CT82C710_INTS_ON; - outb_p(status, ct82c710_status); /* Enable interrupts */ + outb_p(status, CT82C710_STATUS); /* Enable interrupts */ while (ct82c170_wait()) { printk(KERN_ERR "ct82c710: Device busy in open()\n"); status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON); - outb_p(status, ct82c710_status); + outb_p(status, CT82C710_STATUS); free_irq(CT82C710_IRQ, NULL); return -1; } @@ -142,7 +145,7 @@ static int ct82c710_open(struct serio *serio) static int ct82c710_write(struct serio *port, unsigned char c) { if (ct82c170_wait()) return -1; - outb_p(c, ct82c710_data); + outb_p(c, CT82C710_DATA); return 0; } @@ -162,8 +165,9 @@ static int __init ct82c710_probe(void) return -1; /* No: no 82C710 here */ outb_p(0x0d, 0x390); /* Write index */ - ct82c710_data = inb_p(0x391) << 2; /* Get mouse I/O address */ - ct82c710_status = ct82c710_data + 1; + ct82c710_iores.start = inb_p(0x391) << 2; /* Get mouse I/O address */ + ct82c710_iores.end = ct82c710_iores.start + 1; + ct82c710_iores.flags = IORESOURCE_IO; outb_p(0x0f, 0x390); outb_p(0x0f, 0x391); /* Close config mode */ @@ -181,8 +185,9 @@ static struct serio * __init ct82c710_allocate_port(void) serio->open = ct82c710_open; serio->close = ct82c710_close; serio->write = ct82c710_write; + serio->dev.parent = &ct82c710_device->dev; strlcpy(serio->name, "C&T 82c710 mouse port", sizeof(serio->name)); - snprintf(serio->phys, sizeof(serio->phys), "isa%04x/serio0", ct82c710_data); + snprintf(serio->phys, sizeof(serio->phys), "isa%04lx/serio0", CT82C710_DATA); } return serio; @@ -193,18 +198,19 @@ int __init ct82c710_init(void) if (ct82c710_probe()) return -ENODEV; - if (request_region(ct82c710_data, 2, "ct82c710")) - return -EBUSY; + ct82c710_device = platform_device_register_simple("ct82c710", -1, &ct82c710_iores, 1); + if (IS_ERR(ct82c710_device)) + return PTR_ERR(ct82c710_device); if (!(ct82c710_port = ct82c710_allocate_port())) { - release_region(ct82c710_data, 2); + platform_device_unregister(ct82c710_device); return -ENOMEM; } serio_register_port(ct82c710_port); - printk(KERN_INFO "serio: C&T 82c710 mouse port at %#x irq %d\n", - ct82c710_data, CT82C710_IRQ); + printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n", + CT82C710_DATA, CT82C710_IRQ); return 0; } @@ -212,7 +218,7 @@ int __init ct82c710_init(void) void __exit ct82c710_exit(void) { serio_unregister_port(ct82c710_port); - release_region(ct82c710_data, 2); + platform_device_unregister(ct82c710_device); } module_init(ct82c710_init); diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c index e71e05535bae..78f4d9b5a5d9 100644 --- a/drivers/input/serio/maceps2.c +++ b/drivers/input/serio/maceps2.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,7 @@ struct maceps2_data { static struct maceps2_data port_data[2]; static struct serio *maceps2_port[2]; +static struct platform_device *maceps2_device; static int maceps2_write(struct serio *dev, unsigned char val) { @@ -123,13 +125,14 @@ static struct serio * __init maceps2_allocate_port(int idx) serio = kmalloc(sizeof(struct serio), GFP_KERNEL); if (serio) { memset(serio, 0, sizeof(struct serio)); - serio->type = SERIO_8042; - serio->write = maceps2_write; - serio->open = maceps2_open; - serio->close = maceps2_close; + serio->type = SERIO_8042; + serio->write = maceps2_write; + serio->open = maceps2_open; + serio->close = maceps2_close; snprintf(serio->name, sizeof(serio->name), "MACE PS/2 port%d", idx); snprintf(serio->phys, sizeof(serio->phys), "mace/serio%d", idx); - serio->port_data = &port_data[idx]; + serio->port_data = &port_data[idx]; + serio->dev.parent = &maceps2_device->dev; } return serio; @@ -138,6 +141,10 @@ static struct serio * __init maceps2_allocate_port(int idx) static int __init maceps2_init(void) { + maceps2_device = platform_device_register_simple("maceps2", -1, NULL, 0); + if (IS_ERR(maceps2_device)) + return PTR_ERR(maceps2_device); + port_data[0].port = &mace->perif.ps2.keyb; port_data[0].irq = MACEISA_KEYB_IRQ; port_data[1].port = &mace->perif.ps2.mouse; @@ -148,6 +155,7 @@ static int __init maceps2_init(void) if (!maceps2_port[0] || !maceps2_port[1]) { kfree(maceps2_port[0]); kfree(maceps2_port[1]); + platform_device_unregister(maceps2_device); return -ENOMEM; } @@ -161,6 +169,7 @@ static void __exit maceps2_exit(void) { serio_unregister_port(maceps2_port[0]); serio_unregister_port(maceps2_port[1]); + platform_device_unregister(maceps2_device); } module_init(maceps2_init); diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 85d1e1ea64ec..7d5ecce92346 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,7 @@ MODULE_LICENSE("GPL"); spinlock_t q40kbd_lock = SPIN_LOCK_UNLOCKED; static struct serio *q40kbd_port; +static struct platform_device *q40kbd_device; static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -120,9 +122,10 @@ static struct serio * __init q40kbd_allocate_port(void) serio = kmalloc(sizeof(struct serio), GFP_KERNEL); if (serio) { memset(serio, 0, sizeof(struct serio)); - serio->type = SERIO_8042; - serio->open = q40kbd_open; - serio->close = q40kbd_close; + serio->type = SERIO_8042; + serio->open = q40kbd_open; + serio->close = q40kbd_close; + serio->dev.parent = &q40kbd_device->dev; strlcpy(serio->name, "Q40 Kbd Port", sizeof(serio->name)); strlcpy(serio->phys, "Q40", sizeof(serio->phys)); } @@ -135,8 +138,14 @@ static int __init q40kbd_init(void) if (!MACH_IS_Q40) return -EIO; - if (!(q40kbd_port = q40kbd_allocate_port())) + q40kbd_device = platform_device_register_simple("q40kbd", -1, NULL, 0); + if (IS_ERR(q40kbd_device)) + return PTR_ERR(q40kbd_device); + + if (!(q40kbd_port = q40kbd_allocate_port())) { + platform_device_unregister(q40kbd_device); return -ENOMEM; + } serio_register_port(q40kbd_port); printk(KERN_INFO "serio: Q40 kbd registered\n"); @@ -147,6 +156,7 @@ static int __init q40kbd_init(void) static void __exit q40kbd_exit(void) { serio_unregister_port(q40kbd_port); + platform_device_unregister(q40kbd_device); } module_init(q40kbd_init); diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c index a31e760c43a5..b25d2e3b06ba 100644 --- a/drivers/input/serio/rpckbd.c +++ b/drivers/input/serio/rpckbd.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,7 @@ MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver"); MODULE_LICENSE("GPL"); static struct serio *rpckbd_port; +static struct platform_device *rpckbd_device; static int rpckbd_write(struct serio *port, unsigned char val) { @@ -115,10 +117,11 @@ static struct serio * __init rpckbd_allocate_port(void) serio = kmalloc(sizeof(struct serio), GFP_KERNEL); if (serio) { memset(serio, 0, sizeof(struct serio)); - serio->type = SERIO_8042; - serio->write = rpckbd_write; - serio->open = rpckbd_open; - serio->close = rpckbd_close; + serio->type = SERIO_8042; + serio->write = rpckbd_write; + serio->open = rpckbd_open; + serio->close = rpckbd_close; + serio->dev.parent = &rpckbd_device->dev; strlcpy(serio->name, "RiscPC PS/2 kbd port", sizeof(serio->name)); strlcpy(serio->phys, "rpckbd/serio0", sizeof(serio->phys)); } @@ -128,8 +131,14 @@ static struct serio * __init rpckbd_allocate_port(void) static int __init rpckbd_init(void) { - if (!(rpckbd_port = rpckbd_allocate_port())) + rpckbd_device = platform_device_register_simple("rpckbd", -1, NULL, 0); + if (IS_ERR(rpckbd_device)) + return PTR_ERR(rpckbd_device); + + if (!(rpckbd_port = rpckbd_allocate_port())) { + platform_device_unregister(rpckbd_device); return -ENOMEM; + } serio_register_port(rpckbd_port); return 0; @@ -138,6 +147,7 @@ static int __init rpckbd_init(void) static void __exit rpckbd_exit(void) { serio_unregister_port(rpckbd_port); + platform_device_unregister(rpckbd_device); } module_init(rpckbd_init); -- cgit v1.2.3 From 26ecd16b6ac0721b8b3e4084aaaebdf7b65bd9f9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 13:16:28 -0500 Subject: Input: Switch to use bus' default device and driver attributes to manage serio sysfs attributes Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 36de6c228355..0751baaa0f8a 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -245,7 +245,6 @@ static ssize_t serio_show_description(struct device *dev, char *buf) struct serio *serio = to_serio_port(dev); return sprintf(buf, "%s\n", serio->name); } -static DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL); static ssize_t serio_show_driver(struct device *dev, char *buf) { @@ -283,7 +282,13 @@ static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t c return retval; } -static DEVICE_ATTR(driver, S_IWUSR | S_IRUGO, serio_show_driver, serio_rebind_driver); + +static struct device_attribute serio_device_attrs[] = { + __ATTR(description, S_IRUGO, serio_show_description, NULL), + __ATTR(driver, S_IWUSR | S_IRUGO, serio_show_driver, serio_rebind_driver), + __ATTR_NULL +}; + static void serio_release_port(struct device *dev) { @@ -305,8 +310,6 @@ static void serio_create_port(struct serio *serio) if (serio->parent) serio->dev.parent = &serio->parent->dev; device_register(&serio->dev); - device_create_file(&serio->dev, &dev_attr_description); - device_create_file(&serio->dev, &dev_attr_driver); } /* @@ -481,7 +484,11 @@ static ssize_t serio_driver_show_description(struct device_driver *drv, char *bu struct serio_driver *driver = to_serio_driver(drv); return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); } -static DRIVER_ATTR(description, S_IRUGO, serio_driver_show_description, NULL); + +static struct driver_attribute serio_driver_attrs[] = { + __ATTR(description, S_IRUGO, serio_driver_show_description, NULL), + __ATTR_NULL +}; void serio_register_driver(struct serio_driver *drv) { @@ -493,7 +500,6 @@ void serio_register_driver(struct serio_driver *drv) drv->driver.bus = &serio_bus; driver_register(&drv->driver); - driver_create_file(&drv->driver, &driver_attr_description); if (drv->manual_bind) goto out; @@ -597,6 +603,8 @@ static int __init serio_init(void) return -1; } + serio_bus.dev_attrs = serio_device_attrs; + serio_bus.drv_attrs = serio_driver_attrs; bus_register(&serio_bus); return 0; -- cgit v1.2.3 From 7f8215567416f9eeb24f2a3fe4261b313485a91f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 13:17:19 -0500 Subject: Input: allow marking serio ports (in addition to serio drivers) as manual bind only, export the flag through sysfs echo -n "manual" > /sys/bus/serio/devices/serio0/bind_mode echo -n "auto" > /sys/bus/serio/drivers/serio_raw/bind_mode Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 68 +++++++++++++++++++++++++++++++++++++++------ include/linux/serio.h | 4 ++- 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 0751baaa0f8a..bdd0a9d1038a 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -283,9 +283,33 @@ 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) +{ + 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) +{ + struct serio *serio = to_serio_port(dev); + int retval; + + retval = count; + if (!strncmp(buf, "manual", count)) { + serio->manual_bind = 1; + } else if (!strncmp(buf, "auto", count)) { + serio->manual_bind = 0; + } else { + retval = -EINVAL; + } + + return retval; +} + static struct device_attribute serio_device_attrs[] = { __ATTR(description, S_IRUGO, serio_show_description, NULL), __ATTR(driver, S_IWUSR | S_IRUGO, serio_show_driver, serio_rebind_driver), + __ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode), __ATTR_NULL }; @@ -353,7 +377,7 @@ static void serio_connect_port(struct serio *serio, struct serio_driver *drv) if (drv) serio_bind_driver(serio, drv); - else + else if (!serio->manual_bind) serio_find_driver(serio); /* Ok, now bind children, if any */ @@ -365,13 +389,15 @@ static void serio_connect_port(struct serio *serio, struct serio_driver *drv) serio_create_port(serio); - /* - * With children we just _prefer_ passed in driver, - * but we will try other options in case preferred - * is not the one - */ - if (!drv || !serio_bind_driver(serio, drv)) - serio_find_driver(serio); + if (!serio->manual_bind) { + /* + * With children we just _prefer_ passed in driver, + * but we will try other options in case preferred + * is not the one + */ + if (!drv || !serio_bind_driver(serio, drv)) + serio_find_driver(serio); + } } } @@ -485,8 +511,34 @@ static ssize_t serio_driver_show_description(struct device_driver *drv, char *bu return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); } +static ssize_t serio_driver_show_bind_mode(struct device_driver *drv, char *buf) +{ + struct serio_driver *serio_drv = to_serio_driver(drv); + return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto"); +} + +static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char *buf, size_t count) +{ + struct serio_driver *serio_drv = to_serio_driver(drv); + int retval; + + retval = count; + if (!strncmp(buf, "manual", count)) { + serio_drv->manual_bind = 1; + } else if (!strncmp(buf, "auto", count)) { + serio_drv->manual_bind = 0; + } else { + retval = -EINVAL; + } + + return retval; +} + + static struct driver_attribute serio_driver_attrs[] = { __ATTR(description, S_IRUGO, serio_driver_show_description, NULL), + __ATTR(bind_mode, S_IWUSR | S_IRUGO, + serio_driver_show_bind_mode, serio_driver_set_bind_mode), __ATTR_NULL }; diff --git a/include/linux/serio.h b/include/linux/serio.h index d925fba4f96c..f84b362a561f 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -27,6 +27,8 @@ struct serio { char name[32]; char phys[32]; + unsigned int manual_bind; + unsigned short idbus; unsigned short idvendor; unsigned short idproduct; @@ -55,7 +57,7 @@ struct serio_driver { void *private; char *description; - int manual_bind; + unsigned int manual_bind; void (*write_wakeup)(struct serio *); irqreturn_t (*interrupt)(struct serio *, unsigned char, -- cgit v1.2.3 From 3984cbc94049b5da300d75c74844f789d56d3fec Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 19 Jul 2004 13:26:20 -0500 Subject: Input: serio - switch to use driver_find, adjust reference count Signed-off-by: Dmitry Torokhov --- drivers/input/serio/serio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index bdd0a9d1038a..268ca1d63805 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -255,7 +255,6 @@ static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t c { struct serio *serio = to_serio_port(dev); struct device_driver *drv; - struct kobject *k; int retval; retval = down_interruptible(&serio_sem); @@ -270,10 +269,10 @@ static ssize_t serio_rebind_driver(struct device *dev, const char *buf, size_t c } else if (!strncmp(buf, "rescan", count)) { serio_disconnect_port(serio); serio_connect_port(serio, NULL); - } else if ((k = kset_find_obj(&serio_bus.drivers, buf)) != NULL) { - drv = container_of(k, struct device_driver, kobj); + } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { serio_disconnect_port(serio); serio_connect_port(serio, to_serio_driver(drv)); + put_driver(drv); } else { retval = -EINVAL; } -- cgit v1.2.3 From a8c6003aab6404f9912e651484c816df1d194746 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Tue, 27 Jul 2004 18:46:36 +0200 Subject: input: Re-add PC Speaker support for PPC Signed-off-by: Olaf Hering Signed-off-by: Vojtech Pavlik --- drivers/input/misc/Kconfig | 2 +- include/asm-ppc/8253pit.h | 10 ++++++++++ include/asm-ppc64/8253pit.h | 10 ++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 include/asm-ppc/8253pit.h create mode 100644 include/asm-ppc64/8253pit.h diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index d3e5d841ee69..a89050e12bbf 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -14,7 +14,7 @@ config INPUT_MISC config INPUT_PCSPKR tristate "PC Speaker support" - depends on (ALPHA || X86 || X86_64 || MIPS) && INPUT && INPUT_MISC + depends on (ALPHA || X86 || X86_64 || MIPS || PPC_PREP || PPC_CHRP || PPC_PSERIES) && INPUT && INPUT_MISC help Say Y here if you want the standard PC Speaker to be used for bells and whistles. diff --git a/include/asm-ppc/8253pit.h b/include/asm-ppc/8253pit.h new file mode 100644 index 000000000000..285f78488ccb --- /dev/null +++ b/include/asm-ppc/8253pit.h @@ -0,0 +1,10 @@ +/* + * 8253/8254 Programmable Interval Timer + */ + +#ifndef _8253PIT_H +#define _8253PIT_H + +#define PIT_TICK_RATE 1193182UL + +#endif diff --git a/include/asm-ppc64/8253pit.h b/include/asm-ppc64/8253pit.h new file mode 100644 index 000000000000..285f78488ccb --- /dev/null +++ b/include/asm-ppc64/8253pit.h @@ -0,0 +1,10 @@ +/* + * 8253/8254 Programmable Interval Timer + */ + +#ifndef _8253PIT_H +#define _8253PIT_H + +#define PIT_TICK_RATE 1193182UL + +#endif -- cgit v1.2.3 From 83d0c7066bb96a0c2e78e7b2c6e9c4116d630d2c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 27 Jul 2004 14:50:38 -0500 Subject: Input: fix psmouse_sendbyte logic - correctly return NAK when command times out on our side - always reset ACK flag, even when serio_write fails Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 49bd78714d46..2516cdfc7818 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -260,12 +260,17 @@ static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte) { int timeout = 200000; /* 200 msec */ + psmouse->nak = 1; set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + if (serio_write(psmouse->serio, byte)) - return -1; - while (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags) && timeout--) udelay(1); - clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + goto out; + while (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags) && timeout--) + udelay(1); + +out: + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); return -psmouse->nak; } -- cgit v1.2.3 From 6ce315cca9e20f994d824e16bb7c78fb7872dd18 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 27 Jul 2004 14:51:37 -0500 Subject: Input: psmouse - harden command mode processing logic Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 92 +++++++++++++++++++++----------------- drivers/input/mouse/psmouse.h | 4 +- 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 2516cdfc7818..acc49c2d3fdb 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -150,36 +150,47 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, goto out; } - if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) + if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) { switch (data) { case PSMOUSE_RET_ACK: psmouse->nak = 0; - clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); - goto out; break; + case PSMOUSE_RET_NAK: psmouse->nak = 1; - clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); - goto out; - default: - psmouse->nak = 0; /* Workaround for mice which don't ACK the Get ID command */ - clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); - if (!test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) - goto out; + break; + /* + * Workaround for mice which don't ACK the Get ID command. + * These are valid mouse IDs that we recognize. + */ + case 0x00: + case 0x03: + case 0x04: + if (test_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags)) { + psmouse->nak = 0; + break; + } + /* Fall through */ + default: + goto out; } - if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) { + if (!psmouse->nak && psmouse->cmdcnt) { + set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); + } + clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); - psmouse->cmdcnt--; - psmouse->cmdbuf[psmouse->cmdcnt] = data; + if (data == PSMOUSE_RET_ACK || data == PSMOUSE_RET_NAK) + goto out; + } - if (psmouse->cmdcnt == 1) { - if (data != 0xab && data != 0xac) - clear_bit(PSMOUSE_FLAG_ID, &psmouse->flags); - clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); - } + if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) { + if (psmouse->cmdcnt) + psmouse->cmdbuf[--psmouse->cmdcnt] = data; + clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); if (!psmouse->cmdcnt) clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); @@ -284,6 +295,7 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) int timeout = 500000; /* 500 msec */ int send = (command >> 12) & 0xf; int receive = (command >> 8) & 0xf; + int rc = -1; int i; psmouse->cmdcnt = receive; @@ -291,27 +303,20 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) if (command == PSMOUSE_CMD_RESET_BAT) timeout = 4000000; /* 4 sec */ + if (command == PSMOUSE_CMD_GETID) + set_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags); + if (receive && param) for (i = 0; i < receive; i++) psmouse->cmdbuf[(receive - 1) - i] = param[i]; - if (receive) { - set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); - set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); - set_bit(PSMOUSE_FLAG_ID, &psmouse->flags); - } - if (command & 0xff) - if (psmouse_sendbyte(psmouse, command & 0xff)) { - clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); - return -1; - } + if (psmouse_sendbyte(psmouse, command & 0xff)) + goto out; for (i = 0; i < send; i++) - if (psmouse_sendbyte(psmouse, param[i])) { - clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); - return -1; - } + if (psmouse_sendbyte(psmouse, param[i])) + goto out; while (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags) && timeout--) { @@ -320,7 +325,13 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) if (command == PSMOUSE_CMD_RESET_BAT && timeout > 100000) timeout = 100000; - if (command == PSMOUSE_CMD_GETID && !test_bit(PSMOUSE_FLAG_ID, &psmouse->flags)) { + if (command == PSMOUSE_CMD_GETID && + psmouse->cmdbuf[receive - 1] != 0xab && psmouse->cmdbuf[receive - 1] != 0xac) { + /* + * Device behind the port is not a keyboard + * so we don't need to wait for the 2nd byte + * of ID response. + */ clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); psmouse->cmdcnt = 0; break; @@ -330,19 +341,20 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) udelay(1); } - clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); - if (param) for (i = 0; i < receive; i++) param[i] = psmouse->cmdbuf[(receive - 1) - i]; - if (command == PSMOUSE_CMD_RESET_BAT && psmouse->cmdcnt == 1) - return 0; + if (psmouse->cmdcnt && (command != PSMOUSE_CMD_RESET_BAT || psmouse->cmdcnt != 1)) + goto out; - if (psmouse->cmdcnt) - return -1; + rc = 0; - return 0; +out: + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); + clear_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags); + return rc; } /* diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index ffad466db1c8..fa7b55c4c021 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -20,8 +20,8 @@ #define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */ #define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */ -#define PSMOUSE_FLAG_CMD1 2 /* First byte of command response */ -#define PSMOUSE_FLAG_ID 3 /* First byte is not keyboard ID */ +#define PSMOUSE_FLAG_CMD1 2 /* Waiting for the first byte of command response */ +#define PSMOUSE_FLAG_WAITID 3 /* Command execiting is GET ID */ enum psmouse_state { PSMOUSE_IGNORE, -- cgit v1.2.3 From 2da8c34a5b8947bd6c047f873fe813a54661cb41 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 27 Jul 2004 14:52:45 -0500 Subject: Input: switch psmouse driver from busy-polling for command completion to waiting for event Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 71 ++++++++++++++++++++------------------ drivers/input/mouse/psmouse.h | 3 ++ 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index acc49c2d3fdb..7fbd926ddae7 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -147,6 +147,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, psmouse->nak = 1; clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + wake_up_interruptible(&psmouse->wait); goto out; } @@ -181,6 +182,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); } clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); + wake_up_interruptible(&psmouse->wait); if (data == PSMOUSE_RET_ACK || data == PSMOUSE_RET_NAK) goto out; @@ -190,10 +192,13 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, if (psmouse->cmdcnt) psmouse->cmdbuf[--psmouse->cmdcnt] = data; - clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags); - if (!psmouse->cmdcnt) - clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + if (test_and_clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags) && psmouse->cmdcnt) + wake_up_interruptible(&psmouse->wait); + if (!psmouse->cmdcnt) { + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + wake_up_interruptible(&psmouse->wait); + } goto out; } @@ -265,22 +270,20 @@ out: * psmouse_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. + * + * psmouse_sendbyte() can only be called from a process context */ static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte) { - int timeout = 200000; /* 200 msec */ - psmouse->nak = 1; set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); - if (serio_write(psmouse->serio, byte)) - goto out; + if (serio_write(psmouse->serio, byte) == 0) + wait_event_interruptible_timeout(psmouse->wait, + !test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags), + msecs_to_jiffies(200)); - while (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags) && timeout--) - udelay(1); - -out: clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags); return -psmouse->nak; } @@ -288,21 +291,21 @@ out: /* * psmouse_command() sends a command and its parameters to the mouse, * then waits for the response and puts it in the param array. + * + * psmouse_command() can only be called from a process context */ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) { - int timeout = 500000; /* 500 msec */ + int timeout; int send = (command >> 12) & 0xf; int receive = (command >> 8) & 0xf; int rc = -1; int i; - psmouse->cmdcnt = receive; - - if (command == PSMOUSE_CMD_RESET_BAT) - timeout = 4000000; /* 4 sec */ + timeout = msecs_to_jiffies(command == PSMOUSE_CMD_RESET_BAT ? 4000 : 500); + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); if (command == PSMOUSE_CMD_GETID) set_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags); @@ -310,6 +313,8 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) for (i = 0; i < receive; i++) psmouse->cmdbuf[(receive - 1) - i] = param[i]; + psmouse->cmdcnt = receive; + if (command & 0xff) if (psmouse_sendbyte(psmouse, command & 0xff)) goto out; @@ -318,27 +323,26 @@ int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command) if (psmouse_sendbyte(psmouse, param[i])) goto out; - while (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags) && timeout--) { + timeout = wait_event_interruptible_timeout(psmouse->wait, + !test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags), timeout); - if (!test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags)) { + if (psmouse->cmdcnt && timeout > 0) { + if (command == PSMOUSE_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100) + timeout = msecs_to_jiffies(100); - if (command == PSMOUSE_CMD_RESET_BAT && timeout > 100000) - timeout = 100000; - - if (command == PSMOUSE_CMD_GETID && - psmouse->cmdbuf[receive - 1] != 0xab && psmouse->cmdbuf[receive - 1] != 0xac) { - /* - * Device behind the port is not a keyboard - * so we don't need to wait for the 2nd byte - * of ID response. - */ - clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); - psmouse->cmdcnt = 0; - break; - } + if (command == PSMOUSE_CMD_GETID && + psmouse->cmdbuf[receive - 1] != 0xab && psmouse->cmdbuf[receive - 1] != 0xac) { + /* + * Device behind the port is not a keyboard + * so we don't need to wait for the 2nd byte + * of ID response. + */ + clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags); + psmouse->cmdcnt = 0; } - udelay(1); + wait_event_interruptible_timeout(psmouse->wait, + !test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags), timeout); } if (param) @@ -751,6 +755,7 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) memset(psmouse, 0, sizeof(struct psmouse)); + init_waitqueue_head(&psmouse->wait); init_input_dev(&psmouse->dev); psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index fa7b55c4c021..20bbab42d591 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -58,6 +58,9 @@ struct psmouse { char phys[32]; unsigned long flags; + /* Used to signal completion from interrupt handler */ + wait_queue_head_t wait; + psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs); int (*reconnect)(struct psmouse *psmouse); void (*disconnect)(struct psmouse *psmouse); -- cgit v1.2.3 From f69c1f0f8f78e55e654f3edd336baf5b1b1092a2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 27 Jul 2004 14:54:01 -0500 Subject: Input: atkbd - harden ACK/NAK and command processing logic Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 71 ++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 8b7291cd59bd..819967458c3b 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -173,8 +173,7 @@ static unsigned char atkbd_scroll_keys[5][2] = { #define ATKBD_FLAG_ACK 0 /* Waiting for ACK/NAK */ #define ATKBD_FLAG_CMD 1 /* Waiting for command to finish */ #define ATKBD_FLAG_CMD1 2 /* First byte of command response */ -#define ATKBD_FLAG_ID 3 /* First byte is not keyboard ID */ -#define ATKBD_FLAG_ENABLED 4 /* Waining for init to finish */ +#define ATKBD_FLAG_ENABLED 3 /* Waining for init to finish */ /* * The atkbd control structure @@ -254,34 +253,30 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, atkbd->resend = 0; #endif - if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags)) + if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags)) { switch (code) { case ATKBD_RET_ACK: atkbd->nak = 0; if (atkbd->cmdcnt) { set_bit(ATKBD_FLAG_CMD, &atkbd->flags); set_bit(ATKBD_FLAG_CMD1, &atkbd->flags); - set_bit(ATKBD_FLAG_ID, &atkbd->flags); } clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); - goto out; + break; case ATKBD_RET_NAK: atkbd->nak = 1; clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); - goto out; + break; } + goto out; + } if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) { - atkbd->cmdcnt--; - atkbd->cmdbuf[atkbd->cmdcnt] = code; - - if (atkbd->cmdcnt == 1) { - if (code != 0xab && code != 0xac) - clear_bit(ATKBD_FLAG_ID, &atkbd->flags); - clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags); - } + if (atkbd->cmdcnt) + atkbd->cmdbuf[--atkbd->cmdcnt] = code; + clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags); if (!atkbd->cmdcnt) clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); @@ -426,14 +421,14 @@ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) #ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte); #endif - + atkbd->nak = 1; set_bit(ATKBD_FLAG_ACK, &atkbd->flags); - clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); - if (serio_write(atkbd->serio, byte)) - return -1; - while (test_bit(ATKBD_FLAG_ACK, &atkbd->flags) && timeout--) udelay(1); - clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); + if (serio_write(atkbd->serio, byte) == 0) + while (test_bit(ATKBD_FLAG_ACK, &atkbd->flags) && timeout--) + udelay(1); + + clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); return -atkbd->nak; } @@ -447,33 +442,42 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) int timeout = 500000; /* 500 msec */ int send = (command >> 12) & 0xf; int receive = (command >> 8) & 0xf; + int rc = -1; int i; - atkbd->cmdcnt = receive; - if (command == ATKBD_CMD_RESET_BAT) timeout = 4000000; /* 4 sec */ + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + if (receive && param) for (i = 0; i < receive; i++) atkbd->cmdbuf[(receive - 1) - i] = param[i]; + atkbd->cmdcnt = receive; + if (command & 0xff) if (atkbd_sendbyte(atkbd, command & 0xff)) - return -1; + goto out; for (i = 0; i < send; i++) if (atkbd_sendbyte(atkbd, param[i])) - return -1; + goto out; while (test_bit(ATKBD_FLAG_CMD, &atkbd->flags) && timeout--) { if (!test_bit(ATKBD_FLAG_CMD1, &atkbd->flags)) { - + if (command == ATKBD_CMD_RESET_BAT && timeout > 100000) timeout = 100000; - if (command == ATKBD_CMD_GETID && !test_bit(ATKBD_FLAG_ID, &atkbd->flags)) { + if (command == ATKBD_CMD_GETID && + atkbd->cmdbuf[receive - 1] != 0xab && atkbd->cmdbuf[receive - 1] != 0xac) { + /* + * Device behind the port is not a keyboard + * so we don't need to wait for the 2nd byte + * of ID response. + */ clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); atkbd->cmdcnt = 0; break; @@ -483,19 +487,20 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) udelay(1); } - clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); - if (param) for (i = 0; i < receive; i++) param[i] = atkbd->cmdbuf[(receive - 1) - i]; - if (command == ATKBD_CMD_RESET_BAT && atkbd->cmdcnt == 1) - return 0; + if (atkbd->cmdcnt && (command != ATKBD_CMD_RESET_BAT || atkbd->cmdcnt != 1)) + goto out; - if (atkbd->cmdcnt) - return -1; + rc = 0; - return 0; +out: + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + + return rc; } /* -- cgit v1.2.3 From 41b701f97ecd330aba7898b60ddc62ccfecb8659 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 27 Jul 2004 14:54:40 -0500 Subject: Input: switch atkbd driver from busy-polling for command completion to waiting for event Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 137 ++++++++++++++++++++++++++++++++--------- 1 file changed, 107 insertions(+), 30 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 819967458c3b..ec97ae7d5052 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -209,10 +209,25 @@ struct atkbd { unsigned int last; unsigned long time; + /* Ensures that only one command is executing at a time */ + struct semaphore cmd_sem; + + /* Used to signal completion from interrupt handler */ + wait_queue_head_t wait; + /* Flags */ unsigned long flags; }; +/* Work structure to schedule execution of a command */ +struct atkbd_work { + struct work_struct work; + struct atkbd *atkbd; + int command; + unsigned char param[0]; +}; + + static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value) { input_regs(dev, regs); @@ -262,10 +277,12 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, set_bit(ATKBD_FLAG_CMD1, &atkbd->flags); } clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); + wake_up_interruptible(&atkbd->wait); break; case ATKBD_RET_NAK: atkbd->nak = 1; clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); + wake_up_interruptible(&atkbd->wait); break; } goto out; @@ -276,10 +293,13 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, if (atkbd->cmdcnt) atkbd->cmdbuf[--atkbd->cmdcnt] = code; - clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags); - if (!atkbd->cmdcnt) - clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + if (test_and_clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags) && atkbd->cmdcnt) + wake_up_interruptible(&atkbd->wait); + if (!atkbd->cmdcnt) { + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + wake_up_interruptible(&atkbd->wait); + } goto out; } @@ -412,12 +432,12 @@ out: * acknowledge. It doesn't handle resends according to the keyboard * protocol specs, because if these are needed, the keyboard needs * replacement anyway, and they only make a mess in the protocol. + * + * atkbd_sendbyte() can only be called from a process context */ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) { - int timeout = 200000; /* 200 msec */ - #ifdef ATKBD_DEBUG printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte); #endif @@ -425,8 +445,9 @@ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) set_bit(ATKBD_FLAG_ACK, &atkbd->flags); if (serio_write(atkbd->serio, byte) == 0) - while (test_bit(ATKBD_FLAG_ACK, &atkbd->flags) && timeout--) - udelay(1); + wait_event_interruptible_timeout(atkbd->wait, + !test_bit(ATKBD_FLAG_ACK, &atkbd->flags), + msecs_to_jiffies(200)); clear_bit(ATKBD_FLAG_ACK, &atkbd->flags); return -atkbd->nak; @@ -435,19 +456,21 @@ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte) /* * atkbd_command() sends a command, and its parameters to the keyboard, * then waits for the response and puts it in the param array. + * + * atkbd_command() can only be called from a process context */ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) { - int timeout = 500000; /* 500 msec */ + int timeout; int send = (command >> 12) & 0xf; int receive = (command >> 8) & 0xf; int rc = -1; int i; - if (command == ATKBD_CMD_RESET_BAT) - timeout = 4000000; /* 4 sec */ + timeout = msecs_to_jiffies(command == ATKBD_CMD_RESET_BAT ? 4000 : 500); + down(&atkbd->cmd_sem); clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); if (receive && param) @@ -464,27 +487,26 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) if (atkbd_sendbyte(atkbd, param[i])) goto out; - while (test_bit(ATKBD_FLAG_CMD, &atkbd->flags) && timeout--) { + timeout = wait_event_interruptible_timeout(atkbd->wait, + !test_bit(ATKBD_FLAG_CMD1, &atkbd->flags), timeout); - if (!test_bit(ATKBD_FLAG_CMD1, &atkbd->flags)) { + if (atkbd->cmdcnt && timeout > 0) { + if (command == ATKBD_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100) + timeout = msecs_to_jiffies(100); - if (command == ATKBD_CMD_RESET_BAT && timeout > 100000) - timeout = 100000; - - if (command == ATKBD_CMD_GETID && - atkbd->cmdbuf[receive - 1] != 0xab && atkbd->cmdbuf[receive - 1] != 0xac) { - /* - * Device behind the port is not a keyboard - * so we don't need to wait for the 2nd byte - * of ID response. - */ - clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); - atkbd->cmdcnt = 0; - break; - } + if (command == ATKBD_CMD_GETID && + atkbd->cmdbuf[receive - 1] != 0xab && atkbd->cmdbuf[receive - 1] != 0xac) { + /* + * Device behind the port is not a keyboard + * so we don't need to wait for the 2nd byte + * of ID response. + */ + clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); + atkbd->cmdcnt = 0; } - udelay(1); + wait_event_interruptible_timeout(atkbd->wait, + !test_bit(ATKBD_FLAG_CMD, &atkbd->flags), timeout); } if (param) @@ -499,10 +521,58 @@ static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command) out: clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags); + up(&atkbd->cmd_sem); return rc; } +/* + * atkbd_execute_scheduled_command() sends a command, previously scheduled by + * atkbd_schedule_command(), to the keyboard. + */ + +static void atkbd_execute_scheduled_command(void *data) +{ + struct atkbd_work *atkbd_work = data; + + atkbd_command(atkbd_work->atkbd, atkbd_work->param, atkbd_work->command); + + kfree(atkbd_work); +} + +/* + * atkbd_schedule_command() allows to schedule delayed execution of a keyboard + * command and can be used to issue a command from an interrupt or softirq + * context. + */ + +static int atkbd_schedule_command(struct atkbd *atkbd, unsigned char *param, int command) +{ + struct atkbd_work *atkbd_work; + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + + if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags)) + return -1; + + if (!(atkbd_work = kmalloc(sizeof(struct atkbd_work) + max(send, receive), GFP_ATOMIC))) + return -1; + + memset(atkbd_work, 0, sizeof(struct atkbd_work)); + atkbd_work->atkbd = atkbd; + atkbd_work->command = command; + memcpy(atkbd_work->param, param, send); + INIT_WORK(&atkbd_work->work, atkbd_execute_scheduled_command, atkbd_work); + + if (!schedule_work(&atkbd_work->work)) { + kfree(atkbd_work); + return -1; + } + + return 0; +} + + /* * Event callback from the input module. Events that change the state of * the hardware are processed here. @@ -529,7 +599,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co 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); - atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS); + atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETLEDS); if (atkbd->extra) { param[0] = 0; @@ -538,7 +608,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); - atkbd_command(atkbd, param, ATKBD_CMD_EX_SETLEDS); + atkbd_schedule_command(atkbd, param, ATKBD_CMD_EX_SETLEDS); } return 0; @@ -554,7 +624,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co dev->rep[REP_PERIOD] = period[i]; dev->rep[REP_DELAY] = delay[j]; param[0] = i | (j << 5); - atkbd_command(atkbd, param, ATKBD_CMD_SETREP); + atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETREP); return 0; } @@ -726,7 +796,11 @@ static void atkbd_cleanup(struct serio *serio) static void atkbd_disconnect(struct serio *serio) { struct atkbd *atkbd = serio->private; + clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); + synchronize_kernel(); + flush_scheduled_work(); + input_unregister_device(&atkbd->dev); serio_close(serio); kfree(atkbd); @@ -748,6 +822,9 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv) return; memset(atkbd, 0, sizeof(struct atkbd)); + init_MUTEX(&atkbd->cmd_sem); + init_waitqueue_head(&atkbd->wait); + switch (serio->type & SERIO_TYPE) { case SERIO_8042_XL: -- cgit v1.2.3 From e144c08e2d3399d6471d824462071a35cfc8377c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 27 Jul 2004 14:55:34 -0500 Subject: Input: fix reader wakeup conditions in mousedev, joydev and tsdev (we want readers to wake up when underlying device is gone so they would get -ENODEV and close the device). Signed-off-by: Dmitry Torokhov --- drivers/input/joydev.c | 6 ++++-- drivers/input/mousedev.c | 6 +++++- drivers/input/tsdev.c | 10 +++++----- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 5eb884656db8..3e47218e0d6a 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -232,8 +232,10 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo && list->head == list->tail && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(list->joydev->wait, list->joydev->exist - && (list->startup < joydev->nabs + joydev->nkey || list->head != list->tail)); + retval = wait_event_interruptible(list->joydev->wait, + !list->joydev->exist || + list->startup < joydev->nabs + joydev->nkey || + list->head != list->tail); if (retval) return retval; diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 7aeed6fcfc5a..e1dc39a8a2d8 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -524,11 +524,15 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK)) return -EAGAIN; - retval = wait_event_interruptible(list->mousedev->wait, list->ready || list->buffer); + retval = wait_event_interruptible(list->mousedev->wait, + !list->mousedev->exist || list->ready || list->buffer); if (retval) return retval; + if (!list->mousedev->exist) + return -ENODEV; + if (!list->buffer && list->ready) { mousedev_packet(list, list->ps2); list->buffer = list->bufsiz; diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c index 762878cf3d0c..7acacb3c6894 100644 --- a/drivers/input/tsdev.c +++ b/drivers/input/tsdev.c @@ -19,18 +19,18 @@ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to . */ @@ -210,7 +210,7 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, return -EAGAIN; retval = wait_event_interruptible(list->tsdev->wait, - (list->head != list->tail) && list->tsdev->exist); + list->head != list->tail || !list->tsdev->exist); if (retval) return retval; -- cgit v1.2.3 From 419bd06baaf4065d8053107212421312e61d058e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 27 Jul 2004 14:57:35 -0500 Subject: Input: fix absolute device handling in mousedev that was broken by recent change that tried to do better multiplexing. Now every client will keep its own virtual cursor position and both absolute and relative events will update it Signed-off-by: Dmitry Torokhov --- drivers/input/mousedev.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index e1dc39a8a2d8..bd1a6d98bde5 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -52,8 +52,10 @@ static unsigned tap_time = 200; module_param(tap_time, uint, 0); MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); -struct mousedev_motion { +struct mousedev_hw_data { int dx, dy, dz; + int x, y; + int abs_event; unsigned long buttons; }; @@ -66,7 +68,7 @@ struct mousedev { struct list_head list; struct input_handle handle; - struct mousedev_motion packet; + struct mousedev_hw_data packet; unsigned int pkt_count; int old_x[4], old_y[4]; unsigned long touch; @@ -78,6 +80,11 @@ enum mousedev_emul { MOUSEDEV_EMUL_EXPS }; +struct mousedev_motion { + int dx, dy, dz; + unsigned long buttons; +}; + #define PACKET_QUEUE_LEN 16 struct mousedev_list { struct fasync_struct *fasync; @@ -87,6 +94,7 @@ struct mousedev_list { struct mousedev_motion packets[PACKET_QUEUE_LEN]; unsigned int head, tail; spinlock_t packet_lock; + int pos_x, pos_y; signed char ps2[6]; unsigned char ready, buffer, bufsiz; @@ -134,15 +142,19 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, case ABS_X: size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; if (size == 0) size = xres; - mousedev->packet.dx = (value * xres - mousedev->old_x[0]) / size; - mousedev->old_x[0] = mousedev->packet.dx * size; + if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X]; + if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X]; + mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; + mousedev->packet.abs_event = 1; break; case ABS_Y: size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; if (size == 0) size = yres; - mousedev->packet.dy = (value * yres - mousedev->old_y[0]) / size; - mousedev->old_y[0] = mousedev->packet.dy * size; + if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y]; + if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y]; + mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; + mousedev->packet.abs_event = 1; break; } } @@ -188,7 +200,7 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int } } -static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_motion *packet) +static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet) { struct mousedev_list *list; struct mousedev_motion *p; @@ -206,6 +218,18 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_m } } + if (packet->abs_event) { + p->dx += packet->x - list->pos_x; + p->dy += packet->y - list->pos_y; + list->pos_x = packet->x; + list->pos_y = packet->y; + } + + list->pos_x += packet->dx; + list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x); + list->pos_y += packet->dy; + list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y); + p->dx += packet->dx; p->dy += packet->dy; p->dz += packet->dz; @@ -224,7 +248,7 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) { if (!value) { if (mousedev->touch && - !time_after(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) { + time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) { /* * Toggle left button to emulate tap. * We rely on the fact that mousedev_mix always has 0 @@ -289,6 +313,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig mousedev_notify_readers(&mousedev_mix, &mousedev->packet); mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; + mousedev->packet.abs_event = 0; } break; } @@ -374,6 +399,8 @@ static int mousedev_open(struct inode * inode, struct file * file) memset(list, 0, sizeof(struct mousedev_list)); spin_lock_init(&list->packet_lock); + list->pos_x = xres / 2; + list->pos_y = yres / 2; list->mousedev = mousedev_table[i]; list_add_tail(&list->node, &mousedev_table[i]->list); file->private_data = list; -- cgit v1.2.3 From 664bc086b49af87bc3a6059d6c2efc5d7e459948 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Thu, 29 Jul 2004 17:42:55 +0200 Subject: input: Fix a missing index in tmdc.c Signed-off-by: Vojtech Pavlik --- drivers/input/joystick/tmdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index 6ed46ec46570..e11d2914826d 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -322,7 +322,7 @@ static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev) tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) { - if (tmdc->abs[i] < 0) continue; + if (tmdc->abs[j][i] < 0) continue; set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit); tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8; tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248; -- cgit v1.2.3 From 8b2910fd4987cb7c5b0b6c849b4af6119694b6b7 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Thu, 29 Jul 2004 18:13:12 +0200 Subject: input: Check the range for HIDIOC?USAGES num_values. Signed-off-by: Vojtech Pavlik --- drivers/usb/input/hiddev.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 027ec5df56e5..44e466d196b4 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -633,14 +633,11 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd } else if (uref->usage_index >= field->report_count) goto inval; - else if ((cmd == HIDIOCGUSAGES || - cmd == HIDIOCSUSAGES) && - (uref->usage_index + uref_multi->num_values >= - field->report_count || - uref->usage_index + uref_multi->num_values < - uref->usage_index)) + else if ((cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) && + (uref_multi->num_values >= HID_MAX_MULTI_USAGES || + uref->usage_index + uref_multi->num_values >= field->report_count || + uref->usage_index + uref_multi->num_values < uref->usage_index)) goto inval; - } switch (cmd) { -- cgit v1.2.3 From a25defbba3140a442764bde87eff05817d36741c Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Mon, 2 Aug 2004 15:13:22 +0200 Subject: input: Fix an i8042 access timing violation spotted by Alan Cox. --- drivers/input/serio/i8042.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index ac2780bd9a84..151c29ddb635 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -153,6 +153,7 @@ static int i8042_flush(void) spin_lock_irqsave(&i8042_lock, flags); while ((i8042_read_status() & I8042_STR_OBF) && (i++ < I8042_BUFFER_SIZE)) { + udelay(50); data = i8042_read_data(); dbg("%02x <- i8042 (flush, %s)", data, i8042_read_status() & I8042_STR_AUXDATA ? "aux" : "kbd"); -- cgit v1.2.3 From f780670b8813e171b37ebda17fe95ef07efc5554 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 12 Aug 2004 18:56:02 +0200 Subject: input: Update pcips2 driver Use pci_request_regions()/pci_release_regions() instead of request_region()/release_region() Signed-off-by: Russell King Signed-off-by: Vojtech Pavlik --- drivers/input/serio/pcips2.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c index 610f94a18348..489749e7c9d0 100644 --- a/drivers/input/serio/pcips2.c +++ b/drivers/input/serio/pcips2.c @@ -134,13 +134,11 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i ret = pci_enable_device(dev); if (ret) - return ret; + goto out; - if (!request_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0), "pcips2")) { - ret = -EBUSY; + ret = pci_request_regions(dev, "pcips2"); + if (ret) goto disable; - } ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL); serio = kmalloc(sizeof(struct serio), GFP_KERNEL); @@ -172,10 +170,10 @@ static int __devinit pcips2_probe(struct pci_dev *dev, const struct pci_device_i release: kfree(ps2if); kfree(serio); - release_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); + pci_release_regions(dev); disable: pci_disable_device(dev); + out: return ret; } @@ -184,10 +182,9 @@ static void __devexit pcips2_remove(struct pci_dev *dev) struct pcips2_data *ps2if = pci_get_drvdata(dev); serio_unregister_port(ps2if->io); - release_region(pci_resource_start(dev, 0), - pci_resource_len(dev, 0)); pci_set_drvdata(dev, NULL); kfree(ps2if); + pci_release_regions(dev); pci_disable_device(dev); } -- cgit v1.2.3 From 0a521afd3ea758af8a20def1e14927b1c0131eeb Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Mon, 16 Aug 2004 19:16:23 +0200 Subject: input: Update MAINTAINERS entries for Vojtech Pavlik. --- MAINTAINERS | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index c8c25df4347b..50b4b019224c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1060,6 +1060,13 @@ M: lethal@chaoticdreams.org L: linux-fbdev-devel@lists.sourceforge.net S: Maintained +INPUT (KEYBOARD, MOUSE, JOYSTICK) DRIVERS +P: Vojtech Pavlik +M: vojtech@suse.cz +L: linux-input@atrey.karlin.mff.cuni.cz +L: linux-joystick@atrey.karlin.mff.cuni.cz +S: Maintained + INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT P: Ingo Molnar M: mingo@redhat.com @@ -1178,13 +1185,6 @@ L: jfs-discussion@oss.software.ibm.com W: http://oss.software.ibm.com/jfs/ S: Supported -JOYSTICK DRIVER -P: Vojtech Pavlik -M: vojtech@suse.cz -L: linux-joystick@atrey.karlin.mff.cuni.cz -W: http://www.suse.cz/development/joystick/ -S: Maintained - KCONFIG P: Roman Zippel M: zippel@linux-m68k.org @@ -2165,12 +2165,11 @@ M: dbrownell@users.sourceforge.net L: linux-usb-devel@lists.sourceforge.net S: Maintained -USB HID/HIDBP/INPUT DRIVERS +USB HID/HIDBP DRIVERS P: Vojtech Pavlik M: vojtech@suse.cz L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net -W: http://www.suse.cz/development/input/ S: Maintained USB HUB DRIVER -- cgit v1.2.3 From f78ed24bab6eab4e1ebdf3400bd0bc1d729013e9 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Thu, 19 Aug 2004 21:02:03 +0200 Subject: input: Make sure the HID request queue survives report transfer failures gracefully. Signed-off-by: Vojtech Pavlik Problem-spotted-by: Alan Stern --- drivers/usb/input/hid-core.c | 95 +++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 41 deletions(-) diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 7276a6369fd4..216f7f1e64ec 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -219,17 +219,13 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); return -1; } - usages = parser->local.usage_index; + + if (!(usages = max_t(int, parser->local.usage_index, parser->global.report_count))) + return 0; /* Ignore padding fields */ offset = report->size; report->size += parser->global.report_size * parser->global.report_count; - if (usages < parser->global.report_count) - usages = parser->global.report_count; - - if (usages == 0) - return 0; /* ignore padding fields */ - if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) return 0; @@ -923,20 +919,20 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs) int status; switch (urb->status) { - case 0: /* success */ - hid_input_report(HID_INPUT_REPORT, urb, regs); - break; - case -ECONNRESET: /* unlink */ - case -ENOENT: - case -ESHUTDOWN: - return; - default: /* error */ - dbg("nonzero status in input irq %d", urb->status); + case 0: /* success */ + hid_input_report(HID_INPUT_REPORT, urb, regs); + break; + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + warn("input irq status %d received", urb->status); } - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, SLAB_ATOMIC); if (status) - err ("can't resubmit intr, %s-%s/input%d, status %d", + err("can't resubmit intr, %s-%s/input%d, status %d", hid->dev->bus->bus_name, hid->dev->devpath, hid->ifnum, status); } @@ -1137,23 +1133,31 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs) struct hid_device *hid = urb->context; unsigned long flags; - if (urb->status) - warn("output irq status %d received", urb->status); + switch (urb->status) { + case 0: /* success */ + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + break; + default: /* error */ + warn("output irq status %d received", urb->status); + } spin_lock_irqsave(&hid->outlock, flags); hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); if (hid->outhead != hid->outtail) { - hid_submit_out(hid); + if (hid_submit_out(hid)) { + clear_bit(HID_OUT_RUNNING, &hid->iofl);; + wake_up(&hid->wait); + } spin_unlock_irqrestore(&hid->outlock, flags); return; } clear_bit(HID_OUT_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->outlock, flags); - wake_up(&hid->wait); } @@ -1166,26 +1170,34 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs) struct hid_device *hid = urb->context; unsigned long flags; - if (urb->status) - warn("ctrl urb status %d received", urb->status); - spin_lock_irqsave(&hid->ctrllock, flags); - if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) - hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs); + switch (urb->status) { + case 0: /* success */ + if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) + hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, regs); + case -ECONNRESET: /* unlink */ + case -ENOENT: + case -ESHUTDOWN: + case -EPIPE: /* report not available */ + break; + default: /* error */ + warn("ctrl urb status %d received", urb->status); + } hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); if (hid->ctrlhead != hid->ctrltail) { - hid_submit_ctrl(hid); + if (hid_submit_ctrl(hid)) { + clear_bit(HID_CTRL_RUNNING, &hid->iofl); + wake_up(&hid->wait); + } spin_unlock_irqrestore(&hid->ctrllock, flags); return; } clear_bit(HID_CTRL_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->ctrllock, flags); - wake_up(&hid->wait); } @@ -1211,7 +1223,8 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign hid->outhead = head; if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) - hid_submit_out(hid); + if (hid_submit_out(hid)) + clear_bit(HID_OUT_RUNNING, &hid->iofl); spin_unlock_irqrestore(&hid->outlock, flags); return; @@ -1230,7 +1243,8 @@ void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsign hid->ctrlhead = head; if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl)) - hid_submit_ctrl(hid); + if (hid_submit_ctrl(hid)) + clear_bit(HID_CTRL_RUNNING, &hid->iofl); spin_unlock_irqrestore(&hid->ctrllock, flags); } @@ -1282,7 +1296,7 @@ int hid_open(struct hid_device *hid) void hid_close(struct hid_device *hid) { if (!--hid->open) - usb_unlink_urb(hid->urbin); + usb_kill_urb(hid->urbin); } /* @@ -1643,7 +1657,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, len, hid_irq_in, hid, endpoint->bInterval); hid->urbin->transfer_dma = hid->inbuf_dma; - hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + hid->urbin->transfer_flags |=(URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); } else { if (hid->urbout) continue; @@ -1653,7 +1667,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid, 1); hid->urbout->transfer_dma = hid->outbuf_dma; - hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + hid->urbout->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); } } @@ -1703,8 +1717,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) hid->ctrlbuf, 1, hid_ctrl, hid); hid->urbctrl->setup_dma = hid->cr_dma; hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; - hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP - | URB_NO_SETUP_DMA_MAP); + hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP | URB_ASYNC_UNLINK); return hid; @@ -1730,9 +1743,9 @@ static void hid_disconnect(struct usb_interface *intf) return; usb_set_intfdata(intf, NULL); - usb_unlink_urb(hid->urbin); - usb_unlink_urb(hid->urbout); - usb_unlink_urb(hid->urbctrl); + usb_kill_urb(hid->urbin); + usb_kill_urb(hid->urbout); + usb_kill_urb(hid->urbctrl); if (hid->claimed & HID_CLAIMED_INPUT) hidinput_disconnect(hid); -- cgit v1.2.3