ia64/xen-unstable

view xen/drivers/char/serial.c @ 19107:696351cde9a4

Allow memflags to be specified to alloc_xenheap_pages().

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jan 28 16:58:41 2009 +0000 (2009-01-28)
parents 9e47e72fd03e
children 9e3be0660c1e
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 goto out;
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(&port->tx_lock);
94 out:
95 local_irq_restore(flags);
96 }
98 static void __serial_putc(struct serial_port *port, char c)
99 {
100 if ( (port->txbuf != NULL) && !port->sync )
101 {
102 /* Interrupt-driven (asynchronous) transmitter. */
104 if ( port->tx_quench )
105 {
106 /* Buffer filled and we are dropping characters. */
107 if ( (port->txbufp - port->txbufc) > (serial_txbufsz / 2) )
108 return;
109 port->tx_quench = 0;
110 }
112 if ( (port->txbufp - port->txbufc) == serial_txbufsz )
113 {
114 if ( port->tx_log_everything )
115 {
116 /* Buffer is full: we spin waiting for space to appear. */
117 int i;
118 while ( !port->driver->tx_empty(port) )
119 cpu_relax();
120 for ( i = 0; i < port->tx_fifo_size; i++ )
121 port->driver->putc(
122 port,
123 port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
124 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
125 }
126 else
127 {
128 /* Buffer is full: drop chars until buffer is half empty. */
129 port->tx_quench = 1;
130 }
131 return;
132 }
134 if ( ((port->txbufp - port->txbufc) == 0) &&
135 port->driver->tx_empty(port) )
136 {
137 /* Buffer and UART FIFO are both empty. */
138 port->driver->putc(port, c);
139 }
140 else
141 {
142 /* Normal case: buffer the character. */
143 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
144 }
145 }
146 else if ( port->driver->tx_empty )
147 {
148 /* Synchronous finite-capacity transmitter. */
149 while ( !port->driver->tx_empty(port) )
150 cpu_relax();
151 port->driver->putc(port, c);
152 }
153 else
154 {
155 /* Simple synchronous transmitter. */
156 port->driver->putc(port, c);
157 }
158 }
160 void serial_putc(int handle, char c)
161 {
162 struct serial_port *port;
163 unsigned long flags;
165 if ( handle == -1 )
166 return;
168 port = &com[handle & SERHND_IDX];
169 if ( !port->driver || !port->driver->putc )
170 return;
172 spin_lock_irqsave(&port->tx_lock, flags);
174 if ( (c == '\n') && (handle & SERHND_COOKED) )
175 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
177 if ( handle & SERHND_HI )
178 c |= 0x80;
179 else if ( handle & SERHND_LO )
180 c &= 0x7f;
182 __serial_putc(port, c);
184 spin_unlock_irqrestore(&port->tx_lock, flags);
185 }
187 void serial_puts(int handle, const char *s)
188 {
189 struct serial_port *port;
190 unsigned long flags;
191 char c;
193 if ( handle == -1 )
194 return;
196 port = &com[handle & SERHND_IDX];
197 if ( !port->driver || !port->driver->putc )
198 return;
200 spin_lock_irqsave(&port->tx_lock, flags);
202 while ( (c = *s++) != '\0' )
203 {
204 if ( (c == '\n') && (handle & SERHND_COOKED) )
205 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
207 if ( handle & SERHND_HI )
208 c |= 0x80;
209 else if ( handle & SERHND_LO )
210 c &= 0x7f;
212 __serial_putc(port, c);
213 }
215 spin_unlock_irqrestore(&port->tx_lock, flags);
216 }
218 char serial_getc(int handle)
219 {
220 struct serial_port *port;
221 char c;
222 unsigned long flags;
224 if ( handle == -1 )
225 return '\0';
227 port = &com[handle & SERHND_IDX];
228 if ( !port->driver || !port->driver->getc )
229 return '\0';
231 do {
232 for ( ; ; )
233 {
234 spin_lock_irqsave(&port->rx_lock, flags);
236 if ( port->rxbufp != port->rxbufc )
237 {
238 c = port->rxbuf[mask_serial_rxbuf_idx(port->rxbufc++)];
239 spin_unlock_irqrestore(&port->rx_lock, flags);
240 break;
241 }
243 if ( port->driver->getc(port, &c) )
244 {
245 spin_unlock_irqrestore(&port->rx_lock, flags);
246 break;
247 }
249 spin_unlock_irqrestore(&port->rx_lock, flags);
251 cpu_relax();
252 udelay(100);
253 }
254 } while ( ((handle & SERHND_LO) && (c & 0x80)) ||
255 ((handle & SERHND_HI) && !(c & 0x80)) );
257 return c & 0x7f;
258 }
260 int serial_parse_handle(char *conf)
261 {
262 int handle;
264 if ( strncmp(conf, "com", 3) )
265 goto fail;
267 switch ( conf[3] )
268 {
269 case '1':
270 handle = 0;
271 break;
272 case '2':
273 handle = 1;
274 break;
275 default:
276 goto fail;
277 }
279 if ( !com[handle].driver )
280 goto fail;
282 if ( conf[4] == 'H' )
283 handle |= SERHND_HI;
284 else if ( conf[4] == 'L' )
285 handle |= SERHND_LO;
287 handle |= SERHND_COOKED;
289 return handle;
291 fail:
292 return -1;
293 }
295 void serial_set_rx_handler(int handle, serial_rx_fn fn)
296 {
297 struct serial_port *port;
298 unsigned long flags;
300 if ( handle == -1 )
301 return;
303 port = &com[handle & SERHND_IDX];
305 spin_lock_irqsave(&port->rx_lock, flags);
307 if ( port->rx != NULL )
308 goto fail;
310 if ( handle & SERHND_LO )
311 {
312 if ( port->rx_lo != NULL )
313 goto fail;
314 port->rx_lo = fn;
315 }
316 else if ( handle & SERHND_HI )
317 {
318 if ( port->rx_hi != NULL )
319 goto fail;
320 port->rx_hi = fn;
321 }
322 else
323 {
324 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
325 goto fail;
326 port->rx = fn;
327 }
329 spin_unlock_irqrestore(&port->rx_lock, flags);
330 return;
332 fail:
333 spin_unlock_irqrestore(&port->rx_lock, flags);
334 printk("ERROR: Conflicting receive handlers for COM%d\n",
335 handle & SERHND_IDX);
336 }
338 void serial_force_unlock(int handle)
339 {
340 struct serial_port *port;
342 if ( handle == -1 )
343 return;
345 port = &com[handle & SERHND_IDX];
347 spin_lock_init(&port->rx_lock);
348 spin_lock_init(&port->tx_lock);
350 serial_start_sync(handle);
351 }
353 void serial_start_sync(int handle)
354 {
355 struct serial_port *port;
356 unsigned long flags;
358 if ( handle == -1 )
359 return;
361 port = &com[handle & SERHND_IDX];
363 spin_lock_irqsave(&port->tx_lock, flags);
365 if ( port->sync++ == 0 )
366 {
367 while ( (port->txbufp - port->txbufc) != 0 )
368 {
369 while ( !port->driver->tx_empty(port) )
370 cpu_relax();
371 port->driver->putc(
372 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
373 }
374 }
376 spin_unlock_irqrestore(&port->tx_lock, flags);
377 }
379 void serial_end_sync(int handle)
380 {
381 struct serial_port *port;
382 unsigned long flags;
384 if ( handle == -1 )
385 return;
387 port = &com[handle & SERHND_IDX];
389 spin_lock_irqsave(&port->tx_lock, flags);
391 port->sync--;
393 spin_unlock_irqrestore(&port->tx_lock, flags);
394 }
396 void serial_start_log_everything(int handle)
397 {
398 struct serial_port *port;
399 unsigned long flags;
401 if ( handle == -1 )
402 return;
404 port = &com[handle & SERHND_IDX];
406 spin_lock_irqsave(&port->tx_lock, flags);
407 port->tx_log_everything++;
408 port->tx_quench = 0;
409 spin_unlock_irqrestore(&port->tx_lock, flags);
410 }
412 void serial_end_log_everything(int handle)
413 {
414 struct serial_port *port;
415 unsigned long flags;
417 if ( handle == -1 )
418 return;
420 port = &com[handle & SERHND_IDX];
422 spin_lock_irqsave(&port->tx_lock, flags);
423 port->tx_log_everything--;
424 spin_unlock_irqrestore(&port->tx_lock, flags);
425 }
427 int serial_tx_space(int handle)
428 {
429 struct serial_port *port;
430 if ( handle == -1 )
431 return serial_txbufsz;
432 port = &com[handle & SERHND_IDX];
433 return serial_txbufsz - (port->txbufp - port->txbufc);
434 }
436 void __devinit serial_init_preirq(void)
437 {
438 int i;
439 for ( i = 0; i < ARRAY_SIZE(com); i++ )
440 if ( com[i].driver && com[i].driver->init_preirq )
441 com[i].driver->init_preirq(&com[i]);
442 }
444 void __devinit serial_init_postirq(void)
445 {
446 int i;
447 for ( i = 0; i < ARRAY_SIZE(com); i++ )
448 if ( com[i].driver && com[i].driver->init_postirq )
449 com[i].driver->init_postirq(&com[i]);
450 }
452 void __init serial_endboot(void)
453 {
454 int i;
455 for ( i = 0; i < ARRAY_SIZE(com); i++ )
456 if ( com[i].driver && com[i].driver->endboot )
457 com[i].driver->endboot(&com[i]);
458 }
460 int serial_irq(int idx)
461 {
462 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
463 com[idx].driver && com[idx].driver->irq )
464 return com[idx].driver->irq(&com[idx]);
466 return -1;
467 }
469 void serial_suspend(void)
470 {
471 int i, irq;
472 for ( i = 0; i < ARRAY_SIZE(com); i++ )
473 if ( (irq = serial_irq(i)) >= 0 )
474 free_irq(irq);
475 }
477 void serial_resume(void)
478 {
479 serial_init_preirq();
480 serial_init_postirq();
481 }
483 void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
484 {
485 /* Store UART-specific info. */
486 com[idx].driver = driver;
487 com[idx].uart = uart;
489 /* Default is no transmit FIFO. */
490 com[idx].tx_fifo_size = 1;
491 }
493 void serial_async_transmit(struct serial_port *port)
494 {
495 BUG_ON(!port->driver->tx_empty);
496 if ( port->txbuf == NULL )
497 port->txbuf = alloc_xenheap_pages(
498 get_order_from_bytes(serial_txbufsz), 0);
499 }
501 /*
502 * Local variables:
503 * mode: C
504 * c-set-style: "BSD"
505 * c-basic-offset: 4
506 * tab-width: 4
507 * indent-tabs-mode: nil
508 * End:
509 */