debuggers.hg

annotate xen/drivers/char/ns16550.c @ 20955:12fc55dffb6b

Handle bogus serial ports that appear normal, but don't generate
interrupts e.g. the "remote serial console" on Blades.

Authored-by: Gary Grebus <Gary.Grebus@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Feb 08 08:49:19 2010 +0000 (2010-02-08)
parents 5a224e101cb3
children 8cb6e7eff2ba
rev   line source
kaf24@5233 1 /******************************************************************************
kaf24@5233 2 * ns16550.c
kaf24@5233 3 *
kaf24@5233 4 * Driver for 16550-series UARTs. This driver is to be kept within Xen as
kaf24@5233 5 * it permits debugging of seriously-toasted machines (e.g., in situations
kaf24@5233 6 * where a device driver within a guest OS would be inaccessible).
kaf24@5233 7 *
kaf24@5233 8 * Copyright (c) 2003-2005, K A Fraser
kaf24@5233 9 */
kaf24@5233 10
kaf24@5233 11 #include <xen/config.h>
keir@15988 12 #include <xen/console.h>
kaf24@5233 13 #include <xen/init.h>
kaf24@5233 14 #include <xen/irq.h>
kaf24@5233 15 #include <xen/sched.h>
kaf24@5233 16 #include <xen/serial.h>
kaf24@8497 17 #include <xen/iocap.h>
kaf24@5233 18 #include <asm/io.h>
kaf24@5233 19
kaf24@6042 20 /*
keir@18680 21 * Configure serial port with a string:
keir@18680 22 * <baud>[/<clock_hz>][,DPS[,<io-base>[,<irq>]]].
kaf24@6042 23 * The tail of the string can be omitted if platform defaults are sufficient.
kaf24@6042 24 * If the baud rate is pre-configured, perhaps by a bootloader, then 'auto'
keir@18680 25 * can be specified in place of a numeric baud rate. Polled mode is specified
keir@18680 26 * by requesting irq 0.
kaf24@6042 27 */
keir@20173 28 static char __initdata opt_com1[30] = "";
keir@20173 29 static char __initdata opt_com2[30] = "";
kaf24@5233 30 string_param("com1", opt_com1);
kaf24@5233 31 string_param("com2", opt_com2);
kaf24@5233 32
kaf24@5233 33 static struct ns16550 {
keir@18680 34 int baud, clock_hz, data_bits, parity, stop_bits, irq;
kaf24@5337 35 unsigned long io_base; /* I/O port or memory-mapped I/O address. */
kaf24@5337 36 char *remapped_io_base; /* Remapped virtual address of mmap I/O. */
kaf24@8049 37 /* UART with IRQ line: interrupt-driven I/O. */
kaf24@5233 38 struct irqaction irqaction;
kaf24@8049 39 /* UART with no IRQ line: periodically-polled I/O. */
kaf24@8616 40 struct timer timer;
kaf24@8049 41 unsigned int timeout_ms;
keir@20955 42 int probing, intr_works;
kaf24@5814 43 } ns16550_com[2] = { { 0 } };
kaf24@5233 44
kaf24@5233 45 /* Register offsets */
kaf24@5233 46 #define RBR 0x00 /* receive buffer */
kaf24@5233 47 #define THR 0x00 /* transmit holding */
kaf24@5233 48 #define IER 0x01 /* interrupt enable */
kaf24@5233 49 #define IIR 0x02 /* interrupt identity */
kaf24@5233 50 #define FCR 0x02 /* FIFO control */
kaf24@5233 51 #define LCR 0x03 /* line control */
kaf24@5233 52 #define MCR 0x04 /* Modem control */
kaf24@5233 53 #define LSR 0x05 /* line status */
kaf24@5233 54 #define MSR 0x06 /* Modem status */
kaf24@5233 55 #define DLL 0x00 /* divisor latch (ls) (DLAB=1) */
kaf24@5233 56 #define DLM 0x01 /* divisor latch (ms) (DLAB=1) */
kaf24@5233 57
kaf24@5233 58 /* Interrupt Enable Register */
kaf24@5233 59 #define IER_ERDAI 0x01 /* rx data recv'd */
kaf24@5233 60 #define IER_ETHREI 0x02 /* tx reg. empty */
kaf24@5233 61 #define IER_ELSI 0x04 /* rx line status */
kaf24@5233 62 #define IER_EMSI 0x08 /* MODEM status */
kaf24@5233 63
kaf24@5364 64 /* Interrupt Identification Register */
kaf24@5364 65 #define IIR_NOINT 0x01 /* no interrupt pending */
kaf24@5364 66 #define IIR_IMASK 0x06 /* interrupt identity: */
kaf24@5364 67 #define IIR_LSI 0x06 /* - rx line status */
kaf24@5364 68 #define IIR_RDAI 0x04 /* - rx data recv'd */
kaf24@5364 69 #define IIR_THREI 0x02 /* - tx reg. empty */
kaf24@5364 70 #define IIR_MSI 0x00 /* - MODEM status */
kaf24@5364 71
kaf24@5364 72 /* FIFO Control Register */
kaf24@5233 73 #define FCR_ENABLE 0x01 /* enable FIFO */
kaf24@5233 74 #define FCR_CLRX 0x02 /* clear Rx FIFO */
kaf24@5233 75 #define FCR_CLTX 0x04 /* clear Tx FIFO */
kaf24@5233 76 #define FCR_DMA 0x10 /* enter DMA mode */
kaf24@5233 77 #define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */
kaf24@5233 78 #define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */
kaf24@5233 79 #define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
kaf24@5233 80 #define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
kaf24@5233 81
kaf24@5364 82 /* Line Control Register */
kaf24@5233 83 #define LCR_DLAB 0x80 /* Divisor Latch Access */
kaf24@5233 84
kaf24@5233 85 /* Modem Control Register */
kaf24@5233 86 #define MCR_DTR 0x01 /* Data Terminal Ready */
kaf24@5233 87 #define MCR_RTS 0x02 /* Request to Send */
kaf24@5233 88 #define MCR_OUT2 0x08 /* OUT2: interrupt mask */
keir@18511 89 #define MCR_LOOP 0x10 /* Enable loopback test mode */
kaf24@5233 90
kaf24@5233 91 /* Line Status Register */
kaf24@5233 92 #define LSR_DR 0x01 /* Data ready */
kaf24@5233 93 #define LSR_OE 0x02 /* Overrun */
kaf24@5233 94 #define LSR_PE 0x04 /* Parity error */
kaf24@5233 95 #define LSR_FE 0x08 /* Framing error */
kaf24@5233 96 #define LSR_BI 0x10 /* Break */
kaf24@5233 97 #define LSR_THRE 0x20 /* Xmit hold reg empty */
kaf24@5233 98 #define LSR_TEMT 0x40 /* Xmitter empty */
kaf24@5233 99 #define LSR_ERR 0x80 /* Error */
kaf24@5233 100
kaf24@5233 101 /* These parity settings can be ORed directly into the LCR. */
kaf24@5233 102 #define PARITY_NONE (0<<3)
kaf24@5233 103 #define PARITY_ODD (1<<3)
kaf24@5233 104 #define PARITY_EVEN (3<<3)
kaf24@5233 105 #define PARITY_MARK (5<<3)
kaf24@5233 106 #define PARITY_SPACE (7<<3)
kaf24@5233 107
kaf24@9504 108 /* Frequency of external clock source. This definition assumes PC platform. */
kaf24@9504 109 #define UART_CLOCK_HZ 1843200
kaf24@9504 110
kaf24@5337 111 static char ns_read_reg(struct ns16550 *uart, int reg)
kaf24@5337 112 {
kaf24@5337 113 if ( uart->remapped_io_base == NULL )
kaf24@5337 114 return inb(uart->io_base + reg);
kaf24@5337 115 return readb(uart->remapped_io_base + reg);
kaf24@5337 116 }
kaf24@5337 117
kaf24@5337 118 static void ns_write_reg(struct ns16550 *uart, int reg, char c)
kaf24@5337 119 {
kaf24@5337 120 if ( uart->remapped_io_base == NULL )
kaf24@5337 121 return outb(c, uart->io_base + reg);
kaf24@5337 122 writeb(c, uart->remapped_io_base + reg);
kaf24@5337 123 }
kaf24@5337 124
kaf24@5233 125 static void ns16550_interrupt(
kaf24@5233 126 int irq, void *dev_id, struct cpu_user_regs *regs)
kaf24@5233 127 {
kaf24@5359 128 struct serial_port *port = dev_id;
kaf24@5359 129 struct ns16550 *uart = port->uart;
kaf24@5359 130
keir@20955 131 if (uart->intr_works == 0)
keir@20955 132 {
keir@20955 133 uart->probing = 0;
keir@20955 134 uart->intr_works = 1;
keir@20955 135 stop_timer(&uart->timer);
keir@20955 136 }
keir@20955 137
kaf24@5364 138 while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) )
kaf24@5364 139 {
kaf24@9457 140 char lsr = ns_read_reg(uart, LSR);
kaf24@9457 141 if ( lsr & LSR_THRE )
kaf24@9457 142 serial_tx_interrupt(port, regs);
kaf24@9457 143 if ( lsr & LSR_DR )
kaf24@9457 144 serial_rx_interrupt(port, regs);
kaf24@5364 145 }
kaf24@5359 146 }
kaf24@5359 147
kaf24@8049 148 static void ns16550_poll(void *data)
kaf24@8049 149 {
kaf24@8049 150 struct serial_port *port = data;
kaf24@8049 151 struct ns16550 *uart = port->uart;
kaf24@8049 152 struct cpu_user_regs *regs = guest_cpu_user_regs();
kaf24@8049 153
keir@20955 154 if ( uart->intr_works )
keir@20955 155 return; /* Interrupts work - no more polling */
keir@20955 156
keir@20955 157 if ( uart->probing ) {
keir@20955 158 uart->probing = 0;
keir@20955 159 if ( (ns_read_reg(uart, LSR) & 0xff) == 0xff )
keir@20955 160 return; /* All bits set - probably no UART present */
keir@20955 161 }
keir@20955 162
kaf24@8049 163 while ( ns_read_reg(uart, LSR) & LSR_DR )
kaf24@8049 164 serial_rx_interrupt(port, regs);
kaf24@8049 165
kaf24@8049 166 if ( ns_read_reg(uart, LSR) & LSR_THRE )
kaf24@8049 167 serial_tx_interrupt(port, regs);
kaf24@8049 168
kaf24@8616 169 set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
kaf24@8049 170 }
kaf24@8049 171
kaf24@5359 172 static int ns16550_tx_empty(struct serial_port *port)
kaf24@5359 173 {
kaf24@5359 174 struct ns16550 *uart = port->uart;
kaf24@5359 175 return !!(ns_read_reg(uart, LSR) & LSR_THRE);
kaf24@5233 176 }
kaf24@5233 177
kaf24@5233 178 static void ns16550_putc(struct serial_port *port, char c)
kaf24@5233 179 {
kaf24@5233 180 struct ns16550 *uart = port->uart;
kaf24@5337 181 ns_write_reg(uart, THR, c);
kaf24@5233 182 }
kaf24@5233 183
kaf24@5233 184 static int ns16550_getc(struct serial_port *port, char *pc)
kaf24@5233 185 {
kaf24@5233 186 struct ns16550 *uart = port->uart;
kaf24@5233 187
kaf24@5337 188 if ( !(ns_read_reg(uart, LSR) & LSR_DR) )
kaf24@5233 189 return 0;
kaf24@5233 190
kaf24@5337 191 *pc = ns_read_reg(uart, RBR);
kaf24@5233 192 return 1;
kaf24@5233 193 }
kaf24@5233 194
kfraser@15578 195 static void __devinit ns16550_init_preirq(struct serial_port *port)
kaf24@5233 196 {
kaf24@5233 197 struct ns16550 *uart = port->uart;
kaf24@5233 198 unsigned char lcr;
kaf24@9504 199 unsigned int divisor;
kaf24@5233 200
kaf24@5337 201 /* I/O ports are distinguished by their size (16 bits). */
kaf24@5337 202 if ( uart->io_base >= 0x10000 )
kaf24@5337 203 uart->remapped_io_base = (char *)ioremap(uart->io_base, 8);
kaf24@5337 204
kaf24@5233 205 lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
kaf24@5233 206
kaf24@5233 207 /* No interrupts. */
kaf24@5337 208 ns_write_reg(uart, IER, 0);
kaf24@5233 209
kaf24@5233 210 /* Line control and baud-rate generator. */
kaf24@9504 211 ns_write_reg(uart, LCR, lcr | LCR_DLAB);
kaf24@6042 212 if ( uart->baud != BAUD_AUTO )
kaf24@5814 213 {
kaf24@9504 214 /* Baud rate specified: program it into the divisor latch. */
keir@18680 215 divisor = uart->clock_hz / (uart->baud << 4);
kaf24@9504 216 ns_write_reg(uart, DLL, (char)divisor);
kaf24@9504 217 ns_write_reg(uart, DLM, (char)(divisor >> 8));
kaf24@5814 218 }
kaf24@9504 219 else
kaf24@9504 220 {
kaf24@9504 221 /* Baud rate already set: read it out from the divisor latch. */
kaf24@9504 222 divisor = ns_read_reg(uart, DLL);
kaf24@9504 223 divisor |= ns_read_reg(uart, DLM) << 8;
keir@18680 224 uart->baud = uart->clock_hz / (divisor << 4);
kaf24@9504 225 }
kaf24@9504 226 ns_write_reg(uart, LCR, lcr);
kaf24@5233 227
kaf24@5233 228 /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */
kaf24@5337 229 ns_write_reg(uart, MCR, MCR_DTR | MCR_RTS);
kaf24@5233 230
kaf24@5233 231 /* Enable and clear the FIFOs. Set a large trigger threshold. */
kaf24@5337 232 ns_write_reg(uart, FCR, FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14);
kaf24@5359 233
kaf24@5359 234 /* Check this really is a 16550+. Otherwise we have no FIFOs. */
keir@20035 235 if ( ((ns_read_reg(uart, IIR) & 0xc0) == 0xc0) &&
keir@20035 236 ((ns_read_reg(uart, FCR) & FCR_TRG14) == FCR_TRG14) )
kaf24@5359 237 port->tx_fifo_size = 16;
kaf24@5233 238 }
kaf24@5233 239
kfraser@15578 240 static void __devinit ns16550_init_postirq(struct serial_port *port)
kaf24@5233 241 {
kaf24@5233 242 struct ns16550 *uart = port->uart;
kaf24@8049 243 int rc, bits;
kaf24@5233 244
kaf24@8049 245 if ( uart->irq < 0 )
kaf24@5814 246 return;
kaf24@5814 247
kaf24@5359 248 serial_async_transmit(port);
kaf24@5359 249
keir@20955 250 init_timer(&uart->timer, ns16550_poll, port, 0);
keir@20955 251 /* Calculate time to fill RX FIFO and/or empty TX FIFO for polling. */
keir@20955 252 bits = uart->data_bits + uart->stop_bits + !!uart->parity;
keir@20955 253 uart->timeout_ms = max_t(
keir@20955 254 unsigned int, 1, (bits * port->tx_fifo_size * 1000) / uart->baud);
keir@20955 255
kaf24@8049 256 if ( uart->irq == 0 )
kaf24@8616 257 set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
kaf24@8049 258 else
kaf24@8049 259 {
kaf24@8049 260 uart->irqaction.handler = ns16550_interrupt;
kaf24@8049 261 uart->irqaction.name = "ns16550";
kaf24@8049 262 uart->irqaction.dev_id = port;
kaf24@8049 263 if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
kfraser@14763 264 printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);
kaf24@5233 265
kaf24@8049 266 /* Master interrupt enable; also keep DTR/RTS asserted. */
kaf24@8049 267 ns_write_reg(uart, MCR, MCR_OUT2 | MCR_DTR | MCR_RTS);
kaf24@5233 268
kaf24@8049 269 /* Enable receive and transmit interrupts. */
kaf24@8049 270 ns_write_reg(uart, IER, IER_ERDAI | IER_ETHREI);
keir@20955 271
keir@20955 272 /* Do a timed write to make sure we are getting interrupts. */
keir@20955 273 uart->probing = 1;
keir@20955 274 uart->intr_works = 0;
keir@20955 275 ns_write_reg(uart, THR, 0xff);
keir@20955 276 set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
kaf24@8049 277 }
kaf24@5233 278 }
kaf24@5233 279
kaf24@5233 280 #ifdef CONFIG_X86
keir@15081 281 static void __init ns16550_endboot(struct serial_port *port)
kaf24@5233 282 {
kaf24@5233 283 struct ns16550 *uart = port->uart;
kaf24@8498 284 if ( ioports_deny_access(dom0, uart->io_base, uart->io_base + 7) != 0 )
kaf24@8498 285 BUG();
kaf24@5233 286 }
kaf24@5233 287 #else
kaf24@5233 288 #define ns16550_endboot NULL
kaf24@5233 289 #endif
kaf24@5233 290
kaf24@9702 291 static int ns16550_irq(struct serial_port *port)
kaf24@9702 292 {
kaf24@9702 293 struct ns16550 *uart = port->uart;
kaf24@9702 294 return ((uart->irq > 0) ? uart->irq : -1);
kaf24@9702 295 }
kaf24@9702 296
keir@20420 297 static struct uart_driver __read_mostly ns16550_driver = {
kaf24@5233 298 .init_preirq = ns16550_init_preirq,
kaf24@5233 299 .init_postirq = ns16550_init_postirq,
kaf24@5233 300 .endboot = ns16550_endboot,
kaf24@5359 301 .tx_empty = ns16550_tx_empty,
kaf24@5233 302 .putc = ns16550_putc,
kaf24@9702 303 .getc = ns16550_getc,
kaf24@9702 304 .irq = ns16550_irq
kaf24@5233 305 };
kaf24@5233 306
keir@15081 307 static int __init parse_parity_char(int c)
kaf24@5814 308 {
kaf24@5814 309 switch ( c )
kaf24@5814 310 {
kaf24@5814 311 case 'n':
kaf24@5814 312 return PARITY_NONE;
kaf24@5814 313 case 'o':
kaf24@5814 314 return PARITY_ODD;
kaf24@5814 315 case 'e':
kaf24@5814 316 return PARITY_EVEN;
kaf24@5814 317 case 'm':
kaf24@5814 318 return PARITY_MARK;
kaf24@5814 319 case 's':
kaf24@5814 320 return PARITY_SPACE;
kaf24@5814 321 }
kaf24@5814 322 return 0;
kaf24@5814 323 }
kaf24@5814 324
keir@20036 325 static int __init check_existence(struct ns16550 *uart)
keir@18511 326 {
keir@18511 327 unsigned char status, scratch, scratch2, scratch3;
keir@18511 328
keir@18511 329 /*
keir@18899 330 * We can't poke MMIO UARTs until they get I/O remapped later. Assume that
keir@18899 331 * if we're getting MMIO UARTs, the arch code knows what it's doing.
keir@18899 332 */
keir@18899 333 if ( uart->io_base >= 0x10000 )
keir@18899 334 return 1;
keir@18899 335
keir@18899 336 /*
keir@18511 337 * Do a simple existence test first; if we fail this,
keir@18511 338 * there's no point trying anything else.
keir@18511 339 */
keir@18511 340 scratch = ns_read_reg(uart, IER);
keir@18511 341 ns_write_reg(uart, IER, 0);
keir@18511 342
keir@18511 343 /*
keir@18511 344 * Mask out IER[7:4] bits for test as some UARTs (e.g. TL
keir@18511 345 * 16C754B) allow only to modify them if an EFR bit is set.
keir@18511 346 */
keir@18511 347 scratch2 = ns_read_reg(uart, IER) & 0x0f;
keir@18511 348 ns_write_reg(uart, IER, 0x0F);
keir@18511 349 scratch3 = ns_read_reg(uart, IER) & 0x0f;
keir@18511 350 ns_write_reg(uart, IER, scratch);
keir@18511 351 if ( (scratch2 != 0) || (scratch3 != 0x0F) )
keir@18511 352 return 0;
keir@18511 353
keir@18511 354 /*
keir@18511 355 * Check to see if a UART is really there.
keir@18511 356 * Use loopback test mode.
keir@18511 357 */
keir@18511 358 ns_write_reg(uart, MCR, MCR_LOOP | 0x0A);
keir@18511 359 status = ns_read_reg(uart, MSR) & 0xF0;
keir@18511 360 return (status == 0x90);
keir@18511 361 }
keir@18511 362
kaf24@5233 363 #define PARSE_ERR(_f, _a...) \
kaf24@5233 364 do { \
kaf24@5233 365 printk( "ERROR: " _f "\n" , ## _a ); \
kaf24@5233 366 return; \
kaf24@5233 367 } while ( 0 )
kaf24@5233 368
keir@15081 369 static void __init ns16550_parse_port_config(
keir@15081 370 struct ns16550 *uart, const char *conf)
kaf24@5233 371 {
kaf24@5814 372 int baud;
kaf24@5233 373
kaf24@6042 374 /* No user-specified configuration? */
kaf24@5814 375 if ( (conf == NULL) || (*conf == '\0') )
kaf24@6042 376 {
kaf24@6042 377 /* Some platforms may automatically probe the UART configuartion. */
kaf24@6042 378 if ( uart->baud != 0 )
kaf24@6042 379 goto config_parsed;
kaf24@6042 380 return;
kaf24@6042 381 }
kaf24@5814 382
kaf24@6042 383 if ( strncmp(conf, "auto", 4) == 0 )
kaf24@6042 384 {
kaf24@6042 385 uart->baud = BAUD_AUTO;
kaf24@6042 386 conf += 4;
kaf24@6042 387 }
kaf24@6042 388 else if ( (baud = simple_strtoul(conf, &conf, 10)) != 0 )
kaf24@5814 389 uart->baud = baud;
kaf24@5233 390
keir@18680 391 if ( *conf == '/')
keir@18680 392 {
keir@18680 393 conf++;
keir@18680 394 uart->clock_hz = simple_strtoul(conf, &conf, 0) << 4;
keir@18680 395 }
keir@18680 396
kaf24@5233 397 if ( *conf != ',' )
kaf24@5814 398 goto config_parsed;
kaf24@5233 399 conf++;
kaf24@5233 400
kaf24@6042 401 uart->data_bits = simple_strtoul(conf, &conf, 10);
kaf24@5233 402
kaf24@5814 403 uart->parity = parse_parity_char(*conf);
kaf24@5233 404 conf++;
kaf24@5233 405
kaf24@6042 406 uart->stop_bits = simple_strtoul(conf, &conf, 10);
kaf24@5233 407
kaf24@5233 408 if ( *conf == ',' )
kaf24@5233 409 {
kaf24@5233 410 conf++;
kaf24@6042 411 uart->io_base = simple_strtoul(conf, &conf, 0);
kaf24@5233 412
kaf24@5337 413 if ( *conf == ',' )
kaf24@5337 414 {
kaf24@5337 415 conf++;
kaf24@6042 416 uart->irq = simple_strtoul(conf, &conf, 10);
kaf24@5337 417 }
kaf24@5233 418 }
kaf24@5233 419
kaf24@5814 420 config_parsed:
kaf24@5814 421 /* Sanity checks. */
kaf24@6042 422 if ( (uart->baud != BAUD_AUTO) &&
kaf24@6042 423 ((uart->baud < 1200) || (uart->baud > 115200)) )
kaf24@5814 424 PARSE_ERR("Baud rate %d outside supported range.", uart->baud);
kaf24@5814 425 if ( (uart->data_bits < 5) || (uart->data_bits > 8) )
kaf24@5814 426 PARSE_ERR("%d data bits are unsupported.", uart->data_bits);
kaf24@5814 427 if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) )
kaf24@5814 428 PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits);
kaf24@5814 429 if ( uart->io_base == 0 )
kaf24@5814 430 PARSE_ERR("I/O base address must be specified.");
keir@18511 431 if ( !check_existence(uart) )
keir@18511 432 PARSE_ERR("16550-compatible serial UART not present");
kaf24@5814 433
kaf24@5814 434 /* Register with generic serial driver. */
kaf24@5233 435 serial_register_uart(uart - ns16550_com, &ns16550_driver, uart);
kaf24@5233 436 }
kaf24@5233 437
keir@15081 438 void __init ns16550_init(int index, struct ns16550_defaults *defaults)
kaf24@5233 439 {
keir@16286 440 struct ns16550 *uart;
kaf24@5814 441
kaf24@5814 442 if ( (index < 0) || (index > 1) )
kaf24@5814 443 return;
kaf24@5814 444
keir@16286 445 uart = &ns16550_com[index];
keir@16286 446
keir@15988 447 uart->baud = (defaults->baud ? :
keir@15988 448 console_has((index == 0) ? "com1" : "com2")
keir@15988 449 ? BAUD_AUTO : 0);
keir@18680 450 uart->clock_hz = UART_CLOCK_HZ;
keir@15988 451 uart->data_bits = defaults->data_bits;
keir@15988 452 uart->parity = parse_parity_char(defaults->parity);
keir@15988 453 uart->stop_bits = defaults->stop_bits;
keir@15988 454 uart->irq = defaults->irq;
keir@15988 455 uart->io_base = defaults->io_base;
kaf24@5814 456
kaf24@5814 457 ns16550_parse_port_config(uart, (index == 0) ? opt_com1 : opt_com2);
kaf24@5233 458 }
kaf24@5233 459
kaf24@5233 460 /*
kaf24@5233 461 * Local variables:
kaf24@5233 462 * mode: C
kaf24@5233 463 * c-set-style: "BSD"
kaf24@5233 464 * c-basic-offset: 4
kaf24@5233 465 * tab-width: 4
kaf24@5233 466 * indent-tabs-mode: nil
kaf24@5233 467 * End:
kaf24@5233 468 */