aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.rootkeys2
-rw-r--r--xen/arch/ia64/xensetup.c3
-rw-r--r--xen/arch/x86/cdb.c12
-rw-r--r--xen/arch/x86/setup.c5
-rw-r--r--xen/drivers/char/console.c21
-rw-r--r--xen/drivers/char/ns16550.c263
-rw-r--r--xen/drivers/char/serial.c408
-rw-r--r--xen/include/asm-ia64/config.h3
-rw-r--r--xen/include/asm-ia64/serial.h14
-rw-r--r--xen/include/asm-x86/serial.h22
-rw-r--r--xen/include/xen/console.h4
-rw-r--r--xen/include/xen/serial.h129
12 files changed, 440 insertions, 446 deletions
diff --git a/.rootkeys b/.rootkeys
index a8825238d6..16e1ca03ab 100644
--- a/.rootkeys
+++ b/.rootkeys
@@ -1232,6 +1232,7 @@
40715b2cNVOegtvyft_AHFKJYRprfA xen/drivers/acpi/tables.c
3e4a8cb7alzQCDKS7MlioPoHBKYkdQ xen/drivers/char/Makefile
4049e6bfNSIq7s7OV-Bd69QD0RpR2Q xen/drivers/char/console.c
+4298e018XQtZkCdufpyFimOGZqqsFA xen/drivers/char/ns16550.c
3e4a8cb7nMChlro4wvOBo76n__iCFA xen/drivers/char/serial.c
40715b2cFpte_UNWnBZW0Du7z9AhTQ xen/include/acpi/acconfig.h
40715b2ctNvVZ058w8eM8DR9hOat_A xen/include/acpi/acexcep.h
@@ -1356,7 +1357,6 @@
3ddb79c2QF5-pZGzuX4QukPCDAl59A xen/include/asm-x86/processor.h
40cf1596bim9F9DNdV75klgRSZ6Y2A xen/include/asm-x86/regs.h
3ddb79c2plf7ciNgoNjU-RsbUzawsw xen/include/asm-x86/rwlock.h
-42136b49h6MkeayfuOaTPcJQWKga2g xen/include/asm-x86/serial.h
405b8599BsDsDwKEJLS0XipaiQW3TA xen/include/asm-x86/shadow.h
3ddb79c3Hgbb2g8CyWLMCK-6_ZVQSQ xen/include/asm-x86/smp.h
3ddb79c3jn8ALV_S9W5aeTYUQRKBpg xen/include/asm-x86/smpboot.h
diff --git a/xen/arch/ia64/xensetup.c b/xen/arch/ia64/xensetup.c
index ba6cd64f94..f1f10a1f15 100644
--- a/xen/arch/ia64/xensetup.c
+++ b/xen/arch/ia64/xensetup.c
@@ -154,7 +154,8 @@ void start_kernel(void)
early_setup_arch(&cmdline);
/* We initialise the serial devices very early so we can get debugging. */
- serial_init_stage1();
+ ns16550_init();
+ serial_init_preirq();
init_console();
set_printk_prefix("(XEN) ");
diff --git a/xen/arch/x86/cdb.c b/xen/arch/x86/cdb.c
index f92e78f9c6..806b0c479e 100644
--- a/xen/arch/x86/cdb.c
+++ b/xen/arch/x86/cdb.c
@@ -91,11 +91,11 @@ attempt_receive_packet(char *recv_buf, struct xendbg_context *ctx)
u8 ch;
/* Skip over everything up to the first '$' */
- while ((ch = irq_serial_getc(ctx->serhnd)) != '$')
+ while ((ch = serial_getc(ctx->serhnd)) != '$')
;
csum = 0;
for (count = 0; count < 4096; count++) {
- ch = irq_serial_getc(ctx->serhnd);
+ ch = serial_getc(ctx->serhnd);
if (ch == '#')
break;
recv_buf[count] = ch;
@@ -106,8 +106,8 @@ attempt_receive_packet(char *recv_buf, struct xendbg_context *ctx)
return -1;
}
recv_buf[count] = 0;
- received_csum = hex_char_val(irq_serial_getc(ctx->serhnd)) * 16 +
- hex_char_val(irq_serial_getc(ctx->serhnd));
+ received_csum = hex_char_val(serial_getc(ctx->serhnd)) * 16 +
+ hex_char_val(serial_getc(ctx->serhnd));
if (received_csum == csum) {
return 0;
} else {
@@ -163,7 +163,7 @@ xendbg_finish_reply(struct xendbg_context *ctx)
xendbg_put_char('#', ctx);
xendbg_send(buf, 2, ctx);
- ch = irq_serial_getc(ctx->serhnd);
+ ch = serial_getc(ctx->serhnd);
if (ch == '+')
return 0;
else
@@ -394,7 +394,7 @@ initialize_xendbg(void)
{
if (!strcmp(opt_cdb, "none"))
return 0;
- xdb_ctx.serhnd = parse_serial_handle(opt_cdb);
+ xdb_ctx.serhnd = serial_parse_handle(opt_cdb);
if (xdb_ctx.serhnd == -1)
panic("Can't parse %s as CDB serial info.\n", opt_cdb);
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 1a8ff62933..2d16e56a52 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -216,7 +216,7 @@ static void __init start_of_day(void)
initialize_keytable();
- serial_init_stage2();
+ serial_init_postirq();
init_xen_time();
@@ -263,7 +263,8 @@ void __init __start_xen(multiboot_info_t *mbi)
smp_prepare_boot_cpu();
/* We initialise the serial devices very early so we can get debugging. */
- serial_init_stage1();
+ ns16550_init();
+ serial_init_preirq();
init_console();
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index b8e0f15fa4..f588b58945 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -260,7 +260,7 @@ static void switch_serial_input(void)
}
}
-static void __serial_rx(unsigned char c, struct cpu_user_regs *regs)
+static void __serial_rx(char c, struct cpu_user_regs *regs)
{
if ( xen_rx )
return handle_keypress(c, regs);
@@ -272,7 +272,7 @@ static void __serial_rx(unsigned char c, struct cpu_user_regs *regs)
send_guest_virq(dom0->exec_domain[0], VIRQ_CONSOLE);
}
-static void serial_rx(unsigned char c, struct cpu_user_regs *regs)
+static void serial_rx(char c, struct cpu_user_regs *regs)
{
static int switch_code_count = 0;
@@ -416,7 +416,7 @@ void init_console(void)
if ( *p == ',' )
p++;
if ( strncmp(p, "com", 3) == 0 )
- sercon_handle = parse_serial_handle(p);
+ sercon_handle = serial_parse_handle(p);
else if ( strncmp(p, "vga", 3) == 0 )
vgacon_enabled = 1;
}
@@ -465,21 +465,6 @@ void console_force_lock(void)
spin_lock(&console_lock);
}
-void console_putc(char c)
-{
- serial_putc(sercon_handle, c);
-}
-
-int console_getc(void)
-{
- return serial_getc(sercon_handle);
-}
-
-int irq_console_getc(void)
-{
- return irq_serial_getc(sercon_handle);
-}
-
/*
* **************************************************************
diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
new file mode 100644
index 0000000000..89e64497e2
--- /dev/null
+++ b/xen/drivers/char/ns16550.c
@@ -0,0 +1,263 @@
+/******************************************************************************
+ * ns16550.c
+ *
+ * Driver for 16550-series UARTs. This driver is to be kept within Xen as
+ * it permits debugging of seriously-toasted machines (e.g., in situations
+ * where a device driver within a guest OS would be inaccessible).
+ *
+ * Copyright (c) 2003-2005, K A Fraser
+ */
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+#include <xen/serial.h>
+#include <asm/io.h>
+
+/* Config serial port with a string <baud>,DPS,<io-base>,<irq>. */
+static char opt_com1[30] = "", opt_com2[30] = "";
+string_param("com1", opt_com1);
+string_param("com2", opt_com2);
+
+static struct ns16550 {
+ int baud, data_bits, parity, stop_bits, io_base, irq;
+ struct irqaction irqaction;
+} ns16550_com[2] = {
+ { 0, 0, 0, 0, 0x3f8, 4 },
+ { 0, 0, 0, 0, 0x2f8, 3 }
+};
+
+/* Register offsets */
+#define RBR 0x00 /* receive buffer */
+#define THR 0x00 /* transmit holding */
+#define IER 0x01 /* interrupt enable */
+#define IIR 0x02 /* interrupt identity */
+#define FCR 0x02 /* FIFO control */
+#define LCR 0x03 /* line control */
+#define MCR 0x04 /* Modem control */
+#define LSR 0x05 /* line status */
+#define MSR 0x06 /* Modem status */
+#define DLL 0x00 /* divisor latch (ls) (DLAB=1) */
+#define DLM 0x01 /* divisor latch (ms) (DLAB=1) */
+
+/* Interrupt Enable Register */
+#define IER_ERDAI 0x01 /* rx data recv'd */
+#define IER_ETHREI 0x02 /* tx reg. empty */
+#define IER_ELSI 0x04 /* rx line status */
+#define IER_EMSI 0x08 /* MODEM status */
+
+/* FIFO control register */
+#define FCR_ENABLE 0x01 /* enable FIFO */
+#define FCR_CLRX 0x02 /* clear Rx FIFO */
+#define FCR_CLTX 0x04 /* clear Tx FIFO */
+#define FCR_DMA 0x10 /* enter DMA mode */
+#define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */
+#define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */
+#define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
+#define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
+
+/* Line control register */
+#define LCR_DLAB 0x80 /* Divisor Latch Access */
+
+/* Modem Control Register */
+#define MCR_DTR 0x01 /* Data Terminal Ready */
+#define MCR_RTS 0x02 /* Request to Send */
+#define MCR_OUT2 0x08 /* OUT2: interrupt mask */
+
+/* Line Status Register */
+#define LSR_DR 0x01 /* Data ready */
+#define LSR_OE 0x02 /* Overrun */
+#define LSR_PE 0x04 /* Parity error */
+#define LSR_FE 0x08 /* Framing error */
+#define LSR_BI 0x10 /* Break */
+#define LSR_THRE 0x20 /* Xmit hold reg empty */
+#define LSR_TEMT 0x40 /* Xmitter empty */
+#define LSR_ERR 0x80 /* Error */
+
+/* These parity settings can be ORed directly into the LCR. */
+#define PARITY_NONE (0<<3)
+#define PARITY_ODD (1<<3)
+#define PARITY_EVEN (3<<3)
+#define PARITY_MARK (5<<3)
+#define PARITY_SPACE (7<<3)
+
+static void ns16550_interrupt(
+ int irq, void *dev_id, struct cpu_user_regs *regs)
+{
+ serial_rx_interrupt(dev_id, regs);
+}
+
+static void ns16550_putc(struct serial_port *port, char c)
+{
+ struct ns16550 *uart = port->uart;
+
+ while ( !(inb(uart->io_base + LSR) & LSR_THRE) )
+ cpu_relax();
+
+ outb(c, uart->io_base + THR);
+}
+
+static int ns16550_getc(struct serial_port *port, char *pc)
+{
+ struct ns16550 *uart = port->uart;
+
+ if ( !(inb(uart->io_base + LSR) & LSR_DR) )
+ return 0;
+
+ *pc = inb(uart->io_base + RBR);
+ return 1;
+}
+
+static void ns16550_init_preirq(struct serial_port *port)
+{
+ struct ns16550 *uart = port->uart;
+ unsigned char lcr;
+
+ lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
+
+ /* No interrupts. */
+ outb(0, uart->io_base + IER);
+
+ /* Line control and baud-rate generator. */
+ outb(lcr | LCR_DLAB, uart->io_base + LCR);
+ outb(115200/uart->baud, uart->io_base + DLL); /* baud lo */
+ outb(0, uart->io_base + DLM); /* baud hi */
+ outb(lcr, uart->io_base + LCR); /* parity, data, stop */
+
+ /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */
+ outb(MCR_DTR | MCR_RTS, uart->io_base + MCR);
+
+ /* Enable and clear the FIFOs. Set a large trigger threshold. */
+ outb(FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14, uart->io_base + FCR);
+}
+
+static void ns16550_init_postirq(struct serial_port *port)
+{
+ struct ns16550 *uart = port->uart;
+ int rc;
+
+ uart->irqaction.handler = ns16550_interrupt;
+ uart->irqaction.name = "ns16550";
+ uart->irqaction.dev_id = port;
+ if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
+ printk("ERROR: Failed to allocate na16550 IRQ %d\n", uart->irq);
+
+ /* For sanity, clear the receive FIFO. */
+ outb(FCR_ENABLE | FCR_CLRX | FCR_TRG14, uart->io_base + FCR);
+
+ /* Master interrupt enable; also keep DTR/RTS asserted. */
+ outb(MCR_OUT2 | MCR_DTR | MCR_RTS, uart->io_base + MCR);
+
+ /* Enable receive interrupts. */
+ outb(IER_ERDAI, uart->io_base + IER);
+}
+
+#ifdef CONFIG_X86
+#include <asm/physdev.h>
+static void ns16550_endboot(struct serial_port *port)
+{
+ struct ns16550 *uart = port->uart;
+ physdev_modify_ioport_access_range(dom0, 0, uart->io_base, 8);
+}
+#else
+#define ns16550_endboot NULL
+#endif
+
+static struct uart_driver ns16550_driver = {
+ .init_preirq = ns16550_init_preirq,
+ .init_postirq = ns16550_init_postirq,
+ .endboot = ns16550_endboot,
+ .putc = ns16550_putc,
+ .getc = ns16550_getc
+};
+
+#define PARSE_ERR(_f, _a...) \
+ do { \
+ printk( "ERROR: " _f "\n" , ## _a ); \
+ return; \
+ } while ( 0 )
+
+static void ns16550_parse_port_config(struct ns16550 *uart, char *conf)
+{
+ if ( *conf == '\0' )
+ return;
+
+ uart->baud = simple_strtol(conf, &conf, 10);
+ if ( (uart->baud < 1200) || (uart->baud > 115200) )
+ PARSE_ERR("Baud rate %d outside supported range.", uart->baud);
+
+ if ( *conf != ',' )
+ PARSE_ERR("Missing data/parity/stop specifiers.");
+
+ conf++;
+
+ uart->data_bits = simple_strtol(conf, &conf, 10);
+ if ( (uart->data_bits < 5) || (uart->data_bits > 8) )
+ PARSE_ERR("%d data bits are unsupported.", uart->data_bits);
+
+ switch ( *conf )
+ {
+ case 'n':
+ uart->parity = PARITY_NONE;
+ break;
+ case 'o':
+ uart->parity = PARITY_ODD;
+ break;
+ case 'e':
+ uart->parity = PARITY_EVEN;
+ break;
+ case 'm':
+ uart->parity = PARITY_MARK;
+ break;
+ case 's':
+ uart->parity = PARITY_SPACE;
+ break;
+
+ default:
+ PARSE_ERR("Invalid parity specifier '%c'.", *conf);
+ }
+
+ conf++;
+
+ uart->stop_bits = simple_strtol(conf, &conf, 10);
+ if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) )
+ PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits);
+
+ if ( *conf == ',' )
+ {
+ conf++;
+
+ uart->io_base = simple_strtol(conf, &conf, 0);
+ if ( (uart->io_base <= 0x0000) || (uart->io_base > 0xfff0) )
+ PARSE_ERR("I/O port base 0x%x is outside the supported range.",
+ uart->io_base);
+
+ if ( *conf != ',' )
+ PARSE_ERR("Missing IRQ specifier.");
+
+ conf++;
+
+ uart->irq = simple_strtol(conf, &conf, 10);
+ if ( (uart->irq <= 0) || (uart->irq >= 32) )
+ PARSE_ERR("IRQ %d is outside the supported range.", uart->irq);
+ }
+
+ serial_register_uart(uart - ns16550_com, &ns16550_driver, uart);
+}
+
+void ns16550_init(void)
+{
+ ns16550_parse_port_config(&ns16550_com[0], opt_com1);
+ ns16550_parse_port_config(&ns16550_com[1], opt_com2);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c
index 7d9852ebab..c578de152c 100644
--- a/xen/drivers/char/serial.c
+++ b/xen/drivers/char/serial.c
@@ -1,9 +1,7 @@
/******************************************************************************
* serial.c
*
- * Driver for 16550-series UARTs. This driver is to be kept within Xen as
- * it permits debugging of seriously-toasted machines (e.g., in situations
- * where a device driver within a guest OS would be inaccessible).
+ * Framework for serial device drivers.
*
* Copyright (c) 2003-2005, K A Fraser
*/
@@ -15,230 +13,119 @@
#include <xen/reboot.h>
#include <xen/sched.h>
#include <xen/serial.h>
-#include <asm/io.h>
-
-#ifdef CONFIG_X86
-#include <asm/physdev.h>
-#endif
-
-/* Config serial port with a string <baud>,DPS,<io-base>,<irq>. */
-static char opt_com1[30] = OPT_COM1_STR, opt_com2[30] = OPT_COM2_STR;
-string_param("com1", opt_com1);
-string_param("com2", opt_com2);
-
-static struct uart com[2] = {
- { 0, 0, 0, 0, 0x3f8, 4,
- NULL, NULL, NULL,
- SPIN_LOCK_UNLOCKED },
- { 0, 0, 0, 0, 0x2f8, 3,
- NULL, NULL, NULL,
- SPIN_LOCK_UNLOCKED }
-};
-
-#define UART_ENABLED(_u) ((_u)->baud != 0)
-#define DISABLE_UART(_u) ((_u)->baud = 0)
-
-/***********************
- * PRIVATE FUNCTIONS
- */
+static struct serial_port com[2] = {
+ { .lock = SPIN_LOCK_UNLOCKED },
+ { .lock = SPIN_LOCK_UNLOCKED }
+};
-static void uart_rx(struct uart *uart, struct cpu_user_regs *regs)
+void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
{
- unsigned char c;
+ char c;
+ serial_rx_fn fn;
+ unsigned long flags;
- if ( !UART_ENABLED(uart) )
- return;
+ BUG_ON(!port->driver);
+ BUG_ON(!port->driver->getc);
- /*
- * No need for the uart spinlock here. Only the uart's own interrupt
- * handler will read from the RBR and the handler isn't reentrant.
- * Calls to serial_getc() will disable this handler before proceeding.
- */
- while ( inb(uart->io_base + LSR) & LSR_DR )
+ spin_lock_irqsave(&port->lock, flags);
+
+ while ( port->driver->getc(port, &c) )
{
- c = inb(uart->io_base + RBR);
- if ( uart->rx != NULL )
- uart->rx(c, regs);
- else if ( (c & 0x80) && (uart->rx_hi != NULL) )
- uart->rx_hi(c&0x7f, regs);
- else if ( !(c & 0x80) && (uart->rx_lo != NULL) )
- uart->rx_lo(c&0x7f, regs);
- else if ( (uart->rxbufp - uart->rxbufc) != RXBUFSZ )
- uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufp++)] = c;
+ fn = NULL;
+
+ if ( port->rx != NULL )
+ fn = port->rx;
+ else if ( (c & 0x80) && (port->rx_hi != NULL) )
+ fn = port->rx_hi;
+ else if ( !(c & 0x80) && (port->rx_lo != NULL) )
+ fn = port->rx_lo;
+ else if ( (port->rxbufp - port->rxbufc) != RXBUFSZ )
+ port->rxbuf[MASK_RXBUF_IDX(port->rxbufp++)] = c;
+
+ if ( fn != NULL )
+ {
+ spin_unlock_irqrestore(&port->lock, flags);
+ (*fn)(c & 0x7f, regs);
+ spin_lock_irqsave(&port->lock, flags);
+ }
}
-}
-static void serial_interrupt(
- int irq, void *dev_id, struct cpu_user_regs *regs)
-{
- uart_rx((struct uart *)dev_id, regs);
+ spin_unlock_irqrestore(&port->lock, flags);
}
-static inline void __serial_putc(
- struct uart *uart, int handle, unsigned char c)
+void serial_putc(int handle, char c)
{
+ struct serial_port *port = &com[handle & SERHND_IDX];
unsigned long flags;
- int space;
+
+ if ( (handle == -1) || !port->driver || !port->driver->putc )
+ return;
+
+ spin_lock_irqsave(&port->lock, flags);
if ( (c == '\n') && (handle & SERHND_COOKED) )
- __serial_putc(uart, handle, '\r');
+ port->driver->putc(port, '\r');
if ( handle & SERHND_HI )
c |= 0x80;
else if ( handle & SERHND_LO )
c &= 0x7f;
- do {
- spin_lock_irqsave(&uart->lock, flags);
- space = arch_serial_putc(uart, c);
- spin_unlock_irqrestore(&uart->lock, flags);
- }
- while ( !space );
+ port->driver->putc(port, c);
+
+ spin_unlock_irqrestore(&port->lock, flags);
}
-#define PARSE_ERR(_f, _a...) \
- do { \
- printk( "ERROR: " _f "\n" , ## _a ); \
- DISABLE_UART(uart); \
- return; \
-} while ( 0 )
-
-static void parse_port_config(char *conf, struct uart *uart)
+void serial_puts(int handle, const char *s)
{
- if ( *conf == '\0' )
- return;
-
- uart->baud = simple_strtol(conf, &conf, 10);
- if ( (uart->baud < 1200) || (uart->baud > 115200) )
- PARSE_ERR("Baud rate %d outside supported range.", uart->baud);
-
- if ( *conf != ',' )
- PARSE_ERR("Missing data/parity/stop specifiers.");
-
- conf++;
-
- uart->data_bits = simple_strtol(conf, &conf, 10);
- if ( (uart->data_bits < 5) || (uart->data_bits > 8) )
- PARSE_ERR("%d data bits are unsupported.", uart->data_bits);
+ while ( *s != '\0' )
+ serial_putc(handle, *s++);
+}
- switch ( *conf )
+/* Returns TRUE if given character (*pc) matches the serial handle. */
+static int byte_matches(int handle, unsigned char *pc)
+{
+ if ( !(handle & SERHND_HI) )
{
- case 'n':
- uart->parity = PARITY_NONE;
- break;
- case 'o':
- uart->parity = PARITY_ODD;
- break;
- case 'e':
- uart->parity = PARITY_EVEN;
- break;
- case 'm':
- uart->parity = PARITY_MARK;
- break;
- case 's':
- uart->parity = PARITY_SPACE;
- break;
-
- default:
- PARSE_ERR("Invalid parity specifier '%c'.", *conf);
+ if ( !(handle & SERHND_LO) || !(*pc & 0x80) )
+ return 1;
}
-
- conf++;
-
- uart->stop_bits = simple_strtol(conf, &conf, 10);
- if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) )
- PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits);
-
- if ( *conf == ',' )
+ else if ( *pc & 0x80 )
{
- conf++;
-
- uart->io_base = simple_strtol(conf, &conf, 0);
- if ( (uart->io_base <= 0x0000) || (uart->io_base > 0xfff0) )
- PARSE_ERR("I/O port base 0x%x is outside the supported range.",
- uart->io_base);
-
- if ( *conf != ',' )
- PARSE_ERR("Missing IRQ specifier.");
-
- conf++;
-
- uart->irq = simple_strtol(conf, &conf, 10);
- if ( (uart->irq <= 0) || (uart->irq >= 32) )
- PARSE_ERR("IRQ %d is outside the supported range.", uart->irq);
+ *pc &= 0x7f;
+ return 1;
}
+ return 0;
}
-static void uart_config_stage1(struct uart *uart)
-{
- unsigned char lcr;
-
- if ( !UART_ENABLED(uart) )
- return;
-
- lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
-
- /* No interrupts. */
- outb(0, uart->io_base + IER);
-
- /* Line control and baud-rate generator. */
- outb(lcr | LCR_DLAB, uart->io_base + LCR);
- outb(115200/uart->baud, uart->io_base + DLL); /* baud lo */
- outb(0, uart->io_base + DLM); /* baud hi */
- outb(lcr, uart->io_base + LCR); /* parity, data, stop */
-
- /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */
- outb(MCR_DTR | MCR_RTS, uart->io_base + MCR);
-
- /* Enable and clear the FIFOs. Set a large trigger threshold. */
- outb(FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14, uart->io_base + FCR);
-}
-
-static void uart_config_stage2(struct uart *uart)
+char serial_getc(int handle)
{
- int rc;
-
- if ( !UART_ENABLED(uart) )
- return;
-
- uart->irqaction.handler = serial_interrupt;
- uart->irqaction.name = "serial";
- uart->irqaction.dev_id = uart;
- if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
- printk("ERROR: Failed to allocate serial IRQ %d\n", uart->irq);
-
- /* For sanity, clear the receive FIFO. */
- outb(FCR_ENABLE | FCR_CLRX | FCR_TRG14, uart->io_base + FCR);
-
- /* Master interrupt enable; also keep DTR/RTS asserted. */
- outb(MCR_OUT2 | MCR_DTR | MCR_RTS, uart->io_base + MCR);
-
- /* Enable receive interrupts. */
- outb(IER_ERDAI, uart->io_base + IER);
-}
-
+ struct serial_port *port = &com[handle & SERHND_IDX];
+ unsigned char c;
+ unsigned long flags;
-/***********************
- * PUBLIC FUNCTIONS
- */
+ if ( (handle == -1) || !port->driver || !port->driver->getc )
+ return '\0';
-void serial_init_stage1(void)
-{
- parse_port_config(opt_com1, &com[0]);
- parse_port_config(opt_com2, &com[1]);
+ spin_lock_irqsave(&port->lock, flags);
- uart_config_stage1(&com[0]);
- uart_config_stage1(&com[1]);
-}
+ while ( port->rxbufp != port->rxbufc )
+ {
+ c = port->rxbuf[MASK_RXBUF_IDX(port->rxbufc++)];
+ if ( byte_matches(handle, &c) )
+ goto out;
+ }
+
+ while ( !port->driver->getc(port, &c) && !byte_matches(handle, &c) )
+ continue;
-void serial_init_stage2(void)
-{
- uart_config_stage2(&com[0]);
- uart_config_stage2(&com[1]);
+ out:
+ spin_unlock_irqrestore(&port->lock, flags);
+ return c;
}
-int parse_serial_handle(char *conf)
+int serial_parse_handle(char *conf)
{
int handle;
@@ -261,14 +148,6 @@ int parse_serial_handle(char *conf)
goto fail;
}
-#ifndef NO_UART_CONFIG_OK
- if ( !UART_ENABLED(&com[handle]) )
- {
- printk("ERROR: cannot use unconfigured serial port COM%d\n", handle+1);
- return -1;
- }
-#endif
-
if ( conf[4] == 'H' )
handle |= SERHND_HI;
else if ( conf[4] == 'L' )
@@ -285,147 +164,80 @@ int parse_serial_handle(char *conf)
void serial_set_rx_handler(int handle, serial_rx_fn fn)
{
- struct uart *uart = &com[handle & SERHND_IDX];
+ struct serial_port *port = &com[handle & SERHND_IDX];
unsigned long flags;
if ( handle == -1 )
return;
- spin_lock_irqsave(&uart->lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
- if ( uart->rx != NULL )
+ if ( port->rx != NULL )
goto fail;
if ( handle & SERHND_LO )
{
- if ( uart->rx_lo != NULL )
+ if ( port->rx_lo != NULL )
goto fail;
- uart->rx_lo = fn;
+ port->rx_lo = fn;
}
else if ( handle & SERHND_HI )
{
- if ( uart->rx_hi != NULL )
+ if ( port->rx_hi != NULL )
goto fail;
- uart->rx_hi = fn;
+ port->rx_hi = fn;
}
else
{
- if ( (uart->rx_hi != NULL) || (uart->rx_lo != NULL) )
+ if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
goto fail;
- uart->rx = fn;
+ port->rx = fn;
}
- spin_unlock_irqrestore(&uart->lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
return;
fail:
- spin_unlock_irqrestore(&uart->lock, flags);
+ spin_unlock_irqrestore(&port->lock, flags);
printk("ERROR: Conflicting receive handlers for COM%d\n",
handle & SERHND_IDX);
}
-void serial_putc(int handle, unsigned char c)
-{
- struct uart *uart = &com[handle & SERHND_IDX];
-
- if ( handle == -1 )
- return;
-
- __serial_putc(uart, handle, c);
-}
-
-void serial_puts(int handle, const char *s)
-{
- struct uart *uart = &com[handle & SERHND_IDX];
-
- if ( handle == -1 )
- return;
-
- while ( *s != '\0' )
- __serial_putc(uart, handle, *s++);
-}
-
-/* Returns TRUE if given character (*pc) matches the serial handle. */
-static int byte_matches(int handle, unsigned char *pc)
-{
- if ( !(handle & SERHND_HI) )
- {
- if ( !(handle & SERHND_LO) || !(*pc & 0x80) )
- return 1;
- }
- else if ( *pc & 0x80 )
- {
- *pc &= 0x7f;
- return 1;
- }
- return 0;
-}
-
-unsigned char irq_serial_getc(int handle)
+void serial_force_unlock(int handle)
{
- struct uart *uart = &com[handle & SERHND_IDX];
- unsigned char c;
-
-
- while ( uart->rxbufp != uart->rxbufc )
- {
- c = uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufc++)];
- if ( byte_matches(handle, &c) )
- goto out;
- }
-
- /* We now wait for the UART to receive a suitable character. */
- do {
- while ( (inb(uart->io_base + LSR) & LSR_DR) == 0 )
- barrier();
- c = inb(uart->io_base + RBR);
- }
- while ( !byte_matches(handle, &c) );
-
- out:
- return c;
+ struct serial_port *port = &com[handle & SERHND_IDX];
+ if ( handle != -1 )
+ port->lock = SPIN_LOCK_UNLOCKED;
}
-unsigned char serial_getc(int handle)
+void serial_init_preirq(void)
{
- struct uart *uart = &com[handle & SERHND_IDX];
- unsigned char c;
- unsigned long flags;
-
- spin_lock_irqsave(&uart->lock, flags);
-
- while ( uart->rxbufp != uart->rxbufc )
- {
- c = uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufc++)];
- if ( byte_matches(handle, &c) )
- goto out;
- }
-
- disable_irq(uart->irq);
-
- c = irq_serial_getc(handle);
-
- enable_irq(uart->irq);
- out:
- spin_unlock_irqrestore(&uart->lock, flags);
- return c;
+ int i;
+ for ( i = 0; i < ARRAY_SIZE(com); i++ )
+ if ( com[i].driver && com[i].driver->init_preirq )
+ com[i].driver->init_preirq(&com[i]);
}
-void serial_force_unlock(int handle)
+void serial_init_postirq(void)
{
- struct uart *uart = &com[handle & SERHND_IDX];
- if ( handle != -1 )
- uart->lock = SPIN_LOCK_UNLOCKED;
+ int i;
+ for ( i = 0; i < ARRAY_SIZE(com); i++ )
+ if ( com[i].driver && com[i].driver->init_postirq )
+ com[i].driver->init_postirq(&com[i]);
}
void serial_endboot(void)
{
-#ifdef CONFIG_X86
int i;
for ( i = 0; i < ARRAY_SIZE(com); i++ )
- if ( UART_ENABLED(&com[i]) )
- physdev_modify_ioport_access_range(dom0, 0, com[i].io_base, 8);
-#endif
+ if ( com[i].driver && com[i].driver->endboot )
+ com[i].driver->endboot(&com[i]);
+}
+
+void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
+{
+ com[idx].driver = driver;
+ com[idx].uart = uart;
}
/*
diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h
index bb7e5f6e16..34603f5418 100644
--- a/xen/include/asm-ia64/config.h
+++ b/xen/include/asm-ia64/config.h
@@ -160,9 +160,6 @@ void sort_main_extable(void);
(likely(sizeof(count) <= 4) /* disallow 64-bit counts */ && \
access_ok(type,addr,count*size))
-// without this, uart_config_stageX does outb's which are non-portable
-#define NO_UART_CONFIG_OK
-
// see drivers/char/console.c
#ifndef CONFIG_VTI
#define OPT_CONSOLE_STR "com1"
diff --git a/xen/include/asm-ia64/serial.h b/xen/include/asm-ia64/serial.h
index faeaf526e8..4acf7a77f1 100644
--- a/xen/include/asm-ia64/serial.h
+++ b/xen/include/asm-ia64/serial.h
@@ -10,21 +10,11 @@
#define arch_serial_putc(_uart, _c) \
( platform_is_hp_ski() ? (ia64_ssc(c,0,0,0,SSC_PUTCHAR), 1) : \
( longs_peak_putc(c), 1 ))
-
-#define OPT_COM1_STR "115200"
-#define OPT_COM2_STR ""
-#else // CONFIG_VTI
+#else
#define arch_serial_putc(_uart, _c) \
( platform_is_hp_ski() ? (ia64_ssc(c,0,0,0,SSC_PUTCHAR), 1) : \
( (inb((_uart)->io_base + LSR) & LSR_THRE) ? \
(outb((_c), (_uart)->io_base + THR), 1) : 0 ))
-
-#define OPT_COM1_STR ""
-#define OPT_COM2_STR "57600,8n1"
-#endif // CONFIG_VTI
-
-unsigned char irq_serial_getc(int handle);
-
-void serial_force_unlock(int handle);
+#endif
#endif /* __ASM_SERIAL_H__ */
diff --git a/xen/include/asm-x86/serial.h b/xen/include/asm-x86/serial.h
deleted file mode 100644
index b93d28fb7e..0000000000
--- a/xen/include/asm-x86/serial.h
+++ /dev/null
@@ -1,22 +0,0 @@
-
-#ifndef __ASM_X86_SERIAL_H__
-#define __ASM_X86_SERIAL_H__
-
-#define OPT_COM1_STR ""
-#define OPT_COM2_STR ""
-
-#define arch_serial_putc(_uart, _c) \
- ( (inb((_uart)->io_base + LSR) & LSR_THRE) ? \
- (outb((_c), (_uart)->io_base + THR), 1) : 0 )
-
-#endif /* __ASM_X86_SERIAL_H__ */
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
diff --git a/xen/include/xen/console.h b/xen/include/xen/console.h
index f65633a1af..024840c0ad 100644
--- a/xen/include/xen/console.h
+++ b/xen/include/xen/console.h
@@ -22,8 +22,4 @@ void console_endboot(int disable_vga);
void console_force_unlock(void);
void console_force_lock(void);
-void console_putc(char c);
-int console_getc(void);
-int irq_console_getc(void);
-
#endif /* __CONSOLE_H__ */
diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h
index 51a0d1a1f2..73daa385f0 100644
--- a/xen/include/xen/serial.h
+++ b/xen/include/xen/serial.h
@@ -1,9 +1,7 @@
/******************************************************************************
* serial.h
*
- * Driver for 16550-series UARTs. This driver is to be kept within Xen as
- * it permits debugging of seriously-toasted machines (e.g., in situations
- * where a device driver within a guest OS would be inaccessible).
+ * Framework for serial device drivers.
*
* Copyright (c) 2003-2005, K A Fraser
*/
@@ -11,94 +9,61 @@
#ifndef __XEN_SERIAL_H__
#define __XEN_SERIAL_H__
-#include <xen/irq.h>
-#include <asm/regs.h>
-#include <asm/serial.h>
-
-/* Register offsets */
-#define RBR 0x00 /* receive buffer */
-#define THR 0x00 /* transmit holding */
-#define IER 0x01 /* interrupt enable */
-#define IIR 0x02 /* interrupt identity */
-#define FCR 0x02 /* FIFO control */
-#define LCR 0x03 /* line control */
-#define MCR 0x04 /* Modem control */
-#define LSR 0x05 /* line status */
-#define MSR 0x06 /* Modem status */
-#define DLL 0x00 /* divisor latch (ls) (DLAB=1) */
-#define DLM 0x01 /* divisor latch (ms) (DLAB=1) */
-
-/* Interrupt Enable Register */
-#define IER_ERDAI 0x01 /* rx data recv'd */
-#define IER_ETHREI 0x02 /* tx reg. empty */
-#define IER_ELSI 0x04 /* rx line status */
-#define IER_EMSI 0x08 /* MODEM status */
-
-/* FIFO control register */
-#define FCR_ENABLE 0x01 /* enable FIFO */
-#define FCR_CLRX 0x02 /* clear Rx FIFO */
-#define FCR_CLTX 0x04 /* clear Tx FIFO */
-#define FCR_DMA 0x10 /* enter DMA mode */
-#define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */
-#define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */
-#define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
-#define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
-
-/* Line control register */
-#define LCR_DLAB 0x80 /* Divisor Latch Access */
-
-/* Modem Control Register */
-#define MCR_DTR 0x01 /* Data Terminal Ready */
-#define MCR_RTS 0x02 /* Request to Send */
-#define MCR_OUT2 0x08 /* OUT2: interrupt mask */
-
-/* Line Status Register */
-#define LSR_DR 0x01 /* Data ready */
-#define LSR_OE 0x02 /* Overrun */
-#define LSR_PE 0x04 /* Parity error */
-#define LSR_FE 0x08 /* Framing error */
-#define LSR_BI 0x10 /* Break */
-#define LSR_THRE 0x20 /* Xmit hold reg empty */
-#define LSR_TEMT 0x40 /* Xmitter empty */
-#define LSR_ERR 0x80 /* Error */
-
-/* These parity settings can be ORed directly into the LCR. */
-#define PARITY_NONE (0<<3)
-#define PARITY_ODD (1<<3)
-#define PARITY_EVEN (3<<3)
-#define PARITY_MARK (5<<3)
-#define PARITY_SPACE (7<<3)
+struct cpu_user_regs;
/* Register a character-receive hook on the specified COM port. */
-typedef void (*serial_rx_fn)(unsigned char, struct cpu_user_regs *);
+typedef void (*serial_rx_fn)(char, struct cpu_user_regs *);
void serial_set_rx_handler(int handle, serial_rx_fn fn);
+/* Number of characters we buffer for a polling receiver. */
#define RXBUFSZ 32
#define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1))
-struct uart {
- int baud, data_bits, parity, stop_bits, io_base, irq;
- serial_rx_fn rx_lo, rx_hi, rx;
- spinlock_t lock;
- unsigned char rxbuf[RXBUFSZ];
- unsigned int rxbufp, rxbufc;
- struct irqaction irqaction;
+
+struct uart_driver;
+
+struct serial_port {
+ /* Uart-driver parameters. */
+ struct uart_driver *driver;
+ void *uart;
+ /* Receiver callback functions (asynchronous receivers). */
+ serial_rx_fn rx_lo, rx_hi, rx;
+ /* Receive data buffer (polling receivers). */
+ char rxbuf[RXBUFSZ];
+ unsigned int rxbufp, rxbufc;
+ /* Serial I/O is concurrency-safe. */
+ spinlock_t lock;
+};
+
+struct uart_driver {
+ /* Driver initialisation (pre- and post-IRQ subsystem setup). */
+ void (*init_preirq)(struct serial_port *);
+ void (*init_postirq)(struct serial_port *);
+ /* Hook to clean up after Xen bootstrap (before domain 0 runs). */
+ void (*endboot)(struct serial_port *);
+ /* Put a char onto the serial line. */
+ void (*putc)(struct serial_port *, char);
+ /* Get a char from the serial line: returns FALSE if no char available. */
+ int (*getc)(struct serial_port *, char *);
};
-/* 'Serial handles' are comprise the following fields. */
+/* 'Serial handles' are composed from the following fields. */
#define SERHND_IDX (1<<0) /* COM1 or COM2? */
#define SERHND_HI (1<<1) /* Mux/demux each transferred char by MSB. */
#define SERHND_LO (1<<2) /* Ditto, except that the MSB is cleared. */
#define SERHND_COOKED (1<<3) /* Newline/carriage-return translation? */
/* Two-stage initialisation (before/after IRQ-subsystem initialisation). */
-void serial_init_stage1(void);
-void serial_init_stage2(void);
+void serial_init_preirq(void);
+void serial_init_postirq(void);
+
+/* Clean-up hook before domain 0 runs. */
+void serial_endboot(void);
/* Takes a config string and creates a numeric handle on the COM port. */
-int parse_serial_handle(char *conf);
+int serial_parse_handle(char *conf);
/* Transmit a single character via the specified COM port. */
-void serial_putc(int handle, unsigned char c);
+void serial_putc(int handle, char c);
/* Transmit a NULL-terminated string via the specified COM port. */
void serial_puts(int handle, const char *s);
@@ -108,15 +73,21 @@ void serial_puts(int handle, const char *s);
* will not return until a character is available. It can safely be
* called with interrupts disabled.
*/
-unsigned char serial_getc(int handle);
-/*
- * Same as serial_getc but can also be called from interrupt handlers.
- */
-unsigned char irq_serial_getc(int handle);
+char serial_getc(int handle);
+/* Forcibly prevent serial lockup when the system is in a bad way. */
void serial_force_unlock(int handle);
-void serial_endboot(void);
+/* Register a uart on serial port @idx (e.g., @idx==0 is COM1). */
+void serial_register_uart(int idx, struct uart_driver *driver, void *uart);
+
+/* Driver helper function: process receive work in interrupt context. */
+void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs);
+
+/*
+ * Initialisers for individual uart drivers.
+ */
+void ns16550_init(void);
#endif /* __XEN_SERIAL_H__ */