debuggers.hg

view xen/drivers/char/serial.c @ 16679:b0c85bc56f9e

Fix serial output of carriage return when using high-bit stream muxing.
Original patch by Dan Doucette.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 19 15:02:05 2007 +0000 (2007-12-19)
parents 537b8edb1efa
children a7ddd6bcd564
line source
1 /******************************************************************************
2 * serial.c
3 *
4 * Framework for serial device drivers.
5 *
6 * Copyright (c) 2003-2005, K A Fraser
7 */
9 #include <xen/config.h>
10 #include <xen/delay.h>
11 #include <xen/init.h>
12 #include <xen/irq.h>
13 #include <xen/keyhandler.h>
14 #include <xen/sched.h>
15 #include <xen/mm.h>
16 #include <xen/serial.h>
18 static struct serial_port com[2] = {
19 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED },
20 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED }
21 };
23 void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
24 {
25 char c;
26 serial_rx_fn fn = NULL;
27 unsigned long flags;
29 spin_lock_irqsave(&port->rx_lock, flags);
31 if ( port->driver->getc(port, &c) )
32 {
33 if ( port->rx != NULL )
34 fn = port->rx;
35 else if ( (c & 0x80) && (port->rx_hi != NULL) )
36 fn = port->rx_hi;
37 else if ( !(c & 0x80) && (port->rx_lo != NULL) )
38 fn = port->rx_lo;
39 else if ( (port->rxbufp - port->rxbufc) != SERIAL_RXBUFSZ )
40 port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c;
41 }
43 spin_unlock_irqrestore(&port->rx_lock, flags);
45 if ( fn != NULL )
46 (*fn)(c & 0x7f, regs);
47 }
49 void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
50 {
51 int i;
52 unsigned long flags;
54 local_irq_save(flags);
56 /*
57 * Avoid spinning for a long time: if there is a long-term lock holder
58 * then we know that they'll be stuffing bytes into the transmitter which
59 * will therefore not be empty for long.
60 */
61 while ( !spin_trylock(&port->tx_lock) )
62 {
63 if ( !port->driver->tx_empty(port) )
64 return;
65 cpu_relax();
66 }
68 if ( port->driver->tx_empty(port) )
69 {
70 for ( i = 0; i < port->tx_fifo_size; i++ )
71 {
72 if ( port->txbufc == port->txbufp )
73 break;
74 port->driver->putc(
75 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
76 }
77 }
79 spin_unlock_irqrestore(&port->tx_lock, flags);
80 }
82 static void __serial_putc(struct serial_port *port, char c)
83 {
84 int i;
86 if ( (port->txbuf != NULL) && !port->sync )
87 {
88 /* Interrupt-driven (asynchronous) transmitter. */
89 if ( (port->txbufp - port->txbufc) == SERIAL_TXBUFSZ )
90 {
91 /* Buffer is full: we spin, but could alternatively drop chars. */
92 while ( !port->driver->tx_empty(port) )
93 cpu_relax();
94 for ( i = 0; i < port->tx_fifo_size; i++ )
95 port->driver->putc(
96 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
97 port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
98 }
99 else if ( ((port->txbufp - port->txbufc) == 0) &&
100 port->driver->tx_empty(port) )
101 {
102 /* Buffer and UART FIFO are both empty. */
103 port->driver->putc(port, c);
104 }
105 else
106 {
107 /* Normal case: buffer the character. */
108 port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
109 }
110 }
111 else if ( port->driver->tx_empty )
112 {
113 /* Synchronous finite-capacity transmitter. */
114 while ( !port->driver->tx_empty(port) )
115 cpu_relax();
116 port->driver->putc(port, c);
117 }
118 else
119 {
120 /* Simple synchronous transmitter. */
121 port->driver->putc(port, c);
122 }
123 }
125 void serial_putc(int handle, char c)
126 {
127 struct serial_port *port;
128 unsigned long flags;
130 if ( handle == -1 )
131 return;
133 port = &com[handle & SERHND_IDX];
134 if ( !port->driver || !port->driver->putc )
135 return;
137 spin_lock_irqsave(&port->tx_lock, flags);
139 if ( (c == '\n') && (handle & SERHND_COOKED) )
140 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
142 if ( handle & SERHND_HI )
143 c |= 0x80;
144 else if ( handle & SERHND_LO )
145 c &= 0x7f;
147 __serial_putc(port, c);
149 spin_unlock_irqrestore(&port->tx_lock, flags);
150 }
152 void serial_puts(int handle, const char *s)
153 {
154 struct serial_port *port;
155 unsigned long flags;
156 char c;
158 if ( handle == -1 )
159 return;
161 port = &com[handle & SERHND_IDX];
162 if ( !port->driver || !port->driver->putc )
163 return;
165 spin_lock_irqsave(&port->tx_lock, flags);
167 while ( (c = *s++) != '\0' )
168 {
169 if ( (c == '\n') && (handle & SERHND_COOKED) )
170 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
172 if ( handle & SERHND_HI )
173 c |= 0x80;
174 else if ( handle & SERHND_LO )
175 c &= 0x7f;
177 __serial_putc(port, c);
178 }
180 spin_unlock_irqrestore(&port->tx_lock, flags);
181 }
183 char serial_getc(int handle)
184 {
185 struct serial_port *port;
186 char c;
187 unsigned long flags;
189 if ( handle == -1 )
190 return '\0';
192 port = &com[handle & SERHND_IDX];
193 if ( !port->driver || !port->driver->getc )
194 return '\0';
196 do {
197 for ( ; ; )
198 {
199 spin_lock_irqsave(&port->rx_lock, flags);
201 if ( port->rxbufp != port->rxbufc )
202 {
203 c = port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufc++)];
204 spin_unlock_irqrestore(&port->rx_lock, flags);
205 break;
206 }
208 if ( port->driver->getc(port, &c) )
209 {
210 spin_unlock_irqrestore(&port->rx_lock, flags);
211 break;
212 }
214 spin_unlock_irqrestore(&port->rx_lock, flags);
216 cpu_relax();
217 udelay(100);
218 }
219 } while ( ((handle & SERHND_LO) && (c & 0x80)) ||
220 ((handle & SERHND_HI) && !(c & 0x80)) );
222 return c & 0x7f;
223 }
225 int serial_parse_handle(char *conf)
226 {
227 int handle;
229 /* Silently fail if user has explicitly requested no serial I/O. */
230 if ( strcmp(conf, "none") == 0 )
231 return -1;
233 if ( strncmp(conf, "com", 3) != 0 )
234 goto fail;
236 switch ( conf[3] )
237 {
238 case '1':
239 handle = 0;
240 break;
241 case '2':
242 handle = 1;
243 break;
244 default:
245 goto fail;
246 }
248 if ( conf[4] == 'H' )
249 handle |= SERHND_HI;
250 else if ( conf[4] == 'L' )
251 handle |= SERHND_LO;
253 handle |= SERHND_COOKED;
255 return handle;
257 fail:
258 printk("ERROR: bad serial-interface specification '%s'\n", conf);
259 return -1;
260 }
262 void serial_set_rx_handler(int handle, serial_rx_fn fn)
263 {
264 struct serial_port *port;
265 unsigned long flags;
267 if ( handle == -1 )
268 return;
270 port = &com[handle & SERHND_IDX];
272 spin_lock_irqsave(&port->rx_lock, flags);
274 if ( port->rx != NULL )
275 goto fail;
277 if ( handle & SERHND_LO )
278 {
279 if ( port->rx_lo != NULL )
280 goto fail;
281 port->rx_lo = fn;
282 }
283 else if ( handle & SERHND_HI )
284 {
285 if ( port->rx_hi != NULL )
286 goto fail;
287 port->rx_hi = fn;
288 }
289 else
290 {
291 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
292 goto fail;
293 port->rx = fn;
294 }
296 spin_unlock_irqrestore(&port->rx_lock, flags);
297 return;
299 fail:
300 spin_unlock_irqrestore(&port->rx_lock, flags);
301 printk("ERROR: Conflicting receive handlers for COM%d\n",
302 handle & SERHND_IDX);
303 }
305 void serial_force_unlock(int handle)
306 {
307 struct serial_port *port;
309 if ( handle == -1 )
310 return;
312 port = &com[handle & SERHND_IDX];
314 spin_lock_init(&port->rx_lock);
315 spin_lock_init(&port->tx_lock);
317 serial_start_sync(handle);
318 }
320 void serial_start_sync(int handle)
321 {
322 struct serial_port *port;
323 unsigned long flags;
325 if ( handle == -1 )
326 return;
328 port = &com[handle & SERHND_IDX];
330 spin_lock_irqsave(&port->tx_lock, flags);
332 if ( port->sync++ == 0 )
333 {
334 while ( (port->txbufp - port->txbufc) != 0 )
335 {
336 while ( !port->driver->tx_empty(port) )
337 cpu_relax();
338 port->driver->putc(
339 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
340 }
341 }
343 spin_unlock_irqrestore(&port->tx_lock, flags);
344 }
346 void serial_end_sync(int handle)
347 {
348 struct serial_port *port;
349 unsigned long flags;
351 if ( handle == -1 )
352 return;
354 port = &com[handle & SERHND_IDX];
356 spin_lock_irqsave(&port->tx_lock, flags);
358 port->sync--;
360 spin_unlock_irqrestore(&port->tx_lock, flags);
361 }
363 int serial_tx_space(int handle)
364 {
365 struct serial_port *port;
366 if ( handle == -1 )
367 return SERIAL_TXBUFSZ;
368 port = &com[handle & SERHND_IDX];
369 return SERIAL_TXBUFSZ - (port->txbufp - port->txbufc);
370 }
372 void __devinit serial_init_preirq(void)
373 {
374 int i;
375 for ( i = 0; i < ARRAY_SIZE(com); i++ )
376 if ( com[i].driver && com[i].driver->init_preirq )
377 com[i].driver->init_preirq(&com[i]);
378 }
380 void __devinit serial_init_postirq(void)
381 {
382 int i;
383 for ( i = 0; i < ARRAY_SIZE(com); i++ )
384 if ( com[i].driver && com[i].driver->init_postirq )
385 com[i].driver->init_postirq(&com[i]);
386 }
388 void __init serial_endboot(void)
389 {
390 int i;
391 for ( i = 0; i < ARRAY_SIZE(com); i++ )
392 if ( com[i].driver && com[i].driver->endboot )
393 com[i].driver->endboot(&com[i]);
394 }
396 int serial_irq(int idx)
397 {
398 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
399 com[idx].driver && com[idx].driver->irq )
400 return com[idx].driver->irq(&com[idx]);
402 return -1;
403 }
405 void serial_suspend(void)
406 {
407 int i, irq;
408 for ( i = 0; i < ARRAY_SIZE(com); i++ )
409 if ( (irq = serial_irq(i)) >= 0 )
410 free_irq(irq);
411 }
413 void serial_resume(void)
414 {
415 serial_init_preirq();
416 serial_init_postirq();
417 }
419 void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
420 {
421 /* Store UART-specific info. */
422 com[idx].driver = driver;
423 com[idx].uart = uart;
425 /* Default is no transmit FIFO. */
426 com[idx].tx_fifo_size = 1;
427 }
429 void serial_async_transmit(struct serial_port *port)
430 {
431 BUG_ON(!port->driver->tx_empty);
432 if ( port->txbuf == NULL )
433 port->txbuf = alloc_xenheap_pages(
434 get_order_from_bytes(SERIAL_TXBUFSZ));
435 }
437 /*
438 * Local variables:
439 * mode: C
440 * c-set-style: "BSD"
441 * c-basic-offset: 4
442 * tab-width: 4
443 * indent-tabs-mode: nil
444 * End:
445 */