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