1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * Miniature keyboard driver for bootstrap. This allows keyboard
30 * support to continue after we take over interrupts and disable
31 * BIOS keyboard support.
32 */
33
34 #include <sys/types.h>
35 #include <sys/archsystm.h>
36 #include <sys/boot_console.h>
37 #include "boot_keyboard_table.h"
38
39 #if defined(_BOOT)
40 #include "dboot/dboot_asm.h"
41 #include "dboot/dboot_xboot.h"
42 #endif /* _BOOT */
43
44 /*
45 * Definitions for BIOS keyboard state. We use BIOS's variable to store
46 * state, ensuring that we stay in sync with it.
47 */
48 #define BIOS_KB_FLAG 0x417
49 #define BIOS_RIGHT_SHIFT 0x01
50 #define BIOS_LEFT_SHIFT 0x02
51 #define BIOS_EITHER_SHIFT (BIOS_LEFT_SHIFT | BIOS_RIGHT_SHIFT)
52 #define BIOS_CTL_SHIFT 0x04
53 #define BIOS_ALT_SHIFT 0x08
54 #define BIOS_SCROLL_STATE 0x10
55 #define BIOS_NUM_STATE 0x20
56 #define BIOS_CAPS_STATE 0x40
57 #define BIOS_INS_STATE 0x80
58
59 #define BIOS_KB_FLAG_1 0x418
60 #define BIOS_SYS_SHIFT 0x04
61 #define BIOS_HOLD_STATE 0x08
62 #define BIOS_SCROLL_SHIFT 0x10
63 #define BIOS_NUM_SHIFT 0x20
64 #define BIOS_CAPS_SHIFT 0x40
65 #define BIOS_INS_SHIFT 0x80
66
67 #if defined(__xpv) && defined(_BOOT)
68
69 /*
70 * Device memory addresses
71 *
72 * In dboot under the hypervisor we don't have any memory mappings
73 * for the first meg of low memory so we can't access devices there.
74 * Intead we've mapped the device memory that we need to access into
75 * a local variable within dboot so we can access the device memory
76 * there.
77 */
78 extern unsigned short *kb_status;
79 #define kb_flag ((unsigned char *)&kb_status[BIOS_KB_FLAG])
80 #define kb_flag_1 ((unsigned char *)&kb_status[BIOS_KB_FLAG_1])
81
82 #else /* __xpv && _BOOT */
83
84 /* Device memory addresses */
85 #define kb_flag ((unsigned char *)BIOS_KB_FLAG)
86 #define kb_flag_1 ((unsigned char *)BIOS_KB_FLAG_1)
87
88 #endif /* __xpv && _BOOT */
89
90 /*
91 * Keyboard controller registers
92 */
93 #define I8042_DATA 0x60
94 #define I8042_STAT 0x64
95 #define I8042_CMD 0x64
96
97 /*
98 * Keyboard controller status register bits
99 */
100 #define I8042_STAT_OUTBF 0x01
101 #define I8042_STAT_INBF 0x02
102 #define I8042_STAT_AUXBF 0x20
103
104 /*
105 * Keyboard controller commands
106 */
107 #define I8042_RCB 0x20
108 #define I8042_WCB 0x60
109
110 /*
111 * Keyboard commands
112 */
113 #define KB_SET_LED 0xED /* LED byte follows... */
114 #define KB_LED_SCROLL_LOCK 0x01 /* Bits for LED byte */
115 #define KB_LED_NUM_LOCK 0x02
116 #define KB_LED_CAPS_LOCK 0x04
117
118 #ifndef ASSERT
119 #define ASSERT(x)
120 #endif
121
122 #define peek8(p) (*(p))
123 #define poke8(p, val) (*(p) = (val))
124
125 static struct {
126 boolean_t initialized;
127 enum { KB_LED_IDLE, KB_LED_COMMAND_SENT, KB_LED_VALUE_SENT }
128 led_state;
129 int led_commanded;
130 /*
131 * Possible values:
132 *
133 * -1 Nothing pending
134 * 0x000-0x0ff Pending byte
135 * 0x100-0x1ff Needs leading zero, then low byte next.
136 *
137 * Others undefined.
138 */
139 int pending;
140 } kb = {
141 B_FALSE, /* initialized? */
142 KB_LED_IDLE, /* LED command state */
143 -1, /* commanded LEDs - force refresh */
144 -1, /* pending */
145 };
146
147 static int kb_translate(unsigned char code);
148 static void kb_send(unsigned char cmd);
149 static void kb_update_leds(void);
150 static uchar_t kb_calculate_leds(void);
151
152 int
kb_getchar(void)153 kb_getchar(void)
154 {
155 int ret;
156
157 while (!kb_ischar())
158 /* LOOP */;
159
160 /*
161 * kb_ischar() doesn't succeed without leaving kb.pending
162 * set.
163 */
164 ASSERT(kb.pending >= 0);
165
166 if (kb.pending & 0x100) {
167 ret = 0;
168 kb.pending &= 0xff;
169 } else {
170 ret = kb.pending;
171 kb.pending = -1;
172 }
173
174 return (ret);
175 }
176
177 int
kb_ischar(void)178 kb_ischar(void)
179 {
180 unsigned char buffer_stat;
181 unsigned char code;
182 unsigned char leds;
183
184 if (!kb.initialized) {
185 kb_init();
186 kb.initialized = B_TRUE;
187 }
188
189 if (kb.pending >= 0)
190 return (1);
191
192 for (;;) {
193 buffer_stat = inb(I8042_STAT);
194 if (buffer_stat == 0xff)
195 return (0);
196 buffer_stat &= (I8042_STAT_OUTBF | I8042_STAT_AUXBF);
197
198 switch (buffer_stat) {
199 case 0:
200 case I8042_STAT_AUXBF:
201 return (0);
202 case (I8042_STAT_OUTBF | I8042_STAT_AUXBF):
203 /*
204 * Discard unwanted mouse data.
205 */
206 (void) inb(I8042_DATA);
207 continue;
208 }
209
210 code = inb(I8042_DATA);
211
212 switch (code) {
213 /*
214 * case 0xAA:
215 *
216 * You might think that we should ignore 0xAA on the
217 * grounds that it is the BAT Complete response and will
218 * occur on keyboard detach/reattach. Unfortunately,
219 * it is ambiguous - this is also the code for a break
220 * of the left shift key. Since it will be harmless for
221 * us to "spuriously" process a break of Left Shift,
222 * we just let the normal code handle it. Perhaps we
223 * should take a hint and refresh the LEDs, but I
224 * refuse to get very worried about hot-plug issues
225 * in this mini-driver.
226 */
227 case 0xFA:
228
229 switch (kb.led_state) {
230 case KB_LED_IDLE:
231 /*
232 * Spurious. Oh well, ignore it.
233 */
234 break;
235 case KB_LED_COMMAND_SENT:
236 leds = kb_calculate_leds();
237 kb_send(leds);
238 kb.led_commanded = leds;
239 kb.led_state = KB_LED_VALUE_SENT;
240 break;
241 case KB_LED_VALUE_SENT:
242 kb.led_state = KB_LED_IDLE;
243 /*
244 * Check for changes made while we were
245 * working on the last change.
246 */
247 kb_update_leds();
248 break;
249 }
250 continue;
251
252 case 0xE0:
253 case 0xE1:
254 /*
255 * These are used to distinguish the keys added on
256 * the AT-101 keyboard from the original 84 keys.
257 * We don't care, and the codes are carefully arranged
258 * so that we don't have to.
259 */
260 continue;
261
262 default:
263 if (code & 0x80) {
264 /* Release */
265 code &= 0x7f;
266 switch (keyboard_translate[code].normal) {
267 case KBTYPE_SPEC_LSHIFT:
268 poke8(kb_flag, peek8(kb_flag) &
269 ~BIOS_LEFT_SHIFT);
270 break;
271 case KBTYPE_SPEC_RSHIFT:
272 poke8(kb_flag, peek8(kb_flag) &
273 ~BIOS_RIGHT_SHIFT);
274 break;
275 case KBTYPE_SPEC_CTRL:
276 poke8(kb_flag, peek8(kb_flag) &
277 ~BIOS_CTL_SHIFT);
278 break;
279 case KBTYPE_SPEC_ALT:
280 poke8(kb_flag, peek8(kb_flag) &
281 ~BIOS_ALT_SHIFT);
282 break;
283 case KBTYPE_SPEC_CAPS_LOCK:
284 poke8(kb_flag_1, peek8(kb_flag_1) &
285 ~BIOS_CAPS_SHIFT);
286 break;
287 case KBTYPE_SPEC_NUM_LOCK:
288 poke8(kb_flag_1, peek8(kb_flag_1) &
289 ~BIOS_NUM_SHIFT);
290 break;
291 case KBTYPE_SPEC_SCROLL_LOCK:
292 poke8(kb_flag_1, peek8(kb_flag_1) &
293 ~BIOS_SCROLL_SHIFT);
294 break;
295 default:
296 /*
297 * Ignore all other releases.
298 */
299 break;
300 }
301 } else {
302 /* Press */
303
304 kb.pending = kb_translate(code);
305 if (kb.pending >= 0) {
306 return (1);
307 }
308 }
309 }
310 }
311 }
312
313 int
kb_translate(unsigned char code)314 kb_translate(unsigned char code)
315 {
316 struct keyboard_translate *k;
317 unsigned short action;
318 boolean_t shifted;
319
320 k = keyboard_translate + code;
321
322 shifted = (peek8(kb_flag) & BIOS_EITHER_SHIFT) != 0;
323
324 switch (k->normal & 0xFF00) {
325 case KBTYPE_NUMPAD:
326 if (peek8(kb_flag) & BIOS_NUM_STATE)
327 shifted = !shifted;
328 break;
329 case KBTYPE_ALPHA:
330 if (peek8(kb_flag) & BIOS_CAPS_STATE)
331 shifted = !shifted;
332 break;
333 }
334
335 if (peek8(kb_flag) & BIOS_ALT_SHIFT)
336 action = k->alted;
337 else if (peek8(kb_flag) & BIOS_CTL_SHIFT)
338 action = k->ctrled;
339 else if (shifted)
340 action = k->shifted;
341 else
342 action = k->normal;
343
344 switch (action & 0xFF00) {
345 case KBTYPE_NORMAL:
346 case KBTYPE_ALPHA:
347 return (action & 0xFF);
348
349 case KBTYPE_NUMPAD:
350 case KBTYPE_FUNC:
351 return ((action & 0xFF) | 0x100);
352
353 case KBTYPE_SPEC:
354 break;
355
356 default:
357 /*
358 * Bad entry.
359 */
360 ASSERT(0);
361 return (-1);
362 }
363
364 /*
365 * Handle special keys, mostly shifts.
366 */
367 switch (action) {
368 case KBTYPE_SPEC_NOP:
369 case KBTYPE_SPEC_UNDEF:
370 break;
371
372 case KBTYPE_SPEC_LSHIFT:
373 poke8(kb_flag, peek8(kb_flag) | BIOS_LEFT_SHIFT);
374 break;
375
376 case KBTYPE_SPEC_RSHIFT:
377 poke8(kb_flag, peek8(kb_flag) | BIOS_RIGHT_SHIFT);
378 break;
379
380 case KBTYPE_SPEC_CTRL:
381 poke8(kb_flag, peek8(kb_flag) | BIOS_CTL_SHIFT);
382 break;
383
384 case KBTYPE_SPEC_ALT:
385 poke8(kb_flag, peek8(kb_flag) | BIOS_ALT_SHIFT);
386 break;
387
388 case KBTYPE_SPEC_CAPS_LOCK:
389 if (!(peek8(kb_flag_1) & BIOS_CAPS_SHIFT)) {
390 poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_CAPS_SHIFT);
391 poke8(kb_flag, peek8(kb_flag) ^ BIOS_CAPS_STATE);
392 }
393 break;
394
395 case KBTYPE_SPEC_NUM_LOCK:
396 if (!(peek8(kb_flag_1) & BIOS_NUM_SHIFT)) {
397 poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_NUM_SHIFT);
398 poke8(kb_flag, peek8(kb_flag) ^ BIOS_NUM_STATE);
399 }
400 break;
401
402 case KBTYPE_SPEC_SCROLL_LOCK:
403 if (!(peek8(kb_flag_1) & BIOS_SCROLL_SHIFT)) {
404 poke8(kb_flag_1, peek8(kb_flag_1) | BIOS_SCROLL_SHIFT);
405 poke8(kb_flag, peek8(kb_flag) ^ BIOS_SCROLL_STATE);
406 }
407 break;
408
409 case KBTYPE_SPEC_MAYBE_REBOOT:
410 #if 0 /* Solaris doesn't reboot via ctrl-alt-del */
411 if ((peek8(kb_flag) & (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) ==
412 (BIOS_CTL_SHIFT|BIOS_ALT_SHIFT)) {
413 reset();
414 /* NOTREACHED */
415 }
416 #endif
417 break;
418
419 default:
420 /*
421 * Bad entry
422 */
423 ASSERT(0);
424 break;
425 }
426
427 /*
428 * Consider updating the LEDs. This does nothing if nothing
429 * needs to be done.
430 */
431 kb_update_leds();
432
433 return (-1);
434 }
435
436 void
kb_send(unsigned char cmd)437 kb_send(unsigned char cmd)
438 {
439 int retries;
440
441 for (retries = 0;
442 (inb(I8042_STAT) & I8042_STAT_INBF) != 0 && retries < 100000;
443 retries++)
444 /* LOOP */;
445 outb(I8042_DATA, cmd);
446 }
447
448 void
kb_update_leds(void)449 kb_update_leds(void)
450 {
451 if (kb.led_state != KB_LED_IDLE) {
452 /*
453 * The state machine will take care of any additional
454 * changes that are necessary.
455 */
456 return;
457 }
458
459 if (kb_calculate_leds() == kb.led_commanded) {
460 kb.led_state = KB_LED_IDLE;
461 } else {
462 kb_send(KB_SET_LED);
463 kb.led_state = KB_LED_COMMAND_SENT;
464 }
465 }
466
467 #define MIMR_PORT 0x21 /* Mask register for master PIC */
468 #define MIMR_KB 2 /* Keyboard mask bit in master PIC */
469
470 void
kb_init(void)471 kb_init(void)
472 {
473 /*
474 * Resist the urge to muck with the keyboard/mouse. Just assume
475 * that the bios, grub, and any optional hypervisor have left
476 * the keyboard in a sane and usable state. Messing with it now
477 * could result it making it unusuable, which would break early
478 * kmdb debugging support. Note that we don't actually need to
479 * disable interrupts for the keyboard/mouse since we're already
480 * in protected mode and we're not compeating with the bios for
481 * keyboard access. Also, we don't need to disable the mouse
482 * port since our polled input routine will just drop any mouse
483 * data that it recieves.
484 */
485 kb_update_leds();
486 }
487
488 unsigned char
kb_calculate_leds(void)489 kb_calculate_leds(void)
490 {
491 int res;
492
493 res = 0;
494
495 if (peek8(kb_flag) & BIOS_CAPS_STATE)
496 res |= KB_LED_CAPS_LOCK;
497
498 if (peek8(kb_flag) & BIOS_NUM_STATE)
499 res |= KB_LED_NUM_LOCK;
500
501 if (peek8(kb_flag) & BIOS_SCROLL_STATE)
502 res |= KB_LED_SCROLL_LOCK;
503
504 return ((char)res);
505 }
506