This patch converts the PA-RISC PS/2 keyboard & mouse driver to the input layer. New driver written by Laurent Canet & Thibaut Varene. diff -urpNX build-tools/dontdiff linus-2.5/arch/parisc/kernel/Makefile parisc-2.5/arch/parisc/kernel/Makefile --- linus-2.5/arch/parisc/kernel/Makefile Tue Nov 5 11:16:58 2002 +++ parisc-2.5/arch/parisc/kernel/Makefile Fri Nov 8 06:05:52 2002 @@ -11,7 +11,7 @@ endif AFLAGS_entry.o := -traditional AFLAGS_pacache.o := -traditional -export-objs := parisc_ksyms.o keyboard.o +export-objs := parisc_ksyms.o obj-y := cache.o pacache.o setup.o traps.o time.o irq.o \ pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \ @@ -22,7 +22,6 @@ obj-y := cache.o pacache.o setup.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_PA11) += pci-dma.o obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_VT) += keyboard.o obj-$(CONFIG_PARISC64) += binfmt_elf32.o sys_parisc32.o \ ioctl32.o signal32.o # only supported for PCX-W/U in 64-bit mode at the moment diff -urpNX build-tools/dontdiff linus-2.5/arch/parisc/kernel/keyboard.c parisc-2.5/arch/parisc/kernel/keyboard.c --- linus-2.5/arch/parisc/kernel/keyboard.c Mon Nov 11 12:47:37 2002 +++ parisc-2.5/arch/parisc/kernel/keyboard.c Wed Dec 31 17:00:00 1969 @@ -1,101 +0,0 @@ -/* - * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING - * --------------------------------------------------------------- - * This source file will be removed as soon as we have converted - * hp_psaux.c and hp_keyb.c to the input layer ! - * - */ - -/* - * linux/arch/parisc/kernel/keyboard.c - * - * Alex deVries - * Copyright (1999) The Puffin Group - * Mostly rewritten by Philipp Rumpf - * Copyright 2000 Philipp Rumpf - */ - -#include -#include -#include -#include - -static int def_setkeycode(unsigned int x, unsigned int y) -{ - return 0; -} - -static int def_getkeycode(unsigned int x) -{ - return 0; -} - -static int def_translate(unsigned char scancode, unsigned char *keycode, - char raw) -{ - *keycode = scancode; - - return 1; -} - -static char def_unexpected_up(unsigned char c) -{ - return 128; -} - -static void def_leds(unsigned char leds) -{ -} - -static void def_init_hw(void) -{ -} - -static char def_sysrq_xlate[NR_KEYS]; - -#define DEFAULT_KEYB_OPS \ - .setkeycode = def_setkeycode, \ - .getkeycode = def_getkeycode, \ - .translate = def_translate, \ - .unexpected_up = def_unexpected_up, \ - .leds = def_leds, \ - .init_hw = def_init_hw, \ - .sysrq_key = 0xff, \ - .sysrq_xlate = def_sysrq_xlate, - -static struct kbd_ops def_kbd_ops = { - DEFAULT_KEYB_OPS -}; - -struct kbd_ops *kbd_ops = &def_kbd_ops; - -void unregister_kbd_ops(void) -{ - struct kbd_ops new_kbd_ops = { DEFAULT_KEYB_OPS }; - register_kbd_ops(&new_kbd_ops); -} -EXPORT_SYMBOL(unregister_kbd_ops); - -void register_kbd_ops(struct kbd_ops *ops) -{ - if(ops->setkeycode) - kbd_ops->setkeycode = ops->setkeycode; - - if(ops->getkeycode) - kbd_ops->getkeycode = ops->getkeycode; - - if(ops->translate) - kbd_ops->translate = ops->translate; - - if(ops->unexpected_up) - kbd_ops->unexpected_up = ops->unexpected_up; - - if(ops->leds) - kbd_ops->leds = ops->leds; - - if(ops->init_hw) - kbd_ops->init_hw = ops->init_hw; - - kbd_ops->sysrq_key = ops->sysrq_key; - kbd_ops->sysrq_xlate = ops->sysrq_xlate; -} diff -urpNX build-tools/dontdiff linus-2.5/drivers/char/hp_keyb.c parisc-2.5/drivers/char/hp_keyb.c --- linus-2.5/drivers/char/hp_keyb.c Thu Jul 18 09:52:56 2002 +++ parisc-2.5/drivers/char/hp_keyb.c Wed Dec 31 17:00:00 1969 @@ -1,519 +0,0 @@ -/* - * linux/drivers/char/hp_keyb.c - * helper-functions for the keyboard/psaux driver for HP-PARISC workstations - * - * based on pc_keyb.c by Geert Uytterhoeven & Martin Mares - * - * 2000/10/26 Debacker Xavier - * Marteau Thomas - * Djoudi Malek - * - fixed some keysym defines - * - * 2001/04/28 Debacker Xavier - * - scancode translation rewritten in handle_at_scancode() - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define KBD_REPORT_ERR -#define KBD_REPORT_UNKN - -#define KBD_ESCAPEE0 0xe0 /* in */ -#define KBD_ESCAPEE1 0xe1 /* in */ - -#define ESCE0(x) (0xe000|(x)) -#define ESCE1(x) (0xe100|(x)) - -#define KBD_BAT 0xaa /* in */ -#define KBD_SETLEDS 0xed /* out */ -#define KBD_ECHO 0xee /* in/out */ -#define KBD_BREAK 0xf0 /* in */ -#define KBD_TYPRATEDLY 0xf3 /* out */ -#define KBD_SCANENABLE 0xf4 /* out */ -#define KBD_DEFDISABLE 0xf5 /* out */ -#define KBD_DEFAULT 0xf6 /* out */ -#define KBD_ACK 0xfa /* in */ -#define KBD_DIAGFAIL 0xfd /* in */ -#define KBD_RESEND 0xfe /* in/out */ -#define KBD_RESET 0xff /* out */ - -#define CODE_BREAK 1 -#define CODE_ESCAPEE0 2 -#define CODE_ESCAPEE1 4 -#define CODE_ESCAPE12 8 - -#define K_NONE 0x7f -#define K_ESC 0x01 -#define K_F1 0x3b -#define K_F2 0x3c -#define K_F3 0x3d -#define K_F4 0x3e -#define K_F5 0x3f -#define K_F6 0x40 -#define K_F7 0x41 -#define K_F8 0x42 -#define K_F9 0x43 -#define K_F10 0x44 -#define K_F11 0x57 -#define K_F12 0x58 -#define K_PRNT 0x54 -#define K_SCRL 0x46 -#define K_BRK 0x77 -#define K_AGR 0x29 -#define K_1 0x02 -#define K_2 0x03 -#define K_3 0x04 -#define K_4 0x05 -#define K_5 0x06 -#define K_6 0x07 -#define K_7 0x08 -#define K_8 0x09 -#define K_9 0x0a -#define K_0 0x0b -#define K_MINS 0x0c -#define K_EQLS 0x0d -#define K_BKSP 0x0e -#define K_INS 0x6e -#define K_HOME 0x66 -#define K_PGUP 0x68 -#define K_NUML 0x45 -#define KP_SLH 0x62 -#define KP_STR 0x37 -#define KP_MNS 0x4a -#define K_TAB 0x0f -#define K_Q 0x10 -#define K_W 0x11 -#define K_E 0x12 -#define K_R 0x13 -#define K_T 0x14 -#define K_Y 0x15 -#define K_U 0x16 -#define K_I 0x17 -#define K_O 0x18 -#define K_P 0x19 -#define K_LSBK 0x1a -#define K_RSBK 0x1b -#define K_ENTR 0x1c -#define K_DEL 111 -#define K_END 0x6b -#define K_PGDN 0x6d -#define KP_7 0x47 -#define KP_8 0x48 -#define KP_9 0x49 -#define KP_PLS 0x4e -#define K_CAPS 0x3a -#define K_A 0x1e -#define K_S 0x1f -#define K_D 0x20 -#define K_F 0x21 -#define K_G 0x22 -#define K_H 0x23 -#define K_J 0x24 -#define K_K 0x25 -#define K_L 0x26 -#define K_SEMI 0x27 -#define K_SQOT 0x28 -#define K_HASH K_NONE -#define KP_4 0x4b -#define KP_5 0x4c -#define KP_6 0x4d -#define K_LSFT 0x2a -#define K_BSLH 0x2b -#define K_Z 0x2c -#define K_X 0x2d -#define K_C 0x2e -#define K_V 0x2f -#define K_B 0x30 -#define K_N 0x31 -#define K_M 0x32 -#define K_COMA 0x33 -#define K_DOT 0x34 -#define K_FSLH 0x35 -#define K_RSFT 0x36 -#define K_UP 0x67 -#define KP_1 0x4f -#define KP_2 0x50 -#define KP_3 0x51 -#define KP_ENT 0x60 -#define K_LCTL 0x1d -#define K_LALT 0x38 -#define K_SPCE 0x39 -#define K_RALT 0x64 -#define K_RCTL 0x61 -#define K_LEFT 0x69 -#define K_DOWN 0x6c -#define K_RGHT 0x6a -#define KP_0 0x52 -#define KP_DOT 0x53 - -static unsigned char keycode_translate[256] = -{ -/* 00 */ K_NONE, K_F9 , K_NONE, K_F5 , K_F3 , K_F1 , K_F2 , K_F12 , -/* 08 */ K_NONE, K_F10 , K_F8 , K_F6 , K_F4 , K_TAB , K_AGR , K_NONE, -/* 10 */ K_NONE, K_LALT, K_LSFT, K_NONE, K_LCTL, K_Q , K_1 , K_NONE, -/* 18 */ K_NONE, K_NONE, K_Z , K_S , K_A , K_W , K_2 , K_NONE, -/* 20 */ K_NONE, K_C , K_X , K_D , K_E , K_4 , K_3 , K_NONE, -/* 28 */ K_NONE, K_SPCE, K_V , K_F , K_T , K_R , K_5 , K_NONE, -/* 30 */ K_NONE, K_N , K_B , K_H , K_G , K_Y , K_6 , K_NONE, -/* 38 */ K_NONE, K_NONE, K_M , K_J , K_U , K_7 , K_8 , K_NONE, -/* 40 */ K_NONE, K_COMA, K_K , K_I , K_O , K_0 , K_9 , K_NONE, -/* 48 */ K_NONE, K_DOT , K_FSLH, K_L , K_SEMI, K_P , K_MINS, K_NONE, -/* 50 */ K_NONE, K_NONE, K_SQOT, K_NONE, K_LSBK, K_EQLS, K_NONE, K_NONE, -/* 58 */ K_CAPS, K_RSFT, K_ENTR, K_RSBK, K_NONE, K_BSLH, K_NONE, K_NONE, -/* 60 */ K_NONE, K_HASH, K_NONE, K_NONE, K_NONE, K_NONE, K_BKSP, K_NONE, -/* 68 */ K_NONE, KP_1 , K_NONE, KP_4 , KP_7 , K_NONE, K_NONE, K_NONE, -/* 70 */ KP_0 , KP_DOT, KP_2 , KP_5 , KP_6 , KP_8 , K_ESC , K_NUML, -/* 78 */ K_F11 , KP_PLS, KP_3 , KP_MNS, KP_STR, KP_9 , K_SCRL, K_PRNT, -/* 80 */ K_NONE, K_NONE, K_NONE, K_F7 , K_NONE, K_NONE, K_NONE, K_NONE, -/* 88 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* 90 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* 98 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* a0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* a8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* b0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* b8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* c0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* c8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* d0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* d8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* e0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* e8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* f0 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, -/* f8 */ K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, K_NONE, KBD_RESEND, K_NONE -}; - -/* ----- the following code stolen from pc_keyb.c */ - - -#ifdef CONFIG_MAGIC_SYSRQ -unsigned char hp_ps2kbd_sysrq_xlate[128] = - "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ - "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ - "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ - "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ - "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ - "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ - "\r\000/"; /* 0x60 - 0x6f */ -#endif - -/* - * Translation of escaped scancodes to keycodes. - * This is now user-settable. - * The keycodes 1-88,96-111,119 are fairly standard, and - * should probably not be changed - changing might confuse X. - * X also interprets scancode 0x5d (KEY_Begin). - * - * For 1-88 keycode equals scancode. - */ - -#define E0_KPENTER 96 -#define E0_RCTRL 97 -#define E0_KPSLASH 98 -#define E0_PRSCR 99 -#define E0_RALT 100 -#define E0_BREAK 101 /* (control-pause) */ -#define E0_HOME 102 -#define E0_UP 103 -#define E0_PGUP 104 -#define E0_LEFT 105 -#define E0_RIGHT 106 -#define E0_END 107 -#define E0_DOWN 108 -#define E0_PGDN 109 -#define E0_INS 110 -#define E0_DEL 111 - -#define E1_PAUSE 119 - -/* - * The keycodes below are randomly located in 89-95,112-118,120-127. - * They could be thrown away (and all occurrences below replaced by 0), - * but that would force many users to use the `setkeycodes' utility, where - * they needed not before. It does not matter that there are duplicates, as - * long as no duplication occurs for any single keyboard. - */ -#define SC_LIM 89 /* 0x59 == 89 */ - -#define FOCUS_PF1 85 /* actual code! */ -#define FOCUS_PF2 89 -#define FOCUS_PF3 90 -#define FOCUS_PF4 91 -#define FOCUS_PF5 92 -#define FOCUS_PF6 93 -#define FOCUS_PF7 94 -#define FOCUS_PF8 95 -#define FOCUS_PF9 120 -#define FOCUS_PF10 121 -#define FOCUS_PF11 122 -#define FOCUS_PF12 123 - -#define JAP_86 124 -/* tfj@olivia.ping.dk: - * The four keys are located over the numeric keypad, and are - * labelled A1-A4. It's an rc930 keyboard, from - * Regnecentralen/RC International, Now ICL. - * Scancodes: 59, 5a, 5b, 5c. - */ -#define RGN1 124 -#define RGN2 125 -#define RGN3 126 -#define RGN4 127 - -static unsigned char high_keys[128 - SC_LIM] = { - RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ - 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ - 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ - FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ - FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ -}; - -/* BTC */ -#define E0_MACRO 112 -/* LK450 */ -#define E0_F13 113 -#define E0_F14 114 -#define E0_HELP 115 -#define E0_DO 116 -#define E0_F17 117 -#define E0_KPMINPLUS 118 -/* - * My OmniKey generates e0 4c for the "OMNI" key and the - * right alt key does nada. [kkoller@nyx10.cs.du.edu] - */ -#define E0_OK 124 -/* - * New microsoft keyboard is rumoured to have - * e0 5b (left window button), e0 5c (right window button), - * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] - * [or: Windows_L, Windows_R, TaskMan] - */ -#define E0_MSLW 125 -#define E0_MSRW 126 -#define E0_MSTM 127 - -static unsigned char e0_keys[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ - 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ - 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ - E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ - E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ - E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */ - E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ - 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ - 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ - 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ -}; - -int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) -{ - if (scancode < SC_LIM || scancode > 255 || keycode > 127) - return -EINVAL; - if (scancode < 128) - high_keys[scancode - SC_LIM] = keycode; - else - e0_keys[scancode - 128] = keycode; - return 0; -} - -int pckbd_getkeycode(unsigned int scancode) -{ - return - (scancode < SC_LIM || scancode > 255) ? -EINVAL : - (scancode < 128) ? high_keys[scancode - SC_LIM] : - e0_keys[scancode - 128]; -} - -int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode) -{ - static int prev_scancode; - - /* special prefix scancodes.. */ - if (scancode == 0xe0 || scancode == 0xe1) { - prev_scancode = scancode; - return 0; - } - - /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ - if (scancode == 0x00 || scancode == 0xff) { - prev_scancode = 0; - return 0; - } - scancode &= 0x7f; - - if (prev_scancode) { - /* - * usually it will be 0xe0, but a Pause key generates - * e1 1d 45 e1 9d c5 when pressed, and nothing when released - */ - if (prev_scancode != 0xe0) { - if (prev_scancode == 0xe1 && scancode == 0x1d) { - prev_scancode = 0x100; - return 0; - } else if (prev_scancode == 0x100 && scancode == 0x45) { - *keycode = E1_PAUSE; - prev_scancode = 0; - } else { -#ifdef KBD_REPORT_UNKN - if (!raw_mode) - printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); -#endif - prev_scancode = 0; - return 0; - } - } else { - prev_scancode = 0; - /* - * The keyboard maintains its own internal caps lock and - * num lock statuses. In caps lock mode E0 AA precedes make - * code and E0 2A follows break code. In num lock mode, - * E0 2A precedes make code and E0 AA follows break code. - * We do our own book-keeping, so we will just ignore these. - */ - /* - * For my keyboard there is no caps lock mode, but there are - * both Shift-L and Shift-R modes. The former mode generates - * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. - * So, we should also ignore the latter. - aeb@cwi.nl - */ - if (scancode == 0x2a || scancode == 0x36) - return 0; - - if (e0_keys[scancode]) - *keycode = e0_keys[scancode]; - else { -#ifdef KBD_REPORT_UNKN - if (!raw_mode) - printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", - scancode); -#endif - return 0; - } - } - } else if (scancode >= SC_LIM) { - /* This happens with the FOCUS 9000 keyboard - Its keys PF1..PF12 are reported to generate - 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f - Moreover, unless repeated, they do not generate - key-down events, so we have to zero up_flag below */ - /* Also, Japanese 86/106 keyboards are reported to - generate 0x73 and 0x7d for \ - and \ | respectively. */ - /* Also, some Brazilian keyboard is reported to produce - 0x73 and 0x7e for \ ? and KP-dot, respectively. */ - - *keycode = high_keys[scancode - SC_LIM]; - - if (!*keycode) { - if (!raw_mode) { -#ifdef KBD_REPORT_UNKN - printk(KERN_INFO "keyboard: unrecognized scancode (%02x)" - " - ignored\n", scancode); -#endif - } - return 0; - } - } else - *keycode = scancode; - - return 1; -} - -/* ----- end of stolen part ------ */ - - -void kbd_reset_setup(void) -{ -} - -void handle_at_scancode(int keyval) -{ - static int brk; - static int esc0; - static int esc1; - int scancode = 0; - - switch (keyval) { - case KBD_BREAK : - /* sets the "release_key" bit when a key is - released. HP keyboard send f0 followed by - the keycode while AT keyboard send the keycode - with this bit set. */ - brk = 0x80; - return; - case KBD_ESCAPEE0 : - /* 2chars sequence, commonly used to differenciate - the two ALT keys and the two ENTER keys and so - on... */ - esc0 = 2; /* e0-xx are 2 chars */ - scancode = keyval; - break; - case KBD_ESCAPEE1 : - /* 3chars sequence, only used by the Pause key. */ - esc1 = 3; /* e1-xx-xx are 3 chars */ - scancode = keyval; - break; -#if 0 - case KBD_RESEND : - /* dunno what to do when it happens. RFC */ - printk(KERN_INFO "keyboard: KBD_RESEND received.\n"); - return; -#endif - case 0x14 : - /* translate e1-14-77-e1-f0-14-f0-77 to - e1-1d-45-e1-9d-c5 (the Pause key) */ - if (esc1==2) scancode = brk | 0x1d; - break; - case 0x77 : - if (esc1==1) scancode = brk | 0x45; - break; - case 0x12 : - /* an extended key is e0-12-e0-xx e0-f0-xx-e0-f0-12 - on HP, while it is e0-2a-e0-xx e0-(xx|80)-f0-aa - on AT. */ - if (esc0==1) scancode = brk | 0x2a; - break; - } - - - /* translates HP scancodes to AT scancodes */ - if (!scancode) scancode = brk | keycode_translate[keyval]; - - - if (!scancode) printk(KERN_INFO "keyboard: unexpected key code %02x\n",keyval); - - /* now behave like an AT keyboard */ - handle_scancode(scancode,!(scancode&0x80)); - - if (esc0) esc0--; - if (esc1) esc1--; - - /* release key bit must be unset for the next key */ - brk = 0; -} - diff -urpNX build-tools/dontdiff linus-2.5/drivers/char/hp_psaux.c parisc-2.5/drivers/char/hp_psaux.c --- linus-2.5/drivers/char/hp_psaux.c Mon Nov 11 12:47:53 2002 +++ parisc-2.5/drivers/char/hp_psaux.c Wed Dec 31 17:00:00 1969 @@ -1,551 +0,0 @@ -/* - * LASI PS/2 keyboard/psaux driver for HP-PARISC workstations - * - * (c) Copyright 1999 The Puffin Group Inc. - * by Alex deVries - * Copyright 1999, 2000 Philipp Rumpf - * - * 2000/10/26 Debacker Xavier (debackex@esiee.fr) - * Marteau Thomas (marteaut@esiee.fr) - * Djoudi Malek (djoudim@esiee.fr) - * fixed leds control - * implemented the psaux and controlled the mouse scancode based on pc_keyb.c - */ - -#include - -#include -#include -#include - -#include -#include /* interrupt.h wants struct pt_regs defined */ -#include -#include /* for request_irq/free_irq */ -#include -#include -#include -#include -#include -#include -#include -#include - -/* mouse includes */ -#include -#include -#include -#include -#include -#include -#include - -/* HP specific LASI PS/2 keyboard and psaux constants */ -#define AUX_REPLY_ACK 0xFA /* Command byte ACK. */ -#define AUX_RECONNECT 0xAA /* scancode when ps2 device is plugged (back) in */ - -#define LASI_PSAUX_OFFSET 0x0100 /* offset from keyboard to psaux port */ - -#define LASI_ID 0x00 /* ID and reset port offsets */ -#define LASI_RESET 0x00 -#define LASI_RCVDATA 0x04 /* receive and transmit port offsets */ -#define LASI_XMTDATA 0x04 -#define LASI_CONTROL 0x08 /* see: control register bits */ -#define LASI_STATUS 0x0C /* see: status register bits */ - -/* control register bits */ -#define LASI_CTRL_ENBL 0x01 /* enable interface */ -#define LASI_CTRL_LPBXR 0x02 /* loopback operation */ -#define LASI_CTRL_DIAG 0x20 /* directly control clock/data line */ -#define LASI_CTRL_DATDIR 0x40 /* data line direct control */ -#define LASI_CTRL_CLKDIR 0x80 /* clock line direct control */ - -/* status register bits */ -#define LASI_STAT_RBNE 0x01 -#define LASI_STAT_TBNE 0x02 -#define LASI_STAT_TERR 0x04 -#define LASI_STAT_PERR 0x08 -#define LASI_STAT_CMPINTR 0x10 -#define LASI_STAT_DATSHD 0x40 -#define LASI_STAT_CLKSHD 0x80 - -static void *lasikbd_hpa; -static void *lasips2_hpa; - - -static inline u8 read_input(void *hpa) -{ - return gsc_readb(hpa+LASI_RCVDATA); -} - -static inline u8 read_control(void *hpa) -{ - return gsc_readb(hpa+LASI_CONTROL); -} - -static inline void write_control(u8 val, void *hpa) -{ - gsc_writeb(val, hpa+LASI_CONTROL); -} - -static inline u8 read_status(void *hpa) -{ - return gsc_readb(hpa+LASI_STATUS); -} - -static int write_output(u8 val, void *hpa) -{ - int wait = 0; - - while (read_status(hpa) & LASI_STAT_TBNE) { - wait++; - if (wait>10000) { - /* printk(KERN_WARNING "Lasi PS/2 transmit buffer timeout\n"); */ - return 0; - } - } - - if (wait) - printk(KERN_DEBUG "Lasi PS/2 wait %d\n", wait); - - gsc_writeb(val, hpa+LASI_XMTDATA); - - return 1; -} - -/* This function is the PA-RISC adaptation of i386 source */ - -static inline int aux_write_ack(u8 val) -{ - return write_output(val, lasikbd_hpa+LASI_PSAUX_OFFSET); -} - -static void lasikbd_leds(unsigned char leds) -{ - write_output(KBD_CMD_SET_LEDS, lasikbd_hpa); - write_output(leds, lasikbd_hpa); - write_output(KBD_CMD_ENABLE, lasikbd_hpa); -} - -#if 0 -/* this might become useful again at some point. not now -prumpf */ -int lasi_ps2_test(void *hpa) -{ - u8 control,c; - int i, ret = 0; - - control = read_control(hpa); - write_control(control | LASI_CTRL_LPBXR | LASI_CTRL_ENBL, hpa); - - for (i=0; i<256; i++) { - write_output(i, hpa); - - while (!(read_status(hpa) & LASI_STAT_RBNE)) - /* just wait */; - - c = read_input(hpa); - if (c != i) - ret--; - } - - write_control(control, hpa); - - return ret; -} -#endif - -static int __init lasi_ps2_reset(void *hpa, int id) -{ - u8 control; - int ret = 1; - - /* reset the interface */ - gsc_writeb(0xff, hpa+LASI_RESET); - gsc_writeb(0x0 , hpa+LASI_RESET); - - /* enable it */ - control = read_control(hpa); - write_control(control | LASI_CTRL_ENBL, hpa); - - /* initializes the leds at the default state */ - if (id==0) { - write_output(KBD_CMD_SET_LEDS, hpa); - write_output(0, hpa); - ret = write_output(KBD_CMD_ENABLE, hpa); - } - - return ret; -} - -static int inited; - -static void lasi_ps2_init_hw(void) -{ - ++inited; -} - - -/* Greatly inspired by pc_keyb.c */ - -/* - * Wait for keyboard controller input buffer to drain. - * - * Don't use 'jiffies' so that we don't depend on - * interrupts.. - * - * Quote from PS/2 System Reference Manual: - * - * "Address hex 0060 and address hex 0064 should be written only when - * the input-buffer-full bit and output-buffer-full bit in the - * Controller Status register are set 0." - */ -#ifdef CONFIG_PSMOUSE - -static struct aux_queue *queue; -static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED; -static unsigned char mouse_reply_expected; -static int aux_count; - -static int fasync_aux(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &queue->fasync); - if (retval < 0) - return retval; - - return 0; -} - - - -static inline void handle_mouse_scancode(unsigned char scancode) -{ - if (mouse_reply_expected) { - if (scancode == AUX_REPLY_ACK) { - mouse_reply_expected--; - return; - } - mouse_reply_expected = 0; - } - else if (scancode == AUX_RECONNECT) { - queue->head = queue->tail = 0; /* Flush input queue */ - return; - } - - 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; - kill_fasync(&queue->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&queue->proc_list); - } - } -} - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - -static unsigned char get_from_queue(void) -{ - unsigned char result; - unsigned long flags; - - spin_lock_irqsave(&kbd_controller_lock, flags); - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - spin_unlock_irqrestore(&kbd_controller_lock, flags); - - return result; -} - - -/* - * Write to the aux device. - */ - -static ssize_t write_aux(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - ssize_t retval = 0; - - if (count) { - ssize_t written = 0; - - if (count > 32) - count = 32; /* Limit to 32 bytes. */ - do { - char c; - get_user(c, buffer++); - written++; - } while (--count); - retval = -EIO; - if (written) { - retval = written; - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; - } - } - - return retval; -} - - - -static ssize_t read_aux(struct file * file, char * buffer, - size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - ssize_t i = count; - unsigned char c; - - if (queue_empty()) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&queue->proc_list, &wait); -repeat: - set_current_state(TASK_INTERRUPTIBLE); - if (queue_empty() && !signal_pending(current)) { - schedule(); - goto repeat; - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&queue->proc_list, &wait); - } - while (i > 0 && !queue_empty()) { - c = get_from_queue(); - put_user(c, buffer++); - i--; - } - if (count-i) { - file->f_dentry->d_inode->i_atime = CURRENT_TIME; - return count-i; - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - - -static int open_aux(struct inode * inode, struct file * file) -{ - if (aux_count++) - return 0; - - queue->head = queue->tail = 0; /* Flush input queue */ - aux_count = 1; - aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ - - return 0; -} - - -/* No kernel lock held - fine */ -static unsigned int aux_poll(struct file *file, poll_table * wait) -{ - - poll_wait(file, &queue->proc_list, wait); - if (!queue_empty()) - return POLLIN | POLLRDNORM; - return 0; -} - - -static int release_aux(struct inode * inode, struct file * file) -{ - lock_kernel(); - fasync_aux(-1, file, 0); - if (--aux_count) { - unlock_kernel(); - return 0; - } - unlock_kernel(); - return 0; -} - -static struct file_operations psaux_fops = { - .read = read_aux, - .write = write_aux, - .poll = aux_poll, - .open = open_aux, - .release = release_aux, - .fasync = fasync_aux, -}; - -static struct miscdevice psaux_mouse = { - .minor = PSMOUSE_MINOR, - .name = "psaux", - .fops = &psaux_fops, -}; - -#endif /* CONFIG_PSMOUSE */ - - -/* This function is looking at the PS2 controller and empty the two buffers */ - -static u8 handle_lasikbd_event(void *hpa) -{ - u8 status_keyb,status_mouse,scancode,id; - extern void handle_at_scancode(int); /* in drivers/char/keyb_at.c */ - - /* Mask to get the base address of the PS/2 controller */ - id = gsc_readb(hpa+LASI_ID) & 0x0f; - - if (id==1) - hpa -= LASI_PSAUX_OFFSET; - lasikbd_hpa = hpa; - - - status_keyb = read_status(hpa); - status_mouse = read_status(hpa+LASI_PSAUX_OFFSET); - - while ((status_keyb|status_mouse) & LASI_STAT_RBNE){ - - while (status_keyb & LASI_STAT_RBNE) { - - scancode = read_input(hpa); - - /* XXX don't know if this is a valid fix, but filtering - * 0xfa avoids 'unknown scancode' errors on, eg, capslock - * on some keyboards. - */ - if (inited && scancode != 0xfa) - handle_at_scancode(scancode); - - status_keyb =read_status(hpa); - } - -#ifdef CONFIG_PSMOUSE - while (status_mouse & LASI_STAT_RBNE) { - scancode = read_input(hpa+LASI_PSAUX_OFFSET); - handle_mouse_scancode(scancode); - status_mouse = read_status(hpa+LASI_PSAUX_OFFSET); - } - status_mouse = read_status(hpa+LASI_PSAUX_OFFSET); -#endif /* CONFIG_PSMOUSE */ - status_keyb = read_status(hpa); - } - - tasklet_schedule(&keyboard_tasklet); - return (status_keyb|status_mouse); -} - - - - -extern struct pt_regs *kbd_pt_regs; - -static void lasikbd_interrupt(int irq, void *dev, struct pt_regs *regs) -{ - lasips2_hpa = dev; /* save "hpa" for lasikbd_leds() */ - kbd_pt_regs = regs; - handle_lasikbd_event(lasips2_hpa); -} - - -extern int pckbd_translate(unsigned char, unsigned char *, char); - -static struct kbd_ops gsc_ps2_kbd_ops = { - .translate = pckbd_translate, - .init_hw = lasi_ps2_init_hw, - .leds = lasikbd_leds, -#ifdef CONFIG_MAGIC_SYSRQ - .sysrq_key = 0x54, - .sysrq_xlate = hp_ps2kbd_sysrq_xlate, -#endif -}; - -static int __init -lasi_ps2_register(struct hp_device *d, struct pa_iodc_driver *dri) -{ - void *hpa = (void *) d->hpa; - unsigned int irq; - char *name; - int device_found; - u8 id; - - id = gsc_readb(hpa+LASI_ID) & 0x0f; - - switch (id) { - case 0: - name = "keyboard"; - lasikbd_hpa = hpa; - break; - case 1: - name = "psaux"; - break; - default: - printk(KERN_WARNING "%s: Unknown PS/2 port (id=%d) - ignored.\n", - __FUNCTION__, id ); - return 0; - } - - /* reset the PS/2 port */ - device_found = lasi_ps2_reset(hpa,id); - - /* allocate the irq and memory region for that device */ - if (!(irq = busdevice_alloc_irq(d))) - return -ENODEV; - - if (request_irq(irq, lasikbd_interrupt, 0, name, hpa)) - return -ENODEV; - - if (!request_mem_region((unsigned long)hpa, LASI_STATUS + 4, name)) - return -ENODEV; - - switch (id) { - case 0: - register_kbd_ops(&gsc_ps2_kbd_ops); - break; - case 1: -#ifdef CONFIG_PSMOUSE - queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - if (!queue) - return -ENOMEM; - - memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - init_waitqueue_head(&queue->proc_list); - - misc_register(&psaux_mouse); - - aux_write_ack(AUX_ENABLE_DEV); - /* try it a second time, this will give status if the device is - * available */ - device_found = aux_write_ack(AUX_ENABLE_DEV); - break; -#else - /* return without printing any unnecessary and misleading info */ - return 0; -#endif - } /* of case */ - - printk(KERN_INFO "PS/2 %s controller at 0x%08lx (irq %d) found, " - "%sdevice attached.\n", - name, (unsigned long)hpa, irq, - device_found ? "":"no "); - - return 0; -} - - -static struct pa_iodc_driver lasi_psaux_drivers_for[] __initdata = { - {HPHW_FIO, 0x0, 0,0x00084, 0, 0, - DRIVER_CHECK_HWTYPE + DRIVER_CHECK_SVERSION, - "Lasi psaux", "generic", (void *) lasi_ps2_register}, - { 0, } -}; - -static int __init gsc_ps2_init(void) -{ - return pdc_register_driver(lasi_psaux_drivers_for); -} - -module_init(gsc_ps2_init); - diff -urpNX build-tools/dontdiff linus-2.5/drivers/input/misc/Kconfig parisc-2.5/drivers/input/misc/Kconfig --- linus-2.5/drivers/input/misc/Kconfig Thu Oct 31 10:27:26 2002 +++ parisc-2.5/drivers/input/misc/Kconfig Wed Nov 27 09:13:51 2002 @@ -56,3 +56,12 @@ config INPUT_UINPUT The module will be called uinput.o. If you want to compile it as a module, say M here and read . +config INPUT_GSC + tristate "PA-RISC GSC PS/2 keyboard/mouse support" + depends on GSC && INPUT && INPUT_MISC + help + Say Y here if you have a PS/2 keyboard and/or mouse attached + to your PA-RISC box. HP run the keyboard in AT mode rather than + XT mode like everyone else, so we need our own driver. + Furthermore, the GSC PS/2 controller shares IRQ between mouse and + keyboard. diff -urpNX build-tools/dontdiff linus-2.5/drivers/input/misc/Makefile parisc-2.5/drivers/input/misc/Makefile --- linus-2.5/drivers/input/misc/Makefile Fri Oct 18 08:23:04 2002 +++ parisc-2.5/drivers/input/misc/Makefile Wed Nov 27 09:13:51 2002 @@ -8,7 +8,4 @@ obj-$(CONFIG_INPUT_SPARCSPKR) += sparcs obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o - -# The global Rules.make. - -include $(TOPDIR)/Rules.make +obj-$(CONFIG_INPUT_GSC) += gsc_ps2.o diff -urpNX build-tools/dontdiff linus-2.5/drivers/input/misc/gsc_ps2.c parisc-2.5/drivers/input/misc/gsc_ps2.c --- linus-2.5/drivers/input/misc/gsc_ps2.c Wed Dec 31 17:00:00 1969 +++ parisc-2.5/drivers/input/misc/gsc_ps2.c Fri Nov 29 08:30:24 2002 @@ -0,0 +1,699 @@ +/* + * drivers/input/misc/gsc_ps2.c + * + * Copyright (c) 2002 Laurent Canet + * Copyright (c) 2002 Thibaut Varene + * + * Pieces of code based on linux-2.4's hp_mouse.c & hp_keyb.c + * Copyright (c) 1999 Alex deVries + * Copyright (c) 1999-2000 Philipp Rumpf + * Copyright (c) 2000 Xavier Debacker + * Copyright (c) 2000-2001 Thomas Marteau + * + * HP PS/2 Keyboard, found in PA/RISC Workstations + * very similar to AT keyboards, but without i8042 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * STATUS: + * 11/09: lc: Only basic keyboard is supported, mouse still needs to be done. + * 11/12: tv: switching iomapping; cleaning code; improving module stuff. + * 11/13: lc & tv: leds aren't working. auto_repeat/meta are. Generaly good behavior. + * 11/15: tv: 2AM: leds ARE working ! + * 11/16: tv: 3AM: escaped keycodes emulation *handled*, some keycodes are + * still deliberately ignored (18), what are they used for ? + * 11/21: lc: mouse is now working + * 11/29: tv: first try for error handling in init sequence + * + * TODO: + * Error handling in init sequence + * SysRq handling + * Pause key handling + * Intellimouse & other rodents handling (at least send an error when + * such a mouse is plugged : it will totally fault) + * Mouse: set scaling / Dino testing + * Bug chasing... + * + */ + +#include +#include +#include +#include /* interrupt.h wants struct pt_regs defined */ +#include +#include /* for request_irq/free_irq */ +#include +#include +#include +#include +#include + +#include +#include + +/* Debugging stuff */ +#undef KBD_DEBUG +#ifdef KBD_DEBUG + #define DPRINTK(fmt,args...) printk(KERN_DEBUG __FILE__ ":" fmt, ##args) +#else + #define DPRINTK(x,...) +#endif + + +/* + * Driver constants + */ + +/* PS/2 keyboard and mouse constants */ +#define AUX_RECONNECT 0xAA /* PS/2 Mouse end of test successful */ +#define AUX_REPLY_ACK 0xFA + +/* Order of the mouse bytes coming to the host */ +#define PACKET_X 1 +#define PACKET_Y 2 +#define PACKET_CTRL 0 + +#define GSC_MOUSE_OFFSET 0x0100 /* offset from keyboard to mouse port */ +#define GSC_DINO_OFFSET 0x800 /* offset for DINO controller versus LASI one */ + +#define GSC_ID 0x00 /* ID and reset port offsets */ +#define GSC_RESET 0x00 +#define GSC_RCVDATA 0x04 /* receive and transmit port offsets */ +#define GSC_XMTDATA 0x04 +#define GSC_CONTROL 0x08 /* see: control register bits */ +#define GSC_STATUS 0x0C /* see: status register bits */ + +/* Control register bits */ +#define GSC_CTRL_ENBL 0x01 /* enable interface */ +#define GSC_CTRL_LPBXR 0x02 /* loopback operation */ +#define GSC_CTRL_DIAG 0x20 /* directly control clock/data line */ +#define GSC_CTRL_DATDIR 0x40 /* data line direct control */ +#define GSC_CTRL_CLKDIR 0x80 /* clock line direct control */ + +/* Status register bits */ +#define GSC_STAT_RBNE 0x01 /* Receive Buffer Not Empty */ +#define GSC_STAT_TBNE 0x02 /* Transmit Buffer Not Empty */ +#define GSC_STAT_TERR 0x04 /* Timeout Error */ +#define GSC_STAT_PERR 0x08 /* Parity Error */ +#define GSC_STAT_CMPINTR 0x10 /* Composite Interrupt */ +#define GSC_STAT_DATSHD 0x40 /* Data Line Shadow */ +#define GSC_STAT_CLKSHD 0x80 /* Clock Line Shadow */ + +/* Keycode map */ +#define KBD_ESCAPE0 0xe0 +#define KBD_ESCAPE1 0xe1 +#define KBD_RELEASE 0xf0 +#define KBD_ACK 0xfa +#define KBD_RESEND 0xfe +#define KBD_UNKNOWN 0 + +#define KBD_TBLSIZE 512 + +/* Mouse */ +#define MOUSE_LEFTBTN 0x1 +#define MOUSE_MIDBTN 0x4 +#define MOUSE_RIGHTBTN 0x2 +#define MOUSE_ALWAYS1 0x8 +#define MOUSE_XSIGN 0x10 +#define MOUSE_YSIGN 0x20 +#define MOUSE_XOVFLOW 0x40 +#define MOUSE_YOVFLOW 0x80 + + +static unsigned char hpkeyb_keycode[KBD_TBLSIZE] = +{ + /* 00 */ KBD_UNKNOWN, KEY_F9, KBD_UNKNOWN, KEY_F5, KEY_F3, KEY_F1, KEY_F2, KEY_F12, + /* 08 */ KBD_UNKNOWN, KEY_F10, KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_GRAVE, KBD_UNKNOWN, + /* 10 */ KBD_UNKNOWN, KEY_LEFTALT, KEY_LEFTSHIFT, KBD_UNKNOWN, KEY_LEFTCTRL, KEY_Q, KEY_1, KBD_UNKNOWN, + /* 18 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_Z, KEY_S, KEY_A, KEY_W, KEY_2, KBD_UNKNOWN, + /* 20 */ KBD_UNKNOWN, KEY_C, KEY_X, KEY_D, KEY_E, KEY_4, KEY_3, KBD_UNKNOWN, + /* 28 */ KBD_UNKNOWN, KEY_SPACE, KEY_V, KEY_F, KEY_T, KEY_R, KEY_5, KBD_UNKNOWN, + /* 30 */ KBD_UNKNOWN, KEY_N, KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, KBD_UNKNOWN, + /* 38 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_M, KEY_J, KEY_U, KEY_7, KEY_8, KBD_UNKNOWN, + /* 40 */ KBD_UNKNOWN, KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, KEY_9, KBD_UNKNOWN, + /* 48 */ KBD_UNKNOWN, KEY_DOT, KEY_SLASH, KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KBD_UNKNOWN, + /* 50 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_APOSTROPHE,KBD_UNKNOWN, KEY_LEFTBRACE, KEY_EQUAL, KBD_UNKNOWN, KBD_UNKNOWN, + /* 58 */ KEY_CAPSLOCK, KEY_RIGHTSHIFT,KEY_ENTER, KEY_RIGHTBRACE,KBD_UNKNOWN, KEY_BACKSLASH,KBD_UNKNOWN, KBD_UNKNOWN, + /* 60 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_BACKSPACE, KBD_UNKNOWN, + /* 68 */ KBD_UNKNOWN, KEY_KP1, KBD_UNKNOWN, KEY_KP4, KEY_KP7, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 70 */ KEY_KP0, KEY_KPDOT, KEY_KP2, KEY_KP5, KEY_KP6, KEY_KP8, KEY_ESC, KEY_NUMLOCK, + /* 78 */ KEY_F11, KEY_KPPLUS, KEY_KP3, KEY_KPMINUS, KEY_KPASTERISK,KEY_KP9, KEY_SCROLLLOCK,KEY_103RD, + /* 80 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KEY_F7, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 88 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 90 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 98 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* a0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* a8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* b0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* b8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* c0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* c8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* d0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* d8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* e0 */ KBD_ESCAPE0, KBD_ESCAPE1, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* e8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* f0 */ KBD_RELEASE, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* f8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_ACK, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_RESEND, KBD_UNKNOWN, +/* These are offset for escaped keycodes */ + /* 00 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 08 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 10 */ KBD_UNKNOWN, KEY_RIGHTALT, KBD_UNKNOWN, KBD_UNKNOWN, KEY_RIGHTCTRL, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 18 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 20 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 28 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 30 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 38 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 40 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 48 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_KPSLASH, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 50 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 58 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_KPENTER, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 60 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 68 */ KBD_UNKNOWN, KEY_END, KBD_UNKNOWN, KEY_LEFT, KEY_HOME, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 70 */ KEY_INSERT, KEY_DELETE, KEY_DOWN, KBD_UNKNOWN, KEY_RIGHT, KEY_UP, KBD_UNKNOWN, KBD_UNKNOWN, + /* 78 */ KBD_UNKNOWN, KBD_UNKNOWN, KEY_PAGEDOWN, KBD_UNKNOWN, KEY_SYSRQ, KEY_PAGEUP, KBD_UNKNOWN, KBD_UNKNOWN, + /* 80 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 88 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 90 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* 98 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* a0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* a8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* b0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* b8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* c0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* c8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* d0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* d8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* e0 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* e8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* f0 */ KBD_RELEASE, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, + /* f8 */ KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN, KBD_UNKNOWN +}; + + +/* Keyboard struct */ +static struct { + struct input_dev dev; + char * addr; + unsigned int irq; + unsigned int scancode; + unsigned int escaped; + unsigned int released; + unsigned int initialized; +} +hpkeyb = { + .escaped = 0, + .released = 0, + .initialized = 0 +}; + +/* Mouse struct */ +static struct { + struct input_dev dev; + char * addr; + unsigned long irq; + unsigned long initialized; + int nbread; + unsigned char bytes[3]; + unsigned long last; +} +hpmouse = { + .initialized = 0, + .nbread = 0 +}; + +static spinlock_t gscps2_lock = SPIN_LOCK_UNLOCKED; + + +/* + * Various HW level routines + */ + +#define gscps2_readb_input(x) readb(x+GSC_RCVDATA) +#define gscps2_readb_control(x) readb(x+GSC_CONTROL) +#define gscps2_readb_status(x) readb(x+GSC_STATUS) +#define gscps2_writeb_control(x, y) writeb(x, y+GSC_CONTROL) + +static inline void gscps2_writeb_output(u8 val, char * addr) +{ + int wait = 250; /* Keyboard is expected to react within 250ms */ + + while (gscps2_readb_status(addr) & GSC_STAT_TBNE) { + if (!--wait) + return; /* This should not happen */ + mdelay(1); + } + writeb(val, addr+GSC_XMTDATA); +} + +static inline unsigned char gscps2_wait_input(char * addr) +{ + int wait = 250; /* Keyboard is expected to react within 250ms */ + + while (!(gscps2_readb_status(addr) & GSC_STAT_RBNE)) { + if (!--wait) + return 0; /* This should not happen */ + mdelay(1); + } + return gscps2_readb_input(addr); +} + +static int gscps2_writeb_safe_output(u8 val) +{ + /* This function waits for keyboard's ACK */ + u8 scanread = KBD_UNKNOWN; + int loop = 5; + + while (hpkeyb_keycode[scanread]!=KBD_ACK && --loop > 0) { + gscps2_writeb_output(val, hpkeyb.addr); + mdelay(5); + scanread = gscps2_wait_input(hpkeyb.addr); + } + + if (loop <= 0) + return -1; + + return 0; +} + +/* Reset the PS2 port */ +static void __init gscps2_reset(char * addr) +{ + /* reset the interface */ + writeb(0xff, addr+GSC_RESET); + writeb(0x0 , addr+GSC_RESET); + + /* enable it */ + gscps2_writeb_control(gscps2_readb_control(addr) | GSC_CTRL_ENBL, addr); +} + + +/** + * gscps2_kbd_docode() - PS2 Keyboard basic handler + * + * Receives a keyboard scancode, analyses it and sends it to the input layer. + */ + +static void gscps2_kbd_docode(void) +{ + int scancode = gscps2_readb_input(hpkeyb.addr); + DPRINTK("rel=%d scancode=%d, esc=%d ", hpkeyb.released, scancode, hpkeyb.escaped); + + /* Handle previously escaped scancodes */ + if (hpkeyb.escaped == KBD_ESCAPE0) + scancode |= 0x100; /* jump to the next 256 chars of the table */ + + switch (hpkeyb_keycode[scancode]) { + case KBD_RELEASE: + DPRINTK("release\n"); + hpkeyb.released = 1; + break; + case KBD_RESEND: + DPRINTK("resend request\n"); + break; + case KBD_ACK: + DPRINTK("ACK\n"); + break; + case KBD_ESCAPE0: + case KBD_ESCAPE1: + DPRINTK("escape code %d\n", hpkeyb_keycode[scancode]); + hpkeyb.escaped = hpkeyb_keycode[scancode]; + break; + case KBD_UNKNOWN: + DPRINTK("received unknown scancode %d, escape %d.\n", + scancode, hpkeyb.escaped); /* This is a DPRINTK atm since we do not handle escaped scancodes cleanly */ + if (hpkeyb.escaped) + hpkeyb.escaped = 0; + if (hpkeyb.released) + hpkeyb.released = 0; + return; + default: + hpkeyb.scancode = scancode; + DPRINTK("sent=%d, rel=%d\n",hpkeyb.scancode, hpkeyb.released); + input_report_key(&hpkeyb.dev, hpkeyb_keycode[hpkeyb.scancode], !hpkeyb.released); + input_sync(&hpkeyb.dev); + if (hpkeyb.escaped) + hpkeyb.escaped = 0; + if (hpkeyb.released) + hpkeyb.released = 0; + break; + } +} + + +/** + * gscps2_mouse_docode() - PS2 Mouse basic handler + * + * Receives mouse codes, processes them by packets of three, and sends + * correct events to the input layer. + */ + +static void gscps2_mouse_docode(void) +{ + int xrel, yrel; + + /* process BAT (end of basic tests) command */ + if ((hpmouse.nbread == 1) && (hpmouse.bytes[0] == AUX_RECONNECT)) + hpmouse.nbread--; + + /* stolen from psmouse.c */ + if (hpmouse.nbread && time_after(jiffies, hpmouse.last + HZ/20)) { + printk(KERN_DEBUG "%s:%d : Lost mouse synchronization, throwing %d bytes away.\n", __FILE__, __LINE__, + hpmouse.nbread); + hpmouse.nbread = 0; + } + + hpmouse.last = jiffies; + hpmouse.bytes[hpmouse.nbread++] = gscps2_readb_input(hpmouse.addr); + + /* process packet */ + if (hpmouse.nbread == 3) { + + if (!(hpmouse.bytes[PACKET_CTRL] & MOUSE_ALWAYS1)) + DPRINTK("Mouse: error on packet always1 bit checking\n"); + /* XXX should exit now, bad data on the line! */ + + if ((hpmouse.bytes[PACKET_CTRL] & (MOUSE_XOVFLOW | MOUSE_YOVFLOW))) + DPRINTK("Mouse: position overflow\n"); + + input_report_key(&hpmouse.dev, BTN_LEFT, hpmouse.bytes[PACKET_CTRL] & MOUSE_LEFTBTN); + input_report_key(&hpmouse.dev, BTN_MIDDLE, hpmouse.bytes[PACKET_CTRL] & MOUSE_MIDBTN); + input_report_key(&hpmouse.dev, BTN_RIGHT, hpmouse.bytes[PACKET_CTRL] & MOUSE_RIGHTBTN); + + xrel = hpmouse.bytes[PACKET_X]; + yrel = hpmouse.bytes[PACKET_Y]; + + /* Data sent by mouse are 9-bit signed, the sign bit is in the control packet */ + if (xrel && (hpmouse.bytes[PACKET_CTRL] & MOUSE_XSIGN)) + xrel = xrel - 0x100; + if (yrel && (hpmouse.bytes[PACKET_CTRL] & MOUSE_YSIGN)) + yrel = yrel - 0x100; + + input_report_rel(&hpmouse.dev, REL_X, xrel); + input_report_rel(&hpmouse.dev, REL_Y, -yrel); /* Y axis is received upside-down */ + + input_sync(&hpmouse.dev); + + hpmouse.nbread = 0; + } +} + + +/** + * gscps2_interrupt() - Interruption service routine + * + * This processes the list of scancodes queued and sends appropriate + * key value to the system. + */ + +static void gscps2_interrupt(int irq, void *dev, struct pt_regs *reg) +{ + /* process mouse actions */ + while (gscps2_readb_status(hpmouse.addr) & GSC_STAT_RBNE) + gscps2_mouse_docode(); + + /* process keyboard scancode */ + while (gscps2_readb_status(hpkeyb.addr) & GSC_STAT_RBNE) + gscps2_kbd_docode(); +} + + +/** + * gscps2_hpkeyb_event() - Event handler + * @return: success/error report + * + * Currently only updates leds on keyboard + */ + +int gscps2_hpkeyb_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + DPRINTK("Calling %s, type=%d, code=%d, value=%d\n", + __FUNCTION__, type, code, value); + + if (!hpkeyb.initialized) + return -1; + + if (type == EV_LED) { + u8 leds[2]; + + if (gscps2_writeb_safe_output(KBD_CMD_SET_LEDS)) { + printk(KERN_ERR "gsckbd_leds: timeout\n"); + return -1; + } + DPRINTK("KBD_CMD_SET_LEDS\n"); + + *leds = (test_bit(LED_SCROLLL, dev->led) ? LED_SCR : 0) + | (test_bit(LED_NUML, dev->led) ? LED_NUM : 0) + | (test_bit(LED_CAPSL, dev->led) ? LED_CAP : 0); + DPRINTK("Sending leds=%x\n", *leds); + + if (gscps2_writeb_safe_output(*leds)) { + printk(KERN_ERR "gsckbd_leds: timeout\n"); + return -1; + } + DPRINTK("leds sent\n"); + + if (gscps2_writeb_safe_output(KBD_CMD_ENABLE)) { + printk(KERN_ERR "gsckbd_leds: timeout\n"); + return -1; + } + DPRINTK("End\n"); + + return 0; + + } + return -1; +} + + +/** + * gscps2_kbd_probe() - Probes keyboard device and init input_dev structure + * @return: number of device initialized (1, 0 on error) + */ + +static int __init gscps2_kbd_probe(void) +{ + int i, res = 0; + unsigned long flags; + + if (hpkeyb.initialized) { + printk(KERN_ERR "GSC PS/2 keyboard driver already registered\n"); + return 0; + } + + spin_lock_irqsave(&gscps2_lock, flags); + + if (!gscps2_writeb_safe_output(KBD_CMD_SET_LEDS) && + !gscps2_writeb_safe_output(0) && + !gscps2_writeb_safe_output(KBD_CMD_ENABLE)) + res = 1; + + spin_unlock_irqrestore(&gscps2_lock, flags); + + if (!res) + printk(KERN_ERR "Keyboard initialization sequence failled\n"); + + init_input_dev(&hpkeyb.dev); + + for (i = 0; i < KBD_TBLSIZE; i++) + if (hpkeyb_keycode[i] != KBD_UNKNOWN) + set_bit(hpkeyb_keycode[i], hpkeyb.dev.keybit); + + hpkeyb.dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + hpkeyb.dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL); + hpkeyb.dev.keycode = hpkeyb_keycode; + hpkeyb.dev.keycodesize = sizeof(unsigned char); + hpkeyb.dev.keycodemax = KBD_TBLSIZE; + hpkeyb.dev.name = "GSC Keyboard"; + hpkeyb.dev.phys = "hpkbd/input0"; + + hpkeyb.dev.event = gscps2_hpkeyb_event; + + /* TODO These need some adjustement, are they really useful ? */ + hpkeyb.dev.id.bustype = BUS_GSC; + hpkeyb.dev.id.vendor = 0x0001; + hpkeyb.dev.id.product = 0x0001; + hpkeyb.dev.id.version = 0x0010; + hpkeyb.initialized = 1; + + return 1; +} + + +/** + * gscps2_mouse_probe() - Probes mouse device and init input_dev structure + * @return: number of device initialized (1, 0 on error) + * + * Currently no check on initialization is performed + */ + +static int __init gscps2_mouse_probe(void) +{ + if (hpmouse.initialized) { + printk(KERN_ERR "GSC PS/2 Mouse driver already registered\n"); + return 0; + } + + init_input_dev(&hpmouse.dev); + + hpmouse.dev.name = "GSC Mouse"; + hpmouse.dev.phys = "hpmouse/input0"; + hpmouse.dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + hpmouse.dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + hpmouse.dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); + hpmouse.last = 0; + + gscps2_writeb_output(AUX_ENABLE_DEV, hpmouse.addr); + /* Try it a second time, this will give status if the device is available */ + gscps2_writeb_output(AUX_ENABLE_DEV, hpmouse.addr); + + /* TODO These need some adjustement, are they really useful ? */ + hpmouse.dev.id.bustype = BUS_GSC; + hpmouse.dev.id.vendor = 0x0001; + hpmouse.dev.id.product = 0x0001; + hpmouse.dev.id.version = 0x0010; + hpmouse.initialized = 1; + return 1; /* XXX: we don't check if initialization failed */ +} + + +/** + * gscps2_probe() - Probes PS2 devices + * @return: success/error report + */ + +static int __init gscps2_probe(struct parisc_device *dev) +{ + u8 id; + char *addr, *name; + int ret, device_found = 0; + unsigned long hpa = dev->hpa; + + if (!dev->irq) + goto fail_pitifully; + + /* Offset for DINO PS/2. Works with LASI even */ + if (dev->id.sversion == 0x96) + hpa += GSC_DINO_OFFSET; + + addr = ioremap(hpa, 256); + + if (!hpmouse.initialized || !hpkeyb.initialized) + gscps2_reset(addr); + + ret = -EINVAL; + id = readb(addr+GSC_ID) & 0x0f; + switch (id) { + case 0: /* keyboard */ + hpkeyb.addr = addr; + name = "keyboard"; + device_found = gscps2_kbd_probe(); + break; + case 1: /* mouse */ + hpmouse.addr = addr; + name = "mouse"; + device_found = gscps2_mouse_probe(); + break; + default: + printk(KERN_WARNING "%s: Unsupported PS/2 port (id=%d) ignored\n", + __FUNCTION__, id); + goto fail_miserably; + } + + /* No valid device found */ + ret = -ENODEV; + if (!device_found) + goto fail_miserably; + + /* Here we claim only if we have a device attached */ + /* Allocate the irq and memory region for that device */ + ret = -EBUSY; + if (request_irq(dev->irq, gscps2_interrupt, 0, name, NULL)) + goto fail_miserably; + + if (!request_mem_region(hpa, GSC_STATUS + 4, name)) + goto fail_request_mem; + + /* Finalize input struct and register it */ + switch (id) { + case 0: /* keyboard */ + hpkeyb.irq = dev->irq; + input_register_device(&hpkeyb.dev); + break; + case 1: /* mouse */ + hpmouse.irq = dev->irq; + input_register_device(&hpmouse.dev); + break; + default: + break; + } + + printk(KERN_INFO "input: PS/2 %s port at 0x%08lx (irq %d) found and attached\n", + name, hpa, dev->irq); + + return 0; + +fail_request_mem: free_irq(dev->irq, NULL); +fail_miserably: iounmap(addr); +fail_pitifully: return ret; +} + + + +static struct parisc_device_id gscps2_device_tbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00084 }, /* LASI PS/2 */ +/* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00096 }, DINO PS/2 (XXX Not yet tested) */ + { 0, } /* 0 terminated list */ +}; + +static struct parisc_driver gscps2_driver = { + .name = "GSC PS2", + .id_table = gscps2_device_tbl, + .probe = gscps2_probe, +}; + +static int __init gscps2_init(void) +{ + if (register_parisc_driver(&gscps2_driver)) + return -EBUSY; + return 0; +} + +static void __exit gscps2_exit(void) +{ + /* TODO this is probably not very good and needs to be checked */ + if (hpkeyb.initialized) { + free_irq(hpkeyb.irq, gscps2_interrupt); + iounmap(hpkeyb.addr); + hpkeyb.initialized = 0; + input_unregister_device(&hpkeyb.dev); + } + if (hpmouse.initialized) { + free_irq(hpmouse.irq, gscps2_interrupt); + iounmap(hpmouse.addr); + hpmouse.initialized = 0; + input_unregister_device(&hpmouse.dev); + } + unregister_parisc_driver(&gscps2_driver); +} + + +MODULE_AUTHOR("Laurent Canet , Thibaut Varene "); +MODULE_DESCRIPTION("GSC PS/2 keyboard/mouse driver"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl); + + +module_init(gscps2_init); +module_exit(gscps2_exit); .