// SPDX-License-Identifier: GPL-2.0 /* * Derived from many drivers using generic_serial interface, * especially serial_tx3912.c by Steven J. Hill and r39xx_serial.c * (was in Linux/VR tree) by Jim Pick. * * Copyright (C) 1999 Harald Koerfgen * Copyright (C) 2000 Jim Pick <jim@jimpick.com> * Copyright (C) 2001 Steven J. Hill (sjhill@realitydiluted.com) * Copyright (C) 2000-2002 Toshiba Corporation * * Serial driver for TX3927/TX4927/TX4925/TX4938 internal SIO controller
*/
#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL) /* "ttyS" is used for standard serial driver */ #define TXX9_TTY_NAME "ttyTX" #define TXX9_TTY_MINOR_START 196 #define TXX9_TTY_MAJOR 204 #else /* acts like standard serial driver */ #define TXX9_TTY_NAME "ttyS" #define TXX9_TTY_MINOR_START 64 #define TXX9_TTY_MAJOR TTY_MAJOR #endif
/* flag aliases */ #define UPF_TXX9_HAVE_CTS_LINE UPF_BUGGY_UART #define UPF_TXX9_USE_SCLK UPF_MAGIC_MULTIPLIER
#ifdef CONFIG_PCI /* support for Toshiba TC86C001 SIO */ #define ENABLE_SERIAL_TXX9_PCI #endif
/* * Number of serial ports
*/ #define UART_NR CONFIG_SERIAL_TXX9_NR_UARTS
do {
ch = sio_in(up, TXX9_SIRFIFO);
flag = TTY_NORMAL;
up->icount.rx++;
/* mask out RFDN_MASK bit added by previous overrun */
next_ignore_status_mask =
up->ignore_status_mask & ~TXX9_SIDISR_RFDN_MASK; if (unlikely(disr & (TXX9_SIDISR_UBRK | TXX9_SIDISR_UPER |
TXX9_SIDISR_UFER | TXX9_SIDISR_UOER))) { /* * For statistics only
*/ if (disr & TXX9_SIDISR_UBRK) {
disr &= ~(TXX9_SIDISR_UFER | TXX9_SIDISR_UPER);
up->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)) goto ignore_char;
} elseif (disr & TXX9_SIDISR_UPER)
up->icount.parity++; elseif (disr & TXX9_SIDISR_UFER)
up->icount.frame++; if (disr & TXX9_SIDISR_UOER) {
up->icount.overrun++; /* * The receiver read buffer still hold * a char which caused overrun. * Ignore next char by adding RFDN_MASK * to ignore_status_mask temporarily.
*/
next_ignore_status_mask |=
TXX9_SIDISR_RFDN_MASK;
}
/* * Mask off conditions which should be ingored.
*/
disr &= up->read_status_mask;
if (disr & TXX9_SIDISR_UBRK) {
flag = TTY_BREAK;
} elseif (disr & TXX9_SIDISR_UPER)
flag = TTY_PARITY; elseif (disr & TXX9_SIDISR_UFER)
flag = TTY_FRAME;
} if (uart_handle_sysrq_char(up, ch)) goto ignore_char;
/* Wait up to 10ms for the character(s) to be sent. */ while (--tmout &&
!(sio_in(up, TXX9_SICISR) & TXX9_SICISR_TXALS))
udelay(1);
/* Wait up to 1s for flow control if necessary */ if (up->flags & UPF_CONS_FLOW) {
tmout = 1000000; while (--tmout &&
(sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS))
udelay(1);
}
} #endif
#ifdef CONFIG_CONSOLE_POLL /* * Console polling routines for writing and reading from the uart while * in an interrupt or debug context.
*/
staticvoid
serial_txx9_pm(struct uart_port *port, unsignedint state, unsignedint oldstate)
{ /* * If oldstate was -1 this is called from * uart_configure_port(). In this case do not initialize the * port now, because the port was already initialized (for * non-console port) or should not be initialized here (for * console port). If we initialized the port here we lose * serial console settings.
*/ if (state == 0 && oldstate != -1)
serial_txx9_initialize(port);
}
staticint serial_txx9_request_resource(struct uart_port *up)
{ unsignedint size = TXX9_REGION_SIZE; int ret = 0;
switch (up->iotype) { default: if (!up->mapbase) break;
if (!request_mem_region(up->mapbase, size, "serial_txx9")) {
ret = -EBUSY; break;
}
if (up->flags & UPF_IOREMAP) {
up->membase = ioremap(up->mapbase, size); if (!up->membase) {
release_mem_region(up->mapbase, size);
ret = -ENOMEM;
}
} break;
case UPIO_PORT: if (!request_region(up->iobase, size, "serial_txx9"))
ret = -EBUSY; break;
} return ret;
}
staticvoid serial_txx9_config_port(struct uart_port *up, int uflags)
{ int ret;
/* * Find the region that we can probe for. This in turn * tells us whether we can probe for the type of port.
*/
ret = serial_txx9_request_resource(up); if (ret < 0) return;
up->type = PORT_TXX9;
up->fifosize = TXX9_SIO_TX_FIFO;
#ifdef CONFIG_SERIAL_TXX9_CONSOLE if (up->line == up->cons->index) return; #endif
serial_txx9_initialize(up);
}
/* * 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_txx9_console_write(struct console *co, constchar *s, unsignedint count)
{ struct uart_port *up = &serial_txx9_ports[co->index]; unsignedint ier, flcr;
/* * First save the UER then disable the interrupts
*/
ier = sio_in(up, TXX9_SIDICR);
sio_out(up, TXX9_SIDICR, 0); /* * Disable flow-control if enabled (and unnecessary)
*/
flcr = sio_in(up, TXX9_SIFLCR); if (!(up->flags & UPF_CONS_FLOW) && (flcr & TXX9_SIFLCR_TES))
sio_out(up, TXX9_SIFLCR, flcr & ~TXX9_SIFLCR_TES);
/* * Finally, wait for transmitter to become empty * and restore the IER
*/
wait_for_xmitr(up);
sio_out(up, TXX9_SIFLCR, flcr);
sio_out(up, TXX9_SIDICR, ier);
}
staticint __init serial_txx9_console_setup(struct console *co, char *options)
{ struct uart_port *up; int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n';
/* * Check whether an invalid uart number has been specified, and * if so, search for the first available port that does have * console support.
*/ if (co->index >= UART_NR)
co->index = 0;
up = &serial_txx9_ports[co->index]; if (!up->ops) return -ENODEV;
serial_txx9_initialize(up);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
/** * serial_txx9_register_port - register a serial port * @port: serial port template * * Configure the serial port specified by the request. * * The port is then probed and if necessary the IRQ is autodetected * If this fails an error is returned. * * On success the port is ready to use and the line number is returned.
*/ staticint serial_txx9_register_port(struct uart_port *port)
{ int i; struct uart_port *uart; int ret = -ENOSPC;
mutex_lock(&serial_txx9_mutex); for (i = 0; i < UART_NR; i++) {
uart = &serial_txx9_ports[i]; if (uart_match_port(uart, port)) {
uart_remove_one_port(&serial_txx9_reg, uart); break;
}
} if (i == UART_NR) { /* Find unused port */ for (i = 0; i < UART_NR; i++) {
uart = &serial_txx9_ports[i]; if (!(uart->iobase || uart->mapbase)) break;
}
} if (i < UART_NR) {
uart->iobase = port->iobase;
uart->membase = port->membase;
uart->irq = port->irq;
uart->uartclk = port->uartclk;
uart->iotype = port->iotype;
uart->flags = port->flags
| UPF_BOOT_AUTOCONF | UPF_FIXED_PORT;
uart->mapbase = port->mapbase; if (port->dev)
uart->dev = port->dev;
ret = uart_add_one_port(&serial_txx9_reg, uart); if (ret == 0)
ret = uart->line;
}
mutex_unlock(&serial_txx9_mutex); return ret;
}
/** * serial_txx9_unregister_port - remove a txx9 serial port at runtime * @line: serial line number * * Remove one serial port. This may not be called from interrupt * context. We hand the port back to the our control.
*/ staticvoid serial_txx9_unregister_port(int line)
{ struct uart_port *uart = &serial_txx9_ports[line];
/* * Register a set of serial devices attached to a platform device.
*/ staticint serial_txx9_probe(struct platform_device *dev)
{ struct uart_port *p = dev_get_platdata(&dev->dev); struct uart_port port; int ret, i;
memset(&port, 0, sizeof(struct uart_port)); for (i = 0; p && p->uartclk != 0; p++, i++) {
port.iobase = p->iobase;
port.membase = p->membase;
port.irq = p->irq;
port.uartclk = p->uartclk;
port.iotype = p->iotype;
port.flags = p->flags;
port.mapbase = p->mapbase;
port.dev = &dev->dev;
port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_TXX9_CONSOLE);
ret = serial_txx9_register_port(&port); if (ret < 0) {
dev_err(&dev->dev, "unable to register port at index %d " "(IO%lx MEM%llx IRQ%d): %d\n", i,
p->iobase, (unsignedlonglong)p->mapbase,
p->irq, ret);
}
} return 0;
}
/* * Remove serial ports registered against a platform device.
*/ staticvoid serial_txx9_remove(struct platform_device *dev)
{ int i;
for (i = 0; i < UART_NR; i++) { struct uart_port *up = &serial_txx9_ports[i];
if (up->dev == &dev->dev)
serial_txx9_unregister_port(i);
}
}
#ifdef ENABLE_SERIAL_TXX9_PCI /* * Probe one serial board. Unfortunately, there is no rhyme nor reason * to the arrangement of serial ports on a PCI card.
*/ staticint
pciserial_txx9_init_one(struct pci_dev *dev, conststruct pci_device_id *ent)
{ struct uart_port port; int line; int rc;
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.