2004-11-12 06:35:16

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 0/7] New set of input patches

Hi Vojtech,

Here is the new set of input patches. Please do

bk pull bk://dtor.bkbits.net/input

It has the tonight's pull from Linus's tree plus the following patches:

01-i8042-panicblink-cleanup.patch
Move panicbkink parameter definition together with the rest of i8042
module parameters, add description and entry in kernel-parameters.txt

02-serio-start-stop.patch
Add serio start() and stop() methods to serio structure that are
called when serio port is about to be fully registered and when
serio port is about to be unregistered. These methods are useful
for drivers that share interrupt among several serio ports. In this
case interrupt can not be enabled/disabled in open/close methods
and it is very hard to determine if interrupt shoudl be ignored or
passed on.

03-i8042-use-start-stop.patch
Make use of new serio start/stop methods to safely activate and
deactivate ports. Also unify as much as possible port handling
between KBD, AUX and MUX ports. Rename i8042_values into i8042_port.

04-serio-suppress-dup-events.patch
Do not submit serio event into event queue if there is already one
of the same type for the same port in front of it. Also look for
duplicat events once event is processed. This should help with
disconnected ports generating alot of data and consuming memory for
events when kseriod gets behind and prevents constant rescans.
This also allows to remove special check for 0xaa in reconnect path
of interrupt handler known to cause problems with Toshibas keyboards.

05-evdev-buffer-size.patch
Return -EINVAL from evdev_read when passed buffer is too small.
Based on patch by James Lamanna.

06-ps2pp-mouse-name.patch
Set mouse name to "Mouse" instead of leaving it NULL when using
PS2++ protocol and don't have any other information (Wheel, Touchpad)
about the mouse.

07-synaptics-toshiba-rate.patch
Toshiba Satellite KBCs have trouble handling data stream coming from
Synaptics at full rate (80 pps, 480 byte/sec) which causes keyboards
to pause or even get stuck. Use DMI to detect Satellites and limit
rate to 40 pps which cures keyboard.

Thanks!

--
Dmitry


2004-11-12 06:37:18

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 1/7] i8042 panicblink code rearrange


===================================================================


[email protected], 2004-11-11 23:01:22-05:00, [email protected]
Input: i8042 - move panicblink with the rest of module paremeters,
add proper entry to kernel-parameters.txt

Signed-off-by: Dmitry Torokhov <[email protected]>


Documentation/kernel-parameters.txt | 3 +++
drivers/input/serio/i8042.c | 35 ++++++++++++++++++++++-------------
2 files changed, 25 insertions(+), 13 deletions(-)


===================================================================



diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt 2004-11-12 01:00:07 -05:00
+++ b/Documentation/kernel-parameters.txt 2004-11-12 01:00:07 -05:00
@@ -486,6 +486,9 @@
i8042.noaux [HW] Don't check for auxiliary (== mouse) port
i8042.nomux [HW] Don't check presence of an active multiplexing
controller
+ i8042.panicblink=
+ [HW] Frequency with which keyboard LEDs should blink
+ when kernel panics (default is 0.5 sec)
i8042.reset [HW] Reset the controller during init and cleanup
i8042.unlock [HW] Unlock (ignore) the keylock

diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c 2004-11-12 01:00:07 -05:00
+++ b/drivers/input/serio/i8042.c 2004-11-12 01:00:07 -05:00
@@ -54,6 +54,10 @@
module_param_named(noloop, i8042_noloop, bool, 0);
MODULE_PARM_DESC(dumbkbd, "Disable the AUX Loopback command while probing for the AUX port");

+static unsigned int i8042_blink_frequency = 500;
+module_param_named(panicblink, i8042_blink_frequency, uint, 0600);
+MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics");
+
#ifdef CONFIG_ACPI
static int i8042_noacpi;
module_param_named(noacpi, i8042_noacpi, bool, 0);
@@ -821,25 +825,29 @@
}


