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. */
|
---|
64 | PUBLIC int vid_index; /* index of video segment in remote mem map */
|
---|
65 | PUBLIC u16_t vid_seg;
|
---|
66 | PUBLIC vir_bytes vid_off; /* video ram is found at vid_seg:vid_off */
|
---|
67 | PUBLIC unsigned vid_size; /* 0x2000 for color or 0x0800 for mono */
|
---|
68 | PUBLIC unsigned vid_mask; /* 0x1FFF for color or 0x07FF for mono */
|
---|
69 | PUBLIC unsigned blank_color = BLANK_COLOR; /* display code for blank */
|
---|
70 |
|
---|
71 | /* Private variables used by the console driver. */
|
---|
72 | PRIVATE int vid_port; /* I/O port for accessing 6845 */
|
---|
73 | PRIVATE int wrap; /* hardware can wrap? */
|
---|
74 | PRIVATE int softscroll; /* 1 = software scrolling, 0 = hardware */
|
---|
75 | PRIVATE int beeping; /* speaker is beeping? */
|
---|
76 | PRIVATE unsigned font_lines; /* font lines per character */
|
---|
77 | PRIVATE unsigned scr_width; /* # characters on a line */
|
---|
78 | PRIVATE unsigned scr_lines; /* # lines on the screen */
|
---|
79 | PRIVATE unsigned scr_size; /* # characters on the screen */
|
---|
80 |
|
---|
81 | /* Per console data. */
|
---|
82 | typedef 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 |
|
---|
101 | PRIVATE int nr_cons= 1; /* actual number of consoles */
|
---|
102 | PRIVATE console_t cons_table[NR_CONS];
|
---|
103 | PRIVATE 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 */
|
---|
109 | PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
|
---|
110 |
|
---|
111 | /* Structure used for font management */
|
---|
112 | struct sequence {
|
---|
113 | unsigned short index;
|
---|
114 | unsigned char port;
|
---|
115 | unsigned char value;
|
---|
116 | };
|
---|
117 |
|
---|
118 | FORWARD _PROTOTYPE( int cons_write, (struct tty *tp, int try) );
|
---|
119 | FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c) );
|
---|
120 | FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c) );
|
---|
121 | FORWARD _PROTOTYPE( void putk, (int c) );
|
---|
122 | FORWARD _PROTOTYPE( void beep, (void) );
|
---|
123 | FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c) );
|
---|
124 | FORWARD _PROTOTYPE( void flush, (console_t *cons) );
|
---|
125 | FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c) );
|
---|
126 | FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir) );
|
---|
127 | FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val) );
|
---|
128 | FORWARD _PROTOTYPE( void get_6845, (int reg, unsigned *val) );
|
---|
129 | FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp) );
|
---|
130 | FORWARD _PROTOTYPE( void cons_org0, (void) );
|
---|
131 | FORWARD _PROTOTYPE( int ga_program, (struct sequence *seq) );
|
---|
132 | FORWARD _PROTOTYPE( int cons_ioctl, (tty_t *tp, int) );
|
---|
133 |
|
---|
134 | /*===========================================================================*
|
---|
135 | * cons_write *
|
---|
136 | *===========================================================================*/
|
---|
137 | PRIVATE int cons_write(tp, try)
|
---|
138 | register struct tty *tp; /* tells which terminal is to be used */
|
---|
139 | int 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 | *===========================================================================*/
|
---|
206 | PRIVATE void cons_echo(tp, c)
|
---|
207 | register tty_t *tp; /* pointer to tty struct */
|
---|
208 | int 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 | *===========================================================================*/
|
---|
220 | PRIVATE void out_char(cons, c)
|
---|
221 | register console_t *cons; /* pointer to console struct */
|
---|
222 | int 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 | *===========================================================================*/
|
---|
306 | PRIVATE void scroll_screen(cons, dir)
|
---|
307 | register console_t *cons; /* pointer to console struct */
|
---|
308 | int 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 | *===========================================================================*/
|
---|
360 | PRIVATE void flush(cons)
|
---|
361 | register 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 | *===========================================================================*/
|
---|
394 | PRIVATE void parse_escape(cons, c)
|
---|
395 | register console_t *cons; /* pointer to console struct */
|
---|
396 | char 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 | *===========================================================================*/
|
---|
453 | PRIVATE void do_escape(cons, c)
|
---|
454 | register console_t *cons; /* pointer to console struct */
|
---|
455 | char 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 | *===========================================================================*/
|
---|
695 | PRIVATE void set_6845(reg, val)
|
---|
696 | int reg; /* which register pair to set */
|
---|
697 | unsigned 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 | *===========================================================================*/
|
---|
714 | PRIVATE void get_6845(reg, val)
|
---|
715 | int reg; /* which register pair to set */
|
---|
716 | unsigned *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 | *===========================================================================*/
|
---|
730 | PRIVATE 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 | *===========================================================================*/
|
---|
767 | PRIVATE void stop_beep(tmrp)
|
---|
768 | timer_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 | *===========================================================================*/
|
---|
780 | PUBLIC void scr_init(tp)
|
---|
781 | tty_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 | *===========================================================================*/
|
---|
876 | PUBLIC void kputc(c)
|
---|
877 | int c;
|
---|
878 | {
|
---|
879 | putk(c);
|
---|
880 | }
|
---|
881 |
|
---|
882 | /*===========================================================================*
|
---|
883 | * do_new_kmess *
|
---|
884 | *===========================================================================*/
|
---|
885 | PUBLIC void do_new_kmess(m)
|
---|
886 | message *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 | *===========================================================================*/
|
---|
924 | PUBLIC void do_diagnostics(m_ptr)
|
---|
925 | message *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 | *===========================================================================*/
|
---|
951 | PRIVATE void putk(c)
|
---|
952 | int 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 | *===========================================================================*/
|
---|
970 | PUBLIC 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 | *===========================================================================*/
|
---|
982 | PUBLIC 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 | *===========================================================================*/
|
---|
994 | PRIVATE 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 | *===========================================================================*/
|
---|
1018 | PUBLIC 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 | *===========================================================================*/
|
---|
1032 | PUBLIC int con_loadfont(m)
|
---|
1033 | message *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 | *===========================================================================*/
|
---|
1072 | PRIVATE int ga_program(seq)
|
---|
1073 | struct 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 | *===========================================================================*/
|
---|
1088 | PRIVATE int cons_ioctl(tp, try)
|
---|
1089 | tty_t *tp;
|
---|
1090 | int 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 | }
|
---|