debuggers.hg

view xen/drivers/char/serial.c @ 3705:4294cfa9fad3

bitkeeper revision 1.1159.212.95 (4204aa0ee0re5Xx1zWrJ9ejxzgRs3w)

Various cleanups. Remove PDB pending simpler GDB stub and/or NetBSD debugger.
Force emacs mode to appropriate tabbing in various files.
Signed-off-by: keir.fraser@cl.cam.ac.uk
author kaf24@scramble.cl.cam.ac.uk
date Sat Feb 05 11:12:14 2005 +0000 (2005-02-05)
parents 1c55bbe02576
children 88957a238191
line source
1 /* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
2 /******************************************************************************
3 * serial.c
4 *
5 * Driver for 16550-series UARTs. This driver is to be kept within Xen as
6 * it permits debugging of seriously-toasted machines (e.g., in situations
7 * where a device driver within a guest OS would be inaccessible).
8 *
9 * Copyright (c) 2003-2004, K A Fraser
10 */
12 #include <xen/config.h>
13 #include <xen/init.h>
14 #include <xen/irq.h>
15 #include <xen/keyhandler.h>
16 #include <xen/reboot.h>
17 #include <xen/sched.h>
18 #include <xen/serial.h>
19 #include <asm/io.h>
21 /* opt_com[12]: Config serial port with a string <baud>,DPS,<io-base>,<irq>. */
22 static unsigned char opt_com1[30] = "", opt_com2[30] = "";
23 string_param("com1", opt_com1);
24 string_param("com2", opt_com2);
26 /* Register offsets */
27 #define RBR 0x00 /* receive buffer */
28 #define THR 0x00 /* transmit holding */
29 #define IER 0x01 /* interrupt enable */
30 #define IIR 0x02 /* interrupt identity */
31 #define FCR 0x02 /* FIFO control */
32 #define LCR 0x03 /* line control */
33 #define MCR 0x04 /* Modem control */
34 #define LSR 0x05 /* line status */
35 #define MSR 0x06 /* Modem status */
36 #define DLL 0x00 /* divisor latch (ls) (DLAB=1) */
37 #define DLM 0x01 /* divisor latch (ms) (DLAB=1) */
39 /* Interrupt Enable Register */
40 #define IER_ERDAI 0x01 /* rx data recv'd */
41 #define IER_ETHREI 0x02 /* tx reg. empty */
42 #define IER_ELSI 0x04 /* rx line status */
43 #define IER_EMSI 0x08 /* MODEM status */
45 /* FIFO control register */
46 #define FCR_ENABLE 0x01 /* enable FIFO */
47 #define FCR_CLRX 0x02 /* clear Rx FIFO */
48 #define FCR_CLTX 0x04 /* clear Tx FIFO */
49 #define FCR_DMA 0x10 /* enter DMA mode */
50 #define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */
51 #define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */
52 #define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */
53 #define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */
55 /* Line control register */
56 #define LCR_DLAB 0x80 /* Divisor Latch Access */
58 /* Modem Control Register */
59 #define MCR_DTR 0x01 /* Data Terminal Ready */
60 #define MCR_RTS 0x02 /* Request to Send */
61 #define MCR_OUT2 0x08 /* OUT2: interrupt mask */
63 /* Line Status Register */
64 #define LSR_DR 0x01 /* Data ready */
65 #define LSR_OE 0x02 /* Overrun */
66 #define LSR_PE 0x04 /* Parity error */
67 #define LSR_FE 0x08 /* Framing error */
68 #define LSR_BI 0x10 /* Break */
69 #define LSR_THRE 0x20 /* Xmit hold reg empty */
70 #define LSR_TEMT 0x40 /* Xmitter empty */
71 #define LSR_ERR 0x80 /* Error */
73 /* These parity settings can be ORed directly into the LCR. */
74 #define PARITY_NONE (0<<3)
75 #define PARITY_ODD (1<<3)
76 #define PARITY_EVEN (3<<3)
77 #define PARITY_MARK (5<<3)
78 #define PARITY_SPACE (7<<3)
80 #define RXBUFSZ 32
81 #define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1))
82 typedef struct {
83 int baud, data_bits, parity, stop_bits, io_base, irq;
84 serial_rx_fn rx_lo, rx_hi, rx;
85 spinlock_t lock;
86 unsigned char rxbuf[RXBUFSZ];
87 unsigned int rxbufp, rxbufc;
88 struct irqaction irqaction;
89 } uart_t;
91 static uart_t com[2] = {
92 { 0, 0, 0, 0, 0x3f8, 4,
93 NULL, NULL, NULL,
94 SPIN_LOCK_UNLOCKED },
95 { 0, 0, 0, 0, 0x2f8, 3,
96 NULL, NULL, NULL,
97 SPIN_LOCK_UNLOCKED }
98 };
100 #define UART_ENABLED(_u) ((_u)->baud != 0)
101 #define DISABLE_UART(_u) ((_u)->baud = 0)
103 #ifdef CONFIG_X86
104 static inline int arch_serial_putc(uart_t *uart, unsigned char c)
105 {
106 int space;
107 if ( (space = (inb(uart->io_base + LSR) & LSR_THRE)) )
108 outb(c, uart->io_base + THR);
109 return space;
110 }
111 #endif
114 /***********************
115 * PRIVATE FUNCTIONS
116 */
118 static void uart_rx(uart_t *uart, struct xen_regs *regs)
119 {
120 unsigned char c;
122 if ( !UART_ENABLED(uart) )
123 return;
125 /*
126 * No need for the uart spinlock here. Only the uart's own interrupt
127 * handler will read from the RBR and the handler isn't reentrant.
128 * Calls to serial_getc() will disable this handler before proceeding.
129 */
130 while ( inb(uart->io_base + LSR) & LSR_DR )
131 {
132 c = inb(uart->io_base + RBR);
133 if ( uart->rx != NULL )
134 uart->rx(c, regs);
135 else if ( (c & 0x80) && (uart->rx_hi != NULL) )
136 uart->rx_hi(c&0x7f, regs);
137 else if ( !(c & 0x80) && (uart->rx_lo != NULL) )
138 uart->rx_lo(c&0x7f, regs);
139 else if ( (uart->rxbufp - uart->rxbufc) != RXBUFSZ )
140 uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufp++)] = c;
141 }
142 }
144 static void serial_interrupt(int irq, void *dev_id, struct xen_regs *regs)
145 {
146 uart_rx((uart_t *)dev_id, regs);
147 }
149 static inline void __serial_putc(uart_t *uart, int handle, unsigned char c)
150 {
151 unsigned long flags;
152 int space;
154 if ( (c == '\n') && (handle & SERHND_COOKED) )
155 __serial_putc(uart, handle, '\r');
157 if ( handle & SERHND_HI )
158 c |= 0x80;
159 else if ( handle & SERHND_LO )
160 c &= 0x7f;
162 do {
163 spin_lock_irqsave(&uart->lock, flags);
164 space = arch_serial_putc(uart, c);
165 spin_unlock_irqrestore(&uart->lock, flags);
166 }
167 while ( !space );
168 }
170 #define PARSE_ERR(_f, _a...) \
171 do { \
172 printk( "ERROR: " _f "\n" , ## _a ); \
173 DISABLE_UART(uart); \
174 return; \
175 } while ( 0 )
177 static void parse_port_config(char *conf, uart_t *uart)
178 {
179 if ( *conf == '\0' )
180 return;
182 uart->baud = simple_strtol(conf, &conf, 10);
183 if ( (uart->baud < 1200) || (uart->baud > 115200) )
184 PARSE_ERR("Baud rate %d outside supported range.", uart->baud);
186 if ( *conf != ',' )
187 PARSE_ERR("Missing data/parity/stop specifiers.");
189 conf++;
191 uart->data_bits = simple_strtol(conf, &conf, 10);
192 if ( (uart->data_bits < 5) || (uart->data_bits > 8) )
193 PARSE_ERR("%d data bits are unsupported.", uart->data_bits);
195 switch ( *conf )
196 {
197 case 'n':
198 uart->parity = PARITY_NONE;
199 break;
200 case 'o':
201 uart->parity = PARITY_ODD;
202 break;
203 case 'e':
204 uart->parity = PARITY_EVEN;
205 break;
206 case 'm':
207 uart->parity = PARITY_MARK;
208 break;
209 case 's':
210 uart->parity = PARITY_SPACE;
211 break;
213 default:
214 PARSE_ERR("Invalid parity specifier '%c'.", *conf);
215 }
217 conf++;
219 uart->stop_bits = simple_strtol(conf, &conf, 10);
220 if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) )
221 PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits);
223 if ( *conf == ',' )
224 {
225 conf++;
227 uart->io_base = simple_strtol(conf, &conf, 0);
228 if ( (uart->io_base <= 0x0000) || (uart->io_base > 0xfff0) )
229 PARSE_ERR("I/O port base 0x%x is outside the supported range.",
230 uart->io_base);
232 if ( *conf != ',' )
233 PARSE_ERR("Missing IRQ specifier.");
235 conf++;
237 uart->irq = simple_strtol(conf, &conf, 10);
238 if ( (uart->irq <= 0) || (uart->irq >= 32) )
239 PARSE_ERR("IRQ %d is outside the supported range.", uart->irq);
240 }
241 }
243 static void uart_config_stage1(uart_t *uart)
244 {
245 unsigned char lcr;
247 if ( !UART_ENABLED(uart) )
248 return;
250 lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
252 /* No interrupts. */
253 outb(0, uart->io_base + IER);
255 /* Line control and baud-rate generator. */
256 outb(lcr | LCR_DLAB, uart->io_base + LCR);
257 outb(115200/uart->baud, uart->io_base + DLL); /* baud lo */
258 outb(0, uart->io_base + DLM); /* baud hi */
259 outb(lcr, uart->io_base + LCR); /* parity, data, stop */
261 /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */
262 outb(MCR_DTR | MCR_RTS, uart->io_base + MCR);
264 /* Enable and clear the FIFOs. Set a large trigger threshold. */
265 outb(FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14, uart->io_base + FCR);
266 }
268 static void uart_config_stage2(uart_t *uart)
269 {
270 int rc;
272 if ( !UART_ENABLED(uart) )
273 return;
275 uart->irqaction.handler = serial_interrupt;
276 uart->irqaction.name = "serial";
277 uart->irqaction.dev_id = uart;
278 if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
279 printk("ERROR: Failed to allocate serial IRQ %d\n", uart->irq);
281 /* For sanity, clear the receive FIFO. */
282 outb(FCR_ENABLE | FCR_CLRX | FCR_TRG14, uart->io_base + FCR);
284 /* Master interrupt enable; also keep DTR/RTS asserted. */
285 outb(MCR_OUT2 | MCR_DTR | MCR_RTS, uart->io_base + MCR);
287 /* Enable receive interrupts. */
288 outb(IER_ERDAI, uart->io_base + IER);
289 }
292 /***********************
293 * PUBLIC FUNCTIONS
294 */
296 void serial_init_stage1(void)
297 {
298 parse_port_config(opt_com1, &com[0]);
299 parse_port_config(opt_com2, &com[1]);
301 uart_config_stage1(&com[0]);
302 uart_config_stage1(&com[1]);
303 }
305 void serial_init_stage2(void)
306 {
307 uart_config_stage2(&com[0]);
308 uart_config_stage2(&com[1]);
309 }
311 int parse_serial_handle(char *conf)
312 {
313 int handle;
315 /* Silently fail if user has explicitly requested no serial I/O. */
316 if ( strcmp(conf, "none") == 0 )
317 return -1;
319 if ( strncmp(conf, "com", 3) != 0 )
320 goto fail;
322 switch ( conf[3] )
323 {
324 case '1':
325 handle = 0;
326 break;
327 case '2':
328 handle = 1;
329 break;
330 default:
331 goto fail;
332 }
334 #ifndef NO_UART_CONFIG_OK
335 if ( !UART_ENABLED(&com[handle]) )
336 {
337 printk("ERROR: cannot use unconfigured serial port COM%d\n", handle+1);
338 return -1;
339 }
340 #endif
342 if ( conf[4] == 'H' )
343 handle |= SERHND_HI;
344 else if ( conf[4] == 'L' )
345 handle |= SERHND_LO;
347 handle |= SERHND_COOKED;
349 return handle;
351 fail:
352 printk("ERROR: bad serial-interface specification '%s'\n", conf);
353 return -1;
354 }
356 void serial_set_rx_handler(int handle, serial_rx_fn fn)
357 {
358 uart_t *uart = &com[handle & SERHND_IDX];
359 unsigned long flags;
361 if ( handle == -1 )
362 return;
364 spin_lock_irqsave(&uart->lock, flags);
366 if ( uart->rx != NULL )
367 goto fail;
369 if ( handle & SERHND_LO )
370 {
371 if ( uart->rx_lo != NULL )
372 goto fail;
373 uart->rx_lo = fn;
374 }
375 else if ( handle & SERHND_HI )
376 {
377 if ( uart->rx_hi != NULL )
378 goto fail;
379 uart->rx_hi = fn;
380 }
381 else
382 {
383 if ( (uart->rx_hi != NULL) || (uart->rx_lo != NULL) )
384 goto fail;
385 uart->rx = fn;
386 }
388 spin_unlock_irqrestore(&uart->lock, flags);
389 return;
391 fail:
392 spin_unlock_irqrestore(&uart->lock, flags);
393 printk("ERROR: Conflicting receive handlers for COM%d\n",
394 handle & SERHND_IDX);
395 }
397 void serial_putc(int handle, unsigned char c)
398 {
399 uart_t *uart = &com[handle & SERHND_IDX];
401 if ( handle == -1 )
402 return;
404 __serial_putc(uart, handle, c);
405 }
407 void serial_puts(int handle, const unsigned char *s)
408 {
409 uart_t *uart = &com[handle & SERHND_IDX];
411 if ( handle == -1 )
412 return;
414 while ( *s != '\0' )
415 __serial_putc(uart, handle, *s++);
416 }
418 /* Returns TRUE if given character (*pc) matches the serial handle. */
419 static int byte_matches(int handle, unsigned char *pc)
420 {
421 if ( !(handle & SERHND_HI) )
422 {
423 if ( !(handle & SERHND_LO) || !(*pc & 0x80) )
424 return 1;
425 }
426 else if ( *pc & 0x80 )
427 {
428 *pc &= 0x7f;
429 return 1;
430 }
431 return 0;
432 }
434 unsigned char irq_serial_getc(int handle)
435 {
436 uart_t *uart = &com[handle & SERHND_IDX];
437 unsigned char c;
439 while ( uart->rxbufp != uart->rxbufc )
440 {
441 c = uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufc++)];
442 if ( byte_matches(handle, &c) )
443 goto out;
444 }
446 /* We now wait for the UART to receive a suitable character. */
447 do {
448 while ( (inb(uart->io_base + LSR) & LSR_DR) == 0 )
449 barrier();
450 c = inb(uart->io_base + RBR);
451 }
452 while ( !byte_matches(handle, &c) );
454 out:
455 return c;
456 }
458 unsigned char serial_getc(int handle)
459 {
460 uart_t *uart = &com[handle & SERHND_IDX];
461 unsigned char c;
462 unsigned long flags;
464 spin_lock_irqsave(&uart->lock, flags);
466 while ( uart->rxbufp != uart->rxbufc )
467 {
468 c = uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufc++)];
469 if ( byte_matches(handle, &c) )
470 goto out;
471 }
473 disable_irq(uart->irq);
475 c = irq_serial_getc(handle);
477 enable_irq(uart->irq);
478 out:
479 spin_unlock_irqrestore(&uart->lock, flags);
480 return c;
481 }
483 void serial_force_unlock(int handle)
484 {
485 uart_t *uart = &com[handle & SERHND_IDX];
486 if ( handle != -1 )
487 uart->lock = SPIN_LOCK_UNLOCKED;
488 }