-static int blink_frequency = 500;
-module_param_named(panicblink, blink_frequency, int, 0600);
-
-/* Catch the case when the kbd interrupt is off */
-#define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
-
-/* Tell the user who may be running in X and not see the console that we have
- panic'ed. This is to distingush panics from "real" lockups. */
+/*
+ * i8042_panic_blink() will flash the keyboard LEDs and is called when
+ * kernel panics. Flashing LEDs is useful for users running X who may
+ * not see the console and will help distingushing panics from "real"
+ * lockups.
+ */
static long i8042_panic_blink(long count)
{
long delay = 0;
static long last_blink;
static char led;
- /* Roughly 1/2s frequency. KDB uses about 1s. Make sure it is
- different. */
- if (!blink_frequency)
+
+ /*
+ * We expect frequency to be about 1/2s. KDB uses about 1s.
+ * Make sure they are different.
+ */
+ if (!i8042_blink_frequency)
return 0;
- if (count - last_blink < blink_frequency)
+ if (count - last_blink < i8042_blink_frequency)
return 0;
+
+ /* Ensures that we will not get stuck here if kbd interrupt is off */
+#define DELAY do { mdelay(1); if (++delay > 10) return delay; } while(0)
led ^= 0x01 | 0x04;
while (i8042_read_status() & I8042_STR_IBF)
DELAY;
@@ -850,11 +858,12 @@
DELAY;
i8042_write_data(led);
DELAY;
+#undef DELAY
+
last_blink = count;
return delay;
}

-#undef DELAY

/*
* Here we try to restore the original BIOS settings

2004-11-12 06:37:21

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 2/7] Add serio start() and stop() methods



===================================================================


[email protected], 2004-11-11 23:04:12-05:00, [email protected]
Input: add serio->start() and serio->stop() callback methods that
are called whenever serio port is finishes being registered
or unregistered. The callbacks are useful for drivers that
share interrupt between several ports and there is a danger
that interrupt handler will reference port that was just
unregistered.

Signed-off-by: Dmitry Torokhov <[email protected]>


drivers/input/serio/serio.c | 8 +++++++-
include/linux/serio.h | 2 ++
2 files changed, 9 insertions(+), 1 deletion(-)


===================================================================



diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c 2004-11-12 01:00:20 -05:00
+++ b/drivers/input/serio/serio.c 2004-11-12 01:00:20 -05:00
@@ -328,7 +328,10 @@
serio->dev.release = serio_release_port;
if (serio->parent)
serio->dev.parent = &serio->parent->dev;
- device_register(&serio->dev);
+ device_initialize(&serio->dev);
+ if (serio->start)
+ serio->start(serio);
+ device_add(&serio->dev);
}

/*
@@ -350,6 +353,9 @@
up_write(&serio_bus.subsys.rwsem);
put_driver(&drv->driver);
}
+
+ if (serio->stop)
+ serio->stop(serio);

if (serio->parent) {
spin_lock_irqsave(&serio->parent->lock, flags);
diff -Nru a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h 2004-11-12 01:00:20 -05:00
+++ b/include/linux/serio.h 2004-11-12 01:00:20 -05:00
@@ -42,6 +42,8 @@
int (*write)(struct serio *, unsigned char);
int (*open)(struct serio *);
void (*close)(struct serio *);
+ int (*start)(struct serio *);
+ void (*stop)(struct serio *);

struct serio *parent, *child;

2004-11-12 06:41:12

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 5/7] evdev_read: report -EINVAL when buffer is to small


===================================================================


[email protected], 2004-11-12 00:36:10-05:00, [email protected]
Input: evdev - return -EINVAL from evdev_read if read buffer
is too small.

Based on the patch by James Lamanna.

Signed-off-by: Dmitry Torokhov <[email protected]>


evdev.c | 3 +++
1 files changed, 3 insertions(+)


===================================================================



diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c 2004-11-12 01:01:02 -05:00
+++ b/drivers/input/evdev.c 2004-11-12 01:01:02 -05:00
@@ -169,6 +169,9 @@
struct evdev_list *list = file->private_data;
int retval;

+ if (count < sizeof(struct input_event))
+ return -EINVAL;
+
if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
return -EAGAIN;

2004-11-12 06:41:11

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 4/7] suppress duplicate serio events


===================================================================


[email protected], 2004-11-12 00:31:28-05:00, [email protected]
Input: rearrange serio event processing to get rid of duplicate
events - do not sumbit event into the event queue if similar
event has not been processed yet; also once event has been
processed check the queue and delete events of the same type
that have been accumulated in the mean time.

Signed-off-by: Dmitry Torokhov <[email protected]>


serio.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 48 insertions(+), 9 deletions(-)


===================================================================



diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c 2004-11-12 01:00:47 -05:00
+++ b/drivers/input/serio/serio.c 2004-11-12 01:00:47 -05:00
@@ -120,13 +120,28 @@
static DECLARE_COMPLETION(serio_exited);
static int serio_pid;

-static void serio_queue_event(struct serio *serio, int event_type)
+static void serio_queue_event(struct serio *serio, enum serio_event_type event_type)
{
unsigned long flags;
struct serio_event *event;

spin_lock_irqsave(&serio_event_lock, flags);

+ /*
+ * Scan event list for the other events for the same serio port,
+ * starting with the most recent one. If event is the same we
+ * do not need add new one. If event is of different type we
+ * need to add this event and should not look further because
+ * we need to preseve sequence of distinct events.
+ */
+ list_for_each_entry_reverse(event, &serio_event_list, node) {
+ if (event->serio == serio) {
+ if (event->type == event_type)
+ goto out;
+ break;
+ }
+ }
+
if ((event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC))) {
event->type = event_type;
event->serio = serio;
@@ -135,9 +150,37 @@
wake_up(&serio_wait);
}

