Skip to content

Commit

Permalink
[console] Add dual-screen support to console-direct.c
Browse files Browse the repository at this point in the history
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<N>.
To indicate which display is active, the blinking cursor is toggled such
that it only appears on the active display.
  • Loading branch information
vkoskiv committed Sep 2, 2024
1 parent 33a7c93 commit 98f74b7
Show file tree
Hide file tree
Showing 5 changed files with 354 additions and 165 deletions.
60 changes: 37 additions & 23 deletions elks/arch/i86/drivers/char/console-bios.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@

#define MAXPARMS 28

#define MAX_OUTPUTS 1

struct output;
typedef struct output Output;
struct console;
typedef struct console Console;

struct console {
Output *op;
int cx, cy; /* cursor position */
void (*fsm)(Console *, int);
unsigned char attr; /* current attribute */
Expand All @@ -58,10 +63,18 @@ struct console {
#endif
};

static struct wait_queue glock_wait;
static Console Con[MAX_CONSOLES], *Visible;
static Console *glock; /* Which console owns the graphics hardware */
static int Width, MaxCol, Height, MaxRow;
struct output {
unsigned short w;
unsigned short max_col;
unsigned short h;
unsigned short max_row;
Console *visible;
Console *glock; /* Which console owns the graphics hardware */
struct wait_queue glock_wait;
};

static Output Outputs[MAX_OUTPUTS];
static Console Con[MAX_CONSOLES];
static int NumConsoles = MAX_CONSOLES;
static int kraw;
static int Current_VCminor = 0;
Expand Down Expand Up @@ -93,7 +106,7 @@ static void PositionCursorGet (int * x, int * y)
*y = row;
}

static void DisplayCursor(int onoff)
static void DisplayCursor(register Console * C, int onoff)
{
}

Expand All @@ -111,14 +124,14 @@ static void scroll(register Console * C, int n, int x, int y, int xx, int yy)
int a;

