aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2011-12-15 15:36:02 +0000
committerMatt Fleming <matt.fleming@intel.com>2011-12-16 16:38:08 +0000
commit400e21c5f4af4c688907dd8ceb8a1df321ab7f78 (patch)
tree088218336b07a9e8d0cc9970f336e7bb2bd5ed74
parentda5675bb1b93493959379c108c5d02ee9285a3ef (diff)
downloadsyslinux-400e21c5f4af4c688907dd8ceb8a1df321ab7f78.tar.gz
syslinux-400e21c5f4af4c688907dd8ceb8a1df321ab7f78.tar.xz
syslinux-400e21c5f4af4c688907dd8ceb8a1df321ab7f78.zip
com32: Add firmware backend support to ansicon
The way in which I/O is done is firmware backend-specific. Jump through some layers of indirection so that things can be implemented differently for BIOS and EFI. Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--com32/include/syslinux/firmware.h18
-rw-r--r--com32/lib/sys/ansicon_write.c122
-rw-r--r--com32/lib/syslinux/firmware.c31
-rw-r--r--core/conio.c100
4 files changed, 170 insertions, 101 deletions
diff --git a/com32/include/syslinux/firmware.h b/com32/include/syslinux/firmware.h
index 2a7d066b..f664c0cb 100644
--- a/com32/include/syslinux/firmware.h
+++ b/com32/include/syslinux/firmware.h
@@ -4,12 +4,30 @@
#include <syslinux/memscan.h>
#include <disk.h>
+struct output_ops {
+ void (*erase) (int, int, int, int, uint8_t);
+ void (*write_char) (uint8_t, uint8_t);
+ void (*showcursor) (uint16_t);
+ void (*scroll_up) (uint8_t, uint8_t, uint8_t);
+ void (*set_cursor) (int, int, bool);
+ void (*beep) (void);
+ void (*get_mode)(int *, int *);
+ void (*set_mode)(uint16_t);
+ void (*get_cursor)(int *, int *);
+};
+
+struct input_ops {
+ char (*getchar)(void);
+};
+
struct firmware {
void (*init)(void);
int (*scan_memory)(scan_memory_callback_t, void *);
void (*adjust_screen)(void);
void (*cleanup)(void);
struct disk *(*disk_init)(struct disk_private *);
+ struct output_ops *o_ops;
+ struct input_ops *i_ops;
};
extern struct firmware *firmware;
diff --git a/com32/lib/sys/ansicon_write.c b/com32/lib/sys/ansicon_write.c
index b25f2d2e..73580156 100644
--- a/com32/lib/sys/ansicon_write.c
+++ b/com32/lib/sys/ansicon_write.c
@@ -42,6 +42,7 @@
#include <syslinux/config.h>
#include "file.h"
#include "ansi.h"
+#include <syslinux/firmware.h>
static void ansicon_erase(const struct term_state *, int, int, int, int);
static void ansicon_write_char(int, int, uint8_t, const struct term_state *);
@@ -70,12 +71,42 @@ static struct term_info ti = {
#define BIOS_COLS (*(uint16_t *)0x44A)
#define BIOS_PAGE (*(uint8_t *)0x462)
+#define TEXT_MODE 0x0005
+
/* Reference counter to the screen, to keep track of if we need
reinitialization. */
static int ansicon_counter = 0;
static uint16_t cursor_type; /* Saved cursor pattern */
+void bios_set_mode(uint16_t mode)
+{
+ com32sys_t ireg;
+
+ ireg.eax.w[0] = mode;
+ __intcall(0x22, &ireg, NULL);
+}
+
+void bios_get_mode(int *cols, int *rows)
+{
+ *rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
+ *cols = BIOS_COLS;
+}
+
+void bios_get_cursor(int *x, int *y)
+{
+ com32sys_t ireg, oreg;
+
+ memset(&ireg, 0, sizeof(ireg));
+
+ ireg.eax.b[1] = 0x03;
+ ireg.ebx.b[1] = BIOS_PAGE;
+ __intcall(0x10, &ireg, &oreg);
+ cursor_type = oreg.ecx.w[0];
+ *x = oreg.edx.b[0];
+ *y = oreg.edx.b[1];
+}
+
/* Common setup */
int __ansicon_open(struct file_info *fp)
{
@@ -90,21 +121,14 @@ int __ansicon_open(struct file_info *fp)
ti.cols = 80;
} else {
/* Force text mode */
- ireg.eax.w[0] = 0x0005;
- __intcall(0x22, &ireg, NULL);
+ firmware->o_ops->set_mode(TEXT_MODE);
/* Initial state */
- ti.rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
- ti.cols = BIOS_COLS;
+ firmware->o_ops->get_mode(&ti.cols, &ti.rows);
__ansi_init(&ti);
/* Get cursor shape and position */
- ireg.eax.b[1] = 0x03;
- ireg.ebx.b[1] = BIOS_PAGE;
- __intcall(0x10, &ireg, &oreg);
- cursor_type = oreg.ecx.w[0];
- ti.ts->xy.x = oreg.edx.b[0];
- ti.ts->xy.y = oreg.edx.b[1];
+ firmware->o_ops->get_cursor(&ti.ts->xy.x, &ti.ts->xy.y);
}
}
@@ -151,14 +175,12 @@ static uint8_t ansicon_attribute(const struct term_state *st)
return (bg << 4) | fg;
}
-/* Erase a region of the screen */
-static void ansicon_erase(const struct term_state *st,
- int x0, int y0, int x1, int y1)
+void bios_erase(int x0, int y0, int x1, int y1, uint8_t attribute)
{
static com32sys_t ireg;
ireg.eax.w[0] = 0x0600; /* Clear window */
- ireg.ebx.b[1] = ansicon_attribute(st);
+ ireg.ebx.b[1] = attribute;
ireg.ecx.b[0] = x0;
ireg.ecx.b[1] = y0;
ireg.edx.b[0] = x1;
@@ -166,17 +188,33 @@ static void ansicon_erase(const struct term_state *st,
__intcall(0x10, &ireg, NULL);
}
-/* Show or hide the cursor */
-static void ansicon_showcursor(const struct term_state *st)
+/* Erase a region of the screen */
+static void ansicon_erase(const struct term_state *st,
+ int x0, int y0, int x1, int y1)
+{
+ uint8_t attribute = ansicon_attribute(st);
+
+ if (firmware->o_ops->erase)
+ firmware->o_ops->erase(x0, y0, x1, y1, attribute);
+}
+
+void bios_showcursor(uint16_t cursor)
{
static com32sys_t ireg;
ireg.eax.b[1] = 0x01;
- ireg.ecx.w[0] = st->cursor ? cursor_type : 0x2020;
+ ireg.ecx.w[0] = cursor;
__intcall(0x10, &ireg, NULL);
}
-static void ansicon_set_cursor(int x, int y, bool visible)
+/* Show or hide the cursor */
+static void ansicon_showcursor(const struct term_state *st)
+{
+ uint16_t cursor = st->cursor ? cursor_type : 0x2020;
+ firmware->o_ops->showcursor(cursor);
+}
+
+void bios_set_cursor(int x, int y, bool visible)
{
const int page = BIOS_PAGE;
struct curxy xy = BIOS_CURXY[page];
@@ -193,33 +231,55 @@ static void ansicon_set_cursor(int x, int y, bool visible)
}
}
-static void ansicon_write_char(int x, int y, uint8_t ch,
- const struct term_state *st)
+static void ansicon_set_cursor(int x, int y, bool visible)
{
- static com32sys_t ireg;
+ firmware->o_ops->set_cursor(x, y, visible);
+}
- ansicon_set_cursor(x, y, false);
+void bios_write_char(uint8_t ch, uint8_t attribute)
+{
+ static com32sys_t ireg;
ireg.eax.b[1] = 0x09;
ireg.eax.b[0] = ch;
ireg.ebx.b[1] = BIOS_PAGE;
- ireg.ebx.b[0] = ansicon_attribute(st);
+ ireg.ebx.b[0] = attribute;
ireg.ecx.w[0] = 1;
__intcall(0x10, &ireg, NULL);
}
-static void ansicon_scroll_up(const struct term_state *st)
+static void ansicon_write_char(int x, int y, uint8_t ch,
+ const struct term_state *st)
+{
+ uint8_t attribute = ansicon_attribute(st);
+ ansicon_set_cursor(x, y, false);
+
+ firmware->o_ops->write_char(ch, attribute);
+}
+
+void bios_scroll_up(uint8_t cols, uint8_t rows, uint8_t attribute)
{
static com32sys_t ireg;
ireg.eax.w[0] = 0x0601;
- ireg.ebx.b[1] = ansicon_attribute(st);
+ ireg.ebx.b[1] = attribute;
ireg.ecx.w[0] = 0;
- ireg.edx.b[1] = ti.rows - 1;
- ireg.edx.b[0] = ti.cols - 1;
+ ireg.edx.b[1] = rows;
+ ireg.edx.b[0] = cols;
__intcall(0x10, &ireg, NULL); /* Scroll */
}
+static void ansicon_scroll_up(const struct term_state *st)
+{
+ uint8_t rows, cols, attribute;
+
+ cols = ti.cols = 1;
+ rows = ti.rows - 1;
+ attribute = ansicon_attribute(st);
+
+ firmware->o_ops->scroll_up(cols, rows, attribute);
+}
+
ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
{
const unsigned char *bufp = buf;
@@ -238,7 +298,7 @@ ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
return n;
}
-void __ansicon_beep(void)
+void bios_beep(void)
{
static com32sys_t ireg;
@@ -247,6 +307,12 @@ void __ansicon_beep(void)
__intcall(0x10, &ireg, NULL);
}
+void __ansicon_beep(void)
+{
+ if (firmware->o_ops->beep)
+ firmware->o_ops->beep();
+}
+
const struct output_dev dev_ansicon_w = {
.dev_magic = __DEV_MAGIC,
.flags = __DEV_TTY | __DEV_OUTPUT,
diff --git a/com32/lib/syslinux/firmware.c b/com32/lib/syslinux/firmware.c
index 1b8e1b04..d4fcf646 100644
--- a/com32/lib/syslinux/firmware.c
+++ b/com32/lib/syslinux/firmware.c
@@ -5,6 +5,35 @@
#include <syslinux/firmware.h>
struct firmware *firmware = NULL;
+extern struct ansi_ops bios_ansi_ops;
+
+extern void bios_erase(int, int, int, int, uint8_t);
+extern void bios_write_char(uint8_t, uint8_t);
+extern void bios_showcursor(uint16_t);
+extern void bios_scroll_up(uint8_t, uint8_t, uint8_t);
+extern void bios_set_cursor(int, int, bool);
+extern void bios_beep(void);
+extern void bios_set_mode(uint16_t mode);
+extern void bios_get_mode(int *rows, int *cols);
+extern void bios_get_cursor(int *x, int *y);
+
+struct output_ops bios_output_ops = {
+ .erase = bios_erase,
+ .write_char = bios_write_char,
+ .showcursor = bios_showcursor,
+ .set_cursor = bios_set_cursor,
+ .scroll_up = bios_scroll_up,
+ .beep = bios_beep,
+ .get_mode = bios_get_mode,
+ .set_mode = bios_set_mode,
+ .get_cursor = bios_get_cursor,
+};
+
+extern char bios_getchar(void);
+
+struct input_ops bios_input_ops = {
+ .getchar = bios_getchar,
+};
struct firmware bios_fw = {
.init = bios_init,
@@ -12,6 +41,8 @@ struct firmware bios_fw = {
.adjust_screen = bios_adjust_screen,
.cleanup = bios_cleanup_hardware,
.disk_init = bios_disk_init,
+ .o_ops = &bios_output_ops,
+ .i_ops = &bios_input_ops,
};
void syslinux_register_bios(void)
diff --git a/core/conio.c b/core/conio.c
index 5ed0b4b7..860aabcb 100644
--- a/core/conio.c
+++ b/core/conio.c
@@ -29,6 +29,7 @@
#include "bios.h"
#include <com32.h>
#include <sys/cpu.h>
+#include <syslinux/firmware.h>
union screen _cursor;
union screen _screensize;
@@ -116,15 +117,6 @@ int get_msg_file(char *filename)
return 0;
}
-static inline void msg_beep(void)
-{
- com32sys_t ireg, oreg;
-
- ireg.eax.w[0] = 0x0E07; /* Beep */
- ireg.ebx.w[0] = 0x0000;
- __intcall(0x10, &ireg, &oreg);
-}
-
/*
* write_serial: If serial output is enabled, write character on
* serial port.
@@ -262,10 +254,7 @@ int pm_pollchar(com32sys_t *regs)
extern void do_idle(void);
-/*
- * getchar: Read a character from keyboard or serial port
- */
-char getchar(void)
+char bios_getchar(void)
{
com32sys_t ireg, oreg;
unsigned char data;
@@ -329,6 +318,14 @@ char getchar(void)
return data;
}
+/*
+ * getchar: Read a character from keyboard or serial port
+ */
+char getchar(void)
+{
+ return firmware->i_ops->getchar();
+}
+
void pm_getchar(com32sys_t *regs)
{
regs->eax.b[0] = getchar();
@@ -368,15 +365,7 @@ static inline void msg_ctrl_o(void)
static void msg_gotoxy(void)
{
- com32sys_t ireg, oreg;
-
- memset(&ireg, 0, sizeof(ireg));
-
- ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
- ireg.edx.w[0] = CursorDX;
- ireg.eax.b[1] = 0x02; /* Set cursor position */
-
- __intcall(0x10, &ireg, &oreg);
+ firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
}
static void msg_newline(void)
@@ -393,18 +382,11 @@ static void msg_newline(void)
if ((CursorRow + 1) <= VidRows)
CursorRow++;
else {
- ireg.ecx.w[0] = 0x0; /* Upper left hand corner */
- ireg.edx.w[0] = ScreenSize;
-
- CursorRow = ireg.edx.b[1]; /* New cursor at the bottom */
-
- ireg.ebx.b[1] = ScrollAttribute;
- ireg.eax.w[0] = 0x0601; /* Scroll up one line */
-
- __intcall(0x10, &ireg, &oreg);
+ CursorRow = VidRows; /* New cursor at the bottom */
+ firmware->o_ops->scroll_up(VidRows, VidCols, ScrollAttribute);
}
- msg_gotoxy();
+ firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
}
static void msg_formfeed(void)
@@ -414,19 +396,10 @@ static void msg_formfeed(void)
write_serial_str_displaymask(crff_msg);
if (DisplayMask & UsingVGA) {
- com32sys_t ireg, oreg;
-
- memset(&ireg, 0, sizeof(ireg));
-
CursorDX = 0x0; /* Upper left hand corner */
- ireg.edx.w[0] = ScreenSize;
- ireg.ebx.b[1] = TextAttribute;
-
- ireg.eax.w[0] = 0x0600; /* Clear screen region */
- __intcall(0x10, &ireg, &oreg);
-
- msg_gotoxy();
+ firmware->o_ops->erase(0, 0, VidCols, VidRows, TextAttribute);
+ firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
}
}
@@ -488,22 +461,11 @@ static void msg_line_wrap(void)
if ((CursorRow + 1) <= VidRows)
CursorRow++;
else {
- com32sys_t ireg, oreg;
-
- memset(&ireg, 0, sizeof(ireg));
-
- ireg.ecx.w[0] = 0x0; /* Upper left hand corner */
- ireg.edx.w[0] = ScreenSize;
-
- CursorRow = ireg.edx.b[1]; /* New cursor at the bottom */
-
- ireg.ebx.b[1] = ScrollAttribute;
- ireg.eax.w[0] = 0x0601; /* Scroll up one line */
-
- __intcall(0x10, &ireg, &oreg);
+ /* Scroll up one line */
+ firmware->o_ops->scroll_up(VidRows, VidCols, ScrollAttribute);
}
- msg_gotoxy();
+ firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
}
static void msg_normal(char data)
@@ -519,20 +481,12 @@ static void msg_normal(char data)
if (!(DisplayCon & 0x01))
return;
- memset(&ireg, 0, sizeof(ireg));
-
- ireg.ebx.b[0] = TextAttribute;
- ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
- ireg.eax.b[0] = data;
- ireg.eax.b[1] = 0x09; /* Write character/attribute */
- ireg.ecx.w[0] = 1; /* One character only */
-
/* Write to screen */
- __intcall(0x10, &ireg, &oreg);
+ firmware->o_ops->write_char(data, TextAttribute);
if ((CursorCol + 1) <= VidCols) {
CursorCol++;
- msg_gotoxy();
+ firmware->o_ops->set_cursor(CursorCol, CursorRow, true);
} else
msg_line_wrap(); /* Screen wraparound */
}
@@ -565,7 +519,8 @@ static void msg_putchar(char ch)
msg_formfeed();
break;
case 0x07: /* <BEL> = beep */
- msg_beep();
+ if (firmware->o_ops->beep)
+ firmware->o_ops->beep();
break;
case 0x19: /* <EM> = return to text mode */
msg_novga();
@@ -586,12 +541,11 @@ static void msg_putchar(char ch)
void msg_initvars(void)
{
com32sys_t ireg, oreg;
+ int x, y;
- ireg.eax.b[1] = 0x3; /* Read cursor position */
- ireg.ebx.b[1] = *(uint8_t *)BIOS_page;
- __intcall(0x10, &ireg, &oreg);
-
- CursorDX = oreg.edx.w[0];
+ firmware->o_ops->get_cursor(&x, &y);
+ CursorCol = x;
+ CursorRow = y;
/* Initialize state machine */
NextCharJump = msg_putchar;