+out:
+ spin_unlock_irqrestore(&serio_event_lock, flags);
+}
+
+static void serio_remove_duplicate_events(struct serio_event *event)
+{
+ struct list_head *node, *next;
+ struct serio_event *e;
+ unsigned long flags;
+
+ spin_lock_irqsave(&serio_event_lock, flags);
+
+ list_for_each_safe(node, next, &serio_event_list) {
+ e = container_of(node, struct serio_event, node);
+ if (event->serio == e->serio) {
+ /*
+ * If this event is of different type we should not
+ * look further - we only suppress duplicate events
+ * that were sent back-to-back.
+ */
+ if (event->type != e->type)
+ break; /* Stop, when need to preserve event flow */
+ list_del_init(node);
+ kfree(e);
+ }
+ }
+
spin_unlock_irqrestore(&serio_event_lock, flags);
}

+
static struct serio_event *serio_get_event(void)
{
struct serio_event *event;
@@ -192,6 +235,7 @@
}

up(&serio_sem);
+ serio_remove_duplicate_events(event);
kfree(event);
}
}
@@ -637,14 +681,9 @@

if (likely(serio->drv)) {
ret = serio->drv->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;
- }
- }
+ } else if (!dfl) {
+ serio_rescan(serio);
+ ret = IRQ_HANDLED;
}

spin_unlock_irqrestore(&serio->lock, flags);

2004-11-12 06:41:10

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 3/7] i8042 - use start() and stop() methods


===================================================================


[email protected], 2004-11-12 00:25:22-05:00, [email protected]
Input: i8042 - make use of new serio start() and stop() callbacks
to ensure that i8042 interrupt handler that is shared among
several ports does not reference deleted ports. Also rename
i8042_valies structure to i8042_port, consolidate handling
of KBD, AUX and MUX ports, rearrange interrupt handler code.

Signed-off-by: Dmitry Torokhov <[email protected]>


i8042.c | 319 ++++++++++++++++++++++++++++++++--------------------------------
i8042.h | 6 -
2 files changed, 165 insertions(+), 160 deletions(-)


