debuggers.hg

view xen/drivers/char/serial.c @ 22906:700ac6445812

Now add KDB to the non-kdb tree
author Mukesh Rathor
date Thu Feb 03 15:42:41 2011 -0800 (2011-02-03)
parents 5a224e101cb3
children
line source
1 /******************************************************************************
2 * serial.c
3 *
4 * Framework for serial device drivers.
5 *
6 * Copyright (c) 2003-2008, 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 /* Never drop characters, even if the async transmit buffer fills. */
19 /* #define SERIAL_NEVER_DROP_CHARS 1 */
21 unsigned int __read_mostly serial_txbufsz = 16384;
22 size_param("serial_tx_buffer", serial_txbufsz);
24 #define mask_serial_rxbuf_idx(_i) ((_i)&(serial_rxbufsz-1))
25 #define mask_serial_txbuf_idx(_i) ((_i)&(serial_txbufsz-1))
27 static struct serial_port com[2] = {
28 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED },
29 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED }
30 };
32 void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
33 {
34 char c;
35 serial_rx_fn fn = NULL;
36 unsigned long flags;
38 spin_lock_irqsave(&port->rx_lock, flags);
40 if ( port->driver->getc(port, &c) )
41 {
42 if ( port->rx != NULL )
43 fn = port->rx;
44 else if ( (c & 0x80) && (port->rx_hi != NULL) )
45 fn = port->rx_hi;
46 else if ( !(c & 0x80) && (port->rx_lo != NULL) )
47 fn = port->rx_lo;
48 else if ( (port->rxbufp - port->rxbufc) != serial_rxbufsz )
49 port->rxbuf[mask_serial_rxbuf_idx(port->rxbufp++)] = c;
50 }
52 spin_unlock_irqrestore(&port->rx_lock, flags);
54 if ( fn != NULL )
55 (*fn)(c & 0x7f, regs);
56 }
58 void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
59 {
60 int i;
61 unsigned long flags;
63 local_irq_save(flags);
65 /*
66 * Avoid spinning for a long time: if there is a long-term lock holder
67 * then we know that they'll be stuffing bytes into the transmitter which
68 * will therefore not be empty for long.
69 */
70 while ( !spin_trylock(&port->tx_lock) )
71 {
72 if ( !port->driver->tx_empty(port) )
73 goto out;
74 cpu_relax();
75 }
77 if ( port->driver->tx_empty(port) )
78 {
79 for ( i = 0; i < port->tx_fifo_size; i++ )
80 {
81 if ( port->txbufc == port->txbufp )
82 break;
83 port->driver->putc(
84 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
85 }
86 }
88 spin_unlock(&port->tx_lock);
90 out:
91 local_irq_restore(flags);
92 }
94 static void __serial_putc(struct serial_port *port, char c)
95 {
96 if ( (port->txbuf != NULL) && !port->sync )
97 {
98 /* Interrupt-driven (asynchronous) transmitter. */
100 if ( port->tx_quench )
101 {
102 /* Buffer filled and we are dropping characters. */
103 if ( (port->txbufp - port->txbufc) > (serial_txbufsz / 2) )
104 return;
105 port->tx_quench = 0;
106 }
108 if ( (port->txbufp - port->txbufc) == serial_txbufsz )
109 {
110 if ( port->tx_log_everything )
111 {
112 /* Buffer is full: we spin waiting for space to appear. */
113 int i;
114 while ( !port->driver->tx_empty(port) )
115 cpu_relax();
116 for ( i = 0; i < port->tx_fifo_size; i++ )
117 port->driver->putc(
118 port,
119 port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
120 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
121 }
122 else
123 {
124 /* Buffer is full: drop chars until buffer is half empty. */
125 port->tx_quench = 1;
126 }
127 return;
128 }
130 if ( ((port->txbufp - port->txbufc) == 0) &&
131 port->driver->tx_empty(port) )
132 {
133 /* Buffer and UART FIFO are both empty. */
134 port->driver->putc(port, c);
135 }
136 else
137 {
138 /* Normal case: buffer the character. */
139 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
140 }
141 }
142 else if ( port->driver->tx_empty )
143 {
144 /* Synchronous finite-capacity transmitter. */
145 while ( !port->driver->tx_empty(port) )
146 cpu_relax();
147 port->driver->putc(port, c);
148 }
149 else
150 {
151 /* Simple synchronous transmitter. */
152 port->driver->putc(port, c);
153 }
154 }
156 void serial_putc(int handle, char c)
157 {
158 struct serial_port *port;
159 unsigned long flags;
161 if ( handle == -1 )
162 return;
164 port = &com[handle & SERHND_IDX];
165 if ( !port->driver || !port->driver->putc )
166 return;
168 spin_lock_irqsave(&port->tx_lock, flags);
170 if ( (c == '\n') && (handle & SERHND_COOKED) )
171 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
173 if ( handle & SERHND_HI )
174 c |= 0x80;
175 else if ( handle & SERHND_LO )
176 c &= 0x7f;
178 __serial_putc(port, c);
180 spin_unlock_irqrestore(&port->tx_lock, flags);
181 }
183 void serial_puts(int handle, const char *s)
184 {
185 struct serial_port *port;
186 unsigned long flags;
187 char c;
189 if ( handle == -1 )
190 return;
192 port = &com[handle & SERHND_IDX];
193 if ( !port->driver || !port->driver->putc )
194 return;
196 spin_lock_irqsave(&port->tx_lock, flags);
198 while ( (c = *s++) != '\0' )
199 {
200 if ( (c == '\n') && (handle & SERHND_COOKED) )
201 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
203 if ( handle & SERHND_HI )
204 c |= 0x80;
205 else if ( handle & SERHND_LO )
206 c &= 0x7f;
208 __serial_putc(port, c);
209 }
211 spin_unlock_irqrestore(&port->tx_lock, flags);
212 }
214 char serial_getc(int handle)
215 {
216 struct serial_port *port;
217 char c;
218 unsigned long flags;
220 if ( handle == -1 )
221 return '\0';
223 port = &com[handle & SERHND_IDX];
224 if ( !port->driver || !port->driver->getc )
225 return '\0';
227 do {
228 for ( ; ; )
229 {
230 spin_lock_irqsave(&port->rx_lock, flags);
232 if ( port->rxbufp != port->rxbufc )
233 {
234 c = port->rxbuf[mask_serial_rxbuf_idx(port->rxbufc++)];
235 spin_unlock_irqrestore(&port->rx_lock, flags);
236 break;
237 }
239 if ( port->driver->getc(port, &c) )
240 {
241 spin_unlock_irqrestore(&port->rx_lock, flags);
242 break;
243 }
245 spin_unlock_irqrestore(&port->rx_lock, flags);
247 cpu_relax();
248 udelay(100);
249 }
250 } while ( ((handle & SERHND_LO) && (c & 0x80)) ||
251 ((handle & SERHND_HI) && !(c & 0x80)) );
253 return c & 0x7f;
254 }
256 int serial_parse_handle(char *conf)
257 {
258 int handle;
260 if ( strncmp(conf, "com", 3) )
261 goto fail;
263 switch ( conf[3] )
264 {
265 case '1':
266 handle = 0;
267 break;
268 case '2':
269 handle = 1;
270 break;
271 default:
272 goto fail;
273 }
275 if ( !com[handle].driver )
276 goto fail;
278 if ( conf[4] == 'H' )
279 handle |= SERHND_HI;
280 else if ( conf[4] == 'L' )
281 handle |= SERHND_LO;
283 handle |= SERHND_COOKED;
285 return handle;
287 fail:
288 return -1;
289 }
291 void serial_set_rx_handler(int handle, serial_rx_fn fn)
292 {
293 struct serial_port *port;
294 unsigned long flags;
296 if ( handle == -1 )
297 return;
299 port = &com[handle & SERHND_IDX];
301 spin_lock_irqsave(&port->rx_lock, flags);
303 if ( port->rx != NULL )
304 goto fail;
306 if ( handle & SERHND_LO )
307 {
308 if ( port->rx_lo != NULL )
309 goto fail;
310 port->rx_lo = fn;
311 }
312 else if ( handle & SERHND_HI )
313 {
314 if ( port->rx_hi != NULL )
315 goto fail;
316 port->rx_hi = fn;
317 }
318 else
319 {
320 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
321 goto fail;
322 port->rx = fn;
323 }
325 spin_unlock_irqrestore(&port->rx_lock, flags);
326 return;
328 fail:
329 spin_unlock_irqrestore(&port->rx_lock, flags);
330 printk("ERROR: Conflicting receive handlers for COM%d\n",
331 handle & SERHND_IDX);
332 }
334 void serial_force_unlock(int handle)
335 {
336 struct serial_port *port;
338 if ( handle == -1 )
339 return;
341 port = &com[handle & SERHND_IDX];
343 spin_lock_init(&port->rx_lock);
344 spin_lock_init(&port->tx_lock);
346 serial_start_sync(handle);
347 }
349 void serial_start_sync(int handle)
350 {
351 struct serial_port *port;
352 unsigned long flags;
354 if ( handle == -1 )
355 return;
357 port = &com[handle & SERHND_IDX];
359 spin_lock_irqsave(&port->tx_lock, flags);
361 if ( port->sync++ == 0 )
362 {
363 while ( (port->txbufp - port->txbufc) != 0 )
364 {
365 while ( !port->driver->tx_empty(port) )
366 cpu_relax();
367 port->driver->putc(
368 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
369 }
370 }
372 spin_unlock_irqrestore(&port->tx_lock, flags);
373 }
375 void serial_end_sync(int handle)
376 {
377 struct serial_port *port;
378 unsigned long flags;
380 if ( handle == -1 )
381 return;
383 port = &com[handle & SERHND_IDX];
385 spin_lock_irqsave(&port->tx_lock, flags);
387 port->sync--;
389 spin_unlock_irqrestore(&port->tx_lock, flags);
390 }
392 void serial_start_log_everything(int handle)
393 {
394 struct serial_port *port;
395 unsigned long flags;
397 if ( handle == -1 )
398 return;
400 port = &com[handle & SERHND_IDX];
402 spin_lock_irqsave(&port->tx_lock, flags);
403 port->tx_log_everything++;
404 port->tx_quench = 0;
405 spin_unlock_irqrestore(&port->tx_lock, flags);
406 }
408 void serial_end_log_everything(int handle)
409 {
410 struct serial_port *port;
411 unsigned long flags;
413 if ( handle == -1 )
414 return;
416 port = &com[handle & SERHND_IDX];
418 spin_lock_irqsave(&port->tx_lock, flags);
419 port->tx_log_everything--;
420 spin_unlock_irqrestore(&port->tx_lock, flags);
421 }
423 int serial_tx_space(int handle)
424 {
425 struct serial_port *port;
426 if ( handle == -1 )
427 return serial_txbufsz;
428 port = &com[handle & SERHND_IDX];
429 return serial_txbufsz - (port->txbufp - port->txbufc);
430 }
432 void __devinit serial_init_preirq(void)
433 {
434 int i;
435 for ( i = 0; i < ARRAY_SIZE(com); i++ )
436 if ( com[i].driver && com[i].driver->init_preirq )
437 com[i].driver->init_preirq(&com[i]);
438 }
440 void __devinit serial_init_postirq(void)
441 {
442 int i;
443 for ( i = 0; i < ARRAY_SIZE(com); i++ )
444 if ( com[i].driver && com[i].driver->init_postirq )
445 com[i].driver->init_postirq(&com[i]);
446 }
448 void __init serial_endboot(void)
449 {
450 int i;
451 for ( i = 0; i < ARRAY_SIZE(com); i++ )
452 if ( com[i].driver && com[i].driver->endboot )
453 com[i].driver->endboot(&com[i]);
454 }
456 int serial_irq(int idx)
457 {
458 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
459 com[idx].driver && com[idx].driver->irq )
460 return com[idx].driver->irq(&com[idx]);
462 return -1;
463 }
465 void serial_suspend(void)
466 {
467 int i, irq;
468 for ( i = 0; i < ARRAY_SIZE(com); i++ )
469 if ( (irq = serial_irq(i)) >= 0 )
470 release_irq(irq);
471 }
473 void serial_resume(void)
474 {
475 serial_init_preirq();
476 serial_init_postirq();
477 }
479 void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
480 {
481 /* Store UART-specific info. */
482 com[idx].driver = driver;
483 com[idx].uart = uart;
485 /* Default is no transmit FIFO. */
486 com[idx].tx_fifo_size = 1;
487 }
489 void serial_async_transmit(struct serial_port *port)
490 {
491 BUG_ON(!port->driver->tx_empty);
492 if ( port->txbuf != NULL )
493 return;
494 if ( serial_txbufsz < 512 )
495 serial_txbufsz = 512;
496 while ( serial_txbufsz & (serial_txbufsz - 1) )
497 serial_txbufsz &= serial_txbufsz - 1;
498 port->txbuf = alloc_xenheap_pages(
499 get_order_from_bytes(serial_txbufsz), 0);
500 }
502 /*
503 * Local variables:
504 * mode: C
505 * c-set-style: "BSD"
506 * c-basic-offset: 4
507 * tab-width: 4
508 * indent-tabs-mode: nil
509 * End:
510 */