debuggers.hg

annotate xen/drivers/char/serial.c @ 16679:b0c85bc56f9e

Fix serial output of carriage return when using high-bit stream muxing.
Original patch by Dan Doucette.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Dec 19 15:02:05 2007 +0000 (2007-12-19)
parents 537b8edb1efa
children a7ddd6bcd564
rev   line source
kaf24@1142 1 /******************************************************************************
kaf24@1142 2 * serial.c
kaf24@1142 3 *
kaf24@5233 4 * Framework for serial device drivers.
kaf24@1142 5 *
kaf24@3882 6 * Copyright (c) 2003-2005, K A Fraser
kaf24@1142 7 */
kaf24@1142 8
kaf24@1544 9 #include <xen/config.h>
kaf24@9457 10 #include <xen/delay.h>
kaf24@3372 11 #include <xen/init.h>
kaf24@1544 12 #include <xen/irq.h>
kaf24@1248 13 #include <xen/keyhandler.h>
kaf24@1544 14 #include <xen/sched.h>
kaf24@11236 15 #include <xen/mm.h>
kaf24@1248 16 #include <xen/serial.h>
kaf24@1142 17
kaf24@5233 18 static struct serial_port com[2] = {
kaf24@9457 19 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED },
kaf24@9457 20 { .rx_lock = SPIN_LOCK_UNLOCKED, .tx_lock = SPIN_LOCK_UNLOCKED }
kaf24@1142 21 };
kaf24@1142 22
kaf24@5233 23 void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
kaf24@5233 24 {
kaf24@5233 25 char c;
kaf24@5364 26 serial_rx_fn fn = NULL;
kaf24@5233 27 unsigned long flags;
kaf24@1142 28
kaf24@9457 29 spin_lock_irqsave(&port->rx_lock, flags);
kaf24@5233 30
kaf24@5364 31 if ( port->driver->getc(port, &c) )
kaf24@5243 32 {
kaf24@5233 33 if ( port->rx != NULL )
kaf24@5233 34 fn = port->rx;
kaf24@5233 35 else if ( (c & 0x80) && (port->rx_hi != NULL) )
kaf24@5233 36 fn = port->rx_hi;
kaf24@5233 37 else if ( !(c & 0x80) && (port->rx_lo != NULL) )
kaf24@5233 38 fn = port->rx_lo;
kaf24@5359 39 else if ( (port->rxbufp - port->rxbufc) != SERIAL_RXBUFSZ )
kaf24@5359 40 port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufp++)] = c;
kaf24@5233 41 }
kaf24@5233 42
kaf24@9457 43 spin_unlock_irqrestore(&port->rx_lock, flags);
kaf24@5364 44
kaf24@5364 45 if ( fn != NULL )
kaf24@5364 46 (*fn)(c & 0x7f, regs);
kaf24@5233 47 }
kaf24@5233 48
kaf24@5359 49 void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
kaf24@5359 50 {
kaf24@5359 51 int i;
kaf24@5359 52 unsigned long flags;
kaf24@5359 53
kaf24@9457 54 local_irq_save(flags);
kaf24@9457 55
kaf24@9457 56 /*
kaf24@9457 57 * Avoid spinning for a long time: if there is a long-term lock holder
kaf24@9457 58 * then we know that they'll be stuffing bytes into the transmitter which
kaf24@9457 59 * will therefore not be empty for long.
kaf24@9457 60 */
kaf24@9457 61 while ( !spin_trylock(&port->tx_lock) )
kaf24@9457 62 {
kaf24@9457 63 if ( !port->driver->tx_empty(port) )
kaf24@9457 64 return;
kaf24@9457 65 cpu_relax();
kaf24@9457 66 }
kaf24@5359 67
kaf24@5364 68 if ( port->driver->tx_empty(port) )
kaf24@5359 69 {
kaf24@5364 70 for ( i = 0; i < port->tx_fifo_size; i++ )
kaf24@5364 71 {
kaf24@5364 72 if ( port->txbufc == port->txbufp )
kaf24@5364 73 break;
kaf24@5364 74 port->driver->putc(
kaf24@5364 75 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
kaf24@5364 76 }
kaf24@5359 77 }
kaf24@5359 78
kaf24@9457 79 spin_unlock_irqrestore(&port->tx_lock, flags);
kaf24@5359 80 }
kaf24@5359 81
kaf24@5359 82 static void __serial_putc(struct serial_port *port, char c)
kaf24@5359 83 {
kaf24@5359 84 int i;
kaf24@5359 85
kaf24@5359 86 if ( (port->txbuf != NULL) && !port->sync )
kaf24@5359 87 {
kaf24@5359 88 /* Interrupt-driven (asynchronous) transmitter. */
kaf24@5359 89 if ( (port->txbufp - port->txbufc) == SERIAL_TXBUFSZ )
kaf24@5359 90 {
kaf24@5359 91 /* Buffer is full: we spin, but could alternatively drop chars. */
kaf24@5359 92 while ( !port->driver->tx_empty(port) )
kaf24@5359 93 cpu_relax();
kaf24@5359 94 for ( i = 0; i < port->tx_fifo_size; i++ )
kaf24@5359 95 port->driver->putc(
kaf24@5359 96 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
kaf24@5359 97 port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
kaf24@5359 98 }
kaf24@5359 99 else if ( ((port->txbufp - port->txbufc) == 0) &&
kaf24@5359 100 port->driver->tx_empty(port) )
kaf24@5359 101 {
kaf24@5359 102 /* Buffer and UART FIFO are both empty. */
kaf24@5359 103 port->driver->putc(port, c);
kaf24@5359 104 }
kaf24@5359 105 else
kaf24@5359 106 {
kaf24@5359 107 /* Normal case: buffer the character. */
kaf24@5359 108 port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufp++)] = c;
kaf24@5359 109 }
kaf24@5359 110 }
kaf24@5359 111 else if ( port->driver->tx_empty )
kaf24@5359 112 {
kaf24@5359 113 /* Synchronous finite-capacity transmitter. */
kaf24@5359 114 while ( !port->driver->tx_empty(port) )
kaf24@5359 115 cpu_relax();
kaf24@5359 116 port->driver->putc(port, c);
kaf24@5359 117 }
kaf24@5359 118 else
kaf24@5359 119 {
kaf24@5359 120 /* Simple synchronous transmitter. */
kaf24@5359 121 port->driver->putc(port, c);
kaf24@5359 122 }
kaf24@5359 123 }
kaf24@5359 124
kaf24@5233 125 void serial_putc(int handle, char c)
kaf24@1142 126 {
keir@16286 127 struct serial_port *port;
kaf24@5233 128 unsigned long flags;
kaf24@1142 129
keir@16286 130 if ( handle == -1 )
keir@16286 131 return;
keir@16286 132
keir@16286 133 port = &com[handle & SERHND_IDX];
keir@16286 134 if ( !port->driver || !port->driver->putc )
kaf24@1142 135 return;
kaf24@1142 136
kaf24@9457 137 spin_lock_irqsave(&port->tx_lock, flags);
kaf24@2651 138
kaf24@1142 139 if ( (c == '\n') && (handle & SERHND_COOKED) )
keir@16679 140 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
kaf24@1142 141
kaf24@1142 142 if ( handle & SERHND_HI )
kaf24@1142 143 c |= 0x80;
kaf24@1142 144 else if ( handle & SERHND_LO )
kaf24@1194 145 c &= 0x7f;
kaf24@1142 146
kaf24@5359 147 __serial_putc(port, c);
kaf24@5233 148
kaf24@9457 149 spin_unlock_irqrestore(&port->tx_lock, flags);
kaf24@5233 150 }
kaf24@5233 151
kaf24@5233 152 void serial_puts(int handle, const char *s)
kaf24@5233 153 {
keir@16286 154 struct serial_port *port;
kaf24@5364 155 unsigned long flags;
kaf24@5364 156 char c;
kaf24@5364 157
keir@16286 158 if ( handle == -1 )
keir@16286 159 return;
keir@16286 160
keir@16286 161 port = &com[handle & SERHND_IDX];
keir@16286 162 if ( !port->driver || !port->driver->putc )
kaf24@5364 163 return;
kaf24@5364 164
kaf24@9457 165 spin_lock_irqsave(&port->tx_lock, flags);
kaf24@5364 166
kaf24@5364 167 while ( (c = *s++) != '\0' )
kaf24@5364 168 {
kaf24@5364 169 if ( (c == '\n') && (handle & SERHND_COOKED) )
keir@16679 170 __serial_putc(port, '\r' | ((handle & SERHND_HI) ? 0x80 : 0x00));
kaf24@5364 171
kaf24@5364 172 if ( handle & SERHND_HI )
kaf24@5364 173 c |= 0x80;
kaf24@5364 174 else if ( handle & SERHND_LO )
kaf24@5364 175 c &= 0x7f;
kaf24@5364 176
kaf24@5364 177 __serial_putc(port, c);
kaf24@5364 178 }
kaf24@5364 179
kaf24@9457 180 spin_unlock_irqrestore(&port->tx_lock, flags);
kaf24@5233 181 }
kaf24@5233 182
kaf24@5233 183 char serial_getc(int handle)
kaf24@1142 184 {
keir@16286 185 struct serial_port *port;
kaf24@5261 186 char c;
kaf24@5233 187 unsigned long flags;
kaf24@1142 188
keir@16286 189 if ( handle == -1 )
keir@16286 190 return '\0';
keir@16286 191
keir@16286 192 port = &com[handle & SERHND_IDX];
keir@16286 193 if ( !port->driver || !port->driver->getc )
kaf24@5233 194 return '\0';
kaf24@1142 195
kaf24@9457 196 do {
kaf24@5243 197 for ( ; ; )
kaf24@5243 198 {
kaf24@9457 199 spin_lock_irqsave(&port->rx_lock, flags);
kaf24@5243 200
kaf24@5243 201 if ( port->rxbufp != port->rxbufc )
kaf24@5243 202 {
kaf24@5359 203 c = port->rxbuf[MASK_SERIAL_RXBUF_IDX(port->rxbufc++)];
kaf24@9457 204 spin_unlock_irqrestore(&port->rx_lock, flags);
kaf24@5243 205 break;
kaf24@5243 206 }
kaf24@5243 207
kaf24@5243 208 if ( port->driver->getc(port, &c) )
kaf24@5503 209 {
kaf24@9457 210 spin_unlock_irqrestore(&port->rx_lock, flags);
kaf24@5243 211 break;
kaf24@5503 212 }
kaf24@1142 213
kaf24@9457 214 spin_unlock_irqrestore(&port->rx_lock, flags);
kaf24@5243 215
kaf24@5243 216 cpu_relax();
kaf24@9457 217 udelay(100);
kaf24@5243 218 }
kaf24@5243 219 } while ( ((handle & SERHND_LO) && (c & 0x80)) ||
kaf24@5243 220 ((handle & SERHND_HI) && !(c & 0x80)) );
kaf24@5233 221
kaf24@5243 222 return c & 0x7f;
kaf24@1142 223 }
kaf24@1142 224
kaf24@5233 225 int serial_parse_handle(char *conf)
kaf24@1142 226 {
kaf24@1142 227 int handle;
kaf24@1142 228
kaf24@1142 229 /* Silently fail if user has explicitly requested no serial I/O. */
kaf24@1142 230 if ( strcmp(conf, "none") == 0 )
kaf24@1142 231 return -1;
kaf24@1142 232
kaf24@1142 233 if ( strncmp(conf, "com", 3) != 0 )
kaf24@1142 234 goto fail;
kaf24@1142 235
kaf24@1142 236 switch ( conf[3] )
kaf24@1142 237 {
kaf24@1142 238 case '1':
kaf24@1142 239 handle = 0;
kaf24@1142 240 break;
kaf24@1142 241 case '2':
kaf24@1142 242 handle = 1;
kaf24@1142 243 break;
kaf24@1142 244 default:
kaf24@1142 245 goto fail;
kaf24@1142 246 }
kaf24@1142 247
kaf24@1142 248 if ( conf[4] == 'H' )
kaf24@1142 249 handle |= SERHND_HI;
kaf24@1142 250 else if ( conf[4] == 'L' )
kaf24@1142 251 handle |= SERHND_LO;
kaf24@1142 252
kaf24@1142 253 handle |= SERHND_COOKED;
kaf24@1142 254
kaf24@1142 255 return handle;
kaf24@1142 256
kaf24@1142 257 fail:
kaf24@1142 258 printk("ERROR: bad serial-interface specification '%s'\n", conf);
kaf24@1142 259 return -1;
kaf24@1142 260 }
kaf24@1142 261
kaf24@1142 262 void serial_set_rx_handler(int handle, serial_rx_fn fn)
kaf24@1142 263 {
keir@16286 264 struct serial_port *port;
kaf24@1142 265 unsigned long flags;
kaf24@1142 266
kaf24@1142 267 if ( handle == -1 )
kaf24@1142 268 return;
kaf24@1142 269
keir@16286 270 port = &com[handle & SERHND_IDX];
keir@16286 271
kaf24@9457 272 spin_lock_irqsave(&port->rx_lock, flags);
kaf24@1142 273
kaf24@5233 274 if ( port->rx != NULL )
kaf24@1142 275 goto fail;
kaf24@1142 276
kaf24@1142 277 if ( handle & SERHND_LO )
kaf24@1142 278 {
kaf24@5233 279 if ( port->rx_lo != NULL )
kaf24@1142 280 goto fail;
kaf24@5233 281 port->rx_lo = fn;
kaf24@1142 282 }
kaf24@1142 283 else if ( handle & SERHND_HI )
kaf24@1142 284 {
kaf24@5233 285 if ( port->rx_hi != NULL )
kaf24@1142 286 goto fail;
kaf24@5233 287 port->rx_hi = fn;
kaf24@1142 288 }
kaf24@1142 289 else
kaf24@1142 290 {
kaf24@5233 291 if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
kaf24@1142 292 goto fail;
kaf24@5233 293 port->rx = fn;
kaf24@1142 294 }
kaf24@1142 295
kaf24@9457 296 spin_unlock_irqrestore(&port->rx_lock, flags);
kaf24@1142 297 return;
kaf24@1142 298
kaf24@1142 299 fail:
kaf24@9457 300 spin_unlock_irqrestore(&port->rx_lock, flags);
kaf24@1142 301 printk("ERROR: Conflicting receive handlers for COM%d\n",
kaf24@1142 302 handle & SERHND_IDX);
kaf24@1142 303 }
kaf24@1142 304
kaf24@5233 305 void serial_force_unlock(int handle)
kaf24@1142 306 {
keir@16286 307 struct serial_port *port;
kaf24@9457 308
kaf24@9457 309 if ( handle == -1 )
kaf24@9457 310 return;
kaf24@9457 311
keir@16286 312 port = &com[handle & SERHND_IDX];
keir@16286 313
kfraser@11837 314 spin_lock_init(&port->rx_lock);
kfraser@11837 315 spin_lock_init(&port->tx_lock);
kaf24@9457 316
kaf24@5359 317 serial_start_sync(handle);
kaf24@5359 318 }
kaf24@5359 319
kaf24@5359 320 void serial_start_sync(int handle)
kaf24@5359 321 {
keir@16286 322 struct serial_port *port;
kaf24@5359 323 unsigned long flags;
kaf24@5359 324
kaf24@5359 325 if ( handle == -1 )
kaf24@5359 326 return;
kaf24@5359 327
keir@16286 328 port = &com[handle & SERHND_IDX];
keir@16286 329
kaf24@9457 330 spin_lock_irqsave(&port->tx_lock, flags);
kaf24@5359 331
kaf24@5359 332 if ( port->sync++ == 0 )
kaf24@5359 333 {
kaf24@5359 334 while ( (port->txbufp - port->txbufc) != 0 )
kaf24@5359 335 {
kaf24@5359 336 while ( !port->driver->tx_empty(port) )
kaf24@5359 337 cpu_relax();
kaf24@5359 338 port->driver->putc(
kaf24@5359 339 port, port->txbuf[MASK_SERIAL_TXBUF_IDX(port->txbufc++)]);
kaf24@5359 340 }
kaf24@5359 341 }
kaf24@5359 342
kaf24@9457 343 spin_unlock_irqrestore(&port->tx_lock, flags);
kaf24@5359 344 }
kaf24@5359 345
kaf24@5359 346 void serial_end_sync(int handle)
kaf24@5359 347 {
keir@16286 348 struct serial_port *port;
kaf24@5359 349 unsigned long flags;
kaf24@5359 350
kaf24@5359 351 if ( handle == -1 )
kaf24@5359 352 return;
kaf24@5359 353
keir@16286 354 port = &com[handle & SERHND_IDX];
keir@16286 355
kaf24@9457 356 spin_lock_irqsave(&port->tx_lock, flags);
kaf24@5359 357
kaf24@5359 358 port->sync--;
kaf24@5359 359
kaf24@9457 360 spin_unlock_irqrestore(&port->tx_lock, flags);
kaf24@1207 361 }
kaf24@1207 362
kaf24@5365 363 int serial_tx_space(int handle)
kaf24@5365 364 {
keir@16286 365 struct serial_port *port;
kaf24@5365 366 if ( handle == -1 )
kaf24@5365 367 return SERIAL_TXBUFSZ;
keir@16286 368 port = &com[handle & SERHND_IDX];
kaf24@5365 369 return SERIAL_TXBUFSZ - (port->txbufp - port->txbufc);
kaf24@5365 370 }
kaf24@5365 371
kfraser@15578 372 void __devinit serial_init_preirq(void)
cl349@2990 373 {
kaf24@5233 374 int i;
kaf24@5233 375 for ( i = 0; i < ARRAY_SIZE(com); i++ )
kaf24@5233 376 if ( com[i].driver && com[i].driver->init_preirq )
kaf24@5233 377 com[i].driver->init_preirq(&com[i]);
cl349@2990 378 }
cl349@2990 379
kfraser@15578 380 void __devinit serial_init_postirq(void)
kaf24@1207 381 {
kaf24@5233 382 int i;
kaf24@5233 383 for ( i = 0; i < ARRAY_SIZE(com); i++ )
kaf24@5233 384 if ( com[i].driver && com[i].driver->init_postirq )
kaf24@5233 385 com[i].driver->init_postirq(&com[i]);
kaf24@2079 386 }
kaf24@3952 387
keir@15081 388 void __init serial_endboot(void)
iap10@4325 389 {
iap10@4325 390 int i;
kaf24@4326 391 for ( i = 0; i < ARRAY_SIZE(com); i++ )
kaf24@5233 392 if ( com[i].driver && com[i].driver->endboot )
kaf24@5233 393 com[i].driver->endboot(&com[i]);
kaf24@5233 394 }
kaf24@5233 395
kaf24@9702 396 int serial_irq(int idx)
kaf24@9702 397 {
kaf24@9702 398 if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) &&
kaf24@9702 399 com[idx].driver && com[idx].driver->irq )
kaf24@9702 400 return com[idx].driver->irq(&com[idx]);
kaf24@9702 401
kaf24@9702 402 return -1;
kaf24@9702 403 }
kaf24@9702 404
kfraser@15297 405 void serial_suspend(void)
kfraser@15297 406 {
kfraser@15297 407 int i, irq;
kfraser@15297 408 for ( i = 0; i < ARRAY_SIZE(com); i++ )
kfraser@15297 409 if ( (irq = serial_irq(i)) >= 0 )
kfraser@15297 410 free_irq(irq);
kfraser@15297 411 }
kfraser@15297 412
kfraser@15297 413 void serial_resume(void)
kfraser@15297 414 {
kfraser@15297 415 serial_init_preirq();
kfraser@15297 416 serial_init_postirq();
kfraser@15297 417 }
kfraser@15297 418
kaf24@5233 419 void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
kaf24@5233 420 {
kaf24@5359 421 /* Store UART-specific info. */
kaf24@5233 422 com[idx].driver = driver;
kaf24@5233 423 com[idx].uart = uart;
kaf24@5359 424
kaf24@5359 425 /* Default is no transmit FIFO. */
kaf24@5359 426 com[idx].tx_fifo_size = 1;
kaf24@5359 427 }
kaf24@5359 428
kaf24@5359 429 void serial_async_transmit(struct serial_port *port)
kaf24@5359 430 {
kaf24@5359 431 BUG_ON(!port->driver->tx_empty);
kaf24@6722 432 if ( port->txbuf == NULL )
kaf24@6722 433 port->txbuf = alloc_xenheap_pages(
kaf24@6722 434 get_order_from_bytes(SERIAL_TXBUFSZ));
iap10@4325 435 }
iap10@4325 436
kaf24@3952 437 /*
kaf24@3952 438 * Local variables:
kaf24@3952 439 * mode: C
kaf24@3952 440 * c-set-style: "BSD"
kaf24@3952 441 * c-basic-offset: 4
kaf24@3952 442 * tab-width: 4
kaf24@3952 443 * indent-tabs-mode: nil
kaf24@4026 444 * End:
kaf24@3952 445 */