/** * uart_write_wakeup - schedule write processing * @port: port to be processed * * This routine is used by the interrupt handler to schedule processing in the * software interrupt portion of the driver. A driver is expected to call this * function when the number of characters in the transmit buffer have dropped * below a threshold. * * Locking: @port->lock should be held
*/ void uart_write_wakeup(struct uart_port *port)
{ struct uart_state *state = port->state; /* * This means you called this function _after_ the port was * closed. No cookie for you.
*/
BUG_ON(!state);
tty_port_tty_wakeup(&state->port);
}
EXPORT_SYMBOL(uart_write_wakeup);
if (!port || port->flags & UPF_DEAD || uart_tx_stopped(port)) return;
port_dev = port->port_dev;
/* Increment the runtime PM usage count for the active check below */
err = pm_runtime_get(&port_dev->dev); if (err < 0 && err != -EINPROGRESS) {
pm_runtime_put_noidle(&port_dev->dev); return;
}
/* * Start TX if enabled, and kick runtime PM. If the device is not * enabled, serial_port_runtime_resume() calls start_tx() again * after enabling the device.
*/ if (!pm_runtime_enabled(port->dev) || pm_runtime_active(&port_dev->dev))
port->ops->start_tx(port);
pm_runtime_mark_last_busy(&port_dev->dev);
pm_runtime_put_autosuspend(&port_dev->dev);
}
/* * If we have no tty, termios, or the port does not exist, * then we can't set the parameters for this port.
*/ if (!tty || uport->type == PORT_UNKNOWN) return;
/* * Set modem status enables based on termios cflag
*/
uart_port_lock_irq(uport); if (termios->c_cflag & CRTSCTS)
uport->status |= UPSTAT_CTS_ENABLE; else
uport->status &= ~UPSTAT_CTS_ENABLE;
/* * Initialise and allocate the transmit and temporary * buffer.
*/
page = get_zeroed_page(GFP_KERNEL); if (!page) return -ENOMEM;
uport = uart_port_ref_lock(state, &flags); if (!state->port.xmit_buf) {
state->port.xmit_buf = (unsignedchar *)page;
kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
PAGE_SIZE);
uart_port_unlock_deref(uport, flags);
} else {
uart_port_unlock_deref(uport, flags); /* * Do not free() the page under the port lock, see * uart_free_xmit_buf().
*/
free_page(page);
}
/* * Do not free() the transmit buffer page under the port lock since * this can create various circular locking scenarios. For instance, * console driver may need to allocate/free a debug object, which * can end up in printk() recursion.
*/
uport = uart_port_ref_lock(state, &flags);
xmit_buf = port->xmit_buf;
port->xmit_buf = NULL;
INIT_KFIFO(port->xmit_fifo);
uart_port_unlock_deref(uport, flags);
free_page((unsignedlong)xmit_buf);
}
/* * Startup the port. This will be called once per open. All calls * will be serialised by the per-port mutex.
*/ staticint uart_port_startup(struct tty_struct *tty, struct uart_state *state, bool init_hw)
{ struct uart_port *uport = uart_port_check(state); int retval;
if (uport->type == PORT_UNKNOWN) return 1;
/* * Make sure the device is in D0 state.
*/
uart_change_pm(state, UART_PM_STATE_ON);
retval = uart_alloc_xmit_buf(&state->port); if (retval) return retval;
/* * Setup the RTS and DTR signals once the * port is open and ready to respond.
*/ if (init_hw && C_BAUD(tty))
uart_port_dtr_rts(uport, true);
}
/* * This is to allow setserial on this port. People may want to set * port/irq/type and then reconfigure the port properly if it failed * now.
*/ if (retval && capable(CAP_SYS_ADMIN)) return 1;
out_base_port_startup:
uport = uart_port_check(state); if (!uport) return -EIO;
serial_base_port_startup(uport);
return 0;
}
/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. Calls to * uart_shutdown are serialised by the per-port semaphore. * * uport == NULL if uart_port has already been removed
*/ staticvoid uart_shutdown(struct tty_struct *tty, struct uart_state *state)
{ struct uart_port *uport = uart_port_check(state); struct tty_port *port = &state->port;
/* * Set the TTY IO error marker
*/ if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
if (uport)
serial_base_port_shutdown(uport);
if (tty_port_initialized(port)) {
tty_port_set_initialized(port, false);
/* * Turn off DTR and RTS early.
*/ if (uport) { if (uart_console(uport) && tty) {
uport->cons->cflag = tty->termios.c_cflag;
uport->cons->ispeed = tty->termios.c_ispeed;
uport->cons->ospeed = tty->termios.c_ospeed;
}
if (!tty || C_HUPCL(tty))
uart_port_dtr_rts(uport, false);
}
uart_port_shutdown(port);
}
/* * It's possible for shutdown to be called after suspend if we get * a DCD drop (hangup) at just the right time. Clear suspended bit so * we don't try to resume a port that has been shutdown.
*/
tty_port_set_suspended(port, false);
uart_free_xmit_buf(port);
}
/** * uart_update_timeout - update per-port frame timing information * @port: uart_port structure describing the port * @cflag: termios cflag value * @baud: speed of the port * * Set the @port frame timing information from which the FIFO timeout value is * derived. The @cflag value should reflect the actual hardware settings as * number of bits, parity, stop bits and baud rate is taken into account here. * * Locking: caller is expected to take @port->lock
*/ void
uart_update_timeout(struct uart_port *port, unsignedint cflag, unsignedint baud)
{
u64 temp = tty_get_frame_size(cflag);
/** * uart_get_baud_rate - return baud rate for a particular port * @port: uart_port structure describing the port in question. * @termios: desired termios settings * @old: old termios (or %NULL) * @min: minimum acceptable baud rate * @max: maximum acceptable baud rate * * Decode the termios structure into a numeric baud rate, taking account of the * magic 38400 baud rate (with spd_* flags), and mapping the %B0 rate to 9600 * baud. * * If the new baud rate is invalid, try the @old termios setting. If it's still * invalid, we try 9600 baud. If that is also invalid 0 is returned. * * The @termios structure is updated to reflect the baud rate we're actually * going to be using. Don't do this for the case where B0 is requested ("hang * up"). * * Locking: caller dependent
*/ unsignedint
uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, conststruct ktermios *old, unsignedint min, unsignedint max)
{ unsignedinttry; unsignedint baud; unsignedint altbaud; int hung_up = 0;
upf_t flags = port->flags & UPF_SPD_MASK;
switch (flags) { case UPF_SPD_HI:
altbaud = 57600; break; case UPF_SPD_VHI:
altbaud = 115200; break; case UPF_SPD_SHI:
altbaud = 230400; break; case UPF_SPD_WARP:
altbaud = 460800; break; default:
altbaud = 38400; break;
}
/* * Special case: B0 rate.
*/ if (baud == 0) {
hung_up = 1;
baud = 9600;
}
if (baud >= min && baud <= max) return baud;
/* * Oops, the quotient was zero. Try again with * the old baud rate if possible.
*/
termios->c_cflag &= ~CBAUD; if (old) {
baud = tty_termios_baud_rate(old); if (!hung_up)
tty_termios_encode_baud_rate(termios,
baud, baud);
old = NULL; continue;
}
/* * As a last resort, if the range cannot be met then clip to * the nearest chip supported rate.
*/ if (!hung_up) { if (baud <= min)
tty_termios_encode_baud_rate(termios,
min + 1, min + 1); else
tty_termios_encode_baud_rate(termios,
max - 1, max - 1);
}
} return 0;
}
EXPORT_SYMBOL(uart_get_baud_rate);
/** * uart_get_divisor - return uart clock divisor * @port: uart_port structure describing the port * @baud: desired baud rate * * Calculate the divisor (baud_base / baud) for the specified @baud, * appropriately rounded. * * If 38400 baud and custom divisor is selected, return the custom divisor * instead. * * Locking: caller dependent
*/ unsignedint
uart_get_divisor(struct uart_port *port, unsignedint baud)
{ unsignedint quot;
/* * Old custom speed handling.
*/ if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
quot = port->custom_divisor; else
quot = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
return quot;
}
EXPORT_SYMBOL(uart_get_divisor);
staticint uart_put_char(struct tty_struct *tty, u8 c)
{ struct uart_state *state = tty->driver_data; struct uart_port *port; unsignedlong flags; int ret = 0;
port = uart_port_ref_lock(state, &flags); if (!state->port.xmit_buf) {
uart_port_unlock_deref(port, flags); return 0;
}
if (port)
ret = kfifo_put(&state->port.xmit_fifo, c);
uart_port_unlock_deref(port, flags); return ret;
}
port = uart_port_ref_lock(state, &flags); if (!port) return;
kfifo_reset(&state->port.xmit_fifo); if (port->ops->flush_buffer)
port->ops->flush_buffer(port);
uart_port_unlock_deref(port, flags);
tty_port_tty_wakeup(&state->port);
}
/* * This function performs low-level write of high-priority XON/XOFF * character and accounting for it. * * Requires uart_port to implement .serial_out().
*/ void uart_xchar_out(struct uart_port *uport, int offset)
{
serial_port_out(uport, offset, uport->x_char);
uport->icount.tx++;
uport->x_char = 0;
}
EXPORT_SYMBOL_GPL(uart_xchar_out);
/* * This function is used to send a high-priority XON/XOFF character to * the device
*/ staticvoid uart_send_xchar(struct tty_struct *tty, u8 ch)
{ struct uart_state *state = tty->driver_data; struct uart_port *port; unsignedlong flags;
port = uart_port_ref(state); if (!port) return;
if (port->ops->send_xchar)
port->ops->send_xchar(port, ch); else {
uart_port_lock_irqsave(port, &flags);
port->x_char = ch; if (ch)
port->ops->start_tx(port);
uart_port_unlock_irqrestore(port, flags);
}
uart_port_deref(port);
}
/* Initialize structure in case we error out later to prevent any stack info leakage. */
*retinfo = (struct serial_struct){};
/* * Ensure the state we copy is consistent and no hardware changes * occur as we go
*/
guard(mutex)(&port->mutex);
uport = uart_port_check(state); if (!uport) return -ENODEV;
/* * If we fail to request resources for the new port, try to restore the * old settings.
*/
uport->iobase = old_iobase;
uport->type = old_type;
uport->hub6 = old_hub6;
uport->iotype = old_iotype;
uport->regshift = old_shift;
uport->mapbase = old_mapbase;
if (old_type == PORT_UNKNOWN) return retval;
retval = uport->ops->request_port(uport); /* If we failed to restore the old settings, we fail like this. */ if (retval)
uport->type = PORT_UNKNOWN;
/* * Since changing the 'type' of the port changes its resource * allocations, we should treat type changes the same as * IO port changes.
*/
change_port = !(uport->flags & UPF_FIXED_PORT)
&& (new_port != uport->iobase ||
(unsignedlong)new_info->iomem_base != uport->mapbase ||
new_info->hub6 != uport->hub6 ||
new_info->io_type != uport->iotype ||
new_info->iomem_reg_shift != uport->regshift ||
new_info->type != uport->type);
if (!(uport->flags & UPF_FIXED_PORT)) { unsignedint uartclk = new_info->baud_base * 16; /* check needs to be done here before other settings made */ if (uartclk == 0) return -EINVAL;
} if (!capable(CAP_SYS_ADMIN)) { if (change_irq || change_port ||
(new_info->baud_base != uport->uartclk / 16) ||
(close_delay != port->close_delay) ||
(closing_wait != port->closing_wait) ||
(new_info->xmit_fifo_size &&
new_info->xmit_fifo_size != uport->fifosize) ||
(((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) return -EPERM;
uport->flags = ((uport->flags & ~UPF_USR_MASK) |
(new_flags & UPF_USR_MASK));
uport->custom_divisor = new_info->custom_divisor; goto check_and_exit;
}
if (change_irq || change_port) {
retval = security_locked_down(LOCKDOWN_TIOCSSERIAL); if (retval) return retval;
}
/* Ask the low level driver to verify the settings. */ if (uport->ops->verify_port) {
retval = uport->ops->verify_port(uport, new_info); if (retval) return retval;
}
check_and_exit: if (uport->type == PORT_UNKNOWN) return 0;
if (tty_port_initialized(port)) { if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
old_custom_divisor != uport->custom_divisor) { /* * If they're setting up a custom divisor or speed, * instead of clearing it, then bitch about it.
*/ if (uport->flags & UPF_SPD_MASK) {
dev_notice_ratelimited(uport->dev, "%s sets custom speed on %s. This is deprecated.\n",
current->comm,
tty_name(port->tty));
}
uart_change_line_settings(tty, state, NULL);
}
return 0;
}
retval = uart_startup(tty, state, true); if (retval < 0) return retval; if (retval == 0)
tty_port_set_initialized(port, true);
down_write(&tty->termios_rwsem); /* * This semaphore protects port->count. It is also * very useful to prevent opens. Also, take the * port configuration semaphore to make sure that a * module insertion/removal doesn't change anything * under us.
*/
mutex_lock(&port->mutex);
retval = uart_set_info(tty, port, state, ss);
mutex_unlock(&port->mutex);
up_write(&tty->termios_rwsem); return retval;
}
/** * uart_get_lsr_info - get line status register info * @tty: tty associated with the UART * @state: UART being queried * @value: returned modem value
*/ staticint uart_get_lsr_info(struct tty_struct *tty, struct uart_state *state, unsignedint __user *value)
{ struct uart_port *uport = uart_port_check(state); unsignedint result;
result = uport->ops->tx_empty(uport);
/* * If we're about to load something into the transmit * register, we'll pretend the transmitter isn't empty to * avoid a race condition (depending on when the transmit * interrupt happens).
*/ if (uport->x_char ||
(!kfifo_is_empty(&state->port.xmit_fifo) &&
!uart_tx_stopped(uport)))
result &= ~TIOCSER_TEMT;
/* * Take the per-port semaphore. This prevents count from * changing, and hence any extra opens of the port while * we're auto-configuring.
*/
scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &port->mutex) {
uport = uart_port_check(state); if (!uport) return -EIO;
if (tty_port_users(port) != 1) return -EBUSY;
uart_shutdown(tty, state);
/* * If we already have a port type configured, * we must release its resources.
*/ if (uport->type != PORT_UNKNOWN && uport->ops->release_port)
uport->ops->release_port(uport);
flags = UART_CONFIG_TYPE; if (uport->flags & UPF_AUTO_IRQ)
flags |= UART_CONFIG_IRQ;
/* * This will claim the ports resources if * a port is found.
*/
uport->ops->config_port(uport, flags);
ret = uart_startup(tty, state, true); if (ret < 0) return ret; if (ret > 0) return 0;
tty_port_set_initialized(port, true);
}
return 0;
}
staticvoid uart_enable_ms(struct uart_port *uport)
{ /* * Force modem status interrupts on
*/ if (uport->ops->enable_ms)
uport->ops->enable_ms(uport);
}
/* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) * Caller should use TIOCGICOUNT to see which one it was * * FIXME: This wants extracting into a common all driver implementation * of TIOCMWAIT using tty_port.
*/ staticint uart_wait_modem_status(struct uart_state *state, unsignedlong arg)
{ struct uart_port *uport; struct tty_port *port = &state->port;
DECLARE_WAITQUEUE(wait, current); struct uart_icount cprev, cnow; int ret;
/* * note the counters on entry
*/
uport = uart_port_ref(state); if (!uport) return -EIO;
uart_port_lock_irq(uport);
memcpy(&cprev, &uport->icount, sizeof(struct uart_icount));
uart_enable_ms(uport);
uart_port_unlock_irq(uport);
/* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) * Return: write counters to the user passed counter struct * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted.
*/ staticint uart_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount)
{ struct uart_state *state = tty->driver_data; struct uart_icount cnow; struct uart_port *uport; unsignedlong flags;
/* * For any bit outside of the legacy ones that is not supported by * the driver, return -EINVAL.
*/ if (flags & ~port->rs485_supported.flags) return -EINVAL;
/* Asking for address w/o addressing mode? */ if (!(rs485->flags & SER_RS485_ADDRB) &&
(rs485->flags & (SER_RS485_ADDR_RECV|SER_RS485_ADDR_DEST))) return -EINVAL;
/* Address given but not enabled? */ if (!(rs485->flags & SER_RS485_ADDR_RECV) && rs485->addr_recv) return -EINVAL; if (!(rs485->flags & SER_RS485_ADDR_DEST) && rs485->addr_dest) return -EINVAL;
return 0;
}
staticvoid uart_sanitize_serial_rs485_delays(struct uart_port *port, struct serial_rs485 *rs485)
{ if (!port->rs485_supported.delay_rts_before_send) { if (rs485->delay_rts_before_send) {
dev_warn_ratelimited(port->dev, "%s (%u): RTS delay before sending not supported\n",
port->name, port->line);
}
rs485->delay_rts_before_send = 0;
} elseif (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev, "%s (%u): RTS delay before sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_before_send);
}
if (!port->rs485_supported.delay_rts_after_send) { if (rs485->delay_rts_after_send) {
dev_warn_ratelimited(port->dev, "%s (%u): RTS delay after sending not supported\n",
port->name, port->line);
}
rs485->delay_rts_after_send = 0;
} elseif (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) {
rs485->delay_rts_after_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev, "%s (%u): RTS delay after sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_after_send);
}
}
uart_port_lock_irqsave(port, &flags);
aux = port->iso7816;
uart_port_unlock_irqrestore(port, flags);
if (copy_to_user(iso7816, &aux, sizeof(aux))) return -EFAULT;
return 0;
}
staticint uart_set_iso7816_config(struct uart_port *port, struct serial_iso7816 __user *iso7816_user)
{ struct serial_iso7816 iso7816; int i, ret; unsignedlong flags;
if (!port->iso7816_config) return -ENOTTY;
if (copy_from_user(&iso7816, iso7816_user, sizeof(*iso7816_user))) return -EFAULT;
/* * There are 5 words reserved for future use. Check that userspace * doesn't put stuff in there to prevent breakages in the future.
*/ for (i = 0; i < ARRAY_SIZE(iso7816.reserved); i++) if (iso7816.reserved[i]) return -EINVAL;
uart_port_lock_irqsave(port, &flags);
ret = port->iso7816_config(port, &iso7816);
uart_port_unlock_irqrestore(port, flags); if (ret) return ret;
if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816))) return -EFAULT;
return 0;
}
/* * Called via sys_ioctl. We can use spin_lock_irq() here.
*/ staticint
uart_ioctl(struct tty_struct *tty, unsignedint cmd, unsignedlong arg)
{ struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; struct uart_port *uport; void __user *uarg = (void __user *)arg; int ret = -ENOIOCTLCMD;
/* * These ioctls don't rely on the hardware to be present.
*/ switch (cmd) { case TIOCSERCONFIG:
down_write(&tty->termios_rwsem);
ret = uart_do_autoconfig(tty, state);
up_write(&tty->termios_rwsem); break;
}
if (ret != -ENOIOCTLCMD) goto out;
if (tty_io_error(tty)) {
ret = -EIO; goto out;
}
/* * The following should only be used when hardware is present.
*/ switch (cmd) { case TIOCMIWAIT:
ret = uart_wait_modem_status(state, arg); break;
}
if (ret != -ENOIOCTLCMD) goto out;
/* rs485_config requires more locking than others */ if (cmd == TIOCSRS485)
down_write(&tty->termios_rwsem);
uport = uart_port_check(state); if (!uport) return;
/* * Drivers doing software flow control also need to know * about changes to these input settings.
*/ if (uport->flags & UPF_SOFT_FLOW) {
iflag_mask |= IXANY|IXON|IXOFF;
sw_changed =
tty->termios.c_cc[VSTART] != old_termios->c_cc[VSTART] ||
tty->termios.c_cc[VSTOP] != old_termios->c_cc[VSTOP];
}
/* * These are the bits that are used to setup various * flags in the low level driver. We can ignore the Bfoo * bits in c_cflag; c_[io]speed will always be set * appropriately by set_termios() in tty_ioctl.c
*/ if ((cflag ^ old_termios->c_cflag) == 0 &&
tty->termios.c_ospeed == old_termios->c_ospeed &&
tty->termios.c_ispeed == old_termios->c_ispeed &&
((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
!sw_changed) return;
uart_change_line_settings(tty, state, old_termios); /* reload cflag from termios; port driver may have overridden flags */
cflag = tty->termios.c_cflag;
/* Handle transition to B0 status */ if (((old_termios->c_cflag & CBAUD) != B0) && ((cflag & CBAUD) == B0))
uart_clear_mctrl(uport, TIOCM_RTS | TIOCM_DTR); /* Handle transition away from B0 status */ elseif (((old_termios->c_cflag & CBAUD) == B0) && ((cflag & CBAUD) != B0)) { unsignedint mask = TIOCM_DTR;
/* * At this point, we stop accepting input. To do this, we * disable the receive line status interrupts.
*/ if (WARN(!uport, "detached port still initialized!\n")) return;
/* * It's possible for shutdown to be called after suspend if we get * a DCD drop (hangup) at just the right time. Clear suspended bit so * we don't try to resume a port that has been shutdown.
*/
tty_port_set_suspended(port, false);
/* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check * interval should also be less than the timeout. * * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS.
*/
char_time = max(nsecs_to_jiffies(port->frame_time / 5), 1UL);
if (timeout && timeout < char_time)
char_time = timeout;
if (!uart_cts_enabled(port)) { /* * If the transmitter hasn't cleared in twice the approximate * amount of time to send the entire FIFO, it probably won't * ever clear. This assumes the UART isn't doing flow * control, which is currently the case. Hence, if it ever * takes longer than FIFO timeout, this is probably due to a * UART bug of some kind. So, we clamp the timeout parameter at * 2 * FIFO timeout.
*/
fifo_timeout = uart_fifo_timeout(port); if (timeout == 0 || timeout > 2 * fifo_timeout)
timeout = 2 * fifo_timeout;
}
/* * Check whether the transmitter is empty every 'char_time'. * 'timeout' / 'expire' give us the maximum amount of time * we wait.
*/ while (!port->ops->tx_empty(port)) {
msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (timeout && time_after(jiffies, expire)) break;
}
uart_port_deref(port);
}
/* * Calls to uart_hangup() are serialised by the tty_lock in * drivers/tty/tty_io.c:do_tty_hangup() * This runs from a workqueue and can sleep for a _short_ time only.
*/ staticvoid uart_hangup(struct tty_struct *tty)
{ struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; struct uart_port *uport; unsignedlong flags;
pr_debug("uart_hangup(%d)\n", tty->index);
mutex_lock(&port->mutex);
uport = uart_port_check(state);
WARN(!uport, "hangup of detached port!\n");
/* uport == NULL if uart_port has already been removed */ staticvoid uart_port_shutdown(struct tty_port *port)
{ struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport = uart_port_check(state);
/* * clear delta_msr_wait queue to avoid mem leaks: we may free * the irq here so the queue might never be woken up. Note * that we won't end up waiting on delta_msr_wait again since * any outstanding file descriptors should be pointing at * hung_up_tty_fops now.
*/
wake_up_interruptible(&port->delta_msr_wait);
if (uport) { /* Free the IRQ and disable the port. */
uport->ops->shutdown(uport);
/* Ensure that the IRQ handler isn't running on another CPU. */
synchronize_irq(uport->irq);
}
}
uport = uart_port_ref_lock(state, &flags); /* * Should never observe uport == NULL since checks for hangup should * abort the tty_port_block_til_ready() loop before checking for carrier * raised -- but report carrier raised if it does anyway so open will * continue and not sleep
*/ if (WARN_ON(!uport)) returntrue;
uart_enable_ms(uport);
mctrl = uport->ops->get_mctrl(uport);
uart_port_unlock_deref(uport, flags);
/* * Calls to uart_open are serialised by the tty_lock in * drivers/tty/tty_io.c:tty_open() * Note that if this fails, then uart_close() _will_ be called. * * In time, we want to scrap the "opening nonpresent ports" * behaviour and implement an alternative way for setserial * to set base addresses/ports/types. This will allow us to * get rid of a certain amount of extra tests.
*/ staticint uart_open(struct tty_struct *tty, struct file *filp)
{ struct uart_state *state = tty->driver_data; int retval;
#ifdefined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) /** * uart_console_write - write a console message to a serial port * @port: the port to write the message * @s: array of characters * @count: number of characters in string to write * @putchar: function to write character to port
*/ void uart_console_write(struct uart_port *port, constchar *s, unsignedint count, void (*putchar)(struct uart_port *, unsignedchar))
{ unsignedint i;
for (i = 0; i < count; i++, s++) { if (*s == '\n')
putchar(port, '\r');
putchar(port, *s);
}
}
EXPORT_SYMBOL_GPL(uart_console_write);
/** * uart_parse_earlycon - Parse earlycon options * @p: ptr to 2nd field (ie., just beyond '<name>,') * @iotype: ptr for decoded iotype (out) * @addr: ptr for decoded mapbase/iobase (out) * @options: ptr for <options> field; %NULL if not present (out) * * Decodes earlycon kernel command line parameters of the form: * * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options> * * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options> * * The optional form: * * earlycon=<name>,0x<addr>,<options> * * console=<name>,0x<addr>,<options> * * is also accepted; the returned @iotype will be %UPIO_MEM. * * Returns: 0 on success or -%EINVAL on failure
*/ int uart_parse_earlycon(char *p, enum uart_iotype *iotype,
resource_size_t *addr, char **options)
{ if (strncmp(p, "mmio,", 5) == 0) {
*iotype = UPIO_MEM;
p += 5;
} elseif (strncmp(p, "mmio16,", 7) == 0) {
*iotype = UPIO_MEM16;
p += 7;
} elseif (strncmp(p, "mmio32,", 7) == 0) {
*iotype = UPIO_MEM32;
p += 7;
} elseif (strncmp(p, "mmio32be,", 9) == 0) {
*iotype = UPIO_MEM32BE;
p += 9;
} elseif (strncmp(p, "mmio32native,", 13) == 0) {
*iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ?
UPIO_MEM32BE : UPIO_MEM32;
p += 13;
} elseif (strncmp(p, "io,", 3) == 0) {
*iotype = UPIO_PORT;
p += 3;
} elseif (strncmp(p, "0x", 2) == 0) {
*iotype = UPIO_MEM;
} else { return -EINVAL;
}
/* * Before you replace it with kstrtoull(), think about options separator * (',') it will not tolerate
*/
*addr = simple_strtoull(p, NULL, 0);
p = strchr(p, ','); if (p)
p++;
/** * uart_parse_options - Parse serial port baud/parity/bits/flow control. * @options: pointer to option string * @baud: pointer to an 'int' variable for the baud rate. * @parity: pointer to an 'int' variable for the parity. * @bits: pointer to an 'int' variable for the number of data bits. * @flow: pointer to an 'int' variable for the flow control character. * * uart_parse_options() decodes a string containing the serial console * options. The format of the string is <baud><parity><bits><flow>, * eg: 115200n8r
*/ void
uart_parse_options(constchar *options, int *baud, int *parity, int *bits, int *flow)
{ constchar *s = options;
*baud = simple_strtoul(s, NULL, 10); while (*s >= '0' && *s <= '9')
s++; if (*s)
*parity = *s++; if (*s)
*bits = *s++ - '0'; if (*s)
*flow = *s;
}
EXPORT_SYMBOL_GPL(uart_parse_options);
/** * uart_set_options - setup the serial console parameters * @port: pointer to the serial ports uart_port structure * @co: console pointer * @baud: baud rate * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) * @bits: number of data bits * @flow: flow control character - 'r' (rts) * * Locking: Caller must hold console_list_lock in order to serialize * early initialization of the serial-console lock.
*/ int
uart_set_options(struct uart_port *port, struct console *co, int baud, int parity, int bits, int flow)
{ struct ktermios termios; staticstruct ktermios dummy;
/* * Ensure that the serial-console lock is initialised early. * * Note that the console-registered check is needed because * kgdboc can call uart_set_options() for an already registered * console via tty_find_polling_driver() and uart_poll_init().
*/ if (!uart_console_registered_locked(port) && !port->console_reinit)
uart_port_spin_lock_init(port);
/** * uart_change_pm - set power state of the port * * @state: port descriptor * @pm_state: new state * * Locking: port->mutex has to be held
*/ staticvoid uart_change_pm(struct uart_state *state, enum uart_pm_state pm_state)
{ struct uart_port *port = uart_port_check(state);
if (state->pm_state != pm_state) { if (port && port->ops->pm)
port->ops->pm(port, pm_state, state->pm_state);
state->pm_state = pm_state;
}
}
/* * Nothing to do if the console is not suspending * except stop_rx to prevent any asynchronous data * over RX line. However ensure that we will be * able to Re-start_rx later.
*/ if (!console_suspend_enabled && uart_console(uport)) { if (uport->ops->start_rx) {
uart_port_lock_irq(uport);
uport->ops->stop_rx(uport);
uart_port_unlock_irq(uport);
}
device_set_awake_path(uport->dev); return 0;
}
uport->suspended = 1;
if (tty_port_initialized(port)) { conststruct uart_ops *ops = uport->ops; int tries; unsignedint mctrl;
uart_port_lock_irq(uport);
ops->stop_tx(uport); if (!(uport->rs485.flags & SER_RS485_ENABLED))
ops->set_mctrl(uport, 0); /* save mctrl so it can be restored on resume */
mctrl = uport->mctrl;
uport->mctrl = 0;
ops->stop_rx(uport);
uart_port_unlock_irq(uport);
/* * Wait for the transmitter to empty.
*/ for (tries = 3; !ops->tx_empty(uport) && tries; tries--)
msleep(10); if (!tries)
dev_err(uport->dev, "%s: Unable to drain transmitter\n",
uport->name);
ops->shutdown(uport);
uport->mctrl = mctrl;
}
/* * Suspend the console device before suspending the port.
*/ if (uart_console(uport))
console_suspend(uport->cons);
/* * Re-enable the console device after suspending.
*/ if (uart_console(uport)) { /* * First try to use the console cflag setting.
*/
memset(&termios, 0, sizeof(struct ktermios));
termios.c_cflag = uport->cons->cflag;
termios.c_ispeed = uport->cons->ispeed;
termios.c_ospeed = uport->cons->ospeed;
/* * If that's unset, use the tty termios setting.
*/ if (port->tty && termios.c_cflag == 0)
termios = port->tty->termios;
if (console_suspend_enabled)
uart_change_pm(state, UART_PM_STATE_ON);
uport->ops->set_termios(uport, &termios, NULL); if (!console_suspend_enabled && uport->ops->start_rx) {
uart_port_lock_irq(uport);
uport->ops->start_rx(uport);
uart_port_unlock_irq(uport);
} if (console_suspend_enabled)
console_resume(uport->cons);
}
if (tty_port_suspended(port)) { conststruct uart_ops *ops = uport->ops; int ret;
uart_change_pm(state, UART_PM_STATE_ON);
uart_port_lock_irq(uport); if (!(uport->rs485.flags & SER_RS485_ENABLED))
ops->set_mctrl(uport, 0);
uart_port_unlock_irq(uport); if (console_suspend_enabled || !uart_console(uport)) { /* Protected by port mutex for now */ struct tty_struct *tty = port->tty;
ret = ops->startup(uport); if (ret == 0) { if (tty)
uart_change_line_settings(tty, state, NULL);
uart_rs485_config(uport);
uart_port_lock_irq(uport); if (!(uport->rs485.flags & SER_RS485_ENABLED))
ops->set_mctrl(uport, uport->mctrl);
ops->start_tx(uport);
uart_port_unlock_irq(uport);
tty_port_set_initialized(port, true);
} else { /* * Failed to resume - maybe hardware went away? * Clear the "initialized" flag so we won't try * to call the low level drivers shutdown method.
*/
uart_shutdown(tty, state);
}
}
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.