// SPDX-License-Identifier: GPL-2.0+ /* * Based on drivers/serial/8250.c by Russell King. * * Author: Nicolas Pitre * Created: Feb 20, 2003 * Copyright: (C) 2003 Monta Vista Software, Inc. * * Note 1: This driver is made separate from the already too overloaded * 8250.c because it needs some kirks of its own and that'll make it * easier to add DMA support. * * Note 2: I'm too sick of device allocation policies for serial ports. * If someone else wants to request an "official" allocation of major/minor * for this driver please be my guest. And don't forget that new hardware * to come from Intel might have more than 3 or 4 of those UARTs. Let's * hope for a better port registration and dynamic device allocation scheme * with the serial core maintainer satisfaction to appear soon.
*/
staticinlinevoid receive_chars(struct uart_pxa_port *up, int *status)
{
u8 ch, flag; int max_count = 256;
do { /* work around Errata #20 according to * Intel(R) PXA27x Processor Family * Specification Update (May 2005) * * Step 2 * Disable the Reciever Time Out Interrupt via IER[RTOEI]
*/
up->ier &= ~UART_IER_RTOIE;
serial_out(up, UART_IER, up->ier);
ch = serial_in(up, UART_RX);
flag = TTY_NORMAL;
up->port.icount.rx++;
if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
UART_LSR_FE | UART_LSR_OE))) { /* * For statistics only
*/ if (*status & UART_LSR_BI) {
*status &= ~(UART_LSR_FE | UART_LSR_PE);
up->port.icount.brk++; /* * We do the SysRQ and SAK checking * here because otherwise the break * may get masked by ignore_status_mask * or read_status_mask.
*/ if (uart_handle_break(&up->port)) goto ignore_char;
} elseif (*status & UART_LSR_PE)
up->port.icount.parity++; elseif (*status & UART_LSR_FE)
up->port.icount.frame++; if (*status & UART_LSR_OE)
up->port.icount.overrun++;
/* * Mask off conditions which should be ignored.
*/
*status &= up->port.read_status_mask;
#ifdef CONFIG_SERIAL_PXA_CONSOLE if (up->port.line == up->port.cons->index) { /* Recover the break flag from console xmit */
*status |= up->lsr_break_flag;
up->lsr_break_flag = 0;
} #endif if (*status & UART_LSR_BI) {
flag = TTY_BREAK;
} elseif (*status & UART_LSR_PE)
flag = TTY_PARITY; elseif (*status & UART_LSR_FE)
flag = TTY_FRAME;
}
if (uart_prepare_sysrq_char(&up->port, ch)) goto ignore_char;
/* work around Errata #20 according to * Intel(R) PXA27x Processor Family * Specification Update (May 2005) * * Step 6: * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE]
*/
up->ier |= UART_IER_RTOIE;
serial_out(up, UART_IER, up->ier);
}
/* should hold up->port.lock */ staticinlinevoid check_modem_status(struct uart_pxa_port *up)
{ int status;
status = serial_in(up, UART_MSR);
if ((status & UART_MSR_ANY_DELTA) == 0) return;
if (status & UART_MSR_TERI)
up->port.icount.rng++; if (status & UART_MSR_DDSR)
up->port.icount.dsr++; if (status & UART_MSR_DDCD)
uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); if (status & UART_MSR_DCTS)
uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
ret = 0; if (status & UART_MSR_DCD)
ret |= TIOCM_CAR; if (status & UART_MSR_RI)
ret |= TIOCM_RNG; if (status & UART_MSR_DSR)
ret |= TIOCM_DSR; if (status & UART_MSR_CTS)
ret |= TIOCM_CTS; return ret;
}
/* * Finally, enable interrupts. Note: Modem status interrupts * are set via set_termios(), which will be occurring imminently * anyway, so we don't enable them here.
*/
up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
serial_out(up, UART_IER, up->ier);
/* * And clear the interrupt registers again for luck.
*/
(void) serial_in(up, UART_LSR);
(void) serial_in(up, UART_RX);
(void) serial_in(up, UART_IIR);
(void) serial_in(up, UART_MSR);
/* * Characters to ignore
*/
up->port.ignore_status_mask = 0; if (termios->c_iflag & IGNPAR)
up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; if (termios->c_iflag & IGNBRK) {
up->port.ignore_status_mask |= UART_LSR_BI; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support).
*/ if (termios->c_iflag & IGNPAR)
up->port.ignore_status_mask |= UART_LSR_OE;
}
/* * ignore all characters if CREAD is not set
*/ if ((termios->c_cflag & CREAD) == 0)
up->port.ignore_status_mask |= UART_LSR_DR;
/* * CTS flow control flag and modem status interrupts
*/
up->ier &= ~UART_IER_MSI; if (UART_ENABLE_MS(&up->port, termios->c_cflag))
up->ier |= UART_IER_MSI;
staticint
serial_pxa_verify_port(struct uart_port *port, struct serial_struct *ser)
{ /* we don't want the core code to modify any port params */ return -EINVAL;
}
/* Wait up to 10ms for the character(s) to be sent. */ do {
status = serial_in(up, UART_LSR);
if (status & UART_LSR_BI)
up->lsr_break_flag = UART_LSR_BI;
if (--tmout == 0) break;
udelay(1);
} while (!uart_lsr_tx_empty(status));
/* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) {
tmout = 1000000; while (--tmout &&
((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
udelay(1);
}
}
/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * * The console_lock must be held when we get here.
*/ staticvoid
serial_pxa_console_write(struct console *co, constchar *s, unsignedint count)
{ struct uart_pxa_port *up = serial_pxa_ports[co->index]; unsignedint ier; unsignedlong flags; int locked = 1;
clk_enable(up->clk); if (oops_in_progress)
locked = uart_port_trylock_irqsave(&up->port, &flags); else
uart_port_lock_irqsave(&up->port, &flags);
/* * First save the IER then disable the interrupts
*/
ier = serial_in(up, UART_IER);
serial_out(up, UART_IER, UART_IER_UUE);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.