From b2d6d0c0b17015b5fb2f192ae8423882757e09cf Mon Sep 17 00:00:00 2001 From: Valtteri Koskivuori Date: Mon, 2 Sep 2024 20:34:45 +0300 Subject: [PATCH 1/7] [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..956d9587b 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_DISPLAYS 1 + +struct output; +typedef struct output Output; struct console; typedef struct console Console; struct console { + Output *display; 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 Width; + unsigned short MaxCol; + unsigned short Height; + unsigned short MaxRow; + Console *visible; + Console *glock; /* Which console owns the graphics hardware */ + struct wait_queue glock_wait; +}; + +static Output Outputs[MAX_DISPLAYS]; +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(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->display->visible) { bios_setpage(C->pageno); } bios_scroll (a, n, x, y, xx, yy); - if (C != Visible) { - bios_setpage(Visible->pageno); + if (C != C->display->visible) { + bios_setpage(C->display->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->display->MaxCol, C->display->MaxRow); } #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->display->MaxCol, C->display->MaxRow); } #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].display->visible == &Con[N]) || Con[N].display->glock) return; - Visible = &Con[N]; + Con[N].display->visible = &Con[N]; bios_setpage(N); - PositionCursor(Visible); + PositionCursor(Con[N].display->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->MaxCol = (O->Width = SETUP_VID_COLS) - 1; + O->MaxRow = (O->Height = 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->display = 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->display->MaxCol, C->display->MaxRow); */ 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->Width, O->Height, 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..5ae7e16fb 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_DISPLAYS 1 + +struct output; +typedef struct output Output; struct console; typedef struct console Console; struct console { + Output *display; 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 Width; + unsigned short MaxCol; + unsigned short Height; + unsigned short MaxRow; + struct wait_queue glock_wait; + Console *visible; + Console *glock; /* Which console owns the graphics hardware */ +}; + +static Output Outputs[MAX_DISPLAYS]; +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->display->Width * C->cy + C->basepage; cursor_set(Pos * 2); } -static void DisplayCursor(int onoff) +static void DisplayCursor(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->display->Width) << 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->display->Width) << 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->display->Width - 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->display->Width) << 1); + if ((unsigned int)y < C->display->MaxRow) { + fmemcpyb(vp, AttributeSeg, vp + C->display->Width, AttributeSeg, (C->display->MaxRow - y) * (C->display->Width << 1)); + fmemcpyb(vp, C->vseg, vp + C->display->Width, C->vseg, (C->display->MaxRow - y) * (C->display->Width << 1)); } - ClearRange(C, 0, MaxRow, MaxCol, MaxRow); + ClearRange(C, 0, C->display->MaxRow, C->display->MaxCol, C->display->MaxRow); } #ifdef CONFIG_EMUL_ANSI static void ScrollDown(register Console * C, int y) { register __u16 *vp; - int yy = MaxRow; + int yy = C->display->MaxRow; - vp = (__u16 *)((__u16)(yy * Width) << 1); + vp = (__u16 *)((__u16)(yy * C->display->Width) << 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->display->Width, AttributeSeg, C->display->Width << 1); + fmemcpyb(vp, C->vseg, vp - C->display->Width, C->vseg, C->display->Width << 1); + vp -= C->display->Width; } - ClearRange(C, 0, y, MaxCol, y); + ClearRange(C, 0, y, C->display->MaxCol, 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].display->visible == &Con[N]) || Con[N].display->glock) return; - Visible = &Con[N]; + Con[N].display->visible = &Con[N]; - SetDisplayPage(Visible); - PositionCursor(Visible); + SetDisplayPage(Con[N].display->visible); + PositionCursor(Con[N].display->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->MaxCol = (O->Width = 80) - 1; + O->MaxRow = (O->Height = 25) - 1; PageSizeW = 2000; NumConsoles = 1; C = Con; - Visible = C; for (i = 0; i < NumConsoles; i++) { + C->display = 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->Width, O->Height, NumConsoles); } diff --git a/elks/arch/i86/drivers/char/console-direct.c b/elks/arch/i86/drivers/char/console-direct.c index 32ab514ea..85c3af8b5 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_DISPLAYS 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 *display; 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 Width; + unsigned short MaxCol; + unsigned short Height; + unsigned short MaxRow; + 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_DISPLAYS]; +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->display->crtc_base); + outw((C->vseg_offset << 8) | 0x0d, C->display->crtc_base); } static void PositionCursor(register Console * C) { - unsigned int Pos = C->cx + Width * C->cy + C->basepage; + unsigned int Pos = C->cx + C->display->Width * C->cy + C->vseg_offset; - outb(14, CCBase); - outb(Pos >> 8, CCBase + 1); - outb(15, CCBase); - outb(Pos, CCBase + 1); + outb(14, C->display->crtc_base); + outb(Pos >> 8, C->display->crtc_base + 1); + outb(15, C->display->crtc_base); + outb(Pos, C->display->crtc_base + 1); } -static void DisplayCursor(int onoff) +static void DisplayCursor(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->display->type == OT_MDA ? 0x0b0c : (C->display->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->display->crtc_base); + outb(v >> 8, C->display->crtc_base + 1); + outb(11, C->display->crtc_base); + outb(v, C->display->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->display->Width) << 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->display->Width) << 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->display->Width - x2) << 1; } while (++y <= y2); } static void ScrollUp(register Console * C, int y) { register int vp; + int max_row = C->display->Height - 1; + int max_col = C->display->Width - 1; - vp = y * (Width << 1); - if ((unsigned int)y < MaxRow) + vp = y * (C->display->Width << 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->display->Width << 1)), C->vseg, (max_row - y) * C->display->Width); + 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->display->Height - 1; - vp = yy * (Width << 1); + vp = yy * (C->display->Width << 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->display->Width << 1)), C->vseg, C->display->Width); + vp -= C->display->Width << 1; } - ClearRange(C, 0, y, MaxCol, y); + ClearRange(C, 0, y, C->display->Width - 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].display->glock) return; - Visible = &Con[N]; + Con[N].display->visible = &Con[N]; - SetDisplayPage(Visible); - PositionCursor(Visible); + SetDisplayPage(Con[N].display->visible); + PositionCursor(Con[N].display->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->Width = p->w; + o->MaxCol = o->Width - 1; + o->Height = p->h; + o->MaxRow = o->Height - 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->display = 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->display = 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].display->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].Width, Outputs[i].Height); + } } diff --git a/elks/arch/i86/drivers/char/console.c b/elks/arch/i86/drivers/char/console.c index def587669..ca45f8e80 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->display->glock) { + if (C->display->glock == C) return; - sleep_on(&glock_wait); + sleep_on(&C->display->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->display->MaxCol) ? C->display->MaxCol : (xp < 0) ? 0 : xp; xp = y; - C->cy = (xp >= MaxRow) ? MaxRow : (xp < 0) ? 0 : xp; + C->cy = (xp >= C->display->MaxRow) ? C->display->MaxRow : (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->display->MaxRow) + C->cy = C->display->MaxRow; break; case 'd': /* Vertical position absolute */ C->cy = parm1(C->params) - 1; - if (C->cy > MaxRow) - C->cy = MaxRow; + if (C->cy > C->display->MaxRow) + C->cy = C->display->MaxRow; break; case 'C': /* Move right n characters */ C->cx += parm1(C->params); - if (C->cx > MaxCol) - C->cx = MaxCol; + if (C->cx > C->display->MaxCol) + C->cx = C->display->MaxCol; break; case 'G': /* Horizontal position absolute */ C->cx = parm1(C->params) - 1; - if (C->cx > MaxCol) - C->cx = MaxCol; + if (C->cx > C->display->MaxCol) + C->cx = C->display->MaxCol; 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->display->MaxCol, C->cy); + if (C->cy < C->display->MaxRow) + ClearRange(C, 0, C->cy, C->display->MaxCol, C->display->MaxRow); } else if (n == 2) /* all*/ - ClearRange(C, 0, 0, MaxCol, MaxRow); + ClearRange(C, 0, 0, C->display->MaxCol, C->display->MaxRow); 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->display->MaxCol, 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->display->MaxCol, 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->display->MaxRow) { ScrollUp(C, 0); - C->cy = MaxRow; + C->cy = C->display->MaxRow; } } #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->display->MaxCol) { C->XN = 1; - C->cx = MaxCol; + C->cx = C->display->MaxCol; } } - if (C->cy > MaxRow) { + if (C->cy > C->display->MaxRow) { ScrollUp(C, 0); - C->cy = MaxRow; + C->cy = C->display->MaxRow; } } @@ -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->display->glock) { + C->display->glock = C; return 0; } return -EBUSY; case DCREL_GRAPH: - if (glock == C) { - glock = NULL; - wake_up(&glock_wait); + if (C->display->glock == C) { + C->display->glock = NULL; + wake_up(&C->display->glock_wait); return 0; } break; case DCSET_KRAW: - if (glock == C) { + if (C->display->glock == C) { kraw = 1; return 0; } break; case DCREL_KRAW: - if ((glock == C) && (kraw == 1)) { + if ((C->display->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->display->glock) { WriteChar(C, tty_outproc(tty)); cnt++; } - if (C == Visible) + if (C == C->display->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 } From 8b5ef832f7ea4f9836d521e28d2bb4bdb7b93e2a Mon Sep 17 00:00:00 2001 From: Valtteri Koskivuori Date: Mon, 2 Sep 2024 20:54:47 +0300 Subject: [PATCH 2/7] [console+kbd+build] Add /dev/tty4 Since we can now have 4 consoles up at a time (1 on MDA + 3 on CGA), bump up the amount of ttys available. I think CGA could do 4 pages on its own too, but we have to draw the limit somewhere. 3+1 feels nice and even :] --- elks/arch/i86/drivers/char/console-direct.c | 2 +- elks/arch/i86/drivers/char/kbd-poll.c | 4 ++-- elks/arch/i86/drivers/char/kbd-scancode.c | 8 ++++---- elks/fs/msdos/inode.c | 1 + elks/include/linuxmt/devnum.h | 1 + elks/include/linuxmt/msdos_fs_sb.h | 2 +- elks/include/linuxmt/ntty.h | 2 +- elks/init/main.c | 1 + elkscmd/rootfs_template/bin/sys | 1 + elkscmd/rootfs_template/etc/inittab | 3 ++- image/Make.devices | 1 + libc/misc/devname.c | 1 + 12 files changed, 17 insertions(+), 10 deletions(-) diff --git a/elks/arch/i86/drivers/char/console-direct.c b/elks/arch/i86/drivers/char/console-direct.c index 85c3af8b5..e443b8858 100644 --- a/elks/arch/i86/drivers/char/console-direct.c +++ b/elks/arch/i86/drivers/char/console-direct.c @@ -105,7 +105,7 @@ static struct hw_params params[N_DEVICETYPES] = { 0x1F, 0x06, 0x19, 0x1C, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, - }, 16, 2, 2000 + }, 16, 3, 2000 }, /* CGA */ // TODO //{ 0 }, /* EGA */ diff --git a/elks/arch/i86/drivers/char/kbd-poll.c b/elks/arch/i86/drivers/char/kbd-poll.c index be3e3ce17..6c8bcc1ae 100644 --- a/elks/arch/i86/drivers/char/kbd-poll.c +++ b/elks/arch/i86/drivers/char/kbd-poll.c @@ -28,11 +28,11 @@ static void kbd_timer(int data) else { dav = (dav >> 8) & 0xFF; #ifndef CONFIG_CONSOLE_HEADLESS - if (dav >= 0x3B && dav <= 0x3D) { /* temp console switch on F1-F3*/ + if (dav >= 0x3B && dav <= 0x3E) { /* temp console switch on F1-F4*/ Console_set_vc(dav - 0x3B); dav = 0; } - else if ((dav >= 0x68) && (dav < 0x6B)) { /* Change VC */ + else if ((dav >= 0x68) && (dav < 0x6C)) { /* Change VC */ Console_set_vc(dav - 0x68); dav = 0; } diff --git a/elks/arch/i86/drivers/char/kbd-scancode.c b/elks/arch/i86/drivers/char/kbd-scancode.c index 9a4d23096..4782be4e0 100644 --- a/elks/arch/i86/drivers/char/kbd-scancode.c +++ b/elks/arch/i86/drivers/char/kbd-scancode.c @@ -275,8 +275,8 @@ static void keyboard_irq(int irq, struct pt_regs *regs) /* F11 and F12 function keys need 89 byte table like keys-de.h */ /* function keys are not posix standard here */ - /* AltF1-F3 are console switch*/ - if ((ModeState & ALT) && code <= SCAN_F1+2) { + /* AltF1-F4 are console switch*/ + if ((ModeState & ALT) && code <= SCAN_F1+3) { Console_set_vc(code - SCAN_F1); return; } @@ -354,8 +354,8 @@ static void keyboard_irq(int irq, struct pt_regs *regs) /* Step 6: Modify keyboard character based on some special states*/ if ((ModeState & (CTRL|ALT)) == ALT) { - /* Alt-1 - Alt-3 are also console switch (for systems w/no fnkeys)*/ - if (key >= '1' && key <= '3') { + /* Alt-1 - Alt-4 are also console switch (for systems w/no fnkeys)*/ + if (key >= '1' && key <= '4') { Console_set_vc(key - '1'); return; } diff --git a/elks/fs/msdos/inode.c b/elks/fs/msdos/inode.c index 152184c77..9d621ea65 100644 --- a/elks/fs/msdos/inode.c +++ b/elks/fs/msdos/inode.c @@ -51,6 +51,7 @@ struct msdos_devdir_entry devnods[DEVDIR_SIZE] = { { "tty1", S_IFCHR | 0644, MKDEV(TTY_MAJOR, 0) }, { "tty2", S_IFCHR | 0644, MKDEV(TTY_MAJOR, 1) }, { "tty3", S_IFCHR | 0644, MKDEV(TTY_MAJOR, 2) }, + { "tty4", S_IFCHR | 0644, MKDEV(TTY_MAJOR, 3) }, { "ttyS0", S_IFCHR | 0644, MKDEV(TTY_MAJOR, 64) }, { "ttyS1", S_IFCHR | 0644, MKDEV(TTY_MAJOR, 65) }, { "console",S_IFCHR | 0600, MKDEV(TTY_MAJOR, 254) }, diff --git a/elks/include/linuxmt/devnum.h b/elks/include/linuxmt/devnum.h index 1fc116a80..927cc6a9f 100644 --- a/elks/include/linuxmt/devnum.h +++ b/elks/include/linuxmt/devnum.h @@ -27,6 +27,7 @@ #define DEV_TTY1 MKDEV(TTY_MAJOR, 0) #define DEV_TTY2 MKDEV(TTY_MAJOR, 1) #define DEV_TTY3 MKDEV(TTY_MAJOR, 2) +#define DEV_TTY4 MKDEV(TTY_MAJOR, 3) #define DEV_TTYS0 MKDEV(TTY_MAJOR, 64) #define DEV_TTYS1 MKDEV(TTY_MAJOR, 65) diff --git a/elks/include/linuxmt/msdos_fs_sb.h b/elks/include/linuxmt/msdos_fs_sb.h index dba509577..09876f40b 100644 --- a/elks/include/linuxmt/msdos_fs_sb.h +++ b/elks/include/linuxmt/msdos_fs_sb.h @@ -45,7 +45,7 @@ struct msdos_sb_info { /* space in struct super_block is 28 bytes */ #endif #ifdef CONFIG_FS_DEV -#define DEVDIR_SIZE 44 /* # entries in FAT device table */ +#define DEVDIR_SIZE 45 /* # entries in FAT device table */ #define DEVINO_BASE (MSDOS_DPB*2) /* (DEVDIR_SIZE+MSDOS_DBP-1) & ~(MSDOS_DBP-1) */ struct msdos_devdir_entry { diff --git a/elks/include/linuxmt/ntty.h b/elks/include/linuxmt/ntty.h index 3d7f40a02..c918d0a05 100644 --- a/elks/include/linuxmt/ntty.h +++ b/elks/include/linuxmt/ntty.h @@ -23,7 +23,7 @@ /* Predefined maximum number of tty character devices */ -#define MAX_CONSOLES 3 +#define MAX_CONSOLES 4 #define MAX_PTYS 4 #define TTY_MINOR_OFFSET 0 diff --git a/elks/init/main.c b/elks/init/main.c index 62aaa9131..4905a6857 100644 --- a/elks/init/main.c +++ b/elks/init/main.c @@ -314,6 +314,7 @@ static struct dev_name_struct { { "tty1", DEV_TTY1 }, { "tty2", DEV_TTY2 }, { "tty3", DEV_TTY3 }, + { "tty4", DEV_TTY4 }, { NULL, 0 } }; diff --git a/elkscmd/rootfs_template/bin/sys b/elkscmd/rootfs_template/bin/sys index 7f78d6af2..b13a0dbea 100755 --- a/elkscmd/rootfs_template/bin/sys +++ b/elkscmd/rootfs_template/bin/sys @@ -54,6 +54,7 @@ create_dev_dir() mknod $MNT/dev/rd1 b 1 1 mknod $MNT/dev/tty2 c 4 1 mknod $MNT/dev/tty3 c 4 2 + mknod $MNT/dev/tty4 c 4 3 mknod $MNT/dev/ttyS2 c 4 66 mknod $MNT/dev/ttyS3 c 4 67 mknod $MNT/dev/ttyp1 c 4 9 diff --git a/elkscmd/rootfs_template/etc/inittab b/elkscmd/rootfs_template/etc/inittab index 5ffffa1e4..355ea5c54 100644 --- a/elkscmd/rootfs_template/etc/inittab +++ b/elkscmd/rootfs_template/etc/inittab @@ -10,10 +10,11 @@ si::sysinit:/etc/rc.sys # 2 single user ttyS0 only # 3 multiuser tty1 and ttyS0 # 4 multiuser serial only (ttyS0,ttyS1) -# 5 multiuser console only (tty1,tty2,tty3) +# 5 multiuser console only (tty1,tty2,tty3,tty4) # 6 multiuser console and serial t1:1356:respawn:/bin/getty /dev/tty1 t2:56:respawn:/bin/getty /dev/tty2 t3:56:respawn:/bin/getty /dev/tty3 +t4:56:respawn:/bin/getty /dev/tty4 s0:2346:respawn:/bin/getty /dev/ttyS0 s1:46:respawn:/bin/getty /dev/ttyS1 9600 diff --git a/image/Make.devices b/image/Make.devices index 4146f3421..674f0f72a 100755 --- a/image/Make.devices +++ b/image/Make.devices @@ -86,6 +86,7 @@ devices: $(MKDEV) /dev/tty1 c 4 0 $(MKDEV) /dev/tty2 c 4 1 $(MKDEV) /dev/tty3 c 4 2 + $(MKDEV) /dev/tty4 c 4 3 # Pseudo-TTY slave devices. diff --git a/libc/misc/devname.c b/libc/misc/devname.c index 7c9c7988b..57507f636 100644 --- a/libc/misc/devname.c +++ b/libc/misc/devname.c @@ -38,6 +38,7 @@ static struct dev_name_struct { { "tty1", S_IFCHR, DEV_TTY1 }, { "tty2", S_IFCHR, DEV_TTY2 }, { "tty3", S_IFCHR, DEV_TTY3 }, + { "tty4", S_IFCHR, DEV_TTY4 }, }; static char *__fast_devname(dev_t dev, mode_t type) From 5d7826837b9565d5ec4f6d7a702727fbf7f13087 Mon Sep 17 00:00:00 2001 From: Valtteri Koskivuori Date: Sat, 7 Sep 2024 18:59:53 +0300 Subject: [PATCH 3/7] [console] Remove output struct to reduce indirection The init logic in console-direct was much reduced, too. We also now test vram before enabling a card before clearing it, to ensure it's all there. --- elks/arch/i86/drivers/char/console-bios.c | 48 ++-- .../i86/drivers/char/console-direct-pc98.c | 79 +++---- elks/arch/i86/drivers/char/console-direct.c | 222 ++++++++---------- elks/arch/i86/drivers/char/console.c | 68 +++--- 4 files changed, 182 insertions(+), 235 deletions(-) diff --git a/elks/arch/i86/drivers/char/console-bios.c b/elks/arch/i86/drivers/char/console-bios.c index 956d9587b..65bfea9f6 100644 --- a/elks/arch/i86/drivers/char/console-bios.c +++ b/elks/arch/i86/drivers/char/console-bios.c @@ -43,15 +43,13 @@ #define MAX_DISPLAYS 1 -struct output; -typedef struct output Output; struct console; typedef struct console Console; struct console { - Output *display; int cx, cy; /* cursor position */ void (*fsm)(Console *, int); + unsigned char display; unsigned char attr; /* current attribute */ unsigned char XN; /* delayed newline on column 80 */ unsigned char color; /* fg/bg attr */ @@ -61,19 +59,15 @@ struct console { unsigned char *parmptr; /* ptr to params */ unsigned char params[MAXPARMS]; /* ANSI params */ #endif -}; - -struct output { unsigned short Width; unsigned short MaxCol; unsigned short Height; unsigned short MaxRow; - Console *visible; - Console *glock; /* Which console owns the graphics hardware */ - struct wait_queue glock_wait; }; -static Output Outputs[MAX_DISPLAYS]; +static Console *glock[MAX_DISPLAYS]; +static struct wait_queue glock_wait[MAX_DISPLAYS]; +static Console *Visible[MAX_DISPLAYS]; static Console Con[MAX_CONSOLES]; static int NumConsoles = MAX_CONSOLES; static int kraw; @@ -124,14 +118,14 @@ static void scroll(register Console * C, int n, int x, int y, int xx, int yy) int a; a = C->attr; - if (C != C->display->visible) { + if (C != Visible[C->display]) { bios_setpage(C->pageno); } bios_scroll (a, n, x, y, xx, yy); - if (C != C->display->visible) { - bios_setpage(C->display->visible->pageno); + if (C != Visible[C->display]) { + bios_setpage(Visible[C->display]->pageno); } } @@ -142,13 +136,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, C->display->MaxCol, C->display->MaxRow); + scroll(C, 1, 0, y, C->MaxCol, C->MaxRow); } #ifdef CONFIG_EMUL_ANSI static void ScrollDown(register Console * C, int y) { - scroll(C, -1, 0, y, C->display->MaxCol, C->display->MaxRow); + scroll(C, -1, 0, y, C->MaxCol, C->MaxRow); } #endif @@ -161,12 +155,13 @@ static void ScrollDown(register Console * C, int y) void Console_set_vc(int N) { - if ((N >= NumConsoles) || (Con[N].display->visible == &Con[N]) || Con[N].display->glock) + Console *C = &Con[N]; + if ((N >= NumConsoles) || (Visible[C->display] == C) || glock[C->display]) return; - Con[N].display->visible = &Con[N]; + Visible[C->display] = C; bios_setpage(N); - PositionCursor(Con[N].display->visible); + PositionCursor(Visible[C->display]); Current_VCminor = N; } @@ -182,23 +177,20 @@ struct tty_ops bioscon_ops = { void INITPROC console_init(void) { Console *C; - Output *O; int i; - O = &Outputs[0]; - O->MaxCol = (O->Width = SETUP_VID_COLS) - 1; - O->MaxRow = (O->Height = SETUP_VID_LINES) - 1; + C = Con; + C->MaxCol = (C->Width = SETUP_VID_COLS) - 1; + C->MaxRow = (C->Height = SETUP_VID_LINES) - 1; if (peekb(0x49, 0x40) == 7) /* BIOS data segment */ NumConsoles = 1; - C = Con; - for (i = 0; i < NumConsoles; i++) { - C->display = O; + C->display = 0; C->cx = C->cy = 0; if (!i) { - O->visible = C; + Visible[C->display] = C; // Get current cursor position // to write after boot messages PositionCursorGet (&C->cx, &C->cy); @@ -215,7 +207,7 @@ void INITPROC console_init(void) #endif /* Do not erase early printk() */ - /* ClearRange(C, 0, C->cy, C->display->MaxCol, C->display->MaxRow); */ + /* ClearRange(C, 0, C->cy, C->MaxCol, C->MaxRow); */ C++; } @@ -223,5 +215,5 @@ void INITPROC console_init(void) kbd_init(); printk("BIOS console %ux%u"TERM_TYPE"(%d virtual consoles)\n", - O->Width, O->Height, NumConsoles); + Con[0].Width, Con[0].Height, NumConsoles); } diff --git a/elks/arch/i86/drivers/char/console-direct-pc98.c b/elks/arch/i86/drivers/char/console-direct-pc98.c index 5ae7e16fb..7e56c2ff9 100644 --- a/elks/arch/i86/drivers/char/console-direct-pc98.c +++ b/elks/arch/i86/drivers/char/console-direct-pc98.c @@ -50,37 +50,31 @@ #define MAX_DISPLAYS 1 -struct output; -typedef struct output Output; struct console; typedef struct console Console; struct console { - Output *display; + unsigned char display; 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; /* vram for this console page */ + int vseg_offset; /* vram offset of vseg for this console page */ #ifdef CONFIG_EMUL_ANSI int savex, savey; /* saved cursor position */ unsigned char *parmptr; /* ptr to params */ unsigned char params[MAXPARMS]; /* ANSI params */ #endif -}; - -struct output { unsigned short Width; unsigned short MaxCol; unsigned short Height; unsigned short MaxRow; - struct wait_queue glock_wait; - Console *visible; - Console *glock; /* Which console owns the graphics hardware */ }; -static Output Outputs[MAX_DISPLAYS]; +static Console *glock[MAX_DISPLAYS]; +static struct wait_queue glock_wait[MAX_DISPLAYS]; +static Console *Visible[MAX_DISPLAYS]; static Console Con[MAX_CONSOLES]; static int NumConsoles = MAX_CONSOLES; @@ -105,7 +99,7 @@ static void PositionCursor(register Console * C) { int Pos; - Pos = C->cx + C->display->Width * C->cy + C->basepage; + Pos = C->cx + C->Width * C->cy + C->vseg_offset; cursor_set(Pos * 2); } @@ -143,7 +137,7 @@ static void VideoWrite(register Console * C, int c) word_t addr; word_t attr; - addr = (C->cx + C->cy * C->display->Width) << 1; + addr = (C->cx + C->cy * C->Width) << 1; attr = (C->attr == A_DEFAULT) ? A98_DEFAULT : conv_pcattr(C->attr); pokew(addr, (seg_t) AttributeSeg, attr); @@ -158,13 +152,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 * C->display->Width) << 1); + vp = (__u16 *)((__u16)(x + y * C->Width) << 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 += (C->display->Width - xx); + vp += (C->Width - xx); } while (++y <= yy); } @@ -172,27 +166,27 @@ static void ScrollUp(register Console * C, int y) { register __u16 *vp; - vp = (__u16 *)((__u16)(y * C->display->Width) << 1); - if ((unsigned int)y < C->display->MaxRow) { - fmemcpyb(vp, AttributeSeg, vp + C->display->Width, AttributeSeg, (C->display->MaxRow - y) * (C->display->Width << 1)); - fmemcpyb(vp, C->vseg, vp + C->display->Width, C->vseg, (C->display->MaxRow - y) * (C->display->Width << 1)); + vp = (__u16 *)((__u16)(y * C->Width) << 1); + if ((unsigned int)y < C->MaxRow) { + fmemcpyb(vp, AttributeSeg, vp + C->Width, AttributeSeg, (C->MaxRow - y) * (C->Width << 1)); + fmemcpyb(vp, C->vseg, vp + C->Width, C->vseg, (C->MaxRow - y) * (C->Width << 1)); } - ClearRange(C, 0, C->display->MaxRow, C->display->MaxCol, C->display->MaxRow); + ClearRange(C, 0, C->MaxRow, C->MaxCol, C->MaxRow); } #ifdef CONFIG_EMUL_ANSI static void ScrollDown(register Console * C, int y) { register __u16 *vp; - int yy = C->display->MaxRow; + int yy = C->MaxRow; - vp = (__u16 *)((__u16)(yy * C->display->Width) << 1); + vp = (__u16 *)((__u16)(yy * C->Width) << 1); while (--yy >= y) { - fmemcpyb(vp, AttributeSeg, vp - C->display->Width, AttributeSeg, C->display->Width << 1); - fmemcpyb(vp, C->vseg, vp - C->display->Width, C->vseg, C->display->Width << 1); - vp -= C->display->Width; + fmemcpyb(vp, AttributeSeg, vp - C->Width, AttributeSeg, C->Width << 1); + fmemcpyb(vp, C->vseg, vp - C->Width, C->vseg, C->Width << 1); + vp -= C->Width; } - ClearRange(C, 0, y, C->display->MaxCol, y); + ClearRange(C, 0, y, C->MaxCol, y); } #endif @@ -205,12 +199,12 @@ static void ScrollDown(register Console * C, int y) void Console_set_vc(int N) { - if ((N >= NumConsoles) || (Con[N].display->visible == &Con[N]) || Con[N].display->glock) - return; - Con[N].display->visible = &Con[N]; - - SetDisplayPage(Con[N].display->visible); - PositionCursor(Con[N].display->visible); + Console *C = &Con[N]; + if ((N >= NumConsoles) || (Visible[C->display] == C) || glock[C->display]) + return; + Visible[C->display] = C; + SetDisplayPage(Visible[C->display]); + PositionCursor(Visible[C->display]); Current_VCminor = N; } @@ -226,7 +220,6 @@ struct tty_ops dircon_ops = { void INITPROC console_init(void) { Console *C; - Output *O; int i; unsigned PageSizeW; @@ -238,27 +231,25 @@ void INITPROC console_init(void) AttributeSeg = 0xE200; } - O = &Outputs[0]; - O->MaxCol = (O->Width = 80) - 1; - O->MaxRow = (O->Height = 25) - 1; + C = Con; + C->MaxCol = (C->Width = 80) - 1; + C->MaxRow = (C->Height = 25) - 1; PageSizeW = 2000; NumConsoles = 1; - C = Con; - for (i = 0; i < NumConsoles; i++) { - C->display = O; + C->display = 0; C->cx = C->cy = 0; if (!i) { - O->visible = C; + Visible[C->display] = C; C->cx = read_tvram_x() % 160; C->cy = read_tvram_x() / 160; } C->fsm = std_char; - C->basepage = i * PageSizeW; - C->vseg = VideoSeg + (C->basepage >> 3); + C->vseg_offset = i * PageSizeW; + C->vseg = VideoSeg + (C->vseg_offset >> 3); C->attr = A_DEFAULT; #ifdef CONFIG_EMUL_ANSI @@ -276,5 +267,5 @@ void INITPROC console_init(void) kbd_init(); printk("Direct console, %s kbd %ux%u"TERM_TYPE"(du virtual consoles)\n", - kbd_name, O->Width, O->Height, NumConsoles); + kbd_name, Con[0].Width, Con[0].Height, NumConsoles); } diff --git a/elks/arch/i86/drivers/char/console-direct.c b/elks/arch/i86/drivers/char/console-direct.c index e443b8858..8f4581e8a 100644 --- a/elks/arch/i86/drivers/char/console-direct.c +++ b/elks/arch/i86/drivers/char/console-direct.c @@ -31,6 +31,8 @@ #define A_REVERSE 0x70 #define A_BLANK 0x00 +#define CONFIG_CONSOLE_DUAL + #define CRTC_INDX 0x0 #define CRTC_DATA 0x1 #define CRTC_MODE 0x4 @@ -63,18 +65,24 @@ enum OutputType { }; struct console { - Output *display; + unsigned char display; 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 TODO: Could we compute this from vseg_base + vseg_offset? */ - int vseg_offset; /* start of vram for this console */ + unsigned int vseg; /* vram for this console page */ + int vseg_offset; /* vram offset of vseg for this console page */ #ifdef CONFIG_EMUL_ANSI int savex, savey; /* saved cursor position */ unsigned char *parmptr; /* ptr to params */ unsigned char params[MAXPARMS]; /* ANSI params */ #endif + enum OutputType type; + unsigned short Width; + unsigned short MaxCol; + unsigned short Height; + unsigned short MaxRow; + unsigned short crtc_base; /* 6845 CRTC base I/O address */ }; struct hw_params { @@ -87,6 +95,7 @@ struct hw_params { unsigned char n_init_bytes; unsigned char max_pages; unsigned short page_words; + unsigned char is_present; }; static struct hw_params params[N_DEVICETYPES] = { @@ -96,7 +105,7 @@ static struct hw_params params[N_DEVICETYPES] = { 0x19, 0x06, 0x19, 0x19, 0x02, 0x0D, 0x0B, 0x0C, 0x00, 0x00, 0x00, 0x00, - }, 16, 1, 2000 + }, 16, 1, 2000, 0 }, /* MDA */ { 80, 25, 0x3D4, 0xB800, 0x4000, { @@ -105,31 +114,17 @@ static struct hw_params params[N_DEVICETYPES] = { 0x1F, 0x06, 0x19, 0x1C, 0x02, 0x07, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, - }, 16, 3, 2000 + }, 16, 3, 2000, 0 }, /* CGA */ // TODO //{ 0 }, /* EGA */ //{ 0 }, /* VGA */ }; -struct output { - enum OutputType type; - unsigned short Width; - unsigned short MaxCol; - unsigned short Height; - unsigned short MaxRow; - 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_DISPLAYS]; +static Console *glock[MAX_DISPLAYS]; +static struct wait_queue glock_wait[MAX_DISPLAYS]; +static Console *Visible[MAX_DISPLAYS]; 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; @@ -145,18 +140,18 @@ static void std_char(register Console *, int); static void SetDisplayPage(register Console * C) { - outw((C->vseg_offset & 0xff00) | 0x0c, C->display->crtc_base); - outw((C->vseg_offset << 8) | 0x0d, C->display->crtc_base); + outw((C->vseg_offset & 0xff00) | 0x0c, C->crtc_base); + outw((C->vseg_offset << 8) | 0x0d, C->crtc_base); } static void PositionCursor(register Console * C) { - unsigned int Pos = C->cx + C->display->Width * C->cy + C->vseg_offset; + unsigned int Pos = C->cx + C->Width * C->cy + C->vseg_offset; - outb(14, C->display->crtc_base); - outb(Pos >> 8, C->display->crtc_base + 1); - outb(15, C->display->crtc_base); - outb(Pos, C->display->crtc_base + 1); + outb(14, C->crtc_base); + outb(Pos >> 8, C->crtc_base + 1); + outb(15, C->crtc_base); + outb(Pos, C->crtc_base + 1); } static void DisplayCursor(Console * C, int onoff) @@ -165,18 +160,18 @@ static void DisplayCursor(Console * C, int onoff) unsigned int v; if (onoff) - v = C->display->type == OT_MDA ? 0x0b0c : (C->display->type == OT_CGA ? 0x0607: 0x0d0e); + v = C->type == OT_MDA ? 0x0b0c : (C->type == OT_CGA ? 0x0607: 0x0d0e); else v = 0x2000; - outb(10, C->display->crtc_base); - outb(v >> 8, C->display->crtc_base + 1); - outb(11, C->display->crtc_base); - outb(v, C->display->crtc_base + 1); + outb(10, C->crtc_base); + outb(v >> 8, C->crtc_base + 1); + outb(11, C->crtc_base); + outb(v, C->crtc_base + 1); } static void VideoWrite(register Console * C, int c) { - pokew((C->cx + C->cy * C->display->Width) << 1, (seg_t) C->vseg, + pokew((C->cx + C->cy * C->Width) << 1, (seg_t) C->vseg, (C->attr << 8) | (c & 255)); } @@ -185,41 +180,39 @@ static void ClearRange(register Console * C, int x, int y, int x2, int y2) register int vp; x2 = x2 - x + 1; - vp = (x + y * C->display->Width) << 1; + vp = (x + y * C->Width) << 1; do { for (x = 0; x < x2; x++) { pokew(vp, (seg_t) C->vseg, (C->attr << 8) | ' '); vp += 2; } - vp += (C->display->Width - x2) << 1; + vp += (C->Width - x2) << 1; } while (++y <= y2); } static void ScrollUp(register Console * C, int y) { register int vp; - int max_row = C->display->Height - 1; - int max_col = C->display->Width - 1; - vp = y * (C->display->Width << 1); - if ((unsigned int)y < max_row) + vp = y * (C->Width << 1); + if ((unsigned int)y < C->MaxRow) fmemcpyw((void *)vp, C->vseg, - (void *)(vp + (C->display->Width << 1)), C->vseg, (max_row - y) * C->display->Width); - ClearRange(C, 0, max_row, max_col, max_row); + (void *)(vp + (C->Width << 1)), C->vseg, (C->MaxRow - y) * C->Width); + ClearRange(C, 0, C->MaxRow, C->MaxCol, C->MaxRow); } #ifdef CONFIG_EMUL_ANSI static void ScrollDown(register Console * C, int y) { register int vp; - int yy = C->display->Height - 1; + int yy = C->Height - 1; - vp = yy * (C->display->Width << 1); + vp = yy * (C->Width << 1); while (--yy >= y) { - fmemcpyw((void *)vp, C->vseg, (void *)(vp - (C->display->Width << 1)), C->vseg, C->display->Width); - vp -= C->display->Width << 1; + fmemcpyw((void *)vp, C->vseg, (void *)(vp - (C->Width << 1)), C->vseg, C->Width); + vp -= C->Width << 1; } - ClearRange(C, 0, y, C->display->Width - 1, y); + ClearRange(C, 0, y, C->Width - 1, y); } #endif @@ -232,12 +225,13 @@ static void ScrollDown(register Console * C, int y) void Console_set_vc(int N) { - if ((N >= NumConsoles) || Con[N].display->glock) + Console *C = &Con[N]; + if ((N >= NumConsoles) || glock[N]) return; - Con[N].display->visible = &Con[N]; - SetDisplayPage(Con[N].display->visible); - PositionCursor(Con[N].display->visible); + Visible[C->display] = C; + SetDisplayPage(C); + PositionCursor(C); DisplayCursor(&Con[Current_VCminor], 0); Current_VCminor = N; DisplayCursor(&Con[Current_VCminor], 1); @@ -274,29 +268,29 @@ static char probe_crtc(unsigned short crtc_base) return 1; } -static void init_output(Output *o) +static int init_output(enum OutputType t) { int i; - struct hw_params *p = ¶ms[o->type]; - o->Width = p->w; - o->MaxCol = o->Width - 1; - o->Height = p->h; - o->MaxRow = o->Height - 1; - o->vseg_base = p->vseg_base; + struct hw_params *p = ¶ms[t]; /* Set 80x25 mode, video off */ - outb(0x01, o->crtc_base + CRTC_MODE); + outb(0x01, p->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); + outb(i, p->crtc_base + CRTC_INDX); + outb(p->init_bytes[i], p->crtc_base + CRTC_DATA); } - /* Clear vram */ + /* Check & clear vram */ + for (i = 0; i < p->vseg_bytes; i += 2) + pokew(i, p->vseg_base, 0x5555); for (i = 0; i < p->vseg_bytes; i += 2) - pokew(i, o->vseg_base, 0x7 << 8 | ' '); + if (peekw(i, p->vseg_base) != 0x5555) return 1; + for (i = 0; i < p->vseg_bytes; i += 2) + pokew(i, p->vseg_base, 0x7 << 8 | ' '); /* Enable video */ - outb(0x09, o->crtc_base + CRTC_MODE); + outb(0x09, p->crtc_base + CRTC_MODE); + return 0; } static const char *type_string(enum OutputType t) @@ -312,84 +306,54 @@ static const char *type_string(enum OutputType t) void INITPROC console_init(void) { Console *C; - Output *O; - int i; - int screens; + int i, j, dev; 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 */ + enum OutputType boot_type; + unsigned char screens = 0; + unsigned char cur_display = 0; 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->vseg_offset = i * params[O->type].page_words; - C->vseg = params[O->type].vseg_base + (C->vseg_offset >> 3); - C->attr = A_DEFAULT; - C->display = O; -#ifdef CONFIG_EMUL_ANSI - C->savex = C->savey = 0; -#endif + if (params[i].crtc_base == boot_crtc) boot_type = i; - NumConsoles++; - O->consoles[O->n_consoles++] = C++; - } - // FIXME: Remove dumb duplication - - /* Now connect the rest up */ + C = &Con[0]; 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) { + dev = (i + boot_type) % N_DEVICETYPES; + if (!probe_crtc(params[dev].crtc_base)) continue; + params[dev].is_present = 1; + screens++; + init_output(dev); + for (j = 0; j < params[dev].max_pages; ++j) { C->cx = C->cy = 0; - if (!i) { - O->visible = C; + C->display = cur_display; + if (!j) Visible[C->display] = C; + if (!j && !i) { + C->cx = peekb(0x50, 0x40); + C->cy = peekb(0x51, 0x40); } 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->vseg_offset = j * params[dev].page_words; + C->vseg = params[dev].vseg_base + (C->vseg_offset >> 3); C->attr = A_DEFAULT; - C->display = O; - #ifdef CONFIG_EMUL_ANSI + C->type = dev; + C->Width = params[dev].w; + C->MaxCol = C->Width - 1; + C->Height = params[dev].h; + C->MaxRow = C->Height - 1; + C->crtc_base = params[dev].crtc_base; +#ifdef CONFIG_EMUL_ANSI C->savex = C->savey = 0; - #endif - - DisplayCursor(C, 0); +#endif NumConsoles++; - O->consoles[O->n_consoles++] = C++; + if (i) DisplayCursor(C, 0); + C++; } + cur_display++; } - screens = 0; - for (i = 0; i < N_DEVICETYPES; ++i) - if (Outputs[i].crtc_base) screens++; + kbd_init(); - printk("boot_crtc: %x\n", Con[0].display->crtc_base); + printk("boot_crtc: %x\n", Con[0].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].Width, Outputs[i].Height); + for (i = 0; i < NumConsoles; ++i) { + printk("/dev/tty%i, %s, %ux%u\n", i + 1, type_string(Con[i].type), Con[i].Width, Con[i].Height); } } diff --git a/elks/arch/i86/drivers/char/console.c b/elks/arch/i86/drivers/char/console.c index ca45f8e80..2b9303cff 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 (C->display->glock) { - if (C->display->glock == C) + while (glock[C->display]) { + if (glock[C->display] == C) return; - sleep_on(&C->display->glock_wait); + sleep_on(&glock_wait[C->display]); } 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 >= C->display->MaxCol) ? C->display->MaxCol : (xp < 0) ? 0 : xp; + C->cx = (xp >= C->MaxCol) ? C->MaxCol : (xp < 0) ? 0 : xp; xp = y; - C->cy = (xp >= C->display->MaxRow) ? C->display->MaxRow : (xp < 0) ? 0 : xp; + C->cy = (xp >= C->MaxRow) ? C->MaxRow : (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 > C->display->MaxRow) - C->cy = C->display->MaxRow; + if (C->cy > C->MaxRow) + C->cy = C->MaxRow; break; case 'd': /* Vertical position absolute */ C->cy = parm1(C->params) - 1; - if (C->cy > C->display->MaxRow) - C->cy = C->display->MaxRow; + if (C->cy > C->MaxRow) + C->cy = C->MaxRow; break; case 'C': /* Move right n characters */ C->cx += parm1(C->params); - if (C->cx > C->display->MaxCol) - C->cx = C->display->MaxCol; + if (C->cx > C->MaxCol) + C->cx = C->MaxCol; break; case 'G': /* Horizontal position absolute */ C->cx = parm1(C->params) - 1; - if (C->cx > C->display->MaxCol) - C->cx = C->display->MaxCol; + if (C->cx > C->MaxCol) + C->cx = C->MaxCol; 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, C->display->MaxCol, C->cy); - if (C->cy < C->display->MaxRow) - ClearRange(C, 0, C->cy, C->display->MaxCol, C->display->MaxRow); + ClearRange(C, C->cx, C->cy, C->MaxCol, C->cy); + if (C->cy < C->MaxRow) + ClearRange(C, 0, C->cy, C->MaxCol, C->MaxRow); } else if (n == 2) /* all*/ - ClearRange(C, 0, 0, C->display->MaxCol, C->display->MaxRow); + ClearRange(C, 0, 0, C->MaxCol, C->MaxRow); break; case 'K': /* clear line */ n = atoi((char *)C->params); if (n == 0) /* to EOL */ - ClearRange(C, C->cx, C->cy, C->display->MaxCol, C->cy); + ClearRange(C, C->cx, C->cy, C->MaxCol, 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, C->display->MaxCol, C->cy); + ClearRange(C, 0, C->cy, C->MaxCol, C->cy); break; case 'L': /* insert line */ ScrollDown(C, C->cy); @@ -287,9 +287,9 @@ static void std_char(register Console * C, int c) C->XN = 0; C->cx = 0; C->cy++; - if (C->cy > C->display->MaxRow) { + if (C->cy > C->MaxRow) { ScrollUp(C, 0); - C->cy = C->display->MaxRow; + C->cy = C->MaxRow; } } #ifdef CONFIG_CONSOLE_BIOS @@ -300,14 +300,14 @@ static void std_char(register Console * C, int c) C->cx++; } linewrap: - if (C->cx > C->display->MaxCol) { + if (C->cx > C->MaxCol) { C->XN = 1; - C->cx = C->display->MaxCol; + C->cx = C->MaxCol; } } - if (C->cy > C->display->MaxRow) { + if (C->cy > C->MaxRow) { ScrollUp(C, 0); - C->cy = C->display->MaxRow; + C->cy = C->MaxRow; } } @@ -317,26 +317,26 @@ static int Console_ioctl(struct tty *tty, int cmd, char *arg) switch (cmd) { case DCGET_GRAPH: - if (!C->display->glock) { - C->display->glock = C; + if (!glock[C->display]) { + glock[C->display] = C; return 0; } return -EBUSY; case DCREL_GRAPH: - if (C->display->glock == C) { - C->display->glock = NULL; - wake_up(&C->display->glock_wait); + if (glock[C->display] == C) { + glock[C->display] = NULL; + wake_up(&glock_wait[C->display]); return 0; } break; case DCSET_KRAW: - if (C->display->glock == C) { + if (glock[C->display] == C) { kraw = 1; return 0; } break; case DCREL_KRAW: - if ((C->display->glock == C) && (kraw == 1)) { + if ((glock[C->display] == 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) && !C->display->glock) { + while ((tty->outq.len > 0) && !glock[C->display]) { WriteChar(C, tty_outproc(tty)); cnt++; } - if (C == C->display->visible) + if (C == Visible[C->display]) PositionCursor(C); return cnt; } From d72fa5eebc0cffc3e3310ce9fc68551f02122ef1 Mon Sep 17 00:00:00 2001 From: Valtteri Koskivuori Date: Sun, 8 Sep 2024 01:40:28 +0300 Subject: [PATCH 4/7] [console] Incorporate further feedback - Moved struct members for better alignment - Replaced enum with #define - Removed type_string() function --- elks/arch/i86/drivers/char/console-bios.c | 14 ++--- .../i86/drivers/char/console-direct-pc98.c | 16 ++--- elks/arch/i86/drivers/char/console-direct.c | 58 +++++++++---------- elks/arch/i86/drivers/char/console.c | 22 +++---- 4 files changed, 54 insertions(+), 56 deletions(-) diff --git a/elks/arch/i86/drivers/char/console-bios.c b/elks/arch/i86/drivers/char/console-bios.c index 65bfea9f6..44168a941 100644 --- a/elks/arch/i86/drivers/char/console-bios.c +++ b/elks/arch/i86/drivers/char/console-bios.c @@ -54,19 +54,19 @@ struct console { unsigned char XN; /* delayed newline on column 80 */ unsigned char color; /* fg/bg attr */ int pageno; /* video ram page # */ + unsigned short Width; + unsigned short MaxCol; + unsigned short Height; + unsigned short MaxRow; #ifdef CONFIG_EMUL_ANSI int savex, savey; /* saved cursor position */ unsigned char *parmptr; /* ptr to params */ unsigned char params[MAXPARMS]; /* ANSI params */ #endif - unsigned short Width; - unsigned short MaxCol; - unsigned short Height; - unsigned short MaxRow; }; -static Console *glock[MAX_DISPLAYS]; -static struct wait_queue glock_wait[MAX_DISPLAYS]; +static Console *glock; +static struct wait_queue glock_wait; static Console *Visible[MAX_DISPLAYS]; static Console Con[MAX_CONSOLES]; static int NumConsoles = MAX_CONSOLES; @@ -156,7 +156,7 @@ static void ScrollDown(register Console * C, int y) void Console_set_vc(int N) { Console *C = &Con[N]; - if ((N >= NumConsoles) || (Visible[C->display] == C) || glock[C->display]) + if ((N >= NumConsoles) || (Visible[C->display] == C) || glock) return; Visible[C->display] = C; diff --git a/elks/arch/i86/drivers/char/console-direct-pc98.c b/elks/arch/i86/drivers/char/console-direct-pc98.c index 7e56c2ff9..50ed1a13f 100644 --- a/elks/arch/i86/drivers/char/console-direct-pc98.c +++ b/elks/arch/i86/drivers/char/console-direct-pc98.c @@ -54,26 +54,26 @@ struct console; typedef struct console Console; struct console { - unsigned char display; int cx, cy; /* cursor position */ void (*fsm)(Console *, int); + unsigned char display; unsigned char attr; /* current attribute */ unsigned char XN; /* delayed newline on column 80 */ unsigned int vseg; /* vram for this console page */ int vseg_offset; /* vram offset of vseg for this console page */ + unsigned short Width; + unsigned short MaxCol; + unsigned short Height; + unsigned short MaxRow; #ifdef CONFIG_EMUL_ANSI int savex, savey; /* saved cursor position */ unsigned char *parmptr; /* ptr to params */ unsigned char params[MAXPARMS]; /* ANSI params */ #endif - unsigned short Width; - unsigned short MaxCol; - unsigned short Height; - unsigned short MaxRow; }; -static Console *glock[MAX_DISPLAYS]; -static struct wait_queue glock_wait[MAX_DISPLAYS]; +static Console *glock; +static struct wait_queue glock_wait; static Console *Visible[MAX_DISPLAYS]; static Console Con[MAX_CONSOLES]; static int NumConsoles = MAX_CONSOLES; @@ -200,7 +200,7 @@ static void ScrollDown(register Console * C, int y) void Console_set_vc(int N) { Console *C = &Con[N]; - if ((N >= NumConsoles) || (Visible[C->display] == C) || glock[C->display]) + if ((N >= NumConsoles) || (Visible[C->display] == C) || glock) return; Visible[C->display] = C; SetDisplayPage(Visible[C->display]); diff --git a/elks/arch/i86/drivers/char/console-direct.c b/elks/arch/i86/drivers/char/console-direct.c index 8f4581e8a..7ab5b86eb 100644 --- a/elks/arch/i86/drivers/char/console-direct.c +++ b/elks/arch/i86/drivers/char/console-direct.c @@ -50,39 +50,47 @@ #define MAXPARMS 28 #define N_DEVICETYPES 2 + +#ifdef CONFIG_CONSOLE_DUAL #define MAX_DISPLAYS 2 +#else +#define MAX_DISPLAYS 1 +#endif -struct output; -typedef struct output Output; struct console; typedef struct console Console; -enum OutputType { - OT_MDA = 0, - OT_CGA, - OT_EGA, - OT_VGA, +#define OT_MDA 0 +#define OT_CGA 1 +#define OT_EGA 2 +#define OT_VGA 3 + +static const char *type_string[] = { + "MDA", + "CGA", + "EGA", + "VGA", }; struct console { - unsigned char display; int cx, cy; /* cursor position */ void (*fsm)(Console *, int); + unsigned char display; + unsigned char type; unsigned char attr; /* current attribute */ unsigned char XN; /* delayed newline on column 80 */ unsigned int vseg; /* vram for this console page */ int vseg_offset; /* vram offset of vseg for this console page */ -#ifdef CONFIG_EMUL_ANSI - int savex, savey; /* saved cursor position */ - unsigned char *parmptr; /* ptr to params */ - unsigned char params[MAXPARMS]; /* ANSI params */ -#endif - enum OutputType type; unsigned short Width; unsigned short MaxCol; unsigned short Height; unsigned short MaxRow; unsigned short crtc_base; /* 6845 CRTC base I/O address */ +#ifdef CONFIG_EMUL_ANSI + int savex, savey; /* saved cursor position */ + unsigned char *parmptr; /* ptr to params */ + unsigned char params[MAXPARMS]; /* ANSI params */ +#endif }; struct hw_params { @@ -121,8 +129,8 @@ static struct hw_params params[N_DEVICETYPES] = { //{ 0 }, /* VGA */ }; -static Console *glock[MAX_DISPLAYS]; -static struct wait_queue glock_wait[MAX_DISPLAYS]; +static Console *glock; +static struct wait_queue glock_wait; static Console *Visible[MAX_DISPLAYS]; static Console Con[MAX_CONSOLES]; static int NumConsoles = 0; @@ -226,7 +234,7 @@ static void ScrollDown(register Console * C, int y) void Console_set_vc(int N) { Console *C = &Con[N]; - if ((N >= NumConsoles) || glock[N]) + if ((N >= NumConsoles) || glock) return; Visible[C->display] = C; @@ -268,7 +276,7 @@ static char probe_crtc(unsigned short crtc_base) return 1; } -static int init_output(enum OutputType t) +static int init_output(unsigned char t) { int i; struct hw_params *p = ¶ms[t]; @@ -293,22 +301,12 @@ static int init_output(enum OutputType t) return 0; } -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; int i, j, dev; unsigned short boot_crtc; - enum OutputType boot_type; + unsigned char boot_type; unsigned char screens = 0; unsigned char cur_display = 0; boot_crtc = peekw(0x63, 0x40); @@ -354,6 +352,6 @@ void INITPROC console_init(void) printk("boot_crtc: %x\n", Con[0].crtc_base); printk("Direct console %s kbd"TERM_TYPE"(%d screens):\n", kbd_name, screens); for (i = 0; i < NumConsoles; ++i) { - printk("/dev/tty%i, %s, %ux%u\n", i + 1, type_string(Con[i].type), Con[i].Width, Con[i].Height); + printk("/dev/tty%i, %s, %ux%u\n", i + 1, type_string[Con[i].type], Con[i].Width, Con[i].Height); } } diff --git a/elks/arch/i86/drivers/char/console.c b/elks/arch/i86/drivers/char/console.c index 2b9303cff..06ef4365e 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[C->display]) { - if (glock[C->display] == C) + while (glock) { + if (glock == C) return; - sleep_on(&glock_wait[C->display]); + sleep_on(&glock_wait); } C->fsm(C, c); } @@ -317,26 +317,26 @@ static int Console_ioctl(struct tty *tty, int cmd, char *arg) switch (cmd) { case DCGET_GRAPH: - if (!glock[C->display]) { - glock[C->display] = C; + if (!glock) { + glock = C; return 0; } return -EBUSY; case DCREL_GRAPH: - if (glock[C->display] == C) { - glock[C->display] = NULL; - wake_up(&glock_wait[C->display]); + if (glock == C) { + glock = NULL; + wake_up(&glock_wait); return 0; } break; case DCSET_KRAW: - if (glock[C->display] == C) { + if (glock == C) { kraw = 1; return 0; } break; case DCREL_KRAW: - if ((glock[C->display] == C) && (kraw == 1)) { + if ((glock == C) && (kraw == 1)) { kraw = 0; return 1; } @@ -364,7 +364,7 @@ static int Console_write(register struct tty *tty) register Console *C = &Con[tty->minor]; int cnt = 0; - while ((tty->outq.len > 0) && !glock[C->display]) { + while ((tty->outq.len > 0) && !glock) { WriteChar(C, tty_outproc(tty)); cnt++; } From b25f8898ac7863741d54cd5507cdeef962ef3d01 Mon Sep 17 00:00:00 2001 From: Valtteri Koskivuori Date: Sun, 8 Sep 2024 04:15:20 +0300 Subject: [PATCH 5/7] [console] Factor out 6845 code to crtc-6845.c A new config option is now available, CONFIG_CONSOLE_DUAL Disabling it makes `console-direct` behave like it did before, spawning 1-3 consoles depending on the primary display type. Also: - Renamed params -> crtc_params - Renamed init_output() -> crtc_init() - Renamed probe_crtc() -> crtc_probe() - Marked crtc functions as INITPROC --- elks/arch/i86/drivers/char/Makefile | 3 + elks/arch/i86/drivers/char/config.in | 1 + elks/arch/i86/drivers/char/console-direct.c | 191 ++++++++------------ elks/arch/i86/drivers/char/crtc-6845.c | 69 +++++++ elks/arch/i86/drivers/char/crtc-6845.h | 55 ++++++ elks/arch/i86/kernel/timer.c | 15 +- 6 files changed, 214 insertions(+), 120 deletions(-) create mode 100644 elks/arch/i86/drivers/char/crtc-6845.c create mode 100644 elks/arch/i86/drivers/char/crtc-6845.h diff --git a/elks/arch/i86/drivers/char/Makefile b/elks/arch/i86/drivers/char/Makefile index b40a38ce3..e3206c991 100644 --- a/elks/arch/i86/drivers/char/Makefile +++ b/elks/arch/i86/drivers/char/Makefile @@ -62,6 +62,9 @@ endif else ifdef CONFIG_CONSOLE_DIRECT OBJS += console-direct.o bell-8254.o +ifdef CONFIG_CONSOLE_DUAL +OBJS += crtc-6845.o +endif endif endif diff --git a/elks/arch/i86/drivers/char/config.in b/elks/arch/i86/drivers/char/config.in index bad145cc4..bcde5cb59 100644 --- a/elks/arch/i86/drivers/char/config.in +++ b/elks/arch/i86/drivers/char/config.in @@ -12,6 +12,7 @@ mainmenu_option next_comment Headless CONFIG_CONSOLE_HEADLESS" Direct if [ "$CONFIG_CONSOLE_DIRECT" = "y" ]; then bool ' Scancode keyboard driver' CONFIG_KEYBOARD_SCANCODE y + bool ' Dual-screen console support' CONFIG_CONSOLE_DUAL n fi bool 'Serial Console' CONFIG_CONSOLE_SERIAL n if [[ "$CONFIG_CONSOLE_DIRECT" = "y" || "$CONFIG_CONSOLE_BIOS" = "y" ]]; then diff --git a/elks/arch/i86/drivers/char/console-direct.c b/elks/arch/i86/drivers/char/console-direct.c index 7ab5b86eb..5569d9f28 100644 --- a/elks/arch/i86/drivers/char/console-direct.c +++ b/elks/arch/i86/drivers/char/console-direct.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include "console.h" +#include "crtc-6845.h" /* Assumes ASCII values. */ #define isalpha(c) (((unsigned char)(((c) | 0x20) - 'a')) < 26) @@ -31,14 +33,6 @@ #define A_REVERSE 0x70 #define A_BLANK 0x00 -#define CONFIG_CONSOLE_DUAL - -#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' @@ -49,8 +43,6 @@ #define MAXPARMS 28 -#define N_DEVICETYPES 2 - #ifdef CONFIG_CONSOLE_DUAL #define MAX_DISPLAYS 2 #else @@ -60,18 +52,6 @@ struct console; typedef struct console Console; -#define OT_MDA 0 -#define OT_CGA 1 -#define OT_EGA 2 -#define OT_VGA 3 - -static const char *type_string[] = { - "MDA", - "CGA", - "EGA", - "VGA", -}; - struct console { int cx, cy; /* cursor position */ void (*fsm)(Console *, int); @@ -93,42 +73,6 @@ struct console { #endif }; -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; - unsigned char is_present; -}; - -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, 0 - }, /* MDA */ - { 80, 25, 0x3D4, 0xB800, 0x4000, - { - /* CO80 */ - 0x71, 0x50, 0x5A, 0x0A, - 0x1F, 0x06, 0x19, 0x1C, - 0x02, 0x07, 0x06, 0x07, - 0x00, 0x00, 0x00, 0x00, - }, 16, 3, 2000, 0 - }, /* CGA */ - // TODO - //{ 0 }, /* EGA */ - //{ 0 }, /* VGA */ -}; - static Console *glock; static struct wait_queue glock_wait; static Console *Visible[MAX_DISPLAYS]; @@ -136,6 +80,7 @@ static Console Con[MAX_CONSOLES]; static int NumConsoles = 0; int Current_VCminor = 0; +unsigned VideoSeg; int kraw = 0; #ifdef CONFIG_EMUL_ANSI @@ -254,53 +199,73 @@ struct tty_ops dircon_ops = { Console_conout }; - -/* Check to see if this CRTC is present */ -static char probe_crtc(unsigned short crtc_base) +#ifndef CONFIG_CONSOLE_DUAL +void INITPROC console_init(void) { + Console *C; + unsigned char output_type; + unsigned short boot_crtc; int i; - 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; -} + int Width, MaxCol, Height, MaxRow; + unsigned int PageSizeW; -static int init_output(unsigned char t) -{ - int i; - struct hw_params *p = ¶ms[t]; - /* Set 80x25 mode, video off */ - outb(0x01, p->crtc_base + CRTC_MODE); - /* Program CRTC regs */ - for (i = 0; i < p->n_init_bytes; ++i) { - outb(i, p->crtc_base + CRTC_INDX); - outb(p->init_bytes[i], p->crtc_base + CRTC_DATA); + output_type = OT_EGA; + C = &Con[0]; + + MaxCol = (Width = peekb(0x4a, 0x40)) - 1; /* BIOS data segment */ + + /* Trust this. Cga does not support peeking at 0x40:0x84. */ + MaxRow = (Height = 25) - 1; + boot_crtc = peekw(0x63, 0x40); + PageSizeW = ((unsigned int)peekw(0x4C, 0x40) >> 1); + + VideoSeg = 0xb800; + NumConsoles = MAX_CONSOLES - 1; + if (peekb(0x49, 0x40) == 7) { + VideoSeg = 0xB000; + NumConsoles = 1; + output_type = OT_MDA; + } else { + if (peekw(0xA8+2, 0x40) == 0) + output_type = OT_CGA; } - /* Check & clear vram */ - for (i = 0; i < p->vseg_bytes; i += 2) - pokew(i, p->vseg_base, 0x5555); - for (i = 0; i < p->vseg_bytes; i += 2) - if (peekw(i, p->vseg_base) != 0x5555) return 1; - for (i = 0; i < p->vseg_bytes; i += 2) - pokew(i, p->vseg_base, 0x7 << 8 | ' '); - - /* Enable video */ - outb(0x09, p->crtc_base + CRTC_MODE); - return 0; -} + Visible[0] = C; + + for (i = 0; i < NumConsoles; i++) { + C->cx = C->cy = 0; + C->display = 0; + if (!i) { + C->cx = peekb(0x50, 0x40); + C->cy = peekb(0x51, 0x40); + } + C->fsm = std_char; + C->vseg_offset = i * PageSizeW; + C->vseg = VideoSeg + (C->vseg_offset >> 3); + C->attr = A_DEFAULT; + C->type = output_type; + C->Width = Width; + C->MaxCol = MaxCol; + C->Height = Height; + C->MaxRow = MaxRow; + C->crtc_base = boot_crtc; + +#ifdef CONFIG_EMUL_ANSI + C->savex = C->savey = 0; +#endif + /* Do not erase early printk() */ + /* ClearRange(C, 0, C->cy, MaxCol, MaxRow); */ + + C++; + } + + kbd_init(); + + printk("Direct console, %s kbd %ux%u"TERM_TYPE"(%d virtual consoles)\n", + kbd_name, Width, Height, NumConsoles); +} +#else void INITPROC console_init(void) { Console *C; @@ -311,16 +276,15 @@ void INITPROC console_init(void) unsigned char cur_display = 0; boot_crtc = peekw(0x63, 0x40); for (i = 0; i < N_DEVICETYPES; ++i) - if (params[i].crtc_base == boot_crtc) boot_type = i; + if (crtc_params[i].crtc_base == boot_crtc) boot_type = i; C = &Con[0]; for (i = 0; i < N_DEVICETYPES; ++i) { dev = (i + boot_type) % N_DEVICETYPES; - if (!probe_crtc(params[dev].crtc_base)) continue; - params[dev].is_present = 1; + if (!crtc_probe(crtc_params[dev].crtc_base)) continue; screens++; - init_output(dev); - for (j = 0; j < params[dev].max_pages; ++j) { + crtc_init(dev); + for (j = 0; j < crtc_params[dev].max_pages; ++j) { C->cx = C->cy = 0; C->display = cur_display; if (!j) Visible[C->display] = C; @@ -329,15 +293,15 @@ void INITPROC console_init(void) C->cy = peekb(0x51, 0x40); } C->fsm = std_char; - C->vseg_offset = j * params[dev].page_words; - C->vseg = params[dev].vseg_base + (C->vseg_offset >> 3); + C->vseg_offset = j * crtc_params[dev].page_words; + C->vseg = crtc_params[dev].vseg_base + (C->vseg_offset >> 3); C->attr = A_DEFAULT; C->type = dev; - C->Width = params[dev].w; + C->Width = crtc_params[dev].w; C->MaxCol = C->Width - 1; - C->Height = params[dev].h; + C->Height = crtc_params[dev].h; C->MaxRow = C->Height - 1; - C->crtc_base = params[dev].crtc_base; + C->crtc_base = crtc_params[dev].crtc_base; #ifdef CONFIG_EMUL_ANSI C->savex = C->savey = 0; #endif @@ -348,10 +312,13 @@ void INITPROC console_init(void) cur_display++; } + /* For kernel/timer.c */ + VideoSeg = Visible[0]->vseg; + kbd_init(); - printk("boot_crtc: %x\n", Con[0].crtc_base); - printk("Direct console %s kbd"TERM_TYPE"(%d screens):\n", kbd_name, screens); + printk("Direct console %s kbd"TERM_TYPE"(%d screens, %i consoles)\n", kbd_name, screens, NumConsoles); for (i = 0; i < NumConsoles; ++i) { - printk("/dev/tty%i, %s, %ux%u\n", i + 1, type_string[Con[i].type], Con[i].Width, Con[i].Height); + debug("/dev/tty%i, %s, %ux%u\n", i + 1, type_string[Con[i].type], Con[i].Width, Con[i].Height); } } +#endif diff --git a/elks/arch/i86/drivers/char/crtc-6845.c b/elks/arch/i86/drivers/char/crtc-6845.c new file mode 100644 index 000000000..abdd0cfe1 --- /dev/null +++ b/elks/arch/i86/drivers/char/crtc-6845.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include "crtc-6845.h" + +/* + * https://stanislavs.org/helppc/6845.html + * https://www.seasip.info/VintagePC/index.html + * + * I/O VidBase VidLen Notes + * MDA: 0x3B0-0x3BB 0xB0000 4k (0x1000) + * CGA: 0x3D0-0x3DC 0xB8000 16k (0x4000) note: Address not fully decoded, fb is also at 0xBC000 + * EGA: 0x3C0-0x3CF ??????? ????? + * VGA: ????? + */ + +#define CRTC_INDX 0x0 +#define CRTC_DATA 0x1 +#define CRTC_MODE 0x4 +#define CRTC_CSEL 0x5 +#define CRTC_STAT 0x6 + +/* Check to see if this CRTC is present */ +int INITPROC crtc_probe(unsigned short crtc_base) +{ + int i; + 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; +} + +int INITPROC crtc_init(unsigned int t) +{ + int i; + struct hw_params *p = &crtc_params[t]; + /* Set 80x25 mode, video off */ + outb(0x01, p->crtc_base + CRTC_MODE); + /* Program CRTC regs */ + for (i = 0; i < p->n_init_bytes; ++i) { + outb(i, p->crtc_base + CRTC_INDX); + outb(p->init_bytes[i], p->crtc_base + CRTC_DATA); + } + + /* Check & clear vram */ + for (i = 0; i < p->vseg_bytes; i += 2) + pokew(i, p->vseg_base, 0x5555); + for (i = 0; i < p->vseg_bytes; i += 2) + if (peekw(i, p->vseg_base) != 0x5555) return 1; + for (i = 0; i < p->vseg_bytes; i += 2) + pokew(i, p->vseg_base, 0x7 << 8 | ' '); + + /* Enable video */ + outb(0x09, p->crtc_base + CRTC_MODE); + return 0; +} + diff --git a/elks/arch/i86/drivers/char/crtc-6845.h b/elks/arch/i86/drivers/char/crtc-6845.h new file mode 100644 index 000000000..216c594f0 --- /dev/null +++ b/elks/arch/i86/drivers/char/crtc-6845.h @@ -0,0 +1,55 @@ +#define OT_MDA 0 +#define OT_CGA 1 +#define OT_EGA 2 +#define OT_VGA 3 + +#define N_DEVICETYPES 2 + +#ifdef DEBUG +static const char *type_string[] = { + "MDA", + "CGA", + "EGA", + "VGA", +}; +#endif + +struct hw_params { + unsigned short w; + unsigned short h; + unsigned short crtc_base; + unsigned vseg_base; + int vseg_bytes; + unsigned char max_pages; + unsigned short page_words; + unsigned char n_init_bytes; + unsigned char init_bytes[16]; +}; + +#ifdef CONFIG_CONSOLE_DUAL +static struct hw_params crtc_params[N_DEVICETYPES] = { + { 80, 25, 0x3B4, 0xB000, 0x1000, 1, 2000, 16, + { + 0x61, 0x50, 0x52, 0x0F, + 0x19, 0x06, 0x19, 0x19, + 0x02, 0x0D, 0x0B, 0x0C, + 0x00, 0x00, 0x00, 0x00, + } + }, /* MDA */ + { 80, 25, 0x3D4, 0xB800, 0x4000, 3, 2000, 16, + { + /* CO80 */ + 0x71, 0x50, 0x5A, 0x0A, + 0x1F, 0x06, 0x19, 0x1C, + 0x02, 0x07, 0x06, 0x07, + 0x00, 0x00, 0x00, 0x00, + } + }, /* CGA */ + // TODO + //{ 0 }, /* EGA */ + //{ 0 }, /* VGA */ +}; + +int INITPROC crtc_probe(unsigned short crtc_base); +int INITPROC crtc_init(unsigned int t); +#endif diff --git a/elks/arch/i86/kernel/timer.c b/elks/arch/i86/kernel/timer.c index ac75fe85f..83014daea 100644 --- a/elks/arch/i86/kernel/timer.c +++ b/elks/arch/i86/kernel/timer.c @@ -81,20 +81,19 @@ void timer_tick(int irq, struct pt_regs *regs) #ifdef CONFIG_CONSOLE_DIRECT /* spin timer wheel in upper right of screen*/ - // FIXME - // if (spin_on && !(jiffies & 7)) { - // static unsigned char wheel[4] = {'-', '\\', '|', '/'}; - // static int c = 0; + 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 } From 0caac72e21045ff6ed3dccb19d88d0b647eb88d4 Mon Sep 17 00:00:00 2001 From: Valtteri Koskivuori Date: Fri, 13 Sep 2024 18:08:21 +0300 Subject: [PATCH 6/7] [console] Remove zero-init in console drivers .bss is already zeroed, so we don't need these extra zeroes taking up space in the kernel image. --- elks/arch/i86/drivers/char/console-bios.c | 2 +- elks/arch/i86/drivers/char/console-direct-pc98.c | 4 ++-- elks/arch/i86/drivers/char/console-direct.c | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/elks/arch/i86/drivers/char/console-bios.c b/elks/arch/i86/drivers/char/console-bios.c index 44168a941..0766ffc3f 100644 --- a/elks/arch/i86/drivers/char/console-bios.c +++ b/elks/arch/i86/drivers/char/console-bios.c @@ -71,7 +71,7 @@ static Console *Visible[MAX_DISPLAYS]; static Console Con[MAX_CONSOLES]; static int NumConsoles = MAX_CONSOLES; static int kraw; -static int Current_VCminor = 0; +static int Current_VCminor; #ifdef CONFIG_EMUL_ANSI #define TERM_TYPE " emulating ANSI " diff --git a/elks/arch/i86/drivers/char/console-direct-pc98.c b/elks/arch/i86/drivers/char/console-direct-pc98.c index 50ed1a13f..baa9940bc 100644 --- a/elks/arch/i86/drivers/char/console-direct-pc98.c +++ b/elks/arch/i86/drivers/char/console-direct-pc98.c @@ -78,8 +78,8 @@ static Console *Visible[MAX_DISPLAYS]; static Console Con[MAX_CONSOLES]; static int NumConsoles = MAX_CONSOLES; -int Current_VCminor = 0; -int kraw = 0; +int Current_VCminor; +int kraw; unsigned VideoSeg; unsigned AttributeSeg; diff --git a/elks/arch/i86/drivers/char/console-direct.c b/elks/arch/i86/drivers/char/console-direct.c index 5569d9f28..ad66aed34 100644 --- a/elks/arch/i86/drivers/char/console-direct.c +++ b/elks/arch/i86/drivers/char/console-direct.c @@ -77,11 +77,11 @@ static Console *glock; static struct wait_queue glock_wait; static Console *Visible[MAX_DISPLAYS]; static Console Con[MAX_CONSOLES]; -static int NumConsoles = 0; +static int NumConsoles; -int Current_VCminor = 0; +int Current_VCminor; unsigned VideoSeg; -int kraw = 0; +int kraw; #ifdef CONFIG_EMUL_ANSI #define TERM_TYPE " emulating ANSI " From dba7eb1f817bd7fb876a82ebb7cbd98206bb92cc Mon Sep 17 00:00:00 2001 From: Valtteri Koskivuori Date: Sun, 15 Sep 2024 21:43:02 +0300 Subject: [PATCH 7/7] [console] Remove MaxCol & MaxRow --- elks/arch/i86/drivers/char/console-bios.c | 10 ++-- .../i86/drivers/char/console-direct-pc98.c | 26 +++++----- elks/arch/i86/drivers/char/console-direct.c | 20 +++----- elks/arch/i86/drivers/char/console.c | 50 +++++++++++-------- 4 files changed, 54 insertions(+), 52 deletions(-) diff --git a/elks/arch/i86/drivers/char/console-bios.c b/elks/arch/i86/drivers/char/console-bios.c index 0766ffc3f..03a9e6ff6 100644 --- a/elks/arch/i86/drivers/char/console-bios.c +++ b/elks/arch/i86/drivers/char/console-bios.c @@ -55,9 +55,7 @@ struct console { unsigned char color; /* fg/bg attr */ int pageno; /* video ram page # */ unsigned short Width; - unsigned short MaxCol; unsigned short Height; - unsigned short MaxRow; #ifdef CONFIG_EMUL_ANSI int savex, savey; /* saved cursor position */ unsigned char *parmptr; /* ptr to params */ @@ -136,13 +134,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, C->MaxCol, C->MaxRow); + scroll(C, 1, 0, y, C->Width - 1, C->Height - 1); } #ifdef CONFIG_EMUL_ANSI static void ScrollDown(register Console * C, int y) { - scroll(C, -1, 0, y, C->MaxCol, C->MaxRow); + scroll(C, -1, 0, y, C->Width - 1, C->Height - 1); } #endif @@ -180,8 +178,8 @@ void INITPROC console_init(void) int i; C = Con; - C->MaxCol = (C->Width = SETUP_VID_COLS) - 1; - C->MaxRow = (C->Height = SETUP_VID_LINES) - 1; + C->Width = SETUP_VID_COLS; + C->Height = SETUP_VID_LINES; if (peekb(0x49, 0x40) == 7) /* BIOS data segment */ NumConsoles = 1; diff --git a/elks/arch/i86/drivers/char/console-direct-pc98.c b/elks/arch/i86/drivers/char/console-direct-pc98.c index baa9940bc..bd9f5fe45 100644 --- a/elks/arch/i86/drivers/char/console-direct-pc98.c +++ b/elks/arch/i86/drivers/char/console-direct-pc98.c @@ -62,9 +62,7 @@ struct console { unsigned int vseg; /* vram for this console page */ int vseg_offset; /* vram offset of vseg for this console page */ unsigned short Width; - unsigned short MaxCol; unsigned short Height; - unsigned short MaxRow; #ifdef CONFIG_EMUL_ANSI int savex, savey; /* saved cursor position */ unsigned char *parmptr; /* ptr to params */ @@ -164,21 +162,25 @@ static void ClearRange(register Console * C, int x, int y, int xx, int yy) static void ScrollUp(register Console * C, int y) { - register __u16 *vp; + __u16 *vp; + unsigned short MaxRow = C->Height - 1; + unsigned short MaxCol = C->Width - 1; vp = (__u16 *)((__u16)(y * C->Width) << 1); - if ((unsigned int)y < C->MaxRow) { - fmemcpyb(vp, AttributeSeg, vp + C->Width, AttributeSeg, (C->MaxRow - y) * (C->Width << 1)); - fmemcpyb(vp, C->vseg, vp + C->Width, C->vseg, (C->MaxRow - y) * (C->Width << 1)); + if ((unsigned int)y < MaxRow) { + fmemcpyb(vp, AttributeSeg, vp + C->Width, AttributeSeg, (MaxRow - y) * (C->Width << 1)); + fmemcpyb(vp, C->vseg, vp + C->Width, C->vseg, (MaxRow - y) * (C->Width << 1)); } - ClearRange(C, 0, C->MaxRow, C->MaxCol, C->MaxRow); + ClearRange(C, 0, MaxRow, MaxCol, MaxRow); } #ifdef CONFIG_EMUL_ANSI static void ScrollDown(register Console * C, int y) { - register __u16 *vp; - int yy = C->MaxRow; + __u16 *vp; + unsigned short MaxRow = C->Height - 1; + unsigned short MaxCol = C->Width - 1; + int yy = MaxRow; vp = (__u16 *)((__u16)(yy * C->Width) << 1); while (--yy >= y) { @@ -186,7 +188,7 @@ static void ScrollDown(register Console * C, int y) fmemcpyb(vp, C->vseg, vp - C->Width, C->vseg, C->Width << 1); vp -= C->Width; } - ClearRange(C, 0, y, C->MaxCol, y); + ClearRange(C, 0, y, MaxCol, y); } #endif @@ -232,8 +234,8 @@ void INITPROC console_init(void) } C = Con; - C->MaxCol = (C->Width = 80) - 1; - C->MaxRow = (C->Height = 25) - 1; + C->Width = 80; + C->Height = 25; PageSizeW = 2000; diff --git a/elks/arch/i86/drivers/char/console-direct.c b/elks/arch/i86/drivers/char/console-direct.c index ad66aed34..8b7459d46 100644 --- a/elks/arch/i86/drivers/char/console-direct.c +++ b/elks/arch/i86/drivers/char/console-direct.c @@ -62,9 +62,7 @@ struct console { unsigned int vseg; /* vram for this console page */ int vseg_offset; /* vram offset of vseg for this console page */ unsigned short Width; - unsigned short MaxCol; unsigned short Height; - unsigned short MaxRow; unsigned short crtc_base; /* 6845 CRTC base I/O address */ #ifdef CONFIG_EMUL_ANSI int savex, savey; /* saved cursor position */ @@ -146,12 +144,14 @@ static void ClearRange(register Console * C, int x, int y, int x2, int y2) static void ScrollUp(register Console * C, int y) { register int vp; + unsigned short MaxRow = C->Height - 1; + unsigned short MaxCol = C->Width - 1; vp = y * (C->Width << 1); - if ((unsigned int)y < C->MaxRow) + if ((unsigned int)y < MaxRow) fmemcpyw((void *)vp, C->vseg, - (void *)(vp + (C->Width << 1)), C->vseg, (C->MaxRow - y) * C->Width); - ClearRange(C, 0, C->MaxRow, C->MaxCol, C->MaxRow); + (void *)(vp + (C->Width << 1)), C->vseg, (MaxRow - y) * C->Width); + ClearRange(C, 0, MaxRow, MaxCol, MaxRow); } #ifdef CONFIG_EMUL_ANSI @@ -206,16 +206,16 @@ void INITPROC console_init(void) unsigned char output_type; unsigned short boot_crtc; int i; - int Width, MaxCol, Height, MaxRow; + int Width, Height; unsigned int PageSizeW; output_type = OT_EGA; C = &Con[0]; - MaxCol = (Width = peekb(0x4a, 0x40)) - 1; /* BIOS data segment */ + Width = peekb(0x4a, 0x40); /* BIOS data segment */ /* Trust this. Cga does not support peeking at 0x40:0x84. */ - MaxRow = (Height = 25) - 1; + Height = 25; boot_crtc = peekw(0x63, 0x40); PageSizeW = ((unsigned int)peekw(0x4C, 0x40) >> 1); @@ -245,9 +245,7 @@ void INITPROC console_init(void) C->attr = A_DEFAULT; C->type = output_type; C->Width = Width; - C->MaxCol = MaxCol; C->Height = Height; - C->MaxRow = MaxRow; C->crtc_base = boot_crtc; #ifdef CONFIG_EMUL_ANSI @@ -298,9 +296,7 @@ void INITPROC console_init(void) C->attr = A_DEFAULT; C->type = dev; C->Width = crtc_params[dev].w; - C->MaxCol = C->Width - 1; C->Height = crtc_params[dev].h; - C->MaxRow = C->Height - 1; C->crtc_base = crtc_params[dev].crtc_base; #ifdef CONFIG_EMUL_ANSI C->savex = C->savey = 0; diff --git a/elks/arch/i86/drivers/char/console.c b/elks/arch/i86/drivers/char/console.c index 06ef4365e..cd20028c4 100644 --- a/elks/arch/i86/drivers/char/console.c +++ b/elks/arch/i86/drivers/char/console.c @@ -33,10 +33,12 @@ void Console_conin(unsigned char Key) static void Console_gotoxy(register Console * C, int x, int y) { register int xp = x; + unsigned short MaxRow = C->Height - 1; + unsigned short MaxCol = C->Width - 1; - C->cx = (xp >= C->MaxCol) ? C->MaxCol : (xp < 0) ? 0 : xp; + C->cx = (xp >= MaxCol) ? MaxCol : (xp < 0) ? 0 : xp; xp = y; - C->cy = (xp >= C->MaxRow) ? C->MaxRow : (xp < 0) ? 0 : xp; + C->cy = (xp >= MaxRow) ? MaxRow : (xp < 0) ? 0 : xp; C->XN = 0; } @@ -80,6 +82,8 @@ static unsigned char ega_color[16] = { 0, 4, 2, 6, 1, 5, 3, 7, static void AnsiCmd(register Console * C, int c) { int n; + unsigned short MaxRow = C->Height - 1; + unsigned short MaxCol = C->Width - 1; /* ANSI param gathering and processing */ if (C->parmptr < &C->params[MAXPARMS - 1]) @@ -105,23 +109,23 @@ static void AnsiCmd(register Console * C, int c) break; case 'B': /* Move down n lines */ C->cy += parm1(C->params); - if (C->cy > C->MaxRow) - C->cy = C->MaxRow; + if (C->cy > MaxRow) + C->cy = MaxRow; break; case 'd': /* Vertical position absolute */ C->cy = parm1(C->params) - 1; - if (C->cy > C->MaxRow) - C->cy = C->MaxRow; + if (C->cy > MaxRow) + C->cy = MaxRow; break; case 'C': /* Move right n characters */ C->cx += parm1(C->params); - if (C->cx > C->MaxCol) - C->cx = C->MaxCol; + if (C->cx > MaxCol) + C->cx = MaxCol; break; case 'G': /* Horizontal position absolute */ C->cx = parm1(C->params) - 1; - if (C->cx > C->MaxCol) - C->cx = C->MaxCol; + if (C->cx > MaxCol) + C->cx = MaxCol; break; case 'D': /* Move left n characters */ C->cx -= parm1(C->params); @@ -134,20 +138,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, C->MaxCol, C->cy); - if (C->cy < C->MaxRow) - ClearRange(C, 0, C->cy, C->MaxCol, C->MaxRow); + ClearRange(C, C->cx, C->cy, MaxCol, C->cy); + if (C->cy < MaxRow) + ClearRange(C, 0, C->cy, MaxCol, MaxRow); } else if (n == 2) /* all*/ - ClearRange(C, 0, 0, C->MaxCol, C->MaxRow); + ClearRange(C, 0, 0, MaxCol, MaxRow); break; case 'K': /* clear line */ n = atoi((char *)C->params); if (n == 0) /* to EOL */ - ClearRange(C, C->cx, C->cy, C->MaxCol, C->cy); + ClearRange(C, C->cx, C->cy, MaxCol, 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, C->MaxCol, C->cy); + ClearRange(C, 0, C->cy, MaxCol, C->cy); break; case 'L': /* insert line */ ScrollDown(C, C->cy); @@ -250,6 +254,8 @@ static void esc_char(register Console * C, int c) /* Normal character processing */ static void std_char(register Console * C, int c) { + unsigned short MaxRow = C->Height - 1; + unsigned short MaxCol = C->Width - 1; switch(c) { case BEL: bell(); @@ -287,9 +293,9 @@ static void std_char(register Console * C, int c) C->XN = 0; C->cx = 0; C->cy++; - if (C->cy > C->MaxRow) { + if (C->cy > MaxRow) { ScrollUp(C, 0); - C->cy = C->MaxRow; + C->cy = MaxRow; } } #ifdef CONFIG_CONSOLE_BIOS @@ -300,14 +306,14 @@ static void std_char(register Console * C, int c) C->cx++; } linewrap: - if (C->cx > C->MaxCol) { + if (C->cx > MaxCol) { C->XN = 1; - C->cx = C->MaxCol; + C->cx = MaxCol; } } - if (C->cy > C->MaxRow) { + if (C->cy > MaxRow) { ScrollUp(C, 0); - C->cy = C->MaxRow; + C->cy = MaxRow; } }