diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-07 18:52:36 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-06-07 18:52:36 +0200 |
commit | 081096d98bb23946f16215357b141c5616b234bf (patch) | |
tree | 23638d3369fa0c424c1eae203b4c5821281bd2c1 /drivers/tty | |
parent | Merge tag 'usb-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/greg... (diff) | |
parent | tty: serial: qcom_geni_serial: Add 51.2MHz frequency support (diff) | |
download | linux-081096d98bb23946f16215357b141c5616b234bf.tar.xz linux-081096d98bb23946f16215357b141c5616b234bf.zip |
Merge tag 'tty-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty/serial driver updates from Greg KH:
"Here is the tty and serial driver updates for 5.8-rc1
Nothing huge at all, just a lot of little serial driver fixes, updates
for new devices and features, and other small things. Full details are
in the shortlog.
All of these have been in linux-next with no issues for a while"
* tag 'tty-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (67 commits)
tty: serial: qcom_geni_serial: Add 51.2MHz frequency support
tty: serial: imx: clear Ageing Timer Interrupt in handler
serial: 8250_fintek: Add F81966 Support
sc16is7xx: Add flag to activate IrDA mode
dt-bindings: sc16is7xx: Add flag to activate IrDA mode
serial: 8250: Support rs485 bus termination GPIO
serial: 8520_port: Fix function param documentation
dt-bindings: serial: Add binding for rs485 bus termination GPIO
vt: keyboard: avoid signed integer overflow in k_ascii
serial: 8250: Enable 16550A variants by default on non-x86
tty: hvc_console, fix crashes on parallel open/close
serial: imx: Initialize lock for non-registered console
sc16is7xx: Read the LSR register for basic device presence check
sc16is7xx: Allow sharing the IRQ line
sc16is7xx: Use threaded IRQ
sc16is7xx: Always use falling edge IRQ
tty: n_gsm: Fix bogus i++ in gsm_data_kick
tty: n_gsm: Remove unnecessary test in gsm_print_packet()
serial: stm32: add no_console_suspend support
tty: serial: fsl_lpuart: Use __maybe_unused instead of #if CONFIG_PM_SLEEP
...
Diffstat (limited to 'drivers/tty')
32 files changed, 552 insertions, 305 deletions
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 436cc51c92c3..cdcc64ea2554 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -371,15 +371,14 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) * tty fields and return the kref reference. */ if (rc) { - tty_port_tty_set(&hp->port, NULL); - tty->driver_data = NULL; - tty_port_put(&hp->port); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); - } else + } else { /* We are ready... raise DTR/RTS */ if (C_BAUD(tty)) if (hp->ops->dtr_rts) hp->ops->dtr_rts(hp, 1); + tty_port_set_initialized(&hp->port, true); + } /* Force wakeup of the polling thread */ hvc_kick(); @@ -389,22 +388,12 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) static void hvc_close(struct tty_struct *tty, struct file * filp) { - struct hvc_struct *hp; + struct hvc_struct *hp = tty->driver_data; unsigned long flags; if (tty_hung_up_p(filp)) return; - /* - * No driver_data means that this close was issued after a failed - * hvc_open by the tty layer's release_dev() function and we can just - * exit cleanly because the kref reference wasn't made. - */ - if (!tty->driver_data) - return; - - hp = tty->driver_data; - spin_lock_irqsave(&hp->port.lock, flags); if (--hp->port.count == 0) { @@ -412,6 +401,9 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) /* We are done with the tty pointer now. */ tty_port_tty_set(&hp->port, NULL); + if (!tty_port_initialized(&hp->port)) + return; + if (C_HUPCL(tty)) if (hp->ops->dtr_rts) hp->ops->dtr_rts(hp, 0); @@ -428,6 +420,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) * waking periodically to check chars_in_buffer(). */ tty_wait_until_sent(tty, HVC_CLOSE_WAIT); + tty_port_set_initialized(&hp->port, false); } else { if (hp->port.count < 0) printk(KERN_ERR "hvc_close %X: oops, count is %d\n", diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index ee0604cd9c6b..55105ac38f89 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -196,8 +196,6 @@ module_param(hvcs_parm_num_devs, int, 0); static const char hvcs_driver_name[] = "hvcs"; static const char hvcs_device_node[] = "hvcs"; -static const char hvcs_driver_string[] - = "IBM hvcs (Hypervisor Virtual Console Server) Driver"; /* Status of partner info rescan triggered via sysfs. */ static int hvcs_rescan_status; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 9d00ff5ef961..3703987c4666 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -638,16 +638,15 @@ static int mxser_set_baud(struct tty_struct *tty, long newspd) * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static int mxser_change_speed(struct tty_struct *tty) +static void mxser_change_speed(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; unsigned cflag, cval, fcr; - int ret = 0; unsigned char status; cflag = tty->termios.c_cflag; if (!info->ioaddr) - return ret; + return; if (mxser_set_baud_method[tty->index] == 0) mxser_set_baud(tty, tty_get_baud_rate(tty)); @@ -803,8 +802,6 @@ static int mxser_change_speed(struct tty_struct *tty) outb(fcr, info->ioaddr + UART_FCR); /* set fcr */ outb(cval, info->ioaddr + UART_LCR); - - return ret; } static void mxser_check_modem_status(struct tty_struct *tty, diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index d77ed82a4840..0a29a94ec438 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -504,18 +504,7 @@ static void gsm_print_packet(const char *hdr, int addr, int cr, else pr_cont("(F)"); - if (dlen) { - int ct = 0; - while (dlen--) { - if (ct % 8 == 0) { - pr_cont("\n"); - pr_debug(" "); - } - pr_cont("%02X ", *data++); - ct++; - } - } - pr_cont("\n"); + print_hex_dump_bytes("", DUMP_PREFIX_NONE, data, dlen); } @@ -673,11 +662,10 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, * FIXME: lock against link layer control transmissions */ -static void gsm_data_kick(struct gsm_mux *gsm) +static void gsm_data_kick(struct gsm_mux *gsm, struct gsm_dlci *dlci) { struct gsm_msg *msg, *nmsg; int len; - int skip_sof = 0; list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) { if (gsm->constipated && msg->addr) @@ -699,18 +687,23 @@ static void gsm_data_kick(struct gsm_mux *gsm) print_hex_dump_bytes("gsm_data_kick: ", DUMP_PREFIX_OFFSET, gsm->txframe, len); - - if (gsm->output(gsm, gsm->txframe + skip_sof, - len - skip_sof) < 0) + if (gsm->output(gsm, gsm->txframe, len) < 0) break; /* FIXME: Can eliminate one SOF in many more cases */ gsm->tx_bytes -= msg->len; - /* For a burst of frames skip the extra SOF within the - burst */ - skip_sof = 1; list_del(&msg->list); kfree(msg); + + if (dlci) { + tty_port_tty_wakeup(&dlci->port); + } else { + int i = 0; + + for (i = 0; i < NUM_DLCI; i++) + if (gsm->dlci[i]) + tty_port_tty_wakeup(&gsm->dlci[i]->port); + } } } @@ -762,7 +755,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg) /* Add to the actual output queue */ list_add_tail(&msg->list, &gsm->tx_list); gsm->tx_bytes += msg->len; - gsm_data_kick(gsm); + gsm_data_kick(gsm, dlci); } /** @@ -1223,7 +1216,7 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, gsm_control_reply(gsm, CMD_FCON, NULL, 0); /* Kick the link in case it is idling */ spin_lock_irqsave(&gsm->tx_lock, flags); - gsm_data_kick(gsm); + gsm_data_kick(gsm, NULL); spin_unlock_irqrestore(&gsm->tx_lock, flags); break; case CMD_FCOFF: @@ -2545,7 +2538,7 @@ static void gsmld_write_wakeup(struct tty_struct *tty) /* Queue poll */ clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); spin_lock_irqsave(&gsm->tx_lock, flags); - gsm_data_kick(gsm); + gsm_data_kick(gsm, NULL); if (gsm->tx_bytes < TX_THRESH_LO) { gsm_dlci_data_sweep(gsm); } diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index e2138e7d5dc6..2540b2e4c8e8 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -1885,7 +1885,7 @@ static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, */ static __init int register_PCI(int i, struct pci_dev *dev) { - int num_aiops, aiop, max_num_aiops, num_chan, chan; + int num_aiops, aiop, max_num_aiops, chan; unsigned int aiopio[MAX_AIOPS_PER_BOARD]; CONTROLLER_t *ctlp; @@ -2157,8 +2157,7 @@ static __init int register_PCI(int i, struct pci_dev *dev) /* Reset the AIOPIC, init the serial ports */ for (aiop = 0; aiop < num_aiops; aiop++) { sResetAiopByNum(ctlp, aiop); - num_chan = ports_per_aiop; - for (chan = 0; chan < num_chan; chan++) + for (chan = 0; chan < ports_per_aiop; chan++) init_r_port(i, aiop, chan, dev); } @@ -2166,11 +2165,10 @@ static __init int register_PCI(int i, struct pci_dev *dev) if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII) || (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) { - num_chan = ports_per_aiop; - for (chan = 0; chan < num_chan; chan++) + for (chan = 0; chan < ports_per_aiop; chan++) sPCIModemReset(ctlp, chan, 1); msleep(500); - for (chan = 0; chan < num_chan; chan++) + for (chan = 0; chan < ports_per_aiop; chan++) sPCIModemReset(ctlp, chan, 0); msleep(500); rmSpeakerReset(ctlp, rocketModel[i].model); diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 45d9117cab68..fc118f649887 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1026,7 +1026,9 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (up->port.dev) { uart->port.dev = up->port.dev; - uart_get_rs485_mode(uart->port.dev, &uart->port.rs485); + ret = uart_get_rs485_mode(&uart->port); + if (ret) + goto err; } if (up->port.flags & UPF_FIXED_TYPE) @@ -1040,7 +1042,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up) gpios = mctrl_gpio_init(&uart->port, 0); if (IS_ERR(gpios)) { ret = PTR_ERR(gpios); - goto out_unlock; + goto err; } else { uart->gpios = gpios; } @@ -1089,8 +1091,10 @@ int serial8250_register_8250_port(struct uart_8250_port *up) serial8250_apply_quirks(uart); ret = uart_add_one_port(&serial8250_reg, &uart->port); - if (ret == 0) - ret = uart->port.line; + if (ret) + goto err; + + ret = uart->port.line; } else { dev_info(uart->port.dev, "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n", @@ -1112,10 +1116,14 @@ int serial8250_register_8250_port(struct uart_8250_port *up) } } -out_unlock: mutex_unlock(&serial_mutex); return ret; + +err: + uart->port.dev = NULL; + mutex_unlock(&serial_mutex); + return ret; } EXPORT_SYMBOL(serial8250_register_8250_port); diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 59449b6500cd..ddb6aeb76dc5 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -25,13 +25,13 @@ #include "8250.h" -#define PCI_DEVICE_ID_ACCES_COM_2S 0x1052 -#define PCI_DEVICE_ID_ACCES_COM_4S 0x105d -#define PCI_DEVICE_ID_ACCES_COM_8S 0x106c -#define PCI_DEVICE_ID_ACCES_COM232_8 0x10a8 -#define PCI_DEVICE_ID_ACCES_COM_2SM 0x10d2 -#define PCI_DEVICE_ID_ACCES_COM_4SM 0x10db -#define PCI_DEVICE_ID_ACCES_COM_8SM 0x10ea +#define PCI_DEVICE_ID_ACCESSIO_COM_2S 0x1052 +#define PCI_DEVICE_ID_ACCESSIO_COM_4S 0x105d +#define PCI_DEVICE_ID_ACCESSIO_COM_8S 0x106c +#define PCI_DEVICE_ID_ACCESSIO_COM232_8 0x10a8 +#define PCI_DEVICE_ID_ACCESSIO_COM_2SM 0x10d2 +#define PCI_DEVICE_ID_ACCESSIO_COM_4SM 0x10db +#define PCI_DEVICE_ID_ACCESSIO_COM_8SM 0x10ea #define PCI_DEVICE_ID_COMMTECH_4224PCI335 0x0002 #define PCI_DEVICE_ID_COMMTECH_4222PCI335 0x0004 @@ -755,9 +755,7 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { (kernel_ulong_t)&bd \ } -#define EXAR_DEVICE(vend, devid, bd) { \ - PCI_VDEVICE(vend, PCI_DEVICE_ID_##devid), (kernel_ulong_t)&bd \ - } +#define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) } #define IBM_DEVICE(devid, sdevid, bd) { \ PCI_DEVICE_SUB( \ @@ -769,14 +767,13 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { } static const struct pci_device_id exar_pci_tbl[] = { - EXAR_DEVICE(ACCESSIO, ACCES_COM_2S, acces_com_2x), - EXAR_DEVICE(ACCESSIO, ACCES_COM_4S, acces_com_4x), - EXAR_DEVICE(ACCESSIO, ACCES_COM_8S, acces_com_8x), - EXAR_DEVICE(ACCESSIO, ACCES_COM232_8, acces_com_8x), - EXAR_DEVICE(ACCESSIO, ACCES_COM_2SM, acces_com_2x), - EXAR_DEVICE(ACCESSIO, ACCES_COM_4SM, acces_com_4x), - EXAR_DEVICE(ACCESSIO, ACCES_COM_8SM, acces_com_8x), - + EXAR_DEVICE(ACCESSIO, COM_2S, acces_com_2x), + EXAR_DEVICE(ACCESSIO, COM_4S, acces_com_4x), + EXAR_DEVICE(ACCESSIO, COM_8S, acces_com_8x), + EXAR_DEVICE(ACCESSIO, COM232_8, acces_com_8x), + EXAR_DEVICE(ACCESSIO, COM_2SM, acces_com_2x), + EXAR_DEVICE(ACCESSIO, COM_4SM, acces_com_4x), + EXAR_DEVICE(ACCESSIO, COM_8SM, acces_com_8x), CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect), CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), @@ -794,24 +791,24 @@ static const struct pci_device_id exar_pci_tbl[] = { IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn), /* Exar Corp. XR17C15[248] Dual/Quad/Octal UART */ - EXAR_DEVICE(EXAR, EXAR_XR17C152, pbn_exar_XR17C15x), - EXAR_DEVICE(EXAR, EXAR_XR17C154, pbn_exar_XR17C15x), - EXAR_DEVICE(EXAR, EXAR_XR17C158, pbn_exar_XR17C15x), + EXAR_DEVICE(EXAR, XR17C152, pbn_exar_XR17C15x), + EXAR_DEVICE(EXAR, XR17C154, pbn_exar_XR17C15x), + EXAR_DEVICE(EXAR, XR17C158, pbn_exar_XR17C15x), /* Exar Corp. XR17V[48]35[248] Dual/Quad/Octal/Hexa PCIe UARTs */ - EXAR_DEVICE(EXAR, EXAR_XR17V352, pbn_exar_XR17V35x), - EXAR_DEVICE(EXAR, EXAR_XR17V354, pbn_exar_XR17V35x), - EXAR_DEVICE(EXAR, EXAR_XR17V358, pbn_exar_XR17V35x), - EXAR_DEVICE(EXAR, EXAR_XR17V4358, pbn_exar_XR17V4358), - EXAR_DEVICE(EXAR, EXAR_XR17V8358, pbn_exar_XR17V8358), - EXAR_DEVICE(COMMTECH, COMMTECH_4222PCIE, pbn_exar_XR17V35x), - EXAR_DEVICE(COMMTECH, COMMTECH_4224PCIE, pbn_exar_XR17V35x), - EXAR_DEVICE(COMMTECH, COMMTECH_4228PCIE, pbn_exar_XR17V35x), - - EXAR_DEVICE(COMMTECH, COMMTECH_4222PCI335, pbn_fastcom335_2), - EXAR_DEVICE(COMMTECH, COMMTECH_4224PCI335, pbn_fastcom335_4), - EXAR_DEVICE(COMMTECH, COMMTECH_2324PCI335, pbn_fastcom335_4), - EXAR_DEVICE(COMMTECH, COMMTECH_2328PCI335, pbn_fastcom335_8), + EXAR_DEVICE(EXAR, XR17V352, pbn_exar_XR17V35x), + EXAR_DEVICE(EXAR, XR17V354, pbn_exar_XR17V35x), + EXAR_DEVICE(EXAR, XR17V358, pbn_exar_XR17V35x), + EXAR_DEVICE(EXAR, XR17V4358, pbn_exar_XR17V4358), + EXAR_DEVICE(EXAR, XR17V8358, pbn_exar_XR17V8358), + EXAR_DEVICE(COMMTECH, 4222PCIE, pbn_exar_XR17V35x), + EXAR_DEVICE(COMMTECH, 4224PCIE, pbn_exar_XR17V35x), + EXAR_DEVICE(COMMTECH, 4228PCIE, pbn_exar_XR17V35x), + + EXAR_DEVICE(COMMTECH, 4222PCI335, pbn_fastcom335_2), + EXAR_DEVICE(COMMTECH, 4224PCI335, pbn_fastcom335_4), + EXAR_DEVICE(COMMTECH, 2324PCI335, pbn_fastcom335_4), + EXAR_DEVICE(COMMTECH, 2328PCI335, pbn_fastcom335_8), { 0, } }; MODULE_DEVICE_TABLE(pci, exar_pci_tbl); diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c index 31c91c2f8c6e..d1d253c4b518 100644 --- a/drivers/tty/serial/8250/8250_fintek.c +++ b/drivers/tty/serial/8250/8250_fintek.c @@ -19,6 +19,7 @@ #define CHIP_ID2 0x21 #define CHIP_ID_F81865 0x0407 #define CHIP_ID_F81866 0x1010 +#define CHIP_ID_F81966 0x0215 #define CHIP_ID_F81216AD 0x1602 #define CHIP_ID_F81216H 0x0501 #define CHIP_ID_F81216 0x0802 @@ -62,9 +63,9 @@ #define F81216_LDN_HIGH 0x4 /* - * F81866 registers + * F81866/966 registers * - * The IRQ setting mode of F81866 is not the same with F81216 series. + * The IRQ setting mode of F81866/966 is not the same with F81216 series. * Level/Low: IRQ_MODE0:0, IRQ_MODE1:0 * Edge/High: IRQ_MODE0:1, IRQ_MODE1:0 * @@ -155,6 +156,7 @@ static int fintek_8250_check_id(struct fintek_8250 *pdata) switch (chip) { case CHIP_ID_F81865: case CHIP_ID_F81866: + case CHIP_ID_F81966: case CHIP_ID_F81216AD: case CHIP_ID_F81216H: case CHIP_ID_F81216: @@ -171,6 +173,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min, int *max) { switch (pdata->pid) { + case CHIP_ID_F81966: case CHIP_ID_F81865: case CHIP_ID_F81866: *min = F81866_LDN_LOW; @@ -248,6 +251,7 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level) sio_write_reg(pdata, LDN, pdata->index); switch (pdata->pid) { + case CHIP_ID_F81966: case CHIP_ID_F81866: sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1, 0); @@ -274,6 +278,7 @@ static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata) { switch (pdata->pid) { case CHIP_ID_F81216H: /* 128Bytes FIFO */ + case CHIP_ID_F81966: case CHIP_ID_F81866: sio_write_mask_reg(pdata, FIFO_CTRL, FIFO_MODE_MASK | RXFTHR_MODE_MASK, @@ -291,6 +296,7 @@ static void fintek_8250_goto_highspeed(struct uart_8250_port *uart, sio_write_reg(pdata, LDN, pdata->index); switch (pdata->pid) { + case CHIP_ID_F81966: case CHIP_ID_F81866: /* set uart clock for high speed serial mode */ sio_write_mask_reg(pdata, F81866_UART_CLK, F81866_UART_CLK_MASK, @@ -327,6 +333,7 @@ static void fintek_8250_set_termios(struct uart_port *port, case CHIP_ID_F81216H: reg = RS485; break; + case CHIP_ID_F81966: case CHIP_ID_F81866: reg = F81866_UART_CLK; break; @@ -373,6 +380,7 @@ static void fintek_8250_set_termios_handler(struct uart_8250_port *uart) switch (pdata->pid) { case CHIP_ID_F81216H: + case CHIP_ID_F81966: case CHIP_ID_F81866: uart->port.set_termios = fintek_8250_set_termios; break; @@ -443,6 +451,7 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart) switch (pdata->pid) { case CHIP_ID_F81216AD: case CHIP_ID_F81216H: + case CHIP_ID_F81966: case CHIP_ID_F81866: case CHIP_ID_F81865: uart->port.rs485_config = fintek_8250_rs485_config; diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index f77bf820b7a3..1632f7d25acc 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -681,6 +681,9 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485) memset(rs485->padding, 0, sizeof(rs485->padding)); port->rs485 = *rs485; + gpiod_set_value(port->rs485_term_gpio, + rs485->flags & SER_RS485_TERMINATE_BUS); + /* * Both serial8250_em485_init() and serial8250_em485_destroy() * are idempotent. @@ -1432,7 +1435,7 @@ static void serial8250_stop_rx(struct uart_port *port) /** * serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback - * @up: uart 8250 port + * @p: uart 8250 port * * Generic callback usable by 8250 uart drivers to stop rs485 transmission. */ @@ -2615,6 +2618,8 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + unsigned int tolerance = port->uartclk / 100; + /* * Ask the core to calculate the divisor for us. * Allow 1% tolerance at the upper limit so uart clks marginally @@ -2623,7 +2628,7 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, */ return uart_get_baud_rate(port, termios, old, port->uartclk / 16 / UART_DIV_MAX, - port->uartclk); + (port->uartclk + tolerance) / 16); } void diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index af0688156dd0..8195a31519ea 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -63,6 +63,7 @@ config SERIAL_8250_PNP config SERIAL_8250_16550A_VARIANTS bool "Support for variants of the 16550A serial port" depends on SERIAL_8250 + default !X86 help The 8250 driver can probe for many variants of the venerable 16550A serial port. Doing so takes additional time at boot. diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c index c8186a05a453..e3d10794dbba 100644 --- a/drivers/tty/serial/8250/serial_cs.c +++ b/drivers/tty/serial/8250/serial_cs.c @@ -440,7 +440,7 @@ static int simple_config_check_notpicky(struct pcmcia_device *p_dev, static int simple_config(struct pcmcia_device *link) { struct serial_info *info = link->priv; - int i = -ENODEV, try; + int ret, try; /* * First pass: look for a config entry that looks normal. @@ -472,8 +472,8 @@ found_port: if (info->quirk && info->quirk->config) info->quirk->config(link); - i = pcmcia_enable_device(link); - if (i != 0) + ret = pcmcia_enable_device(link); + if (ret != 0) return -1; return setup_serial(link, info, link->resource[0]->start, link->irq); } diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index adf9e80e7dc9..0282ad9cdaa7 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1034,13 +1034,22 @@ config SERIAL_SIFIVE_CONSOLE boot time.) config SERIAL_LANTIQ - bool "Lantiq serial driver" - depends on LANTIQ + tristate "Lantiq serial driver" + depends on (LANTIQ || X86) || COMPILE_TEST select SERIAL_CORE + help + Support for UART on Lantiq and Intel SoCs. + To compile this driver as a module, select M here. The + module will be called lantiq. + +config SERIAL_LANTIQ_CONSOLE + bool "Console on Lantiq UART" + depends on SERIAL_LANTIQ=y select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON help - Support for console and UART on Lantiq SoCs. + Select this option if you would like to use a Lantiq UART as the + system console. config SERIAL_QE tristate "Freescale QUICC Engine serial port support" @@ -1462,6 +1471,7 @@ config SERIAL_STM32 tristate "STMicroelectronics STM32 serial port support" select SERIAL_CORE depends on ARCH_STM32 || COMPILE_TEST + select SERIAL_MCTRL_GPIO if GPIOLIB help This driver is for the on-chip Serial Controller on STMicroelectronics STM32 MCUs. diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index c010f639298d..8efd7c2a34fe 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2607,6 +2607,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, uap->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_AMBA_PL011_CONSOLE); uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = index; + spin_lock_init(&uap->port.lock); amba_ports[index] = uap; diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 7e7f1398019f..0c80a79d7442 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -766,8 +766,6 @@ static int ar933x_uart_probe(struct platform_device *pdev) goto err_disable_clk; } - uart_get_rs485_mode(&pdev->dev, &port->rs485); - port->mapbase = mem_res->start; port->line = id; port->irq = irq_res->start; @@ -786,6 +784,10 @@ static int ar933x_uart_probe(struct platform_device *pdev) baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP); up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD); + ret = uart_get_rs485_mode(port); + if (ret) + goto err_disable_clk; + up->gpios = mctrl_gpio_init(port, 0); if (IS_ERR(up->gpios) && PTR_ERR(up->gpios) != -ENOSYS) return PTR_ERR(up->gpios); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 8d7080efad9b..e43471b33710 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -2491,8 +2491,6 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, atmel_init_property(atmel_port, pdev); atmel_set_ops(port); - uart_get_rs485_mode(&mpdev->dev, &port->rs485); - port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP; port->ops = &atmel_pops; @@ -2506,6 +2504,10 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); + ret = uart_get_rs485_mode(port); + if (ret) + return ret; + /* for console, the clock could already be configured */ if (!atmel_port->clk) { atmel_port->clk = clk_get(&mpdev->dev, "usart"); diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 5d41075964f2..90298c403042 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1231,9 +1231,7 @@ static void lpuart_dma_rx_free(struct uart_port *port) struct lpuart_port, port); struct dma_chan *chan = sport->dma_rx_chan; - if (chan) - dmaengine_terminate_all(chan); - + dmaengine_terminate_all(chan); dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); kfree(sport->rx_ring.buf); sport->rx_ring.tail = 0; @@ -1514,17 +1512,17 @@ static void lpuart_request_dma(struct lpuart_port *sport) { sport->dma_tx_chan = dma_request_chan(sport->port.dev, "tx"); if (IS_ERR(sport->dma_tx_chan)) { - dev_info_once(sport->port.dev, - "DMA tx channel request failed, operating without tx DMA (%ld)\n", - PTR_ERR(sport->dma_tx_chan)); + dev_dbg_once(sport->port.dev, + "DMA tx channel request failed, operating without tx DMA (%ld)\n", + PTR_ERR(sport->dma_tx_chan)); sport->dma_tx_chan = NULL; } sport->dma_rx_chan = dma_request_chan(sport->port.dev, "rx"); if (IS_ERR(sport->dma_rx_chan)) { - dev_info_once(sport->port.dev, - "DMA rx channel request failed, operating without rx DMA (%ld)\n", - PTR_ERR(sport->dma_rx_chan)); + dev_dbg_once(sport->port.dev, + "DMA rx channel request failed, operating without rx DMA (%ld)\n", + PTR_ERR(sport->dma_rx_chan)); sport->dma_rx_chan = NULL; } } @@ -2621,7 +2619,9 @@ static int lpuart_probe(struct platform_device *pdev) if (ret) goto failed_attach_port; - uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); + ret = uart_get_rs485_mode(&sport->port); + if (ret) + goto failed_get_rs485; if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX) dev_err(&pdev->dev, "driver doesn't support RX during TX\n"); @@ -2634,6 +2634,7 @@ static int lpuart_probe(struct platform_device *pdev) return 0; +failed_get_rs485: failed_attach_port: failed_irq_request: lpuart_disable_clks(sport); @@ -2664,8 +2665,7 @@ static int lpuart_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int lpuart_suspend(struct device *dev) +static int __maybe_unused lpuart_suspend(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); unsigned long temp; @@ -2723,7 +2723,7 @@ static int lpuart_suspend(struct device *dev) return 0; } -static int lpuart_resume(struct device *dev) +static int __maybe_unused lpuart_resume(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); @@ -2754,7 +2754,6 @@ static int lpuart_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index f4d68109bc8b..1265e8d86d8a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -909,6 +909,8 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) usr2 &= ~USR2_ORE; if (usr1 & (USR1_RRDY | USR1_AGTIM)) { + imx_uart_writel(sport, USR1_AGTIM, USR1); + __imx_uart_rxint(irq, dev_id); ret = IRQ_HANDLED; } @@ -2252,6 +2254,8 @@ static int imx_uart_probe(struct platform_device *pdev) return PTR_ERR(base); rxirq = platform_get_irq(pdev, 0); + if (rxirq < 0) + return rxirq; txirq = platform_get_irq_optional(pdev, 1); rtsirq = platform_get_irq_optional(pdev, 2); @@ -2302,7 +2306,11 @@ static int imx_uart_probe(struct platform_device *pdev) sport->ucr4 = readl(sport->port.membase + UCR4); sport->ufcr = readl(sport->port.membase + UFCR); - uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); + ret = uart_get_rs485_mode(&sport->port); + if (ret) { + clk_disable_unprepare(sport->clk_ipg); + return ret; + } if (sport->port.rs485.flags & SER_RS485_ENABLED && (!sport->have_rtscts && !sport->have_rtsgpio)) @@ -2398,6 +2406,9 @@ static int imx_uart_probe(struct platform_device *pdev) } } + /* We need to initialize lock even for non-registered console */ + spin_lock_init(&sport->port.lock); + imx_uart_ports[sport->port.line] = sport; platform_set_drvdata(pdev, sport); diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index c5e46ff972e4..62813e421f12 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -15,6 +15,7 @@ #include <linux/io.h> #include <linux/ioport.h> #include <linux/lantiq.h> +#include <linux/module.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> @@ -597,6 +598,7 @@ static const struct uart_ops lqasc_pops = { .verify_port = lqasc_verify_port, }; +#ifdef CONFIG_SERIAL_LANTIQ_CONSOLE static void lqasc_console_putchar(struct uart_port *port, int ch) { @@ -705,6 +707,14 @@ lqasc_serial_early_console_setup(struct earlycon_device *device, OF_EARLYCON_DECLARE(lantiq, "lantiq,asc", lqasc_serial_early_console_setup); OF_EARLYCON_DECLARE(lantiq, "intel,lgm-asc", lqasc_serial_early_console_setup); +#define LANTIQ_SERIAL_CONSOLE (&lqasc_console) + +#else + +#define LANTIQ_SERIAL_CONSOLE NULL + +#endif /* CONFIG_SERIAL_LANTIQ_CONSOLE */ + static struct uart_driver lqasc_reg = { .owner = THIS_MODULE, .driver_name = DRVNAME, @@ -712,7 +722,7 @@ static struct uart_driver lqasc_reg = { .major = 0, .minor = 0, .nr = MAXPORTS, - .cons = &lqasc_console, + .cons = LANTIQ_SERIAL_CONSOLE, }; static int fetch_irq_lantiq(struct device *dev, struct ltq_uart_port *ltq_port) @@ -814,8 +824,7 @@ static void free_irq_intel(struct uart_port *port) free_irq(ltq_port->common_irq, port); } -static int __init -lqasc_probe(struct platform_device *pdev) +static int lqasc_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct ltq_uart_port *ltq_port; @@ -899,6 +908,13 @@ lqasc_probe(struct platform_device *pdev) return ret; } +static int lqasc_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + + return uart_remove_one_port(&lqasc_reg, port); +} + static const struct ltq_soc_data soc_data_lantiq = { .fetch_irq = fetch_irq_lantiq, .request_irq = request_irq_lantiq, @@ -916,8 +932,11 @@ static const struct of_device_id ltq_asc_match[] = { { .compatible = "intel,lgm-asc", .data = &soc_data_intel }, {}, }; +MODULE_DEVICE_TABLE(of, ltq_asc_match); static struct platform_driver lqasc_driver = { + .probe = lqasc_probe, + .remove = lqasc_remove, .driver = { .name = DRVNAME, .of_match_table = ltq_asc_match, @@ -933,10 +952,21 @@ init_lqasc(void) if (ret != 0) return ret; - ret = platform_driver_probe(&lqasc_driver, lqasc_probe); + ret = platform_driver_register(&lqasc_driver); if (ret != 0) uart_unregister_driver(&lqasc_reg); return ret; } -device_initcall(init_lqasc); + +static void __exit exit_lqasc(void) +{ + platform_driver_unregister(&lqasc_driver); + uart_unregister_driver(&lqasc_reg); +} + +module_init(init_lqasc); +module_exit(exit_lqasc); + +MODULE_DESCRIPTION("Serial driver for Lantiq & Intel gateway SoCs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index 9a836dcac157..b5898c932036 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -23,7 +23,6 @@ #include <linux/nmi.h> #include <linux/io.h> #include <linux/irq.h> -#include <linux/gpio.h> #include <linux/of.h> #include <linux/sizes.h> #include <linux/soc/nxp/lpc32xx-misc.h> diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index f7d6b3c9ea45..8573fc9cb0cd 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -33,8 +33,7 @@ #include <linux/pm_wakeirq.h> #include <linux/of.h> #include <linux/of_irq.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/platform_data/serial-omap.h> #define OMAP_MAX_HSUART_PORTS 10 @@ -153,7 +152,7 @@ struct uart_omap_port { u32 errata; u32 features; - int rts_gpio; + struct gpio_desc *rts_gpiod; struct pm_qos_request pm_qos_request; u32 latency; @@ -303,11 +302,11 @@ static void serial_omap_stop_tx(struct uart_port *port) serial_out(up, UART_OMAP_SCR, up->scr); res = (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) ? 1 : 0; - if (gpio_get_value(up->rts_gpio) != res) { + if (gpiod_get_value(up->rts_gpiod) != res) { if (port->rs485.delay_rts_after_send > 0) mdelay( port->rs485.delay_rts_after_send); - gpio_set_value(up->rts_gpio, res); + gpiod_set_value(up->rts_gpiod, res); } } else { /* We're asked to stop, but there's still stuff in the @@ -412,8 +411,8 @@ static void serial_omap_start_tx(struct uart_port *port) /* if rts not already enabled */ res = (port->rs485.flags & SER_RS485_RTS_ON_SEND) ? 1 : 0; - if (gpio_get_value(up->rts_gpio) != res) { - gpio_set_value(up->rts_gpio, res); + if (gpiod_get_value(up->rts_gpiod) != res) { + gpiod_set_value(up->rts_gpiod, res); if (port->rs485.delay_rts_before_send > 0) mdelay(port->rs485.delay_rts_before_send); } @@ -1414,12 +1413,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) * Just as a precaution, only allow rs485 * to be enabled if the gpio pin is valid */ - if (gpio_is_valid(up->rts_gpio)) { + if (up->rts_gpiod) { /* enable / disable rts */ val = (port->rs485.flags & SER_RS485_ENABLED) ? SER_RS485_RTS_AFTER_SEND : SER_RS485_RTS_ON_SEND; val = (port->rs485.flags & val) ? 1 : 0; - gpio_set_value(up->rts_gpio, val); + gpiod_set_value(up->rts_gpiod, val); } else port->rs485.flags &= ~SER_RS485_ENABLED; @@ -1596,18 +1595,22 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev) } static int serial_omap_probe_rs485(struct uart_omap_port *up, - struct device_node *np) + struct device *dev) { struct serial_rs485 *rs485conf = &up->port.rs485; + struct device_node *np = dev->of_node; + enum gpiod_flags gflags; int ret; rs485conf->flags = 0; - up->rts_gpio = -EINVAL; + up->rts_gpiod = NULL; if (!np) return 0; - uart_get_rs485_mode(up->dev, rs485conf); + ret = uart_get_rs485_mode(&up->port); + if (ret) + return ret; if (of_property_read_bool(np, "rs485-rts-active-high")) { rs485conf->flags |= SER_RS485_RTS_ON_SEND; @@ -1618,19 +1621,20 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, } /* check for tx enable gpio */ - up->rts_gpio = of_get_named_gpio(np, "rts-gpio", 0); - if (gpio_is_valid(up->rts_gpio)) { - ret = devm_gpio_request(up->dev, up->rts_gpio, "omap-serial"); - if (ret < 0) - return ret; - ret = rs485conf->flags & SER_RS485_RTS_AFTER_SEND ? 1 : 0; - ret = gpio_direction_output(up->rts_gpio, ret); - if (ret < 0) + gflags = rs485conf->flags & SER_RS485_RTS_AFTER_SEND ? + GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + up->rts_gpiod = devm_gpiod_get_optional(dev, "rts", gflags); + if (IS_ERR(up->rts_gpiod)) { + ret = PTR_ERR(up->rts_gpiod); + if (ret == -EPROBE_DEFER) return ret; - } else if (up->rts_gpio == -EPROBE_DEFER) { - return -EPROBE_DEFER; + /* + * FIXME: the code historically ignored any other error than + * -EPROBE_DEFER and just went on without GPIO. + */ + up->rts_gpiod = NULL; } else { - up->rts_gpio = -EINVAL; + gpiod_set_consumer_name(up->rts_gpiod, "omap-serial"); } return 0; @@ -1703,7 +1707,7 @@ static int serial_omap_probe(struct platform_device *pdev) dev_info(up->port.dev, "no wakeirq for uart%d\n", up->port.line); - ret = serial_omap_probe_rs485(up, pdev->dev.of_node); + ret = serial_omap_probe_rs485(up, &pdev->dev); if (ret < 0) goto err_rs485; diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 6bace1c6bb09..457c0bf8cbf8 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -141,9 +141,10 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport); static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop); static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200, - 32000000, 48000000, 64000000, 80000000, - 96000000, 100000000, 102400000, - 112000000, 120000000, 128000000}; + 32000000, 48000000, 51200000, 64000000, + 80000000, 96000000, 100000000, + 102400000, 112000000, 120000000, + 128000000}; #define to_dev_port(ptr, member) \ container_of(ptr, struct qcom_geni_serial_port, member) diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 73f951d65b93..d913d9b2762a 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -154,10 +154,33 @@ struct s3c24xx_uart_port { #define portaddrl(port, reg) \ ((unsigned long *)(unsigned long)((port)->membase + (reg))) -#define rd_regb(port, reg) (readb_relaxed(portaddr(port, reg))) +static u32 rd_reg(struct uart_port *port, u32 reg) +{ + switch (port->iotype) { + case UPIO_MEM: + return readb_relaxed(portaddr(port, reg)); + case UPIO_MEM32: + return readl_relaxed(portaddr(port, reg)); + default: + return 0; + } + return 0; +} + #define rd_regl(port, reg) (readl_relaxed(portaddr(port, reg))) -#define wr_regb(port, reg, val) writeb_relaxed(val, portaddr(port, reg)) +static void wr_reg(struct uart_port *port, u32 reg, u32 val) +{ + switch (port->iotype) { + case UPIO_MEM: + writeb_relaxed(val, portaddr(port, reg)); + break; + case UPIO_MEM32: + writel_relaxed(val, portaddr(port, reg)); + break; + } +} + #define wr_regl(port, reg, val) writel_relaxed(val, portaddr(port, reg)) /* Byte-order aware bit setting/clearing functions. */ @@ -714,7 +737,7 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) fifocnt--; uerstat = rd_regl(port, S3C2410_UERSTAT); - ch = rd_regb(port, S3C2410_URXH); + ch = rd_reg(port, S3C2410_URXH); if (port->flags & UPF_CONS_FLOW) { int txe = s3c24xx_serial_txempty_nofifo(port); @@ -826,7 +849,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) } if (port->x_char) { - wr_regb(port, S3C2410_UTXH, port->x_char); + wr_reg(port, S3C2410_UTXH, port->x_char); port->icount.tx++; port->x_char = 0; goto out; @@ -852,7 +875,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull) break; - wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]); + wr_reg(port, S3C2410_UTXH, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; count--; @@ -916,7 +939,7 @@ static unsigned int s3c24xx_serial_tx_empty(struct uart_port *port) /* no modem control lines */ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port) { - unsigned int umstat = rd_regb(port, S3C2410_UMSTAT); + unsigned int umstat = rd_reg(port, S3C2410_UMSTAT); if (umstat & S3C2410_UMSTAT_CTS) return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; @@ -1281,14 +1304,14 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport, struct s3c24xx_uart_info *info = ourport->info; struct clk *clk; unsigned long rate; - unsigned int cnt, baud, quot, clk_sel, best_quot = 0; + unsigned int cnt, baud, quot, best_quot = 0; char clkname[MAX_CLK_NAME_LENGTH]; int calc_deviation, deviation = (1 << 30) - 1; - clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel : - ourport->info->def_clk_sel; for (cnt = 0; cnt < info->num_clks; cnt++) { - if (!(clk_sel & (1 << cnt))) + /* Keep selected clock if provided */ + if (ourport->cfg->clk_sel && + !(ourport->cfg->clk_sel & (1 << cnt))) continue; sprintf(clkname, "clk_uart_baud%d", cnt); @@ -1974,7 +1997,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct s3c24xx_uart_port *ourport; int index = probe_index; - int ret; + int ret, prop = 0; if (np) { ret = of_alias_get_id(np, "serial"); @@ -2000,10 +2023,27 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dev_get_platdata(&pdev->dev) : ourport->drv_data->def_cfg; - if (np) + if (np) { of_property_read_u32(np, "samsung,uart-fifosize", &ourport->port.fifosize); + if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { + switch (prop) { + case 1: + ourport->port.iotype = UPIO_MEM; + break; + case 4: + ourport->port.iotype = UPIO_MEM32; + break; + default: + dev_warn(&pdev->dev, "unsupported reg-io-width (%d)\n", + prop); + ret = -EINVAL; + break; + } + } + } + if (ourport->drv_data->fifosize[index]) ourport->port.fifosize = ourport->drv_data->fifosize[index]; else if (ourport->info->fifosize) @@ -2185,7 +2225,7 @@ static int s3c24xx_serial_get_poll_char(struct uart_port *port) if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0) return NO_POLL_CHAR; - return rd_regb(port, S3C2410_URXH); + return rd_reg(port, S3C2410_URXH); } static void s3c24xx_serial_put_poll_char(struct uart_port *port, @@ -2200,7 +2240,7 @@ static void s3c24xx_serial_put_poll_char(struct uart_port *port, while (!s3c24xx_serial_console_txrdy(port, ufcon)) cpu_relax(); - wr_regb(port, S3C2410_UTXH, c); + wr_reg(port, S3C2410_UTXH, c); } #endif /* CONFIG_CONSOLE_POLL */ @@ -2212,7 +2252,7 @@ s3c24xx_serial_console_putchar(struct uart_port *port, int ch) while (!s3c24xx_serial_console_txrdy(port, ufcon)) cpu_relax(); - wr_regb(port, S3C2410_UTXH, ch); + wr_reg(port, S3C2410_UTXH, ch); } static void @@ -2587,6 +2627,18 @@ module_platform_driver(samsung_serial_driver); * Early console. */ +static void wr_reg_barrier(struct uart_port *port, u32 reg, u32 val) +{ + switch (port->iotype) { + case UPIO_MEM: + writeb(val, portaddr(port, reg)); + break; + case UPIO_MEM32: + writel(val, portaddr(port, reg)); + break; + } +} + struct samsung_early_console_data { u32 txfull_mask; }; @@ -2612,7 +2664,7 @@ static void samsung_early_putc(struct uart_port *port, int c) else samsung_early_busyuart(port); - writeb(c, port->membase + S3C2410_UTXH); + wr_reg_barrier(port, S3C2410_UTXH, c); } static void samsung_early_write(struct console *con, const char *s, diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 06e8071d5601..d2e5c6c86643 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -315,6 +315,7 @@ struct sc16is7xx_one { struct kthread_work tx_work; struct kthread_work reg_work; struct sc16is7xx_one_config config; + bool irda_mode; }; struct sc16is7xx_port { @@ -327,7 +328,6 @@ struct sc16is7xx_port { unsigned char buf[SC16IS7XX_FIFO_SIZE]; struct kthread_worker kworker; struct task_struct *kworker_task; - struct kthread_work irq_work; struct mutex efr_lock; struct sc16is7xx_one p[]; }; @@ -710,9 +710,9 @@ static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) return true; } -static void sc16is7xx_ist(struct kthread_work *ws) +static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) { - struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); + struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; mutex_lock(&s->efr_lock); @@ -727,13 +727,6 @@ static void sc16is7xx_ist(struct kthread_work *ws) } mutex_unlock(&s->efr_lock); -} - -static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) -{ - struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; - - kthread_queue_work(&s->kworker, &s->irq_work); return IRQ_HANDLED; } @@ -994,6 +987,7 @@ static int sc16is7xx_config_rs485(struct uart_port *port, static int sc16is7xx_startup(struct uart_port *port) { + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); struct sc16is7xx_port *s = dev_get_drvdata(port->dev); unsigned int val; @@ -1032,6 +1026,13 @@ static int sc16is7xx_startup(struct uart_port *port) /* Now, initialize the UART */ sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, SC16IS7XX_LCR_WORD_LEN_8); + /* Enable IrDA mode if requested in DT */ + /* This bit must be written with LCR[7] = 0 */ + sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_IRDA_BIT, + one->irda_mode ? + SC16IS7XX_MCR_IRDA_BIT : 0); + /* Enable the Rx and Tx FIFO */ sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_RXDISABLE_BIT | @@ -1176,10 +1177,11 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, static int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype, - struct regmap *regmap, int irq, unsigned long flags) + struct regmap *regmap, int irq) { struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 }; unsigned long freq = 0, *pfreq = dev_get_platdata(dev); + unsigned int val; u32 uartclk = 0; int i, ret; struct sc16is7xx_port *s; @@ -1187,6 +1189,16 @@ static int sc16is7xx_probe(struct device *dev, if (IS_ERR(regmap)) return PTR_ERR(regmap); + /* + * This device does not have an identification register that would + * tell us if we are really connected to the correct device. + * The best we can do is to check if communication is at all possible. + */ + ret = regmap_read(regmap, + SC16IS7XX_LSR_REG << SC16IS7XX_REG_SHIFT, &val); + if (ret < 0) + return ret; + /* Alloc port structure */ s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL); if (!s) { @@ -1221,7 +1233,6 @@ static int sc16is7xx_probe(struct device *dev, mutex_init(&s->efr_lock); kthread_init_worker(&s->kworker); - kthread_init_work(&s->irq_work, sc16is7xx_ist); s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, "sc16is7xx"); if (IS_ERR(s->kworker_task)) { @@ -1302,9 +1313,33 @@ static int sc16is7xx_probe(struct device *dev, sc16is7xx_power(&s->p[i].port, 0); } - /* Setup interrupt */ - ret = devm_request_irq(dev, irq, sc16is7xx_irq, - flags, dev_name(dev), s); + if (dev->of_node) { + struct property *prop; + const __be32 *p; + u32 u; + + of_property_for_each_u32(dev->of_node, "irda-mode-ports", + prop, p, u) + if (u < devtype->nr_uart) + s->p[u].irda_mode = true; + } + + /* + * Setup interrupt. We first try to acquire the IRQ line as level IRQ. + * If that succeeds, we can allow sharing the interrupt as well. + * In case the interrupt controller doesn't support that, we fall + * back to a non-shared falling-edge trigger. + */ + ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_irq, + IRQF_TRIGGER_LOW | IRQF_SHARED | + IRQF_ONESHOT, + dev_name(dev), s); + if (!ret) + return 0; + + ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(dev), s); if (!ret) return 0; @@ -1378,7 +1413,6 @@ static struct regmap_config regcfg = { static int sc16is7xx_spi_probe(struct spi_device *spi) { const struct sc16is7xx_devtype *devtype; - unsigned long flags = 0; struct regmap *regmap; int ret; @@ -1399,14 +1433,13 @@ static int sc16is7xx_spi_probe(struct spi_device *spi) const struct spi_device_id *id_entry = spi_get_device_id(spi); devtype = (struct sc16is7xx_devtype *)id_entry->driver_data; - flags = IRQF_TRIGGER_FALLING; } regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | (devtype->nr_uart - 1); regmap = devm_regmap_init_spi(spi, ®cfg); - return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq, flags); + return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq); } static int sc16is7xx_spi_remove(struct spi_device *spi) @@ -1445,7 +1478,6 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { const struct sc16is7xx_devtype *devtype; - unsigned long flags = 0; struct regmap *regmap; if (i2c->dev.of_node) { @@ -1454,14 +1486,13 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c, return -ENODEV; } else { devtype = (struct sc16is7xx_devtype *)id->driver_data; - flags = IRQF_TRIGGER_FALLING; } regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | (devtype->nr_uart - 1); regmap = devm_regmap_init_i2c(i2c, ®cfg); - return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq, flags); + return sc16is7xx_probe(&i2c->dev, devtype, regmap, i2c->irq); } static int sc16is7xx_i2c_remove(struct i2c_client *client) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 66a5e2faf57e..57840cf90388 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3295,8 +3295,10 @@ EXPORT_SYMBOL(uart_remove_one_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; @@ -3315,6 +3317,7 @@ void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf) * 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; @@ -3328,6 +3331,23 @@ void uart_get_rs485_mode(struct device *dev, struct serial_rs485 *rs485conf) 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; + if (ret != -EPROBE_DEFER) + dev_err(dev, "Cannot get rs485-term-gpios\n"); + return ret; + } + + return 0; } EXPORT_SYMBOL_GPL(uart_get_rs485_mode); diff --git a/drivers/tty/serial/sh-sci.h b/drivers/tty/serial/sh-sci.h index 0b9e804e61a9..c0dfe4382898 100644 --- a/drivers/tty/serial/sh-sci.h +++ b/drivers/tty/serial/sh-sci.h @@ -2,7 +2,6 @@ #include <linux/bitops.h> #include <linux/serial_core.h> #include <linux/io.h> -#include <linux/gpio.h> #define SCI_MAJOR 204 #define SCI_MINOR_START 8 diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 5e93e8d40f59..8602ff357321 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -31,6 +31,7 @@ #include <linux/tty_flip.h> #include <linux/tty.h> +#include "serial_mctrl_gpio.h" #include "stm32-usart.h" static void stm32_stop_tx(struct uart_port *port); @@ -158,9 +159,7 @@ static int stm32_init_rs485(struct uart_port *port, if (!pdev->dev.of_node) return -ENODEV; - uart_get_rs485_mode(&pdev->dev, rs485conf); - - return 0; + return uart_get_rs485_mode(port); } static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, @@ -510,12 +509,29 @@ static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE); else stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE); + + mctrl_gpio_set(stm32_port->gpios, mctrl); } static unsigned int stm32_get_mctrl(struct uart_port *port) { + struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int ret; + /* This routine is used to get signals of: DCD, DSR, RI, and CTS */ - return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; + ret = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; + + return mctrl_gpio_get(stm32_port->gpios, &ret); +} + +static void stm32_enable_ms(struct uart_port *port) +{ + mctrl_gpio_enable_ms(to_stm32_port(port)->gpios); +} + +static void stm32_disable_ms(struct uart_port *port) +{ + mctrl_gpio_disable_ms(to_stm32_port(port)->gpios); } /* Transmit stop */ @@ -626,6 +642,9 @@ static void stm32_shutdown(struct uart_port *port) u32 val, isr; int ret; + /* Disable modem control interrupts */ + stm32_disable_ms(port); + val = USART_CR1_TXEIE | USART_CR1_TE; val |= stm32_port->cr1_irq | USART_CR1_RE; val |= BIT(cfg->uart_enable_bit); @@ -764,6 +783,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; } + /* Handle modem control interrupts */ + if (UART_ENABLE_MS(port, termios->c_cflag)) + stm32_enable_ms(port); + else + stm32_disable_ms(port); + usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); /* @@ -898,6 +923,7 @@ static const struct uart_ops stm32_uart_ops = { .throttle = stm32_throttle, .unthrottle = stm32_unthrottle, .stop_rx = stm32_stop_rx, + .enable_ms = stm32_enable_ms, .break_ctl = stm32_break_ctl, .startup = stm32_startup, .shutdown = stm32_shutdown, @@ -931,7 +957,9 @@ static int stm32_init_port(struct stm32_port *stm32port, port->rs485_config = stm32_config_rs485; - stm32_init_rs485(port, pdev); + ret = stm32_init_rs485(port, pdev); + if (ret) + return ret; if (stm32port->info->cfg.has_wakeup) { stm32port->wakeirq = platform_get_irq(pdev, 1); @@ -960,11 +988,32 @@ static int stm32_init_port(struct stm32_port *stm32port, stm32port->port.uartclk = clk_get_rate(stm32port->clk); if (!stm32port->port.uartclk) { - clk_disable_unprepare(stm32port->clk); ret = -EINVAL; + goto err_clk; + } + + stm32port->gpios = mctrl_gpio_init(&stm32port->port, 0); + if (IS_ERR(stm32port->gpios)) { + ret = PTR_ERR(stm32port->gpios); + goto err_clk; + } + + /* Both CTS/RTS gpios and "st,hw-flow-ctrl" should not be specified */ + if (stm32port->hw_flow_control) { + if (mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_CTS) || + mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_RTS)) { + dev_err(&pdev->dev, "Conflicting RTS/CTS config\n"); + ret = -EINVAL; + goto err_clk; + } } return ret; + +err_clk: + clk_disable_unprepare(stm32port->clk); + + return ret; } static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) @@ -1375,7 +1424,18 @@ static int __maybe_unused stm32_serial_suspend(struct device *dev) else stm32_serial_enable_wakeup(port, false); - pinctrl_pm_select_sleep_state(dev); + /* + * When "no_console_suspend" is enabled, keep the pinctrl default state + * and rely on bootloader stage to restore this state upon resume. + * Otherwise, apply the idle or sleep states depending on wakeup + * capabilities. + */ + if (console_suspend_enabled || !uart_console(port)) { + if (device_may_wakeup(dev)) + pinctrl_pm_select_idle_state(dev); + else + pinctrl_pm_select_sleep_state(dev); + } return 0; } diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index db8bf0d4982d..d4c916e78d40 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -274,6 +274,7 @@ struct stm32_port { bool fifoen; int wakeirq; int rdr_mask; /* receive data register mask */ + struct mctrl_gpios *gpios; /* modem control gpios */ }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 35e9e8faf8de..b9d672af8b65 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1235,9 +1235,7 @@ static void cdns_uart_console_write(struct console *co, const char *s, writel(ctrl, port->membase + CDNS_UART_CR); uart_console_write(port, s, count, cdns_uart_console_putchar); - while ((readl(port->membase + CDNS_UART_SR) & - (CDNS_UART_SR_TXEMPTY | CDNS_UART_SR_TACTIVE)) != - CDNS_UART_SR_TXEMPTY) + while (cdns_uart_tx_empty(port) != TIOCSER_TEMT) cpu_relax(); /* restore interrupt state */ @@ -1262,6 +1260,7 @@ static int cdns_uart_console_setup(struct console *co, char *options) int bits = 8; int parity = 'n'; int flow = 'n'; + unsigned long time_out; if (!port->membase) { pr_debug("console on " CDNS_UART_TTY_NAME "%i not present\n", @@ -1272,6 +1271,13 @@ static int cdns_uart_console_setup(struct console *co, char *options) if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); + /* Wait for tx_empty before setting up the console */ + time_out = jiffies + usecs_to_jiffies(TX_TIMEOUT); + + while (time_before(jiffies, time_out) && + cdns_uart_tx_empty(port) != TIOCSER_TEMT) + cpu_relax(); + return uart_set_options(port, co, baud, parity, bits, flow); } diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 0dc3878794fd..477cdc1e9cf3 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -106,7 +106,7 @@ static void sysrq_handle_loglevel(int key) pr_info("Loglevel set to %d\n", i); console_loglevel = i; } -static struct sysrq_key_op sysrq_loglevel_op = { +static const struct sysrq_key_op sysrq_loglevel_op = { .handler = sysrq_handle_loglevel, .help_msg = "loglevel(0-9)", .action_msg = "Changing Loglevel", @@ -119,14 +119,14 @@ static void sysrq_handle_SAK(int key) struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; schedule_work(SAK_work); } -static struct sysrq_key_op sysrq_SAK_op = { +static const struct sysrq_key_op sysrq_SAK_op = { .handler = sysrq_handle_SAK, .help_msg = "sak(k)", .action_msg = "SAK", .enable_mask = SYSRQ_ENABLE_KEYBOARD, }; #else -#define sysrq_SAK_op (*(struct sysrq_key_op *)NULL) +#define sysrq_SAK_op (*(const struct sysrq_key_op *)NULL) #endif #ifdef CONFIG_VT @@ -135,14 +135,14 @@ static void sysrq_handle_unraw(int key) vt_reset_unicode(fg_console); } -static struct sysrq_key_op sysrq_unraw_op = { +static const struct sysrq_key_op sysrq_unraw_op = { .handler = sysrq_handle_unraw, .help_msg = "unraw(r)", .action_msg = "Keyboard mode set to system default", .enable_mask = SYSRQ_ENABLE_KEYBOARD, }; #else -#define sysrq_unraw_op (*(struct sysrq_key_op *)NULL) +#define sysrq_unraw_op (*(const struct sysrq_key_op *)NULL) #endif /* CONFIG_VT */ static void sysrq_handle_crash(int key) @@ -152,7 +152,7 @@ static void sysrq_handle_crash(int key) panic("sysrq triggered crash\n"); } -static struct sysrq_key_op sysrq_crash_op = { +static const struct sysrq_key_op sysrq_crash_op = { .handler = sysrq_handle_crash, .help_msg = "crash(c)", .action_msg = "Trigger a crash", @@ -165,18 +165,20 @@ static void sysrq_handle_reboot(int key) local_irq_enable(); emergency_restart(); } -static struct sysrq_key_op sysrq_reboot_op = { +static const struct sysrq_key_op sysrq_reboot_op = { .handler = sysrq_handle_reboot, .help_msg = "reboot(b)", .action_msg = "Resetting", .enable_mask = SYSRQ_ENABLE_BOOT, }; +const struct sysrq_key_op *__sysrq_reboot_op = &sysrq_reboot_op; + static void sysrq_handle_sync(int key) { emergency_sync(); } -static struct sysrq_key_op sysrq_sync_op = { +static const struct sysrq_key_op sysrq_sync_op = { .handler = sysrq_handle_sync, .help_msg = "sync(s)", .action_msg = "Emergency Sync", @@ -188,7 +190,7 @@ static void sysrq_handle_show_timers(int key) sysrq_timer_list_show(); } -static struct sysrq_key_op sysrq_show_timers_op = { +static const struct sysrq_key_op sysrq_show_timers_op = { .handler = sysrq_handle_show_timers, .help_msg = "show-all-timers(q)", .action_msg = "Show clockevent devices & pending hrtimers (no others)", @@ -198,7 +200,7 @@ static void sysrq_handle_mountro(int key) { emergency_remount(); } -static struct sysrq_key_op sysrq_mountro_op = { +static const struct sysrq_key_op sysrq_mountro_op = { .handler = sysrq_handle_mountro, .help_msg = "unmount(u)", .action_msg = "Emergency Remount R/O", @@ -211,13 +213,13 @@ static void sysrq_handle_showlocks(int key) debug_show_all_locks(); } -static struct sysrq_key_op sysrq_showlocks_op = { +static const struct sysrq_key_op sysrq_showlocks_op = { .handler = sysrq_handle_showlocks, .help_msg = "show-all-locks(d)", .action_msg = "Show Locks Held", }; #else -#define sysrq_showlocks_op (*(struct sysrq_key_op *)NULL) +#define sysrq_showlocks_op (*(const struct sysrq_key_op *)NULL) #endif #ifdef CONFIG_SMP @@ -264,7 +266,7 @@ static void sysrq_handle_showallcpus(int key) } } -static struct sysrq_key_op sysrq_showallcpus_op = { +static const struct sysrq_key_op sysrq_showallcpus_op = { .handler = sysrq_handle_showallcpus, .help_msg = "show-backtrace-all-active-cpus(l)", .action_msg = "Show backtrace of all active CPUs", @@ -282,7 +284,7 @@ static void sysrq_handle_showregs(int key) show_regs(regs); perf_event_print_debug(); } -static struct sysrq_key_op sysrq_showregs_op = { +static const struct sysrq_key_op sysrq_showregs_op = { .handler = sysrq_handle_showregs, .help_msg = "show-registers(p)", .action_msg = "Show Regs", @@ -294,7 +296,7 @@ static void sysrq_handle_showstate(int key) show_state(); show_workqueue_state(); } -static struct sysrq_key_op sysrq_showstate_op = { +static const struct sysrq_key_op sysrq_showstate_op = { .handler = sysrq_handle_showstate, .help_msg = "show-task-states(t)", .action_msg = "Show State", @@ -305,7 +307,7 @@ static void sysrq_handle_showstate_blocked(int key) { show_state_filter(TASK_UNINTERRUPTIBLE); } -static struct sysrq_key_op sysrq_showstate_blocked_op = { +static const struct sysrq_key_op sysrq_showstate_blocked_op = { .handler = sysrq_handle_showstate_blocked, .help_msg = "show-blocked-tasks(w)", .action_msg = "Show Blocked State", @@ -319,21 +321,21 @@ static void sysrq_ftrace_dump(int key) { ftrace_dump(DUMP_ALL); } -static struct sysrq_key_op sysrq_ftrace_dump_op = { +static const struct sysrq_key_op sysrq_ftrace_dump_op = { .handler = sysrq_ftrace_dump, .help_msg = "dump-ftrace-buffer(z)", .action_msg = "Dump ftrace buffer", .enable_mask = SYSRQ_ENABLE_DUMP, }; #else -#define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL) +#define sysrq_ftrace_dump_op (*(const struct sysrq_key_op *)NULL) #endif static void sysrq_handle_showmem(int key) { show_mem(0, NULL); } -static struct sysrq_key_op sysrq_showmem_op = { +static const struct sysrq_key_op sysrq_showmem_op = { .handler = sysrq_handle_showmem, .help_msg = "show-memory-usage(m)", .action_msg = "Show Memory", @@ -364,7 +366,7 @@ static void sysrq_handle_term(int key) send_sig_all(SIGTERM); console_loglevel = CONSOLE_LOGLEVEL_DEBUG; } -static struct sysrq_key_op sysrq_term_op = { +static const struct sysrq_key_op sysrq_term_op = { .handler = sysrq_handle_term, .help_msg = "terminate-all-tasks(e)", .action_msg = "Terminate All Tasks", @@ -394,7 +396,7 @@ static void sysrq_handle_moom(int key) { schedule_work(&moom_work); } -static struct sysrq_key_op sysrq_moom_op = { +static const struct sysrq_key_op sysrq_moom_op = { .handler = sysrq_handle_moom, .help_msg = "memory-full-oom-kill(f)", .action_msg = "Manual OOM execution", @@ -406,7 +408,7 @@ static void sysrq_handle_thaw(int key) { emergency_thaw_all(); } -static struct sysrq_key_op sysrq_thaw_op = { +static const struct sysrq_key_op sysrq_thaw_op = { .handler = sysrq_handle_thaw, .help_msg = "thaw-filesystems(j)", .action_msg = "Emergency Thaw of all frozen filesystems", @@ -419,7 +421,7 @@ static void sysrq_handle_kill(int key) send_sig_all(SIGKILL); console_loglevel = CONSOLE_LOGLEVEL_DEBUG; } -static struct sysrq_key_op sysrq_kill_op = { +static const struct sysrq_key_op sysrq_kill_op = { .handler = sysrq_handle_kill, .help_msg = "kill-all-tasks(i)", .action_msg = "Kill All Tasks", @@ -430,7 +432,7 @@ static void sysrq_handle_unrt(int key) { normalize_rt_tasks(); } -static struct sysrq_key_op sysrq_unrt_op = { +static const struct sysrq_key_op sysrq_unrt_op = { .handler = sysrq_handle_unrt, .help_msg = "nice-all-RT-tasks(n)", .action_msg = "Nice All RT Tasks", @@ -440,7 +442,7 @@ static struct sysrq_key_op sysrq_unrt_op = { /* Key Operations table and lock */ static DEFINE_SPINLOCK(sysrq_key_table_lock); -static struct sysrq_key_op *sysrq_key_table[36] = { +static const struct sysrq_key_op *sysrq_key_table[36] = { &sysrq_loglevel_op, /* 0 */ &sysrq_loglevel_op, /* 1 */ &sysrq_loglevel_op, /* 2 */ @@ -516,9 +518,9 @@ static int sysrq_key_table_key2index(int key) /* * get and put functions for the table, exposed to modules. */ -struct sysrq_key_op *__sysrq_get_key_op(int key) +static const struct sysrq_key_op *__sysrq_get_key_op(int key) { - struct sysrq_key_op *op_p = NULL; + const struct sysrq_key_op *op_p = NULL; int i; i = sysrq_key_table_key2index(key); @@ -528,7 +530,7 @@ struct sysrq_key_op *__sysrq_get_key_op(int key) return op_p; } -static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) +static void __sysrq_put_key_op(int key, const struct sysrq_key_op *op_p) { int i = sysrq_key_table_key2index(key); @@ -538,7 +540,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) void __handle_sysrq(int key, bool check_mask) { - struct sysrq_key_op *op_p; + const struct sysrq_key_op *op_p; int orig_log_level; int orig_suppress_printk; int i; @@ -1061,8 +1063,8 @@ int sysrq_toggle_support(int enable_mask) } EXPORT_SYMBOL_GPL(sysrq_toggle_support); -static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, - struct sysrq_key_op *remove_op_p) +static int __sysrq_swap_key_ops(int key, const struct sysrq_key_op *insert_op_p, + const struct sysrq_key_op *remove_op_p) { int retval; @@ -1085,13 +1087,13 @@ static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p, return retval; } -int register_sysrq_key(int key, struct sysrq_key_op *op_p) +int register_sysrq_key(int key, const struct sysrq_key_op *op_p) { return __sysrq_swap_key_ops(key, op_p, NULL); } EXPORT_SYMBOL(register_sysrq_key); -int unregister_sysrq_key(int key, struct sysrq_key_op *op_p) +int unregister_sysrq_key(int key, const struct sysrq_key_op *op_p) { return __sysrq_swap_key_ops(key, NULL, op_p); } diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index d2a1e1228c82..9ffd42e333b8 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -605,6 +605,7 @@ static int vcc_probe(struct vio_dev *vdev, const struct vio_device_id *id) port->index = vcc_table_add(port); if (port->index == -1) { pr_err("VCC: no more TTY indices left for allocation\n"); + rv = -ENOMEM; goto free_ldc; } diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 15d33fa0c925..568b2171f335 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -127,7 +127,11 @@ static DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf' and friends */ static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ static bool dead_key_next; -static int npadch = -1; /* -1 or number assembled on pad */ + +/* Handles a number being assembled on the number pad */ +static bool npadch_active; +static unsigned int npadch_value; + static unsigned int diacr; static char rep; /* flag telling character repeat */ @@ -845,12 +849,12 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) shift_state &= ~(1 << value); /* kludge */ - if (up_flag && shift_state != old_state && npadch != -1) { + if (up_flag && shift_state != old_state && npadch_active) { if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, npadch); + to_utf8(vc, npadch_value); else - put_queue(vc, npadch & 0xff); - npadch = -1; + put_queue(vc, npadch_value & 0xff); + npadch_active = false; } } @@ -868,7 +872,7 @@ static void k_meta(struct vc_data *vc, unsigned char value, char up_flag) static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) { - int base; + unsigned int base; if (up_flag) return; @@ -882,10 +886,12 @@ static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag) base = 16; } - if (npadch == -1) - npadch = value; - else - npadch = npadch * base + value; + if (!npadch_active) { + npadch_value = 0; + npadch_active = true; + } + + npadch_value = npadch_value * base + value; } static void k_lock(struct vc_data *vc, unsigned char value, char up_flag) diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index d54a549c5892..31bb3647a99c 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -185,47 +185,54 @@ int set_selection_user(const struct tiocl_selection __user *sel, return set_selection_kernel(&v, tty); } -static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) +static int vc_selection_store_chars(struct vc_data *vc, bool unicode) { - struct vc_data *vc = vc_cons[fg_console].d; - int new_sel_start, new_sel_end, spc; char *bp, *obp; - int i, ps, pe; - u32 c; - int ret = 0; - bool unicode; - - poke_blanked_console(); - - v->xs = min_t(u16, v->xs - 1, vc->vc_cols - 1); - v->ys = min_t(u16, v->ys - 1, vc->vc_rows - 1); - v->xe = min_t(u16, v->xe - 1, vc->vc_cols - 1); - v->ye = min_t(u16, v->ye - 1, vc->vc_rows - 1); - ps = v->ys * vc->vc_size_row + (v->xs << 1); - pe = v->ye * vc->vc_size_row + (v->xe << 1); + unsigned int i; - if (v->sel_mode == TIOCL_SELCLEAR) { - /* useful for screendump without selection highlights */ + /* Allocate a new buffer before freeing the old one ... */ + /* chars can take up to 4 bytes with unicode */ + bp = kmalloc_array((vc_sel.end - vc_sel.start) / 2 + 1, unicode ? 4 : 1, + GFP_KERNEL); + if (!bp) { + printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); - return 0; + return -ENOMEM; } + kfree(vc_sel.buffer); + vc_sel.buffer = bp; - if (mouse_reporting() && (v->sel_mode & TIOCL_SELMOUSEREPORT)) { - mouse_report(tty, v->sel_mode & TIOCL_SELBUTTONMASK, v->xs, - v->ys); - return 0; + obp = bp; + for (i = vc_sel.start; i <= vc_sel.end; i += 2) { + u32 c = sel_pos(i, unicode); + if (unicode) + bp += store_utf8(c, bp); + else + *bp++ = c; + if (!isspace(c)) + obp = bp; + if (!((i + 2) % vc->vc_size_row)) { + /* strip trailing blanks from line and add newline, + unless non-space at end of line. */ + if (obp != bp) { + bp = obp; + *bp++ = '\r'; + } + obp = bp; + } } + vc_sel.buf_len = bp - vc_sel.buffer; - if (ps > pe) /* make vc_sel.start <= vc_sel.end */ - swap(ps, pe); + return 0; +} - if (vc_sel.cons != vc_cons[fg_console].d) { - clear_selection(); - vc_sel.cons = vc_cons[fg_console].d; - } - unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE; +static int vc_do_selection(struct vc_data *vc, unsigned short mode, int ps, + int pe) +{ + int new_sel_start, new_sel_end, spc; + bool unicode = vt_do_kdgkbmode(fg_console) == K_UNICODE; - switch (v->sel_mode) { + switch (mode) { case TIOCL_SELCHAR: /* character-by-character selection */ new_sel_start = ps; new_sel_end = pe; @@ -303,40 +310,44 @@ static int __set_selection_kernel(struct tiocl_selection *v, struct tty_struct * vc_sel.start = new_sel_start; vc_sel.end = new_sel_end; - /* Allocate a new buffer before freeing the old one ... */ - /* chars can take up to 4 bytes with unicode */ - bp = kmalloc_array((vc_sel.end - vc_sel.start) / 2 + 1, unicode ? 4 : 1, - GFP_KERNEL); - if (!bp) { - printk(KERN_WARNING "selection: kmalloc() failed\n"); + return vc_selection_store_chars(vc, unicode); +} + +static int vc_selection(struct vc_data *vc, struct tiocl_selection *v, + struct tty_struct *tty) +{ + int ps, pe; + + poke_blanked_console(); + + if (v->sel_mode == TIOCL_SELCLEAR) { + /* useful for screendump without selection highlights */ clear_selection(); - return -ENOMEM; + return 0; } - kfree(vc_sel.buffer); - vc_sel.buffer = bp; - obp = bp; - for (i = vc_sel.start; i <= vc_sel.end; i += 2) { - c = sel_pos(i, unicode); - if (unicode) - bp += store_utf8(c, bp); - else - *bp++ = c; - if (!isspace(c)) - obp = bp; - if (! ((i + 2) % vc->vc_size_row)) { - /* strip trailing blanks from line and add newline, - unless non-space at end of line. */ - if (obp != bp) { - bp = obp; - *bp++ = '\r'; - } - obp = bp; - } + v->xs = min_t(u16, v->xs - 1, vc->vc_cols - 1); + v->ys = min_t(u16, v->ys - 1, vc->vc_rows - 1); + v->xe = min_t(u16, v->xe - 1, vc->vc_cols - 1); + v->ye = min_t(u16, v->ye - 1, vc->vc_rows - 1); + + if (mouse_reporting() && (v->sel_mode & TIOCL_SELMOUSEREPORT)) { + mouse_report(tty, v->sel_mode & TIOCL_SELBUTTONMASK, v->xs, + v->ys); + return 0; } - vc_sel.buf_len = bp - vc_sel.buffer; - return ret; + ps = v->ys * vc->vc_size_row + (v->xs << 1); + pe = v->ye * vc->vc_size_row + (v->xe << 1); + if (ps > pe) /* make vc_sel.start <= vc_sel.end */ + swap(ps, pe); + + if (vc_sel.cons != vc) { + clear_selection(); + vc_sel.cons = vc; + } + + return vc_do_selection(vc, v->sel_mode, ps, pe); } int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) @@ -345,7 +356,7 @@ int set_selection_kernel(struct tiocl_selection *v, struct tty_struct *tty) mutex_lock(&vc_sel.lock); console_lock(); - ret = __set_selection_kernel(v, tty); + ret = vc_selection(vc_cons[fg_console].d, v, tty); console_unlock(); mutex_unlock(&vc_sel.lock); |