2003-09-19 10:26:52

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 1/11] input: Restore synaptics pad mode on module unload

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 00:20:17-07:00, [email protected]
synaptics.c, psmouse-base.c:
input: Restore synaptics pad mode on module unload.


psmouse-base.c | 3 ++-
synaptics.c | 7 +++++--
2 files changed, 7 insertions(+), 3 deletions(-)

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

diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:16:53 2003
+++ b/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:16:53 2003
@@ -478,9 +478,10 @@
static void psmouse_disconnect(struct serio *serio)
{
struct psmouse *psmouse = serio->private;
+ if (psmouse->type == PSMOUSE_SYNAPTICS)
+ synaptics_disconnect(psmouse);
input_unregister_device(&psmouse->dev);
serio_close(serio);
- synaptics_disconnect(psmouse);
kfree(psmouse);
}

diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c Fri Sep 19 12:16:53 2003
+++ b/drivers/input/mouse/synaptics.c Fri Sep 19 12:16:53 2003
@@ -144,7 +144,7 @@
static void print_ident(struct synaptics_data *priv)
{
printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
- printk(KERN_INFO " Firware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
+ printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
SYN_ID_MINOR(priv->identity));

if (SYN_MODEL_ROT180(priv->model_id))
@@ -228,7 +228,7 @@
/*
* The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
* which says that they should be valid regardless of the actual size of
- * the senser.
+ * the sensor.
*/
set_bit(EV_ABS, psmouse->dev.evbit);
set_abs_params(&psmouse->dev, ABS_X, 1472, 5472, 0, 0);
@@ -258,6 +258,9 @@
void synaptics_disconnect(struct psmouse *psmouse)
{
struct synaptics_data *priv = psmouse->private;
+
+ /* Restore touchpad to power on default state */
+ synaptics_set_mode(psmouse, 0);

kfree(priv);
}


2003-09-19 10:26:57

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 5/11] input: Fix resume of PS/2 mouse

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 01:18:46-07:00, [email protected]
psmouse-base.c:
Fix resume of PS/2 mouse. Uses old PM interface at the moment.


psmouse-base.c | 32 ++++++++++++++++++++++++++++++++
1 files changed, 32 insertions(+)

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

diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:16:24 2003
+++ b/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:16:24 2003
@@ -17,6 +17,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
+#include <linux/pm.h>
#include "psmouse.h"
#include "synaptics.h"
#include "logips2pp.h"
@@ -512,6 +513,30 @@
}

/*
+ * Reinitialize mouse hardware after software suspend.
+ */
+
+static int psmouse_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
+{
+ struct psmouse *psmouse = dev->data;
+ struct serio_dev *ser_dev = psmouse->serio->dev;
+
+ synaptics_disconnect(psmouse);
+
+ /* We need to reopen the serio port to reinitialize the i8042 controller */
+ serio_close(psmouse->serio);
+ serio_open(psmouse->serio, ser_dev);
+
+ /* Probe and re-initialize the mouse */
+ psmouse_probe(psmouse);
+ psmouse_initialize(psmouse);
+ synaptics_pt_init(psmouse);
+ psmouse_activate(psmouse);
+
+ return 0;
+}
+
+/*
* psmouse_connect() is a callback from the serio module when
* an unhandled serio port is found.
*/
@@ -519,6 +544,7 @@
static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
{
struct psmouse *psmouse;
+ struct pm_dev *pmdev;

if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
(serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
@@ -551,6 +577,12 @@
return;
}

+ pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, psmouse_pm_callback);
+ if (pmdev) {
+ psmouse->dev.pm_dev = pmdev;
+ pmdev->data = psmouse;
+ }
+
sprintf(psmouse->devname, "%s %s %s",
psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
sprintf(psmouse->phys, "%s/input0",

2003-09-19 10:28:27

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 8/11] input: Fix the INPUT_KEYCODE macro and its usage

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 01:22:06-07:00, [email protected]
input.h, keyboard.c, evdev.c:
Fix the INPUT_KEYCODE macro and its usage.


drivers/char/keyboard.c | 2 +-
drivers/input/evdev.c | 12 +++++-------
include/linux/input.h | 2 +-
3 files changed, 7 insertions(+), 9 deletions(-)

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

diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c Fri Sep 19 12:16:01 2003
+++ b/drivers/char/keyboard.c Fri Sep 19 12:16:01 2003
@@ -205,7 +205,7 @@
INPUT_KEYCODE(dev, scancode) = keycode;

for (i = 0; i < dev->keycodemax; i++)
- if(INPUT_KEYCODE(dev, scancode) == oldkey)
+ if(keycode == oldkey)
break;
if (i == dev->keycodemax)
clear_bit(oldkey, dev->keybit);
diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c Fri Sep 19 12:16:01 2003
+++ b/drivers/input/evdev.c Fri Sep 19 12:16:01 2003
@@ -208,7 +208,7 @@
struct evdev *evdev = list->evdev;
struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs;
- int i, t, u;
+ int i, t, u, v;

if (!evdev->exist) return -ENODEV;

@@ -239,14 +239,12 @@
case EVIOCSKEYCODE:
if (get_user(t, ((int *) arg) + 0)) return -EFAULT;
if (t < 0 || t > dev->keycodemax || !dev->keycodesize) return -EINVAL;
+ if (get_user(v, ((int *) arg) + 1)) return -EFAULT;
u = INPUT_KEYCODE(dev, t);
- if (get_user(INPUT_KEYCODE(dev, t), ((int *) arg) + 1)) return -EFAULT;
-
- for (i = 0; i < dev->keycodemax; i++)
- if(INPUT_KEYCODE(dev, t) == u) break;
+ INPUT_KEYCODE(dev, t) = v;
+ for (i = 0; i < dev->keycodemax; i++) if (v == u) break;
if (i == dev->keycodemax) clear_bit(u, dev->keybit);
- set_bit(INPUT_KEYCODE(dev, t), dev->keybit);
-
+ set_bit(v, dev->keybit);
return 0;

case EVIOCSFF:
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h Fri Sep 19 12:16:01 2003
+++ b/include/linux/input.h Fri Sep 19 12:16:01 2003
@@ -751,7 +751,7 @@
#define LONG(x) ((x)/BITS_PER_LONG)

#define INPUT_KEYCODE(dev, scancode) ((dev->keycodesize == 1) ? ((u8*)dev->keycode)[scancode] : \
- ((dev->keycodesize == 1) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))
+ ((dev->keycodesize == 2) ? ((u16*)dev->keycode)[scancode] : (((u32*)dev->keycode)[scancode])))

#define init_input_dev(dev) do { INIT_LIST_HEAD(&((dev)->h_list)); INIT_LIST_HEAD(&((dev)->node)); } while (0)


2003-09-19 10:28:28

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 10/11] input: Fix I-Force sleeping issues

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 01:24:36-07:00, [email protected]
iforce-usb.c, iforce-packets.c:
Fix I-Force sleeping issues.


iforce-packets.c | 5 ++---
iforce-usb.c | 6 ++----
2 files changed, 4 insertions(+), 7 deletions(-)

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

diff -Nru a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
--- a/drivers/input/joystick/iforce/iforce-packets.c Fri Sep 19 12:15:47 2003
+++ b/drivers/input/joystick/iforce/iforce-packets.c Fri Sep 19 12:15:47 2003
@@ -166,8 +166,7 @@
iforce->expect_packet = 0;
iforce->ecmd = cmd;
memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
+ wake_up(&iforce->wait);
}
#endif

@@ -264,7 +263,7 @@
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&iforce->wait, &wait);

- if (usb_submit_urb(iforce->ctrl, GFP_KERNEL)) {
+ if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&iforce->wait, &wait);
return -1;
diff -Nru a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
--- a/drivers/input/joystick/iforce/iforce-usb.c Fri Sep 19 12:15:47 2003
+++ b/drivers/input/joystick/iforce/iforce-usb.c Fri Sep 19 12:15:47 2003
@@ -116,8 +116,7 @@

iforce_usb_xmit(iforce);

- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
+ wake_up(&iforce->wait);
}

static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs)
@@ -125,8 +124,7 @@
struct iforce *iforce = urb->context;
if (urb->status) return;
iforce->ecmd = 0xff00 | urb->actual_length;
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
+ wake_up(&iforce->wait);
}

static int iforce_usb_probe(struct usb_interface *intf,

2003-09-19 10:31:29

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 7/11] input: Fix psmouse->pktcnt in Synaptics mode

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 01:20:33-07:00, [email protected]
psmouse-base.c:
Make sure psmouse->pktcnt is zero after passing a byte
to be processed by synaptics code.


psmouse-base.c | 1 +
1 files changed, 1 insertion(+)

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

diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:16:08 2003
+++ b/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:16:08 2003
@@ -173,6 +173,7 @@
* so it needs to receive all bytes one at a time.
*/
synaptics_process_byte(psmouse, regs);
+ psmouse->pktcnt = 0;
goto out;
}


2003-09-19 10:28:32

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 9/11] input: Enlarge the timeout for PS/2 mouse full reset

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 01:23:29-07:00, [email protected]
psmouse-base.c:
Enlarge the timeout for PS/2 mouse full reset.


psmouse-base.c | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)

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

diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:15:54 2003
+++ b/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:15:54 2003
@@ -223,7 +223,7 @@
psmouse->cmdcnt = receive;

if (command == PSMOUSE_CMD_RESET_BAT)
- timeout = 2000000; /* 2 sec */
+ timeout = 4000000; /* 4 sec */

