Annotation of prex-old/dev/i386/pc/kbd.c, Revision 1.1.1.1
1.1 nbrk 1: /*-
2: * Copyright (c) 2005, Kohsuke Ohtani
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. Neither the name of the author nor the names of any co-contributors
14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: */
29:
30: /*
31: * kbd.c - keyboard driver for PC
32: */
33:
34: #include <driver.h>
35: #include <prex/keycode.h>
36: #include <sys/tty.h>
37: #include <cpu.h>
38: #include <pm.h>
39: #include "kmc.h"
40:
41: extern void console_attach(struct tty **tpp);
42:
43:
44: /* Parameters */
45: #define KBD_IRQ 1
46:
47: static int kbd_init(void);
48:
49: /*
50: * Driver structure
51: */
52: struct driver kbd_drv = {
53: /* name */ "PC/AT Keyboard",
54: /* order */ 8,
55: /* init */ kbd_init,
56: };
57:
58: static struct devio kbd_io = {
59: /* open */ NULL,
60: /* close */ NULL,
61: /* read */ NULL,
62: /* write */ NULL,
63: /* ioctl */ NULL,
64: /* event */ NULL,
65: };
66:
67: /*
68: * Key map
69: */
70: static const u_char key_map[] = {
71: 0, 0x1b, '1', '2', '3', '4', '5', '6',
72: '7', '8', '9', '0', '-', '=', '\b', '\t',
73: 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
74: 'o', 'p', '[', ']', '\n', K_CTRL, 'a', 's',
75: 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
76: '\'', '`', K_SHFT, '\\', 'z', 'x', 'c', 'v',
77: 'b', 'n', 'm', ',', '.', '/', K_SHFT, '*',
78: K_ALT, ' ', K_CAPS, K_F1, K_F2, K_F3, K_F4, K_F5,
79: K_F6, K_F7, K_F8, K_F9, K_F10, 0, 0, K_HOME,
80: K_UP, K_PGUP, 0, K_LEFT, 0, K_RGHT, 0, K_END,
81: K_DOWN, K_PGDN, K_INS, 0x7f, K_F11, K_F12
82: };
83:
84: #define KEY_MAX (sizeof(key_map) / sizeof(u_char))
85:
86: static const u_char shift_map[] = {
87: 0, 0x1b, '!', '@', '#', '$', '%', '^',
88: '&', '*', '(', ')', '_', '+', '\b', '\t',
89: 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
90: 'O', 'P', '{', '}', '\n', K_CTRL, 'A', 'S',
91: 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
92: '"', '~', 0, '|', 'Z', 'X', 'C', 'V',
93: 'B', 'N', 'M', '<', '>', '?', 0, '*',
94: K_ALT, ' ', 0, 0, 0, 0, 0, 0,
95: 0, 0, 0, 0, 0, 0, 0, K_HOME,
96: K_UP, K_PGUP, 0, K_LEFT, 0, K_RGHT, 0, K_END,
97: K_DOWN, K_PGDN, K_INS, 0x7f, 0, 0
98: };
99:
100: static device_t kbd_dev; /* Device object */
101: static int kbd_irq; /* Handle for keyboard irq */
102: static struct tty *tty;
103:
104: static int shift;
105: static int alt;
106: static int ctrl;
107: static int capslk;
108:
109: static int led_sts;
110:
111:
112: /*
113: * Send command to keyboard controller
114: */
115: static void
116: kbd_cmd(int cmd)
117: {
118:
119: wait_ibe();
120: outb(cmd, KMC_CMD);
121: }
122:
123:
124: /*
125: * Update LEDs for current modifier state.
126: */
127: static void
128: kbd_setleds(void)
129: {
130:
131: outb(0xed, KMC_DATA);
132: while (inb(KMC_STS) & 2);
133: outb(led_sts, KMC_DATA);
134: while (inb(KMC_STS) & 2);
135: }
136:
137: #ifdef CONFIG_KDUMP
138: /*
139: * Help for keyboard debug function
140: */
141: static void
142: kbd_dump_help(void)
143: {
144:
145: printk("\nSystem dump usage:\n");
146: printk("F1=help F2=thread F3=task F4=object F5=timer F6=irq F7=dev F8=mem F9=dmesg\n");
147: }
148: #endif
149:
150:
151: /*
152: * Interrupt service routine
153: */
154: static int
155: kbd_isr(int irq)
156: {
157: u_char sc, ac; /* scan & ascii code */
158: int val, press;
159:
160: /* Get scan code */
161: wait_obf();
162: sc = inb(KMC_DATA);
163:
164: /* Send ack to the controller */
165: val = inb(KMC_PORTB);
166: outb(val | 0x80, KMC_PORTB);
167: outb(val, KMC_PORTB);
168:
169: /* Convert scan code to ascii */
170: press = sc & 0x80 ? 0 : 1;
171: sc = sc & 0x7f;
172: if (sc >= KEY_MAX)
173: return 0;
174: ac = key_map[sc];
175:
176: #ifdef CONFIG_PM
177: /* Reload power management timer */
178: if (press)
179: pm_active();
180: #endif
181:
182: /* Check meta key */
183: switch (ac) {
184: case K_SHFT:
185: shift = press;
186: return 0;
187: case K_CTRL:
188: ctrl = press;
189: return 0;
190: case K_ALT:
191: alt = press;
192: return 0;
193: case K_CAPS:
194: capslk = !capslk;
195: return INT_CONTINUE;
196: }
197:
198: /* Ignore key release */
199: if (!press)
200: return 0;
201:
202: #ifdef CONFIG_KDUMP
203: if (ac == K_F1) {
204: kbd_dump_help();
205: return 0;
206: }
207: if (ac >= K_F2 && ac <= K_F12) {
208: debug_dump(ac - K_F1);
209: return 0;
210: }
211: #endif
212: if (ac >= 0x80) {
213: tty_input(ac, tty);
214: return 0;
215: }
216:
217: /* Check Alt+Ctrl+Del */
218: if (alt && ctrl && ac == 0x7f) {
219: printk("Rebooting...");
220: machine_reset();
221: }
222:
223: /* Check ctrl & shift state */
224: if (ctrl) {
225: if (ac >= 'a' && ac <= 'z')
226: ac = ac - 'a' + 0x01;
227: else if (ac == '\\')
228: ac = 0x1c;
229: else
230: ac = 0;
231: } else if (shift)
232: ac = shift_map[sc];
233:
234: if (ac == 0)
235: return 0;
236:
237: /* Check caps lock state */
238: if (capslk) {
239: if (ac >= 'A' && ac <= 'Z')
240: ac += 'a' - 'A';
241: else if (ac >= 'a' && ac <= 'z')
242: ac -= 'a' - 'A';
243: }
244:
245: /* Check alt key */
246: if (alt)
247: ac |= 0x80;
248:
249: /* Insert key to queue */
250: tty_input(ac, tty);
251: return 0;
252: }
253:
254: /*
255: * Interrupt service thread
256: */
257: static void
258: kbd_ist(int irq)
259: {
260: int val = 0;
261:
262: /* Update LEDs */
263: if (capslk)
264: val |= 0x04;
265: if (led_sts != val) {
266: led_sts = val;
267: kbd_setleds();
268: }
269: return;
270: }
271:
272: int
273: kbd_init(void)
274: {
275:
276: kbd_dev = device_create(&kbd_io, "kbd", DF_CHR);
277: ASSERT(kbd_dev);
278:
279: /* Disable keyboard controller */
280: kbd_cmd(CMD_KBD_DIS);
281:
282: led_sts = 0;
283: /* kbd_setleds(); */
284:
285: kbd_irq = irq_attach(KBD_IRQ, IPL_INPUT, 0, kbd_isr, kbd_ist);
286: ASSERT(kbd_irq != -1);
287:
288: /* Discard garbage data */
289: while (inb(KMC_STS) & STS_OBF)
290: inb(KMC_DATA);
291:
292: /* Enable keyboard controller */
293: kbd_cmd(CMD_KBD_EN);
294:
295: console_attach(&tty);
296: return 0;
297: }
CVSweb