summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/n_tty.c4
-rw-r--r--drivers/tty/serdev/core.c31
-rw-r--r--drivers/tty/serdev/serdev-ttyport.c26
-rw-r--r--drivers/tty/serial/8250/8250_early.c14
-rw-r--r--drivers/tty/serial/8250/8250_pci.c3
5 files changed, 65 insertions, 13 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 081bbbb7d49c..478a9b40fd03 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1762,7 +1762,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
struct n_tty_data *ldata = tty->disc_data;
- if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) {
+ if (!old || (old->c_lflag ^ tty->termios.c_lflag) & (ICANON | EXTPROC)) {
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
ldata->line_start = ldata->read_tail;
if (!L_ICANON(tty) || !read_cnt(ldata)) {
@@ -2425,7 +2425,7 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
case TIOCINQ:
down_write(&tty->termios_rwsem);
- if (L_ICANON(tty))
+ if (L_ICANON(tty) && !L_EXTPROC(tty))
retval = inq_canon(ldata);
else
retval = read_cnt(ldata);
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index 1bef39828ca7..28133dbd2808 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -132,6 +132,33 @@ void serdev_device_close(struct serdev_device *serdev)
}
EXPORT_SYMBOL_GPL(serdev_device_close);
+static void devm_serdev_device_release(struct device *dev, void *dr)
+{
+ serdev_device_close(*(struct serdev_device **)dr);
+}
+
+int devm_serdev_device_open(struct device *dev, struct serdev_device *serdev)
+{
+ struct serdev_device **dr;
+ int ret;
+
+ dr = devres_alloc(devm_serdev_device_release, sizeof(*dr), GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ ret = serdev_device_open(serdev);
+ if (ret) {
+ devres_free(dr);
+ return ret;
+ }
+
+ *dr = serdev;
+ devres_add(dev, dr);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_serdev_device_open);
+
void serdev_device_write_wakeup(struct serdev_device *serdev)
{
complete(&serdev->write_comp);
@@ -268,8 +295,8 @@ static int serdev_drv_probe(struct device *dev)
static int serdev_drv_remove(struct device *dev)
{
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
-
- sdrv->remove(to_serdev_device(dev));
+ if (sdrv->remove)
+ sdrv->remove(to_serdev_device(dev));
return 0;
}
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index ce7ad0acee7a..247788a16f0b 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -27,23 +27,41 @@ static int ttyport_receive_buf(struct tty_port *port, const unsigned char *cp,
{
struct serdev_controller *ctrl = port->client_data;
struct serport *serport = serdev_controller_get_drvdata(ctrl);
+ int ret;
if (!test_bit(SERPORT_ACTIVE, &serport->flags))
return 0;
- return serdev_controller_receive_buf(ctrl, cp, count);
+ ret = serdev_controller_receive_buf(ctrl, cp, count);
+
+ dev_WARN_ONCE(&ctrl->dev, ret < 0 || ret > count,
+ "receive_buf returns %d (count = %zu)\n",
+ ret, count);
+ if (ret < 0)
+ return 0;
+ else if (ret > count)
+ return count;
+
+ return ret;
}
static void ttyport_write_wakeup(struct tty_port *port)
{
struct serdev_controller *ctrl = port->client_data;
struct serport *serport = serdev_controller_get_drvdata(ctrl);
+ struct tty_struct *tty;
+
+ tty = tty_port_tty_get(port);
+ if (!tty)
+ return;
- if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &port->tty->flags) &&
+ if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
test_bit(SERPORT_ACTIVE, &serport->flags))
serdev_controller_write_wakeup(ctrl);
- wake_up_interruptible_poll(&port->tty->write_wait, POLLOUT);
+ wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
+
+ tty_kref_put(tty);
}
static const struct tty_port_client_operations client_ops = {
@@ -136,8 +154,10 @@ static void ttyport_close(struct serdev_controller *ctrl)
clear_bit(SERPORT_ACTIVE, &serport->flags);
+ tty_lock(tty);
if (tty->ops->close)
tty->ops->close(tty, NULL);
+ tty_unlock(tty);
tty_release_struct(tty, serport->tty_idx);
}
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 362c25ff188a..ae6a256524d8 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -122,12 +122,14 @@ static void __init init_port(struct earlycon_device *device)
serial8250_early_out(port, UART_FCR, 0); /* no fifo */
serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */
- divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
- c = serial8250_early_in(port, UART_LCR);
- serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB);
- serial8250_early_out(port, UART_DLL, divisor & 0xff);
- serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff);
- serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
+ if (port->uartclk && device->baud) {
+ divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud);
+ c = serial8250_early_in(port, UART_LCR);
+ serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB);
+ serial8250_early_out(port, UART_DLL, divisor & 0xff);
+ serial8250_early_out(port, UART_DLM, (divisor >> 8) & 0xff);
+ serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB);
+ }
}
int __init early_serial8250_setup(struct earlycon_device *device,
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index b7e0e3416641..54adf8d56350 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -5135,6 +5135,9 @@ static const struct pci_device_id serial_pci_tbl[] = {
{ PCI_DEVICE(0x1601, 0x0800), .driver_data = pbn_b0_4_1250000 },
{ PCI_DEVICE(0x1601, 0xa801), .driver_data = pbn_b0_4_1250000 },
+ /* Amazon PCI serial device */
+ { PCI_DEVICE(0x1d0f, 0x8250), .driver_data = pbn_b0_1_115200 },
+
/*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL