dec21140A ethernet driver for virtualpc, contributed by nicolas tittley.
[minix.git] / drivers / tty / console.c
blob7fc93ecacabb4bd5d8556ac15ad04677cbb8d439
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 "../drivers.h"
20 #include <termios.h>
21 #include <sys/ioctl.h>
22 #include <sys/vm.h>
23 #include <sys/video.h>
24 #include <sys/mman.h>
25 #include <minix/tty.h>
26 #include <minix/callnr.h>
27 #include <minix/com.h>
28 #include <minix/sys_config.h>
29 #include <minix/vm.h>
30 #include "tty.h"
32 /* Set this to 1 if you want console output duplicated on the first
33 * serial line.
35 #define DUP_CONS_TO_SER 0
37 /* The clock task should provide an interface for this */
38 #define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */
40 /* Global variables used by the console driver and assembly support. */
41 PUBLIC phys_bytes vid_size; /* 0x2000 for color or 0x0800 for mono */
42 PUBLIC phys_bytes vid_base;
43 PUBLIC unsigned vid_mask; /* 0x1FFF for color or 0x07FF for mono */
44 PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */
46 /* Private variables used by the console driver. */
47 PRIVATE int vid_port; /* I/O port for accessing 6845 */
48 PRIVATE int wrap; /* hardware can wrap? */
49 PRIVATE int softscroll; /* 1 = software scrolling, 0 = hardware */
50 PRIVATE int beeping; /* speaker is beeping? */
51 PRIVATE unsigned font_lines; /* font lines per character */
52 PRIVATE unsigned scr_width; /* # characters on a line */
53 PRIVATE unsigned scr_lines; /* # lines on the screen */
54 PRIVATE unsigned scr_size; /* # characters on the screen */
56 /* tells mem_vid_copy() to blank the screen */
57 #define BLANK_MEM ((vir_bytes) 0)
59 PRIVATE int disabled_vc = -1; /* Virtual console that was active when
60 * disable_console was called.
62 PRIVATE int disabled_sm; /* Scroll mode to be restored when re-enabling
63 * console
66 char *console_memory = NULL;
67 char *font_memory = NULL;
69 /* Per console data. */
70 typedef struct console {
71 tty_t *c_tty; /* associated TTY struct */
72 int c_column; /* current column number (0-origin) */
73 int c_row; /* current row (0 at top of screen) */
74 int c_rwords; /* number of WORDS (not bytes) in outqueue */
75 unsigned c_start; /* start of video memory of this console */
76 unsigned c_limit; /* limit of this console's video memory */
77 unsigned c_org; /* location in RAM where 6845 base points */
78 unsigned c_cur; /* current position of cursor in video RAM */
79 unsigned c_attr; /* character attribute */
80 unsigned c_blank; /* blank attribute */
81 char c_reverse; /* reverse video */
82 char c_esc_state; /* 0=normal, 1=ESC, 2=ESC[ */
83 char c_esc_intro; /* Distinguishing character following ESC */
84 int *c_esc_parmp; /* pointer to current escape parameter */
85 int c_esc_parmv[MAX_ESC_PARMS]; /* list of escape parameters */
86 u16_t c_ramqueue[CONS_RAM_WORDS]; /* buffer for video RAM */
87 int c_line; /* line no */
88 } console_t;
90 #define UPDATE_CURSOR(ccons, cursor) { \
91 ccons->c_cur = cursor; \
92 if(curcons && ccons == curcons) \
93 set_6845(CURSOR, ccons->c_cur); \
96 #define UPDATE_ORIGIN(ccons, origin) { \
97 ccons->c_org = origin; \
98 if (curcons && ccons == curcons) \
99 set_6845(VID_ORG, ccons->c_org); \
102 PRIVATE int nr_cons= 1; /* actual number of consoles */
103 PRIVATE console_t cons_table[NR_CONS];
104 PRIVATE console_t *curcons = NULL; /* currently visible */
106 PRIVATE int shutting_down = FALSE; /* don't allow console switches */
108 /* Color if using a color controller. */
109 #define color (vid_port == C_6845)
111 /* Map from ANSI colors to the attributes used by the PC */
112 PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
114 /* Structure used for font management */
115 struct sequence {
116 unsigned short index;
117 unsigned char port;
118 unsigned char value;
121 FORWARD _PROTOTYPE( int cons_write, (struct tty *tp, int try) );
122 FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c) );
123 FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c) );
124 FORWARD _PROTOTYPE( void cons_putk, (int c) );
125 FORWARD _PROTOTYPE( void beep, (void) );
126 FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c) );
127 FORWARD _PROTOTYPE( void flush, (console_t *cons) );
128 FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c) );
129 FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir) );
130 FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val) );
131 FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp) );
132 FORWARD _PROTOTYPE( void cons_org0, (void) );
133 FORWARD _PROTOTYPE( void disable_console, (void) );
134 FORWARD _PROTOTYPE( void reenable_console, (void) );
135 FORWARD _PROTOTYPE( int ga_program, (struct sequence *seq) );
136 FORWARD _PROTOTYPE( int cons_ioctl, (tty_t *tp, int) );
137 FORWARD _PROTOTYPE( void mem_vid_copy, (vir_bytes src, int dst, int count) );
138 FORWARD _PROTOTYPE( void vid_vid_copy, (int src, int dst, int count) );
140 #if 0
141 FORWARD _PROTOTYPE( void get_6845, (int reg, unsigned *val) );
142 #endif
144 /*===========================================================================*
145 * cons_write *
146 *===========================================================================*/
147 PRIVATE 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;
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_out_safe) {
175 if ((result = sys_safecopyfrom(tp->tty_outproc, tp->tty_out_vir_g,
176 tp->tty_out_vir_offset, (vir_bytes) buf, count, D)) != OK)
177 break;
178 tp->tty_out_vir_offset += count;
179 } else {
180 if ((result = sys_vircopy(tp->tty_outproc, D, tp->tty_out_vir_g,
181 SELF, D, (vir_bytes) buf, (vir_bytes) count)) != OK)
182 break;
183 tp->tty_out_vir_g += count;
185 tbuf = buf;
187 /* Update terminal data structure. */
188 tp->tty_outcum += count;
189 tp->tty_outleft -= count;
191 /* Output each byte of the copy to the screen. Avoid calling
192 * out_char() for the "easy" characters, put them into the buffer
193 * directly.
195 do {
196 if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
197 || cons->c_column >= scr_width
198 || cons->c_rwords >= buflen(cons->c_ramqueue))
200 out_char(cons, *tbuf++);
201 } else {
202 #if DUP_CONS_TO_SER
203 if (cons == &cons_table[0]) ser_putc(*tbuf);
204 #endif
205 cons->c_ramqueue[cons->c_rwords++] =
206 cons->c_attr | (*tbuf++ & BYTE);
207 cons->c_column++;
209 } while (--count != 0);
210 } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
212 flush(cons); /* transfer anything buffered to the screen */
214 /* Reply to the writer if all output is finished or if an error occured. */
215 if (tp->tty_outleft == 0 || result != OK) {
216 /* REVIVE is not possible. I/O on memory mapped consoles finishes. */
217 tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc,
218 tp->tty_outcum);
219 tp->tty_outcum = 0;
222 return 0;
225 /*===========================================================================*
226 * cons_echo *
227 *===========================================================================*/
228 PRIVATE void cons_echo(tp, c)
229 register tty_t *tp; /* pointer to tty struct */
230 int c; /* character to be echoed */
232 /* Echo keyboard input (print & flush). */
233 console_t *cons = tp->tty_priv;
235 out_char(cons, c);
236 flush(cons);
239 /*===========================================================================*
240 * out_char *
241 *===========================================================================*/
242 PRIVATE void out_char(cons, c)
243 register console_t *cons; /* pointer to console struct */
244 int c; /* character to be output */
246 /* Output a character on the console. Check for escape sequences first. */
247 if (cons->c_esc_state > 0) {
248 parse_escape(cons, c);
249 return;
252 #if DUP_CONS_TO_SER
253 if (cons == &cons_table[0] && c != '\0')
255 if (c == '\n')
256 ser_putc('\r');
257 ser_putc(c);
259 #endif
261 switch(c) {
262 case 000: /* null is typically used for padding */
263 return; /* better not do anything */
265 case 007: /* ring the bell */
266 flush(cons); /* print any chars queued for output */
267 beep();
268 return;
270 case '\b': /* backspace */
271 if (--cons->c_column < 0) {
272 if (--cons->c_row >= 0) cons->c_column += scr_width;
274 flush(cons);
275 return;
277 case '\n': /* line feed */
278 if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
279 == (OPOST|ONLCR)) {
280 cons->c_column = 0;
282 /*FALL THROUGH*/
283 case 013: /* CTRL-K */
284 case 014: /* CTRL-L */
285 if (cons->c_row == scr_lines-1) {
286 scroll_screen(cons, SCROLL_UP);
287 } else {
288 cons->c_row++;
290 flush(cons);
291 return;
293 case '\r': /* carriage return */
294 cons->c_column = 0;
295 flush(cons);
296 return;
298 case '\t': /* tab */
299 cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
300 if (cons->c_column > scr_width) {
301 cons->c_column -= scr_width;
302 if (cons->c_row == scr_lines-1) {
303 scroll_screen(cons, SCROLL_UP);
304 } else {
305 cons->c_row++;
308 flush(cons);
309 return;
311 case 033: /* ESC - start of an escape sequence */
312 flush(cons); /* print any chars queued for output */
313 cons->c_esc_state = 1; /* mark ESC as seen */
314 return;
316 default: /* printable chars are stored in ramqueue */
317 if (cons->c_column >= scr_width) {
318 if (!LINEWRAP) return;
319 if (cons->c_row == scr_lines-1) {
320 scroll_screen(cons, SCROLL_UP);
321 } else {
322 cons->c_row++;
324 cons->c_column = 0;
325 flush(cons);
327 if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons);
328 cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE);
329 cons->c_column++; /* next column */
330 return;
334 /*===========================================================================*
335 * scroll_screen *
336 *===========================================================================*/
337 PRIVATE void scroll_screen(cons, dir)
338 register console_t *cons; /* pointer to console struct */
339 int dir; /* SCROLL_UP or SCROLL_DOWN */
341 unsigned new_line, new_org, chars;
343 flush(cons);
344 chars = scr_size - scr_width; /* one screen minus one line */
346 /* Scrolling the screen is a real nuisance due to the various incompatible
347 * video cards. This driver supports software scrolling (Hercules?),
348 * hardware scrolling (mono and CGA cards) and hardware scrolling without
349 * wrapping (EGA cards). In the latter case we must make sure that
350 * c_start <= c_org && c_org + scr_size <= c_limit
351 * holds, because EGA doesn't wrap around the end of video memory.
353 if (dir == SCROLL_UP) {
354 /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
355 if (softscroll) {
356 vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars);
357 } else
358 if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) {
359 vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars);
360 UPDATE_ORIGIN(cons, cons->c_start);
361 } else {
362 UPDATE_ORIGIN(cons, (cons->c_org + scr_width) & vid_mask);
364 new_line = (cons->c_org + chars) & vid_mask;
365 } else {
366 /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
367 if (softscroll) {
368 vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars);
369 } else
370 if (!wrap && cons->c_org < cons->c_start + scr_width) {
371 new_org = cons->c_limit - scr_size;
372 vid_vid_copy(cons->c_org, new_org + scr_width, chars);
373 UPDATE_ORIGIN(cons, new_org);
374 } else {
375 UPDATE_ORIGIN(cons, (cons->c_org - scr_width) & vid_mask);
377 new_line = cons->c_org;
379 /* Blank the new line at top or bottom. */
380 blank_color = cons->c_blank;
381 mem_vid_copy(BLANK_MEM, new_line, scr_width);
383 flush(cons);
386 /*===========================================================================*
387 * flush *
388 *===========================================================================*/
389 PRIVATE void flush(cons)
390 register console_t *cons; /* pointer to console struct */
392 /* Send characters buffered in 'ramqueue' to screen memory, check the new
393 * cursor position, compute the new hardware cursor position and set it.
395 unsigned cur;
396 tty_t *tp = cons->c_tty;
398 /* Have the characters in 'ramqueue' transferred to the screen. */
399 if (cons->c_rwords > 0) {
400 mem_vid_copy((vir_bytes) cons->c_ramqueue, cons->c_cur, cons->c_rwords);
401 cons->c_rwords = 0;
403 /* TTY likes to know the current column and if echoing messed up. */
404 tp->tty_position = cons->c_column;
405 tp->tty_reprint = TRUE;
408 /* Check and update the cursor position. */
409 if (cons->c_column < 0) cons->c_column = 0;
410 if (cons->c_column > scr_width) cons->c_column = scr_width;
411 if (cons->c_row < 0) cons->c_row = 0;
412 if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1;
413 cur = cons->c_org + cons->c_row * scr_width + cons->c_column;
414 if (cur != cons->c_cur)
415 UPDATE_CURSOR(cons, cur);
418 /*===========================================================================*
419 * parse_escape *
420 *===========================================================================*/
421 PRIVATE void parse_escape(cons, c)
422 register console_t *cons; /* pointer to console struct */
423 char c; /* next character in escape sequence */
425 /* The following ANSI escape sequences are currently supported.
426 * If n and/or m are omitted, they default to 1.
427 * ESC [nA moves up n lines
428 * ESC [nB moves down n lines
429 * ESC [nC moves right n spaces
430 * ESC [nD moves left n spaces
431 * ESC [m;nH" moves cursor to (m,n)
432 * ESC [J clears screen from cursor
433 * ESC [K clears line from cursor
434 * ESC [nL inserts n lines ar cursor
435 * ESC [nM deletes n lines at cursor
436 * ESC [nP deletes n chars at cursor
437 * ESC [n@ inserts n chars at cursor
438 * ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
439 * ESC M scrolls the screen backwards if the cursor is on the top line
442 switch (cons->c_esc_state) {
443 case 1: /* ESC seen */
444 cons->c_esc_intro = '\0';
445 cons->c_esc_parmp = bufend(cons->c_esc_parmv);
446 do {
447 *--cons->c_esc_parmp = 0;
448 } while (cons->c_esc_parmp > cons->c_esc_parmv);
449 switch (c) {
450 case '[': /* Control Sequence Introducer */
451 cons->c_esc_intro = c;
452 cons->c_esc_state = 2;
453 break;
454 case 'M': /* Reverse Index */
455 do_escape(cons, c);
456 break;
457 default:
458 cons->c_esc_state = 0;
460 break;
462 case 2: /* ESC [ seen */
463 if (c >= '0' && c <= '9') {
464 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
465 *cons->c_esc_parmp = *cons->c_esc_parmp * 10 + (c-'0');
466 } else
467 if (c == ';') {
468 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
469 cons->c_esc_parmp++;
470 } else {
471 do_escape(cons, c);
473 break;
477 /*===========================================================================*
478 * do_escape *
479 *===========================================================================*/
480 PRIVATE void do_escape(cons, c)
481 register console_t *cons; /* pointer to console struct */
482 char c; /* next character in escape sequence */
484 int value, n;
485 unsigned src, dst, count;
486 int *parmp;
488 /* Some of these things hack on screen RAM, so it had better be up to date */
489 flush(cons);
491 if (cons->c_esc_intro == '\0') {
492 /* Handle a sequence beginning with just ESC */
493 switch (c) {
494 case 'M': /* Reverse Index */
495 if (cons->c_row == 0) {
496 scroll_screen(cons, SCROLL_DOWN);
497 } else {
498 cons->c_row--;
500 flush(cons);
501 break;
503 default: break;
505 } else
506 if (cons->c_esc_intro == '[') {
507 /* Handle a sequence beginning with ESC [ and parameters */
508 value = cons->c_esc_parmv[0];
509 switch (c) {
510 case 'A': /* ESC [nA moves up n lines */
511 n = (value == 0 ? 1 : value);
512 cons->c_row -= n;
513 flush(cons);
514 break;
516 case 'B': /* ESC [nB moves down n lines */
517 n = (value == 0 ? 1 : value);
518 cons->c_row += n;
519 flush(cons);
520 break;
522 case 'C': /* ESC [nC moves right n spaces */
523 n = (value == 0 ? 1 : value);
524 cons->c_column += n;
525 flush(cons);
526 break;
528 case 'D': /* ESC [nD moves left n spaces */
529 n = (value == 0 ? 1 : value);
530 cons->c_column -= n;
531 flush(cons);
532 break;
534 case 'H': /* ESC [m;nH" moves cursor to (m,n) */
535 cons->c_row = cons->c_esc_parmv[0] - 1;
536 cons->c_column = cons->c_esc_parmv[1] - 1;
537 flush(cons);
538 break;
540 case 'J': /* ESC [sJ clears in display */
541 switch (value) {
542 case 0: /* Clear from cursor to end of screen */
543 count = scr_size - (cons->c_cur - cons->c_org);
544 dst = cons->c_cur;
545 break;
546 case 1: /* Clear from start of screen to cursor */
547 count = cons->c_cur - cons->c_org;
548 dst = cons->c_org;
549 break;
550 case 2: /* Clear entire screen */
551 count = scr_size;
552 dst = cons->c_org;
553 break;
554 default: /* Do nothing */
555 count = 0;
556 dst = cons->c_org;
558 blank_color = cons->c_blank;
559 mem_vid_copy(BLANK_MEM, dst, count);
560 break;
562 case 'K': /* ESC [sK clears line from cursor */
563 switch (value) {
564 case 0: /* Clear from cursor to end of line */
565 count = scr_width - cons->c_column;
566 dst = cons->c_cur;
567 break;
568 case 1: /* Clear from beginning of line to cursor */
569 count = cons->c_column;
570 dst = cons->c_cur - cons->c_column;
571 break;
572 case 2: /* Clear entire line */
573 count = scr_width;
574 dst = cons->c_cur - cons->c_column;
575 break;
576 default: /* Do nothing */
577 count = 0;
578 dst = cons->c_cur;
580 blank_color = cons->c_blank;
581 mem_vid_copy(BLANK_MEM, dst, count);
582 break;
584 case 'L': /* ESC [nL inserts n lines at cursor */
585 n = value;
586 if (n < 1) n = 1;
587 if (n > (scr_lines - cons->c_row))
588 n = scr_lines - cons->c_row;
590 src = cons->c_org + cons->c_row * scr_width;
591 dst = src + n * scr_width;
592 count = (scr_lines - cons->c_row - n) * scr_width;
593 vid_vid_copy(src, dst, count);
594 blank_color = cons->c_blank;
595 mem_vid_copy(BLANK_MEM, src, n * scr_width);
596 break;
598 case 'M': /* ESC [nM deletes n lines at cursor */
599 n = value;
600 if (n < 1) n = 1;
601 if (n > (scr_lines - cons->c_row))
602 n = scr_lines - cons->c_row;
604 dst = cons->c_org + cons->c_row * scr_width;
605 src = dst + n * scr_width;
606 count = (scr_lines - cons->c_row - n) * scr_width;
607 vid_vid_copy(src, dst, count);
608 blank_color = cons->c_blank;
609 mem_vid_copy(BLANK_MEM, dst + count, n * scr_width);
610 break;
612 case '@': /* ESC [n@ inserts n chars at cursor */
613 n = value;
614 if (n < 1) n = 1;
615 if (n > (scr_width - cons->c_column))
616 n = scr_width - cons->c_column;
618 src = cons->c_cur;
619 dst = src + n;
620 count = scr_width - cons->c_column - n;
621 vid_vid_copy(src, dst, count);
622 blank_color = cons->c_blank;
623 mem_vid_copy(BLANK_MEM, src, n);
624 break;
626 case 'P': /* ESC [nP deletes n chars at cursor */
627 n = value;
628 if (n < 1) n = 1;
629 if (n > (scr_width - cons->c_column))
630 n = scr_width - cons->c_column;
632 dst = cons->c_cur;
633 src = dst + n;
634 count = scr_width - cons->c_column - n;
635 vid_vid_copy(src, dst, count);
636 blank_color = cons->c_blank;
637 mem_vid_copy(BLANK_MEM, dst + count, n);
638 break;
640 case 'm': /* ESC [nm enables rendition n */
641 for (parmp = cons->c_esc_parmv; parmp <= cons->c_esc_parmp
642 && parmp < bufend(cons->c_esc_parmv); parmp++) {
643 if (cons->c_reverse) {
644 /* Unswap fg and bg colors */
645 cons->c_attr = ((cons->c_attr & 0x7000) >> 4) |
646 ((cons->c_attr & 0x0700) << 4) |
647 ((cons->c_attr & 0x8800));
649 switch (n = *parmp) {
650 case 0: /* NORMAL */
651 cons->c_attr = cons->c_blank = BLANK_COLOR;
652 cons->c_reverse = FALSE;
653 break;
655 case 1: /* BOLD */
656 /* Set intensity bit */
657 cons->c_attr |= 0x0800;
658 break;
660 case 4: /* UNDERLINE */
661 if (color) {
662 /* Change white to cyan, i.e. lose red
664 cons->c_attr = (cons->c_attr & 0xBBFF);
665 } else {
666 /* Set underline attribute */
667 cons->c_attr = (cons->c_attr & 0x99FF);
669 break;
671 case 5: /* BLINKING */
672 /* Set the blink bit */
673 cons->c_attr |= 0x8000;
674 break;
676 case 7: /* REVERSE */
677 cons->c_reverse = TRUE;
678 break;
680 default: /* COLOR */
681 if (n == 39) n = 37; /* set default color */
682 if (n == 49) n = 40;
684 if (!color) {
685 /* Don't mess up a monochrome screen */
686 } else
687 if (30 <= n && n <= 37) {
688 /* Foreground color */
689 cons->c_attr =
690 (cons->c_attr & 0xF8FF) |
691 (ansi_colors[(n - 30)] << 8);
692 cons->c_blank =
693 (cons->c_blank & 0xF8FF) |
694 (ansi_colors[(n - 30)] << 8);
695 } else
696 if (40 <= n && n <= 47) {
697 /* Background color */
698 cons->c_attr =
699 (cons->c_attr & 0x8FFF) |
700 (ansi_colors[(n - 40)] << 12);
701 cons->c_blank =
702 (cons->c_blank & 0x8FFF) |
703 (ansi_colors[(n - 40)] << 12);
706 if (cons->c_reverse) {
707 /* Swap fg and bg colors */
708 cons->c_attr = ((cons->c_attr & 0x7000) >> 4) |
709 ((cons->c_attr & 0x0700) << 4) |
710 ((cons->c_attr & 0x8800));
713 break;
716 cons->c_esc_state = 0;
719 /*===========================================================================*
720 * set_6845 *
721 *===========================================================================*/
722 PRIVATE void set_6845(reg, val)
723 int reg; /* which register pair to set */
724 unsigned val; /* 16-bit value to set it to */
726 /* Set a register pair inside the 6845.
727 * Registers 12-13 tell the 6845 where in video ram to start
728 * Registers 14-15 tell the 6845 where to put the cursor
730 pvb_pair_t char_out[4];
731 pv_set(char_out[0], vid_port + INDEX, reg); /* set index register */
732 pv_set(char_out[1], vid_port + DATA, (val>>8) & BYTE); /* high byte */
733 pv_set(char_out[2], vid_port + INDEX, reg + 1); /* again */
734 pv_set(char_out[3], vid_port + DATA, val&BYTE); /* low byte */
735 sys_voutb(char_out, 4); /* do actual output */
738 #if 0
739 /*===========================================================================*
740 * get_6845 *
741 *===========================================================================*/
742 PRIVATE void get_6845(reg, val)
743 int reg; /* which register pair to set */
744 unsigned *val; /* 16-bit value to set it to */
746 char v1, v2;
747 unsigned long v;
748 /* Get a register pair inside the 6845. */
749 sys_outb(vid_port + INDEX, reg);
750 sys_inb(vid_port + DATA, &v);
751 v1 = v;
752 sys_outb(vid_port + INDEX, reg+1);
753 sys_inb(vid_port + DATA, &v);
754 v2 = v;
755 *val = (v1 << 8) | v2;
757 #endif
759 /*===========================================================================*
760 * beep *
761 *===========================================================================*/
762 PRIVATE void beep()
764 /* Making a beeping sound on the speaker (output for CRTL-G).
765 * This routine works by turning on the bits 0 and 1 in port B of the 8255
766 * chip that drive the speaker.
768 static timer_t tmr_stop_beep;
769 pvb_pair_t char_out[3];
770 clock_t now;
771 unsigned long port_b_val;
772 int s;
774 /* Fetch current time in advance to prevent beeping delay. */
775 if ((s=getuptime(&now)) != OK)
776 panic("TTY","Console couldn't get clock's uptime.", s);
777 if (!beeping) {
778 /* Set timer channel 2, square wave, with given frequency. */
779 pv_set(char_out[0], TIMER_MODE, 0xB6);
780 pv_set(char_out[1], TIMER2, (BEEP_FREQ >> 0) & BYTE);
781 pv_set(char_out[2], TIMER2, (BEEP_FREQ >> 8) & BYTE);
782 if (sys_voutb(char_out, 3)==OK) {
783 if (sys_inb(PORT_B, &port_b_val)==OK &&
784 sys_outb(PORT_B, (port_b_val|3))==OK)
785 beeping = TRUE;
788 /* Add a timer to the timers list. Possibly reschedule the alarm. */
789 tmrs_settimer(&tty_timers, &tmr_stop_beep, now+B_TIME, stop_beep, NULL);
790 if (tty_timers->tmr_exp_time != tty_next_timeout) {
791 tty_next_timeout = tty_timers->tmr_exp_time;
792 if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
793 panic("TTY","Console couldn't set alarm.", s);
798 /*===========================================================================*
799 * do_video *
800 *===========================================================================*/
801 PUBLIC void do_video(message *m)
803 int r, safe = 0;
805 /* Execute the requested device driver function. */
806 r= EINVAL; /* just in case */
807 switch (m->m_type) {
808 case DEV_OPEN:
809 /* Should grant IOPL */
810 disable_console();
811 r= OK;
812 break;
813 case DEV_CLOSE:
814 reenable_console();
815 r= OK;
816 break;
817 case DEV_IOCTL_S:
818 safe=1;
819 switch(m->TTY_REQUEST) {
820 case TIOCMAPMEM:
821 case TIOCUNMAPMEM: {
822 int r, do_map;
823 struct mapreqvm mapreqvm;
824 void *result;
826 do_map= (m->REQUEST == TIOCMAPMEM); /* else unmap */
828 /* Get request structure */
829 if(!safe) {
830 printf("tty: safecopy only\n");
831 return;
834 r = sys_safecopyfrom(m->IO_ENDPT,
835 (vir_bytes)m->ADDRESS, 0, (vir_bytes) &mapreqvm,
836 sizeof(mapreqvm), D);
838 if (r != OK)
840 printf("tty: sys_safecopyfrom failed\n");
841 tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT,
843 return;
846 /* In safe ioctl mode, the POSITION field contains
847 * the endpt number of the original requestor.
848 * IO_ENDPT is always FS.
851 if(do_map) {
852 mapreqvm.vaddr_ret = vm_map_phys(m->POSITION,
853 (void *) mapreqvm.phys_offset, mapreqvm.size);
854 if((r = sys_safecopyto(m->IO_ENDPT,
855 (vir_bytes)m->ADDRESS, 0,
856 (vir_bytes) &mapreqvm,
857 sizeof(mapreqvm), D)) != OK) {
858 printf("tty: sys_safecopyto failed\n");
860 } else {
861 r = vm_unmap_phys(m->POSITION,
862 mapreqvm.vaddr, mapreqvm.size);
864 tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r);
865 return;
868 r= ENOTTY;
869 break;
871 default:
872 printf(
873 "Warning, TTY(video) got unexpected request %d from %d\n",
874 m->m_type, m->m_source);
875 r= EINVAL;
877 tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r);
881 /*===========================================================================*
882 * beep_x *
883 *===========================================================================*/
884 PUBLIC void beep_x(freq, dur)
885 unsigned freq;
886 clock_t dur;
888 /* Making a beeping sound on the speaker.
889 * This routine works by turning on the bits 0 and 1 in port B of the 8255
890 * chip that drive the speaker.
892 static timer_t tmr_stop_beep;
893 pvb_pair_t char_out[3];
894 clock_t now;
895 unsigned long port_b_val;
896 int s;
898 unsigned long ival= TIMER_FREQ / freq;
899 if (ival == 0 || ival > 0xffff)
900 return; /* Frequency out of range */
902 /* Fetch current time in advance to prevent beeping delay. */
903 if ((s=getuptime(&now)) != OK)
904 panic("TTY","Console couldn't get clock's uptime.", s);
905 if (!beeping) {
906 /* Set timer channel 2, square wave, with given frequency. */
907 pv_set(char_out[0], TIMER_MODE, 0xB6);
908 pv_set(char_out[1], TIMER2, (ival >> 0) & BYTE);
909 pv_set(char_out[2], TIMER2, (ival >> 8) & BYTE);
910 if (sys_voutb(char_out, 3)==OK) {
911 if (sys_inb(PORT_B, &port_b_val)==OK &&
912 sys_outb(PORT_B, (port_b_val|3))==OK)
913 beeping = TRUE;
916 /* Add a timer to the timers list. Possibly reschedule the alarm. */
917 tmrs_settimer(&tty_timers, &tmr_stop_beep, now+dur, stop_beep, NULL);
918 if (tty_timers->tmr_exp_time != tty_next_timeout) {
919 tty_next_timeout = tty_timers->tmr_exp_time;
920 if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
921 panic("TTY","Console couldn't set alarm.", s);
925 /*===========================================================================*
926 * stop_beep *
927 *===========================================================================*/
928 PRIVATE void stop_beep(tmrp)
929 timer_t *tmrp;
931 /* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
932 unsigned long port_b_val;
933 if (sys_inb(PORT_B, &port_b_val)==OK &&
934 sys_outb(PORT_B, (port_b_val & ~3))==OK)
935 beeping = FALSE;
938 /*===========================================================================*
939 * scr_init *
940 *===========================================================================*/
941 PUBLIC void scr_init(tp)
942 tty_t *tp;
944 /* Initialize the screen driver. */
945 console_t *cons;
946 u16_t bios_columns, bios_crtbase, bios_fontlines;
947 u8_t bios_rows;
948 int line;
949 int s;
950 static int vdu_initialized = 0;
951 static unsigned page_size;
953 /* Associate console and TTY. */
954 line = tp - &tty_table[0];
955 if (line >= nr_cons) return;
956 cons = &cons_table[line];
957 cons->c_tty = tp;
958 cons->c_line = line;
959 tp->tty_priv = cons;
961 /* Fill in TTY function hooks. */
962 tp->tty_devwrite = cons_write;
963 tp->tty_echo = cons_echo;
964 tp->tty_ioctl = cons_ioctl;
966 /* Get the BIOS parameters that describe the VDU. */
967 if (! vdu_initialized++) {
969 /* How about error checking? What to do on failure??? */
970 s=sys_readbios(VDU_SCREEN_COLS_ADDR, &bios_columns,
971 VDU_SCREEN_COLS_SIZE);
972 s=sys_readbios(VDU_CRT_BASE_ADDR, &bios_crtbase,
973 VDU_CRT_BASE_SIZE);
974 s=sys_readbios( VDU_SCREEN_ROWS_ADDR, &bios_rows,
975 VDU_SCREEN_ROWS_SIZE);
976 s=sys_readbios(VDU_FONTLINES_ADDR, &bios_fontlines,
977 VDU_FONTLINES_SIZE);
979 vid_port = bios_crtbase;
980 scr_width = bios_columns;
981 font_lines = bios_fontlines;
982 scr_lines = machine.vdu_ega ? bios_rows+1 : 25;
984 if (color) {
985 vid_base = COLOR_BASE;
986 vid_size = COLOR_SIZE;
987 } else {
988 vid_base = MONO_BASE;
989 vid_size = MONO_SIZE;
991 if (machine.vdu_ega) vid_size = EGA_SIZE;
992 wrap = ! machine.vdu_ega;
994 console_memory = vm_map_phys(SELF, (void *) vid_base, vid_size);
996 if(console_memory == MAP_FAILED)
997 panic("TTY","Console couldn't map video memory", NO_NUM);
999 font_memory = vm_map_phys(SELF, (void *)GA_VIDEO_ADDRESS, GA_FONT_SIZE);
1001 if(font_memory == MAP_FAILED)
1002 panic("TTY","Console couldn't map font memory", NO_NUM);
1005 vid_size >>= 1; /* word count */
1006 vid_mask = vid_size - 1;
1008 /* Size of the screen (number of displayed characters.) */
1009 scr_size = scr_lines * scr_width;
1011 /* There can be as many consoles as video memory allows. */
1012 nr_cons = vid_size / scr_size;
1014 if (nr_cons > NR_CONS) nr_cons = NR_CONS;
1015 if (nr_cons > 1) wrap = 0;
1016 page_size = vid_size / nr_cons;
1019 cons->c_start = line * page_size;
1020 cons->c_limit = cons->c_start + page_size;
1021 cons->c_cur = cons->c_org = cons->c_start;
1022 cons->c_attr = cons->c_blank = BLANK_COLOR;
1024 if (line != 0) {
1025 /* Clear the non-console vtys. */
1026 blank_color = BLANK_COLOR;
1027 mem_vid_copy(BLANK_MEM, cons->c_start, scr_size);
1028 } else {
1029 /* Set the cursor of the console vty at the bottom. c_cur
1030 * is updated automatically later.
1032 scroll_screen(cons, SCROLL_UP);
1033 cons->c_row = scr_lines - 1;
1034 cons->c_column = 0;
1036 select_console(0);
1037 cons_ioctl(tp, 0);
1040 /*===========================================================================*
1041 * kputc *
1042 *===========================================================================*/
1043 PUBLIC void kputc(c)
1044 int c;
1046 /* Accumulate a single character for a kernel message. Send a notification
1047 * the to output driver if an END_OF_KMESS is encountered.
1049 #if 0
1050 ser_putc(c);
1051 return;
1052 #endif
1054 #if 0
1055 if (panicing)
1056 #endif
1057 cons_putk(c);
1058 if (c != 0) {
1059 kmess.km_buf[kmess.km_next] = c; /* put normal char in buffer */
1060 if (kmess.km_size < _KMESS_BUF_SIZE)
1061 kmess.km_size += 1;
1062 kmess.km_next = (kmess.km_next + 1) % _KMESS_BUF_SIZE;
1063 } else {
1064 notify(LOG_PROC_NR);
1068 /*===========================================================================*
1069 * do_new_kmess *
1070 *===========================================================================*/
1071 PUBLIC void do_new_kmess(m)
1072 message *m;
1074 /* Notification for a new kernel message. */
1075 static struct kmessages kmess; /* kmessages structure */
1076 static int prev_next = 0; /* previous next seen */
1077 int bytes;
1078 int r;
1080 /* Try to get a fresh copy of the buffer with kernel messages. */
1081 #if DEAD_CODE
1082 /* During shutdown, the reply is garbled because new notifications arrive
1083 * while the system task makes a copy of the kernel messages buffer.
1084 * Hence, don't check the return value.
1086 if ((r=sys_getkmessages(&kmess)) != OK) {
1087 printf("TTY: couldn't get copy of kmessages: %d, 0x%x\n", r,r);
1088 return;
1090 #endif
1091 sys_getkmessages(&kmess);
1093 /* Print only the new part. Determine how many new bytes there are with
1094 * help of the current and previous 'next' index. Note that the kernel
1095 * buffer is circular. This works fine if less then _KMESS_BUF_SIZE bytes
1096 * is new data; else we miss % _KMESS_BUF_SIZE here.
1097 * Check for size being positive, the buffer might as well be emptied!
1099 if (kmess.km_size > 0) {
1100 bytes = ((kmess.km_next + _KMESS_BUF_SIZE) - prev_next) % _KMESS_BUF_SIZE;
1101 r=prev_next; /* start at previous old */
1102 while (bytes > 0) {
1103 cons_putk( kmess.km_buf[(r%_KMESS_BUF_SIZE)] );
1104 bytes --;
1105 r ++;
1107 cons_putk(0); /* terminate to flush output */
1110 /* Almost done, store 'next' so that we can determine what part of the
1111 * kernel messages buffer to print next time a notification arrives.
1113 prev_next = kmess.km_next;
1116 /*===========================================================================*
1117 * do_diagnostics *
1118 *===========================================================================*/
1119 PUBLIC void do_diagnostics(m_ptr, safe)
1120 message *m_ptr; /* pointer to request message */
1121 int safe;
1123 /* Print a string for a server. */
1124 char c;
1125 vir_bytes src;
1126 int count, offset = 0;
1127 int result = OK;
1128 int proc_nr = m_ptr->m_source;
1130 src = (vir_bytes) m_ptr->DIAG_PRINT_BUF_G;
1131 for (count = m_ptr->DIAG_BUF_COUNT; count > 0; count--) {
1132 int r;
1133 if(safe) {
1134 r = sys_safecopyfrom(proc_nr, src, offset, (vir_bytes) &c, 1, D);
1135 if(r != OK)
1136 printf("<tty: proc %d, grant %ld>", proc_nr, src);
1137 } else {
1138 r = sys_vircopy(proc_nr, D, src+offset, SELF, D, (vir_bytes) &c, 1);
1140 offset++;
1141 if(r != OK) {
1142 result = EFAULT;
1143 break;
1145 cons_putk(c);
1147 cons_putk(0); /* always terminate, even with EFAULT */
1149 if(m_ptr->m_type != ASYN_DIAGNOSTICS_OLD) {
1150 m_ptr->m_type = DIAG_REPL_OLD;
1151 m_ptr->REP_STATUS = result;
1152 send(m_ptr->m_source, m_ptr);
1156 /*===========================================================================*
1157 * do_get_kmess *
1158 *===========================================================================*/
1159 PUBLIC void do_get_kmess(m_ptr)
1160 message *m_ptr; /* pointer to request message */
1162 /* Provide the log device with debug output */
1163 vir_bytes dst;
1164 int r;
1166 dst = (vir_bytes) m_ptr->GETKM_PTR;
1167 r= OK;
1168 if (sys_vircopy(SELF, D, (vir_bytes)&kmess, m_ptr->m_source, D,
1169 dst, sizeof(kmess)) != OK) {
1170 r = EFAULT;
1172 m_ptr->m_type = r;
1173 send(m_ptr->m_source, m_ptr);
1176 /*===========================================================================*
1177 * do_get_kmess_s *
1178 *===========================================================================*/
1179 PUBLIC void do_get_kmess_s(m_ptr)
1180 message *m_ptr; /* pointer to request message */
1182 /* Provide the log device with debug output */
1183 cp_grant_id_t gid;
1184 int r;
1186 gid = m_ptr->GETKM_GRANT;
1187 r= OK;
1188 if (sys_safecopyto(m_ptr->m_source, gid, 0, (vir_bytes)&kmess, sizeof(kmess),
1189 D) != OK) {
1190 r = EFAULT;
1192 m_ptr->m_type = r;
1193 send(m_ptr->m_source, m_ptr);
1196 /*===========================================================================*
1197 * cons_putk *
1198 *===========================================================================*/
1199 PRIVATE void cons_putk(c)
1200 int c; /* character to print */
1202 /* This procedure is used to print a character on the console.
1204 if (c != 0) {
1205 if (c == '\n') cons_putk('\r');
1206 out_char(&cons_table[0], (int) c);
1207 #if 0
1208 ser_putc(c);
1209 #endif
1210 } else {
1211 flush(&cons_table[0]);
1215 /*===========================================================================*
1216 * toggle_scroll *
1217 *===========================================================================*/
1218 PUBLIC void toggle_scroll()
1220 /* Toggle between hardware and software scroll. */
1222 cons_org0();
1223 softscroll = !softscroll;
1224 printf("%sware scrolling enabled.\n", softscroll ? "Soft" : "Hard");
1227 /*===========================================================================*
1228 * cons_stop *
1229 *===========================================================================*/
1230 PUBLIC void cons_stop()
1232 /* Prepare for halt or reboot. */
1233 cons_org0();
1234 softscroll = 1;
1235 select_console(0);
1236 cons_table[0].c_attr = cons_table[0].c_blank = BLANK_COLOR;
1237 shutting_down = TRUE;
1240 /*===========================================================================*
1241 * cons_org0 *
1242 *===========================================================================*/
1243 PRIVATE void cons_org0()
1245 /* Scroll video memory back to put the origin at 0. */
1246 int cons_line;
1247 console_t *cons;
1248 unsigned n;
1250 for (cons_line = 0; cons_line < nr_cons; cons_line++) {
1251 cons = &cons_table[cons_line];
1252 while (cons->c_org > cons->c_start) {
1253 n = vid_size - scr_size; /* amount of unused memory */
1254 if (n > cons->c_org - cons->c_start)
1255 n = cons->c_org - cons->c_start;
1256 vid_vid_copy(cons->c_org, cons->c_org - n, scr_size);
1257 UPDATE_ORIGIN(cons, cons->c_org - n);
1259 flush(cons);
1261 select_console(ccurrent);
1264 /*===========================================================================*
1265 * disable_console *
1266 *===========================================================================*/
1267 PRIVATE void disable_console()
1269 if (disabled_vc != -1)
1270 return;
1272 disabled_vc = ccurrent;
1273 disabled_sm = softscroll;
1275 cons_org0();
1276 softscroll = 1;
1277 select_console(0);
1279 /* Should also disable further output to virtual consoles */
1282 /*===========================================================================*
1283 * reenable_console *
1284 *===========================================================================*/
1285 PRIVATE void reenable_console()
1287 if (disabled_vc == -1)
1288 return;
1290 softscroll = disabled_sm;
1291 select_console(disabled_vc);
1292 disabled_vc = -1;
1295 /*===========================================================================*
1296 * select_console *
1297 *===========================================================================*/
1298 PUBLIC void select_console(int cons_line)
1300 /* Set the current console to console number 'cons_line'. */
1302 if (shutting_down) return;
1304 if (cons_line < 0 || cons_line >= nr_cons) return;
1306 ccurrent = cons_line;
1307 curcons = &cons_table[cons_line];
1309 UPDATE_CURSOR(curcons, curcons->c_cur);
1310 UPDATE_ORIGIN(curcons, curcons->c_org);
1313 /*===========================================================================*
1314 * con_loadfont *
1315 *===========================================================================*/
1316 PUBLIC int con_loadfont(m)
1317 message *m;
1320 /* Load a font into the EGA or VGA adapter. */
1321 int result;
1322 static struct sequence seq1[7] = {
1323 { GA_SEQUENCER_INDEX, 0x00, 0x01 },
1324 { GA_SEQUENCER_INDEX, 0x02, 0x04 },
1325 { GA_SEQUENCER_INDEX, 0x04, 0x07 },
1326 { GA_SEQUENCER_INDEX, 0x00, 0x03 },
1327 { GA_GRAPHICS_INDEX, 0x04, 0x02 },
1328 { GA_GRAPHICS_INDEX, 0x05, 0x00 },
1329 { GA_GRAPHICS_INDEX, 0x06, 0x00 },
1331 static struct sequence seq2[7] = {
1332 { GA_SEQUENCER_INDEX, 0x00, 0x01 },
1333 { GA_SEQUENCER_INDEX, 0x02, 0x03 },
1334 { GA_SEQUENCER_INDEX, 0x04, 0x03 },
1335 { GA_SEQUENCER_INDEX, 0x00, 0x03 },
1336 { GA_GRAPHICS_INDEX, 0x04, 0x00 },
1337 { GA_GRAPHICS_INDEX, 0x05, 0x10 },
1338 { GA_GRAPHICS_INDEX, 0x06, 0 },
1341 seq2[6].value= color ? 0x0E : 0x0A;
1343 if (!machine.vdu_ega) return(ENOTTY);
1344 result = ga_program(seq1); /* bring font memory into view */
1346 if(sys_safecopyfrom(m->IO_ENDPT, (cp_grant_id_t) m->ADDRESS, 0,
1347 (vir_bytes) font_memory, GA_FONT_SIZE, D) != OK) {
1348 printf("tty: copying from %d failed\n", m->IO_ENDPT);
1349 return EFAULT;
1352 result = ga_program(seq2); /* restore */
1354 return(result);
1357 /*===========================================================================*
1358 * ga_program *
1359 *===========================================================================*/
1360 PRIVATE int ga_program(seq)
1361 struct sequence *seq;
1363 pvb_pair_t char_out[14];
1364 int i;
1365 for (i=0; i<7; i++) {
1366 pv_set(char_out[2*i], seq->index, seq->port);
1367 pv_set(char_out[2*i+1], seq->index+1, seq->value);
1368 seq++;
1370 return sys_voutb(char_out, 14);
1373 /*===========================================================================*
1374 * cons_ioctl *
1375 *===========================================================================*/
1376 PRIVATE int cons_ioctl(tp, try)
1377 tty_t *tp;
1378 int try;
1380 /* Set the screen dimensions. */
1382 tp->tty_winsize.ws_row= scr_lines;
1383 tp->tty_winsize.ws_col= scr_width;
1384 tp->tty_winsize.ws_xpixel= scr_width * 8;
1385 tp->tty_winsize.ws_ypixel= scr_lines * font_lines;
1387 return 0;
1390 #define LIMITINDEX(mask, start, size, ct) { \
1391 int countlimit = size - start; \
1392 start &= mask; \
1393 if(ct > countlimit) ct = countlimit; \
1396 /*===========================================================================*
1397 * mem_vid_copy *
1398 *===========================================================================*/
1399 PRIVATE void mem_vid_copy(vir_bytes src, int dst_index, int count)
1401 u16_t *src_mem = (u16_t *) src;
1402 while(count > 0) {
1403 int i, subcount = count;
1404 u16_t *dst_mem;
1405 LIMITINDEX(vid_mask, dst_index, vid_size, subcount);
1406 dst_mem = (u16_t *) console_memory + dst_index;
1407 if(!src)
1408 for(i = 0; i < subcount; i++)
1409 *dst_mem++ = blank_color;
1410 else
1411 for(i = 0; i < subcount; i++)
1412 *dst_mem++ = *src_mem++;
1413 count -= subcount;
1414 dst_index += subcount;
1418 /*===========================================================================*
1419 * vid_vid_copy *
1420 *===========================================================================*/
1421 PRIVATE void vid_vid_copy(int src_index, int dst_index, int count)
1423 int backwards = 0;
1424 if(src_index < dst_index)
1425 backwards = 1;
1426 while(count > 0) {
1427 int i, subcount = count;
1428 u16_t *dst_mem, *src_mem;
1429 LIMITINDEX(vid_mask, src_index, vid_size, subcount);
1430 LIMITINDEX(vid_mask, dst_index, vid_size, subcount);
1431 src_mem = (u16_t *) console_memory + src_index;
1432 dst_mem = (u16_t *) console_memory + dst_index;
1433 if(backwards) {
1434 src_mem += subcount - 1;
1435 dst_mem += subcount - 1;
1436 for(i = 0; i < subcount; i++)
1437 *dst_mem-- = *src_mem--;
1438 } else {
1439 for(i = 0; i < subcount; i++)
1440 *dst_mem++ = *src_mem++;
1442 count -= subcount;
1443 dst_index += subcount;
1444 src_index += subcount;