Commit 2ef6e58b authored by Dmitry Torokhov's avatar Dmitry Torokhov Committed by Vojtech Pavlik

Input: pull common code from psmouse and atkbd into libps2 module

Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 9e61cbe0
...@@ -16,6 +16,7 @@ config KEYBOARD_ATKBD ...@@ -16,6 +16,7 @@ config KEYBOARD_ATKBD
default y default y
depends on INPUT && INPUT_KEYBOARD depends on INPUT && INPUT_KEYBOARD
select SERIO select SERIO
select SERIO_LIBPS2
select SERIO_I8042 if PC select SERIO_I8042 if PC
select SERIO_GSCPS2 if GSC select SERIO_GSCPS2 if GSC
help help
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/libps2.h>
#define DRIVER_DESC "AT and PS/2 keyboard driver" #define DRIVER_DESC "AT and PS/2 keyboard driver"
...@@ -170,21 +171,17 @@ static unsigned char atkbd_scroll_keys[5][2] = { ...@@ -170,21 +171,17 @@ static unsigned char atkbd_scroll_keys[5][2] = {
{ ATKBD_SCR_CLICK, 0x60 }, { 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 * The atkbd control structure
*/ */
struct atkbd { struct atkbd {
struct ps2dev ps2dev;
/* Written only during init */ /* Written only during init */
char name[64]; char name[64];
char phys[32]; char phys[32];
struct serio *serio;
struct input_dev dev; struct input_dev dev;
unsigned char set; unsigned char set;
...@@ -194,12 +191,7 @@ struct atkbd { ...@@ -194,12 +191,7 @@ struct atkbd {
unsigned char extra; unsigned char extra;
unsigned char write; unsigned char write;
/* Protected by FLAG_ACK */ unsigned char enabled;
unsigned char nak;
/* Protected by FLAG_CMD */
unsigned char cmdbuf[4];
unsigned char cmdcnt;
/* Accessed only from interrupt */ /* Accessed only from interrupt */
unsigned char emul; unsigned char emul;
...@@ -208,26 +200,8 @@ struct atkbd { ...@@ -208,26 +200,8 @@ struct atkbd {
unsigned char bat_xl; unsigned char bat_xl;
unsigned int last; unsigned int last;
unsigned long time; 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) static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value)
{ {
input_regs(dev, regs); input_regs(dev, regs);
...@@ -268,42 +242,15 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -268,42 +242,15 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd->resend = 0; atkbd->resend = 0;
#endif #endif
if (test_bit(ATKBD_FLAG_ACK, &atkbd->flags)) { if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
switch (code) { if (ps2_handle_ack(&atkbd->ps2dev, data))
case ATKBD_RET_ACK: goto out;
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 (!atkbd->cmdcnt) { if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD))
clear_bit(ATKBD_FLAG_CMD, &atkbd->flags); if (ps2_handle_response(&atkbd->ps2dev, data))
wake_up_interruptible(&atkbd->wait); goto out;
}
goto out;
}
if (!test_bit(ATKBD_FLAG_ENABLED, &atkbd->flags)) if (!atkbd->enabled)
goto out; goto out;
input_event(&atkbd->dev, EV_MSC, MSC_RAW, code); input_event(&atkbd->dev, EV_MSC, MSC_RAW, code);
...@@ -326,8 +273,8 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -326,8 +273,8 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
switch (code) { switch (code) {
case ATKBD_RET_BAT: case ATKBD_RET_BAT:
clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); atkbd->enabled = 0;
serio_rescan(atkbd->serio); serio_rescan(atkbd->ps2dev.serio);
goto out; goto out;
case ATKBD_RET_EMUL0: case ATKBD_RET_EMUL0:
atkbd->emul = 1; atkbd->emul = 1;
...@@ -427,151 +374,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, ...@@ -427,151 +374,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
return IRQ_HANDLED; 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 * Event callback from the input module. Events that change the state of
...@@ -599,7 +401,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co ...@@ -599,7 +401,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
| (test_bit(LED_NUML, dev->led) ? 2 : 0) | (test_bit(LED_NUML, dev->led) ? 2 : 0)
| (test_bit(LED_CAPSL, dev->led) ? 4 : 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) { if (atkbd->extra) {
param[0] = 0; param[0] = 0;
...@@ -608,7 +410,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co ...@@ -608,7 +410,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
| (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
| (test_bit(LED_MISC, dev->led) ? 0x10 : 0) | (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
| (test_bit(LED_MUTE, dev->led) ? 0x20 : 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; return 0;
...@@ -624,7 +426,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co ...@@ -624,7 +426,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
dev->rep[REP_PERIOD] = period[i]; dev->rep[REP_PERIOD] = period[i];
dev->rep[REP_DELAY] = delay[j]; dev->rep[REP_DELAY] = delay[j];
param[0] = i | (j << 5); param[0] = i | (j << 5);
atkbd_schedule_command(atkbd, param, ATKBD_CMD_SETREP); ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP);
return 0; return 0;
} }
...@@ -638,6 +440,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co ...@@ -638,6 +440,7 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
static int atkbd_probe(struct atkbd *atkbd) static int atkbd_probe(struct atkbd *atkbd)
{ {
struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[2]; unsigned char param[2];
/* /*
...@@ -647,8 +450,8 @@ static int atkbd_probe(struct atkbd *atkbd) ...@@ -647,8 +450,8 @@ static int atkbd_probe(struct atkbd *atkbd)
*/ */
if (atkbd_reset) if (atkbd_reset)
if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT)) if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT))
printk(KERN_WARNING "atkbd.c: keyboard reset failed on %s\n", atkbd->serio->phys); 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. * Then we check the keyboard ID. We should get 0xab83 under normal conditions.
...@@ -658,7 +461,7 @@ static int atkbd_probe(struct atkbd *atkbd) ...@@ -658,7 +461,7 @@ static int atkbd_probe(struct atkbd *atkbd)
*/ */
param[0] = param[1] = 0xa5; /* initialize with invalid values */ 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 * If the get ID command failed, we check if we can at least set the LEDs on
...@@ -666,7 +469,7 @@ static int atkbd_probe(struct atkbd *atkbd) ...@@ -666,7 +469,7 @@ static int atkbd_probe(struct atkbd *atkbd)
* the LEDs off, which we want anyway. * the LEDs off, which we want anyway.
*/ */
param[0] = 0; param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS)) if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
return -1; return -1;
atkbd->id = 0xabba; atkbd->id = 0xabba;
return 0; return 0;
...@@ -693,6 +496,7 @@ static int atkbd_probe(struct atkbd *atkbd) ...@@ -693,6 +496,7 @@ static int atkbd_probe(struct atkbd *atkbd)
static int atkbd_set_3(struct atkbd *atkbd) static int atkbd_set_3(struct atkbd *atkbd)
{ {
struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[2]; unsigned char param[2];
/* /*
...@@ -706,13 +510,13 @@ static int atkbd_set_3(struct atkbd *atkbd) ...@@ -706,13 +510,13 @@ static int atkbd_set_3(struct atkbd *atkbd)
if (atkbd->id == 0xaca1) { if (atkbd->id == 0xaca1) {
param[0] = 3; param[0] = 3;
atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET); ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET);
return 3; return 3;
} }
if (atkbd_extra) { if (atkbd_extra) {
param[0] = 0x71; param[0] = 0x71;
if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE)) { if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) {
atkbd->extra = 1; atkbd->extra = 1;
return 2; return 2;
} }
...@@ -721,32 +525,33 @@ static int atkbd_set_3(struct atkbd *atkbd) ...@@ -721,32 +525,33 @@ static int atkbd_set_3(struct atkbd *atkbd)
if (atkbd_set != 3) if (atkbd_set != 3)
return 2; 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]; atkbd->id = param[0] << 8 | param[1];
return 2; return 2;
} }
param[0] = 3; param[0] = 3;
if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET)) if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
return 2; return 2;
param[0] = 0; param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_GSCANSET)) if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET))
return 2; return 2;
if (param[0] != 3) { if (param[0] != 3) {
param[0] = 2; param[0] = 2;
if (atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET)) if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET))
return 2; return 2;
} }
atkbd_command(atkbd, param, ATKBD_CMD_SETALL_MBR); ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR);
return 3; return 3;
} }
static int atkbd_enable(struct atkbd *atkbd) static int atkbd_enable(struct atkbd *atkbd)
{ {
struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[1]; unsigned char param[1];
/* /*
...@@ -754,7 +559,7 @@ static int atkbd_enable(struct atkbd *atkbd) ...@@ -754,7 +559,7 @@ static int atkbd_enable(struct atkbd *atkbd)
*/ */
param[0] = 0; param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS)) if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS))
return -1; return -1;
/* /*
...@@ -762,16 +567,16 @@ static int atkbd_enable(struct atkbd *atkbd) ...@@ -762,16 +567,16 @@ static int atkbd_enable(struct atkbd *atkbd)
*/ */
param[0] = 0; param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_SETREP)) if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP))
return -1; return -1;
/* /*
* Enable the keyboard to receive keystrokes. * 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", printk(KERN_ERR "atkbd.c: Failed to enable keyboard on %s\n",
atkbd->serio->phys); ps2dev->serio->phys);
return -1; return -1;
} }
...@@ -786,7 +591,7 @@ static int atkbd_enable(struct atkbd *atkbd) ...@@ -786,7 +591,7 @@ static int atkbd_enable(struct atkbd *atkbd)
static void atkbd_cleanup(struct serio *serio) static void atkbd_cleanup(struct serio *serio)
{ {
struct atkbd *atkbd = serio->private; 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 @@ static void atkbd_disconnect(struct serio *serio) ...@@ -797,7 +602,11 @@ static void atkbd_disconnect(struct serio *serio)
{ {
struct atkbd *atkbd = serio->private; 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(); synchronize_kernel();
flush_scheduled_work(); flush_scheduled_work();
...@@ -822,8 +631,7 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv) ...@@ -822,8 +631,7 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
return; return;
memset(atkbd, 0, sizeof(struct atkbd)); memset(atkbd, 0, sizeof(struct atkbd));
init_MUTEX(&atkbd->cmd_sem); ps2_init(&atkbd->ps2dev, serio);
init_waitqueue_head(&atkbd->wait);
switch (serio->type & SERIO_TYPE) { switch (serio->type & SERIO_TYPE) {
...@@ -857,8 +665,6 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv) ...@@ -857,8 +665,6 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
atkbd->dev.rep[REP_PERIOD] = 33; atkbd->dev.rep[REP_PERIOD] = 33;
} else atkbd_softraw = 1; } else atkbd_softraw = 1;
atkbd->serio = serio;
init_input_dev(&atkbd->dev); init_input_dev(&atkbd->dev);
atkbd->dev.keycode = atkbd->keycode; atkbd->dev.keycode = atkbd->keycode;
...@@ -932,7 +738,9 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv) ...@@ -932,7 +738,9 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
input_register_device(&atkbd->dev); 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); printk(KERN_INFO "input: %s on %s\n", atkbd->name, serio->phys);
} }
...@@ -953,6 +761,10 @@ static int atkbd_reconnect(struct serio *serio) ...@@ -953,6 +761,10 @@ static int atkbd_reconnect(struct serio *serio)
return -1; return -1;
} }
serio_pause_rx(serio);
atkbd->enabled = 0;
serio_continue_rx(serio);
if (atkbd->write) { if (atkbd->write) {
param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0) param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
| (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0) | (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0)
...@@ -965,11 +777,13 @@ static int atkbd_reconnect(struct serio *serio) ...@@ -965,11 +777,13 @@ static int atkbd_reconnect(struct serio *serio)
atkbd_enable(atkbd); atkbd_enable(atkbd);
if (atkbd_command(atkbd, param, ATKBD_CMD_SETLEDS)) if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
return -1; return -1;
} }
set_bit(ATKBD_FLAG_ENABLED, &atkbd->flags); serio_pause_rx(serio);
atkbd->enabled = 1;
serio_continue_rx(serio);
return 0; return 0;
} }
......
...@@ -16,6 +16,7 @@ config MOUSE_PS2 ...@@ -16,6 +16,7 @@ config MOUSE_PS2
default y default y
depends on INPUT && INPUT_MOUSE depends on INPUT && INPUT_MOUSE
select SERIO select SERIO
select SERIO_LIBPS2
select SERIO_I8042 if PC select SERIO_I8042 if PC
select SERIO_GSCPS2 if GSC select SERIO_GSCPS2 if GSC
---help--- ---help---
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/libps2.h>
#include "psmouse.h" #include "psmouse.h"
#include "alps.h" #include "alps.h"
...@@ -187,6 +188,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs * ...@@ -187,6 +188,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *
int alps_get_model(struct psmouse *psmouse) int alps_get_model(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4]; unsigned char param[4];
int i; int i;
...@@ -195,14 +197,14 @@ int alps_get_model(struct psmouse *psmouse) ...@@ -195,14 +197,14 @@ int alps_get_model(struct psmouse *psmouse)
* ALPS should return 0x00,0x00,0x0a or 0x00,0x00,0x64 * ALPS should return 0x00,0x00,0x0a or 0x00,0x00,0x64
*/ */
param[0] = 0; param[0] = 0;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES) || if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
return -1; return -1;
param[0] = param[1] = param[2] = 0xff; param[0] = param[1] = param[2] = 0xff;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO)) if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1; return -1;
dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); dbg("E6 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
...@@ -212,14 +214,14 @@ int alps_get_model(struct psmouse *psmouse) ...@@ -212,14 +214,14 @@ int alps_get_model(struct psmouse *psmouse)
/* Now try "E7 report". ALPS should return 0x33 in byte 1 */ /* Now try "E7 report". ALPS should return 0x33 in byte 1 */
param[0] = 0; param[0] = 0;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES) || if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21)) ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21))
return -1; return -1;
param[0] = param[1] = param[2] = 0xff; param[0] = param[1] = param[2] = 0xff;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO)) if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1; return -1;
dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); dbg("E7 report: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
...@@ -238,36 +240,39 @@ int alps_get_model(struct psmouse *psmouse) ...@@ -238,36 +240,39 @@ int alps_get_model(struct psmouse *psmouse)
*/ */
static int alps_passthrough_mode(struct psmouse *psmouse, int enable) static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[3]; unsigned char param[3];
int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11; int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
if (psmouse_command(psmouse, NULL, cmd) || if (ps2_command(ps2dev, NULL, cmd) ||
psmouse_command(psmouse, NULL, cmd) || ps2_command(ps2dev, NULL, cmd) ||
psmouse_command(psmouse, NULL, cmd) || ps2_command(ps2dev, NULL, cmd) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE)) ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
return -1; return -1;
/* we may get 3 more bytes, just ignore them */ /* we may get 3 more bytes, just ignore them */
psmouse_command(psmouse, param, 0x0300); ps2_command(ps2dev, param, 0x0300);
return 0; return 0;
} }
static int alps_magic_knock(struct psmouse *psmouse) static int alps_magic_knock(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
/* Try ALPS magic knock - 4 disable before enable */ /* Try ALPS magic knock - 4 disable before enable */
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
return -1; return -1;
return 0; return 0;
} }
static int alps_absolute_mode(struct psmouse *psmouse) static int alps_absolute_mode(struct psmouse *psmouse)
{ {
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
return -1; return -1;
if (alps_passthrough_mode(psmouse, 1)) if (alps_passthrough_mode(psmouse, 1))
...@@ -286,16 +291,18 @@ static int alps_absolute_mode(struct psmouse *psmouse) ...@@ -286,16 +291,18 @@ static int alps_absolute_mode(struct psmouse *psmouse)
* Switch mouse to poll (remote) mode so motion data will not * Switch mouse to poll (remote) mode so motion data will not
* get in our way * get in our way
*/ */
return psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETPOLL); return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
} }
static int alps_get_status(struct psmouse *psmouse, char *param) static int alps_get_status(struct psmouse *psmouse, char *param)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
/* Get status: 0xF5 0xF5 0xF5 0xE9 */ /* Get status: 0xF5 0xF5 0xF5 0xE9 */
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO)) ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1; return -1;
dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]); dbg("Status: %2.2x %2.2x %2.2x", param[0], param[1], param[2]);
...@@ -315,6 +322,7 @@ static int alps_get_status(struct psmouse *psmouse, char *param) ...@@ -315,6 +322,7 @@ static int alps_get_status(struct psmouse *psmouse, char *param)
static int alps_tap_mode(struct psmouse *psmouse, int model, int enable) static int alps_tap_mode(struct psmouse *psmouse, int model, int enable)
{ {
int rc = 0; int rc = 0;
struct ps2dev *ps2dev = &psmouse->ps2dev;
int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES; int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES;
unsigned char tap_arg = enable ? 0x0A : 0x00; unsigned char tap_arg = enable ? 0x0A : 0x00;
unsigned char param[4]; unsigned char param[4];
...@@ -322,10 +330,10 @@ static int alps_tap_mode(struct psmouse *psmouse, int model, int enable) ...@@ -322,10 +330,10 @@ static int alps_tap_mode(struct psmouse *psmouse, int model, int enable)
if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1)) if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 1))
return -1; return -1;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO) || if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, &tap_arg, cmd)) ps2_command(ps2dev, &tap_arg, cmd))
rc = -1; rc = -1;
if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0)) if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/libps2.h>
#include "psmouse.h" #include "psmouse.h"
#include "logips2pp.h" #include "logips2pp.h"
...@@ -97,7 +98,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha ...@@ -97,7 +98,7 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
if (psmouse_sliced_command(psmouse, command)) if (psmouse_sliced_command(psmouse, command))
return -1; return -1;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_POLL)) if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL))
return -1; return -1;
return 0; return 0;
...@@ -113,19 +114,20 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha ...@@ -113,19 +114,20 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
static void ps2pp_set_smartscroll(struct psmouse *psmouse) static void ps2pp_set_smartscroll(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4]; unsigned char param[4];
ps2pp_cmd(psmouse, param, 0x32); ps2pp_cmd(psmouse, param, 0x32);
param[0] = 0; param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
if (psmouse_smartscroll < 2) { if (psmouse_smartscroll < 2) {
/* 0 - disabled, 1 - enabled */ /* 0 - disabled, 1 - enabled */
param[0] = psmouse_smartscroll; param[0] = psmouse_smartscroll;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
} }
} }
...@@ -137,11 +139,13 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse) ...@@ -137,11 +139,13 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse)
void ps2pp_set_800dpi(struct psmouse *psmouse) void ps2pp_set_800dpi(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param = 3; unsigned char param = 3;
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, &param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
} }
static struct ps2pp_info *get_model_info(unsigned char model) static struct ps2pp_info *get_model_info(unsigned char model)
...@@ -238,18 +242,19 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_inf ...@@ -238,18 +242,19 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_inf
int ps2pp_init(struct psmouse *psmouse, int set_properties) int ps2pp_init(struct psmouse *psmouse, int set_properties)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4]; unsigned char param[4];
unsigned char protocol = PSMOUSE_PS2; unsigned char protocol = PSMOUSE_PS2;
unsigned char model, buttons; unsigned char model, buttons;
struct ps2pp_info *model_info; struct ps2pp_info *model_info;
param[0] = 0; param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
param[1] = 0; param[1] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
if (param[1] != 0) { if (param[1] != 0) {
model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78);
...@@ -263,16 +268,16 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties) ...@@ -263,16 +268,16 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
/* Unprotect RAM */ /* Unprotect RAM */
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
psmouse_command(psmouse, param, 0x30d1); ps2_command(ps2dev, param, 0x30d1);
/* Enable features */ /* Enable features */
param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b;
psmouse_command(psmouse, param, 0x30d1); ps2_command(ps2dev, param, 0x30d1);
/* Enable PS2++ */ /* Enable PS2++ */
param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3;
psmouse_command(psmouse, param, 0x30d1); ps2_command(ps2dev, param, 0x30d1);
param[0] = 0; param[0] = 0;
if (!psmouse_command(psmouse, param, 0x13d1) && if (!ps2_command(ps2dev, param, 0x13d1) &&
param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) {
protocol = PSMOUSE_PS2TPP; protocol = PSMOUSE_PS2TPP;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/libps2.h>
#include "psmouse.h" #include "psmouse.h"
#include "synaptics.h" #include "synaptics.h"
#include "logips2pp.h" #include "logips2pp.h"
...@@ -155,63 +156,17 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -155,63 +156,17 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n", printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
flags & SERIO_TIMEOUT ? " timeout" : "", flags & SERIO_TIMEOUT ? " timeout" : "",
flags & SERIO_PARITY ? " bad parity" : ""); flags & SERIO_PARITY ? " bad parity" : "");
psmouse->nak = 1; ps2_cmd_aborted(&psmouse->ps2dev);
clear_bit(PSMOUSE_FLAG_ACK, &psmouse->flags);
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
wake_up_interruptible(&psmouse->wait);
goto out; goto out;
} }
if (test_bit(PSMOUSE_FLAG_ACK, &psmouse->flags)) { if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK))
switch (data) { if (ps2_handle_ack(&psmouse->ps2dev, 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)
goto out; 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) if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD))
wake_up_interruptible(&psmouse->wait); if (ps2_handle_response(&psmouse->ps2dev, data))
goto out;
if (!psmouse->cmdcnt) {
clear_bit(PSMOUSE_FLAG_CMD, &psmouse->flags);
wake_up_interruptible(&psmouse->wait);
}
goto out;
}
if (psmouse->state == PSMOUSE_INITIALIZING) if (psmouse->state == PSMOUSE_INITIALIZING)
goto out; goto out;
...@@ -257,7 +212,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -257,7 +212,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
if (++psmouse->out_of_sync == psmouse_resetafter) { if (++psmouse->out_of_sync == psmouse_resetafter) {
psmouse->state = PSMOUSE_IGNORE; psmouse->state = PSMOUSE_IGNORE;
printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n");
serio_reconnect(psmouse->serio); serio_reconnect(psmouse->ps2dev.serio);
} }
break; break;
...@@ -277,100 +232,6 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -277,100 +232,6 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
return IRQ_HANDLED; 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 * psmouse_sliced_command() sends an extended PS/2 command to the mouse
...@@ -383,12 +244,12 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command) ...@@ -383,12 +244,12 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
{ {
int i; int i;
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11)) if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11))
return -1; return -1;
for (i = 6; i >= 0; i -= 2) { for (i = 6; i >= 0; i -= 2) {
unsigned char d = (command >> i) & 3; 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; return -1;
} }
...@@ -403,7 +264,7 @@ int psmouse_reset(struct psmouse *psmouse) ...@@ -403,7 +264,7 @@ int psmouse_reset(struct psmouse *psmouse)
{ {
unsigned char param[2]; 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; return -1;
if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID) if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID)
...@@ -418,14 +279,15 @@ int psmouse_reset(struct psmouse *psmouse) ...@@ -418,14 +279,15 @@ int psmouse_reset(struct psmouse *psmouse)
*/ */
static int genius_detect(struct psmouse *psmouse) static int genius_detect(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4]; unsigned char param[4];
param[0] = 3; param[0] = 3;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE11); ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
return param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55; return param[0] == 0x00 && param[1] == 0x33 && param[2] == 0x55;
} }
...@@ -435,15 +297,16 @@ static int genius_detect(struct psmouse *psmouse) ...@@ -435,15 +297,16 @@ static int genius_detect(struct psmouse *psmouse)
*/ */
static int intellimouse_detect(struct psmouse *psmouse) static int intellimouse_detect(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2]; unsigned char param[2];
param[0] = 200; param[0] = 200;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 100; param[0] = 100;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 80; param[0] = 80;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID); ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
return param[0] == 3; return param[0] == 3;
} }
...@@ -453,17 +316,18 @@ static int intellimouse_detect(struct psmouse *psmouse) ...@@ -453,17 +316,18 @@ static int intellimouse_detect(struct psmouse *psmouse)
*/ */
static int im_explorer_detect(struct psmouse *psmouse) static int im_explorer_detect(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2]; unsigned char param[2];
intellimouse_detect(psmouse); intellimouse_detect(psmouse);
param[0] = 200; param[0] = 200;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 200; param[0] = 200;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 80; param[0] = 80;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID); ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
return param[0] == 4; return param[0] == 4;
} }
...@@ -473,17 +337,18 @@ static int im_explorer_detect(struct psmouse *psmouse) ...@@ -473,17 +337,18 @@ static int im_explorer_detect(struct psmouse *psmouse)
*/ */
static int thinking_detect(struct psmouse *psmouse) static int thinking_detect(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2]; unsigned char param[2];
unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 }; unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 };
int i; int i;
param[0] = 10; param[0] = 10;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 0; param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
for (i = 0; seq[i]; i++) for (i = 0; seq[i]; i++)
psmouse_command(psmouse, seq + i, PSMOUSE_CMD_SETRATE); ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID); ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
return param[0] == 2; return param[0] == 2;
} }
...@@ -615,7 +480,7 @@ static int psmouse_extensions(struct psmouse *psmouse, ...@@ -615,7 +480,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
* extensions. * extensions.
*/ */
psmouse_reset(psmouse); psmouse_reset(psmouse);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS); ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
} }
return PSMOUSE_PS2; return PSMOUSE_PS2;
...@@ -627,6 +492,7 @@ static int psmouse_extensions(struct psmouse *psmouse, ...@@ -627,6 +492,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
static int psmouse_probe(struct psmouse *psmouse) static int psmouse_probe(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2]; unsigned char param[2];
/* /*
...@@ -635,8 +501,7 @@ static int psmouse_probe(struct psmouse *psmouse) ...@@ -635,8 +501,7 @@ static int psmouse_probe(struct psmouse *psmouse)
*/ */
param[0] = 0xa5; param[0] = 0xa5;
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETID))
return -1; return -1;
if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04) if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04)
...@@ -646,8 +511,8 @@ static int psmouse_probe(struct psmouse *psmouse) ...@@ -646,8 +511,8 @@ static int psmouse_probe(struct psmouse *psmouse)
* Then we reset and disable the mouse so that it doesn't generate events. * Then we reset and disable the mouse so that it doesn't generate events.
*/ */
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS)) if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS))
printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", psmouse->serio->phys); printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys);
return 0; return 0;
} }
...@@ -674,7 +539,7 @@ static void psmouse_set_resolution(struct psmouse *psmouse) ...@@ -674,7 +539,7 @@ static void psmouse_set_resolution(struct psmouse *psmouse)
else if (psmouse_resolution) else if (psmouse_resolution)
param[0] = 0; param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRES);
} }
/* /*
...@@ -687,7 +552,7 @@ static void psmouse_set_rate(struct psmouse *psmouse) ...@@ -687,7 +552,7 @@ static void psmouse_set_rate(struct psmouse *psmouse)
int i = 0; int i = 0;
while (rates[i] > psmouse_rate) i++; while (rates[i] > psmouse_rate) i++;
psmouse_command(psmouse, rates + i, PSMOUSE_CMD_SETRATE); ps2_command(&psmouse->ps2dev, rates + i, PSMOUSE_CMD_SETRATE);
} }
/* /*
...@@ -705,14 +570,14 @@ static void psmouse_initialize(struct psmouse *psmouse) ...@@ -705,14 +570,14 @@ static void psmouse_initialize(struct psmouse *psmouse)
if (psmouse_max_proto != PSMOUSE_PS2) { if (psmouse_max_proto != PSMOUSE_PS2) {
psmouse_set_rate(psmouse); psmouse_set_rate(psmouse);
psmouse_set_resolution(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. * We set the mouse into streaming mode.
*/ */
psmouse_command(psmouse, param, PSMOUSE_CMD_SETSTREAM); ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETSTREAM);
} }
/* /*
...@@ -723,11 +588,11 @@ static void psmouse_initialize(struct psmouse *psmouse) ...@@ -723,11 +588,11 @@ static void psmouse_initialize(struct psmouse *psmouse)
static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) 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->state = new_state;
psmouse->pktcnt = psmouse->cmdcnt = psmouse->out_of_sync = 0; psmouse->pktcnt = psmouse->out_of_sync = 0;
psmouse->flags = 0; psmouse->ps2dev.flags = 0;
serio_continue_rx(psmouse->serio); serio_continue_rx(psmouse->ps2dev.serio);
} }
/* /*
...@@ -736,8 +601,9 @@ static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_st ...@@ -736,8 +601,9 @@ static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_st
static void psmouse_activate(struct psmouse *psmouse) static void psmouse_activate(struct psmouse *psmouse)
{ {
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE))
printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys); printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n",
psmouse->ps2dev.serio->phys);
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
} }
...@@ -750,8 +616,9 @@ static void psmouse_activate(struct psmouse *psmouse) ...@@ -750,8 +616,9 @@ static void psmouse_activate(struct psmouse *psmouse)
static void psmouse_deactivate(struct psmouse *psmouse) static void psmouse_deactivate(struct psmouse *psmouse)
{ {
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE)) if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE))
printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", psmouse->serio->phys); printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n",
psmouse->ps2dev.serio->phys);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
} }
...@@ -821,12 +688,10 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv) ...@@ -821,12 +688,10 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv)
memset(psmouse, 0, sizeof(struct psmouse)); memset(psmouse, 0, sizeof(struct psmouse));
init_waitqueue_head(&psmouse->wait); ps2_init(&psmouse->ps2dev, serio);
init_input_dev(&psmouse->dev);
psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); 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.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
psmouse->serio = serio;
psmouse->dev.private = psmouse; psmouse->dev.private = psmouse;
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
......
...@@ -20,11 +20,6 @@ ...@@ -20,11 +20,6 @@
#define PSMOUSE_RET_ACK 0xfa #define PSMOUSE_RET_ACK 0xfa
#define PSMOUSE_RET_NAK 0xfe #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 { enum psmouse_state {
PSMOUSE_IGNORE, PSMOUSE_IGNORE,
PSMOUSE_INITIALIZING, PSMOUSE_INITIALIZING,
...@@ -42,26 +37,18 @@ typedef enum { ...@@ -42,26 +37,18 @@ typedef enum {
struct psmouse { struct psmouse {
void *private; void *private;
struct input_dev dev; struct input_dev dev;
struct serio *serio; struct ps2dev ps2dev;
char *vendor; char *vendor;
char *name; char *name;
unsigned char cmdbuf[8];
unsigned char packet[8]; unsigned char packet[8];
unsigned char cmdcnt;
unsigned char pktcnt; unsigned char pktcnt;
unsigned char type; unsigned char type;
unsigned char model; unsigned char model;
unsigned long last; unsigned long last;
unsigned long out_of_sync; unsigned long out_of_sync;
enum psmouse_state state; enum psmouse_state state;
unsigned char nak;
char error;
char devname[64]; char devname[64];
char phys[32]; 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); psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
int (*reconnect)(struct psmouse *psmouse); int (*reconnect)(struct psmouse *psmouse);
...@@ -84,7 +71,6 @@ enum psmouse_type { ...@@ -84,7 +71,6 @@ enum psmouse_type {
PSMOUSE_ALPS, PSMOUSE_ALPS,
}; };
int psmouse_command(struct psmouse *psmouse, unsigned char *param, int command);
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
int psmouse_reset(struct psmouse *psmouse); int psmouse_reset(struct psmouse *psmouse);
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/libps2.h>
#include "psmouse.h" #include "psmouse.h"
#include "synaptics.h" #include "synaptics.h"
...@@ -50,7 +51,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned ...@@ -50,7 +51,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned
{ {
if (psmouse_sliced_command(psmouse, c)) if (psmouse_sliced_command(psmouse, c))
return -1; return -1;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO)) if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1; return -1;
return 0; return 0;
} }
...@@ -65,7 +66,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) ...@@ -65,7 +66,7 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
if (psmouse_sliced_command(psmouse, mode)) if (psmouse_sliced_command(psmouse, mode))
return -1; return -1;
param[0] = SYN_PS_SET_MODE2; 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 -1;
return 0; return 0;
} }
...@@ -219,7 +220,7 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c) ...@@ -219,7 +220,7 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c)
if (psmouse_sliced_command(parent, c)) if (psmouse_sliced_command(parent, c))
return -1; return -1;
if (psmouse_command(parent, &rate_param, PSMOUSE_CMD_SETRATE)) if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE))
return -1; return -1;
return 0; return 0;
} }
...@@ -245,7 +246,7 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet ...@@ -245,7 +246,7 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
static void synaptics_pt_activate(struct psmouse *psmouse) 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 */ /* adjust the touchpad to child's choice of protocol */
if (child && child->type >= PSMOUSE_GENPS) { if (child && child->type >= PSMOUSE_GENPS) {
...@@ -270,11 +271,11 @@ static void synaptics_pt_create(struct psmouse *psmouse) ...@@ -270,11 +271,11 @@ static void synaptics_pt_create(struct psmouse *psmouse)
strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name));
strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name));
serio->write = synaptics_pt_write; serio->write = synaptics_pt_write;
serio->parent = psmouse->serio; serio->parent = psmouse->ps2dev.serio;
psmouse->pt_activate = synaptics_pt_activate; psmouse->pt_activate = synaptics_pt_activate;
psmouse->serio->child = serio; psmouse->ps2dev.serio->child = serio;
} }
/***************************************************************************** /*****************************************************************************
...@@ -470,8 +471,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r ...@@ -470,8 +471,8 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r
priv->pkt_type = synaptics_detect_pkt_type(psmouse); priv->pkt_type = synaptics_detect_pkt_type(psmouse);
if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) { if (SYN_CAP_PASS_THROUGH(priv->capabilities) && synaptics_is_pt_packet(psmouse->packet)) {
if (psmouse->serio->child) if (psmouse->ps2dev.serio->child)
synaptics_pass_pt_packet(psmouse->serio->child, psmouse->packet); synaptics_pass_pt_packet(psmouse->ps2dev.serio->child, psmouse->packet);
} else } else
synaptics_process_packet(psmouse); synaptics_process_packet(psmouse);
...@@ -561,15 +562,16 @@ static int synaptics_reconnect(struct psmouse *psmouse) ...@@ -561,15 +562,16 @@ static int synaptics_reconnect(struct psmouse *psmouse)
int synaptics_detect(struct psmouse *psmouse) int synaptics_detect(struct psmouse *psmouse)
{ {
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4]; unsigned char param[4];
param[0] = 0; param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO);
return param[1] == 0x47; return param[1] == 0x47;
} }
......
...@@ -131,6 +131,16 @@ config SERIO_MACEPS2 ...@@ -131,6 +131,16 @@ config SERIO_MACEPS2
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called maceps2. 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 config SERIO_RAW
tristate "Raw access to serio ports" tristate "Raw access to serio ports"
depends on SERIO depends on SERIO
......
...@@ -17,4 +17,5 @@ obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o ...@@ -17,4 +17,5 @@ obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o
obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
obj-$(CONFIG_SERIO_RAW) += serio_raw.o obj-$(CONFIG_SERIO_RAW) += serio_raw.o
/*
* 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;
}
#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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment