--- pc_keyb.c.old Thu Jun 8 14:33:31 2000 +++ pc_keyb.c Wed Jun 7 22:12:14 2000 @@ -13,8 +13,13 @@ * Code fixes to handle mouse ACKs properly. * C. Scott Ananian 1999-01-29. * + * Added code to support G1200-S stylus (ps/2 class device) + * Monty R. Walls 2000-05-25. + * */ +#define G1200S_PEN 1 + #include #include @@ -30,6 +35,9 @@ #include #include #include +#ifdef G1200S_PEN +#include +#endif #include #include @@ -82,6 +90,25 @@ #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*/ + +#ifdef G1200S_PEN + +#define PEN_ENABLE 0x01 +#define PEN_DISABLE 0x00 +#define PEN_LOAD 0x11 +#define PEN_CMD_BYTE 0xbf +#define PEN_CMOS_FLAG 0x41 +#define PEN_CMOS_DATA 0x5a +#define PEN_CMOS_LENGTH 0x1c + +static struct pen_command_buffer { + unsigned char opcode; + unsigned char buffer[PEN_CMOS_LENGTH]; +} penbuf; + +static int using_pen; + +#endif /* G1200S_PEN */ #endif /* CONFIG_PSMOUSE */ /* @@ -294,7 +321,7 @@ prev_scancode = 0; return 0; } - + scancode &= 0x7f; if (prev_scancode) { @@ -527,7 +554,8 @@ #define KBD_NO_DATA (-1) /* No data */ #define KBD_BAD_DATA (-2) /* Parity or other error */ -static int __init kbd_read_data(void) +/* needed also by pen open */ +static int kbd_read_data(void) { int retval = KBD_NO_DATA; unsigned char status; @@ -553,7 +581,8 @@ } while (--maxread); } -static int __init kbd_wait_for_input(void) +/* needed also by pen open */ +static int kbd_wait_for_input(void) { long timeout = KBD_INIT_TIMEOUT; @@ -598,6 +627,22 @@ kbd_write_output(cmd); spin_unlock_irqrestore(&kbd_controller_lock, flags); } +#ifdef G1200S_PEN +static int kbd_read_cmd(void) +{ + int data; + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kb_wait(); + kbd_write_command(KBD_CCMD_READ_MODE); + kb_wait(); + data = kbd_wait_for_input(); + spin_unlock_irqrestore(&kbd_controller_lock, flags); + + return (data); +} +#endif #endif /* CONFIG_PSMOUSE */ static char * __init initialize_kbd(void) @@ -721,7 +766,85 @@ } #if defined CONFIG_PSMOUSE +#ifdef G1200S_PEN +static int pen_packet_io(unsigned char *src, int scnt, unsigned char *dest, int dcnt) +{ + int n; + + kbd_write_command_w(PEN_CMD_BYTE); + + while (scnt-- > 0) + kbd_write_output_w(*src++); + + /* this doesn't make sense to me, but it's what the win31 + * driver did, so ... + */ + if ((n = kbd_wait_for_input()) & 0xf0) + return (n); + + if (!dcnt) + return (n); + + n &= 0x0f; + if (n < dcnt) + dcnt = n; + + /* if we're here dest is non-null & dcnt is non-zero */ + while (dcnt-- > 0) + *dest++ = kbd_wait_for_input(); + + return (-1); /* no value, not error */ +} + +static int pen_readwrite(unsigned char *src, int scnt, unsigned char *dest, int dcnt) +{ + int c, r; + + c = kbd_read_cmd(); + kbd_write_cmd(c & ~(KBD_MODE_KBD_INT|KBD_MODE_MOUSE_INT)); /* disable keyboard & mouse interrupts */ + + r = pen_packet_io(src, scnt, dest, dcnt); + + kbd_write_cmd(c); + + return (r); +} + +static int pen_write_cmd(int op) +{ + penbuf.opcode = (op & 0x0f) | 0x50; + + return (pen_readwrite((unsigned char *)&penbuf, 1, NULL, 0)); +} + +/* + * check and see if anything is connect to the ps2 mouse port + */ + +static int __init detect_connected(void) +{ + /* send a command to the ps2 mouse type device and + * check for success for execution of that command. + * If that works, we can ignore the pen and + * return true here. + */ + int ps2 = 0; +#if 0 + unsigned long flags; + + spin_lock_irqsave(&kbd_controller_lock, flags); + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); + + /* put test here */ + + kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); + spin_unlock_irqrestore(&kbd_controller_lock, flags); +#endif + return (ps2); +} + +#endif /* G1200S_PEN */ /* * Check if this is a dual port controller. */ @@ -837,7 +960,20 @@ if (--aux_count) return 0; kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ +#ifdef G1200S_PEN + if (using_pen) { + /* disable 8042 */ + kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); + kbd_write_command_w(KBD_CCMD_KBD_DISABLE); + + pen_write_cmd(PEN_DISABLE); + + /* enable 8042 keyboard */ + kbd_write_command_w(KBD_CCMD_KBD_ENABLE); + } +#else kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); +#endif aux_free_irq(AUX_DEV); return 0; } @@ -857,10 +993,30 @@ aux_count--; return -EBUSY; } +#ifdef G1200S_PEN + if (using_pen) { + /* disable 8042 */ + kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); + kbd_write_command_w(KBD_CCMD_KBD_DISABLE); + + pen_write_cmd(PEN_ENABLE); + + /* enable 8042 */ + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); + kbd_write_command_w(KBD_CCMD_KBD_ENABLE); + } + else { + kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the + auxiliary port on + controller. */ + aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ + } +#else kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable the auxiliary port on controller. */ aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ +#endif kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */ return 0; @@ -957,6 +1113,69 @@ fasync_aux, }; +#ifdef G1200S_PEN +static unsigned int read_cmos(unsigned int port) +{ + unsigned int flags; + unsigned char c; + + save_flags(flags); + cli(); + c = CMOS_READ(port); + restore_flags(flags); + return (c); +} + +static void pen_read_cmos(char *dest, int dcnt) +{ + int idx = PEN_CMOS_DATA; + + while (dcnt-- > 0) { + *dest++ = read_cmos(idx++); + } +} + +/* load calibration to pen device(with retries), then activate pen */ +static void pen_load_calibration(void) +{ + unsigned long flags; + int cnt, v; + + printk(KERN_INFO "Detected Pen, loading calibration.\n"); + + spin_lock_irqsave(&kbd_controller_lock, flags); + + penbuf.opcode = PEN_LOAD; + pen_read_cmos((unsigned char *)&penbuf.buffer[0], PEN_CMOS_LENGTH); + + /* disable 8042 */ + kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); + kbd_write_command_w(KBD_CCMD_KBD_DISABLE); + + for (cnt = 20; cnt > 0; --cnt) { + if ((pen_readwrite((unsigned char *)&penbuf, sizeof(penbuf), NULL, 0) & 0xf0) == 0) + break; + + mdelay(1); + } + + /* enable 8042 */ + kbd_write_command_w(KBD_CCMD_KBD_ENABLE); + + spin_unlock_irqrestore(&kbd_controller_lock, flags); + + printk(KERN_INFO "Detected Pen, finished loading calibration.\n"); + +} + +static int pen_has_calibration(void) +{ + printk(KERN_INFO "Detecting PS/2 Pen Port.\n"); + return ((read_cmos(PEN_CMOS_FLAG) & 0x80) != 0x80); +} + +#endif + /* * Initialize driver. */ @@ -974,7 +1193,7 @@ memset(queue, 0, sizeof(*queue)); queue->head = queue->tail = 0; queue->proc_list = NULL; - +#ifndef G1200S_PEN #ifdef INITIALIZE_MOUSE kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux. */ aux_write_ack(AUX_SET_SAMPLE); @@ -983,6 +1202,14 @@ aux_write_ack(3); /* 8 counts per mm */ aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ #endif /* INITIALIZE_MOUSE */ +#else + /* Test for a ps/2 device, and not initialize the + * pen if the ps/2 device is connected. + */ + if (detect_connected() == 0) + if ((using_pen = pen_has_calibration()) != 0) + pen_load_calibration(); +#endif kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable aux device. */ kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints. */