ia64/xen-unstable

view xen/drivers/char/serial.c @ 11430:0419253c81de

Fix inverted sense of getRequiredAvailableMemory and
getRequiredInitialReservation on x86 HVM.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Tue Sep 05 16:23:11 2006 +0100 (2006-09-05)
parents 03fd2accb4d9
children 21f8c507da29
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/mm.h>
16 #include <xen/serial.h>
18 static struct serial_port com[2] = {
19 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED },
20 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED }
21 };
23 void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
24 {
25 char c;
26 serial_rx_fn fn = NULL;
27 unsigned long flags;
29 spin_lock_irqsave(&port->rx_lock, flags);
31 if ( port->driver->getc(port, &c) )
32 {
33 if ( port->rx != NULL )
34 fn = port->rx;
35 else if ( (c & 0x80) && (port->rx_hi != NULL) )
36 fn = port->rx_hi;
37 else if ( !(c & 0x80) && (port->rx_lo != NULL) )
38 fn = port->rx_lo;
39 else if ( (port->rxbufp - port->rxbufc) != SERIAL_RXBUFSZ )
40 port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c;
41 }
43 spin_unlock_irqrestore(&port->rx_lock, flags);
45 if ( fn != NULL )
46 (*fn)(c & 0x7f, regs);
47 }
49 void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
50 {
51 int i;
52 unsigned long flags;
54 local_irq_save(flags);
56 /*
57 * Avoid spinning for a long time: if there is a long-term lock holder
58 * then we know that they'll be stuffing bytes into the transmitter which
59 * will therefore not be empty for long.
60 */
61 while ( !spin_trylock(&port->tx_lock) )
62 {
63 if ( !port->driver->tx_empty(port) )
64 return;
65 cpu_relax();
66 }
68 if ( port->driver->tx_empty(port) )
69 {
70 for ( i = 0; i < port->tx_fifo_size; i++ )
71 {
72 if ( port->txbufc == port->txbufp )
73 break;
74 port->driver->putc(
75 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
76 }
77 }
79 spin_unlock_irqrestore(&port->tx_lock, flags);
80 }
82 static void __serial_putc(struct serial_port *port, char c)
83 {
84 int i;
86 if ( (port->txbuf != NULL) && !port->sync )
87 {
88 /* Interrupt-driven (asynchronous) transmitter. */
89 if ( (port->txbufp - port->txbufc) == SERIAL_TXBUFSZ )
90 {
91 /* Buffer is full: we spin, but could alternatively drop chars. */
92 while ( !port->driver->tx_empty(port) )
93 cpu_relax();
94 for ( i = 0; i < port->tx_fifo_size; i++ )
95 port->driver->putc(
96 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
97 port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
98 }
99 else if ( ((port->txbufp - port->txbufc) == 0) &&
100 port->driver->tx_empty(port) )
101 {
102 /* Buffer and UART FIFO are both empty. */
103 port->driver->putc(port, c);
104 }
105 else
106 {
107 /* Normal case: buffer the character. */
108 port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
109 }
110 }
111 else if ( port->driver->tx_empty )
112 {
113 /* Synchronous finite-capacity transmitter. */
114 while ( !port->driver->tx_empty(port) )
115 cpu_relax();
116 port->driver->putc(port, c);
117 }
118 else
119 {
120 /* Simple synchronous transmitter. */
121 port->driver->putc(port, c);
122 }
123 }
125 void serial_putc(int handle, char c)
126 {
127 struct serial_port *port = &com[handle & SERHND_IDX];
128 unsigned long flags;
130 if ( (handle == -1) || !port->driver || !port->driver->putc )
131 return;
133 spin_lock_irqsave(&port->tx_lock, flags);
135 if ( (c == '\n') && (handle & SERHND_COOKED) )
136 __serial_putc(port, '\r');
138 if ( handle & SERHND_HI )
139 c |= 0x80;
140 else if ( handle & SERHND_LO )
141 c &= 0x7f;
143 __serial_putc(port, c);
145 spin_unlock_irqrestore(&port->tx_lock, flags);
146 }
148 void serial_puts(int handle, const char *s)
149 {
150 struct serial_port *port = &com[handle & SERHND_IDX];
151 unsigned long flags;
152 char c;
154 if ( (handle == -1) || !port->driver || !port->driver->putc )
155 return;
157 spin_lock_irqsave(&port->tx_lock, flags);
159 while ( (c = *s++) != '\0' )
160 {
161 if ( (c == '\n') && (handle & SERHND_COOKED) )
162 __serial_putc(port, '\r');
164 if ( handle & SERHND_HI )
165 c |= 0x80;
166 else if ( handle & SERHND_LO )
167 c &= 0x7f;
169 __serial_putc(port, c);
170 }
172 spin_unlock_irqrestore(&port->tx_lock, flags);
173 }
175 char serial_getc(int handle)
176 {
177 struct serial_port *port = &com[handle & SERHND_IDX];
178 char c;
179 unsigned long flags;
181 if ( (handle == -1) || !port->driver || !port->driver->getc )
182 return '\0';
184 do {
185 for ( ; ; )
186 {
187 spin_lock_irqsave(&port->rx_lock, flags);
189 if ( port->rxbufp != port->rxbufc )
190 {
191 c = port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufc++)];
192 spin_unlock_irqrestore(&port->rx_lock, flags);
193 break;
194 }
196 if ( port->driver->getc(port, &c) )
197 {
198 spin_unlock_irqrestore(&port->rx_lock, flags);
199 break;
200 }
202 spin_unlock_irqrestore(&port->rx_lock, flags);
204 cpu_relax();
205 udelay(100);
206 }
207 } while ( ((handle & SERHND_LO) && (c & 0x80)) ||
208 ((handle & SERHND_HI) && !(c & 0x80)) );
210 return c & 0x7f;
211 }
213 int serial_parse_handle(char *conf)
214 {
215 int handle;
217 /* Silently fail if user has explicitly requested no serial I/O. */
218 if ( strcmp(conf, "none") == 0 )
219 return -1;
221 if ( strncmp(conf, "com", 3) != 0 )
222 goto fail;
224 switch ( conf[3] )
225 {
226 case '1':
227 handle = 0;
228 break;
229 case '2':
230 handle = 1;
231 break;
232 default:
233 goto fail;
234 }
236 if ( conf[4] == 'H' )
237 handle |= SERHND_HI;
238 else if ( conf[4] == 'L' )
239 handle |= SERHND_LO;
241 handle |= SERHND_COOKED;
243 return handle;
245 fail:
246 printk("ERROR: bad serial-interface specification '%s'\n", conf);
247 return -1;
248 }
250 void serial_set_rx_handler(int handle, serial_rx_fn fn)
251 {
252 struct serial_port *port = &com[handle & SERHND_IDX];
253 unsigned long flags;
255 if ( handle == -1 )
256 return;
258 spin_lock_irqsave(&port->rx_lock, flags);
260 if ( port->rx != NULL )
261 goto fail;
263 if ( handle & SERHND_LO )
264 {
265 if ( port->rx_lo != NULL )
266 goto fail;
267 port->rx_lo = fn;
268 }
269 else if ( handle & SERHND_HI )
270 {
271 if ( port->rx_hi != NULL )
272 goto fail;
273 port->rx_hi = fn;
274 }
275 else
276 {
277 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
278 goto fail;
279 port->rx = fn;
280 }
282 spin_unlock_irqrestore(&port->rx_lock, flags);
283 return;
285 fail:
286 spin_unlock_irqrestore(&port->rx_lock, flags);
287 printk("ERROR: Conflicting receive handlers for COM%d\n",
288 handle & SERHND_IDX);
289 }
291 void serial_force_unlock(int handle)
292 {
293 struct serial_port *port = &com[handle & SERHND_IDX];
295 if ( handle == -1 )
296 return;
298 port->rx_lock = SPIN_LOCK_UNLOCKED;
299 port->tx_lock = SPIN_LOCK_UNLOCKED;
301 serial_start_sync(handle);
302 }
304 void serial_start_sync(int handle)
305 {
306 struct serial_port *port = &com[handle & SERHND_IDX];
307 unsigned long flags;
309 if ( handle == -1 )
310 return;
312 spin_lock_irqsave(&port->tx_lock, flags);
314 if ( port->sync++ == 0 )
315 {
316 while ( (port->txbufp - port->txbufc) != 0 )
317 {
318 while ( !port->driver->tx_empty(port) )
319 cpu_relax();
320 port->driver->putc(
321 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
322 }
323 }
325 spin_unlock_irqrestore(&port->tx_lock, flags);
326 }
328 void serial_end_sync(int handle)
329 {
330 struct serial_port *port = &com[handle & SERHND_IDX];
331 unsigned long flags;
333 if ( handle == -1 )
334 return;
336 spin_lock_irqsave(&port->tx_lock, flags);
338 port->sync--;
340 spin_unlock_irqrestore(&port->tx_lock, flags);
341 }
343 int serial_tx_space(int handle)
344 {
345 struct serial_port *port = &com[handle & SERHND_IDX];
346 if ( handle == -1 )
347 return SERIAL_TXBUFSZ;
348 return SERIAL_TXBUFSZ - (port->txbufp - port->txbufc);
349 }
351 void serial_init_preirq(void)
352 {
353 int i;
354 for ( i = 0; i < ARRAY_SIZE(com); i++ )
355 if ( com[i].driver && com[i].driver->init_preirq )
356 com[i].driver->init_preirq(&com[i]);
357 }
359 void serial_init_postirq(void)
360 {
361 int i;
362 for ( i = 0; i < ARRAY_SIZE(com); i++ )
363 if ( com[i].driver && com[i].driver->init_postirq )
364 com[i].driver->init_postirq(&com[i]);
365 }
367 void serial_endboot(void)
368 {
369 int i;
370 for ( i = 0; i < ARRAY_SIZE(com); i++ )
371 if ( com[i].driver && com[i].driver->endboot )
372 com[i].driver->endboot(&com[i]);
373 }
375 int serial_irq(int idx)
376 {
377 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
378 com[idx].driver && com[idx].driver->irq )
379 return com[idx].driver->irq(&com[idx]);
381 return -1;
382 }
384 void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
385 {
386 /* Store UART-specific info. */
387 com[idx].driver = driver;
388 com[idx].uart = uart;
390 /* Default is no transmit FIFO. */
391 com[idx].tx_fifo_size = 1;
392 }
394 void serial_async_transmit(struct serial_port *port)
395 {
396 BUG_ON(!port->driver->tx_empty);
397 if ( port->txbuf == NULL )
398 port->txbuf = alloc_xenheap_pages(
399 get_order_from_bytes(SERIAL_TXBUFSZ));
400 }
402 /*
403 * Local variables:
404 * mode: C
405 * c-set-style: "BSD"
406 * c-basic-offset: 4
407 * tab-width: 4
408 * indent-tabs-mode: nil
409 * End:
410 */