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