static _INLINE_ void transmit_chars(struct xmb_serial *info, volatile unsigned int *uartp) { if (info->x_char) { /* Send special char, probably flow control */ unsigned int ch = info->x_char; uartp[XUL_TX_FIFO_OFFSET/4] = ch; info->x_char=0; info->stats.tx++; } /* Don't send anything if there's nothing to send or tty is stopped */ if ((info->xmit_cnt <= 0) || info->tty->stopped) { return; } /* Fill the UART TX buffer again */ while (!(uartp[XUL_STATUS_REG_OFFSET/4] & XUL_SR_TX_FIFO_FULL)) { unsigned int ch = info->xmit_buf[info->xmit_tail++]; uartp[XUL_TX_FIFO_OFFSET/4] = ch; info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->stats.tx++; if (--info->xmit_cnt <= 0) break; } if (info->xmit_cnt < WAKEUP_CHARS) xmbrs_sched_event(info, RS_EVENT_WRITE_WAKEUP); return; }
/* Force a refill of the TX FIFO. This happens in user space, outside of interrupts so we cli() for the duration to prevent corruption of the output buffer data structure */ void force_tx_fifo_fill(struct xmb_serial *info) { unsigned int flags; volatile unsigned int *uartp=(volatile unsigned int *)info->addr; save_flags(flags); /* Block until TX FIFO can take more chars */ while(uartp[XUL_STATUS_REG_OFFSET/4] & XUL_SR_TX_FIFO_FULL) ; cli(); /* Force out any special character */ if (info->x_char) { /* Send special char, probably flow control */ unsigned int ch = info->x_char; uartp[XUL_TX_FIFO_OFFSET/4]=ch; info->x_char=0; info->stats.tx++; } restore_flags(flags); cli(); /* Don't send anything if there's nothing to send or tty is stopped */ if ((info->xmit_cnt <= 0) || info->tty->stopped) { restore_flags(flags); return; } restore_flags(flags); /* Fill the UART TX buffer again */ while(1) { unsigned int ch; if(uartp[XUL_STATUS_REG_OFFSET/4] & XUL_SR_TX_FIFO_FULL) break; cli(); ch = info->xmit_buf[info->xmit_tail++]; uartp[XUL_TX_FIFO_OFFSET/4]=ch; info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); info->stats.tx++; if (--info->xmit_cnt <= 0) break; restore_flags(flags); } restore_flags(flags); if (info->xmit_cnt < WAKEUP_CHARS) xmbrs_sched_event(info, RS_EVENT_WRITE_WAKEUP); return; }