Commit 33124340 authored by Vojtech Pavlik's avatar Vojtech Pavlik

Add support for PS/2 Active Multiplexing Spec, updates for PS/2 mouse

and keyboard handling - proper cleanup on reboot, allow USB-emulated
AT keyboards, option to restrict PS/2 mouse to generic mode.
parent e0fcd3bc
......@@ -22,9 +22,15 @@
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("AT and PS/2 keyboard driver");
MODULE_PARM(atkbd_set, "1i");
MODULE_PARM(atkbd_reset, "1i");
MODULE_LICENSE("GPL");
static int atkbd_set = 2;
#if defined(__i386__) || defined (__x86_64__)
static int atkbd_reset;
#else
static int atkbd_reset = 1;
#endif
/*
* Scancode to keycode tables. These are just the default setting, and
......@@ -89,6 +95,7 @@ static unsigned char atkbd_set3_keycode[512] = {
#define ATKBD_CMD_RESEND 0x00fe
#define ATKBD_CMD_EX_ENABLE 0x10ea
#define ATKBD_CMD_EX_SETLEDS 0x20eb
#define ATKBD_CMD_OK_GETID 0x02e8
#define ATKBD_RET_ACK 0xfa
#define ATKBD_RET_NAK 0xfe
......@@ -113,6 +120,7 @@ struct atkbd {
unsigned char cmdbuf[4];
unsigned char cmdcnt;
unsigned char set;
unsigned char oldset;
unsigned char release;
signed char ack;
unsigned char emul;
......@@ -134,7 +142,6 @@ static void atkbd_interrupt(struct serio *serio, unsigned char data, unsigned in
printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
#endif
/* Interface error. Request that the keyboard resend. */
if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && atkbd->write) {
printk("atkbd.c: frame/parity error: %02x\n", flags);
serio_write(serio, ATKBD_CMD_RESEND);
......@@ -205,7 +212,9 @@ static int atkbd_sendbyte(struct atkbd *atkbd, unsigned char byte)
#ifdef ATKBD_DEBUG
printk(KERN_DEBUG "atkbd.c: Sent: %02x\n", byte);
#endif
serio_write(atkbd->serio, byte);
if (serio_write(atkbd->serio, byte))
return -1;
while (!atkbd->ack && timeout--) udelay(10);
return -(atkbd->ack <= 0);
......@@ -289,34 +298,41 @@ static int atkbd_event(struct input_dev *dev, unsigned int type, unsigned int co
static int atkbd_set_3(struct atkbd *atkbd)
{
unsigned char param;
unsigned char param[2];
/*
* Remember original scancode set value, so that we can restore it on exit.
*/
if (atkbd_command(atkbd, &atkbd->oldset, ATKBD_CMD_GSCANSET))
atkbd->oldset = 2;
/*
* For known special keyboards we can go ahead and set the correct set.
* We check for NCD PS/2 Sun, NorthGate OmniKey 101 and IBM RapidAccess
* keyboards.
*/
if (atkbd->id == 0xaca1) {
param = 3;
atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET);
param[0] = 3;
atkbd_command(atkbd, param, ATKBD_CMD_SSCANSET);
return 3;
}
/*
* We check for the extra keys on an some keyboards that need extra
* command to get enabled. This shouldn't harm any keyboards not
* knowing the command.
*/
if (!atkbd_command(atkbd, param, ATKBD_CMD_OK_GETID)) {
atkbd->id = param[0] << 8 | param[1];
return 2;
}
param = 0x71;
if (!atkbd_command(atkbd, &param, ATKBD_CMD_EX_ENABLE))
param[0] = 0x71;
if (!atkbd_command(atkbd, param, ATKBD_CMD_EX_ENABLE))
return 4;
/*
* Try to set the set we want.
*/
param = atkbd_set;
if (atkbd_command(atkbd, &param, ATKBD_CMD_SSCANSET))
if (atkbd_command(atkbd, &atkbd_set, ATKBD_CMD_SSCANSET))
return 2;
/*
......@@ -327,8 +343,8 @@ static int atkbd_set_3(struct atkbd *atkbd)
* In that case we time out, and return 2.
*/
param = 0;
if (atkbd_command(atkbd, &param, ATKBD_CMD_GSCANSET))
param[0] = 0;
if (atkbd_command(atkbd, param, ATKBD_CMD_GSCANSET))
return 2;
/*
......@@ -336,7 +352,7 @@ static int atkbd_set_3(struct atkbd *atkbd)
* itself.
*/
return (param == 3) ? 3 : 2;
return (param[0] == 3) ? 3 : 2;
}
/*
......@@ -353,10 +369,9 @@ static int atkbd_probe(struct atkbd *atkbd)
* these systems the BIOS also usually doesn't do it for us.
*/
#ifdef CONFIG_KEYBOARD_ATKBD_RESET
if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
printk(KERN_WARNING "atkbd.c: keyboard reset failed\n");
#endif
if (atkbd_reset)
if (atkbd_command(atkbd, NULL, ATKBD_CMD_RESET_BAT))
printk(KERN_WARNING "atkbd.c: keyboard reset failed\n");
/*
* Next we check we can set LEDs on the keyboard. This should work on every
......@@ -405,7 +420,18 @@ static int atkbd_probe(struct atkbd *atkbd)
}
/*
* atkbd_disconnect() cleans up behind us ...
* atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
* reboot.
*/
static void atkbd_cleanup(struct serio *serio)
{
struct atkbd *atkbd = serio->private;
atkbd_command(atkbd, &atkbd->oldset, ATKBD_CMD_SSCANSET);
}
/*
* atkbd_disconnect() closes and frees.
*/
static void atkbd_disconnect(struct serio *serio)
......@@ -508,18 +534,28 @@ static void atkbd_connect(struct serio *serio, struct serio_dev *dev)
static struct serio_dev atkbd_dev = {
.interrupt = atkbd_interrupt,
.connect = atkbd_connect,
.disconnect = atkbd_disconnect
.disconnect = atkbd_disconnect,
.cleanup = atkbd_cleanup,
};
#ifndef MODULE
static int __init atkbd_setup(char *str)
static int __init atkbd_setup_set(char *str)
{
int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] > 0) atkbd_set = ints[1];
return 1;
}
__setup("atkbd_set=", atkbd_setup);
static int __init atkbd_setup_reset(char *str)
{
int ints[4];
str = get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] > 0) atkbd_reset = ints[1];
return 1;
}
__setup("atkbd_set=", atkbd_setup_set);
__setup("atkbd_reset", atkbd_setup_reset);
#endif
int __init atkbd_init(void)
......
......@@ -21,8 +21,11 @@
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("PS/2 mouse driver");
MODULE_PARM(psmouse_noext, "1i");
MODULE_LICENSE("GPL");
static int psmouse_noext;
#define PSMOUSE_CMD_SETSCALE11 0x00e6
#define PSMOUSE_CMD_SETRES 0x10e8
#define PSMOUSE_CMD_GETINFO 0x03e9
......@@ -33,6 +36,7 @@ MODULE_LICENSE("GPL");
#define PSMOUSE_CMD_SETRATE 0x10f3
#define PSMOUSE_CMD_ENABLE 0x00f4
#define PSMOUSE_CMD_RESET_DIS 0x00f6
#define PSMOUSE_CMD_RESET_BAT 0x02ff
#define PSMOUSE_RET_BAT 0xaa
#define PSMOUSE_RET_ACK 0xfa
......@@ -222,7 +226,11 @@ static int psmouse_sendbyte(struct psmouse *psmouse, unsigned char byte)
psmouse->ack = 0;
psmouse->acking = 1;
serio_write(psmouse->serio, byte);
if (serio_write(psmouse->serio, byte)) {
psmouse->acking = 0;
return -1;
}
while (!psmouse->ack && timeout--) udelay(10);
return -(psmouse->ack <= 0);
......@@ -302,6 +310,9 @@ static int psmouse_extensions(struct psmouse *psmouse)
psmouse->name = "Mouse";
psmouse->model = 0;
if (psmouse_noext)
return PSMOUSE_PS2;
/*
* Try Genius NetMouse magic init.
*/
......@@ -529,15 +540,24 @@ static void psmouse_initialize(struct psmouse *psmouse)
* Last, we enable the mouse so that we get reports from it.
*/
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE)) {
if (psmouse_command(psmouse, NULL, PSMOUSE_CMD_ENABLE))
printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", psmouse->serio->phys);
}
}
/*
* psmouse_disconnect() cleans up after we don't want talk
* to the mouse anymore.
* psmouse_cleanup() resets the mouse into power-on state.
*/
static void psmouse_cleanup(struct serio *serio)
{
struct psmouse *psmouse = serio->private;
unsigned char param[2];
psmouse_command(psmouse, param, PSMOUSE_CMD_RESET_BAT);
}
/*
* psmouse_disconnect() closes and frees.
*/
static void psmouse_disconnect(struct serio *serio)
......@@ -607,9 +627,19 @@ static void psmouse_connect(struct serio *serio, struct serio_dev *dev)
static struct serio_dev psmouse_dev = {
.interrupt = psmouse_interrupt,
.connect = psmouse_connect,
.disconnect = psmouse_disconnect
.disconnect = psmouse_disconnect,
.cleanup = psmouse_cleanup,
};
#ifndef MODULE
static int __init psmouse_setup(char *str)
{
psmouse_noext = 1;
return 1;
}
__setup("psmouse_noext", psmouse_setup);
#endif
int __init psmouse_init(void)
{
serio_register_device(&psmouse_dev);
......
......@@ -13,6 +13,7 @@
#define I8042_KBD_PHYS_DESC "isa0060/serio0"
#define I8042_AUX_PHYS_DESC "isa0060/serio1"
#define I8042_MUX_PHYS_DESC "isa0060/serio%d"
/*
* IRQs.
......@@ -64,9 +65,13 @@ static inline int i8042_platform_init(void)
*/
#if !defined(__i386__) && !defined(__sh__) && !defined(__alpha__) && !defined(__x86_64__)
if (!request_region(I8042_DATA_REG, 16, "i8042"))
return 0;
return -1;
#endif
return 1;
#if !defined(__i386__) && !defined(__x86_64__)
i8042_reset = 1;
#endif
return 0;
}
static inline void i8042_platform_exit(void)
......
......@@ -14,6 +14,7 @@
#define I8042_KBD_PHYS_DESC "walnutps2/serio0"
#define I8042_AUX_PHYS_DESC "walnutps2/serio1"
#define I8042_MUX_PHYS_DESC "walnutps2/serio%d"
extern void *kb_cs;
extern void *kb_data;
......@@ -34,18 +35,17 @@ static inline int i8042_read_status(void)
static inline void i8042_write_data(int val)
{
writeb(val, kb_data);
return;
}
static inline void i8042_write_command(int val)
{
writeb(val, kb_cs);
return;
}
static inline int i8042_platform_init(void)
{
return 1;
i8042_reset = 1;
return 0;
}
static inline void i8042_platform_exit(void)
......@@ -59,6 +59,7 @@ static inline void i8042_platform_exit(void)
#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
#define I8042_MUX_PHYS_DESC "spruceps2/serio%d"
#define I8042_COMMAND_REG 0xff810000
#define I8042_DATA_REG 0xff810001
......@@ -109,18 +110,17 @@ static inline int i8042_read_status(void)
static inline void i8042_write_data(int val)
{
*((unsigned char *)0xff810000) = (char)val;
return;
}
static inline void i8042_write_command(int val)
{
*((unsigned char *)0xff810001) = (char)val;
return;
}
static inline int i8042_platform_init(void)
{
return 1;
i8042_reset = 1;
return 0;
}
static inline void i8042_platform_exit(void)
......
......@@ -11,6 +11,7 @@ static int i8042_aux_irq = -1;
#define I8042_KBD_PHYS_DESC "sparcps2/serio0"
#define I8042_AUX_PHYS_DESC "sparcps2/serio1"
#define I8042_MUX_PHYS_DESC "sparcps2/serio%d"
static unsigned long kbd_iobase;
......@@ -50,14 +51,14 @@ static int i8042_platform_init(void)
len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
if (len < 0) {
printk("i8042: Cannot get name property of root OBP node.\n");
return 0;
return -1;
}
if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) {
/* Hardcoded values for MrCoffee. */
i8042_kbd_irq = i8042_aux_irq = 13 | 0x20;
kbd_iobase = (unsigned long) ioremap(0x71300060, 8);
if (!kbd_iobase)
return 0;
return -1;
} else {
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
......@@ -69,7 +70,7 @@ static int i8042_platform_init(void)
goto edev_found;
}
}
return 0;
return -1;
edev_found:
for_each_edevchild(edev, child) {
......@@ -87,11 +88,13 @@ static int i8042_platform_init(void)
i8042_aux_irq == -1) {
printk("i8042: Error, 8042 device lacks both kbd and "
"mouse nodes.\n");
return 0;
return -1;
}
}
return 1;
i8042_reset = 1;
return 0;
}
static inline void i8042_platform_exit(void)
......
This diff is collapsed.
......@@ -21,13 +21,6 @@
#include "i8042-io.h"
#endif
/*
* If you want to trace all the i/o the i8042 module does for
* debugging purposes, define this.
*/
#undef I8042_DEBUG_IO
/*
* This is in 50us units, the time we wait for the i8042 to react. This
* has to be long enough for the i8042 itself to timeout on sending a byte
......@@ -54,6 +47,7 @@
#define I8042_STR_AUXDATA 0x20
#define I8042_STR_KEYLOCK 0x10
#define I8042_STR_CMDDAT 0x08
#define I8042_STR_MUXERR 0x04
#define I8042_STR_IBF 0x02
#define I8042_STR_OBF 0x01
......@@ -87,6 +81,9 @@
#define I8042_CMD_AUX_SEND 0x10d4
#define I8042_CMD_AUX_LOOP 0x11d3
#define I8042_CMD_MUX_PFX 0x0090
#define I8042_CMD_MUX_SEND 0x1090
/*
* Return codes.
*/
......@@ -100,4 +97,18 @@
#define I8042_BUFFER_SIZE 32
/*
* Debug.
*/
#ifdef DEBUG
static unsigned long i8042_start;
#define dbg_init() do { i8042_start = jiffies; } while (0);
#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "[%d]\n" ,\
## arg, (int) (jiffies - i8042_start))
#else
#define dbg_init() do { } while (0);
#define dbg(format, arg...) do {} while (0)
#endif
#endif /* _I8042_H */
......@@ -69,6 +69,7 @@ struct serio_dev {
void (*interrupt)(struct serio *, unsigned char, unsigned int);
void (*connect)(struct serio *, struct serio_dev *dev);
void (*disconnect)(struct serio *);
void (*cleanup)(struct serio *);
struct serio_dev *next;
};
......@@ -85,7 +86,10 @@ void serio_unregister_device(struct serio_dev *dev);
static __inline__ int serio_write(struct serio *serio, unsigned char data)
{
return serio->write(serio, data);
if (serio->write)
return serio->write(serio, data);
else
return -1;
}
static __inline__ void serio_dev_write_wakeup(struct serio *serio)
......@@ -94,6 +98,12 @@ static __inline__ void serio_dev_write_wakeup(struct serio *serio)
serio->dev->write_wakeup(serio);
}
static __inline__ void serio_cleanup(struct serio *serio)
{
if (serio->dev && serio->dev->cleanup)
serio->dev->cleanup(serio);
}
/*
* bit masks for use in "interrupt" flags (3rd argument)
*/
......
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