1 /*
2  *  linux/arch/m68k/hp300/hil.c
3  *
4  *  Copyright (C) 1998 Philip Blundell <philb@gnu.org>
5  *
6  *  HP300 Human Interface Loop driver.  This handles the keyboard and mouse.
7  */
8 
9 #include <linux/stddef.h>
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/init.h>
13 #include <linux/keyboard.h>
14 #include <linux/kbd_ll.h>
15 #include <asm/io.h>
16 #include <asm/hwtest.h>
17 #include <asm/ptrace.h>
18 #include <asm/irq.h>
19 #include <asm/system.h>
20 
21 #define HILBASE			0xf0428000
22 #define HIL_DATA			0x1
23 #define HIL_CMD			0x3
24 
25 #define	HIL_BUSY		0x02
26 #define	HIL_DATA_RDY		0x01
27 
28 #define hil_busy()		(in_8(HILBASE + HIL_CMD) & HIL_BUSY)
29 #define hil_data_available()	(in_8(HILBASE + HIL_CMD) & HIL_DATA_RDY)
30 #define hil_status()		(in_8(HILBASE + HIL_CMD))
31 #define hil_command(x)		out_8(HILBASE + HIL_CMD, (x))
32 #define hil_read_data()		(in_8(HILBASE + HIL_DATA))
33 #define hil_write_data(x)	out_8(HILBASE + HIL_DATA, (x))
34 
35 #define	HIL_SETARD		0xA0		/* set auto-repeat delay */
36 #define	HIL_SETARR		0xA2		/* set auto-repeat rate */
37 #define	HIL_SETTONE		0xA3		/* set tone generator */
38 #define	HIL_CNMT		0xB2		/* clear nmi */
39 #define	HIL_INTON		0x5C		/* Turn on interrupts. */
40 #define	HIL_INTOFF		0x5D		/* Turn off interrupts. */
41 #define	HIL_TRIGGER		0xC5		/* trigger command */
42 #define	HIL_STARTCMD		0xE0		/* start loop command */
43 #define	HIL_TIMEOUT		0xFE		/* timeout */
44 #define	HIL_READTIME		0x13		/* Read real time register */
45 
46 #define	HIL_READBUSY		0x02		/* internal "busy" register */
47 #define	HIL_READKBDLANG		0x12		/* read keyboard language code */
48 #define	HIL_READKBDSADR	 	0xF9
49 #define	HIL_WRITEKBDSADR 	0xE9
50 #define	HIL_READLPSTAT  	0xFA
51 #define	HIL_WRITELPSTAT 	0xEA
52 #define	HIL_READLPCTRL  	0xFB
53 #define	HIL_WRITELPCTRL 	0xEB
54 
55 #define HIL_IRQ			1
56 
57 #define plain_map		hp_plain_map
58 #define shift_map		hp_shift_map
59 #define altgr_map		hp_altgr_map
60 #define ctrl_map		hp_ctrl_map
61 #define shift_ctrl_map		hp_shift_ctrl_map
62 #define alt_map			hp_alt_map
63 #define ctrl_alt_map		hp_ctrl_alt_map
64 
65 u_short plain_map[NR_KEYS] = {
66 	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
67 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
68 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
69 	0xfb62,	0xfb76,	0xfb63,	0xfb78,	0xfb7a,	0xf200,	0xf200,	0xf01b,
70 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
71 	0xfb68,	0xfb67,	0xfb66,	0xfb64,	0xfb73,	0xfb61,	0xf200,	0xf207,
72 	0xfb75,	0xfb79,	0xfb74,	0xfb72,	0xfb65,	0xfb77,	0xfb71,	0xf009,
73 	0xf037,	0xf036,	0xf035,	0xf034,	0xf033,	0xf032,	0xf031,	0xf060,
74 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
75 	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
76 	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
77 	0xf038,	0xf039,	0xf030,	0xf02d,	0xf03d,	0xf008,	0xf200,	0xf200,
78 	0xfb69,	0xfb6f,	0xfb70,	0xf05b,	0xf05d,	0xf05c,	0xf200,	0xf200,
79 	0xfb6a,	0xfb6b,	0xfb6c,	0xf03b,	0xf027,	0xf201,	0xf200,	0xf200,
80 	0xfb6d,	0xf02c,	0xf02e,	0xf02f,	0xf200,	0xf200,	0xf200,	0xf200,
81 	0xfb6e,	0xf020,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
82 };
83 
84 u_short shift_map[NR_KEYS] = {
85 	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
86 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
87 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
88 	0xfb42,	0xfb56,	0xfb43,	0xfb58,	0xfb5a,	0xf200,	0xf200,	0xf07f,
89 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
90 	0xfb48,	0xfb47,	0xfb46,	0xfb44,	0xfb53,	0xfb41,	0xf200,	0xf207,
91 	0xfb55,	0xfb59,	0xfb54,	0xfb52,	0xfb45,	0xfb57,	0xfb51,	0xf009,
92 	0xf026,	0xf05e,	0xf025,	0xf024,	0xf023,	0xf040,	0xf021,	0xf07e,
93 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
94 	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
95 	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
96 	0xf02a,	0xf028,	0xf029,	0xf05f,	0xf02b,	0xf200,	0xf200,	0xf200,
97 	0xfb49,	0xfb4f,	0xfb50,	0xf07b,	0xf07d,	0xf07c,	0xf200,	0xf200,
98 	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,	0xf022,	0xf201,	0xf200,	0xf200,
99 	0xfb4d,	0xf03c,	0xf03e,	0xf03f,	0xf200,	0xf200,	0xf200,	0xf200,
100 	0xfb4e,	0xf020,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
101 };
102 
103 u_short altgr_map[NR_KEYS] = {
104 	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
105 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
106 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
107 	0xfb62,	0xfb76,	0xfb63,	0xfb78,	0xfb7a,	0xf200,	0xf200,	0xf200,
108 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
109 	0xfb68,	0xfb67,	0xfb66,	0xfb64,	0xfb73,	0xfb61,	0xf200,	0xf207,
110 	0xfb75,	0xfb79,	0xfb74,	0xfb72,	0xfb65,	0xfb77,	0xfb71,	0xf200,
111 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf040,	0xf021,	0xf200,
112 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
113 	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
114 	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
115 	0xf02a,	0xf05b,	0xf05d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
116 	0xfb69,	0xfb6f,	0xfb70,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
117 	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,	0xf200,	0xf201,	0xf200,	0xf200,
118 	0xfb6d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
119 	0xfb6e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
120 };
121 
122 u_short ctrl_map[NR_KEYS] = {
123 	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
124 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
125 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
126 	0xf002,	0xf016,	0xf003,	0xf018,	0xf01a,	0xf200,	0xf200,	0xf200,
127 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
128 	0xf008,	0xf007,	0xf006,	0xf004,	0xf013,	0xf001,	0xf200,	0xf207,
129 	0xf015,	0xf019,	0xf014,	0xf012,	0xf005,	0xf017,	0xf011,	0xf200,
130 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf000,
131 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
132 	0xf200,	0xf503,	0xf502,	0xf501,	0xf500,	0xf200,	0xf200,	0xf200,
133 	0xf200,	0xf504,	0xf505,	0xf506,	0xf507,	0xf200,	0xf200,	0xf200,
134 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
135 	0xf009,	0xf00f,	0xf010,	0xf200,	0xf200,	0xf01c,	0xf200,	0xf200,
136 	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf007,	0xf201,	0xf200,	0xf200,
137 	0xf00d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
138 	0xf00e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
139 };
140 
141 u_short shift_ctrl_map[NR_KEYS] = {
142 	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
143 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
144 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
145 	0xf002,	0xf016,	0xf003,	0xf018,	0xf01a,	0xf200,	0xf200,	0xf200,
146 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
147 	0xf008,	0xf007,	0xf006,	0xf004,	0xf013,	0xf001,	0xf200,	0xf207,
148 	0xf015,	0xf019,	0xf014,	0xf012,	0xf005,	0xf017,	0xf011,	0xf200,
149 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
150 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
151 	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
152 	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
153 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
154 	0xf009,	0xf00f,	0xf010,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
155 	0xf00a,	0xf00b,	0xf00c,	0xf200,	0xf200,	0xf201,	0xf200,	0xf200,
156 	0xf00d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
157 	0xf00e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
158 };
159 
160 u_short alt_map[NR_KEYS] = {
161 	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
162 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
163 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
164 	0xf862,	0xf876,	0xf863,	0xf878,	0xf87a,	0xf200,	0xf200,	0xf200,
165 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
166 	0xf868,	0xf867,	0xf866,	0xf864,	0xf873,	0xf861,	0xf200,	0xf207,
167 	0xf875,	0xf879,	0xf874,	0xf872,	0xf865,	0xf877,	0xf871,	0xf809,
168 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf860,
169 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
170 	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
171 	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
172 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
173 	0xf869,	0xf86f,	0xf870,	0xf200,	0xf200,	0xf85c,	0xf200,	0xf200,
174 	0xf86a,	0xf86b,	0xf86c,	0xf83b,	0xf827,	0xf201,	0xf200,	0xf200,
175 	0xf86d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
176 	0xf86e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
177 };
178 
179 u_short ctrl_alt_map[NR_KEYS] = {
180 	0xf200,	0xf200,	0xf703,	0xf703,	0xf700,	0xf700,	0xf702,	0xf200,
181 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
182 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
183 	0xf802,	0xf816,	0xf803,	0xf818,	0xf81a,	0xf200,	0xf200,	0xf200,
184 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
185 	0xf808,	0xf807,	0xf806,	0xf804,	0xf813,	0xf801,	0xf200,	0xf207,
186 	0xf815,	0xf819,	0xf814,	0xf812,	0xf805,	0xf817,	0xf811,	0xf200,
187 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
188 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
189 	0xf200,	0xf103,	0xf102,	0xf101,	0xf100,	0xf200,	0xf200,	0xf200,
190 	0xf200,	0xf104,	0xf105,	0xf106,	0xf107,	0xf200,	0xf200,	0xf200,
191 	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
192 	0xf809,	0xf80f,	0xf810,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
193 	0xf80a,	0xf80b,	0xf80c,	0xf200,	0xf200,	0xf201,	0xf200,	0xf200,
194 	0xf80d,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
195 	0xf80e,	0xf200,	0xf200,	0xf200,	0xf601,	0xf600,	0xf603,	0xf602,
196 };
197 
198 #undef plain_map
199 #undef ctrl_alt_map
200 #undef shift_map
201 #undef altgr_map
202 #undef ctrl_map
203 #undef shift_ctrl_map
204 #undef alt_map
205 
206 struct {
207   unsigned char s, c;
208   int valid;
209 } hil_last;
210 
211 #define hil_getlast(s,c)  do { s = hil_last.s; c = hil_last.c; hil_last.valid = 0; } while (0)
212 
213 struct {
214   unsigned char data[16];
215   unsigned int ptr;
216 } poll;
217 
218 unsigned char curdev = 0;
219 
poll_finished(void)220 static void poll_finished(void)
221 {
222   switch (poll.data[0])
223   {
224   case 0x40:
225     {
226       int down = (poll.data[1] & 1) == 0;
227       unsigned char scode = poll.data[1] >> 1;
228 #if 0
229       if (down)
230 	printk("[%02x]", scode);
231 #endif
232       handle_scancode(scode, down);
233     }
234     break;
235   }
236   curdev = 0;
237 }
238 
handle_status(unsigned char s,unsigned char c)239 static inline void handle_status(unsigned char s, unsigned char c)
240 {
241   if (c & 0x8) {
242     /* End of block */
243     if (c & 0x10)
244       poll_finished();
245   } else {
246     if (c & 0x10) {
247       if (curdev)
248 	poll_finished();		/* just in case */
249       curdev = c & 7;
250       poll.ptr = 0;
251     }
252   }
253 }
254 
handle_data(unsigned char s,unsigned char c)255 static inline void handle_data(unsigned char s, unsigned char c)
256 {
257   if (curdev)
258     poll.data[poll.ptr++] = c;
259 }
260 
261 /*
262  * Handle HIL interrupts.
263  */
264 
hil_interrupt(int irq,void * handle,struct pt_regs * regs)265 static void hil_interrupt(int irq, void *handle, struct pt_regs *regs)
266 {
267   unsigned char s, c;
268   s = hil_status(); c = hil_read_data();
269   switch (s >> 4)
270   {
271   case 0x5:
272     handle_status(s, c);
273     break;
274   case 0x6:
275     handle_data(s, c);
276     break;
277   case 0x4:
278     hil_last.s = s;
279     hil_last.c = c;
280     mb();
281     hil_last.valid = 1;
282     break;
283   }
284 }
285 
286 /*
287  * Send a command to the HIL
288  */
289 
hil_do(unsigned char cmd,unsigned char * data,unsigned int len)290 static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
291 {
292   unsigned long flags;
293   save_flags(flags); cli();
294   while (hil_busy());
295   hil_command(cmd);
296   while (len--) {
297     while (hil_busy());
298     hil_write_data(*(data++));
299   }
300   restore_flags(flags);
301 }
302 
303 /*
304  * Initialise HIL.
305  */
306 
hp300_keyb_init(void)307 int __init hp300_keyb_init(void)
308 {
309   unsigned char s, c, kbid;
310   unsigned int n = 0;
311 
312   memcpy(key_maps[0], hp_plain_map, sizeof(plain_map));
313   memcpy(key_maps[1], hp_shift_map, sizeof(plain_map));
314   memcpy(key_maps[4], hp_ctrl_map, sizeof(plain_map));
315 
316   if (!hwreg_present((void *)(HILBASE + HIL_DATA)))
317     return 1;		/* maybe this can happen */
318 
319   request_irq(HIL_IRQ, hil_interrupt, 0, "HIL", NULL);
320 
321   /* Turn on interrupts */
322   hil_do(HIL_INTON, NULL, 0);
323 
324   /* Look for keyboards */
325   hil_do(HIL_READKBDSADR, NULL, 0);
326   while (!hil_last.valid) {
327     if (n++ > 100000) {
328       printk("HIL: timed out, assuming no keyboard present.\n");
329       return 1;
330     }
331     mb();
332   }
333   hil_getlast(s, c);
334   if (c == 0) {
335     printk("HIL: no keyboard present.\n");
336     return 1;
337   }
338   for (kbid = 0; (kbid < 8) && ((c & (1<<kbid)) == 0); kbid++);
339   printk("HIL: keyboard found at id %d\n", kbid);
340   /* set it to raw mode */
341   c = 0;
342   hil_do(HIL_WRITEKBDSADR, &c, 1);
343   return 0;
344 }
345