if (command & 0xff)
if (psmouse_sendbyte(psmouse, command & 0xff))

2003-09-19 10:33:47

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 4/11] input: Big Synaptics pad update

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 01:17:37-07:00, [email protected]
Input: Big Synaptics update:
Restore synaptics pad mode on module unload.
Support Synaptics touchpads with multiple buttons.
Make Synaptics touchpad support optional.
Add passthrough support for Synaptics touchpads. [Dmitry]
Add support for old Synaptics protocol.
Set mode byte correctly for old Synaptics pads.
Fix multibutton support of Synaptics pads.


Documentation/kernel-parameters.txt | 4
drivers/input/mouse/Kconfig | 20 +
drivers/input/mouse/psmouse-base.c | 69 +++++-
drivers/input/mouse/psmouse.h | 22 +-
drivers/input/mouse/synaptics.c | 364 ++++++++++++++++++++++++++++--------
drivers/input/mouse/synaptics.h | 27 ++
drivers/input/serio/serio.c | 25 ++
include/linux/serio.h | 3
8 files changed, 424 insertions(+), 110 deletions(-)

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

diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt Fri Sep 19 12:16:32 2003
+++ b/Documentation/kernel-parameters.txt Fri Sep 19 12:16:32 2003
@@ -788,6 +788,10 @@

psmouse_noext [HW,MOUSE] Disable probing for PS2 mouse protocol extensions

+ psmouse_resetafter=
+ [HW,MOUSE] Try to reset Synaptics Touchpad after so many
+ bad packets (0 = never).
+
pss= [HW,OSS] Personal Sound System (ECHO ESC614)
Format: <io>,<mss_io>,<mss_irq>,<mss_dma>,<mpu_io>,<mpu_irq>

diff -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
--- a/drivers/input/mouse/Kconfig Fri Sep 19 12:16:32 2003
+++ b/drivers/input/mouse/Kconfig Fri Sep 19 12:16:32 2003
@@ -19,9 +19,7 @@
Say Y here if you have a PS/2 mouse connected to your system. This
includes the standard 2 or 3-button PS/2 mouse, as well as PS/2
mice with wheels and extra buttons, Microsoft, Logitech or Genius
- compatible. Support for Synaptics TouchPads is also included.
- For Synaptics TouchPad support in XFree86 you'll need this XFree86
- driver: http://w1.894.telia.com/~u89404340/touchpad/index.html
+ compatible.

If unsure, say Y.

@@ -29,6 +27,22 @@
inserted in and removed from the running kernel whenever you want).
The module will be called psmouse. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
+
+config MOUSE_PS2_SYNAPTICS
+ bool "Synaptics TouchPad"
+ default n
+ depends on INPUT && INPUT_MOUSE && SERIO && MOUSE_PS2
+ ---help---
+ Say Y here if you have a Synaptics TouchPad connected to your system.
+ This touchpad is found on many modern laptop computers.
+
+ Note that you also need a user space driver to interpret the data
+ generated by the kernel. A compatible driver for XFree86 is available
+ from http://w1.894.telia.com/~u89404340/touchpad/index.html
+
+ The gpm program is not yet able to interpret the data from this
+ driver, so if you need to use the touchpad in the console, you have to
+ say N for now.

config MOUSE_SERIAL
tristate "Serial mouse"
diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:16:32 2003
+++ b/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:16:32 2003
@@ -29,6 +29,8 @@
MODULE_PARM_DESC(psmouse_resolution, "Resolution, in dpi.");
MODULE_PARM(psmouse_smartscroll, "i");
MODULE_PARM_DESC(psmouse_smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled.");
+MODULE_PARM(psmouse_resetafter, "i");
+MODULE_PARM_DESC(psmouse_resetafter, "Reset Synaptics Touchpad after so many bad packets (0 = never).");
MODULE_LICENSE("GPL");

#define PSMOUSE_LOGITECH_SMARTSCROLL 1
@@ -36,11 +38,12 @@
static int psmouse_noext;
int psmouse_resolution;
int psmouse_smartscroll = PSMOUSE_LOGITECH_SMARTSCROLL;
+unsigned int psmouse_resetafter;

static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};

/*
- * psmouse_process_packet() anlyzes the PS/2 mouse packet contents and
+ * psmouse_process_packet() analyzes the PS/2 mouse packet contents and
* reports relevant events to the input module.
*/

@@ -108,6 +111,9 @@
{
struct psmouse *psmouse = serio->private;

+ if (psmouse->state == PSMOUSE_IGNORE)
+ goto out;
+
if (psmouse->acking) {
switch (data) {
case PSMOUSE_RET_ACK:
@@ -132,31 +138,46 @@
}

if (psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) {
- printk(KERN_WARNING "psmouse.c: Lost synchronization, throwing %d bytes away.\n", psmouse->pktcnt);
+ printk(KERN_WARNING "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n",
+ psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->pktcnt = 0;
}

psmouse->last = jiffies;
psmouse->packet[psmouse->pktcnt++] = data;

- if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
- psmouse_process_packet(psmouse, regs);
- psmouse->pktcnt = 0;
- goto out;
+ if (psmouse->packet[0] == PSMOUSE_RET_BAT) {
+ if (psmouse->pktcnt == 1)
+ goto out;
+
+ if (psmouse->pktcnt == 2) {
+ if (psmouse->packet[1] == PSMOUSE_RET_ID) {
+ psmouse->state = PSMOUSE_IGNORE;
+ serio_rescan(serio);
+ goto out;
+ }
+ if (psmouse->type == PSMOUSE_SYNAPTICS) {
+ /* neither 0xAA nor 0x00 are valid first bytes
+ * for a packet in absolute mode
+ */
+ psmouse->pktcnt = 0;
+ goto out;
+ }
+ }
}

- if (psmouse->pktcnt == 1 && psmouse->type == PSMOUSE_SYNAPTICS) {
+ if (psmouse->type == PSMOUSE_SYNAPTICS) {
/*
* The synaptics driver has its own resync logic,
* so it needs to receive all bytes one at a time.
*/
synaptics_process_byte(psmouse, regs);
- psmouse->pktcnt = 0;
goto out;
}

- if (psmouse->pktcnt == 1 && psmouse->packet[0] == PSMOUSE_RET_BAT) {
- serio_rescan(serio);
+ if (psmouse->pktcnt == 3 + (psmouse->type >= PSMOUSE_GENPS)) {
+ psmouse_process_packet(psmouse, regs);
+ psmouse->pktcnt = 0;
goto out;
}
out:
@@ -227,7 +248,7 @@
for (i = 0; i < receive; i++)
param[i] = psmouse->cmdbuf[(receive - 1) - i];

- if (psmouse->cmdcnt)
+ if (psmouse->cmdcnt)
return (psmouse->cmdcnt = 0) - 1;

return 0;
@@ -450,14 +471,18 @@
*/

psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+}

/*
- * Last, we enable the mouse so that we get reports from it.
+ * psmouse_activate() enables the mouse so that we get motion reports from it.
*/

+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;
}

/*
@@ -478,8 +503,9 @@
static void psmouse_disconnect(struct serio *serio)
{
struct psmouse *psmouse = serio->private;
- if (psmouse->type == PSMOUSE_SYNAPTICS)
- synaptics_disconnect(psmouse);
+
+ psmouse->state = PSMOUSE_IGNORE;
+ synaptics_disconnect(psmouse);
input_unregister_device(&psmouse->dev);
serio_close(serio);
kfree(psmouse);
@@ -494,7 +520,8 @@
{
struct psmouse *psmouse;

- if ((serio->type & SERIO_TYPE) != SERIO_8042)
+ if ((serio->type & SERIO_TYPE) != SERIO_8042 &&
+ (serio->type & SERIO_TYPE) != SERIO_PS_PSTHRU)
return;

if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL)))
@@ -507,6 +534,7 @@
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_NEW_DEVICE;
psmouse->serio = serio;
psmouse->dev.private = psmouse;

@@ -540,6 +568,10 @@
printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);

psmouse_initialize(psmouse);
+
+ synaptics_pt_init(psmouse);
+
+ psmouse_activate(psmouse);
}

static struct serio_dev psmouse_dev = {
@@ -568,9 +600,16 @@
return 1;
}

+static int __init psmouse_resetafter_setup(char *str)
+{
+ get_option(&str, &psmouse_resetafter);
+ return 1;
+}
+
__setup("psmouse_noext", psmouse_noext_setup);
__setup("psmouse_resolution=", psmouse_resolution_setup);
__setup("psmouse_smartscroll=", psmouse_smartscroll_setup);
+__setup("psmouse_resetafter=", psmouse_resetafter_setup);

#endif

diff -Nru a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
--- a/drivers/input/mouse/psmouse.h Fri Sep 19 12:16:32 2003
+++ b/drivers/input/mouse/psmouse.h Fri Sep 19 12:16:32 2003
@@ -13,9 +13,15 @@
#define PSMOUSE_CMD_RESET_BAT 0x02ff

#define PSMOUSE_RET_BAT 0xaa
+#define PSMOUSE_RET_ID 0x00
#define PSMOUSE_RET_ACK 0xfa
#define PSMOUSE_RET_NAK 0xfe

+/* psmouse states */
+#define PSMOUSE_NEW_DEVICE 0
+#define PSMOUSE_ACTIVATED 1
+#define PSMOUSE_IGNORE 2
+
struct psmouse {
void *private;
struct input_dev dev;
@@ -29,6 +35,7 @@
unsigned char type;
unsigned char model;
unsigned long last;
+ unsigned char state;
char acking;
volatile char ack;
char error;
@@ -36,16 +43,17 @@
char phys[32];
};

-#define PSMOUSE_PS2 1
-#define PSMOUSE_PS2PP 2
-#define PSMOUSE_PS2TPP 3
-#define PSMOUSE_GENPS 4
-#define PSMOUSE_IMPS 5
-#define PSMOUSE_IMEX 6
-#define PSMOUSE_SYNAPTICS 7
+#define PSMOUSE_PS2 1
+#define PSMOUSE_PS2PP 2
+#define PSMOUSE_PS2TPP 3
+#define PSMOUSE_GENPS 4
+#define PSMOUSE_IMPS 5
+#define PSMOUSE_IMEX 6
+#define PSMOUSE_SYNAPTICS 7

int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);

extern int psmouse_smartscroll;
+extern unsigned int psmouse_resetafter;

#endif /* _PSMOUSE_H */
diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c Fri Sep 19 12:16:32 2003
+++ b/drivers/input/mouse/synaptics.c Fri Sep 19 12:16:32 2003
@@ -1,6 +1,9 @@
/*
* Synaptics TouchPad PS/2 mouse driver
*
+ * 2003 Dmitry Torokhov <[email protected]>
+ * Added support for pass-through port
+ *
* 2003 Peter Osterlund <[email protected]>
* Ported to 2.5 input device infrastructure.
*
@@ -21,6 +24,7 @@

#include <linux/module.h>
#include <linux/input.h>
+#include <linux/serio.h>
#include "psmouse.h"
#include "synaptics.h"

@@ -71,7 +75,7 @@

if (synaptics_special_cmd(psmouse, mode))
return -1;
- param[0] = 0x14;
+ param[0] = SYN_PS_SET_MODE2;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
return -1;
return 0;
@@ -83,7 +87,7 @@

if (psmouse_command(psmouse, r, PSMOUSE_CMD_RESET_BAT))
return -1;
- if (r[0] == 0xAA && r[1] == 0x00)
+ if (r[0] == PSMOUSE_RET_BAT && r[1] == PSMOUSE_RET_ID)
return 0;
return -1;
}
@@ -106,16 +110,25 @@
* Read the capability-bits from the touchpad
* see also the SYN_CAP_* macros
*/
-static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability)
+static int synaptics_capability(struct psmouse *psmouse, unsigned long int *capability, unsigned long int *ext_cap)
{
unsigned char cap[3];

if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap))
return -1;
*capability = (cap[0]<<16) | (cap[1]<<8) | cap[2];
- if (SYN_CAP_VALID(*capability))
- return 0;
- return -1;
+ *ext_cap = 0;
+ if (!SYN_CAP_VALID(*capability))
+ return -1;
+
+ if (SYN_EXT_CAP_REQUESTS(*capability)) {
+ if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) {
+ printk(KERN_ERR "Synaptics claims to have extended capabilities,"
+ " but I'm not able to read them.");
+ } else
+ *ext_cap = (cap[0]<<16) | (cap[1]<<8) | cap[2];
+ }
+ return 0;
}

