diff options
author | Matt Fleming <matt.fleming@intel.com> | 2011-12-15 15:36:02 +0000 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2011-12-16 16:38:08 +0000 |
commit | 400e21c5f4af4c688907dd8ceb8a1df321ab7f78 (patch) | |
tree | 088218336b07a9e8d0cc9970f336e7bb2bd5ed74 | |
parent | da5675bb1b93493959379c108c5d02ee9285a3ef (diff) | |
download | syslinux-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.h | 18 | ||||
-rw-r--r-- | com32/lib/sys/ansicon_write.c | 122 | ||||
-rw-r--r-- | com32/lib/syslinux/firmware.c | 31 | ||||
-rw-r--r-- | 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 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; |