===================================================================



diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c 2004-11-12 01:00:34 -05:00
+++ b/drivers/input/serio/i8042.c 2004-11-12 01:00:34 -05:00
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/err.h>
+#include <linux/rcupdate.h>

#include <asm/io.h>

@@ -82,7 +83,8 @@

spinlock_t i8042_lock = SPIN_LOCK_UNLOCKED;

-struct i8042_values {
+struct i8042_port {
+ struct serio *serio;
int irq;
unsigned char disable;
unsigned char irqen;
@@ -91,25 +93,25 @@
char name[8];
};

-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",
+#define I8042_KBD_PORT_NO 0
+#define I8042_AUX_PORT_NO 1
+#define I8042_MUX_PORT_NO 2
+#define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2)
+static struct i8042_port i8042_ports[I8042_NUM_PORTS] = {
+ {
+ .disable = I8042_CTR_KBDDIS,
+ .irqen = I8042_CTR_KBDINT,
+ .mux = -1,
+ .name = "KBD",
+ },
+ {
+ .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;
@@ -117,6 +119,7 @@
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
* multiple devices
@@ -250,19 +253,19 @@
* i8042_aux_write() sends a byte out through the aux interface.
*/

-static int i8042_aux_write(struct serio *port, unsigned char c)
+static int i8042_aux_write(struct serio *serio, unsigned char c)
{
- struct i8042_values *values = port->port_data;
+ struct i8042_port *port = serio->port_data;
int retval;

/*
* Send the byte out.
*/

- if (values->mux == -1)
+ if (port->mux == -1)
retval = i8042_command(&c, I8042_CMD_AUX_SEND);
else
- retval = i8042_command(&c, I8042_CMD_MUX_SEND + values->mux);
+ retval = i8042_command(&c, I8042_CMD_MUX_SEND + port->mux);

/*
* Make sure the interrupt happens and the character is received even
@@ -278,9 +281,10 @@
* i8042_activate_port() enables port on a chip.
*/

-static int i8042_activate_port(struct serio *port)
+static int i8042_activate_port(struct i8042_port *port)
{
- struct i8042_values *values = port->port_data;
+ if (!port->serio)
+ return -1;

i8042_flush();

@@ -288,12 +292,12 @@
* Enable port again here because it is disabled if we are
* resuming (normally it is enabled already).
*/
- i8042_ctr &= ~values->disable;
+ i8042_ctr &= ~port->disable;

- i8042_ctr |= values->irqen;
+ i8042_ctr |= port->irqen;

if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- i8042_ctr &= ~values->irqen;
+ i8042_ctr &= ~port->irqen;
return -1;
}

@@ -306,22 +310,22 @@
* It allocates the interrupt and calls i8042_enable_port.
*/

-static int i8042_open(struct serio *port)
+static int i8042_open(struct serio *serio)
{
- struct i8042_values *values = port->port_data;
+ struct i8042_port *port = serio->port_data;

- if (values->mux != -1)
+ if (port->mux != -1)
if (i8042_mux_open++)
return 0;

- if (request_irq(values->irq, i8042_interrupt,
+ if (request_irq(port->irq, i8042_interrupt,
SA_SHIRQ, "i8042", i8042_request_irq_cookie)) {
- printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name);
+ printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", port->irq, port->name);
goto irq_fail;
}

if (i8042_activate_port(port)) {
- printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", values->name);
+ printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", port->name);
goto activate_fail;
}

@@ -330,11 +334,10 @@
return 0;

activate_fail:
- free_irq(values->irq, i8042_request_irq_cookie);
+ free_irq(port->irq, i8042_request_irq_cookie);

irq_fail:
- values->exists = 0;
- serio_unregister_port_delayed(port);
+ serio_unregister_port_delayed(serio);

return -1;
}
@@ -345,27 +348,58 @@
* the BIOS could have used the AUX interrupt for PCI.
*/

-static void i8042_close(struct serio *port)
+static void i8042_close(struct serio *serio)
{
- struct i8042_values *values = port->port_data;
+ struct i8042_port *port = serio->port_data;

- if (values->mux != -1)
+ if (port->mux != -1)
if (--i8042_mux_open)
return;

- i8042_ctr &= ~values->irqen;
+ i8042_ctr &= ~port->irqen;

if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- printk(KERN_ERR "i8042.c: Can't write CTR while closing %s.\n", values->name);
- return;
+ printk(KERN_WARNING "i8042.c: Can't write CTR while closing %s.\n", port->name);
+/*
+ * We still want to continue and free IRQ so if more data keeps coming in
+ * kernel will just ignore the irq.
+ */
}

- free_irq(values->irq, i8042_request_irq_cookie);
+ free_irq(port->irq, i8042_request_irq_cookie);

i8042_flush();
}

/*
+ * i8042_start() is called by serio core when port is about to finish
+ * registering. It will mark port as existing so i8042_interrupt can
+ * start sending data through it.
+ */
+static int i8042_start(struct serio *serio)
+{
+ struct i8042_port *port = serio->port_data;
+
+ port->exists = 1;
+ mb();
+ return 0;
+}
+
+/*
+ * i8042_stop() marks serio port as non-existing so i8042_interrupt
+ * will not try to send data to the port that is about to go away.
+ * The function is called by serio core as part of unregister procedure.
+ */
+static void i8042_stop(struct serio *serio)
+{
+ struct i8042_port *port = serio->port_data;
+
+ port->exists = 0;
+ synchronize_kernel();
+ port->serio = NULL;
+}
+
+/*
* 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.
@@ -373,25 +407,25 @@

static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
+ struct i8042_port *port;
unsigned long flags;
- unsigned char str, data = 0;
+ unsigned char str, data;
unsigned int dfl;
- unsigned int aux_idx;
+ unsigned int port_no;
int ret;

mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);

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 (~str & I8042_STR_OBF) {
+ if (unlikely(~str & I8042_STR_OBF)) {
+ spin_unlock_irqrestore(&i8042_lock, flags);
if (irq) dbg("Interrupt %d, without any data", irq);
ret = 0;
goto out;
}
+ data = i8042_read_data();
+ spin_unlock_irqrestore(&i8042_lock, flags);

if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
static unsigned long last_transmit;
@@ -423,39 +457,28 @@
}
}

- aux_idx = (str >> 6) & 3;
-
- dbg("%02x <- i8042 (interrupt, aux%d, %d%s%s)",
- data, aux_idx, irq,
- dfl & SERIO_PARITY ? ", bad parity" : "",
- dfl & SERIO_TIMEOUT ? ", timeout" : "");
-
- if (likely(i8042_mux_values[aux_idx].exists))
- serio_interrupt(i8042_mux_port[aux_idx], data, dfl, regs);
-
+ port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3);
last_str = str;
last_transmit = jiffies;
- goto irq_ret;
+ } else {
+
+ dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
+ ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
+
+ port_no = (str & I8042_STR_AUXDATA) ?
+ I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
}

- dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
- ((str & I8042_STR_TIMEOUT) ? SERIO_TIMEOUT : 0);
+ port = &i8042_ports[port_no];

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" : "");
+ data, port->name, irq,
+ dfl & SERIO_PARITY ? ", bad parity" : "",
+ dfl & SERIO_TIMEOUT ? ", timeout" : "");

+ if (likely(port->exists))
+ serio_interrupt(port->serio, 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;
out:
return IRQ_RETVAL(ret);
@@ -467,7 +490,7 @@
* Legacy) mode.
*/

-static int i8042_enable_mux_mode(struct i8042_values *values, unsigned char *mux_version)
+static int i8042_enable_mux_mode(unsigned char *mux_version)
{

unsigned char param;
@@ -505,7 +528,7 @@
* the controller has been switched into Multiplexed mode
*/

-static int i8042_enable_mux_ports(struct i8042_values *values)
+static int i8042_enable_mux_ports(void)
{
unsigned char param;
int i;
@@ -540,11 +563,11 @@
* LCS/Telegraphics.
*/

-static int __init i8042_check_mux(struct i8042_values *values)
+static int __init i8042_check_mux(void)
{
unsigned char mux_version;

- if (i8042_enable_mux_mode(values, &mux_version))
+ if (i8042_enable_mux_mode(&mux_version))
return -1;

/* Workaround for broken chips which seem to support MUX, but in reality don't. */
@@ -555,7 +578,7 @@
printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
(mux_version >> 4) & 0xf, mux_version & 0xf);

- if (i8042_enable_mux_ports(values))
+ if (i8042_enable_mux_ports())
return -1;

i8042_mux_present = 1;
@@ -568,7 +591,7 @@
* the presence of an AUX interface.
*/

-static int __init i8042_check_aux(struct i8042_values *values)
+static int __init i8042_check_aux(void)
{
unsigned char param;
static int i8042_check_aux_cookie;
@@ -578,10 +601,10 @@
* in trying to detect AUX presence.
*/

- if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ,
- "i8042", &i8042_check_aux_cookie))
+ if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt,
+ SA_SHIRQ, "i8042", &i8042_check_aux_cookie))
return -1;
- free_irq(values->irq, &i8042_check_aux_cookie);
+ free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie);

/*
* Get rid of bytes in the queue.
@@ -646,27 +669,25 @@
* registers it, and reports to the user.
*/

-static int __init i8042_port_register(struct serio *port)
+static int __init i8042_port_register(struct i8042_port *port)
{
- struct i8042_values *values = port->port_data;
-
- values->exists = 1;
-
- i8042_ctr &= ~values->disable;
+ i8042_ctr &= ~port->disable;

if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n");
- values->exists = 0;
+ kfree(port->serio);
+ port->serio = NULL;
+ i8042_ctr |= port->disable;
return -1;
}

printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n",
- values->name,
+ port->name,
(unsigned long) I8042_DATA_REG,
(unsigned long) I8042_COMMAND_REG,
- values->irq);
+ port->irq);

