source: trunk/minix/drivers/tty/console.c@ 10

Last change on this file since 10 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

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