[syslinux:firmware] com32: Add firmware backend support to ansicon

syslinux-bot for Matt Fleming matt.fleming at intel.com
Fri Nov 9 09:06:09 PST 2012


Commit-ID:  400e21c5f4af4c688907dd8ceb8a1df321ab7f78
Gitweb:     http://www.syslinux.org/commit/400e21c5f4af4c688907dd8ceb8a1df321ab7f78
Author:     Matt Fleming <matt.fleming at intel.com>
AuthorDate: Thu, 15 Dec 2011 15:36:02 +0000
Committer:  Matt Fleming <matt.fleming at intel.com>
CommitDate: Fri, 16 Dec 2011 16:38:08 +0000

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 at intel.com>

---
 com32/include/syslinux/firmware.h |   18 ++++++
 com32/lib/sys/ansicon_write.c     |  122 ++++++++++++++++++++++++++++---------
 com32/lib/syslinux/firmware.c     |   31 +++++++++
 core/conio.c                      |  100 ++++++++----------------------
 4 files changed, 170 insertions(+), 101 deletions(-)

diff --git a/com32/include/syslinux/firmware.h b/com32/include/syslinux/firmware.h
index 2a7d066..f664c0c 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 b25f2d2..7358015 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 1b8e1b0..d4fcf64 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 5ed0b4b..860aabc 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;


More information about the Syslinux-commits mailing list