diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-01 09:51:16 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-09-01 09:51:16 -0700 |
commit | 7c314bdfb64e4bb8d2f829376ed56ce663483752 (patch) | |
tree | ce846e0c4e8c8138258dd00c1f15aad7368fafbb | |
parent | ebf435d3b51b22340ef047aad0c2936ec4833ab2 (diff) | |
parent | 2e5f3a69b6fcd52a64ce3d746c6ee8390b6cabe8 (diff) | |
download | linux-stable-7c314bdfb64e4bb8d2f829376ed56ce663483752.tar.gz linux-stable-7c314bdfb64e4bb8d2f829376ed56ce663483752.tar.bz2 linux-stable-7c314bdfb64e4bb8d2f829376ed56ce663483752.zip |
Merge tag 'tty-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty / serial updates from Greg KH:
"Here is the "big" set of tty/serial driver patches for 5.15-rc1
Nothing major in here at all, just some driver updates and more
cleanups on old tty apis and code that needed it that includes:
- tty.h cleanup of things that didn't belong in it
- other tty cleanups by Jiri
- driver cleanups
- rs485 support added to amba-pl011 driver
- dts updates
- stm32 serial driver updates
- other minor fixes and driver updates
All have been in linux-next for a while with no reported problems"
* tag 'tty-5.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (83 commits)
tty: serial: uartlite: Use read_poll_timeout for a polling loop
tty: serial: uartlite: Use constants in early_uartlite_putc
tty: Fix data race between tiocsti() and flush_to_ldisc()
serial: vt8500: Use of_device_get_match_data
serial: tegra: Use of_device_get_match_data
serial: 8250_ingenic: Use of_device_get_match_data
tty: serial: linflexuart: Remove redundant check to simplify the code
tty: serial: fsl_lpuart: do software reset for imx7ulp and imx8qxp
tty: serial: fsl_lpuart: enable two stop bits for lpuart32
tty: serial: fsl_lpuart: fix the wrong mapbase value
mxser: use semi-colons instead of commas
tty: moxa: use semi-colons instead of commas
tty: serial: fsl_lpuart: check dma_tx_in_progress in tx dma callback
tty: replace in_irq() with in_hardirq()
serial: sh-sci: fix break handling for sysrq
serial: stm32: use devm_platform_get_and_ioremap_resource()
serial: stm32: use the defined variable to simplify code
Revert "arm pl011 serial: support multi-irq request"
tty: serial: samsung: Add Exynos850 SoC data
tty: serial: samsung: Fix driver data macros style
...
86 files changed, 1411 insertions, 1037 deletions
diff --git a/Documentation/devicetree/bindings/serial/8250.yaml b/Documentation/devicetree/bindings/serial/8250.yaml index a0bf061b80fe..fa767440f281 100644 --- a/Documentation/devicetree/bindings/serial/8250.yaml +++ b/Documentation/devicetree/bindings/serial/8250.yaml @@ -66,6 +66,12 @@ properties: - const: nxp,lpc3220-uart - items: - enum: + - exar,xr16l2552 + - exar,xr16l2551 + - exar,xr16l2550 + - const: ns8250 + - items: + - enum: - altr,16550-FIFO32 - altr,16550-FIFO64 - altr,16550-FIFO128 diff --git a/Documentation/devicetree/bindings/serial/8250_omap.yaml b/Documentation/devicetree/bindings/serial/8250_omap.yaml index 1c826fcf5828..ab0c0feed8f0 100644 --- a/Documentation/devicetree/bindings/serial/8250_omap.yaml +++ b/Documentation/devicetree/bindings/serial/8250_omap.yaml @@ -79,6 +79,7 @@ properties: power-domains: true clock-frequency: true current-speed: true + overrun-throttle-ms: true required: - compatible diff --git a/Documentation/devicetree/bindings/serial/cdns,uart.txt b/Documentation/devicetree/bindings/serial/cdns,uart.txt deleted file mode 100644 index 4efc560f90ab..000000000000 --- a/Documentation/devicetree/bindings/serial/cdns,uart.txt +++ /dev/null @@ -1,27 +0,0 @@ -Binding for Cadence UART Controller - -Required properties: -- compatible : - Use "xlnx,xuartps","cdns,uart-r1p8" for Zynq-7xxx SoC. - Use "xlnx,zynqmp-uart","cdns,uart-r1p12" for Zynq Ultrascale+ MPSoC. -- reg: Should contain UART controller registers location and length. -- interrupts: Should contain UART controller interrupts. -- clocks: Must contain phandles to the UART clocks - See ../clocks/clock-bindings.txt for details. -- clock-names: Tuple to identify input clocks, must contain "uart_clk" and "pclk" - See ../clocks/clock-bindings.txt for details. - - -Optional properties: -- cts-override : Override the CTS modem status signal. This signal will - always be reported as active instead of being obtained from the modem status - register. Define this if your serial port does not use this pin - -Example: - uart@e0000000 { - compatible = "cdns,uart-r1p8"; - clocks = <&clkc 23>, <&clkc 40>; - clock-names = "uart_clk", "pclk"; - reg = <0xE0000000 0x1000>; - interrupts = <0 27 4>; - }; diff --git a/Documentation/devicetree/bindings/serial/cdns,uart.yaml b/Documentation/devicetree/bindings/serial/cdns,uart.yaml new file mode 100644 index 000000000000..fcdbe6f87e98 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/cdns,uart.yaml @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/cdns,uart.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Cadence UART Controller Device Tree Bindings + +maintainers: + - Michal Simek <michal.simek@xilinx.com> + +allOf: + - $ref: /schemas/serial.yaml# + +properties: + compatible: + oneOf: + - description: UART controller for Zynq-7xxx SoC + items: + - const: xlnx,xuartps + - const: cdns,uart-r1p8 + - description: UART controller for Zynq Ultrascale+ MPSoC + items: + - const: xlnx,zynqmp-uart + - const: cdns,uart-r1p12 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 2 + + clock-names: + items: + - const: uart_clk + - const: pclk + + cts-override: + description: | + Override the CTS modem status signal. This signal will + always be reported as active instead of being obtained + from the modem status register. Define this if your serial + port does not use this pin. + type: boolean + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +unevaluatedProperties: false + +examples: + - | + uart0: serial@e0000000 { + compatible = "xlnx,xuartps", "cdns,uart-r1p8"; + clocks = <&clkc 23>, <&clkc 40>; + clock-names = "uart_clk", "pclk"; + reg = <0xE0000000 0x1000>; + interrupts = <0 27 4>; + }; diff --git a/Documentation/devicetree/bindings/serial/mtk-uart.txt b/Documentation/devicetree/bindings/serial/mtk-uart.txt index 64c4fb59acd1..b3a0bfef0d54 100644 --- a/Documentation/devicetree/bindings/serial/mtk-uart.txt +++ b/Documentation/devicetree/bindings/serial/mtk-uart.txt @@ -15,6 +15,7 @@ Required properties: * "mediatek,mt7622-uart" for MT7622 compatible UARTS * "mediatek,mt7623-uart" for MT7623 compatible UARTS * "mediatek,mt7629-uart" for MT7629 compatible UARTS + * "mediatek,mt7986-uart", "mediatek,mt6577-uart" for MT7986 compatible UARTS * "mediatek,mt8127-uart" for MT8127 compatible UARTS * "mediatek,mt8135-uart" for MT8135 compatible UARTS * "mediatek,mt8173-uart" for MT8173 compatible UARTS diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index fc03471a0b0f..90635ef5dafa 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -204,9 +204,9 @@ srmcons_init(void) struct tty_driver *driver; int err; - driver = alloc_tty_driver(MAX_SRM_CONSOLE_DEVICES); - if (!driver) - return -ENOMEM; + driver = tty_alloc_driver(MAX_SRM_CONSOLE_DEVICES, 0); + if (IS_ERR(driver)) + return PTR_ERR(driver); tty_port_init(&srmcons_singleton.port); @@ -221,7 +221,7 @@ srmcons_init(void) tty_port_link_device(&srmcons_singleton.port, driver, 0); err = tty_register_driver(driver); if (err) { - put_tty_driver(driver); + tty_driver_kref_put(driver); tty_port_destroy(&srmcons_singleton.port); return err; } diff --git a/arch/m68k/emu/nfcon.c b/arch/m68k/emu/nfcon.c index 92636c89d65b..557d60867f98 100644 --- a/arch/m68k/emu/nfcon.c +++ b/arch/m68k/emu/nfcon.c @@ -120,35 +120,37 @@ early_param("debug", nf_debug_setup); static int __init nfcon_init(void) { + struct tty_driver *driver; int res; stderr_id = nf_get_id("NF_STDERR"); if (!stderr_id) return -ENODEV; - nfcon_tty_driver = alloc_tty_driver(1); - if (!nfcon_tty_driver) - return -ENOMEM; + driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); + if (IS_ERR(driver)) + return PTR_ERR(driver); tty_port_init(&nfcon_tty_port); - nfcon_tty_driver->driver_name = "nfcon"; - nfcon_tty_driver->name = "nfcon"; - nfcon_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; - nfcon_tty_driver->subtype = SYSTEM_TYPE_TTY; - nfcon_tty_driver->init_termios = tty_std_termios; - nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW; + driver->driver_name = "nfcon"; + driver->name = "nfcon"; + driver->type = TTY_DRIVER_TYPE_SYSTEM; + driver->subtype = SYSTEM_TYPE_TTY; + driver->init_termios = tty_std_termios; - tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops); - tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0); - res = tty_register_driver(nfcon_tty_driver); + tty_set_operations(driver, &nfcon_tty_ops); + tty_port_link_device(&nfcon_tty_port, driver, 0); + res = tty_register_driver(driver); if (res) { pr_err("failed to register nfcon tty driver\n"); - put_tty_driver(nfcon_tty_driver); + tty_driver_kref_put(driver); tty_port_destroy(&nfcon_tty_port); return res; } + nfcon_tty_driver = driver; + if (!(nf_console.flags & CON_ENABLED)) register_console(&nf_console); @@ -159,7 +161,7 @@ static void __exit nfcon_exit(void) { unregister_console(&nf_console); tty_unregister_driver(nfcon_tty_driver); - put_tty_driver(nfcon_tty_driver); + tty_driver_kref_put(nfcon_tty_driver); tty_port_destroy(&nfcon_tty_port); } diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c index 39ccad063533..2661cdd256ae 100644 --- a/arch/parisc/kernel/pdc_cons.c +++ b/arch/parisc/kernel/pdc_cons.c @@ -138,6 +138,7 @@ static struct tty_driver *pdc_console_tty_driver; static int __init pdc_console_tty_driver_init(void) { + struct tty_driver *driver; int err; /* Check if the console driver is still registered. @@ -160,31 +161,32 @@ static int __init pdc_console_tty_driver_init(void) printk(KERN_INFO "The PDC console driver is still registered, removing CON_BOOT flag\n"); pdc_cons.flags &= ~CON_BOOT; - pdc_console_tty_driver = alloc_tty_driver(1); - - if (!pdc_console_tty_driver) - return -ENOMEM; + driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_RESET_TERMIOS); + if (IS_ERR(driver)) + return PTR_ERR(driver); tty_port_init(&tty_port); - pdc_console_tty_driver->driver_name = "pdc_cons"; - pdc_console_tty_driver->name = "ttyB"; - pdc_console_tty_driver->major = MUX_MAJOR; - pdc_console_tty_driver->minor_start = 0; - pdc_console_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM; - pdc_console_tty_driver->init_termios = tty_std_termios; - pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW | - TTY_DRIVER_RESET_TERMIOS; - tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops); - tty_port_link_device(&tty_port, pdc_console_tty_driver, 0); - - err = tty_register_driver(pdc_console_tty_driver); + driver->driver_name = "pdc_cons"; + driver->name = "ttyB"; + driver->major = MUX_MAJOR; + driver->minor_start = 0; + driver->type = TTY_DRIVER_TYPE_SYSTEM; + driver->init_termios = tty_std_termios; + tty_set_operations(driver, &pdc_console_tty_ops); + tty_port_link_device(&tty_port, driver, 0); + + err = tty_register_driver(driver); if (err) { printk(KERN_ERR "Unable to register the PDC console TTY driver\n"); tty_port_destroy(&tty_port); + tty_driver_kref_put(driver); return err; } + pdc_console_tty_driver = driver; + return 0; } device_initcall(pdc_console_tty_driver_init); diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index fbc623d2cc07..8febf95da96e 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c @@ -538,12 +538,14 @@ int register_lines(struct line_driver *line_driver, const struct tty_operations *ops, struct line *lines, int nlines) { - struct tty_driver *driver = alloc_tty_driver(nlines); + struct tty_driver *driver; int err; int i; - if (!driver) - return -ENOMEM; + driver = tty_alloc_driver(nlines, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(driver)) + return PTR_ERR(driver); driver->driver_name = line_driver->name; driver->name = line_driver->device_name; @@ -551,9 +553,8 @@ int register_lines(struct line_driver *line_driver, driver->minor_start = line_driver->minor_start; driver->type = line_driver->type; driver->subtype = line_driver->subtype; - driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; driver->init_termios = tty_std_termios; - + for (i = 0; i < nlines; i++) { tty_port_init(&lines[i].port); lines[i].port.ops = &line_port_ops; @@ -567,7 +568,7 @@ int register_lines(struct line_driver *line_driver, if (err) { printk(KERN_ERR "register_lines : can't register %s driver\n", line_driver->name); - put_tty_driver(driver); + tty_driver_kref_put(driver); for (i = 0; i < nlines; i++) tty_port_destroy(&lines[i].port); return err; diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index 21184488c277..81f988914d9a 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -136,28 +136,41 @@ static const struct tty_operations serial_ops = { static int __init rs_init(void) { - tty_port_init(&serial_port); + struct tty_driver *driver; + int ret; + + driver = tty_alloc_driver(SERIAL_MAX_NUM_LINES, TTY_DRIVER_REAL_RAW); + if (IS_ERR(driver)) + return PTR_ERR(driver); - serial_driver = alloc_tty_driver(SERIAL_MAX_NUM_LINES); + tty_port_init(&serial_port); /* Initialize the tty_driver structure */ - serial_driver->driver_name = "iss_serial"; - serial_driver->name = "ttyS"; - serial_driver->major = TTY_MAJOR; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = + driver->driver_name = "iss_serial"; + driver->name = "ttyS"; + driver->major = TTY_MAJOR; + driver->minor_start = 64; + driver->type = TTY_DRIVER_TYPE_SERIAL; + driver->subtype = SERIAL_TYPE_NORMAL; + driver->init_termios = tty_std_termios; + driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(serial_driver, &serial_ops); - tty_port_link_device(&serial_port, serial_driver, 0); + tty_set_operations(driver, &serial_ops); + tty_port_link_device(&serial_port, driver, 0); + + ret = tty_register_driver(driver); + if (ret) { + pr_err("Couldn't register serial driver\n"); + tty_driver_kref_put(driver); + tty_port_destroy(&serial_port); + + return ret; + } + + serial_driver = driver; - if (tty_register_driver(serial_driver)) - panic("Couldn't register serial driver\n"); return 0; } @@ -165,7 +178,7 @@ static int __init rs_init(void) static __exit void rs_exit(void) { tty_unregister_driver(serial_driver); - put_tty_driver(serial_driver); + tty_driver_kref_put(serial_driver); tty_port_destroy(&serial_port); } diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 5ac53dcb3a6a..78baba55a8b5 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -2841,7 +2841,7 @@ static int __init synclink_cs_init(void) err_unreg_tty: tty_unregister_driver(serial_driver); err_put_tty: - put_tty_driver(serial_driver); + tty_driver_kref_put(serial_driver); err: return rc; } @@ -2850,7 +2850,7 @@ static void __exit synclink_cs_exit(void) { pcmcia_unregister_driver(&mgslpc_driver); tty_unregister_driver(serial_driver); - put_tty_driver(serial_driver); + tty_driver_kref_put(serial_driver); } module_init(synclink_cs_init); diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 230b2c9b3e3c..adf941c47506 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -198,7 +198,7 @@ static int __init ttyprintk_init(void) return 0; error: - put_tty_driver(ttyprintk_driver); + tty_driver_kref_put(ttyprintk_driver); tty_port_destroy(&tpk_port.port); return ret; } @@ -206,7 +206,7 @@ error: static void __exit ttyprintk_exit(void) { tty_unregister_driver(ttyprintk_driver); - put_tty_driver(ttyprintk_driver); + tty_driver_kref_put(ttyprintk_driver); tty_port_destroy(&tpk_port.port); } diff --git a/drivers/ipack/devices/ipoctal.c b/drivers/ipack/devices/ipoctal.c index 20fa02c81070..c14e65a5d38f 100644 --- a/drivers/ipack/devices/ipoctal.c +++ b/drivers/ipack/devices/ipoctal.c @@ -347,10 +347,10 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, /* Register the TTY device */ /* Each IP-OCTAL channel is a TTY port */ - tty = alloc_tty_driver(NR_CHANNELS); - - if (!tty) - return -ENOMEM; + tty = tty_alloc_driver(NR_CHANNELS, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(tty)) + return PTR_ERR(tty); /* Fill struct tty_driver with ipoctal data */ tty->owner = THIS_MODULE; @@ -362,7 +362,6 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, tty->minor_start = 0; tty->type = TTY_DRIVER_TYPE_SERIAL; tty->subtype = SERIAL_TYPE_NORMAL; - tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty->init_termios = tty_std_termios; tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; tty->init_termios.c_ispeed = 9600; @@ -372,7 +371,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, res = tty_register_driver(tty); if (res) { dev_err(&ipoctal->dev->dev, "Can't register tty driver.\n"); - put_tty_driver(tty); + tty_driver_kref_put(tty); return res; } @@ -697,7 +696,7 @@ static void __ipoctal_remove(struct ipoctal *ipoctal) } tty_unregister_driver(ipoctal->tty_drv); - put_tty_driver(ipoctal->tty_drv); + tty_driver_kref_put(ipoctal->tty_drv); kfree(ipoctal); } diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index d5f9261fa879..0f00be62438d 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1269,10 +1269,11 @@ static int __init capinc_tty_init(void) if (!capiminors) return -ENOMEM; - drv = alloc_tty_driver(capi_ttyminors); - if (!drv) { + drv = tty_alloc_driver(capi_ttyminors, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(drv)) { kfree(capiminors); - return -ENOMEM; + return PTR_ERR(drv); } drv->driver_name = "capi_nc"; drv->name = "capi!"; @@ -1285,14 +1286,11 @@ static int __init capinc_tty_init(void) drv->init_termios.c_oflag = OPOST | ONLCR; drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; drv->init_termios.c_lflag = 0; - drv->flags = - TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(drv, &capinc_ops); err = tty_register_driver(drv); if (err) { - put_tty_driver(drv); + tty_driver_kref_put(drv); kfree(capiminors); printk(KERN_ERR "Couldn't register capi_nc driver\n"); return err; @@ -1304,7 +1302,7 @@ static int __init capinc_tty_init(void) static void __exit capinc_tty_exit(void) { tty_unregister_driver(capinc_tty_driver); - put_tty_driver(capinc_tty_driver); + tty_driver_kref_put(capinc_tty_driver); kfree(capiminors); } diff --git a/drivers/misc/bcm-vk/bcm_vk_tty.c b/drivers/misc/bcm-vk/bcm_vk_tty.c index dae9eeed84a2..1b6076a89ca6 100644 --- a/drivers/misc/bcm-vk/bcm_vk_tty.c +++ b/drivers/misc/bcm-vk/bcm_vk_tty.c @@ -249,7 +249,7 @@ int bcm_vk_tty_init(struct bcm_vk *vk, char *name) tty_drv->name = kstrdup(name, GFP_KERNEL); if (!tty_drv->name) { err = -ENOMEM; - goto err_put_tty_driver; + goto err_tty_driver_kref_put; } tty_drv->type = TTY_DRIVER_TYPE_SERIAL; tty_drv->subtype = SERIAL_TYPE_NORMAL; @@ -295,8 +295,8 @@ err_kfree_tty_name: kfree(tty_drv->name); tty_drv->name = NULL; -err_put_tty_driver: - put_tty_driver(tty_drv); +err_tty_driver_kref_put: + tty_driver_kref_put(tty_drv); return err; } @@ -317,7 +317,7 @@ void bcm_vk_tty_exit(struct bcm_vk *vk) kfree(vk->tty_drv->name); vk->tty_drv->name = NULL; - put_tty_driver(vk->tty_drv); + tty_driver_kref_put(vk->tty_drv); } void bcm_vk_tty_terminate_tty_user(struct bcm_vk *vk) diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c index c36242b86b1d..04c0823e0359 100644 --- a/drivers/mmc/core/sdio_uart.c +++ b/drivers/mmc/core/sdio_uart.c @@ -1135,9 +1135,10 @@ static int __init sdio_uart_init(void) int ret; struct tty_driver *tty_drv; - sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR); - if (!tty_drv) - return -ENOMEM; + sdio_uart_tty_driver = tty_drv = tty_alloc_driver(UART_NR, + TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(tty_drv)) + return PTR_ERR(tty_drv); tty_drv->driver_name = "sdio_uart"; tty_drv->name = "ttySDIO"; @@ -1145,7 +1146,6 @@ static int __init sdio_uart_init(void) tty_drv->minor_start = 0; tty_drv->type = TTY_DRIVER_TYPE_SERIAL; tty_drv->subtype = SERIAL_TYPE_NORMAL; - tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_drv->init_termios = tty_std_termios; tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL; tty_drv->init_termios.c_ispeed = 4800; @@ -1165,7 +1165,7 @@ static int __init sdio_uart_init(void) err2: tty_unregister_driver(tty_drv); err1: - put_tty_driver(tty_drv); + tty_driver_kref_put(tty_drv); return ret; } @@ -1173,7 +1173,7 @@ static void __exit sdio_uart_exit(void) { sdio_unregister_driver(&sdio_uart_driver); tty_unregister_driver(sdio_uart_tty_driver); - put_tty_driver(sdio_uart_tty_driver); + tty_driver_kref_put(sdio_uart_tty_driver); } module_init(sdio_uart_init); diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 24bc1e678b7b..7dc1ef3f93c3 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -3241,9 +3241,10 @@ static int __init hso_init(void) serial_table[i] = NULL; /* allocate our driver using the proper amount of supported minors */ - tty_drv = alloc_tty_driver(HSO_SERIAL_TTY_MINORS); - if (!tty_drv) - return -ENOMEM; + tty_drv = tty_alloc_driver(HSO_SERIAL_TTY_MINORS, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(tty_drv)) + return PTR_ERR(tty_drv); /* fill in all needed values */ tty_drv->driver_name = driver_name; @@ -3256,7 +3257,6 @@ static int __init hso_init(void) tty_drv->minor_start = 0; tty_drv->type = TTY_DRIVER_TYPE_SERIAL; tty_drv->subtype = SERIAL_TYPE_NORMAL; - tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_drv->init_termios = tty_std_termios; hso_init_termios(&tty_drv->init_termios); tty_set_operations(tty_drv, &hso_serial_ops); @@ -3281,7 +3281,7 @@ static int __init hso_init(void) err_unreg_tty: tty_unregister_driver(tty_drv); err_free_tty: - put_tty_driver(tty_drv); + tty_driver_kref_put(tty_drv); return result; } @@ -3292,7 +3292,7 @@ static void __exit hso_exit(void) tty_unregister_driver(tty_drv); /* deregister the usb driver */ usb_deregister(&hso_driver); - put_tty_driver(tty_drv); + tty_driver_kref_put(tty_drv); } /* Module definitions */ diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c index 279d9df19c01..c61bbeeec2df 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -301,20 +301,13 @@ static acpi_status ssam_serdev_setup_via_acpi_crs(struct acpi_resource *rsc, void *ctx) { struct serdev_device *serdev = ctx; - struct acpi_resource_common_serialbus *serial; struct acpi_resource_uart_serialbus *uart; bool flow_control; int status = 0; - if (rsc->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) + if (!serdev_acpi_get_uart_resource(rsc, &uart)) return AE_OK; - serial = &rsc->data.common_serial_bus; - if (serial->type != ACPI_RESOURCE_SERIAL_TYPE_UART) - return AE_OK; - - uart = &rsc->data.uart_serial_bus; - /* Set up serdev device. */ serdev_device_set_baudrate(serdev, uart->default_baud_rate); diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 67c0009ca545..f356607835d8 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -1076,13 +1076,13 @@ static int __init tty3215_init(void) if (!CONSOLE_IS_3215) return 0; - driver = alloc_tty_driver(NR_3215); - if (!driver) - return -ENOMEM; + driver = tty_alloc_driver(NR_3215, TTY_DRIVER_REAL_RAW); + if (IS_ERR(driver)) + return PTR_ERR(driver); ret = ccw_driver_register(&raw3215_ccw_driver); if (ret) { - put_tty_driver(driver); + tty_driver_kref_put(driver); return ret; } /* @@ -1101,11 +1101,10 @@ static int __init tty3215_init(void) driver->init_termios.c_iflag = IGNBRK | IGNPAR; driver->init_termios.c_oflag = ONLCR; driver->init_termios.c_lflag = ISIG; - driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &tty3215_ops); ret = tty_register_driver(driver); if (ret) { - put_tty_driver(driver); + tty_driver_kref_put(driver); return ret; } tty3215_driver = driver; diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 6be9de8ed37d..971fbb52740b 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -503,20 +503,20 @@ sclp_tty_init(void) return 0; if (!sclp.has_linemode) return 0; - driver = alloc_tty_driver(1); - if (!driver) - return -ENOMEM; + driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); + if (IS_ERR(driver)) + return PTR_ERR(driver); rc = sclp_rw_init(); if (rc) { - put_tty_driver(driver); + tty_driver_kref_put(driver); return rc; } /* Allocate pages for output buffering */ for (i = 0; i < MAX_KMEM_PAGES; i++) { page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); if (page == NULL) { - put_tty_driver(driver); + tty_driver_kref_put(driver); return -ENOMEM; } list_add_tail((struct list_head *) page, &sclp_tty_pages); @@ -532,7 +532,7 @@ sclp_tty_init(void) rc = sclp_register(&sclp_input_event); if (rc) { - put_tty_driver(driver); + tty_driver_kref_put(driver); return rc; } @@ -548,12 +548,11 @@ sclp_tty_init(void) driver->init_termios.c_iflag = IGNBRK | IGNPAR; driver->init_termios.c_oflag = ONLCR; driver->init_termios.c_lflag = ISIG | ECHO; - driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &sclp_ops); tty_port_link_device(&sclp_port, driver, 0); rc = tty_register_driver(driver); if (rc) { - put_tty_driver(driver); + tty_driver_kref_put(driver); tty_port_destroy(&sclp_port); return rc; } diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index da2496306c04..29a6a0099f83 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -732,9 +732,9 @@ static int __init sclp_vt220_tty_init(void) /* Note: we're not testing for CONSOLE_IS_SCLP here to preserve * symmetry between VM and LPAR systems regarding ttyS1. */ - driver = alloc_tty_driver(1); - if (!driver) - return -ENOMEM; + driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); + if (IS_ERR(driver)) + return PTR_ERR(driver); rc = __sclp_vt220_init(MAX_KMEM_PAGES); if (rc) goto out_driver; @@ -746,7 +746,6 @@ static int __init sclp_vt220_tty_init(void) driver->type = TTY_DRIVER_TYPE_SYSTEM; driver->subtype = SYSTEM_TYPE_TTY; driver->init_termios = tty_std_termios; - driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(driver, &sclp_vt220_ops); tty_port_link_device(&sclp_vt220_port, driver, 0); @@ -764,7 +763,7 @@ out_reg: out_init: __sclp_vt220_cleanup(); out_driver: - put_tty_driver(driver); + tty_driver_kref_put(driver); return rc; } __initcall(sclp_vt220_tty_init); diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index adc33846bf8e..5c83f71c1d0e 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -1935,7 +1935,7 @@ static int __init tty3270_init(void) tty_set_operations(driver, &tty3270_ops); ret = tty_register_driver(driver); if (ret) { - put_tty_driver(driver); + tty_driver_kref_put(driver); return ret; } tty3270_driver = driver; @@ -1952,7 +1952,7 @@ tty3270_exit(void) driver = tty3270_driver; tty3270_driver = NULL; tty_unregister_driver(driver); - put_tty_driver(driver); + tty_driver_kref_put(driver); tty3270_del_views(); } diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index 38a280e876c2..e8fa7f53cd5e 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c @@ -2852,11 +2852,11 @@ unregister_loop: tty_unregister_driver(fwloop_driver); put_loop: if (create_loop_dev) - put_tty_driver(fwloop_driver); + tty_driver_kref_put(fwloop_driver); unregister_driver: tty_unregister_driver(fwtty_driver); put_tty: - put_tty_driver(fwtty_driver); + tty_driver_kref_put(fwtty_driver); remove_debugfs: debugfs_remove_recursive(fwserial_debugfs); @@ -2871,10 +2871,10 @@ static void __exit fwserial_exit(void) kmem_cache_destroy(fwtty_txn_cache); if (create_loop_dev) { tty_unregister_driver(fwloop_driver); - put_tty_driver(fwloop_driver); + tty_driver_kref_put(fwloop_driver); } tty_unregister_driver(fwtty_driver); - put_tty_driver(fwtty_driver); + tty_driver_kref_put(fwtty_driver); debugfs_remove_recursive(fwserial_debugfs); } diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c index 279de2cd9c4a..04df6f9f5403 100644 --- a/drivers/staging/gdm724x/gdm_tty.c +++ b/drivers/staging/gdm724x/gdm_tty.c @@ -281,9 +281,10 @@ int register_lte_tty_driver(void) int ret; for (i = 0; i < TTY_MAX_COUNT; i++) { - tty_driver = alloc_tty_driver(GDM_TTY_MINOR); - if (!tty_driver) - return -ENOMEM; + tty_driver = tty_alloc_driver(GDM_TTY_MINOR, + TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(tty_driver)) + return PTR_ERR(tty_driver); tty_driver->owner = THIS_MODULE; tty_driver->driver_name = DRIVER_STRING[i]; @@ -291,8 +292,6 @@ int register_lte_tty_driver(void) tty_driver->major = GDM_TTY_MAJOR; tty_driver->type = TTY_DRIVER_TYPE_SERIAL; tty_driver->subtype = SERIAL_TYPE_NORMAL; - tty_driver->flags = TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV; tty_driver->init_termios = tty_std_termios; tty_driver->init_termios.c_cflag = B9600 | CS8 | HUPCL | CLOCAL; tty_driver->init_termios.c_lflag = ISIG | ICANON | IEXTEN; @@ -300,7 +299,7 @@ int register_lte_tty_driver(void) ret = tty_register_driver(tty_driver); if (ret) { - put_tty_driver(tty_driver); + tty_driver_kref_put(tty_driver); return ret; } @@ -319,7 +318,7 @@ void unregister_lte_tty_driver(void) tty_driver = gdm_driver[i]; if (tty_driver) { tty_unregister_driver(tty_driver); - put_tty_driver(tty_driver); + tty_driver_kref_put(tty_driver); } } } diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index 73f01ed1e5b7..e6d860a9678e 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -973,7 +973,7 @@ static int gb_tty_init(void) return 0; fail_put_gb_tty: - put_tty_driver(gb_tty_driver); + tty_driver_kref_put(gb_tty_driver); fail_unregister_dev: return retval; } @@ -981,7 +981,7 @@ fail_unregister_dev: static void gb_tty_exit(void) { tty_unregister_driver(gb_tty_driver); - put_tty_driver(gb_tty_driver); + tty_driver_kref_put(gb_tty_driver); idr_destroy(&tty_minors); } diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 5ec19c48fb7a..1e60dbef676c 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -22,8 +22,6 @@ * */ -#include <linux/delay.h> - /* Set of debugging defines */ #undef SERIAL_DEBUG_INTR @@ -31,55 +29,42 @@ #undef SERIAL_DEBUG_FLOW #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT -/* Sanity checks */ - -#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) -#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - tty->name, (info->tport.flags), serial_driver->refcount,info->count,tty->count,s) -#else -#define DBG_CNT(s) -#endif - /* * End of serial driver configuration section. */ -#include <linux/module.h> - -#include <linux/types.h> -#include <linux/serial.h> -#include <linux/serial_reg.h> -static char *serial_version = "4.30"; - -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> +#include <linux/bitops.h> #include <linux/circ_buf.h> #include <linux/console.h> -#include <linux/major.h> -#include <linux/string.h> +#include <linux/delay.h> +#include <linux/errno.h> #include <linux/fcntl.h> -#include <linux/ptrace.h> +#include <linux/init.h> +#include <linux/interrupt.h> #include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/major.h> #include <linux/mm.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/ptrace.h> #include <linux/seq_file.h> +#include <linux/serial.h> +#include <linux/serial_reg.h> +#include <linux/sched.h> +#include <linux/signal.h> #include <linux/slab.h> -#include <linux/init.h> -#include <linux/bitops.h> -#include <linux/platform_device.h> - -#include <asm/setup.h> - - -#include <asm/irq.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/tty_flip.h> +#include <linux/tty.h> +#include <linux/types.h> +#include <linux/uaccess.h> #include <asm/amigahw.h> #include <asm/amigaints.h> +#include <asm/irq.h> +#include <asm/setup.h> struct serial_state { struct tty_port tport; @@ -88,7 +73,6 @@ struct serial_state { unsigned long port; int baud_base; - int xmit_fifo_size; int custom_divisor; int read_status_mask; int ignore_status_mask; @@ -99,14 +83,13 @@ struct serial_state { int x_char; /* xon/xoff character */ }; -#define custom amiga_custom -static char *serial_name = "Amiga-builtin serial driver"; - static struct tty_driver *serial_driver; /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 +#define XMIT_FIFO_SIZE 1 + static unsigned char current_ctl_bits; static void change_speed(struct tty_struct *tty, struct serial_state *info, @@ -114,13 +97,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, static void rs_wait_until_sent(struct tty_struct *tty, int timeout); -static struct serial_state rs_table[1]; - -#define NR_PORTS ARRAY_SIZE(rs_table) - -#include <linux/uaccess.h> - -#define serial_isroot() (capable(CAP_SYS_ADMIN)) +static struct serial_state serial_state; /* some serial hardware definitions */ #define SDR_OVRUN (1<<15) @@ -161,9 +138,9 @@ static void rs_stop(struct tty_struct *tty) if (info->IER & UART_IER_THRI) { info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ - custom.intena = IF_TBE; + amiga_custom.intena = IF_TBE; mb(); - custom.intreq = IF_TBE; + amiga_custom.intreq = IF_TBE; mb(); } local_irq_restore(flags); @@ -179,10 +156,10 @@ static void rs_start(struct tty_struct *tty) && info->xmit.buf && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; - custom.intena = IF_SETCLR | IF_TBE; + amiga_custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ - custom.intreq = IF_SETCLR | IF_TBE; + amiga_custom.intreq = IF_SETCLR | IF_TBE; mb(); } local_irq_restore(flags); @@ -191,21 +168,8 @@ static void rs_start(struct tty_struct *tty) /* * ---------------------------------------------------------------------- * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. + * Here start the interrupt handling routines. * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 * ----------------------------------------------------------------------- */ @@ -220,9 +184,9 @@ static void receive_chars(struct serial_state *info) icount = &info->icount; status = UART_LSR_DR; /* We obviously have a character! */ - serdatr = custom.serdatr; + serdatr = amiga_custom.serdatr; mb(); - custom.intreq = IF_RBF; + amiga_custom.intreq = IF_RBF; mb(); if((serdatr & 0x1ff) == 0) @@ -299,10 +263,10 @@ out: static void transmit_chars(struct serial_state *info) { - custom.intreq = IF_TBE; + amiga_custom.intreq = IF_TBE; mb(); if (info->x_char) { - custom.serdat = info->x_char | 0x100; + amiga_custom.serdat = info->x_char | 0x100; mb(); info->icount.tx++; info->x_char = 0; @@ -312,12 +276,12 @@ static void transmit_chars(struct serial_state *info) || info->tport.tty->flow.stopped || info->tport.tty->hw_stopped) { info->IER &= ~UART_IER_THRI; - custom.intena = IF_TBE; + amiga_custom.intena = IF_TBE; mb(); return; } - custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100; + amiga_custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100; mb(); info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1); info->icount.tx++; @@ -331,7 +295,7 @@ static void transmit_chars(struct serial_state *info) printk("THRE..."); #endif if (info->xmit.head == info->xmit.tail) { - custom.intena = IF_TBE; + amiga_custom.intena = IF_TBE; mb(); info->IER &= ~UART_IER_THRI; } @@ -384,10 +348,10 @@ static void check_modem_status(struct serial_state *info) #endif port->tty->hw_stopped = 0; info->IER |= UART_IER_THRI; - custom.intena = IF_SETCLR | IF_TBE; + amiga_custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ - custom.intreq = IF_SETCLR | IF_TBE; + amiga_custom.intreq = IF_SETCLR | IF_TBE; mb(); tty_wakeup(port->tty); return; @@ -400,9 +364,9 @@ static void check_modem_status(struct serial_state *info) port->tty->hw_stopped = 1; info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ - custom.intena = IF_TBE; + amiga_custom.intena = IF_TBE; mb(); - custom.intreq = IF_TBE; + amiga_custom.intreq = IF_TBE; mb(); } } @@ -444,7 +408,7 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id) { struct serial_state *info = dev_id; - if (custom.serdatr & SDR_TBE) { + if (amiga_custom.serdatr & SDR_TBE) { #ifdef SERIAL_DEBUG_INTR printk("ser_tx_int..."); #endif @@ -504,20 +468,20 @@ static int startup(struct tty_struct *tty, struct serial_state *info) /* Clear anything in the input buffer */ - custom.intreq = IF_RBF; + amiga_custom.intreq = IF_RBF; mb(); retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info); if (retval) { - if (serial_isroot()) { - set_bit(TTY_IO_ERROR, &tty->flags); - retval = 0; - } - goto errout; + if (capable(CAP_SYS_ADMIN)) { + set_bit(TTY_IO_ERROR, &tty->flags); + retval = 0; + } + goto errout; } /* enable both Rx and Tx interrupts */ - custom.intena = IF_SETCLR | IF_RBF | IF_TBE; + amiga_custom.intena = IF_SETCLR | IF_RBF | IF_TBE; mb(); info->IER = UART_IER_MSI; @@ -553,13 +517,10 @@ errout: static void shutdown(struct tty_struct *tty, struct serial_state *info) { unsigned long flags; - struct serial_state *state; if (!tty_port_initialized(&info->tport)) return; - state = info; - #ifdef SERIAL_DEBUG_OPEN printk("Shutting down serial port %d ....\n", info->line); #endif @@ -583,11 +544,11 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info) } info->IER = 0; - custom.intena = IF_RBF | IF_TBE; + amiga_custom.intena = IF_RBF | IF_TBE; mb(); /* disable break condition */ - custom.adkcon = AC_UARTBRK; + amiga_custom.adkcon = AC_UARTBRK; mb(); if (C_HUPCL(tty)) @@ -671,7 +632,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, if (!quot) quot = baud_base / 9600; info->quot = quot; - info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); + info->timeout = (XMIT_FIFO_SIZE*HZ*bits*quot) / baud_base; info->timeout += HZ/50; /* Add .02 seconds of slop */ /* CTS flow control flag and modem status interrupts */ @@ -731,7 +692,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info, if(cval & UART_LCR_PARITY) serper |= (SERPER_PARENB); - custom.serper = serper; + amiga_custom.serper = serper; mb(); } @@ -775,10 +736,10 @@ static void rs_flush_chars(struct tty_struct *tty) local_irq_save(flags); info->IER |= UART_IER_THRI; - custom.intena = IF_SETCLR | IF_TBE; + amiga_custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ - custom.intreq = IF_SETCLR | IF_TBE; + amiga_custom.intreq = IF_SETCLR | IF_TBE; mb(); local_irq_restore(flags); } @@ -817,10 +778,10 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; local_irq_disable(); - custom.intena = IF_SETCLR | IF_TBE; + amiga_custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ - custom.intreq = IF_SETCLR | IF_TBE; + amiga_custom.intreq = IF_SETCLR | IF_TBE; mb(); local_irq_restore(flags); } @@ -867,11 +828,11 @@ static void rs_send_xchar(struct tty_struct *tty, char ch) /* Check this ! */ local_irq_save(flags); - if(!(custom.intenar & IF_TBE)) { - custom.intena = IF_SETCLR | IF_TBE; + if(!(amiga_custom.intenar & IF_TBE)) { + amiga_custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ - custom.intreq = IF_SETCLR | IF_TBE; + amiga_custom.intreq = IF_SETCLR | IF_TBE; mb(); } local_irq_restore(flags); @@ -948,7 +909,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) ss->line = tty->index; ss->port = state->port; ss->flags = state->tport.flags; - ss->xmit_fifo_size = state->xmit_fifo_size; + ss->xmit_fifo_size = XMIT_FIFO_SIZE; ss->baud_base = state->baud_base; ss->close_delay = close_delay; ss->closing_wait = closing_wait; @@ -969,7 +930,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) change_spd = ((ss->flags ^ port->flags) & ASYNC_SPD_MASK) || ss->custom_divisor != state->custom_divisor; if (ss->irq || ss->port != state->port || - ss->xmit_fifo_size != state->xmit_fifo_size) { + ss->xmit_fifo_size != XMIT_FIFO_SIZE) { tty_unlock(tty); return -EINVAL; } @@ -979,11 +940,10 @@ static int set_serial_info(struct tty_struct *tty, struct serial_struct *ss) if (closing_wait != ASYNC_CLOSING_WAIT_NONE) closing_wait = msecs_to_jiffies(closing_wait * 10); - if (!serial_isroot()) { + if (!capable(CAP_SYS_ADMIN)) { if ((ss->baud_base != state->baud_base) || (close_delay != port->close_delay) || (closing_wait != port->closing_wait) || - (ss->xmit_fifo_size != state->xmit_fifo_size) || ((ss->flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { tty_unlock(tty); @@ -1043,7 +1003,7 @@ static int get_lsr_info(struct serial_state *info, unsigned int __user *value) unsigned long flags; local_irq_save(flags); - status = custom.serdatr; + status = amiga_custom.serdatr; mb(); local_irq_restore(flags); result = ((status & SDR_TSRE) ? TIOCSER_TEMT : 0); @@ -1105,9 +1065,9 @@ static int rs_break(struct tty_struct *tty, int break_state) local_irq_save(flags); if (break_state == -1) - custom.adkcon = AC_SETCLR | AC_UARTBRK; + amiga_custom.adkcon = AC_SETCLR | AC_UARTBRK; else - custom.adkcon = AC_UARTBRK; + amiga_custom.adkcon = AC_UARTBRK; mb(); local_irq_restore(flags); return 0; @@ -1284,10 +1244,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp) state->read_status_mask &= ~UART_LSR_DR; if (tty_port_initialized(port)) { /* disable receive interrupts */ - custom.intena = IF_RBF; + amiga_custom.intena = IF_RBF; mb(); /* clear any pending receive interrupt */ - custom.intreq = IF_RBF; + amiga_custom.intreq = IF_RBF; mb(); /* @@ -1315,9 +1275,6 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) unsigned long orig_jiffies, char_time; int lsr; - if (info->xmit_fifo_size == 0) - return; /* Just in case.... */ - orig_jiffies = jiffies; /* @@ -1328,7 +1285,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ - char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; + char_time = (info->timeout - HZ/50) / XMIT_FIFO_SIZE; char_time = char_time / 5; if (char_time == 0) char_time = 1; @@ -1349,7 +1306,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); printk("jiff=%lu...", jiffies); #endif - while(!((lsr = custom.serdatr) & SDR_TSRE)) { + while(!((lsr = amiga_custom.serdatr) & SDR_TSRE)) { #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("serdatr = %d (jiff=%lu)...", lsr, jiffies); #endif @@ -1389,14 +1346,14 @@ static void rs_hangup(struct tty_struct *tty) */ static int rs_open(struct tty_struct *tty, struct file * filp) { - struct serial_state *info = rs_table + tty->index; - struct tty_port *port = &info->tport; + struct tty_port *port = tty->port; + struct serial_state *info = container_of(port, struct serial_state, + tport); int retval; port->count++; port->tty = tty; tty->driver_data = info; - tty->port = port; retval = startup(tty, info); if (retval) { @@ -1461,8 +1418,8 @@ static inline void line_info(struct seq_file *m, int line, static int rs_proc_show(struct seq_file *m, void *v) { - seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); - line_info(m, 0, &rs_table[0]); + seq_printf(m, "serinfo:1.0 driver:4.30\n"); + line_info(m, 0, &serial_state); return 0; } @@ -1474,17 +1431,6 @@ static int rs_proc_show(struct seq_file *m, void *v) * --------------------------------------------------------------------- */ -/* - * This routine prints out the appropriate serial driver version - * number, and identifies which options were configured into this - * driver. - */ -static void show_serial_version(void) -{ - printk(KERN_INFO "%s version %s\n", serial_name, serial_version); -} - - static const struct tty_operations serial_ops = { .open = rs_open, .close = rs_close, @@ -1543,52 +1489,43 @@ static const struct tty_port_operations amiga_port_ops = { */ static int __init amiga_serial_probe(struct platform_device *pdev) { + struct serial_state *state = &serial_state; + struct tty_driver *driver; unsigned long flags; - struct serial_state * state; int error; - serial_driver = alloc_tty_driver(NR_PORTS); - if (!serial_driver) - return -ENOMEM; - - show_serial_version(); + driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); + if (IS_ERR(driver)) + return PTR_ERR(driver); /* Initialize the tty_driver structure */ - serial_driver->driver_name = "amiserial"; - serial_driver->name = "ttyS"; - serial_driver->major = TTY_MAJOR; - serial_driver->minor_start = 64; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = + driver->driver_name = "amiserial"; + driver->name = "ttyS"; + driver->major = TTY_MAJOR; + driver->minor_start = 64; + driver->type = TTY_DRIVER_TYPE_SERIAL; + driver->subtype = SERIAL_TYPE_NORMAL; + driver->init_termios = tty_std_termios; + driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(serial_driver, &serial_ops); - - state = rs_table; - state->port = (int)&custom.serdatr; /* Just to give it a value */ - state->custom_divisor = 0; - state->icount.cts = state->icount.dsr = - state->icount.rng = state->icount.dcd = 0; - state->icount.rx = state->icount.tx = 0; - state->icount.frame = state->icount.parity = 0; - state->icount.overrun = state->icount.brk = 0; + tty_set_operations(driver, &serial_ops); + + memset(state, 0, sizeof(*state)); + state->port = (int)&amiga_custom.serdatr; /* Just to give it a value */ tty_port_init(&state->tport); state->tport.ops = &amiga_port_ops; - tty_port_link_device(&state->tport, serial_driver, 0); + tty_port_link_device(&state->tport, driver, 0); - error = tty_register_driver(serial_driver); + error = tty_register_driver(driver); if (error) - goto fail_put_tty_driver; + goto fail_tty_driver_kref_put; printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n"); /* Hardware set up */ state->baud_base = amiga_colorclock; - state->xmit_fifo_size = 1; /* set ISRs, and then disable the rx interrupts */ error = request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state); @@ -1603,11 +1540,11 @@ static int __init amiga_serial_probe(struct platform_device *pdev) local_irq_save(flags); /* turn off Rx and Tx interrupts */ - custom.intena = IF_RBF | IF_TBE; + amiga_custom.intena = IF_RBF | IF_TBE; mb(); /* clear any pending interrupt */ - custom.intreq = IF_RBF | IF_TBE; + amiga_custom.intreq = IF_RBF | IF_TBE; mb(); local_irq_restore(flags); @@ -1621,15 +1558,17 @@ static int __init amiga_serial_probe(struct platform_device *pdev) platform_set_drvdata(pdev, state); + serial_driver = driver; + return 0; fail_free_irq: free_irq(IRQ_AMIGA_TBE, state); fail_unregister: - tty_unregister_driver(serial_driver); -fail_put_tty_driver: + tty_unregister_driver(driver); +fail_tty_driver_kref_put: tty_port_destroy(&state->tport); - put_tty_driver(serial_driver); + tty_driver_kref_put(driver); return error; } @@ -1637,9 +1576,8 @@ static int __exit amiga_serial_remove(struct platform_device *pdev) { struct serial_state *state = platform_get_drvdata(pdev); - /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ tty_unregister_driver(serial_driver); - put_tty_driver(serial_driver); + tty_driver_kref_put(serial_driver); tty_port_destroy(&state->tport); free_irq(IRQ_AMIGA_TBE, state); @@ -1668,8 +1606,8 @@ module_platform_driver_probe(amiga_serial_driver, amiga_serial_probe); static void amiga_serial_putc(char c) { - custom.serdat = (unsigned char)c | 0x100; - while (!(custom.serdatr & 0x2000)) + amiga_custom.serdat = (unsigned char)c | 0x100; + while (!(amiga_custom.serdatr & 0x2000)) barrier(); } @@ -1682,9 +1620,9 @@ static void amiga_serial_putc(char c) static void serial_console_write(struct console *co, const char *s, unsigned count) { - unsigned short intena = custom.intenar; + unsigned short intena = amiga_custom.intenar; - custom.intena = IF_TBE; + amiga_custom.intena = IF_TBE; while (count--) { if (*s == '\n') @@ -1692,7 +1630,7 @@ static void serial_console_write(struct console *co, const char *s, amiga_serial_putc(*s++); } - custom.intena = IF_SETCLR | (intena & IF_TBE); + amiga_custom.intena = IF_SETCLR | (intena & IF_TBE); } static struct tty_driver *serial_console_device(struct console *c, int *index) diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 445e5ff9b36d..19d32cb6af84 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -751,6 +751,7 @@ static struct platform_driver ehv_bc_tty_driver = { */ static int __init ehv_bc_init(void) { + struct tty_driver *driver; struct device_node *np; unsigned int count = 0; /* Number of elements in bcs[] */ int ret; @@ -773,26 +774,28 @@ static int __init ehv_bc_init(void) if (!bcs) return -ENOMEM; - ehv_bc_driver = alloc_tty_driver(count); - if (!ehv_bc_driver) { - ret = -ENOMEM; + driver = tty_alloc_driver(count, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(driver)) { + ret = PTR_ERR(driver); goto err_free_bcs; } - ehv_bc_driver->driver_name = "ehv-bc"; - ehv_bc_driver->name = ehv_bc_console.name; - ehv_bc_driver->type = TTY_DRIVER_TYPE_CONSOLE; - ehv_bc_driver->subtype = SYSTEM_TYPE_CONSOLE; - ehv_bc_driver->init_termios = tty_std_termios; - ehv_bc_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_set_operations(ehv_bc_driver, &ehv_bc_ops); + driver->driver_name = "ehv-bc"; + driver->name = ehv_bc_console.name; + driver->type = TTY_DRIVER_TYPE_CONSOLE; + driver->subtype = SYSTEM_TYPE_CONSOLE; + driver->init_termios = tty_std_termios; + tty_set_operations(driver, &ehv_bc_ops); - ret = tty_register_driver(ehv_bc_driver); + ret = tty_register_driver(driver); if (ret) { pr_err("ehv-bc: could not register tty driver (ret=%i)\n", ret); - goto err_put_tty_driver; + goto err_tty_driver_kref_put; } + ehv_bc_driver = driver; + ret = platform_driver_register(&ehv_bc_tty_driver); if (ret) { pr_err("ehv-bc: could not register platform driver (ret=%i)\n", @@ -803,9 +806,10 @@ static int __init ehv_bc_init(void) return 0; err_deregister_tty_driver: - tty_unregister_driver(ehv_bc_driver); -err_put_tty_driver: - put_tty_driver(ehv_bc_driver); + ehv_bc_driver = NULL; + tty_unregister_driver(driver); +err_tty_driver_kref_put: + tty_driver_kref_put(driver); err_free_bcs: kfree(bcs); diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index ccb683a6e6f5..d24af649a8bb 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -253,18 +253,18 @@ static int goldfish_tty_create_driver(void) ret = -ENOMEM; goto err_alloc_goldfish_ttys_failed; } - tty = alloc_tty_driver(goldfish_tty_line_count); - if (tty == NULL) { - ret = -ENOMEM; - goto err_alloc_tty_driver_failed; + tty = tty_alloc_driver(goldfish_tty_line_count, + TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(tty)) { + ret = PTR_ERR(tty); + goto err_tty_alloc_driver_failed; } tty->driver_name = "goldfish"; tty->name = "ttyGF"; tty->type = TTY_DRIVER_TYPE_SERIAL; tty->subtype = SERIAL_TYPE_NORMAL; tty->init_termios = tty_std_termios; - tty->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(tty, &goldfish_tty_ops); ret = tty_register_driver(tty); if (ret) @@ -274,8 +274,8 @@ static int goldfish_tty_create_driver(void) return 0; err_tty_register_driver_failed: - put_tty_driver(tty); -err_alloc_tty_driver_failed: + tty_driver_kref_put(tty); +err_tty_alloc_driver_failed: kfree(goldfish_ttys); goldfish_ttys = NULL; err_alloc_goldfish_ttys_failed: @@ -285,7 +285,7 @@ err_alloc_goldfish_ttys_failed: static void goldfish_tty_delete_driver(void) { tty_unregister_driver(goldfish_tty_driver); - put_tty_driver(goldfish_tty_driver); + tty_driver_kref_put(goldfish_tty_driver); goldfish_tty_driver = NULL; kfree(goldfish_ttys); goldfish_ttys = NULL; diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 5bb8c4e44961..7b30d5a05e2f 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -1021,9 +1021,10 @@ static int hvc_init(void) int err; /* We need more than hvc_count adapters due to hotplug additions. */ - drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); - if (!drv) { - err = -ENOMEM; + drv = tty_alloc_driver(HVC_ALLOC_TTY_ADAPTERS, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_RESET_TERMIOS); + if (IS_ERR(drv)) { + err = PTR_ERR(drv); goto out; } @@ -1033,7 +1034,6 @@ static int hvc_init(void) drv->minor_start = HVC_MINOR; drv->type = TTY_DRIVER_TYPE_SYSTEM; drv->init_termios = tty_std_termios; - drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; tty_set_operations(drv, &hvc_ops); /* Always start the kthread because there can be hotplug vty adapters @@ -1063,7 +1063,7 @@ stop_thread: kthread_stop(hvc_task); hvc_task = NULL; put_tty: - put_tty_driver(drv); + tty_driver_kref_put(drv); out: return err; } diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 92c9a476defc..8f143c09a169 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -86,7 +86,11 @@ static int __write_console(struct xencons_info *xencons, cons = intf->out_cons; prod = intf->out_prod; mb(); /* update queue values before going on */ - BUG_ON((prod - cons) > sizeof(intf->out)); + + if ((prod - cons) > sizeof(intf->out)) { + pr_err_once("xencons: Illegal ring page indices"); + return -EINVAL; + } while ((sent < len) && ((prod - cons) < sizeof(intf->out))) intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++]; @@ -114,7 +118,10 @@ static int domU_write_console(uint32_t vtermno, const char *data, int len) */ while (len) { int sent = __write_console(cons, data, len); - + + if (sent < 0) + return sent; + data += sent; len -= sent; @@ -138,7 +145,11 @@ static int domU_read_console(uint32_t vtermno, char *buf, int len) cons = intf->in_cons; prod = intf->in_prod; mb(); /* get pointers before reading ring */ - BUG_ON((prod - cons) > sizeof(intf->in)); + + if ((prod - cons) > sizeof(intf->in)) { + pr_err_once("xencons: Illegal ring page indices"); + return -EINVAL; + } while (cons != prod && recv < len) buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)]; diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index fe5e6b4f43de..245da1dfd818 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -1445,10 +1445,11 @@ static int hvcs_initialize(void) } else num_ttys_to_alloc = hvcs_parm_num_devs; - hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc); - if (!hvcs_tty_driver) { + hvcs_tty_driver = tty_alloc_driver(num_ttys_to_alloc, + TTY_DRIVER_REAL_RAW); + if (IS_ERR(hvcs_tty_driver)) { mutex_unlock(&hvcs_init_mutex); - return -ENOMEM; + return PTR_ERR(hvcs_tty_driver); } if (hvcs_alloc_index_list(num_ttys_to_alloc)) { @@ -1473,7 +1474,6 @@ static int hvcs_initialize(void) * throw us into a horrible recursive echo-echo-echo loop. */ hvcs_tty_driver->init_termios = hvcs_tty_termios; - hvcs_tty_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(hvcs_tty_driver, &hvcs_ops); @@ -1509,7 +1509,7 @@ buff_alloc_fail: register_fail: hvcs_free_index_list(); index_fail: - put_tty_driver(hvcs_tty_driver); + tty_driver_kref_put(hvcs_tty_driver); hvcs_tty_driver = NULL; mutex_unlock(&hvcs_init_mutex); return rc; @@ -1562,7 +1562,7 @@ static void __exit hvcs_module_exit(void) hvcs_free_index_list(); - put_tty_driver(hvcs_tty_driver); + tty_driver_kref_put(hvcs_tty_driver); printk(KERN_INFO "HVCS: driver module removed.\n"); } diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index bfc15279d5bc..aa81f4835fef 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -1038,29 +1038,29 @@ static const struct tty_operations hvsi_ops = { static int __init hvsi_init(void) { - int i; - - hvsi_driver = alloc_tty_driver(hvsi_count); - if (!hvsi_driver) - return -ENOMEM; - - hvsi_driver->driver_name = "hvsi"; - hvsi_driver->name = "hvsi"; - hvsi_driver->major = HVSI_MAJOR; - hvsi_driver->minor_start = HVSI_MINOR; - hvsi_driver->type = TTY_DRIVER_TYPE_SYSTEM; - hvsi_driver->init_termios = tty_std_termios; - hvsi_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; - hvsi_driver->init_termios.c_ispeed = 9600; - hvsi_driver->init_termios.c_ospeed = 9600; - hvsi_driver->flags = TTY_DRIVER_REAL_RAW; - tty_set_operations(hvsi_driver, &hvsi_ops); + struct tty_driver *driver; + int i, ret; + + driver = tty_alloc_driver(hvsi_count, TTY_DRIVER_REAL_RAW); + if (IS_ERR(driver)) + return PTR_ERR(driver); + + driver->driver_name = "hvsi"; + driver->name = "hvsi"; + driver->major = HVSI_MAJOR; + driver->minor_start = HVSI_MINOR; + driver->type = TTY_DRIVER_TYPE_SYSTEM; + driver->init_termios = tty_std_termios; + driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; + driver->init_termios.c_ispeed = 9600; + driver->init_termios.c_ospeed = 9600; + tty_set_operations(driver, &hvsi_ops); for (i=0; i < hvsi_count; i++) { struct hvsi_struct *hp = &hvsi_ports[i]; int ret = 1; - tty_port_link_device(&hp->port, hvsi_driver, i); + tty_port_link_device(&hp->port, driver, i); ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp); if (ret) @@ -1069,12 +1069,27 @@ static int __init hvsi_init(void) } hvsi_wait = wait_for_state; /* irqs active now */ - if (tty_register_driver(hvsi_driver)) - panic("Couldn't register hvsi console driver\n"); + ret = tty_register_driver(driver); + if (ret) { + pr_err("Couldn't register hvsi console driver\n"); + goto err_free_irq; + } + + hvsi_driver = driver; printk(KERN_DEBUG "HVSI: registered %i devices\n", hvsi_count); return 0; +err_free_irq: + hvsi_wait = poll_for_state; + for (i = 0; i < hvsi_count; i++) { + struct hvsi_struct *hp = &hvsi_ports[i]; + + free_irq(hp->virq, hp); + } + tty_driver_kref_put(driver); + + return ret; } device_initcall(hvsi_init); diff --git a/drivers/tty/ipwireless/tty.c b/drivers/tty/ipwireless/tty.c index e3a5a5ba752c..9edd5ae17580 100644 --- a/drivers/tty/ipwireless/tty.c +++ b/drivers/tty/ipwireless/tty.c @@ -564,9 +564,10 @@ int ipwireless_tty_init(void) { int result; - ipw_tty_driver = alloc_tty_driver(IPWIRELESS_PCMCIA_MINORS); - if (!ipw_tty_driver) - return -ENOMEM; + ipw_tty_driver = tty_alloc_driver(IPWIRELESS_PCMCIA_MINORS, + TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(ipw_tty_driver)) + return PTR_ERR(ipw_tty_driver); ipw_tty_driver->driver_name = IPWIRELESS_PCCARD_NAME; ipw_tty_driver->name = "ttyIPWp"; @@ -574,7 +575,6 @@ int ipwireless_tty_init(void) ipw_tty_driver->minor_start = IPWIRELESS_PCMCIA_START; ipw_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; ipw_tty_driver->subtype = SERIAL_TYPE_NORMAL; - ipw_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; ipw_tty_driver->init_termios = tty_std_termios; ipw_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -585,7 +585,7 @@ int ipwireless_tty_init(void) if (result) { printk(KERN_ERR IPWIRELESS_PCCARD_NAME ": failed to register tty driver\n"); - put_tty_driver(ipw_tty_driver); + tty_driver_kref_put(ipw_tty_driver); return result; } @@ -595,7 +595,7 @@ int ipwireless_tty_init(void) void ipwireless_tty_release(void) { tty_unregister_driver(ipw_tty_driver); - put_tty_driver(ipw_tty_driver); + tty_driver_kref_put(ipw_tty_driver); } int ipwireless_tty_is_modem(struct ipw_tty *tty) diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 3b5915b94fac..02c10a968de1 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -1042,7 +1042,7 @@ err_destroy_ports: dport = &priv->ports[nport]; tty_port_destroy(&dport->port); } - put_tty_driver(priv->driver); + tty_driver_kref_put(priv->driver); return ret; } diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 64b18177c790..bf17e90858b8 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1053,7 +1053,7 @@ static int __init moxa_init(void) if (tty_register_driver(moxaDriver)) { printk(KERN_ERR "can't register MOXA Smartio tty driver!\n"); - put_tty_driver(moxaDriver); + tty_driver_kref_put(moxaDriver); return -1; } @@ -1119,7 +1119,7 @@ static void __exit moxa_exit(void) del_timer_sync(&moxaTimer); tty_unregister_driver(moxaDriver); - put_tty_driver(moxaDriver); + tty_driver_kref_put(moxaDriver); } module_init(moxa_init); @@ -2034,10 +2034,10 @@ static int moxa_get_serial_info(struct tty_struct *tty, if (!info) return -ENODEV; mutex_lock(&info->port.mutex); - ss->type = info->type, - ss->line = info->port.tty->index, - ss->flags = info->port.flags, - ss->baud_base = 921600, + ss->type = info->type; + ss->line = info->port.tty->index; + ss->flags = info->port.flags; + ss->baud_base = 921600; ss->close_delay = jiffies_to_msecs(info->port.close_delay) / 10; mutex_unlock(&info->port.mutex); return 0; diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 900ccb2ca166..1216f3985e18 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -1039,12 +1039,12 @@ static int mxser_get_serial_info(struct tty_struct *tty, if (closing_wait != ASYNC_CLOSING_WAIT_NONE) closing_wait = jiffies_to_msecs(closing_wait) / 10; - ss->type = info->type, - ss->line = tty->index, - ss->port = info->ioaddr, - ss->irq = info->board->irq, - ss->flags = info->port.flags, - ss->baud_base = MXSER_BAUD_BASE, + ss->type = info->type; + ss->line = tty->index; + ss->port = info->ioaddr; + ss->irq = info->board->irq; + ss->flags = info->port.flags; + ss->baud_base = MXSER_BAUD_BASE; ss->close_delay = close_delay; ss->closing_wait = closing_wait; ss->custom_divisor = MXSER_CUSTOM_DIVISOR, @@ -1976,9 +1976,10 @@ static int __init mxser_module_init(void) { int retval; - mxvar_sdriver = alloc_tty_driver(MXSER_PORTS); - if (!mxvar_sdriver) - return -ENOMEM; + mxvar_sdriver = tty_alloc_driver(MXSER_PORTS, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(mxvar_sdriver)) + return PTR_ERR(mxvar_sdriver); /* Initialize the tty_driver structure */ mxvar_sdriver->name = "ttyMI"; @@ -1988,7 +1989,6 @@ static int __init mxser_module_init(void) mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL; mxvar_sdriver->init_termios = tty_std_termios; mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; - mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(mxvar_sdriver, &mxser_ops); retval = tty_register_driver(mxvar_sdriver); @@ -2008,7 +2008,7 @@ static int __init mxser_module_init(void) err_unr: tty_unregister_driver(mxvar_sdriver); err_put: - put_tty_driver(mxvar_sdriver); + tty_driver_kref_put(mxvar_sdriver); return retval; } @@ -2016,7 +2016,7 @@ static void __exit mxser_module_exit(void) { pci_unregister_driver(&mxser_driver); tty_unregister_driver(mxvar_sdriver); - put_tty_driver(mxvar_sdriver); + tty_driver_kref_put(mxvar_sdriver); } module_init(mxser_module_init); diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index e907b7a5cab5..1d92d2a84889 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -3252,10 +3252,11 @@ static int __init gsm_init(void) return status; } - gsm_tty_driver = alloc_tty_driver(256); - if (!gsm_tty_driver) { + gsm_tty_driver = tty_alloc_driver(256, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK); + if (IS_ERR(gsm_tty_driver)) { pr_err("gsm_init: tty allocation failed.\n"); - status = -ENOMEM; + status = PTR_ERR(gsm_tty_driver); goto err_unreg_ldisc; } gsm_tty_driver->driver_name = "gsmtty"; @@ -3264,8 +3265,6 @@ static int __init gsm_init(void) gsm_tty_driver->minor_start = 0; gsm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; gsm_tty_driver->subtype = SERIAL_TYPE_NORMAL; - gsm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV - | TTY_DRIVER_HARDWARE_BREAK; gsm_tty_driver->init_termios = tty_std_termios; /* Fixme */ gsm_tty_driver->init_termios.c_lflag &= ~ECHO; @@ -3280,7 +3279,7 @@ static int __init gsm_init(void) gsm_tty_driver->major, gsm_tty_driver->minor_start); return 0; err_put_driver: - put_tty_driver(gsm_tty_driver); + tty_driver_kref_put(gsm_tty_driver); err_unreg_ldisc: tty_unregister_ldisc(&tty_ldisc_packet); return status; @@ -3290,7 +3289,7 @@ static void __exit gsm_exit(void) { tty_unregister_ldisc(&tty_ldisc_packet); tty_unregister_driver(gsm_tty_driver); - put_tty_driver(gsm_tty_driver); + tty_driver_kref_put(gsm_tty_driver); } module_init(gsm_init); diff --git a/drivers/tty/nozomi.c b/drivers/tty/nozomi.c index 0c80f25c8c3d..0454c78deee6 100644 --- a/drivers/tty/nozomi.c +++ b/drivers/tty/nozomi.c @@ -1824,16 +1824,16 @@ static __init int nozomi_init(void) { int ret; - ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); - if (!ntty_driver) - return -ENOMEM; + ntty_driver = tty_alloc_driver(NTTY_TTY_MAXMINORS, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(ntty_driver)) + return PTR_ERR(ntty_driver); ntty_driver->driver_name = NOZOMI_NAME_TTY; ntty_driver->name = "noz"; ntty_driver->major = 0; ntty_driver->type = TTY_DRIVER_TYPE_SERIAL; ntty_driver->subtype = SERIAL_TYPE_NORMAL; - ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; ntty_driver->init_termios = tty_std_termios; ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \ HUPCL | CLOCAL; @@ -1857,7 +1857,7 @@ static __init int nozomi_init(void) unr_tty: tty_unregister_driver(ntty_driver); free_tty: - put_tty_driver(ntty_driver); + tty_driver_kref_put(ntty_driver); return ret; } @@ -1865,7 +1865,7 @@ static __exit void nozomi_exit(void) { pci_unregister_driver(&nozomi_driver); tty_unregister_driver(ntty_driver); - put_tty_driver(ntty_driver); + tty_driver_kref_put(ntty_driver); } module_init(nozomi_init); diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index 92498961fd92..f1324fe99378 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -562,23 +562,45 @@ struct acpi_serdev_lookup { int index; }; +/** + * serdev_acpi_get_uart_resource - Gets UARTSerialBus resource if type matches + * @ares: ACPI resource + * @uart: Pointer to UARTSerialBus resource will be returned here + * + * Checks if the given ACPI resource is of type UARTSerialBus. + * In this case, returns a pointer to it to the caller. + * + * Return: True if resource type is of UARTSerialBus, otherwise false. + */ +bool serdev_acpi_get_uart_resource(struct acpi_resource *ares, + struct acpi_resource_uart_serialbus **uart) +{ + struct acpi_resource_uart_serialbus *sb; + + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) + return false; + + sb = &ares->data.uart_serial_bus; + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_UART) + return false; + + *uart = sb; + return true; +} +EXPORT_SYMBOL_GPL(serdev_acpi_get_uart_resource); + static int acpi_serdev_parse_resource(struct acpi_resource *ares, void *data) { struct acpi_serdev_lookup *lookup = data; struct acpi_resource_uart_serialbus *sb; acpi_status status; - if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) - return 1; - - if (ares->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART) + if (!serdev_acpi_get_uart_resource(ares, &sb)) return 1; if (lookup->index != -1 && lookup->n++ != lookup->index) return 1; - sb = &ares->data.uart_serial_bus; - status = acpi_get_handle(lookup->device_handle, sb->resource_source.string_ptr, &lookup->controller_handle); @@ -586,7 +608,7 @@ static int acpi_serdev_parse_resource(struct acpi_resource *ares, void *data) return 1; /* - * NOTE: Ideally, we would also want to retreive other properties here, + * NOTE: Ideally, we would also want to retrieve other properties here, * once setting them before opening the device is supported by serdev. */ diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 725a450058f8..7f656fac503f 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -941,7 +941,7 @@ static int brcmuart_probe(struct platform_device *pdev) struct clk *baud_mux_clk; struct uart_8250_port up; struct resource *irq; - void __iomem *membase = 0; + void __iomem *membase = NULL; resource_size_t mapbase = 0; u32 clk_rate = 0; int ret; diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index 3ffeedc29c83..d502240bbcf2 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -114,6 +114,7 @@ struct exar8250; struct exar8250_platform { int (*rs485_config)(struct uart_port *, struct serial_rs485 *); int (*register_gpio)(struct pci_dev *, struct uart_8250_port *); + void (*unregister_gpio)(struct uart_8250_port *); }; /** @@ -352,9 +353,8 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p) writeb(0x00, p + UART_EXAR_MPIOOD_15_8); } -static void * -__xr17v35x_register_gpio(struct pci_dev *pcidev, - const struct software_node *node) +static struct platform_device *__xr17v35x_register_gpio(struct pci_dev *pcidev, + const struct software_node *node) { struct platform_device *pdev; @@ -374,6 +374,12 @@ __xr17v35x_register_gpio(struct pci_dev *pcidev, return pdev; } +static void __xr17v35x_unregister_gpio(struct platform_device *pdev) +{ + device_remove_software_node(&pdev->dev); + platform_device_unregister(pdev); +} + static const struct property_entry exar_gpio_properties[] = { PROPERTY_ENTRY_U32("exar,first-pin", 0), PROPERTY_ENTRY_U32("ngpios", 16), @@ -384,8 +390,7 @@ static const struct software_node exar_gpio_node = { .properties = exar_gpio_properties, }; -static int xr17v35x_register_gpio(struct pci_dev *pcidev, - struct uart_8250_port *port) +static int xr17v35x_register_gpio(struct pci_dev *pcidev, struct uart_8250_port *port) { if (pcidev->vendor == PCI_VENDOR_ID_EXAR) port->port.private_data = @@ -394,6 +399,15 @@ static int xr17v35x_register_gpio(struct pci_dev *pcidev, return 0; } +static void xr17v35x_unregister_gpio(struct uart_8250_port *port) +{ + if (!port->port.private_data) + return; + + __xr17v35x_unregister_gpio(port->port.private_data); + port->port.private_data = NULL; +} + static int generic_rs485_config(struct uart_port *port, struct serial_rs485 *rs485) { @@ -419,6 +433,7 @@ static int generic_rs485_config(struct uart_port *port, static const struct exar8250_platform exar8250_default_platform = { .register_gpio = xr17v35x_register_gpio, + .unregister_gpio = xr17v35x_unregister_gpio, .rs485_config = generic_rs485_config, }; @@ -484,6 +499,7 @@ static int iot2040_register_gpio(struct pci_dev *pcidev, static const struct exar8250_platform iot2040_platform = { .rs485_config = iot2040_rs485_config, .register_gpio = iot2040_register_gpio, + .unregister_gpio = xr17v35x_unregister_gpio, }; /* @@ -555,17 +571,11 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev, static void pci_xr17v35x_exit(struct pci_dev *pcidev) { + const struct exar8250_platform *platform = exar_get_platform(); struct exar8250 *priv = pci_get_drvdata(pcidev); struct uart_8250_port *port = serial8250_get_port(priv->line[0]); - struct platform_device *pdev; - pdev = port->port.private_data; - if (!pdev) - return; - - device_remove_software_node(&pdev->dev); - platform_device_unregister(pdev); - port->port.private_data = NULL; + platform->unregister_gpio(port); } static inline void exar_misc_clear(struct exar8250 *priv) diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 988bf6bcce42..65402d05eff9 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -209,16 +209,14 @@ static int ingenic_uart_probe(struct platform_device *pdev) struct uart_8250_port uart = {}; struct ingenic_uart_data *data; const struct ingenic_uart_config *cdata; - const struct of_device_id *match; struct resource *regs; int irq, err, line; - match = of_match_device(of_match, &pdev->dev); - if (!match) { + cdata = of_device_get_match_data(&pdev->dev); + if (!cdata) { dev_err(&pdev->dev, "Error: No device match found\n"); return -ENODEV; } - cdata = match->data; irq = platform_get_irq(pdev, 0); if (irq < 0) diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 4dee8a9e0c95..848d81e3838c 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -158,6 +158,16 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) static int ehl_serial_setup(struct lpss8250 *lpss, struct uart_port *port) { + struct uart_8250_dma *dma = &lpss->data.dma; + struct uart_8250_port *up = up_to_u8250p(port); + + /* + * This simply makes the checks in the 8250_port to try the DMA + * channel request which in turn uses the magic of ACPI tables + * parsing (see drivers/dma/acpi-dma.c for the details) and + * matching with the registered General Purpose DMA controllers. + */ + up->dma = dma; return 0; } diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 79418d4beb48..891fd8345e25 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -538,7 +538,7 @@ static void omap_8250_pm(struct uart_port *port, unsigned int state, static void omap_serial_fill_features_erratas(struct uart_8250_port *up, struct omap8250_priv *priv) { - const struct soc_device_attribute k3_soc_devices[] = { + static const struct soc_device_attribute k3_soc_devices[] = { { .family = "AM65X", }, { .family = "J721E", .revision = "SR1.0" }, { /* sentinel */ } @@ -617,7 +617,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id) struct uart_port *port = dev_id; struct omap8250_priv *priv = port->private_data; struct uart_8250_port *up = up_to_u8250p(port); - unsigned int iir; + unsigned int iir, lsr; int ret; #ifdef CONFIG_SERIAL_8250_DMA @@ -628,6 +628,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id) #endif serial8250_rpm_get(up); + lsr = serial_port_in(port, UART_LSR); iir = serial_port_in(port, UART_IIR); ret = serial8250_handle_irq(port, iir); @@ -642,6 +643,24 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id) serial_port_in(port, UART_RX); } + /* Stop processing interrupts on input overrun */ + if ((lsr & UART_LSR_OE) && up->overrun_backoff_time_ms > 0) { + unsigned long delay; + + up->ier = port->serial_in(port, UART_IER); + if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) { + port->ops->stop_rx(port); + } else { + /* Keep restarting the timer until + * the input overrun subsides. + */ + cancel_delayed_work(&up->overrun_backoff); + } + + delay = msecs_to_jiffies(up->overrun_backoff_time_ms); + schedule_delayed_work(&up->overrun_backoff, delay); + } + serial8250_rpm_put(up); return IRQ_RETVAL(ret); @@ -1353,6 +1372,10 @@ static int omap8250_probe(struct platform_device *pdev) } } + if (of_property_read_u32(np, "overrun-throttle-ms", + &up.overrun_backoff_time_ms) != 0) + up.overrun_backoff_time_ms = 0; + priv->wakeirq = irq_of_parse_and_map(np, 1); pdata = of_device_get_match_data(&pdev->dev); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index a808c283883e..726912b16a55 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -87,7 +87,7 @@ static void moan_device(const char *str, struct pci_dev *dev) static int setup_port(struct serial_private *priv, struct uart_8250_port *port, - int bar, int offset, int regshift) + u8 bar, unsigned int offset, int regshift) { struct pci_dev *dev = priv->dev; diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c index de90d681b64c..98e5ee4d0d08 100644 --- a/drivers/tty/serial/8250/8250_pnp.c +++ b/drivers/tty/serial/8250/8250_pnp.c @@ -13,6 +13,7 @@ #include <linux/pnp.h> #include <linux/string.h> #include <linux/kernel.h> +#include <linux/property.h> #include <linux/serial_core.h> #include <linux/bitops.h> @@ -475,6 +476,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE) uart.port.flags |= UPF_SHARE_IRQ; uart.port.uartclk = 1843200; + device_property_read_u32(&dev->dev, "clock-frequency", &uart.port.uartclk); uart.port.dev = &dev->dev; line = serial8250_register_8250_port(&uart); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 1da29a219842..66374704747e 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -122,7 +122,8 @@ static const struct serial8250_config uart_config[] = { .name = "16C950/954", .fifo_size = 128, .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01, + .rxtrig_bytes = {16, 32, 112, 120}, /* UART_CAP_EFR breaks billionon CF bluetooth card. */ .flags = UART_CAP_FIFO | UART_CAP_SLEEP, }, diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index d1b3c2373fa4..71ae16de0f90 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -363,7 +363,7 @@ config SERIAL_8250_BCM2835AUX config SERIAL_8250_FSL bool depends on SERIAL_8250_CONSOLE - default PPC || ARM || ARM64 + default PPC || ARM || ARM64 || COMPILE_TEST config SERIAL_8250_DW tristate "Support for Synopsys DesignWare 8250 quirks" @@ -375,7 +375,8 @@ config SERIAL_8250_DW config SERIAL_8250_EM tristate "Support for Emma Mobile integrated serial port" - depends on SERIAL_8250 && ARM && HAVE_CLK + depends on SERIAL_8250 && HAVE_CLK + depends on ARM || COMPILE_TEST help Selecting this option will add support for the integrated serial port hardware found on the Emma Mobile line of processors. @@ -383,7 +384,8 @@ config SERIAL_8250_EM config SERIAL_8250_IOC3 tristate "SGI IOC3 8250 UART support" - depends on SGI_MFD_IOC3 && SERIAL_8250 + depends on SERIAL_8250 + depends on SGI_MFD_IOC3 || COMPILE_TEST select SERIAL_8250_EXTENDED select SERIAL_8250_SHARE_IRQ help @@ -495,7 +497,7 @@ config SERIAL_8250_MID config SERIAL_8250_PXA tristate "PXA serial port support" depends on SERIAL_8250 - depends on ARCH_PXA || ARCH_MMP + depends on ARCH_PXA || ARCH_MMP || COMPILE_TEST help If you have a machine based on an Intel XScale PXA2xx CPU you can enable its onboard serial ports by enabling this option. The option is diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 24282ad99d85..131a6a587acd 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -959,7 +959,7 @@ config SERIAL_VT8500_CONSOLE config SERIAL_OMAP tristate "OMAP serial port support" - depends on ARCH_OMAP2PLUS || COMPILE_TEST + depends on (ARCH_OMAP2PLUS && !SERIAL_8250_OMAP) || COMPILE_TEST select SERIAL_CORE help If you have a machine based on an Texas Instruments OMAP CPU you @@ -1382,7 +1382,7 @@ config SERIAL_ST_ASC select SERIAL_CORE depends on ARM || COMPILE_TEST help - This driver is for the on-chip Asychronous Serial Controller on + This driver is for the on-chip Asynchronous Serial Controller on STMicroelectronics STi SoCs. ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality. It support all industry standard baud rates. diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index e14f3378b8a0..d361cd84ff8c 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -265,6 +265,8 @@ struct uart_amba_port { unsigned int old_cr; /* state during shutdown */ unsigned int fixed_baud; /* vendor-set fixed baud rate */ char type[12]; + bool rs485_tx_started; + unsigned int rs485_tx_drain_interval; /* usecs */ #ifdef CONFIG_DMA_ENGINE /* DMA stuff */ bool using_tx_dma; @@ -275,6 +277,8 @@ struct uart_amba_port { #endif }; +static unsigned int pl011_tx_empty(struct uart_port *port); + static unsigned int pl011_reg_to_offset(const struct uart_amba_port *uap, unsigned int reg) { @@ -1282,6 +1286,42 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap) #define pl011_dma_flush_buffer NULL #endif +static void pl011_rs485_tx_stop(struct uart_amba_port *uap) +{ + struct uart_port *port = &uap->port; + int i = 0; + u32 cr; + + /* Wait until hardware tx queue is empty */ + while (!pl011_tx_empty(port)) { + if (i == port->fifosize) { + dev_warn(port->dev, + "timeout while draining hardware tx queue\n"); + break; + } + + udelay(uap->rs485_tx_drain_interval); + i++; + } + + if (port->rs485.delay_rts_after_send) + mdelay(port->rs485.delay_rts_after_send); + + cr = pl011_read(uap, REG_CR); + + if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + cr &= ~UART011_CR_RTS; + else + cr |= UART011_CR_RTS; + + /* Disable the transmitter and reenable the transceiver */ + cr &= ~UART011_CR_TXE; + cr |= UART011_CR_RXE; + pl011_write(cr, uap, REG_CR); + + uap->rs485_tx_started = false; +} + static void pl011_stop_tx(struct uart_port *port) { struct uart_amba_port *uap = @@ -1290,6 +1330,9 @@ static void pl011_stop_tx(struct uart_port *port) uap->im &= ~UART011_TXIM; pl011_write(uap->im, uap, REG_IMSC); pl011_dma_tx_stop(uap); + + if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started) + pl011_rs485_tx_stop(uap); } static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); @@ -1380,6 +1423,32 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, return true; } +static void pl011_rs485_tx_start(struct uart_amba_port *uap) +{ + struct uart_port *port = &uap->port; + u32 cr; + + /* Enable transmitter */ + cr = pl011_read(uap, REG_CR); + cr |= UART011_CR_TXE; + + /* Disable receiver if half-duplex */ + if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) + cr &= ~UART011_CR_RXE; + + if (port->rs485.flags & SER_RS485_RTS_ON_SEND) + cr &= ~UART011_CR_RTS; + else + cr |= UART011_CR_RTS; + + pl011_write(cr, uap, REG_CR); + + if (port->rs485.delay_rts_before_send) + mdelay(port->rs485.delay_rts_before_send); + + uap->rs485_tx_started = true; +} + /* Returns true if tx interrupts have to be (kept) enabled */ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) { @@ -1397,6 +1466,10 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) return false; } + if ((uap->port.rs485.flags & SER_RS485_ENABLED) && + !uap->rs485_tx_started) + pl011_rs485_tx_start(uap); + /* If we are using DMA mode, try to send some characters. */ if (pl011_dma_tx_irq(uap)) return true; @@ -1542,6 +1615,9 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) container_of(port, struct uart_amba_port, port); unsigned int cr; + if (port->rs485.flags & SER_RS485_ENABLED) + mctrl &= ~TIOCM_RTS; + cr = pl011_read(uap, REG_CR); #define TIOCMBIT(tiocmbit, uartbit) \ @@ -1763,7 +1839,17 @@ static int pl011_startup(struct uart_port *port) /* restore RTS and DTR */ cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); - cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; + cr |= UART01x_CR_UARTEN | UART011_CR_RXE; + + if (port->rs485.flags & SER_RS485_ENABLED) { + if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + cr &= ~UART011_CR_RTS; + else + cr |= UART011_CR_RTS; + } else { + cr |= UART011_CR_TXE; + } + pl011_write(cr, uap, REG_CR); spin_unlock_irq(&uap->port.lock); @@ -1864,6 +1950,9 @@ static void pl011_shutdown(struct uart_port *port) pl011_dma_shutdown(uap); + if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started) + pl011_rs485_tx_stop(uap); + free_irq(uap->port.irq, uap); pl011_disable_uart(uap); @@ -1941,6 +2030,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int lcr_h, old_cr; unsigned long flags; unsigned int baud, quot, clkdiv; + unsigned int bits; if (uap->vendor->oversampling) clkdiv = 8; @@ -1991,6 +2081,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, if (uap->fifosize > 1) lcr_h |= UART01x_LCRH_FEN; + bits = tty_get_frame_size(termios->c_cflag); + spin_lock_irqsave(&port->lock, flags); /* @@ -1998,11 +2090,21 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, */ uart_update_timeout(port, termios->c_cflag, baud); + /* + * Calculate the approximated time it takes to transmit one character + * with the given baud rate. We use this as the poll interval when we + * wait for the tx queue to empty. + */ + uap->rs485_tx_drain_interval = (bits * 1000 * 1000) / baud; + pl011_setup_status_masks(port, termios); if (UART_ENABLE_MS(port, termios->c_cflag)) pl011_enable_ms(port); + if (port->rs485.flags & SER_RS485_ENABLED) + termios->c_cflag &= ~CRTSCTS; + /* first, disable everything */ old_cr = pl011_read(uap, REG_CR); pl011_write(0, uap, REG_CR); @@ -2124,6 +2226,41 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser) return ret; } +static int pl011_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + + /* pick sane settings if the user hasn't */ + if (!(rs485->flags & SER_RS485_RTS_ON_SEND) == + !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) { + rs485->flags |= SER_RS485_RTS_ON_SEND; + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + } + /* clamp the delays to [0, 100ms] */ + rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); + rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); + memset(rs485->padding, 0, sizeof(rs485->padding)); + + if (port->rs485.flags & SER_RS485_ENABLED) + pl011_rs485_tx_stop(uap); + + /* Set new configuration */ + port->rs485 = *rs485; + + /* Make sure auto RTS is disabled */ + if (port->rs485.flags & SER_RS485_ENABLED) { + u32 cr = pl011_read(uap, REG_CR); + + cr &= ~UART011_CR_RTSEN; + pl011_write(cr, uap, REG_CR); + port->status &= ~UPSTAT_AUTORTS; + } + + return 0; +} + static const struct uart_ops amba_pl011_pops = { .tx_empty = pl011_tx_empty, .set_mctrl = pl011_set_mctrl, @@ -2588,10 +2725,28 @@ static int pl011_find_free_port(void) return -EBUSY; } +static int pl011_get_rs485_mode(struct uart_amba_port *uap) +{ + struct uart_port *port = &uap->port; + struct serial_rs485 *rs485 = &port->rs485; + int ret; + + ret = uart_get_rs485_mode(port); + if (ret) + return ret; + + /* clamp the delays to [0, 100ms] */ + rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); + rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); + + return 0; +} + static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, struct resource *mmiobase, int index) { void __iomem *base; + int ret; base = devm_ioremap_resource(dev, mmiobase); if (IS_ERR(base)) @@ -2608,6 +2763,10 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, uap->port.flags = UPF_BOOT_AUTOCONF; uap->port.line = index; + ret = pl011_get_rs485_mode(uap); + if (ret) + return ret; + amba_ports[index] = uap; return 0; @@ -2665,7 +2824,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM; uap->port.irq = dev->irq[0]; uap->port.ops = &amba_pl011_pops; - + uap->port.rs485_config = pl011_rs485_config; snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr); diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c index d87048073abe..283757264608 100644 --- a/drivers/tty/serial/fsl_linflexuart.c +++ b/drivers/tty/serial/fsl_linflexuart.c @@ -861,11 +861,7 @@ static int linflex_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sport); - ret = uart_add_one_port(&linflex_reg, sport); - if (ret) - return ret; - - return 0; + return uart_add_one_port(&linflex_reg, sport); } static int linflex_remove(struct platform_device *pdev) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index f0e5da77ed6d..b1e7190ae483 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -7,6 +7,7 @@ #include <linux/clk.h> #include <linux/console.h> +#include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/dmapool.h> @@ -109,6 +110,11 @@ #define UARTSFIFO_TXOF 0x02 #define UARTSFIFO_RXUF 0x01 +/* 32-bit global registers only for i.MX7ULP/i.MX8x + * Used to reset all internal logic and registers, except the Global Register. + */ +#define UART_GLOBAL 0x8 + /* 32-bit register definition */ #define UARTBAUD 0x00 #define UARTSTAT 0x04 @@ -219,6 +225,10 @@ #define UARTWATER_TXWATER_OFF 0 #define UARTWATER_RXWATER_OFF 16 +#define UART_GLOBAL_RST 0x2 +#define GLOBAL_RST_MIN_US 20 +#define GLOBAL_RST_MAX_US 40 + /* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */ #define DMA_RX_TIMEOUT (10) @@ -320,6 +330,11 @@ static inline bool is_layerscape_lpuart(struct lpuart_port *sport) sport->devtype == LS1028A_LPUART); } +static inline bool is_imx7ulp_lpuart(struct lpuart_port *sport) +{ + return sport->devtype == IMX7ULP_LPUART; +} + static inline bool is_imx8qxp_lpuart(struct lpuart_port *sport) { return sport->devtype == IMX8QXP_LPUART; @@ -383,6 +398,33 @@ static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport) #define lpuart_enable_clks(x) __lpuart_enable_clks(x, true) #define lpuart_disable_clks(x) __lpuart_enable_clks(x, false) +static int lpuart_global_reset(struct lpuart_port *sport) +{ + struct uart_port *port = &sport->port; + void __iomem *global_addr; + int ret; + + if (uart_console(port)) + return 0; + + ret = clk_prepare_enable(sport->ipg_clk); + if (ret) { + dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret); + return ret; + } + + if (is_imx7ulp_lpuart(sport) || is_imx8qxp_lpuart(sport)) { + global_addr = port->membase + UART_GLOBAL - IMX_REG_OFF; + writel(UART_GLOBAL_RST, global_addr); + usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US); + writel(0, global_addr); + usleep_range(GLOBAL_RST_MIN_US, GLOBAL_RST_MAX_US); + } + + clk_disable_unprepare(sport->ipg_clk); + return 0; +} + static void lpuart_stop_tx(struct uart_port *port) { unsigned char temp; @@ -479,6 +521,10 @@ static void lpuart_dma_tx_complete(void *arg) unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); + if (!sport->dma_tx_in_progress) { + spin_unlock_irqrestore(&sport->port.lock, flags); + return; + } dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); @@ -2045,11 +2091,12 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); unsigned long flags; - unsigned long ctrl, old_ctrl, modem; + unsigned long ctrl, old_ctrl, bd, modem; unsigned int baud; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL); + bd = lpuart32_read(&sport->port, UARTBAUD); modem = lpuart32_read(&sport->port, UARTMODIR); /* * only support CS8 and CS7, and for CS7 must enable PE. @@ -2093,7 +2140,9 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, } if (termios->c_cflag & CSTOPB) - termios->c_cflag &= ~CSTOPB; + bd |= UARTBAUD_SBNS; + else + bd &= ~UARTBAUD_SBNS; /* parity must be enabled when CS7 to match 8-bits format */ if ((termios->c_cflag & CSIZE) == CS7) @@ -2163,6 +2212,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), UARTCTRL); + lpuart32_write(&sport->port, bd, UARTBAUD); lpuart32_serial_setbrg(sport, baud); lpuart32_write(&sport->port, modem, UARTMODIR); lpuart32_write(&sport->port, ctrl, UARTCTRL); @@ -2611,7 +2661,7 @@ static int lpuart_probe(struct platform_device *pdev) return PTR_ERR(sport->port.membase); sport->port.membase += sdata->reg_off; - sport->port.mapbase = res->start; + sport->port.mapbase = res->start + sdata->reg_off; sport->port.dev = &pdev->dev; sport->port.type = PORT_LPUART; sport->devtype = sdata->devtype; @@ -2691,6 +2741,10 @@ static int lpuart_probe(struct platform_device *pdev) if (ret) goto failed_attach_port; + ret = lpuart_global_reset(sport); + if (ret) + goto failed_reset; + ret = uart_get_rs485_mode(&sport->port); if (ret) goto failed_get_rs485; @@ -2707,6 +2761,8 @@ static int lpuart_probe(struct platform_device *pdev) return 0; failed_get_rs485: +failed_reset: + uart_remove_one_port(&lpuart_reg, &sport->port); failed_attach_port: failed_irq_request: lpuart_disable_clks(sport); diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index bf0e2a4cb0ce..c6f927a76c3b 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -815,7 +815,9 @@ static void neo_parse_isr(struct jsm_board *brd, u32 port) /* Parse any modem signal changes */ jsm_dbg(INTR, &ch->ch_bd->pci_dev, "MOD_STAT: sending to parse_modem_sigs\n"); + spin_lock_irqsave(&ch->uart_port.lock, lock_flags); neo_parse_modem(ch, readb(&ch->ch_neo_uart->msr)); + spin_unlock_irqrestore(&ch->uart_port.lock, lock_flags); } } diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 8e42a7682c63..d74cbbbf33c6 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -187,6 +187,7 @@ static void jsm_tty_break(struct uart_port *port, int break_state) static int jsm_tty_open(struct uart_port *port) { + unsigned long lock_flags; struct jsm_board *brd; struct jsm_channel *channel = container_of(port, struct jsm_channel, uart_port); @@ -240,6 +241,7 @@ static int jsm_tty_open(struct uart_port *port) channel->ch_cached_lsr = 0; channel->ch_stops_sent = 0; + spin_lock_irqsave(&port->lock, lock_flags); termios = &port->state->port.tty->termios; channel->ch_c_cflag = termios->c_cflag; channel->ch_c_iflag = termios->c_iflag; @@ -259,6 +261,7 @@ static int jsm_tty_open(struct uart_port *port) jsm_carrier(channel); channel->ch_open_count++; + spin_unlock_irqrestore(&port->lock, lock_flags); jsm_dbg(OPEN, &channel->ch_bd->pci_dev, "finish\n"); return 0; diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c index 3e7c6ee8e4b3..55c3c9db7462 100644 --- a/drivers/tty/serial/kgdb_nmi.c +++ b/drivers/tty/serial/kgdb_nmi.c @@ -330,17 +330,16 @@ int kgdb_register_nmi_console(void) if (!arch_kgdb_ops.enable_nmi) return 0; - kgdb_nmi_tty_driver = alloc_tty_driver(1); - if (!kgdb_nmi_tty_driver) { + kgdb_nmi_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW); + if (IS_ERR(kgdb_nmi_tty_driver)) { pr_err("%s: cannot allocate tty\n", __func__); - return -ENOMEM; + return PTR_ERR(kgdb_nmi_tty_driver); } kgdb_nmi_tty_driver->driver_name = "ttyNMI"; kgdb_nmi_tty_driver->name = "ttyNMI"; kgdb_nmi_tty_driver->num = 1; kgdb_nmi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; kgdb_nmi_tty_driver->subtype = SERIAL_TYPE_NORMAL; - kgdb_nmi_tty_driver->flags = TTY_DRIVER_REAL_RAW; kgdb_nmi_tty_driver->init_termios = tty_std_termios; tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios, KGDB_NMI_BAUD, KGDB_NMI_BAUD); @@ -356,7 +355,7 @@ int kgdb_register_nmi_console(void) return 0; err_drv_reg: - put_tty_driver(kgdb_nmi_tty_driver); + tty_driver_kref_put(kgdb_nmi_tty_driver); return ret; } EXPORT_SYMBOL_GPL(kgdb_register_nmi_console); @@ -374,7 +373,7 @@ int kgdb_unregister_nmi_console(void) return ret; tty_unregister_driver(kgdb_nmi_tty_driver); - put_tty_driver(kgdb_nmi_tty_driver); + tty_driver_kref_put(kgdb_nmi_tty_driver); return 0; } diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index ef11860cd69e..3df0788ddeb0 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1271,18 +1271,13 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty /* Always ask for fixed clock rate from a property. */ device_property_read_u32(dev, "clock-frequency", &uartclk); - s->clk = devm_clk_get_optional(dev, "osc"); + xtal = device_property_match_string(dev, "clock-names", "osc") < 0; + if (xtal) + s->clk = devm_clk_get_optional(dev, "xtal"); + else + s->clk = devm_clk_get_optional(dev, "osc"); if (IS_ERR(s->clk)) return PTR_ERR(s->clk); - if (s->clk) { - xtal = false; - } else { - s->clk = devm_clk_get_optional(dev, "xtal"); - if (IS_ERR(s->clk)) - return PTR_ERR(s->clk); - - xtal = true; - } ret = clk_prepare_enable(s->clk); if (ret) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 9e81b09ba08e..0862941862c8 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -276,11 +276,8 @@ static void serial_omap_enable_ms(struct uart_port *port) dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->port.line); - pm_runtime_get_sync(up->dev); up->ier |= UART_IER_MSI; serial_out(up, UART_IER, up->ier); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_stop_tx(struct uart_port *port) @@ -288,8 +285,6 @@ static void serial_omap_stop_tx(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); int res; - pm_runtime_get_sync(up->dev); - /* Handle RS-485 */ if (port->rs485.flags & SER_RS485_ENABLED) { if (up->scr & OMAP_UART_SCR_TX_EMPTY) { @@ -330,21 +325,15 @@ static void serial_omap_stop_tx(struct uart_port *port) up->ier &= ~UART_IER_THRI; serial_out(up, UART_IER, up->ier); } - - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_stop_rx(struct uart_port *port) { struct uart_omap_port *up = to_uart_omap_port(port); - pm_runtime_get_sync(up->dev); up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); up->port.read_status_mask &= ~UART_LSR_DR; serial_out(up, UART_IER, up->ier); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void transmit_chars(struct uart_omap_port *up, unsigned int lsr) @@ -399,8 +388,6 @@ static void serial_omap_start_tx(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); int res; - pm_runtime_get_sync(up->dev); - /* Handle RS-485 */ if (port->rs485.flags & SER_RS485_ENABLED) { /* Fire THR interrupts when FIFO is below trigger level */ @@ -421,8 +408,6 @@ static void serial_omap_start_tx(struct uart_port *port) up->rs485_tx_filter_count = 0; serial_omap_enable_ier_thri(up); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_throttle(struct uart_port *port) @@ -430,13 +415,10 @@ static void serial_omap_throttle(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags; - pm_runtime_get_sync(up->dev); spin_lock_irqsave(&up->port.lock, flags); up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); serial_out(up, UART_IER, up->ier); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_unthrottle(struct uart_port *port) @@ -444,13 +426,10 @@ static void serial_omap_unthrottle(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); unsigned long flags; - pm_runtime_get_sync(up->dev); spin_lock_irqsave(&up->port.lock, flags); up->ier |= UART_IER_RLSI | UART_IER_RDI; serial_out(up, UART_IER, up->ier); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static unsigned int check_modem_status(struct uart_omap_port *up) @@ -576,7 +555,6 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) int max_count = 256; spin_lock(&up->port.lock); - pm_runtime_get_sync(up->dev); do { iir = serial_in(up, UART_IIR); @@ -616,8 +594,6 @@ static irqreturn_t serial_omap_irq(int irq, void *dev_id) tty_flip_buffer_push(&up->port.state->port); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); up->port_activity = jiffies; return ret; @@ -629,13 +605,11 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port) unsigned long flags; unsigned int ret = 0; - pm_runtime_get_sync(up->dev); dev_dbg(up->port.dev, "serial_omap_tx_empty+%d\n", up->port.line); spin_lock_irqsave(&up->port.lock, flags); ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); + return ret; } @@ -645,10 +619,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port) unsigned int status; unsigned int ret = 0; - pm_runtime_get_sync(up->dev); status = check_modem_status(up); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); dev_dbg(up->port.dev, "serial_omap_get_mctrl+%d\n", up->port.line); @@ -680,7 +651,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) if (mctrl & TIOCM_LOOP) mcr |= UART_MCR_LOOP; - pm_runtime_get_sync(up->dev); old_mcr = serial_in(up, UART_MCR); old_mcr &= ~(UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_OUT1 | UART_MCR_DTR | UART_MCR_RTS); @@ -696,9 +666,6 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl) up->efr &= ~UART_EFR_RTS; serial_out(up, UART_EFR, up->efr); serial_out(up, UART_LCR, lcr); - - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_break_ctl(struct uart_port *port, int break_state) @@ -707,7 +674,6 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) unsigned long flags; dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line); - pm_runtime_get_sync(up->dev); spin_lock_irqsave(&up->port.lock, flags); if (break_state == -1) up->lcr |= UART_LCR_SBC; @@ -715,8 +681,6 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state) up->lcr &= ~UART_LCR_SBC; serial_out(up, UART_LCR, up->lcr); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static int serial_omap_startup(struct uart_port *port) @@ -788,8 +752,6 @@ static int serial_omap_startup(struct uart_port *port) serial_out(up, UART_OMAP_WER, up->wer); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); up->port_activity = jiffies; return 0; } @@ -801,7 +763,6 @@ static void serial_omap_shutdown(struct uart_port *port) dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line); - pm_runtime_get_sync(up->dev); /* * Disable interrupts from this port */ @@ -825,8 +786,7 @@ static void serial_omap_shutdown(struct uart_port *port) if (serial_in(up, UART_LSR) & UART_LSR_DR) (void) serial_in(up, UART_RX); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); + pm_runtime_put_sync(up->dev); free_irq(up->port.irq, up); dev_pm_clear_wake_irq(up->dev); } @@ -896,7 +856,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, * Ok, we're now changing the port state. Do it with * interrupts disabled. */ - pm_runtime_get_sync(up->dev); spin_lock_irqsave(&up->port.lock, flags); /* @@ -1096,8 +1055,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios, serial_omap_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line); } @@ -1110,7 +1067,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state, dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->port.line); - pm_runtime_get_sync(up->dev); serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); efr = serial_in(up, UART_EFR); serial_out(up, UART_EFR, efr | UART_EFR_ECB); @@ -1120,9 +1076,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state, serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); serial_out(up, UART_EFR, efr); serial_out(up, UART_LCR, 0); - - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static void serial_omap_release_port(struct uart_port *port) @@ -1202,11 +1155,8 @@ static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch) { struct uart_omap_port *up = to_uart_omap_port(port); - pm_runtime_get_sync(up->dev); wait_for_xmitr(up); serial_out(up, UART_TX, ch); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); } static int serial_omap_poll_get_char(struct uart_port *port) @@ -1214,7 +1164,6 @@ static int serial_omap_poll_get_char(struct uart_port *port) struct uart_omap_port *up = to_uart_omap_port(port); unsigned int status; - pm_runtime_get_sync(up->dev); status = serial_in(up, UART_LSR); if (!(status & UART_LSR_DR)) { status = NO_POLL_CHAR; @@ -1224,9 +1173,6 @@ static int serial_omap_poll_get_char(struct uart_port *port) status = serial_in(up, UART_RX); out: - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); - return status; } @@ -1309,8 +1255,6 @@ serial_omap_console_write(struct console *co, const char *s, unsigned int ier; int locked = 1; - pm_runtime_get_sync(up->dev); - local_irq_save(flags); if (up->port.sysrq) locked = 0; @@ -1343,8 +1287,6 @@ serial_omap_console_write(struct console *co, const char *s, if (up->msr_saved_flags) check_modem_status(up); - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); if (locked) spin_unlock(&up->port.lock); local_irq_restore(flags); @@ -1403,8 +1345,6 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) unsigned int mode; int val; - pm_runtime_get_sync(up->dev); - /* Disable interrupts from this port */ mode = up->ier; up->ier = 0; @@ -1438,9 +1378,6 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) serial_out(up, UART_OMAP_SCR, up->scr); } - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); - return 0; } @@ -1737,11 +1674,7 @@ static int serial_omap_probe(struct platform_device *pdev) omap_up_info->autosuspend_timeout = -1; device_init_wakeup(up->dev, true); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_autosuspend_delay(&pdev->dev, - omap_up_info->autosuspend_timeout); - pm_runtime_irq_safe(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); @@ -1755,12 +1688,9 @@ static int serial_omap_probe(struct platform_device *pdev) if (ret != 0) goto err_add_port; - pm_runtime_mark_last_busy(up->dev); - pm_runtime_put_autosuspend(up->dev); return 0; err_add_port: - pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); cpu_latency_qos_remove_request(&up->pm_qos_request); @@ -1778,7 +1708,6 @@ static int serial_omap_remove(struct platform_device *dev) uart_remove_one_port(&serial_omap_reg, &up->port); - pm_runtime_dont_use_autosuspend(up->dev); pm_runtime_put_sync(up->dev); pm_runtime_disable(up->dev); cpu_latency_qos_remove_request(&up->pm_qos_request); diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index 9fbc61151c2e..e2f49863e9c2 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -65,6 +65,7 @@ enum s3c24xx_port_type { struct s3c24xx_uart_info { char *name; enum s3c24xx_port_type type; + unsigned int has_usi; unsigned int port_type; unsigned int fifosize; unsigned long rx_fifomask; @@ -305,8 +306,9 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port) dmaengine_pause(dma->tx_chan); dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state); dmaengine_terminate_all(dma->tx_chan); - dma_sync_single_for_cpu(ourport->port.dev, - dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE); + dma_sync_single_for_cpu(dma->tx_chan->device->dev, + dma->tx_transfer_addr, dma->tx_size, + DMA_TO_DEVICE); async_tx_ack(dma->tx_desc); count = dma->tx_bytes_requested - state.residue; xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); @@ -338,8 +340,9 @@ static void s3c24xx_serial_tx_dma_complete(void *args) count = dma->tx_bytes_requested - state.residue; async_tx_ack(dma->tx_desc); - dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr, - dma->tx_size, DMA_TO_DEVICE); + dma_sync_single_for_cpu(dma->tx_chan->device->dev, + dma->tx_transfer_addr, dma->tx_size, + DMA_TO_DEVICE); spin_lock_irqsave(&port->lock, flags); @@ -443,8 +446,9 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport, dma->tx_size = count & ~(dma_get_cache_alignment() - 1); dma->tx_transfer_addr = dma->tx_addr + xmit->tail; - dma_sync_single_for_device(ourport->port.dev, dma->tx_transfer_addr, - dma->tx_size, DMA_TO_DEVICE); + dma_sync_single_for_device(dma->tx_chan->device->dev, + dma->tx_transfer_addr, dma->tx_size, + DMA_TO_DEVICE); dma->tx_desc = dmaengine_prep_slave_single(dma->tx_chan, dma->tx_transfer_addr, dma->tx_size, @@ -515,7 +519,7 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport, if (!count) return; - dma_sync_single_for_cpu(ourport->port.dev, dma->rx_addr, + dma_sync_single_for_cpu(dma->rx_chan->device->dev, dma->rx_addr, dma->rx_size, DMA_FROM_DEVICE); ourport->port.icount.rx += count; @@ -636,8 +640,8 @@ static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport) { struct s3c24xx_uart_dma *dma = ourport->dma; - dma_sync_single_for_device(ourport->port.dev, dma->rx_addr, - dma->rx_size, DMA_FROM_DEVICE); + dma_sync_single_for_device(dma->rx_chan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan, dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM, @@ -1102,18 +1106,19 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) goto err_release_tx; } - dma->rx_addr = dma_map_single(p->port.dev, dma->rx_buf, - dma->rx_size, DMA_FROM_DEVICE); - if (dma_mapping_error(p->port.dev, dma->rx_addr)) { + dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf, + dma->rx_size, DMA_FROM_DEVICE); + if (dma_mapping_error(dma->rx_chan->device->dev, dma->rx_addr)) { reason = "DMA mapping error for RX buffer"; ret = -EIO; goto err_free_rx; } /* TX buffer */ - dma->tx_addr = dma_map_single(p->port.dev, p->port.state->xmit.buf, - UART_XMIT_SIZE, DMA_TO_DEVICE); - if (dma_mapping_error(p->port.dev, dma->tx_addr)) { + dma->tx_addr = dma_map_single(dma->tx_chan->device->dev, + p->port.state->xmit.buf, UART_XMIT_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(dma->tx_chan->device->dev, dma->tx_addr)) { reason = "DMA mapping error for TX buffer"; ret = -EIO; goto err_unmap_rx; @@ -1122,8 +1127,8 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) return 0; err_unmap_rx: - dma_unmap_single(p->port.dev, dma->rx_addr, dma->rx_size, - DMA_FROM_DEVICE); + dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); err_free_rx: kfree(dma->rx_buf); err_release_tx: @@ -1142,8 +1147,8 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p) if (dma->rx_chan) { dmaengine_terminate_all(dma->rx_chan); - dma_unmap_single(p->port.dev, dma->rx_addr, - dma->rx_size, DMA_FROM_DEVICE); + dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); kfree(dma->rx_buf); dma_release_channel(dma->rx_chan); dma->rx_chan = NULL; @@ -1151,8 +1156,8 @@ static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p) if (dma->tx_chan) { dmaengine_terminate_all(dma->tx_chan); - dma_unmap_single(p->port.dev, dma->tx_addr, - UART_XMIT_SIZE, DMA_TO_DEVICE); + dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr, + UART_XMIT_SIZE, DMA_TO_DEVICE); dma_release_channel(dma->tx_chan); dma->tx_chan = NULL; } @@ -1352,6 +1357,28 @@ static int apple_s5l_serial_startup(struct uart_port *port) return ret; } +static void exynos_usi_init(struct uart_port *port) +{ + struct s3c24xx_uart_port *ourport = to_ourport(port); + struct s3c24xx_uart_info *info = ourport->info; + unsigned int val; + + if (!info->has_usi) + return; + + /* Clear the software reset of USI block (it's set at startup) */ + val = rd_regl(port, USI_CON); + val &= ~USI_CON_RESET_MASK; + wr_regl(port, USI_CON, val); + udelay(1); + + /* Continuously provide the clock to USI IP w/o gating (for Rx mode) */ + val = rd_regl(port, USI_OPTION); + val &= ~USI_OPTION_HWACG_MASK; + val |= USI_OPTION_HWACG_CLKREQ_ON; + wr_regl(port, USI_OPTION, val); +} + /* power power management control */ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, @@ -1379,6 +1406,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, if (!IS_ERR(ourport->baudclk)) clk_prepare_enable(ourport->baudclk); + exynos_usi_init(port); break; default: dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level); @@ -2102,6 +2130,8 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, if (ret) pr_warn("uart: failed to enable baudclk\n"); + exynos_usi_init(port); + /* Keep all interrupts masked and cleared */ switch (ourport->info->type) { case TYPE_S3C6400: @@ -2750,10 +2780,11 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { #endif #if defined(CONFIG_ARCH_EXYNOS) -#define EXYNOS_COMMON_SERIAL_DRV_DATA \ +#define EXYNOS_COMMON_SERIAL_DRV_DATA_USI(_has_usi) \ .info = &(struct s3c24xx_uart_info) { \ .name = "Samsung Exynos UART", \ .type = TYPE_S3C6400, \ + .has_usi = _has_usi, \ .port_type = PORT_S3C6400, \ .has_divslot = 1, \ .rx_fifomask = S5PV210_UFSTAT_RXMASK, \ @@ -2773,6 +2804,9 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { .has_fracval = 1, \ } \ +#define EXYNOS_COMMON_SERIAL_DRV_DATA \ + EXYNOS_COMMON_SERIAL_DRV_DATA_USI(0) + static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = { EXYNOS_COMMON_SERIAL_DRV_DATA, .fifosize = { 256, 64, 16, 16 }, @@ -2783,11 +2817,19 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { .fifosize = { 64, 256, 16, 256 }, }; +static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { + EXYNOS_COMMON_SERIAL_DRV_DATA_USI(1), + .fifosize = { 256, 64, 64, 64 }, +}; + #define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos4210_serial_drv_data) #define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos5433_serial_drv_data) +#define EXYNOS850_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos850_serial_drv_data) + #else -#define EXYNOS4210_SERIAL_DRV_DATA (kernel_ulong_t)NULL -#define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL +#define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)NULL) +#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)NULL) +#define EXYNOS850_SERIAL_DRV_DATA ((kernel_ulong_t)NULL) #endif #ifdef CONFIG_ARCH_APPLE @@ -2843,6 +2885,9 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = { }, { .name = "s5l-uart", .driver_data = S5L_SERIAL_DRV_DATA, + }, { + .name = "exynos850-uart", + .driver_data = EXYNOS850_SERIAL_DRV_DATA, }, { }, }; @@ -2866,6 +2911,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = { .data = (void *)EXYNOS5433_SERIAL_DRV_DATA }, { .compatible = "apple,s5l-uart", .data = (void *)S5L_SERIAL_DRV_DATA }, + { .compatible = "samsung,exynos850-uart", + .data = (void *)EXYNOS850_SERIAL_DRV_DATA }, {}, }; MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match); diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index eba5b9ecba34..45e2e4109acd 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -1568,14 +1568,12 @@ static int tegra_uart_probe(struct platform_device *pdev) struct resource *resource; int ret; const struct tegra_uart_chip_data *cdata; - const struct of_device_id *match; - match = of_match_device(tegra_uart_of_match, &pdev->dev); - if (!match) { + cdata = of_device_get_match_data(&pdev->dev); + if (!cdata) { dev_err(&pdev->dev, "Error: No device match found\n"); return -ENODEV; } - cdata = match->data; tup = devm_kzalloc(&pdev->dev, sizeof(*tup), GFP_KERNEL); if (!tup) { diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 69092deba11f..0e2e35ab64c7 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2314,6 +2314,14 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) port->dev ? ": " : "", port->name, address, port->irq, port->uartclk / 16, uart_type(port)); + + /* The magic multiplier feature is a bit obscure, so report it too. */ + if (port->flags & UPF_MAGIC_MULTIPLIER) + pr_info("%s%s%s extra baud rates supported: %d, %d", + port->dev ? dev_name(port->dev) : "", + port->dev ? ": " : "", + port->name, + port->uartclk / 8, port->uartclk / 4); } static void @@ -2522,9 +2530,12 @@ int uart_register_driver(struct uart_driver *drv) if (!drv->state) goto out; - normal = alloc_tty_driver(drv->nr); - if (!normal) + normal = tty_alloc_driver(drv->nr, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(normal)) { + retval = PTR_ERR(normal); goto out_kfree; + } drv->tty_driver = normal; @@ -2537,7 +2548,6 @@ int uart_register_driver(struct uart_driver *drv) normal->init_termios = tty_std_termios; normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600; - normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; normal->driver_state = drv; tty_set_operations(normal, &uart_ops); @@ -2558,7 +2568,7 @@ int uart_register_driver(struct uart_driver *drv) for (i = 0; i < drv->nr; i++) tty_port_destroy(&drv->state[i].port); - put_tty_driver(normal); + tty_driver_kref_put(normal); out_kfree: kfree(drv->state); out: @@ -2580,7 +2590,7 @@ void uart_unregister_driver(struct uart_driver *drv) unsigned int i; tty_unregister_driver(p); - put_tty_driver(p); + tty_driver_kref_put(p); for (i = 0; i < drv->nr; i++) tty_port_destroy(&drv->state[i].port); kfree(drv->state); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 07eb56294371..89ee43061d3a 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1758,6 +1758,10 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr) /* Handle BREAKs */ sci_handle_breaks(port); + + /* drop invalid character received before break was detected */ + serial_port_in(port, SCxRDR); + sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port)); return IRQ_HANDLED; @@ -1837,7 +1841,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) ret = sci_er_interrupt(irq, ptr); /* Break Interrupt */ - if ((ssr_status & SCxSR_BRK(port)) && err_enabled) + if (s->irqs[SCIx_ERI_IRQ] != s->irqs[SCIx_BRI_IRQ] && + (ssr_status & SCxSR_BRK(port)) && err_enabled) ret = sci_br_interrupt(irq, ptr); /* Overrun Interrupt */ diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index ef793b3b4591..8f032e77b954 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -1034,8 +1034,8 @@ static int stm32_usart_init_port(struct stm32_port *stm32port, int ret, irq; irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return irq ? : -ENODEV; + if (irq < 0) + return irq; port->iotype = UPIO_MEM; port->flags = UPF_BOOT_AUTOCONF; @@ -1064,8 +1064,7 @@ static int stm32_usart_init_port(struct stm32_port *stm32port, &stm32port->txftcfg); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - port->membase = devm_ioremap_resource(&pdev->dev, res); + port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(port->membase)) return PTR_ERR(port->membase); port->mapbase = res->start; @@ -1177,7 +1176,7 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, if (uart_console(port)) return -ENODEV; - stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, + stm32port->rx_buf = dma_alloc_coherent(dev, RX_BUF_L, &stm32port->rx_dma_buf, GFP_KERNEL); if (!stm32port->rx_buf) @@ -1243,7 +1242,7 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, stm32port->tx_dma_busy = false; - stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L, + stm32port->tx_buf = dma_alloc_coherent(dev, TX_BUF_L, &stm32port->tx_dma_buf, GFP_KERNEL); if (!stm32port->tx_buf) diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index a5f15f22d9ef..dfc1ba4e1572 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -17,11 +17,13 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/clk.h> +#include <linux/pm_runtime.h> #define ULITE_NAME "ttyUL" #define ULITE_MAJOR 204 @@ -54,6 +56,7 @@ #define ULITE_CONTROL_RST_TX 0x01 #define ULITE_CONTROL_RST_RX 0x02 #define ULITE_CONTROL_IE 0x10 +#define UART_AUTOSUSPEND_TIMEOUT 3000 /* ms */ /* Static pointer to console port */ #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE @@ -390,12 +393,16 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) static void ulite_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct uartlite_data *pdata = port->private_data; + int ret; - if (!state) - clk_enable(pdata->clk); - else - clk_disable(pdata->clk); + if (!state) { + ret = pm_runtime_get_sync(port->dev); + if (ret < 0) + dev_err(port->dev, "Failed to enable clocks\n"); + } else { + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + } } #ifdef CONFIG_CONSOLE_POLL @@ -448,24 +455,15 @@ static const struct uart_ops ulite_ops = { static void ulite_console_wait_tx(struct uart_port *port) { u8 val; - unsigned long timeout; /* * Spin waiting for TX fifo to have space available. * When using the Microblaze Debug Module this can take up to 1s */ - timeout = jiffies + msecs_to_jiffies(1000); - while (1) { - val = uart_in32(ULITE_STATUS, port); - if ((val & ULITE_STATUS_TXFULL) == 0) - break; - if (time_after(jiffies, timeout)) { - dev_warn(port->dev, - "timeout waiting for TX buffer empty\n"); - break; - } - cpu_relax(); - } + if (read_poll_timeout_atomic(uart_in32, val, !(val & ULITE_STATUS_TXFULL), + 0, 1000000, false, ULITE_STATUS, port)) + dev_warn(port->dev, + "timeout waiting for TX buffer empty\n"); } static void ulite_console_putchar(struct uart_port *port, int ch) @@ -555,16 +553,15 @@ static void early_uartlite_putc(struct uart_port *port, int c) * This limit is pretty arbitrary, unless we are at about 10 baud * we'll never timeout on a working UART. */ - unsigned retries = 1000000; - /* read status bit - 0x8 offset */ - while (--retries && (readl(port->membase + 8) & (1 << 3))) + + while (--retries && + (readl(port->membase + ULITE_STATUS) & ULITE_STATUS_TXFULL)) ; /* Only attempt the iowrite if we didn't timeout */ - /* write to TX_FIFO - 0x4 offset */ if (retries) - writel(c & 0xff, port->membase + 4); + writel(c & 0xff, port->membase + ULITE_TX); } static void early_uartlite_write(struct console *console, @@ -719,11 +716,38 @@ static int __maybe_unused ulite_resume(struct device *dev) return 0; } +static int __maybe_unused ulite_runtime_suspend(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct uartlite_data *pdata = port->private_data; + + clk_disable(pdata->clk); + return 0; +}; + +static int __maybe_unused ulite_runtime_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct uartlite_data *pdata = port->private_data; + int ret; + + ret = clk_enable(pdata->clk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + return 0; +} + /* --------------------------------------------------------------------- * Platform bus binding */ -static SIMPLE_DEV_PM_OPS(ulite_pm_ops, ulite_suspend, ulite_resume); +static const struct dev_pm_ops ulite_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ulite_suspend, ulite_resume) + SET_RUNTIME_PM_OPS(ulite_runtime_suspend, + ulite_runtime_resume, NULL) +}; #if defined(CONFIG_OF) /* Match table for of_platform binding */ @@ -779,18 +803,25 @@ static int ulite_probe(struct platform_device *pdev) return ret; } + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + if (!ulite_uart_driver.state) { dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n"); ret = uart_register_driver(&ulite_uart_driver); if (ret < 0) { dev_err(&pdev->dev, "Failed to register driver\n"); + clk_disable_unprepare(pdata->clk); return ret; } } ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata); - clk_disable(pdata->clk); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); return ret; } @@ -799,9 +830,14 @@ static int ulite_remove(struct platform_device *pdev) { struct uart_port *port = dev_get_drvdata(&pdev->dev); struct uartlite_data *pdata = port->private_data; + int rc; clk_disable_unprepare(pdata->clk); - return ulite_release(&pdev->dev); + rc = ulite_release(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + return rc; } /* work with hotplug and coldplug */ diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index c5edd56ff830..e15b2bf69904 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -623,17 +623,14 @@ static int vt8500_serial_probe(struct platform_device *pdev) struct vt8500_port *vt8500_port; struct resource *mmres, *irqres; struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match; const unsigned int *flags; int ret; int port; - match = of_match_device(wmt_dt_ids, &pdev->dev); - if (!match) + flags = of_device_get_match_data(&pdev->dev); + if (!flags) return -EINVAL; - flags = match->data; - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!mmres || !irqres) diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 3e3b8873fa29..a9acd93e85b7 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -3647,7 +3647,7 @@ static void slgt_cleanup(void) for (info=slgt_device_list ; info != NULL ; info=info->next_device) tty_unregister_device(serial_driver, info->line); tty_unregister_driver(serial_driver); - put_tty_driver(serial_driver); + tty_driver_kref_put(serial_driver); } /* reset devices */ @@ -3686,10 +3686,11 @@ static int __init slgt_init(void) printk(KERN_INFO "%s\n", driver_name); - serial_driver = alloc_tty_driver(MAX_DEVICES); - if (!serial_driver) { + serial_driver = tty_alloc_driver(MAX_DEVICES, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(serial_driver)) { printk("%s can't allocate tty driver\n", driver_name); - return -ENOMEM; + return PTR_ERR(serial_driver); } /* Initialize the tty_driver structure */ @@ -3705,11 +3706,10 @@ static int __init slgt_init(void) B9600 | CS8 | CREAD | HUPCL | CLOCAL; serial_driver->init_termios.c_ispeed = 9600; serial_driver->init_termios.c_ospeed = 9600; - serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(serial_driver, &ops); if ((rc = tty_register_driver(serial_driver)) < 0) { DBGERR(("%s can't register serial driver\n", driver_name)); - put_tty_driver(serial_driver); + tty_driver_kref_put(serial_driver); serial_driver = NULL; goto error; } diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 6628792431dc..c911196ac893 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -258,7 +258,7 @@ static void sysrq_handle_showallcpus(int key) if (!trigger_all_cpu_backtrace()) { struct pt_regs *regs = NULL; - if (in_irq()) + if (in_hardirq()) regs = get_irq_regs(); if (regs) { pr_info("CPU%d:\n", smp_processor_id()); @@ -280,7 +280,7 @@ static void sysrq_handle_showregs(int key) { struct pt_regs *regs = NULL; - if (in_irq()) + if (in_hardirq()) regs = get_irq_regs(); if (regs) show_regs(regs); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 26debec26b4e..6616d4a0d41d 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2290,8 +2290,6 @@ static int tty_fasync(int fd, struct file *filp, int on) * Locking: * Called functions take tty_ldiscs_lock * current->signal->tty check is safe without locks - * - * FIXME: may race normal receive processing */ static int tiocsti(struct tty_struct *tty, char __user *p) @@ -2307,8 +2305,10 @@ static int tiocsti(struct tty_struct *tty, char __user *p) ld = tty_ldisc_ref_wait(tty); if (!ld) return -EIO; + tty_buffer_lock_exclusive(tty->port); if (ld->ops->receive_buf) ld->ops->receive_buf(tty, &ch, &mbz, 1); + tty_buffer_unlock_exclusive(tty->port); tty_ldisc_deref(ld); return 0; } @@ -3438,19 +3438,6 @@ void tty_driver_kref_put(struct tty_driver *driver) } EXPORT_SYMBOL(tty_driver_kref_put); -void tty_set_operations(struct tty_driver *driver, - const struct tty_operations *op) -{ - driver->ops = op; -}; -EXPORT_SYMBOL(tty_set_operations); - -void put_tty_driver(struct tty_driver *d) -{ - tty_driver_kref_put(d); -} -EXPORT_SYMBOL(put_tty_driver); - /* * Called by a tty driver to register itself. */ diff --git a/drivers/tty/ttynull.c b/drivers/tty/ttynull.c index af3311a24917..1d4438472442 100644 --- a/drivers/tty/ttynull.c +++ b/drivers/tty/ttynull.c @@ -84,7 +84,7 @@ static int __init ttynull_init(void) ret = tty_register_driver(driver); if (ret < 0) { - put_tty_driver(driver); + tty_driver_kref_put(driver); tty_port_destroy(&ttynull_port); return ret; } @@ -99,7 +99,7 @@ static void __exit ttynull_exit(void) { unregister_console(&ttynull_console); tty_unregister_driver(ttynull_driver); - put_tty_driver(ttynull_driver); + tty_driver_kref_put(ttynull_driver); tty_port_destroy(&ttynull_port); } diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index d06bcc3b4c07..e11383ae1e7e 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -1028,7 +1028,7 @@ static int vcc_tty_init(void) rv = tty_register_driver(vcc_tty_driver); if (rv) { pr_err("VCC: TTY driver registration failed\n"); - put_tty_driver(vcc_tty_driver); + tty_driver_kref_put(vcc_tty_driver); vcc_tty_driver = NULL; return rv; } @@ -1041,7 +1041,7 @@ static int vcc_tty_init(void) static void vcc_tty_exit(void) { tty_unregister_driver(vcc_tty_driver); - put_tty_driver(vcc_tty_driver); + tty_driver_kref_put(vcc_tty_driver); vccdbg("VCC: TTY driver unregistered\n"); vcc_tty_driver = NULL; diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 4b0d69042ceb..c7fbbcdcc346 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1171,9 +1171,9 @@ static inline unsigned char getleds(void) * * Check the status of a keyboard led flag and report it back */ -int vt_get_leds(int console, int flag) +int vt_get_leds(unsigned int console, int flag) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; int ret; unsigned long flags; @@ -1193,9 +1193,9 @@ EXPORT_SYMBOL_GPL(vt_get_leds); * Set the LEDs on a console. This is a wrapper for the VT layer * so that we can keep kbd knowledge internal */ -void vt_set_led_state(int console, int leds) +void vt_set_led_state(unsigned int console, int leds) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; setledstate(kb, leds); } @@ -1212,9 +1212,9 @@ void vt_set_led_state(int console, int leds) * don't hold the lock. We probably need to split out an LED lock * but not during an -rc release! */ -void vt_kbd_con_start(int console) +void vt_kbd_con_start(unsigned int console) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; unsigned long flags; spin_lock_irqsave(&led_lock, flags); clr_vc_kbd_led(kb, VC_SCROLLOCK); @@ -1229,9 +1229,9 @@ void vt_kbd_con_start(int console) * Handle console stop. This is a wrapper for the VT layer * so that we can keep kbd knowledge internal */ -void vt_kbd_con_stop(int console) +void vt_kbd_con_stop(unsigned int console) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; unsigned long flags; spin_lock_irqsave(&led_lock, flags); set_vc_kbd_led(kb, VC_SCROLLOCK); @@ -1377,7 +1377,7 @@ static void kbd_rawcode(unsigned char data) { struct vc_data *vc = vc_cons[fg_console].d; - kbd = kbd_table + vc->vc_num; + kbd = &kbd_table[vc->vc_num]; if (kbd->kbdmode == VC_RAW) put_queue(vc, data); } @@ -1400,7 +1400,7 @@ static void kbd_keycode(unsigned int keycode, int down, bool hw_raw) tty->driver_data = vc; } - kbd = kbd_table + vc->vc_num; + kbd = &kbd_table[vc->vc_num]; #ifdef CONFIG_SPARC if (keycode == KEY_STOP) @@ -1825,9 +1825,9 @@ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) * Update the keyboard mode bits while holding the correct locks. * Return 0 for success or an error code. */ -int vt_do_kdskbmode(int console, unsigned int arg) +int vt_do_kdskbmode(unsigned int console, unsigned int arg) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; int ret = 0; unsigned long flags; @@ -1865,9 +1865,9 @@ int vt_do_kdskbmode(int console, unsigned int arg) * Update the keyboard meta bits while holding the correct locks. * Return 0 for success or an error code. */ -int vt_do_kdskbmeta(int console, unsigned int arg) +int vt_do_kdskbmeta(unsigned int console, unsigned int arg) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; int ret = 0; unsigned long flags; @@ -2008,9 +2008,9 @@ out: } int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, - int console) + unsigned int console) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; struct kbentry kbe; if (copy_from_user(&kbe, user_kbe, sizeof(struct kbentry))) @@ -2097,9 +2097,9 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) return ret; } -int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) +int vt_do_kdskled(unsigned int console, int cmd, unsigned long arg, int perm) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; unsigned long flags; unsigned char ucval; @@ -2139,9 +2139,9 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) return -ENOIOCTLCMD; } -int vt_do_kdgkbmode(int console) +int vt_do_kdgkbmode(unsigned int console) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; /* This is a spot read so needs no locking */ switch (kb->kbdmode) { case VC_RAW: @@ -2163,9 +2163,9 @@ int vt_do_kdgkbmode(int console) * * Report the meta flag status of this console */ -int vt_do_kdgkbmeta(int console) +int vt_do_kdgkbmeta(unsigned int console) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; /* Again a spot read so no locking */ return vc_kbd_mode(kb, VC_META) ? K_ESCPREFIX : K_METABIT; } @@ -2176,7 +2176,7 @@ int vt_do_kdgkbmeta(int console) * * Restore the unicode console state to its default */ -void vt_reset_unicode(int console) +void vt_reset_unicode(unsigned int console) { unsigned long flags; @@ -2204,9 +2204,9 @@ int vt_get_shift_state(void) * Reset the keyboard bits for a console as part of a general console * reset event */ -void vt_reset_keyboard(int console) +void vt_reset_keyboard(unsigned int console) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); @@ -2234,9 +2234,9 @@ void vt_reset_keyboard(int console) * caller must be sure that there are no synchronization needs */ -int vt_get_kbd_mode_bit(int console, int bit) +int vt_get_kbd_mode_bit(unsigned int console, int bit) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; return vc_kbd_mode(kb, bit); } @@ -2249,9 +2249,9 @@ int vt_get_kbd_mode_bit(int console, int bit) * caller must be sure that there are no synchronization needs */ -void vt_set_kbd_mode_bit(int console, int bit) +void vt_set_kbd_mode_bit(unsigned int console, int bit) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); @@ -2268,9 +2268,9 @@ void vt_set_kbd_mode_bit(int console, int bit) * caller must be sure that there are no synchronization needs */ -void vt_clr_kbd_mode_bit(int console, int bit) +void vt_clr_kbd_mode_bit(unsigned int console, int bit) { - struct kbd_struct *kb = kbd_table + console; + struct kbd_struct *kb = &kbd_table[console]; unsigned long flags; spin_lock_irqsave(&kbd_event_lock, flags); diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index cb72393f92d3..7359c3e80d63 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1219,8 +1219,25 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, new_row_size = new_cols << 1; new_screen_size = new_row_size * new_rows; - if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) - return 0; + if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) { + /* + * This function is being called here to cover the case + * where the userspace calls the FBIOPUT_VSCREENINFO twice, + * passing the same fb_var_screeninfo containing the fields + * yres/xres equal to a number non-multiple of vc_font.height + * and yres_virtual/xres_virtual equal to number lesser than the + * vc_font.height and yres/xres. + * In the second call, the struct fb_var_screeninfo isn't + * being modified by the underlying driver because of the + * if above, and this causes the fbcon_display->vrows to become + * negative and it eventually leads to out-of-bound + * access by the imageblit function. + * To give the correct values to the struct and to not have + * to deal with possible errors from the code below, we call + * the resize_screen here as well. + */ + return resize_screen(vc, new_cols, new_rows, user); + } if (new_screen_size > KMALLOC_MAX_SIZE || !new_screen_size) return -EINVAL; @@ -3582,8 +3599,9 @@ int __init vty_init(const struct file_operations *console_fops) vcs_init(); - console_driver = alloc_tty_driver(MAX_NR_CONSOLES); - if (!console_driver) + console_driver = tty_alloc_driver(MAX_NR_CONSOLES, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_RESET_TERMIOS); + if (IS_ERR(console_driver)) panic("Couldn't allocate console driver\n"); console_driver->name = "tty"; @@ -3594,7 +3612,6 @@ int __init vty_init(const struct file_operations *console_fops) console_driver->init_termios = tty_std_termios; if (default_utf8) console_driver->init_termios.c_iflag |= IUTF8; - console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; tty_set_operations(console_driver, &con_ops); if (tty_register_driver(console_driver)) panic("Couldn't register console driver\n"); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 4895325b16a4..8bbd8e29e60d 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -2027,16 +2027,16 @@ static const struct tty_operations acm_ops = { static int __init acm_init(void) { int retval; - acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS); - if (!acm_tty_driver) - return -ENOMEM; + acm_tty_driver = tty_alloc_driver(ACM_TTY_MINORS, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(acm_tty_driver)) + return PTR_ERR(acm_tty_driver); acm_tty_driver->driver_name = "acm", acm_tty_driver->name = "ttyACM", acm_tty_driver->major = ACM_TTY_MAJOR, acm_tty_driver->minor_start = 0, acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL, acm_tty_driver->subtype = SERIAL_TYPE_NORMAL, - acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; acm_tty_driver->init_termios = tty_std_termios; acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -2044,14 +2044,14 @@ static int __init acm_init(void) retval = tty_register_driver(acm_tty_driver); if (retval) { - put_tty_driver(acm_tty_driver); + tty_driver_kref_put(acm_tty_driver); return retval; } retval = usb_register(&acm_driver); if (retval) { tty_unregister_driver(acm_tty_driver); - put_tty_driver(acm_tty_driver); + tty_driver_kref_put(acm_tty_driver); return retval; } @@ -2064,7 +2064,7 @@ static void __exit acm_exit(void) { usb_deregister(&acm_driver); tty_unregister_driver(acm_tty_driver); - put_tty_driver(acm_tty_driver); + tty_driver_kref_put(acm_tty_driver); idr_destroy(&acm_minors); } diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 281ca766698a..6f68cbeeee7c 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -1445,51 +1445,53 @@ EXPORT_SYMBOL_GPL(gserial_resume); static int userial_init(void) { + struct tty_driver *driver; unsigned i; int status; - gs_tty_driver = alloc_tty_driver(MAX_U_SERIAL_PORTS); - if (!gs_tty_driver) - return -ENOMEM; + driver = tty_alloc_driver(MAX_U_SERIAL_PORTS, TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(driver)) + return PTR_ERR(driver); - gs_tty_driver->driver_name = "g_serial"; - gs_tty_driver->name = "ttyGS"; + driver->driver_name = "g_serial"; + driver->name = "ttyGS"; /* uses dynamically assigned dev_t values */ - gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - gs_tty_driver->subtype = SERIAL_TYPE_NORMAL; - gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - gs_tty_driver->init_termios = tty_std_termios; + driver->type = TTY_DRIVER_TYPE_SERIAL; + driver->subtype = SERIAL_TYPE_NORMAL; + driver->init_termios = tty_std_termios; /* 9600-8-N-1 ... matches defaults expected by "usbser.sys" on * MS-Windows. Otherwise, most of these flags shouldn't affect * anything unless we were to actually hook up to a serial line. */ - gs_tty_driver->init_termios.c_cflag = + driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - gs_tty_driver->init_termios.c_ispeed = 9600; - gs_tty_driver->init_termios.c_ospeed = 9600; + driver->init_termios.c_ispeed = 9600; + driver->init_termios.c_ospeed = 9600; - tty_set_operations(gs_tty_driver, &gs_tty_ops); + tty_set_operations(driver, &gs_tty_ops); for (i = 0; i < MAX_U_SERIAL_PORTS; i++) mutex_init(&ports[i].lock); /* export the driver ... */ - status = tty_register_driver(gs_tty_driver); + status = tty_register_driver(driver); if (status) { pr_err("%s: cannot register, err %d\n", __func__, status); goto fail; } + gs_tty_driver = driver; + pr_debug("%s: registered %d ttyGS* device%s\n", __func__, MAX_U_SERIAL_PORTS, (MAX_U_SERIAL_PORTS == 1) ? "" : "s"); return status; fail: - put_tty_driver(gs_tty_driver); - gs_tty_driver = NULL; + tty_driver_kref_put(driver); return status; } module_init(userial_init); @@ -1497,7 +1499,7 @@ module_init(userial_init); static void userial_cleanup(void) { tty_unregister_driver(gs_tty_driver); - put_tty_driver(gs_tty_driver); + tty_driver_kref_put(gs_tty_driver); gs_tty_driver = NULL; } module_exit(userial_cleanup); diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index bef104511352..6e784f2fc26d 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -541,7 +541,7 @@ static int dbc_tty_init(void) ret = tty_register_driver(dbc_tty_driver); if (ret) { pr_err("Can't register dbc tty driver\n"); - put_tty_driver(dbc_tty_driver); + tty_driver_kref_put(dbc_tty_driver); } return ret; } @@ -550,7 +550,7 @@ static void dbc_tty_exit(void) { if (dbc_tty_driver) { tty_unregister_driver(dbc_tty_driver); - put_tty_driver(dbc_tty_driver); + tty_driver_kref_put(dbc_tty_driver); dbc_tty_driver = NULL; } } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index eeb441c77207..090a78c948f2 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1319,9 +1319,10 @@ static int __init usb_serial_init(void) { int result; - usb_serial_tty_driver = alloc_tty_driver(USB_SERIAL_TTY_MINORS); - if (!usb_serial_tty_driver) - return -ENOMEM; + usb_serial_tty_driver = tty_alloc_driver(USB_SERIAL_TTY_MINORS, + TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(usb_serial_tty_driver)) + return PTR_ERR(usb_serial_tty_driver); /* Initialize our global data */ result = bus_register(&usb_serial_bus_type); @@ -1336,8 +1337,6 @@ static int __init usb_serial_init(void) usb_serial_tty_driver->minor_start = 0; usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL; - usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV; usb_serial_tty_driver->init_termios = tty_std_termios; usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -1367,7 +1366,7 @@ exit_reg_driver: exit_bus: pr_err("%s - returning with error %d\n", __func__, result); - put_tty_driver(usb_serial_tty_driver); + tty_driver_kref_put(usb_serial_tty_driver); return result; } @@ -1379,7 +1378,7 @@ static void __exit usb_serial_exit(void) usb_serial_generic_deregister(); tty_unregister_driver(usb_serial_tty_driver); - put_tty_driver(usb_serial_tty_driver); + tty_driver_kref_put(usb_serial_tty_driver); bus_unregister(&usb_serial_bus_type); idr_destroy(&serial_minors); } diff --git a/include/linux/serdev.h b/include/linux/serdev.h index 9f14f9c12ec4..3368c261ab62 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -327,4 +327,18 @@ static inline int serdev_tty_port_unregister(struct tty_port *port) } #endif /* CONFIG_SERIAL_DEV_CTRL_TTYPORT */ +struct acpi_resource; +struct acpi_resource_uart_serialbus; + +#ifdef CONFIG_ACPI +bool serdev_acpi_get_uart_resource(struct acpi_resource *ares, + struct acpi_resource_uart_serialbus **uart); +#else +static inline bool serdev_acpi_get_uart_resource(struct acpi_resource *ares, + struct acpi_resource_uart_serialbus **uart) +{ + return false; +} +#endif /* CONFIG_ACPI */ + #endif /*_LINUX_SERDEV_H */ diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h index f6c3323fc4c5..cf0de4a86640 100644 --- a/include/linux/serial_s3c.h +++ b/include/linux/serial_s3c.h @@ -27,6 +27,15 @@ #define S3C2410_UERSTAT (0x14) #define S3C2410_UFSTAT (0x18) #define S3C2410_UMSTAT (0x1C) +#define USI_CON (0xC4) +#define USI_OPTION (0xC8) + +#define USI_CON_RESET (1<<0) +#define USI_CON_RESET_MASK (1<<0) + +#define USI_OPTION_HWACG_CLKREQ_ON (1<<1) +#define USI_OPTION_HWACG_CLKSTOP_ON (1<<2) +#define USI_OPTION_HWACG_MASK (3<<1) #define S3C2410_LCON_CFGMASK ((0xF<<3)|(0x3)) diff --git a/include/linux/tty.h b/include/linux/tty.h index 19dc1097e09c..168e57e40bbb 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -6,11 +6,12 @@ #include <linux/major.h> #include <linux/termios.h> #include <linux/workqueue.h> +#include <linux/tty_buffer.h> #include <linux/tty_driver.h> #include <linux/tty_ldisc.h> +#include <linux/tty_port.h> #include <linux/mutex.h> #include <linux/tty_flags.h> -#include <linux/seq_file.h> #include <uapi/linux/tty.h> #include <linux/rwsem.h> #include <linux/llist.h> @@ -31,54 +32,6 @@ */ #define __DISABLED_CHAR '\0' -struct tty_buffer { - union { - struct tty_buffer *next; - struct llist_node free; - }; - int used; - int size; - int commit; - int read; - int flags; - /* Data points here */ - unsigned long data[]; -}; - -/* Values for .flags field of tty_buffer */ -#define TTYB_NORMAL 1 /* buffer has no flags buffer */ - -static inline unsigned char *char_buf_ptr(struct tty_buffer *b, int ofs) -{ - return ((unsigned char *)b->data) + ofs; -} - -static inline char *flag_buf_ptr(struct tty_buffer *b, int ofs) -{ - return (char *)char_buf_ptr(b, ofs) + b->size; -} - -struct tty_bufhead { - struct tty_buffer *head; /* Queue head */ - struct work_struct work; - struct mutex lock; - atomic_t priority; - struct tty_buffer sentinel; - struct llist_head free; /* Free queue head */ - atomic_t mem_used; /* In-use buffers excluding free list */ - int mem_limit; - struct tty_buffer *tail; /* Active buffer */ -}; -/* - * When a break, frame error, or parity error happens, these codes are - * stuffed into the flags buffer. - */ -#define TTY_NORMAL 0 -#define TTY_BREAK 1 -#define TTY_FRAME 2 -#define TTY_PARITY 3 -#define TTY_OVERRUN 4 - #define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) #define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) #define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) @@ -164,85 +117,6 @@ struct tty_bufhead { struct device; struct signal_struct; - -/* - * Port level information. Each device keeps its own port level information - * so provide a common structure for those ports wanting to use common support - * routines. - * - * The tty port has a different lifetime to the tty so must be kept apart. - * In addition be careful as tty -> port mappings are valid for the life - * of the tty object but in many cases port -> tty mappings are valid only - * until a hangup so don't use the wrong path. - */ - -struct tty_port; - -struct tty_port_operations { - /* Return 1 if the carrier is raised */ - int (*carrier_raised)(struct tty_port *port); - /* Control the DTR line */ - void (*dtr_rts)(struct tty_port *port, int raise); - /* Called when the last close completes or a hangup finishes - IFF the port was initialized. Do not use to free resources. Called - under the port mutex to serialize against activate/shutdowns */ - void (*shutdown)(struct tty_port *port); - /* Called under the port mutex from tty_port_open, serialized using - the port mutex */ - /* FIXME: long term getting the tty argument *out* of this would be - good for consoles */ - int (*activate)(struct tty_port *port, struct tty_struct *tty); - /* Called on the final put of a port */ - void (*destruct)(struct tty_port *port); -}; - -struct tty_port_client_operations { - int (*receive_buf)(struct tty_port *port, const unsigned char *, const unsigned char *, size_t); - void (*write_wakeup)(struct tty_port *port); -}; - -extern const struct tty_port_client_operations tty_port_default_client_ops; - -struct tty_port { - struct tty_bufhead buf; /* Locked internally */ - struct tty_struct *tty; /* Back pointer */ - struct tty_struct *itty; /* internal back ptr */ - const struct tty_port_operations *ops; /* Port operations */ - const struct tty_port_client_operations *client_ops; /* Port client operations */ - spinlock_t lock; /* Lock protecting tty field */ - int blocked_open; /* Waiting to open */ - int count; /* Usage count */ - wait_queue_head_t open_wait; /* Open waiters */ - wait_queue_head_t delta_msr_wait; /* Modem status change */ - unsigned long flags; /* User TTY flags ASYNC_ */ - unsigned long iflags; /* Internal flags TTY_PORT_ */ - unsigned char console:1; /* port is a console */ - struct mutex mutex; /* Locking */ - struct mutex buf_mutex; /* Buffer alloc lock */ - unsigned char *xmit_buf; /* Optional buffer */ - unsigned int close_delay; /* Close port delay */ - unsigned int closing_wait; /* Delay for output */ - int drain_delay; /* Set to zero if no pure time - based drain is needed else - set to size of fifo */ - struct kref kref; /* Ref counter */ - void *client_data; -}; - -/* tty_port::iflags bits -- use atomic bit ops */ -#define TTY_PORT_INITIALIZED 0 /* device is initialized */ -#define TTY_PORT_SUSPENDED 1 /* device is suspended */ -#define TTY_PORT_ACTIVE 2 /* device is open */ - -/* - * uart drivers: use the uart_port::status field and the UPSTAT_* defines - * for s/w-based flow control steering and carrier detection status - */ -#define TTY_PORT_CTS_FLOW 3 /* h/w flow control enabled */ -#define TTY_PORT_CHECK_CD 4 /* carrier detect enabled */ -#define TTY_PORT_KOPENED 5 /* device exclusively opened by - kernel */ - struct tty_operations; /** @@ -446,15 +320,6 @@ extern const char *tty_driver_name(const struct tty_struct *tty); extern void tty_wait_until_sent(struct tty_struct *tty, long timeout); extern void stop_tty(struct tty_struct *tty); extern void start_tty(struct tty_struct *tty); -extern int tty_register_driver(struct tty_driver *driver); -extern void tty_unregister_driver(struct tty_driver *driver); -extern struct device *tty_register_device(struct tty_driver *driver, - unsigned index, struct device *dev); -extern struct device *tty_register_device_attr(struct tty_driver *driver, - unsigned index, struct device *device, - void *drvdata, - const struct attribute_group **attr_grp); -extern void tty_unregister_device(struct tty_driver *driver, unsigned index); extern void tty_write_message(struct tty_struct *tty, char *msg); extern int tty_send_xchar(struct tty_struct *tty, char ch); extern int tty_put_char(struct tty_struct *tty, unsigned char c); @@ -502,13 +367,7 @@ extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old); extern int tty_termios_hw_change(const struct ktermios *a, const struct ktermios *b); extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); -extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *); -extern void tty_ldisc_deref(struct tty_ldisc *); -extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *); -extern const struct seq_operations tty_ldiscs_seq_ops; - extern void tty_wakeup(struct tty_struct *tty); -extern void tty_ldisc_flush(struct tty_struct *tty); extern int tty_mode_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); @@ -522,128 +381,6 @@ extern int tty_standard_install(struct tty_driver *driver, extern struct mutex tty_mutex; -extern void tty_port_init(struct tty_port *port); -extern void tty_port_link_device(struct tty_port *port, - struct tty_driver *driver, unsigned index); -extern struct device *tty_port_register_device(struct tty_port *port, - struct tty_driver *driver, unsigned index, - struct device *device); -extern struct device *tty_port_register_device_attr(struct tty_port *port, - struct tty_driver *driver, unsigned index, - struct device *device, void *drvdata, - const struct attribute_group **attr_grp); -extern struct device *tty_port_register_device_serdev(struct tty_port *port, - struct tty_driver *driver, unsigned index, - struct device *device); -extern struct device *tty_port_register_device_attr_serdev(struct tty_port *port, - struct tty_driver *driver, unsigned index, - struct device *device, void *drvdata, - const struct attribute_group **attr_grp); -extern void tty_port_unregister_device(struct tty_port *port, - struct tty_driver *driver, unsigned index); -extern int tty_port_alloc_xmit_buf(struct tty_port *port); -extern void tty_port_free_xmit_buf(struct tty_port *port); -extern void tty_port_destroy(struct tty_port *port); -extern void tty_port_put(struct tty_port *port); - -static inline struct tty_port *tty_port_get(struct tty_port *port) -{ - if (port && kref_get_unless_zero(&port->kref)) - return port; - return NULL; -} - -/* If the cts flow control is enabled, return true. */ -static inline bool tty_port_cts_enabled(const struct tty_port *port) -{ - return test_bit(TTY_PORT_CTS_FLOW, &port->iflags); -} - -static inline void tty_port_set_cts_flow(struct tty_port *port, bool val) -{ - assign_bit(TTY_PORT_CTS_FLOW, &port->iflags, val); -} - -static inline bool tty_port_active(const struct tty_port *port) -{ - return test_bit(TTY_PORT_ACTIVE, &port->iflags); -} - -static inline void tty_port_set_active(struct tty_port *port, bool val) -{ - assign_bit(TTY_PORT_ACTIVE, &port->iflags, val); -} - -static inline bool tty_port_check_carrier(const struct tty_port *port) -{ - return test_bit(TTY_PORT_CHECK_CD, &port->iflags); -} - -static inline void tty_port_set_check_carrier(struct tty_port *port, bool val) -{ - assign_bit(TTY_PORT_CHECK_CD, &port->iflags, val); -} - -static inline bool tty_port_suspended(const struct tty_port *port) -{ - return test_bit(TTY_PORT_SUSPENDED, &port->iflags); -} - -static inline void tty_port_set_suspended(struct tty_port *port, bool val) -{ - assign_bit(TTY_PORT_SUSPENDED, &port->iflags, val); -} - -static inline bool tty_port_initialized(const struct tty_port *port) -{ - return test_bit(TTY_PORT_INITIALIZED, &port->iflags); -} - -static inline void tty_port_set_initialized(struct tty_port *port, bool val) -{ - assign_bit(TTY_PORT_INITIALIZED, &port->iflags, val); -} - -static inline bool tty_port_kopened(const struct tty_port *port) -{ - return test_bit(TTY_PORT_KOPENED, &port->iflags); -} - -static inline void tty_port_set_kopened(struct tty_port *port, bool val) -{ - assign_bit(TTY_PORT_KOPENED, &port->iflags, val); -} - -extern struct tty_struct *tty_port_tty_get(struct tty_port *port); -extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); -extern int tty_port_carrier_raised(struct tty_port *port); -extern void tty_port_raise_dtr_rts(struct tty_port *port); -extern void tty_port_lower_dtr_rts(struct tty_port *port); -extern void tty_port_hangup(struct tty_port *port); -extern void tty_port_tty_hangup(struct tty_port *port, bool check_clocal); -extern void tty_port_tty_wakeup(struct tty_port *port); -extern int tty_port_block_til_ready(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -extern int tty_port_close_start(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); -extern void tty_port_close(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -extern int tty_port_install(struct tty_port *port, struct tty_driver *driver, - struct tty_struct *tty); -extern int tty_port_open(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -static inline int tty_port_users(struct tty_port *port) -{ - return port->count + port->blocked_open; -} - -extern int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc); -extern void tty_unregister_ldisc(struct tty_ldisc_ops *ldisc); -extern int tty_set_ldisc(struct tty_struct *tty, int disc); -extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, - const char *f, int count); - /* n_tty.c */ extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops); #ifdef CONFIG_TTY @@ -691,12 +428,4 @@ extern void tty_lock_slave(struct tty_struct *tty); extern void tty_unlock_slave(struct tty_struct *tty); extern void tty_set_lock_subclass(struct tty_struct *tty); -#ifdef CONFIG_PROC_FS -extern void proc_tty_register_driver(struct tty_driver *); -extern void proc_tty_unregister_driver(struct tty_driver *); -#else -static inline void proc_tty_register_driver(struct tty_driver *d) {} -static inline void proc_tty_unregister_driver(struct tty_driver *d) {} -#endif - #endif diff --git a/include/linux/tty_buffer.h b/include/linux/tty_buffer.h new file mode 100644 index 000000000000..3b9d77604291 --- /dev/null +++ b/include/linux/tty_buffer.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_TTY_BUFFER_H +#define _LINUX_TTY_BUFFER_H + +#include <linux/atomic.h> +#include <linux/llist.h> +#include <linux/mutex.h> +#include <linux/workqueue.h> + +struct tty_buffer { + union { + struct tty_buffer *next; + struct llist_node free; + }; + int used; + int size; + int commit; + int read; + int flags; + /* Data points here */ + unsigned long data[]; +}; + +/* Values for .flags field of tty_buffer */ +#define TTYB_NORMAL 1 /* buffer has no flags buffer */ + +static inline unsigned char *char_buf_ptr(struct tty_buffer *b, int ofs) +{ + return ((unsigned char *)b->data) + ofs; +} + +static inline char *flag_buf_ptr(struct tty_buffer *b, int ofs) +{ + return (char *)char_buf_ptr(b, ofs) + b->size; +} + +struct tty_bufhead { + struct tty_buffer *head; /* Queue head */ + struct work_struct work; + struct mutex lock; + atomic_t priority; + struct tty_buffer sentinel; + struct llist_head free; /* Free queue head */ + atomic_t mem_used; /* In-use buffers excluding free list */ + int mem_limit; + struct tty_buffer *tail; /* Active buffer */ +}; + +/* + * When a break, frame error, or parity error happens, these codes are + * stuffed into the flags buffer. + */ +#define TTY_NORMAL 0 +#define TTY_BREAK 1 +#define TTY_FRAME 2 +#define TTY_PARITY 3 +#define TTY_OVERRUN 4 + +#endif diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 448f8ee6db6e..c20431d8def8 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -233,6 +233,7 @@ #include <linux/export.h> #include <linux/fs.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/cdev.h> #include <linux/termios.h> @@ -328,9 +329,6 @@ extern struct list_head tty_drivers; extern struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, unsigned long flags); -extern void put_tty_driver(struct tty_driver *driver); -extern void tty_set_operations(struct tty_driver *driver, - const struct tty_operations *op); extern struct tty_driver *tty_find_polling_driver(char *name, int *line); extern void tty_driver_kref_put(struct tty_driver *driver); @@ -339,24 +337,18 @@ extern void tty_driver_kref_put(struct tty_driver *driver); #define tty_alloc_driver(lines, flags) \ __tty_alloc_driver(lines, THIS_MODULE, flags) -/* - * DEPRECATED Do not use this in new code, use tty_alloc_driver instead. - * (And change the return value checks.) - */ -static inline struct tty_driver *alloc_tty_driver(unsigned int lines) -{ - struct tty_driver *ret = tty_alloc_driver(lines, 0); - if (IS_ERR(ret)) - return NULL; - return ret; -} - static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) { kref_get(&d->kref); return d; } +static inline void tty_set_operations(struct tty_driver *driver, + const struct tty_operations *op) +{ + driver->ops = op; +} + /* tty driver magic number */ #define TTY_DRIVER_MAGIC 0x5402 @@ -434,4 +426,21 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) /* serial subtype definitions */ #define SERIAL_TYPE_NORMAL 1 +int tty_register_driver(struct tty_driver *driver); +void tty_unregister_driver(struct tty_driver *driver); +struct device *tty_register_device(struct tty_driver *driver, unsigned index, + struct device *dev); +struct device *tty_register_device_attr(struct tty_driver *driver, + unsigned index, struct device *device, void *drvdata, + const struct attribute_group **attr_grp); +void tty_unregister_device(struct tty_driver *driver, unsigned index); + +#ifdef CONFIG_PROC_FS +void proc_tty_register_driver(struct tty_driver *); +void proc_tty_unregister_driver(struct tty_driver *); +#else +static inline void proc_tty_register_driver(struct tty_driver *d) {} +static inline void proc_tty_unregister_driver(struct tty_driver *d) {} +#endif + #endif /* #ifdef _LINUX_TTY_DRIVER_H */ diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index 67d78dc553e1..32284992b31a 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -2,7 +2,10 @@ #ifndef _LINUX_TTY_FLIP_H #define _LINUX_TTY_FLIP_H -#include <linux/tty.h> +#include <linux/tty_buffer.h> +#include <linux/tty_port.h> + +struct tty_ldisc; extern int tty_buffer_set_limit(struct tty_port *port, int limit); extern unsigned int tty_buffer_space_avail(struct tty_port *port); @@ -39,6 +42,9 @@ static inline int tty_insert_flip_string(struct tty_port *port, return tty_insert_flip_string_fixed_flag(port, chars, TTY_NORMAL, size); } +int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, + const char *f, int count); + extern void tty_buffer_lock_exclusive(struct tty_port *port); extern void tty_buffer_unlock_exclusive(struct tty_port *port); diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index fbe9de278629..b1d812e902aa 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -2,6 +2,8 @@ #ifndef _LINUX_TTY_LDISC_H #define _LINUX_TTY_LDISC_H +struct tty_struct; + /* * This structure defines the interface between the tty line discipline * implementation and the tty routines. The following routines can be @@ -126,6 +128,9 @@ #include <linux/fs.h> #include <linux/wait.h> #include <linux/atomic.h> +#include <linux/list.h> +#include <linux/lockdep.h> +#include <linux/seq_file.h> /* * the semaphore definition @@ -220,4 +225,16 @@ struct tty_ldisc { #define MODULE_ALIAS_LDISC(ldisc) \ MODULE_ALIAS("tty-ldisc-" __stringify(ldisc)) +extern const struct seq_operations tty_ldiscs_seq_ops; + +struct tty_ldisc *tty_ldisc_ref(struct tty_struct *); +void tty_ldisc_deref(struct tty_ldisc *); +struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *); + +void tty_ldisc_flush(struct tty_struct *tty); + +int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc); +void tty_unregister_ldisc(struct tty_ldisc_ops *ldisc); +int tty_set_ldisc(struct tty_struct *tty, int disc); + #endif /* _LINUX_TTY_LDISC_H */ diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h new file mode 100644 index 000000000000..6e86e9e118b6 --- /dev/null +++ b/include/linux/tty_port.h @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_TTY_PORT_H +#define _LINUX_TTY_PORT_H + +#include <linux/kref.h> +#include <linux/mutex.h> +#include <linux/tty_buffer.h> +#include <linux/wait.h> + +/* + * Port level information. Each device keeps its own port level information + * so provide a common structure for those ports wanting to use common support + * routines. + * + * The tty port has a different lifetime to the tty so must be kept apart. + * In addition be careful as tty -> port mappings are valid for the life + * of the tty object but in many cases port -> tty mappings are valid only + * until a hangup so don't use the wrong path. + */ + +struct attribute_group; +struct tty_driver; +struct tty_port; +struct tty_struct; + +struct tty_port_operations { + /* Return 1 if the carrier is raised */ + int (*carrier_raised)(struct tty_port *port); + /* Control the DTR line */ + void (*dtr_rts)(struct tty_port *port, int raise); + /* Called when the last close completes or a hangup finishes + IFF the port was initialized. Do not use to free resources. Called + under the port mutex to serialize against activate/shutdowns */ + void (*shutdown)(struct tty_port *port); + /* Called under the port mutex from tty_port_open, serialized using + the port mutex */ + /* FIXME: long term getting the tty argument *out* of this would be + good for consoles */ + int (*activate)(struct tty_port *port, struct tty_struct *tty); + /* Called on the final put of a port */ + void (*destruct)(struct tty_port *port); +}; + +struct tty_port_client_operations { + int (*receive_buf)(struct tty_port *port, const unsigned char *, const unsigned char *, size_t); + void (*write_wakeup)(struct tty_port *port); +}; + +extern const struct tty_port_client_operations tty_port_default_client_ops; + +struct tty_port { + struct tty_bufhead buf; /* Locked internally */ + struct tty_struct *tty; /* Back pointer */ + struct tty_struct *itty; /* internal back ptr */ + const struct tty_port_operations *ops; /* Port operations */ + const struct tty_port_client_operations *client_ops; /* Port client operations */ + spinlock_t lock; /* Lock protecting tty field */ + int blocked_open; /* Waiting to open */ + int count; /* Usage count */ + wait_queue_head_t open_wait; /* Open waiters */ + wait_queue_head_t delta_msr_wait; /* Modem status change */ + unsigned long flags; /* User TTY flags ASYNC_ */ + unsigned long iflags; /* Internal flags TTY_PORT_ */ + unsigned char console:1; /* port is a console */ + struct mutex mutex; /* Locking */ + struct mutex buf_mutex; /* Buffer alloc lock */ + unsigned char *xmit_buf; /* Optional buffer */ + unsigned int close_delay; /* Close port delay */ + unsigned int closing_wait; /* Delay for output */ + int drain_delay; /* Set to zero if no pure time + based drain is needed else + set to size of fifo */ + struct kref kref; /* Ref counter */ + void *client_data; +}; + +/* tty_port::iflags bits -- use atomic bit ops */ +#define TTY_PORT_INITIALIZED 0 /* device is initialized */ +#define TTY_PORT_SUSPENDED 1 /* device is suspended */ +#define TTY_PORT_ACTIVE 2 /* device is open */ + +/* + * uart drivers: use the uart_port::status field and the UPSTAT_* defines + * for s/w-based flow control steering and carrier detection status + */ +#define TTY_PORT_CTS_FLOW 3 /* h/w flow control enabled */ +#define TTY_PORT_CHECK_CD 4 /* carrier detect enabled */ +#define TTY_PORT_KOPENED 5 /* device exclusively opened by + kernel */ + +void tty_port_init(struct tty_port *port); +void tty_port_link_device(struct tty_port *port, struct tty_driver *driver, + unsigned index); +struct device *tty_port_register_device(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device); +struct device *tty_port_register_device_attr(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device, void *drvdata, + const struct attribute_group **attr_grp); +struct device *tty_port_register_device_serdev(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device); +struct device *tty_port_register_device_attr_serdev(struct tty_port *port, + struct tty_driver *driver, unsigned index, + struct device *device, void *drvdata, + const struct attribute_group **attr_grp); +void tty_port_unregister_device(struct tty_port *port, + struct tty_driver *driver, unsigned index); +int tty_port_alloc_xmit_buf(struct tty_port *port); +void tty_port_free_xmit_buf(struct tty_port *port); +void tty_port_destroy(struct tty_port *port); +void tty_port_put(struct tty_port *port); + +static inline struct tty_port *tty_port_get(struct tty_port *port) +{ + if (port && kref_get_unless_zero(&port->kref)) + return port; + return NULL; +} + +/* If the cts flow control is enabled, return true. */ +static inline bool tty_port_cts_enabled(const struct tty_port *port) +{ + return test_bit(TTY_PORT_CTS_FLOW, &port->iflags); +} + +static inline void tty_port_set_cts_flow(struct tty_port *port, bool val) +{ + assign_bit(TTY_PORT_CTS_FLOW, &port->iflags, val); +} + +static inline bool tty_port_active(const struct tty_port *port) +{ + return test_bit(TTY_PORT_ACTIVE, &port->iflags); +} + +static inline void tty_port_set_active(struct tty_port *port, bool val) +{ + assign_bit(TTY_PORT_ACTIVE, &port->iflags, val); +} + +static inline bool tty_port_check_carrier(const struct tty_port *port) +{ + return test_bit(TTY_PORT_CHECK_CD, &port->iflags); +} + +static inline void tty_port_set_check_carrier(struct tty_port *port, bool val) +{ + assign_bit(TTY_PORT_CHECK_CD, &port->iflags, val); +} + +static inline bool tty_port_suspended(const struct tty_port *port) +{ + return test_bit(TTY_PORT_SUSPENDED, &port->iflags); +} + +static inline void tty_port_set_suspended(struct tty_port *port, bool val) +{ + assign_bit(TTY_PORT_SUSPENDED, &port->iflags, val); +} + +static inline bool tty_port_initialized(const struct tty_port *port) +{ + return test_bit(TTY_PORT_INITIALIZED, &port->iflags); +} + +static inline void tty_port_set_initialized(struct tty_port *port, bool val) +{ + assign_bit(TTY_PORT_INITIALIZED, &port->iflags, val); +} + +static inline bool tty_port_kopened(const struct tty_port *port) +{ + return test_bit(TTY_PORT_KOPENED, &port->iflags); +} + +static inline void tty_port_set_kopened(struct tty_port *port, bool val) +{ + assign_bit(TTY_PORT_KOPENED, &port->iflags, val); +} + +struct tty_struct *tty_port_tty_get(struct tty_port *port); +void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); +int tty_port_carrier_raised(struct tty_port *port); +void tty_port_raise_dtr_rts(struct tty_port *port); +void tty_port_lower_dtr_rts(struct tty_port *port); +void tty_port_hangup(struct tty_port *port); +void tty_port_tty_hangup(struct tty_port *port, bool check_clocal); +void tty_port_tty_wakeup(struct tty_port *port); +int tty_port_block_til_ready(struct tty_port *port, struct tty_struct *tty, + struct file *filp); +int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, + struct file *filp); +void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); +void tty_port_close(struct tty_port *port, struct tty_struct *tty, + struct file *filp); +int tty_port_install(struct tty_port *port, struct tty_driver *driver, + struct tty_struct *tty); +int tty_port_open(struct tty_port *port, struct tty_struct *tty, + struct file *filp); + +static inline int tty_port_users(struct tty_port *port) +{ + return port->count + port->blocked_open; +} + +#endif diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 0da94a6dee15..b5ab452fca5b 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -148,26 +148,26 @@ void hide_boot_cursor(bool hide); /* keyboard provided interfaces */ int vt_do_diacrit(unsigned int cmd, void __user *up, int eperm); -int vt_do_kdskbmode(int console, unsigned int arg); -int vt_do_kdskbmeta(int console, unsigned int arg); +int vt_do_kdskbmode(unsigned int console, unsigned int arg); +int vt_do_kdskbmeta(unsigned int console, unsigned int arg); int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm); int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, - int console); + unsigned int console); int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm); -int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm); -int vt_do_kdgkbmode(int console); -int vt_do_kdgkbmeta(int console); -void vt_reset_unicode(int console); +int vt_do_kdskled(unsigned int console, int cmd, unsigned long arg, int perm); +int vt_do_kdgkbmode(unsigned int console); +int vt_do_kdgkbmeta(unsigned int console); +void vt_reset_unicode(unsigned int console); int vt_get_shift_state(void); -void vt_reset_keyboard(int console); -int vt_get_leds(int console, int flag); -int vt_get_kbd_mode_bit(int console, int bit); -void vt_set_kbd_mode_bit(int console, int bit); -void vt_clr_kbd_mode_bit(int console, int bit); -void vt_set_led_state(int console, int leds); -void vt_kbd_con_start(int console); -void vt_kbd_con_stop(int console); +void vt_reset_keyboard(unsigned int console); +int vt_get_leds(unsigned int console, int flag); +int vt_get_kbd_mode_bit(unsigned int console, int bit); +void vt_set_kbd_mode_bit(unsigned int console, int bit); +void vt_clr_kbd_mode_bit(unsigned int console, int bit); +void vt_set_led_state(unsigned int console, int leds); +void vt_kbd_con_start(unsigned int console); +void vt_kbd_con_stop(unsigned int console); void vc_scrolldelta_helper(struct vc_data *c, int lines, unsigned int rolled_over, void *_base, unsigned int size); diff --git a/include/uapi/linux/serial_reg.h b/include/uapi/linux/serial_reg.h index be07b5470f4b..f51bc8f36813 100644 --- a/include/uapi/linux/serial_reg.h +++ b/include/uapi/linux/serial_reg.h @@ -62,6 +62,7 @@ * ST16C654: 8 16 56 60 8 16 32 56 PORT_16654 * TI16C750: 1 16 32 56 xx xx xx xx PORT_16750 * TI16C752: 8 16 56 60 8 16 32 56 + * OX16C950: 16 32 112 120 16 32 64 112 PORT_16C950 * Tegra: 1 4 8 14 16 8 4 1 PORT_TEGRA */ #define UART_FCR_R_TRIG_00 0x00 diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 4e095746e002..ebd78fdbd6e8 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -1127,9 +1127,10 @@ int __init rfcomm_init_ttys(void) { int error; - rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS); - if (!rfcomm_tty_driver) - return -ENOMEM; + rfcomm_tty_driver = tty_alloc_driver(RFCOMM_TTY_PORTS, + TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); + if (IS_ERR(rfcomm_tty_driver)) + return PTR_ERR(rfcomm_tty_driver); rfcomm_tty_driver->driver_name = "rfcomm"; rfcomm_tty_driver->name = "rfcomm"; @@ -1137,7 +1138,6 @@ int __init rfcomm_init_ttys(void) rfcomm_tty_driver->minor_start = RFCOMM_TTY_MINOR; rfcomm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; rfcomm_tty_driver->subtype = SERIAL_TYPE_NORMAL; - rfcomm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; rfcomm_tty_driver->init_termios = tty_std_termios; rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON; @@ -1146,7 +1146,7 @@ int __init rfcomm_init_ttys(void) error = tty_register_driver(rfcomm_tty_driver); if (error) { BT_ERR("Can't register RFCOMM TTY driver"); - put_tty_driver(rfcomm_tty_driver); + tty_driver_kref_put(rfcomm_tty_driver); return error; } @@ -1158,5 +1158,5 @@ int __init rfcomm_init_ttys(void) void rfcomm_cleanup_ttys(void) { tty_unregister_driver(rfcomm_tty_driver); - put_tty_driver(rfcomm_tty_driver); + tty_driver_kref_put(rfcomm_tty_driver); } |