Annotation of prex/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 <cpufunc.h>
38: #include <pm.h>
39: #include <console.h>
40: #include "kmc.h"
41:
42: /* Parameters */
43: #define KBD_IRQ 1
44:
45: static int kbd_init(void);
46:
47: /*
48: * Driver structure
49: */
50: struct driver kbd_drv = {
51: /* name */ "PC/AT Keyboard",
52: /* order */ 8,
53: /* init */ kbd_init,
54: };
55:
56: /*
57: * Device I/O table
58: */
59: static struct devio kbd_io = {
60: /* open */ NULL,
61: /* close */ NULL,
62: /* read */ NULL,
63: /* write */ NULL,
64: /* ioctl */ NULL,
65: /* event */ NULL,
66: };
67:
68: /*
69: * Key map
70: */
71: static const u_char key_map[] = {
72: 0, 0x1b, '1', '2', '3', '4', '5', '6',
73: '7', '8', '9', '0', '-', '=', '\b', '\t',
74: 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
75: 'o', 'p', '[', ']', '\n', K_CTRL, 'a', 's',
76: 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
77: '\'', '`', K_SHFT, '\\', 'z', 'x', 'c', 'v',
78: 'b', 'n', 'm', ',', '.', '/', K_SHFT, '*',
79: K_ALT, ' ', K_CAPS, K_F1, K_F2, K_F3, K_F4, K_F5,
80: K_F6, K_F7, K_F8, K_F9, K_F10, 0, 0, K_HOME,
81: K_UP, K_PGUP, 0, K_LEFT, 0, K_RGHT, 0, K_END,
82: K_DOWN, K_PGDN, K_INS, 0x7f, K_F11, K_F12
83: };
84:
85: #define KEY_MAX (sizeof(key_map) / sizeof(char))
86:
87: static const u_char shift_map[] = {
88: 0, 0x1b, '!', '@', '#', '$', '%', '^',
89: '&', '*', '(', ')', '_', '+', '\b', '\t',
90: 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
91: 'O', 'P', '{', '}', '\n', K_CTRL, 'A', 'S',
92: 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
93: '"', '~', 0, '|', 'Z', 'X', 'C', 'V',
94: 'B', 'N', 'M', '<', '>', '?', 0, '*',
95: K_ALT, ' ', 0, 0, 0, 0, 0, 0,
96: 0, 0, 0, 0, 0, 0, 0, K_HOME,
97: K_UP, K_PGUP, 0, K_LEFT, 0, K_RGHT, 0, K_END,
98: K_DOWN, K_PGDN, K_INS, 0x7f, 0, 0
99: };
100:
101: static device_t kbd_dev; /* Device object */
102: static irq_t kbd_irq; /* Handle for keyboard irq */
103: static struct tty *tty;
104:
105: static int shift;
106: static int alt;
107: static int ctrl;
108: static int capslk;
109:
110: static int led_sts;
111:
112:
113: /*
114: * Send command to keyboard controller
115: */
116: static void
117: kbd_cmd(u_char cmd)
118: {
119:
120: wait_ibe();
121: outb(cmd, KMC_CMD);
122: }
123:
124:
125: /*
126: * Update LEDs for current modifier state.
127: */
128: static void
129: kbd_setleds(void)
130: {
131:
132: outb(0xed, KMC_DATA);
133: while (inb(KMC_STS) & 2);
134: outb(led_sts, KMC_DATA);
135: while (inb(KMC_STS) & 2);
136: }
137:
138: #ifdef DEBUG
139: /*
140: * Help for keyboard debug function
141: */
142: static void
143: kbd_dump_help(void)
144: {
145:
146: printf("\nSystem dump usage:\n");
147: printf("F1=help F2=thread F3=task F4=mem\n");
148: }
149: #endif
150:
151:
152: /*
153: * Interrupt service routine
154: */
155: static int
156: kbd_isr(int irq)
157: {
158: u_char sc, ac; /* scan & ascii code */
159: u_char val;
160: int press;
161:
162: /* Get scan code */
163: wait_obf();
164: sc = inb(KMC_DATA);
165:
166: /* Send ack to the controller */
167: val = inb(KMC_PORTB);
168: outb(val | 0x80, KMC_PORTB);
169: outb(val, KMC_PORTB);
170:
171: /* Convert scan code to ascii */
172: press = sc & 0x80 ? 0 : 1;
173: sc = sc & 0x7f;
174: if (sc >= KEY_MAX)
175: return 0;
176: ac = key_map[sc];
177:
178: #ifdef CONFIG_PM
179: /* Reload power management timer */
180: if (press)
181: pm_active();
182: #endif
183:
184: /* Check meta key */
185: switch (ac) {
186: case K_SHFT:
187: shift = press;
188: return 0;
189: case K_CTRL:
190: ctrl = press;
191: return 0;
192: case K_ALT:
193: alt = press;
194: return 0;
195: case K_CAPS:
196: capslk = !capslk;
197: return INT_CONTINUE;
198: }
199:
200: /* Ignore key release */
201: if (!press)
202: return 0;
203:
204: #ifdef DEBUG
205: if (ac == K_F1) {
206: kbd_dump_help();
207: return 0;
208: }
209: if (ac >= K_F2 && ac <= K_F12) {
210: debug_dump(ac - K_F1);
211: return 0;
212: }
213: #endif
214: if (ac >= 0x80) {
215: tty_input(ac, tty);
216: return 0;
217: }
218:
219: /* Check Alt+Ctrl+Del */
220: if (alt && ctrl && ac == 0x7f) {
221: machine_reset();
222: }
223:
224: /* Check ctrl & shift state */
225: if (ctrl) {
226: if (ac >= 'a' && ac <= 'z')
227: ac = ac - 'a' + 0x01;
228: else if (ac == '\\')
229: ac = 0x1c;
230: else
231: ac = 0;
232: } else if (shift)
233: ac = shift_map[sc];
234:
235: if (ac == 0)
236: return 0;
237:
238: /* Check caps lock state */
239: if (capslk) {
240: if (ac >= 'A' && ac <= 'Z')
241: ac += 'a' - 'A';
242: else if (ac >= 'a' && ac <= 'z')
243: ac -= 'a' - 'A';
244: }
245:
246: /* Check alt key */
247: if (alt)
248: ac |= 0x80;
249:
250: /* Insert key to queue */
251: tty_input(ac, tty);
252: return 0;
253: }
254:
255: /*
256: * Interrupt service thread
257: */
258: static void
259: kbd_ist(int irq)
260: {
261: int val = 0;
262:
263: /* Update LEDs */
264: if (capslk)
265: val |= 0x04;
266: if (led_sts != val) {
267: led_sts = val;
268: kbd_setleds();
269: }
270: return;
271: }
272:
273: int
274: kbd_init(void)
275: {
276:
277: kbd_dev = device_create(&kbd_io, "kbd", DF_CHR);
278: ASSERT(kbd_dev);
279:
280: /* Disable keyboard controller */
281: kbd_cmd(CMD_KBD_DIS);
282:
283: led_sts = 0;
284: /* kbd_setleds(); */
285:
286: kbd_irq = irq_attach(KBD_IRQ, IPL_INPUT, 0, kbd_isr, kbd_ist);
287: ASSERT(kbd_irq != IRQ_NULL);
288:
289: /* Discard garbage data */
290: while (inb(KMC_STS) & STS_OBF)
291: inb(KMC_DATA);
292:
293: /* Enable keyboard controller */
294: kbd_cmd(CMD_KBD_EN);
295:
296: console_attach(&tty);
297: return 0;
298: }
CVSweb