- serio_register_port(port);
+ serio_register_port(port->serio);

return 0;
}
@@ -811,15 +832,9 @@
* Reset anything that is connected to the ports.
*/

- if (i8042_kbd_values.exists)
- serio_cleanup(i8042_kbd_port);
-
- if (i8042_aux_values.exists)
- serio_cleanup(i8042_aux_port);
-
- for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
- if (i8042_mux_values[i].exists)
- serio_cleanup(i8042_mux_port[i]);
+ for (i = 0; i < I8042_NUM_PORTS; i++)
+ if (i8042_ports[i].exists)
+ serio_cleanup(i8042_ports[i].serio);

i8042_controller_reset();
}
@@ -897,8 +912,7 @@
}

if (i8042_mux_present)
- if (i8042_enable_mux_mode(&i8042_aux_values, NULL) ||
- i8042_enable_mux_ports(&i8042_aux_values)) {
+ if (i8042_enable_mux_mode(NULL) || i8042_enable_mux_ports()) {
printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n");
}

@@ -906,15 +920,9 @@
* 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_aux_values.exists && i8042_activate_port(i8042_aux_port) == 0)
- serio_reconnect(i8042_aux_port);
-
- 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]);
+ for (i = 0; i < I8042_NUM_PORTS; i++)
+ if (i8042_activate_port(&i8042_ports[i]) == 0)
+ serio_reconnect(i8042_ports[i].serio);
/*
* Restart timer (for polling "stuck" data)
*/
@@ -944,9 +952,10 @@
.shutdown = i8042_shutdown,
};

