From 98f74b7826c1c178c3585e5f61e051e59ac0c318 Mon Sep 17 00:00:00 2001 From: Valtteri Koskivuori Date: Mon, 2 Sep 2024 20:34:45 +0300 Subject: [PATCH] [console] Add dual-screen support to console-direct.c Thanks to some clever design from IBM folks, even the original 1981 IBM PC had support for more than one display at a time by 1983. The CRTC I/O base and vram segments don't always overlap, so nothing prevents the system from addressing two compatible adapters simultaneously. The switch on the PC motherboard just tells the BIOS which output it should set up on boot. This patch introduces the concept of an output to the console drivers, and adds support for probing, setting up, and managing multiple display adapters to the console-direct driver. There are no new options. The adapter indicated by the BIOS as the primary adapter is set up as the primary display, and a potential secondary adapter will be set up as a secondary display, if present. Depending on the runlevel, each display can get 0 or more consoles allocated to it, and switching between them works the same as before, by using CTRL+ALT+F. To indicate which display is active, the blinking cursor is toggled such that it only appears on the active display. --- elks/arch/i86/drivers/char/console-bios.c | 60 ++-- .../i86/drivers/char/console-direct-pc98.c | 73 +++-- elks/arch/i86/drivers/char/console-direct.c | 301 +++++++++++++----- elks/arch/i86/drivers/char/console.c | 70 ++-- elks/arch/i86/kernel/timer.c | 15 +- 5 files changed, 354 insertions(+), 165 deletions(-) diff --git a/elks/arch/i86/drivers/char/console-bios.c b/elks/arch/i86/drivers/char/console-bios.c index 849614c83..dfd27f10c 100644 --- a/elks/arch/i86/drivers/char/console-bios.c +++ b/elks/arch/i86/drivers/char/console-bios.c @@ -41,10 +41,15 @@ #define MAXPARMS 28 +#define MAX_OUTPUTS 1 + +struct output; +typedef struct output Output; struct console; typedef struct console Console; struct console { + Output *op; int cx, cy; /* cursor position */ void (*fsm)(Console *, int); unsigned char attr; /* current attribute */ @@ -58,10 +63,18 @@ struct console { #endif }; -static struct wait_queue glock_wait; -static Console Con[MAX_CONSOLES], *Visible; -static Console *glock; /* Which console owns the graphics hardware */ -static int Width, MaxCol, Height, MaxRow; +struct output { + unsigned short w; + unsigned short max_col; + unsigned short h; + unsigned short max_row; + Console *visible; + Console *glock; /* Which console owns the graphics hardware */ + struct wait_queue glock_wait; +}; + +static Output Outputs[MAX_OUTPUTS]; +static Console Con[MAX_CONSOLES]; static int NumConsoles = MAX_CONSOLES; static int kraw; static int Current_VCminor = 0; @@ -93,7 +106,7 @@ static void PositionCursorGet (int * x, int * y) *y = row; } -static void DisplayCursor(int onoff) +static void DisplayCursor(register Console * C, int onoff) { } @@ -111,14 +124,14 @@ static void scroll(register Console * C, int n, int x, int y, int xx, int yy) int a; a = C->attr; - if (C != Visible) { + if (C != C->op->visible) { bios_setpage(C->pageno); } bios_scroll (a, n, x, y, xx, yy); - if (C != Visible) { - bios_setpage(Visible->pageno); + if (C != C->op->visible) { + bios_setpage(C->op->visible->pageno); } } @@ -129,13 +142,13 @@ static void ClearRange(register Console * C, int x, int y, int xx, int yy) static void ScrollUp(register Console * C, int y) { - scroll(C, 1, 0, y, MaxCol, MaxRow); + scroll(C, 1, 0, y, C->op->max_col, C->op->max_row); } #ifdef CONFIG_EMUL_ANSI static void ScrollDown(register Console * C, int y) { - scroll(C, -1, 0, y, MaxCol, MaxRow); + scroll(C, -1, 0, y, C->op->max_col, C->op->max_row); } #endif @@ -148,12 +161,12 @@ static void ScrollDown(register Console * C, int y) void Console_set_vc(int N) { - if ((N >= NumConsoles) || (Visible == &Con[N]) || glock) + if ((N >= NumConsoles) || (Con[N].op->visible == &Con[N]) || Con[N].op->glock) return; - Visible = &Con[N]; + Con[N].op->visible = &Con[N]; bios_setpage(N); - PositionCursor(Visible); + PositionCursor(Con[N].op->visible); Current_VCminor = N; } @@ -169,25 +182,26 @@ struct tty_ops bioscon_ops = { void INITPROC console_init(void) { Console *C; + Output *O; int i; - MaxCol = (Width = SETUP_VID_COLS) - 1; - - /* Trust this. Cga does not support peeking at 0x40:0x84. */ - MaxRow = (Height = SETUP_VID_LINES) - 1; + O = &Outputs[0]; + O->max_col = (O->w = SETUP_VID_COLS) - 1; + O->max_row = (O->h = SETUP_VID_LINES) - 1; if (peekb(0x49, 0x40) == 7) /* BIOS data segment */ NumConsoles = 1; C = Con; - Visible = C; for (i = 0; i < NumConsoles; i++) { + C->op = O; C->cx = C->cy = 0; if (!i) { - // Get current cursor position - // to write after boot messages - PositionCursorGet (&C->cx, &C->cy); + O->visible = C; + // Get current cursor position + // to write after boot messages + PositionCursorGet (&C->cx, &C->cy); } C->fsm = std_char; C->pageno = i; @@ -201,7 +215,7 @@ void INITPROC console_init(void) #endif /* Do not erase early printk() */ - /* ClearRange(C, 0, C->cy, MaxCol, MaxRow); */ + /* ClearRange(C, 0, C->cy, C->op->max_col, C->op->max_row); */ C++; } @@ -209,5 +223,5 @@ void INITPROC console_init(void) kbd_init(); printk("BIOS console %ux%u"TERM_TYPE"(%d virtual consoles)\n", - Width, Height, NumConsoles); + O->w, O->h, NumConsoles); } diff --git a/elks/arch/i86/drivers/char/console-direct-pc98.c b/elks/arch/i86/drivers/char/console-direct-pc98.c index 96d38dccb..2e0a04b2f 100644 --- a/elks/arch/i86/drivers/char/console-direct-pc98.c +++ b/elks/arch/i86/drivers/char/console-direct-pc98.c @@ -48,10 +48,15 @@ #define MAXPARMS 28 +#define MAX_OUTPUTS 1 + +struct output; +typedef struct output Output; struct console; typedef struct console Console; struct console { + Output *op; int cx, cy; /* cursor position */ void (*fsm)(Console *, int); unsigned char attr; /* current attribute */ @@ -65,10 +70,18 @@ struct console { #endif }; -static struct wait_queue glock_wait; -static Console Con[MAX_CONSOLES], *Visible; -static Console *glock; /* Which console owns the graphics hardware */ -static int Width, MaxCol, Height, MaxRow; +struct output { + unsigned short w; + unsigned short max_col; + unsigned short h; + unsigned short max_row; + struct wait_queue glock_wait; + Console *visible; + Console *glock; /* Which console owns the graphics hardware */ +}; + +static Output Outputs[MAX_OUTPUTS]; +static Console Con[MAX_CONSOLES]; static int NumConsoles = MAX_CONSOLES; int Current_VCminor = 0; @@ -92,11 +105,11 @@ static void PositionCursor(register Console * C) { int Pos; - Pos = C->cx + Width * C->cy + C->basepage; + Pos = C->cx + C->op->w * C->cy + C->basepage; cursor_set(Pos * 2); } -static void DisplayCursor(int onoff) +static void DisplayCursor(register Console * C, int onoff) { if (onoff) cursor_on(); @@ -130,7 +143,7 @@ static void VideoWrite(register Console * C, int c) word_t addr; word_t attr; - addr = (C->cx + C->cy * Width) << 1; + addr = (C->cx + C->cy * C->op->w) << 1; attr = (C->attr == A_DEFAULT) ? A98_DEFAULT : conv_pcattr(C->attr); pokew(addr, (seg_t) AttributeSeg, attr); @@ -145,13 +158,13 @@ static void ClearRange(register Console * C, int x, int y, int xx, int yy) attr = (C->attr == A_DEFAULT) ? A98_DEFAULT : conv_pcattr(C->attr); xx = xx - x + 1; - vp = (__u16 *)((__u16)(x + y * Width) << 1); + vp = (__u16 *)((__u16)(x + y * C->op->w) << 1); do { for (x = 0; x < xx; x++) { pokew((word_t) vp, AttributeSeg, attr); pokew((word_t) (vp++), (seg_t) C->vseg, (word_t) ' '); } - vp += (Width - xx); + vp += (C->op->w - xx); } while (++y <= yy); } @@ -159,27 +172,27 @@ static void ScrollUp(register Console * C, int y) { register __u16 *vp; - vp = (__u16 *)((__u16)(y * Width) << 1); - if ((unsigned int)y < MaxRow) { - fmemcpyb(vp, AttributeSeg, vp + Width, AttributeSeg, (MaxRow - y) * (Width << 1)); - fmemcpyb(vp, C->vseg, vp + Width, C->vseg, (MaxRow - y) * (Width << 1)); + vp = (__u16 *)((__u16)(y * C->op->w) << 1); + if ((unsigned int)y < C->op->max_row) { + fmemcpyb(vp, AttributeSeg, vp + C->op->w, AttributeSeg, (C->op->max_row - y) * (C->op->w << 1)); + fmemcpyb(vp, C->vseg, vp + C->op->w, C->vseg, (C->op->max_row - y) * (C->op->w << 1)); } - ClearRange(C, 0, MaxRow, MaxCol, MaxRow); + ClearRange(C, 0, C->op->max_row, C->op->max_col, C->op->max_row); } #ifdef CONFIG_EMUL_ANSI static void ScrollDown(register Console * C, int y) { register __u16 *vp; - int yy = MaxRow; + int yy = C->op->max_row; - vp = (__u16 *)((__u16)(yy * Width) << 1); + vp = (__u16 *)((__u16)(yy * C->op->w) << 1); while (--yy >= y) { - fmemcpyb(vp, AttributeSeg, vp - Width, AttributeSeg, Width << 1); - fmemcpyb(vp, C->vseg, vp - Width, C->vseg, Width << 1); - vp -= Width; + fmemcpyb(vp, AttributeSeg, vp - C->op->w, AttributeSeg, C->op->w << 1); + fmemcpyb(vp, C->vseg, vp - C->op->w, C->vseg, C->op->w << 1); + vp -= C->op->w; } - ClearRange(C, 0, y, MaxCol, y); + ClearRange(C, 0, y, C->op->max_col, y); } #endif @@ -192,12 +205,12 @@ static void ScrollDown(register Console * C, int y) void Console_set_vc(int N) { - if ((N >= NumConsoles) || (Visible == &Con[N]) || glock) + if ((N >= NumConsoles) || (Con[N].op->visible == &Con[N]) || Con[N].op->glock) return; - Visible = &Con[N]; + Con[N].op->visible = &Con[N]; - SetDisplayPage(Visible); - PositionCursor(Visible); + SetDisplayPage(Con[N].op->visible); + PositionCursor(Con[N].op->visible); Current_VCminor = N; } @@ -213,6 +226,7 @@ struct tty_ops dircon_ops = { void INITPROC console_init(void) { Console *C; + Output *O; int i; unsigned PageSizeW; @@ -224,20 +238,21 @@ void INITPROC console_init(void) AttributeSeg = 0xE200; } - MaxCol = (Width = 80) - 1; - - MaxRow = (Height = 25) - 1; + O = &Outputs[0]; + O->max_col = (O->w = 80) - 1; + O->max_row = (O->h = 25) - 1; PageSizeW = 2000; NumConsoles = 1; C = Con; - Visible = C; for (i = 0; i < NumConsoles; i++) { + C->op = O; C->cx = C->cy = 0; if (!i) { + O->visible = C; C->cx = read_tvram_x() % 160; C->cy = read_tvram_x() / 160; } @@ -261,5 +276,5 @@ void INITPROC console_init(void) kbd_init(); printk("Direct console, %s kbd %ux%u"TERM_TYPE"(du virtual consoles)\n", - kbd_name, Width, Height, NumConsoles); + kbd_name, O->w, O->h, NumConsoles); } diff --git a/elks/arch/i86/drivers/char/console-direct.c b/elks/arch/i86/drivers/char/console-direct.c index 32ab514ea..289e68e97 100644 --- a/elks/arch/i86/drivers/char/console-direct.c +++ b/elks/arch/i86/drivers/char/console-direct.c @@ -31,6 +31,12 @@ #define A_REVERSE 0x70 #define A_BLANK 0x00 +#define CRTC_INDX 0x0 +#define CRTC_DATA 0x1 +#define CRTC_MODE 0x4 +#define CRTC_CSEL 0x5 +#define CRTC_STAT 0x6 + /* character definitions*/ #define BS '\b' #define NL '\n' @@ -41,16 +47,29 @@ #define MAXPARMS 28 +#define N_DEVICETYPES 2 +#define MAX_OUTPUTS 2 + +struct output; +typedef struct output Output; struct console; typedef struct console Console; +enum OutputType { + OT_MDA = 0, + OT_CGA, + OT_EGA, + OT_VGA, +}; + struct console { + Output *op; int cx, cy; /* cursor position */ void (*fsm)(Console *, int); unsigned char attr; /* current attribute */ unsigned char XN; /* delayed newline on column 80 */ - unsigned int vseg; /* video segment for page */ - int basepage; /* start of video ram */ + unsigned int vseg; /* video segment for page TODO: Could we compute this from vseg_base + vseg_offset? */ + int vseg_offset; /* start of vram for this console */ #ifdef CONFIG_EMUL_ANSI int savex, savey; /* saved cursor position */ unsigned char *parmptr; /* ptr to params */ @@ -58,17 +77,63 @@ struct console { #endif }; -static struct wait_queue glock_wait; -static Console Con[MAX_CONSOLES], *Visible; -static Console *glock; /* Which console owns the graphics hardware */ -static unsigned short CCBase; /* 6845 CRTC base I/O address */ -static int Width, MaxCol, Height, MaxRow; -static int NumConsoles = MAX_CONSOLES; -static unsigned char isMDA, isCGA; +struct hw_params { + unsigned short w; + unsigned short h; + unsigned short crtc_base; + unsigned vseg_base; + int vseg_bytes; + unsigned char init_bytes[16]; + unsigned char n_init_bytes; + unsigned char max_pages; + unsigned short page_words; +}; + +static struct hw_params params[N_DEVICETYPES] = { + { 80, 25, 0x3B4, 0xB000, 0x1000, + { + 0x61, 0x50, 0x52, 0x0F, + 0x19, 0x06, 0x19, 0x19, + 0x02, 0x0D, 0x0B, 0x0C, + 0x00, 0x00, 0x00, 0x00, + }, 16, 1, 2000 + }, /* MDA */ + { 80, 25, 0x3D4, 0xB800, 0x4000, + { + /* CO80 */ + 0x71, 0x50, 0x5A, 0x0A, + 0x1F, 0x06, 0x19, 0x1C, + 0x02, 0x07, 0x06, 0x07, + 0x00, 0x00, 0x00, 0x00, + }, 16, 2, 2000 + }, /* CGA */ + // TODO + //{ 0 }, /* EGA */ + //{ 0 }, /* VGA */ +}; + +struct output { + enum OutputType type; + unsigned short w; + unsigned short max_col; + unsigned short h; + unsigned short max_row; + unsigned short crtc_base; /* 6845 CRTC base I/O address */ + unsigned vseg_base; /* Start of vram for this card */ + Console *consoles[MAX_CONSOLES]; + Console *visible; + Console *glock; /* Which console owns the graphics hardware */ + struct wait_queue glock_wait; + unsigned char n_consoles; +}; + +static Output Outputs[MAX_OUTPUTS]; +static Console Con[MAX_CONSOLES]; +// FIXME: We probably need to rework glock logic for multi-console mode +static int NumConsoles = 0; int Current_VCminor = 0; int kraw = 0; -unsigned VideoSeg = 0xB800; #ifdef CONFIG_EMUL_ANSI #define TERM_TYPE " emulating ANSI " @@ -80,38 +145,38 @@ static void std_char(register Console *, int); static void SetDisplayPage(register Console * C) { - outw((C->basepage & 0xff00) | 0x0c, CCBase); - outw((C->basepage << 8) | 0x0d, CCBase); + outw((C->vseg_offset & 0xff00) | 0x0c, C->op->crtc_base); + outw((C->vseg_offset << 8) | 0x0d, C->op->crtc_base); } static void PositionCursor(register Console * C) { - unsigned int Pos = C->cx + Width * C->cy + C->basepage; + unsigned int Pos = C->cx + C->op->w * C->cy + C->vseg_offset; - outb(14, CCBase); - outb(Pos >> 8, CCBase + 1); - outb(15, CCBase); - outb(Pos, CCBase + 1); + outb(14, C->op->crtc_base); + outb(Pos >> 8, C->op->crtc_base + 1); + outb(15, C->op->crtc_base); + outb(Pos, C->op->crtc_base + 1); } -static void DisplayCursor(int onoff) +static void DisplayCursor(register Console * C, int onoff) { /* unfortunately, the cursor start/end at BDA 0x0460 can't be relied on! */ unsigned int v; if (onoff) - v = isMDA? 0x0b0c: (isCGA? 0x0607: 0x0d0e); + v = C->op->type == OT_MDA ? 0x0b0c : (C->op->type == OT_CGA ? 0x0607: 0x0d0e); else v = 0x2000; - outb(10, CCBase); - outb(v >> 8, CCBase + 1); - outb(11, CCBase); - outb(v, CCBase + 1); + outb(10, C->op->crtc_base); + outb(v >> 8, C->op->crtc_base + 1); + outb(11, C->op->crtc_base); + outb(v, C->op->crtc_base + 1); } static void VideoWrite(register Console * C, int c) { - pokew((C->cx + C->cy * Width) << 1, (seg_t) C->vseg, + pokew((C->cx + C->cy * C->op->w) << 1, (seg_t) C->vseg, (C->attr << 8) | (c & 255)); } @@ -120,39 +185,41 @@ static void ClearRange(register Console * C, int x, int y, int x2, int y2) register int vp; x2 = x2 - x + 1; - vp = (x + y * Width) << 1; + vp = (x + y * C->op->w) << 1; do { for (x = 0; x < x2; x++) { pokew(vp, (seg_t) C->vseg, (C->attr << 8) | ' '); vp += 2; } - vp += (Width - x2) << 1; + vp += (C->op->w - x2) << 1; } while (++y <= y2); } static void ScrollUp(register Console * C, int y) { register int vp; + int max_row = C->op->h - 1; + int max_col = C->op->w - 1; - vp = y * (Width << 1); - if ((unsigned int)y < MaxRow) + vp = y * (C->op->w << 1); + if ((unsigned int)y < max_row) fmemcpyw((void *)vp, C->vseg, - (void *)(vp + (Width << 1)), C->vseg, (MaxRow - y) * Width); - ClearRange(C, 0, MaxRow, MaxCol, MaxRow); + (void *)(vp + (C->op->w << 1)), C->vseg, (max_row - y) * C->op->w); + ClearRange(C, 0, max_row, max_col, max_row); } #ifdef CONFIG_EMUL_ANSI static void ScrollDown(register Console * C, int y) { register int vp; - int yy = MaxRow; + int yy = C->op->h - 1; - vp = yy * (Width << 1); + vp = yy * (C->op->w << 1); while (--yy >= y) { - fmemcpyw((void *)vp, C->vseg, (void *)(vp - (Width << 1)), C->vseg, Width); - vp -= Width << 1; + fmemcpyw((void *)vp, C->vseg, (void *)(vp - (C->op->w << 1)), C->vseg, C->op->w); + vp -= C->op->w << 1; } - ClearRange(C, 0, y, MaxCol, y); + ClearRange(C, 0, y, C->op->w - 1, y); } #endif @@ -165,13 +232,15 @@ static void ScrollDown(register Console * C, int y) void Console_set_vc(int N) { - if ((N >= NumConsoles) || (Visible == &Con[N]) || glock) + if ((N >= NumConsoles) || Con[N].op->glock) return; - Visible = &Con[N]; + Con[N].op->visible = &Con[N]; - SetDisplayPage(Visible); - PositionCursor(Visible); + SetDisplayPage(Con[N].op->visible); + PositionCursor(Con[N].op->visible); + DisplayCursor(&Con[Current_VCminor], 0); Current_VCminor = N; + DisplayCursor(&Con[Current_VCminor], 1); } struct tty_ops dircon_ops = { @@ -183,54 +252,144 @@ struct tty_ops dircon_ops = { Console_conout }; -void INITPROC console_init(void) + +/* Check to see if this CRTC is present */ +static char probe_crtc(unsigned short crtc_base) { - Console *C; int i; - unsigned int PageSizeW; - - MaxCol = (Width = peekb(0x4a, 0x40)) - 1; /* BIOS data segment */ - - /* Trust this. Cga does not support peeking at 0x40:0x84. */ - MaxRow = (Height = 25) - 1; - CCBase = peekw(0x63, 0x40); - PageSizeW = ((unsigned int)peekw(0x4C, 0x40) >> 1); - - VideoSeg = 0xb800; - if (peekb(0x49, 0x40) == 7) { - VideoSeg = 0xB000; - NumConsoles = 1; - isMDA = 1; - } else { - isCGA = peekw(0xA8+2, 0x40) == 0; + unsigned char test = 0x55; + /* We'll try writing a value to cursor address LSB reg (0x0F), then reading it back */ + outb(0x0F, crtc_base + CRTC_INDX); + unsigned char original = inb(crtc_base + CRTC_DATA); + if (original == test) test += 0x10; + outb(0x0F, crtc_base + CRTC_INDX); + outb(test, crtc_base + CRTC_DATA); + /* Now wait a bit */ + for (i = 0; i < 100; ++i) {} // TODO: Verify this doesn't get optimized out + outb(0x0F, crtc_base + CRTC_INDX); + unsigned char value = inb(crtc_base + CRTC_DATA); + if (value != test) return 0; + outb(0x0F, crtc_base + CRTC_INDX); + outb(original, crtc_base + CRTC_DATA); + return 1; +} + +static void init_output(Output *o) +{ + int i; + struct hw_params *p = ¶ms[o->type]; + o->w = p->w; + o->max_col = o->w - 1; + o->h = p->h; + o->max_row = o->h - 1; + o->vseg_base = p->vseg_base; + /* Set 80x25 mode, video off */ + outb(0x01, o->crtc_base + CRTC_MODE); + /* Program CRTC regs */ + for (i = 0; i < p->n_init_bytes; ++i) { + outb(i, o->crtc_base + CRTC_INDX); + outb(p->init_bytes[i], o->crtc_base + CRTC_DATA); } - C = Con; - Visible = C; + /* Clear vram */ + for (i = 0; i < p->vseg_bytes; i += 2) + pokew(i, o->vseg_base, 0x7 << 8 | ' '); - for (i = 0; i < NumConsoles; i++) { + /* Enable video */ + outb(0x09, o->crtc_base + CRTC_MODE); +} + +static const char *type_string(enum OutputType t) +{ + switch (t) { + case OT_MDA: return "MDA"; + case OT_CGA: return "CGA"; + case OT_EGA: return "EGA"; + case OT_VGA: return "VGA"; + } +} + +void INITPROC console_init(void) +{ + Console *C; + Output *O; + int i; + int screens; + unsigned short boot_crtc; + // 1. Map out hardware + for (i = 0; i < N_DEVICETYPES; ++i) + if (probe_crtc(params[i].crtc_base)) { + Outputs[i].type = i; + Outputs[i].crtc_base = params[i].crtc_base; + } + /* Ask the BIOS which adapter is selected as the primary one */ + boot_crtc = peekw(0x63, 0x40); + for (i = 0; i < N_DEVICETYPES; ++i) + if (boot_crtc == params[i].crtc_base && !Outputs[i].crtc_base) + panic("boot_crtc not found"); + // 2. Set up hardware + /* boot_crtc was already set up by bios, but reprogramming it should be fine */ + for (i = 0; i < N_DEVICETYPES; ++i) + init_output(&Outputs[i]); + // 3. Map consoles to hardware + C = &Con[0]; + /* Start with boot crtc */ + for (i = 0; i < N_DEVICETYPES; ++i) + if (Outputs[i].crtc_base == boot_crtc) O = &Outputs[i]; + + for (i = 0; i < params[O->type].max_pages; ++i) { C->cx = C->cy = 0; if (!i) { + O->visible = C; C->cx = peekb(0x50, 0x40); C->cy = peekb(0x51, 0x40); } C->fsm = std_char; - C->basepage = i * PageSizeW; - C->vseg = VideoSeg + (C->basepage >> 3); + C->vseg_offset = i * params[O->type].page_words; + C->vseg = params[O->type].vseg_base + (C->vseg_offset >> 3); C->attr = A_DEFAULT; - + C->op = O; #ifdef CONFIG_EMUL_ANSI C->savex = C->savey = 0; #endif - /* Do not erase early printk() */ - /* ClearRange(C, 0, C->cy, MaxCol, MaxRow); */ - - C++; + NumConsoles++; + O->consoles[O->n_consoles++] = C++; } - + // FIXME: Remove dumb duplication + + /* Now connect the rest up */ + for (i = 0; i < N_DEVICETYPES; ++i) { + if (Outputs[i].crtc_base == boot_crtc) continue; + O = &Outputs[i]; + for (i = 0; i < params[O->type].max_pages; ++i) { + C->cx = C->cy = 0; + if (!i) { + O->visible = C; + } + C->fsm = std_char; + C->vseg_offset = i * params[O->type].page_words; + C->vseg = params[O->type].vseg_base + (C->vseg_offset >> 3); + C->attr = A_DEFAULT; + C->op = O; + #ifdef CONFIG_EMUL_ANSI + C->savex = C->savey = 0; + #endif + + DisplayCursor(C, 0); + NumConsoles++; + O->consoles[O->n_consoles++] = C++; + } + } + screens = 0; + for (i = 0; i < N_DEVICETYPES; ++i) + if (Outputs[i].crtc_base) screens++; kbd_init(); - - printk("Direct console, %s kbd %ux%u"TERM_TYPE"(%d virtual consoles)\n", - kbd_name, Width, Height, NumConsoles); + printk("boot_crtc: %x\n", Con[0].op->crtc_base); + printk("Direct console %s kbd"TERM_TYPE"(%d screens):\n", kbd_name, screens); + for (i = 0; i < N_DEVICETYPES; ++i) { + if (!Outputs[i].crtc_base) continue; + printk("Screen %d, %d consoles, %s, %ux%u\n", i, Outputs[i].n_consoles, + type_string(Outputs[i].type), Outputs[i].w, Outputs[i].h); + } } diff --git a/elks/arch/i86/drivers/char/console.c b/elks/arch/i86/drivers/char/console.c index def587669..d1fe94e5c 100644 --- a/elks/arch/i86/drivers/char/console.c +++ b/elks/arch/i86/drivers/char/console.c @@ -3,10 +3,10 @@ static void WriteChar(register Console * C, int c) { /* check for graphics lock */ - while (glock) { - if (glock == C) + while (C->op->glock) { + if (C->op->glock == C) return; - sleep_on(&glock_wait); + sleep_on(&C->op->glock_wait); } C->fsm(C, c); } @@ -34,9 +34,9 @@ static void Console_gotoxy(register Console * C, int x, int y) { register int xp = x; - C->cx = (xp >= MaxCol) ? MaxCol : (xp < 0) ? 0 : xp; + C->cx = (xp >= C->op->max_col) ? C->op->max_col : (xp < 0) ? 0 : xp; xp = y; - C->cy = (xp >= MaxRow) ? MaxRow : (xp < 0) ? 0 : xp; + C->cy = (xp >= C->op->max_row) ? C->op->max_row : (xp < 0) ? 0 : xp; C->XN = 0; } @@ -105,23 +105,23 @@ static void AnsiCmd(register Console * C, int c) break; case 'B': /* Move down n lines */ C->cy += parm1(C->params); - if (C->cy > MaxRow) - C->cy = MaxRow; + if (C->cy > C->op->max_row) + C->cy = C->op->max_row; break; case 'd': /* Vertical position absolute */ C->cy = parm1(C->params) - 1; - if (C->cy > MaxRow) - C->cy = MaxRow; + if (C->cy > C->op->max_row) + C->cy = C->op->max_row; break; case 'C': /* Move right n characters */ C->cx += parm1(C->params); - if (C->cx > MaxCol) - C->cx = MaxCol; + if (C->cx > C->op->max_col) + C->cx = C->op->max_col; break; case 'G': /* Horizontal position absolute */ C->cx = parm1(C->params) - 1; - if (C->cx > MaxCol) - C->cx = MaxCol; + if (C->cx > C->op->max_col) + C->cx = C->op->max_col; break; case 'D': /* Move left n characters */ C->cx -= parm1(C->params); @@ -134,20 +134,20 @@ static void AnsiCmd(register Console * C, int c) case 'J': /* clear screen */ n = atoi((char *)C->params); if (n == 0) { /* to bottom */ - ClearRange(C, C->cx, C->cy, MaxCol, C->cy); - if (C->cy < MaxRow) - ClearRange(C, 0, C->cy, MaxCol, MaxRow); + ClearRange(C, C->cx, C->cy, C->op->max_col, C->cy); + if (C->cy < C->op->max_row) + ClearRange(C, 0, C->cy, C->op->max_col, C->op->max_row); } else if (n == 2) /* all*/ - ClearRange(C, 0, 0, MaxCol, MaxRow); + ClearRange(C, 0, 0, C->op->max_col, C->op->max_row); break; case 'K': /* clear line */ n = atoi((char *)C->params); if (n == 0) /* to EOL */ - ClearRange(C, C->cx, C->cy, MaxCol, C->cy); + ClearRange(C, C->cx, C->cy, C->op->max_col, C->cy); else if (n == 1) /* to BOL */ ClearRange(C, 0, C->cy, C->cx, C->cy); else if (n == 2) /* all */ - ClearRange(C, 0, C->cy, MaxCol, C->cy); + ClearRange(C, 0, C->cy, C->op->max_col, C->cy); break; case 'L': /* insert line */ ScrollDown(C, C->cy); @@ -218,7 +218,7 @@ static void AnsiCmd(register Console * C, int c) case 'h': /* cursor on */ case 'l': /* cursor off */ if (C->params[0] == '?' && atoi((const char *)C->params+1) == 25) { - DisplayCursor(c == 'h'); + DisplayCursor(C, c == 'h'); } break; } @@ -287,9 +287,9 @@ static void std_char(register Console * C, int c) C->XN = 0; C->cx = 0; C->cy++; - if (C->cy > MaxRow) { + if (C->cy > C->op->max_row) { ScrollUp(C, 0); - C->cy = MaxRow; + C->cy = C->op->max_row; } } #ifdef CONFIG_CONSOLE_BIOS @@ -300,14 +300,14 @@ static void std_char(register Console * C, int c) C->cx++; } linewrap: - if (C->cx > MaxCol) { + if (C->cx > C->op->max_col) { C->XN = 1; - C->cx = MaxCol; + C->cx = C->op->max_col; } } - if (C->cy > MaxRow) { + if (C->cy > C->op->max_row) { ScrollUp(C, 0); - C->cy = MaxRow; + C->cy = C->op->max_row; } } @@ -317,26 +317,26 @@ static int Console_ioctl(struct tty *tty, int cmd, char *arg) switch (cmd) { case DCGET_GRAPH: - if (!glock) { - glock = C; + if (!C->op->glock) { + C->op->glock = C; return 0; } return -EBUSY; case DCREL_GRAPH: - if (glock == C) { - glock = NULL; - wake_up(&glock_wait); + if (C->op->glock == C) { + C->op->glock = NULL; + wake_up(&C->op->glock_wait); return 0; } break; case DCSET_KRAW: - if (glock == C) { + if (C->op->glock == C) { kraw = 1; return 0; } break; case DCREL_KRAW: - if ((glock == C) && (kraw == 1)) { + if ((C->op->glock == C) && (kraw == 1)) { kraw = 0; return 1; } @@ -364,11 +364,11 @@ static int Console_write(register struct tty *tty) register Console *C = &Con[tty->minor]; int cnt = 0; - while ((tty->outq.len > 0) && !glock) { + while ((tty->outq.len > 0) && !C->op->glock) { WriteChar(C, tty_outproc(tty)); cnt++; } - if (C == Visible) + if (C == C->op->visible) PositionCursor(C); return cnt; } diff --git a/elks/arch/i86/kernel/timer.c b/elks/arch/i86/kernel/timer.c index 83014daea..ac75fe85f 100644 --- a/elks/arch/i86/kernel/timer.c +++ b/elks/arch/i86/kernel/timer.c @@ -81,19 +81,20 @@ void timer_tick(int irq, struct pt_regs *regs) #ifdef CONFIG_CONSOLE_DIRECT /* spin timer wheel in upper right of screen*/ - if (spin_on && !(jiffies & 7)) { - static unsigned char wheel[4] = {'-', '\\', '|', '/'}; - static int c = 0; + // FIXME + // if (spin_on && !(jiffies & 7)) { + // static unsigned char wheel[4] = {'-', '\\', '|', '/'}; + // static int c = 0; - pokeb((79 + 0*80) * 2, VideoSeg, wheel[c++ & 0x03]); - } + // pokeb((79 + 0*80) * 2, VideoSeg, wheel[c++ & 0x03]); + // } #endif } void spin_timer(int onflag) { #ifdef CONFIG_CONSOLE_DIRECT - if ((spin_on = onflag) == 0) - pokeb((79 + 0*80) * 2, VideoSeg, ' '); + // if ((spin_on = onflag) == 0) + // pokeb((79 + 0*80) * 2, VideoSeg, ' '); #endif }