/*
@@ -134,19 +147,11 @@
return -1;
}

-static int synaptics_enable_device(struct psmouse *psmouse)
-{
- if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
- return -1;
- return 0;
-}
-
static void print_ident(struct synaptics_data *priv)
{
printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity));
printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity),
SYN_ID_MINOR(priv->identity));
-
if (SYN_MODEL_ROT180(priv->model_id))
printk(KERN_INFO " 180 degree mounted touchpad\n");
if (SYN_MODEL_PORTRAIT(priv->model_id))
@@ -159,12 +164,17 @@

if (SYN_CAP_EXTENDED(priv->capabilities)) {
printk(KERN_INFO " Touchpad has extended capability bits\n");
- if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
+ if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+ printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n",
+ (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)));
+ else if (SYN_CAP_FOUR_BUTTON(priv->capabilities))
printk(KERN_INFO " -> four buttons\n");
if (SYN_CAP_MULTIFINGER(priv->capabilities))
printk(KERN_INFO " -> multifinger detection\n");
if (SYN_CAP_PALMDETECT(priv->capabilities))
printk(KERN_INFO " -> palm detection\n");
+ if (SYN_CAP_PASS_THROUGH(priv->capabilities))
+ printk(KERN_INFO " -> pass-through port\n");
}
}

@@ -172,6 +182,7 @@
{
struct synaptics_data *priv = psmouse->private;
int retries = 0;
+ int mode;

while ((retries++ < 3) && synaptics_reset(psmouse))
printk(KERN_ERR "synaptics reset failed\n");
@@ -180,17 +191,107 @@
return -1;
if (synaptics_model_id(psmouse, &priv->model_id))
return -1;
- if (synaptics_capability(psmouse, &priv->capabilities))
+ if (synaptics_capability(psmouse, &priv->capabilities, &priv->ext_cap))
return -1;
- if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
- SYN_BIT_HIGH_RATE |
- SYN_BIT_DISABLE_GESTURE |
- SYN_BIT_W_MODE)))
+
+ mode = SYN_BIT_ABSOLUTE_MODE | SYN_BIT_HIGH_RATE;
+ if (SYN_ID_MAJOR(priv->identity) >= 4)
+ mode |= SYN_BIT_DISABLE_GESTURE;
+ if (SYN_CAP_EXTENDED(priv->capabilities))
+ mode |= SYN_BIT_W_MODE;
+ if (synaptics_set_mode(psmouse, mode))
return -1;

- synaptics_enable_device(psmouse);
+ return 0;
+}

- print_ident(priv);
+/*****************************************************************************
+ * Synaptics pass-through PS/2 port support
+ ****************************************************************************/
+static int synaptics_pt_open(struct serio *port)
+{
+ return 0;
+}
+
+static void synaptics_pt_close(struct serio *port)
+{
+}
+
+static int synaptics_pt_write(struct serio *port, unsigned char c)
+{
+ struct psmouse *parent = port->driver;
+ char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */
+
+ if (synaptics_special_cmd(parent, c))
+ return -1;
+ if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
+ return -1;
+ return 0;
+}
+
+static inline int synaptics_is_pt_packet(unsigned char *buf)
+{
+ return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
+}
+
+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);
+ }
+ }
+}
+
+int synaptics_pt_init(struct psmouse *psmouse)
+{
+ struct synaptics_data *priv = psmouse->private;
+ struct serio *port;
+ struct psmouse *child;
+
+ if (psmouse->type != PSMOUSE_SYNAPTICS)
+ return -1;
+ if (!SYN_CAP_EXTENDED(priv->capabilities))
+ return -1;
+ if (!SYN_CAP_PASS_THROUGH(priv->capabilities))
+ return -1;
+
+ priv->ptport = port = kmalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!port) {
+ printk(KERN_ERR "synaptics: not enough memory to allocate serio port\n");
+ return -1;
+ }
+
+ memset(port, 0, sizeof(struct serio));
+ port->type = SERIO_PS_PSTHRU;
+ port->name = "Synaptics pass-through";
+ port->phys = "synaptics-pt/serio0";
+ port->write = synaptics_pt_write;
+ port->open = synaptics_pt_open;
+ port->close = synaptics_pt_close;
+ port->driver = psmouse;
+
+ printk(KERN_INFO "serio: %s port at %s\n", port->name, psmouse->phys);
+ serio_register_slave_port(port);
+
+ /* adjust the touchpad to child's choice of protocol */
+ child = port->private;
+ if (child && child->type >= PSMOUSE_GENPS) {
+ if (synaptics_set_mode(psmouse, (SYN_BIT_ABSOLUTE_MODE |
+ SYN_BIT_HIGH_RATE |
+ SYN_BIT_DISABLE_GESTURE |
+ SYN_BIT_FOUR_BYTE_CLIENT |
+ SYN_BIT_W_MODE)))
+ printk(KERN_INFO "synaptics: failed to enable 4-byte guest protocol\n");
+ }

return 0;
}
@@ -213,18 +314,23 @@
{
struct synaptics_data *priv;

+#ifndef CONFIG_MOUSE_PS2_SYNAPTICS
+ return -1;
+#endif
psmouse->private = priv = kmalloc(sizeof(struct synaptics_data), GFP_KERNEL);
if (!priv)
return -1;
memset(priv, 0, sizeof(struct synaptics_data));

- priv->inSync = 1;
+ priv->out_of_sync = 0;

if (query_hardware(psmouse)) {
printk(KERN_ERR "Unable to query/initialize Synaptics hardware.\n");
goto init_fail;
}

+ print_ident(priv);
+
/*
* The x/y limits are taken from the Synaptics TouchPad interfacing Guide,
* which says that they should be valid regardless of the actual size of
@@ -243,7 +349,24 @@
set_bit(BTN_RIGHT, psmouse->dev.keybit);
set_bit(BTN_FORWARD, psmouse->dev.keybit);
set_bit(BTN_BACK, psmouse->dev.keybit);
-
+ if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+ switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
+ default:
+ printk(KERN_ERR "This touchpad reports more than 8 multi-buttons, don't know how to handle.\n");
+ case 8:
+ set_bit(BTN_7, psmouse->dev.keybit);
+ set_bit(BTN_6, psmouse->dev.keybit);
+ case 6:
+ set_bit(BTN_5, psmouse->dev.keybit);
+ set_bit(BTN_4, psmouse->dev.keybit);
+ case 4:
+ set_bit(BTN_3, psmouse->dev.keybit);
+ set_bit(BTN_2, psmouse->dev.keybit);
+ case 2:
+ set_bit(BTN_1, psmouse->dev.keybit);
+ set_bit(BTN_0, psmouse->dev.keybit);
+ break;
+ }
clear_bit(EV_REL, psmouse->dev.evbit);
clear_bit(REL_X, psmouse->dev.relbit);
clear_bit(REL_Y, psmouse->dev.relbit);
@@ -259,45 +382,85 @@
{
struct synaptics_data *priv = psmouse->private;

- /* Restore touchpad to power on default state */
- synaptics_set_mode(psmouse, 0);
-
- kfree(priv);
+ if (psmouse->type == PSMOUSE_SYNAPTICS && priv) {
+ synaptics_set_mode(psmouse, 0);
+ if (priv->ptport) {
+ serio_unregister_slave_port(priv->ptport);
+ kfree(priv->ptport);
+ }
+ kfree(priv);
+ }
}

