source: branches/minix3-book/drivers/tty/console.c

Last change on this file was 4, checked in by Mattia Monga, 14 years ago

Importazione sorgenti libro

File size: 34.5 KB
Line 
1/* Code and data for the IBM console driver.
2 *
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.
17 */
18
19#include "../drivers.h"
20#include <termios.h>
21#include <minix/callnr.h>
22#include <minix/com.h>
23#include "tty.h"
24
25#include "../../kernel/const.h"
26#include "../../kernel/config.h"
27#include "../../kernel/type.h"
28
29/* Definitions used by the console driver. */
30#define MONO_BASE 0xB0000L /* base of mono video memory */
31#define COLOR_BASE 0xB8000L /* base of color video memory */
32#define MONO_SIZE 0x1000 /* 4K mono video memory */
33#define COLOR_SIZE 0x4000 /* 16K color video memory */
34#define EGA_SIZE 0x8000 /* EGA & VGA have at least 32K */
35#define BLANK_COLOR 0x0700 /* determines cursor color on blank screen */
36#define SCROLL_UP 0 /* scroll forward */
37#define SCROLL_DOWN 1 /* scroll backward */
38#define BLANK_MEM ((u16_t *) 0) /* tells mem_vid_copy() to blank the screen */
39#define CONS_RAM_WORDS 80 /* video ram buffer size */
40#define MAX_ESC_PARMS 4 /* number of escape sequence params allowed */
41
42/* Constants relating to the controller chips. */
43#define M_6845 0x3B4 /* port for 6845 mono */
44#define C_6845 0x3D4 /* port for 6845 color */
45#define INDEX 0 /* 6845's index register */
46#define DATA 1 /* 6845's data register */
47#define STATUS 6 /* 6845's status register */
48#define VID_ORG 12 /* 6845's origin register */
49#define CURSOR 14 /* 6845's cursor register */
50
51/* Beeper. */
52#define BEEP_FREQ 0x0533 /* value to put into timer to set beep freq */
53#define B_TIME 3 /* length of CTRL-G beep is ticks */
54
55/* definitions used for font management */
56#define GA_SEQUENCER_INDEX 0x3C4
57#define GA_SEQUENCER_DATA 0x3C5
58#define GA_GRAPHICS_INDEX 0x3CE
59#define GA_GRAPHICS_DATA 0x3CF
60#define GA_VIDEO_ADDRESS 0xA0000L
61#define GA_FONT_SIZE 8192
62
63/* Global variables used by the console driver and assembly support. */
64PUBLIC int vid_index; /* index of video segment in remote mem map */
65PUBLIC u16_t vid_seg;
66PUBLIC vir_bytes vid_off; /* video ram is found at vid_seg:vid_off */
67PUBLIC unsigned vid_size; /* 0x2000 for color or 0x0800 for mono */
68PUBLIC unsigned vid_mask; /* 0x1FFF for color or 0x07FF for mono */
69PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */
70
71/* Private variables used by the console driver. */
72PRIVATE int vid_port; /* I/O port for accessing 6845 */
73PRIVATE int wrap; /* hardware can wrap? */
74PRIVATE int softscroll; /* 1 = software scrolling, 0 = hardware */
75PRIVATE int beeping; /* speaker is beeping? */
76PRIVATE unsigned font_lines; /* font lines per character */
77PRIVATE unsigned scr_width; /* # characters on a line */
78PRIVATE unsigned scr_lines; /* # lines on the screen */
79PRIVATE unsigned scr_size; /* # characters on the screen */
80
81/* Per console data. */
82typedef struct console {
83 tty_t *c_tty; /* associated TTY struct */
84 int c_column; /* current column number (0-origin) */
85 int c_row; /* current row (0 at top of screen) */
86 int c_rwords; /* number of WORDS (not bytes) in outqueue */
87 unsigned c_start; /* start of video memory of this console */
88 unsigned c_limit; /* limit of this console's video memory */
89 unsigned c_org; /* location in RAM where 6845 base points */
90 unsigned c_cur; /* current position of cursor in video RAM */
91 unsigned c_attr; /* character attribute */
92 unsigned c_blank; /* blank attribute */
93 char c_reverse; /* reverse video */
94 char c_esc_state; /* 0=normal, 1=ESC, 2=ESC[ */
95 char c_esc_intro; /* Distinguishing character following ESC */
96 int *c_esc_parmp; /* pointer to current escape parameter */
97 int c_esc_parmv[MAX_ESC_PARMS]; /* list of escape parameters */
98 u16_t c_ramqueue[CONS_RAM_WORDS]; /* buffer for video RAM */
99} console_t;
100
101PRIVATE int nr_cons= 1; /* actual number of consoles */
102PRIVATE console_t cons_table[NR_CONS];
103PRIVATE console_t *curcons; /* currently visible */
104
105/* Color if using a color controller. */
106#define color (vid_port == C_6845)
107
108/* Map from ANSI colors to the attributes used by the PC */
109PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
110
111/* Structure used for font management */
112struct sequence {
113 unsigned short index;
114 unsigned char port;
115 unsigned char value;
116};
117
118FORWARD _PROTOTYPE( int cons_write, (struct tty *tp, int try) );
119FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c) );
120FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c) );
121FORWARD _PROTOTYPE( void putk, (int c) );
122FORWARD _PROTOTYPE( void beep, (void) );
123FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c) );
124FORWARD _PROTOTYPE( void flush, (console_t *cons) );
125FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c) );
126FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir) );
127FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val) );
128FORWARD _PROTOTYPE( void get_6845, (int reg, unsigned *val) );
129FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp) );
130FORWARD _PROTOTYPE( void cons_org0, (void) );
131FORWARD _PROTOTYPE( int ga_program, (struct sequence *seq) );
132FORWARD _PROTOTYPE( int cons_ioctl, (tty_t *tp, int) );
133
134/*===========================================================================*
135 * cons_write *
136 *===========================================================================*/
137PRIVATE int cons_write(tp, try)
138register struct tty *tp; /* tells which terminal is to be used */
139int try;
140{
141/* Copy as much data as possible to the output queue, then start I/O. On
142 * memory-mapped terminals, such as the IBM console, the I/O will also be
143 * finished, and the counts updated. Keep repeating until all I/O done.
144 */
145
146 int count;
147 int result;
148 register char *tbuf;
149 char buf[64];
150 console_t *cons = tp->tty_priv;
151
152 if (try) return 1; /* we can always write to console */
153
154 /* Check quickly for nothing to do, so this can be called often without
155 * unmodular tests elsewhere.
156 */
157 if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return;
158
159 /* Copy the user bytes to buf[] for decent addressing. Loop over the
160 * copies, since the user buffer may be much larger than buf[].
161 */
162 do {
163 if (count > sizeof(buf)) count = sizeof(buf);
164 if ((result = sys_vircopy(tp->tty_outproc, D, tp->tty_out_vir,
165 SELF, D, (vir_bytes) buf, (vir_bytes) count)) != OK)
166 break;
167 tbuf = buf;
168
169 /* Update terminal data structure. */
170 tp->tty_out_vir += count;
171 tp->tty_outcum += count;
172 tp->tty_outleft -= count;
173
174 /* Output each byte of the copy to the screen. Avoid calling
175 * out_char() for the "easy" characters, put them into the buffer
176 * directly.
177 */
178 do {
179 if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
180 || cons->c_column >= scr_width
181 || cons->c_rwords >= buflen(cons->c_ramqueue))
182 {
183 out_char(cons, *tbuf++);
184 } else {
185 cons->c_ramqueue[cons->c_rwords++] =
186 cons->c_attr | (*tbuf++ & BYTE);
187 cons->c_column++;
188 }
189 } while (--count != 0);
190 } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
191
192 flush(cons); /* transfer anything buffered to the screen */
193
194 /* Reply to the writer if all output is finished or if an error occured. */
195 if (tp->tty_outleft == 0 || result != OK) {
196 /* REVIVE is not possible. I/O on memory mapped consoles finishes. */
197 tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc,
198 tp->tty_outcum);
199 tp->tty_outcum = 0;
200 }
201}
202
203/*===========================================================================*
204 * cons_echo *
205 *===========================================================================*/
206PRIVATE void cons_echo(tp, c)
207register tty_t *tp; /* pointer to tty struct */
208int c; /* character to be echoed */
209{
210/* Echo keyboard input (print & flush). */
211 console_t *cons = tp->tty_priv;
212
213 out_char(cons, c);
214 flush(cons);
215}
216
217/*===========================================================================*
218 * out_char *
219 *===========================================================================*/
220PRIVATE void out_char(cons, c)
221register console_t *cons; /* pointer to console struct */
222int c; /* character to be output */
223{
224/* Output a character on the console. Check for escape sequences first. */
225 if (cons->c_esc_state > 0) {
226 parse_escape(cons, c);
227 return;
228 }
229
230 switch(c) {
231 case 000: /* null is typically used for padding */
232 return; /* better not do anything */
233
234 case 007: /* ring the bell */
235 flush(cons); /* print any chars queued for output */
236 beep();
237 return;
238
239 case '\b': /* backspace */
240 if (--cons->c_column < 0) {
241 if (--cons->c_row >= 0) cons->c_column += scr_width;
242 }
243 flush(cons);
244 return;
245
246 case '\n': /* line feed */
247 if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
248 == (OPOST|ONLCR)) {
249 cons->c_column = 0;
250 }
251 /*FALL THROUGH*/
252 case 013: /* CTRL-K */
253 case 014: /* CTRL-L */
254 if (cons->c_row == scr_lines-1) {
255 scroll_screen(cons, SCROLL_UP);
256 } else {
257 cons->c_row++;
258 }
259 flush(cons);
260 return;
261
262 case '\r': /* carriage return */
263 cons->c_column = 0;
264 flush(cons);
265 return;
266
267 case '\t': /* tab */
268 cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
269 if (cons->c_column > scr_width) {
270 cons->c_column -= scr_width;
271 if (cons->c_row == scr_lines-1) {
272 scroll_screen(cons, SCROLL_UP);
273 } else {
274 cons->c_row++;
275 }
276 }
277 flush(cons);
278 return;
279
280 case 033: /* ESC - start of an escape sequence */
281 flush(cons); /* print any chars queued for output */
282 cons->c_esc_state = 1; /* mark ESC as seen */
283 return;
284
285 default: /* printable chars are stored in ramqueue */
286 if (cons->c_column >= scr_width) {
287 if (!LINEWRAP) return;
288 if (cons->c_row == scr_lines-1) {
289 scroll_screen(cons, SCROLL_UP);
290 } else {
291 cons->c_row++;
292 }
293 cons->c_column = 0;
294 flush(cons);
295 }
296 if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons);
297 cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE);
298 cons->c_column++; /* next column */
299 return;
300 }
301}
302
303/*===========================================================================*
304 * scroll_screen *
305 *===========================================================================*/
306PRIVATE void scroll_screen(cons, dir)
307register console_t *cons; /* pointer to console struct */
308int dir; /* SCROLL_UP or SCROLL_DOWN */
309{
310 unsigned new_line, new_org, chars;
311
312 flush(cons);
313 chars = scr_size - scr_width; /* one screen minus one line */
314
315 /* Scrolling the screen is a real nuisance due to the various incompatible
316 * video cards. This driver supports software scrolling (Hercules?),
317 * hardware scrolling (mono and CGA cards) and hardware scrolling without
318 * wrapping (EGA cards). In the latter case we must make sure that
319 * c_start <= c_org && c_org + scr_size <= c_limit
320 * holds, because EGA doesn't wrap around the end of video memory.
321 */
322 if (dir == SCROLL_UP) {
323 /* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
324 if (softscroll) {
325 vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars);
326 } else
327 if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) {
328 vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars);
329 cons->c_org = cons->c_start;
330 } else {
331 cons->c_org = (cons->c_org + scr_width) & vid_mask;
332 }
333 new_line = (cons->c_org + chars) & vid_mask;
334 } else {
335 /* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
336 if (softscroll) {
337 vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars);
338 } else
339 if (!wrap && cons->c_org < cons->c_start + scr_width) {
340 new_org = cons->c_limit - scr_size;
341 vid_vid_copy(cons->c_org, new_org + scr_width, chars);
342 cons->c_org = new_org;
343 } else {
344 cons->c_org = (cons->c_org - scr_width) & vid_mask;
345 }
346 new_line = cons->c_org;
347 }
348 /* Blank the new line at top or bottom. */
349 blank_color = cons->c_blank;
350 mem_vid_copy(BLANK_MEM, new_line, scr_width);
351
352 /* Set the new video origin. */
353 if (cons == curcons) set_6845(VID_ORG, cons->c_org);
354 flush(cons);
355}
356
357/*===========================================================================*
358 * flush *
359 *===========================================================================*/
360PRIVATE void flush(cons)
361register console_t *cons; /* pointer to console struct */
362{
363/* Send characters buffered in 'ramqueue' to screen memory, check the new
364 * cursor position, compute the new hardware cursor position and set it.
365 */
366 unsigned cur;
367 tty_t *tp = cons->c_tty;
368
369 /* Have the characters in 'ramqueue' transferred to the screen. */
370 if (cons->c_rwords > 0) {
371 mem_vid_copy(cons->c_ramqueue, cons->c_cur, cons->c_rwords);
372 cons->c_rwords = 0;
373
374 /* TTY likes to know the current column and if echoing messed up. */
375 tp->tty_position = cons->c_column;
376 tp->tty_reprint = TRUE;
377 }
378
379 /* Check and update the cursor position. */
380 if (cons->c_column < 0) cons->c_column = 0;
381 if (cons->c_column > scr_width) cons->c_column = scr_width;
382 if (cons->c_row < 0) cons->c_row = 0;
383 if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1;
384 cur = cons->c_org + cons->c_row * scr_width + cons->c_column;
385 if (cur != cons->c_cur) {
386 if (cons == curcons) set_6845(CURSOR, cur);
387 cons->c_cur = cur;
388 }
389}
390
391/*===========================================================================*
392 * parse_escape *
393 *===========================================================================*/
394PRIVATE void parse_escape(cons, c)
395register console_t *cons; /* pointer to console struct */
396char c; /* next character in escape sequence */
397{
398/* The following ANSI escape sequences are currently supported.
399 * If n and/or m are omitted, they default to 1.
400 * ESC [nA moves up n lines
401 * ESC [nB moves down n lines
402 * ESC [nC moves right n spaces
403 * ESC [nD moves left n spaces
404 * ESC [m;nH" moves cursor to (m,n)
405 * ESC [J clears screen from cursor
406 * ESC [K clears line from cursor
407 * ESC [nL inserts n lines ar cursor
408 * ESC [nM deletes n lines at cursor
409 * ESC [nP deletes n chars at cursor
410 * ESC [n@ inserts n chars at cursor
411 * ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
412 * ESC M scrolls the screen backwards if the cursor is on the top line
413 */
414
415 switch (cons->c_esc_state) {
416 case 1: /* ESC seen */
417 cons->c_esc_intro = '\0';
418 cons->c_esc_parmp = bufend(cons->c_esc_parmv);
419 do {
420 *--cons->c_esc_parmp = 0;
421 } while (cons->c_esc_parmp > cons->c_esc_parmv);
422 switch (c) {
423 case '[': /* Control Sequence Introducer */
424 cons->c_esc_intro = c;
425 cons->c_esc_state = 2;
426 break;
427 case 'M': /* Reverse Index */
428 do_escape(cons, c);
429 break;
430 default:
431 cons->c_esc_state = 0;
432 }
433 break;
434
435 case 2: /* ESC [ seen */
436 if (c >= '0' && c <= '9') {
437 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
438 *cons->c_esc_parmp = *cons->c_esc_parmp * 10 + (c-'0');
439 } else
440 if (c == ';') {
441 if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
442 cons->c_esc_parmp++;
443 } else {
444 do_escape(cons, c);
445 }
446 break;
447 }
448}
449
450/*===========================================================================*
451 * do_escape *
452 *===========================================================================*/
453PRIVATE void do_escape(cons, c)
454register console_t *cons; /* pointer to console struct */
455char c; /* next character in escape sequence */
456{
457 int value, n;
458 unsigned src, dst, count;
459 int *parmp;
460
461 /* Some of these things hack on screen RAM, so it had better be up to date */
462 flush(cons);
463
464 if (cons->c_esc_intro == '\0') {
465 /* Handle a sequence beginning with just ESC */
466 switch (c) {
467 case 'M': /* Reverse Index */
468 if (cons->c_row == 0) {
469 scroll_screen(cons, SCROLL_DOWN);
470 } else {
471 cons->c_row--;
472 }
473 flush(cons);
474 break;
475
476 default: break;
477 }
478 } else
479 if (cons->c_esc_intro == '[') {
480 /* Handle a sequence beginning with ESC [ and parameters */
481 value = cons->c_esc_parmv[0];
482 switch (c) {
483 case 'A': /* ESC [nA moves up n lines */
484 n = (value == 0 ? 1 : value);
485 cons->c_row -= n;
486 flush(cons);
487 break;
488
489 case 'B': /* ESC [nB moves down n lines */
490 n = (value == 0 ? 1 : value);
491 cons->c_row += n;
492 flush(cons);
493 break;
494
495 case 'C': /* ESC [nC moves right n spaces */
496 n = (value == 0 ? 1 : value);
497 cons->c_column += n;
498 flush(cons);
499 break;
500
501 case 'D': /* ESC [nD moves left n spaces */
502 n = (value == 0 ? 1 : value);
503 cons->c_column -= n;
504 flush(cons);
505 break;
506
507 case 'H': /* ESC [m;nH" moves cursor to (m,n) */
508 cons->c_row = cons->c_esc_parmv[0] - 1;
509 cons->c_column = cons->c_esc_parmv[1] - 1;
510 flush(cons);
511 break;
512
513 case 'J': /* ESC [sJ clears in display */
514 switch (value) {
515 case 0: /* Clear from cursor to end of screen */
516 count = scr_size - (cons->c_cur - cons->c_org);
517 dst = cons->c_cur;
518 break;
519 case 1: /* Clear from start of screen to cursor */
520 count = cons->c_cur - cons->c_org;
521 dst = cons->c_org;
522 break;
523 case 2: /* Clear entire screen */
524 count = scr_size;
525 dst = cons->c_org;
526 break;
527 default: /* Do nothing */
528 count = 0;
529 dst = cons->c_org;
530 }
531 blank_color = cons->c_blank;
532 mem_vid_copy(BLANK_MEM, dst, count);
533 break;
534
535 case 'K': /* ESC [sK clears line from cursor */
536 switch (value) {
537 case 0: /* Clear from cursor to end of line */
538 count = scr_width - cons->c_column;
539 dst = cons->c_cur;
540 break;
541 case 1: /* Clear from beginning of line to cursor */
542 count = cons->c_column;
543 dst = cons->c_cur - cons->c_column;
544 break;
545 case 2: /* Clear entire line */
546 count = scr_width;
547 dst = cons->c_cur - cons->c_column;
548 break;
549 default: /* Do nothing */
550 count = 0;
551 dst = cons->c_cur;
552 }
553 blank_color = cons->c_blank;
554 mem_vid_copy(BLANK_MEM, dst, count);
555 break;
556
557 case 'L': /* ESC [nL inserts n lines at cursor */
558 n = value;
559 if (n < 1) n = 1;
560 if (n > (scr_lines - cons->c_row))
561 n = scr_lines - cons->c_row;
562
563 src = cons->c_org + cons->c_row * scr_width;
564 dst = src + n * scr_width;
565 count = (scr_lines - cons->c_row - n) * scr_width;
566 vid_vid_copy(src, dst, count);
567 blank_color = cons->c_blank;
568 mem_vid_copy(BLANK_MEM, src, n * scr_width);
569 break;
570
571 case 'M': /* ESC [nM deletes n lines at cursor */
572 n = value;
573 if (n < 1) n = 1;
574 if (n > (scr_lines - cons->c_row))
575 n = scr_lines - cons->c_row;
576
577 dst = cons->c_org + cons->c_row * scr_width;
578 src = dst + n * scr_width;
579 count = (scr_lines - cons->c_row - n) * scr_width;
580 vid_vid_copy(src, dst, count);
581 blank_color = cons->c_blank;
582 mem_vid_copy(BLANK_MEM, dst + count, n * scr_width);
583 break;
584
585 case '@': /* ESC [n@ inserts n chars at cursor */
586 n = value;
587 if (n < 1) n = 1;
588 if (n > (scr_width - cons->c_column))
589 n = scr_width - cons->c_column;
590
591 src = cons->c_cur;
592 dst = src + n;
593 count = scr_width - cons->c_column - n;
594 vid_vid_copy(src, dst, count);
595 blank_color = cons->c_blank;
596 mem_vid_copy(BLANK_MEM, src, n);
597 break;
598
599 case 'P': /* ESC [nP deletes n chars at cursor */
600 n = value;
601 if (n < 1) n = 1;
602 if (n > (scr_width - cons->c_column))
603 n = scr_width - cons->c_column;
604
605 dst = cons->c_cur;
606 src = dst + n;
607 count = scr_width - cons->c_column - n;
608 vid_vid_copy(src, dst, count);
609 blank_color = cons->c_blank;
610 mem_vid_copy(BLANK_MEM, dst + count, n);
611 break;
612
613 case 'm': /* ESC [nm enables rendition n */
614 for (parmp = cons->c_esc_parmv; parmp <= cons->c_esc_parmp
615 && parmp < bufend(cons->c_esc_parmv); parmp++) {
616 if (cons->c_reverse) {
617 /* Unswap fg and bg colors */
618 cons->c_attr = ((cons->c_attr & 0x7000) >> 4) |
619 ((cons->c_attr & 0x0700) << 4) |
620 ((cons->c_attr & 0x8800));
621 }
622 switch (n = *parmp) {
623 case 0: /* NORMAL */
624 cons->c_attr = cons->c_blank = BLANK_COLOR;
625 cons->c_reverse = FALSE;
626 break;
627
628 case 1: /* BOLD */
629 /* Set intensity bit */
630 cons->c_attr |= 0x0800;
631 break;
632
633 case 4: /* UNDERLINE */
634 if (color) {
635 /* Change white to cyan, i.e. lose red
636 */
637 cons->c_attr = (cons->c_attr & 0xBBFF);
638 } else {
639 /* Set underline attribute */
640 cons->c_attr = (cons->c_attr & 0x99FF);
641 }
642 break;
643
644 case 5: /* BLINKING */
645 /* Set the blink bit */
646 cons->c_attr |= 0x8000;
647 break;
648
649 case 7: /* REVERSE */
650 cons->c_reverse = TRUE;
651 break;
652
653 default: /* COLOR */
654 if (n == 39) n = 37; /* set default color */
655 if (n == 49) n = 40;
656
657 if (!color) {
658 /* Don't mess up a monochrome screen */
659 } else
660 if (30 <= n && n <= 37) {
661 /* Foreground color */
662 cons->c_attr =
663 (cons->c_attr & 0xF8FF) |
664 (ansi_colors[(n - 30)] << 8);
665 cons->c_blank =
666 (cons->c_blank & 0xF8FF) |
667 (ansi_colors[(n - 30)] << 8);
668 } else
669 if (40 <= n && n <= 47) {
670 /* Background color */
671 cons->c_attr =
672 (cons->c_attr & 0x8FFF) |
673 (ansi_colors[(n - 40)] << 12);
674 cons->c_blank =
675 (cons->c_blank & 0x8FFF) |
676 (ansi_colors[(n - 40)] << 12);
677 }
678 }
679 if (cons->c_reverse) {
680 /* Swap fg and bg colors */
681 cons->c_attr = ((cons->c_attr & 0x7000) >> 4) |
682 ((cons->c_attr & 0x0700) << 4) |
683 ((cons->c_attr & 0x8800));
684 }
685 }
686 break;
687 }
688 }
689 cons->c_esc_state = 0;
690}
691
692/*===========================================================================*
693 * set_6845 *
694 *===========================================================================*/
695PRIVATE void set_6845(reg, val)
696int reg; /* which register pair to set */
697unsigned val; /* 16-bit value to set it to */
698{
699/* Set a register pair inside the 6845.
700 * Registers 12-13 tell the 6845 where in video ram to start
701 * Registers 14-15 tell the 6845 where to put the cursor
702 */
703 pvb_pair_t char_out[4];
704 pv_set(char_out[0], vid_port + INDEX, reg); /* set index register */
705 pv_set(char_out[1], vid_port + DATA, (val>>8) & BYTE); /* high byte */
706 pv_set(char_out[2], vid_port + INDEX, reg + 1); /* again */
707 pv_set(char_out[3], vid_port + DATA, val&BYTE); /* low byte */
708 sys_voutb(char_out, 4); /* do actual output */
709}
710
711/*===========================================================================*
712 * get_6845 *
713 *===========================================================================*/
714PRIVATE void get_6845(reg, val)
715int reg; /* which register pair to set */
716unsigned *val; /* 16-bit value to set it to */
717{
718 char v1, v2;
719/* Get a register pair inside the 6845. */
720 sys_outb(vid_port + INDEX, reg);
721 sys_inb(vid_port + DATA, &v1);
722 sys_outb(vid_port + INDEX, reg+1);
723 sys_inb(vid_port + DATA, &v2);
724 *val = (v1 << 8) | v2;
725}
726
727/*===========================================================================*
728 * beep *
729 *===========================================================================*/
730PRIVATE void beep()
731{
732/* Making a beeping sound on the speaker (output for CRTL-G).
733 * This routine works by turning on the bits 0 and 1 in port B of the 8255
734 * chip that drive the speaker.
735 */
736 static timer_t tmr_stop_beep;
737 pvb_pair_t char_out[3];
738 clock_t now;
739 int port_b_val, s;
740
741 /* Fetch current time in advance to prevent beeping delay. */
742 if ((s=getuptime(&now)) != OK)
743 panic("TTY","Console couldn't get clock's uptime.", s);
744 if (!beeping) {
745 /* Set timer channel 2, square wave, with given frequency. */
746 pv_set(char_out[0], TIMER_MODE, 0xB6);
747 pv_set(char_out[1], TIMER2, (BEEP_FREQ >> 0) & BYTE);
748 pv_set(char_out[2], TIMER2, (BEEP_FREQ >> 8) & BYTE);
749 if (sys_voutb(char_out, 3)==OK) {
750 if (sys_inb(PORT_B, &port_b_val)==OK &&
751 sys_outb(PORT_B, (port_b_val|3))==OK)
752 beeping = TRUE;
753 }
754 }
755 /* Add a timer to the timers list. Possibly reschedule the alarm. */
756 tmrs_settimer(&tty_timers, &tmr_stop_beep, now+B_TIME, stop_beep, NULL);
757 if (tty_timers->tmr_exp_time != tty_next_timeout) {
758 tty_next_timeout = tty_timers->tmr_exp_time;
759 if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
760 panic("TTY","Console couldn't set alarm.", s);
761 }
762}
763
764/*===========================================================================*
765 * stop_beep *
766 *===========================================================================*/
767PRIVATE void stop_beep(tmrp)
768timer_t *tmrp;
769{
770/* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
771 int port_b_val;
772 if (sys_inb(PORT_B, &port_b_val)==OK &&
773 sys_outb(PORT_B, (port_b_val & ~3))==OK)
774 beeping = FALSE;
775}
776
777/*===========================================================================*
778 * scr_init *
779 *===========================================================================*/
780PUBLIC void scr_init(tp)
781tty_t *tp;
782{
783/* Initialize the screen driver. */
784 console_t *cons;
785 phys_bytes vid_base;
786 u16_t bios_columns, bios_crtbase, bios_fontlines;
787 u8_t bios_rows;
788 int line;
789 int s;
790 static int vdu_initialized = 0;
791 unsigned page_size;
792
793 /* Associate console and TTY. */
794 line = tp - &tty_table[0];
795 if (line >= nr_cons) return;
796 cons = &cons_table[line];
797 cons->c_tty = tp;
798 tp->tty_priv = cons;
799
800 /* Initialize the keyboard driver. */
801 kb_init(tp);
802
803 /* Fill in TTY function hooks. */
804 tp->tty_devwrite = cons_write;
805 tp->tty_echo = cons_echo;
806 tp->tty_ioctl = cons_ioctl;
807
808 /* Get the BIOS parameters that describe the VDU. */
809 if (! vdu_initialized++) {
810
811 /* How about error checking? What to do on failure??? */
812 s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_SCREEN_COLS_ADDR,
813 SELF, D, (vir_bytes) &bios_columns, VDU_SCREEN_COLS_SIZE);
814 s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_CRT_BASE_ADDR,
815 SELF, D, (vir_bytes) &bios_crtbase, VDU_CRT_BASE_SIZE);
816 s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_SCREEN_ROWS_ADDR,
817 SELF, D, (vir_bytes) &bios_rows, VDU_SCREEN_ROWS_SIZE);
818 s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_FONTLINES_ADDR,
819 SELF, D, (vir_bytes) &bios_fontlines, VDU_FONTLINES_SIZE);
820
821 vid_port = bios_crtbase;
822 scr_width = bios_columns;
823 font_lines = bios_fontlines;
824 scr_lines = machine.vdu_ega ? bios_rows+1 : 25;
825
826 if (color) {
827 vid_base = COLOR_BASE;
828 vid_size = COLOR_SIZE;
829 } else {
830 vid_base = MONO_BASE;
831 vid_size = MONO_SIZE;
832 }
833 if (machine.vdu_ega) vid_size = EGA_SIZE;
834 wrap = ! machine.vdu_ega;
835
836 s = sys_segctl(&vid_index, &vid_seg, &vid_off, vid_base, vid_size);
837
838 vid_size >>= 1; /* word count */
839 vid_mask = vid_size - 1;
840
841 /* Size of the screen (number of displayed characters.) */
842 scr_size = scr_lines * scr_width;
843
844 /* There can be as many consoles as video memory allows. */
845 nr_cons = vid_size / scr_size;
846 if (nr_cons > NR_CONS) nr_cons = NR_CONS;
847 if (nr_cons > 1) wrap = 0;
848 page_size = vid_size / nr_cons;
849 }
850
851 cons->c_start = line * page_size;
852 cons->c_limit = cons->c_start + page_size;
853 cons->c_cur = cons->c_org = cons->c_start;
854 cons->c_attr = cons->c_blank = BLANK_COLOR;
855
856 if (line != 0) {
857 /* Clear the non-console vtys. */
858 blank_color = BLANK_COLOR;
859 mem_vid_copy(BLANK_MEM, cons->c_start, scr_size);
860 } else {
861 int i, n;
862 /* Set the cursor of the console vty at the bottom. c_cur
863 * is updated automatically later.
864 */
865 scroll_screen(cons, SCROLL_UP);
866 cons->c_row = scr_lines - 1;
867 cons->c_column = 0;
868 }
869 select_console(0);
870 cons_ioctl(tp, 0);
871}
872
873/*===========================================================================*
874 * kputc *
875 *===========================================================================*/
876PUBLIC void kputc(c)
877int c;
878{
879 putk(c);
880}
881
882/*===========================================================================*
883 * do_new_kmess *
884 *===========================================================================*/
885PUBLIC void do_new_kmess(m)
886message *m;
887{
888/* Notification for a new kernel message. */
889 struct kmessages kmess; /* kmessages structure */
890 static int prev_next = 0; /* previous next seen */
891 int size, next;
892 int bytes;
893 int r;
894
895 /* Try to get a fresh copy of the buffer with kernel messages. */
896 sys_getkmessages(&kmess);
897
898 /* Print only the new part. Determine how many new bytes there are with
899 * help of the current and previous 'next' index. Note that the kernel
900 * buffer is circular. This works fine if less then KMESS_BUF_SIZE bytes
901 * is new data; else we miss % KMESS_BUF_SIZE here.
902 * Check for size being positive, the buffer might as well be emptied!
903 */
904 if (kmess.km_size > 0) {
905 bytes = ((kmess.km_next + KMESS_BUF_SIZE) - prev_next) % KMESS_BUF_SIZE;
906 r=prev_next; /* start at previous old */
907 while (bytes > 0) {
908 putk( kmess.km_buf[(r%KMESS_BUF_SIZE)] );
909 bytes --;
910 r ++;
911 }
912 putk(0); /* terminate to flush output */
913 }
914
915 /* Almost done, store 'next' so that we can determine what part of the
916 * kernel messages buffer to print next time a notification arrives.
917 */
918 prev_next = kmess.km_next;
919}
920
921/*===========================================================================*
922 * do_diagnostics *
923 *===========================================================================*/
924PUBLIC void do_diagnostics(m_ptr)
925message *m_ptr; /* pointer to request message */
926{
927/* Print a string for a server. */
928 char c;
929 vir_bytes src;
930 int count;
931 int result = OK;
932 int proc_nr = m_ptr->DIAG_PROC_NR;
933 if (proc_nr == SELF) proc_nr = m_ptr->m_source;
934
935 src = (vir_bytes) m_ptr->DIAG_PRINT_BUF;
936 for (count = m_ptr->DIAG_BUF_COUNT; count > 0; count--) {
937 if (sys_vircopy(proc_nr, D, src++, SELF, D, (vir_bytes) &c, 1) != OK) {
938 result = EFAULT;
939 break;
940 }
941 putk(c);
942 }
943 putk(0); /* always terminate, even with EFAULT */
944 m_ptr->m_type = result;
945 send(m_ptr->m_source, m_ptr);
946}
947
948/*===========================================================================*
949 * putk *
950 *===========================================================================*/
951PRIVATE void putk(c)
952int c; /* character to print */
953{
954/* This procedure is used by the version of printf() that is linked with
955 * the TTY driver. The one in the library sends a message to FS, which is
956 * not what is needed for printing within the TTY. This version just queues
957 * the character and starts the output.
958 */
959 if (c != 0) {
960 if (c == '\n') putk('\r');
961 out_char(&cons_table[0], (int) c);
962 } else {
963 flush(&cons_table[0]);
964 }
965}
966
967/*===========================================================================*
968 * toggle_scroll *
969 *===========================================================================*/
970PUBLIC void toggle_scroll()
971{
972/* Toggle between hardware and software scroll. */
973
974 cons_org0();
975 softscroll = !softscroll;
976 printf("%sware scrolling enabled.\n", softscroll ? "Soft" : "Hard");
977}
978
979/*===========================================================================*
980 * cons_stop *
981 *===========================================================================*/
982PUBLIC void cons_stop()
983{
984/* Prepare for halt or reboot. */
985 cons_org0();
986 softscroll = 1;
987 select_console(0);
988 cons_table[0].c_attr = cons_table[0].c_blank = BLANK_COLOR;
989}
990
991/*===========================================================================*
992 * cons_org0 *
993 *===========================================================================*/
994PRIVATE void cons_org0()
995{
996/* Scroll video memory back to put the origin at 0. */
997 int cons_line;
998 console_t *cons;
999 unsigned n;
1000
1001 for (cons_line = 0; cons_line < nr_cons; cons_line++) {
1002 cons = &cons_table[cons_line];
1003 while (cons->c_org > cons->c_start) {
1004 n = vid_size - scr_size; /* amount of unused memory */
1005 if (n > cons->c_org - cons->c_start)
1006 n = cons->c_org - cons->c_start;
1007 vid_vid_copy(cons->c_org, cons->c_org - n, scr_size);
1008 cons->c_org -= n;
1009 }
1010 flush(cons);
1011 }
1012 select_console(ccurrent);
1013}
1014
1015/*===========================================================================*
1016 * select_console *
1017 *===========================================================================*/
1018PUBLIC void select_console(int cons_line)
1019{
1020/* Set the current console to console number 'cons_line'. */
1021
1022 if (cons_line < 0 || cons_line >= nr_cons) return;
1023 ccurrent = cons_line;
1024 curcons = &cons_table[cons_line];
1025 set_6845(VID_ORG, curcons->c_org);
1026 set_6845(CURSOR, curcons->c_cur);
1027}
1028
1029/*===========================================================================*
1030 * con_loadfont *
1031 *===========================================================================*/
1032PUBLIC int con_loadfont(m)
1033message *m;
1034{
1035/* Load a font into the EGA or VGA adapter. */
1036 int result;
1037 static struct sequence seq1[7] = {
1038 { GA_SEQUENCER_INDEX, 0x00, 0x01 },
1039 { GA_SEQUENCER_INDEX, 0x02, 0x04 },
1040 { GA_SEQUENCER_INDEX, 0x04, 0x07 },
1041 { GA_SEQUENCER_INDEX, 0x00, 0x03 },
1042 { GA_GRAPHICS_INDEX, 0x04, 0x02 },
1043 { GA_GRAPHICS_INDEX, 0x05, 0x00 },
1044 { GA_GRAPHICS_INDEX, 0x06, 0x00 },
1045 };
1046 static struct sequence seq2[7] = {
1047 { GA_SEQUENCER_INDEX, 0x00, 0x01 },
1048 { GA_SEQUENCER_INDEX, 0x02, 0x03 },
1049 { GA_SEQUENCER_INDEX, 0x04, 0x03 },
1050 { GA_SEQUENCER_INDEX, 0x00, 0x03 },
1051 { GA_GRAPHICS_INDEX, 0x04, 0x00 },
1052 { GA_GRAPHICS_INDEX, 0x05, 0x10 },
1053 { GA_GRAPHICS_INDEX, 0x06, 0 },
1054 };
1055
1056 seq2[6].value= color ? 0x0E : 0x0A;
1057
1058 if (!machine.vdu_ega) return(ENOTTY);
1059 result = ga_program(seq1); /* bring font memory into view */
1060
1061 result = sys_physcopy(m->PROC_NR, D, (vir_bytes) m->ADDRESS,
1062 NONE, PHYS_SEG, (phys_bytes) GA_VIDEO_ADDRESS, (phys_bytes)GA_FONT_SIZE);
1063
1064 result = ga_program(seq2); /* restore */
1065
1066 return(result);
1067}
1068
1069/*===========================================================================*
1070 * ga_program *
1071 *===========================================================================*/
1072PRIVATE int ga_program(seq)
1073struct sequence *seq;
1074{
1075 pvb_pair_t char_out[14];
1076 int i;
1077 for (i=0; i<7; i++) {
1078 pv_set(char_out[2*i], seq->index, seq->port);
1079 pv_set(char_out[2*i+1], seq->index+1, seq->value);
1080 seq++;
1081 }
1082 return sys_voutb(char_out, 14);
1083}
1084
1085/*===========================================================================*
1086 * cons_ioctl *
1087 *===========================================================================*/
1088PRIVATE int cons_ioctl(tp, try)
1089tty_t *tp;
1090int try;
1091{
1092/* Set the screen dimensions. */
1093
1094 tp->tty_winsize.ws_row= scr_lines;
1095 tp->tty_winsize.ws_col= scr_width;
1096 tp->tty_winsize.ws_xpixel= scr_width * 8;
1097 tp->tty_winsize.ws_ypixel= scr_lines * font_lines;
1098}
Note: See TracBrowser for help on using the repository browser.