From f1e5076de4234fa7f71a1f6d8801b8f8ee60b726 Mon Sep 17 00:00:00 2001 From: marcus Date: Fri, 19 Sep 2003 17:49:59 +0000 Subject: laden/ 2003-09-19 Marcus Brinkmann * Makefile.am (laden_CFLAGS): Add -I$(top_srcdir)/libc-parts. * output.c: Include and . * output.h (struct output_driver): Add CFG argument to INIT function. (output_init): Make NAME argument const, rename it to DRIVER. * output.c (output_init): Likewise. Only check if the prefix of DRIVER is a driver name. Then skip a trailing comma and pass the remainder via the new variable DRIVER_CFG to the init function of the driver. * output-vga.c (vga_init): Add CFG argument. * output-serial.c: New file by Daniel Wagner . wortel/ 2003-09-19 Marcus Brinkmann * Makefile.am (wortel_CFLAGS): Add -I$(top_srcdir)/libc-parts. * output.c: Include and . * output.h (struct output_driver): Add CFG argument to INIT function. (output_init): Make NAME argument const, rename it to DRIVER. * output.c (output_init): Likewise. Only check if the prefix of DRIVER is a driver name. Then skip a trailing comma and pass the remainder via the new variable DRIVER_CFG to the init function of the driver. * output-vga.c (vga_init): Add CFG argument. * output-serial.c: New file by Daniel Wagner . --- laden/ChangeLog | 14 +++++ laden/Makefile.am | 5 +- laden/README | 19 +++++- laden/ia32-output.c | 2 + laden/output-serial.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++ laden/output-vga.c | 2 +- laden/output.c | 25 ++++++-- laden/output.h | 15 +++-- 8 files changed, 225 insertions(+), 15 deletions(-) create mode 100644 laden/output-serial.c (limited to 'laden') diff --git a/laden/ChangeLog b/laden/ChangeLog index fbbd212..2568a5a 100644 --- a/laden/ChangeLog +++ b/laden/ChangeLog @@ -1,3 +1,17 @@ +2003-09-19 Marcus Brinkmann + + * Makefile.am (laden_CFLAGS): Add -I$(top_srcdir)/libc-parts. + * output.c: Include and . + * output.h (struct output_driver): Add CFG argument to INIT + function. + (output_init): Make NAME argument const, rename it to DRIVER. + * output.c (output_init): Likewise. Only check if the prefix of + DRIVER is a driver name. Then skip a trailing comma and pass the + remainder via the new variable DRIVER_CFG to the init function of + the driver. + * output-vga.c (vga_init): Add CFG argument. + * output-serial.c: New file by Daniel Wagner . + 2003-07-26 Marcus Brinkmann * Initial check-in. diff --git a/laden/Makefile.am b/laden/Makefile.am index 4c9e9a1..09d1048 100644 --- a/laden/Makefile.am +++ b/laden/Makefile.am @@ -20,12 +20,13 @@ if ARCH_IA32 ARCH_SOURCES = multiboot.h ia32-crt0.S ia32-cmain.c \ - ia32-output.c output-vga.c ia32-shutdown.c + ia32-output.c output-vga.c output-serial.c ia32-shutdown.c endif noinst_PROGRAMS = laden -laden_CFLAGS = -I$(srcdir) -I$(top_srcdir)/include $(AM_CFLAGS) +laden_CFLAGS = -I$(srcdir) -I$(top_srcdir)/include \ + -I$(top_srcdir)/libc-parts $(AM_CFLAGS) laden_SOURCES = $(ARCH_SOURCES) \ output.h output.c output-none.c \ diff --git a/laden/README b/laden/README index 945ebe1..da490f4 100644 --- a/laden/README +++ b/laden/README @@ -35,6 +35,23 @@ The available output drivers are architecture specific (see below for details). You can suppress all output by using the output driver "none", which is available on all architectures. +Some drivers support options. You list the options you want to use +directly following the driver name, separated by commas. For example, +to specify COM2 and a baud rate of 9600, you would use the option "-o +serial,uart2,speed=9600". Note that spaces are not allowed (as spaces +separate the arguments to laden). Which options are recognized +depends on the driver. + +Serial output +------------- + +The serial output driver supports options to configure the serial +port. The following options are recognized: + +uart1 Select UART1 (aka COM1). +uart2 Select UART2 (aka COM2). +speed=BAUD Set the baud rate to BAUD. Possible values are 50 to 115200. + Architecture Specific Notes =========================== @@ -51,4 +68,4 @@ addresses so that the programs do not overlap. The boot info field in the KIP will be set to the multiboot information structure. -On this architecture laden supports VGA output. +On this architecture, laden supports VGA and serial output. diff --git a/laden/ia32-output.c b/laden/ia32-output.c index 88c45cc..f4ad778 100644 --- a/laden/ia32-output.c +++ b/laden/ia32-output.c @@ -26,12 +26,14 @@ extern struct output_driver vga_output; +extern struct output_driver serial_output; extern struct output_driver no_output; /* A list of all output drivers, terminated with a null pointer. */ struct output_driver *output_drivers[] = { &vga_output, + &serial_output, &no_output, 0 }; diff --git a/laden/output-serial.c b/laden/output-serial.c new file mode 100644 index 0000000..9b5e2e7 --- /dev/null +++ b/laden/output-serial.c @@ -0,0 +1,158 @@ +/* output-serial.c - A serial port output driver. + Copyright (C) 2003 Free Software Foundation, Inc. + Written by Daniel Wagner. + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "output.h" + + +/* The base I/O ports for the serial device ports COM1 and COM2. */ +#define UART1_BASE 0x3f8 +#define UART2_BASE 0x2f8 + +/* The selected base port. */ +static unsigned short int uart_base = UART1_BASE; + +/* The data register. */ +#define UART_DR (uart_base + 0) + +/* The interrupt enable and ID registers. */ +#define UART_IER (uart_base + 1) +#define UART_IIR (uart_base + 2) + +/* The line and modem control and status registers. */ +#define UART_LCR (uart_base + 3) +#define UART_MCR (uart_base + 4) +#define UART_LSR (uart_base + 5) +#define UART_LSR_THRE (1 << 5) +#define UART_MSR (uart_base + 6) + + +/* Baudrate divisor LSB and MSB registers. */ +#define UART_LSB (uart_base + 0) +#define UART_MSB (uart_base + 1) + +/* The default speed setting. */ +#define UART_SPEED_MAX 115200 +#define UART_SPEED_MIN 50 +#define UART_SPEED_DEFAULT UART_SPEED_MAX + + +static void +serial_init (const char *driver_cfg) +{ + static const char delimiters[] = ","; + /* Twice the desired UART speed, to allow for .5 values. */ + unsigned int uart_speed = 2 * UART_SPEED_DEFAULT; + unsigned int divider; + volatile int busy_wait_var; + + if (driver_cfg) + { + char *cfg = strdupa (driver_cfg); + char *token = strtok (cfg, delimiters); + + while (token) + { + if (!strcmp (token, "uart1")) + uart_base = UART1_BASE; + if (!strcmp (token, "uart2")) + uart_base = UART2_BASE; + if (!strncmp (token, "speed=", 6)) + { + char *tail; + unsigned long new_speed; + + errno = 0; + new_speed = strtoul (&token[6], &tail, 0); + + /* Allow .5 for speeds like 134.5. */ + new_speed <<= 1; + if (tail[0] == '.' && tail[1] == '5') + { + new_speed++; + tail += 2; + } + if (!errno && !*tail + && new_speed > UART_SPEED_MIN && new_speed < UART_SPEED_MAX) + uart_speed = new_speed; + } + token = strtok (NULL, delimiters); + } + } + + /* Parity bit. */ + outb (UART_LCR, 0x80); + + /* FIXME: Wait a bit. Would be nice to have a real sleep function. */ + for (busy_wait_var = 0; busy_wait_var < 1000000; busy_wait_var++); + + /* Set baud rate. */ + divider = (2 * UART_SPEED_MAX) / uart_speed; + outb ((divider >> 0) & 0xff, UART_LSB); + outb ((divider >> 8) & 0xff, UART_MSB); + + /* Set 8,N,1. */ + outb (0x03, UART_LCR); + + /* Disable interrupts. */ + outb (0x00, UART_IER); + + /* Enable FIFOs. */ + outb (0x07, UART_IIR); + + /* Enable RX interrupts. */ + outb (0x01, UART_IER); + + inb (UART_IER); + inb (UART_IIR); + inb (UART_LCR); + inb (UART_MCR); + inb (UART_LSR); + inb (UART_MSR); +} + + +static void +serial_putchar (int chr) +{ + while (!(inb (UART_LSR) & UART_LSR_THRE)) + ; + + outb (chr, UART_DR); + + if (chr == '\n') + serial_putchar ('\r'); +} + + +struct output_driver serial_output = + { + "serial", + serial_init, + 0, /* deinit */ + serial_putchar + }; diff --git a/laden/output-vga.c b/laden/output-vga.c index 82234e5..0826618 100644 --- a/laden/output-vga.c +++ b/laden/output-vga.c @@ -80,7 +80,7 @@ static char *video; static void -vga_init (void) +vga_init (const char *cfg) { unsigned int pos = vga_get_cursor_pos (); col = pos % VGA_COLUMNS; diff --git a/laden/output.c b/laden/output.c index 8d40cb1..f6f4a59 100644 --- a/laden/output.c +++ b/laden/output.c @@ -22,7 +22,9 @@ #include #endif +#include #include +#include #include "output.h" @@ -40,23 +42,32 @@ static struct output_driver *output; putchar or any other output routine. Returns 0 if NAME is not a valid output driver name, otherwise 1 on success. */ int -output_init (char *name) +output_init (const char *driver) { + const char *driver_cfg = NULL; + if (output) { output_deinit (); output = 0; } - if (name) + if (driver) { struct output_driver **out = &output_drivers[0]; while (*out) { - if (!strcmp (name, (*out)->name)) + unsigned int name_len = strlen ((*out)->name); + if (!strncmp (driver, (*out)->name, name_len)) { - output = *out; - break; + const char *cfg = driver + name_len; + if (!*cfg || *cfg == ',') + { + if (*cfg) + driver_cfg = cfg + 1; + output = *out; + break; + } } out++; } @@ -67,7 +78,7 @@ output_init (char *name) output = output_drivers[0]; if (output->init) - (*output->init) (); + (*output->init) (driver_cfg); return 1; } @@ -251,6 +262,8 @@ printf (const char *fmt, ...) break; case 'p': + putchar ('0'); + putchar ('x'); print_nr ((unsigned int) va_arg (ap, void *), 16); p++; break; diff --git a/laden/output.h b/laden/output.h index c8d1e24..5ab13fa 100644 --- a/laden/output.h +++ b/laden/output.h @@ -31,7 +31,7 @@ struct output_driver const char *name; /* Initialize the output device. */ - void (*init) (void); + void (*init) (const char *cfg); /* Deinitialize the output device. */ void (*deinit) (void); @@ -47,16 +47,20 @@ struct output_driver extern struct output_driver *output_drivers[]; -/* Activate the output driver NAME or the default one if NAME is a +/* Activate the output driver DRIVER or the default one if DRIVER is a null pointer. Must be called once at startup, before calling - putchar or any other output routine. Returns 0 if NAME is not a - valid output driver name, otherwise 1 on success. */ -int output_init (char *name); + putchar or any other output routine. DRIVER has the pattern + NAME[,CONFIG...], for example "serial,uart2,speed=9600". Returns 0 + if DRIVER is not a valid output driver specification, otherwise 1 + on success. */ +int output_init (const char *driver); + /* Deactivate the output driver. Must be called after the last time putchar or any other output routine is called. */ void output_deinit (void); + /* Print the single character CHR on the output device. */ int putchar (int chr); @@ -67,6 +71,7 @@ int printf (const char *fmt, ...); /* True if debug mode is enabled. */ extern int output_debug; + /* Print a debug message. */ #define debug(...) do { if (output_debug) printf (__VA_ARGS__); } while (0) -- cgit v1.2.3