Annotation of prex/dev/i386/pc/console.c, Revision 1.1.1.1
1.1 nbrk 1: /*-
2: * Copyright (c) 2005-2007, 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: * console.c - pc console driver
32: */
33:
34: #include <driver.h>
35: #include <cpufunc.h>
36: #include <console.h>
37: #include <sys/tty.h>
38:
39: #define CRTC_INDEX 0x3d4
40: #define CRTC_DATA 0x3d5
41: #define GRAC_INDEX 0x3ce
42: #define GRAC_DATA 0x3cf
43:
44: #define VID_RAM 0xB8000
45:
46: static int console_init(void);
47: static int console_read(device_t, char *, size_t *, int);
48: static int console_write(device_t, char *, size_t *, int);
49: static int console_ioctl(device_t, u_long, void *);
50:
51: /*
52: * Driver structure
53: */
54: struct driver console_drv = {
55: /* name */ "Console",
56: /* order */ 4,
57: /* init */ console_init,
58: };
59:
60: /*
61: * Device I/O table
62: */
63: static struct devio console_io = {
64: /* open */ NULL,
65: /* close */ NULL,
66: /* read */ console_read,
67: /* write */ console_write,
68: /* ioctl */ console_ioctl,
69: /* event */ NULL,
70: };
71:
72: static device_t console_dev;
73: static struct tty console_tty;
74:
75: static short *vram;
76: static int pos_x;
77: static int pos_y;
78: static int cols;
79: static int rows;
80: static u_short attrib;
81:
82: static int esc_index;
83: static int esc_arg1;
84: static int esc_arg2;
85: static int esc_argc;
86: static int esc_saved_x;
87: static int esc_saved_y;
88:
89: static u_short ansi_colors[] = {0, 4, 2, 6, 1, 5, 3, 7};
90:
91: static void
92: scroll_up(void)
93: {
94: int i;
95:
96: memcpy(vram, vram + cols, (size_t)(cols * (rows - 1) * 2));
97: for (i = 0; i < cols; i++)
98: vram[cols * (rows - 1) + i] = ' ' | (attrib << 8);
99: }
100:
101: static void
102: move_cursor(void)
103: {
104: int pos = pos_y * cols + pos_x;
105:
106: irq_lock();
107: outb(0x0e, CRTC_INDEX);
108: outb((pos >> 8) & 0xff, CRTC_DATA);
109: outb(0x0f, CRTC_INDEX);
110: outb(pos & 0xff, CRTC_DATA);
111: irq_unlock();
112: }
113:
114: static void
115: reset_cursor(void)
116: {
117: u_int offset;
118:
119: irq_lock();
120: outb(0x0e, CRTC_INDEX);
121: offset = (u_int)inb(CRTC_DATA);
122: offset <<= 8;
123: outb(0x0f, CRTC_INDEX);
124: offset += (u_int)inb(CRTC_DATA);
125: pos_x = offset % cols;
126: pos_y = offset / cols;
127: irq_unlock();
128: }
129:
130: static void
131: new_line(void)
132: {
133:
134: pos_x = 0;
135: pos_y++;
136: if (pos_y >= rows) {
137: pos_y = rows - 1;
138: scroll_up();
139: }
140: }
141:
142: static void
143: clear_screen(void)
144: {
145: int i;
146:
147: for (i = 0; i < cols * rows; i++)
148: vram[i] = ' ' | (attrib << 8);
149: pos_x = 0;
150: pos_y = 0;
151: move_cursor();
152: }
153:
154: /*
155: * Check for escape code sequence.
156: * Rreturn true if escape
157: *
158: * <Support list>
159: * ESC[#;#H or : moves cursor to line #, column #
160: * ESC[#;#f
161: * ESC[#A : moves cursor up # lines
162: * ESC[#B : moves cursor down # lines
163: * ESC[#C : moves cursor right # spaces
164: * ESC[#D : moves cursor left # spaces
165: * ESC[#;#R : reports current cursor line & column
166: * ESC[s : save cursor position for recall later
167: * ESC[u : return to saved cursor position
168: * ESC[2J : clear screen and home cursor
169: * ESC[K : clear to end of line
170: * ESC[#m : attribute (0=attribure off, 4=underline, 5=blink)
171: */
172: static int
173: check_escape(char c)
174: {
175: int move = 0;
176: int val;
177: u_short color;
178:
179: if (c == 033) {
180: esc_index = 1;
181: esc_argc = 0;
182: return 1;
183: }
184: if (esc_index == 0)
185: return 0;
186:
187: if (c >= '0' && c <= '9') {
188: val = c - '0';
189: switch (esc_argc) {
190: case 0:
191: esc_arg1 = val;
192: esc_index++;
193: break;
194: case 1:
195: esc_arg1 = esc_arg1 * 10 + val;
196: break;
197: case 2:
198: esc_arg2 = val;
199: esc_index++;
200: break;
201: case 3:
202: esc_arg2 = esc_arg2 * 10 + val;
203: break;
204: default:
205: goto reset;
206: }
207: esc_argc++;
208: return 1;
209: }
210:
211: esc_index++;
212:
213: switch (esc_index) {
214: case 2:
215: if (c != '[')
216: goto reset;
217: return 1;
218: case 3:
219: switch (c) {
220: case 's': /* Save cursor position */
221: esc_saved_x = pos_x;
222: esc_saved_y = pos_y;
223: break;
224: case 'u': /* Return to saved cursor position */
225: pos_x = esc_saved_x;
226: pos_y = esc_saved_y;
227: move_cursor();
228: break;
229: case 'K': /* Clear to end of line */
230: break;
231: }
232: goto reset;
233: case 4:
234: switch (c) {
235: case 'A': /* Move cursor up # lines */
236: pos_y -= esc_arg1;
237: if (pos_y < 0)
238: pos_y = 0;
239: move = 1;
240: break;
241: case 'B': /* Move cursor down # lines */
242: pos_y += esc_arg1;
243: if (pos_y >= rows)
244: pos_y = rows - 1;
245: move = 1;
246: break;
247: case 'C': /* Move cursor forward # spaces */
248: pos_x += esc_arg1;
249: if (pos_x >= cols)
250: pos_x = cols - 1;
251: move = 1;
252: break;
253: case 'D': /* Move cursor back # spaces */
254: pos_x -= esc_arg1;
255: if (pos_x < 0)
256: pos_x = 0;
257: move = 1;
258: break;
259: case ';':
260: if (esc_argc == 1)
261: esc_argc = 2;
262: return 1;
263: case 'J':
264: if (esc_arg1 == 2) /* Clear screen */
265: clear_screen();
266: break;
267: case 'm': /* Change attribute */
268: switch (esc_arg1) {
269: case 0: /* reset */
270: attrib = 0x0F;
271: break;
272: case 1: /* bold */
273: attrib = 0x0F;
274: break;
275: case 4: /* under line */
276: break;
277: case 5: /* blink */
278: attrib |= 0x80;
279: break;
280: case 30: case 31: case 32: case 33:
281: case 34: case 35: case 36: case 37:
282: color = ansi_colors[esc_arg1 - 30];
283: attrib = (attrib & 0xf0) | color;
284: break;
285: case 40: case 41: case 42: case 43:
286: case 44: case 45: case 46: case 47:
287: color = ansi_colors[esc_arg1 - 40];
288: attrib = (attrib & 0x0f) | (color << 4);
289: break;
290: }
291: break;
292:
293: }
294: if (move)
295: move_cursor();
296: goto reset;
297: case 6:
298: switch (c) {
299: case 'H':
300: case 'f':
301: pos_y = esc_arg1;
302: pos_x = esc_arg2;
303: if (pos_y >= rows)
304: pos_y = rows - 1;
305: if (pos_x >= cols)
306: pos_x = cols - 1;
307: move_cursor();
308: break;
309: case 'R':
310: /* XXX */
311: break;
312: }
313: goto reset;
314: default:
315: goto reset;
316: }
317: return 1;
318: reset:
319: esc_index = 0;
320: esc_argc = 0;
321: return 1;
322: }
323:
324: static void
325: put_char(char c)
326: {
327:
328: if (check_escape(c))
329: return;
330:
331: switch (c) {
332: case '\n':
333: new_line();
334: return;
335: case '\r':
336: pos_x = 0;
337: return;
338: case '\b':
339: if (pos_x == 0)
340: return;
341: pos_x--;
342: return;
343: }
344:
345: vram[pos_y * cols + pos_x] = c | (attrib << 8);
346: pos_x++;
347: if (pos_x >= cols) {
348: pos_x = 0;
349: pos_y++;
350: if (pos_y >= rows) {
351: pos_y = rows - 1;
352: scroll_up();
353: }
354: }
355: }
356:
357: static void
358: console_output(struct tty *tp)
359: {
360: int c;
361:
362: sched_lock();
363: while ((c = ttyq_getc(&tp->t_outq)) >= 0)
364: put_char(c);
365: move_cursor();
366: esc_index = 0;
367: sched_unlock();
368: }
369:
370: /*
371: * Read
372: */
373: static int
374: console_read(device_t dev, char *buf, size_t *nbyte, int blkno)
375: {
376:
377: return tty_read(&console_tty, buf, nbyte);
378: }
379:
380: /*
381: * Write
382: */
383: static int
384: console_write(device_t dev, char *buf, size_t *nbyte, int blkno)
385: {
386:
387: return tty_write(&console_tty, buf, nbyte);
388: }
389:
390: /*
391: * I/O control
392: */
393: static int
394: console_ioctl(device_t dev, u_long cmd, void *arg)
395: {
396:
397: return tty_ioctl(&console_tty, cmd, arg);
398: }
399:
400: /*
401: * Attach input device.
402: */
403: void
404: console_attach(struct tty **tpp)
405: {
406:
407: *tpp = &console_tty;
408: }
409:
410: #if defined(DEBUG) && defined(CONFIG_DIAG_SCREEN)
411: /*
412: * Diag print handler
413: */
414: static void
415: diag_print(char *str)
416: {
417: size_t count;
418: char c;
419:
420: sched_lock();
421: for (count = 0; count < 128; count++) {
422: c = *str;
423: if (c == '\0')
424: break;
425: put_char(c);
426: #if defined(CONFIG_DIAG_BOCHS)
427: if (inb(0xe9) == 0xe9) {
428: if (c == '\n')
429: outb((int)'\r', 0xe9);
430: outb(c, 0xe9);
431: }
432: #endif
433: str++;
434: }
435: move_cursor();
436: esc_index = 0;
437: sched_unlock();
438: }
439: #endif
440:
441: /*
442: * Init
443: */
444: static int
445: console_init(void)
446: {
447: struct boot_info *boot_info;
448:
449: machine_bootinfo(&boot_info);
450: cols = boot_info->video.text_x;
451: rows = boot_info->video.text_y;
452:
453: esc_index = 0;
454: attrib = 0x0F;
455:
456: vram = phys_to_virt((void *)VID_RAM);
457: console_dev = device_create(&console_io, "console", DF_CHR);
458: reset_cursor();
459: #if defined(DEBUG) && defined(CONFIG_DIAG_SCREEN)
460: debug_attach(diag_print);
461: #endif
462: tty_register(&console_io, &console_tty, console_output);
463: console_tty.t_winsize.ws_row = (u_short)rows;
464: console_tty.t_winsize.ws_col = (u_short)cols;
465: return 0;
466: }
CVSweb