-static struct serio * __init i8042_allocate_kbd_port(void)
+static void __init i8042_create_kbd_port(void)
{
struct serio *serio;
+ struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];

serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
@@ -955,18 +964,22 @@
serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write,
serio->open = i8042_open,
serio->close = i8042_close,
- serio->port_data = &i8042_kbd_values,
+ serio->start = i8042_start,
+ serio->stop = i8042_stop,
+ serio->port_data = port,
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));
- }

- return serio;
+ port->serio = serio;
+ i8042_port_register(port);
+ }
}

-static struct serio * __init i8042_allocate_aux_port(void)
+static void __init i8042_create_aux_port(void)
{
struct serio *serio;
+ struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO];

serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
if (serio) {
@@ -975,38 +988,44 @@
serio->write = i8042_aux_write;
serio->open = i8042_open;
serio->close = i8042_close;
- serio->port_data = &i8042_aux_values,
+ serio->start = i8042_start,
+ serio->stop = i8042_stop,
+ serio->port_data = port,
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));
- }

- return serio;
+ port->serio = serio;
+ i8042_port_register(port);
+ }
}

-static struct serio * __init i8042_allocate_mux_port(int index)
+static void __init i8042_create_mux_port(int index)
{
struct serio *serio;
- struct i8042_values *values = &i8042_mux_values[index];
+ struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + 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;
+ serio->start = i8042_start,
+ serio->stop = i8042_stop,
+ serio->port_data = port;
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);
- }

