kernel: scheduling fix for ARM
[minix.git] / drivers / tty / arch / i386 / console.c
blobcd383c46ffd8cd6beeb331c7d649736bef49fc82
1 /* Code and data for the IBM console driver.
3 * The 6845 video controller used by the IBM PC shares its video memory with
4 * the CPU somewhere in the 0xB0000 memory bank. To the 6845 this memory
5 * consists of 16-bit words. Each word has a character code in the low byte
6 * and a so-called attribute byte in the high byte. The CPU directly modifies
7 * video memory to display characters, and sets two registers on the 6845 that
8 * specify the video origin and the cursor position. The video origin is the
9 * place in video memory where the first character (upper left corner) can
10 * be found. Moving the origin is a fast way to scroll the screen. Some
11 * video adapters wrap around the top of video memory, so the origin can
12 * move without bounds. For other adapters screen memory must sometimes be
13 * moved to reset the origin. All computations on video memory use character
14 * (word) addresses for simplicity and assume there is no wrapping. The
15 * assembly support functions translate the word addresses to byte addresses
16 * and the scrolling function worries about wrapping.
19 #include <minix/drivers.h>
20 #include <termios.h>
21 #include <assert.h>
22 #include <sys/ioctl.h>
23 #include <sys/vm.h>
24 #include <sys/video.h>
25 #include <sys/mman.h>
26 #include <minix/tty.h>
27 #include <minix/callnr.h>
28 #include <minix/com.h>
29 #include <minix/sys_config.h>
30 #include <minix/vm.h>
31 #include "tty.h"
33 /* Set this to 1 if you want console output duplicated on the first
34 * serial line.
36 #define DUP_CONS_TO_SER 0
38 /* The clock task should provide an interface for this */
39 #define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */
41 /* Global variables used by the console driver and assembly support. */
42 static phys_bytes vid_size; /* 0x2000 for color or 0x0800 for mono */
43 static phys_bytes vid_base;
44 static unsigned vid_mask; /* 0x1FFF for color or 0x07FF for mono */
45 static unsigned blank_color = BLANK_COLOR; /* display code for blank */
47 /* Private variables used by the console driver. */
48 static int vid_port; /* I/O port for accessing 6845 */
49 static int wrap; /* hardware can wrap? */
50 static int softscroll; /* 1 = software scrolling, 0 = hardware */
51 static int beeping; /* speaker is beeping? */
52 static unsigned font_lines; /* font lines per character */
53 static unsigned scr_width; /* # characters on a line */
54 static unsigned scr_lines; /* # lines on the screen */
55 static unsigned scr_size; /* # characters on the screen */
57 /* tells mem_vid_copy() to blank the screen */
58 #define BLANK_MEM ((vir_bytes) 0)
60 static int disabled_vc = -1; /* Virtual console that was active when
61 * disable_console was called.
63 static int disabled_sm; /* Scroll mode to be restored when re-enabling
64 * console
67 static char *console_memory = NULL;
68 static char *font_memory = NULL;
70 /* Per console data. */
71 typedef struct console {
72 tty_t *c_tty; /* associated TTY struct */
73 int c_column; /* current column number (0-origin) */
74 int c_row; /* current row (0 at top of screen) */
75 int c_rwords; /* number of WORDS (not bytes) in outqueue */
76 unsigned c_start; /* start of video memory of this console */
77 unsigned c_limit; /* limit of this console's video memory */
78 unsigned c_org; /* location in RAM where 6845 base points */
79 unsigned c_cur; /* current position of cursor in video RAM */
80 unsigned c_attr; /* character attribute */
81 unsigned c_blank; /* blank attribute */
82 char c_reverse; /* reverse video */
83 char c_esc_state; /* 0=normal, 1=ESC, 2=ESC[ */
84 char c_esc_intro; /* Distinguishing character following ESC */
85 int *c_esc_parmp; /* pointer to current escape parameter */
86 int c_esc_parmv[MAX_ESC_PARMS]; /* list of escape parameters */
87 u16_t c_ramqueue[CONS_RAM_WORDS]; /* buffer for video RAM */
88 int c_line; /* line no */
89 } console_t;
91 #define UPDATE_CURSOR(ccons, cursor) { \
92 ccons->c_cur = cursor; \
93 if(curcons && ccons == curcons) \
94 set_6845(CURSOR, ccons->c_cur); \
97 #define UPDATE_ORIGIN(ccons, origin) { \
98 ccons->c_org = origin; \
99 if (curcons && ccons == curcons) \
100 set_6845(VID_ORG, ccons->c_org); \
103 static int nr_cons= 1; /* actual number of consoles */
104 static console_t cons_table[NR_CONS];
105 static console_t *curcons = NULL; /* currently visible */
107 static int shutting_down = FALSE; /* don't allow console switches */
109 /* Color if using a color controller. */
110 #define color (vid_port == C_6845)
112 /* Map from ANSI colors to the attributes used by the PC */
113 static int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
115 /* Structure used for font management */
116 struct sequence {
117 unsigned short index;
118 unsigned char port;
119 unsigned char value;
122 static int cons_write(struct tty *tp, int try);
123 static void cons_echo(tty_t *tp, int c);
124 static void out_char(console_t *cons, int c);
125 static void beep(void);
126 static void do_escape(console_t *cons, int c);
127 static void flush(console_t *cons);
128 static void parse_escape(console_t *cons, int c);
129 static void scroll_screen(console_t *cons, int dir);
130 static void set_6845(int reg, unsigned val);
131 static void stop_beep(timer_t *tmrp);
132 static void cons_org0(void);
133 static void disable_console(void);
134 static void reenable_console(void);
135 static int ga_program(struct sequence *seq);
136 static int cons_ioctl(tty_t *tp, int);
137 static void mem_vid_copy(vir_bytes src, int dst, int count);
138 static void vid_vid_copy(int src, int dst, int count);
140 #if 0
141 static void get_6845(int reg, unsigned *val);
142 #endif
144 /*===========================================================================*
145 * cons_write *
146 *===========================================================================*/
147 static int cons_write(tp, try)
148 register struct tty *tp; /* tells which terminal is to be used */
149 int try;
151 /* Copy as much data as possible to the output queue, then start I/O. On
152 * memory-mapped terminals, such as the IBM console, the I/O will also be
153 * finished, and the counts updated. Keep repeating until all I/O done.
156 int count;
157 int result = OK;
158 register char *tbuf;
159 char buf[64];
160 console_t *cons = tp->tty_priv;
162 if (try) return 1; /* we can always write to console */
164 /* Check quickly for nothing to do, so this can be called often without
165 * unmodular tests elsewhere.
167 if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return 0;
169 /* Copy the user bytes to buf[] for decent addressing. Loop over the
170 * copies, since the user buffer may be much larger than buf[].
172 do {
173 if (count > sizeof(buf)) count = sizeof(buf);
174 if (tp->tty_outcaller == KERNEL) {
175 /* We're trying to print on kernel's behalf */
176 memcpy(buf, (void *) tp->tty_outgrant + tp->tty_outoffset,
177 count);
178 } else {
179 if ((result = sys_safecopyfrom(tp->tty_outcaller,
180 tp->tty_outgrant, tp->tty_outoffset,
181 (vir_bytes) buf, count)) != OK) {
182 break;
185 tp->tty_outoffset += count;
186 tbuf = buf;
188 /* Update terminal data structure. */
189 tp->tty_outcum += count;
190 tp->tty_outleft -= count;
192 /* Output each byte of the copy to the screen. Avoid calling
193 * out_char() for the "easy" characters, put them into the buffer
194 * directly.
196 do {
197 if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
198 || cons->c_column >= scr_width
199 || cons->c_rwords >= buflen(cons->c_ramqueue))
201 out_char(cons, *tbuf++);
202 } else {
203 #if DUP_CONS_TO_SER
204 if (cons == &cons_table[0]) ser_putc(*tbuf);
205 #endif
206 cons->c_ramqueue[cons->c_rwords++] =
207 cons->c_attr | (*tbuf++ & BYTE);
208 cons->c_column++;
210 } while (--count != 0);
211 } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
213 flush(cons); /* transfer anything buffered to the screen */
215 /* Reply to the writer if all output is finished or if an error occured. */
216 if (tp->tty_outleft == 0 || result != OK) {
217 if(tp->tty_outrepcode == TTY_REVIVE) {
218 notify(tp->tty_outcaller);
219 tp->tty_outrevived = 1;
220 } else {
221 tty_reply(tp->tty_outrepcode, tp->tty_outcaller,
222 tp->tty_outproc, tp->tty_outcum);
223 tp->tty_outcum = 0;
227 return 0;
230 /*===========================================================================*
231 * cons_echo *
232 *===========================================================================*/
233 static void cons_echo(tp, c)
234 register tty_t *tp; /* pointer to tty struct */
235 int c; /* character to be echoed */
237 /* Echo keyboard input (print & flush). */
238 console_t *cons = tp->tty_priv;
240 out_char(cons, c);
241 flush(cons);
244 /*===========================================================================*
245 * out_char *
246 *===========================================================================*/
247 static void out_char(cons, c)
248 register console_t *cons; /* pointer to console struct */
249 int c; /* character to be output */
251 /* Output a character on the console. Check for escape sequences first. */
252 if (cons->c_esc_state > 0) {
253 parse_escape(cons, c);
254 return;
257 #if DUP_CONS_TO_SER
258 if (cons == &cons_table[0] && c != '\0')
260 if (c == '\n')
261 ser_putc('\r');
262 ser_putc(c);
264 #endif
266 switch(c) {
267 case 000: /* null is typically used for padding */
268 return; /* better not do anything */
270 case 007: /* ring the bell */
271 flush(cons); /* print any chars queued for output */
272 beep();
273 return;
275 case '\b': /* backspace */
276 if (--cons->c_column < 0) {
277 if (--cons->c_row >= 0) cons->c_column += scr_width;
279 flush(cons);
280 return;
282 case '\n': /* line feed */
283 if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
284 == (OPOST|ONLCR)) {
285 cons->c_column = 0;
287 /*FALL THROUGH*/
288 case 013: /* CTRL-K */
289 case 014: /* CTRL-L */
290 if (cons->c_row == scr_lines-1) {
291 scroll_screen(cons, SCROLL_UP);
292 } else {
293 cons->c_row++;
295 flush(cons);
296 return;
298 case '\r': /* carriage return */
299 cons->c_column = 0;
300 flush(cons);
301 return;
303 case '\t': /* tab */
304 cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
305 if (cons->c_column > scr_width) {
306 cons->c_column -= scr_width;
307 if (cons->c_row == scr_lines-1) {
308 scroll_screen(cons, SCROLL_UP);
309 } else {
310 cons->c_row++;
313 flush(cons);
314 return;
316 case 033: /* ESC - start of an escape sequence */
317 flush(cons); /* print any chars queued for output */
318 cons->c_esc_state = 1; /* mark ESC as seen */
319 return;
321 default: /* printable chars are stored in ramqueue */
322 if (cons->c_column >= scr_width) {
323 if (!LINEWRAP) return;
324 if (cons->c_row == scr_lines-1) {
325 scroll_screen(cons, SCROLL_UP);
326 } else {
327 cons->c_row++;
329 cons->c_column = 0;
330 flush(cons);
332 if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons);
333 cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE);
334 cons->c_column++; /* next column */
335 return;
339 /*===========================================================================*
340 * scroll_screen *
341 *===========================================================================*/
342 static void scroll_screen(cons, dir)
343 register console_t *cons; /* pointer to console struct */
344 int dir; /* SCROLL_UP or SCROLL_DOWN */
346 unsigned new_line, new_org, chars;
348 flush(cons);
349 chars = scr_size - scr_width; /* one screen minus one line */
351 /* Scrolling the screen is a real nuisance due to the various incompatible
352 * video cards. This driver supports software scrolling (Hercules?),
353 * hardware scrolling (mono and CGA cards) and hardware scrolling without
354 * wrapping (EGA cards). In the latter case we must make sure that
355 * c_start <= c_org && c_org + scr_size <= c_limit
356 * holds, because EGA doesn't wrap around the end of video memory.
358 if (dir == SCROLL_UP) {
359 /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
360 if (softscroll) {
361 vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars);
362 } else
363 if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) {
364 vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars);
365 UPDATE_ORIGIN(cons, cons->c_start);
366 } else {
367 UPDATE_ORIGIN(cons, (cons->c_org + scr_width) & vid_mask);
369 new_line = (cons->c_org + chars) & vid_mask;
370 } else {
371 /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
372 if (softscroll) {
373 vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars);
374 } else
375 if (!wrap && cons->c_org < cons->c_start + scr_width) {
376 new_org = cons->c_limit - scr_size;
377 vid_vid_copy(cons->c_org, new_org + scr_width, chars);
378 UPDATE_ORIGIN(cons, new_org);
379 } else {
380 UPDATE_ORIGIN(cons, (cons->c_org - scr_width) & vid_mask);
382 new_line = cons->c_org;
384 /* Blank the new line at top or bottom. */
385 blank_color = cons->c_blank;
386 mem_vid_copy(BLANK_MEM, new_line, scr_width);
388 flush(cons);
391 /*===========================================================================*
392 * flush *
393 *===========================================================================*/
394 static void flush(cons)
395 register console_t *cons; /* pointer to console struct */
397 /* Send characters buffered in 'ramqueue' to screen memory, check the new
398 * cursor position, compute the new hardware cursor position and set it.
400 unsigned cur;
401 tty_t *tp = cons->c_tty;
403 /* Have the characters in 'ramqueue' transferred to the screen. */
404 if (cons->c_rwords > 0) {
405 mem_vid_copy((vir_bytes) cons->c_ramqueue, cons->c_cur, cons->c_rwords);
406 cons->c_rwords = 0;
408 /* TTY likes to know the current column and if echoing messed up. */
409 tp->tty_position = cons->c_column;
410 tp->tty_reprint = TRUE;
413 /* Check and update the cursor position. */
414 if (cons->c_column < 0) cons->c_column = 0;
415 if (cons->c_column > scr_width) cons->c_column = scr_width;
416 if (cons->c_row < 0) cons->c_row = 0;
417 if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1;
418 cur = cons->c_org + cons->c_row * scr_width + cons->c_column;
419 if (cur != cons->c_cur)
420 UPDATE_CURSOR(cons, cur);
423 /*===========================================================================*
424 * parse_escape *
425 *===========================================================================*/
426 static void parse_escape(cons, c)
427 register console_t *cons; /* pointer to console struct */
428 char c; /* next character in escape sequence */
430 /* The following ANSI escape sequences are currently supported.
431 * If n and/or m are omitted, they default to 1.
432 * ESC [nA moves up n lines
433 * ESC [nB moves down n lines
434 * ESC [nC moves right n spaces
435 * ESC [nD moves left n spaces
436 * ESC [m;nH" moves cursor to (m,n)
437 * ESC [J clears screen from cursor
438 * ESC [K clears line from cursor
439 * ESC [nL inserts n lines ar cursor
440 * ESC [nM deletes n lines at cursor
441 * ESC [nP deletes n chars at cursor
442 * ESC [n@ inserts n chars at cursor
443 * ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
444 * ESC M scrolls the screen backwards if the cursor is on the top line
447 switch (cons->c_esc_state) {
448 case 1: /* ESC seen */
449 cons->c_esc_intro = '\0';
450 cons->c_esc_parmp = bufend(cons->c_esc_parmv);
451 do {
452 *--cons->c_esc_parmp = 0;
453 } while (cons->c_esc_parmp > cons->c_esc_parmv);
454 switch (c) {
455 case '[': /* Control Sequence Introducer */
456 cons->c_esc_intro = c;
457 cons->c_esc_state = 2;
458 break;
459 case 'M': /* Reverse Index */
460 do_escape(cons, c);
461 break;
462 default:
463 cons->c_esc_state = 0;
465 break;
467 case 2: /* ESC [ seen */
468 if (c >= '0' && c <= '9') {
469 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
470 *cons->c_esc_parmp = *cons->c_esc_parmp * 10 + (c-'0');
471 } else
472 if (c == ';') {
473 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
474 cons->c_esc_parmp++;
475 } else {
476 do_escape(cons, c);
478 break;
482 /*===========================================================================*
483 * do_escape *
484 *===========================================================================*/
485 static void do_escape(cons, c)
486 register console_t *cons; /* pointer to console struct */
487 char c; /* next character in escape sequence */
489 int value, n;
490 unsigned src, dst, count;
491 int *parmp;
493 /* Some of these things hack on screen RAM, so it had better be up to date */
494 flush(cons);
496 if (cons->c_esc_intro == '\0') {
497 /* Handle a sequence beginning with just ESC */
498 switch (c) {
499 case 'M': /* Reverse Index */
500 if (cons->c_row == 0) {
501 scroll_screen(cons, SCROLL_DOWN);
502 } else {
503 cons->c_row--;
505 flush(cons);
506 break;
508 default: break;
510 } else
511 if (cons->c_esc_intro == '[') {
512 /* Handle a sequence beginning with ESC [ and parameters */
513 value = cons->c_esc_parmv[0];
514 switch (c) {
515 case 'A': /* ESC [nA moves up n lines */
516 n = (value == 0 ? 1 : value);
517 cons->c_row -= n;
518 flush(cons);
519 break;
521 case 'B': /* ESC [nB moves down n lines */
522 n = (value == 0 ? 1 : value);
523 cons->c_row += n;
524 flush(cons);
525 break;
527 case 'C': /* ESC [nC moves right n spaces */
528 n = (value == 0 ? 1 : value);
529 cons->c_column += n;
530 flush(cons);
531 break;
533 case 'D': /* ESC [nD moves left n spaces */
534 n = (value == 0 ? 1 : value);
535 cons->c_column -= n;
536 flush(cons);
537 break;
539 case 'H': /* ESC [m;nH" moves cursor to (m,n) */
540 cons->c_row = cons->c_esc_parmv[0] - 1;
541 cons->c_column = cons->c_esc_parmv[1] - 1;
542 flush(cons);
543 break;
545 case 'J': /* ESC [sJ clears in display */
546 switch (value) {
547 case 0: /* Clear from cursor to end of screen */
548 count = scr_size - (cons->c_cur - cons->c_org);
549 dst = cons->c_cur;
550 break;
551 case 1: /* Clear from start of screen to cursor */
552 count = cons->c_cur - cons->c_org;
553 dst = cons->c_org;
554 break;
555 case 2: /* Clear entire screen */
556 count = scr_size;
557 dst = cons->c_org;
558 break;
559 default: /* Do nothing */
560 count = 0;
561 dst = cons->c_org;
563 blank_color = cons->c_blank;
564 mem_vid_copy(BLANK_MEM, dst, count);
565 break;
567 case 'K': /* ESC [sK clears line from cursor */
568 switch (value) {
569 case 0: /* Clear from cursor to end of line */
570 count = scr_width - cons->c_column;
571 dst = cons->c_cur;
572 break;
573 case 1: /* Clear from beginning of line to cursor */
574 count = cons->c_column;
575 dst = cons->c_cur - cons->c_column;
576 break;
577 case 2: /* Clear entire line */
578 count = scr_width;
579 dst = cons->c_cur - cons->c_column;
580 break;
581 default: /* Do nothing */
582 count = 0;
583 dst = cons->c_cur;
585 blank_color = cons->c_blank;
586 mem_vid_copy(BLANK_MEM, dst, count);
587 break;
589 case 'L': /* ESC [nL inserts n lines at cursor */
590 n = value;
591 if (n < 1) n = 1;
592 if (n > (scr_lines - cons->c_row))
593 n = scr_lines - cons->c_row;
595 src = cons->c_org + cons->c_row * scr_width;
596 dst = src + n * scr_width;
597 count = (scr_lines - cons->c_row - n) * scr_width;
598 vid_vid_copy(src, dst, count);
599 blank_color = cons->c_blank;
600 mem_vid_copy(BLANK_MEM, src, n * scr_width);
601 break;
603 case 'M': /* ESC [nM deletes n lines at cursor */
604 n = value;
605 if (n < 1) n = 1;
606 if (n > (scr_lines - cons->c_row))
607 n = scr_lines - cons->c_row;
609 dst = cons->c_org + cons->c_row * scr_width;
610 src = dst + n * scr_width;
611 count = (scr_lines - cons->c_row - n) * scr_width;
612 vid_vid_copy(src, dst, count);
613 blank_color = cons->c_blank;
614 mem_vid_copy(BLANK_MEM, dst + count, n * scr_width);
615 break;
617 case '@': /* ESC [n@ inserts n chars at cursor */
618 n = value;
619 if (n < 1) n = 1;
620 if (n > (scr_width - cons->c_column))
621 n = scr_width - cons->c_column;
623 src = cons->c_cur;
624 dst = src + n;
625 count = scr_width - cons->c_column - n;
626 vid_vid_copy(src, dst, count);
627 blank_color = cons->c_blank;
628 mem_vid_copy(BLANK_MEM, src, n);
629 break;
631 case 'P': /* ESC [nP deletes n chars at cursor */
632 n = value;
633 if (n < 1) n = 1;
634 if (n > (scr_width - cons->c_column))
635 n = scr_width - cons->c_column;
637 dst = cons->c_cur;
638 src = dst + n;
639 count = scr_width - cons->c_column - n;
640 vid_vid_copy(src, dst, count);
641 blank_color = cons->c_blank;
642 mem_vid_copy(BLANK_MEM, dst + count, n);
643 break;
645 case 'm': /* ESC [nm enables rendition n */
646 for (parmp = cons->c_esc_parmv; parmp <= cons->c_esc_parmp
647 && parmp < bufend(cons->c_esc_parmv); parmp++) {
648 if (cons->c_reverse) {
649 /* Unswap fg and bg colors */
650 cons->c_attr = ((cons->c_attr & 0x7000) >> 4) |
651 ((cons->c_attr & 0x0700) << 4) |
652 ((cons->c_attr & 0x8800));
654 switch (n = *parmp) {
655 case 0: /* NORMAL */
656 cons->c_attr = cons->c_blank = BLANK_COLOR;
657 cons->c_reverse = FALSE;
658 break;
660 case 1: /* BOLD */
661 /* Set intensity bit */
662 cons->c_attr |= 0x0800;
663 break;
665 case 4: /* UNDERLINE */
666 if (color) {
667 /* Change white to cyan, i.e. lose red
669 cons->c_attr = (cons->c_attr & 0xBBFF);
670 } else {
671 /* Set underline attribute */
672 cons->c_attr = (cons->c_attr & 0x99FF);
674 break;
676 case 5: /* BLINKING */
677 /* Set the blink bit */
678 cons->c_attr |= 0x8000;
679 break;
681 case 7: /* REVERSE */
682 cons->c_reverse = TRUE;
683 break;
685 default: /* COLOR */
686 if (n == 39) n = 37; /* set default color */
687 if (n == 49) n = 40;
689 if (!color) {
690 /* Don't mess up a monochrome screen */
691 } else
692 if (30 <= n && n <= 37) {
693 /* Foreground color */
694 cons->c_attr =
695 (cons->c_attr & 0xF8FF) |
696 (ansi_colors[(n - 30)] << 8);
697 cons->c_blank =
698 (cons->c_blank & 0xF8FF) |
699 (ansi_colors[(n - 30)] << 8);
700 } else
701 if (40 <= n && n <= 47) {
702 /* Background color */
703 cons->c_attr =
704 (cons->c_attr & 0x8FFF) |
705 (ansi_colors[(n - 40)] << 12);
706 cons->c_blank =
707 (cons->c_blank & 0x8FFF) |
708 (ansi_colors[(n - 40)] << 12);
711 if (cons->c_reverse) {
712 /* Swap fg and bg colors */
713 cons->c_attr = ((cons->c_attr & 0x7000) >> 4) |
714 ((cons->c_attr & 0x0700) << 4) |
715 ((cons->c_attr & 0x8800));
718 break;
721 cons->c_esc_state = 0;
724 /*===========================================================================*
725 * set_6845 *
726 *===========================================================================*/
727 static void set_6845(reg, val)
728 int reg; /* which register pair to set */
729 unsigned val; /* 16-bit value to set it to */
731 /* Set a register pair inside the 6845.
732 * Registers 12-13 tell the 6845 where in video ram to start
733 * Registers 14-15 tell the 6845 where to put the cursor
735 pvb_pair_t char_out[4];
736 pv_set(char_out[0], vid_port + INDEX, reg); /* set index register */
737 pv_set(char_out[1], vid_port + DATA, (val>>8) & BYTE); /* high byte */
738 pv_set(char_out[2], vid_port + INDEX, reg + 1); /* again */
739 pv_set(char_out[3], vid_port + DATA, val&BYTE); /* low byte */
740 sys_voutb(char_out, 4); /* do actual output */
743 #if 0
744 /*===========================================================================*
745 * get_6845 *
746 *===========================================================================*/
747 static void get_6845(reg, val)
748 int reg; /* which register pair to set */
749 unsigned *val; /* 16-bit value to set it to */
751 char v1, v2;
752 u32_t v;
753 /* Get a register pair inside the 6845. */
754 sys_outb(vid_port + INDEX, reg);
755 sys_inb(vid_port + DATA, &v);
756 v1 = v;
757 sys_outb(vid_port + INDEX, reg+1);
758 sys_inb(vid_port + DATA, &v);
759 v2 = v;
760 *val = (v1 << 8) | v2;
762 #endif
764 /*===========================================================================*
765 * beep *
766 *===========================================================================*/
767 static void beep()
769 /* Making a beeping sound on the speaker (output for CRTL-G).
770 * This routine works by turning on the bits 0 and 1 in port B of the 8255
771 * chip that drive the speaker.
773 static timer_t tmr_stop_beep;
774 pvb_pair_t char_out[3];
775 u32_t port_b_val;
777 /* Set timer in advance to prevent beeping delay. */
778 set_timer(&tmr_stop_beep, B_TIME, stop_beep, 0);
780 if (!beeping) {
781 /* Set timer channel 2, square wave, with given frequency. */
782 pv_set(char_out[0], TIMER_MODE, 0xB6);
783 pv_set(char_out[1], TIMER2, (BEEP_FREQ >> 0) & BYTE);
784 pv_set(char_out[2], TIMER2, (BEEP_FREQ >> 8) & BYTE);
785 if (sys_voutb(char_out, 3)==OK) {
786 if (sys_inb(PORT_B, &port_b_val)==OK &&
787 sys_outb(PORT_B, (port_b_val|3))==OK)
788 beeping = TRUE;
794 /*===========================================================================*
795 * do_video *
796 *===========================================================================*/
797 void do_video(message *m)
799 int r;
801 /* Execute the requested device driver function. */
802 r= EINVAL; /* just in case */
803 switch (m->m_type) {
804 case DEV_OPEN:
805 /* Should grant IOPL */
806 disable_console();
807 r= OK;
808 break;
809 case DEV_CLOSE:
810 reenable_console();
811 r= OK;
812 break;
813 case DEV_IOCTL_S:
814 switch(m->TTY_REQUEST) {
815 case TIOCMAPMEM:
816 case TIOCUNMAPMEM: {
817 int r, do_map;
818 struct mapreqvm mapreqvm;
820 do_map= (m->REQUEST == TIOCMAPMEM); /* else unmap */
822 r = sys_safecopyfrom(m->m_source,
823 (cp_grant_id_t) m->IO_GRANT, 0,
824 (vir_bytes) &mapreqvm, sizeof(mapreqvm));
826 if (r != OK)
828 printf("tty: sys_safecopyfrom failed\n");
829 tty_reply(TASK_REPLY, m->m_source,
830 m->USER_ENDPT, r);
831 return;
834 /* In safe ioctl mode, the POSITION field contains
835 * the endpt number of the original requestor.
836 * USER_ENDPT is always FS.
839 if(do_map) {
840 mapreqvm.vaddr_ret = vm_map_phys(m->POSITION,
841 (void *) mapreqvm.phys_offset, mapreqvm.size);
842 if((r = sys_safecopyto(m->m_source,
843 (cp_grant_id_t) m->IO_GRANT, 0,
844 (vir_bytes) &mapreqvm,
845 sizeof(mapreqvm))) != OK) {
846 printf("tty: sys_safecopyto failed\n");
848 } else {
849 r = vm_unmap_phys(m->POSITION,
850 mapreqvm.vaddr, mapreqvm.size);
852 tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r);
853 return;
856 r= ENOTTY;
857 break;
859 default:
860 printf(
861 "Warning, TTY(video) got unexpected request %d from %d\n",
862 m->m_type, m->m_source);
863 r= EINVAL;
865 tty_reply(TASK_REPLY, m->m_source, m->USER_ENDPT, r);
869 /*===========================================================================*
870 * beep_x *
871 *===========================================================================*/
872 void beep_x(freq, dur)
873 unsigned freq;
874 clock_t dur;
876 /* Making a beeping sound on the speaker.
877 * This routine works by turning on the bits 0 and 1 in port B of the 8255
878 * chip that drive the speaker.
880 static timer_t tmr_stop_beep;
881 pvb_pair_t char_out[3];
882 u32_t port_b_val;
884 unsigned long ival= TIMER_FREQ / freq;
885 if (ival == 0 || ival > 0xffff)
886 return; /* Frequency out of range */
888 /* Set timer in advance to prevent beeping delay. */
889 set_timer(&tmr_stop_beep, dur, stop_beep, 0);
891 if (!beeping) {
892 /* Set timer channel 2, square wave, with given frequency. */
893 pv_set(char_out[0], TIMER_MODE, 0xB6);
894 pv_set(char_out[1], TIMER2, (ival >> 0) & BYTE);
895 pv_set(char_out[2], TIMER2, (ival >> 8) & BYTE);
896 if (sys_voutb(char_out, 3)==OK) {
897 if (sys_inb(PORT_B, &port_b_val)==OK &&
898 sys_outb(PORT_B, (port_b_val|3))==OK)
899 beeping = TRUE;
904 /*===========================================================================*
905 * stop_beep *
906 *===========================================================================*/
907 static void stop_beep(timer_t *UNUSED(tmrp))
909 /* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
910 u32_t port_b_val;
911 if (sys_inb(PORT_B, &port_b_val)==OK &&
912 sys_outb(PORT_B, (port_b_val & ~3))==OK)
913 beeping = FALSE;
916 /*===========================================================================*
917 * scr_init *
918 *===========================================================================*/
919 void scr_init(tp)
920 tty_t *tp;
922 /* Initialize the screen driver. */
923 console_t *cons;
924 u16_t bios_columns, bios_crtbase, bios_fontlines;
925 u8_t bios_rows;
926 int line;
927 int s;
928 static int vdu_initialized = 0;
929 static unsigned page_size;
931 /* Associate console and TTY. */
932 line = tp - &tty_table[0];
933 if (line >= nr_cons) return;
934 cons = &cons_table[line];
935 cons->c_tty = tp;
936 cons->c_line = line;
937 tp->tty_priv = cons;
939 /* Fill in TTY function hooks. */
940 tp->tty_devwrite = cons_write;
941 tp->tty_echo = cons_echo;
942 tp->tty_ioctl = cons_ioctl;
944 /* Get the BIOS parameters that describe the VDU. */
945 if (! vdu_initialized++) {
947 /* FIXME: How about error checking? What to do on failure??? */
948 s=sys_readbios(VDU_SCREEN_COLS_ADDR, &bios_columns,
949 VDU_SCREEN_COLS_SIZE);
950 s=sys_readbios(VDU_CRT_BASE_ADDR, &bios_crtbase,
951 VDU_CRT_BASE_SIZE);
952 s=sys_readbios( VDU_SCREEN_ROWS_ADDR, &bios_rows,
953 VDU_SCREEN_ROWS_SIZE);
954 s=sys_readbios(VDU_FONTLINES_ADDR, &bios_fontlines,
955 VDU_FONTLINES_SIZE);
957 vid_port = bios_crtbase;
958 scr_width = bios_columns;
959 font_lines = bios_fontlines;
960 scr_lines = bios_rows+1;
962 if (color) {
963 vid_base = COLOR_BASE;
964 vid_size = COLOR_SIZE;
965 } else {
966 vid_base = MONO_BASE;
967 vid_size = MONO_SIZE;
969 vid_size = EGA_SIZE;
970 wrap = 0;
972 console_memory = vm_map_phys(SELF, (void *) vid_base, vid_size);
974 if(console_memory == MAP_FAILED)
975 panic("Console couldn't map video memory");
977 font_memory = vm_map_phys(SELF, (void *)GA_VIDEO_ADDRESS, GA_FONT_SIZE);
979 if(font_memory == MAP_FAILED)
980 panic("Console couldn't map font memory");
982 vid_size >>= 1; /* word count */
983 vid_mask = vid_size - 1;
985 /* Size of the screen (number of displayed characters.) */
986 scr_size = scr_lines * scr_width;
988 /* There can be as many consoles as video memory allows. */
989 nr_cons = vid_size / scr_size;
991 if (nr_cons > NR_CONS) nr_cons = NR_CONS;
992 if (nr_cons > 1) wrap = 0;
993 if (nr_cons < 1) panic("no consoles");
994 page_size = vid_size / nr_cons;
997 cons->c_start = line * page_size;
998 cons->c_limit = cons->c_start + page_size;
999 cons->c_cur = cons->c_org = cons->c_start;
1000 cons->c_attr = cons->c_blank = BLANK_COLOR;
1002 if (line != 0) {
1003 /* Clear the non-console vtys. */
1004 blank_color = BLANK_COLOR;
1005 mem_vid_copy(BLANK_MEM, cons->c_start, scr_size);
1006 } else {
1007 /* Set the cursor of the console vty at the bottom. c_cur
1008 * is updated automatically later.
1010 scroll_screen(cons, SCROLL_UP);
1011 cons->c_row = scr_lines - 1;
1012 cons->c_column = 0;
1014 select_console(0);
1015 cons_ioctl(tp, 0);
1018 /*===========================================================================*
1019 * toggle_scroll *
1020 *===========================================================================*/
1021 void toggle_scroll()
1023 /* Toggle between hardware and software scroll. */
1025 cons_org0();
1026 softscroll = !softscroll;
1027 printf("%sware scrolling enabled.\n", softscroll ? "Soft" : "Hard");
1030 /*===========================================================================*
1031 * cons_stop *
1032 *===========================================================================*/
1033 void cons_stop()
1035 /* Prepare for halt or reboot. */
1036 cons_org0();
1037 softscroll = 1;
1038 select_console(0);
1039 cons_table[0].c_attr = cons_table[0].c_blank = BLANK_COLOR;
1040 shutting_down = TRUE;
1043 /*===========================================================================*
1044 * cons_org0 *
1045 *===========================================================================*/
1046 static void cons_org0()
1048 /* Scroll video memory back to put the origin at 0. */
1049 int cons_line;
1050 console_t *cons;
1051 unsigned n;
1053 for (cons_line = 0; cons_line < nr_cons; cons_line++) {
1054 cons = &cons_table[cons_line];
1055 while (cons->c_org > cons->c_start) {
1056 n = vid_size - scr_size; /* amount of unused memory */
1057 if (n > cons->c_org - cons->c_start)
1058 n = cons->c_org - cons->c_start;
1059 vid_vid_copy(cons->c_org, cons->c_org - n, scr_size);
1060 UPDATE_ORIGIN(cons, cons->c_org - n);
1062 flush(cons);
1064 select_console(ccurrent);
1067 /*===========================================================================*
1068 * disable_console *
1069 *===========================================================================*/
1070 static void disable_console()
1072 if (disabled_vc != -1)
1073 return;
1075 disabled_vc = ccurrent;
1076 disabled_sm = softscroll;
1078 cons_org0();
1079 softscroll = 1;
1080 select_console(0);
1082 /* Should also disable further output to virtual consoles */
1085 /*===========================================================================*
1086 * reenable_console *
1087 *===========================================================================*/
1088 static void reenable_console()
1090 if (disabled_vc == -1)
1091 return;
1093 softscroll = disabled_sm;
1094 select_console(disabled_vc);
1095 disabled_vc = -1;
1098 /*===========================================================================*
1099 * select_console *
1100 *===========================================================================*/
1101 void select_console(int cons_line)
1103 /* Set the current console to console number 'cons_line'. */
1105 if (shutting_down) return;
1107 if (cons_line < 0 || cons_line >= nr_cons) return;
1109 ccurrent = cons_line;
1110 curcons = &cons_table[cons_line];
1112 UPDATE_CURSOR(curcons, curcons->c_cur);
1113 UPDATE_ORIGIN(curcons, curcons->c_org);
1116 /*===========================================================================*
1117 * con_loadfont *
1118 *===========================================================================*/
1119 int con_loadfont(m)
1120 message *m;
1123 /* Load a font into the EGA or VGA adapter. */
1124 int result;
1125 static struct sequence seq1[7] = {
1126 { GA_SEQUENCER_INDEX, 0x00, 0x01 },
1127 { GA_SEQUENCER_INDEX, 0x02, 0x04 },
1128 { GA_SEQUENCER_INDEX, 0x04, 0x07 },
1129 { GA_SEQUENCER_INDEX, 0x00, 0x03 },
1130 { GA_GRAPHICS_INDEX, 0x04, 0x02 },
1131 { GA_GRAPHICS_INDEX, 0x05, 0x00 },
1132 { GA_GRAPHICS_INDEX, 0x06, 0x00 },
1134 static struct sequence seq2[7] = {
1135 { GA_SEQUENCER_INDEX, 0x00, 0x01 },
1136 { GA_SEQUENCER_INDEX, 0x02, 0x03 },
1137 { GA_SEQUENCER_INDEX, 0x04, 0x03 },
1138 { GA_SEQUENCER_INDEX, 0x00, 0x03 },
1139 { GA_GRAPHICS_INDEX, 0x04, 0x00 },
1140 { GA_GRAPHICS_INDEX, 0x05, 0x10 },
1141 { GA_GRAPHICS_INDEX, 0x06, 0 },
1144 seq2[6].value= color ? 0x0E : 0x0A;
1146 result = ga_program(seq1); /* bring font memory into view */
1148 if(sys_safecopyfrom(m->m_source, (cp_grant_id_t) m->IO_GRANT, 0,
1149 (vir_bytes) font_memory, GA_FONT_SIZE) != OK) {
1150 printf("tty: copying from %d failed\n", m->m_source);
1151 return EFAULT;
1154 result = ga_program(seq2); /* restore */
1156 return(result);
1159 /*===========================================================================*
1160 * ga_program *
1161 *===========================================================================*/
1162 static int ga_program(seq)
1163 struct sequence *seq;
1165 pvb_pair_t char_out[14];
1166 int i;
1167 for (i=0; i<7; i++) {
1168 pv_set(char_out[2*i], seq->index, seq->port);
1169 pv_set(char_out[2*i+1], seq->index+1, seq->value);
1170 seq++;
1172 return sys_voutb(char_out, 14);
1175 /*===========================================================================*
1176 * cons_ioctl *
1177 *===========================================================================*/
1178 static int cons_ioctl(tty_t *tp, int UNUSED(try))
1180 /* Set the screen dimensions. */
1182 tp->tty_winsize.ws_row= scr_lines;
1183 tp->tty_winsize.ws_col= scr_width;
1184 tp->tty_winsize.ws_xpixel= scr_width * 8;
1185 tp->tty_winsize.ws_ypixel= scr_lines * font_lines;
1187 return 0;
1190 #define LIMITINDEX(mask, start, size, ct) { \
1191 int countlimit = size - start; \
1192 start &= mask; \
1193 if(ct > countlimit) ct = countlimit; \
1196 /*===========================================================================*
1197 * mem_vid_copy *
1198 *===========================================================================*/
1199 static void mem_vid_copy(vir_bytes src, int dst_index, int count)
1201 u16_t *src_mem = (u16_t *) src;
1202 while(count > 0) {
1203 int i, subcount = count;
1204 u16_t *dst_mem;
1205 LIMITINDEX(vid_mask, dst_index, vid_size, subcount);
1206 dst_mem = (u16_t *) console_memory + dst_index;
1207 if(!src)
1208 for(i = 0; i < subcount; i++)
1209 *dst_mem++ = blank_color;
1210 else
1211 for(i = 0; i < subcount; i++)
1212 *dst_mem++ = *src_mem++;
1213 count -= subcount;
1214 dst_index += subcount;
1218 /*===========================================================================*
1219 * vid_vid_copy *
1220 *===========================================================================*/
1221 static void vid_vid_copy(int src_index, int dst_index, int count)
1223 int backwards = 0;
1224 if(src_index < dst_index)
1225 backwards = 1;
1226 while(count > 0) {
1227 int i, subcount = count;
1228 u16_t *dst_mem, *src_mem;
1229 LIMITINDEX(vid_mask, src_index, vid_size, subcount);
1230 LIMITINDEX(vid_mask, dst_index, vid_size, subcount);
1231 src_mem = (u16_t *) console_memory + src_index;
1232 dst_mem = (u16_t *) console_memory + dst_index;
1233 if(backwards) {
1234 src_mem += subcount - 1;
1235 dst_mem += subcount - 1;
1236 for(i = 0; i < subcount; i++)
1237 *dst_mem-- = *src_mem--;
1238 } else {
1239 for(i = 0; i < subcount; i++)
1240 *dst_mem++ = *src_mem++;
1242 count -= subcount;
1243 dst_index += subcount;
1244 src_index += subcount;