1 /******************************************************************************
2 * serial.c
3 *
4 * Framework for serial device drivers.
5 *
6 * Copyright (c) 2003-2008, K A Fraser
7 */
8
9 #include <xen/delay.h>
10 #include <xen/init.h>
11 #include <xen/mm.h>
12 #include <xen/serial.h>
13 #include <xen/cache.h>
14
15 /* Never drop characters, even if the async transmit buffer fills. */
16 /* #define SERIAL_NEVER_DROP_CHARS 1 */
17
18 unsigned int __read_mostly serial_txbufsz = 16384;
19 size_param("serial_tx_buffer", serial_txbufsz);
20
21 #define mask_serial_rxbuf_idx(_i) ((_i)&(serial_rxbufsz-1))
22 #define mask_serial_txbuf_idx(_i) ((_i)&(serial_txbufsz-1))
23
24 static struct serial_port com[SERHND_IDX + 1] = {
25 [0 ... SERHND_IDX] = {
26 .rx_lock = SPIN_LOCK_UNLOCKED,
27 .tx_lock = SPIN_LOCK_UNLOCKED
28 }
29 };
30
31 static bool_t __read_mostly post_irq;
32
serial_start_tx(struct serial_port * port)33 static inline void serial_start_tx(struct serial_port *port)
34 {
35 if ( port->driver->start_tx != NULL )
36 port->driver->start_tx(port);
37 }
38
serial_stop_tx(struct serial_port * port)39 static inline void serial_stop_tx(struct serial_port *port)
40 {
41 if ( port->driver->stop_tx != NULL )
42 port->driver->stop_tx(port);
43 }
44
serial_rx_interrupt(struct serial_port * port,struct cpu_user_regs * regs)45 void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
46 {
47 char c;
48 serial_rx_fn fn = NULL;
49 unsigned long flags;
50
51 spin_lock_irqsave(&port->rx_lock, flags);
52
53 if ( port->driver->getc(port, &c) )
54 {
55 if ( port->rx != NULL )
56 fn = port->rx;
57 else if ( (c & 0x80) && (port->rx_hi != NULL) )
58 fn = port->rx_hi;
59 else if ( !(c & 0x80) && (port->rx_lo != NULL) )
60 fn = port->rx_lo;
61 else if ( (port->rxbufp - port->rxbufc) != serial_rxbufsz )
62 port->rxbuf[mask_serial_rxbuf_idx(port->rxbufp++)] = c;
63 }
64
65 spin_unlock_irqrestore(&port->rx_lock, flags);
66
67 if ( fn != NULL )
68 (*fn)(c & 0x7f, regs);
69 }
70
serial_tx_interrupt(struct serial_port * port,struct cpu_user_regs * regs)71 void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
72 {
73 int i, n;
74 unsigned long flags;
75
76 local_irq_save(flags);
77
78 /*
79 * Avoid spinning for a long time: if there is a long-term lock holder
80 * then we know that they'll be stuffing bytes into the transmitter which
81 * will therefore not be empty for long.
82 */
83 while ( !spin_trylock(&port->tx_lock) )
84 {
85 if ( port->driver->tx_ready(port) <= 0 )
86 goto out;
87 cpu_relax();
88 }
89
90 if ( port->txbufc == port->txbufp )
91 {
92 /* Disable TX. nothing to send */
93 serial_stop_tx(port);
94 spin_unlock(&port->tx_lock);
95 goto out;
96 }
97 else
98 {
99 if ( port->driver->tx_ready(port) )
100 serial_start_tx(port);
101 }
102 for ( i = 0, n = port->driver->tx_ready(port); i < n; i++ )
103 {
104 if ( port->txbufc == port->txbufp )
105 break;
106 port->driver->putc(
107 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
108 }
109 if ( i && port->driver->flush )
110 port->driver->flush(port);
111
112 spin_unlock(&port->tx_lock);
113
114 out:
115 local_irq_restore(flags);
116 }
117
__serial_putc(struct serial_port * port,char c)118 static void __serial_putc(struct serial_port *port, char c)
119 {
120 if ( (port->txbuf != NULL) && !port->sync )
121 {
122 /* Interrupt-driven (asynchronous) transmitter. */
123
124 if ( port->tx_quench )
125 {
126 /* Buffer filled and we are dropping characters. */
127 if ( (port->txbufp - port->txbufc) > (serial_txbufsz / 2) )
128 return;
129 port->tx_quench = 0;
130 }
131
132 if ( (port->txbufp - port->txbufc) == serial_txbufsz )
133 {
134 if ( port->tx_log_everything )
135 {
136 /* Buffer is full: we spin waiting for space to appear. */
137 int n;
138
139 while ( (n = port->driver->tx_ready(port)) == 0 )
140 cpu_relax();
141 if ( n > 0 )
142 {
143 /* Enable TX before sending chars */
144 serial_start_tx(port);
145 while ( n-- )
146 port->driver->putc(
147 port,
148 port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
149 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
150 }
151 }
152 else
153 {
154 /* Buffer is full: drop chars until buffer is half empty. */
155 port->tx_quench = 1;
156 }
157 return;
158 }
159
160 if ( ((port->txbufp - port->txbufc) == 0) &&
161 port->driver->tx_ready(port) > 0 )
162 {
163 /* Enable TX before sending chars */
164 serial_start_tx(port);
165 /* Buffer and UART FIFO are both empty, and port is available. */
166 port->driver->putc(port, c);
167 }
168 else
169 {
170 /* Normal case: buffer the character. */
171 port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
172 }
173 }
174 else if ( port->driver->tx_ready )
175 {
176 int n;
177
178 /* Synchronous finite-capacity transmitter. */
179 while ( !(n = port->driver->tx_ready(port)) )
180 cpu_relax();
181 if ( n > 0 )
182 {
183 /* Enable TX before sending chars */
184 serial_start_tx(port);
185 port->driver->putc(port, c);
186 }
187 }
188 else
189 {
190 /* Simple synchronous transmitter. */
191 serial_start_tx(port);
192 port->driver->putc(port, c);
193 }
194 }
195
serial_putc(int handle,char c)196 void serial_putc(int handle, char c)
197 {
198 struct serial_port *port;
199 unsigned long flags;
200
201 if ( handle == -1 )
202 return;
203
204 port = &com[handle & SERHND_IDX];
205 if ( !port->driver || !port->driver->putc )
206 return;
207
208 spin_lock_irqsave(&port->tx_lock, flags);
209
210 if ( (c == '\n') && (handle & SERHND_COOKED) )
211 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
212
213 if ( handle & SERHND_HI )
214 c |= 0x80;
215 else if ( handle & SERHND_LO )
216 c &= 0x7f;
217
218 __serial_putc(port, c);
219
220 if ( port->driver->flush )
221 port->driver->flush(port);
222
223 spin_unlock_irqrestore(&port->tx_lock, flags);
224 }
225
serial_puts(int handle,const char * s)226 void serial_puts(int handle, const char *s)
227 {
228 struct serial_port *port;
229 unsigned long flags;
230 char c;
231
232 if ( handle == -1 )
233 return;
234
235 port = &com[handle & SERHND_IDX];
236 if ( !port->driver || !port->driver->putc )
237 return;
238
239 spin_lock_irqsave(&port->tx_lock, flags);
240
241 while ( (c = *s++) != '\0' )
242 {
243 if ( (c == '\n') && (handle & SERHND_COOKED) )
244 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
245
246 if ( handle & SERHND_HI )
247 c |= 0x80;
248 else if ( handle & SERHND_LO )
249 c &= 0x7f;
250
251 __serial_putc(port, c);
252 }
253
254 if ( port->driver->flush )
255 port->driver->flush(port);
256
257 spin_unlock_irqrestore(&port->tx_lock, flags);
258 }
259
serial_getc(int handle)260 char serial_getc(int handle)
261 {
262 struct serial_port *port;
263 char c;
264 unsigned long flags;
265
266 if ( handle == -1 )
267 return '\0';
268
269 port = &com[handle & SERHND_IDX];
270 if ( !port->driver || !port->driver->getc )
271 return '\0';
272
273 do {
274 for ( ; ; )
275 {
276 spin_lock_irqsave(&port->rx_lock, flags);
277
278 if ( port->rxbufp != port->rxbufc )
279 {
280 c = port->rxbuf[mask_serial_rxbuf_idx(port->rxbufc++)];
281 spin_unlock_irqrestore(&port->rx_lock, flags);
282 break;
283 }
284
285 if ( port->driver->getc(port, &c) )
286 {
287 spin_unlock_irqrestore(&port->rx_lock, flags);
288 break;
289 }
290
291 spin_unlock_irqrestore(&port->rx_lock, flags);
292
293 cpu_relax();
294 udelay(100);
295 }
296 } while ( ((handle & SERHND_LO) && (c & 0x80)) ||
297 ((handle & SERHND_HI) && !(c & 0x80)) );
298
299 return c & 0x7f;
300 }
301
serial_parse_handle(char * conf)302 int __init serial_parse_handle(char *conf)
303 {
304 int handle, flags = 0;
305
306 if ( !strncmp(conf, "dbgp", 4) && (!conf[4] || conf[4] == ',') )
307 {
308 handle = SERHND_DBGP;
309 goto common;
310 }
311
312 if ( !strncmp(conf, "dtuart", 6) )
313 {
314 handle = SERHND_DTUART;
315 goto common;
316 }
317
318 if ( strncmp(conf, "com", 3) )
319 goto fail;
320
321 switch ( conf[3] )
322 {
323 case '1':
324 handle = SERHND_COM1;
325 break;
326 case '2':
327 handle = SERHND_COM2;
328 break;
329 default:
330 goto fail;
331 }
332
333 if ( conf[4] == 'H' )
334 flags |= SERHND_HI;
335 else if ( conf[4] == 'L' )
336 flags |= SERHND_LO;
337
338 common:
339 if ( !com[handle].driver )
340 goto fail;
341
342 if ( !post_irq )
343 com[handle].state = serial_parsed;
344 else if ( com[handle].state != serial_initialized )
345 {
346 if ( com[handle].driver->init_postirq )
347 com[handle].driver->init_postirq(&com[handle]);
348 com[handle].state = serial_initialized;
349 }
350
351 return handle | flags | SERHND_COOKED;
352
353 fail:
354 return -1;
355 }
356
serial_set_rx_handler(int handle,serial_rx_fn fn)357 void __init serial_set_rx_handler(int handle, serial_rx_fn fn)
358 {
359 struct serial_port *port;
360 unsigned long flags;
361
362 if ( handle == -1 )
363 return;
364
365 port = &com[handle & SERHND_IDX];
366
367 spin_lock_irqsave(&port->rx_lock, flags);
368
369 if ( port->rx != NULL )
370 goto fail;
371
372 if ( handle & SERHND_LO )
373 {
374 if ( port->rx_lo != NULL )
375 goto fail;
376 port->rx_lo = fn;
377 }
378 else if ( handle & SERHND_HI )
379 {
380 if ( port->rx_hi != NULL )
381 goto fail;
382 port->rx_hi = fn;
383 }
384 else
385 {
386 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
387 goto fail;
388 port->rx = fn;
389 }
390
391 spin_unlock_irqrestore(&port->rx_lock, flags);
392 return;
393
394 fail:
395 spin_unlock_irqrestore(&port->rx_lock, flags);
396 printk("ERROR: Conflicting receive handlers for COM%d\n",
397 handle & SERHND_IDX);
398 }
399
serial_force_unlock(int handle)400 void serial_force_unlock(int handle)
401 {
402 struct serial_port *port;
403
404 if ( handle == -1 )
405 return;
406
407 port = &com[handle & SERHND_IDX];
408
409 spin_lock_init(&port->rx_lock);
410 spin_lock_init(&port->tx_lock);
411
412 serial_start_sync(handle);
413 }
414
serial_start_sync(int handle)415 void serial_start_sync(int handle)
416 {
417 struct serial_port *port;
418 unsigned long flags;
419
420 if ( handle == -1 )
421 return;
422
423 port = &com[handle & SERHND_IDX];
424
425 spin_lock_irqsave(&port->tx_lock, flags);
426
427 if ( port->sync++ == 0 )
428 {
429 while ( (port->txbufp - port->txbufc) != 0 )
430 {
431 int n;
432
433 while ( !(n = port->driver->tx_ready(port)) )
434 cpu_relax();
435 if ( n < 0 )
436 /* port is unavailable and might not come up until reenabled by
437 dom0, we can't really do proper sync */
438 break;
439 serial_start_tx(port);
440 port->driver->putc(
441 port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
442 }
443 if ( port->driver->flush )
444 port->driver->flush(port);
445 }
446
447 spin_unlock_irqrestore(&port->tx_lock, flags);
448 }
449
serial_end_sync(int handle)450 void serial_end_sync(int handle)
451 {
452 struct serial_port *port;
453 unsigned long flags;
454
455 if ( handle == -1 )
456 return;
457
458 port = &com[handle & SERHND_IDX];
459
460 spin_lock_irqsave(&port->tx_lock, flags);
461
462 port->sync--;
463
464 spin_unlock_irqrestore(&port->tx_lock, flags);
465 }
466
serial_start_log_everything(int handle)467 void serial_start_log_everything(int handle)
468 {
469 struct serial_port *port;
470 unsigned long flags;
471
472 if ( handle == -1 )
473 return;
474
475 port = &com[handle & SERHND_IDX];
476
477 spin_lock_irqsave(&port->tx_lock, flags);
478 port->tx_log_everything++;
479 port->tx_quench = 0;
480 spin_unlock_irqrestore(&port->tx_lock, flags);
481 }
482
serial_end_log_everything(int handle)483 void serial_end_log_everything(int handle)
484 {
485 struct serial_port *port;
486 unsigned long flags;
487
488 if ( handle == -1 )
489 return;
490
491 port = &com[handle & SERHND_IDX];
492
493 spin_lock_irqsave(&port->tx_lock, flags);
494 port->tx_log_everything--;
495 spin_unlock_irqrestore(&port->tx_lock, flags);
496 }
497
serial_init_preirq(void)498 void __init serial_init_preirq(void)
499 {
500 int i;
501 for ( i = 0; i < ARRAY_SIZE(com); i++ )
502 if ( com[i].driver && com[i].driver->init_preirq )
503 com[i].driver->init_preirq(&com[i]);
504 }
505
serial_init_postirq(void)506 void __init serial_init_postirq(void)
507 {
508 int i;
509 for ( i = 0; i < ARRAY_SIZE(com); i++ )
510 if ( com[i].state == serial_parsed )
511 {
512 if ( com[i].driver->init_postirq )
513 com[i].driver->init_postirq(&com[i]);
514 com[i].state = serial_initialized;
515 }
516 post_irq = 1;
517 }
518
serial_endboot(void)519 void __init serial_endboot(void)
520 {
521 int i;
522 for ( i = 0; i < ARRAY_SIZE(com); i++ )
523 if ( com[i].driver && com[i].driver->endboot )
524 com[i].driver->endboot(&com[i]);
525 }
526
serial_irq(int idx)527 int __init serial_irq(int idx)
528 {
529 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
530 com[idx].driver && com[idx].driver->irq )
531 return com[idx].driver->irq(&com[idx]);
532
533 return -1;
534 }
535
serial_vuart_info(int idx)536 const struct vuart_info *serial_vuart_info(int idx)
537 {
538 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
539 com[idx].driver && com[idx].driver->vuart_info )
540 return com[idx].driver->vuart_info(&com[idx]);
541
542 return NULL;
543 }
544
serial_suspend(void)545 void serial_suspend(void)
546 {
547 int i;
548 for ( i = 0; i < ARRAY_SIZE(com); i++ )
549 if ( com[i].state == serial_initialized && com[i].driver->suspend )
550 com[i].driver->suspend(&com[i]);
551 }
552
serial_resume(void)553 void serial_resume(void)
554 {
555 int i;
556 for ( i = 0; i < ARRAY_SIZE(com); i++ )
557 if ( com[i].state == serial_initialized && com[i].driver->resume )
558 com[i].driver->resume(&com[i]);
559 }
560
serial_register_uart(int idx,struct uart_driver * driver,void * uart)561 void __init serial_register_uart(int idx, struct uart_driver *driver,
562 void *uart)
563 {
564 /* Store UART-specific info. */
565 com[idx].driver = driver;
566 com[idx].uart = uart;
567 }
568
serial_async_transmit(struct serial_port * port)569 void __init serial_async_transmit(struct serial_port *port)
570 {
571 BUG_ON(!port->driver->tx_ready);
572 if ( port->txbuf != NULL )
573 return;
574 if ( serial_txbufsz < PAGE_SIZE )
575 serial_txbufsz = PAGE_SIZE;
576 while ( serial_txbufsz & (serial_txbufsz - 1) )
577 serial_txbufsz &= serial_txbufsz - 1;
578 port->txbuf = alloc_xenheap_pages(
579 get_order_from_bytes(serial_txbufsz), 0);
580 }
581
582 /*
583 * Local variables:
584 * mode: C
585 * c-file-style: "BSD"
586 * c-basic-offset: 4
587 * tab-width: 4
588 * indent-tabs-mode: nil
589 * End:
590 */
591