aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2003-09-21 17:48:32 +0000
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>2003-09-21 17:48:32 +0000
commit6e837f6a4a063518025a60c1f38aff088b347211 (patch)
tree76220ae49fdd0dc4b7270c1902e064826c99056b
parent6c6454c920beb1e3a706401d245d0a8c3610ff08 (diff)
downloadxen-6e837f6a4a063518025a60c1f38aff088b347211.tar.gz
xen-6e837f6a4a063518025a60c1f38aff088b347211.tar.bz2
xen-6e837f6a4a063518025a60c1f38aff088b347211.zip
bitkeeper revision 1.456 (3f6de470w7_JGb139gaotteaX7UDcQ)
xen_serial.c, kernel.c: Robustify Xen's serial handling. We now assert DTR and RTS so that we play nicely with flow control. Also the rx interrupt reads all chars from the fifo rather than just one. TODO: tx should be interrupt driven, and domains shouldn't be echo to serial but should go to DOM0 only.
-rw-r--r--xen/common/kernel.c10
-rw-r--r--xen/drivers/char/xen_serial.c34
2 files changed, 22 insertions, 22 deletions
diff --git a/xen/common/kernel.c b/xen/common/kernel.c
index d1cbe51863..7b384a90ca 100644
--- a/xen/common/kernel.c
+++ b/xen/common/kernel.c
@@ -218,8 +218,6 @@ void cmain (unsigned long magic, multiboot_info_t *mbi)
}
-#ifdef CONFIG_OUTPUT_SERIAL
-
#define SERIAL_BASE 0x3f8
#define RX_BUF 0
#define TX_HOLD 0
@@ -239,24 +237,24 @@ void init_serial(void)
outb(115200/opt_ser_baud, SERIAL_BASE+DIVISOR_LO);
outb(0, SERIAL_BASE+DIVISOR_HI);
outb(0x03, SERIAL_BASE+DATA_FORMAT);
+
+ /* DTR and RTS should both be high, to keep other end happy. */
+ outb(0x02, SERIAL_BASE+LINE_CTL);
/* No interrupts. */
outb(0x00, SERIAL_BASE+INT_ENABLE);
}
+#ifdef CONFIG_OUTPUT_SERIAL
void putchar_serial(unsigned char c)
{
if ( c == '\n' ) putchar_serial('\r');
while ( !(inb(SERIAL_BASE+LINE_STATUS)&(1<<5)) ) barrier();
outb(c, SERIAL_BASE+TX_HOLD);
}
-
#else
-
-void init_serial(void) {}
void putchar_serial(unsigned char c) {}
-
#endif
diff --git a/xen/drivers/char/xen_serial.c b/xen/drivers/char/xen_serial.c
index 95107e587d..7a1560ca5b 100644
--- a/xen/drivers/char/xen_serial.c
+++ b/xen/drivers/char/xen_serial.c
@@ -56,15 +56,16 @@ static void serial_rx_int(int irq, void *dev_id, struct pt_regs *regs)
u_char c;
key_handler *handler;
- /* clear the interrupt by reading the character */
- c = inb(SERIAL_BASE + NS16550_RBR);
+ while ( (inb(SERIAL_BASE + NS16550_LSR) & 1) == 1 )
+ {
+ c = inb(SERIAL_BASE + NS16550_RBR);
- /* if there's a handler, call it: we trust it won't screw us too badly */
- if((handler = get_key_handler(c)) != NULL)
- (*handler)(c, dev_id, regs);
+ if( (handler = get_key_handler(c)) != NULL )
+ (*handler)(c, dev_id, regs);
- if(serial_echo)
- printk("%c", c);
+ if ( serial_echo )
+ printk("%c", c);
+ }
}
void initialize_serial()
@@ -74,16 +75,17 @@ void initialize_serial()
/* setup key handler */
add_key_handler('~', toggle_echo, "toggle serial echo");
- /* Should detect this, but must be a ns16550a at least, surely? */
- fifo = 1;
- if(fifo) {
- /* Clear FIFOs, enable, trigger at 1 byte */
- outb(NS16550_FCR_TRG1 | NS16550_FCR_ENABLE |
- NS16550_FCR_CLRX | NS16550_FCR_CLTX, SERIAL_BASE+NS16550_FCR);
- }
+ /* This assumes we have a 16550. It's pretty darned likely really! */
+ /* Clear FIFOs, enable, trigger at 1 byte */
+ outb(NS16550_FCR_TRG1 | NS16550_FCR_ENABLE |
+ NS16550_FCR_CLRX | NS16550_FCR_CLTX,
+ SERIAL_BASE+NS16550_FCR);
- outb(NS16550_MCR_OUT2, SERIAL_BASE + NS16550_MCR); /* Modem control */
- outb(NS16550_IER_ERDAI, SERIAL_BASE + NS16550_IER ); /* Setup interrupts */
+ /* Enable receive interrupts. Also remember to keep DTR/RTS asserted. */
+ outb(NS16550_MCR_OUT2|NS16550_MCR_DTR|NS16550_MCR_RTS,
+ SERIAL_BASE + NS16550_MCR);
+ outb(NS16550_IER_ERDAI,
+ SERIAL_BASE + NS16550_IER );
if((rc = request_irq(4, serial_rx_int, SA_NOPROFILE, "serial", 0)))
printk("initialize_serial: failed to get IRQ4, rc=%d\n", rc);