ldlinux: Add support for parsing "serial" config directive
authorMatt Fleming <matt.fleming@linux.intel.com>
Fri, 27 May 2011 16:10:32 +0000 (17:10 +0100)
committerMatt Fleming <matt.fleming@linux.intel.com>
Tue, 7 Jun 2011 19:02:55 +0000 (20:02 +0100)
Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
com32/elflink/ldlinux/readconfig.c
core/conio.inc
core/diskfs.inc
core/diskstart.inc
core/include/core.h
core/isolinux.asm
core/parseconfig.inc
core/pxelinux.asm
core/serirq.inc

index add6994..f0e45e9 100644 (file)
@@ -11,6 +11,7 @@
  *
  * ----------------------------------------------------------------------- */
 
+#include <sys/io.h>
 #include <stdio.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <syslinux/adv.h>
 #include <syslinux/config.h>
 #include <dprintf.h>
+#include <ctype.h>
 
 #include "menu.h"
 #include "config.h"
 #include "getkey.h"
+#include "core.h"
 
 const struct menu_parameter mparm[NPARAMS] = {
     [P_WIDTH] = {"width", 0},
@@ -112,14 +115,6 @@ static struct menu *find_menu(const char *label)
 
 #define MAX_LINE 4096
 
-static char *skipspace(char *p)
-{
-    while (*p && my_isspace(*p))
-       p++;
-
-    return p;
-}
-
 /* Strip ^ from a string, returning a new reference to the same refstring
    if none present */
 static const char *strip_caret(const char *str)
@@ -709,6 +704,30 @@ static char *is_fkey(char *cmdstr, int *fkeyno)
     return q;
 }
 
