debuggers.hg

view xen/drivers/char/serial.c @ 10989:16aa4b417c6b

[XEN] Clean up shutdown handling and ignore opt_noreboot if dom0
shuts down cleanly. The option is intended only to retain information
on the local console in case of a crash.

Based on a patch from Muli Ben-Yehuda <muli@il.ibm.com>

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Mon Aug 07 15:35:06 2006 +0100 (2006-08-07)
parents b39365343de0
children 03fd2accb4d9
line source
1 /******************************************************************************
2 * serial.c
3 *
4 * Framework for serial device drivers.
5 *
6 * Copyright (c) 2003-2005, 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/serial.h>
17 static struct serial_port com[2] = {
18 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED },
19 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED }
20 };
22 void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
23 {
24 char c;
25 serial_rx_fn fn = NULL;
26 unsigned long flags;
28 spin_lock_irqsave(&port->rx_lock, flags);
30 if ( port->driver->getc(port, &c) )
31 {
32 if ( port->rx != NULL )
33 fn = port->rx;
34 else if ( (c & 0x80) && (port->rx_hi != NULL) )
35 fn = port->rx_hi;
36 else if ( !(c & 0x80) && (port->rx_lo != NULL) )
37 fn = port->rx_lo;
38 else if ( (port->rxbufp - port->rxbufc) != SERIAL_RXBUFSZ )
39 port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c;
40 }
42 spin_unlock_irqrestore(&port->rx_lock, flags);
44 if ( fn != NULL )
45 (*fn)(c & 0x7f, regs);
46 }
48 void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
49 {
50 int i;
51 unsigned long flags;
53 local_irq_save(flags);
55 /*
56 * Avoid spinning for a long time: if there is a long-term lock holder
57 * then we know that they'll be stuffing bytes into the transmitter which
58 * will therefore not be empty for long.
59 */
60 while ( !spin_trylock(&port->tx_lock) )
61 {
62 if ( !port->driver->tx_empty(port) )
63 return;
64 cpu_relax();
65 }
67 if ( port->driver->tx_empty(port) )
68 {
69 for ( i = 0; i < port->tx_fifo_size; i++ )
70 {
71 if ( port->txbufc == port->txbufp )
72 break;
73 port->driver->putc(
74 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
75 }
76 }
78 spin_unlock_irqrestore(&port->tx_lock, flags);
79 }
81 static void __serial_putc(struct serial_port *port, char c)
82 {
83 int i;
85 if ( (port->txbuf != NULL) && !port->sync )
86 {
87 /* Interrupt-driven (asynchronous) transmitter. */
88 if ( (port->txbufp - port->txbufc) == SERIAL_TXBUFSZ )
89 {
90 /* Buffer is full: we spin, but could alternatively drop chars. */
91 while ( !port->driver->tx_empty(port) )
92 cpu_relax();
93 for ( i = 0; i < port->tx_fifo_size; i++ )
94 port->driver->putc(
95 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
96 port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
97 }
98 else if ( ((port->txbufp - port->txbufc) == 0) &&
99 port->driver->tx_empty(port) )
100 {
101 /* Buffer and UART FIFO are both empty. */
102 port->driver->putc(port, c);
103 }
104 else
105 {
106 /* Normal case: buffer the character. */
107 port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
108 }
109 }
110 else if ( port->driver->tx_empty )
111 {
112 /* Synchronous finite-capacity transmitter. */
113 while ( !port->driver->tx_empty(port) )
114 cpu_relax();
115 port->driver->putc(port, c);
116 }
117 else
118 {
119 /* Simple synchronous transmitter. */
120 port->driver->putc(port, c);
121 }
122 }
124 void serial_putc(int handle, char c)
125 {
126 struct serial_port *port = &com[handle & SERHND_IDX];
127 unsigned long flags;
129 if ( (handle == -1) || !port->driver || !port->driver->putc )
130 return;
132 spin_lock_irqsave(&port->tx_lock, flags);
134 if ( (c == '\n') && (handle & SERHND_COOKED) )
135 __serial_putc(port, '\r');
137 if ( handle & SERHND_HI )
138 c |= 0x80;
139 else if ( handle & SERHND_LO )
140 c &= 0x7f;
142 __serial_putc(port, c);
144 spin_unlock_irqrestore(&port->tx_lock, flags);
145 }
147 void serial_puts(int handle, const char *s)
148 {
149 struct serial_port *port = &com[handle & SERHND_IDX];
150 unsigned long flags;
151 char c;
153 if ( (handle == -1) || !port->driver || !port->driver->putc )
154 return;
156 spin_lock_irqsave(&port->tx_lock, flags);
158 while ( (c = *s++) != '\0' )
159 {
160 if ( (c == '\n') && (handle & SERHND_COOKED) )
161 __serial_putc(port, '\r');
163 if ( handle & SERHND_HI )
164 c |= 0x80;
165 else if ( handle & SERHND_LO )
166 c &= 0x7f;
168 __serial_putc(port, c);
169 }
171 spin_unlock_irqrestore(&port->tx_lock, flags);
172 }
174 char serial_getc(int handle)
175 {
176 struct serial_port *port = &com[handle & SERHND_IDX];
177 char c;
178 unsigned long flags;
180 if ( (handle == -1) || !port->driver || !port->driver->getc )
181 return '\0';
183 do {
184 for ( ; ; )
185 {
186 spin_lock_irqsave(&port->rx_lock, flags);
188 if ( port->rxbufp != port->rxbufc )
189 {
190 c = port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufc++)];
191 spin_unlock_irqrestore(&port->rx_lock, flags);
192 break;
193 }
195 if ( port->driver->getc(port, &c) )
196 {
197 spin_unlock_irqrestore(&port->rx_lock, flags);
198 break;
199 }
201 spin_unlock_irqrestore(&port->rx_lock, flags);
203 cpu_relax();
204 udelay(100);
205 }
206 } while ( ((handle & SERHND_LO) && (c & 0x80)) ||
207 ((handle & SERHND_HI) && !(c & 0x80)) );
209 return c & 0x7f;
210 }
212 int serial_parse_handle(char *conf)
213 {
214 int handle;
216 /* Silently fail if user has explicitly requested no serial I/O. */
217 if ( strcmp(conf, "none") == 0 )
218 return -1;
220 if ( strncmp(conf, "com", 3) != 0 )
221 goto fail;
223 switch ( conf[3] )
224 {
225 case '1':
226 handle = 0;
227 break;
228 case '2':
229 handle = 1;
230 break;
231 default:
232 goto fail;
233 }
235 if ( conf[4] == 'H' )
236 handle |= SERHND_HI;
237 else if ( conf[4] == 'L' )
238 handle |= SERHND_LO;
240 handle |= SERHND_COOKED;
242 return handle;
244 fail:
245 printk("ERROR: bad serial-interface specification '%s'\n", conf);
246 return -1;
247 }
249 void serial_set_rx_handler(int handle, serial_rx_fn fn)
250 {
251 struct serial_port *port = &com[handle & SERHND_IDX];
252 unsigned long flags;
254 if ( handle == -1 )
255 return;
257 spin_lock_irqsave(&port->rx_lock, flags);
259 if ( port->rx != NULL )
260 goto fail;
262 if ( handle & SERHND_LO )
263 {
264 if ( port->rx_lo != NULL )
265 goto fail;
266 port->rx_lo = fn;
267 }
268 else if ( handle & SERHND_HI )
269 {
270 if ( port->rx_hi != NULL )
271 goto fail;
272 port->rx_hi = fn;
273 }
274 else
275 {
276 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
277 goto fail;
278 port->rx = fn;
279 }
281 spin_unlock_irqrestore(&port->rx_lock, flags);
282 return;
284 fail:
285 spin_unlock_irqrestore(&port->rx_lock, flags);
286 printk("ERROR: Conflicting receive handlers for COM%d\n",
287 handle & SERHND_IDX);
288 }
290 void serial_force_unlock(int handle)
291 {
292 struct serial_port *port = &com[handle & SERHND_IDX];
294 if ( handle == -1 )
295 return;
297 port->rx_lock = SPIN_LOCK_UNLOCKED;
298 port->tx_lock = SPIN_LOCK_UNLOCKED;
300 serial_start_sync(handle);
301 }
303 void serial_start_sync(int handle)
304 {
305 struct serial_port *port = &com[handle & SERHND_IDX];
306 unsigned long flags;
308 if ( handle == -1 )
309 return;
311 spin_lock_irqsave(&port->tx_lock, flags);
313 if ( port->sync++ == 0 )
314 {
315 while ( (port->txbufp - port->txbufc) != 0 )
316 {
317 while ( !port->driver->tx_empty(port) )
318 cpu_relax();
319 port->driver->putc(
320 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
321 }
322 }
324 spin_unlock_irqrestore(&port->tx_lock, flags);
325 }
327 void serial_end_sync(int handle)
328 {
329 struct serial_port *port = &com[handle & SERHND_IDX];
330 unsigned long flags;
332 if ( handle == -1 )
333 return;
335 spin_lock_irqsave(&port->tx_lock, flags);
337 port->sync--;
339 spin_unlock_irqrestore(&port->tx_lock, flags);
340 }
342 int serial_tx_space(int handle)
343 {
344 struct serial_port *port = &com[handle & SERHND_IDX];
345 if ( handle == -1 )
346 return SERIAL_TXBUFSZ;
347 return SERIAL_TXBUFSZ - (port->txbufp - port->txbufc);
348 }
350 void serial_init_preirq(void)
351 {
352 int i;
353 for ( i = 0; i < ARRAY_SIZE(com); i++ )
354 if ( com[i].driver && com[i].driver->init_preirq )
355 com[i].driver->init_preirq(&com[i]);
356 }
358 void serial_init_postirq(void)
359 {
360 int i;
361 for ( i = 0; i < ARRAY_SIZE(com); i++ )
362 if ( com[i].driver && com[i].driver->init_postirq )
363 com[i].driver->init_postirq(&com[i]);
364 }
366 void serial_endboot(void)
367 {
368 int i;
369 for ( i = 0; i < ARRAY_SIZE(com); i++ )
370 if ( com[i].driver && com[i].driver->endboot )
371 com[i].driver->endboot(&com[i]);
372 }
374 int serial_irq(int idx)
375 {
376 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
377 com[idx].driver && com[idx].driver->irq )
378 return com[idx].driver->irq(&com[idx]);
380 return -1;
381 }
383 void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
384 {
385 /* Store UART-specific info. */
386 com[idx].driver = driver;
387 com[idx].uart = uart;
389 /* Default is no transmit FIFO. */
390 com[idx].tx_fifo_size = 1;
391 }
393 void serial_async_transmit(struct serial_port *port)
394 {
395 BUG_ON(!port->driver->tx_empty);
396 if ( port->txbuf == NULL )
397 port->txbuf = alloc_xenheap_pages(
398 get_order_from_bytes(SERIAL_TXBUFSZ));
399 }
401 /*
402 * Local variables:
403 * mode: C
404 * c-set-style: "BSD"
405 * c-basic-offset: 4
406 * tab-width: 4
407 * indent-tabs-mode: nil
408 * End:
409 */