ia64/xen-unstable

view xen/drivers/char/serial.c @ 18487:982e6fce0e47

Check the existence of serial port before using

Signed-off-by: Huacai Chen <huacai.chen@intel.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Sep 12 11:43:47 2008 +0100 (2008-09-12)
parents d4dcd4d39952
children 9e47e72fd03e
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 serial_txbufsz = 16384;
22 static void __init parse_serial_tx_buffer(const char *s)
23 {
24 serial_txbufsz = max((unsigned int)parse_size_and_unit(s, NULL), 512u);
25 }
26 custom_param("serial_tx_buffer", parse_serial_tx_buffer);
28 #define mask_serial_rxbuf_idx(_i) ((_i)&(serial_rxbufsz-1))
29 #define mask_serial_txbuf_idx(_i) ((_i)&(serial_txbufsz-1))
31 static struct serial_port com[2] = {
32 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED },
33 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED }
34 };
36 void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
37 {
38 char c;
39 serial_rx_fn fn = NULL;
40 unsigned long flags;
42 spin_lock_irqsave(&port->rx_lock, flags);
44 if ( port->driver->getc(port, &c) )
45 {
46 if ( port->rx != NULL )
47 fn = port->rx;
48 else if ( (c & 0x80) && (port->rx_hi != NULL) )
49 fn = port->rx_hi;
50 else if ( !(c & 0x80) && (port->rx_lo != NULL) )
51 fn = port->rx_lo;
52 else if ( (port->rxbufp - port->rxbufc) != serial_rxbufsz )
53 port->rxbuf[mask_serial_rxbuf_idx(port->rxbufp++)] = c;
54 }
56 spin_unlock_irqrestore(&port->rx_lock, flags);
58 if ( fn != NULL )
59 (*fn)(c & 0x7f, regs);
60 }
62 void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
63 {
64 int i;
65 unsigned long flags;
67 local_irq_save(flags);
69 /*
70 * Avoid spinning for a long time: if there is a long-term lock holder
71 * then we know that they'll be stuffing bytes into the transmitter which
72 * will therefore not be empty for long.
73 */
74 while ( !spin_trylock(&port->tx_lock) )
75 {
76 if ( !port->driver->tx_empty(port) )
77 return;
78 cpu_relax();
79 }
81 if ( port->driver->tx_empty(port) )
82 {
83 for ( i = 0; i < port->tx_fifo_size; i++ )
84 {
85 if ( port->txbufc == port->txbufp )
86 break;
87 port->driver->putc(
88 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
89 }
90 }
92 spin_unlock_irqrestore(&port->tx_lock, flags);
93 }
95 static void __serial_putc(struct serial_port *port, char c)
96 {
97 if ( (port->txbuf != NULL) && !port->sync )
98 {
99 /* Interrupt-driven (asynchronous) transmitter. */
101 if ( port->tx_quench )
102 {
103 /* Buffer filled and we are dropping characters. */
104 if ( (port->txbufp - port->txbufc) > (serial_txbufsz / 2) )
105 return;
106 port->tx_quench = 0;
107 }
109 if ( (port->txbufp - port->txbufc) == serial_txbufsz )
110 {
111 if ( port->tx_log_everything )
112 {
113 /* Buffer is full: we spin waiting for space to appear. */
114 int i;
115 while ( !port->driver->tx_empty(port) )
116 cpu_relax();
117 for ( i = 0; i < port->tx_fifo_size; i++ )
118 port->driver->putc(
119 port,
120 port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
121 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
122 }
123 else
124 {
125 /* Buffer is full: drop chars until buffer is half empty. */
126 port->tx_quench = 1;
127 }
128 return;
129 }
131 if ( ((port->txbufp - port->txbufc) == 0) &&
132 port->driver->tx_empty(port) )
133 {
134 /* Buffer and UART FIFO are both empty. */
135 port->driver->putc(port, c);
136 }
137 else
138 {
139 /* Normal case: buffer the character. */
140 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
141 }
142 }
143 else if ( port->driver->tx_empty )
144 {
145 /* Synchronous finite-capacity transmitter. */
146 while ( !port->driver->tx_empty(port) )
147 cpu_relax();
148 port->driver->putc(port, c);
149 }
150 else
151 {
152 /* Simple synchronous transmitter. */
153 port->driver->putc(port, c);
154 }
155 }
157 void serial_putc(int handle, char c)
158 {
159 struct serial_port *port;
160 unsigned long flags;
162 if ( handle == -1 )
163 return;
165 port = &com[handle & SERHND_IDX];
166 if ( !port->driver || !port->driver->putc )
167 return;
169 spin_lock_irqsave(&port->tx_lock, flags);
171 if ( (c == '\n') && (handle & SERHND_COOKED) )
172 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
174 if ( handle & SERHND_HI )
175 c |= 0x80;
176 else if ( handle & SERHND_LO )
177 c &= 0x7f;
179 __serial_putc(port, c);
181 spin_unlock_irqrestore(&port->tx_lock, flags);
182 }
184 void serial_puts(int handle, const char *s)
185 {
186 struct serial_port *port;
187 unsigned long flags;
188 char c;
190 if ( handle == -1 )
191 return;
193 port = &com[handle & SERHND_IDX];
194 if ( !port->driver || !port->driver->putc )
195 return;
197 spin_lock_irqsave(&port->tx_lock, flags);
199 while ( (c = *s++) != '\0' )
200 {
201 if ( (c == '\n') && (handle & SERHND_COOKED) )
202 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
204 if ( handle & SERHND_HI )
205 c |= 0x80;
206 else if ( handle & SERHND_LO )
207 c &= 0x7f;
209 __serial_putc(port, c);
210 }
212 spin_unlock_irqrestore(&port->tx_lock, flags);
213 }
215 char serial_getc(int handle)
216 {
217 struct serial_port *port;
218 char c;
219 unsigned long flags;
221 if ( handle == -1 )
222 return '\0';
224 port = &com[handle & SERHND_IDX];
225 if ( !port->driver || !port->driver->getc )
226 return '\0';
228 do {
229 for ( ; ; )
230 {
231 spin_lock_irqsave(&port->rx_lock, flags);
233 if ( port->rxbufp != port->rxbufc )
234 {
235 c = port->rxbuf[mask_serial_rxbuf_idx(port->rxbufc++)];
236 spin_unlock_irqrestore(&port->rx_lock, flags);
237 break;
238 }
240 if ( port->driver->getc(port, &c) )
241 {
242 spin_unlock_irqrestore(&port->rx_lock, flags);
243 break;
244 }
246 spin_unlock_irqrestore(&port->rx_lock, flags);
248 cpu_relax();
249 udelay(100);
250 }
251 } while ( ((handle & SERHND_LO) && (c & 0x80)) ||
252 ((handle & SERHND_HI) && !(c & 0x80)) );
254 return c & 0x7f;
255 }
257 int serial_parse_handle(char *conf)
258 {
259 int handle;
261 if ( strncmp(conf, "com", 3) )
262 goto fail;
264 switch ( conf[3] )
265 {
266 case '1':
267 handle = 0;
268 break;
269 case '2':
270 handle = 1;
271 break;
272 default:
273 goto fail;
274 }
276 if ( !com[handle].driver )
277 goto fail;
279 if ( conf[4] == 'H' )
280 handle |= SERHND_HI;
281 else if ( conf[4] == 'L' )
282 handle |= SERHND_LO;
284 handle |= SERHND_COOKED;
286 return handle;
288 fail:
289 return -1;
290 }
292 void serial_set_rx_handler(int handle, serial_rx_fn fn)
293 {
294 struct serial_port *port;
295 unsigned long flags;
297 if ( handle == -1 )
298 return;
300 port = &com[handle & SERHND_IDX];
302 spin_lock_irqsave(&port->rx_lock, flags);
304 if ( port->rx != NULL )
305 goto fail;
307 if ( handle & SERHND_LO )
308 {
309 if ( port->rx_lo != NULL )
310 goto fail;
311 port->rx_lo = fn;
312 }
313 else if ( handle & SERHND_HI )
314 {
315 if ( port->rx_hi != NULL )
316 goto fail;
317 port->rx_hi = fn;
318 }
319 else
320 {
321 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
322 goto fail;
323 port->rx = fn;
324 }
326 spin_unlock_irqrestore(&port->rx_lock, flags);
327 return;
329 fail:
330 spin_unlock_irqrestore(&port->rx_lock, flags);
331 printk("ERROR: Conflicting receive handlers for COM%d\n",
332 handle & SERHND_IDX);
333 }
335 void serial_force_unlock(int handle)
336 {
337 struct serial_port *port;
339 if ( handle == -1 )
340 return;
342 port = &com[handle & SERHND_IDX];
344 spin_lock_init(&port->rx_lock);
345 spin_lock_init(&port->tx_lock);
347 serial_start_sync(handle);
348 }
350 void serial_start_sync(int handle)
351 {
352 struct serial_port *port;
353 unsigned long flags;
355 if ( handle == -1 )
356 return;
358 port = &com[handle & SERHND_IDX];
360 spin_lock_irqsave(&port->tx_lock, flags);
362 if ( port->sync++ == 0 )
363 {
364 while ( (port->txbufp - port->txbufc) != 0 )
365 {
366 while ( !port->driver->tx_empty(port) )
367 cpu_relax();
368 port->driver->putc(
369 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
370 }
371 }
373 spin_unlock_irqrestore(&port->tx_lock, flags);
374 }
376 void serial_end_sync(int handle)
377 {
378 struct serial_port *port;
379 unsigned long flags;
381 if ( handle == -1 )
382 return;
384 port = &com[handle & SERHND_IDX];
386 spin_lock_irqsave(&port->tx_lock, flags);
388 port->sync--;
390 spin_unlock_irqrestore(&port->tx_lock, flags);
391 }
393 void serial_start_log_everything(int handle)
394 {
395 struct serial_port *port;
396 unsigned long flags;
398 if ( handle == -1 )
399 return;
401 port = &com[handle & SERHND_IDX];
403 spin_lock_irqsave(&port->tx_lock, flags);
404 port->tx_log_everything++;
405 port->tx_quench = 0;
406 spin_unlock_irqrestore(&port->tx_lock, flags);
407 }
409 void serial_end_log_everything(int handle)
410 {
411 struct serial_port *port;
412 unsigned long flags;
414 if ( handle == -1 )
415 return;
417 port = &com[handle & SERHND_IDX];
419 spin_lock_irqsave(&port->tx_lock, flags);
420 port->tx_log_everything--;
421 spin_unlock_irqrestore(&port->tx_lock, flags);
422 }
424 int serial_tx_space(int handle)
425 {
426 struct serial_port *port;
427 if ( handle == -1 )
428 return serial_txbufsz;
429 port = &com[handle & SERHND_IDX];
430 return serial_txbufsz - (port->txbufp - port->txbufc);
431 }
433 void __devinit serial_init_preirq(void)
434 {
435 int i;
436 for ( i = 0; i < ARRAY_SIZE(com); i++ )
437 if ( com[i].driver && com[i].driver->init_preirq )
438 com[i].driver->init_preirq(&com[i]);
439 }
441 void __devinit serial_init_postirq(void)
442 {
443 int i;
444 for ( i = 0; i < ARRAY_SIZE(com); i++ )
445 if ( com[i].driver && com[i].driver->init_postirq )
446 com[i].driver->init_postirq(&com[i]);
447 }
449 void __init serial_endboot(void)
450 {
451 int i;
452 for ( i = 0; i < ARRAY_SIZE(com); i++ )
453 if ( com[i].driver && com[i].driver->endboot )
454 com[i].driver->endboot(&com[i]);
455 }
457 int serial_irq(int idx)
458 {
459 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
460 com[idx].driver && com[idx].driver->irq )
461 return com[idx].driver->irq(&com[idx]);
463 return -1;
464 }
466 void serial_suspend(void)
467 {
468 int i, irq;
469 for ( i = 0; i < ARRAY_SIZE(com); i++ )
470 if ( (irq = serial_irq(i)) >= 0 )
471 free_irq(irq);
472 }
474 void serial_resume(void)
475 {
476 serial_init_preirq();
477 serial_init_postirq();
478 }
480 void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
481 {
482 /* Store UART-specific info. */
483 com[idx].driver = driver;
484 com[idx].uart = uart;
486 /* Default is no transmit FIFO. */
487 com[idx].tx_fifo_size = 1;
488 }
490 void serial_async_transmit(struct serial_port *port)
491 {
492 BUG_ON(!port->driver->tx_empty);
493 if ( port->txbuf == NULL )
494 port->txbuf = alloc_xenheap_pages(
495 get_order_from_bytes(serial_txbufsz));
496 }
498 /*
499 * Local variables:
500 * mode: C
501 * c-set-style: "BSD"
502 * c-basic-offset: 4
503 * tab-width: 4
504 * indent-tabs-mode: nil
505 * End:
506 */