static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo) { u_char c, *cp; volatile cbd_t *bdp; int i; /* Get the address of the host memory buffer. */ bdp = pinfo->rx_cur; while (bdp->cbd_sc & BD_SC_EMPTY) ; /* If the buffer address is in the CPM DPRAM, don't * convert it. */ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); if (obuf) { i = c = bdp->cbd_datlen; while (i-- > 0) *obuf++ = *cp++; } else c = *cp; bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID); bdp->cbd_sc |= BD_SC_EMPTY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = pinfo->rx_bd_base; else bdp++; pinfo->rx_cur = (cbd_t *)bdp; return (int)c; }
/* * Receive character from the serial port. This only works well * before the port is initialize for real use. */ static int kgdb_wait_key(char *obuf) { struct uart_cpm_port *pinfo; u_char c, *cp; volatile cbd_t *bdp; int i; pinfo = &cpm_uart_ports[KGDB_PINFO_INDEX]; /* Get the address of the host memory buffer. */ bdp = pinfo->rx_cur; while (bdp->cbd_sc & BD_SC_EMPTY); /* If the buffer address is in the CPM DPRAM, don't * convert it. */ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); if (obuf) { i = c = bdp->cbd_datlen; while (i-- > 0) *obuf++ = *cp++; } else c = *cp; bdp->cbd_sc |= BD_SC_EMPTY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = pinfo->rx_bd_base; else bdp++; pinfo->rx_cur = (cbd_t *)bdp; return (int)c; }
/* * Transmit characters, refill buffer descriptor, if possible */ static int cpm_uart_tx_pump(struct uart_port *port) { volatile cbd_t *bdp; unsigned char *p; int count; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; struct circ_buf *xmit = &port->info->xmit; /* Handle xon/xoff */ if (port->x_char) { /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); *p++ = port->x_char; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; /* Get next BD. */ if (bdp->cbd_sc & BD_SC_WRAP) bdp = pinfo->tx_bd_base; else bdp++; pinfo->tx_cur = bdp; port->icount.tx++; port->x_char = 0; return 1; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { cpm_uart_stop_tx(port); return 0; } /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) { count = 0; p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); while (count < pinfo->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; count++; if (xmit->head == xmit->tail) break; } bdp->cbd_datlen = count; bdp->cbd_sc |= BD_SC_READY; __asm__("eieio"); /* Get next BD. */ if (bdp->cbd_sc & BD_SC_WRAP) bdp = pinfo->tx_bd_base; else bdp++; } pinfo->tx_cur = bdp; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); if (uart_circ_empty(xmit)) { cpm_uart_stop_tx(port); return 0; } return 1; }
/* * Receive characters */ static void cpm_uart_int_rx(struct uart_port *port) { int i; unsigned char ch, *cp; struct tty_struct *tty = port->info->tty; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; volatile cbd_t *bdp; u16 status; unsigned int flg; pr_debug("CPM uart[%d]:RX INT\n", port->line); /* Just loop through the closed BDs and copy the characters into * the buffer. */ bdp = pinfo->rx_cur; for (;;) { /* get status */ status = bdp->cbd_sc; /* If this one is empty, return happy */ if (status & BD_SC_EMPTY) break; /* get number of characters, and check spce in flip-buffer */ i = bdp->cbd_datlen; /* If we have not enough room in tty flip buffer, then we try * later, which will be the next rx-interrupt or a timeout */ if(tty_buffer_request_room(tty, i) < i) { printk(KERN_WARNING "No room in flip buffer\n"); return; } /* get pointer */ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); /* loop through the buffer */ while (i-- > 0) { ch = *cp++; port->icount.rx++; flg = TTY_NORMAL; if (status & (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV)) goto handle_error; if (uart_handle_sysrq_char(port, ch)) continue; error_return: tty_insert_flip_char(tty, ch, flg); } /* End while (i--) */ /* This BD is ready to be used again. Clear status. get next */ bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID); bdp->cbd_sc |= BD_SC_EMPTY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = pinfo->rx_bd_base; else bdp++; } /* End for (;;) */ /* Write back buffer pointer */ pinfo->rx_cur = (volatile cbd_t *) bdp; /* activate BH processing */ tty_flip_buffer_push(tty); return; /* Error processing */ handle_error: /* Statistics */ if (status & BD_SC_BR) port->icount.brk++; if (status & BD_SC_PR) port->icount.parity++; if (status & BD_SC_FR) port->icount.frame++; if (status & BD_SC_OV) port->icount.overrun++; /* Mask out ignored conditions */ status &= port->read_status_mask; /* Handle the remaining ones */ if (status & BD_SC_BR) flg = TTY_BREAK; else if (status & BD_SC_PR) flg = TTY_PARITY; else if (status & BD_SC_FR) flg = TTY_FRAME; /* overrun does not affect the current character ! */ if (status & BD_SC_OV) { ch = 0; flg = TTY_OVERRUN; /* We skip this buffer */ /* CHECK: Is really nothing senseful there */ /* ASSUMPTION: it contains nothing valid */ i = 0; } #ifdef SUPPORT_SYSRQ port->sysrq = 0; #endif goto error_return; }
/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * * Note that this is called with interrupts already disabled */ static void cpm_uart_console_write(struct console *co, const char *s, u_int count) { struct uart_cpm_port *pinfo = &cpm_uart_ports[cpm_uart_port_map[co->index]]; unsigned int i; volatile cbd_t *bdp, *bdbase; volatile unsigned char *cp; /* Get the address of the host memory buffer. */ bdp = pinfo->tx_cur; bdbase = pinfo->tx_bd_base; /* * Now, do each character. This is not as bad as it looks * since this is a holding FIFO and not a transmitting FIFO. * We could add the complexity of filling the entire transmit * buffer, but we would just wait longer between accesses...... */ for (i = 0; i < count; i++, s++) { /* Wait for transmitter fifo to empty. * Ready indicates output is ready, and xmt is doing * that, not that it is ready for us to send. */ while ((bdp->cbd_sc & BD_SC_READY) != 0) ; /* Send the character out. * If the buffer address is in the CPM DPRAM, don't * convert it. */ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); *cp = *s; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = bdbase; else bdp++; /* if a LF, also do CR... */ if (*s == 10) { while ((bdp->cbd_sc & BD_SC_READY) != 0) ; cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo); *cp = 13; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = bdbase; else bdp++; } } /* * Finally, Wait for transmitter & holding register to empty * and restore the IER */ while ((bdp->cbd_sc & BD_SC_READY) != 0) ; pinfo->tx_cur = (volatile cbd_t *) bdp; }
/* * Transmit characters, refill buffer descriptor, if possible */ static int cpm_uart_tx_pump(struct uart_port *port) { cbd_t __iomem *bdp; u8 *p; int count; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; struct circ_buf *xmit = &port->info->xmit; /* Handle xon/xoff */ if (port->x_char) { /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *p++ = port->x_char; out_be16(&bdp->cbd_datlen, 1); setbits16(&bdp->cbd_sc, BD_SC_READY); /* Get next BD. */ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = pinfo->tx_bd_base; else bdp++; pinfo->tx_cur = bdp; port->icount.tx++; port->x_char = 0; return 1; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { cpm_uart_stop_tx(port); return 0; } /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && xmit->tail != xmit->head) { count = 0; p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); while (count < pinfo->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; count++; if (xmit->head == xmit->tail) break; } out_be16(&bdp->cbd_datlen, count); setbits16(&bdp->cbd_sc, BD_SC_READY); /* Get next BD. */ if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = pinfo->tx_bd_base; else bdp++; } pinfo->tx_cur = bdp; if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); if (uart_circ_empty(xmit)) { cpm_uart_stop_tx(port); return 0; } return 1; }
/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * * Note that this is called with interrupts already disabled */ static void cpm_uart_console_write(struct console *co, const char *s, u_int count) { struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index]; unsigned int i; cbd_t __iomem *bdp, *bdbase; unsigned char *cp; unsigned long flags; int nolock = oops_in_progress; if (unlikely(nolock)) { local_irq_save(flags); } else { spin_lock_irqsave(&pinfo->port.lock, flags); } /* Get the address of the host memory buffer. */ bdp = pinfo->tx_cur; bdbase = pinfo->tx_bd_base; /* * Now, do each character. This is not as bad as it looks * since this is a holding FIFO and not a transmitting FIFO. * We could add the complexity of filling the entire transmit * buffer, but we would just wait longer between accesses...... */ for (i = 0; i < count; i++, s++) { /* Wait for transmitter fifo to empty. * Ready indicates output is ready, and xmt is doing * that, not that it is ready for us to send. */ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; /* Send the character out. * If the buffer address is in the CPM DPRAM, don't * convert it. */ cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *cp = *s; out_be16(&bdp->cbd_datlen, 1); setbits16(&bdp->cbd_sc, BD_SC_READY); if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = bdbase; else bdp++; /* if a LF, also do CR... */ if (*s == 10) { while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *cp = 13; out_be16(&bdp->cbd_datlen, 1); setbits16(&bdp->cbd_sc, BD_SC_READY); if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = bdbase; else bdp++; } } /* * Finally, Wait for transmitter & holding register to empty * and restore the IER */ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; pinfo->tx_cur = bdp; if (unlikely(nolock)) { local_irq_restore(flags); } else { spin_unlock_irqrestore(&pinfo->port.lock, flags); } }
/* * Write a string to the serial port * Note that this is called with interrupts already disabled */ static void cpm_uart_early_write(struct uart_cpm_port *pinfo, const char *string, u_int count) { unsigned int i; cbd_t __iomem *bdp, *bdbase; unsigned char *cpm_outp_addr; /* Get the address of the host memory buffer. */ bdp = pinfo->tx_cur; bdbase = pinfo->tx_bd_base; /* * Now, do each character. This is not as bad as it looks * since this is a holding FIFO and not a transmitting FIFO. * We could add the complexity of filling the entire transmit * buffer, but we would just wait longer between accesses...... */ for (i = 0; i < count; i++, string++) { /* Wait for transmitter fifo to empty. * Ready indicates output is ready, and xmt is doing * that, not that it is ready for us to send. */ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; /* Send the character out. * If the buffer address is in the CPM DPRAM, don't * convert it. */ cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *cpm_outp_addr = *string; out_be16(&bdp->cbd_datlen, 1); setbits16(&bdp->cbd_sc, BD_SC_READY); if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = bdbase; else bdp++; /* if a LF, also do CR... */ if (*string == 10) { while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; cpm_outp_addr = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo); *cpm_outp_addr = 13; out_be16(&bdp->cbd_datlen, 1); setbits16(&bdp->cbd_sc, BD_SC_READY); if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) bdp = bdbase; else bdp++; } } /* * Finally, Wait for transmitter & holding register to empty * and restore the IER */ while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0) ; pinfo->tx_cur = bdp; }