a = C->attr;
if (C != Visible) {
if (C != C->op->visible) {
bios_setpage(C->pageno);
}

bios_scroll (a, n, x, y, xx, yy);

if (C != Visible) {
bios_setpage(Visible->pageno);
if (C != C->op->visible) {
bios_setpage(C->op->visible->pageno);
}
}

Expand All @@ -129,13 +142,13 @@ static void ClearRange(register Console * C, int x, int y, int xx, int yy)

static void ScrollUp(register Console * C, int y)
{
scroll(C, 1, 0, y, MaxCol, MaxRow);
scroll(C, 1, 0, y, C->op->max_col, C->op->max_row);
}

#ifdef CONFIG_EMUL_ANSI
static void ScrollDown(register Console * C, int y)
{
scroll(C, -1, 0, y, MaxCol, MaxRow);
scroll(C, -1, 0, y, C->op->max_col, C->op->max_row);
}
#endif

Expand All @@ -148,12 +161,12 @@ static void ScrollDown(register Console * C, int y)

void Console_set_vc(int N)
{
if ((N >= NumConsoles) || (Visible == &Con[N]) || glock)
if ((N >= NumConsoles) || (Con[N].op->visible == &Con[N]) || Con[N].op->glock)
return;
Visible = &Con[N];
Con[N].op->visible = &Con[N];

bios_setpage(N);
PositionCursor(Visible);
PositionCursor(Con[N].op->visible);
Current_VCminor = N;
}

Expand All @@ -169,25 +182,26 @@ struct tty_ops bioscon_ops = {
void INITPROC console_init(void)
{
Console *C;
Output *O;
int i;

MaxCol = (Width = SETUP_VID_COLS) - 1;

/* Trust this. Cga does not support peeking at 0x40:0x84. */
MaxRow = (Height = SETUP_VID_LINES) - 1;
O = &Outputs[0];
O->max_col = (O->w = SETUP_VID_COLS) - 1;
O->max_row = (O->h = SETUP_VID_LINES) - 1;

if (peekb(0x49, 0x40) == 7) /* BIOS data segment */
NumConsoles = 1;

C = Con;
Visible = C;

for (i = 0; i < NumConsoles; i++) {
C->op = O;
C->cx = C->cy = 0;
if (!i) {
// Get current cursor position
// to write after boot messages
PositionCursorGet (&C->cx, &C->cy);
O->visible = C;
// Get current cursor position
// to write after boot messages
PositionCursorGet (&C->cx, &C->cy);
}
C->fsm = std_char;
C->pageno = i;
Expand All @@ -201,13 +215,13 @@ void INITPROC console_init(void)
#endif

/* Do not erase early printk() */
/* ClearRange(C, 0, C->cy, MaxCol, MaxRow); */
/* ClearRange(C, 0, C->cy, C->op->max_col, C->op->max_row); */

C++;
}

kbd_init();

printk("BIOS console %ux%u"TERM_TYPE"(%d virtual consoles)\n",
Width, Height, NumConsoles);
O->w, O->h, NumConsoles);
}
73 changes: 44 additions & 29 deletions elks/arch/i86/drivers/char/console-direct-pc98.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,15 @@

#define MAXPARMS 28

#define MAX_OUTPUTS 1

struct output;
typedef struct output Output;
struct console;
typedef struct console Console;

struct console {
Output *op;
int cx, cy; /* cursor position */
void (*fsm)(Console *, int);
unsigned char attr; /* current attribute */
Expand All @@ -65,10 +70,18 @@ struct console {
#endif
};

static struct wait_queue glock_wait;
static Console Con[MAX_CONSOLES], *Visible;
static Console *glock; /* Which console owns the graphics hardware */
static int Width, MaxCol, Height, MaxRow;
struct output {
unsigned short w;
unsigned short max_col;
unsigned short h;
unsigned short max_row;
struct wait_queue glock_wait;
Console *visible;
Console *glock; /* Which console owns the graphics hardware */
};

static Output Outputs[MAX_OUTPUTS];
static Console Con[MAX_CONSOLES];
static int NumConsoles = MAX_CONSOLES;

int Current_VCminor = 0;
Expand All @@ -92,11 +105,11 @@ static void PositionCursor(register Console * C)
{
int Pos;

Pos = C->cx + Width * C->cy + C->basepage;
Pos = C->cx + C->op->w * C->cy + C->basepage;
cursor_set(Pos * 2);
}

static void DisplayCursor(int onoff)
static void DisplayCursor(register Console * C, int onoff)
{
if (onoff)
cursor_on();
Expand Down Expand Up @@ -130,7 +143,7 @@ static void VideoWrite(register Console * C, int c)
word_t addr;
word_t attr;

addr = (C->cx + C->cy * Width) << 1;
addr = (C->cx + C->cy * C->op->w) << 1;
attr = (C->attr == A_DEFAULT) ? A98_DEFAULT : conv_pcattr(C->attr);

pokew(addr, (seg_t) AttributeSeg, attr);
Expand All @@ -145,41 +158,41 @@ static void ClearRange(register Console * C, int x, int y, int xx, int yy)
attr = (C->attr == A_DEFAULT) ? A98_DEFAULT : conv_pcattr(C->attr);

xx = xx - x + 1;
vp = (__u16 *)((__u16)(x + y * Width) << 1);
vp = (__u16 *)((__u16)(x + y * C->op->w) << 1);
do {
for (x = 0; x < xx; x++) {
pokew((word_t) vp, AttributeSeg, attr);
pokew((word_t) (vp++), (seg_t) C->vseg, (word_t) ' ');
}
vp += (Width - xx);
vp += (C->op->w - xx);
} while (++y <= yy);
}

static void ScrollUp(register Console * C, int y)
{
register __u16 *vp;

vp = (__u16 *)((__u16)(y * Width) << 1);
if ((unsigned int)y < MaxRow) {
fmemcpyb(vp, AttributeSeg, vp + Width, AttributeSeg, (MaxRow - y) * (Width << 1));
fmemcpyb(vp, C->vseg, vp + Width, C->vseg, (MaxRow - y) * (Width << 1));
vp = (__u16 *)((__u16)(y * C->op->w) << 1);
if ((unsigned int)y < C->op->max_row) {
fmemcpyb(vp, AttributeSeg, vp + C->op->w, AttributeSeg, (C->op->max_row - y) * (C->op->w << 1));
fmemcpyb(vp, C->vseg, vp + C->op->w, C->vseg, (C->op->max_row - y) * (C->op->w << 1));
}
ClearRange(C, 0, MaxRow, MaxCol, MaxRow);
ClearRange(C, 0, C->op->max_row, C->op->max_col, C->op->max_row);
}

#ifdef CONFIG_EMUL_ANSI
static void ScrollDown(register Console * C, int y)
{
register __u16 *vp;
int yy = MaxRow;
int yy = C->op->max_row;

vp = (__u16 *)((__u16)(yy * Width) << 1);
vp = (__u16 *)((__u16)(yy * C->op->w) << 1);
while (--yy >= y) {
fmemcpyb(vp, AttributeSeg, vp - Width, AttributeSeg, Width << 1);
fmemcpyb(vp, C->vseg, vp - Width, C->vseg, Width << 1);
vp -= Width;
fmemcpyb(vp, AttributeSeg, vp - C->op->w, AttributeSeg, C->op->w << 1);
fmemcpyb(vp, C->vseg, vp - C->op->w, C->vseg, C->op->w << 1);
vp -= C->op->w;
}
ClearRange(C, 0, y, MaxCol, y);
ClearRange(C, 0, y, C->op->max_col, y);
}
#endif

Expand All @@ -192,12 +205,12 @@ static void ScrollDown(register Console * C, int y)

void Console_set_vc(int N)
{
if ((N >= NumConsoles) || (Visible == &Con[N]) || glock)
if ((N >= NumConsoles) || (Con[N].op->visible == &Con[N]) || Con[N].op->glock)
return;
Visible = &Con[N];
Con[N].op->visible = &Con[N];

SetDisplayPage(Visible);
PositionCursor(Visible);
SetDisplayPage(Con[N].op->visible);
PositionCursor(Con[N].op->visible);
Current_VCminor = N;
}

Expand All @@ -213,6 +226,7 @@ struct tty_ops dircon_ops = {
void INITPROC console_init(void)
{
Console *C;
Output *O;
int i;
unsigned PageSizeW;

Expand All @@ -224,20 +238,21 @@ void INITPROC console_init(void)
AttributeSeg = 0xE200;
}

MaxCol = (Width = 80) - 1;

MaxRow = (Height = 25) - 1;
O = &Outputs[0];
O->max_col = (O->w = 80) - 1;
O->max_row = (O->h = 25) - 1;

PageSizeW = 2000;

NumConsoles = 1;

C = Con;
Visible = C;

for (i = 0; i < NumConsoles; i++) {
C->op = O;
C->cx = C->cy = 0;
if (!i) {
O->visible = C;
C->cx = read_tvram_x() % 160;
C->cy = read_tvram_x() / 160;
}
Expand All @@ -261,5 +276,5 @@ void INITPROC console_init(void)
kbd_init();

printk("Direct console, %s kbd %ux%u"TERM_TYPE"(du virtual consoles)\n",
kbd_name, Width, Height, NumConsoles);
kbd_name, O->w, O->h, NumConsoles);
}
Loading

0 comments on commit 98f74b7

Please sign in to comment.