2005-04-21 16:53:53 +02:00
|
|
|
/* Code and data for the IBM console driver.
|
|
|
|
*
|
|
|
|
* The 6845 video controller used by the IBM PC shares its video memory with
|
|
|
|
* the CPU somewhere in the 0xB0000 memory bank. To the 6845 this memory
|
|
|
|
* consists of 16-bit words. Each word has a character code in the low byte
|
|
|
|
* and a so-called attribute byte in the high byte. The CPU directly modifies
|
|
|
|
* video memory to display characters, and sets two registers on the 6845 that
|
|
|
|
* specify the video origin and the cursor position. The video origin is the
|
|
|
|
* place in video memory where the first character (upper left corner) can
|
|
|
|
* be found. Moving the origin is a fast way to scroll the screen. Some
|
|
|
|
* video adapters wrap around the top of video memory, so the origin can
|
|
|
|
* move without bounds. For other adapters screen memory must sometimes be
|
|
|
|
* moved to reset the origin. All computations on video memory use character
|
|
|
|
* (word) addresses for simplicity and assume there is no wrapping. The
|
|
|
|
* assembly support functions translate the word addresses to byte addresses
|
|
|
|
* and the scrolling function worries about wrapping.
|
|
|
|
*/
|
|
|
|
|
2010-03-22 22:25:22 +01:00
|
|
|
#include <minix/drivers.h>
|
2005-04-21 16:53:53 +02:00
|
|
|
#include <termios.h>
|
2005-11-09 16:45:48 +01:00
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/vm.h>
|
2008-11-19 13:26:10 +01:00
|
|
|
#include <sys/video.h>
|
2009-05-12 14:43:18 +02:00
|
|
|
#include <sys/mman.h>
|
2008-11-19 13:26:10 +01:00
|
|
|
#include <minix/tty.h>
|
2005-04-21 16:53:53 +02:00
|
|
|
#include <minix/callnr.h>
|
|
|
|
#include <minix/com.h>
|
2008-11-19 13:26:10 +01:00
|
|
|
#include <minix/sys_config.h>
|
2008-12-08 17:40:29 +01:00
|
|
|
#include <minix/vm.h>
|
2005-04-21 16:53:53 +02:00
|
|
|
#include "tty.h"
|
|
|
|
|
2007-08-07 13:27:03 +02:00
|
|
|
/* Set this to 1 if you want console output duplicated on the first
|
|
|
|
* serial line.
|
|
|
|
*/
|
|
|
|
#define DUP_CONS_TO_SER 0
|
|
|
|
|
2005-10-24 15:57:19 +02:00
|
|
|
/* The clock task should provide an interface for this */
|
|
|
|
#define TIMER_FREQ 1193182L /* clock frequency for timer in PC and AT */
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/* Global variables used by the console driver and assembly support. */
|
2010-02-09 16:23:38 +01:00
|
|
|
PRIVATE phys_bytes vid_size; /* 0x2000 for color or 0x0800 for mono */
|
|
|
|
PRIVATE phys_bytes vid_base;
|
|
|
|
PRIVATE unsigned vid_mask; /* 0x1FFF for color or 0x07FF for mono */
|
|
|
|
PRIVATE unsigned blank_color = BLANK_COLOR; /* display code for blank */
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
/* Private variables used by the console driver. */
|
|
|
|
PRIVATE int vid_port; /* I/O port for accessing 6845 */
|
|
|
|
PRIVATE int wrap; /* hardware can wrap? */
|
|
|
|
PRIVATE int softscroll; /* 1 = software scrolling, 0 = hardware */
|
|
|
|
PRIVATE int beeping; /* speaker is beeping? */
|
|
|
|
PRIVATE unsigned font_lines; /* font lines per character */
|
|
|
|
PRIVATE unsigned scr_width; /* # characters on a line */
|
|
|
|
PRIVATE unsigned scr_lines; /* # lines on the screen */
|
|
|
|
PRIVATE unsigned scr_size; /* # characters on the screen */
|
|
|
|
|
2009-05-12 14:43:18 +02:00
|
|
|
/* tells mem_vid_copy() to blank the screen */
|
|
|
|
#define BLANK_MEM ((vir_bytes) 0)
|
|
|
|
|
2006-07-19 13:50:18 +02:00
|
|
|
PRIVATE int disabled_vc = -1; /* Virtual console that was active when
|
|
|
|
* disable_console was called.
|
|
|
|
*/
|
|
|
|
PRIVATE int disabled_sm; /* Scroll mode to be restored when re-enabling
|
|
|
|
* console
|
|
|
|
*/
|
|
|
|
|
2010-02-09 16:23:38 +01:00
|
|
|
PRIVATE char *console_memory = NULL;
|
|
|
|
PRIVATE char *font_memory = NULL;
|
2008-11-19 13:26:10 +01:00
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/* Per console data. */
|
|
|
|
typedef struct console {
|
|
|
|
tty_t *c_tty; /* associated TTY struct */
|
|
|
|
int c_column; /* current column number (0-origin) */
|
|
|
|
int c_row; /* current row (0 at top of screen) */
|
|
|
|
int c_rwords; /* number of WORDS (not bytes) in outqueue */
|
|
|
|
unsigned c_start; /* start of video memory of this console */
|
|
|
|
unsigned c_limit; /* limit of this console's video memory */
|
|
|
|
unsigned c_org; /* location in RAM where 6845 base points */
|
|
|
|
unsigned c_cur; /* current position of cursor in video RAM */
|
|
|
|
unsigned c_attr; /* character attribute */
|
|
|
|
unsigned c_blank; /* blank attribute */
|
|
|
|
char c_reverse; /* reverse video */
|
|
|
|
char c_esc_state; /* 0=normal, 1=ESC, 2=ESC[ */
|
|
|
|
char c_esc_intro; /* Distinguishing character following ESC */
|
|
|
|
int *c_esc_parmp; /* pointer to current escape parameter */
|
|
|
|
int c_esc_parmv[MAX_ESC_PARMS]; /* list of escape parameters */
|
|
|
|
u16_t c_ramqueue[CONS_RAM_WORDS]; /* buffer for video RAM */
|
2008-11-19 13:26:10 +01:00
|
|
|
int c_line; /* line no */
|
2005-04-21 16:53:53 +02:00
|
|
|
} console_t;
|
|
|
|
|
2008-11-19 13:26:10 +01:00
|
|
|
#define UPDATE_CURSOR(ccons, cursor) { \
|
|
|
|
ccons->c_cur = cursor; \
|
|
|
|
if(curcons && ccons == curcons) \
|
|
|
|
set_6845(CURSOR, ccons->c_cur); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define UPDATE_ORIGIN(ccons, origin) { \
|
|
|
|
ccons->c_org = origin; \
|
|
|
|
if (curcons && ccons == curcons) \
|
|
|
|
set_6845(VID_ORG, ccons->c_org); \
|
|
|
|
}
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
PRIVATE int nr_cons= 1; /* actual number of consoles */
|
|
|
|
PRIVATE console_t cons_table[NR_CONS];
|
2008-11-19 13:26:10 +01:00
|
|
|
PRIVATE console_t *curcons = NULL; /* currently visible */
|
2005-04-21 16:53:53 +02:00
|
|
|
|
2009-12-22 00:19:01 +01:00
|
|
|
PRIVATE int shutting_down = FALSE; /* don't allow console switches */
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/* Color if using a color controller. */
|
|
|
|
#define color (vid_port == C_6845)
|
|
|
|
|
|
|
|
/* Map from ANSI colors to the attributes used by the PC */
|
|
|
|
PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
|
|
|
|
|
|
|
|
/* Structure used for font management */
|
|
|
|
struct sequence {
|
|
|
|
unsigned short index;
|
|
|
|
unsigned char port;
|
|
|
|
unsigned char value;
|
|
|
|
};
|
|
|
|
|
2005-09-11 19:09:11 +02:00
|
|
|
FORWARD _PROTOTYPE( int cons_write, (struct tty *tp, int try) );
|
2005-04-21 16:53:53 +02:00
|
|
|
FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c) );
|
|
|
|
FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c) );
|
2005-09-30 15:01:34 +02:00
|
|
|
FORWARD _PROTOTYPE( void cons_putk, (int c) );
|
2005-04-21 16:53:53 +02:00
|
|
|
FORWARD _PROTOTYPE( void beep, (void) );
|
|
|
|
FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c) );
|
|
|
|
FORWARD _PROTOTYPE( void flush, (console_t *cons) );
|
|
|
|
FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c) );
|
|
|
|
FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir) );
|
|
|
|
FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val) );
|
2005-09-11 19:09:11 +02:00
|
|
|
FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp) );
|
2005-04-21 16:53:53 +02:00
|
|
|
FORWARD _PROTOTYPE( void cons_org0, (void) );
|
2006-07-19 13:50:18 +02:00
|
|
|
FORWARD _PROTOTYPE( void disable_console, (void) );
|
|
|
|
FORWARD _PROTOTYPE( void reenable_console, (void) );
|
2005-04-21 16:53:53 +02:00
|
|
|
FORWARD _PROTOTYPE( int ga_program, (struct sequence *seq) );
|
2005-06-17 15:37:41 +02:00
|
|
|
FORWARD _PROTOTYPE( int cons_ioctl, (tty_t *tp, int) );
|
2009-05-12 14:43:18 +02:00
|
|
|
FORWARD _PROTOTYPE( void mem_vid_copy, (vir_bytes src, int dst, int count) );
|
|
|
|
FORWARD _PROTOTYPE( void vid_vid_copy, (int src, int dst, int count) );
|
2008-11-19 13:26:10 +01:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
FORWARD _PROTOTYPE( void get_6845, (int reg, unsigned *val) );
|
|
|
|
#endif
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* cons_write *
|
|
|
|
*===========================================================================*/
|
2005-06-17 15:37:41 +02:00
|
|
|
PRIVATE int cons_write(tp, try)
|
2005-04-21 16:53:53 +02:00
|
|
|
register struct tty *tp; /* tells which terminal is to be used */
|
2005-06-17 15:37:41 +02:00
|
|
|
int try;
|
2005-04-21 16:53:53 +02:00
|
|
|
{
|
|
|
|
/* Copy as much data as possible to the output queue, then start I/O. On
|
|
|
|
* memory-mapped terminals, such as the IBM console, the I/O will also be
|
|
|
|
* finished, and the counts updated. Keep repeating until all I/O done.
|
|
|
|
*/
|
|
|
|
|
|
|
|
int count;
|
|
|
|
int result;
|
|
|
|
register char *tbuf;
|
|
|
|
char buf[64];
|
|
|
|
console_t *cons = tp->tty_priv;
|
|
|
|
|
2005-09-11 19:09:11 +02:00
|
|
|
if (try) return 1; /* we can always write to console */
|
2005-06-17 15:37:41 +02:00
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/* Check quickly for nothing to do, so this can be called often without
|
|
|
|
* unmodular tests elsewhere.
|
|
|
|
*/
|
2008-11-19 13:26:10 +01:00
|
|
|
if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return 0;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
/* Copy the user bytes to buf[] for decent addressing. Loop over the
|
|
|
|
* copies, since the user buffer may be much larger than buf[].
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
if (count > sizeof(buf)) count = sizeof(buf);
|
2006-06-20 11:02:54 +02:00
|
|
|
if(tp->tty_out_safe) {
|
|
|
|
if ((result = sys_safecopyfrom(tp->tty_outproc, tp->tty_out_vir_g,
|
|
|
|
tp->tty_out_vir_offset, (vir_bytes) buf, count, D)) != OK)
|
|
|
|
break;
|
|
|
|
tp->tty_out_vir_offset += count;
|
|
|
|
} else {
|
|
|
|
if ((result = sys_vircopy(tp->tty_outproc, D, tp->tty_out_vir_g,
|
2005-04-21 16:53:53 +02:00
|
|
|
SELF, D, (vir_bytes) buf, (vir_bytes) count)) != OK)
|
|
|
|
break;
|
2006-06-20 11:02:54 +02:00
|
|
|
tp->tty_out_vir_g += count;
|
|
|
|
}
|
2005-04-21 16:53:53 +02:00
|
|
|
tbuf = buf;
|
|
|
|
|
|
|
|
/* Update terminal data structure. */
|
|
|
|
tp->tty_outcum += count;
|
|
|
|
tp->tty_outleft -= count;
|
|
|
|
|
|
|
|
/* Output each byte of the copy to the screen. Avoid calling
|
|
|
|
* out_char() for the "easy" characters, put them into the buffer
|
|
|
|
* directly.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
|
|
|
|
|| cons->c_column >= scr_width
|
|
|
|
|| cons->c_rwords >= buflen(cons->c_ramqueue))
|
|
|
|
{
|
|
|
|
out_char(cons, *tbuf++);
|
|
|
|
} else {
|
2007-08-07 13:27:03 +02:00
|
|
|
#if DUP_CONS_TO_SER
|
|
|
|
if (cons == &cons_table[0]) ser_putc(*tbuf);
|
|
|
|
#endif
|
2005-04-21 16:53:53 +02:00
|
|
|
cons->c_ramqueue[cons->c_rwords++] =
|
|
|
|
cons->c_attr | (*tbuf++ & BYTE);
|
|
|
|
cons->c_column++;
|
|
|
|
}
|
|
|
|
} while (--count != 0);
|
|
|
|
} while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
|
|
|
|
|
|
|
|
flush(cons); /* transfer anything buffered to the screen */
|
|
|
|
|
|
|
|
/* Reply to the writer if all output is finished or if an error occured. */
|
|
|
|
if (tp->tty_outleft == 0 || result != OK) {
|
2005-07-27 16:32:16 +02:00
|
|
|
/* REVIVE is not possible. I/O on memory mapped consoles finishes. */
|
2005-04-21 16:53:53 +02:00
|
|
|
tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc,
|
|
|
|
tp->tty_outcum);
|
|
|
|
tp->tty_outcum = 0;
|
|
|
|
}
|
2008-11-19 13:26:10 +01:00
|
|
|
|
|
|
|
return 0;
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* cons_echo *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void cons_echo(tp, c)
|
|
|
|
register tty_t *tp; /* pointer to tty struct */
|
|
|
|
int c; /* character to be echoed */
|
|
|
|
{
|
|
|
|
/* Echo keyboard input (print & flush). */
|
|
|
|
console_t *cons = tp->tty_priv;
|
|
|
|
|
|
|
|
out_char(cons, c);
|
|
|
|
flush(cons);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* out_char *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void out_char(cons, c)
|
|
|
|
register console_t *cons; /* pointer to console struct */
|
|
|
|
int c; /* character to be output */
|
|
|
|
{
|
|
|
|
/* Output a character on the console. Check for escape sequences first. */
|
|
|
|
if (cons->c_esc_state > 0) {
|
|
|
|
parse_escape(cons, c);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-08-07 13:27:03 +02:00
|
|
|
#if DUP_CONS_TO_SER
|
|
|
|
if (cons == &cons_table[0] && c != '\0')
|
|
|
|
{
|
|
|
|
if (c == '\n')
|
|
|
|
ser_putc('\r');
|
|
|
|
ser_putc(c);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
switch(c) {
|
|
|
|
case 000: /* null is typically used for padding */
|
|
|
|
return; /* better not do anything */
|
|
|
|
|
|
|
|
case 007: /* ring the bell */
|
|
|
|
flush(cons); /* print any chars queued for output */
|
|
|
|
beep();
|
|
|
|
return;
|
|
|
|
|
|
|
|
case '\b': /* backspace */
|
|
|
|
if (--cons->c_column < 0) {
|
|
|
|
if (--cons->c_row >= 0) cons->c_column += scr_width;
|
|
|
|
}
|
|
|
|
flush(cons);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case '\n': /* line feed */
|
|
|
|
if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
|
|
|
|
== (OPOST|ONLCR)) {
|
|
|
|
cons->c_column = 0;
|
|
|
|
}
|
|
|
|
/*FALL THROUGH*/
|
|
|
|
case 013: /* CTRL-K */
|
|
|
|
case 014: /* CTRL-L */
|
|
|
|
if (cons->c_row == scr_lines-1) {
|
|
|
|
scroll_screen(cons, SCROLL_UP);
|
|
|
|
} else {
|
|
|
|
cons->c_row++;
|
|
|
|
}
|
|
|
|
flush(cons);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case '\r': /* carriage return */
|
|
|
|
cons->c_column = 0;
|
|
|
|
flush(cons);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case '\t': /* tab */
|
|
|
|
cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
|
|
|
|
if (cons->c_column > scr_width) {
|
|
|
|
cons->c_column -= scr_width;
|
|
|
|
if (cons->c_row == scr_lines-1) {
|
|
|
|
scroll_screen(cons, SCROLL_UP);
|
|
|
|
} else {
|
|
|
|
cons->c_row++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
flush(cons);
|
|
|
|
return;
|
|
|
|
|
|
|
|
case 033: /* ESC - start of an escape sequence */
|
|
|
|
flush(cons); /* print any chars queued for output */
|
|
|
|
cons->c_esc_state = 1; /* mark ESC as seen */
|
|
|
|
return;
|
|
|
|
|
|
|
|
default: /* printable chars are stored in ramqueue */
|
|
|
|
if (cons->c_column >= scr_width) {
|
|
|
|
if (!LINEWRAP) return;
|
|
|
|
if (cons->c_row == scr_lines-1) {
|
|
|
|
scroll_screen(cons, SCROLL_UP);
|
|
|
|
} else {
|
|
|
|
cons->c_row++;
|
|
|
|
}
|
|
|
|
cons->c_column = 0;
|
|
|
|
flush(cons);
|
|
|
|
}
|
|
|
|
if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons);
|
|
|
|
cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE);
|
|
|
|
cons->c_column++; /* next column */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* scroll_screen *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void scroll_screen(cons, dir)
|
|
|
|
register console_t *cons; /* pointer to console struct */
|
|
|
|
int dir; /* SCROLL_UP or SCROLL_DOWN */
|
|
|
|
{
|
|
|
|
unsigned new_line, new_org, chars;
|
|
|
|
|
|
|
|
flush(cons);
|
|
|
|
chars = scr_size - scr_width; /* one screen minus one line */
|
|
|
|
|
|
|
|
/* Scrolling the screen is a real nuisance due to the various incompatible
|
|
|
|
* video cards. This driver supports software scrolling (Hercules?),
|
|
|
|
* hardware scrolling (mono and CGA cards) and hardware scrolling without
|
|
|
|
* wrapping (EGA cards). In the latter case we must make sure that
|
|
|
|
* c_start <= c_org && c_org + scr_size <= c_limit
|
|
|
|
* holds, because EGA doesn't wrap around the end of video memory.
|
|
|
|
*/
|
|
|
|
if (dir == SCROLL_UP) {
|
|
|
|
/* Scroll one line up in 3 ways: soft, avoid wrap, use origin. */
|
|
|
|
if (softscroll) {
|
|
|
|
vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars);
|
|
|
|
} else
|
|
|
|
if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) {
|
|
|
|
vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars);
|
2008-11-19 13:26:10 +01:00
|
|
|
UPDATE_ORIGIN(cons, cons->c_start);
|
2005-04-21 16:53:53 +02:00
|
|
|
} else {
|
2008-11-19 13:26:10 +01:00
|
|
|
UPDATE_ORIGIN(cons, (cons->c_org + scr_width) & vid_mask);
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
new_line = (cons->c_org + chars) & vid_mask;
|
|
|
|
} else {
|
|
|
|
/* Scroll one line down in 3 ways: soft, avoid wrap, use origin. */
|
|
|
|
if (softscroll) {
|
|
|
|
vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars);
|
|
|
|
} else
|
|
|
|
if (!wrap && cons->c_org < cons->c_start + scr_width) {
|
|
|
|
new_org = cons->c_limit - scr_size;
|
|
|
|
vid_vid_copy(cons->c_org, new_org + scr_width, chars);
|
2008-11-19 13:26:10 +01:00
|
|
|
UPDATE_ORIGIN(cons, new_org);
|
2005-04-21 16:53:53 +02:00
|
|
|
} else {
|
2008-11-19 13:26:10 +01:00
|
|
|
UPDATE_ORIGIN(cons, (cons->c_org - scr_width) & vid_mask);
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
new_line = cons->c_org;
|
|
|
|
}
|
|
|
|
/* Blank the new line at top or bottom. */
|
|
|
|
blank_color = cons->c_blank;
|
|
|
|
mem_vid_copy(BLANK_MEM, new_line, scr_width);
|
|
|
|
|
|
|
|
flush(cons);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* flush *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void flush(cons)
|
|
|
|
register console_t *cons; /* pointer to console struct */
|
|
|
|
{
|
|
|
|
/* Send characters buffered in 'ramqueue' to screen memory, check the new
|
|
|
|
* cursor position, compute the new hardware cursor position and set it.
|
|
|
|
*/
|
|
|
|
unsigned cur;
|
|
|
|
tty_t *tp = cons->c_tty;
|
|
|
|
|
|
|
|
/* Have the characters in 'ramqueue' transferred to the screen. */
|
|
|
|
if (cons->c_rwords > 0) {
|
2009-05-12 14:43:18 +02:00
|
|
|
mem_vid_copy((vir_bytes) cons->c_ramqueue, cons->c_cur, cons->c_rwords);
|
2005-04-21 16:53:53 +02:00
|
|
|
cons->c_rwords = 0;
|
|
|
|
|
|
|
|
/* TTY likes to know the current column and if echoing messed up. */
|
|
|
|
tp->tty_position = cons->c_column;
|
|
|
|
tp->tty_reprint = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check and update the cursor position. */
|
|
|
|
if (cons->c_column < 0) cons->c_column = 0;
|
|
|
|
if (cons->c_column > scr_width) cons->c_column = scr_width;
|
|
|
|
if (cons->c_row < 0) cons->c_row = 0;
|
|
|
|
if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1;
|
|
|
|
cur = cons->c_org + cons->c_row * scr_width + cons->c_column;
|
2008-11-19 13:26:10 +01:00
|
|
|
if (cur != cons->c_cur)
|
|
|
|
UPDATE_CURSOR(cons, cur);
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* parse_escape *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void parse_escape(cons, c)
|
|
|
|
register console_t *cons; /* pointer to console struct */
|
|
|
|
char c; /* next character in escape sequence */
|
|
|
|
{
|
|
|
|
/* The following ANSI escape sequences are currently supported.
|
|
|
|
* If n and/or m are omitted, they default to 1.
|
|
|
|
* ESC [nA moves up n lines
|
|
|
|
* ESC [nB moves down n lines
|
|
|
|
* ESC [nC moves right n spaces
|
|
|
|
* ESC [nD moves left n spaces
|
|
|
|
* ESC [m;nH" moves cursor to (m,n)
|
|
|
|
* ESC [J clears screen from cursor
|
|
|
|
* ESC [K clears line from cursor
|
|
|
|
* ESC [nL inserts n lines ar cursor
|
|
|
|
* ESC [nM deletes n lines at cursor
|
|
|
|
* ESC [nP deletes n chars at cursor
|
|
|
|
* ESC [n@ inserts n chars at cursor
|
|
|
|
* ESC [nm enables rendition n (0=normal, 4=bold, 5=blinking, 7=reverse)
|
|
|
|
* ESC M scrolls the screen backwards if the cursor is on the top line
|
|
|
|
*/
|
|
|
|
|
|
|
|
switch (cons->c_esc_state) {
|
|
|
|
case 1: /* ESC seen */
|
|
|
|
cons->c_esc_intro = '\0';
|
|
|
|
cons->c_esc_parmp = bufend(cons->c_esc_parmv);
|
|
|
|
do {
|
|
|
|
*--cons->c_esc_parmp = 0;
|
|
|
|
} while (cons->c_esc_parmp > cons->c_esc_parmv);
|
|
|
|
switch (c) {
|
|
|
|
case '[': /* Control Sequence Introducer */
|
|
|
|
cons->c_esc_intro = c;
|
|
|
|
cons->c_esc_state = 2;
|
|
|
|
break;
|
|
|
|
case 'M': /* Reverse Index */
|
|
|
|
do_escape(cons, c);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cons->c_esc_state = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: /* ESC [ seen */
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
|
|
|
|
*cons->c_esc_parmp = *cons->c_esc_parmp * 10 + (c-'0');
|
|
|
|
} else
|
|
|
|
if (c == ';') {
|
|
|
|
if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
|
|
|
|
cons->c_esc_parmp++;
|
|
|
|
} else {
|
|
|
|
do_escape(cons, c);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* do_escape *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void do_escape(cons, c)
|
|
|
|
register console_t *cons; /* pointer to console struct */
|
|
|
|
char c; /* next character in escape sequence */
|
|
|
|
{
|
|
|
|
int value, n;
|
|
|
|
unsigned src, dst, count;
|
|
|
|
int *parmp;
|
|
|
|
|
|
|
|
/* Some of these things hack on screen RAM, so it had better be up to date */
|
|
|
|
flush(cons);
|
|
|
|
|
|
|
|
if (cons->c_esc_intro == '\0') {
|
|
|
|
/* Handle a sequence beginning with just ESC */
|
|
|
|
switch (c) {
|
|
|
|
case 'M': /* Reverse Index */
|
|
|
|
if (cons->c_row == 0) {
|
|
|
|
scroll_screen(cons, SCROLL_DOWN);
|
|
|
|
} else {
|
|
|
|
cons->c_row--;
|
|
|
|
}
|
|
|
|
flush(cons);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
if (cons->c_esc_intro == '[') {
|
|
|
|
/* Handle a sequence beginning with ESC [ and parameters */
|
|
|
|
value = cons->c_esc_parmv[0];
|
|
|
|
switch (c) {
|
|
|
|
case 'A': /* ESC [nA moves up n lines */
|
|
|
|
n = (value == 0 ? 1 : value);
|
|
|
|
cons->c_row -= n;
|
|
|
|
flush(cons);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'B': /* ESC [nB moves down n lines */
|
|
|
|
n = (value == 0 ? 1 : value);
|
|
|
|
cons->c_row += n;
|
|
|
|
flush(cons);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'C': /* ESC [nC moves right n spaces */
|
|
|
|
n = (value == 0 ? 1 : value);
|
|
|
|
cons->c_column += n;
|
|
|
|
flush(cons);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'D': /* ESC [nD moves left n spaces */
|
|
|
|
n = (value == 0 ? 1 : value);
|
|
|
|
cons->c_column -= n;
|
|
|
|
flush(cons);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'H': /* ESC [m;nH" moves cursor to (m,n) */
|
|
|
|
cons->c_row = cons->c_esc_parmv[0] - 1;
|
|
|
|
cons->c_column = cons->c_esc_parmv[1] - 1;
|
|
|
|
flush(cons);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'J': /* ESC [sJ clears in display */
|
|
|
|
switch (value) {
|
|
|
|
case 0: /* Clear from cursor to end of screen */
|
|
|
|
count = scr_size - (cons->c_cur - cons->c_org);
|
|
|
|
dst = cons->c_cur;
|
|
|
|
break;
|
|
|
|
case 1: /* Clear from start of screen to cursor */
|
|
|
|
count = cons->c_cur - cons->c_org;
|
|
|
|
dst = cons->c_org;
|
|
|
|
break;
|
|
|
|
case 2: /* Clear entire screen */
|
|
|
|
count = scr_size;
|
|
|
|
dst = cons->c_org;
|
|
|
|
break;
|
|
|
|
default: /* Do nothing */
|
|
|
|
count = 0;
|
|
|
|
dst = cons->c_org;
|
|
|
|
}
|
|
|
|
blank_color = cons->c_blank;
|
|
|
|
mem_vid_copy(BLANK_MEM, dst, count);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'K': /* ESC [sK clears line from cursor */
|
|
|
|
switch (value) {
|
|
|
|
case 0: /* Clear from cursor to end of line */
|
|
|
|
count = scr_width - cons->c_column;
|
|
|
|
dst = cons->c_cur;
|
|
|
|
break;
|
|
|
|
case 1: /* Clear from beginning of line to cursor */
|
|
|
|
count = cons->c_column;
|
|
|
|
dst = cons->c_cur - cons->c_column;
|
|
|
|
break;
|
|
|
|
case 2: /* Clear entire line */
|
|
|
|
count = scr_width;
|
|
|
|
dst = cons->c_cur - cons->c_column;
|
|
|
|
break;
|
|
|
|
default: /* Do nothing */
|
|
|
|
count = 0;
|
|
|
|
dst = cons->c_cur;
|
|
|
|
}
|
|
|
|
blank_color = cons->c_blank;
|
|
|
|
mem_vid_copy(BLANK_MEM, dst, count);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'L': /* ESC [nL inserts n lines at cursor */
|
|
|
|
n = value;
|
|
|
|
if (n < 1) n = 1;
|
|
|
|
if (n > (scr_lines - cons->c_row))
|
|
|
|
n = scr_lines - cons->c_row;
|
|
|
|
|
|
|
|
src = cons->c_org + cons->c_row * scr_width;
|
|
|
|
dst = src + n * scr_width;
|
|
|
|
count = (scr_lines - cons->c_row - n) * scr_width;
|
|
|
|
vid_vid_copy(src, dst, count);
|
|
|
|
blank_color = cons->c_blank;
|
|
|
|
mem_vid_copy(BLANK_MEM, src, n * scr_width);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'M': /* ESC [nM deletes n lines at cursor */
|
|
|
|
n = value;
|
|
|
|
if (n < 1) n = 1;
|
|
|
|
if (n > (scr_lines - cons->c_row))
|
|
|
|
n = scr_lines - cons->c_row;
|
|
|
|
|
|
|
|
dst = cons->c_org + cons->c_row * scr_width;
|
|
|
|
src = dst + n * scr_width;
|
|
|
|
count = (scr_lines - cons->c_row - n) * scr_width;
|
|
|
|
vid_vid_copy(src, dst, count);
|
|
|
|
blank_color = cons->c_blank;
|
|
|
|
mem_vid_copy(BLANK_MEM, dst + count, n * scr_width);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '@': /* ESC [n@ inserts n chars at cursor */
|
|
|
|
n = value;
|
|
|
|
if (n < 1) n = 1;
|
|
|
|
if (n > (scr_width - cons->c_column))
|
|
|
|
n = scr_width - cons->c_column;
|
|
|
|
|
|
|
|
src = cons->c_cur;
|
|
|
|
dst = src + n;
|
|
|
|
count = scr_width - cons->c_column - n;
|
|
|
|
vid_vid_copy(src, dst, count);
|
|
|
|
blank_color = cons->c_blank;
|
|
|
|
mem_vid_copy(BLANK_MEM, src, n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'P': /* ESC [nP deletes n chars at cursor */
|
|
|
|
n = value;
|
|
|
|
if (n < 1) n = 1;
|
|
|
|
if (n > (scr_width - cons->c_column))
|
|
|
|
n = scr_width - cons->c_column;
|
|
|
|
|
|
|
|
dst = cons->c_cur;
|
|
|
|
src = dst + n;
|
|
|
|
count = scr_width - cons->c_column - n;
|
|
|
|
vid_vid_copy(src, dst, count);
|
|
|
|
blank_color = cons->c_blank;
|
|
|
|
mem_vid_copy(BLANK_MEM, dst + count, n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'm': /* ESC [nm enables rendition n */
|
|
|
|
for (parmp = cons->c_esc_parmv; parmp <= cons->c_esc_parmp
|
|
|
|
&& parmp < bufend(cons->c_esc_parmv); parmp++) {
|
|
|
|
if (cons->c_reverse) {
|
|
|
|
/* Unswap fg and bg colors */
|
|
|
|
cons->c_attr = ((cons->c_attr & 0x7000) >> 4) |
|
|
|
|
((cons->c_attr & 0x0700) << 4) |
|
|
|
|
((cons->c_attr & 0x8800));
|
|
|
|
}
|
|
|
|
switch (n = *parmp) {
|
|
|
|
case 0: /* NORMAL */
|
|
|
|
cons->c_attr = cons->c_blank = BLANK_COLOR;
|
|
|
|
cons->c_reverse = FALSE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: /* BOLD */
|
|
|
|
/* Set intensity bit */
|
|
|
|
cons->c_attr |= 0x0800;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4: /* UNDERLINE */
|
|
|
|
if (color) {
|
|
|
|
/* Change white to cyan, i.e. lose red
|
|
|
|
*/
|
|
|
|
cons->c_attr = (cons->c_attr & 0xBBFF);
|
|
|
|
} else {
|
|
|
|
/* Set underline attribute */
|
|
|
|
cons->c_attr = (cons->c_attr & 0x99FF);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 5: /* BLINKING */
|
|
|
|
/* Set the blink bit */
|
|
|
|
cons->c_attr |= 0x8000;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 7: /* REVERSE */
|
|
|
|
cons->c_reverse = TRUE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: /* COLOR */
|
|
|
|
if (n == 39) n = 37; /* set default color */
|
|
|
|
if (n == 49) n = 40;
|
|
|
|
|
|
|
|
if (!color) {
|
|
|
|
/* Don't mess up a monochrome screen */
|
|
|
|
} else
|
|
|
|
if (30 <= n && n <= 37) {
|
|
|
|
/* Foreground color */
|
|
|
|
cons->c_attr =
|
|
|
|
(cons->c_attr & 0xF8FF) |
|
|
|
|
(ansi_colors[(n - 30)] << 8);
|
|
|
|
cons->c_blank =
|
|
|
|
(cons->c_blank & 0xF8FF) |
|
|
|
|
(ansi_colors[(n - 30)] << 8);
|
|
|
|
} else
|
|
|
|
if (40 <= n && n <= 47) {
|
|
|
|
/* Background color */
|
|
|
|
cons->c_attr =
|
|
|
|
(cons->c_attr & 0x8FFF) |
|
|
|
|
(ansi_colors[(n - 40)] << 12);
|
|
|
|
cons->c_blank =
|
|
|
|
(cons->c_blank & 0x8FFF) |
|
|
|
|
(ansi_colors[(n - 40)] << 12);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cons->c_reverse) {
|
|
|
|
/* Swap fg and bg colors */
|
|
|
|
cons->c_attr = ((cons->c_attr & 0x7000) >> 4) |
|
|
|
|
((cons->c_attr & 0x0700) << 4) |
|
|
|
|
((cons->c_attr & 0x8800));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cons->c_esc_state = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* set_6845 *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void set_6845(reg, val)
|
|
|
|
int reg; /* which register pair to set */
|
|
|
|
unsigned val; /* 16-bit value to set it to */
|
|
|
|
{
|
|
|
|
/* Set a register pair inside the 6845.
|
|
|
|
* Registers 12-13 tell the 6845 where in video ram to start
|
|
|
|
* Registers 14-15 tell the 6845 where to put the cursor
|
|
|
|
*/
|
|
|
|
pvb_pair_t char_out[4];
|
|
|
|
pv_set(char_out[0], vid_port + INDEX, reg); /* set index register */
|
|
|
|
pv_set(char_out[1], vid_port + DATA, (val>>8) & BYTE); /* high byte */
|
|
|
|
pv_set(char_out[2], vid_port + INDEX, reg + 1); /* again */
|
|
|
|
pv_set(char_out[3], vid_port + DATA, val&BYTE); /* low byte */
|
|
|
|
sys_voutb(char_out, 4); /* do actual output */
|
|
|
|
}
|
|
|
|
|
2008-11-19 13:26:10 +01:00
|
|
|
#if 0
|
2005-05-30 17:09:51 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* get_6845 *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void get_6845(reg, val)
|
|
|
|
int reg; /* which register pair to set */
|
|
|
|
unsigned *val; /* 16-bit value to set it to */
|
|
|
|
{
|
|
|
|
char v1, v2;
|
2006-03-24 15:16:13 +01:00
|
|
|
unsigned long v;
|
2005-05-30 17:09:51 +02:00
|
|
|
/* Get a register pair inside the 6845. */
|
|
|
|
sys_outb(vid_port + INDEX, reg);
|
2006-03-24 15:16:13 +01:00
|
|
|
sys_inb(vid_port + DATA, &v);
|
|
|
|
v1 = v;
|
2005-05-30 17:09:51 +02:00
|
|
|
sys_outb(vid_port + INDEX, reg+1);
|
2006-03-24 15:16:13 +01:00
|
|
|
sys_inb(vid_port + DATA, &v);
|
|
|
|
v2 = v;
|
2005-05-30 17:09:51 +02:00
|
|
|
*val = (v1 << 8) | v2;
|
|
|
|
}
|
2008-11-19 13:26:10 +01:00
|
|
|
#endif
|
2005-05-30 17:09:51 +02:00
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* beep *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void beep()
|
|
|
|
{
|
|
|
|
/* Making a beeping sound on the speaker (output for CRTL-G).
|
|
|
|
* This routine works by turning on the bits 0 and 1 in port B of the 8255
|
|
|
|
* chip that drive the speaker.
|
|
|
|
*/
|
|
|
|
static timer_t tmr_stop_beep;
|
|
|
|
pvb_pair_t char_out[3];
|
|
|
|
clock_t now;
|
2006-03-24 15:16:13 +01:00
|
|
|
unsigned long port_b_val;
|
|
|
|
int s;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
/* Fetch current time in advance to prevent beeping delay. */
|
2005-07-14 17:15:18 +02:00
|
|
|
if ((s=getuptime(&now)) != OK)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("Console couldn't get clock's uptime: %d", s);
|
2005-04-21 16:53:53 +02:00
|
|
|
if (!beeping) {
|
|
|
|
/* Set timer channel 2, square wave, with given frequency. */
|
|
|
|
pv_set(char_out[0], TIMER_MODE, 0xB6);
|
|
|
|
pv_set(char_out[1], TIMER2, (BEEP_FREQ >> 0) & BYTE);
|
|
|
|
pv_set(char_out[2], TIMER2, (BEEP_FREQ >> 8) & BYTE);
|
|
|
|
if (sys_voutb(char_out, 3)==OK) {
|
|
|
|
if (sys_inb(PORT_B, &port_b_val)==OK &&
|
|
|
|
sys_outb(PORT_B, (port_b_val|3))==OK)
|
|
|
|
beeping = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Add a timer to the timers list. Possibly reschedule the alarm. */
|
2005-06-17 15:37:41 +02:00
|
|
|
tmrs_settimer(&tty_timers, &tmr_stop_beep, now+B_TIME, stop_beep, NULL);
|
2005-04-21 16:53:53 +02:00
|
|
|
if (tty_timers->tmr_exp_time != tty_next_timeout) {
|
|
|
|
tty_next_timeout = tty_timers->tmr_exp_time;
|
2005-07-29 17:00:22 +02:00
|
|
|
if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("Console couldn't set alarm: %d", s);
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-10-24 15:57:19 +02:00
|
|
|
|
2005-11-09 16:45:48 +01:00
|
|
|
/*===========================================================================*
|
|
|
|
* do_video *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void do_video(message *m)
|
|
|
|
{
|
2008-11-19 13:26:10 +01:00
|
|
|
int r, safe = 0;
|
2005-11-09 16:45:48 +01:00
|
|
|
|
|
|
|
/* Execute the requested device driver function. */
|
|
|
|
r= EINVAL; /* just in case */
|
|
|
|
switch (m->m_type) {
|
|
|
|
case DEV_OPEN:
|
|
|
|
/* Should grant IOPL */
|
2006-07-19 13:50:18 +02:00
|
|
|
disable_console();
|
2005-11-09 16:45:48 +01:00
|
|
|
r= OK;
|
|
|
|
break;
|
|
|
|
case DEV_CLOSE:
|
2006-07-19 13:50:18 +02:00
|
|
|
reenable_console();
|
2005-11-09 16:45:48 +01:00
|
|
|
r= OK;
|
|
|
|
break;
|
2006-06-20 11:02:54 +02:00
|
|
|
case DEV_IOCTL_S:
|
|
|
|
safe=1;
|
2008-11-19 13:26:10 +01:00
|
|
|
switch(m->TTY_REQUEST) {
|
|
|
|
case TIOCMAPMEM:
|
|
|
|
case TIOCUNMAPMEM: {
|
|
|
|
int r, do_map;
|
|
|
|
struct mapreqvm mapreqvm;
|
|
|
|
|
|
|
|
do_map= (m->REQUEST == TIOCMAPMEM); /* else unmap */
|
|
|
|
|
|
|
|
/* Get request structure */
|
2008-12-08 17:40:29 +01:00
|
|
|
if(!safe) {
|
|
|
|
printf("tty: safecopy only\n");
|
|
|
|
return;
|
2008-11-19 13:26:10 +01:00
|
|
|
}
|
2008-12-08 17:40:29 +01:00
|
|
|
|
|
|
|
r = sys_safecopyfrom(m->IO_ENDPT,
|
|
|
|
(vir_bytes)m->ADDRESS, 0, (vir_bytes) &mapreqvm,
|
|
|
|
sizeof(mapreqvm), D);
|
|
|
|
|
2008-11-19 13:26:10 +01:00
|
|
|
if (r != OK)
|
|
|
|
{
|
2008-12-08 17:40:29 +01:00
|
|
|
printf("tty: sys_safecopyfrom failed\n");
|
2008-11-19 13:26:10 +01:00
|
|
|
tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT,
|
|
|
|
r);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In safe ioctl mode, the POSITION field contains
|
|
|
|
* the endpt number of the original requestor.
|
|
|
|
* IO_ENDPT is always FS.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if(do_map) {
|
2008-12-08 17:40:29 +01:00
|
|
|
mapreqvm.vaddr_ret = vm_map_phys(m->POSITION,
|
|
|
|
(void *) mapreqvm.phys_offset, mapreqvm.size);
|
|
|
|
if((r = sys_safecopyto(m->IO_ENDPT,
|
|
|
|
(vir_bytes)m->ADDRESS, 0,
|
|
|
|
(vir_bytes) &mapreqvm,
|
|
|
|
sizeof(mapreqvm), D)) != OK) {
|
|
|
|
printf("tty: sys_safecopyto failed\n");
|
|
|
|
}
|
2008-11-19 13:26:10 +01:00
|
|
|
} else {
|
2008-12-08 17:40:29 +01:00
|
|
|
r = vm_unmap_phys(m->POSITION,
|
|
|
|
mapreqvm.vaddr, mapreqvm.size);
|
2008-11-19 13:26:10 +01:00
|
|
|
}
|
2006-03-03 11:21:45 +01:00
|
|
|
tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r);
|
2005-11-09 16:45:48 +01:00
|
|
|
return;
|
2008-11-19 13:26:10 +01:00
|
|
|
}
|
2005-11-09 16:45:48 +01:00
|
|
|
}
|
|
|
|
r= ENOTTY;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
printf(
|
|
|
|
"Warning, TTY(video) got unexpected request %d from %d\n",
|
|
|
|
m->m_type, m->m_source);
|
|
|
|
r= EINVAL;
|
|
|
|
}
|
2006-03-03 11:21:45 +01:00
|
|
|
tty_reply(TASK_REPLY, m->m_source, m->IO_ENDPT, r);
|
2005-11-09 16:45:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-24 15:57:19 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* beep_x *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void beep_x(freq, dur)
|
|
|
|
unsigned freq;
|
|
|
|
clock_t dur;
|
|
|
|
{
|
|
|
|
/* Making a beeping sound on the speaker.
|
|
|
|
* This routine works by turning on the bits 0 and 1 in port B of the 8255
|
|
|
|
* chip that drive the speaker.
|
|
|
|
*/
|
|
|
|
static timer_t tmr_stop_beep;
|
|
|
|
pvb_pair_t char_out[3];
|
|
|
|
clock_t now;
|
2006-03-24 15:16:13 +01:00
|
|
|
unsigned long port_b_val;
|
|
|
|
int s;
|
2005-10-24 15:57:19 +02:00
|
|
|
|
|
|
|
unsigned long ival= TIMER_FREQ / freq;
|
|
|
|
if (ival == 0 || ival > 0xffff)
|
|
|
|
return; /* Frequency out of range */
|
|
|
|
|
|
|
|
/* Fetch current time in advance to prevent beeping delay. */
|
|
|
|
if ((s=getuptime(&now)) != OK)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("Console couldn't get clock's uptime: %d", s);
|
2005-10-24 15:57:19 +02:00
|
|
|
if (!beeping) {
|
|
|
|
/* Set timer channel 2, square wave, with given frequency. */
|
|
|
|
pv_set(char_out[0], TIMER_MODE, 0xB6);
|
|
|
|
pv_set(char_out[1], TIMER2, (ival >> 0) & BYTE);
|
|
|
|
pv_set(char_out[2], TIMER2, (ival >> 8) & BYTE);
|
|
|
|
if (sys_voutb(char_out, 3)==OK) {
|
|
|
|
if (sys_inb(PORT_B, &port_b_val)==OK &&
|
|
|
|
sys_outb(PORT_B, (port_b_val|3))==OK)
|
|
|
|
beeping = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Add a timer to the timers list. Possibly reschedule the alarm. */
|
|
|
|
tmrs_settimer(&tty_timers, &tmr_stop_beep, now+dur, stop_beep, NULL);
|
|
|
|
if (tty_timers->tmr_exp_time != tty_next_timeout) {
|
|
|
|
tty_next_timeout = tty_timers->tmr_exp_time;
|
|
|
|
if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("Console couldn't set alarm: %d", s);
|
2005-10-24 15:57:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* stop_beep *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void stop_beep(tmrp)
|
|
|
|
timer_t *tmrp;
|
|
|
|
{
|
|
|
|
/* Turn off the beeper by turning off bits 0 and 1 in PORT_B. */
|
2006-03-24 15:16:13 +01:00
|
|
|
unsigned long port_b_val;
|
2005-04-21 16:53:53 +02:00
|
|
|
if (sys_inb(PORT_B, &port_b_val)==OK &&
|
|
|
|
sys_outb(PORT_B, (port_b_val & ~3))==OK)
|
|
|
|
beeping = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* scr_init *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void scr_init(tp)
|
|
|
|
tty_t *tp;
|
|
|
|
{
|
|
|
|
/* Initialize the screen driver. */
|
|
|
|
console_t *cons;
|
|
|
|
u16_t bios_columns, bios_crtbase, bios_fontlines;
|
|
|
|
u8_t bios_rows;
|
|
|
|
int line;
|
|
|
|
int s;
|
|
|
|
static int vdu_initialized = 0;
|
2008-11-19 13:26:10 +01:00
|
|
|
static unsigned page_size;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
/* Associate console and TTY. */
|
|
|
|
line = tp - &tty_table[0];
|
|
|
|
if (line >= nr_cons) return;
|
|
|
|
cons = &cons_table[line];
|
|
|
|
cons->c_tty = tp;
|
2008-11-19 13:26:10 +01:00
|
|
|
cons->c_line = line;
|
2005-04-21 16:53:53 +02:00
|
|
|
tp->tty_priv = cons;
|
|
|
|
|
|
|
|
/* Fill in TTY function hooks. */
|
|
|
|
tp->tty_devwrite = cons_write;
|
|
|
|
tp->tty_echo = cons_echo;
|
|
|
|
tp->tty_ioctl = cons_ioctl;
|
|
|
|
|
|
|
|
/* Get the BIOS parameters that describe the VDU. */
|
|
|
|
if (! vdu_initialized++) {
|
|
|
|
|
2010-04-15 20:49:36 +02:00
|
|
|
/* FIXME: How about error checking? What to do on failure??? */
|
2006-07-10 14:37:39 +02:00
|
|
|
s=sys_readbios(VDU_SCREEN_COLS_ADDR, &bios_columns,
|
|
|
|
VDU_SCREEN_COLS_SIZE);
|
|
|
|
s=sys_readbios(VDU_CRT_BASE_ADDR, &bios_crtbase,
|
|
|
|
VDU_CRT_BASE_SIZE);
|
|
|
|
s=sys_readbios( VDU_SCREEN_ROWS_ADDR, &bios_rows,
|
|
|
|
VDU_SCREEN_ROWS_SIZE);
|
|
|
|
s=sys_readbios(VDU_FONTLINES_ADDR, &bios_fontlines,
|
|
|
|
VDU_FONTLINES_SIZE);
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
vid_port = bios_crtbase;
|
|
|
|
scr_width = bios_columns;
|
|
|
|
font_lines = bios_fontlines;
|
2005-04-29 17:36:43 +02:00
|
|
|
scr_lines = machine.vdu_ega ? bios_rows+1 : 25;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
if (color) {
|
|
|
|
vid_base = COLOR_BASE;
|
|
|
|
vid_size = COLOR_SIZE;
|
|
|
|
} else {
|
|
|
|
vid_base = MONO_BASE;
|
|
|
|
vid_size = MONO_SIZE;
|
|
|
|
}
|
2005-04-29 17:36:43 +02:00
|
|
|
if (machine.vdu_ega) vid_size = EGA_SIZE;
|
|
|
|
wrap = ! machine.vdu_ega;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
2009-05-12 14:43:18 +02:00
|
|
|
console_memory = vm_map_phys(SELF, (void *) vid_base, vid_size);
|
|
|
|
|
|
|
|
if(console_memory == MAP_FAILED)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("Console couldn't map video memory");
|
2005-04-21 16:53:53 +02:00
|
|
|
|
2009-09-21 16:25:54 +02:00
|
|
|
font_memory = vm_map_phys(SELF, (void *)GA_VIDEO_ADDRESS, GA_FONT_SIZE);
|
|
|
|
|
|
|
|
if(font_memory == MAP_FAILED)
|
2010-03-05 16:05:11 +01:00
|
|
|
panic("Console couldn't map font memory");
|
2009-09-21 16:25:54 +02:00
|
|
|
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
vid_size >>= 1; /* word count */
|
|
|
|
vid_mask = vid_size - 1;
|
|
|
|
|
|
|
|
/* Size of the screen (number of displayed characters.) */
|
|
|
|
scr_size = scr_lines * scr_width;
|
|
|
|
|
|
|
|
/* There can be as many consoles as video memory allows. */
|
2009-09-21 16:25:54 +02:00
|
|
|
nr_cons = vid_size / scr_size;
|
2008-11-19 13:26:10 +01:00
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
if (nr_cons > NR_CONS) nr_cons = NR_CONS;
|
|
|
|
if (nr_cons > 1) wrap = 0;
|
|
|
|
page_size = vid_size / nr_cons;
|
|
|
|
}
|
|
|
|
|
|
|
|
cons->c_start = line * page_size;
|
|
|
|
cons->c_limit = cons->c_start + page_size;
|
|
|
|
cons->c_cur = cons->c_org = cons->c_start;
|
|
|
|
cons->c_attr = cons->c_blank = BLANK_COLOR;
|
|
|
|
|
2005-09-11 19:09:11 +02:00
|
|
|
if (line != 0) {
|
2005-05-30 17:09:51 +02:00
|
|
|
/* Clear the non-console vtys. */
|
|
|
|
blank_color = BLANK_COLOR;
|
|
|
|
mem_vid_copy(BLANK_MEM, cons->c_start, scr_size);
|
|
|
|
} else {
|
|
|
|
/* Set the cursor of the console vty at the bottom. c_cur
|
|
|
|
* is updated automatically later.
|
|
|
|
*/
|
|
|
|
scroll_screen(cons, SCROLL_UP);
|
2005-08-04 21:23:03 +02:00
|
|
|
cons->c_row = scr_lines - 1;
|
2005-05-30 17:09:51 +02:00
|
|
|
cons->c_column = 0;
|
|
|
|
}
|
2005-04-21 16:53:53 +02:00
|
|
|
select_console(0);
|
2005-06-17 15:37:41 +02:00
|
|
|
cons_ioctl(tp, 0);
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
2005-09-11 19:09:11 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* kputc *
|
|
|
|
*===========================================================================*/
|
2010-02-09 16:23:38 +01:00
|
|
|
PUBLIC void kputc(int c)
|
2005-04-21 16:53:53 +02:00
|
|
|
{
|
2005-09-30 15:01:34 +02:00
|
|
|
/* Accumulate a single character for a kernel message. Send a notification
|
|
|
|
* the to output driver if an END_OF_KMESS is encountered.
|
|
|
|
*/
|
2005-10-24 15:57:19 +02:00
|
|
|
#if 0
|
|
|
|
ser_putc(c);
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
2005-09-30 15:01:34 +02:00
|
|
|
if (c != 0) {
|
|
|
|
kmess.km_buf[kmess.km_next] = c; /* put normal char in buffer */
|
2008-11-19 13:26:10 +01:00
|
|
|
if (kmess.km_size < _KMESS_BUF_SIZE)
|
2005-09-30 15:01:34 +02:00
|
|
|
kmess.km_size += 1;
|
2008-11-19 13:26:10 +01:00
|
|
|
kmess.km_next = (kmess.km_next + 1) % _KMESS_BUF_SIZE;
|
2005-09-30 15:01:34 +02:00
|
|
|
} else {
|
|
|
|
notify(LOG_PROC_NR);
|
|
|
|
}
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
2005-09-11 19:09:11 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* do_new_kmess *
|
|
|
|
*===========================================================================*/
|
New RS and new signal handling for system processes.
UPDATING INFO:
20100317:
/usr/src/etc/system.conf updated to ignore default kernel calls: copy
it (or merge it) to /etc/system.conf.
The hello driver (/dev/hello) added to the distribution:
# cd /usr/src/commands/scripts && make clean install
# cd /dev && MAKEDEV hello
KERNEL CHANGES:
- Generic signal handling support. The kernel no longer assumes PM as a signal
manager for every process. The signal manager of a given process can now be
specified in its privilege slot. When a signal has to be delivered, the kernel
performs the lookup and forwards the signal to the appropriate signal manager.
PM is the default signal manager for user processes, RS is the default signal
manager for system processes. To enable ptrace()ing for system processes, it
is sufficient to change the default signal manager to PM. This will temporarily
disable crash recovery, though.
- sys_exit() is now split into sys_exit() (i.e. exit() for system processes,
which generates a self-termination signal), and sys_clear() (i.e. used by PM
to ask the kernel to clear a process slot when a process exits).
- Added a new kernel call (i.e. sys_update()) to swap two process slots and
implement live update.
PM CHANGES:
- Posix signal handling is no longer allowed for system processes. System
signals are split into two fixed categories: termination and non-termination
signals. When a non-termination signaled is processed, PM transforms the signal
into an IPC message and delivers the message to the system process. When a
termination signal is processed, PM terminates the process.
- PM no longer assumes itself as the signal manager for system processes. It now
makes sure that every system signal goes through the kernel before being
actually processes. The kernel will then dispatch the signal to the appropriate
signal manager which may or may not be PM.
SYSLIB CHANGES:
- Simplified SEF init and LU callbacks.
- Added additional predefined SEF callbacks to debug crash recovery and
live update.
- Fixed a temporary ack in the SEF init protocol. SEF init reply is now
completely synchronous.
- Added SEF signal event type to provide a uniform interface for system
processes to deal with signals. A sef_cb_signal_handler() callback is
available for system processes to handle every received signal. A
sef_cb_signal_manager() callback is used by signal managers to process
system signals on behalf of the kernel.
- Fixed a few bugs with memory mapping and DS.
VM CHANGES:
- Page faults and memory requests coming from the kernel are now implemented
using signals.
- Added a new VM call to swap two process slots and implement live update.
- The call is used by RS at update time and in turn invokes the kernel call
sys_update().
RS CHANGES:
- RS has been reworked with a better functional decomposition.
- Better kernel call masks. com.h now defines the set of very basic kernel calls
every system service is allowed to use. This makes system.conf simpler and
easier to maintain. In addition, this guarantees a higher level of isolation
for system libraries that use one or more kernel calls internally (e.g. printf).
- RS is the default signal manager for system processes. By default, RS
intercepts every signal delivered to every system process. This makes crash
recovery possible before bringing PM and friends in the loop.
- RS now supports fast rollback when something goes wrong while initializing
the new version during a live update.
- Live update is now implemented by keeping the two versions side-by-side and
swapping the process slots when the old version is ready to update.
- Crash recovery is now implemented by keeping the two versions side-by-side
and cleaning up the old version only when the recovery process is complete.
DS CHANGES:
- Fixed a bug when the process doing ds_publish() or ds_delete() is not known
by DS.
- Fixed the completely broken support for strings. String publishing is now
implemented in the system library and simply wraps publishing of memory ranges.
Ideally, we should adopt a similar approach for other data types as well.
- Test suite fixed.
DRIVER CHANGES:
- The hello driver has been added to the Minix distribution to demonstrate basic
live update and crash recovery functionalities.
- Other drivers have been adapted to conform the new SEF interface.
2010-03-17 02:15:29 +01:00
|
|
|
PUBLIC void do_new_kmess()
|
2005-04-21 16:53:53 +02:00
|
|
|
{
|
|
|
|
/* Notification for a new kernel message. */
|
2008-11-19 13:26:10 +01:00
|
|
|
static struct kmessages kmess; /* kmessages structure */
|
2005-04-21 16:53:53 +02:00
|
|
|
static int prev_next = 0; /* previous next seen */
|
|
|
|
int bytes;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
/* Try to get a fresh copy of the buffer with kernel messages. */
|
2005-05-26 15:17:57 +02:00
|
|
|
#if DEAD_CODE
|
|
|
|
/* During shutdown, the reply is garbled because new notifications arrive
|
|
|
|
* while the system task makes a copy of the kernel messages buffer.
|
|
|
|
* Hence, don't check the return value.
|
|
|
|
*/
|
2005-04-21 16:53:53 +02:00
|
|
|
if ((r=sys_getkmessages(&kmess)) != OK) {
|
2005-05-24 16:35:58 +02:00
|
|
|
printf("TTY: couldn't get copy of kmessages: %d, 0x%x\n", r,r);
|
2005-04-21 16:53:53 +02:00
|
|
|
return;
|
|
|
|
}
|
2005-05-26 15:17:57 +02:00
|
|
|
#endif
|
|
|
|
sys_getkmessages(&kmess);
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
/* Print only the new part. Determine how many new bytes there are with
|
|
|
|
* help of the current and previous 'next' index. Note that the kernel
|
2008-11-19 13:26:10 +01:00
|
|
|
* buffer is circular. This works fine if less then _KMESS_BUF_SIZE bytes
|
|
|
|
* is new data; else we miss % _KMESS_BUF_SIZE here.
|
2005-04-21 16:53:53 +02:00
|
|
|
* Check for size being positive, the buffer might as well be emptied!
|
|
|
|
*/
|
|
|
|
if (kmess.km_size > 0) {
|
2008-11-19 13:26:10 +01:00
|
|
|
bytes = ((kmess.km_next + _KMESS_BUF_SIZE) - prev_next) % _KMESS_BUF_SIZE;
|
2005-04-21 16:53:53 +02:00
|
|
|
r=prev_next; /* start at previous old */
|
|
|
|
while (bytes > 0) {
|
2008-11-19 13:26:10 +01:00
|
|
|
cons_putk( kmess.km_buf[(r%_KMESS_BUF_SIZE)] );
|
2005-04-21 16:53:53 +02:00
|
|
|
bytes --;
|
|
|
|
r ++;
|
|
|
|
}
|
2005-09-30 15:01:34 +02:00
|
|
|
cons_putk(0); /* terminate to flush output */
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Almost done, store 'next' so that we can determine what part of the
|
|
|
|
* kernel messages buffer to print next time a notification arrives.
|
|
|
|
*/
|
|
|
|
prev_next = kmess.km_next;
|
|
|
|
}
|
|
|
|
|
2005-09-11 19:09:11 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* do_diagnostics *
|
|
|
|
*===========================================================================*/
|
2006-06-20 11:02:54 +02:00
|
|
|
PUBLIC void do_diagnostics(m_ptr, safe)
|
2005-04-21 16:53:53 +02:00
|
|
|
message *m_ptr; /* pointer to request message */
|
2006-06-20 11:02:54 +02:00
|
|
|
int safe;
|
2005-04-21 16:53:53 +02:00
|
|
|
{
|
|
|
|
/* Print a string for a server. */
|
|
|
|
char c;
|
|
|
|
vir_bytes src;
|
2006-06-20 11:02:54 +02:00
|
|
|
int count, offset = 0;
|
2005-04-21 16:53:53 +02:00
|
|
|
int result = OK;
|
2006-06-20 11:02:54 +02:00
|
|
|
int proc_nr = m_ptr->m_source;
|
2005-04-21 16:53:53 +02:00
|
|
|
|
2006-06-20 11:02:54 +02:00
|
|
|
src = (vir_bytes) m_ptr->DIAG_PRINT_BUF_G;
|
2005-04-21 16:53:53 +02:00
|
|
|
for (count = m_ptr->DIAG_BUF_COUNT; count > 0; count--) {
|
2006-06-20 11:02:54 +02:00
|
|
|
int r;
|
|
|
|
if(safe) {
|
|
|
|
r = sys_safecopyfrom(proc_nr, src, offset, (vir_bytes) &c, 1, D);
|
2008-11-19 13:26:10 +01:00
|
|
|
if(r != OK)
|
|
|
|
printf("<tty: proc %d, grant %ld>", proc_nr, src);
|
2006-06-20 11:02:54 +02:00
|
|
|
} else {
|
|
|
|
r = sys_vircopy(proc_nr, D, src+offset, SELF, D, (vir_bytes) &c, 1);
|
|
|
|
}
|
|
|
|
offset++;
|
|
|
|
if(r != OK) {
|
2005-04-21 16:53:53 +02:00
|
|
|
result = EFAULT;
|
|
|
|
break;
|
|
|
|
}
|
2005-09-30 15:01:34 +02:00
|
|
|
cons_putk(c);
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
2005-09-30 15:01:34 +02:00
|
|
|
cons_putk(0); /* always terminate, even with EFAULT */
|
2008-11-19 13:26:10 +01:00
|
|
|
|
2009-01-26 18:43:59 +01:00
|
|
|
if(m_ptr->m_type != ASYN_DIAGNOSTICS_OLD) {
|
|
|
|
m_ptr->m_type = DIAG_REPL_OLD;
|
2008-11-19 13:26:10 +01:00
|
|
|
m_ptr->REP_STATUS = result;
|
|
|
|
send(m_ptr->m_source, m_ptr);
|
|
|
|
}
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
2005-09-30 15:01:34 +02:00
|
|
|
* do_get_kmess *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void do_get_kmess(m_ptr)
|
|
|
|
message *m_ptr; /* pointer to request message */
|
|
|
|
{
|
|
|
|
/* Provide the log device with debug output */
|
|
|
|
vir_bytes dst;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
dst = (vir_bytes) m_ptr->GETKM_PTR;
|
|
|
|
r= OK;
|
|
|
|
if (sys_vircopy(SELF, D, (vir_bytes)&kmess, m_ptr->m_source, D,
|
|
|
|
dst, sizeof(kmess)) != OK) {
|
|
|
|
r = EFAULT;
|
|
|
|
}
|
|
|
|
m_ptr->m_type = r;
|
|
|
|
send(m_ptr->m_source, m_ptr);
|
|
|
|
}
|
|
|
|
|
2006-07-10 14:37:39 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* do_get_kmess_s *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void do_get_kmess_s(m_ptr)
|
|
|
|
message *m_ptr; /* pointer to request message */
|
|
|
|
{
|
|
|
|
/* Provide the log device with debug output */
|
|
|
|
cp_grant_id_t gid;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
gid = m_ptr->GETKM_GRANT;
|
|
|
|
r= OK;
|
|
|
|
if (sys_safecopyto(m_ptr->m_source, gid, 0, (vir_bytes)&kmess, sizeof(kmess),
|
|
|
|
D) != OK) {
|
|
|
|
r = EFAULT;
|
|
|
|
}
|
|
|
|
m_ptr->m_type = r;
|
|
|
|
send(m_ptr->m_source, m_ptr);
|
|
|
|
}
|
|
|
|
|
2005-09-30 15:01:34 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* cons_putk *
|
2005-04-21 16:53:53 +02:00
|
|
|
*===========================================================================*/
|
2005-09-30 15:01:34 +02:00
|
|
|
PRIVATE void cons_putk(c)
|
2005-04-21 16:53:53 +02:00
|
|
|
int c; /* character to print */
|
|
|
|
{
|
2005-09-30 15:01:34 +02:00
|
|
|
/* This procedure is used to print a character on the console.
|
2005-04-21 16:53:53 +02:00
|
|
|
*/
|
|
|
|
if (c != 0) {
|
2005-09-30 15:01:34 +02:00
|
|
|
if (c == '\n') cons_putk('\r');
|
2005-04-21 16:53:53 +02:00
|
|
|
out_char(&cons_table[0], (int) c);
|
2007-04-23 16:59:32 +02:00
|
|
|
#if 0
|
|
|
|
ser_putc(c);
|
|
|
|
#endif
|
2005-04-21 16:53:53 +02:00
|
|
|
} else {
|
|
|
|
flush(&cons_table[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* toggle_scroll *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void toggle_scroll()
|
|
|
|
{
|
|
|
|
/* Toggle between hardware and software scroll. */
|
|
|
|
|
|
|
|
cons_org0();
|
|
|
|
softscroll = !softscroll;
|
|
|
|
printf("%sware scrolling enabled.\n", softscroll ? "Soft" : "Hard");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* cons_stop *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void cons_stop()
|
|
|
|
{
|
|
|
|
/* Prepare for halt or reboot. */
|
|
|
|
cons_org0();
|
|
|
|
softscroll = 1;
|
2009-12-22 00:19:01 +01:00
|
|
|
select_console(0);
|
2005-04-21 16:53:53 +02:00
|
|
|
cons_table[0].c_attr = cons_table[0].c_blank = BLANK_COLOR;
|
2009-12-22 00:19:01 +01:00
|
|
|
shutting_down = TRUE;
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* cons_org0 *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void cons_org0()
|
|
|
|
{
|
|
|
|
/* Scroll video memory back to put the origin at 0. */
|
|
|
|
int cons_line;
|
|
|
|
console_t *cons;
|
|
|
|
unsigned n;
|
|
|
|
|
|
|
|
for (cons_line = 0; cons_line < nr_cons; cons_line++) {
|
|
|
|
cons = &cons_table[cons_line];
|
|
|
|
while (cons->c_org > cons->c_start) {
|
|
|
|
n = vid_size - scr_size; /* amount of unused memory */
|
|
|
|
if (n > cons->c_org - cons->c_start)
|
|
|
|
n = cons->c_org - cons->c_start;
|
|
|
|
vid_vid_copy(cons->c_org, cons->c_org - n, scr_size);
|
2008-11-19 13:26:10 +01:00
|
|
|
UPDATE_ORIGIN(cons, cons->c_org - n);
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
flush(cons);
|
|
|
|
}
|
|
|
|
select_console(ccurrent);
|
|
|
|
}
|
|
|
|
|
2006-07-19 13:50:18 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* disable_console *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void disable_console()
|
|
|
|
{
|
|
|
|
if (disabled_vc != -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
disabled_vc = ccurrent;
|
|
|
|
disabled_sm = softscroll;
|
|
|
|
|
|
|
|
cons_org0();
|
|
|
|
softscroll = 1;
|
|
|
|
select_console(0);
|
|
|
|
|
|
|
|
/* Should also disable further output to virtual consoles */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* reenable_console *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void reenable_console()
|
|
|
|
{
|
|
|
|
if (disabled_vc == -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
softscroll = disabled_sm;
|
|
|
|
select_console(disabled_vc);
|
|
|
|
disabled_vc = -1;
|
|
|
|
}
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/*===========================================================================*
|
|
|
|
* select_console *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC void select_console(int cons_line)
|
|
|
|
{
|
|
|
|
/* Set the current console to console number 'cons_line'. */
|
|
|
|
|
2009-12-22 00:19:01 +01:00
|
|
|
if (shutting_down) return;
|
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
if (cons_line < 0 || cons_line >= nr_cons) return;
|
2008-11-19 13:26:10 +01:00
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
ccurrent = cons_line;
|
|
|
|
curcons = &cons_table[cons_line];
|
2008-11-19 13:26:10 +01:00
|
|
|
|
|
|
|
UPDATE_CURSOR(curcons, curcons->c_cur);
|
|
|
|
UPDATE_ORIGIN(curcons, curcons->c_org);
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* con_loadfont *
|
|
|
|
*===========================================================================*/
|
|
|
|
PUBLIC int con_loadfont(m)
|
|
|
|
message *m;
|
|
|
|
{
|
2009-09-21 16:25:54 +02:00
|
|
|
|
2005-04-21 16:53:53 +02:00
|
|
|
/* Load a font into the EGA or VGA adapter. */
|
|
|
|
int result;
|
|
|
|
static struct sequence seq1[7] = {
|
|
|
|
{ GA_SEQUENCER_INDEX, 0x00, 0x01 },
|
|
|
|
{ GA_SEQUENCER_INDEX, 0x02, 0x04 },
|
|
|
|
{ GA_SEQUENCER_INDEX, 0x04, 0x07 },
|
|
|
|
{ GA_SEQUENCER_INDEX, 0x00, 0x03 },
|
|
|
|
{ GA_GRAPHICS_INDEX, 0x04, 0x02 },
|
|
|
|
{ GA_GRAPHICS_INDEX, 0x05, 0x00 },
|
|
|
|
{ GA_GRAPHICS_INDEX, 0x06, 0x00 },
|
|
|
|
};
|
|
|
|
static struct sequence seq2[7] = {
|
|
|
|
{ GA_SEQUENCER_INDEX, 0x00, 0x01 },
|
|
|
|
{ GA_SEQUENCER_INDEX, 0x02, 0x03 },
|
|
|
|
{ GA_SEQUENCER_INDEX, 0x04, 0x03 },
|
|
|
|
{ GA_SEQUENCER_INDEX, 0x00, 0x03 },
|
|
|
|
{ GA_GRAPHICS_INDEX, 0x04, 0x00 },
|
|
|
|
{ GA_GRAPHICS_INDEX, 0x05, 0x10 },
|
|
|
|
{ GA_GRAPHICS_INDEX, 0x06, 0 },
|
|
|
|
};
|
|
|
|
|
|
|
|
seq2[6].value= color ? 0x0E : 0x0A;
|
|
|
|
|
2005-04-29 17:36:43 +02:00
|
|
|
if (!machine.vdu_ega) return(ENOTTY);
|
2005-04-21 16:53:53 +02:00
|
|
|
result = ga_program(seq1); /* bring font memory into view */
|
|
|
|
|
2009-09-21 16:25:54 +02:00
|
|
|
if(sys_safecopyfrom(m->IO_ENDPT, (cp_grant_id_t) m->ADDRESS, 0,
|
|
|
|
(vir_bytes) font_memory, GA_FONT_SIZE, D) != OK) {
|
|
|
|
printf("tty: copying from %d failed\n", m->IO_ENDPT);
|
|
|
|
return EFAULT;
|
|
|
|
}
|
2005-04-21 16:53:53 +02:00
|
|
|
|
|
|
|
result = ga_program(seq2); /* restore */
|
|
|
|
|
|
|
|
return(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* ga_program *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE int ga_program(seq)
|
|
|
|
struct sequence *seq;
|
|
|
|
{
|
|
|
|
pvb_pair_t char_out[14];
|
|
|
|
int i;
|
|
|
|
for (i=0; i<7; i++) {
|
|
|
|
pv_set(char_out[2*i], seq->index, seq->port);
|
|
|
|
pv_set(char_out[2*i+1], seq->index+1, seq->value);
|
|
|
|
seq++;
|
|
|
|
}
|
|
|
|
return sys_voutb(char_out, 14);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* cons_ioctl *
|
|
|
|
*===========================================================================*/
|
2005-06-17 15:37:41 +02:00
|
|
|
PRIVATE int cons_ioctl(tp, try)
|
2005-04-21 16:53:53 +02:00
|
|
|
tty_t *tp;
|
2005-06-17 15:37:41 +02:00
|
|
|
int try;
|
2005-04-21 16:53:53 +02:00
|
|
|
{
|
|
|
|
/* Set the screen dimensions. */
|
|
|
|
|
|
|
|
tp->tty_winsize.ws_row= scr_lines;
|
|
|
|
tp->tty_winsize.ws_col= scr_width;
|
|
|
|
tp->tty_winsize.ws_xpixel= scr_width * 8;
|
|
|
|
tp->tty_winsize.ws_ypixel= scr_lines * font_lines;
|
2008-11-19 13:26:10 +01:00
|
|
|
|
|
|
|
return 0;
|
2005-04-21 16:53:53 +02:00
|
|
|
}
|
2005-10-24 15:57:19 +02:00
|
|
|
|
2009-05-12 14:43:18 +02:00
|
|
|
#define LIMITINDEX(mask, start, size, ct) { \
|
|
|
|
int countlimit = size - start; \
|
|
|
|
start &= mask; \
|
|
|
|
if(ct > countlimit) ct = countlimit; \
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* mem_vid_copy *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void mem_vid_copy(vir_bytes src, int dst_index, int count)
|
|
|
|
{
|
|
|
|
u16_t *src_mem = (u16_t *) src;
|
|
|
|
while(count > 0) {
|
|
|
|
int i, subcount = count;
|
|
|
|
u16_t *dst_mem;
|
|
|
|
LIMITINDEX(vid_mask, dst_index, vid_size, subcount);
|
|
|
|
dst_mem = (u16_t *) console_memory + dst_index;
|
|
|
|
if(!src)
|
|
|
|
for(i = 0; i < subcount; i++)
|
|
|
|
*dst_mem++ = blank_color;
|
|
|
|
else
|
|
|
|
for(i = 0; i < subcount; i++)
|
|
|
|
*dst_mem++ = *src_mem++;
|
|
|
|
count -= subcount;
|
|
|
|
dst_index += subcount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
|
|
* vid_vid_copy *
|
|
|
|
*===========================================================================*/
|
|
|
|
PRIVATE void vid_vid_copy(int src_index, int dst_index, int count)
|
|
|
|
{
|
|
|
|
int backwards = 0;
|
|
|
|
if(src_index < dst_index)
|
|
|
|
backwards = 1;
|
|
|
|
while(count > 0) {
|
|
|
|
int i, subcount = count;
|
|
|
|
u16_t *dst_mem, *src_mem;
|
|
|
|
LIMITINDEX(vid_mask, src_index, vid_size, subcount);
|
|
|
|
LIMITINDEX(vid_mask, dst_index, vid_size, subcount);
|
|
|
|
src_mem = (u16_t *) console_memory + src_index;
|
|
|
|
dst_mem = (u16_t *) console_memory + dst_index;
|
|
|
|
if(backwards) {
|
|
|
|
src_mem += subcount - 1;
|
|
|
|
dst_mem += subcount - 1;
|
|
|
|
for(i = 0; i < subcount; i++)
|
|
|
|
*dst_mem-- = *src_mem--;
|
|
|
|
} else {
|
|
|
|
for(i = 0; i < subcount; i++)
|
|
|
|
*dst_mem++ = *src_mem++;
|
|
|
|
}
|
|
|
|
count -= subcount;
|
|
|
|
dst_index += subcount;
|
|
|
|
src_index += subcount;
|
|
|
|
}
|
|
|
|
}
|