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
default y
depends on INPUT && INPUT_KEYBOARD
select SERIO
select SERIO_LIBPS2
select SERIO_I8042 if PC
select SERIO_GSCPS2 if GSC
help
......
......@@ -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 @@ static unsigned char atkbd_scroll_keys[5][2] = {
{ ATKBD_SCR_CLICK, 0x60 },
};
#define ATKBD_FLAG_ACK 0 /* Waiting for ACK/NAK */
#define ATKBD_FLAG_CMD 1 /* Waiting for command to finish */
#define ATKBD_FLAG_CMD1 2 /* First byte of command response */
#define ATKBD_FLAG_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 @@ struct atkbd {
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 @@ struct atkbd {
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 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
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;
}
if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK))
if (ps2_handle_ack(&atkbd->ps2dev, data))
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) {
clear_bit(ATKBD_FLAG_CMD, &atkbd->flags);
wake_up_interruptible(&atkbd->wait);
}
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 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
switch (code) {
case ATKBD_RET_BAT:
clear_bit(ATKBD_FLAG_ENABLED, &atkbd->flags);
serio_rescan(atkbd->serio);
atkbd->enabled = 0;
serio_rescan(atkbd->ps2dev.serio);
goto out;
case ATKBD_RET_EMUL0:
atkbd->emul = 1;
......@@ -427,151 +374,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
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 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
| (test_bit(LED_NUML, dev->led) ? 2 : 0)
| (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
atkbd_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 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
| (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
| (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
| (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
atkbd_schedule_command(atkbd, param, ATKBD_CMD_EX_SETLEDS);
ps2_schedule_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
}
return 0;
......@@ -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_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_event(struct input_dev *dev, unsigned int type, unsigned int co
static int atkbd_probe(struct atkbd *atkbd)
{
struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[2];
/*
......@@ -647,8 +450,8 @@ static int atkbd_probe(struct atkbd *atkbd)
*/
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 @@ static int atkbd_probe(struct atkbd *atkbd)
*/
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 @@ static int atkbd_probe(struct atkbd *atkbd)
* 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_probe(struct atkbd *atkbd)
static int atkbd_set_3(struct atkbd *atkbd)
{
struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[2];
/*
......@@ -706,13 +510,13 @@ static int atkbd_set_3(struct atkbd *atkbd)
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 @@ static int atkbd_set_3(struct atkbd *atkbd)
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 @@ static int atkbd_enable(struct atkbd *atkbd)
*/
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 @@ static int atkbd_enable(struct atkbd *atkbd)
*/
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 int atkbd_enable(struct atkbd *atkbd)
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 @@ static void atkbd_disconnect(struct serio *serio)
{
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 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
return;
memset(atkbd, 0, sizeof(struct atkbd));
init_MUTEX(&atkbd->cmd_sem);
init_waitqueue_head(&atkbd->wait);
ps2_init(&atkbd->ps2dev, serio);
switch (serio->type & SERIO_TYPE) {
......@@ -857,8 +665,6 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
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 @@ static void atkbd_connect(struct serio *serio, struct serio_driver *drv)
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 @@ static int atkbd_reconnect(struct serio *serio)
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 @@ static int atkbd_reconnect(struct serio *serio)
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;
}
......
......@@ -16,6 +16,7 @@ config MOUSE_PS2
default y
depends on INPUT && INPUT_MOUSE
select SERIO
select SERIO_LIBPS2
select SERIO_I8042 if PC
select SERIO_GSCPS2 if GSC
---help---
......
......@@ -15,6 +15,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/libps2.h>
#include "psmouse.h"
#include "alps.h"
......@@ -187,6 +188,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *
int alps_get_model(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
int i;
......@@ -195,14 +197,14 @@ int alps_get_model(struct psmouse *psmouse)
* ALPS should return 0x00,0x00,0x0a or 0x00,0x00,0x64
*/
param[0] = 0;
if (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))
if (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))
return -1;
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;
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)
/* Now try "E7 report". ALPS should return 0x33 in byte 1 */
param[0] = 0;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_SETSCALE21))
if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21))
return -1;
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;
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)
*/
static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[3];
int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
if (psmouse_command(psmouse, NULL, cmd) ||
psmouse_command(psmouse, NULL, cmd) ||
psmouse_command(psmouse, NULL, cmd) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE))
if (ps2_command(ps2dev, NULL, cmd) ||
ps2_command(ps2dev, NULL, cmd) ||
ps2_command(ps2dev, NULL, cmd) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
return -1;
/* we may get 3 more bytes, just ignore them */
psmouse_command(psmouse, param, 0x0300);
ps2_command(ps2dev, param, 0x0300);
return 0;
}
static int alps_magic_knock(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
/* Try ALPS magic knock - 4 disable before enable */
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
return -1;
return 0;
}
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;
if (alps_passthrough_mode(psmouse, 1))
......@@ -286,16 +291,18 @@ static int alps_absolute_mode(struct psmouse *psmouse)
* Switch mouse to poll (remote) mode so motion data will not
* 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)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
/* Get status: 0xF5 0xF5 0xF5 0xE9 */
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO))
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
return -1;
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)
static int alps_tap_mode(struct psmouse *psmouse, int model, int enable)
{
int rc = 0;
struct ps2dev *ps2dev = &psmouse->ps2dev;
int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES;
unsigned char tap_arg = enable ? 0x0A : 0x00;
unsigned char param[4];
......@@ -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))
return -1;
if (psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, NULL, PSMOUSE_CMD_DISABLE) ||
psmouse_command(psmouse, &tap_arg, cmd))
if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
ps2_command(ps2dev, &tap_arg, cmd))
rc = -1;
if (model == ALPS_MODEL_DUALPOINT && alps_passthrough_mode(psmouse, 0))
......
......@@ -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 @@ static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
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 int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned cha
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 @@ static void ps2pp_set_smartscroll(struct psmouse *psmouse)
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, &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_SETRES);
}
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
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 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
/* 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;
}
......
......@@ -19,6 +19,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"
......@@ -155,63 +156,17 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n",
flags & SERIO_TIMEOUT ? " timeout" : "",
flags & SERIO_PARITY ? " bad parity" : "");
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:
if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK))
if (ps2_handle_ack(&psmouse->ps2dev, data))
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;
}
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);
}
if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD))
if (ps2_handle_response(&psmouse->ps2dev, data))
goto out;
}
if (psmouse->state == PSMOUSE_INITIALIZING)
goto out;
......@@ -257,7 +212,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
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;
......@@ -277,100 +232,6 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
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
......@@ -383,12 +244,12 @@ int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command)
{
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;
}
......@@ -403,7 +264,7 @@ int psmouse_reset(struct psmouse *psmouse)
{
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)
......@@ -418,14 +279,15 @@ int psmouse_reset(struct psmouse *psmouse)
*/
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;
}
......@@ -435,15 +297,16 @@ static int genius_detect(struct psmouse *psmouse)
*/
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;
}
......@@ -453,17 +316,18 @@ static int intellimouse_detect(struct psmouse *psmouse)
*/
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;
}
......@@ -473,17 +337,18 @@ static int im_explorer_detect(struct psmouse *psmouse)
*/
static int thinking_detect(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 };
int i;
param[0] = 10;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRATE);
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 0;
psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES);
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
for (i = 0; seq[i]; i++)
psmouse_command(psmouse, seq + i, PSMOUSE_CMD_SETRATE);
psmouse_command(psmouse, param, PSMOUSE_CMD_GETID);
ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE);
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
return param[0] == 2;
}
......@@ -615,7 +480,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
* extensions.
*/
psmouse_reset(psmouse);
psmouse_command(psmouse, NULL, PSMOUSE_CMD_RESET_DIS);
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
}
return PSMOUSE_PS2;
......@@ -627,6 +492,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
static int psmouse_probe(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
/*
......@@ -635,8 +501,7 @@ static int psmouse_probe(struct psmouse *psmouse)
*/
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)
......@@ -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.
*/
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;
}
......@@ -674,7 +539,7 @@ static void psmouse_set_resolution(struct psmouse *psmouse)
else if (psmouse_resolution)
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)
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);
}
/*
......@@ -705,14 +570,14 @@ static void psmouse_initialize(struct psmouse *psmouse)
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);
}
/*
......@@ -723,11 +588,11 @@ static void psmouse_initialize(struct psmouse *psmouse)
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);
}
/*
......@@ -736,8 +601,9 @@ static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_st
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);
}
......@@ -750,8 +616,9 @@ static void psmouse_activate(struct psmouse *psmouse)
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);
}
......@@ -821,12 +688,10 @@ static void psmouse_connect(struct serio *serio, struct serio_driver *drv)
memset(psmouse, 0, sizeof(struct psmouse));
init_waitqueue_head(&psmouse->wait);
init_input_dev(&psmouse->dev);
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);
......
......@@ -20,11 +20,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,
......@@ -42,26 +37,18 @@ typedef enum {
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);
......@@ -84,7 +71,6 @@ enum psmouse_type {
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_reset(struct psmouse *psmouse);
......
......@@ -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 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned
{
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 @@ static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode)
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 @@ static int synaptics_pt_write(struct serio *serio, unsigned char c)
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_pass_pt_packet(struct serio *ptport, unsigned char *packet
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 @@ static void synaptics_pt_create(struct psmouse *psmouse)
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 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_r
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 @@ static int synaptics_reconnect(struct psmouse *psmouse)
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;
}
......
......@@ -131,6 +131,16 @@ config SERIO_MACEPS2
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
......
......@@ -17,4 +17,5 @@ obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o
obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
obj-$(CONFIG_SERIO_LIBPS2) += libps2.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