/*****************************************************************************
* Functions to interpret the absolute mode packets
****************************************************************************/

-static void synaptics_parse_hw_state(struct synaptics_data *priv, struct synaptics_hw_state *hw)
+static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
{
- unsigned char *buf = priv->proto_buf;
-
- hw->x = (((buf[3] & 0x10) << 8) |
- ((buf[1] & 0x0f) << 8) |
- buf[4]);
- hw->y = (((buf[3] & 0x20) << 7) |
- ((buf[1] & 0xf0) << 4) |
- buf[5]);
-
- hw->z = buf[2];
- hw->w = (((buf[0] & 0x30) >> 2) |
- ((buf[0] & 0x04) >> 1) |
- ((buf[3] & 0x04) >> 2));
-
- hw->left = (buf[0] & 0x01) ? 1 : 0;
- hw->right = (buf[0] & 0x2) ? 1 : 0;
hw->up = 0;
hw->down = 0;
+ hw->b0 = 0;
+ hw->b1 = 0;
+ hw->b2 = 0;
+ hw->b3 = 0;
+ hw->b4 = 0;
+ hw->b5 = 0;
+ hw->b6 = 0;
+ hw->b7 = 0;
+
+ if (SYN_MODEL_NEWABS(priv->model_id)) {
+ hw->x = (((buf[3] & 0x10) << 8) |
+ ((buf[1] & 0x0f) << 8) |
+ buf[4]);
+ hw->y = (((buf[3] & 0x20) << 7) |
+ ((buf[1] & 0xf0) << 4) |
+ buf[5]);
+
+ hw->z = buf[2];
+ hw->w = (((buf[0] & 0x30) >> 2) |
+ ((buf[0] & 0x04) >> 1) |
+ ((buf[3] & 0x04) >> 2));
+
+ hw->left = (buf[0] & 0x01) ? 1 : 0;
+ hw->right = (buf[0] & 0x02) ? 1 : 0;
+ if (SYN_CAP_EXTENDED(priv->capabilities) &&
+ (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
+ hw->up = ((buf[3] & 0x01)) ? 1 : 0;
+ if (hw->left)
+ hw->up = !hw->up;
+ hw->down = ((buf[3] & 0x02)) ? 1 : 0;
+ if (hw->right)
+ hw->down = !hw->down;
+ }
+ if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
+ ((buf[3] & 2) ? !hw->right : hw->right)) {
+ switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
+ default:
+ ; /* we did comment while initialising... */
+ case 8:
+ hw->b7 = ((buf[5] & 0x08)) ? 1 : 0;
+ hw->b6 = ((buf[4] & 0x08)) ? 1 : 0;
+ case 6:
+ hw->b5 = ((buf[5] & 0x04)) ? 1 : 0;
+ hw->b4 = ((buf[4] & 0x04)) ? 1 : 0;
+ case 4:
+ hw->b3 = ((buf[5] & 0x02)) ? 1 : 0;
+ hw->b2 = ((buf[4] & 0x02)) ? 1 : 0;
+ case 2:
+ hw->b1 = ((buf[5] & 0x01)) ? 1 : 0;
+ hw->b0 = ((buf[4] & 0x01)) ? 1 : 0;
+ }
+ }
+ } else {
+ hw->x = (((buf[1] & 0x1f) << 8) | buf[2]);
+ hw->y = (((buf[4] & 0x1f) << 8) | buf[5]);

- if (SYN_CAP_EXTENDED(priv->capabilities) &&
- (SYN_CAP_FOUR_BUTTON(priv->capabilities))) {
- hw->up = ((buf[3] & 0x01)) ? 1 : 0;
- if (hw->left)
- hw->up = !hw->up;
- hw->down = ((buf[3] & 0x02)) ? 1 : 0;
- if (hw->right)
- hw->down = !hw->down;
+ hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F));
+ hw->w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1));
+
+ hw->left = (buf[0] & 0x01) ? 1 : 0;
+ hw->right = (buf[0] & 0x02) ? 1 : 0;
}
}

@@ -310,7 +473,7 @@
struct synaptics_data *priv = psmouse->private;
struct synaptics_hw_state hw;

- synaptics_parse_hw_state(priv, &hw);
+ synaptics_parse_hw_state(psmouse->packet, priv, &hw);

if (hw.z > 0) {
int w_ok = 0;
@@ -350,7 +513,24 @@
input_report_key(dev, BTN_RIGHT, hw.right);
input_report_key(dev, BTN_FORWARD, hw.up);
input_report_key(dev, BTN_BACK, hw.down);
-
+ if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))
+ switch(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
+ default:
+ ; /* we did comment while initialising... */
+ case 8:
+ input_report_key(dev, BTN_7, hw.b7);
+ input_report_key(dev, BTN_6, hw.b6);
+ case 6:
+ input_report_key(dev, BTN_5, hw.b5);
+ input_report_key(dev, BTN_4, hw.b4);
+ case 4:
+ input_report_key(dev, BTN_3, hw.b3);
+ input_report_key(dev, BTN_2, hw.b2);
+ case 2:
+ input_report_key(dev, BTN_1, hw.b1);
+ input_report_key(dev, BTN_0, hw.b0);
+ break;
+ }
input_sync(dev);
}

@@ -358,35 +538,59 @@
{
struct input_dev *dev = &psmouse->dev;
struct synaptics_data *priv = psmouse->private;
- unsigned char *pBuf = priv->proto_buf;
- unsigned char u = psmouse->packet[0];
+ unsigned char data = psmouse->packet[psmouse->pktcnt - 1];
+ int newabs = SYN_MODEL_NEWABS(priv->model_id);

input_regs(dev, regs);

- pBuf[priv->proto_buf_tail++] = u;
+ switch (psmouse->pktcnt) {
+ case 1:
+ if (newabs ? ((data & 0xC8) != 0x80) : ((data & 0xC0) != 0xC0)) {
+ printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
+ goto bad_sync;
+ }
+ break;
+ case 2:
+ if (!newabs && ((data & 0x60) != 0x00)) {
+ printk(KERN_WARNING "Synaptics driver lost sync at 2nd byte\n");
+ goto bad_sync;
+ }
+ break;
+ case 4:
+ if (newabs ? ((data & 0xC8) != 0xC0) : ((data & 0xC0) != 0x80)) {
+ printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
+ goto bad_sync;
+ }
+ break;
+ case 5:
+ if (!newabs && ((data & 0x60) != 0x00)) {
+ printk(KERN_WARNING "Synaptics driver lost sync at 5th byte\n");
+ goto bad_sync;
+ }
+ break;
+ default:
+ if (psmouse->pktcnt >= 6) { /* Full packet received */
+ if (priv->out_of_sync) {
+ priv->out_of_sync = 0;
+ printk(KERN_NOTICE "Synaptics driver resynced.\n");
+ }
+
+ if (priv->ptport && synaptics_is_pt_packet(psmouse->packet))
+ synaptics_pass_pt_packet(priv->ptport, psmouse->packet);
+ else
+ synaptics_process_packet(psmouse);

- /* check first byte */
- if ((priv->proto_buf_tail == 1) && ((u & 0xC8) != 0x80)) {
- priv->inSync = 0;
- priv->proto_buf_tail = 0;
- printk(KERN_WARNING "Synaptics driver lost sync at 1st byte\n");
- return;
- }
-
- /* check 4th byte */
- if ((priv->proto_buf_tail == 4) && ((u & 0xc8) != 0xc0)) {
- priv->inSync = 0;
- priv->proto_buf_tail = 0;
- printk(KERN_WARNING "Synaptics driver lost sync at 4th byte\n");
- return;
- }
-
- if (priv->proto_buf_tail >= 6) { /* Full packet received */
- if (!priv->inSync) {
- priv->inSync = 1;
- printk(KERN_NOTICE "Synaptics driver resynced.\n");
+ psmouse->pktcnt = 0;
}
- synaptics_process_packet(psmouse);
- priv->proto_buf_tail = 0;
+ break;
+ }
+ return;
+
+ bad_sync:
+ priv->out_of_sync++;
+ psmouse->pktcnt = 0;
+ if (psmouse_resetafter > 0 && priv->out_of_sync == psmouse_resetafter) {
+ psmouse->state = PSMOUSE_IGNORE;
+ serio_rescan(psmouse->serio);
}
}
diff -Nru a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
--- a/drivers/input/mouse/synaptics.h Fri Sep 19 12:16:32 2003
+++ b/drivers/input/mouse/synaptics.h Fri Sep 19 12:16:32 2003
@@ -12,6 +12,7 @@

extern void synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs);
extern int synaptics_init(struct psmouse *psmouse);
+extern int synaptics_pt_init(struct psmouse *psmouse);
extern void synaptics_disconnect(struct psmouse *psmouse);

/* synaptics queries */
@@ -22,12 +23,14 @@
#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06
#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07
#define SYN_QUE_RESOLUTION 0x08
+#define SYN_QUE_EXT_CAPAB 0x09

/* synatics modes */
#define SYN_BIT_ABSOLUTE_MODE (1 << 7)
#define SYN_BIT_HIGH_RATE (1 << 6)
#define SYN_BIT_SLEEP_MODE (1 << 3)
#define SYN_BIT_DISABLE_GESTURE (1 << 2)
+#define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1)
#define SYN_BIT_W_MODE (1 << 0)

/* synaptics model ID bits */
@@ -42,11 +45,14 @@

/* synaptics capability bits */
#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23))
+#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7))
#define SYN_CAP_SLEEP(c) ((c) & (1 << 4))
#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
+#define SYN_EXT_CAP_REQUESTS(c) ((((c) & 0x700000) >> 20) == 1)
+#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)

/* synaptics modes query bits */
#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7))
@@ -62,6 +68,10 @@
#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)

+/* synaptics special commands */
+#define SYN_PS_SET_MODE2 0x14
+#define SYN_PS_CLIENT_CMD 0x28
+
/*
* A structure to describe the state of the touchpad hardware (buttons and pad)
*/
@@ -75,21 +85,28 @@
int right;
int up;
int down;
+ int b0;
+ int b1;
+ int b2;
+ int b3;
+ int b4;
+ int b5;
+ int b6;
+ int b7;
};

struct synaptics_data {
/* Data read from the touchpad */
unsigned long int model_id; /* Model-ID */
unsigned long int capabilities; /* Capabilities */
+ unsigned long int ext_cap; /* Extended Capabilities */
unsigned long int identity; /* Identification */

/* Data for normal processing */
- unsigned char proto_buf[6]; /* Buffer for Packet */
- unsigned char last_byte; /* last received byte */
- int inSync; /* Packets in sync */
- int proto_buf_tail;
-
+ unsigned int out_of_sync; /* # of packets out of sync */
int old_w; /* Previous w value */
+
+ struct serio *ptport; /* pass-through port */
};

#endif /* _SYNAPTICS_H */
diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c Fri Sep 19 12:16:32 2003
+++ b/drivers/input/serio/serio.c Fri Sep 19 12:16:32 2003
@@ -49,7 +49,9 @@

EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(serio_register_port);
+EXPORT_SYMBOL(serio_register_slave_port);
EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_slave_port);
EXPORT_SYMBOL(serio_register_device);
EXPORT_SYMBOL(serio_unregister_device);
EXPORT_SYMBOL(serio_open);
@@ -166,6 +168,17 @@
up(&serio_sem);
}

+/*
+ * Same as serio_register_port but does not try to acquire serio_sem.
+ * Should be used when registering a serio from other input device's
+ * connect() function.
+ */
+void serio_register_slave_port(struct serio *serio)
+{
+ list_add_tail(&serio->node, &serio_list);
+ serio_find_dev(serio);
+}
+
void serio_unregister_port(struct serio *serio)
{
down(&serio_sem);
@@ -173,6 +186,18 @@
if (serio->dev && serio->dev->disconnect)
serio->dev->disconnect(serio);
up(&serio_sem);
+}
+
+/*
+ * Same as serio_unregister_port but does not try to acquire serio_sem.
+ * Should be used when unregistering a serio from other input device's
+ * disconnect() function.
+ */
+void serio_unregister_slave_port(struct serio *serio)
+{
+ list_del_init(&serio->node);
+ if (serio->dev && serio->dev->disconnect)
+ serio->dev->disconnect(serio);
}

void serio_register_device(struct serio_dev *dev)
diff -Nru a/include/linux/serio.h b/include/linux/serio.h
--- a/include/linux/serio.h Fri Sep 19 12:16:32 2003
+++ b/include/linux/serio.h Fri Sep 19 12:16:32 2003
@@ -65,7 +65,9 @@
irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);

void serio_register_port(struct serio *serio);
+void serio_register_slave_port(struct serio *serio);
void serio_unregister_port(struct serio *serio);
+void serio_unregister_slave_port(struct serio *serio);
void serio_register_device(struct serio_dev *dev);
void serio_unregister_device(struct serio_dev *dev);

@@ -104,6 +106,7 @@
#define SERIO_RS232 0x02000000UL
#define SERIO_HIL_MLC 0x03000000UL
#define SERIO_PC9800 0x04000000UL
+#define SERIO_PS_PSTHRU 0x05000000UL

#define SERIO_PROTO 0xFFUL
#define SERIO_MSC 0x01

2003-09-19 10:28:32

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 11/11] input: Claim serio early in serio_open()

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 01:25:39-07:00, [email protected]
serio.c:
claim serio early in serio_open()


serio.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)

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

diff -Nru a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
--- a/drivers/input/serio/serio.c Fri Sep 19 12:15:39 2003
+++ b/drivers/input/serio/serio.c Fri Sep 19 12:15:39 2003
@@ -229,9 +229,11 @@
/* called from serio_dev->connect/disconnect methods under serio_sem */
int serio_open(struct serio *serio, struct serio_dev *dev)
{
- if (serio->open(serio))
- return -1;
serio->dev = dev;
+ if (serio->open(serio)) {
+ serio->dev = NULL;
+ return -1;
+ }
return 0;
}


2003-09-19 10:31:29

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 3/11] input: Fix Sega Saturn pad support

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 01:01:20-07:00, [email protected]
db9.c:
input: Fix Sega Saturn pad support.


db9.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 269 insertions(+), 44 deletions(-)

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

diff -Nru a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
--- a/drivers/input/joystick/db9.c Fri Sep 19 12:16:39 2003
+++ b/drivers/input/joystick/db9.c Fri Sep 19 12:16:39 2003
@@ -55,7 +55,9 @@
#define DB9_MULTI_0802 0x08
#define DB9_MULTI_0802_2 0x09
#define DB9_CD32_PAD 0x0A
-#define DB9_MAX_PAD 0x0B
+#define DB9_SATURN_DPP 0x0B
+#define DB9_SATURN_DPP_2 0x0C
+#define DB9_MAX_PAD 0x0D

#define DB9_UP 0x01
#define DB9_DOWN 0x02
@@ -69,10 +71,7 @@
#define DB9_NORMAL 0x0a
#define DB9_NOSELECT 0x08

-#define DB9_SATURN0 0x00
-#define DB9_SATURN1 0x02
-#define DB9_SATURN2 0x04
-#define DB9_SATURN3 0x06
+#define DB9_MAX_DEVICES 2

#define DB9_GENESIS6_DELAY 14
#define DB9_REFRESH_TIME HZ/100
@@ -82,7 +81,7 @@
static int db9_3[] __initdata = { -1, 0 };

struct db9 {
- struct input_dev dev[2];
+ struct input_dev dev[DB9_MAX_DEVICES];
struct timer_list timer;
struct pardevice *pd;
int mode;
@@ -96,12 +95,247 @@
static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };

