ehci_dbgp_flush(port);
}
-static unsigned int ehci_dbgp_tx_ready(struct serial_port *port)
+static int ehci_dbgp_tx_ready(struct serial_port *port)
{
struct ehci_dbgp *dbgp = port->uart;
writeb(c, uart->remapped_io_base + reg);
}
+static int ns16550_ioport_invalid(struct ns16550 *uart)
+{
+ return (unsigned char)ns_read_reg(uart, UART_IER) == 0xff;
+}
+
static void ns16550_interrupt(
int irq, void *dev_id, struct cpu_user_regs *regs)
{
return; /* Interrupts work - no more polling */
while ( ns_read_reg(uart, UART_LSR) & UART_LSR_DR )
+ {
+ if ( ns16550_ioport_invalid(uart) )
+ goto out;
+
serial_rx_interrupt(port, regs);
+ }
if ( ns_read_reg(uart, UART_LSR) & UART_LSR_THRE )
serial_tx_interrupt(port, regs);
+out:
set_timer(&uart->timer, NOW() + MILLISECS(uart->timeout_ms));
}
#endif
}
-static unsigned int ns16550_tx_ready(struct serial_port *port)
+static int ns16550_tx_ready(struct serial_port *port)
{
struct ns16550 *uart = port->uart;
+ if ( ns16550_ioport_invalid(uart) )
+ return -EIO;
return ns_read_reg(uart, UART_LSR) & UART_LSR_THRE ? uart->fifo_size : 0;
}
{
struct ns16550 *uart = port->uart;
- if ( !(ns_read_reg(uart, UART_LSR) & UART_LSR_DR) )
+ if ( ns16550_ioport_invalid(uart) ||
+ !(ns_read_reg(uart, UART_LSR) & UART_LSR_DR) )
return 0;
*pc = ns_read_reg(uart, UART_RBR);
ns16550_setup_postirq(port->uart);
}
-static int ns16550_ioport_invalid(struct ns16550 *uart)
-{
- return ((((unsigned char)ns_read_reg(uart, UART_LSR)) == 0xff) &&
- (((unsigned char)ns_read_reg(uart, UART_MCR)) == 0xff) &&
- (((unsigned char)ns_read_reg(uart, UART_IER)) == 0xff) &&
- (((unsigned char)ns_read_reg(uart, UART_IIR)) == 0xff) &&
- (((unsigned char)ns_read_reg(uart, UART_LCR)) == 0xff));
-}
-
static int delayed_resume_tries;
static void ns16550_delayed_resume(void *data)
{
void serial_tx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
{
- unsigned int i, n;
+ int i, n;
unsigned long flags;
local_irq_save(flags);
*/
while ( !spin_trylock(&port->tx_lock) )
{
- if ( !port->driver->tx_ready(port) )
+ if ( port->driver->tx_ready(port) <= 0 )
goto out;
cpu_relax();
}
if ( port->tx_log_everything )
{
/* Buffer is full: we spin waiting for space to appear. */
- unsigned int n;
+ 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;
+ if ( n > 0 )
+ {
+ while ( n-- )
+ port->driver->putc(
+ port,
+ port->txbuf[mask_serial_txbuf_idx(port->txbufc++)]);
+ port->txbuf[mask_serial_txbuf_idx(port->txbufp++)] = c;
+ }
}
else
{
}
if ( ((port->txbufp - port->txbufc) == 0) &&
- port->driver->tx_ready(port) )
+ port->driver->tx_ready(port) > 0 )
{
- /* Buffer and UART FIFO are both empty. */
+ /* Buffer and UART FIFO are both empty, and port is available. */
port->driver->putc(port, c);
}
else
}
else if ( port->driver->tx_ready )
{
+ int n;
+
/* Synchronous finite-capacity transmitter. */
- while ( !port->driver->tx_ready(port) )
+ while ( !(n = port->driver->tx_ready(port)) )
cpu_relax();
- port->driver->putc(port, c);
+ if ( n > 0 )
+ port->driver->putc(port, c);
}
else
{
{
while ( (port->txbufp - port->txbufc) != 0 )
{
- while ( !port->driver->tx_ready(port) )
+ 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++)]);
}
/* Driver suspend/resume. */
void (*suspend)(struct serial_port *);
void (*resume)(struct serial_port *);
- /* Return number of characters the port can hold for transmit. */
- unsigned int (*tx_ready)(struct serial_port *);
+ /* Return number of characters the port can hold for transmit,
+ * or -EIO if port is inaccesible */
+ int (*tx_ready)(struct serial_port *);
/* Put a character onto the serial line. */
void (*putc)(struct serial_port *, char);
/* Flush accumulated characters. */