summaryrefslogtreecommitdiff
path: root/laden
diff options
context:
space:
mode:
authormarcus <marcus>2003-09-19 17:49:59 +0000
committermarcus <marcus>2003-09-19 17:49:59 +0000
commitf1e5076de4234fa7f71a1f6d8801b8f8ee60b726 (patch)
tree4040a1ffda2c181e0d373dc1e23b9d7971a07ceb /laden
parentb6f88d4911cc9b17022f5e763cd04343a05ef241 (diff)
laden/
2003-09-19 Marcus Brinkmann <marcus@gnu.org> * Makefile.am (laden_CFLAGS): Add -I$(top_srcdir)/libc-parts. * output.c: Include <stdlib.h> and <string.h>. * 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 <wagi@gmx.de>. wortel/ 2003-09-19 Marcus Brinkmann <marcus@gnu.org> * Makefile.am (wortel_CFLAGS): Add -I$(top_srcdir)/libc-parts. * output.c: Include <stdlib.h> and <string.h>. * 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 <wagi@gmx.de>.
Diffstat (limited to 'laden')
-rw-r--r--laden/ChangeLog14
-rw-r--r--laden/Makefile.am5
-rw-r--r--laden/README19
-rw-r--r--laden/ia32-output.c2
-rw-r--r--laden/output-serial.c158
-rw-r--r--laden/output-vga.c2
-rw-r--r--laden/output.c25
-rw-r--r--laden/output.h15
8 files changed, 225 insertions, 15 deletions
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 <marcus@gnu.org>
+
+ * Makefile.am (laden_CFLAGS): Add -I$(top_srcdir)/libc-parts.
+ * output.c: Include <stdlib.h> and <string.h>.
+ * 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 <wagi@gmx.de>.
+
2003-07-26 Marcus Brinkmann <marcus@gnu.org>
* 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 <config.h>
+#endif
+
+#include <sys/io.h>
+#include <string.h>
+#include <errno.h>
+
+#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 <config.h>
#endif
+#include <stdlib.h>
#include <stdarg.h>
+#include <string.h>
#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)