Hi,
Next round of patches. Changes:
* Moved it all to a new sercon.c file. * Code maps cp437 to utf8 now, giving a much nicer display. Compare "Use the ↑ and ↓ keys to change the selection." (this series) with "Use the ^ and v keys to change the selection." (sgabios) ;-) * Simplified keyboard code, using enqueue_key now. * Restructed code, to cleanup things and to address review comments.
cheers, Gerd
Gerd Hoffmann (3): std: add cp437 to unicode map kbd: make enqueue_key public, add ascii_to_keycode add serial console support
Makefile | 2 +- src/clock.c | 1 + src/kbd.c | 17 +- src/misc.c | 2 + src/optionroms.c | 4 +- src/sercon.c | 545 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/std/cp437.h | 258 ++++++++++++++++++++++++++ src/util.h | 5 + 8 files changed, 831 insertions(+), 3 deletions(-) create mode 100644 src/sercon.c create mode 100644 src/std/cp437.h
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/std/cp437.h | 258 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 src/std/cp437.h
diff --git a/src/std/cp437.h b/src/std/cp437.h new file mode 100644 index 0000000..fafb864 --- /dev/null +++ b/src/std/cp437.h @@ -0,0 +1,258 @@ +/* https://en.wikipedia.org/wiki/Code_page_437 */ +[ 0x00 ] = 0x0000, +[ 0x01 ] = 0x263A, +[ 0x02 ] = 0x263B, +[ 0x03 ] = 0x2665, +[ 0x04 ] = 0x2666, +[ 0x05 ] = 0x2663, +[ 0x06 ] = 0x2660, +[ 0x07 ] = 0x2022, +[ 0x08 ] = 0x25D8, +[ 0x09 ] = 0x25CB, +[ 0x0a ] = 0x25D9, +[ 0x0b ] = 0x2642, +[ 0x0c ] = 0x2640, +[ 0x0d ] = 0x266A, +[ 0x0e ] = 0x266B, +[ 0x0f ] = 0x263C, +[ 0x10 ] = 0x25BA, +[ 0x11 ] = 0x25C4, +[ 0x12 ] = 0x2195, +[ 0x13 ] = 0x203C, +[ 0x14 ] = 0x00B6, +[ 0x15 ] = 0x00A7, +[ 0x16 ] = 0x25AC, +[ 0x17 ] = 0x21A8, +[ 0x18 ] = 0x2191, +[ 0x19 ] = 0x2193, +[ 0x1a ] = 0x2192, +[ 0x1b ] = 0x2190, +[ 0x1c ] = 0x221F, +[ 0x1d ] = 0x2194, +[ 0x1e ] = 0x25B2, +[ 0x1f ] = 0x25BC, +/* http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT */ +[ 0x20 ] = 0x0020, // SPACE +[ 0x21 ] = 0x0021, // EXCLAMATION MARK +[ 0x22 ] = 0x0022, // QUOTATION MARK +[ 0x23 ] = 0x0023, // NUMBER SIGN +[ 0x24 ] = 0x0024, // DOLLAR SIGN +[ 0x25 ] = 0x0025, // PERCENT SIGN +[ 0x26 ] = 0x0026, // AMPERSAND +[ 0x27 ] = 0x0027, // APOSTROPHE +[ 0x28 ] = 0x0028, // LEFT PARENTHESIS +[ 0x29 ] = 0x0029, // RIGHT PARENTHESIS +[ 0x2a ] = 0x002a, // ASTERISK +[ 0x2b ] = 0x002b, // PLUS SIGN +[ 0x2c ] = 0x002c, // COMMA +[ 0x2d ] = 0x002d, // HYPHEN-MINUS +[ 0x2e ] = 0x002e, // FULL STOP +[ 0x2f ] = 0x002f, // SOLIDUS +[ 0x30 ] = 0x0030, // DIGIT ZERO +[ 0x31 ] = 0x0031, // DIGIT ONE +[ 0x32 ] = 0x0032, // DIGIT TWO +[ 0x33 ] = 0x0033, // DIGIT THREE +[ 0x34 ] = 0x0034, // DIGIT FOUR +[ 0x35 ] = 0x0035, // DIGIT FIVE +[ 0x36 ] = 0x0036, // DIGIT SIX +[ 0x37 ] = 0x0037, // DIGIT SEVEN +[ 0x38 ] = 0x0038, // DIGIT EIGHT +[ 0x39 ] = 0x0039, // DIGIT NINE +[ 0x3a ] = 0x003a, // COLON +[ 0x3b ] = 0x003b, // SEMICOLON +[ 0x3c ] = 0x003c, // LESS-THAN SIGN +[ 0x3d ] = 0x003d, // EQUALS SIGN +[ 0x3e ] = 0x003e, // GREATER-THAN SIGN +[ 0x3f ] = 0x003f, // QUESTION MARK +[ 0x40 ] = 0x0040, // COMMERCIAL AT +[ 0x41 ] = 0x0041, // LATIN CAPITAL LETTER A +[ 0x42 ] = 0x0042, // LATIN CAPITAL LETTER B +[ 0x43 ] = 0x0043, // LATIN CAPITAL LETTER C +[ 0x44 ] = 0x0044, // LATIN CAPITAL LETTER D +[ 0x45 ] = 0x0045, // LATIN CAPITAL LETTER E +[ 0x46 ] = 0x0046, // LATIN CAPITAL LETTER F +[ 0x47 ] = 0x0047, // LATIN CAPITAL LETTER G +[ 0x48 ] = 0x0048, // LATIN CAPITAL LETTER H +[ 0x49 ] = 0x0049, // LATIN CAPITAL LETTER I +[ 0x4a ] = 0x004a, // LATIN CAPITAL LETTER J +[ 0x4b ] = 0x004b, // LATIN CAPITAL LETTER K +[ 0x4c ] = 0x004c, // LATIN CAPITAL LETTER L +[ 0x4d ] = 0x004d, // LATIN CAPITAL LETTER M +[ 0x4e ] = 0x004e, // LATIN CAPITAL LETTER N +[ 0x4f ] = 0x004f, // LATIN CAPITAL LETTER O +[ 0x50 ] = 0x0050, // LATIN CAPITAL LETTER P +[ 0x51 ] = 0x0051, // LATIN CAPITAL LETTER Q +[ 0x52 ] = 0x0052, // LATIN CAPITAL LETTER R +[ 0x53 ] = 0x0053, // LATIN CAPITAL LETTER S +[ 0x54 ] = 0x0054, // LATIN CAPITAL LETTER T +[ 0x55 ] = 0x0055, // LATIN CAPITAL LETTER U +[ 0x56 ] = 0x0056, // LATIN CAPITAL LETTER V +[ 0x57 ] = 0x0057, // LATIN CAPITAL LETTER W +[ 0x58 ] = 0x0058, // LATIN CAPITAL LETTER X +[ 0x59 ] = 0x0059, // LATIN CAPITAL LETTER Y +[ 0x5a ] = 0x005a, // LATIN CAPITAL LETTER Z +[ 0x5b ] = 0x005b, // LEFT SQUARE BRACKET +[ 0x5c ] = 0x005c, // REVERSE SOLIDUS +[ 0x5d ] = 0x005d, // RIGHT SQUARE BRACKET +[ 0x5e ] = 0x005e, // CIRCUMFLEX ACCENT +[ 0x5f ] = 0x005f, // LOW LINE +[ 0x60 ] = 0x0060, // GRAVE ACCENT +[ 0x61 ] = 0x0061, // LATIN SMALL LETTER A +[ 0x62 ] = 0x0062, // LATIN SMALL LETTER B +[ 0x63 ] = 0x0063, // LATIN SMALL LETTER C +[ 0x64 ] = 0x0064, // LATIN SMALL LETTER D +[ 0x65 ] = 0x0065, // LATIN SMALL LETTER E +[ 0x66 ] = 0x0066, // LATIN SMALL LETTER F +[ 0x67 ] = 0x0067, // LATIN SMALL LETTER G +[ 0x68 ] = 0x0068, // LATIN SMALL LETTER H +[ 0x69 ] = 0x0069, // LATIN SMALL LETTER I +[ 0x6a ] = 0x006a, // LATIN SMALL LETTER J +[ 0x6b ] = 0x006b, // LATIN SMALL LETTER K +[ 0x6c ] = 0x006c, // LATIN SMALL LETTER L +[ 0x6d ] = 0x006d, // LATIN SMALL LETTER M +[ 0x6e ] = 0x006e, // LATIN SMALL LETTER N +[ 0x6f ] = 0x006f, // LATIN SMALL LETTER O +[ 0x70 ] = 0x0070, // LATIN SMALL LETTER P +[ 0x71 ] = 0x0071, // LATIN SMALL LETTER Q +[ 0x72 ] = 0x0072, // LATIN SMALL LETTER R +[ 0x73 ] = 0x0073, // LATIN SMALL LETTER S +[ 0x74 ] = 0x0074, // LATIN SMALL LETTER T +[ 0x75 ] = 0x0075, // LATIN SMALL LETTER U +[ 0x76 ] = 0x0076, // LATIN SMALL LETTER V +[ 0x77 ] = 0x0077, // LATIN SMALL LETTER W +[ 0x78 ] = 0x0078, // LATIN SMALL LETTER X +[ 0x79 ] = 0x0079, // LATIN SMALL LETTER Y +[ 0x7a ] = 0x007a, // LATIN SMALL LETTER Z +[ 0x7b ] = 0x007b, // LEFT CURLY BRACKET +[ 0x7c ] = 0x007c, // VERTICAL LINE +[ 0x7d ] = 0x007d, // RIGHT CURLY BRACKET +[ 0x7e ] = 0x007e, // TILDE +[ 0x7f ] = 0x007f, // DELETE +[ 0x80 ] = 0x00c7, // LATIN CAPITAL LETTER C WITH CEDILLA +[ 0x81 ] = 0x00fc, // LATIN SMALL LETTER U WITH DIAERESIS +[ 0x82 ] = 0x00e9, // LATIN SMALL LETTER E WITH ACUTE +[ 0x83 ] = 0x00e2, // LATIN SMALL LETTER A WITH CIRCUMFLEX +[ 0x84 ] = 0x00e4, // LATIN SMALL LETTER A WITH DIAERESIS +[ 0x85 ] = 0x00e0, // LATIN SMALL LETTER A WITH GRAVE +[ 0x86 ] = 0x00e5, // LATIN SMALL LETTER A WITH RING ABOVE +[ 0x87 ] = 0x00e7, // LATIN SMALL LETTER C WITH CEDILLA +[ 0x88 ] = 0x00ea, // LATIN SMALL LETTER E WITH CIRCUMFLEX +[ 0x89 ] = 0x00eb, // LATIN SMALL LETTER E WITH DIAERESIS +[ 0x8a ] = 0x00e8, // LATIN SMALL LETTER E WITH GRAVE +[ 0x8b ] = 0x00ef, // LATIN SMALL LETTER I WITH DIAERESIS +[ 0x8c ] = 0x00ee, // LATIN SMALL LETTER I WITH CIRCUMFLEX +[ 0x8d ] = 0x00ec, // LATIN SMALL LETTER I WITH GRAVE +[ 0x8e ] = 0x00c4, // LATIN CAPITAL LETTER A WITH DIAERESIS +[ 0x8f ] = 0x00c5, // LATIN CAPITAL LETTER A WITH RING ABOVE +[ 0x90 ] = 0x00c9, // LATIN CAPITAL LETTER E WITH ACUTE +[ 0x91 ] = 0x00e6, // LATIN SMALL LIGATURE AE +[ 0x92 ] = 0x00c6, // LATIN CAPITAL LIGATURE AE +[ 0x93 ] = 0x00f4, // LATIN SMALL LETTER O WITH CIRCUMFLEX +[ 0x94 ] = 0x00f6, // LATIN SMALL LETTER O WITH DIAERESIS +[ 0x95 ] = 0x00f2, // LATIN SMALL LETTER O WITH GRAVE +[ 0x96 ] = 0x00fb, // LATIN SMALL LETTER U WITH CIRCUMFLEX +[ 0x97 ] = 0x00f9, // LATIN SMALL LETTER U WITH GRAVE +[ 0x98 ] = 0x00ff, // LATIN SMALL LETTER Y WITH DIAERESIS +[ 0x99 ] = 0x00d6, // LATIN CAPITAL LETTER O WITH DIAERESIS +[ 0x9a ] = 0x00dc, // LATIN CAPITAL LETTER U WITH DIAERESIS +[ 0x9b ] = 0x00a2, // CENT SIGN +[ 0x9c ] = 0x00a3, // POUND SIGN +[ 0x9d ] = 0x00a5, // YEN SIGN +[ 0x9e ] = 0x20a7, // PESETA SIGN +[ 0x9f ] = 0x0192, // LATIN SMALL LETTER F WITH HOOK +[ 0xa0 ] = 0x00e1, // LATIN SMALL LETTER A WITH ACUTE +[ 0xa1 ] = 0x00ed, // LATIN SMALL LETTER I WITH ACUTE +[ 0xa2 ] = 0x00f3, // LATIN SMALL LETTER O WITH ACUTE +[ 0xa3 ] = 0x00fa, // LATIN SMALL LETTER U WITH ACUTE +[ 0xa4 ] = 0x00f1, // LATIN SMALL LETTER N WITH TILDE +[ 0xa5 ] = 0x00d1, // LATIN CAPITAL LETTER N WITH TILDE +[ 0xa6 ] = 0x00aa, // FEMININE ORDINAL INDICATOR +[ 0xa7 ] = 0x00ba, // MASCULINE ORDINAL INDICATOR +[ 0xa8 ] = 0x00bf, // INVERTED QUESTION MARK +[ 0xa9 ] = 0x2310, // REVERSED NOT SIGN +[ 0xaa ] = 0x00ac, // NOT SIGN +[ 0xab ] = 0x00bd, // VULGAR FRACTION ONE HALF +[ 0xac ] = 0x00bc, // VULGAR FRACTION ONE QUARTER +[ 0xad ] = 0x00a1, // INVERTED EXCLAMATION MARK +[ 0xae ] = 0x00ab, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +[ 0xaf ] = 0x00bb, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +[ 0xb0 ] = 0x2591, // LIGHT SHADE +[ 0xb1 ] = 0x2592, // MEDIUM SHADE +[ 0xb2 ] = 0x2593, // DARK SHADE +[ 0xb3 ] = 0x2502, // BOX DRAWINGS LIGHT VERTICAL +[ 0xb4 ] = 0x2524, // BOX DRAWINGS LIGHT VERTICAL AND LEFT +[ 0xb5 ] = 0x2561, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE +[ 0xb6 ] = 0x2562, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE +[ 0xb7 ] = 0x2556, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE +[ 0xb8 ] = 0x2555, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE +[ 0xb9 ] = 0x2563, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT +[ 0xba ] = 0x2551, // BOX DRAWINGS DOUBLE VERTICAL +[ 0xbb ] = 0x2557, // BOX DRAWINGS DOUBLE DOWN AND LEFT +[ 0xbc ] = 0x255d, // BOX DRAWINGS DOUBLE UP AND LEFT +[ 0xbd ] = 0x255c, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE +[ 0xbe ] = 0x255b, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE +[ 0xbf ] = 0x2510, // BOX DRAWINGS LIGHT DOWN AND LEFT +[ 0xc0 ] = 0x2514, // BOX DRAWINGS LIGHT UP AND RIGHT +[ 0xc1 ] = 0x2534, // BOX DRAWINGS LIGHT UP AND HORIZONTAL +[ 0xc2 ] = 0x252c, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL +[ 0xc3 ] = 0x251c, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT +[ 0xc4 ] = 0x2500, // BOX DRAWINGS LIGHT HORIZONTAL +[ 0xc5 ] = 0x253c, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL +[ 0xc6 ] = 0x255e, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE +[ 0xc7 ] = 0x255f, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE +[ 0xc8 ] = 0x255a, // BOX DRAWINGS DOUBLE UP AND RIGHT +[ 0xc9 ] = 0x2554, // BOX DRAWINGS DOUBLE DOWN AND RIGHT +[ 0xca ] = 0x2569, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL +[ 0xcb ] = 0x2566, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL +[ 0xcc ] = 0x2560, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT +[ 0xcd ] = 0x2550, // BOX DRAWINGS DOUBLE HORIZONTAL +[ 0xce ] = 0x256c, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL +[ 0xcf ] = 0x2567, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE +[ 0xd0 ] = 0x2568, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE +[ 0xd1 ] = 0x2564, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE +[ 0xd2 ] = 0x2565, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE +[ 0xd3 ] = 0x2559, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE +[ 0xd4 ] = 0x2558, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE +[ 0xd5 ] = 0x2552, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE +[ 0xd6 ] = 0x2553, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE +[ 0xd7 ] = 0x256b, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE +[ 0xd8 ] = 0x256a, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE +[ 0xd9 ] = 0x2518, // BOX DRAWINGS LIGHT UP AND LEFT +[ 0xda ] = 0x250c, // BOX DRAWINGS LIGHT DOWN AND RIGHT +[ 0xdb ] = 0x2588, // FULL BLOCK +[ 0xdc ] = 0x2584, // LOWER HALF BLOCK +[ 0xdd ] = 0x258c, // LEFT HALF BLOCK +[ 0xde ] = 0x2590, // RIGHT HALF BLOCK +[ 0xdf ] = 0x2580, // UPPER HALF BLOCK +[ 0xe0 ] = 0x03b1, // GREEK SMALL LETTER ALPHA +[ 0xe1 ] = 0x00df, // LATIN SMALL LETTER SHARP S +[ 0xe2 ] = 0x0393, // GREEK CAPITAL LETTER GAMMA +[ 0xe3 ] = 0x03c0, // GREEK SMALL LETTER PI +[ 0xe4 ] = 0x03a3, // GREEK CAPITAL LETTER SIGMA +[ 0xe5 ] = 0x03c3, // GREEK SMALL LETTER SIGMA +[ 0xe6 ] = 0x00b5, // MICRO SIGN +[ 0xe7 ] = 0x03c4, // GREEK SMALL LETTER TAU +[ 0xe8 ] = 0x03a6, // GREEK CAPITAL LETTER PHI +[ 0xe9 ] = 0x0398, // GREEK CAPITAL LETTER THETA +[ 0xea ] = 0x03a9, // GREEK CAPITAL LETTER OMEGA +[ 0xeb ] = 0x03b4, // GREEK SMALL LETTER DELTA +[ 0xec ] = 0x221e, // INFINITY +[ 0xed ] = 0x03c6, // GREEK SMALL LETTER PHI +[ 0xee ] = 0x03b5, // GREEK SMALL LETTER EPSILON +[ 0xef ] = 0x2229, // INTERSECTION +[ 0xf0 ] = 0x2261, // IDENTICAL TO +[ 0xf1 ] = 0x00b1, // PLUS-MINUS SIGN +[ 0xf2 ] = 0x2265, // GREATER-THAN OR EQUAL TO +[ 0xf3 ] = 0x2264, // LESS-THAN OR EQUAL TO +[ 0xf4 ] = 0x2320, // TOP HALF INTEGRAL +[ 0xf5 ] = 0x2321, // BOTTOM HALF INTEGRAL +[ 0xf6 ] = 0x00f7, // DIVISION SIGN +[ 0xf7 ] = 0x2248, // ALMOST EQUAL TO +[ 0xf8 ] = 0x00b0, // DEGREE SIGN +[ 0xf9 ] = 0x2219, // BULLET OPERATOR +[ 0xfa ] = 0x00b7, // MIDDLE DOT +[ 0xfb ] = 0x221a, // SQUARE ROOT +[ 0xfc ] = 0x207f, // SUPERSCRIPT LATIN SMALL LETTER N +[ 0xfd ] = 0x00b2, // SUPERSCRIPT TWO +[ 0xfe ] = 0x25a0, // BLACK SQUARE +[ 0xff ] = 0x00a0, // NO-BREAK SPACE
On Mon, Jul 04, 2016 at 10:39:52PM +0200, Gerd Hoffmann wrote:
Signed-off-by: Gerd Hoffmann kraxel@redhat.com
Nice!
[...]
--- /dev/null +++ b/src/std/cp437.h
Instead of making a header file and including it in an array in the C code I think it would be better to instead introduce cp437.c with:
u16 sercon_cp437[256] VARFSEG = { ... };
[...]
+[ 0x7f ] = 0x007f, // DELETE
That should be 0x2302 (see the wikipedia page).
-Kevin
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/kbd.c | 17 ++++++++++++++++- src/util.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/src/kbd.c b/src/kbd.c index 61d9df0..7c43129 100644 --- a/src/kbd.c +++ b/src/kbd.c @@ -51,7 +51,7 @@ kbd_init(void) , x + FIELD_SIZEOF(struct bios_data_area_s, kbd_buf)); }
-static u8 +u8 enqueue_key(u16 keycode) { u16 buffer_start = GET_BDA(kbd_buf_start_offset); @@ -376,6 +376,21 @@ static struct scaninfo { { 0x8600, 0x8800, 0x8a00, 0x8c00 }, /* F12 */ };
+u16 ascii_to_keycode(u8 ascii) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(scan_to_keycode); i++) { + if ((GET_GLOBAL(scan_to_keycode[i].normal) & 0xff) == ascii) + return GET_GLOBAL(scan_to_keycode[i].normal); + if ((GET_GLOBAL(scan_to_keycode[i].shift) & 0xff) == ascii) + return GET_GLOBAL(scan_to_keycode[i].shift); + if ((GET_GLOBAL(scan_to_keycode[i].control) & 0xff) == ascii) + return GET_GLOBAL(scan_to_keycode[i].control); + } + return 0; +} + // Handle a ps2 style scancode read from the keyboard. static void __process_key(u8 scancode) diff --git a/src/util.h b/src/util.h index 7b41207..cfcf4a3 100644 --- a/src/util.h +++ b/src/util.h @@ -184,6 +184,8 @@ int jpeg_show(struct jpeg_decdata *jpeg, unsigned char *pic, int width void kbd_init(void); void handle_15c2(struct bregs *regs); void process_key(u8 key); +u8 enqueue_key(u16 keycode); +u16 ascii_to_keycode(u8 ascii);
// misc.c extern int HaveRunPost;
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- Makefile | 2 +- src/clock.c | 1 + src/misc.c | 2 + src/optionroms.c | 4 +- src/sercon.c | 545 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/util.h | 3 + 6 files changed, 555 insertions(+), 2 deletions(-) create mode 100644 src/sercon.c
diff --git a/Makefile b/Makefile index 4930b3a..3f6248d 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ LD32BIT_FLAG:=-melf_i386
# Source files SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \ - system.c serial.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \ + system.c serial.c sercon.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \ hw/pci.c hw/timer.c hw/rtc.c hw/dma.c hw/pic.c hw/ps2port.c hw/serialio.c \ hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \ hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \ diff --git a/src/clock.c b/src/clock.c index e83e0f3..e44e112 100644 --- a/src/clock.c +++ b/src/clock.c @@ -295,6 +295,7 @@ clock_update(void) floppy_tick(); usb_check_event(); ps2_check_event(); + sercon_check_event(); }
// INT 08h System Timer ISR Entry Point diff --git a/src/misc.c b/src/misc.c index f02237c..f4b656d 100644 --- a/src/misc.c +++ b/src/misc.c @@ -11,6 +11,7 @@ #include "output.h" // debug_enter #include "stacks.h" // call16_int #include "string.h" // memset +#include "util.h" // serial_10
#define PORT_MATH_CLEAR 0x00f0
@@ -57,6 +58,7 @@ handle_10(struct bregs *regs) { debug_enter(regs, DEBUG_HDL_10); // don't do anything, since the VGA BIOS handles int10h requests + sercon_10(regs); }
// NMI handler diff --git a/src/optionroms.c b/src/optionroms.c index 65f7fe0..e6b308c 100644 --- a/src/optionroms.c +++ b/src/optionroms.c @@ -432,9 +432,11 @@ vgarom_setup(void) run_file_roms("vgaroms/", 1, NULL); rom_reserve(0);
- if (rom_get_last() == BUILD_ROM_START) + if (rom_get_last() == BUILD_ROM_START) { // No VGA rom found + sercon_enable(); return; + }
VgaROM = (void*)BUILD_ROM_START; enable_vga_console(); diff --git a/src/sercon.c b/src/sercon.c new file mode 100644 index 0000000..31e33f7 --- /dev/null +++ b/src/sercon.c @@ -0,0 +1,545 @@ +#include "biosvar.h" // SET_BDA +#include "bregs.h" // struct bregs +#include "stacks.h" // yield +#include "output.h" // dprintf +#include "util.h" // irqtimer_calc_ticks +#include "hw/serialio.h" // SEROFF_IER + +static u8 video_rows(void) +{ + return GET_BDA(video_rows)+1; +} + +static u8 video_cols(void) +{ + return GET_BDA(video_cols); +} + +static u8 cursor_pos_col(void) +{ + u16 pos = GET_BDA(cursor_pos[0]); + return pos & 0xff; +} + +static u8 cursor_pos_row(void) +{ + u16 pos = GET_BDA(cursor_pos[0]); + return (pos >> 8) & 0xff; +} + +static void cursor_pos_set(u8 row, u8 col) +{ + u16 pos = ((u16)row << 8) | col; + SET_BDA(cursor_pos[0], pos); +} + +/**************************************************************** + * serial console output + ****************************************************************/ + +VARLOW u16 sercon_port; + +/* + * We have a small output buffer here, for lazy output. That allows + * to avoid a whole bunch of control sequences for pointless cursor + * moves, so when logging the output it'll be *alot* less cluttered. + * + * sercon_char/attr is the actual output buffer. + * sercon_attr_last is the most recent attribute sent to the terminal. + * sercon_col_last is the most recent column sent to the terminal. + * sercon_row_last is the most recent row sent to the terminal. + */ +VARLOW u8 sercon_attr_last; +VARLOW u8 sercon_col_last; +VARLOW u8 sercon_row_last; +VARLOW u8 sercon_char[8]; +VARLOW u8 sercon_attr[8]; + +static VAR16 u8 sercon_cmap[8] = { '0', '4', '2', '6', '1', '5', '3', '7' }; +static VAR16 u16 sercon_cp437[256] = { +#include "std/cp437.h" +}; + +static void sercon_putchar(u8 chr) +{ + u16 addr = GET_LOW(sercon_port); + u32 end = irqtimer_calc_ticks(0x0a); + + for (;;) { + u8 lsr = inb(addr+SEROFF_LSR); + if ((lsr & 0x60) == 0x60) { + // Success - can write data + outb(chr, addr+SEROFF_DATA); + break; + } + if (irqtimer_check(end)) { + break; + } + yield(); + } +} + +static void sercon_term_reset(void) +{ + sercon_putchar('\x1b'); + sercon_putchar('c'); +} + +static void sercon_term_clear_screen(void) +{ + sercon_putchar('\x1b'); + sercon_putchar('['); + sercon_putchar('2'); + sercon_putchar('J'); +} + +static void sercon_term_cursor_right(void) +{ + sercon_putchar('\x1b'); + sercon_putchar('['); + sercon_putchar('C'); +} + +static void sercon_term_cursor_goto(u8 row, u8 col) +{ + row++; col++; + sercon_putchar('\x1b'); + sercon_putchar('['); + sercon_putchar('0' + row / 10); + sercon_putchar('0' + row % 10); + sercon_putchar(';'); + sercon_putchar('0' + col / 10); + sercon_putchar('0' + col % 10); + sercon_putchar('H'); +} + +static void sercon_term_set_color(u8 fg, u8 bg, u8 bold) +{ + sercon_putchar('\x1b'); + sercon_putchar('['); + sercon_putchar('0'); + if (fg != 7) { + sercon_putchar(';'); + sercon_putchar('3'); + sercon_putchar(GET_GLOBAL(sercon_cmap[fg & 7])); + } + if (bg != 0) { + sercon_putchar(';'); + sercon_putchar('4'); + sercon_putchar(GET_GLOBAL(sercon_cmap[bg & 7])); + } + if (bold) { + sercon_putchar(';'); + sercon_putchar('1'); + } + sercon_putchar('m'); +} + +static void sercon_set_attr(u8 attr) +{ + if (attr == GET_LOW(sercon_attr_last)) + return; + + SET_LOW(sercon_attr_last, attr); + sercon_term_set_color((attr >> 0) & 7, + (attr >> 4) & 7, + attr & 0x08); +} + +static void sercon_print_utf8(u8 chr) +{ + u16 unicode = GET_GLOBAL(sercon_cp437[chr]); + + if (unicode < 0x7f) { + sercon_putchar(unicode); + } else if (unicode < 0x7ff) { + sercon_putchar(0xc0 | ((unicode >> 6) & 0x1f)); + sercon_putchar(0x80 | ((unicode >> 0) & 0x3f)); + } else { + sercon_putchar(0xe0 | ((unicode >> 12) & 0x0f)); + sercon_putchar(0x80 | ((unicode >> 6) & 0x3f)); + sercon_putchar(0x80 | ((unicode >> 0) & 0x3f)); + } +} + +static void sercon_lazy_flush(void) +{ + u8 idx, chr, attr; + + for (idx = 0; idx < ARRAY_SIZE(sercon_char); idx++) { + chr = GET_LOW(sercon_char[idx]); + attr = GET_LOW(sercon_attr[idx]); + if (chr) { + sercon_set_attr(attr); + sercon_print_utf8(chr); + SET_LOW(sercon_col_last, GET_LOW(sercon_col_last) + 1); + continue; + } + if (GET_LOW(sercon_col_last) == cursor_pos_col() && + GET_LOW(sercon_row_last) == cursor_pos_row()) { + break; + } + sercon_term_cursor_right(); + SET_LOW(sercon_col_last, GET_LOW(sercon_col_last) + 1); + } + + if (GET_LOW(sercon_col_last) != cursor_pos_col() || + GET_LOW(sercon_row_last) != cursor_pos_row()) { + sercon_term_cursor_goto(cursor_pos_row(), cursor_pos_col()); + SET_LOW(sercon_col_last, cursor_pos_col()); + SET_LOW(sercon_row_last, cursor_pos_row()); + } + + for (idx = 0; idx < ARRAY_SIZE(sercon_char); idx++) { + SET_LOW(sercon_attr[idx], 0x07); + SET_LOW(sercon_char[idx], 0x00); + } +} + +static void sercon_lazy_putchar(u8 chr, u8 attr, u8 teletype) +{ + u8 idx; + + if (cursor_pos_row() != GET_LOW(sercon_row_last) || + cursor_pos_col() < GET_LOW(sercon_col_last) || + cursor_pos_col() >= GET_LOW(sercon_col_last) + ARRAY_SIZE(sercon_char)) { + sercon_lazy_flush(); + } + + idx = cursor_pos_col() - GET_LOW(sercon_col_last); + SET_LOW(sercon_char[idx], chr); + if (teletype) + cursor_pos_set(cursor_pos_row(), + cursor_pos_col()+1); + else + SET_LOW(sercon_attr[idx], attr); +} + +static void sercon_lazy_cursor_update(u8 row, u8 col) +{ + cursor_pos_set(row, col); + SET_LOW(sercon_col_last, row); + SET_LOW(sercon_row_last, col); +} + +static void sercon_lazy_backspace(void) +{ + u8 col; + + sercon_lazy_flush(); + col = cursor_pos_col(); + if (col > 0) { + sercon_putchar(8); + sercon_lazy_cursor_update(cursor_pos_row(), col-1); + } +} + +static void sercon_lazy_cr(void) +{ + sercon_lazy_flush(); + sercon_putchar('\r'); + sercon_lazy_cursor_update(cursor_pos_row(), 0); +} + +static void sercon_lazy_lf(void) +{ + u8 row; + + sercon_lazy_flush(); + sercon_putchar('\n'); + row = cursor_pos_row() + 1; + if (row >= video_rows()) + row = video_rows()-1; + sercon_lazy_cursor_update(row, cursor_pos_col()); +} + +/* Set video mode */ +static void sercon_1000(struct bregs *regs) +{ + int mode, rows, cols; + + mode = regs->al; + switch (mode) { + case 0x03: + default: + cols = 80; + rows = 25; + regs->al = 0x30; + } + SET_LOW(sercon_col_last, 0); + SET_LOW(sercon_row_last, 0); + + cursor_pos_set(0, 0); + SET_BDA(video_mode, mode); + SET_BDA(video_cols, cols); + SET_BDA(video_rows, rows-1); + SET_BDA(cursor_type, 0x0007); + + sercon_term_reset(); + sercon_term_clear_screen(); +} + +/* Set text-mode cursor shape */ +static void sercon_1001(struct bregs *regs) +{ + /* dummy (add show/hide cursor?) */ +} + +/* Set cursor position */ +static void sercon_1002(struct bregs *regs) +{ + u8 row = regs->dh; + u8 col = regs->dl; + + cursor_pos_set(row, col); +} + +/* Get cursor position */ +static void sercon_1003(struct bregs *regs) +{ + regs->ax = 0; + regs->ch = 0; + regs->cl = 7; + regs->dh = cursor_pos_row(); + regs->dl = cursor_pos_col(); +} + +/* Scroll up window */ +static void sercon_1006(struct bregs *regs) +{ + sercon_lazy_flush(); + if (regs->al == 0) { + /* clear rect, do only in case this looks like a fullscreen clear */ + if (regs->ch == 0 && + regs->cl == 0 && + regs->dh == video_rows()-1 && + regs->dl == video_cols()-1) { + sercon_set_attr(regs->bh); + sercon_term_clear_screen(); + } + } else { + sercon_putchar('\r'); + sercon_putchar('\n'); + } +} + +/* Read character and attribute at cursor position */ +static void sercon_1008(struct bregs *regs) +{ + regs->ah = 0x07; + regs->bh = ' '; +} + +/* Write character and attribute at cursor position */ +static void sercon_1009(struct bregs *regs) +{ + u16 count = regs->cx; + + if (count == 1) { + sercon_lazy_putchar(regs->al, regs->bl, 0); + + } else if (regs->al == 0x20 && + video_rows() * video_cols() == count && + cursor_pos_row() == 0 && + cursor_pos_col() == 0) { + /* override everything with spaces -> this is clear screen */ + sercon_lazy_flush(); + sercon_set_attr(regs->bl); + sercon_term_clear_screen(); + + } else { + sercon_lazy_flush(); + sercon_set_attr(regs->bl); + while (count) { + sercon_putchar(regs->al); + count--; + } + sercon_term_cursor_goto(cursor_pos_row(), + cursor_pos_col()); + } +} + +/* Teletype output */ +static void sercon_100e(struct bregs *regs) +{ + switch (regs->al) { + case 7: + // beep + break; + case 8: + sercon_lazy_backspace(); + break; + case '\r': + sercon_lazy_cr(); + break; + case '\n': + sercon_lazy_lf(); + break; + default: + sercon_lazy_putchar(regs->al, 0, 1); + break; + } +} + +/* Get current video mode */ +static void sercon_100f(struct bregs *regs) +{ + regs->al = GET_BDA(video_mode); + regs->ah = GET_BDA(video_cols); +} + +/* VBE 2.0 */ +static void sercon_104f(struct bregs *regs) +{ + regs->ax = 0x0100; +} + +static void sercon_10XX(struct bregs *regs) +{ + warn_unimplemented(regs); +} + +void VISIBLE16 +sercon_10(struct bregs *regs) +{ + if (!GET_LOW(sercon_port)) + return; + + switch (regs->ah) { + case 0x00: sercon_1000(regs); break; + case 0x01: sercon_1001(regs); break; + case 0x02: sercon_1002(regs); break; + case 0x03: sercon_1003(regs); break; + case 0x06: sercon_1006(regs); break; + case 0x08: sercon_1008(regs); break; + case 0x09: sercon_1009(regs); break; + case 0x0e: sercon_100e(regs); break; + case 0x0f: sercon_100f(regs); break; + case 0x4f: sercon_104f(regs); break; + default: sercon_10XX(regs); break; + } +} + +void sercon_enable(void) +{ + u16 addr = PORT_SERIAL1; + + SET_LOW(sercon_port, addr); + outb(0x03, addr + SEROFF_LCR); // 8N1 + outb(0x01, addr + 0x02); // enable fifo + enable_vga_console(); +} + +/**************************************************************** + * serial input + ****************************************************************/ + +VARLOW u8 rx_buf[16]; +VARLOW u8 rx_bytes; + +static VAR16 struct { + char seq[4]; + u8 len; + u16 keycode; +} termseq[] = { + { .seq = "OP", .len = 2, .keycode = 0x3b00 }, // F1 + { .seq = "OQ", .len = 2, .keycode = 0x3c00 }, // F2 + { .seq = "OR", .len = 2, .keycode = 0x3d00 }, // F3 + { .seq = "OS", .len = 2, .keycode = 0x3e00 }, // F4 + + { .seq = "[15~", .len = 4, .keycode = 0x3f00 }, // F5 + { .seq = "[17~", .len = 4, .keycode = 0x4000 }, // F6 + { .seq = "[18~", .len = 4, .keycode = 0x4100 }, // F7 + { .seq = "[19~", .len = 4, .keycode = 0x4200 }, // F8 + { .seq = "[20~", .len = 4, .keycode = 0x4300 }, // F9 + { .seq = "[21~", .len = 4, .keycode = 0x4400 }, // F10 + { .seq = "[23~", .len = 4, .keycode = 0x5700 }, // F11 + { .seq = "[24~", .len = 4, .keycode = 0x5800 }, // F12 + + { .seq = "[2~", .len = 3, .keycode = 0x52e0 }, // insert + { .seq = "[3~", .len = 3, .keycode = 0x53e0 }, // delete + { .seq = "[5~", .len = 3, .keycode = 0x49e0 }, // page up + { .seq = "[6~", .len = 3, .keycode = 0x51e0 }, // page down + + { .seq = "[A", .len = 2, .keycode = 0x48e0 }, // up + { .seq = "[B", .len = 2, .keycode = 0x50e0 }, // down + { .seq = "[C", .len = 2, .keycode = 0x4de0 }, // right + { .seq = "[D", .len = 2, .keycode = 0x4be0 }, // left + + { .seq = "[H", .len = 2, .keycode = 0x47e0 }, // home + { .seq = "[F", .len = 2, .keycode = 0x4fe0 }, // end +}; + +static void shiftbuf(int remove) +{ + int i, remaining; + + remaining = GET_LOW(rx_bytes) - remove; + SET_LOW(rx_bytes, remaining); + for (i = 0; i < remaining; i++) + SET_LOW(rx_buf[i], GET_LOW(rx_buf[i + remove])); +} + +void VISIBLE16 +sercon_check_event(void) +{ + u16 addr = GET_LOW(sercon_port); + u16 keycode; + u8 byte, count = 0; + int seq, chr, len; + + // check to see if there is a active serial port + if (!addr) + return; + if (inb(addr + SEROFF_LSR) == 0xFF) + return; + + // flush pending output + sercon_lazy_flush(); + + // read all available data + while (inb(addr + SEROFF_LSR) & 0x01) { + byte = inb(addr + SEROFF_DATA); + if (GET_LOW(rx_bytes) < sizeof(rx_buf)) { + SET_LOW(rx_buf[rx_bytes], byte); + SET_LOW(rx_bytes, GET_LOW(rx_bytes) + 1); + count++; + } + } + +next_char: + // no (more) input data + if (!GET_LOW(rx_bytes)) + return; + + // lookup escape sequences + if (GET_LOW(rx_bytes) > 1 && GET_LOW(rx_buf[0]) == 0x1b) { + for (seq = 0; seq < ARRAY_SIZE(termseq); seq++) { + len = GET_GLOBAL(termseq[seq].len); + if (GET_LOW(rx_bytes) < len + 1) + continue; + for (chr = 0; chr < len; chr++) { + if (GET_GLOBAL(termseq[seq].seq[chr]) != GET_LOW(rx_buf[chr + 1])) + break; + } + if (chr == len) { + enqueue_key(GET_GLOBAL(termseq[seq].keycode)); + shiftbuf(len + 1); + goto next_char; + } + } + } + + // Seems we got a escape sequence we didn't recognise. + // -> If we received data wait for more, maybe it is just incomplete. + if (GET_LOW(rx_buf[0]) == 0x1b && count) + return; + + // Handle input as individual chars. + chr = GET_LOW(rx_buf[0]); + keycode = ascii_to_keycode(chr); + if (keycode) + enqueue_key(keycode); + shiftbuf(1); + goto next_char; +} diff --git a/src/util.h b/src/util.h index cfcf4a3..1df8d0b 100644 --- a/src/util.h +++ b/src/util.h @@ -232,6 +232,9 @@ void code_mutable_preinit(void); // serial.c void serial_setup(void); void lpt_setup(void); +void sercon_10(struct bregs *regs); +void sercon_enable(void); +void sercon_check_event(void);
// vgahooks.c void handle_155f(struct bregs *regs);
On Mon, Jul 04, 2016 at 10:39:54PM +0200, Gerd Hoffmann wrote:
Signed-off-by: Gerd Hoffmann kraxel@redhat.com
Not sure if this is still an RFC. I think it needs to have a Kconfig option. It should probably also have runtime enable option.
[...]
--- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ LD32BIT_FLAG:=-melf_i386
# Source files SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \
- system.c serial.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \
- system.c serial.c sercon.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \
How about console.c instead of sercon.c?
[...]
--- /dev/null +++ b/src/sercon.c @@ -0,0 +1,545 @@
There should be a copyright statement.
[...]
+VARLOW u8 sercon_char[8]; +VARLOW u8 sercon_attr[8];
Out of curiosity, is 8 needed for effective "uncluttering" or is it an optimization? (That is, would a size of 1 suffice for the common case?)
[...]
+static void sercon_lazy_putchar(u8 chr, u8 attr, u8 teletype) +{
- u8 idx;
- if (cursor_pos_row() != GET_LOW(sercon_row_last) ||
cursor_pos_col() < GET_LOW(sercon_col_last) ||
cursor_pos_col() >= GET_LOW(sercon_col_last) + ARRAY_SIZE(sercon_char)) {
sercon_lazy_flush();
- }
- idx = cursor_pos_col() - GET_LOW(sercon_col_last);
- SET_LOW(sercon_char[idx], chr);
- if (teletype)
cursor_pos_set(cursor_pos_row(),
cursor_pos_col()+1);
This doesn't handle end of column wrapping properly.
- else
SET_LOW(sercon_attr[idx], attr);
+}
FYI, once sercon_1013 is implemented then 'teletype' is not mutually exclusive with 'use_attr'.
[...]
+static void sercon_1000(struct bregs *regs) +{
- int mode, rows, cols;
- mode = regs->al;
- switch (mode) {
- case 0x03:
- default:
cols = 80;
rows = 25;
regs->al = 0x30;
- }
- SET_LOW(sercon_col_last, 0);
- SET_LOW(sercon_row_last, 0);
- cursor_pos_set(0, 0);
- SET_BDA(video_mode, mode);
- SET_BDA(video_cols, cols);
- SET_BDA(video_rows, rows-1);
- SET_BDA(cursor_type, 0x0007);
- sercon_term_reset();
- sercon_term_clear_screen();
Should only clear screen if high-bit of regs->al not set.
+/* Set text-mode cursor shape */ +static void sercon_1001(struct bregs *regs) +{
- /* dummy (add show/hide cursor?) */
+}
Not sure if hiding the cursor is necessary, but it should SET_BDA(cursor_type, regs->cx)
[...]
+static void sercon_1003(struct bregs *regs) +{
- regs->ax = 0;
- regs->ch = 0;
- regs->cl = 7;
regs->cx = GET_BDA(cursor_type)
Not sure why regs->ax is cleared.
[...]
+static void sercon_1009(struct bregs *regs) +{
- u16 count = regs->cx;
- if (count == 1) {
sercon_lazy_putchar(regs->al, regs->bl, 0);
- } else if (regs->al == 0x20 &&
video_rows() * video_cols() == count &&
cursor_pos_row() == 0 &&
cursor_pos_col() == 0) {
/* override everything with spaces -> this is clear screen */
sercon_lazy_flush();
sercon_set_attr(regs->bl);
sercon_term_clear_screen();
- } else {
sercon_lazy_flush();
sercon_set_attr(regs->bl);
while (count) {
sercon_putchar(regs->al);
At a minimum that should be sercon_print_utf8(), though could sercon_lazy_putchar() be used?
[...]
+static void sercon_100e(struct bregs *regs) +{
- switch (regs->al) {
- case 7:
// beep
break;
sercon_putchar(0x07)
+void VISIBLE16 +sercon_10(struct bregs *regs) +{
- if (!GET_LOW(sercon_port))
return;
- switch (regs->ah) {
- case 0x00: sercon_1000(regs); break;
- case 0x01: sercon_1001(regs); break;
- case 0x02: sercon_1002(regs); break;
- case 0x03: sercon_1003(regs); break;
- case 0x06: sercon_1006(regs); break;
- case 0x08: sercon_1008(regs); break;
- case 0x09: sercon_1009(regs); break;
- case 0x0e: sercon_100e(regs); break;
- case 0x0f: sercon_100f(regs); break;
- case 0x4f: sercon_104f(regs); break;
- default: sercon_10XX(regs); break;
- }
+}
I noticed sercon_1007, sercon_100a, and sercon_1013 aren't implemented. I guess they aren't used frequently, but they've been around since the original IBM MDA adapter.
[...]
+void VISIBLE16 +sercon_check_event(void)
Not sure VISIBLE16 is needed.
+{
- u16 addr = GET_LOW(sercon_port);
- u16 keycode;
- u8 byte, count = 0;
- int seq, chr, len;
- // check to see if there is a active serial port
- if (!addr)
return;
- if (inb(addr + SEROFF_LSR) == 0xFF)
return;
- // flush pending output
- sercon_lazy_flush();
- // read all available data
- while (inb(addr + SEROFF_LSR) & 0x01) {
byte = inb(addr + SEROFF_DATA);
if (GET_LOW(rx_bytes) < sizeof(rx_buf)) {
SET_LOW(rx_buf[rx_bytes], byte);
SET_LOW(rx_bytes, GET_LOW(rx_bytes) + 1);
count++;
}
- }
+next_char:
- // no (more) input data
- if (!GET_LOW(rx_bytes))
return;
- // lookup escape sequences
- if (GET_LOW(rx_bytes) > 1 && GET_LOW(rx_buf[0]) == 0x1b) {
for (seq = 0; seq < ARRAY_SIZE(termseq); seq++) {
len = GET_GLOBAL(termseq[seq].len);
if (GET_LOW(rx_bytes) < len + 1)
continue;
for (chr = 0; chr < len; chr++) {
if (GET_GLOBAL(termseq[seq].seq[chr]) != GET_LOW(rx_buf[chr + 1]))
break;
}
if (chr == len) {
enqueue_key(GET_GLOBAL(termseq[seq].keycode));
shiftbuf(len + 1);
goto next_char;
}
}
- }
- // Seems we got a escape sequence we didn't recognise.
- // -> If we received data wait for more, maybe it is just incomplete.
- if (GET_LOW(rx_buf[0]) == 0x1b && count)
return;
- // Handle input as individual chars.
- chr = GET_LOW(rx_buf[0]);
- keycode = ascii_to_keycode(chr);
- if (keycode)
enqueue_key(keycode);
- shiftbuf(1);
- goto next_char;
+}
I would prefer if we could avoid backwards gotos.
In general, looks good. -Kevin
On Di, 2016-07-05 at 10:30 -0400, Kevin O'Connor wrote:
On Mon, Jul 04, 2016 at 10:39:54PM +0200, Gerd Hoffmann wrote:
Signed-off-by: Gerd Hoffmann kraxel@redhat.com
Not sure if this is still an RFC. I think it needs to have a Kconfig option. It should probably also have runtime enable option.
Yes, still RfC. I want have feature parity with sgabios before merging this. Big missing piece is output to both vga and serial, and various little things like implementing the missing interrupts.
runtime option is there meanwhile, using NOGRAPHIC as suggested by paolo:
https://www.kraxel.org/cgit/seabios/commit/?h=serial&id=21e51b3e0a37733e...
compile time option will be added too.
I also hacked up a patch to send output to both vga + serial:
https://www.kraxel.org/cgit/seabios/commit/?h=serial&id=3afd7b8bb96126b0...
Not working stable though, seems to corrupt memory, not sure why. I'm storing the vgabios int10 vector at 0x5f, then chain-call into vgabios via "int 5f" instruction. Anything obviously wrong with that?
# Source files SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \
- system.c serial.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \
- system.c serial.c sercon.c clock.c resume.c pnpbios.c vgahooks.c pcibios.c apm.c \
How about console.c instead of sercon.c?
sercon.c is consistent with the sercon_* naming of most functions.
[...]
+VARLOW u8 sercon_char[8]; +VARLOW u8 sercon_attr[8];
Out of curiosity, is 8 needed for effective "uncluttering" or is it an optimization? (That is, would a size of 1 suffice for the common case?)
I think size 1 (maybe 2) would catch (almost?) all cases too.
I've started with a complete line (80), then decided to try something smaller so the flushing is triggered more often and I can easily see whenever it works as intended or not. So I removed the '0', '8' left and it still looks that way ;)
I've also tried to use the sgabios approach of not buffering any characters and be only lazy on cursor updates instead. That didn't work well with ipxe though which uses int10/09 (set char + attr, don't move cursor) + int10/03 (set char only, move cursor) combination to print colored + bold characters.
- } else {
sercon_lazy_flush();
sercon_set_attr(regs->bl);
while (count) {
sercon_putchar(regs->al);
At a minimum that should be sercon_print_utf8(), though could sercon_lazy_putchar() be used?
The use patterns I've seen are either single chars (which already go through sercon_lazy_putchar) or bulky output to fill/clear screen areas much larger than our 8 char buffer, so using sercon_lazy_putchar looks pointless for those.
I'll go over the other comments too and fix up things for the next round.
cheers, Gerd
On Tue, Jul 05, 2016 at 05:07:08PM +0200, Gerd Hoffmann wrote:
I also hacked up a patch to send output to both vga + serial:
https://www.kraxel.org/cgit/seabios/commit/?h=serial&id=3afd7b8bb96126b0...
Not working stable though, seems to corrupt memory, not sure why. I'm storing the vgabios int10 vector at 0x5f, then chain-call into vgabios via "int 5f" instruction. Anything obviously wrong with that?
Not sure why it isn't working. Take a look at vgaentry.S:entry_timer_hook and vgainit.c:hook_timer_irq() though. That shows a working example of "hooking" an interrupt.
As an aside, I think it would be better if save/restoring the BDA cursor position could be avoided.
-Kevin
On Mon, Jul 04, 2016 at 10:39:51PM +0200, Gerd Hoffmann wrote:
Hi,
Next round of patches. Changes:
- Moved it all to a new sercon.c file.
- Code maps cp437 to utf8 now, giving a much nicer display. Compare "Use the ↑ and ↓ keys to change the selection." (this series) with "Use the ^ and v keys to change the selection." (sgabios) ;-)
- Simplified keyboard code, using enqueue_key now.
- Restructed code, to cleanup things and to address review comments.
Currently libvirt has an option to turn on serial console support for the BIOS. When this is set it adds the sga device. How will libvirt know when seabios has this feature built-in, and thus does not need to add the sga device ?
Regards, Daniel
On Di, 2016-07-05 at 09:06 +0100, Daniel P. Berrange wrote:
On Mon, Jul 04, 2016 at 10:39:51PM +0200, Gerd Hoffmann wrote:
Hi,
Next round of patches. Changes:
- Moved it all to a new sercon.c file.
- Code maps cp437 to utf8 now, giving a much nicer display. Compare "Use the ↑ and ↓ keys to change the selection." (this series) with "Use the ^ and v keys to change the selection." (sgabios) ;-)
- Simplified keyboard code, using enqueue_key now.
- Restructed code, to cleanup things and to address review comments.
Currently libvirt has an option to turn on serial console support for the BIOS. When this is set it adds the sga device. How will libvirt know when seabios has this feature built-in, and thus does not need to add the sga device ?
Current code activates the serial console (unconditionally) in case no vga is present. I want also support output on both vga and serial console, but code for the later isn't there yet.
What the final default behavior will be is not clear yet. Not enabled? Enabled in case no VGA is present? Enabled unconditionally (simliar to ovmf)?
Likewise it is not clear yet how we'll go enable/disable this.
One option would be to continue using sgabios.bin in fw_cfg. But instead of loading and executing it activate the build-in serial console if we find the file. That would make the switch completely transparent to upper layers. But it is quite hackish of course ...
Comments and ideas are welcome.
cheers, Gerd
On Tue, Jul 05, 2016 at 12:00:48PM +0200, Gerd Hoffmann wrote:
On Di, 2016-07-05 at 09:06 +0100, Daniel P. Berrange wrote:
On Mon, Jul 04, 2016 at 10:39:51PM +0200, Gerd Hoffmann wrote:
Hi,
Next round of patches. Changes:
- Moved it all to a new sercon.c file.
- Code maps cp437 to utf8 now, giving a much nicer display. Compare "Use the ↑ and ↓ keys to change the selection." (this series) with "Use the ^ and v keys to change the selection." (sgabios) ;-)
- Simplified keyboard code, using enqueue_key now.
- Restructed code, to cleanup things and to address review comments.
Currently libvirt has an option to turn on serial console support for the BIOS. When this is set it adds the sga device. How will libvirt know when seabios has this feature built-in, and thus does not need to add the sga device ?
Current code activates the serial console (unconditionally) in case no vga is present. I want also support output on both vga and serial console, but code for the later isn't there yet.
What the final default behavior will be is not clear yet. Not enabled? Enabled in case no VGA is present? Enabled unconditionally (simliar to ovmf)?
(Bitter) experiance in libvirt has shown us that magically enabling things based on whether or not some other feature is enabled leads to pain and suffering in the long term.
So from libvirt's POV, we would like an explicit command line flag to turn on/off seabios serial console support, with no dependancy on whether VGA is present or not.
Regards, Daniel
On 05/07/2016 12:07, Daniel P. Berrange wrote:
What the final default behavior will be is not clear yet. Not enabled? Enabled in case no VGA is present? Enabled unconditionally (simliar to ovmf)?
(Bitter) experiance in libvirt has shown us that magically enabling things based on whether or not some other feature is enabled leads to pain and suffering in the long term.
So from libvirt's POV, we would like an explicit command line flag to turn on/off seabios serial console support, with no dependancy on whether VGA is present or not.
With my other proposal, "-machine graphics=no -device sga" should do it.
However, for libvirt to do this, it should stop using "-nographic" to disable all display backends, and instead use "-display none". The advantage is that neither "-display none" nor "-machine graphics=no" do any magic redirection of the monitor and the serial ports to stdio.
"-display none" is supported since QEMU 1.0. For old QEMU without query-command-line-options it can be scraped from help text; for new QEMU with query-command-line-options it can be treated as always there.
Paolo
On Tue, Jul 05, 2016 at 01:45:10PM +0200, Paolo Bonzini wrote:
On 05/07/2016 12:07, Daniel P. Berrange wrote:
What the final default behavior will be is not clear yet. Not enabled? Enabled in case no VGA is present? Enabled unconditionally (simliar to ovmf)?
(Bitter) experiance in libvirt has shown us that magically enabling things based on whether or not some other feature is enabled leads to pain and suffering in the long term.
So from libvirt's POV, we would like an explicit command line flag to turn on/off seabios serial console support, with no dependancy on whether VGA is present or not.
With my other proposal, "-machine graphics=no -device sga" should do it.
Ok, so that combination would just "do the right thing" and use Seabios built-in serial if available, and fallback to sgabios if not.
However, for libvirt to do this, it should stop using "-nographic" to disable all display backends, and instead use "-display none". The advantage is that neither "-display none" nor "-machine graphics=no" do any magic redirection of the monitor and the serial ports to stdio.
"-display none" is supported since QEMU 1.0. For old QEMU without query-command-line-options it can be scraped from help text; for new QEMU with query-command-line-options it can be treated as always there.
Sure, switching to -display none instead of -nographic is no problem at all.
Regards, Daniel
On 05/07/2016 12:00, Gerd Hoffmann wrote:
One option would be to continue using sgabios.bin in fw_cfg. But instead of loading and executing it activate the build-in serial console if we find the file. That would make the switch completely transparent to upper layers. But it is quite hackish of course ...
OpenBIOS uses FW_CFG_NOGRAPHIC for this, which is the negation of qdev_get_machine()->enable_graphics and set by both "-nographic" and "-machine graphics=no" ("-nographic" is a shortcut for "-display none -machine graphics=no"). The default is "-machine graphics=yes".
As long as QEMU doesn't enable both FW_CFG_NOGRAPHIC and sgabios.bin, it should be fine. For example, if SeaBIOS's serial console is made accessible with "-machine graphics=no", then:
* QEMU's "-device sga" should do nothing if machine->enable_graphics is set.
* For old machine types, QEMU should hardcode FW_CFG_NOGRAPHIC to false(*) so that sgabios is never blocked.
For new machine types, SGABIOS will still be accessible with "-device sga". New machine types depend on SeaBIOS that has a serial console, otherwise "-nographic -device sga" breaks.
Paolo
(*) Hardcoding FW_CFG_NOGRAPHIC to false doesn't match what old QEMU does, but provides the best backwards-compatibility:
- old->new: Because old QEMU provides sgabios, you have to include sgabios.bin in the destination too or migration fails. After migration, the BIOS comes from old QEMU and itnever looks at FW_CFG_NOGRAPHIC, so the value doesn't matter---we just make it false.
- new->old: Because old QEMU expects sgabios to be there, you have to include sgabios.bin. The BIOS comes from new QEMU and looks at FW_CFG_NOGRAPHIC. To avoid double hooking FW_CFG_NOGRAPHIC has to be false.