* because they share the same hardware.
* Johan Myreen <jem@iki.fi> 1998-10-08.
*
+ * Code fixes to handle mouse ACKs properly.
+ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
+ *
*/
#include <linux/config.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/irq.h>
/* Some configuration switches are present in the include file... */
@@ -74,16+76,18 @@ static int __init psaux_init(void);
static struct aux_queue *queue; /* Mouse data buffer. */
static int aux_count = 0;
+/* used when we send commands to the mouse that expect an ACK. */
+static unsigned char mouse_reply_expected = 0;
#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
#define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
#define MAX_RETRIES 60 /* some aux operations take long time*/
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-# define AUX_IRQ 9 /* Jensen is odd indeed */
-#else
+
+#ifndef AUX_IRQ
# define AUX_IRQ 12
#endif
+
#endif /* CONFIG_PSMOUSE */
/*
@@ -99,7+103,7 @@ static int aux_count = 0; * Controller Status register are set 0."
*/
-static inline void kb_wait(void)
+static void kb_wait(void)
{
unsigned long timeout = KBC_TIMEOUT;
@@ -235,8+239,6 @@ static unsigned char e0_keys[128] = { 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
};
-static unsigned int prev_scancode = 0; /* remember E0, E1 */
-
int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
{
if (scancode < SC_LIM || scancode > 255 || keycode > 127)
@@ -279,41+281,28 @@ static int do_acknowledge(unsigned char scancode) scancode);
#endif
}
- if (scancode == 0) {
-#ifdef KBD_REPORT_ERR
- printk(KERN_INFO "Keyboard buffer overflow\n");
-#endif
- prev_scancode = 0;
- return 0;
- }
return 1;
}
-int pckbd_pretranslate(unsigned char scancode, char raw_mode)
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+ char raw_mode)
{
- if (scancode == 0xff) {
- /* in scancode mode 1, my ESC key generates 0xff */
- /* the calculator keys on a FOCUS 9000 generate 0xff */
-#ifndef KBD_IS_FOCUS_9000
-#ifdef KBD_REPORT_ERR
- if (!raw_mode)
- printk(KERN_DEBUG "Keyboard error\n");
-#endif
-#endif
- prev_scancode = 0;
- return 0;
- }
+ static int prev_scancode = 0;
+ /* special prefix scancodes.. */
if (scancode == 0xe0 || scancode == 0xe1) {
prev_scancode = scancode;
return 0;
- }
- return 1;
-}
+ }
+
+ /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
+ if (scancode == 0x00 || scancode == 0xff) {
+ prev_scancode = 0;
+ return 0;
+ }
+
+ scancode &= 0x7f;
-int pckbd_translate(unsigned char scancode, unsigned char *keycode,
- char raw_mode)
-{
if (prev_scancode) {
/*
* usually it will be 0xe0, but a Pause key generates
@@ -400,6+389,33 @@ char pckbd_unexpected_up(unsigned char keycode) return 0200;
}
+static inline void handle_mouse_event(unsigned char scancode)
+{
+#ifdef CONFIG_PSMOUSE
+ if (mouse_reply_expected) {
+ if (scancode == AUX_ACK) {
+ mouse_reply_expected--;
+ return;
+ }
+ mouse_reply_expected = 0;
+ }
+
+ add_mouse_randomness(scancode);
+ if (aux_count) {
+ int head = queue->head;
+
+ queue->buf[head] = scancode;
+ head = (head + 1) & (AUX_BUF_SIZE-1);
+ if (head != queue->tail) {
+ queue->head = head;
+ if (queue->fasync)
+ kill_fasync(queue->fasync, SIGIO);
+ wake_up_interruptible(&queue->proc_list);
+ }
+ }
+#endif
+}
+
/*
* This reads the keyboard status port, and does the
* appropriate action.
@@ -417,24+433,10 @@ static unsigned char handle_kbd_event(void) scancode = inb(KBD_DATA_REG);
if (status & KBD_STAT_MOUSE_OBF) {
-#ifdef CONFIG_PSMOUSE
- /* Mouse data. */
- if (aux_count) {
- int head = queue->head;
- queue->buf[head] = scancode;
- add_mouse_randomness(scancode);
- head = (head + 1) & (AUX_BUF_SIZE-1);
- if (head != queue->tail) {
- queue->head = head;
- if (queue->fasync)
- kill_fasync(queue->fasync, SIGIO);
- wake_up_interruptible(&queue->proc_list);
- }
- }
-#endif
+ handle_mouse_event(scancode);
} else {
if (do_acknowledge(scancode))
- handle_scancode(scancode);
+ handle_scancode(scancode, !(scancode & 0x80));
mark_bh(KEYBOARD_BH);
}
@@ -516,11+518,14 @@ void pckbd_leds(unsigned char leds) #endif
/* for "kbd-reset" cmdline param */
-void __init kbd_reset_setup(char *str, int *ints)
+static int __init kbd_reset_setup(char *str)
{
kbd_startup_reset = 1;
+ return 1;
}
+__setup("kbd-reset", kbd_reset_setup);
+
#define KBD_NO_DATA (-1) /* No data */
#define KBD_BAD_DATA (-2) /* Parity or other error */
@@ -688,9+693,6 @@ static char * __init initialize_kbd(void)
void __init pckbd_init_hw(void)
{
- /* Get the keyboard controller registers (incomplete decode) */
- request_region(0x60, 16, "keyboard");
-
/* Flush any pending input. */
kbd_clear_input();
@@ -716,9+718,7 @@ void __init pckbd_init_hw(void) static int __init detect_auxiliary_port(void)
{
unsigned long flags;
- unsigned char status;
- unsigned char val;
- int loops = 5;
+ int loops = 10;
int retval = 0;
spin_lock_irqsave(&kbd_controller_lock, flags);
@@ -736,20+736,19 @@ static int __init detect_auxiliary_port(void) kb_wait();
outb(0x5a, KBD_DATA_REG); /* 0x5a is a random dummy value. */
- status = inb(KBD_STATUS_REG);
- while (!(status & KBD_STAT_OBF) && loops--) {
- mdelay(1);
- status = inb(KBD_STATUS_REG);
- }
+ do {
+ unsigned char status = inb(KBD_STATUS_REG);
- if (status & KBD_STAT_OBF) {
- val = inb(KBD_DATA_REG);
- if (status & KBD_STAT_MOUSE_OBF) {
- printk(KERN_INFO "Detected PS/2 Mouse Port.\n");
- retval = 1;
+ if (status & KBD_STAT_OBF) {
+ (void) inb(KBD_DATA_REG);
+ if (status & KBD_STAT_MOUSE_OBF) {
+ printk(KERN_INFO "Detected PS/2 Mouse Port.\n");
+ retval = 1;
+ }
+ break;
}
- }
-
+ mdelay(1);
+ } while (--loops);
spin_unlock_irqrestore(&kbd_controller_lock, flags);
return retval;
@@ -770,16+769,33 @@ static void aux_write_dev(int val) spin_unlock_irqrestore(&kbd_controller_lock, flags);
}
-static unsigned int get_from_queue(void)
+/*
+ * Send a byte to the mouse & handle returned ack
+ */
+static void aux_write_ack(int val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&kbd_controller_lock, flags);
+ kb_wait();
+ outb(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
+ kb_wait();
+ outb(val, KBD_DATA_REG);
+ /* we expect an ACK in response. */
+ mouse_reply_expected++;
+ kb_wait();
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
+}
+
+static unsigned char get_from_queue(void)
{
- unsigned int result;
+ unsigned char result;
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&kbd_controller_lock, flags);
result = queue->buf[queue->tail];
queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
- restore_flags(flags);
+ spin_unlock_irqrestore(&kbd_controller_lock, flags);
return result;
}
@@ -811,7+827,7 @@ static int release_aux(struct inode * inode, struct file * file) if (--aux_count)
return 0;
kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
- kbd_write(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG);
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE);
free_irq(AUX_IRQ, AUX_DEV);
return 0;
}
@@ -831,10+847,10 @@ static int open_aux(struct inode * inode, struct file * file) aux_count--;
return -EBUSY;
}
- kbd_write(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable the
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable the
auxiliary port on
controller. */
- aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */
+ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */
kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
return 0;
@@ -847,7+863,7 @@ static int open_aux(struct inode * inode, struct file * file) static ssize_t read_aux(struct file * file, char * buffer,
size_t count, loff_t *ppos)
{
- struct wait_queue wait = { current, NULL };
+ DECLARE_WAITQUEUE(wait, current);
ssize_t i = count;
unsigned char c;
@@ -856,7+872,7 @@ static ssize_t read_aux(struct file * file, char * buffer, return -EAGAIN;
add_wait_queue(&queue->proc_list, &wait);
repeat:
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
if (queue_empty() && !signal_pending(current)) {
schedule();
goto repeat;
@@ -947,17+963,17 @@ static int __init psaux_init(void) queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
memset(queue, 0, sizeof(*queue));
queue->head = queue->tail = 0;
- queue->proc_list = NULL;
+ init_waitqueue_head(&queue->proc_list);
#ifdef INITIALIZE_MOUSE
- kbd_write(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux. */
- aux_write_dev(AUX_SET_SAMPLE);
- aux_write_dev(100); /* 100 samples/sec */
- aux_write_dev(AUX_SET_RES);
- aux_write_dev(3); /* 8 counts per mm */
- aux_write_dev(AUX_SET_SCALE21); /* 2:1 scaling */
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */
+ aux_write_ack(AUX_SET_SAMPLE);
+ aux_write_ack(100); /* 100 samples/sec */
+ aux_write_ack(AUX_SET_RES);
+ aux_write_ack(3); /* 8 counts per mm */
+ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
#endif /* INITIALIZE_MOUSE */
- kbd_write(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable aux device. */
+ kbd_write(KBD_CNTL_REG, KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */
kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */
return 0;