ia64/xen-unstable

view xen/drivers/char/ns16550.c @ 14730:3121ffb809e9

xen: Fix typo in ns16550 driver.
Signed-off-by: Akio Takebe <takebe_akio@jp.fujitsu.com>
author kfraser@localhost.localdomain
date Thu Apr 05 08:42:34 2007 +0100 (2007-04-05)
parents 3e2d3d737624
children 759d924af6d8
line source
1 /******************************************************************************
2 * ns16550.c
3 *
4 * Driver for 16550-series UARTs. This driver is to be kept within Xen as
5 * it permits debugging of seriously-toasted machines (e.g., in situations
6 * where a device driver within a guest OS would be inaccessible).
7 *
8 * Copyright (c) 2003-2005, K A Fraser
9 */
11 #include <xen/config.h>
12 #include <xen/init.h>
13 #include <xen/irq.h>
14 #include <xen/sched.h>
15 #include <xen/serial.h>
16 #include <xen/iocap.h>
17 #include <asm/io.h>
19 /*
20 * Configure serial port with a string <baud>,DPS,<io-base>,<irq>.
21 * The tail of the string can be omitted if platform defaults are sufficient.
22 * If the baud rate is pre-configured, perhaps by a bootloader, then 'auto'
23 * can be specified in place of a numeric baud rate.
24 */
25 static char opt_com1[30] = "", opt_com2[30] = "";
26 string_param("com1", opt_com1);
27 string_param("com2", opt_com2);
29 static struct ns16550 {
30 int baud, data_bits, parity, stop_bits, irq;
31 unsigned long io_base; /* I/O port or memory-mapped I/O address. */
32 char *remapped_io_base; /* Remapped virtual address of mmap I/O. */
33 /* UART with IRQ line: interrupt-driven I/O. */
34 struct irqaction irqaction;
35 /* UART with no IRQ line: periodically-polled I/O. */
36 struct timer timer;
37 unsigned int timeout_ms;
38 } ns16550_com[2] = { { 0 } };
40 /* Register offsets */
41 #define RBR 0x00 /* receive buffer */
42 #define THR 0x00 /* transmit holding */
43 #define IER 0x01 /* interrupt enable */
44 #define IIR 0x02 /* interrupt identity */
45 #define FCR 0x02 /* FIFO control */
46 #define LCR 0x03 /* line control */
47 #define MCR 0x04 /* Modem control */
48 #define LSR 0x05 /* line status */
49 #define MSR 0x06 /* Modem status */
50 #define DLL 0x00 /* divisor latch (ls) (DLAB=1) */
51 #define DLM 0x01 /* divisor latch (ms) (DLAB=1) */
53 /* Interrupt Enable Register */
54 #define IER_ERDAI 0x01 /* rx data recv'd */
55 #define IER_ETHREI 0x02 /* tx reg. empty */
56 #define IER_ELSI 0x04 /* rx line status */
57 #define IER_EMSI 0x08 /* MODEM status */
59 /* Interrupt Identification Register */
60 #define IIR_NOINT 0x01 /* no interrupt pending */
61 #define IIR_IMASK 0x06 /* interrupt identity: */
62 #define IIR_LSI 0x06 /* - rx line status */
63 #define IIR_RDAI 0x04 /* - rx data recv'd */
64 #define IIR_THREI 0x02 /* - tx reg. empty */
65 #define IIR_MSI 0x00 /* - MODEM status */
67 /* FIFO Control Register */
68 #define FCR_ENABLE 0x01 /* enable FIFO */
69 #define FCR_CLRX 0x02 /* clear Rx FIFO */
70 #define FCR_CLTX 0x04 /* clear Tx FIFO */
71 #define FCR_DMA 0x10 /* enter DMA mode */
72 #define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */
73 #define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */
74 #define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
75 #define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
77 /* Line Control Register */
78 #define LCR_DLAB 0x80 /* Divisor Latch Access */
80 /* Modem Control Register */
81 #define MCR_DTR 0x01 /* Data Terminal Ready */
82 #define MCR_RTS 0x02 /* Request to Send */
83 #define MCR_OUT2 0x08 /* OUT2: interrupt mask */
85 /* Line Status Register */
86 #define LSR_DR 0x01 /* Data ready */
87 #define LSR_OE 0x02 /* Overrun */
88 #define LSR_PE 0x04 /* Parity error */
89 #define LSR_FE 0x08 /* Framing error */
90 #define LSR_BI 0x10 /* Break */
91 #define LSR_THRE 0x20 /* Xmit hold reg empty */
92 #define LSR_TEMT 0x40 /* Xmitter empty */
93 #define LSR_ERR 0x80 /* Error */
95 /* These parity settings can be ORed directly into the LCR. */
96 #define PARITY_NONE (0<<3)
97 #define PARITY_ODD (1<<3)
98 #define PARITY_EVEN (3<<3)
99 #define PARITY_MARK (5<<3)
100 #define PARITY_SPACE (7<<3)
102 /* Frequency of external clock source. This definition assumes PC platform. */
103 #define UART_CLOCK_HZ 1843200
105 static char ns_read_reg(struct ns16550 *uart, int reg)
106 {
107 if ( uart->remapped_io_base == NULL )
108 return inb(uart->io_base + reg);
109 return readb(uart->remapped_io_base + reg);
110 }
112 static void ns_write_reg(struct ns16550 *uart, int reg, char c)
113 {
114 if ( uart->remapped_io_base == NULL )
115 return outb(c, uart->io_base + reg);
116 writeb(c, uart->remapped_io_base + reg);
117 }
119 static void ns16550_interrupt(
120 int irq, void *dev_id, struct cpu_user_regs *regs)
121 {
122 struct serial_port *port = dev_id;
123 struct ns16550 *uart = port->uart;
125 while ( !(ns_read_reg(uart, IIR) & IIR_NOINT) )
126 {
127 char lsr = ns_read_reg(uart, LSR);
128 if ( lsr & LSR_THRE )
129 serial_tx_interrupt(port, regs);
130 if ( lsr & LSR_DR )
131 serial_rx_interrupt(port, regs);
132 }
133 }
135 static void ns16550_poll(void *data)
136 {
137 struct serial_port *port = data;
138 struct ns16550 *uart = port->uart;
139 struct cpu_user_regs *regs = guest_cpu_user_regs();
141 while ( ns_read_reg(uart, LSR) & LSR_DR )
142 serial_rx_interrupt(port, regs);
144 if ( ns_read_reg(uart, LSR) & LSR_THRE )
145 serial_tx_interrupt(port, regs);
147 set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
148 }
150 static int ns16550_tx_empty(struct serial_port *port)
151 {
152 struct ns16550 *uart = port->uart;
153 return !!(ns_read_reg(uart, LSR) & LSR_THRE);
154 }
156 static void ns16550_putc(struct serial_port *port, char c)
157 {
158 struct ns16550 *uart = port->uart;
159 ns_write_reg(uart, THR, c);
160 }
162 static int ns16550_getc(struct serial_port *port, char *pc)
163 {
164 struct ns16550 *uart = port->uart;
166 if ( !(ns_read_reg(uart, LSR) & LSR_DR) )
167 return 0;
169 *pc = ns_read_reg(uart, RBR);
170 return 1;
171 }
173 static void ns16550_init_preirq(struct serial_port *port)
174 {
175 struct ns16550 *uart = port->uart;
176 unsigned char lcr;
177 unsigned int divisor;
179 /* I/O ports are distinguished by their size (16 bits). */
180 if ( uart->io_base >= 0x10000 )
181 uart->remapped_io_base = (char *)ioremap(uart->io_base, 8);
183 lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
185 /* No interrupts. */
186 ns_write_reg(uart, IER, 0);
188 /* Line control and baud-rate generator. */
189 ns_write_reg(uart, LCR, lcr | LCR_DLAB);
190 if ( uart->baud != BAUD_AUTO )
191 {
192 /* Baud rate specified: program it into the divisor latch. */
193 divisor = UART_CLOCK_HZ / (uart->baud * 16);
194 ns_write_reg(uart, DLL, (char)divisor);
195 ns_write_reg(uart, DLM, (char)(divisor >> 8));
196 }
197 else
198 {
199 /* Baud rate already set: read it out from the divisor latch. */
200 divisor = ns_read_reg(uart, DLL);
201 divisor |= ns_read_reg(uart, DLM) << 8;
202 uart->baud = UART_CLOCK_HZ / (divisor * 16);
203 }
204 ns_write_reg(uart, LCR, lcr);
206 /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */
207 ns_write_reg(uart, MCR, MCR_DTR | MCR_RTS);
209 /* Enable and clear the FIFOs. Set a large trigger threshold. */
210 ns_write_reg(uart, FCR, FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14);
212 /* Check this really is a 16550+. Otherwise we have no FIFOs. */
213 if ( (ns_read_reg(uart, IIR) & 0xc0) == 0xc0 )
214 port->tx_fifo_size = 16;
215 }
217 static void ns16550_init_postirq(struct serial_port *port)
218 {
219 struct ns16550 *uart = port->uart;
220 int rc, bits;
222 if ( uart->irq < 0 )
223 return;
225 serial_async_transmit(port);
227 if ( uart->irq == 0 )
228 {
229 /* Polled mode. Calculate time to fill RX FIFO and/or empty TX FIFO. */
230 bits = uart->data_bits + uart->stop_bits + !!uart->parity;
231 uart->timeout_ms = max_t(
232 unsigned int, 1, (bits * port->tx_fifo_size * 1000) / uart->baud);
233 init_timer(&uart->timer, ns16550_poll, port, 0);
234 set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
235 }
236 else
237 {
238 uart->irqaction.handler = ns16550_interrupt;
239 uart->irqaction.name = "ns16550";
240 uart->irqaction.dev_id = port;
241 if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
242 printk("ERROR: Failed to allocate ns16550 IRQ %d\n", uart->irq);
244 /* Master interrupt enable; also keep DTR/RTS asserted. */
245 ns_write_reg(uart, MCR, MCR_OUT2 | MCR_DTR | MCR_RTS);
247 /* Enable receive and transmit interrupts. */
248 ns_write_reg(uart, IER, IER_ERDAI | IER_ETHREI);
249 }
250 }
252 #ifdef CONFIG_X86
253 static void ns16550_endboot(struct serial_port *port)
254 {
255 struct ns16550 *uart = port->uart;
256 if ( ioports_deny_access(dom0, uart->io_base, uart->io_base + 7) != 0 )
257 BUG();
258 }
259 #else
260 #define ns16550_endboot NULL
261 #endif
263 static int ns16550_irq(struct serial_port *port)
264 {
265 struct ns16550 *uart = port->uart;
266 return ((uart->irq > 0) ? uart->irq : -1);
267 }
269 static struct uart_driver ns16550_driver = {
270 .init_preirq = ns16550_init_preirq,
271 .init_postirq = ns16550_init_postirq,
272 .endboot = ns16550_endboot,
273 .tx_empty = ns16550_tx_empty,
274 .putc = ns16550_putc,
275 .getc = ns16550_getc,
276 .irq = ns16550_irq
277 };
279 static int parse_parity_char(int c)
280 {
281 switch ( c )
282 {
283 case 'n':
284 return PARITY_NONE;
285 case 'o':
286 return PARITY_ODD;
287 case 'e':
288 return PARITY_EVEN;
289 case 'm':
290 return PARITY_MARK;
291 case 's':
292 return PARITY_SPACE;
293 }
294 return 0;
295 }
297 #define PARSE_ERR(_f, _a...) \
298 do { \
299 printk( "ERROR: " _f "\n" , ## _a ); \
300 return; \
301 } while ( 0 )
303 static void ns16550_parse_port_config(struct ns16550 *uart, const char *conf)
304 {
305 int baud;
307 /* No user-specified configuration? */
308 if ( (conf == NULL) || (*conf == '\0') )
309 {
310 /* Some platforms may automatically probe the UART configuartion. */
311 if ( uart->baud != 0 )
312 goto config_parsed;
313 return;
314 }
316 if ( strncmp(conf, "auto", 4) == 0 )
317 {
318 uart->baud = BAUD_AUTO;
319 conf += 4;
320 }
321 else if ( (baud = simple_strtoul(conf, &conf, 10)) != 0 )
322 uart->baud = baud;
324 if ( *conf != ',' )
325 goto config_parsed;
326 conf++;
328 uart->data_bits = simple_strtoul(conf, &conf, 10);
330 uart->parity = parse_parity_char(*conf);
331 conf++;
333 uart->stop_bits = simple_strtoul(conf, &conf, 10);
335 if ( *conf == ',' )
336 {
337 conf++;
338 uart->io_base = simple_strtoul(conf, &conf, 0);
340 if ( *conf == ',' )
341 {
342 conf++;
343 uart->irq = simple_strtoul(conf, &conf, 10);
344 }
345 }
347 config_parsed:
348 /* Sanity checks. */
349 if ( (uart->baud != BAUD_AUTO) &&
350 ((uart->baud < 1200) || (uart->baud > 115200)) )
351 PARSE_ERR("Baud rate %d outside supported range.", uart->baud);
352 if ( (uart->data_bits < 5) || (uart->data_bits > 8) )
353 PARSE_ERR("%d data bits are unsupported.", uart->data_bits);
354 if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) )
355 PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits);
356 if ( uart->io_base == 0 )
357 PARSE_ERR("I/O base address must be specified.");
359 /* Register with generic serial driver. */
360 serial_register_uart(uart - ns16550_com, &ns16550_driver, uart);
361 }
363 void ns16550_init(int index, struct ns16550_defaults *defaults)
364 {
365 struct ns16550 *uart = &ns16550_com[index];
367 if ( (index < 0) || (index > 1) )
368 return;
370 if ( defaults != NULL )
371 {
372 uart->baud = defaults->baud;
373 uart->data_bits = defaults->data_bits;
374 uart->parity = parse_parity_char(defaults->parity);
375 uart->stop_bits = defaults->stop_bits;
376 uart->irq = defaults->irq;
377 uart->io_base = defaults->io_base;
378 }
380 ns16550_parse_port_config(uart, (index == 0) ? opt_com1 : opt_com2);
381 }
383 /*
384 * Local variables:
385 * mode: C
386 * c-set-style: "BSD"
387 * c-basic-offset: 4
388 * tab-width: 4
389 * indent-tabs-mode: nil
390 * End:
391 */