-static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 };
+static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 9, 1, 1, 7, 9, 9 };
static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn,
- db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn };
+ db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn,
+ db9_cd32_btn, db9_cd32_btn };
static char *db9_name[DB9_MAX_PAD] = { NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
- "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad" };
+ "Multisystem (0.8.0.2-dual) joystick", "Amiga CD-32 pad", "Saturn dpp", "Saturn dpp dual" };
+
+static const int db9_max_pads[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 6, 1, 2, 1, 6, 12 };
+static const int db9_num_axis[DB9_MAX_PAD] = { 0, 2, 2, 2, 0, 2, 2, 7, 2, 2, 2 ,7, 7 };
+static const short db9_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_RZ, ABS_Z, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
+static const int db9_bidirectional[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0 };
+static const int db9_reverse[DB9_MAX_PAD] = { 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0 };
+
+/*
+ * Saturn controllers
+ */
+#define DB9_SATURN_DELAY 300
+static const int db9_saturn_byte[] = { 1, 1, 1, 2, 2, 2, 2, 2, 1 };
+static const unsigned char db9_saturn_mask[] = { 0x04, 0x01, 0x02, 0x40, 0x20, 0x10, 0x08, 0x80, 0x08 };
+
+/*
+ * db9_saturn_write_sub() writes 2 bit data.
+ */
+static void db9_saturn_write_sub(struct parport *port, int type, unsigned char data, int powered, int pwr_sub)
+{
+ unsigned char c;
+
+ switch (type) {
+ case 1: /* DPP1 */
+ c = 0x80 | 0x30 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | data;
+ parport_write_data(port, c);
+ break;
+ case 2: /* DPP2 */
+ c = 0x40 | data << 4 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | 0x03;
+ parport_write_data(port, c);
+ break;
+ case 0: /* DB9 */
+ c = ((((data & 2) ? 2 : 0) | ((data & 1) ? 4 : 0)) ^ 0x02) | !powered;
+ parport_write_control(port, c);
+ break;
+ }
+}
+
+/*
+ * gc_saturn_read_sub() reads 4 bit data.
+ */
+static unsigned char db9_saturn_read_sub(struct parport *port, int type)
+{
+ unsigned char data;
+
+ if (type) {
+ /* DPP */
+ data = parport_read_status(port) ^ 0x80;
+ return (data & 0x80 ? 1 : 0) | (data & 0x40 ? 2 : 0)
+ | (data & 0x20 ? 4 : 0) | (data & 0x10 ? 8 : 0);
+ } else {
+ /* DB9 */
+ data = parport_read_data(port) & 0x0f;
+ return (data & 0x8 ? 1 : 0) | (data & 0x4 ? 2 : 0)
+ | (data & 0x2 ? 4 : 0) | (data & 0x1 ? 8 : 0);
+ }
+}
+
+/*
+ * db9_saturn_read_analog() sends clock and reads 8 bit data.
+ */
+static unsigned char db9_saturn_read_analog(struct parport *port, int type, int powered)
+{
+ unsigned char data;
+
+ db9_saturn_write_sub(port, type, 0, powered, 0);
+ udelay(DB9_SATURN_DELAY);
+ data = db9_saturn_read_sub(port, type) << 4;
+ db9_saturn_write_sub(port, type, 2, powered, 0);
+ udelay(DB9_SATURN_DELAY);
+ data |= db9_saturn_read_sub(port, type);
+ return data;
+}
+
+/*
+ * db9_saturn_read_packet() reads whole saturn packet at connector
+ * and returns device identifier code.
+ */
+static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char *data, int type, int powered)
+{
+ int i, j;
+ unsigned char tmp;
+
+ db9_saturn_write_sub(port, type, 3, powered, 0);
+ data[0] = db9_saturn_read_sub(port, type);
+ switch (data[0] & 0x0f) {
+ case 0xf:
+ /* 1111 no pad */
+ return data[0] = 0xff;
+ case 0x4: case 0x4 | 0x8:
+ /* ?100 : digital controller */
+ db9_saturn_write_sub(port, type, 0, powered, 1);
+ data[2] = db9_saturn_read_sub(port, type) << 4;
+ db9_saturn_write_sub(port, type, 2, powered, 1);
+ data[1] = db9_saturn_read_sub(port, type) << 4;
+ db9_saturn_write_sub(port, type, 1, powered, 1);
+ data[1] |= db9_saturn_read_sub(port, type);
+ db9_saturn_write_sub(port, type, 3, powered, 1);
+ /* data[2] |= db9_saturn_read_sub(port, type); */
+ data[2] |= data[0];
+ return data[0] = 0x02;
+ case 0x1:
+ /* 0001 : analog controller or multitap */
+ db9_saturn_write_sub(port, type, 2, powered, 0);
+ udelay(DB9_SATURN_DELAY);
+ data[0] = db9_saturn_read_analog(port, type, powered);
+ if (data[0] != 0x41) {
+ /* read analog controller */
+ for (i = 0; i < (data[0] & 0x0f); i++)
+ data[i + 1] = db9_saturn_read_analog(port, type, powered);
+ db9_saturn_write_sub(port, type, 3, powered, 0);
+ return data[0];
+ } else {
+ /* read multitap */
+ if (db9_saturn_read_analog(port, type, powered) != 0x60)
+ return data[0] = 0xff;
+ for (i = 0; i < 60; i += 10) {
+ data[i] = db9_saturn_read_analog(port, type, powered);
+ if (data[i] != 0xff)
+ /* read each pad */
+ for (j = 0; j < (data[i] & 0x0f); j++)
+ data[i + j + 1] = db9_saturn_read_analog(port, type, powered);
+ }
+ db9_saturn_write_sub(port, type, 3, powered, 0);
+ return 0x41;
+ }
+ case 0x0:
+ /* 0000 : mouse */
+ db9_saturn_write_sub(port, type, 2, powered, 0);
+ udelay(DB9_SATURN_DELAY);
+ tmp = db9_saturn_read_analog(port, type, powered);
+ if (tmp == 0xff) {
+ for (i = 0; i < 3; i++)
+ data[i + 1] = db9_saturn_read_analog(port, type, powered);
+ db9_saturn_write_sub(port, type, 3, powered, 0);
+ return data[0] = 0xe3;
+ }
+ default:
+ return data[0];
+ }
+}
+
+/*
+ * db9_saturn_report() analyzes packet and reports.
+ */
+static int db9_saturn_report(unsigned char id, unsigned char data[60], struct input_dev *dev, int n, int max_pads)
+{
+ int tmp, i, j;
+
+ tmp = (id == 0x41) ? 60 : 10;
+ for (j = 0; (j < tmp) && (n < max_pads); j += 10, n++) {
+ switch (data[j]) {
+ case 0x16: /* multi controller (analog 4 axis) */
+ input_report_abs(dev + n, db9_abs[5], data[j + 6]);
+ case 0x15: /* mission stick (analog 3 axis) */
+ input_report_abs(dev + n, db9_abs[3], data[j + 4]);
+ input_report_abs(dev + n, db9_abs[4], data[j + 5]);
+ case 0x13: /* racing controller (analog 1 axis) */
+ input_report_abs(dev + n, db9_abs[2], data[j + 3]);
+ case 0x34: /* saturn keyboard (udlr ZXC ASD QE Esc) */
+ case 0x02: /* digital pad (digital 2 axis + buttons) */
+ input_report_abs(dev + n, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
+ input_report_abs(dev + n, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16));
+ for (i = 0; i < 9; i++)
+ input_report_key(dev + n, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]);
+ break;
+ case 0x19: /* mission stick x2 (analog 6 axis + buttons) */
+ input_report_abs(dev + n, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
+ input_report_abs(dev + n, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16));
+ for (i = 0; i < 9; i++)
+ input_report_key(dev + n, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]);
+ input_report_abs(dev + n, db9_abs[2], data[j + 3]);
+ input_report_abs(dev + n, db9_abs[3], data[j + 4]);
+ input_report_abs(dev + n, db9_abs[4], data[j + 5]);
+ /*
+ input_report_abs(dev + n, db9_abs[8], (data[j + 6] & 128 ? 0 : 1) - (data[j + 6] & 64 ? 0 : 1));
+ input_report_abs(dev + n, db9_abs[9], (data[j + 6] & 32 ? 0 : 1) - (data[j + 6] & 16 ? 0 : 1));
+ */
+ input_report_abs(dev + n, db9_abs[6], data[j + 7]);
+ input_report_abs(dev + n, db9_abs[7], data[j + 8]);
+ input_report_abs(dev + n, db9_abs[5], data[j + 9]);
+ break;
+ case 0xd3: /* sankyo ff (analog 1 axis + stop btn) */
+ input_report_key(dev + n, BTN_A, data[j + 3] & 0x80);
+ input_report_abs(dev + n, db9_abs[2], data[j + 3] & 0x7f);
+ break;
+ case 0xe3: /* shuttle mouse (analog 2 axis + buttons. signed value) */
+ input_report_key(dev + n, BTN_START, data[j + 1] & 0x08);
+ input_report_key(dev + n, BTN_A, data[j + 1] & 0x04);
+ input_report_key(dev + n, BTN_C, data[j + 1] & 0x02);
+ input_report_key(dev + n, BTN_B, data[j + 1] & 0x01);
+ input_report_abs(dev + n, db9_abs[2], data[j + 2] ^ 0x80);
+ input_report_abs(dev + n, db9_abs[3], (0xff-(data[j + 3] ^ 0x80))+1); /* */
+ break;
+ case 0xff:
+ default: /* no pad */
+ input_report_abs(dev + n, db9_abs[0], 0);
+ input_report_abs(dev + n, db9_abs[1], 0);
+ for (i = 0; i < 9; i++)
+ input_report_key(dev + n, db9_cd32_btn[i], 0);
+ break;
+ }
+ }
+ return n;
+}
+
+static int db9_saturn(int mode, struct parport *port, struct input_dev *dev)
+{
+ unsigned char id, data[60];
+ int type, n, max_pads;
+ int tmp, i;
+
+ switch (mode) {
+ case DB9_SATURN_PAD:
+ type = 0;
+ n = 1;
+ break;
+ case DB9_SATURN_DPP:
+ type = 1;
+ n = 1;
+ break;
+ case DB9_SATURN_DPP_2:
+ type = 1;
+ n = 2;
+ break;
+ default:
+ return -1;
+ }
+ max_pads = min(db9_max_pads[mode], DB9_MAX_DEVICES);
+ for (tmp = 0, i = 0; i < n; i++) {
+ id = db9_saturn_read_packet(port, data, type + i, 1);
+ tmp = db9_saturn_report(id, data, dev, tmp, max_pads);
+ }
+ return 0;
+}

static void db9_timer(unsigned long private)
{
@@ -222,28 +456,10 @@
break;

case DB9_SATURN_PAD:
+ case DB9_SATURN_DPP:
+ case DB9_SATURN_DPP_2:

- parport_write_control(port, DB9_SATURN0);
- data = parport_read_data(port);
-
- input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
- input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
- input_report_key(dev, BTN_TL, ~data & DB9_UP);
- input_report_key(dev, BTN_TR, ~data & DB9_RIGHT);
-
- parport_write_control(port, DB9_SATURN2);
- data = parport_read_data(port);
-
- input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
-
- parport_write_control(port, DB9_NORMAL);
- data = parport_read_data(port);
-
- input_report_key(dev, BTN_A, ~data & DB9_LEFT);
- input_report_key(dev, BTN_B, ~data & DB9_UP);
- input_report_key(dev, BTN_C, ~data & DB9_DOWN);
- input_report_key(dev, BTN_X, ~data & DB9_RIGHT);
+ db9_saturn(db9->mode, port, dev);
break;

case DB9_CD32_PAD:
@@ -279,8 +495,10 @@
if (!db9->used++) {
parport_claim(db9->pd);
parport_write_data(port, 0xff);
- parport_data_reverse(port);
- parport_write_control(port, DB9_NORMAL);
+ if (db9_reverse[db9->mode]) {
+ parport_data_reverse(port);
+ parport_write_control(port, DB9_NORMAL);
+ }
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
}

@@ -321,11 +539,13 @@
return NULL;
}

