From 1c055e55a242a33e574e48be530e06770a210dcd Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 19 Feb 2024 03:26:26 +0000 Subject: [PATCH] add r8169 read mac form eeprom --- kernel/drivers/tty/serial/serial_core.c | 467 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 files changed, 346 insertions(+), 121 deletions(-) diff --git a/kernel/drivers/tty/serial/serial_core.c b/kernel/drivers/tty/serial/serial_core.c index fc1c7d5..76cdf3f 100644 --- a/kernel/drivers/tty/serial/serial_core.c +++ b/kernel/drivers/tty/serial/serial_core.c @@ -14,14 +14,17 @@ #include <linux/sched/signal.h> #include <linux/init.h> #include <linux/console.h> +#include <linux/gpio/consumer.h> #include <linux/of.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/device.h> #include <linux/serial.h> /* for serial_state and serial_icounter_struct */ #include <linux/serial_core.h> +#include <linux/sysrq.h> #include <linux/delay.h> #include <linux/mutex.h> +#include <linux/security.h> #include <linux/irq.h> #include <linux/uaccess.h> @@ -38,6 +41,11 @@ static struct lock_class_key port_lock_key; #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) + +/* + * Max time with active RTS before/after data is sent. + */ +#define RS485_MAX_RTS_DELAY 100 /* msecs */ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state, struct ktermios *old_termios); @@ -144,7 +152,7 @@ spin_lock_irqsave(&port->lock, flags); old = port->mctrl; port->mctrl = (old & ~clear) | set; - if (old != port->mctrl) + if (old != port->mctrl && !(port->rs485.flags & SER_RS485_ENABLED)) port->ops->set_mctrl(port, port->mctrl); spin_unlock_irqrestore(&port->lock, flags); } @@ -154,23 +162,10 @@ static void uart_port_dtr_rts(struct uart_port *uport, int raise) { - int rs485_on = uport->rs485_config && - (uport->rs485.flags & SER_RS485_ENABLED); - int RTS_after_send = !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND); - - if (raise) { - if (rs485_on && RTS_after_send) { - uart_set_mctrl(uport, TIOCM_DTR); - uart_clear_mctrl(uport, TIOCM_RTS); - } else { - uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); - } - } else { - unsigned int clear = TIOCM_DTR; - - clear |= (!rs485_on || RTS_after_send) ? TIOCM_RTS : 0; - uart_clear_mctrl(uport, clear); - } + if (raise) + uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); + else + uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); } /* @@ -667,6 +662,20 @@ } /* + * 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 */ @@ -792,17 +801,13 @@ return ret; } -static int uart_get_info_user(struct tty_port *port, - struct serial_struct __user *retinfo) +static int uart_get_info_user(struct tty_struct *tty, + struct serial_struct *ss) { - struct serial_struct tmp; + struct uart_state *state = tty->driver_data; + struct tty_port *port = &state->port; - if (uart_get_info(port, &tmp) < 0) - return -EIO; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; + return uart_get_info(port, ss) < 0 ? -EIO : 0; } static int uart_set_info(struct tty_struct *tty, struct tty_port *port, @@ -864,6 +869,12 @@ (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) + goto exit; } /* @@ -1004,16 +1015,13 @@ return retval; } -static int uart_set_info_user(struct tty_struct *tty, struct uart_state *state, - struct serial_struct __user *newinfo) +static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss) { - struct serial_struct new_serial; + struct uart_state *state = tty->driver_data; struct tty_port *port = &state->port; int retval; - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - + down_write(&tty->termios_rwsem); /* * This semaphore protects port->count. It is also * very useful to prevent opens. Also, take the @@ -1022,8 +1030,9 @@ * under us. */ mutex_lock(&port->mutex); - retval = uart_set_info(tty, port, state, &new_serial); + retval = uart_set_info(tty, port, state, ss); mutex_unlock(&port->mutex); + up_write(&tty->termios_rwsem); return retval; } @@ -1120,7 +1129,7 @@ return ret; } -static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) +static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state) { struct tty_port *port = &state->port; struct uart_port *uport; @@ -1305,18 +1314,103 @@ unsigned long flags; if (!port->rs485_config) - return -ENOIOCTLCMD; + return -ENOTTY; if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user))) return -EFAULT; + /* pick sane settings if the user hasn't */ + if (!(rs485.flags & SER_RS485_RTS_ON_SEND) == + !(rs485.flags & SER_RS485_RTS_AFTER_SEND)) { + dev_warn_ratelimited(port->dev, + "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n", + port->name, port->line); + rs485.flags |= SER_RS485_RTS_ON_SEND; + rs485.flags &= ~SER_RS485_RTS_AFTER_SEND; + } + + if (rs485.delay_rts_before_send > RS485_MAX_RTS_DELAY) { + rs485.delay_rts_before_send = RS485_MAX_RTS_DELAY; + dev_warn_ratelimited(port->dev, + "%s (%d): RTS delay before sending clamped to %u ms\n", + port->name, port->line, rs485.delay_rts_before_send); + } + + if (rs485.delay_rts_after_send > RS485_MAX_RTS_DELAY) { + rs485.delay_rts_after_send = RS485_MAX_RTS_DELAY; + dev_warn_ratelimited(port->dev, + "%s (%d): RTS delay after sending clamped to %u ms\n", + port->name, port->line, rs485.delay_rts_after_send); + } + /* Return clean padding area to userspace */ + memset(rs485.padding, 0, sizeof(rs485.padding)); + spin_lock_irqsave(&port->lock, flags); ret = port->rs485_config(port, &rs485); + if (!ret) { + port->rs485 = rs485; + + /* Reset RTS and other mctrl lines when disabling RS485 */ + if (!(rs485.flags & SER_RS485_ENABLED)) + port->ops->set_mctrl(port, port->mctrl); + } spin_unlock_irqrestore(&port->lock, flags); if (ret) return ret; if (copy_to_user(rs485_user, &port->rs485, sizeof(port->rs485))) + return -EFAULT; + + return 0; +} + +static int uart_get_iso7816_config(struct uart_port *port, + struct serial_iso7816 __user *iso7816) +{ + unsigned long flags; + struct serial_iso7816 aux; + + if (!port->iso7816_config) + return -ENOTTY; + + spin_lock_irqsave(&port->lock, flags); + aux = port->iso7816; + spin_unlock_irqrestore(&port->lock, flags); + + if (copy_to_user(iso7816, &aux, sizeof(aux))) + return -EFAULT; + + return 0; +} + +static int uart_set_iso7816_config(struct uart_port *port, + struct serial_iso7816 __user *iso7816_user) +{ + struct serial_iso7816 iso7816; + int i, ret; + unsigned long 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 < 5; i++) + if (iso7816.reserved[i]) + return -EINVAL; + + spin_lock_irqsave(&port->lock, flags); + ret = port->iso7816_config(port, &iso7816); + spin_unlock_irqrestore(&port->lock, flags); + if (ret) + return ret; + + if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816))) return -EFAULT; return 0; @@ -1339,25 +1433,10 @@ * These ioctls don't rely on the hardware to be present. */ switch (cmd) { - case TIOCGSERIAL: - ret = uart_get_info_user(port, uarg); - break; - - case TIOCSSERIAL: - down_write(&tty->termios_rwsem); - ret = uart_set_info_user(tty, state, uarg); - up_write(&tty->termios_rwsem); - break; - case TIOCSERCONFIG: down_write(&tty->termios_rwsem); ret = uart_do_autoconfig(tty, state); up_write(&tty->termios_rwsem); - break; - - case TIOCSERGWILD: /* obsolete */ - case TIOCSERSWILD: /* obsolete */ - ret = 0; break; } @@ -1405,6 +1484,14 @@ case TIOCSRS485: ret = uart_set_rs485_config(uport, uarg); + break; + + case TIOCSISO7816: + ret = uart_set_iso7816_config(state->uart_port, uarg); + break; + + case TIOCGISO7816: + ret = uart_get_iso7816_config(state->uart_port, uarg); break; default: if (uport->ops->ioctl) @@ -1473,7 +1560,7 @@ } uart_change_speed(tty, state, old_termios); - /* reload cflag from termios; port driver may have overriden flags */ + /* reload cflag from termios; port driver may have overridden flags */ cflag = tty->termios.c_cflag; /* Handle transition to B0 status */ @@ -1482,6 +1569,7 @@ /* Handle transition away from B0 status */ else if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { unsigned int mask = TIOCM_DTR; + if (!(cflag & CRTSCTS) || !tty_throttled(tty)) mask |= TIOCM_RTS; uart_set_mctrl(uport, mask); @@ -1879,6 +1967,12 @@ } #endif +static void uart_port_spin_lock_init(struct uart_port *port) +{ + spin_lock_init(&port->lock); + lockdep_set_class(&port->lock, &port_lock_key); +} + #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) /** * uart_console_write - write a console message to a serial port @@ -1935,8 +2029,10 @@ * 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 @@ -2030,15 +2126,14 @@ static struct ktermios dummy; /* - * Ensure that the serial console lock is initialised - * early. - * If this port is a console, then the spinlock is already - * initialised. + * Ensure that the serial-console lock is initialised early. + * + * Note that the console-enabled check is needed because of kgdboc, + * which can end up calling uart_set_options() for an already enabled + * console via tty_find_polling_driver() and uart_poll_init(). */ - if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) { - spin_lock_init(&port->lock); - lockdep_set_class(&port->lock, &port_lock_key); - } + if (!uart_console_enabled(port) && !port->console_reinit) + uart_port_spin_lock_init(port); memset(&termios, 0, sizeof(struct ktermios)); @@ -2053,7 +2148,7 @@ switch (parity) { case 'o': case 'O': termios.c_cflag |= PARODD; - /*fall through*/ + fallthrough; case 'e': case 'E': termios.c_cflag |= PARENB; break; @@ -2149,7 +2244,8 @@ spin_lock_irq(&uport->lock); ops->stop_tx(uport); - ops->set_mctrl(uport, 0); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, 0); ops->stop_rx(uport); spin_unlock_irq(&uport->lock); @@ -2228,17 +2324,22 @@ uart_change_pm(state, UART_PM_STATE_ON); spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, 0); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, 0); spin_unlock_irq(&uport->lock); 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_speed(tty, state, NULL); spin_lock_irq(&uport->lock); - ops->set_mctrl(uport, uport->mctrl); + if (!(uport->rs485.flags & SER_RS485_ENABLED)) + ops->set_mctrl(uport, uport->mctrl); + else + uport->rs485_config(uport, &uport->rs485); ops->start_tx(uport); spin_unlock_irq(&uport->lock); tty_port_set_initialized(port, 1); @@ -2336,7 +2437,10 @@ */ spin_lock_irqsave(&port->lock, flags); port->mctrl &= TIOCM_DTR; - port->ops->set_mctrl(port, port->mctrl); + if (!(port->rs485.flags & SER_RS485_ENABLED)) + port->ops->set_mctrl(port, port->mctrl); + else + port->rs485_config(port, &port->rs485); spin_unlock_irqrestore(&port->lock, flags); /* @@ -2456,6 +2560,8 @@ #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, + .set_serial = uart_set_info_user, + .get_serial = uart_get_info_user, .get_icount = uart_get_icount, #ifdef CONFIG_CONSOLE_POLL .poll_init = uart_poll_init, @@ -2487,7 +2593,7 @@ int uart_register_driver(struct uart_driver *drv) { struct tty_driver *normal; - int i, retval; + int i, retval = -ENOMEM; BUG_ON(drv->state); @@ -2539,7 +2645,7 @@ out_kfree: kfree(drv->state); out: - return -ENOMEM; + return retval; } /** @@ -2573,36 +2679,37 @@ } EXPORT_SYMBOL_GPL(uart_console_device); -static ssize_t uart_get_attr_uartclk(struct device *dev, +static ssize_t uartclk_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.baud_base * 16); + return sprintf(buf, "%d\n", tmp.baud_base * 16); } -static ssize_t uart_get_attr_type(struct device *dev, +static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.type); + return sprintf(buf, "%d\n", tmp.type); } -static ssize_t uart_get_attr_line(struct device *dev, + +static ssize_t line_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.line); + return sprintf(buf, "%d\n", tmp.line); } -static ssize_t uart_get_attr_port(struct device *dev, +static ssize_t port_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; @@ -2613,135 +2720,187 @@ ioaddr = tmp.port; if (HIGH_BITS_OFFSET) ioaddr |= (unsigned long)tmp.port_high << HIGH_BITS_OFFSET; - return snprintf(buf, PAGE_SIZE, "0x%lX\n", ioaddr); + return sprintf(buf, "0x%lX\n", ioaddr); } -static ssize_t uart_get_attr_irq(struct device *dev, +static ssize_t irq_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.irq); + return sprintf(buf, "%d\n", tmp.irq); } -static ssize_t uart_get_attr_flags(struct device *dev, +static ssize_t flags_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "0x%X\n", tmp.flags); + return sprintf(buf, "0x%X\n", tmp.flags); } -static ssize_t uart_get_attr_xmit_fifo_size(struct device *dev, +static ssize_t xmit_fifo_size_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.xmit_fifo_size); + return sprintf(buf, "%d\n", tmp.xmit_fifo_size); } - -static ssize_t uart_get_attr_close_delay(struct device *dev, +static ssize_t close_delay_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.close_delay); + return sprintf(buf, "%d\n", tmp.close_delay); } - -static ssize_t uart_get_attr_closing_wait(struct device *dev, +static ssize_t closing_wait_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.closing_wait); + return sprintf(buf, "%d\n", tmp.closing_wait); } -static ssize_t uart_get_attr_custom_divisor(struct device *dev, +static ssize_t custom_divisor_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.custom_divisor); + return sprintf(buf, "%d\n", tmp.custom_divisor); } -static ssize_t uart_get_attr_io_type(struct device *dev, +static ssize_t io_type_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.io_type); + return sprintf(buf, "%d\n", tmp.io_type); } -static ssize_t uart_get_attr_iomem_base(struct device *dev, +static ssize_t iomem_base_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "0x%lX\n", (unsigned long)tmp.iomem_base); + return sprintf(buf, "0x%lX\n", (unsigned long)tmp.iomem_base); } -static ssize_t uart_get_attr_iomem_reg_shift(struct device *dev, +static ssize_t iomem_reg_shift_show(struct device *dev, struct device_attribute *attr, char *buf) { struct serial_struct tmp; struct tty_port *port = dev_get_drvdata(dev); uart_get_info(port, &tmp); - return snprintf(buf, PAGE_SIZE, "%d\n", tmp.iomem_reg_shift); + return sprintf(buf, "%d\n", tmp.iomem_reg_shift); } -static DEVICE_ATTR(type, S_IRUSR | S_IRGRP, uart_get_attr_type, NULL); -static DEVICE_ATTR(line, S_IRUSR | S_IRGRP, uart_get_attr_line, NULL); -static DEVICE_ATTR(port, S_IRUSR | S_IRGRP, uart_get_attr_port, NULL); -static DEVICE_ATTR(irq, S_IRUSR | S_IRGRP, uart_get_attr_irq, NULL); -static DEVICE_ATTR(flags, S_IRUSR | S_IRGRP, uart_get_attr_flags, NULL); -static DEVICE_ATTR(xmit_fifo_size, S_IRUSR | S_IRGRP, uart_get_attr_xmit_fifo_size, NULL); -static DEVICE_ATTR(uartclk, S_IRUSR | S_IRGRP, uart_get_attr_uartclk, NULL); -static DEVICE_ATTR(close_delay, S_IRUSR | S_IRGRP, uart_get_attr_close_delay, NULL); -static DEVICE_ATTR(closing_wait, S_IRUSR | S_IRGRP, uart_get_attr_closing_wait, NULL); -static DEVICE_ATTR(custom_divisor, S_IRUSR | S_IRGRP, uart_get_attr_custom_divisor, NULL); -static DEVICE_ATTR(io_type, S_IRUSR | S_IRGRP, uart_get_attr_io_type, NULL); -static DEVICE_ATTR(iomem_base, S_IRUSR | S_IRGRP, uart_get_attr_iomem_base, NULL); -static DEVICE_ATTR(iomem_reg_shift, S_IRUSR | S_IRGRP, uart_get_attr_iomem_reg_shift, NULL); +static ssize_t console_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport; + bool console = false; + + mutex_lock(&port->mutex); + uport = uart_port_check(state); + if (uport) + console = uart_console_enabled(uport); + mutex_unlock(&port->mutex); + + return sprintf(buf, "%c\n", console ? 'Y' : 'N'); +} + +static ssize_t console_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tty_port *port = dev_get_drvdata(dev); + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport; + bool oldconsole, newconsole; + int ret; + + ret = kstrtobool(buf, &newconsole); + if (ret) + return ret; + + mutex_lock(&port->mutex); + uport = uart_port_check(state); + if (uport) { + oldconsole = uart_console_enabled(uport); + if (oldconsole && !newconsole) { + ret = unregister_console(uport->cons); + } else if (!oldconsole && newconsole) { + if (uart_console(uport)) { + uport->console_reinit = 1; + register_console(uport->cons); + } else { + ret = -ENOENT; + } + } + } else { + ret = -ENXIO; + } + mutex_unlock(&port->mutex); + + return ret < 0 ? ret : count; +} + +static DEVICE_ATTR_RO(uartclk); +static DEVICE_ATTR_RO(type); +static DEVICE_ATTR_RO(line); +static DEVICE_ATTR_RO(port); +static DEVICE_ATTR_RO(irq); +static DEVICE_ATTR_RO(flags); +static DEVICE_ATTR_RO(xmit_fifo_size); +static DEVICE_ATTR_RO(close_delay); +static DEVICE_ATTR_RO(closing_wait); +static DEVICE_ATTR_RO(custom_divisor); +static DEVICE_ATTR_RO(io_type); +static DEVICE_ATTR_RO(iomem_base); +static DEVICE_ATTR_RO(iomem_reg_shift); +static DEVICE_ATTR_RW(console); static struct attribute *tty_dev_attrs[] = { + &dev_attr_uartclk.attr, &dev_attr_type.attr, &dev_attr_line.attr, &dev_attr_port.attr, &dev_attr_irq.attr, &dev_attr_flags.attr, &dev_attr_xmit_fifo_size.attr, - &dev_attr_uartclk.attr, &dev_attr_close_delay.attr, &dev_attr_closing_wait.attr, &dev_attr_custom_divisor.attr, &dev_attr_io_type.attr, &dev_attr_iomem_base.attr, &dev_attr_iomem_reg_shift.attr, - NULL, - }; + &dev_attr_console.attr, + NULL +}; static const struct attribute_group tty_dev_attr_group = { .attrs = tty_dev_attrs, - }; +}; /** * uart_add_one_port - attach a driver-defined port structure @@ -2793,13 +2952,12 @@ } /* - * If this port is a console, then the spinlock is already + * If this port is in use as a console then the spinlock is already * initialised. */ - if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) { - spin_lock_init(&uport->lock); - lockdep_set_class(&uport->lock, &port_lock_key); - } + if (!uart_console_enabled(uport)) + uart_port_spin_lock_init(uport); + if (uport->cons && uport->dev) of_console_check(uport->dev->of_node, uport->cons->name, uport->line); @@ -2828,7 +2986,7 @@ */ tty_dev = tty_port_register_device_attr_serdev(port, drv->tty_driver, uport->line, uport->dev, port, uport->tty_groups); - if (likely(!IS_ERR(tty_dev))) { + if (!IS_ERR(tty_dev)) { device_set_wakeup_capable(tty_dev, 1); } else { dev_err(uport->dev, "Cannot register tty device on line %d\n", @@ -3050,6 +3208,56 @@ } EXPORT_SYMBOL_GPL(uart_insert_char); +#ifdef CONFIG_MAGIC_SYSRQ_SERIAL +static const char sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE; + +static void uart_sysrq_on(struct work_struct *w) +{ + int sysrq_toggle_seq_len = strlen(sysrq_toggle_seq); + + sysrq_toggle_support(1); + pr_info("SysRq is enabled by magic sequence '%*pE' on serial\n", + sysrq_toggle_seq_len, sysrq_toggle_seq); +} +static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on); + +/** + * uart_try_toggle_sysrq - Enables SysRq from serial line + * @port: uart_port structure where char(s) after BREAK met + * @ch: new character in the sequence after received BREAK + * + * Enables magic SysRq when the required sequence is met on port + * (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE). + * + * Returns false if @ch is out of enabling sequence and should be + * handled some other way, true if @ch was consumed. + */ +bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch) +{ + int sysrq_toggle_seq_len = strlen(sysrq_toggle_seq); + + if (!sysrq_toggle_seq_len) + return false; + + BUILD_BUG_ON(ARRAY_SIZE(sysrq_toggle_seq) >= U8_MAX); + if (sysrq_toggle_seq[port->sysrq_seq] != ch) { + port->sysrq_seq = 0; + return false; + } + + if (++port->sysrq_seq < sysrq_toggle_seq_len) { + port->sysrq = jiffies + SYSRQ_TIMEOUT; + return true; + } + + schedule_work(&sysrq_enable_work); + + port->sysrq = 0; + return true; +} +EXPORT_SYMBOL_GPL(uart_try_toggle_sysrq); +#endif + EXPORT_SYMBOL(uart_write_wakeup); EXPORT_SYMBOL(uart_register_driver); EXPORT_SYMBOL(uart_unregister_driver); @@ -3060,14 +3268,15 @@ /** * uart_get_rs485_mode() - retrieve rs485 properties for given uart - * @dev: uart device - * @rs485conf: output parameter + * @port: uart device's target port * * This function implements the device tree binding described in * Documentation/devicetree/bindings/serial/rs485.txt. */ -void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf) +int uart_get_rs485_mode(struct uart_port *port) { + struct serial_rs485 *rs485conf = &port->rs485; + struct device *dev = port->dev; u32 rs485_delay[2]; int ret; @@ -3086,6 +3295,7 @@ * to get to a defined state with the following properties: */ rs485conf->flags &= ~(SER_RS485_RX_DURING_TX | SER_RS485_ENABLED | + SER_RS485_TERMINATE_BUS | SER_RS485_RTS_AFTER_SEND); rs485conf->flags |= SER_RS485_RTS_ON_SEND; @@ -3099,6 +3309,21 @@ rs485conf->flags &= ~SER_RS485_RTS_ON_SEND; rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; } + + /* + * Disabling termination by default is the safe choice: Else if many + * bus participants enable it, no communication is possible at all. + * Works fine for short cables and users may enable for longer cables. + */ + port->rs485_term_gpio = devm_gpiod_get_optional(dev, "rs485-term", + GPIOD_OUT_LOW); + if (IS_ERR(port->rs485_term_gpio)) { + ret = PTR_ERR(port->rs485_term_gpio); + port->rs485_term_gpio = NULL; + return dev_err_probe(dev, ret, "Cannot get rs485-term-gpios\n"); + } + + return 0; } EXPORT_SYMBOL_GPL(uart_get_rs485_mode); -- Gitblit v1.6.2