void serial_start_sync(int handle) { struct serial_port *port; unsigned long flags; if ( handle == -1 ) return; port = &com[handle & SERHND_IDX]; spin_lock_irqsave(&port->tx_lock, flags); if ( port->sync++ == 0 ) { while ( (port->txbufp - port->txbufc) != 0 ) { while ( !port->driver->tx_ready(port) ) cpu_relax(); port->driver->putc( port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]); } if ( port->driver->flush ) port->driver->flush(port); } spin_unlock_irqrestore(&port->tx_lock, flags); }
void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs) { unsigned int i, n; unsigned long flags; local_irq_save(flags); /* * Avoid spinning for a long time: if there is a long-term lock holder * then we know that they'll be stuffing bytes into the transmitter which * will therefore not be empty for long. */ while ( !spin_trylock(&port->tx_lock) ) { if ( !port->driver->tx_ready(port) ) goto out; cpu_relax(); } for ( i = 0, n = port->driver->tx_ready(port); i < n; i++ ) { if ( port->txbufc == port->txbufp ) break; port->driver->putc( port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]); } if ( i && port->driver->flush ) port->driver->flush(port); spin_unlock(&port->tx_lock); out: local_irq_restore(flags); }
void serial_start_sync(int handle) { struct serial_port *port; unsigned long flags; if ( handle == -1 ) return; port = &com[handle & SERHND_IDX]; spin_lock_irqsave(&port->tx_lock, flags); if ( port->sync++ == 0 ) { while ( (port->txbufp - port->txbufc) != 0 ) { int n; while ( !(n = port->driver->tx_ready(port)) ) cpu_relax(); if ( n < 0 ) /* port is unavailable and might not come up until reenabled by dom0, we can't really do proper sync */ break; port->driver->putc( port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]); } if ( port->driver->flush ) port->driver->flush(port); } spin_unlock_irqrestore(&port->tx_lock, flags); }
static void __serial_putc(struct serial_port *port, char c) { if ( (port->txbuf != NULL) && !port->sync ) { /* Interrupt-driven (asynchronous) transmitter. */ if ( port->tx_quench ) { /* Buffer filled and we are dropping characters. */ if ( (port->txbufp - port->txbufc) > (serial_txbufsz / 2) ) return; port->tx_quench = 0; } if ( (port->txbufp - port->txbufc) == serial_txbufsz ) { if ( port->tx_log_everything ) { /* Buffer is full: we spin waiting for space to appear. */ unsigned int n; while ( (n = port->driver->tx_ready(port)) == 0 ) cpu_relax(); while ( n-- ) port->driver->putc( port, port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]); port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c; } else { /* Buffer is full: drop chars until buffer is half empty. */ port->tx_quench = 1; } return; } if ( ((port->txbufp - port->txbufc) == 0) && port->driver->tx_ready(port) ) { /* Buffer and UART FIFO are both empty. */ port->driver->putc(port, c); } else { /* Normal case: buffer the character. */ port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c; } } else if ( port->driver->tx_ready ) { /* Synchronous finite-capacity transmitter. */ while ( !port->driver->tx_ready(port) ) cpu_relax(); port->driver->putc(port, c); } else { /* Simple synchronous transmitter. */ port->driver->putc(port, c); } }