- if (!(pp->modes & PARPORT_MODE_TRISTATE) && config[1] != DB9_MULTI_0802) {
- printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
- return NULL;
+ if (db9_bidirectional[config[1]]) {
+ if (!(pp->modes & PARPORT_MODE_TRISTATE)) {
+ printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
+ return NULL;
+ }
}
-
+
if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL)))
return NULL;
memset(db9, 0, sizeof(struct db9));
@@ -343,7 +563,7 @@
return NULL;
}

- for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) {
+ for (i = 0; i < (min(db9_max_pads[db9->mode], DB9_MAX_DEVICES)); i++) {

sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i);

@@ -359,14 +579,19 @@
db9->dev[i].id.version = 0x0100;

db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-
for (j = 0; j < db9_buttons[db9->mode]; j++)
set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit);
-
- db9->dev[i].absmin[ABS_X] = -1; db9->dev[i].absmax[ABS_X] = 1;
- db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1;
-
+ for (j = 0; j < db9_num_axis[db9->mode]; j++) {
+ set_bit(db9_abs[j], db9->dev[i].absbit);
+ if (j < 2) {
+ db9->dev[i].absmin[db9_abs[j]] = -1;
+ db9->dev[i].absmax[db9_abs[j]] = 1;
+ } else {
+ db9->dev[i].absmin[db9_abs[j]] = 1;
+ db9->dev[i].absmax[db9_abs[j]] = 255;
+ db9->dev[i].absflat[db9_abs[j]] = 0;
+ }
+ }
input_register_device(db9->dev + i);
printk(KERN_INFO "input: %s on %s\n", db9->dev[i].name, db9->pd->port->name);
}
@@ -419,7 +644,7 @@

for (i = 0; i < 3; i++)
if (db9_base[i]) {
- for (j = 0; j < 1 + (db9_base[i]->mode == DB9_MULTI_0802_2); j++)
+ for (j = 0; j < min(db9_max_pads[db9_base[i]->mode], DB9_MAX_DEVICES); j++)
input_unregister_device(db9_base[i]->dev + j);
parport_unregister_device(db9_base[i]->pd);
}

2003-09-19 10:28:31

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 2/11] input: Forced release of keys on AT kbds

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 00:58:34-07:00, [email protected]
input.c:
input: Don't set autorepeat times in core if already set by driver.
atkbd.c:
input: Automatic forced release of keys if keyrelease gets lost


input.c | 6 +
keyboard/atkbd.c | 173 ++++++++++++++++++++++++++++++-------------------------
2 files changed, 99 insertions(+), 80 deletions(-)

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

diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c Fri Sep 19 12:16:46 2003
+++ b/drivers/input/input.c Fri Sep 19 12:16:46 2003
@@ -426,8 +426,10 @@
init_timer(&dev->timer);
dev->timer.data = (long) dev;
dev->timer.function = input_repeat_key;
- dev->rep[REP_DELAY] = HZ/4;
- dev->rep[REP_PERIOD] = HZ/33;
+ if (!dev->rep[REP_DELAY])
+ dev->rep[REP_DELAY] = HZ/4;
+ if (!dev->rep[REP_PERIOD])
+ dev->rep[REP_PERIOD] = HZ/33;

INIT_LIST_HEAD(&dev->h_list);
list_add_tail(&dev->node, &input_dev_list);
diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
--- a/drivers/input/keyboard/atkbd.c Fri Sep 19 12:16:46 2003
+++ b/drivers/input/keyboard/atkbd.c Fri Sep 19 12:16:46 2003
@@ -18,6 +18,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/workqueue.h>
+#include <linux/timer.h>

MODULE_AUTHOR("Vojtech Pavlik <[email protected]>");
MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
@@ -40,8 +41,8 @@
static unsigned char atkbd_set2_keycode[512] = {
0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41, 85,
0, 56, 42,182, 29, 16, 2, 89, 0, 0, 44, 31, 30, 17, 3, 90,
- 0, 46, 45, 32, 18, 5, 4, 91, 0, 57, 47, 33, 20, 19, 6, 0,
- 0, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
+ 0, 46, 45, 32, 18, 5, 4, 91, 90, 57, 47, 33, 20, 19, 6, 0,
+ 91, 49, 48, 35, 34, 21, 7, 0, 0, 0, 50, 36, 22, 8, 9, 0,
0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
122, 89, 40,120, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 0,
85, 86, 90, 91, 92, 93, 14, 94, 95, 79,183, 75, 71,121, 0,123,
@@ -87,10 +88,10 @@
#define ATKBD_CMD_GSCANSET 0x11f0
#define ATKBD_CMD_SSCANSET 0x10f0
#define ATKBD_CMD_GETID 0x02f2
+#define ATKBD_CMD_SETREP 0x10f3
#define ATKBD_CMD_ENABLE 0x00f4
#define ATKBD_CMD_RESET_DIS 0x00f5
#define ATKBD_CMD_RESET_BAT 0x02ff
-#define ATKBD_CMD_SETALL_MB 0x00f8
#define ATKBD_CMD_RESEND 0x00fe
#define ATKBD_CMD_EX_ENABLE 0x10ea
#define ATKBD_CMD_EX_SETLEDS 0x20eb
@@ -114,12 +115,14 @@
unsigned char keycode[512];
struct input_dev dev;
struct serio *serio;
+ struct timer_list timer;
char name[64];
char phys[32];
unsigned char cmdbuf[4];
unsigned char cmdcnt;
unsigned char set;
unsigned char release;
+ int lastkey;
volatile signed char ack;
unsigned char emul;
unsigned short id;
@@ -142,6 +145,7 @@
printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
#endif

+#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);
serio_write(serio, ATKBD_CMD_RESEND);
@@ -151,6 +155,7 @@

if (!flags)
atkbd->resend = 0;
+#endif

switch (code) {
case ATKBD_RET_ACK:
@@ -195,6 +200,14 @@
atkbd->set, code, serio->phys, atkbd->release ? "released" : "pressed");
break;
default:
+
+ if (!atkbd->release) {
+ mod_timer(&atkbd->timer,
+ jiffies + (test_bit(atkbd->keycode[code],
+ &atkbd->dev.key) ? HZ/33 : HZ/4) + HZ/100);
+ atkbd->lastkey = atkbd->keycode[code];
+ }
+
input_regs(&atkbd->dev, regs);
input_report_key(&atkbd->dev, atkbd->keycode[code], !atkbd->release);
input_sync(&atkbd->dev);
@@ -205,6 +218,13 @@
return IRQ_HANDLED;
}

+static void atkbd_force_key_up(unsigned long data)
+{
+ struct atkbd *atkbd = (void *) data;
+ input_report_key(&atkbd->dev, atkbd->lastkey, 0);
+ input_sync(&atkbd->dev);
+}
+
/*
* atkbd_sendbyte() sends a byte to the keyboard, and waits for
* acknowledge. It doesn't handle resends according to the keyboard
@@ -214,7 +234,7 @@

static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
{
- int timeout = 10000; /* 100 msec */
+ int timeout = 20000; /* 200 msec */
atkbd->ack = 0;

#ifdef ATKBD_DEBUG
@@ -322,13 +342,50 @@
}

/*
- * Enable keyboard.
+ * atkbd_probe() probes for an AT keyboard on a serio port.
*/
-static void atkbd_enable(struct atkbd *atkbd)
+
+static int atkbd_probe(struct atkbd *atkbd)
{
- if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE))
- printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
- atkbd->serio->phys);
+ unsigned char param[2];
+
+/*
+ * Some systems, where the bit-twiddling when testing the io-lines of the
+ * controller may confuse the keyboard need a full reset of the keyboard. On
+ * these systems the BIOS also usually doesn't do it for us.
+ */
+
+ if (atkbd_reset)
+ if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
+ printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", atkbd->serio->phys);
+
+/*
+ * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
+ * Some keyboards report different values, but the first byte is always 0xab or
+ * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this
+ * should make sure we don't try to set the LEDs on it.
+ */
+
+ if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) {
+
+/*
+ * If the get ID command failed, we check if we can at least set the LEDs on
+ * the keyboard. This should work on every keyboard out there. It also turns
+ * the LEDs off, which we want anyway.
+ */
+ param[0] = 0;
+ if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+ return -1;
+ atkbd->id = 0xabba;
+ return 0;
+ }
+
+ if (param[0] != 0xab && param[0] != 0xac)
+ return -1;
+ atkbd->id = (param[0] << 8) | param[1];
+
+
+ return 0;
}

/*
@@ -365,103 +422,57 @@
return 4;
}

-/*
- * Try to set the set we want.
- */
+ if (atkbd_set != 3)
+ return 2;

- param[0] = atkbd_set;
+ param[0] = 3;
if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
return 2;

