patch-2.4.15 linux/drivers/char/hp_keyb.c

Next file: linux/drivers/char/hp_psaux.c
Previous file: linux/drivers/char/esp.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.14/linux/drivers/char/hp_keyb.c linux/drivers/char/hp_keyb.c
@@ -0,0 +1,519 @@
+/*
+ * 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 <debackex@esiee.fr>
+ *		Marteau Thomas <marteaut@esiee.fr>
+ *		Djoudi Malek <djoudim@esiee.fr>
+ * - fixed some keysym defines 
+ *
+ * 2001/04/28	Debacker Xavier <debackex@esiee.fr>
+ * - scancode translation rewritten in handle_at_scancode()
+ */  
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/signal.h>
+#include <linux/timer.h>
+#include <linux/random.h>
+#include <linux/ctype.h>
+#include <linux/kbd_ll.h>
+#include <linux/init.h>
+
+#include <asm/bitops.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#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;
+}
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)