+extern uint8_t FlowIgnore;
+extern uint8_t FlowInput;
+extern uint8_t FlowOutput;
+extern uint16_t SerialPort;
+extern uint16_t BaudDivisor;
+extern uint8_t SerialNotice;
+
+#define DEFAULT_BAUD   9600
+#define BAUD_DIVISOR   115200
+#define serial_base    0x0400
+
+extern void sirq_cleanup_nowipe(void);
+extern void sirq_install(void);
+extern void write_serial_str(void);
+
+static inline void io_delay(void)
+{
+       outb(0, 0x80);
+       outb(0, 0x80);
+}
+
+extern char syslinux_banner[];
+extern char copyright_str[];
+
 static void parse_config_file(FILE * f)
 {
     char line[MAX_LINE], *p, *ep, ch;
@@ -1130,10 +1149,126 @@ do_include:
 
        /* serial setting, bps, flow control */
        else if (looking_at(p, "serial")) {
-               /* core/conio.inc
-                * should be able to find some code in com32
+               com32sys_t ireg;
+               uint16_t port, flow;
+               uint32_t baud;
+
+               p = skipspace(p + 6);
+               port = atoi(p);
+
+               while (isalnum(*p))
+                       p++;
+               p = skipspace(p);
+
+               /* Default to no flow control */
+               FlowOutput = 0;
+               FlowInput = 0;
+
+               baud = DEFAULT_BAUD;
+               if (isalnum(*p)) {
+                       uint8_t ignore;
+
+                       /* setup baud */
+                       baud = atoi(p);
+                       while (isalnum(*p))
+                               p++;
+                       p = skipspace(p);
+
+                       ignore = 0;
+                       flow = 0;
+                       if (isalnum(*p)) {
+                               /* flow control */
+                               flow = atoi(p);
+                               ignore = ((flow & 0x0F00) >> 4);
+                       }
+
+                       FlowIgnore = ignore;
+                       flow = ((flow & 0xff) << 8) | (flow & 0xff);
+                       flow &= 0xF00B;
+                       FlowOutput = (flow & 0xff);
+                       FlowInput = ((flow & 0xff00) >> 8);
+               }
+
+               /*
+                * Parse baud
                 */
+               if (baud < 75) {
+                       /* < 75 baud == bogus */
+                       SerialPort = 0;
+                       continue;
+               }
+
+               baud = BAUD_DIVISOR / baud;
+               baud &= 0xffff;
+               BaudDivisor = baud;
+
+               /*
+                * If port > 3 then port is I/O addr
+                */
+               if (port <= 3) {
+                       /* Get the I/O port from the BIOS */
+                       port <<= 1;
+                       port = *(volatile uint16_t *)serial_base;
+               }
+
+               
+               SerialPort = port;
+
+               /*
+                * Begin code to actually set up the serial port
+                */
+               memset(&ireg, 0, sizeof(ireg));
+               call16(sirq_cleanup_nowipe, &ireg, NULL);
+
+               outb(0x83, port + 3); /* Enable DLAB */
+               io_delay();
+
+               outb((baud & 0xff), port); /* write divisor to LS */
+               io_delay();
+
+               outb(((baud & 0xff00) >> 8), port + 1); /* write to MS */
+               io_delay();
+
+               outb(0x03, port + 3); /* Disable DLAB */
+               io_delay();
+
+               /*
+                * Read back LCR (detect missing hw). If nothing here
+                * we'll read 00 or FF.
+                */
+               if (inb(port + 3) != 0x03) {
+                       /* Assume serial port busted */
+                       SerialPort = 0;
+                       continue;
+               }
+
+               outb(0x01, port + 2); /* Enable FIFOs if present */
+               io_delay();
+
+               /* Disable FIFO if unusable */
+               if (inb(port + 2) < 0x0C0) {
+                       outb(0, port + 2);
+                       io_delay();
+               }
+
+               /* Assert bits in MCR */
+               outb(FlowOutput, port + 4);
+               io_delay();
+
+               /* Enable interrupts if requested */
+               if (FlowOutput & 0x8)
+                       call16(sirq_install, &ireg, NULL);
 
+               /* Show some life */
+               if (SerialNotice != 0) {
+                       SerialNotice = 0;
+
+                       ireg.esi.w[0] = syslinux_banner;
+                       call16(write_serial_str, &ireg, NULL);
+
+                       ireg.esi.w[0] = copyright_str;
+                       call16(write_serial_str, &ireg, NULL);
+               }
        } else if (looking_at(p, "say")) {
                printf("%s\n", p + 4);
        }
@@ -1166,6 +1301,10 @@ static int parse_one_config(const char *filename)
        if (f)
                goto config_found;
 
+       f = fopen("pxelinux.cfg/default", "r");
+       if (f)
+               goto config_found;
+
        return -1;
 config_found:
        parse_config_file(f);
index b450502..6d6f234 100644 (file)
@@ -274,6 +274,7 @@ write_serial_str_displaymask:
                test byte [DisplayMask], 04h
                jz write_serial_str.end
 
+               global write_serial_str
 write_serial_str:
 .loop          lodsb
                and al,al
@@ -415,6 +416,7 @@ VidRows         resb 1                      ; Rows on screen-1
 ; loading a new config file to undo this setting.
                section .data16
                alignz 4
+               global SerialPort, BaudDivisor, FlowIgnore, FlowInput, FlowOutput
 SerialPort     dw 0                    ; Serial port base (or 0 for no serial port)
 BaudDivisor    dw 115200/9600          ; Baud rate divisor
 FlowControl    equ $
index 470aa42..2684328 100644 (file)
@@ -125,6 +125,7 @@ kaboom2:
 ; -----------------------------------------------------------------------------
 
                section .data16
+               global copyright_str
 copyright_str   db ' Copyright (C) 1994-'
                asciidec YEAR
                db ' H. Peter Anvin et al', CR, LF, 0
index e0a710d..c8f7936 100644 (file)
@@ -514,6 +514,7 @@ SuperInfo   resq 16                 ; The first 16 bytes expanded 8 times
 ; Banner information not needed in sector 1
 ;
                section .data16
+               global syslinux_banner
 syslinux_banner        db CR, LF, MY_NAME, ' ', VERSION_STR
 late_banner    db ' ', DATE_STR, 0
 
index 6e6f7fb..4435922 100644 (file)
@@ -14,6 +14,8 @@ extern char ConfigName[];
 extern char KernelName[];
 extern char cmd_line[];
 extern char ConfigFile[];
+extern char syslinux_banner[];
+extern char copyright_str[];
 
 /* diskstart.inc isolinux.asm*/
 extern void getlinsec(void);
index 344cb1e..895468c 100644 (file)
@@ -1034,6 +1034,7 @@ writestr_early    equ writestr
 ; Data that needs to be in the first sector
 ; -----------------------------------------------------------------------------
 
+               global syslinux_banner, copyright_str
 syslinux_banner        db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
 copyright_str   db ' Copyright (C) 1994-'
                asciidec YEAR
index 512f16b..f24efe4 100644 (file)
@@ -432,6 +432,7 @@ commit_vk:
                ret
 
                section .data16
+               global SerialNotice
 vk_overflow_msg        db 'Out of memory parsing config file', CR, LF, 0
 SerialNotice   db 1                    ; Only print this once
 
index 10fe72e..8c56022 100644 (file)
@@ -518,6 +518,7 @@ writestr_early      equ writestr
 
                section .data16
 
+               global copyright_str, syslinux_banner
 copyright_str   db ' Copyright (C) 1994-'
                asciidec YEAR
                db ' H. Peter Anvin et al', CR, LF, 0
index 47ccd50..bd08b69 100644 (file)
@@ -96,6 +96,7 @@ IRQMask               resw 1                  ; PIC IRQ mask status
 
                section .text16
 
+               global sirq_install
 sirq_install:
                pushad
 
@@ -155,6 +156,7 @@ sirq_install:
                popad
                ret
 
+               global sirq_cleanup_nowipe
 sirq_cleanup_nowipe:
                pushad
                push ds