- return serio;
+ *port = i8042_ports[I8042_AUX_PORT_NO];
+ port->exists = 0;
+ snprintf(port->name, sizeof(port->name), "AUX%d", index);
+ port->mux = index;
+ port->serio = serio;
+ i8042_port_register(port);
+ }
}

int __init i8042_init(void)
@@ -1022,8 +1041,8 @@
if (i8042_platform_init())
return -EBUSY;

- i8042_aux_values.irq = I8042_AUX_IRQ;
- i8042_kbd_values.irq = I8042_KBD_IRQ;
+ i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ;
+ i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ;

if (i8042_controller_init())
return -ENODEV;
@@ -1038,23 +1057,15 @@
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++) {
- i8042_mux_port[i] = i8042_allocate_mux_port(i);
- if (i8042_mux_port[i])
- i8042_port_register(i8042_mux_port[i]);
- }
- else {
- i8042_aux_port = i8042_allocate_aux_port();
- if (i8042_aux_port)
- i8042_port_register(i8042_aux_port);
- }
+ if (!i8042_noaux && !i8042_check_aux()) {
+ if (!i8042_nomux && !i8042_check_mux())
+ for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
+ i8042_create_mux_port(i);
+ else
+ i8042_create_aux_port();
}

- i8042_kbd_port = i8042_allocate_kbd_port();
- if (i8042_kbd_port)
- i8042_port_register(i8042_kbd_port);
+ i8042_create_kbd_port();

mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);

@@ -1067,15 +1078,9 @@

i8042_controller_cleanup();

- if (i8042_kbd_values.exists)
- serio_unregister_port(i8042_kbd_port);
-
- if (i8042_aux_values.exists)
- serio_unregister_port(i8042_aux_port);
-
- for (i = 0; i < I8042_NUM_MUX_PORTS; i++)
- if (i8042_mux_values[i].exists)
- serio_unregister_port(i8042_mux_port[i]);
+ for (i = 0; i < I8042_NUM_PORTS; i++)
+ if (i8042_ports[i].exists)
+ serio_unregister_port(i8042_ports[i].serio);

del_timer_sync(&i8042_timer);

diff -Nru a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
--- a/drivers/input/serio/i8042.h 2004-11-12 01:00:34 -05:00
+++ b/drivers/input/serio/i8042.h 2004-11-12 01:00:34 -05:00
@@ -117,13 +117,13 @@
*/

