ia64/xen-unstable

view xen/drivers/char/serial.c @ 6708:aa0990ef260f

merge
author iap10@freefall.cl.cam.ac.uk
date Thu Sep 08 17:42:49 2005 +0000 (2005-09-08)
parents 3bde4219c681 e3fd0fa58364
children 2704a88c3295 cdfa7dd00c44
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/init.h>
11 #include <xen/irq.h>
12 #include <xen/keyhandler.h>
13 #include <xen/reboot.h>
14 #include <xen/sched.h>
15 #include <xen/serial.h>
17 static struct serial_port com[2] = {
18 { .lock = SPIN_LOCK_UNLOCKED },
19 { .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->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->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 spin_lock_irqsave(&port->lock, flags);
55 if ( port->driver->tx_empty(port) )
56 {
57 for ( i = 0; i < port->tx_fifo_size; i++ )
58 {
59 if ( port->txbufc == port->txbufp )
60 break;
61 port->driver->putc(
62 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
63 }
64 }
66 spin_unlock_irqrestore(&port->lock, flags);
67 }
69 static void __serial_putc(struct serial_port *port, char c)
70 {
71 int i;
73 if ( (port->txbuf != NULL) && !port->sync )
74 {
75 /* Interrupt-driven (asynchronous) transmitter. */
76 if ( (port->txbufp - port->txbufc) == SERIAL_TXBUFSZ )
77 {
78 /* Buffer is full: we spin, but could alternatively drop chars. */
79 while ( !port->driver->tx_empty(port) )
80 cpu_relax();
81 for ( i = 0; i < port->tx_fifo_size; i++ )
82 port->driver->putc(
83 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
84 port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
85 }
86 else if ( ((port->txbufp - port->txbufc) == 0) &&
87 port->driver->tx_empty(port) )
88 {
89 /* Buffer and UART FIFO are both empty. */
90 port->driver->putc(port, c);
91 }
92 else
93 {
94 /* Normal case: buffer the character. */
95 port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
96 }
97 }
98 else if ( port->driver->tx_empty )
99 {
100 /* Synchronous finite-capacity transmitter. */
101 while ( !port->driver->tx_empty(port) )
102 cpu_relax();
103 port->driver->putc(port, c);
104 }
105 else
106 {
107 /* Simple synchronous transmitter. */
108 port->driver->putc(port, c);
109 }
110 }
112 void serial_putc(int handle, char c)
113 {
114 struct serial_port *port = &com[handle & SERHND_IDX];
115 unsigned long flags;
117 if ( (handle == -1) || !port->driver || !port->driver->putc )
118 return;
120 spin_lock_irqsave(&port->lock, flags);
122 if ( (c == '\n') && (handle & SERHND_COOKED) )
123 __serial_putc(port, '\r');
125 if ( handle & SERHND_HI )
126 c |= 0x80;
127 else if ( handle & SERHND_LO )
128 c &= 0x7f;
130 __serial_putc(port, c);
132 spin_unlock_irqrestore(&port->lock, flags);
133 }
135 void serial_puts(int handle, const char *s)
136 {
137 struct serial_port *port = &com[handle & SERHND_IDX];
138 unsigned long flags;
139 char c;
141 if ( (handle == -1) || !port->driver || !port->driver->putc )
142 return;
144 spin_lock_irqsave(&port->lock, flags);
146 while ( (c = *s++) != '\0' )
147 {
148 if ( (c == '\n') && (handle & SERHND_COOKED) )
149 __serial_putc(port, '\r');
151 if ( handle & SERHND_HI )
152 c |= 0x80;
153 else if ( handle & SERHND_LO )
154 c &= 0x7f;
156 __serial_putc(port, c);
157 }
159 spin_unlock_irqrestore(&port->lock, flags);
160 }
162 char serial_getc(int handle)
163 {
164 struct serial_port *port = &com[handle & SERHND_IDX];
165 char c;
166 unsigned long flags;
168 if ( (handle == -1) || !port->driver || !port->driver->getc )
169 return '\0';
171 do {
172 for ( ; ; )
173 {
174 spin_lock_irqsave(&port->lock, flags);
176 if ( port->rxbufp != port->rxbufc )
177 {
178 c = port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufc++)];
179 spin_unlock_irqrestore(&port->lock, flags);
180 break;
181 }
183 if ( port->driver->getc(port, &c) )
184 {
185 spin_unlock_irqrestore(&port->lock, flags);
186 break;
187 }
189 spin_unlock_irqrestore(&port->lock, flags);
191 cpu_relax();
192 }
193 } while ( ((handle & SERHND_LO) && (c & 0x80)) ||
194 ((handle & SERHND_HI) && !(c & 0x80)) );
196 return c & 0x7f;
197 }
199 int serial_parse_handle(char *conf)
200 {
201 int handle;
203 /* Silently fail if user has explicitly requested no serial I/O. */
204 if ( strcmp(conf, "none") == 0 )
205 return -1;
207 if ( strncmp(conf, "com", 3) != 0 )
208 goto fail;
210 switch ( conf[3] )
211 {
212 case '1':
213 handle = 0;
214 break;
215 case '2':
216 handle = 1;
217 break;
218 default:
219 goto fail;
220 }
222 if ( conf[4] == 'H' )
223 handle |= SERHND_HI;
224 else if ( conf[4] == 'L' )
225 handle |= SERHND_LO;
227 handle |= SERHND_COOKED;
229 return handle;
231 fail:
232 printk("ERROR: bad serial-interface specification '%s'\n", conf);
233 return -1;
234 }
236 void serial_set_rx_handler(int handle, serial_rx_fn fn)
237 {
238 struct serial_port *port = &com[handle & SERHND_IDX];
239 unsigned long flags;
241 if ( handle == -1 )
242 return;
244 spin_lock_irqsave(&port->lock, flags);
246 if ( port->rx != NULL )
247 goto fail;
249 if ( handle & SERHND_LO )
250 {
251 if ( port->rx_lo != NULL )
252 goto fail;
253 port->rx_lo = fn;
254 }
255 else if ( handle & SERHND_HI )
256 {
257 if ( port->rx_hi != NULL )
258 goto fail;
259 port->rx_hi = fn;
260 }
261 else
262 {
263 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
264 goto fail;
265 port->rx = fn;
266 }
268 spin_unlock_irqrestore(&port->lock, flags);
269 return;
271 fail:
272 spin_unlock_irqrestore(&port->lock, flags);
273 printk("ERROR: Conflicting receive handlers for COM%d\n",
274 handle & SERHND_IDX);
275 }
277 void serial_force_unlock(int handle)
278 {
279 struct serial_port *port = &com[handle & SERHND_IDX];
280 if ( handle != -1 )
281 port->lock = SPIN_LOCK_UNLOCKED;
282 serial_start_sync(handle);
283 }
285 void serial_start_sync(int handle)
286 {
287 struct serial_port *port = &com[handle & SERHND_IDX];
288 unsigned long flags;
290 if ( handle == -1 )
291 return;
293 spin_lock_irqsave(&port->lock, flags);
295 if ( port->sync++ == 0 )
296 {
297 while ( (port->txbufp - port->txbufc) != 0 )
298 {
299 while ( !port->driver->tx_empty(port) )
300 cpu_relax();
301 port->driver->putc(
302 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
303 }
304 }
306 spin_unlock_irqrestore(&port->lock, flags);
307 }
309 void serial_end_sync(int handle)
310 {
311 struct serial_port *port = &com[handle & SERHND_IDX];
312 unsigned long flags;
314 if ( handle == -1 )
315 return;
317 spin_lock_irqsave(&port->lock, flags);
319 port->sync--;
321 spin_unlock_irqrestore(&port->lock, flags);
322 }
324 int serial_tx_space(int handle)
325 {
326 struct serial_port *port = &com[handle & SERHND_IDX];
327 if ( handle == -1 )
328 return SERIAL_TXBUFSZ;
329 return SERIAL_TXBUFSZ - (port->txbufp - port->txbufc);
330 }
332 void serial_init_preirq(void)
333 {
334 int i;
335 for ( i = 0; i < ARRAY_SIZE(com); i++ )
336 if ( com[i].driver && com[i].driver->init_preirq )
337 com[i].driver->init_preirq(&com[i]);
338 }
340 void serial_init_postirq(void)
341 {
342 int i;
343 for ( i = 0; i < ARRAY_SIZE(com); i++ )
344 if ( com[i].driver && com[i].driver->init_postirq )
345 com[i].driver->init_postirq(&com[i]);
346 }
348 void serial_endboot(void)
349 {
350 int i;
351 for ( i = 0; i < ARRAY_SIZE(com); i++ )
352 if ( com[i].driver && com[i].driver->endboot )
353 com[i].driver->endboot(&com[i]);
354 }
356 void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
357 {
358 /* Store UART-specific info. */
359 com[idx].driver = driver;
360 com[idx].uart = uart;
362 /* Default is no transmit FIFO. */
363 com[idx].tx_fifo_size = 1;
364 }
366 void serial_async_transmit(struct serial_port *port)
367 {
368 BUG_ON(!port->driver->tx_empty);
369 if ( port->txbuf == NULL )
370 port->txbuf = alloc_xenheap_pages(
371 get_order_from_bytes(SERIAL_TXBUFSZ));
372 }
374 /*
375 * Local variables:
376 * mode: C
377 * c-set-style: "BSD"
378 * c-basic-offset: 4
379 * tab-width: 4
380 * indent-tabs-mode: nil
381 * End:
382 */