From: Dmitry Torokhov <dtor_core@ameritech.net>
To: Vojtech Pavlik <vojtech@suse.cz>
Cc: linux-kernel@vger.kernel.org
Subject: [PATCH 1/3] libps2.patch
Date: Thu, 16 Sep 2004 23:59:44 -0500 [thread overview]
Message-ID: <200409162359.45766.dtor_core@ameritech.net> (raw)
In-Reply-To: <200409162358.27678.dtor_core@ameritech.net>
===================================================================
ChangeSet@1.1832.46.2, 2004-09-01 01:00:06-05:00, dtor_core@ameritech.net
Input: pull common code from psmouse and atkbd into libps2 module
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
drivers/input/keyboard/Kconfig | 1
drivers/input/keyboard/atkbd.c | 290 ++++++-------------------------------
drivers/input/mouse/Kconfig | 1
drivers/input/mouse/logips2pp.c | 41 ++---
drivers/input/mouse/psmouse-base.c | 230 +++++------------------------
drivers/input/mouse/psmouse.h | 16 --
drivers/input/mouse/synaptics.c | 28 +--
drivers/input/serio/Kconfig | 10 +
drivers/input/serio/Makefile | 1
drivers/input/serio/libps2.c | 273 ++++++++++++++++++++++++++++++++++
include/linux/libps2.h | 50 ++++++
11 files changed, 474 insertions(+), 467 deletions(-)
===================================================================
diff -Nru a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
--- a/drivers/input/keyboard/Kconfig 2004-09-16 23:30:14 -05:00
+++ b/drivers/input/keyboard/Kconfig 2004-09-16 23:30:14 -05:00
@@ -16,6 +16,7 @@
default y
depends on INPUT && INPUT_KEYBOARD
select SERIO
+ select SERIO_LIBPS2
select SERIO_I8042 if PC
select SERIO_GSCPS2 if GSC
help
diff -Nru a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
--- a/drivers/input/keyboard/atkbd.c 2004-09-16 23:30:14 -05:00
+++ b/drivers/input/keyboard/atkbd.c 2004-09-16 23:30:14 -05:00
@@ -26,6 +26,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/workqueue.h>
+#include <linux/libps2.h>
#define DRIVER_DESC "AT and PS/2 keyboard driver"
@@ -170,21 +171,17 @@
{ ATKBD_SCR_CLICK, 0x60 },
};
-#define ATKBD_FLAG_ACK 0 /* Waiting for ACK/NAK */
-#define ATKBD_FLAG_CMD 1 /* Waiting for command to finish */
-#define ATKBD_FLAG_CMD1 2 /* First byte of command response */
-#define ATKBD_FLAG_ENABLED 3 /* Waining for init to finish */
-
/*
* The atkbd control structure
*/
struct atkbd {
+ struct ps2dev ps2dev;
+
/* Written only during init */
char name[64];
char phys[32];
- struct serio *serio;
struct input_dev dev;
unsigned char set;
@@ -194,12 +191,7 @@
unsigned char extra;
unsigned char write;
- /* Protected by FLAG_ACK */
- unsigned char nak;
-
- /* Protected by FLAG_CMD */
- unsigned char cmdbuf[4];
- unsigned char cmdcnt;
+ unsigned char enabled;
/* Accessed only from interrupt */
unsigned char emul;
@@ -208,26 +200,8 @@
unsigned char bat_xl;
unsigned int last;
unsigned long time;
-
- /* Ensures that only one command is executing at a time */
- struct semaphore cmd_sem;
-
- /* Used to signal completion from interrupt handler */
- wait_queue_head_t wait;
-
- /* Flags */
- unsigned long flags;
};
-/* Work structure to schedule execution of a command */
-struct atkbd_work {
- struct work_struct work;
- struct atkbd *atkbd;
- int command;
- unsigned char param[0];
-};
-
-
static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value)
{
input_regs(dev, regs);
@@ -268,42 +242,15 @@
atkbd->resend = 0;
#endif
- if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags)) {
- switch (code) {
- case ATKBD_RET_ACK:
- atkbd->nak = 0;
- if (atkbd->cmdcnt) {
- set_bit(ATKBD_FLAG_CMD, &atkbd->flags);
- set_bit(ATKBD_FLAG_CMD1, &atkbd->flags);
- }
- clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
- wake_up_interruptible(&atkbd->wait);
- break;
- case ATKBD_RET_NAK:
- atkbd->nak = 1;
- clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
- wake_up_interruptible(&atkbd->wait);
- break;
- }
- goto out;
- }
-
- if (test_bit(ATKBD_FLAG_CMD, &atkbd->flags)) {
-
- if (atkbd->cmdcnt)
- atkbd->cmdbuf[--atkbd->cmdcnt] = code;
-
- if (test_and_clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags) && atkbd->cmdcnt)
- wake_up_interruptible(&atkbd->wait);
+ if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
+ if (ps2_handle_ack(&atkbd->ps2dev, data))
+ goto out;
- if (!atkbd->cmdcnt) {
- clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
- wake_up_interruptible(&atkbd->wait);
- }
- goto out;
- }
+ if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD))
+ if (ps2_handle_response(&atkbd->ps2dev, data))
+ goto out;
- if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags))
+ if (!atkbd->enabled)
goto out;
input_event(&atkbd->dev, EV_MSC, MSC_RAW, code);
@@ -326,8 +273,8 @@
switch (code) {
case ATKBD_RET_BAT:
- clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
- serio_rescan(atkbd->serio);
+ atkbd->enabled = 0;
+ serio_rescan(atkbd->ps2dev.serio);
goto out;
case ATKBD_RET_EMUL0:
atkbd->emul = 1;
@@ -427,151 +374,6 @@
return IRQ_HANDLED;
}
-/*
- * atkbd_sendbyte() sends a byte to the keyboard, and waits for
- * acknowledge. It doesn't handle resends according to the keyboard
- * protocol specs, because if these are needed, the keyboard needs
- * replacement anyway, and they only make a mess in the protocol.
- *
- * atkbd_sendbyte() can only be called from a process context
- */
-
-static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
-{
-#ifdef ATKBD_DEBUG
- printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
-#endif
- atkbd->nak = 1;
- set_bit(ATKBD_FLAG_ACK, &atkbd->flags);
-
- if (serio_write(atkbd->serio, byte) == 0)
- wait_event_interruptible_timeout(atkbd->wait,
- !test_bit(ATKBD_FLAG_ACK, &atkbd->flags),
- msecs_to_jiffies(200));
-
- clear_bit(ATKBD_FLAG_ACK, &atkbd->flags);
- return -atkbd->nak;
-}
-
-/*
- * atkbd_command() sends a command, and its parameters to the keyboard,
- * then waits for the response and puts it in the param array.
- *
- * atkbd_command() can only be called from a process context
- */
-
-static int atkbd_command(struct atkbd *atkbd, unsigned char *param, int command)
-{
- int timeout;
- int send = (command >> 12) & 0xf;
- int receive = (command >> 8) & 0xf;
- int rc = -1;
- int i;
-
- timeout = msecs_to_jiffies(command == ATKBD_CMD_RESET_BAT ? 4000 : 500);
-
- down(&atkbd->cmd_sem);
- clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
-
- if (receive && param)
- for (i = 0; i < receive; i++)
- atkbd->cmdbuf[(receive - 1) - i] = param[i];
-
- atkbd->cmdcnt = receive;
-
- if (command & 0xff)
- if (atkbd_sendbyte(atkbd, command & 0xff))
- goto out;
-
- for (i = 0; i < send; i++)
- if (atkbd_sendbyte(atkbd, param[i]))
- goto out;
-
- timeout = wait_event_interruptible_timeout(atkbd->wait,
- !test_bit(ATKBD_FLAG_CMD1, &atkbd->flags), timeout);
-
- if (atkbd->cmdcnt && timeout > 0) {
- if (command == ATKBD_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100)
- timeout = msecs_to_jiffies(100);
-
- if (command == ATKBD_CMD_GETID &&
- atkbd->cmdbuf[receive - 1] != 0xab && atkbd->cmdbuf[receive - 1] != 0xac) {
- /*
- * Device behind the port is not a keyboard
- * so we don't need to wait for the 2nd byte
- * of ID response.
- */
- clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
- atkbd->cmdcnt = 0;
- }
-
- wait_event_interruptible_timeout(atkbd->wait,
- !test_bit(ATKBD_FLAG_CMD, &atkbd->flags), timeout);
- }
-
- if (param)
- for (i = 0; i < receive; i++)
- param[i] = atkbd->cmdbuf[(receive - 1) - i];
-
- if (atkbd->cmdcnt && (command != ATKBD_CMD_RESET_BAT || atkbd->cmdcnt != 1))
- goto out;
-
- rc = 0;
-
-out:
- clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
- clear_bit(ATKBD_FLAG_CMD1, &atkbd->flags);
- up(&atkbd->cmd_sem);
-
- return rc;
-}
-
-/*
- * atkbd_execute_scheduled_command() sends a command, previously scheduled by
- * atkbd_schedule_command(), to the keyboard.
- */
-
-static void atkbd_execute_scheduled_command(void *data)
-{
- struct atkbd_work *atkbd_work = data;
-
- atkbd_command(atkbd_work->atkbd, atkbd_work->param, atkbd_work->command);
-
- kfree(atkbd_work);
-}
-
-/*
- * atkbd_schedule_command() allows to schedule delayed execution of a keyboard
- * command and can be used to issue a command from an interrupt or softirq
- * context.
- */
-
-static int atkbd_schedule_command(struct atkbd *atkbd, unsigned char *param, int command)
-{
- struct atkbd_work *atkbd_work;
- int send = (command >> 12) & 0xf;
- int receive = (command >> 8) & 0xf;
-
- if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags))
- return -1;
-
- if (!(atkbd_work = kmalloc(sizeof(struct atkbd_work) + max(send, receive), GFP_ATOMIC)))
- return -1;
-
- memset(atkbd_work, 0, sizeof(struct atkbd_work));
- atkbd_work->atkbd = atkbd;
- atkbd_work->command = command;
- memcpy(atkbd_work->param, param, send);
- INIT_WORK(&atkbd_work->work, atkbd_execute_scheduled_command, atkbd_work);
-
- if (!schedule_work(&atkbd_work->work)) {
- kfree(atkbd_work);
- return -1;
- }
-
- return 0;
-}
-
/*
* Event callback from the input module. Events that change the state of
@@ -599,7 +401,7 @@
param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
| (test_bit(LED_NUML, dev->led) ? 2 : 0)
| (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
- atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETLEDS);
+ ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS);
if (atkbd->extra) {
param[0] = 0;
@@ -608,7 +410,7 @@
| (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
| (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
| (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
- atkbd_schedule_command(atkbd, param, ATKBD_CMD_EX_SETLEDS);
+ ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
}
return 0;
@@ -624,7 +426,7 @@
dev->rep[REP_PERIOD] = period[i];
dev->rep[REP_DELAY] = delay[j];
param[0] = i | (j << 5);
- atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETREP);
+ ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP);
return 0;
}
@@ -638,6 +440,7 @@
static int atkbd_probe(struct atkbd *atkbd)
{
+ struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[2];
/*
@@ -647,8 +450,8 @@
*/
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);
+ if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
+ printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", ps2dev->serio->phys);
/*
* Then we check the keyboard ID. We should get 0xab83 under normal conditions.
@@ -658,7 +461,7 @@
*/
param[0] = param[1] = 0xa5; /* initialize with invalid values */
- if (atkbd_command(atkbd, param, ATKBD_CMD_GETID)) {
+ if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
/*
* If the get ID command failed, we check if we can at least set the LEDs on
@@ -666,7 +469,7 @@
* the LEDs off, which we want anyway.
*/
param[0] = 0;
- if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+ if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
return -1;
atkbd->id = 0xabba;
return 0;
@@ -693,6 +496,7 @@
static int atkbd_set_3(struct atkbd *atkbd)
{
+ struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[2];
/*
@@ -706,13 +510,13 @@
if (atkbd->id == 0xaca1) {
param[0] = 3;
- atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET);
+ ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);
return 3;
}
if (atkbd_extra) {
param[0] = 0x71;
- if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE)) {
+ if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
atkbd->extra = 1;
return 2;
}
@@ -721,32 +525,33 @@
if (atkbd_set != 3)
return 2;
- if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) {
+ if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) {
atkbd->id = param[0] << 8 | param[1];
return 2;
}
param[0] = 3;
- if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
+ if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
return 2;
param[0] = 0;
- if (atkbd_command(atkbd, param, ATKBD_CMD_GSCANSET))
+ if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))
return 2;
if (param[0] != 3) {
param[0] = 2;
- if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET))
+ if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
return 2;
}
- atkbd_command(atkbd, param, ATKBD_CMD_SETALL_MBR);
+ ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
return 3;
}
static int atkbd_enable(struct atkbd *atkbd)
{
+ struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[1];
/*
@@ -754,7 +559,7 @@
*/
param[0] = 0;
- if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+ if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
return -1;
/*
@@ -762,16 +567,16 @@
*/
param[0] = 0;
- if (atkbd_command(atkbd, param, ATKBD_CMD_SETREP))
+ if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
return -1;
/*
* Enable the keyboard to receive keystrokes.
*/
- if (atkbd_command(atkbd, NULL, ATKBD_CMD_ENABLE)) {
+ if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
- atkbd->serio->phys);
+ ps2dev->serio->phys);
return -1;
}
@@ -786,7 +591,7 @@
static void atkbd_cleanup(struct serio *serio)
{
struct atkbd *atkbd = serio->private;
- atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT);
+ ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_BAT);
}
/*
@@ -797,7 +602,11 @@
{
struct atkbd *atkbd = serio->private;
- clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
+ serio_pause_rx(serio);
+ atkbd->enabled = 0;
+ serio_continue_rx(serio);
+
+ /* make sure we don't have a command in flight */
synchronize_kernel();
flush_scheduled_work();
@@ -822,8 +631,7 @@
return;
memset(atkbd, 0, sizeof(struct atkbd));
- init_MUTEX(&atkbd->cmd_sem);
- init_waitqueue_head(&atkbd->wait);
+ ps2_init(&atkbd->ps2dev, serio);
switch (serio->type & SERIO_TYPE) {
@@ -857,8 +665,6 @@
atkbd->dev.rep[REP_PERIOD] = 33;
} else atkbd_softraw = 1;
- atkbd->serio = serio;
-
init_input_dev(&atkbd->dev);
atkbd->dev.keycode = atkbd->keycode;
@@ -932,7 +738,9 @@
input_register_device(&atkbd->dev);
- set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
+ serio_pause_rx(serio);
+ atkbd->enabled = 1;
+ serio_continue_rx(serio);
printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
}
@@ -953,6 +761,10 @@
return -1;
}
+ serio_pause_rx(serio);
+ atkbd->enabled = 0;
+ serio_continue_rx(serio);
+
if (atkbd->write) {
param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
| (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0)
@@ -965,11 +777,13 @@
atkbd_enable(atkbd);
- if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS))
+ if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
return -1;
}
- set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
+ serio_pause_rx(serio);
+ atkbd->enabled = 1;
+ serio_continue_rx(serio);
return 0;
}
diff -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
--- a/drivers/input/mouse/Kconfig 2004-09-16 23:30:14 -05:00
+++ b/drivers/input/mouse/Kconfig 2004-09-16 23:30:14 -05:00
@@ -16,6 +16,7 @@
default y
depends on INPUT && INPUT_MOUSE
select SERIO
+ select SERIO_LIBPS2
select SERIO_I8042 if PC
select SERIO_GSCPS2 if GSC
---help---
diff -Nru a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
--- a/drivers/input/mouse/logips2pp.c 2004-09-16 23:30:14 -05:00
+++ b/drivers/input/mouse/logips2pp.c 2004-09-16 23:30:14 -05:00
@@ -11,6 +11,7 @@
#include <linux/input.h>
#include <linux/serio.h>
+#include <linux/libps2.h>
#include "psmouse.h"
#include "logips2pp.h"
@@ -97,7 +98,7 @@
if (psmouse_sliced_command(psmouse, command))
return -1;
- if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL))
+ if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL))
return -1;
return 0;
@@ -113,19 +114,20 @@
static void ps2pp_set_smartscroll(struct psmouse *psmouse)
{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
ps2pp_cmd(psmouse, param, 0x32);
param[0] = 0;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
if (psmouse_smartscroll < 2) {
/* 0 - disabled, 1 - enabled */
param[0] = psmouse_smartscroll;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
}
}
@@ -137,11 +139,13 @@
void ps2pp_set_800dpi(struct psmouse *psmouse)
{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param = 3;
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
- psmouse_command(psmouse, ¶m, PSMOUSE_CMD_SETRES);
+
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+ ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
}
static struct ps2pp_info *get_model_info(unsigned char model)
@@ -238,18 +242,19 @@
int ps2pp_init(struct psmouse *psmouse, int set_properties)
{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
unsigned char protocol = PSMOUSE_PS2;
unsigned char model, buttons;
struct ps2pp_info *model_info;
param[0] = 0;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
param[1] = 0;
- psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
if (param[1] != 0) {
model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
@@ -263,16 +268,16 @@
/* Unprotect RAM */
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
- psmouse_command(psmouse, param, 0x30d1);
+ ps2_command(ps2dev, param, 0x30d1);
/* Enable features */
param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
- psmouse_command(psmouse, param, 0x30d1);
+ ps2_command(ps2dev, param, 0x30d1);
/* Enable PS2++ */
param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
- psmouse_command(psmouse, param, 0x30d1);
+ ps2_command(ps2dev, param, 0x30d1);
param[0] = 0;
- if (!psmouse_command(psmouse, param, 0x13d1) &&
+ if (!ps2_command(ps2dev, param, 0x13d1) &&
param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
protocol = PSMOUSE_PS2TPP;
}
diff -Nru a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
--- a/drivers/input/mouse/psmouse-base.c 2004-09-16 23:30:14 -05:00
+++ b/drivers/input/mouse/psmouse-base.c 2004-09-16 23:30:14 -05:00
@@ -18,6 +18,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
+#include <linux/libps2.h>
#include "psmouse.h"
#include "synaptics.h"
#include "logips2pp.h"
@@ -144,63 +145,17 @@
printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
flags & SERIO_TIMEOUT ? " timeout" : "",
flags & SERIO_PARITY ? " bad parity" : "");
- psmouse->nak = 1;
- clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
- clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
- wake_up_interruptible(&psmouse->wait);
+ ps2_cmd_aborted(&psmouse->ps2dev);
goto out;
}
- if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) {
- switch (data) {
- case PSMOUSE_RET_ACK:
- psmouse->nak = 0;
- break;
-
- case PSMOUSE_RET_NAK:
- psmouse->nak = 1;
- break;
-
- /*
- * Workaround for mice which don't ACK the Get ID command.
- * These are valid mouse IDs that we recognize.
- */
- case 0x00:
- case 0x03:
- case 0x04:
- if (test_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags)) {
- psmouse->nak = 0;
- break;
- }
- /* Fall through */
- default:
- goto out;
- }
-
- if (!psmouse->nak && psmouse->cmdcnt) {
- set_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
- set_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
- }
- clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
- wake_up_interruptible(&psmouse->wait);
-
- if (data == PSMOUSE_RET_ACK || data == PSMOUSE_RET_NAK)
+ if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK))
+ if (ps2_handle_ack(&psmouse->ps2dev, data))
goto out;
- }
- if (test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags)) {
- if (psmouse->cmdcnt)
- psmouse->cmdbuf[--psmouse->cmdcnt] = data;
-
- if (test_and_clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags) && psmouse->cmdcnt)
- wake_up_interruptible(&psmouse->wait);
-
- if (!psmouse->cmdcnt) {
- clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
- wake_up_interruptible(&psmouse->wait);
- }
- goto out;
- }
+ if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD))
+ if (ps2_handle_response(&psmouse->ps2dev, data))
+ goto out;
if (psmouse->state == PSMOUSE_INITIALIZING)
goto out;
@@ -246,7 +201,7 @@
if (++psmouse->out_of_sync == psmouse_resetafter) {
psmouse->state = PSMOUSE_IGNORE;
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
- serio_reconnect(psmouse->serio);
+ serio_reconnect(psmouse->ps2dev.serio);
}
break;
@@ -266,100 +221,6 @@
return IRQ_HANDLED;
}
-/*
- * psmouse_sendbyte() sends a byte to the mouse, and waits for acknowledge.
- * It doesn't handle retransmission, though it could - because when there would
- * be need for retransmissions, the mouse has to be replaced anyway.
- *
- * psmouse_sendbyte() can only be called from a process context
- */
-
-static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
-{
- psmouse->nak = 1;
- set_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
-
- if (serio_write(psmouse->serio, byte) == 0)
- wait_event_interruptible_timeout(psmouse->wait,
- !test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags),
- msecs_to_jiffies(200));
-
- clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
- return -psmouse->nak;
-}
-
-/*
- * psmouse_command() sends a command and its parameters to the mouse,
- * then waits for the response and puts it in the param array.
- *
- * psmouse_command() can only be called from a process context
- */
-
-int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command)
-{
- int timeout;
- int send = (command >> 12) & 0xf;
- int receive = (command >> 8) & 0xf;
- int rc = -1;
- int i;
-
- timeout = msecs_to_jiffies(command == PSMOUSE_CMD_RESET_BAT ? 4000 : 500);
-
- clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
- if (command == PSMOUSE_CMD_GETID)
- set_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags);
-
- if (receive && param)
- for (i = 0; i < receive; i++)
- psmouse->cmdbuf[(receive - 1) - i] = param[i];
-
- psmouse->cmdcnt = receive;
-
- if (command & 0xff)
- if (psmouse_sendbyte(psmouse, command & 0xff))
- goto out;
-
- for (i = 0; i < send; i++)
- if (psmouse_sendbyte(psmouse, param[i]))
- goto out;
-
- timeout = wait_event_interruptible_timeout(psmouse->wait,
- !test_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags), timeout);
-
- if (psmouse->cmdcnt && timeout > 0) {
- if (command == PSMOUSE_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100)
- timeout = msecs_to_jiffies(100);
-
- if (command == PSMOUSE_CMD_GETID &&
- psmouse->cmdbuf[receive - 1] != 0xab && psmouse->cmdbuf[receive - 1] != 0xac) {
- /*
- * Device behind the port is not a keyboard
- * so we don't need to wait for the 2nd byte
- * of ID response.
- */
- clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
- psmouse->cmdcnt = 0;
- }
-
- wait_event_interruptible_timeout(psmouse->wait,
- !test_bit(PSMOUSE_FLAG_CMD, &psmouse->flags), timeout);
- }
-
- if (param)
- for (i = 0; i < receive; i++)
- param[i] = psmouse->cmdbuf[(receive - 1) - i];
-
- if (psmouse->cmdcnt && (command != PSMOUSE_CMD_RESET_BAT || psmouse->cmdcnt != 1))
- goto out;
-
- rc = 0;
-
-out:
- clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
- clear_bit(PSMOUSE_FLAG_CMD1, &psmouse->flags);
- clear_bit(PSMOUSE_FLAG_WAITID, &psmouse->flags);
- return rc;
-}
/*
* psmouse_sliced_command() sends an extended PS/2 command to the mouse
@@ -372,12 +233,12 @@
{
int i;
- if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11))
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
return -1;
for (i = 6; i >= 0; i -= 2) {
unsigned char d = (command >> i) & 3;
- if (psmouse_command(psmouse, &d, PSMOUSE_CMD_SETRES))
+ if (ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES))
return -1;
}
@@ -392,7 +253,7 @@
{
unsigned char param[2];
- if (psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT))
+ if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT))
return -1;
if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID)
@@ -407,14 +268,15 @@
*/
static int genius_detect(struct psmouse *psmouse)
{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
param[0] = 3;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
- psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
return param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55;
}
@@ -424,15 +286,16 @@
*/
static int intellimouse_detect(struct psmouse *psmouse)
{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
param[0] = 200;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 100;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 80;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
- psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
return param[0] == 3;
}
@@ -442,17 +305,18 @@
*/
static int im_explorer_detect(struct psmouse *psmouse)
{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
intellimouse_detect(psmouse);
param[0] = 200;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 200;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 80;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
- psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
return param[0] == 4;
}
@@ -549,7 +413,7 @@
* extensions.
*/
psmouse_reset(psmouse);
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS);
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
}
return PSMOUSE_PS2;
@@ -561,6 +425,7 @@
static int psmouse_probe(struct psmouse *psmouse)
{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
/*
@@ -569,8 +434,7 @@
*/
param[0] = 0xa5;
-
- if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID))
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
return -1;
if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
@@ -580,8 +444,8 @@
* Then we reset and disable the mouse so that it doesn't generate events.
*/
- if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS))
- printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys);
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
+ printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys);
return 0;
}
@@ -608,7 +472,7 @@
else if (psmouse_resolution)
param[0] = 0;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
+ ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRES);
}
/*
@@ -621,7 +485,7 @@
int i = 0;
while (rates[i] > psmouse_rate) i++;
- psmouse_command(psmouse, rates + i, PSMOUSE_CMD_SETRATE);
+ ps2_command(&psmouse->ps2dev, rates + i, PSMOUSE_CMD_SETRATE);
}
/*
@@ -639,14 +503,14 @@
if (psmouse_max_proto != PSMOUSE_PS2) {
psmouse_set_rate(psmouse);
psmouse_set_resolution(psmouse);
- psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
+ ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
}
/*
* We set the mouse into streaming mode.
*/
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM);
+ ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETSTREAM);
}
/*
@@ -657,11 +521,11 @@
static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
{
- serio_pause_rx(psmouse->serio);
+ serio_pause_rx(psmouse->ps2dev.serio);
psmouse->state = new_state;
- psmouse->pktcnt = psmouse->cmdcnt = psmouse->out_of_sync = 0;
- psmouse->flags = 0;
- serio_continue_rx(psmouse->serio);
+ psmouse->pktcnt = psmouse->out_of_sync = 0;
+ psmouse->ps2dev.flags = 0;
+ serio_continue_rx(psmouse->ps2dev.serio);
}
/*
@@ -670,8 +534,9 @@
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);
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
+ printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n",
+ psmouse->ps2dev.serio->phys);
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
}
@@ -684,8 +549,9 @@
static void psmouse_deactivate(struct psmouse *psmouse)
{
- if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE))
- printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", psmouse->serio->phys);
+ if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
+ printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n",
+ psmouse->ps2dev.serio->phys);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
}
@@ -755,12 +621,10 @@
memset(psmouse, 0, sizeof(struct psmouse));
- init_waitqueue_head(&psmouse->wait);
- init_input_dev(&psmouse->dev);
+ ps2_init(&psmouse->ps2dev, serio);
psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
- psmouse->serio = serio;
psmouse->dev.private = psmouse;
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
diff -Nru a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
--- a/drivers/input/mouse/psmouse.h 2004-09-16 23:30:14 -05:00
+++ b/drivers/input/mouse/psmouse.h 2004-09-16 23:30:14 -05:00
@@ -18,11 +18,6 @@
#define PSMOUSE_RET_ACK 0xfa
#define PSMOUSE_RET_NAK 0xfe
-#define PSMOUSE_FLAG_ACK 0 /* Waiting for ACK/NAK */
-#define PSMOUSE_FLAG_CMD 1 /* Waiting for command to finish */
-#define PSMOUSE_FLAG_CMD1 2 /* Waiting for the first byte of command response */
-#define PSMOUSE_FLAG_WAITID 3 /* Command execiting is GET ID */
-
enum psmouse_state {
PSMOUSE_IGNORE,
PSMOUSE_INITIALIZING,
@@ -40,26 +35,18 @@
struct psmouse {
void *private;
struct input_dev dev;
- struct serio *serio;
+ struct ps2dev ps2dev;
char *vendor;
char *name;
- unsigned char cmdbuf[8];
unsigned char packet[8];
- unsigned char cmdcnt;
unsigned char pktcnt;
unsigned char type;
unsigned char model;
unsigned long last;
unsigned long out_of_sync;
enum psmouse_state state;
- unsigned char nak;
- char error;
char devname[64];
char phys[32];
- unsigned long flags;
-
- /* Used to signal completion from interrupt handler */
- wait_queue_head_t wait;
psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
int (*reconnect)(struct psmouse *psmouse);
@@ -77,7 +64,6 @@
#define PSMOUSE_IMEX 6
#define PSMOUSE_SYNAPTICS 7
-int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
int psmouse_reset(struct psmouse *psmouse);
diff -Nru a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
--- a/drivers/input/mouse/synaptics.c 2004-09-16 23:30:14 -05:00
+++ b/drivers/input/mouse/synaptics.c 2004-09-16 23:30:14 -05:00
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/input.h>
#include <linux/serio.h>
+#include <linux/libps2.h>
#include "psmouse.h"
#include "synaptics.h"
@@ -50,7 +51,7 @@
{
if (psmouse_sliced_command(psmouse, c))
return -1;
- if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
+ if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1;
return 0;
}
@@ -65,7 +66,7 @@
if (psmouse_sliced_command(psmouse, mode))
return -1;
param[0] = SYN_PS_SET_MODE2;
- if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE))
+ if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE))
return -1;
return 0;
}
@@ -219,7 +220,7 @@
if (psmouse_sliced_command(parent, c))
return -1;
- if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE))
+ if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE))
return -1;
return 0;
}
@@ -245,7 +246,7 @@
static void synaptics_pt_activate(struct psmouse *psmouse)
{
- struct psmouse *child = psmouse->serio->child->private;
+ struct psmouse *child = psmouse->ps2dev.serio->child->private;
/* adjust the touchpad to child's choice of protocol */
if (child && child->type >= PSMOUSE_GENPS) {
@@ -270,11 +271,11 @@
strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
serio->write = synaptics_pt_write;
- serio->parent = psmouse->serio;
+ serio->parent = psmouse->ps2dev.serio;
psmouse->pt_activate = synaptics_pt_activate;
- psmouse->serio->child = serio;
+ psmouse->ps2dev.serio->child = serio;
}
/*****************************************************************************
@@ -470,8 +471,8 @@
priv->pkt_type = synaptics_detect_pkt_type(psmouse);
if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) {
- if (psmouse->serio->child)
- synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet);
+ if (psmouse->ps2dev.serio->child)
+ synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet);
} else
synaptics_process_packet(psmouse);
@@ -561,15 +562,16 @@
int synaptics_detect(struct psmouse *psmouse)
{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
param[0] = 0;
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
- psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
+ ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
return param[1] == 0x47;
}
diff -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
--- a/drivers/input/serio/Kconfig 2004-09-16 23:30:14 -05:00
+++ b/drivers/input/serio/Kconfig 2004-09-16 23:30:14 -05:00
@@ -131,6 +131,16 @@
To compile this driver as a module, choose M here: the
module will be called maceps2.
+config SERIO_LIBPS2
+ tristate "PS/2 driver library"
+ depends on SERIO
+ help
+ Say Y here if you are using a driver for device connected
+ to a PS/2 port, such as PS/2 mouse or standard AT keyboard.
+
+ To compile this driver as a module, choose M here: the
+ module will be called libps2.
+
config SERIO_RAW
tristate "Raw access to serio ports"
depends on SERIO
diff -Nru a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
--- a/drivers/input/serio/Makefile 2004-09-16 23:30:14 -05:00
+++ b/drivers/input/serio/Makefile 2004-09-16 23:30:14 -05:00
@@ -17,4 +17,5 @@
obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
+obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
obj-$(CONFIG_SERIO_RAW) += serio_raw.o
diff -Nru a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/drivers/input/serio/libps2.c 2004-09-16 23:30:14 -05:00
@@ -0,0 +1,273 @@
+/*
+ * PS/2 driver library
+ *
+ * Copyright (c) 1999-2002 Vojtech Pavlik
+ * Copyright (c) 2004 Dmitry Torokhov
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+#include <linux/libps2.h>
+
+#define DRIVER_DESC "PS/2 driver library"
+
+MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
+MODULE_DESCRIPTION("PS/2 driver library");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(ps2_init);
+EXPORT_SYMBOL(ps2_sendbyte);
+EXPORT_SYMBOL(ps2_command);
+EXPORT_SYMBOL(ps2_schedule_command);
+EXPORT_SYMBOL(ps2_handle_ack);
+EXPORT_SYMBOL(ps2_handle_response);
+EXPORT_SYMBOL(ps2_cmd_aborted);
+
+/* Work structure to schedule execution of a command */
+struct ps2work {
+ struct work_struct work;
+ struct ps2dev *ps2dev;
+ int command;
+ unsigned char param[0];
+};
+
+
+/*
+ * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge.
+ * It doesn't handle retransmission, though it could - because when there would
+ * be need for retransmissions, the mouse has to be replaced anyway.
+ *
+ * ps2_sendbyte() can only be called from a process context
+ */
+
+int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte)
+{
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->nak = 1;
+ ps2dev->flags |= PS2_FLAG_ACK;
+ serio_continue_rx(ps2dev->serio);
+
+ if (serio_write(ps2dev->serio, byte) == 0)
+ wait_event_interruptible_timeout(ps2dev->wait,
+ !(ps2dev->flags & PS2_FLAG_ACK),
+ msecs_to_jiffies(200));
+
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags &= ~PS2_FLAG_ACK;
+ serio_continue_rx(ps2dev->serio);
+
+ return -ps2dev->nak;
+}
+
+/*
+ * ps2_command() sends a command and its parameters to the mouse,
+ * then waits for the response and puts it in the param array.
+ *
+ * ps2_command() can only be called from a process context
+ */
+
+int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
+{
+ int timeout;
+ int send = (command >> 12) & 0xf;
+ int receive = (command >> 8) & 0xf;
+ int rc = -1;
+ int i;
+
+ down(&ps2dev->cmd_sem);
+
+ timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500);
+
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
+ ps2dev->cmdcnt = receive;
+ if (receive && param)
+ for (i = 0; i < receive; i++)
+ ps2dev->cmdbuf[(receive - 1) - i] = param[i];
+ serio_continue_rx(ps2dev->serio);
+
+ if (command & 0xff)
+ if (ps2_sendbyte(ps2dev, command & 0xff))
+ goto out;
+
+ for (i = 0; i < send; i++)
+ if (ps2_sendbyte(ps2dev, param[i]))
+ goto out;
+
+ timeout = wait_event_interruptible_timeout(ps2dev->wait,
+ !(ps2dev->flags & PS2_FLAG_CMD1), timeout);
+
+ if (ps2dev->cmdcnt && timeout > 0) {
+ if (command == PS2_CMD_RESET_BAT && jiffies_to_msecs(timeout) > 100)
+ timeout = msecs_to_jiffies(100);
+
+ if (command == PS2_CMD_GETID &&
+ ps2dev->cmdbuf[receive - 1] != 0xab && ps2dev->cmdbuf[receive - 1] != 0xac) {
+ /*
+ * Device behind the port is not a keyboard
+ * so we don't need to wait for the 2nd byte
+ * of ID response.
+ */
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = ps2dev->cmdcnt = 0;
+ serio_continue_rx(ps2dev->serio);
+ }
+
+ wait_event_interruptible_timeout(ps2dev->wait,
+ !(ps2dev->flags & PS2_FLAG_CMD), timeout);
+ }
+
+ if (param)
+ for (i = 0; i < receive; i++)
+ param[i] = ps2dev->cmdbuf[(receive - 1) - i];
+
+ if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1))
+ goto out;
+
+ rc = 0;
+
+out:
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = 0;
+ serio_continue_rx(ps2dev->serio);
+
+ up(&ps2dev->cmd_sem);
+ return rc;
+}
+
+/*
+ * ps2_execute_scheduled_command() sends a command, previously scheduled by
+ * ps2_schedule_command(), to a PS/2 device (keyboard, mouse, etc.)
+ */
+
+static void ps2_execute_scheduled_command(void *data)
+{
+ struct ps2work *ps2work = data;
+
+ ps2_command(ps2work->ps2dev, ps2work->param, ps2work->command);
+ kfree(ps2work);
+}
+
+/*
+ * ps2_schedule_command() allows to schedule delayed execution of a PS/2
+ * command and can be used to issue a command from an interrupt or softirq
+ * context.
+ */
+
+int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command)
+{
+ struct ps2work *ps2work;
+ int send = (command >> 12) & 0xf;
+ int receive = (command >> 8) & 0xf;
+
+ if (!(ps2work = kmalloc(sizeof(struct ps2work) + max(send, receive), GFP_ATOMIC)))
+ return -1;
+
+ memset(ps2work, 0, sizeof(struct ps2work));
+ ps2work->ps2dev = ps2dev;
+ ps2work->command = command;
+ memcpy(ps2work->param, param, send);
+ INIT_WORK(&ps2work->work, ps2_execute_scheduled_command, ps2work);
+
+ if (!schedule_work(&ps2work->work)) {
+ kfree(ps2work);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * ps2_init() initializes ps2dev structure
+ */
+
+void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
+{
+ init_MUTEX(&ps2dev->cmd_sem);
+ init_waitqueue_head(&ps2dev->wait);
+ ps2dev->serio = serio;
+}
+
+/*
+ * ps2_handle_ack()
+ */
+
+int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
+{
+ switch (data) {
+ case PS2_RET_ACK:
+ ps2dev->nak = 0;
+ break;
+
+ case PS2_RET_NAK:
+ ps2dev->nak = 1;
+ break;
+
+ /*
+ * Workaround for mice which don't ACK the Get ID command.
+ * These are valid mouse IDs that we recognize.
+ */
+ case 0x00:
+ case 0x03:
+ case 0x04:
+ if (ps2dev->flags & PS2_FLAG_WAITID) {
+ ps2dev->nak = 0;
+ break;
+ }
+ /* Fall through */
+ default:
+ return 1;
+ }
+
+ if (!ps2dev->nak && ps2dev->cmdcnt)
+ ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1;
+
+ ps2dev->flags &= ~PS2_FLAG_ACK;
+ wake_up_interruptible(&ps2dev->wait);
+
+ return data == PS2_RET_ACK || data == PS2_RET_NAK;
+}
+
+
+int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data)
+{
+ if (ps2dev->cmdcnt)
+ ps2dev->cmdbuf[--ps2dev->cmdcnt] = data;
+
+ if (ps2dev->flags & PS2_FLAG_CMD1) {
+ ps2dev->flags &= ~PS2_FLAG_CMD1;
+ if (ps2dev->cmdcnt)
+ wake_up_interruptible(&ps2dev->wait);
+ }
+
+ if (!ps2dev->cmdcnt) {
+ ps2dev->flags &= ~PS2_FLAG_CMD;
+ wake_up_interruptible(&ps2dev->wait);
+ }
+
+ return 1;
+}
+
+void ps2_cmd_aborted(struct ps2dev *ps2dev)
+{
+ if (ps2dev->flags & PS2_FLAG_ACK)
+ ps2dev->nak = 1;
+
+ if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD))
+ wake_up_interruptible(&ps2dev->wait);
+
+ ps2dev->flags = 0;
+}
+
diff -Nru a/include/linux/libps2.h b/include/linux/libps2.h
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/include/linux/libps2.h 2004-09-16 23:30:14 -05:00
@@ -0,0 +1,50 @@
+#ifndef _LIBPS2_H
+#define _LIBPS2_H
+
+/*
+ * Copyright (C) 1999-2002 Vojtech Pavlik
+ * Copyright (C) 2004 Dmitry Torokhov
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+
+#define PS2_CMD_GETID 0x02f2
+#define PS2_CMD_RESET_BAT 0x02ff
+
+#define PS2_RET_BAT 0xaa
+#define PS2_RET_ID 0x00
+#define PS2_RET_ACK 0xfa
+#define PS2_RET_NAK 0xfe
+
+#define PS2_FLAG_ACK 1 /* Waiting for ACK/NAK */
+#define PS2_FLAG_CMD 2 /* Waiting for command to finish */
+#define PS2_FLAG_CMD1 4 /* Waiting for the first byte of command response */
+#define PS2_FLAG_WAITID 8 /* Command execiting is GET ID */
+
+struct ps2dev {
+ struct serio *serio;
+
+ /* Ensures that only one command is executing at a time */
+ struct semaphore cmd_sem;
+
+ /* Used to signal completion from interrupt handler */
+ wait_queue_head_t wait;
+
+ unsigned long flags;
+ unsigned char cmdbuf[6];
+ unsigned char cmdcnt;
+ unsigned char nak;
+};
+
+void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
+int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte);
+int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
+int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command);
+int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
+int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data);
+void ps2_cmd_aborted(struct ps2dev *ps2dev);
+
+#endif /* _LIBPS2_H */
next prev parent reply other threads:[~2004-09-17 5:06 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-09-17 4:58 [PATCH 0/3] New input patches Dmitry Torokhov
2004-09-17 4:59 ` Dmitry Torokhov [this message]
2004-09-17 5:00 ` [PATCH 2/3] serio-pin-driver.patch Dmitry Torokhov
2004-09-17 5:01 ` [PATCH 3/3] atkbd-sysfs-attr.patch Dmitry Torokhov
2004-09-21 12:10 ` [PATCH 0/3] New input patches Vojtech Pavlik
2004-09-21 13:15 ` Dmitry Torokhov
2004-09-22 7:12 ` Dmitry Torokhov
2004-09-22 7:30 ` Vojtech Pavlik
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200409162359.45766.dtor_core@ameritech.net \
--to=dtor_core@ameritech.net \
--cc=linux-kernel@vger.kernel.org \
--cc=vojtech@suse.cz \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.