#ifdef DEBUG
-static unsigned long i8042_start;
-#define dbg_init() do { i8042_start = jiffies; } while (0)
+static unsigned long i8042_start_time;
+#define dbg_init() do { i8042_start_time = jiffies; } while (0)
#define dbg(format, arg...) \
do { \
if (i8042_debug) \
printk(KERN_DEBUG __FILE__ ": " format " [%d]\n" , \
- ## arg, (int) (jiffies - i8042_start)); \
+ ## arg, (int) (jiffies - i8042_start_time)); \
} while (0)
#else
#define dbg_init() do { } while (0)

2004-11-12 06:41:10

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 7/7] Limit Synaptics rate on Toshibas


===================================================================


[email protected], 2004-11-12 00:47:33-05:00, [email protected]
Input: synaptics - use DMI to detect Toshiba Satellite notebooks
and automatically reduce touchpad reporting rate to 40 pps
as they have trouble handling high rate (80 pps).

Signed-off-by: Dmitry Torokhov <[email protected]>


synaptics.c | 26 ++++++++++++++++++++++++++
1 files changed, 26 insertions(+)


===================================================================



diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c 2004-11-12 01:01:27 -05:00
+++ b/drivers/input/mouse/synaptics.c 2004-11-12 01:01:27 -05:00
@@ -604,6 +604,20 @@
return 0;
}

+#if defined(__i386__)
+#include <linux/dmi.h>
+static struct dmi_system_id toshiba_dmi_table[] = {
+ {
+ .ident = "Toshiba Satellite",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME , "Satellite"),
+ },
+ },
+ { }
+};
+#endif
+
int synaptics_init(struct psmouse *psmouse)
{
struct synaptics_data *priv;
@@ -636,6 +650,18 @@
psmouse->disconnect = synaptics_disconnect;
psmouse->reconnect = synaptics_reconnect;
psmouse->pktsize = 6;
+
+#if defined(__i386__)
+ /*
+ * Toshiba's KBC seems to have trouble handling data from
+ * Synaptics as full rate, switch to lower rate which is roughly
+ * thye same as rate of standard PS/2 mouse.
+ */
+ if (psmouse->rate >= 80 && dmi_check_system(toshiba_dmi_table)) {
+ printk(KERN_INFO "synaptics: Toshiba Satellite detected, limiting rate to 40pps.\n");
+ psmouse->rate = 40;
+ }
+#endif

return 0;

2004-11-12 06:41:08

by Dmitry Torokhov

[permalink] [raw]
Subject: [PATCH 6/7] Correctly set mouse name when using PS2++ protocol


===================================================================


[email protected], 2004-11-12 00:39:02-05:00, [email protected]
Input: psmouse - set mouse name to "Mouse" when using PS2++ and
don't have any other information about the mouse.

Signed-off-by: Dmitry Torokhov <[email protected]>


logips2pp.c | 15 +++++++++++++--
1 files changed, 13 insertions(+), 2 deletions(-)


===================================================================



diff -Nru a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
--- a/drivers/input/mouse/logips2pp.c 2004-11-12 01:01:15 -05:00
+++ b/drivers/input/mouse/logips2pp.c 2004-11-12 01:01:15 -05:00
@@ -245,7 +245,8 @@
* Set up input device's properties based on the detected mouse model.
*/

-static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info)
+static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info,
+ int using_ps2pp)
{
if (model_info->features & PS2PP_SIDE_BTN)
set_bit(BTN_SIDE, psmouse->dev.keybit);
@@ -279,6 +280,16 @@
case PS2PP_KIND_TP3:
psmouse->name = "TouchPad 3";
break;
+
+ default:
+ /*
+ * Set name to "Mouse" only when using PS2++,
+ * otherwise let other protocols define suitable
+ * name
+ */
+ if (using_ps2pp)
+ psmouse->name = "Mouse";
+ break;
}
}

@@ -371,7 +382,7 @@
clear_bit(BTN_RIGHT, psmouse->dev.keybit);

if (model_info)
- ps2pp_set_model_properties(psmouse, model_info);
+ ps2pp_set_model_properties(psmouse, model_info, use_ps2pp);
}

return use_ps2pp ? 0 : -1;