-/*
- * Read set number. Beware here. Some keyboards always send '2'
- * or some other number regardless into what mode they have been
- * attempted to be set. Other keyboards treat the '0' command as
- * 'set to set 0', and not 'report current set' as they should.
- * In that case we time out, and return 2.
- */
-
param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_GSCANSET))
return 2;

-/*
- * Here we return the set number the keyboard reports about
- * itself.
- */
+ if (param[0] != 3)
+ return 2;

- return (param[0] == 3) ? 3 : 2;
+ return 3;
}

-/*
- * atkbd_probe() probes for an AT keyboard on a serio port.
- */
-
-static int atkbd_probe(struct atkbd *atkbd)
+static int atkbd_enable(struct atkbd *atkbd)
{
- unsigned char param[2];
+ unsigned char param[1];

/*
- * Some systems, where the bit-twiddling when testing the io-lines of the
- * controller may confuse the keyboard need a full reset of the keyboard. On
- * these systems the BIOS also usually doesn't do it for us.
+ * Set the LEDs to a defined state.
*/

- if (atkbd_reset)
- if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
- printk(KERN_WARNING
- "atkbd.c: keyboard reset failed on %s\n",
- atkbd->serio->phys);
+ param[0] = 0;
+ if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+ return -1;

/*
- * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
- * Some keyboards report different values, but the first byte is always 0xab or
- * 0xac. Some old AT keyboards don't report anything.
+ * Set autorepeat to fastest possible.
*/

- if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) {
-
-/*
- * If the get ID command failed, we check if we can at least set the LEDs on
- * the keyboard. This should work on every keyboard out there. It also turns
- * the LEDs off, which we want anyway.
- */
- param[0] = 0;
- if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
- return -1;
- atkbd->id = 0xabba;
- return 0;
- }
-
- if (param[0] != 0xab && param[0] != 0xac)
+ param[0] = 0;
+ if (atkbd_command(atkbd, param, ATKBD_CMD_SETREP))
return -1;
- atkbd->id = (param[0] << 8) | param[1];

/*
- * Set the LEDs to a defined state.
+ * Enable the keyboard to receive keystrokes.
*/

- param[0] = 0;
- if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+ if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE)) {
+ printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
+ atkbd->serio->phys);
return -1;
+ }

return 0;
}

/*
- * Disable autorepeat. We don't need it, as we do it in software anyway,
- * because that way can get faster repeat, and have less system load (less
- * accesses to the slow ISA hardware). If this fails, we don't care, and will
- * just ignore the repeated keys.
- *
- * This command is for scancode set 3 only.
- */
-static void atkbd_disable_autorepeat(struct atkbd *atkbd)
-{
- atkbd_command(atkbd, NULL, ATKBD_CMD_SETALL_MB);
-}
-
-/*
* atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
* reboot.
*/
@@ -485,7 +496,7 @@
}

/*
- * atkbd_connect() is called when the serio module finds an interface
+ * atkbd_connect() is called when the serio module finds and interface
* that isn't handled yet by an appropriate device driver. We check if
* there is an AT keyboard out there and if yes, we register ourselves
* to the input module.
@@ -513,6 +524,9 @@
atkbd->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL);
} else atkbd->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);

+ atkbd->dev.rep[REP_DELAY] = HZ/4 + HZ/50;
+ atkbd->dev.rep[REP_PERIOD] = HZ/33;
+
atkbd->serio = serio;

init_input_dev(&atkbd->dev);
@@ -525,6 +539,10 @@

serio->private = atkbd;

+ init_timer(&atkbd->timer);
+ atkbd->timer.data = (long) atkbd;
+ atkbd->timer.function = atkbd_force_key_up;
+
if (serio_open(serio, dev)) {
kfree(atkbd);
return;
@@ -539,9 +557,8 @@
}

atkbd->set = atkbd_set_3(atkbd);
- if (atkbd->set == 3)
- atkbd_disable_autorepeat(atkbd);
atkbd_enable(atkbd);
+
} else {
atkbd->set = 2;
atkbd->id = 0xab00;

2003-09-19 10:28:31

by Vojtech Pavlik

[permalink] [raw]
Subject: [PATCH 6/11] input: Change name of Synaptics protocol to SynPS/2

You can pull this changeset from:
bk://kernel.bkbits.net/vojtech/input

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

[email protected], 2003-09-19 01:19:41-07:00, [email protected]
psmouse-base.c:
Change the name od the Synaptics protocol to SynPS/2


psmouse-base.c | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)

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

diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:16:16 2003
+++ b/drivers/input/mouse/psmouse-base.c Fri Sep 19 12:16:16 2003
@@ -41,7 +41,7 @@
int psmouse_smartscroll = PSMOUSE_LOGITECH_SMARTSCROLL;
unsigned int psmouse_resetafter;

-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "Synaptics"};
+static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "PS2T++", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2"};

/*
* psmouse_process_packet() analyzes the PS/2 mouse packet contents and

2003-09-20 20:29:33

by Joseph Fannin

[permalink] [raw]
Subject: Re: [PATCH 1/11] input: Restore synaptics pad mode on module unload


Vojtech, how do you feel about the psmouse_imps2 patch[1] that's
been in -mm since -test4-mm5? Several people have told me it's been
useful for them, to either make their Belkin KVM switches work with
Logitech mice or to disable the Synaptics touchpad driver at runtime
and still be able to use scroll mice.

[1] http://www.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.0-test4/2.6.0-test4-mm5/broken-out/psmouse_ipms2-option.patch

I could write a patch to selectively enable or disable all the
different mouse drivers if you would prefer something more general.

--
Joseph Fannin
[email protected]

"That's all I have to say about that." -- Forrest Gump.


Attachments:
(No filename) (681.00 B)
signature.asc (189.00 B)
Digital signature
Download all attachments

2003-09-21 13:02:53

by Peter Osterlund

[permalink] [raw]
Subject: Re: [PATCH 7/11] input: Fix psmouse->pktcnt in Synaptics mode

Vojtech Pavlik <[email protected]> writes:

> [email protected], 2003-09-19 01:20:33-07:00, [email protected]
> psmouse-base.c:
> Make sure psmouse->pktcnt is zero after passing a byte
> to be processed by synaptics code.

This patch breaks synaptics support, because the pktcnt variable is
now used by the synaptics code. (Previously the synpatics code used a
private buffer, which was unnecessary and therefore removed.)
Reverting this patch makes the touchpad work again for me using kernel
2.6.0-test5-bk8:

linux-petero/drivers/input/mouse/psmouse-base.c | 1 -
1 files changed, 1 deletion(-)

diff -puN drivers/input/mouse/psmouse-base.c~fix-psmouse-breakage drivers/input/mouse/psmouse-base.c
--- linux/drivers/input/mouse/psmouse-base.c~fix-psmouse-breakage 2003-09-21 14:51:59.000000000 +0200
+++ linux-petero/drivers/input/mouse/psmouse-base.c 2003-09-21 14:52:10.000000000 +0200
@@ -173,7 +173,6 @@ static irqreturn_t psmouse_interrupt(str
* so it needs to receive all bytes one at a time.
*/
synaptics_process_byte(psmouse, regs);
- psmouse->pktcnt = 0;
goto out;
}


_

--
Peter Osterlund - [email protected]
http://w1.894.telia.com/~u89404340

2003-09-21 17:19:32

by Vojtech Pavlik

[permalink] [raw]
Subject: Re: [PATCH 7/11] input: Fix psmouse->pktcnt in Synaptics mode

On Sun, Sep 21, 2003 at 03:02:40PM +0200, Peter Osterlund wrote:

> Vojtech Pavlik <[email protected]> writes:
>
> > [email protected], 2003-09-19 01:20:33-07:00, [email protected]
> > psmouse-base.c:
> > Make sure psmouse->pktcnt is zero after passing a byte
> > to be processed by synaptics code.
>
> This patch breaks synaptics support, because the pktcnt variable is
> now used by the synaptics code. (Previously the synpatics code used a
> private buffer, which was unnecessary and therefore removed.)
> Reverting this patch makes the touchpad work again for me using kernel
> 2.6.0-test5-bk8:

Sorry for introducing the breakage. Applied to my tree.

> linux-petero/drivers/input/mouse/psmouse-base.c | 1 -
> 1 files changed, 1 deletion(-)
>
> diff -puN drivers/input/mouse/psmouse-base.c~fix-psmouse-breakage drivers/input/mouse/psmouse-base.c
> --- linux/drivers/input/mouse/psmouse-base.c~fix-psmouse-breakage 2003-09-21 14:51:59.000000000 +0200
> +++ linux-petero/drivers/input/mouse/psmouse-base.c 2003-09-21 14:52:10.000000000 +0200
> @@ -173,7 +173,6 @@ static irqreturn_t psmouse_interrupt(str
> * so it needs to receive all bytes one at a time.
> */
> synaptics_process_byte(psmouse, regs);
> - psmouse->pktcnt = 0;
> goto out;
> }
>
>
> _
>
> --
> Peter Osterlund - [email protected]
> http://w1.894.telia.com/~u89404340

--
Vojtech Pavlik
SuSE Labs, SuSE CR

2003-09-25 07:18:26

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 5/11] input: Fix resume of PS/2 mouse

Hi!

>
> [email protected], 2003-09-19 01:18:46-07:00, [email protected]
> psmouse-base.c:
> Fix resume of PS/2 mouse. Uses old PM interface at the moment.
>

I'm not sure how resume using old PM code is usefull...
Well at least its usefull as documentation :-).
--
Pavel
Written on sharp zaurus, because my Velo1 broke. If you have Velo you don't need...