--- zzzz-none-000/linux-4.9.279/drivers/tty/serial/serial_core.c 2021-08-08 06:38:54.000000000 +0000 +++ puma7-atom-6591-750/linux-4.9.279/drivers/tty/serial/serial_core.c 2023-02-08 11:43:42.000000000 +0000 @@ -34,10 +34,15 @@ #include #include #include +#include #include #include +#ifdef CONFIG_INTEL_UART_ENABLE_CONTROL +#include +#endif + /* * This is used to lock changes in serial line configuration. */ @@ -131,6 +136,9 @@ struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; + if (port->ops->wake_peer) + port->ops->wake_peer(port); + if (port && !uart_tx_stopped(port)) port->ops->start_tx(port); } @@ -2021,7 +2029,8 @@ * If this port is a console, then the spinlock is already * initialised. */ - if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) { + if (!((uart_console(port) && (port->cons->flags & CON_ENABLED)) || + (port->flags & UPF_AVM_POLLING))) { spin_lock_init(&port->lock); lockdep_set_class(&port->lock, &port_lock_key); } @@ -2416,7 +2425,7 @@ if (!port) return; - if (ch == '\n') + if (ch == '\n' && !(port->flags & UPF_AVM_POLLING)) port->ops->poll_put_char(port, '\r'); port->ops->poll_put_char(port, ch); uart_port_deref(port); @@ -2474,6 +2483,188 @@ .shutdown = uart_tty_port_shutdown, }; +#ifdef CONFIG_AVM_TTY_POLLING +struct polling_tty_port { + struct tty_driver *driver; + int line; +}; + +struct polling_tty_port *avm_tty_poll_acquire(const char *ttyname) +{ + struct polling_tty_port *pport; + struct tty_driver *ttydrv; + struct uart_driver *drv; + struct uart_state *state; + struct uart_port *uport; + struct tty_port *port; + int line, err; + char name[40]; + + pr_debug("Acquiring polling tty port %s\n", ttyname); + + strlcpy(name, ttyname, sizeof(name)); + ttydrv = tty_find_polling_driver(name, &line); + if (!ttydrv) { + err = -ENODEV; + goto err_out; + } + + drv = ttydrv->driver_state; + state = drv->state + line; + if (!state) + goto noport; + port = &state->port; + + mutex_lock(&port->mutex); + + uport = uart_port_check(state); + if (!uport) { + mutex_unlock(&port->mutex); + goto noport; + } + + pport = kmalloc(sizeof(*pport), GFP_KERNEL); + if (!pport) { + err = -ENOMEM; + mutex_unlock(&port->mutex); + goto put_driver; + } + + if (uport->irq) + disable_irq(uport->irq); + pm_runtime_get_sync(uport->dev); + uport->flags |= UPF_AVM_POLLING; + + mutex_unlock(&port->mutex); + + pport->driver = ttydrv; + pport->line = line; + + return pport; +noport: + pr_err("No port state for %s\n", ttyname); + err = -EL3HLT; +put_driver: + put_tty_driver(ttydrv); +err_out: + pr_err("Error acquiring polling tty port %s: %d\n", ttyname, err); + + return ERR_PTR(err); +} +EXPORT_SYMBOL(avm_tty_poll_acquire); + +int avm_tty_poll_configure(struct polling_tty_port *pport, int baud, + int parity, int bits, int flow) +{ + struct tty_driver *ttydrv = pport->driver; + struct uart_driver *drv; + struct uart_state *state; + struct uart_port *uport; + struct tty_port *port; + + pr_debug("Setting polling tty port %s%d to %u baud\n", + ttydrv->name, pport->line, baud); + + drv = ttydrv->driver_state; + state = drv->state + pport->line; + if (!state) + goto noport; + port = &state->port; + + mutex_lock(&port->mutex); + uport = uart_port_check(state); + if (!uport) { + mutex_unlock(&port->mutex); + goto noport; + } + uart_set_options(uport, NULL, baud, parity, bits, flow); + mutex_unlock(&port->mutex); + + return 0; +noport: + pr_err("Error setting baudrate of polling tty port %s%d: no port state\n", + ttydrv->name, pport->line); + return -EL3HLT; +} +EXPORT_SYMBOL(avm_tty_poll_configure); + +void avm_tty_poll_release(struct polling_tty_port *pport) +{ + struct tty_driver *ttydrv = pport->driver; + struct uart_driver *drv; + struct uart_state *state; + struct uart_port *uport; + struct tty_port *port; + + pr_debug("Releasing polling tty port %s%d\n", + ttydrv->name, pport->line); + + drv = ttydrv->driver_state; + state = drv->state + pport->line; + if (!state) + goto out; + + port = &state->port; + mutex_lock(&port->mutex); + + uport = uart_port_check(state); + if (!uport) { + mutex_unlock(&port->mutex); + goto out; + } + + if (uport->irq) + enable_irq(uport->irq); + + uport->flags &= ~UPF_AVM_POLLING; + + pm_runtime_put(uport->dev); + mutex_unlock(&port->mutex); +out: + put_tty_driver(ttydrv); + kfree(pport); +} +EXPORT_SYMBOL(avm_tty_poll_release); + +int avm_tty_poll_get_char(struct polling_tty_port *pport) +{ + return pport->driver->ops->poll_get_char(pport->driver, pport->line); +} +EXPORT_SYMBOL(avm_tty_poll_get_char); + +void avm_tty_poll_put_char(struct polling_tty_port *pport, unsigned char c) +{ + pport->driver->ops->poll_put_char(pport->driver, pport->line, c); +} +EXPORT_SYMBOL(avm_tty_poll_put_char); +#endif /* CONFIG_AVM_TTY_POLLING */ + +#ifdef CONFIG_INTEL_UART_ENABLE_CONTROL +static ssize_t uart_get_attr_enable_ctrl(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int enable; + + if (intel_ce2700_read_atom_uartctrl(&enable) != IOCNFG_OK) + pr_err(KERN_ERR "Unable to read AtomUartCtrl status\n"); + + return sprintf(buf, "%d\n", enable); +} + +static ssize_t uart_set_attr_enable_ctrl(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int enable; + + enable = (int)(buf[0] - '0'); + if ((enable == 0) || (enable == 1)) + intel_ce2700_config_atom_uartctrl(enable); + else + pr_info(KERN_ERR "uart_enable_ctrl: 0(disable) / 1(enable) UART\n"); + + return count; +} +#endif /** * uart_register_driver - register a driver with the uart core layer * @drv: low level driver structure @@ -2723,6 +2914,9 @@ 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); +#ifdef CONFIG_INTEL_UART_ENABLE_CONTROL +static DEVICE_ATTR(uart_enable_ctrl, S_IRUSR | S_IWUSR, uart_get_attr_enable_ctrl, uart_set_attr_enable_ctrl); +#endif static struct attribute *tty_dev_attrs[] = { &dev_attr_type.attr, @@ -3045,6 +3239,20 @@ } EXPORT_SYMBOL_GPL(uart_insert_char); +#ifdef CONFIG_INTEL_UART_ENABLE_CONTROL +int uart_sysfs_create_uart_enable_ctrl(void) +{ + int retval = sysfs_create_file(kernel_kobj, &dev_attr_uart_enable_ctrl.attr); + + if (retval) + return -ENOMEM; + + return retval; +} +EXPORT_SYMBOL_GPL(uart_sysfs_create_uart_enable_ctrl); +#endif + + EXPORT_SYMBOL(uart_write_wakeup); EXPORT_SYMBOL(uart_register_driver); EXPORT_SYMBOL(uart_unregister_driver);