* same with xv6
[mascara-docs.git] / i386 / standford / 2004 / src / lab2 / kern / console.c
blob28718834403880ec5006e6ef866c25e51aaefe90
1 /* See COPYRIGHT for copyright information. */
3 #include <inc/x86.h>
4 #include <inc/pmap.h>
5 #include <inc/kbdreg.h>
6 #include <inc/string.h>
7 #include <inc/assert.h>
9 #include <kern/console.h>
12 void cons_intr(int (*proc)(void));
15 /***** Serial I/O code *****/
17 #define COM1 0x3F8
18 #define COMSTATUS 5
19 #define COMDATA 0x01
20 #define COMREAD 0
21 #define COMWRITE 0
23 int
24 serial_proc_data(void)
26 if (!(inb(COM1+COMSTATUS) & COMDATA))
27 return -1;
28 return inb(COM1+COMREAD);
31 void
32 serial_intr(void)
34 cons_intr(serial_proc_data);
37 void
38 serial_init(void)
44 /***** Parallel port output code *****/
45 // For information on PC parallel port programming, see:
47 // Stupid I/O delay routine necessitated by historical PC design flaws
48 static void
49 delay(void)
51 inb(0x84);
52 inb(0x84);
53 inb(0x84);
54 inb(0x84);
57 static void
58 lpt_putc(int c)
60 int i;
62 for (i=0; !(inb(0x378+1)&0x80) && i<12800; i++)
63 delay();
64 outb(0x378+0, c);
65 outb(0x378+2, 0x08|0x01);
66 outb(0x378+2, 0x08);
72 /***** Text-mode CGA/VGA display output *****/
74 static unsigned addr_6845;
75 static u_short *crt_buf;
76 static short crt_pos;
78 void
79 cga_init(void)
81 u_short volatile *cp;
82 u_short was;
83 u_int pos;
85 cp = (short *) (KERNBASE + CGA_BUF);
86 was = *cp;
87 *cp = (u_short) 0xA55A;
88 if (*cp != 0xA55A) {
89 cp = (short *) (KERNBASE + MONO_BUF);
90 addr_6845 = MONO_BASE;
91 } else {
92 *cp = was;
93 addr_6845 = CGA_BASE;
96 /* Extract cursor location */
97 outb(addr_6845, 14);
98 pos = inb(addr_6845+1) << 8;
99 outb(addr_6845, 15);
100 pos |= inb(addr_6845+1);
102 crt_buf = (u_short *)cp;
103 crt_pos = pos;
107 void
108 cga_putc(int c)
110 /* if no attribute given, then use black on white */
111 if (!(c & ~0xff)) c |= 0x0700;
113 switch (c & 0xff) {
114 case '\b':
115 if (crt_pos > 0) {
116 crt_pos--;
117 crt_buf[crt_pos] = (c&~0xff) | ' ';
119 break;
120 case '\n':
121 crt_pos += CRT_COLS;
122 /* cascade */
123 case '\r':
124 crt_pos -= (crt_pos % CRT_COLS);
125 break;
126 case '\t':
127 cons_putc(' ');
128 cons_putc(' ');
129 cons_putc(' ');
130 cons_putc(' ');
131 cons_putc(' ');
132 break;
133 default:
134 crt_buf[crt_pos++] = c; /* write the character */
135 break;
138 /* scroll if necessary */
139 if (crt_pos >= CRT_SIZE) {
140 int i;
141 memcpy(crt_buf, crt_buf + CRT_COLS, CRT_SIZE << 1);
142 for (i = CRT_SIZE - CRT_COLS; i < CRT_SIZE; i++)
143 crt_buf[i] = 0x0700 | ' ';
144 crt_pos -= CRT_COLS;
147 /* move that little blinky thing */
148 outb(addr_6845, 14);
149 outb(addr_6845+1, crt_pos >> 8);
150 outb(addr_6845, 15);
151 outb(addr_6845+1, crt_pos);
156 /***** Keyboard input code *****/
158 #define NO 0
160 #define SHIFT (1<<0)
161 #define CTL (1<<1)
162 #define ALT (1<<2)
164 #define CAPSLOCK (1<<3)
165 #define NUMLOCK (1<<4)
166 #define SCROLLOCK (1<<5)
168 static int shiftcode[256] =
170 [29] CTL,
171 [42] SHIFT,
172 [54] SHIFT,
173 [56] ALT,
176 static int togglecode[256] =
178 [58] CAPSLOCK,
179 [69] NUMLOCK,
180 [70] SCROLLOCK,
183 static char normalmap[256] =
185 NO, 033, '1', '2', '3', '4', '5', '6',
186 '7', '8', '9', '0', '-', '=', '\b', '\t',
187 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
188 'o', 'p', '[', ']', '\n', NO, 'a', 's',
189 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
190 '\'', '`', NO, '\\', 'z', 'x', 'c', 'v',
191 'b', 'n', 'm', ',', '.', '/', NO, '*',
192 NO, ' ', NO, NO, NO, NO, NO, NO,
193 NO, NO, NO, NO, NO, NO, NO, '7',
194 '8', '9', '-', '4', '5', '6', '+', '1',
195 '2', '3', '0', '.',
198 static char shiftmap[256] =
200 NO, 033, '!', '@', '#', '$', '%', '^',
201 '&', '*', '(', ')', '_', '+', '\b', '\t',
202 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
203 'O', 'P', '{', '}', '\n', NO, 'A', 'S',
204 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';',
205 '"', '~', NO, '|', 'Z', 'X', 'C', 'V',
206 'B', 'N', 'M', '<', '>', '?', NO, '*',
207 NO, ' ', NO, NO, NO, NO, NO, NO,
208 NO, NO, NO, NO, NO, NO, NO, '7',
209 '8', '9', '-', '4', '5', '6', '+', '1',
210 '2', '3', '0', '.',
213 #define C(x) (x-'@')
215 static char ctlmap[256] =
217 NO, NO, NO, NO, NO, NO, NO, NO,
218 NO, NO, NO, NO, NO, NO, NO, NO,
219 C('Q'), C('W'), C('E'), C('R'), C('T'), C('Y'), C('U'), C('I'),
220 C('O'), C('P'), NO, NO, '\r', NO, C('A'), C('S'),
221 C('D'), C('F'), C('G'), C('H'), C('J'), C('K'), C('L'), NO,
222 NO, NO, NO, C('\\'), C('Z'), C('X'), C('C'), C('V'),
223 C('B'), C('N'), C('M'), NO, NO, C('/'), NO, NO,
226 static char *charcode[4] = {
227 normalmap,
228 shiftmap,
229 ctlmap,
230 ctlmap,
234 * Get data from the keyboard. If we finish a character, return it. Else 0.
235 * Return -1 if no data.
237 static int
238 kbd_proc_data(void)
240 int c;
241 u_char data;
242 static u_int shift;
244 if ((inb(KBSTATP) & KBS_DIB) == 0)
245 return -1;
247 data = inb(KBDATAP);
249 if (data & 0x80) {
250 /* key up */
251 shift &= ~shiftcode[data&~0x80];
252 return 0;
255 /* key down */
256 shift |= shiftcode[data];
257 shift ^= togglecode[data];
258 c = charcode[shift&(CTL|SHIFT)][data];
260 if (shift&CAPSLOCK) {
261 if ('a' <= c && c <= 'z')
262 c += 'A' - 'a';
263 else if ('A' <= c && c <= 'Z')
264 c += 'a' - 'A';
267 return c;
270 void
271 kbd_intr(void)
273 cons_intr(kbd_proc_data);
276 void
277 kbd_init(void)
283 /***** General device-independent console code *****/
284 // Here we manage the console input buffer,
285 // where we stash characters received from the keyboard or serial port
286 // whenever the corresponding interrupt occurs.
288 #define BY2CONS 512
290 static struct {
291 u_char buf[BY2CONS];
292 u_int rpos;
293 u_int wpos;
294 } cons;
296 // called by device interrupt routines to feed input characters
297 // into the circular console input buffer.
298 void
299 cons_intr(int (*proc)(void))
301 int c;
303 while ((c = (*proc)()) != -1) {
304 if (c == 0)
305 continue;
306 cons.buf[cons.wpos++] = c;
307 if (cons.wpos == BY2CONS)
308 cons.wpos = 0;
312 // return the next input character from the console, or 0 if none waiting
314 cons_getc(void)
316 int c;
318 // poll for any pending input characters,
319 // so that this function works even when interrupts are disabled
320 // (e.g., when called from the kernel monitor).
321 serial_intr();
322 kbd_intr();
324 // grab the next character from the input buffer.
325 if (cons.rpos != cons.wpos) {
326 c = cons.buf[cons.rpos++];
327 if (cons.rpos == BY2CONS)
328 cons.rpos = 0;
329 return c;
331 return 0;
334 // output a character to the console
335 void
336 cons_putc(int c)
338 lpt_putc(c);
339 cga_putc(c);
342 // initialize the console devices
343 void
344 cons_init(void)
346 cga_init();
347 kbd_init();
348 serial_init();
353 // `High'-level console I/O. Used by readline and printf.
355 void
356 putchar(int c)
358 cons_putc(c);
362 getchar(void)
364 int c;
366 while ((c = cons_getc()) == 0)
367 ; // spin
368 return c;
372 iscons(int fdnum)
374 // used by readline
375 return 1;