mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 23:13:01 +02:00
TTY/Serial driver updates for 6.15-rc1
Here is the big set of serial and tty driver updates for 6.15-rc1. Include in here are the following: - more great tty layer cleanups from Jiri. Someday this will be done, but that's not going to be any year soon... - kdb debug driver reverts to fix a reported issue - lots of .dts binding updates for different devices with serial devices - lots of tiny updates and tweaks and a few bugfixes for different serial drivers. All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZ+2YPA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yn2OQCgvxCyoeuNPuV4X89JdrgocMTMyTYAn15pGgDa r7w9UDO/D7UqRnKEnFy+ =lJwK -----END PGP SIGNATURE----- Merge tag 'tty-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver updates from Greg KH: "Here is the big set of serial and tty driver updates for 6.15-rc1. Include in here are the following: - more great tty layer cleanups from Jiri. Someday this will be done, but that's not going to be any year soon... - kdb debug driver reverts to fix a reported issue - lots of .dts binding updates for different devices with serial devices - lots of tiny updates and tweaks and a few bugfixes for different serial drivers. All of these have been in linux-next for a while with no reported issues" * tag 'tty-6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (79 commits) tty: serial: fsl_lpuart: Fix unused variable 'sport' build warning serial: stm32: do not deassert RS485 RTS GPIO prematurely serial: 8250: add driver for NI UARTs dt-bindings: serial: snps-dw-apb-uart: document RZ/N1 binding without DMA serial: icom: fix code format problems serial: sh-sci: Save and restore more registers tty: serial: pl011: remove incorrect of_match_ptr annotation dt-bindings: serial: snps-dw-apb-uart: Add support for rk3562 tty: serial: lpuart: only disable CTS instead of overwriting the whole UARTMODIR register tty: caif: removed unused function debugfs_tx() serial: 8250_dma: terminate correct DMA in tx_dma_flush() tty: serial: fsl_lpuart: rename register variables more specifically tty: serial: fsl_lpuart: use port struct directly to simply code tty: serial: fsl_lpuart: Use u32 and u8 for register variables tty: serial: fsl_lpuart: disable transmitter before changing RS485 related registers tty: serial: 8250: Add Brainboxes XC devices dt-bindings: serial: fsl-lpuart: support i.MX94 tty: serial: 8250: Add some more device IDs dt-bindings: serial: samsung: add exynos7870-uart compatible serial: 8250_dw: Comment possible corner cases in serial_out() implementation ...
This commit is contained in:
commit
ddd0172f18
|
@ -77,7 +77,6 @@ properties:
|
||||||
- altr,16550-FIFO64
|
- altr,16550-FIFO64
|
||||||
- altr,16550-FIFO128
|
- altr,16550-FIFO128
|
||||||
- fsl,16550-FIFO64
|
- fsl,16550-FIFO64
|
||||||
- fsl,ns16550
|
|
||||||
- andestech,uart16550
|
- andestech,uart16550
|
||||||
- nxp,lpc1850-uart
|
- nxp,lpc1850-uart
|
||||||
- opencores,uart16550-rtlsvn105
|
- opencores,uart16550-rtlsvn105
|
||||||
|
@ -86,6 +85,7 @@ properties:
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
- ns16750
|
- ns16750
|
||||||
|
- fsl,ns16550
|
||||||
- cavium,octeon-3860-uart
|
- cavium,octeon-3860-uart
|
||||||
- xlnx,xps-uart16550-2.00.b
|
- xlnx,xps-uart16550-2.00.b
|
||||||
- ralink,rt2880-uart
|
- ralink,rt2880-uart
|
||||||
|
|
|
@ -30,6 +30,7 @@ properties:
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
- fsl,imx93-lpuart
|
- fsl,imx93-lpuart
|
||||||
|
- fsl,imx94-lpuart
|
||||||
- fsl,imx95-lpuart
|
- fsl,imx95-lpuart
|
||||||
- const: fsl,imx8ulp-lpuart
|
- const: fsl,imx8ulp-lpuart
|
||||||
- const: fsl,imx7ulp-lpuart
|
- const: fsl,imx7ulp-lpuart
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/serial/nvidia,tegra264-utc.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: NVIDIA Tegra UTC (UART Trace Controller) client
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Kartik Rajput <kkartik@nvidia.com>
|
||||||
|
- Thierry Reding <thierry.reding@gmail.com>
|
||||||
|
- Jonathan Hunter <jonathanh@nvidia.com>
|
||||||
|
|
||||||
|
description:
|
||||||
|
Represents a client interface of the Tegra UTC (UART Trace Controller). The
|
||||||
|
Tegra UTC allows multiple clients within the Tegra SoC to share a physical
|
||||||
|
UART interface. It supports up to 16 clients. Each client operates as an
|
||||||
|
independent UART endpoint with a dedicated interrupt and 128-character TX/RX
|
||||||
|
FIFOs.
|
||||||
|
|
||||||
|
The Tegra UTC clients use 8-N-1 configuration and operates on a baudrate
|
||||||
|
configured by the bootloader at the controller level.
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: serial.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: nvidia,tegra264-utc
|
||||||
|
|
||||||
|
reg:
|
||||||
|
items:
|
||||||
|
- description: TX region.
|
||||||
|
- description: RX region.
|
||||||
|
|
||||||
|
reg-names:
|
||||||
|
items:
|
||||||
|
- const: tx
|
||||||
|
- const: rx
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
tx-threshold:
|
||||||
|
minimum: 1
|
||||||
|
maximum: 128
|
||||||
|
|
||||||
|
rx-threshold:
|
||||||
|
minimum: 1
|
||||||
|
maximum: 128
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- reg-names
|
||||||
|
- interrupts
|
||||||
|
- tx-threshold
|
||||||
|
- rx-threshold
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||||
|
|
||||||
|
tegra_utc: serial@c4e0000 {
|
||||||
|
compatible = "nvidia,tegra264-utc";
|
||||||
|
reg = <0xc4e0000 0x8000>, <0xc4e8000 0x8000>;
|
||||||
|
reg-names = "tx", "rx";
|
||||||
|
interrupts = <GIC_SPI 514 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
tx-threshold = <4>;
|
||||||
|
rx-threshold = <4>;
|
||||||
|
};
|
|
@ -92,6 +92,9 @@ properties:
|
||||||
3000ms.
|
3000ms.
|
||||||
default: 3000
|
default: 3000
|
||||||
|
|
||||||
|
power-domains:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
resets:
|
resets:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,10 @@ properties:
|
||||||
- samsung,exynosautov9-uart
|
- samsung,exynosautov9-uart
|
||||||
- samsung,exynosautov920-uart
|
- samsung,exynosautov920-uart
|
||||||
- const: samsung,exynos850-uart
|
- const: samsung,exynos850-uart
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- samsung,exynos7870-uart
|
||||||
|
- const: samsung,exynos8895-uart
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
|
@ -13,6 +13,20 @@ allOf:
|
||||||
- $ref: serial.yaml#
|
- $ref: serial.yaml#
|
||||||
- $ref: rs485.yaml#
|
- $ref: rs485.yaml#
|
||||||
|
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
items:
|
||||||
|
- enum:
|
||||||
|
- renesas,r9a06g032-uart
|
||||||
|
- renesas,r9a06g033-uart
|
||||||
|
- const: renesas,rzn1-uart
|
||||||
|
- const: snps,dw-apb-uart
|
||||||
|
then:
|
||||||
|
properties:
|
||||||
|
dmas: false
|
||||||
|
dma-names: false
|
||||||
|
|
||||||
- if:
|
- if:
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
|
@ -30,6 +44,12 @@ allOf:
|
||||||
properties:
|
properties:
|
||||||
compatible:
|
compatible:
|
||||||
oneOf:
|
oneOf:
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
|
- renesas,r9a06g032-uart
|
||||||
|
- renesas,r9a06g033-uart
|
||||||
|
- const: renesas,rzn1-uart
|
||||||
|
- const: snps,dw-apb-uart
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
- renesas,r9a06g032-uart
|
- renesas,r9a06g032-uart
|
||||||
|
@ -51,6 +71,7 @@ properties:
|
||||||
- rockchip,rk3368-uart
|
- rockchip,rk3368-uart
|
||||||
- rockchip,rk3399-uart
|
- rockchip,rk3399-uart
|
||||||
- rockchip,rk3528-uart
|
- rockchip,rk3528-uart
|
||||||
|
- rockchip,rk3562-uart
|
||||||
- rockchip,rk3568-uart
|
- rockchip,rk3568-uart
|
||||||
- rockchip,rk3576-uart
|
- rockchip,rk3576-uart
|
||||||
- rockchip,rk3588-uart
|
- rockchip,rk3588-uart
|
||||||
|
|
|
@ -17,13 +17,18 @@ properties:
|
||||||
oneOf:
|
oneOf:
|
||||||
- items:
|
- items:
|
||||||
- enum:
|
- enum:
|
||||||
- sprd,sc9632-uart
|
- sprd,ums9632-uart
|
||||||
|
- const: sprd,sc9632-uart
|
||||||
|
- items:
|
||||||
|
- enum:
|
||||||
- sprd,sc9860-uart
|
- sprd,sc9860-uart
|
||||||
- sprd,sc9863a-uart
|
- sprd,sc9863a-uart
|
||||||
- sprd,ums512-uart
|
- sprd,ums512-uart
|
||||||
- sprd,ums9620-uart
|
- sprd,ums9620-uart
|
||||||
- const: sprd,sc9836-uart
|
- const: sprd,sc9836-uart
|
||||||
- const: sprd,sc9836-uart
|
- enum:
|
||||||
|
- sprd,sc9632-uart
|
||||||
|
- sprd,sc9836-uart
|
||||||
|
|
||||||
reg:
|
reg:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
|
@ -101,6 +101,6 @@ Modem control lines via GPIO
|
||||||
Some helpers are provided in order to set/get modem control lines via GPIO.
|
Some helpers are provided in order to set/get modem control lines via GPIO.
|
||||||
|
|
||||||
.. kernel-doc:: drivers/tty/serial/serial_mctrl_gpio.c
|
.. kernel-doc:: drivers/tty/serial/serial_mctrl_gpio.c
|
||||||
:identifiers: mctrl_gpio_init mctrl_gpio_free mctrl_gpio_to_gpiod
|
:identifiers: mctrl_gpio_init mctrl_gpio_to_gpiod
|
||||||
mctrl_gpio_set mctrl_gpio_get mctrl_gpio_enable_ms
|
mctrl_gpio_set mctrl_gpio_get mctrl_gpio_enable_ms
|
||||||
mctrl_gpio_disable_ms
|
mctrl_gpio_disable_ms_sync mctrl_gpio_disable_ms_no_sync
|
||||||
|
|
|
@ -25,6 +25,8 @@ freed.
|
||||||
For reference, both allocation and deallocation functions are explained here in
|
For reference, both allocation and deallocation functions are explained here in
|
||||||
detail:
|
detail:
|
||||||
|
|
||||||
|
.. kernel-doc:: include/linux/tty_driver.h
|
||||||
|
:identifiers: tty_alloc_driver
|
||||||
.. kernel-doc:: drivers/tty/tty_io.c
|
.. kernel-doc:: drivers/tty/tty_io.c
|
||||||
:identifiers: __tty_alloc_driver tty_driver_kref_put
|
:identifiers: __tty_alloc_driver tty_driver_kref_put
|
||||||
|
|
||||||
|
@ -35,7 +37,7 @@ Here comes the documentation of flags accepted by tty_alloc_driver() (or
|
||||||
__tty_alloc_driver()):
|
__tty_alloc_driver()):
|
||||||
|
|
||||||
.. kernel-doc:: include/linux/tty_driver.h
|
.. kernel-doc:: include/linux/tty_driver.h
|
||||||
:doc: TTY Driver Flags
|
:identifiers: tty_driver_flag
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ TTY Struct Flags
|
||||||
================
|
================
|
||||||
|
|
||||||
.. kernel-doc:: include/linux/tty.h
|
.. kernel-doc:: include/linux/tty.h
|
||||||
:doc: TTY Struct Flags
|
:identifiers: tty_struct_flags
|
||||||
|
|
||||||
TTY Struct Reference
|
TTY Struct Reference
|
||||||
====================
|
====================
|
||||||
|
|
|
@ -16550,6 +16550,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next
|
||||||
F: drivers/mtd/nand/
|
F: drivers/mtd/nand/
|
||||||
F: include/linux/mtd/*nand*.h
|
F: include/linux/mtd/*nand*.h
|
||||||
|
|
||||||
|
NATIONAL INSTRUMENTS SERIAL DRIVER
|
||||||
|
M: Chaitanya Vadrevu <chaitanya.vadrevu@emerson.com>
|
||||||
|
L: linux-serial@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: drivers/tty/serial/8250/8250_ni.c
|
||||||
|
|
||||||
NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
|
NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
|
||||||
M: Daniel Mack <zonque@gmail.com>
|
M: Daniel Mack <zonque@gmail.com>
|
||||||
L: linux-sound@vger.kernel.org
|
L: linux-sound@vger.kernel.org
|
||||||
|
|
|
@ -196,40 +196,44 @@ static const struct tty_operations srmcons_ops = {
|
||||||
static int __init
|
static int __init
|
||||||
srmcons_init(void)
|
srmcons_init(void)
|
||||||
{
|
{
|
||||||
|
struct tty_driver *driver;
|
||||||
|
int err;
|
||||||
|
|
||||||
timer_setup(&srmcons_singleton.timer, srmcons_receive_chars, 0);
|
timer_setup(&srmcons_singleton.timer, srmcons_receive_chars, 0);
|
||||||
if (srm_is_registered_console) {
|
|
||||||
struct tty_driver *driver;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
driver = tty_alloc_driver(MAX_SRM_CONSOLE_DEVICES, 0);
|
if (!srm_is_registered_console)
|
||||||
if (IS_ERR(driver))
|
return -ENODEV;
|
||||||
return PTR_ERR(driver);
|
|
||||||
|
|
||||||
tty_port_init(&srmcons_singleton.port);
|
driver = tty_alloc_driver(MAX_SRM_CONSOLE_DEVICES, 0);
|
||||||
|
if (IS_ERR(driver))
|
||||||
|
return PTR_ERR(driver);
|
||||||
|
|
||||||
driver->driver_name = "srm";
|
tty_port_init(&srmcons_singleton.port);
|
||||||
driver->name = "srm";
|
|
||||||
driver->major = 0; /* dynamic */
|
|
||||||
driver->minor_start = 0;
|
|
||||||
driver->type = TTY_DRIVER_TYPE_SYSTEM;
|
|
||||||
driver->subtype = SYSTEM_TYPE_SYSCONS;
|
|
||||||
driver->init_termios = tty_std_termios;
|
|
||||||
tty_set_operations(driver, &srmcons_ops);
|
|
||||||
tty_port_link_device(&srmcons_singleton.port, driver, 0);
|
|
||||||
err = tty_register_driver(driver);
|
|
||||||
if (err) {
|
|
||||||
tty_driver_kref_put(driver);
|
|
||||||
tty_port_destroy(&srmcons_singleton.port);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
srmcons_driver = driver;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -ENODEV;
|
driver->driver_name = "srm";
|
||||||
|
driver->name = "srm";
|
||||||
|
driver->major = 0; /* dynamic */
|
||||||
|
driver->minor_start = 0;
|
||||||
|
driver->type = TTY_DRIVER_TYPE_SYSTEM;
|
||||||
|
driver->subtype = SYSTEM_TYPE_SYSCONS;
|
||||||
|
driver->init_termios = tty_std_termios;
|
||||||
|
tty_set_operations(driver, &srmcons_ops);
|
||||||
|
tty_port_link_device(&srmcons_singleton.port, driver, 0);
|
||||||
|
err = tty_register_driver(driver);
|
||||||
|
if (err)
|
||||||
|
goto err_free_drv;
|
||||||
|
|
||||||
|
srmcons_driver = driver;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err_free_drv:
|
||||||
|
tty_driver_kref_put(driver);
|
||||||
|
tty_port_destroy(&srmcons_singleton.port);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
device_initcall(srmcons_init);
|
device_initcall(srmcons_init);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The console driver
|
* The console driver
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -330,7 +330,7 @@ static int ldisc_open(struct tty_struct *tty)
|
||||||
ser->tty = tty_kref_get(tty);
|
ser->tty = tty_kref_get(tty);
|
||||||
ser->dev = dev;
|
ser->dev = dev;
|
||||||
debugfs_init(ser, tty);
|
debugfs_init(ser, tty);
|
||||||
tty->receive_room = N_TTY_BUF_SIZE;
|
tty->receive_room = 4096;
|
||||||
tty->disc_data = ser;
|
tty->disc_data = ser;
|
||||||
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
|
|
@ -948,7 +948,8 @@ static int gb_tty_init(void)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
gb_tty_driver = tty_alloc_driver(GB_NUM_MINORS, 0);
|
gb_tty_driver = tty_alloc_driver(GB_NUM_MINORS, TTY_DRIVER_REAL_RAW |
|
||||||
|
TTY_DRIVER_DYNAMIC_DEV);
|
||||||
if (IS_ERR(gb_tty_driver)) {
|
if (IS_ERR(gb_tty_driver)) {
|
||||||
pr_err("Can not allocate tty driver\n");
|
pr_err("Can not allocate tty driver\n");
|
||||||
retval = -ENOMEM;
|
retval = -ENOMEM;
|
||||||
|
@ -961,7 +962,6 @@ static int gb_tty_init(void)
|
||||||
gb_tty_driver->minor_start = 0;
|
gb_tty_driver->minor_start = 0;
|
||||||
gb_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
|
gb_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
|
||||||
gb_tty_driver->subtype = SERIAL_TYPE_NORMAL;
|
gb_tty_driver->subtype = SERIAL_TYPE_NORMAL;
|
||||||
gb_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
|
|
||||||
gb_tty_driver->init_termios = tty_std_termios;
|
gb_tty_driver->init_termios = tty_std_termios;
|
||||||
gb_tty_driver->init_termios.c_cflag = B9600 | CS8 |
|
gb_tty_driver->init_termios.c_cflag = B9600 | CS8 |
|
||||||
CREAD | HUPCL | CLOCAL;
|
CREAD | HUPCL | CLOCAL;
|
||||||
|
|
|
@ -210,7 +210,7 @@ config SERIAL_NONSTANDARD
|
||||||
|
|
||||||
config MOXA_INTELLIO
|
config MOXA_INTELLIO
|
||||||
tristate "Moxa Intellio support"
|
tristate "Moxa Intellio support"
|
||||||
depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
|
depends on SERIAL_NONSTANDARD && PCI
|
||||||
select FW_LOADER
|
select FW_LOADER
|
||||||
help
|
help
|
||||||
Say Y here if you have a Moxa Intellio multiport serial card.
|
Say Y here if you have a Moxa Intellio multiport serial card.
|
||||||
|
|
|
@ -43,15 +43,6 @@
|
||||||
#include <linux/ratelimit.h>
|
#include <linux/ratelimit.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <linux/uaccess.h>
|
|
||||||
|
|
||||||
#define MOXA 0x400
|
|
||||||
#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
|
|
||||||
#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
|
|
||||||
#define MOXA_GETDATACOUNT (MOXA + 23)
|
|
||||||
#define MOXA_GET_IOQUEUE (MOXA + 27)
|
|
||||||
#define MOXA_FLUSH_QUEUE (MOXA + 28)
|
|
||||||
#define MOXA_GETMSTATUS (MOXA + 65)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* System Configuration
|
* System Configuration
|
||||||
|
@ -347,8 +338,6 @@
|
||||||
#define MX_PARMARK 0xA0
|
#define MX_PARMARK 0xA0
|
||||||
#define MX_PARSPACE 0x20
|
#define MX_PARSPACE 0x20
|
||||||
|
|
||||||
#define MOXA_VERSION "6.0k"
|
|
||||||
|
|
||||||
#define MOXA_FW_HDRLEN 32
|
#define MOXA_FW_HDRLEN 32
|
||||||
|
|
||||||
#define MOXAMAJOR 172
|
#define MOXAMAJOR 172
|
||||||
|
@ -357,33 +346,21 @@
|
||||||
#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
|
#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
|
||||||
#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)
|
#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)
|
||||||
|
|
||||||
#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
|
#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_PCI)
|
||||||
(brd)->boardType == MOXA_BOARD_C320_PCI)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define the Moxa PCI vendor and device IDs.
|
|
||||||
*/
|
|
||||||
#define MOXA_BUS_TYPE_ISA 0
|
|
||||||
#define MOXA_BUS_TYPE_PCI 1
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MOXA_BOARD_C218_PCI = 1,
|
MOXA_BOARD_C218_PCI = 1,
|
||||||
MOXA_BOARD_C218_ISA,
|
|
||||||
MOXA_BOARD_C320_PCI,
|
MOXA_BOARD_C320_PCI,
|
||||||
MOXA_BOARD_C320_ISA,
|
|
||||||
MOXA_BOARD_CP204J,
|
MOXA_BOARD_CP204J,
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *moxa_brdname[] =
|
static char *moxa_brdname[] =
|
||||||
{
|
{
|
||||||
"C218 Turbo PCI series",
|
"C218 Turbo PCI series",
|
||||||
"C218 Turbo ISA series",
|
|
||||||
"C320 Turbo PCI series",
|
"C320 Turbo PCI series",
|
||||||
"C320 Turbo ISA series",
|
|
||||||
"CP-204J series",
|
"CP-204J series",
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_PCI
|
|
||||||
static const struct pci_device_id moxa_pcibrds[] = {
|
static const struct pci_device_id moxa_pcibrds[] = {
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
|
{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
|
||||||
.driver_data = MOXA_BOARD_C218_PCI },
|
.driver_data = MOXA_BOARD_C218_PCI },
|
||||||
|
@ -394,14 +371,12 @@ static const struct pci_device_id moxa_pcibrds[] = {
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
|
MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
|
||||||
#endif /* CONFIG_PCI */
|
|
||||||
|
|
||||||
struct moxa_port;
|
struct moxa_port;
|
||||||
|
|
||||||
static struct moxa_board_conf {
|
static struct moxa_board_conf {
|
||||||
int boardType;
|
int boardType;
|
||||||
int numPorts;
|
int numPorts;
|
||||||
int busType;
|
|
||||||
|
|
||||||
unsigned int ready;
|
unsigned int ready;
|
||||||
|
|
||||||
|
@ -413,19 +388,6 @@ static struct moxa_board_conf {
|
||||||
void __iomem *intTable;
|
void __iomem *intTable;
|
||||||
} moxa_boards[MAX_BOARDS];
|
} moxa_boards[MAX_BOARDS];
|
||||||
|
|
||||||
struct mxser_mstatus {
|
|
||||||
tcflag_t cflag;
|
|
||||||
int cts;
|
|
||||||
int dsr;
|
|
||||||
int ri;
|
|
||||||
int dcd;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct moxaq_str {
|
|
||||||
int inq;
|
|
||||||
int outq;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct moxa_port {
|
struct moxa_port {
|
||||||
struct tty_port port;
|
struct tty_port port;
|
||||||
struct moxa_board_conf *board;
|
struct moxa_board_conf *board;
|
||||||
|
@ -440,12 +402,6 @@ struct moxa_port {
|
||||||
u8 lowChkFlag;
|
u8 lowChkFlag;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mon_str {
|
|
||||||
int tick;
|
|
||||||
int rxcnt[MAX_PORTS];
|
|
||||||
int txcnt[MAX_PORTS];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* statusflags */
|
/* statusflags */
|
||||||
#define TXSTOPPED 1
|
#define TXSTOPPED 1
|
||||||
#define LOWWAIT 2
|
#define LOWWAIT 2
|
||||||
|
@ -455,17 +411,11 @@ struct mon_str {
|
||||||
#define WAKEUP_CHARS 256
|
#define WAKEUP_CHARS 256
|
||||||
|
|
||||||
static int ttymajor = MOXAMAJOR;
|
static int ttymajor = MOXAMAJOR;
|
||||||
static struct mon_str moxaLog;
|
|
||||||
static unsigned int moxaFuncTout = HZ / 2;
|
static unsigned int moxaFuncTout = HZ / 2;
|
||||||
static unsigned int moxaLowWaterChk;
|
static unsigned int moxaLowWaterChk;
|
||||||
static DEFINE_MUTEX(moxa_openlock);
|
static DEFINE_MUTEX(moxa_openlock);
|
||||||
static DEFINE_SPINLOCK(moxa_lock);
|
static DEFINE_SPINLOCK(moxa_lock);
|
||||||
|
|
||||||
static unsigned long baseaddr[MAX_BOARDS];
|
|
||||||
static unsigned int type[MAX_BOARDS];
|
|
||||||
static unsigned int numports[MAX_BOARDS];
|
|
||||||
static struct tty_port moxa_service_port;
|
|
||||||
|
|
||||||
MODULE_AUTHOR("William Chen");
|
MODULE_AUTHOR("William Chen");
|
||||||
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
|
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@ -473,13 +423,6 @@ MODULE_FIRMWARE("c218tunx.cod");
|
||||||
MODULE_FIRMWARE("cp204unx.cod");
|
MODULE_FIRMWARE("cp204unx.cod");
|
||||||
MODULE_FIRMWARE("c320tunx.cod");
|
MODULE_FIRMWARE("c320tunx.cod");
|
||||||
|
|
||||||
module_param_array(type, uint, NULL, 0);
|
|
||||||
MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
|
|
||||||
module_param_hw_array(baseaddr, ulong, ioport, NULL, 0);
|
|
||||||
MODULE_PARM_DESC(baseaddr, "base address");
|
|
||||||
module_param_array(numports, uint, NULL, 0);
|
|
||||||
MODULE_PARM_DESC(numports, "numports (ignored for C218)");
|
|
||||||
|
|
||||||
module_param(ttymajor, int, 0);
|
module_param(ttymajor, int, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -583,104 +526,6 @@ static void moxa_low_water_check(void __iomem *ofsAddr)
|
||||||
* TTY operations
|
* TTY operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int moxa_ioctl(struct tty_struct *tty,
|
|
||||||
unsigned int cmd, unsigned long arg)
|
|
||||||
{
|
|
||||||
struct moxa_port *ch = tty->driver_data;
|
|
||||||
void __user *argp = (void __user *)arg;
|
|
||||||
int status, ret = 0;
|
|
||||||
|
|
||||||
if (tty->index == MAX_PORTS) {
|
|
||||||
if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
|
|
||||||
cmd != MOXA_GETMSTATUS)
|
|
||||||
return -EINVAL;
|
|
||||||
} else if (!ch)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case MOXA_GETDATACOUNT:
|
|
||||||
moxaLog.tick = jiffies;
|
|
||||||
if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
|
|
||||||
ret = -EFAULT;
|
|
||||||
break;
|
|
||||||
case MOXA_FLUSH_QUEUE:
|
|
||||||
MoxaPortFlushData(ch, arg);
|
|
||||||
break;
|
|
||||||
case MOXA_GET_IOQUEUE: {
|
|
||||||
struct moxaq_str __user *argm = argp;
|
|
||||||
struct moxaq_str tmp;
|
|
||||||
struct moxa_port *p;
|
|
||||||
unsigned int i, j;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_BOARDS; i++) {
|
|
||||||
p = moxa_boards[i].ports;
|
|
||||||
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
|
|
||||||
memset(&tmp, 0, sizeof(tmp));
|
|
||||||
spin_lock_bh(&moxa_lock);
|
|
||||||
if (moxa_boards[i].ready) {
|
|
||||||
tmp.inq = MoxaPortRxQueue(p);
|
|
||||||
tmp.outq = MoxaPortTxQueue(p);
|
|
||||||
}
|
|
||||||
spin_unlock_bh(&moxa_lock);
|
|
||||||
if (copy_to_user(argm, &tmp, sizeof(tmp)))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} case MOXA_GET_OQUEUE:
|
|
||||||
status = MoxaPortTxQueue(ch);
|
|
||||||
ret = put_user(status, (unsigned long __user *)argp);
|
|
||||||
break;
|
|
||||||
case MOXA_GET_IQUEUE:
|
|
||||||
status = MoxaPortRxQueue(ch);
|
|
||||||
ret = put_user(status, (unsigned long __user *)argp);
|
|
||||||
break;
|
|
||||||
case MOXA_GETMSTATUS: {
|
|
||||||
struct mxser_mstatus __user *argm = argp;
|
|
||||||
struct mxser_mstatus tmp;
|
|
||||||
struct moxa_port *p;
|
|
||||||
unsigned int i, j;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_BOARDS; i++) {
|
|
||||||
p = moxa_boards[i].ports;
|
|
||||||
for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
|
|
||||||
struct tty_struct *ttyp;
|
|
||||||
memset(&tmp, 0, sizeof(tmp));
|
|
||||||
spin_lock_bh(&moxa_lock);
|
|
||||||
if (!moxa_boards[i].ready) {
|
|
||||||
spin_unlock_bh(&moxa_lock);
|
|
||||||
goto copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
status = MoxaPortLineStatus(p);
|
|
||||||
spin_unlock_bh(&moxa_lock);
|
|
||||||
|
|
||||||
if (status & 1)
|
|
||||||
tmp.cts = 1;
|
|
||||||
if (status & 2)
|
|
||||||
tmp.dsr = 1;
|
|
||||||
if (status & 4)
|
|
||||||
tmp.dcd = 1;
|
|
||||||
|
|
||||||
ttyp = tty_port_tty_get(&p->port);
|
|
||||||
if (!ttyp)
|
|
||||||
tmp.cflag = p->cflag;
|
|
||||||
else
|
|
||||||
tmp.cflag = ttyp->termios.c_cflag;
|
|
||||||
tty_kref_put(ttyp);
|
|
||||||
copy:
|
|
||||||
if (copy_to_user(argm, &tmp, sizeof(tmp)))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ret = -ENOIOCTLCMD;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int moxa_break_ctl(struct tty_struct *tty, int state)
|
static int moxa_break_ctl(struct tty_struct *tty, int state)
|
||||||
{
|
{
|
||||||
struct moxa_port *port = tty->driver_data;
|
struct moxa_port *port = tty->driver_data;
|
||||||
|
@ -697,7 +542,6 @@ static const struct tty_operations moxa_ops = {
|
||||||
.write_room = moxa_write_room,
|
.write_room = moxa_write_room,
|
||||||
.flush_buffer = moxa_flush_buffer,
|
.flush_buffer = moxa_flush_buffer,
|
||||||
.chars_in_buffer = moxa_chars_in_buffer,
|
.chars_in_buffer = moxa_chars_in_buffer,
|
||||||
.ioctl = moxa_ioctl,
|
|
||||||
.set_termios = moxa_set_termios,
|
.set_termios = moxa_set_termios,
|
||||||
.stop = moxa_stop,
|
.stop = moxa_stop,
|
||||||
.start = moxa_start,
|
.start = moxa_start,
|
||||||
|
@ -725,7 +569,6 @@ static DEFINE_TIMER(moxaTimer, moxa_poll);
|
||||||
static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
|
static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
|
||||||
{
|
{
|
||||||
switch (brd->boardType) {
|
switch (brd->boardType) {
|
||||||
case MOXA_BOARD_C218_ISA:
|
|
||||||
case MOXA_BOARD_C218_PCI:
|
case MOXA_BOARD_C218_PCI:
|
||||||
if (model != 1)
|
if (model != 1)
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -769,7 +612,6 @@ static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
|
||||||
msleep(2000);
|
msleep(2000);
|
||||||
|
|
||||||
switch (brd->boardType) {
|
switch (brd->boardType) {
|
||||||
case MOXA_BOARD_C218_ISA:
|
|
||||||
case MOXA_BOARD_C218_PCI:
|
case MOXA_BOARD_C218_PCI:
|
||||||
tmp = readw(baseAddr + C218_key);
|
tmp = readw(baseAddr + C218_key);
|
||||||
if (tmp != C218_KeyCode)
|
if (tmp != C218_KeyCode)
|
||||||
|
@ -833,7 +675,6 @@ static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
|
||||||
|
|
||||||
switch (brd->boardType) {
|
switch (brd->boardType) {
|
||||||
case MOXA_BOARD_CP204J:
|
case MOXA_BOARD_CP204J:
|
||||||
case MOXA_BOARD_C218_ISA:
|
|
||||||
case MOXA_BOARD_C218_PCI:
|
case MOXA_BOARD_C218_PCI:
|
||||||
key = C218_key;
|
key = C218_key;
|
||||||
loadbuf = C218_LoadBuf;
|
loadbuf = C218_LoadBuf;
|
||||||
|
@ -898,15 +739,9 @@ static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (MOXA_IS_320(brd)) {
|
if (MOXA_IS_320(brd)) {
|
||||||
if (brd->busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
|
writew(0x3800, baseAddr + TMS320_PORT1);
|
||||||
writew(0x3800, baseAddr + TMS320_PORT1);
|
writew(0x3900, baseAddr + TMS320_PORT2);
|
||||||
writew(0x3900, baseAddr + TMS320_PORT2);
|
writew(28499, baseAddr + TMS320_CLOCK);
|
||||||
writew(28499, baseAddr + TMS320_CLOCK);
|
|
||||||
} else {
|
|
||||||
writew(0x3200, baseAddr + TMS320_PORT1);
|
|
||||||
writew(0x3400, baseAddr + TMS320_PORT2);
|
|
||||||
writew(19999, baseAddr + TMS320_CLOCK);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
writew(1, baseAddr + Disable_IRQ);
|
writew(1, baseAddr + Disable_IRQ);
|
||||||
writew(0, baseAddr + Magic_no);
|
writew(0, baseAddr + Magic_no);
|
||||||
|
@ -957,7 +792,6 @@ static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
switch (brd->boardType) {
|
switch (brd->boardType) {
|
||||||
case MOXA_BOARD_C218_ISA:
|
|
||||||
case MOXA_BOARD_C218_PCI:
|
case MOXA_BOARD_C218_PCI:
|
||||||
case MOXA_BOARD_CP204J:
|
case MOXA_BOARD_CP204J:
|
||||||
port = brd->ports;
|
port = brd->ports;
|
||||||
|
@ -1141,7 +975,6 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (brd->boardType) {
|
switch (brd->boardType) {
|
||||||
case MOXA_BOARD_C218_ISA:
|
|
||||||
case MOXA_BOARD_C218_PCI:
|
case MOXA_BOARD_C218_PCI:
|
||||||
file = "c218tunx.cod";
|
file = "c218tunx.cod";
|
||||||
break;
|
break;
|
||||||
|
@ -1227,7 +1060,6 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
|
||||||
kfree(brd->ports);
|
kfree(brd->ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PCI
|
|
||||||
static int moxa_pci_probe(struct pci_dev *pdev,
|
static int moxa_pci_probe(struct pci_dev *pdev,
|
||||||
const struct pci_device_id *ent)
|
const struct pci_device_id *ent)
|
||||||
{
|
{
|
||||||
|
@ -1270,7 +1102,6 @@ static int moxa_pci_probe(struct pci_dev *pdev,
|
||||||
|
|
||||||
board->boardType = board_type;
|
board->boardType = board_type;
|
||||||
switch (board_type) {
|
switch (board_type) {
|
||||||
case MOXA_BOARD_C218_ISA:
|
|
||||||
case MOXA_BOARD_C218_PCI:
|
case MOXA_BOARD_C218_PCI:
|
||||||
board->numPorts = 8;
|
board->numPorts = 8;
|
||||||
break;
|
break;
|
||||||
|
@ -1282,7 +1113,6 @@ static int moxa_pci_probe(struct pci_dev *pdev,
|
||||||
board->numPorts = 0;
|
board->numPorts = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
board->busType = MOXA_BUS_TYPE_PCI;
|
|
||||||
|
|
||||||
retval = moxa_init_board(board, &pdev->dev);
|
retval = moxa_init_board(board, &pdev->dev);
|
||||||
if (retval)
|
if (retval)
|
||||||
|
@ -1318,21 +1148,12 @@ static struct pci_driver moxa_pci_driver = {
|
||||||
.probe = moxa_pci_probe,
|
.probe = moxa_pci_probe,
|
||||||
.remove = moxa_pci_remove
|
.remove = moxa_pci_remove
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_PCI */
|
|
||||||
|
|
||||||
static int __init moxa_init(void)
|
static int __init moxa_init(void)
|
||||||
{
|
{
|
||||||
unsigned int isabrds = 0;
|
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
struct moxa_board_conf *brd = moxa_boards;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
printk(KERN_INFO "MOXA Intellio family driver version %s\n",
|
moxaDriver = tty_alloc_driver(MAX_PORTS,
|
||||||
MOXA_VERSION);
|
|
||||||
|
|
||||||
tty_port_init(&moxa_service_port);
|
|
||||||
|
|
||||||
moxaDriver = tty_alloc_driver(MAX_PORTS + 1,
|
|
||||||
TTY_DRIVER_REAL_RAW |
|
TTY_DRIVER_REAL_RAW |
|
||||||
TTY_DRIVER_DYNAMIC_DEV);
|
TTY_DRIVER_DYNAMIC_DEV);
|
||||||
if (IS_ERR(moxaDriver))
|
if (IS_ERR(moxaDriver))
|
||||||
|
@ -1348,8 +1169,6 @@ static int __init moxa_init(void)
|
||||||
moxaDriver->init_termios.c_ispeed = 9600;
|
moxaDriver->init_termios.c_ispeed = 9600;
|
||||||
moxaDriver->init_termios.c_ospeed = 9600;
|
moxaDriver->init_termios.c_ospeed = 9600;
|
||||||
tty_set_operations(moxaDriver, &moxa_ops);
|
tty_set_operations(moxaDriver, &moxa_ops);
|
||||||
/* Having one more port only for ioctls is ugly */
|
|
||||||
tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS);
|
|
||||||
|
|
||||||
if (tty_register_driver(moxaDriver)) {
|
if (tty_register_driver(moxaDriver)) {
|
||||||
printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
|
printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
|
||||||
|
@ -1357,64 +1176,16 @@ static int __init moxa_init(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the boards defined from module args. */
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_BOARDS; i++) {
|
|
||||||
if (!baseaddr[i])
|
|
||||||
break;
|
|
||||||
if (type[i] == MOXA_BOARD_C218_ISA ||
|
|
||||||
type[i] == MOXA_BOARD_C320_ISA) {
|
|
||||||
pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
|
|
||||||
isabrds + 1, moxa_brdname[type[i] - 1],
|
|
||||||
baseaddr[i]);
|
|
||||||
brd->boardType = type[i];
|
|
||||||
brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
|
|
||||||
numports[i];
|
|
||||||
brd->busType = MOXA_BUS_TYPE_ISA;
|
|
||||||
brd->basemem = ioremap(baseaddr[i], 0x4000);
|
|
||||||
if (!brd->basemem) {
|
|
||||||
printk(KERN_ERR "MOXA: can't remap %lx\n",
|
|
||||||
baseaddr[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (moxa_init_board(brd, NULL)) {
|
|
||||||
iounmap(brd->basemem);
|
|
||||||
brd->basemem = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
printk(KERN_INFO "MOXA isa board found at 0x%.8lx and "
|
|
||||||
"ready (%u ports, firmware loaded)\n",
|
|
||||||
baseaddr[i], brd->numPorts);
|
|
||||||
|
|
||||||
brd++;
|
|
||||||
isabrds++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI
|
|
||||||
retval = pci_register_driver(&moxa_pci_driver);
|
retval = pci_register_driver(&moxa_pci_driver);
|
||||||
if (retval) {
|
if (retval)
|
||||||
printk(KERN_ERR "Can't register MOXA pci driver!\n");
|
printk(KERN_ERR "Can't register MOXA pci driver!\n");
|
||||||
if (isabrds)
|
|
||||||
retval = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit moxa_exit(void)
|
static void __exit moxa_exit(void)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI
|
|
||||||
pci_unregister_driver(&moxa_pci_driver);
|
pci_unregister_driver(&moxa_pci_driver);
|
||||||
#endif
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
|
|
||||||
if (moxa_boards[i].ready)
|
|
||||||
moxa_board_deinit(&moxa_boards[i]);
|
|
||||||
|
|
||||||
del_timer_sync(&moxaTimer);
|
del_timer_sync(&moxaTimer);
|
||||||
|
|
||||||
|
@ -1457,9 +1228,6 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
port = tty->index;
|
port = tty->index;
|
||||||
if (port == MAX_PORTS) {
|
|
||||||
return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
|
|
||||||
}
|
|
||||||
if (mutex_lock_interruptible(&moxa_openlock))
|
if (mutex_lock_interruptible(&moxa_openlock))
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
|
brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
|
||||||
|
@ -2182,7 +1950,6 @@ static ssize_t MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer,
|
||||||
c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
|
c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
|
||||||
if (c > len)
|
if (c > len)
|
||||||
c = len;
|
c = len;
|
||||||
moxaLog.txcnt[port->port.tty->index] += c;
|
|
||||||
total = c;
|
total = c;
|
||||||
if (spage == epage) {
|
if (spage == epage) {
|
||||||
bufhead = readw(ofsAddr + Ofs_txb);
|
bufhead = readw(ofsAddr + Ofs_txb);
|
||||||
|
@ -2224,7 +1991,6 @@ static ssize_t MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer,
|
||||||
|
|
||||||
static int MoxaPortReadData(struct moxa_port *port)
|
static int MoxaPortReadData(struct moxa_port *port)
|
||||||
{
|
{
|
||||||
struct tty_struct *tty = port->port.tty;
|
|
||||||
void __iomem *baseAddr, *ofsAddr, *ofs;
|
void __iomem *baseAddr, *ofsAddr, *ofs;
|
||||||
u8 *dst;
|
u8 *dst;
|
||||||
unsigned int count, len, total;
|
unsigned int count, len, total;
|
||||||
|
@ -2243,7 +2009,6 @@ static int MoxaPortReadData(struct moxa_port *port)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
total = count;
|
total = count;
|
||||||
moxaLog.rxcnt[tty->index] += total;
|
|
||||||
if (spage == epage) {
|
if (spage == epage) {
|
||||||
bufhead = readw(ofsAddr + Ofs_rxb);
|
bufhead = readw(ofsAddr + Ofs_rxb);
|
||||||
writew(spage, baseAddr + Control_reg);
|
writew(spage, baseAddr + Control_reg);
|
||||||
|
@ -2331,8 +2096,6 @@ static int moxa_get_serial_info(struct tty_struct *tty,
|
||||||
{
|
{
|
||||||
struct moxa_port *info = tty->driver_data;
|
struct moxa_port *info = tty->driver_data;
|
||||||
|
|
||||||
if (tty->index == MAX_PORTS)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
mutex_lock(&info->port.mutex);
|
mutex_lock(&info->port.mutex);
|
||||||
|
@ -2352,8 +2115,6 @@ static int moxa_set_serial_info(struct tty_struct *tty,
|
||||||
struct moxa_port *info = tty->driver_data;
|
struct moxa_port *info = tty->driver_data;
|
||||||
unsigned int close_delay;
|
unsigned int close_delay;
|
||||||
|
|
||||||
if (tty->index == MAX_PORTS)
|
|
||||||
return -EINVAL;
|
|
||||||
if (!info)
|
if (!info)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,8 @@
|
||||||
*/
|
*/
|
||||||
#define WAKEUP_CHARS 256
|
#define WAKEUP_CHARS 256
|
||||||
|
|
||||||
|
#define N_TTY_BUF_SIZE 4096
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This defines the low- and high-watermarks for throttling and
|
* This defines the low- and high-watermarks for throttling and
|
||||||
* unthrottling the TTY driver. These watermarks are used for
|
* unthrottling the TTY driver. These watermarks are used for
|
||||||
|
@ -79,14 +81,6 @@
|
||||||
#define ECHO_BLOCK 256
|
#define ECHO_BLOCK 256
|
||||||
#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
|
#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
|
||||||
|
|
||||||
|
|
||||||
#undef N_TTY_TRACE
|
|
||||||
#ifdef N_TTY_TRACE
|
|
||||||
# define n_tty_trace(f, args...) trace_printk(f, ##args)
|
|
||||||
#else
|
|
||||||
# define n_tty_trace(f, args...) no_printk(f, ##args)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct n_tty_data {
|
struct n_tty_data {
|
||||||
/* producer-published */
|
/* producer-published */
|
||||||
size_t read_head;
|
size_t read_head;
|
||||||
|
@ -486,18 +480,13 @@ static int do_output_char(u8 c, struct tty_struct *tty, int space)
|
||||||
static int process_output(u8 c, struct tty_struct *tty)
|
static int process_output(u8 c, struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct n_tty_data *ldata = tty->disc_data;
|
struct n_tty_data *ldata = tty->disc_data;
|
||||||
int space, retval;
|
|
||||||
|
|
||||||
mutex_lock(&ldata->output_lock);
|
guard(mutex)(&ldata->output_lock);
|
||||||
|
|
||||||
space = tty_write_room(tty);
|
if (do_output_char(c, tty, tty_write_room(tty)) < 0)
|
||||||
retval = do_output_char(c, tty, space);
|
|
||||||
|
|
||||||
mutex_unlock(&ldata->output_lock);
|
|
||||||
if (retval < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
else
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -522,17 +511,15 @@ static ssize_t process_output_block(struct tty_struct *tty,
|
||||||
const u8 *buf, unsigned int nr)
|
const u8 *buf, unsigned int nr)
|
||||||
{
|
{
|
||||||
struct n_tty_data *ldata = tty->disc_data;
|
struct n_tty_data *ldata = tty->disc_data;
|
||||||
int space;
|
unsigned int space, i;
|
||||||
int i;
|
|
||||||
const u8 *cp;
|
const u8 *cp;
|
||||||
|
|
||||||
mutex_lock(&ldata->output_lock);
|
guard(mutex)(&ldata->output_lock);
|
||||||
|
|
||||||
space = tty_write_room(tty);
|
space = tty_write_room(tty);
|
||||||
if (space <= 0) {
|
if (space == 0)
|
||||||
mutex_unlock(&ldata->output_lock);
|
return 0;
|
||||||
return space;
|
|
||||||
}
|
|
||||||
if (nr > space)
|
if (nr > space)
|
||||||
nr = space;
|
nr = space;
|
||||||
|
|
||||||
|
@ -544,18 +531,18 @@ static ssize_t process_output_block(struct tty_struct *tty,
|
||||||
if (O_ONLRET(tty))
|
if (O_ONLRET(tty))
|
||||||
ldata->column = 0;
|
ldata->column = 0;
|
||||||
if (O_ONLCR(tty))
|
if (O_ONLCR(tty))
|
||||||
goto break_out;
|
goto do_write;
|
||||||
ldata->canon_column = ldata->column;
|
ldata->canon_column = ldata->column;
|
||||||
break;
|
break;
|
||||||
case '\r':
|
case '\r':
|
||||||
if (O_ONOCR(tty) && ldata->column == 0)
|
if (O_ONOCR(tty) && ldata->column == 0)
|
||||||
goto break_out;
|
goto do_write;
|
||||||
if (O_OCRNL(tty))
|
if (O_OCRNL(tty))
|
||||||
goto break_out;
|
goto do_write;
|
||||||
ldata->canon_column = ldata->column = 0;
|
ldata->canon_column = ldata->column = 0;
|
||||||
break;
|
break;
|
||||||
case '\t':
|
case '\t':
|
||||||
goto break_out;
|
goto do_write;
|
||||||
case '\b':
|
case '\b':
|
||||||
if (ldata->column > 0)
|
if (ldata->column > 0)
|
||||||
ldata->column--;
|
ldata->column--;
|
||||||
|
@ -563,18 +550,15 @@ static ssize_t process_output_block(struct tty_struct *tty,
|
||||||
default:
|
default:
|
||||||
if (!iscntrl(c)) {
|
if (!iscntrl(c)) {
|
||||||
if (O_OLCUC(tty))
|
if (O_OLCUC(tty))
|
||||||
goto break_out;
|
goto do_write;
|
||||||
if (!is_continuation(c, tty))
|
if (!is_continuation(c, tty))
|
||||||
ldata->column++;
|
ldata->column++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break_out:
|
do_write:
|
||||||
i = tty->ops->write(tty, buf, i);
|
return tty->ops->write(tty, buf, i);
|
||||||
|
|
||||||
mutex_unlock(&ldata->output_lock);
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int n_tty_process_echo_ops(struct tty_struct *tty, size_t *tail,
|
static int n_tty_process_echo_ops(struct tty_struct *tty, size_t *tail,
|
||||||
|
@ -696,7 +680,7 @@ static int n_tty_process_echo_ops(struct tty_struct *tty, size_t *tail,
|
||||||
static size_t __process_echoes(struct tty_struct *tty)
|
static size_t __process_echoes(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct n_tty_data *ldata = tty->disc_data;
|
struct n_tty_data *ldata = tty->disc_data;
|
||||||
int space, old_space;
|
unsigned int space, old_space;
|
||||||
size_t tail;
|
size_t tail;
|
||||||
u8 c;
|
u8 c;
|
||||||
|
|
||||||
|
@ -2034,9 +2018,6 @@ static bool canon_copy_from_read_buf(const struct tty_struct *tty, u8 **kbp,
|
||||||
tail = MASK(ldata->read_tail);
|
tail = MASK(ldata->read_tail);
|
||||||
size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
|
size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
|
||||||
|
|
||||||
n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu\n",
|
|
||||||
__func__, *nr, tail, n, size);
|
|
||||||
|
|
||||||
eol = find_next_bit(ldata->read_flags, size, tail);
|
eol = find_next_bit(ldata->read_flags, size, tail);
|
||||||
more = n - (size - tail);
|
more = n - (size - tail);
|
||||||
if (eol == N_TTY_BUF_SIZE && more) {
|
if (eol == N_TTY_BUF_SIZE && more) {
|
||||||
|
@ -2054,9 +2035,6 @@ static bool canon_copy_from_read_buf(const struct tty_struct *tty, u8 **kbp,
|
||||||
if (!found || read_buf(ldata, eol) != __DISABLED_CHAR)
|
if (!found || read_buf(ldata, eol) != __DISABLED_CHAR)
|
||||||
n = c;
|
n = c;
|
||||||
|
|
||||||
n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n",
|
|
||||||
__func__, eol, found, n, c, tail, more);
|
|
||||||
|
|
||||||
tty_copy(tty, *kbp, tail, n);
|
tty_copy(tty, *kbp, tail, n);
|
||||||
*kbp += n;
|
*kbp += n;
|
||||||
*nr -= n;
|
*nr -= n;
|
||||||
|
@ -2133,6 +2111,66 @@ static int job_control(struct tty_struct *tty, struct file *file)
|
||||||
return __tty_check_change(tty, SIGTTIN);
|
return __tty_check_change(tty, SIGTTIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We still hold the atomic_read_lock and the termios_rwsem, and can just
|
||||||
|
* continue to copy data.
|
||||||
|
*/
|
||||||
|
static ssize_t n_tty_continue_cookie(struct tty_struct *tty, u8 *kbuf,
|
||||||
|
size_t nr, void **cookie)
|
||||||
|
{
|
||||||
|
struct n_tty_data *ldata = tty->disc_data;
|
||||||
|
u8 *kb = kbuf;
|
||||||
|
|
||||||
|
if (ldata->icanon && !L_EXTPROC(tty)) {
|
||||||
|
/*
|
||||||
|
* If we have filled the user buffer, see if we should skip an
|
||||||
|
* EOF character before releasing the lock and returning done.
|
||||||
|
*/
|
||||||
|
if (!nr)
|
||||||
|
canon_skip_eof(ldata);
|
||||||
|
else if (canon_copy_from_read_buf(tty, &kb, &nr))
|
||||||
|
return kb - kbuf;
|
||||||
|
} else {
|
||||||
|
if (copy_from_read_buf(tty, &kb, &nr))
|
||||||
|
return kb - kbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No more data - release locks and stop retries */
|
||||||
|
n_tty_kick_worker(tty);
|
||||||
|
n_tty_check_unthrottle(tty);
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
|
mutex_unlock(&ldata->atomic_read_lock);
|
||||||
|
*cookie = NULL;
|
||||||
|
|
||||||
|
return kb - kbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int n_tty_wait_for_input(struct tty_struct *tty, struct file *file,
|
||||||
|
struct wait_queue_entry *wait, long *timeout)
|
||||||
|
{
|
||||||
|
if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
|
||||||
|
return -EIO;
|
||||||
|
if (tty_hung_up_p(file))
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
|
* Abort readers for ttys which never actually get hung up.
|
||||||
|
* See __tty_hangup().
|
||||||
|
*/
|
||||||
|
if (test_bit(TTY_HUPPING, &tty->flags))
|
||||||
|
return 0;
|
||||||
|
if (!*timeout)
|
||||||
|
return 0;
|
||||||
|
if (tty_io_nonblock(tty, file))
|
||||||
|
return -EAGAIN;
|
||||||
|
if (signal_pending(current))
|
||||||
|
return -ERESTARTSYS;
|
||||||
|
|
||||||
|
up_read(&tty->termios_rwsem);
|
||||||
|
*timeout = wait_woken(wait, TASK_INTERRUPTIBLE, *timeout);
|
||||||
|
down_read(&tty->termios_rwsem);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* n_tty_read - read function for tty
|
* n_tty_read - read function for tty
|
||||||
|
@ -2166,36 +2204,9 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
|
||||||
bool packet;
|
bool packet;
|
||||||
size_t old_tail;
|
size_t old_tail;
|
||||||
|
|
||||||
/*
|
/* Is this a continuation of a read started earlier? */
|
||||||
* Is this a continuation of a read started earler?
|
if (*cookie)
|
||||||
*
|
return n_tty_continue_cookie(tty, kbuf, nr, cookie);
|
||||||
* If so, we still hold the atomic_read_lock and the
|
|
||||||
* termios_rwsem, and can just continue to copy data.
|
|
||||||
*/
|
|
||||||
if (*cookie) {
|
|
||||||
if (ldata->icanon && !L_EXTPROC(tty)) {
|
|
||||||
/*
|
|
||||||
* If we have filled the user buffer, see
|
|
||||||
* if we should skip an EOF character before
|
|
||||||
* releasing the lock and returning done.
|
|
||||||
*/
|
|
||||||
if (!nr)
|
|
||||||
canon_skip_eof(ldata);
|
|
||||||
else if (canon_copy_from_read_buf(tty, &kb, &nr))
|
|
||||||
return kb - kbuf;
|
|
||||||
} else {
|
|
||||||
if (copy_from_read_buf(tty, &kb, &nr))
|
|
||||||
return kb - kbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No more data - release locks and stop retries */
|
|
||||||
n_tty_kick_worker(tty);
|
|
||||||
n_tty_check_unthrottle(tty);
|
|
||||||
up_read(&tty->termios_rwsem);
|
|
||||||
mutex_unlock(&ldata->atomic_read_lock);
|
|
||||||
*cookie = NULL;
|
|
||||||
return kb - kbuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
retval = job_control(tty, file);
|
retval = job_control(tty, file);
|
||||||
if (retval < 0)
|
if (retval < 0)
|
||||||
|
@ -2250,34 +2261,12 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
|
||||||
tty_buffer_flush_work(tty->port);
|
tty_buffer_flush_work(tty->port);
|
||||||
down_read(&tty->termios_rwsem);
|
down_read(&tty->termios_rwsem);
|
||||||
if (!input_available_p(tty, 0)) {
|
if (!input_available_p(tty, 0)) {
|
||||||
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
|
int ret = n_tty_wait_for_input(tty, file, &wait,
|
||||||
retval = -EIO;
|
&timeout);
|
||||||
|
if (ret <= 0) {
|
||||||
|
retval = ret;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tty_hung_up_p(file))
|
|
||||||
break;
|
|
||||||
/*
|
|
||||||
* Abort readers for ttys which never actually
|
|
||||||
* get hung up. See __tty_hangup().
|
|
||||||
*/
|
|
||||||
if (test_bit(TTY_HUPPING, &tty->flags))
|
|
||||||
break;
|
|
||||||
if (!timeout)
|
|
||||||
break;
|
|
||||||
if (tty_io_nonblock(tty, file)) {
|
|
||||||
retval = -EAGAIN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (signal_pending(current)) {
|
|
||||||
retval = -ERESTARTSYS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
up_read(&tty->termios_rwsem);
|
|
||||||
|
|
||||||
timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
|
|
||||||
timeout);
|
|
||||||
|
|
||||||
down_read(&tty->termios_rwsem);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2292,21 +2281,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
|
||||||
nr--;
|
nr--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (copy_from_read_buf(tty, &kb, &nr) && kb - kbuf >= minimum)
|
||||||
* Copy data, and if there is more to be had
|
goto more_to_be_read;
|
||||||
* and we have nothing more to wait for, then
|
|
||||||
* let's mark us for retries.
|
|
||||||
*
|
|
||||||
* NOTE! We return here with both the termios_sem
|
|
||||||
* and atomic_read_lock still held, the retries
|
|
||||||
* will release them when done.
|
|
||||||
*/
|
|
||||||
if (copy_from_read_buf(tty, &kb, &nr) && kb - kbuf >= minimum) {
|
|
||||||
more_to_be_read:
|
|
||||||
remove_wait_queue(&tty->read_wait, &wait);
|
|
||||||
*cookie = cookie;
|
|
||||||
return kb - kbuf;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n_tty_check_unthrottle(tty);
|
n_tty_check_unthrottle(tty);
|
||||||
|
@ -2333,6 +2309,18 @@ more_to_be_read:
|
||||||
retval = kb - kbuf;
|
retval = kb - kbuf;
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
more_to_be_read:
|
||||||
|
/*
|
||||||
|
* There is more to be had and we have nothing more to wait for, so
|
||||||
|
* let's mark us for retries.
|
||||||
|
*
|
||||||
|
* NOTE! We return here with both the termios_sem and atomic_read_lock
|
||||||
|
* still held, the retries will release them when done.
|
||||||
|
*/
|
||||||
|
remove_wait_queue(&tty->read_wait, &wait);
|
||||||
|
*cookie = cookie;
|
||||||
|
|
||||||
|
return kb - kbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -316,17 +316,6 @@ void serdev_device_write_flush(struct serdev_device *serdev)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(serdev_device_write_flush);
|
EXPORT_SYMBOL_GPL(serdev_device_write_flush);
|
||||||
|
|
||||||
int serdev_device_write_room(struct serdev_device *serdev)
|
|
||||||
{
|
|
||||||
struct serdev_controller *ctrl = serdev->ctrl;
|
|
||||||
|
|
||||||
if (!ctrl || !ctrl->ops->write_room)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return serdev->ctrl->ops->write_room(ctrl);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(serdev_device_write_room);
|
|
||||||
|
|
||||||
unsigned int serdev_device_set_baudrate(struct serdev_device *serdev, unsigned int speed)
|
unsigned int serdev_device_set_baudrate(struct serdev_device *serdev, unsigned int speed)
|
||||||
{
|
{
|
||||||
struct serdev_controller *ctrl = serdev->ctrl;
|
struct serdev_controller *ctrl = serdev->ctrl;
|
||||||
|
|
|
@ -92,14 +92,6 @@ static void ttyport_write_flush(struct serdev_controller *ctrl)
|
||||||
tty_driver_flush_buffer(tty);
|
tty_driver_flush_buffer(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ttyport_write_room(struct serdev_controller *ctrl)
|
|
||||||
{
|
|
||||||
struct serport *serport = serdev_controller_get_drvdata(ctrl);
|
|
||||||
struct tty_struct *tty = serport->tty;
|
|
||||||
|
|
||||||
return tty_write_room(tty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ttyport_open(struct serdev_controller *ctrl)
|
static int ttyport_open(struct serdev_controller *ctrl)
|
||||||
{
|
{
|
||||||
struct serport *serport = serdev_controller_get_drvdata(ctrl);
|
struct serport *serport = serdev_controller_get_drvdata(ctrl);
|
||||||
|
@ -259,7 +251,6 @@ static int ttyport_break_ctl(struct serdev_controller *ctrl, unsigned int break_
|
||||||
static const struct serdev_controller_ops ctrl_ops = {
|
static const struct serdev_controller_ops ctrl_ops = {
|
||||||
.write_buf = ttyport_write_buf,
|
.write_buf = ttyport_write_buf,
|
||||||
.write_flush = ttyport_write_flush,
|
.write_flush = ttyport_write_flush,
|
||||||
.write_room = ttyport_write_room,
|
|
||||||
.open = ttyport_open,
|
.open = ttyport_open,
|
||||||
.close = ttyport_close,
|
.close = ttyport_close,
|
||||||
.set_flow_control = ttyport_set_flow_control,
|
.set_flow_control = ttyport_set_flow_control,
|
||||||
|
|
|
@ -162,7 +162,7 @@ void serial8250_tx_dma_flush(struct uart_8250_port *p)
|
||||||
*/
|
*/
|
||||||
dma->tx_size = 0;
|
dma->tx_size = 0;
|
||||||
|
|
||||||
dmaengine_terminate_async(dma->rxchan);
|
dmaengine_terminate_async(dma->txchan);
|
||||||
}
|
}
|
||||||
|
|
||||||
int serial8250_rx_dma(struct uart_8250_port *p)
|
int serial8250_rx_dma(struct uart_8250_port *p)
|
||||||
|
|
|
@ -107,11 +107,23 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is being called as part of the uart_port::serial_out()
|
||||||
|
* routine. Hence, it must not call serial_port_out() or serial_out()
|
||||||
|
* against the modified registers here, i.e. LCR.
|
||||||
|
*/
|
||||||
static void dw8250_force_idle(struct uart_port *p)
|
static void dw8250_force_idle(struct uart_port *p)
|
||||||
{
|
{
|
||||||
struct uart_8250_port *up = up_to_u8250p(p);
|
struct uart_8250_port *up = up_to_u8250p(p);
|
||||||
unsigned int lsr;
|
unsigned int lsr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following call currently performs serial_out()
|
||||||
|
* against the FCR register. Because it differs to LCR
|
||||||
|
* there will be no infinite loop, but if it ever gets
|
||||||
|
* modified, we might need a new custom version of it
|
||||||
|
* that avoids infinite recursion.
|
||||||
|
*/
|
||||||
serial8250_clear_and_reinit_fifos(up);
|
serial8250_clear_and_reinit_fifos(up);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -120,14 +132,19 @@ static void dw8250_force_idle(struct uart_port *p)
|
||||||
* enabled.
|
* enabled.
|
||||||
*/
|
*/
|
||||||
if (up->fcr & UART_FCR_ENABLE_FIFO) {
|
if (up->fcr & UART_FCR_ENABLE_FIFO) {
|
||||||
lsr = p->serial_in(p, UART_LSR);
|
lsr = serial_port_in(p, UART_LSR);
|
||||||
if (!(lsr & UART_LSR_DR))
|
if (!(lsr & UART_LSR_DR))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)p->serial_in(p, UART_RX);
|
serial_port_in(p, UART_RX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is being called as part of the uart_port::serial_out()
|
||||||
|
* routine. Hence, it must not call serial_port_out() or serial_out()
|
||||||
|
* against the modified registers here, i.e. LCR.
|
||||||
|
*/
|
||||||
static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
|
static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
|
||||||
{
|
{
|
||||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||||
|
@ -139,7 +156,7 @@ static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
|
||||||
|
|
||||||
/* Make sure LCR write wasn't ignored */
|
/* Make sure LCR write wasn't ignored */
|
||||||
while (tries--) {
|
while (tries--) {
|
||||||
unsigned int lcr = p->serial_in(p, offset);
|
unsigned int lcr = serial_port_in(p, offset);
|
||||||
|
|
||||||
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
|
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
|
||||||
return;
|
return;
|
||||||
|
@ -260,7 +277,7 @@ static int dw8250_handle_irq(struct uart_port *p)
|
||||||
{
|
{
|
||||||
struct uart_8250_port *up = up_to_u8250p(p);
|
struct uart_8250_port *up = up_to_u8250p(p);
|
||||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||||
unsigned int iir = p->serial_in(p, UART_IIR);
|
unsigned int iir = serial_port_in(p, UART_IIR);
|
||||||
bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT;
|
bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT;
|
||||||
unsigned int quirks = d->pdata->quirks;
|
unsigned int quirks = d->pdata->quirks;
|
||||||
unsigned int status;
|
unsigned int status;
|
||||||
|
@ -281,7 +298,7 @@ static int dw8250_handle_irq(struct uart_port *p)
|
||||||
status = serial_lsr_in(up);
|
status = serial_lsr_in(up);
|
||||||
|
|
||||||
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
|
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
|
||||||
(void) p->serial_in(p, UART_RX);
|
serial_port_in(p, UART_RX);
|
||||||
|
|
||||||
uart_port_unlock_irqrestore(p, flags);
|
uart_port_unlock_irqrestore(p, flags);
|
||||||
}
|
}
|
||||||
|
@ -303,7 +320,7 @@ static int dw8250_handle_irq(struct uart_port *p)
|
||||||
|
|
||||||
if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
|
if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
|
||||||
/* Clear the USR */
|
/* Clear the USR */
|
||||||
(void)p->serial_in(p, d->pdata->usr_reg);
|
serial_port_in(p, d->pdata->usr_reg);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -390,7 +407,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
|
||||||
static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
|
static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
|
||||||
{
|
{
|
||||||
struct uart_8250_port *up = up_to_u8250p(p);
|
struct uart_8250_port *up = up_to_u8250p(p);
|
||||||
unsigned int mcr = p->serial_in(p, UART_MCR);
|
unsigned int mcr = serial_port_in(p, UART_MCR);
|
||||||
|
|
||||||
if (up->capabilities & UART_CAP_IRDA) {
|
if (up->capabilities & UART_CAP_IRDA) {
|
||||||
if (termios->c_line == N_IRDA)
|
if (termios->c_line == N_IRDA)
|
||||||
|
@ -398,7 +415,7 @@ static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
|
||||||
else
|
else
|
||||||
mcr &= ~DW_UART_MCR_SIRE;
|
mcr &= ~DW_UART_MCR_SIRE;
|
||||||
|
|
||||||
p->serial_out(p, UART_MCR, mcr);
|
serial_port_out(p, UART_MCR, mcr);
|
||||||
}
|
}
|
||||||
serial8250_do_set_ldisc(p, termios);
|
serial8250_do_set_ldisc(p, termios);
|
||||||
}
|
}
|
||||||
|
@ -421,6 +438,18 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
|
||||||
return param == chan->device->dev;
|
return param == chan->device->dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dw8250_setup_dma_filter(struct uart_port *p, struct dw8250_data *data)
|
||||||
|
{
|
||||||
|
/* Platforms with iDMA 64-bit */
|
||||||
|
if (platform_get_resource_byname(to_platform_device(p->dev), IORESOURCE_MEM, "lpss_priv")) {
|
||||||
|
data->data.dma.rx_param = p->dev->parent;
|
||||||
|
data->data.dma.tx_param = p->dev->parent;
|
||||||
|
data->data.dma.fn = dw8250_idma_filter;
|
||||||
|
} else {
|
||||||
|
data->data.dma.fn = dw8250_fallback_dma_filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static u32 dw8250_rzn1_get_dmacr_burst(int max_burst)
|
static u32 dw8250_rzn1_get_dmacr_burst(int max_burst)
|
||||||
{
|
{
|
||||||
if (max_burst >= 8)
|
if (max_burst >= 8)
|
||||||
|
@ -459,8 +488,8 @@ static void dw8250_prepare_rx_dma(struct uart_8250_port *p)
|
||||||
|
|
||||||
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
|
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
|
||||||
{
|
{
|
||||||
unsigned int quirks = data->pdata ? data->pdata->quirks : 0;
|
unsigned int quirks = data->pdata->quirks;
|
||||||
u32 cpr_value = data->pdata ? data->pdata->cpr_value : 0;
|
u32 cpr_value = data->pdata->cpr_value;
|
||||||
|
|
||||||
if (quirks & DW_UART_QUIRK_CPR_VALUE)
|
if (quirks & DW_UART_QUIRK_CPR_VALUE)
|
||||||
data->data.cpr_value = cpr_value;
|
data->data.cpr_value = cpr_value;
|
||||||
|
@ -491,14 +520,6 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
|
||||||
p->serial_in = dw8250_serial_in32;
|
p->serial_in = dw8250_serial_in32;
|
||||||
data->uart_16550_compatible = true;
|
data->uart_16550_compatible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Platforms with iDMA 64-bit */
|
|
||||||
if (platform_get_resource_byname(to_platform_device(p->dev),
|
|
||||||
IORESOURCE_MEM, "lpss_priv")) {
|
|
||||||
data->data.dma.rx_param = p->dev->parent;
|
|
||||||
data->data.dma.tx_param = p->dev->parent;
|
|
||||||
data->data.dma.fn = dw8250_idma_filter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dw8250_reset_control_assert(void *data)
|
static void dw8250_reset_control_assert(void *data)
|
||||||
|
@ -520,7 +541,6 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||||
return dev_err_probe(dev, -EINVAL, "no registers defined\n");
|
return dev_err_probe(dev, -EINVAL, "no registers defined\n");
|
||||||
|
|
||||||
spin_lock_init(&p->lock);
|
spin_lock_init(&p->lock);
|
||||||
p->handle_irq = dw8250_handle_irq;
|
|
||||||
p->pm = dw8250_do_pm;
|
p->pm = dw8250_do_pm;
|
||||||
p->type = PORT_8250;
|
p->type = PORT_8250;
|
||||||
p->flags = UPF_FIXED_PORT;
|
p->flags = UPF_FIXED_PORT;
|
||||||
|
@ -532,13 +552,8 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
data->data.dma.fn = dw8250_fallback_dma_filter;
|
|
||||||
data->pdata = device_get_match_data(p->dev);
|
|
||||||
p->private_data = &data->data;
|
p->private_data = &data->data;
|
||||||
|
|
||||||
data->uart_16550_compatible = device_property_read_bool(dev,
|
|
||||||
"snps,uart-16550-compatible");
|
|
||||||
|
|
||||||
p->mapbase = regs->start;
|
p->mapbase = regs->start;
|
||||||
p->mapsize = resource_size(regs);
|
p->mapsize = resource_size(regs);
|
||||||
|
|
||||||
|
@ -626,11 +641,19 @@ static int dw8250_probe(struct platform_device *pdev)
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
dw8250_quirks(p, data);
|
data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible");
|
||||||
|
|
||||||
|
data->pdata = device_get_match_data(p->dev);
|
||||||
|
if (data->pdata)
|
||||||
|
dw8250_quirks(p, data);
|
||||||
|
|
||||||
/* If the Busy Functionality is not implemented, don't handle it */
|
/* If the Busy Functionality is not implemented, don't handle it */
|
||||||
if (data->uart_16550_compatible)
|
if (data->uart_16550_compatible)
|
||||||
p->handle_irq = NULL;
|
p->handle_irq = NULL;
|
||||||
|
else if (data->pdata)
|
||||||
|
p->handle_irq = dw8250_handle_irq;
|
||||||
|
|
||||||
|
dw8250_setup_dma_filter(p, data);
|
||||||
|
|
||||||
if (!data->skip_autocfg)
|
if (!data->skip_autocfg)
|
||||||
dw8250_setup_port(p);
|
dw8250_setup_port(p);
|
||||||
|
|
|
@ -32,7 +32,7 @@ int fsl8250_handle_irq(struct uart_port *port)
|
||||||
|
|
||||||
uart_port_lock_irqsave(&up->port, &flags);
|
uart_port_lock_irqsave(&up->port, &flags);
|
||||||
|
|
||||||
iir = port->serial_in(port, UART_IIR);
|
iir = serial_port_in(port, UART_IIR);
|
||||||
if (iir & UART_IIR_NO_INT) {
|
if (iir & UART_IIR_NO_INT) {
|
||||||
uart_port_unlock_irqrestore(&up->port, flags);
|
uart_port_unlock_irqrestore(&up->port, flags);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -54,12 +54,12 @@ int fsl8250_handle_irq(struct uart_port *port)
|
||||||
if (unlikely((iir & UART_IIR_ID) == UART_IIR_RLSI &&
|
if (unlikely((iir & UART_IIR_ID) == UART_IIR_RLSI &&
|
||||||
(up->lsr_saved_flags & UART_LSR_BI))) {
|
(up->lsr_saved_flags & UART_LSR_BI))) {
|
||||||
up->lsr_saved_flags &= ~UART_LSR_BI;
|
up->lsr_saved_flags &= ~UART_LSR_BI;
|
||||||
port->serial_in(port, UART_RX);
|
serial_port_in(port, UART_RX);
|
||||||
uart_port_unlock_irqrestore(&up->port, flags);
|
uart_port_unlock_irqrestore(&up->port, flags);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
|
lsr = orig_lsr = serial_port_in(port, UART_LSR);
|
||||||
|
|
||||||
/* Process incoming characters first */
|
/* Process incoming characters first */
|
||||||
if ((lsr & (UART_LSR_DR | UART_LSR_BI)) &&
|
if ((lsr & (UART_LSR_DR | UART_LSR_BI)) &&
|
||||||
|
@ -71,7 +71,7 @@ int fsl8250_handle_irq(struct uart_port *port)
|
||||||
if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) {
|
if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) {
|
||||||
unsigned long delay;
|
unsigned long delay;
|
||||||
|
|
||||||
up->ier = port->serial_in(port, UART_IER);
|
up->ier = serial_port_in(port, UART_IER);
|
||||||
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
|
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
|
||||||
port->ops->stop_rx(port);
|
port->ops->stop_rx(port);
|
||||||
} else {
|
} else {
|
||||||
|
|
461
drivers/tty/serial/8250/8250_ni.c
Normal file
461
drivers/tty/serial/8250/8250_ni.c
Normal file
|
@ -0,0 +1,461 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* NI 16550 UART Driver
|
||||||
|
*
|
||||||
|
* The National Instruments (NI) 16550 is a UART that is compatible with the
|
||||||
|
* TL16C550C and OX16C950B register interfaces, but has additional functions
|
||||||
|
* for RS-485 transceiver control. This driver implements support for the
|
||||||
|
* additional functionality on top of the standard serial8250 core.
|
||||||
|
*
|
||||||
|
* Copyright 2012-2023 National Instruments Corporation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/acpi.h>
|
||||||
|
#include <linux/bitfield.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/property.h>
|
||||||
|
#include <linux/clk.h>
|
||||||
|
|
||||||
|
#include "8250.h"
|
||||||
|
|
||||||
|
/* Extra bits in UART_ACR */
|
||||||
|
#define NI16550_ACR_AUTO_DTR_EN BIT(4)
|
||||||
|
|
||||||
|
/* TFS - TX FIFO Size */
|
||||||
|
#define NI16550_TFS_OFFSET 0x0C
|
||||||
|
/* RFS - RX FIFO Size */
|
||||||
|
#define NI16550_RFS_OFFSET 0x0D
|
||||||
|
|
||||||
|
/* PMR - Port Mode Register */
|
||||||
|
#define NI16550_PMR_OFFSET 0x0E
|
||||||
|
/* PMR[1:0] - Port Capabilities */
|
||||||
|
#define NI16550_PMR_CAP_MASK GENMASK(1, 0)
|
||||||
|
#define NI16550_PMR_NOT_IMPL FIELD_PREP(NI16550_PMR_CAP_MASK, 0) /* not implemented */
|
||||||
|
#define NI16550_PMR_CAP_RS232 FIELD_PREP(NI16550_PMR_CAP_MASK, 1) /* RS-232 capable */
|
||||||
|
#define NI16550_PMR_CAP_RS485 FIELD_PREP(NI16550_PMR_CAP_MASK, 2) /* RS-485 capable */
|
||||||
|
#define NI16550_PMR_CAP_DUAL FIELD_PREP(NI16550_PMR_CAP_MASK, 3) /* dual-port */
|
||||||
|
/* PMR[4] - Interface Mode */
|
||||||
|
#define NI16550_PMR_MODE_MASK GENMASK(4, 4)
|
||||||
|
#define NI16550_PMR_MODE_RS232 FIELD_PREP(NI16550_PMR_MODE_MASK, 0) /* currently 232 */
|
||||||
|
#define NI16550_PMR_MODE_RS485 FIELD_PREP(NI16550_PMR_MODE_MASK, 1) /* currently 485 */
|
||||||
|
|
||||||
|
/* PCR - Port Control Register */
|
||||||
|
/*
|
||||||
|
* Wire Mode | Tx enabled? | Rx enabled?
|
||||||
|
* ---------------|----------------------|--------------------------
|
||||||
|
* PCR_RS422 | Always | Always
|
||||||
|
* PCR_ECHO_RS485 | When DTR asserted | Always
|
||||||
|
* PCR_DTR_RS485 | When DTR asserted | Disabled when TX enabled
|
||||||
|
* PCR_AUTO_RS485 | When data in TX FIFO | Disabled when TX enabled
|
||||||
|
*/
|
||||||
|
#define NI16550_PCR_OFFSET 0x0F
|
||||||
|
#define NI16550_PCR_WIRE_MODE_MASK GENMASK(1, 0)
|
||||||
|
#define NI16550_PCR_RS422 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 0)
|
||||||
|
#define NI16550_PCR_ECHO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 1)
|
||||||
|
#define NI16550_PCR_DTR_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 2)
|
||||||
|
#define NI16550_PCR_AUTO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 3)
|
||||||
|
#define NI16550_PCR_TXVR_ENABLE_BIT BIT(3)
|
||||||
|
#define NI16550_PCR_RS485_TERMINATION_BIT BIT(6)
|
||||||
|
|
||||||
|
/* flags for ni16550_device_info */
|
||||||
|
#define NI_HAS_PMR BIT(0)
|
||||||
|
|
||||||
|
struct ni16550_device_info {
|
||||||
|
u32 uartclk;
|
||||||
|
u8 prescaler;
|
||||||
|
u8 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ni16550_data {
|
||||||
|
int line;
|
||||||
|
struct clk *clk;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int ni16550_enable_transceivers(struct uart_port *port)
|
||||||
|
{
|
||||||
|
u8 pcr;
|
||||||
|
|
||||||
|
pcr = port->serial_in(port, NI16550_PCR_OFFSET);
|
||||||
|
pcr |= NI16550_PCR_TXVR_ENABLE_BIT;
|
||||||
|
dev_dbg(port->dev, "enable transceivers: write pcr: 0x%02x\n", pcr);
|
||||||
|
port->serial_out(port, NI16550_PCR_OFFSET, pcr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ni16550_disable_transceivers(struct uart_port *port)
|
||||||
|
{
|
||||||
|
u8 pcr;
|
||||||
|
|
||||||
|
pcr = port->serial_in(port, NI16550_PCR_OFFSET);
|
||||||
|
pcr &= ~NI16550_PCR_TXVR_ENABLE_BIT;
|
||||||
|
dev_dbg(port->dev, "disable transceivers: write pcr: 0x%02x\n", pcr);
|
||||||
|
port->serial_out(port, NI16550_PCR_OFFSET, pcr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ni16550_rs485_config(struct uart_port *port,
|
||||||
|
struct ktermios *termios,
|
||||||
|
struct serial_rs485 *rs485)
|
||||||
|
{
|
||||||
|
struct uart_8250_port *up = container_of(port, struct uart_8250_port, port);
|
||||||
|
u8 pcr;
|
||||||
|
|
||||||
|
pcr = serial_in(up, NI16550_PCR_OFFSET);
|
||||||
|
pcr &= ~NI16550_PCR_WIRE_MODE_MASK;
|
||||||
|
|
||||||
|
if ((rs485->flags & SER_RS485_MODE_RS422) ||
|
||||||
|
!(rs485->flags & SER_RS485_ENABLED)) {
|
||||||
|
/* RS-422 */
|
||||||
|
pcr |= NI16550_PCR_RS422;
|
||||||
|
up->acr &= ~NI16550_ACR_AUTO_DTR_EN;
|
||||||
|
} else {
|
||||||
|
/* RS-485 2-wire Auto */
|
||||||
|
pcr |= NI16550_PCR_AUTO_RS485;
|
||||||
|
up->acr |= NI16550_ACR_AUTO_DTR_EN;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(port->dev, "config rs485: write pcr: 0x%02x, acr: %02x\n", pcr, up->acr);
|
||||||
|
serial_out(up, NI16550_PCR_OFFSET, pcr);
|
||||||
|
serial_icr_write(up, UART_ACR, up->acr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_pmr_rs232_mode(struct uart_8250_port *up)
|
||||||
|
{
|
||||||
|
u8 pmr = serial_in(up, NI16550_PMR_OFFSET);
|
||||||
|
u8 pmr_mode = pmr & NI16550_PMR_MODE_MASK;
|
||||||
|
u8 pmr_cap = pmr & NI16550_PMR_CAP_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the PMR is not implemented, then by default NI UARTs are
|
||||||
|
* connected to RS-485 transceivers
|
||||||
|
*/
|
||||||
|
if (pmr_cap == NI16550_PMR_NOT_IMPL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (pmr_cap == NI16550_PMR_CAP_DUAL)
|
||||||
|
/*
|
||||||
|
* If the port is dual-mode capable, then read the mode bit
|
||||||
|
* to know the current mode
|
||||||
|
*/
|
||||||
|
return pmr_mode == NI16550_PMR_MODE_RS232;
|
||||||
|
/*
|
||||||
|
* If it is not dual-mode capable, then decide based on the
|
||||||
|
* capability
|
||||||
|
*/
|
||||||
|
return pmr_cap == NI16550_PMR_CAP_RS232;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ni16550_config_prescaler(struct uart_8250_port *up,
|
||||||
|
u8 prescaler)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Page in the Enhanced Mode Registers
|
||||||
|
* Sets EFR[4] for Enhanced Mode.
|
||||||
|
*/
|
||||||
|
u8 lcr_value;
|
||||||
|
u8 efr_value;
|
||||||
|
|
||||||
|
lcr_value = serial_in(up, UART_LCR);
|
||||||
|
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||||
|
|
||||||
|
efr_value = serial_in(up, UART_EFR);
|
||||||
|
efr_value |= UART_EFR_ECB;
|
||||||
|
|
||||||
|
serial_out(up, UART_EFR, efr_value);
|
||||||
|
|
||||||
|
/* Page out the Enhanced Mode Registers */
|
||||||
|
serial_out(up, UART_LCR, lcr_value);
|
||||||
|
|
||||||
|
/* Set prescaler to CPR register. */
|
||||||
|
serial_out(up, UART_SCR, UART_CPR);
|
||||||
|
serial_out(up, UART_ICR, prescaler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct serial_rs485 ni16550_rs485_supported = {
|
||||||
|
.flags = SER_RS485_ENABLED | SER_RS485_MODE_RS422 | SER_RS485_RTS_ON_SEND |
|
||||||
|
SER_RS485_RTS_AFTER_SEND,
|
||||||
|
/*
|
||||||
|
* delay_rts_* and RX_DURING_TX are not supported.
|
||||||
|
*
|
||||||
|
* RTS_{ON,AFTER}_SEND are supported, but ignored; the transceiver
|
||||||
|
* is connected in only one way and we don't need userspace to tell
|
||||||
|
* us, but want to retain compatibility with applications that do.
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ni16550_rs485_setup(struct uart_port *port)
|
||||||
|
{
|
||||||
|
port->rs485_config = ni16550_rs485_config;
|
||||||
|
port->rs485_supported = ni16550_rs485_supported;
|
||||||
|
/*
|
||||||
|
* The hardware comes up by default in 2-wire auto mode and we
|
||||||
|
* set the flags to represent that
|
||||||
|
*/
|
||||||
|
port->rs485.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ni16550_port_startup(struct uart_port *port)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = serial8250_do_startup(port);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return ni16550_enable_transceivers(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ni16550_port_shutdown(struct uart_port *port)
|
||||||
|
{
|
||||||
|
ni16550_disable_transceivers(port);
|
||||||
|
|
||||||
|
serial8250_do_shutdown(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ni16550_get_regs(struct platform_device *pdev,
|
||||||
|
struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct resource *regs;
|
||||||
|
|
||||||
|
regs = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||||
|
if (regs) {
|
||||||
|
port->iotype = UPIO_PORT;
|
||||||
|
port->iobase = regs->start;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (regs) {
|
||||||
|
port->iotype = UPIO_MEM;
|
||||||
|
port->mapbase = regs->start;
|
||||||
|
port->mapsize = resource_size(regs);
|
||||||
|
port->flags |= UPF_IOREMAP;
|
||||||
|
|
||||||
|
port->membase = devm_ioremap(&pdev->dev, port->mapbase,
|
||||||
|
port->mapsize);
|
||||||
|
if (!port->membase)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_err(&pdev->dev, "no registers defined\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Very old implementations don't have the TFS or RFS registers
|
||||||
|
* defined, so we may read all-0s or all-1s. For such devices,
|
||||||
|
* assume a FIFO size of 128.
|
||||||
|
*/
|
||||||
|
static u8 ni16550_read_fifo_size(struct uart_8250_port *uart, int reg)
|
||||||
|
{
|
||||||
|
u8 value = serial_in(uart, reg);
|
||||||
|
|
||||||
|
if (value == 0x00 || value == 0xFF)
|
||||||
|
return 128;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ni16550_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||||
|
{
|
||||||
|
struct uart_8250_port *up = up_to_u8250p(port);
|
||||||
|
|
||||||
|
up->mcr |= UART_MCR_CLKSEL;
|
||||||
|
serial8250_do_set_mctrl(port, mctrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ni16550_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
const struct ni16550_device_info *info;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct uart_8250_port uart = {};
|
||||||
|
unsigned int txfifosz, rxfifosz;
|
||||||
|
unsigned int prescaler = 0;
|
||||||
|
struct ni16550_data *data;
|
||||||
|
const char *portmode;
|
||||||
|
bool rs232_property;
|
||||||
|
int ret;
|
||||||
|
int irq;
|
||||||
|
|
||||||
|
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||||
|
if (!data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
spin_lock_init(&uart.port.lock);
|
||||||
|
|
||||||
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
if (irq < 0)
|
||||||
|
return irq;
|
||||||
|
|
||||||
|
ret = ni16550_get_regs(pdev, &uart.port);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* early setup so that serial_in()/serial_out() work */
|
||||||
|
serial8250_set_defaults(&uart);
|
||||||
|
|
||||||
|
info = device_get_match_data(dev);
|
||||||
|
|
||||||
|
uart.port.dev = dev;
|
||||||
|
uart.port.irq = irq;
|
||||||
|
uart.port.irqflags = IRQF_SHARED;
|
||||||
|
uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
|
||||||
|
| UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||||
|
uart.port.startup = ni16550_port_startup;
|
||||||
|
uart.port.shutdown = ni16550_port_shutdown;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hardware instantiation of FIFO sizes are held in registers.
|
||||||
|
*/
|
||||||
|
txfifosz = ni16550_read_fifo_size(&uart, NI16550_TFS_OFFSET);
|
||||||
|
rxfifosz = ni16550_read_fifo_size(&uart, NI16550_RFS_OFFSET);
|
||||||
|
|
||||||
|
dev_dbg(dev, "NI 16550 has TX FIFO size %u, RX FIFO size %u\n",
|
||||||
|
txfifosz, rxfifosz);
|
||||||
|
|
||||||
|
uart.port.type = PORT_16550A;
|
||||||
|
uart.port.fifosize = txfifosz;
|
||||||
|
uart.tx_loadsz = txfifosz;
|
||||||
|
uart.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
|
||||||
|
uart.capabilities = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Declaration of the base clock frequency can come from one of:
|
||||||
|
* - static declaration in this driver (for older ACPI IDs)
|
||||||
|
* - a "clock-frquency" ACPI
|
||||||
|
*/
|
||||||
|
if (info->uartclk)
|
||||||
|
uart.port.uartclk = info->uartclk;
|
||||||
|
if (device_property_read_u32(dev, "clock-frequency",
|
||||||
|
&uart.port.uartclk)) {
|
||||||
|
data->clk = devm_clk_get_enabled(dev, NULL);
|
||||||
|
if (!IS_ERR(data->clk))
|
||||||
|
uart.port.uartclk = clk_get_rate(data->clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uart.port.uartclk) {
|
||||||
|
dev_err(dev, "unable to determine clock frequency!\n");
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->prescaler)
|
||||||
|
prescaler = info->prescaler;
|
||||||
|
device_property_read_u32(dev, "clock-prescaler", &prescaler);
|
||||||
|
|
||||||
|
if (prescaler != 0) {
|
||||||
|
uart.port.set_mctrl = ni16550_set_mctrl;
|
||||||
|
ni16550_config_prescaler(&uart, (u8)prescaler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The determination of whether or not this is an RS-485 or RS-232 port
|
||||||
|
* can come from the PMR (if present), otherwise we're solely an RS-485
|
||||||
|
* port.
|
||||||
|
*
|
||||||
|
* This is a device-specific property, and there are old devices in the
|
||||||
|
* field using "transceiver" as an ACPI property, so we have to check
|
||||||
|
* for that as well.
|
||||||
|
*/
|
||||||
|
if (!device_property_read_string(dev, "transceiver", &portmode)) {
|
||||||
|
rs232_property = strncmp(portmode, "RS-232", 6) == 0;
|
||||||
|
|
||||||
|
dev_dbg(dev, "port is in %s mode (via device property)\n",
|
||||||
|
rs232_property ? "RS-232" : "RS-485");
|
||||||
|
} else if (info->flags & NI_HAS_PMR) {
|
||||||
|
rs232_property = is_pmr_rs232_mode(&uart);
|
||||||
|
|
||||||
|
dev_dbg(dev, "port is in %s mode (via PMR)\n",
|
||||||
|
rs232_property ? "RS-232" : "RS-485");
|
||||||
|
} else {
|
||||||
|
rs232_property = 0;
|
||||||
|
|
||||||
|
dev_dbg(dev, "port is fixed as RS-485\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rs232_property) {
|
||||||
|
/*
|
||||||
|
* Neither the 'transceiver' property nor the PMR indicate
|
||||||
|
* that this is an RS-232 port, so it must be an RS-485 one.
|
||||||
|
*/
|
||||||
|
ni16550_rs485_setup(&uart.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = serial8250_register_8250_port(&uart);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
data->line = ret;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, data);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ni16550_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct ni16550_data *data = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
serial8250_unregister_port(data->line);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_ACPI
|
||||||
|
/* NI 16550 RS-485 Interface */
|
||||||
|
static const struct ni16550_device_info nic7750 = {
|
||||||
|
.uartclk = 33333333,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NI CVS-145x RS-485 Interface */
|
||||||
|
static const struct ni16550_device_info nic7772 = {
|
||||||
|
.uartclk = 1843200,
|
||||||
|
.flags = NI_HAS_PMR,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NI cRIO-904x RS-485 Interface */
|
||||||
|
static const struct ni16550_device_info nic792b = {
|
||||||
|
/* Sets UART clock rate to 22.222 MHz with 1.125 prescale */
|
||||||
|
.uartclk = 22222222,
|
||||||
|
.prescaler = 0x09,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NI sbRIO 96x8 RS-232/485 Interfaces */
|
||||||
|
static const struct ni16550_device_info nic7a69 = {
|
||||||
|
/* Set UART clock rate to 29.629 MHz with 1.125 prescale */
|
||||||
|
.uartclk = 29629629,
|
||||||
|
.prescaler = 0x09,
|
||||||
|
};
|
||||||
|
static const struct acpi_device_id ni16550_acpi_match[] = {
|
||||||
|
{ "NIC7750", (kernel_ulong_t)&nic7750 },
|
||||||
|
{ "NIC7772", (kernel_ulong_t)&nic7772 },
|
||||||
|
{ "NIC792B", (kernel_ulong_t)&nic792b },
|
||||||
|
{ "NIC7A69", (kernel_ulong_t)&nic7a69 },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(acpi, ni16550_acpi_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct platform_driver ni16550_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "ni16550",
|
||||||
|
.acpi_match_table = ACPI_PTR(ni16550_acpi_match),
|
||||||
|
},
|
||||||
|
.probe = ni16550_probe,
|
||||||
|
.remove = ni16550_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(ni16550_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Emerson Electric Co.");
|
||||||
|
MODULE_DESCRIPTION("NI 16550 Driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -692,7 +692,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
|
||||||
|
|
||||||
/* Synchronize UART_IER access against the console. */
|
/* Synchronize UART_IER access against the console. */
|
||||||
uart_port_lock(port);
|
uart_port_lock(port);
|
||||||
up->ier = port->serial_in(port, UART_IER);
|
up->ier = serial_port_in(port, UART_IER);
|
||||||
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
|
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
|
||||||
port->ops->stop_rx(port);
|
port->ops->stop_rx(port);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -2727,6 +2727,22 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
|
||||||
.init = pci_oxsemi_tornado_init,
|
.init = pci_oxsemi_tornado_init,
|
||||||
.setup = pci_oxsemi_tornado_setup,
|
.setup = pci_oxsemi_tornado_setup,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.vendor = PCI_VENDOR_ID_INTASHIELD,
|
||||||
|
.device = 0x4026,
|
||||||
|
.subvendor = PCI_ANY_ID,
|
||||||
|
.subdevice = PCI_ANY_ID,
|
||||||
|
.init = pci_oxsemi_tornado_init,
|
||||||
|
.setup = pci_oxsemi_tornado_setup,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor = PCI_VENDOR_ID_INTASHIELD,
|
||||||
|
.device = 0x4021,
|
||||||
|
.subvendor = PCI_ANY_ID,
|
||||||
|
.subdevice = PCI_ANY_ID,
|
||||||
|
.init = pci_oxsemi_tornado_init,
|
||||||
|
.setup = pci_oxsemi_tornado_setup,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.vendor = PCI_VENDOR_ID_INTEL,
|
.vendor = PCI_VENDOR_ID_INTEL,
|
||||||
.device = 0x8811,
|
.device = 0x8811,
|
||||||
|
@ -5253,6 +5269,14 @@ static const struct pci_device_id serial_pci_tbl[] = {
|
||||||
PCI_ANY_ID, PCI_ANY_ID,
|
PCI_ANY_ID, PCI_ANY_ID,
|
||||||
0, 0,
|
0, 0,
|
||||||
pbn_b2_2_115200 },
|
pbn_b2_2_115200 },
|
||||||
|
{ PCI_VENDOR_ID_INTASHIELD, 0x0BA2,
|
||||||
|
PCI_ANY_ID, PCI_ANY_ID,
|
||||||
|
0, 0,
|
||||||
|
pbn_b2_2_115200 },
|
||||||
|
{ PCI_VENDOR_ID_INTASHIELD, 0x0BA3,
|
||||||
|
PCI_ANY_ID, PCI_ANY_ID,
|
||||||
|
0, 0,
|
||||||
|
pbn_b2_2_115200 },
|
||||||
/*
|
/*
|
||||||
* Brainboxes UC-235/246
|
* Brainboxes UC-235/246
|
||||||
*/
|
*/
|
||||||
|
@ -5373,6 +5397,14 @@ static const struct pci_device_id serial_pci_tbl[] = {
|
||||||
PCI_ANY_ID, PCI_ANY_ID,
|
PCI_ANY_ID, PCI_ANY_ID,
|
||||||
0, 0,
|
0, 0,
|
||||||
pbn_b2_4_115200 },
|
pbn_b2_4_115200 },
|
||||||
|
{ PCI_VENDOR_ID_INTASHIELD, 0x0C42,
|
||||||
|
PCI_ANY_ID, PCI_ANY_ID,
|
||||||
|
0, 0,
|
||||||
|
pbn_b2_4_115200 },
|
||||||
|
{ PCI_VENDOR_ID_INTASHIELD, 0x0C43,
|
||||||
|
PCI_ANY_ID, PCI_ANY_ID,
|
||||||
|
0, 0,
|
||||||
|
pbn_b2_4_115200 },
|
||||||
/*
|
/*
|
||||||
* Brainboxes UC-420
|
* Brainboxes UC-420
|
||||||
*/
|
*/
|
||||||
|
@ -5599,6 +5631,20 @@ static const struct pci_device_id serial_pci_tbl[] = {
|
||||||
PCI_ANY_ID, PCI_ANY_ID,
|
PCI_ANY_ID, PCI_ANY_ID,
|
||||||
0, 0,
|
0, 0,
|
||||||
pbn_oxsemi_1_15625000 },
|
pbn_oxsemi_1_15625000 },
|
||||||
|
/*
|
||||||
|
* Brainboxes XC-235
|
||||||
|
*/
|
||||||
|
{ PCI_VENDOR_ID_INTASHIELD, 0x4026,
|
||||||
|
PCI_ANY_ID, PCI_ANY_ID,
|
||||||
|
0, 0,
|
||||||
|
pbn_oxsemi_1_15625000 },
|
||||||
|
/*
|
||||||
|
* Brainboxes XC-475
|
||||||
|
*/
|
||||||
|
{ PCI_VENDOR_ID_INTASHIELD, 0x4021,
|
||||||
|
PCI_ANY_ID, PCI_ANY_ID,
|
||||||
|
0, 0,
|
||||||
|
pbn_oxsemi_1_15625000 },
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perle PCI-RAS cards
|
* Perle PCI-RAS cards
|
||||||
|
|
|
@ -1678,7 +1678,7 @@ static void serial8250_disable_ms(struct uart_port *port)
|
||||||
if (up->bugs & UART_BUG_NOMSR)
|
if (up->bugs & UART_BUG_NOMSR)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mctrl_gpio_disable_ms(up->gpios);
|
mctrl_gpio_disable_ms_no_sync(up->gpios);
|
||||||
|
|
||||||
up->ier &= ~UART_IER_MSI;
|
up->ier &= ~UART_IER_MSI;
|
||||||
serial_port_out(port, UART_IER, up->ier);
|
serial_port_out(port, UART_IER, up->ier);
|
||||||
|
@ -2406,28 +2406,26 @@ int serial8250_do_startup(struct uart_port *port)
|
||||||
* test if we receive TX irq. This way, we'll never enable
|
* test if we receive TX irq. This way, we'll never enable
|
||||||
* UART_BUG_TXEN.
|
* UART_BUG_TXEN.
|
||||||
*/
|
*/
|
||||||
if (up->port.quirks & UPQ_NO_TXEN_TEST)
|
if (!(up->port.quirks & UPQ_NO_TXEN_TEST)) {
|
||||||
goto dont_test_tx_en;
|
/*
|
||||||
|
* Do a quick test to see if we receive an interrupt when we
|
||||||
|
* enable the TX irq.
|
||||||
|
*/
|
||||||
|
serial_port_out(port, UART_IER, UART_IER_THRI);
|
||||||
|
lsr = serial_port_in(port, UART_LSR);
|
||||||
|
iir = serial_port_in(port, UART_IIR);
|
||||||
|
serial_port_out(port, UART_IER, 0);
|
||||||
|
|
||||||
/*
|
if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
|
||||||
* Do a quick test to see if we receive an interrupt when we enable
|
if (!(up->bugs & UART_BUG_TXEN)) {
|
||||||
* the TX irq.
|
up->bugs |= UART_BUG_TXEN;
|
||||||
*/
|
dev_dbg(port->dev, "enabling bad tx status workarounds\n");
|
||||||
serial_port_out(port, UART_IER, UART_IER_THRI);
|
}
|
||||||
lsr = serial_port_in(port, UART_LSR);
|
} else {
|
||||||
iir = serial_port_in(port, UART_IIR);
|
up->bugs &= ~UART_BUG_TXEN;
|
||||||
serial_port_out(port, UART_IER, 0);
|
|
||||||
|
|
||||||
if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
|
|
||||||
if (!(up->bugs & UART_BUG_TXEN)) {
|
|
||||||
up->bugs |= UART_BUG_TXEN;
|
|
||||||
dev_dbg(port->dev, "enabling bad tx status workarounds\n");
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
up->bugs &= ~UART_BUG_TXEN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dont_test_tx_en:
|
|
||||||
uart_port_unlock_irqrestore(port, flags);
|
uart_port_unlock_irqrestore(port, flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2968,7 +2966,6 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
|
||||||
{
|
{
|
||||||
unsigned int size = serial8250_port_size(up);
|
unsigned int size = serial8250_port_size(up);
|
||||||
struct uart_port *port = &up->port;
|
struct uart_port *port = &up->port;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
switch (port->iotype) {
|
switch (port->iotype) {
|
||||||
case UPIO_AU:
|
case UPIO_AU:
|
||||||
|
@ -2977,32 +2974,28 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
|
||||||
case UPIO_MEM32BE:
|
case UPIO_MEM32BE:
|
||||||
case UPIO_MEM16:
|
case UPIO_MEM16:
|
||||||
case UPIO_MEM:
|
case UPIO_MEM:
|
||||||
if (!port->mapbase) {
|
if (!port->mapbase)
|
||||||
ret = -EINVAL;
|
return -EINVAL;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!request_mem_region(port->mapbase, size, "serial")) {
|
if (!request_mem_region(port->mapbase, size, "serial"))
|
||||||
ret = -EBUSY;
|
return -EBUSY;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (port->flags & UPF_IOREMAP) {
|
if (port->flags & UPF_IOREMAP) {
|
||||||
port->membase = ioremap(port->mapbase, size);
|
port->membase = ioremap(port->mapbase, size);
|
||||||
if (!port->membase) {
|
if (!port->membase) {
|
||||||
release_mem_region(port->mapbase, size);
|
release_mem_region(port->mapbase, size);
|
||||||
ret = -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
return 0;
|
||||||
|
|
||||||
case UPIO_HUB6:
|
case UPIO_HUB6:
|
||||||
case UPIO_PORT:
|
case UPIO_PORT:
|
||||||
if (!request_region(port->iobase, size, "serial"))
|
if (!request_region(port->iobase, size, "serial"))
|
||||||
ret = -EBUSY;
|
return -EBUSY;
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void serial8250_release_std_resource(struct uart_8250_port *up)
|
static void serial8250_release_std_resource(struct uart_8250_port *up)
|
||||||
|
|
|
@ -16,30 +16,27 @@ static unsigned int probe_rsa_count;
|
||||||
|
|
||||||
static int rsa8250_request_resource(struct uart_8250_port *up)
|
static int rsa8250_request_resource(struct uart_8250_port *up)
|
||||||
{
|
{
|
||||||
unsigned long start = UART_RSA_BASE << up->port.regshift;
|
|
||||||
unsigned int size = 8 << up->port.regshift;
|
|
||||||
struct uart_port *port = &up->port;
|
struct uart_port *port = &up->port;
|
||||||
int ret = -EINVAL;
|
unsigned long start = UART_RSA_BASE << port->regshift;
|
||||||
|
unsigned int size = 8 << port->regshift;
|
||||||
|
|
||||||
switch (port->iotype) {
|
switch (port->iotype) {
|
||||||
case UPIO_HUB6:
|
case UPIO_HUB6:
|
||||||
case UPIO_PORT:
|
case UPIO_PORT:
|
||||||
start += port->iobase;
|
start += port->iobase;
|
||||||
if (request_region(start, size, "serial-rsa"))
|
if (!request_region(start, size, "serial-rsa"))
|
||||||
ret = 0;
|
return -EBUSY;
|
||||||
else
|
return 0;
|
||||||
ret = -EBUSY;
|
default:
|
||||||
break;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rsa8250_release_resource(struct uart_8250_port *up)
|
static void rsa8250_release_resource(struct uart_8250_port *up)
|
||||||
{
|
{
|
||||||
unsigned long offset = UART_RSA_BASE << up->port.regshift;
|
|
||||||
unsigned int size = 8 << up->port.regshift;
|
|
||||||
struct uart_port *port = &up->port;
|
struct uart_port *port = &up->port;
|
||||||
|
unsigned long offset = UART_RSA_BASE << port->regshift;
|
||||||
|
unsigned int size = 8 << port->regshift;
|
||||||
|
|
||||||
switch (port->iotype) {
|
switch (port->iotype) {
|
||||||
case UPIO_HUB6:
|
case UPIO_HUB6:
|
||||||
|
|
|
@ -569,6 +569,19 @@ config SERIAL_8250_BCM7271
|
||||||
including DMA support and high accuracy BAUD rates, say
|
including DMA support and high accuracy BAUD rates, say
|
||||||
Y to this option. If unsure, say N.
|
Y to this option. If unsure, say N.
|
||||||
|
|
||||||
|
config SERIAL_8250_NI
|
||||||
|
tristate "NI 16550 based serial port"
|
||||||
|
depends on SERIAL_8250
|
||||||
|
depends on (X86 && ACPI) || COMPILE_TEST
|
||||||
|
help
|
||||||
|
This driver supports the integrated serial ports on National
|
||||||
|
Instruments (NI) controller hardware. This is required for all NI
|
||||||
|
controller models with onboard RS-485 or dual-mode RS-485/RS-232
|
||||||
|
ports.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module
|
||||||
|
will be called 8250_ni.
|
||||||
|
|
||||||
config SERIAL_OF_PLATFORM
|
config SERIAL_OF_PLATFORM
|
||||||
tristate "Devicetree based probing for 8250 ports"
|
tristate "Devicetree based probing for 8250 ports"
|
||||||
depends on SERIAL_8250 && OF
|
depends on SERIAL_8250 && OF
|
||||||
|
|
|
@ -40,6 +40,7 @@ obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
|
||||||
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
|
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
|
||||||
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
|
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
|
||||||
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
|
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
|
||||||
|
obj-$(CONFIG_SERIAL_8250_NI) += 8250_ni.o
|
||||||
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
|
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
|
||||||
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
|
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
|
||||||
obj-$(CONFIG_SERIAL_8250_PARISC) += 8250_parisc.o
|
obj-$(CONFIG_SERIAL_8250_PARISC) += 8250_parisc.o
|
||||||
|
|
|
@ -179,25 +179,6 @@ config SERIAL_ATMEL_TTYAT
|
||||||
|
|
||||||
Say Y if you have an external 8250/16C550 UART. If unsure, say N.
|
Say Y if you have an external 8250/16C550 UART. If unsure, say N.
|
||||||
|
|
||||||
config SERIAL_KGDB_NMI
|
|
||||||
bool "Serial console over KGDB NMI debugger port"
|
|
||||||
depends on KGDB_SERIAL_CONSOLE
|
|
||||||
help
|
|
||||||
This special driver allows you to temporary use NMI debugger port
|
|
||||||
as a normal console (assuming that the port is attached to KGDB).
|
|
||||||
|
|
||||||
Unlike KDB's disable_nmi command, with this driver you are always
|
|
||||||
able to go back to the debugger using KGDB escape sequence ($3#33).
|
|
||||||
This is because this console driver processes the input in NMI
|
|
||||||
context, and thus is able to intercept the magic sequence.
|
|
||||||
|
|
||||||
Note that since the console interprets input and uses polling
|
|
||||||
communication methods, for things like PPP you still must fully
|
|
||||||
detach debugger port from the KGDB NMI (i.e. disable_nmi), and
|
|
||||||
use raw console.
|
|
||||||
|
|
||||||
If unsure, say N.
|
|
||||||
|
|
||||||
config SERIAL_MESON
|
config SERIAL_MESON
|
||||||
tristate "Meson serial port support"
|
tristate "Meson serial port support"
|
||||||
depends on ARCH_MESON || COMPILE_TEST
|
depends on ARCH_MESON || COMPILE_TEST
|
||||||
|
@ -306,6 +287,29 @@ config SERIAL_TEGRA_TCU_CONSOLE
|
||||||
|
|
||||||
If unsure, say Y.
|
If unsure, say Y.
|
||||||
|
|
||||||
|
config SERIAL_TEGRA_UTC
|
||||||
|
tristate "NVIDIA Tegra UART Trace Controller"
|
||||||
|
depends on ARCH_TEGRA || COMPILE_TEST
|
||||||
|
select SERIAL_CORE
|
||||||
|
help
|
||||||
|
Support for Tegra UTC (UART Trace controller) client serial port.
|
||||||
|
|
||||||
|
UTC is a HW based serial port that allows multiplexing multiple data
|
||||||
|
streams of up to 16 UTC clients into a single hardware serial port.
|
||||||
|
|
||||||
|
config SERIAL_TEGRA_UTC_CONSOLE
|
||||||
|
bool "Support for console on a Tegra UTC serial port"
|
||||||
|
depends on SERIAL_TEGRA_UTC
|
||||||
|
select SERIAL_CORE_CONSOLE
|
||||||
|
default SERIAL_TEGRA_UTC
|
||||||
|
help
|
||||||
|
If you say Y here, it will be possible to use a Tegra UTC client as
|
||||||
|
the system console (the system console is the device which receives
|
||||||
|
all kernel messages and warnings and which allows logins in single
|
||||||
|
user mode).
|
||||||
|
|
||||||
|
If unsure, say Y.
|
||||||
|
|
||||||
config SERIAL_MAX3100
|
config SERIAL_MAX3100
|
||||||
tristate "MAX3100/3110/3111/3222 support"
|
tristate "MAX3100/3110/3111/3222 support"
|
||||||
depends on SPI
|
depends on SPI
|
||||||
|
|
|
@ -86,6 +86,7 @@ obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
|
||||||
obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o
|
obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o
|
||||||
obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
|
obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
|
||||||
obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
|
obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
|
||||||
|
obj-$(CONFIG_SERIAL_TEGRA_UTC) += tegra-utc.o
|
||||||
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
|
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
|
||||||
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
|
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
|
||||||
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
|
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
|
||||||
|
@ -96,6 +97,5 @@ obj-$(CONFIG_SERIAL_ZS) += zs.o
|
||||||
# GPIOLIB helpers for modem control lines
|
# GPIOLIB helpers for modem control lines
|
||||||
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
|
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
|
||||||
|
|
||||||
obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
|
|
||||||
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
|
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
|
||||||
obj-$(CONFIG_SERIAL_NUVOTON_MA35D1) += ma35d1_serial.o
|
obj-$(CONFIG_SERIAL_NUVOTON_MA35D1) += ma35d1_serial.o
|
||||||
|
|
|
@ -272,6 +272,7 @@ struct uart_amba_port {
|
||||||
enum pl011_rs485_tx_state rs485_tx_state;
|
enum pl011_rs485_tx_state rs485_tx_state;
|
||||||
struct hrtimer trigger_start_tx;
|
struct hrtimer trigger_start_tx;
|
||||||
struct hrtimer trigger_stop_tx;
|
struct hrtimer trigger_stop_tx;
|
||||||
|
bool console_line_ended;
|
||||||
#ifdef CONFIG_DMA_ENGINE
|
#ifdef CONFIG_DMA_ENGINE
|
||||||
/* DMA stuff */
|
/* DMA stuff */
|
||||||
unsigned int dmacr; /* dma control reg */
|
unsigned int dmacr; /* dma control reg */
|
||||||
|
@ -2366,50 +2367,7 @@ static void pl011_console_putchar(struct uart_port *port, unsigned char ch)
|
||||||
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
|
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
pl011_write(ch, uap, REG_DR);
|
pl011_write(ch, uap, REG_DR);
|
||||||
}
|
uap->console_line_ended = (ch == '\n');
|
||||||
|
|
||||||
static void
|
|
||||||
pl011_console_write(struct console *co, const char *s, unsigned int count)
|
|
||||||
{
|
|
||||||
struct uart_amba_port *uap = amba_ports[co->index];
|
|
||||||
unsigned int old_cr = 0, new_cr;
|
|
||||||
unsigned long flags;
|
|
||||||
int locked = 1;
|
|
||||||
|
|
||||||
clk_enable(uap->clk);
|
|
||||||
|
|
||||||
if (oops_in_progress)
|
|
||||||
locked = uart_port_trylock_irqsave(&uap->port, &flags);
|
|
||||||
else
|
|
||||||
uart_port_lock_irqsave(&uap->port, &flags);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* First save the CR then disable the interrupts
|
|
||||||
*/
|
|
||||||
if (!uap->vendor->always_enabled) {
|
|
||||||
old_cr = pl011_read(uap, REG_CR);
|
|
||||||
new_cr = old_cr & ~UART011_CR_CTSEN;
|
|
||||||
new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
|
|
||||||
pl011_write(new_cr, uap, REG_CR);
|
|
||||||
}
|
|
||||||
|
|
||||||
uart_console_write(&uap->port, s, count, pl011_console_putchar);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Finally, wait for transmitter to become empty and restore the
|
|
||||||
* TCR. Allow feature register bits to be inverted to work around
|
|
||||||
* errata.
|
|
||||||
*/
|
|
||||||
while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr)
|
|
||||||
& uap->vendor->fr_busy)
|
|
||||||
cpu_relax();
|
|
||||||
if (!uap->vendor->always_enabled)
|
|
||||||
pl011_write(old_cr, uap, REG_CR);
|
|
||||||
|
|
||||||
if (locked)
|
|
||||||
uart_port_unlock_irqrestore(&uap->port, flags);
|
|
||||||
|
|
||||||
clk_disable(uap->clk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
|
static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
|
||||||
|
@ -2472,6 +2430,8 @@ static int pl011_console_setup(struct console *co, char *options)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
uap->console_line_ended = true;
|
||||||
|
|
||||||
if (dev_get_platdata(uap->port.dev)) {
|
if (dev_get_platdata(uap->port.dev)) {
|
||||||
struct amba_pl011_data *plat;
|
struct amba_pl011_data *plat;
|
||||||
|
|
||||||
|
@ -2555,14 +2515,105 @@ static int pl011_console_match(struct console *co, char *name, int idx,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pl011_console_write_atomic(struct console *co, struct nbcon_write_context *wctxt)
|
||||||
|
{
|
||||||
|
struct uart_amba_port *uap = amba_ports[co->index];
|
||||||
|
unsigned int old_cr = 0;
|
||||||
|
|
||||||
|
if (!nbcon_enter_unsafe(wctxt))
|
||||||
|
return;
|
||||||
|
|
||||||
|
clk_enable(uap->clk);
|
||||||
|
|
||||||
|
if (!uap->vendor->always_enabled) {
|
||||||
|
old_cr = pl011_read(uap, REG_CR);
|
||||||
|
pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE),
|
||||||
|
uap, REG_CR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uap->console_line_ended)
|
||||||
|
uart_console_write(&uap->port, "\n", 1, pl011_console_putchar);
|
||||||
|
uart_console_write(&uap->port, wctxt->outbuf, wctxt->len, pl011_console_putchar);
|
||||||
|
|
||||||
|
while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
|
||||||
|
cpu_relax();
|
||||||
|
|
||||||
|
if (!uap->vendor->always_enabled)
|
||||||
|
pl011_write(old_cr, uap, REG_CR);
|
||||||
|
|
||||||
|
clk_disable(uap->clk);
|
||||||
|
|
||||||
|
nbcon_exit_unsafe(wctxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pl011_console_write_thread(struct console *co, struct nbcon_write_context *wctxt)
|
||||||
|
{
|
||||||
|
struct uart_amba_port *uap = amba_ports[co->index];
|
||||||
|
unsigned int old_cr = 0;
|
||||||
|
|
||||||
|
if (!nbcon_enter_unsafe(wctxt))
|
||||||
|
return;
|
||||||
|
|
||||||
|
clk_enable(uap->clk);
|
||||||
|
|
||||||
|
if (!uap->vendor->always_enabled) {
|
||||||
|
old_cr = pl011_read(uap, REG_CR);
|
||||||
|
pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE),
|
||||||
|
uap, REG_CR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbcon_exit_unsafe(wctxt)) {
|
||||||
|
int i;
|
||||||
|
unsigned int len = READ_ONCE(wctxt->len);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (!nbcon_enter_unsafe(wctxt))
|
||||||
|
break;
|
||||||
|
uart_console_write(&uap->port, wctxt->outbuf + i, 1, pl011_console_putchar);
|
||||||
|
if (!nbcon_exit_unsafe(wctxt))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!nbcon_enter_unsafe(wctxt))
|
||||||
|
nbcon_reacquire_nobuf(wctxt);
|
||||||
|
|
||||||
|
while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
|
||||||
|
cpu_relax();
|
||||||
|
|
||||||
|
if (!uap->vendor->always_enabled)
|
||||||
|
pl011_write(old_cr, uap, REG_CR);
|
||||||
|
|
||||||
|
clk_disable(uap->clk);
|
||||||
|
|
||||||
|
nbcon_exit_unsafe(wctxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pl011_console_device_lock(struct console *co, unsigned long *flags)
|
||||||
|
{
|
||||||
|
__uart_port_lock_irqsave(&amba_ports[co->index]->port, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pl011_console_device_unlock(struct console *co, unsigned long flags)
|
||||||
|
{
|
||||||
|
__uart_port_unlock_irqrestore(&amba_ports[co->index]->port, flags);
|
||||||
|
}
|
||||||
|
|
||||||
static struct uart_driver amba_reg;
|
static struct uart_driver amba_reg;
|
||||||
static struct console amba_console = {
|
static struct console amba_console = {
|
||||||
.name = "ttyAMA",
|
.name = "ttyAMA",
|
||||||
.write = pl011_console_write,
|
|
||||||
.device = uart_console_device,
|
.device = uart_console_device,
|
||||||
.setup = pl011_console_setup,
|
.setup = pl011_console_setup,
|
||||||
.match = pl011_console_match,
|
.match = pl011_console_match,
|
||||||
.flags = CON_PRINTBUFFER | CON_ANYTIME,
|
.write_atomic = pl011_console_write_atomic,
|
||||||
|
.write_thread = pl011_console_write_thread,
|
||||||
|
.device_lock = pl011_console_device_lock,
|
||||||
|
.device_unlock = pl011_console_device_unlock,
|
||||||
|
.flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON,
|
||||||
.index = -1,
|
.index = -1,
|
||||||
.data = &amba_reg,
|
.data = &amba_reg,
|
||||||
};
|
};
|
||||||
|
@ -3000,7 +3051,7 @@ static const struct of_device_id sbsa_uart_of_match[] = {
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
|
MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
|
||||||
|
|
||||||
static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = {
|
static const struct acpi_device_id sbsa_uart_acpi_match[] = {
|
||||||
{ "ARMH0011", 0 },
|
{ "ARMH0011", 0 },
|
||||||
{ "ARMHB000", 0 },
|
{ "ARMHB000", 0 },
|
||||||
{},
|
{},
|
||||||
|
@ -3013,8 +3064,8 @@ static struct platform_driver arm_sbsa_uart_platform_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "sbsa-uart",
|
.name = "sbsa-uart",
|
||||||
.pm = &pl011_dev_pm_ops,
|
.pm = &pl011_dev_pm_ops,
|
||||||
.of_match_table = of_match_ptr(sbsa_uart_of_match),
|
.of_match_table = sbsa_uart_of_match,
|
||||||
.acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
|
.acpi_match_table = sbsa_uart_acpi_match,
|
||||||
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
|
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -700,7 +700,7 @@ static void atmel_disable_ms(struct uart_port *port)
|
||||||
|
|
||||||
atmel_port->ms_irq_enabled = false;
|
atmel_port->ms_irq_enabled = false;
|
||||||
|
|
||||||
mctrl_gpio_disable_ms(atmel_port->gpios);
|
mctrl_gpio_disable_ms_no_sync(atmel_port->gpios);
|
||||||
|
|
||||||
if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
|
if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
|
||||||
idr |= ATMEL_US_CTSIC;
|
idr |= ATMEL_US_CTSIC;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1764,11 +1764,10 @@ static int icom_probe(struct pci_dev *dev,
|
||||||
goto probe_exit1;
|
goto probe_exit1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save off irq and request irq line */
|
/* save off irq and request irq line */
|
||||||
retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter);
|
retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, icom_adapter);
|
||||||
if (retval) {
|
if (retval)
|
||||||
goto probe_exit2;
|
goto probe_exit2;
|
||||||
}
|
|
||||||
|
|
||||||
retval = icom_load_ports(icom_adapter);
|
retval = icom_load_ports(icom_adapter);
|
||||||
|
|
||||||
|
|
|
@ -1608,7 +1608,7 @@ static void imx_uart_shutdown(struct uart_port *port)
|
||||||
imx_uart_dma_exit(sport);
|
imx_uart_dma_exit(sport);
|
||||||
}
|
}
|
||||||
|
|
||||||
mctrl_gpio_disable_ms(sport->gpios);
|
mctrl_gpio_disable_ms_sync(sport->gpios);
|
||||||
|
|
||||||
uart_port_lock_irqsave(&sport->port, &flags);
|
uart_port_lock_irqsave(&sport->port, &flags);
|
||||||
ucr2 = imx_uart_readl(sport, UCR2);
|
ucr2 = imx_uart_readl(sport, UCR2);
|
||||||
|
|
|
@ -1,280 +0,0 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0
|
|
||||||
/*
|
|
||||||
* KGDB NMI serial console
|
|
||||||
*
|
|
||||||
* Copyright 2010 Google, Inc.
|
|
||||||
* Arve Hjønnevåg <arve@android.com>
|
|
||||||
* Colin Cross <ccross@android.com>
|
|
||||||
* Copyright 2012 Linaro Ltd.
|
|
||||||
* Anton Vorontsov <anton.vorontsov@linaro.org>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/compiler.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/errno.h>
|
|
||||||
#include <linux/atomic.h>
|
|
||||||
#include <linux/console.h>
|
|
||||||
#include <linux/tty.h>
|
|
||||||
#include <linux/tty_driver.h>
|
|
||||||
#include <linux/tty_flip.h>
|
|
||||||
#include <linux/serial_core.h>
|
|
||||||
#include <linux/interrupt.h>
|
|
||||||
#include <linux/hrtimer.h>
|
|
||||||
#include <linux/tick.h>
|
|
||||||
#include <linux/kfifo.h>
|
|
||||||
#include <linux/kgdb.h>
|
|
||||||
#include <linux/kdb.h>
|
|
||||||
|
|
||||||
static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
|
|
||||||
|
|
||||||
static int kgdb_nmi_console_setup(struct console *co, char *options)
|
|
||||||
{
|
|
||||||
arch_kgdb_ops.enable_nmi(1);
|
|
||||||
|
|
||||||
/* The NMI console uses the dbg_io_ops to issue console messages. To
|
|
||||||
* avoid duplicate messages during kdb sessions we must inform kdb's
|
|
||||||
* I/O utilities that messages sent to the console will automatically
|
|
||||||
* be displayed on the dbg_io.
|
|
||||||
*/
|
|
||||||
dbg_io_ops->cons = co;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < c; i++)
|
|
||||||
dbg_io_ops->write_char(s[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct tty_driver *kgdb_nmi_tty_driver;
|
|
||||||
|
|
||||||
static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
|
|
||||||
{
|
|
||||||
*idx = co->index;
|
|
||||||
return kgdb_nmi_tty_driver;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct console kgdb_nmi_console = {
|
|
||||||
.name = "ttyNMI",
|
|
||||||
.setup = kgdb_nmi_console_setup,
|
|
||||||
.write = kgdb_nmi_console_write,
|
|
||||||
.device = kgdb_nmi_console_device,
|
|
||||||
.flags = CON_PRINTBUFFER | CON_ANYTIME,
|
|
||||||
.index = -1,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is usually the maximum rate on debug ports. We make fifo large enough
|
|
||||||
* to make copy-pasting to the terminal usable.
|
|
||||||
*/
|
|
||||||
#define KGDB_NMI_BAUD 115200
|
|
||||||
#define KGDB_NMI_FIFO_SIZE roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ)
|
|
||||||
|
|
||||||
struct kgdb_nmi_tty_priv {
|
|
||||||
struct tty_port port;
|
|
||||||
struct timer_list timer;
|
|
||||||
STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct tty_port *kgdb_nmi_port;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The tasklet is cheap, it does not cause wakeups when reschedules itself,
|
|
||||||
* instead it waits for the next tick.
|
|
||||||
*/
|
|
||||||
static void kgdb_nmi_tty_receiver(struct timer_list *t)
|
|
||||||
{
|
|
||||||
struct kgdb_nmi_tty_priv *priv = from_timer(priv, t, timer);
|
|
||||||
char ch;
|
|
||||||
|
|
||||||
priv->timer.expires = jiffies + (HZ/100);
|
|
||||||
add_timer(&priv->timer);
|
|
||||||
|
|
||||||
if (likely(!atomic_read(&kgdb_nmi_num_readers) ||
|
|
||||||
!kfifo_len(&priv->fifo)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (kfifo_out(&priv->fifo, &ch, 1))
|
|
||||||
tty_insert_flip_char(&priv->port, ch, TTY_NORMAL);
|
|
||||||
tty_flip_buffer_push(&priv->port);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
struct kgdb_nmi_tty_priv *priv =
|
|
||||||
container_of(port, struct kgdb_nmi_tty_priv, port);
|
|
||||||
|
|
||||||
kgdb_nmi_port = port;
|
|
||||||
priv->timer.expires = jiffies + (HZ/100);
|
|
||||||
add_timer(&priv->timer);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void kgdb_nmi_tty_shutdown(struct tty_port *port)
|
|
||||||
{
|
|
||||||
struct kgdb_nmi_tty_priv *priv =
|
|
||||||
container_of(port, struct kgdb_nmi_tty_priv, port);
|
|
||||||
|
|
||||||
del_timer(&priv->timer);
|
|
||||||
kgdb_nmi_port = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct tty_port_operations kgdb_nmi_tty_port_ops = {
|
|
||||||
.activate = kgdb_nmi_tty_activate,
|
|
||||||
.shutdown = kgdb_nmi_tty_shutdown,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
struct kgdb_nmi_tty_priv *priv;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
|
||||||
if (!priv)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
INIT_KFIFO(priv->fifo);
|
|
||||||
timer_setup(&priv->timer, kgdb_nmi_tty_receiver, 0);
|
|
||||||
tty_port_init(&priv->port);
|
|
||||||
priv->port.ops = &kgdb_nmi_tty_port_ops;
|
|
||||||
tty->driver_data = priv;
|
|
||||||
|
|
||||||
ret = tty_port_install(&priv->port, drv, tty);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("%s: can't install tty port: %d\n", __func__, ret);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
err:
|
|
||||||
tty_port_destroy(&priv->port);
|
|
||||||
kfree(priv);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void kgdb_nmi_tty_cleanup(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
struct kgdb_nmi_tty_priv *priv = tty->driver_data;
|
|
||||||
|
|
||||||
tty->driver_data = NULL;
|
|
||||||
tty_port_destroy(&priv->port);
|
|
||||||
kfree(priv);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file)
|
|
||||||
{
|
|
||||||
struct kgdb_nmi_tty_priv *priv = tty->driver_data;
|
|
||||||
unsigned int mode = file->f_flags & O_ACCMODE;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = tty_port_open(&priv->port, tty, file);
|
|
||||||
if (!ret && (mode == O_RDONLY || mode == O_RDWR))
|
|
||||||
atomic_inc(&kgdb_nmi_num_readers);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file)
|
|
||||||
{
|
|
||||||
struct kgdb_nmi_tty_priv *priv = tty->driver_data;
|
|
||||||
unsigned int mode = file->f_flags & O_ACCMODE;
|
|
||||||
|
|
||||||
if (mode == O_RDONLY || mode == O_RDWR)
|
|
||||||
atomic_dec(&kgdb_nmi_num_readers);
|
|
||||||
|
|
||||||
tty_port_close(&priv->port, tty, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void kgdb_nmi_tty_hangup(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
struct kgdb_nmi_tty_priv *priv = tty->driver_data;
|
|
||||||
|
|
||||||
tty_port_hangup(&priv->port);
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int kgdb_nmi_tty_write_room(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
/* Actually, we can handle any amount as we use polled writes. */
|
|
||||||
return 2048;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t kgdb_nmi_tty_write(struct tty_struct *tty, const u8 *buf,
|
|
||||||
size_t c)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < c; i++)
|
|
||||||
dbg_io_ops->write_char(buf[i]);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct tty_operations kgdb_nmi_tty_ops = {
|
|
||||||
.open = kgdb_nmi_tty_open,
|
|
||||||
.close = kgdb_nmi_tty_close,
|
|
||||||
.install = kgdb_nmi_tty_install,
|
|
||||||
.cleanup = kgdb_nmi_tty_cleanup,
|
|
||||||
.hangup = kgdb_nmi_tty_hangup,
|
|
||||||
.write_room = kgdb_nmi_tty_write_room,
|
|
||||||
.write = kgdb_nmi_tty_write,
|
|
||||||
};
|
|
||||||
|
|
||||||
int kgdb_register_nmi_console(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!arch_kgdb_ops.enable_nmi)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
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 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->init_termios = tty_std_termios;
|
|
||||||
tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios,
|
|
||||||
KGDB_NMI_BAUD, KGDB_NMI_BAUD);
|
|
||||||
tty_set_operations(kgdb_nmi_tty_driver, &kgdb_nmi_tty_ops);
|
|
||||||
|
|
||||||
ret = tty_register_driver(kgdb_nmi_tty_driver);
|
|
||||||
if (ret) {
|
|
||||||
pr_err("%s: can't register tty driver: %d\n", __func__, ret);
|
|
||||||
goto err_drv_reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
register_console(&kgdb_nmi_console);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
err_drv_reg:
|
|
||||||
tty_driver_kref_put(kgdb_nmi_tty_driver);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(kgdb_register_nmi_console);
|
|
||||||
|
|
||||||
int kgdb_unregister_nmi_console(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!arch_kgdb_ops.enable_nmi)
|
|
||||||
return 0;
|
|
||||||
arch_kgdb_ops.enable_nmi(0);
|
|
||||||
|
|
||||||
ret = unregister_console(&kgdb_nmi_console);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
tty_unregister_driver(kgdb_nmi_tty_driver);
|
|
||||||
tty_driver_kref_put(kgdb_nmi_tty_driver);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console);
|
|
|
@ -186,8 +186,6 @@ static void cleanup_kgdboc(void)
|
||||||
if (configured != 1)
|
if (configured != 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (kgdb_unregister_nmi_console())
|
|
||||||
return;
|
|
||||||
kgdboc_unregister_kbd();
|
kgdboc_unregister_kbd();
|
||||||
kgdb_unregister_io_module(&kgdboc_io_ops);
|
kgdb_unregister_io_module(&kgdboc_io_ops);
|
||||||
}
|
}
|
||||||
|
@ -250,16 +248,10 @@ do_register:
|
||||||
if (err)
|
if (err)
|
||||||
goto noconfig;
|
goto noconfig;
|
||||||
|
|
||||||
err = kgdb_register_nmi_console();
|
|
||||||
if (err)
|
|
||||||
goto nmi_con_failed;
|
|
||||||
|
|
||||||
configured = 1;
|
configured = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nmi_con_failed:
|
|
||||||
kgdb_unregister_io_module(&kgdboc_io_ops);
|
|
||||||
noconfig:
|
noconfig:
|
||||||
kgdboc_unregister_kbd();
|
kgdboc_unregister_kbd();
|
||||||
configured = 0;
|
configured = 0;
|
||||||
|
|
|
@ -799,7 +799,7 @@ static struct platform_driver ma35d1serial_driver = {
|
||||||
.resume = ma35d1serial_resume,
|
.resume = ma35d1serial_resume,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ma35d1-uart",
|
.name = "ma35d1-uart",
|
||||||
.of_match_table = of_match_ptr(ma35d1_serial_of_match),
|
.of_match_table = ma35d1_serial_of_match,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1351,7 +1351,6 @@ static const struct uart_ops mpc52xx_uart_ops = {
|
||||||
.startup = mpc52xx_uart_startup,
|
.startup = mpc52xx_uart_startup,
|
||||||
.shutdown = mpc52xx_uart_shutdown,
|
.shutdown = mpc52xx_uart_shutdown,
|
||||||
.set_termios = mpc52xx_uart_set_termios,
|
.set_termios = mpc52xx_uart_set_termios,
|
||||||
/* .pm = mpc52xx_uart_pm, Not supported yet */
|
|
||||||
.type = mpc52xx_uart_type,
|
.type = mpc52xx_uart_type,
|
||||||
.release_port = mpc52xx_uart_release_port,
|
.release_port = mpc52xx_uart_release_port,
|
||||||
.request_port = mpc52xx_uart_request_port,
|
.request_port = mpc52xx_uart_request_port,
|
||||||
|
|
|
@ -1515,7 +1515,6 @@ static const struct uart_ops pch_uart_ops = {
|
||||||
.startup = pch_uart_startup,
|
.startup = pch_uart_startup,
|
||||||
.shutdown = pch_uart_shutdown,
|
.shutdown = pch_uart_shutdown,
|
||||||
.set_termios = pch_uart_set_termios,
|
.set_termios = pch_uart_set_termios,
|
||||||
/* .pm = pch_uart_pm, Not supported yet */
|
|
||||||
.type = pch_uart_type,
|
.type = pch_uart_type,
|
||||||
.release_port = pch_uart_release_port,
|
.release_port = pch_uart_release_port,
|
||||||
.request_port = pch_uart_request_port,
|
.request_port = pch_uart_request_port,
|
||||||
|
|
|
@ -895,8 +895,8 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
|
||||||
{
|
{
|
||||||
struct uart_port *uport = uart_port_check(state);
|
struct uart_port *uport = uart_port_check(state);
|
||||||
unsigned long new_port;
|
unsigned long new_port;
|
||||||
unsigned int change_irq, change_port, closing_wait;
|
unsigned int old_custom_divisor, close_delay, closing_wait;
|
||||||
unsigned int old_custom_divisor, close_delay;
|
bool change_irq, change_port;
|
||||||
upf_t old_flags, new_flags;
|
upf_t old_flags, new_flags;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
|
@ -2013,9 +2013,8 @@ static const char *uart_type(struct uart_port *port)
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
|
|
||||||
static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
|
static void uart_line_info(struct seq_file *m, struct uart_state *state)
|
||||||
{
|
{
|
||||||
struct uart_state *state = drv->state + i;
|
|
||||||
struct tty_port *port = &state->port;
|
struct tty_port *port = &state->port;
|
||||||
enum uart_pm_state pm_state;
|
enum uart_pm_state pm_state;
|
||||||
struct uart_port *uport;
|
struct uart_port *uport;
|
||||||
|
@ -2100,7 +2099,7 @@ static int uart_proc_show(struct seq_file *m, void *v)
|
||||||
|
|
||||||
seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", "");
|
seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", "");
|
||||||
for (i = 0; i < drv->nr; i++)
|
for (i = 0; i < drv->nr; i++)
|
||||||
uart_line_info(m, drv, i);
|
uart_line_info(m, drv->state + i);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -3156,7 +3155,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
|
||||||
if (uport->cons && uport->dev)
|
if (uport->cons && uport->dev)
|
||||||
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
|
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
|
||||||
|
|
||||||
tty_port_link_device(port, drv->tty_driver, uport->line);
|
|
||||||
uart_configure_port(drv, state, uport);
|
uart_configure_port(drv, state, uport);
|
||||||
|
|
||||||
port->console = uart_console(uport);
|
port->console = uart_console(uport);
|
||||||
|
|
|
@ -217,7 +217,7 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
|
||||||
*
|
*
|
||||||
* This will get the {cts,rts,...}-gpios from device tree if they are present
|
* This will get the {cts,rts,...}-gpios from device tree if they are present
|
||||||
* and request them, set direction etc, and return an allocated structure.
|
* and request them, set direction etc, and return an allocated structure.
|
||||||
* `devm_*` functions are used, so there's no need to call mctrl_gpio_free().
|
* `devm_*` functions are used, so there's no need to explicitly free.
|
||||||
* As this sets up the irq handling, make sure to not handle changes to the
|
* As this sets up the irq handling, make sure to not handle changes to the
|
||||||
* gpio input lines in your driver, too.
|
* gpio input lines in your driver, too.
|
||||||
*/
|
*/
|
||||||
|
@ -267,32 +267,6 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
|
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
|
||||||
|
|
||||||
/**
|
|
||||||
* mctrl_gpio_free - explicitly free uart gpios
|
|
||||||
* @dev: uart port's device
|
|
||||||
* @gpios: gpios structure to be freed
|
|
||||||
*
|
|
||||||
* This will free the requested gpios in mctrl_gpio_init(). As `devm_*`
|
|
||||||
* functions are used, there's generally no need to call this function.
|
|
||||||
*/
|
|
||||||
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
|
||||||
{
|
|
||||||
enum mctrl_gpio_idx i;
|
|
||||||
|
|
||||||
if (gpios == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (i = 0; i < UART_GPIO_MAX; i++) {
|
|
||||||
if (gpios->irq[i])
|
|
||||||
devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
|
|
||||||
|
|
||||||
if (gpios->gpio[i])
|
|
||||||
devm_gpiod_put(dev, gpios->gpio[i]);
|
|
||||||
}
|
|
||||||
devm_kfree(dev, gpios);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(mctrl_gpio_free);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines
|
* mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines
|
||||||
* @gpios: gpios to enable
|
* @gpios: gpios to enable
|
||||||
|
@ -322,11 +296,7 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
|
EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
|
||||||
|
|
||||||
/**
|
static void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios, bool sync)
|
||||||
* mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines
|
|
||||||
* @gpios: gpios to disable
|
|
||||||
*/
|
|
||||||
void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
|
||||||
{
|
{
|
||||||
enum mctrl_gpio_idx i;
|
enum mctrl_gpio_idx i;
|
||||||
|
|
||||||
|
@ -342,10 +312,34 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
||||||
if (!gpios->irq[i])
|
if (!gpios->irq[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
disable_irq(gpios->irq[i]);
|
if (sync)
|
||||||
|
disable_irq(gpios->irq[i]);
|
||||||
|
else
|
||||||
|
disable_irq_nosync(gpios->irq[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
|
|
||||||
|
/**
|
||||||
|
* mctrl_gpio_disable_ms_sync - disable irqs and handling of changes to the ms
|
||||||
|
* lines, and wait for any pending IRQ to be processed
|
||||||
|
* @gpios: gpios to disable
|
||||||
|
*/
|
||||||
|
void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios)
|
||||||
|
{
|
||||||
|
mctrl_gpio_disable_ms(gpios, true);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_sync);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mctrl_gpio_disable_ms_no_sync - disable irqs and handling of changes to the
|
||||||
|
* ms lines, and return immediately
|
||||||
|
* @gpios: gpios to disable
|
||||||
|
*/
|
||||||
|
void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios)
|
||||||
|
{
|
||||||
|
mctrl_gpio_disable_ms(gpios, false);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_no_sync);
|
||||||
|
|
||||||
void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios)
|
void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios)
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,7 +59,7 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||||
/*
|
/*
|
||||||
* Request and set direction of modem control line GPIOs and set up irq
|
* Request and set direction of modem control line GPIOs and set up irq
|
||||||
* handling.
|
* handling.
|
||||||
* devm_* functions are used, so there's no need to call mctrl_gpio_free().
|
* devm_* functions are used, so there's no need to explicitly free.
|
||||||
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
|
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
|
||||||
* allocation error.
|
* allocation error.
|
||||||
*/
|
*/
|
||||||
|
@ -67,29 +67,29 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Request and set direction of modem control line GPIOs.
|
* Request and set direction of modem control line GPIOs.
|
||||||
* devm_* functions are used, so there's no need to call mctrl_gpio_free().
|
* devm_* functions are used, so there's no need to explicitly free.
|
||||||
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
|
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
|
||||||
* allocation error.
|
* allocation error.
|
||||||
*/
|
*/
|
||||||
struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev,
|
struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev,
|
||||||
unsigned int idx);
|
unsigned int idx);
|
||||||
|
|
||||||
/*
|
|
||||||
* Free the mctrl_gpios structure.
|
|
||||||
* Normally, this function will not be called, as the GPIOs will
|
|
||||||
* be disposed of by the resource management code.
|
|
||||||
*/
|
|
||||||
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable gpio interrupts to report status line changes.
|
* Enable gpio interrupts to report status line changes.
|
||||||
*/
|
*/
|
||||||
void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
|
void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable gpio interrupts to report status line changes.
|
* Disable gpio interrupts to report status line changes, and block until
|
||||||
|
* any corresponding IRQ is processed
|
||||||
*/
|
*/
|
||||||
void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios);
|
void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable gpio interrupts to report status line changes, and return
|
||||||
|
* immediately
|
||||||
|
*/
|
||||||
|
void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable gpio wakeup interrupts to enable wake up source.
|
* Enable gpio wakeup interrupts to enable wake up source.
|
||||||
|
@ -139,16 +139,15 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
|
||||||
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
|
static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
static inline void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,20 @@ struct plat_sci_reg {
|
||||||
u8 offset, size;
|
u8 offset, size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct sci_suspend_regs {
|
||||||
|
u16 scdl;
|
||||||
|
u16 sccks;
|
||||||
|
u16 scsmr;
|
||||||
|
u16 scscr;
|
||||||
|
u16 scfcr;
|
||||||
|
u16 scsptr;
|
||||||
|
u16 hssrr;
|
||||||
|
u16 scpcr;
|
||||||
|
u16 scpdr;
|
||||||
|
u8 scbrr;
|
||||||
|
u8 semr;
|
||||||
|
};
|
||||||
|
|
||||||
struct sci_port_params {
|
struct sci_port_params {
|
||||||
const struct plat_sci_reg regs[SCIx_NR_REGS];
|
const struct plat_sci_reg regs[SCIx_NR_REGS];
|
||||||
unsigned int fifosize;
|
unsigned int fifosize;
|
||||||
|
@ -134,6 +148,8 @@ struct sci_port {
|
||||||
struct dma_chan *chan_tx;
|
struct dma_chan *chan_tx;
|
||||||
struct dma_chan *chan_rx;
|
struct dma_chan *chan_rx;
|
||||||
|
|
||||||
|
struct reset_control *rstc;
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_SH_SCI_DMA
|
#ifdef CONFIG_SERIAL_SH_SCI_DMA
|
||||||
struct dma_chan *chan_tx_saved;
|
struct dma_chan *chan_tx_saved;
|
||||||
struct dma_chan *chan_rx_saved;
|
struct dma_chan *chan_rx_saved;
|
||||||
|
@ -153,6 +169,7 @@ struct sci_port {
|
||||||
int rx_trigger;
|
int rx_trigger;
|
||||||
struct timer_list rx_fifo_timer;
|
struct timer_list rx_fifo_timer;
|
||||||
int rx_fifo_timeout;
|
int rx_fifo_timeout;
|
||||||
|
struct sci_suspend_regs suspend_regs;
|
||||||
u16 hscif_tot;
|
u16 hscif_tot;
|
||||||
|
|
||||||
bool has_rtscts;
|
bool has_rtscts;
|
||||||
|
@ -2297,7 +2314,7 @@ static void sci_shutdown(struct uart_port *port)
|
||||||
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
|
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
|
||||||
|
|
||||||
s->autorts = false;
|
s->autorts = false;
|
||||||
mctrl_gpio_disable_ms(to_sci_port(port)->gpios);
|
mctrl_gpio_disable_ms_sync(to_sci_port(port)->gpios);
|
||||||
|
|
||||||
uart_port_lock_irqsave(port, &flags);
|
uart_port_lock_irqsave(port, &flags);
|
||||||
sci_stop_rx(port);
|
sci_stop_rx(port);
|
||||||
|
@ -3373,6 +3390,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
sp = &sci_ports[id];
|
sp = &sci_ports[id];
|
||||||
|
sp->rstc = rstc;
|
||||||
*dev_id = id;
|
*dev_id = id;
|
||||||
|
|
||||||
p->type = SCI_OF_TYPE(data);
|
p->type = SCI_OF_TYPE(data);
|
||||||
|
@ -3545,13 +3563,77 @@ static int sci_probe(struct platform_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sci_console_save(struct sci_port *s)
|
||||||
|
{
|
||||||
|
struct sci_suspend_regs *regs = &s->suspend_regs;
|
||||||
|
struct uart_port *port = &s->port;
|
||||||
|
|
||||||
|
if (sci_getreg(port, SCDL)->size)
|
||||||
|
regs->scdl = sci_serial_in(port, SCDL);
|
||||||
|
if (sci_getreg(port, SCCKS)->size)
|
||||||
|
regs->sccks = sci_serial_in(port, SCCKS);
|
||||||
|
if (sci_getreg(port, SCSMR)->size)
|
||||||
|
regs->scsmr = sci_serial_in(port, SCSMR);
|
||||||
|
if (sci_getreg(port, SCSCR)->size)
|
||||||
|
regs->scscr = sci_serial_in(port, SCSCR);
|
||||||
|
if (sci_getreg(port, SCFCR)->size)
|
||||||
|
regs->scfcr = sci_serial_in(port, SCFCR);
|
||||||
|
if (sci_getreg(port, SCSPTR)->size)
|
||||||
|
regs->scsptr = sci_serial_in(port, SCSPTR);
|
||||||
|
if (sci_getreg(port, SCBRR)->size)
|
||||||
|
regs->scbrr = sci_serial_in(port, SCBRR);
|
||||||
|
if (sci_getreg(port, HSSRR)->size)
|
||||||
|
regs->hssrr = sci_serial_in(port, HSSRR);
|
||||||
|
if (sci_getreg(port, SCPCR)->size)
|
||||||
|
regs->scpcr = sci_serial_in(port, SCPCR);
|
||||||
|
if (sci_getreg(port, SCPDR)->size)
|
||||||
|
regs->scpdr = sci_serial_in(port, SCPDR);
|
||||||
|
if (sci_getreg(port, SEMR)->size)
|
||||||
|
regs->semr = sci_serial_in(port, SEMR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sci_console_restore(struct sci_port *s)
|
||||||
|
{
|
||||||
|
struct sci_suspend_regs *regs = &s->suspend_regs;
|
||||||
|
struct uart_port *port = &s->port;
|
||||||
|
|
||||||
|
if (sci_getreg(port, SCDL)->size)
|
||||||
|
sci_serial_out(port, SCDL, regs->scdl);
|
||||||
|
if (sci_getreg(port, SCCKS)->size)
|
||||||
|
sci_serial_out(port, SCCKS, regs->sccks);
|
||||||
|
if (sci_getreg(port, SCSMR)->size)
|
||||||
|
sci_serial_out(port, SCSMR, regs->scsmr);
|
||||||
|
if (sci_getreg(port, SCSCR)->size)
|
||||||
|
sci_serial_out(port, SCSCR, regs->scscr);
|
||||||
|
if (sci_getreg(port, SCFCR)->size)
|
||||||
|
sci_serial_out(port, SCFCR, regs->scfcr);
|
||||||
|
if (sci_getreg(port, SCSPTR)->size)
|
||||||
|
sci_serial_out(port, SCSPTR, regs->scsptr);
|
||||||
|
if (sci_getreg(port, SCBRR)->size)
|
||||||
|
sci_serial_out(port, SCBRR, regs->scbrr);
|
||||||
|
if (sci_getreg(port, HSSRR)->size)
|
||||||
|
sci_serial_out(port, HSSRR, regs->hssrr);
|
||||||
|
if (sci_getreg(port, SCPCR)->size)
|
||||||
|
sci_serial_out(port, SCPCR, regs->scpcr);
|
||||||
|
if (sci_getreg(port, SCPDR)->size)
|
||||||
|
sci_serial_out(port, SCPDR, regs->scpdr);
|
||||||
|
if (sci_getreg(port, SEMR)->size)
|
||||||
|
sci_serial_out(port, SEMR, regs->semr);
|
||||||
|
}
|
||||||
|
|
||||||
static __maybe_unused int sci_suspend(struct device *dev)
|
static __maybe_unused int sci_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct sci_port *sport = dev_get_drvdata(dev);
|
struct sci_port *sport = dev_get_drvdata(dev);
|
||||||
|
|
||||||
if (sport)
|
if (sport) {
|
||||||
uart_suspend_port(&sci_uart_driver, &sport->port);
|
uart_suspend_port(&sci_uart_driver, &sport->port);
|
||||||
|
|
||||||
|
if (!console_suspend_enabled && uart_console(&sport->port))
|
||||||
|
sci_console_save(sport);
|
||||||
|
else
|
||||||
|
return reset_control_assert(sport->rstc);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3559,8 +3641,18 @@ static __maybe_unused int sci_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct sci_port *sport = dev_get_drvdata(dev);
|
struct sci_port *sport = dev_get_drvdata(dev);
|
||||||
|
|
||||||
if (sport)
|
if (sport) {
|
||||||
|
if (!console_suspend_enabled && uart_console(&sport->port)) {
|
||||||
|
sci_console_restore(sport);
|
||||||
|
} else {
|
||||||
|
int ret = reset_control_deassert(sport->rstc);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
uart_resume_port(&sci_uart_driver, &sport->port);
|
uart_resume_port(&sci_uart_driver, &sport->port);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -944,7 +944,7 @@ static void stm32_usart_enable_ms(struct uart_port *port)
|
||||||
|
|
||||||
static void stm32_usart_disable_ms(struct uart_port *port)
|
static void stm32_usart_disable_ms(struct uart_port *port)
|
||||||
{
|
{
|
||||||
mctrl_gpio_disable_ms(to_stm32_port(port)->gpios);
|
mctrl_gpio_disable_ms_sync(to_stm32_port(port)->gpios);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transmit stop */
|
/* Transmit stop */
|
||||||
|
@ -965,10 +965,8 @@ static void stm32_usart_start_tx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct tty_port *tport = &port->state->port;
|
struct tty_port *tport = &port->state->port;
|
||||||
|
|
||||||
if (kfifo_is_empty(&tport->xmit_fifo) && !port->x_char) {
|
if (kfifo_is_empty(&tport->xmit_fifo) && !port->x_char)
|
||||||
stm32_usart_rs485_rts_disable(port);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
stm32_usart_rs485_rts_enable(port);
|
stm32_usart_rs485_rts_enable(port);
|
||||||
|
|
||||||
|
|
|
@ -150,16 +150,6 @@ static void serial_out(struct uart_sunsu_port *up, int offset, int value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We used to support using pause I/O for certain machines. We
|
|
||||||
* haven't supported this for a while, but just in case it's badly
|
|
||||||
* needed for certain old 386 machines, I've left these #define's
|
|
||||||
* in....
|
|
||||||
*/
|
|
||||||
#define serial_inp(up, offset) serial_in(up, offset)
|
|
||||||
#define serial_outp(up, offset, value) serial_out(up, offset, value)
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For the 16C950
|
* For the 16C950
|
||||||
*/
|
*/
|
||||||
|
@ -169,20 +159,6 @@ static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
|
||||||
serial_out(up, UART_ICR, value);
|
serial_out(up, UART_ICR, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0 /* Unused currently */
|
|
||||||
static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset)
|
|
||||||
{
|
|
||||||
unsigned int value;
|
|
||||||
|
|
||||||
serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
|
|
||||||
serial_out(up, UART_SCR, offset);
|
|
||||||
value = serial_in(up, UART_ICR);
|
|
||||||
serial_icr_write(up, UART_ACR, up->acr);
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_8250_RSA
|
#ifdef CONFIG_SERIAL_8250_RSA
|
||||||
/*
|
/*
|
||||||
* Attempts to turn on the RSA FIFO. Returns zero on failure.
|
* Attempts to turn on the RSA FIFO. Returns zero on failure.
|
||||||
|
@ -193,12 +169,12 @@ static int __enable_rsa(struct uart_sunsu_port *up)
|
||||||
unsigned char mode;
|
unsigned char mode;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
mode = serial_inp(up, UART_RSA_MSR);
|
mode = serial_in(up, UART_RSA_MSR);
|
||||||
result = mode & UART_RSA_MSR_FIFO;
|
result = mode & UART_RSA_MSR_FIFO;
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
|
serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
|
||||||
mode = serial_inp(up, UART_RSA_MSR);
|
mode = serial_in(up, UART_RSA_MSR);
|
||||||
result = mode & UART_RSA_MSR_FIFO;
|
result = mode & UART_RSA_MSR_FIFO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +193,7 @@ static void enable_rsa(struct uart_sunsu_port *up)
|
||||||
uart_port_unlock_irq(&up->port);
|
uart_port_unlock_irq(&up->port);
|
||||||
}
|
}
|
||||||
if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
|
if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
|
||||||
serial_outp(up, UART_RSA_FRR, 0);
|
serial_out(up, UART_RSA_FRR, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,12 +212,12 @@ static void disable_rsa(struct uart_sunsu_port *up)
|
||||||
up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
|
up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
|
||||||
uart_port_lock_irq(&up->port);
|
uart_port_lock_irq(&up->port);
|
||||||
|
|
||||||
mode = serial_inp(up, UART_RSA_MSR);
|
mode = serial_in(up, UART_RSA_MSR);
|
||||||
result = !(mode & UART_RSA_MSR_FIFO);
|
result = !(mode & UART_RSA_MSR_FIFO);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
|
serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
|
||||||
mode = serial_inp(up, UART_RSA_MSR);
|
mode = serial_in(up, UART_RSA_MSR);
|
||||||
result = !(mode & UART_RSA_MSR_FIFO);
|
result = !(mode & UART_RSA_MSR_FIFO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +302,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
|
||||||
int saw_console_brk = 0;
|
int saw_console_brk = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ch = serial_inp(up, UART_RX);
|
ch = serial_in(up, UART_RX);
|
||||||
flag = TTY_NORMAL;
|
flag = TTY_NORMAL;
|
||||||
up->port.icount.rx++;
|
up->port.icount.rx++;
|
||||||
|
|
||||||
|
@ -387,7 +363,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
|
||||||
*/
|
*/
|
||||||
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
tty_insert_flip_char(port, 0, TTY_OVERRUN);
|
||||||
ignore_char:
|
ignore_char:
|
||||||
*status = serial_inp(up, UART_LSR);
|
*status = serial_in(up, UART_LSR);
|
||||||
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
|
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
|
||||||
|
|
||||||
if (saw_console_brk)
|
if (saw_console_brk)
|
||||||
|
@ -401,7 +377,7 @@ static void transmit_chars(struct uart_sunsu_port *up)
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
if (up->port.x_char) {
|
if (up->port.x_char) {
|
||||||
serial_outp(up, UART_TX, up->port.x_char);
|
serial_out(up, UART_TX, up->port.x_char);
|
||||||
up->port.icount.tx++;
|
up->port.icount.tx++;
|
||||||
up->port.x_char = 0;
|
up->port.x_char = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -460,7 +436,7 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
|
||||||
uart_port_lock_irqsave(&up->port, &flags);
|
uart_port_lock_irqsave(&up->port, &flags);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
status = serial_inp(up, UART_LSR);
|
status = serial_in(up, UART_LSR);
|
||||||
if (status & UART_LSR_DR)
|
if (status & UART_LSR_DR)
|
||||||
receive_chars(up, &status);
|
receive_chars(up, &status);
|
||||||
check_modem_status(up);
|
check_modem_status(up);
|
||||||
|
@ -498,7 +474,7 @@ static void sunsu_change_mouse_baud(struct uart_sunsu_port *up)
|
||||||
static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
|
static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
unsigned char ch = serial_inp(up, UART_RX);
|
unsigned char ch = serial_in(up, UART_RX);
|
||||||
|
|
||||||
/* Stop-A is handled by drivers/char/keyboard.c now. */
|
/* Stop-A is handled by drivers/char/keyboard.c now. */
|
||||||
if (up->su_type == SU_PORT_KBD) {
|
if (up->su_type == SU_PORT_KBD) {
|
||||||
|
@ -530,7 +506,7 @@ static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
|
||||||
struct uart_sunsu_port *up = dev_id;
|
struct uart_sunsu_port *up = dev_id;
|
||||||
|
|
||||||
if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) {
|
if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) {
|
||||||
unsigned char status = serial_inp(up, UART_LSR);
|
unsigned char status = serial_in(up, UART_LSR);
|
||||||
|
|
||||||
if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
|
if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
|
||||||
receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
|
receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
|
||||||
|
@ -619,14 +595,14 @@ static int sunsu_startup(struct uart_port *port)
|
||||||
if (up->port.type == PORT_16C950) {
|
if (up->port.type == PORT_16C950) {
|
||||||
/* Wake up and initialize UART */
|
/* Wake up and initialize UART */
|
||||||
up->acr = 0;
|
up->acr = 0;
|
||||||
serial_outp(up, UART_LCR, 0xBF);
|
serial_out(up, UART_LCR, 0xBF);
|
||||||
serial_outp(up, UART_EFR, UART_EFR_ECB);
|
serial_out(up, UART_EFR, UART_EFR_ECB);
|
||||||
serial_outp(up, UART_IER, 0);
|
serial_out(up, UART_IER, 0);
|
||||||
serial_outp(up, UART_LCR, 0);
|
serial_out(up, UART_LCR, 0);
|
||||||
serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
|
serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
|
||||||
serial_outp(up, UART_LCR, 0xBF);
|
serial_out(up, UART_LCR, 0xBF);
|
||||||
serial_outp(up, UART_EFR, UART_EFR_ECB);
|
serial_out(up, UART_EFR, UART_EFR_ECB);
|
||||||
serial_outp(up, UART_LCR, 0);
|
serial_out(up, UART_LCR, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_8250_RSA
|
#ifdef CONFIG_SERIAL_8250_RSA
|
||||||
|
@ -642,19 +618,19 @@ static int sunsu_startup(struct uart_port *port)
|
||||||
* (they will be reenabled in set_termios())
|
* (they will be reenabled in set_termios())
|
||||||
*/
|
*/
|
||||||
if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
|
if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
|
||||||
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
||||||
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
|
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
|
||||||
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
|
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
|
||||||
serial_outp(up, UART_FCR, 0);
|
serial_out(up, UART_FCR, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the interrupt registers.
|
* Clear the interrupt registers.
|
||||||
*/
|
*/
|
||||||
(void) serial_inp(up, UART_LSR);
|
(void) serial_in(up, UART_LSR);
|
||||||
(void) serial_inp(up, UART_RX);
|
(void) serial_in(up, UART_RX);
|
||||||
(void) serial_inp(up, UART_IIR);
|
(void) serial_in(up, UART_IIR);
|
||||||
(void) serial_inp(up, UART_MSR);
|
(void) serial_in(up, UART_MSR);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point, there's no way the LSR could still be 0xff;
|
* At this point, there's no way the LSR could still be 0xff;
|
||||||
|
@ -662,7 +638,7 @@ static int sunsu_startup(struct uart_port *port)
|
||||||
* here.
|
* here.
|
||||||
*/
|
*/
|
||||||
if (!(up->port.flags & UPF_BUGGY_UART) &&
|
if (!(up->port.flags & UPF_BUGGY_UART) &&
|
||||||
(serial_inp(up, UART_LSR) == 0xff)) {
|
(serial_in(up, UART_LSR) == 0xff)) {
|
||||||
printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
|
printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -682,7 +658,7 @@ static int sunsu_startup(struct uart_port *port)
|
||||||
/*
|
/*
|
||||||
* Now, initialize the UART
|
* Now, initialize the UART
|
||||||
*/
|
*/
|
||||||
serial_outp(up, UART_LCR, UART_LCR_WLEN8);
|
serial_out(up, UART_LCR, UART_LCR_WLEN8);
|
||||||
|
|
||||||
uart_port_lock_irqsave(&up->port, &flags);
|
uart_port_lock_irqsave(&up->port, &flags);
|
||||||
|
|
||||||
|
@ -697,7 +673,7 @@ static int sunsu_startup(struct uart_port *port)
|
||||||
* anyway, so we don't enable them here.
|
* anyway, so we don't enable them here.
|
||||||
*/
|
*/
|
||||||
up->ier = UART_IER_RLSI | UART_IER_RDI;
|
up->ier = UART_IER_RLSI | UART_IER_RDI;
|
||||||
serial_outp(up, UART_IER, up->ier);
|
serial_out(up, UART_IER, up->ier);
|
||||||
|
|
||||||
if (up->port.flags & UPF_FOURPORT) {
|
if (up->port.flags & UPF_FOURPORT) {
|
||||||
unsigned int icp;
|
unsigned int icp;
|
||||||
|
@ -712,10 +688,10 @@ static int sunsu_startup(struct uart_port *port)
|
||||||
/*
|
/*
|
||||||
* And clear the interrupt registers again for luck.
|
* And clear the interrupt registers again for luck.
|
||||||
*/
|
*/
|
||||||
(void) serial_inp(up, UART_LSR);
|
(void) serial_in(up, UART_LSR);
|
||||||
(void) serial_inp(up, UART_RX);
|
(void) serial_in(up, UART_RX);
|
||||||
(void) serial_inp(up, UART_IIR);
|
(void) serial_in(up, UART_IIR);
|
||||||
(void) serial_inp(up, UART_MSR);
|
(void) serial_in(up, UART_MSR);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -730,7 +706,7 @@ static void sunsu_shutdown(struct uart_port *port)
|
||||||
* Disable interrupts from this port
|
* Disable interrupts from this port
|
||||||
*/
|
*/
|
||||||
up->ier = 0;
|
up->ier = 0;
|
||||||
serial_outp(up, UART_IER, 0);
|
serial_out(up, UART_IER, 0);
|
||||||
|
|
||||||
uart_port_lock_irqsave(&up->port, &flags);
|
uart_port_lock_irqsave(&up->port, &flags);
|
||||||
if (up->port.flags & UPF_FOURPORT) {
|
if (up->port.flags & UPF_FOURPORT) {
|
||||||
|
@ -746,11 +722,11 @@ static void sunsu_shutdown(struct uart_port *port)
|
||||||
/*
|
/*
|
||||||
* Disable break condition and FIFOs
|
* Disable break condition and FIFOs
|
||||||
*/
|
*/
|
||||||
serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
|
serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
|
||||||
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
|
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
|
||||||
UART_FCR_CLEAR_RCVR |
|
UART_FCR_CLEAR_RCVR |
|
||||||
UART_FCR_CLEAR_XMIT);
|
UART_FCR_CLEAR_XMIT);
|
||||||
serial_outp(up, UART_FCR, 0);
|
serial_out(up, UART_FCR, 0);
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_8250_RSA
|
#ifdef CONFIG_SERIAL_8250_RSA
|
||||||
/*
|
/*
|
||||||
|
@ -872,22 +848,22 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
|
||||||
serial_out(up, UART_IER, up->ier);
|
serial_out(up, UART_IER, up->ier);
|
||||||
|
|
||||||
if (uart_config[up->port.type].flags & UART_STARTECH) {
|
if (uart_config[up->port.type].flags & UART_STARTECH) {
|
||||||
serial_outp(up, UART_LCR, 0xBF);
|
serial_out(up, UART_LCR, 0xBF);
|
||||||
serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
|
serial_out(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
|
||||||
}
|
}
|
||||||
serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
|
serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
|
||||||
serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
|
serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
|
||||||
serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
|
serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
|
||||||
if (up->port.type == PORT_16750)
|
if (up->port.type == PORT_16750)
|
||||||
serial_outp(up, UART_FCR, fcr); /* set fcr */
|
serial_out(up, UART_FCR, fcr); /* set fcr */
|
||||||
serial_outp(up, UART_LCR, cval); /* reset DLAB */
|
serial_out(up, UART_LCR, cval); /* reset DLAB */
|
||||||
up->lcr = cval; /* Save LCR */
|
up->lcr = cval; /* Save LCR */
|
||||||
if (up->port.type != PORT_16750) {
|
if (up->port.type != PORT_16750) {
|
||||||
if (fcr & UART_FCR_ENABLE_FIFO) {
|
if (fcr & UART_FCR_ENABLE_FIFO) {
|
||||||
/* emulated UARTs (Lucent Venus 167x) need two steps */
|
/* emulated UARTs (Lucent Venus 167x) need two steps */
|
||||||
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
||||||
}
|
}
|
||||||
serial_outp(up, UART_FCR, fcr); /* set fcr */
|
serial_out(up, UART_FCR, fcr); /* set fcr */
|
||||||
}
|
}
|
||||||
|
|
||||||
up->cflag = cflag;
|
up->cflag = cflag;
|
||||||
|
@ -1051,18 +1027,18 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
|
||||||
* 0x80 is a non-existent port; which should be safe since
|
* 0x80 is a non-existent port; which should be safe since
|
||||||
* include/asm/io.h also makes this assumption.
|
* include/asm/io.h also makes this assumption.
|
||||||
*/
|
*/
|
||||||
scratch = serial_inp(up, UART_IER);
|
scratch = serial_in(up, UART_IER);
|
||||||
serial_outp(up, UART_IER, 0);
|
serial_out(up, UART_IER, 0);
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
outb(0xff, 0x080);
|
outb(0xff, 0x080);
|
||||||
#endif
|
#endif
|
||||||
scratch2 = serial_inp(up, UART_IER);
|
scratch2 = serial_in(up, UART_IER);
|
||||||
serial_outp(up, UART_IER, 0x0f);
|
serial_out(up, UART_IER, 0x0f);
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
outb(0, 0x080);
|
outb(0, 0x080);
|
||||||
#endif
|
#endif
|
||||||
scratch3 = serial_inp(up, UART_IER);
|
scratch3 = serial_in(up, UART_IER);
|
||||||
serial_outp(up, UART_IER, scratch);
|
serial_out(up, UART_IER, scratch);
|
||||||
if (scratch2 != 0 || scratch3 != 0x0F)
|
if (scratch2 != 0 || scratch3 != 0x0F)
|
||||||
goto out; /* We failed; there's nothing here */
|
goto out; /* We failed; there's nothing here */
|
||||||
}
|
}
|
||||||
|
@ -1080,16 +1056,16 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
|
||||||
* that conflicts with COM 1-4 --- we hope!
|
* that conflicts with COM 1-4 --- we hope!
|
||||||
*/
|
*/
|
||||||
if (!(up->port.flags & UPF_SKIP_TEST)) {
|
if (!(up->port.flags & UPF_SKIP_TEST)) {
|
||||||
serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
|
serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A);
|
||||||
status1 = serial_inp(up, UART_MSR) & 0xF0;
|
status1 = serial_in(up, UART_MSR) & 0xF0;
|
||||||
serial_outp(up, UART_MCR, save_mcr);
|
serial_out(up, UART_MCR, save_mcr);
|
||||||
if (status1 != 0x90)
|
if (status1 != 0x90)
|
||||||
goto out; /* We failed loopback test */
|
goto out; /* We failed loopback test */
|
||||||
}
|
}
|
||||||
serial_outp(up, UART_LCR, 0xBF); /* set up for StarTech test */
|
serial_out(up, UART_LCR, 0xBF); /* set up for StarTech test */
|
||||||
serial_outp(up, UART_EFR, 0); /* EFR is the same as FCR */
|
serial_out(up, UART_EFR, 0); /* EFR is the same as FCR */
|
||||||
serial_outp(up, UART_LCR, 0);
|
serial_out(up, UART_LCR, 0);
|
||||||
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
||||||
scratch = serial_in(up, UART_IIR) >> 6;
|
scratch = serial_in(up, UART_IIR) >> 6;
|
||||||
switch (scratch) {
|
switch (scratch) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -1107,19 +1083,19 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
|
||||||
}
|
}
|
||||||
if (up->port.type == PORT_16550A) {
|
if (up->port.type == PORT_16550A) {
|
||||||
/* Check for Startech UART's */
|
/* Check for Startech UART's */
|
||||||
serial_outp(up, UART_LCR, UART_LCR_DLAB);
|
serial_out(up, UART_LCR, UART_LCR_DLAB);
|
||||||
if (serial_in(up, UART_EFR) == 0) {
|
if (serial_in(up, UART_EFR) == 0) {
|
||||||
up->port.type = PORT_16650;
|
up->port.type = PORT_16650;
|
||||||
} else {
|
} else {
|
||||||
serial_outp(up, UART_LCR, 0xBF);
|
serial_out(up, UART_LCR, 0xBF);
|
||||||
if (serial_in(up, UART_EFR) == 0)
|
if (serial_in(up, UART_EFR) == 0)
|
||||||
up->port.type = PORT_16650V2;
|
up->port.type = PORT_16650V2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (up->port.type == PORT_16550A) {
|
if (up->port.type == PORT_16550A) {
|
||||||
/* Check for TI 16750 */
|
/* Check for TI 16750 */
|
||||||
serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB);
|
serial_out(up, UART_LCR, save_lcr | UART_LCR_DLAB);
|
||||||
serial_outp(up, UART_FCR,
|
serial_out(up, UART_FCR,
|
||||||
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
|
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
|
||||||
scratch = serial_in(up, UART_IIR) >> 5;
|
scratch = serial_in(up, UART_IIR) >> 5;
|
||||||
if (scratch == 7) {
|
if (scratch == 7) {
|
||||||
|
@ -1129,24 +1105,24 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
|
||||||
* mode if the UART_FCR7_64BYTE bit was set
|
* mode if the UART_FCR7_64BYTE bit was set
|
||||||
* while UART_LCR_DLAB was latched.
|
* while UART_LCR_DLAB was latched.
|
||||||
*/
|
*/
|
||||||
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
||||||
serial_outp(up, UART_LCR, 0);
|
serial_out(up, UART_LCR, 0);
|
||||||
serial_outp(up, UART_FCR,
|
serial_out(up, UART_FCR,
|
||||||
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
|
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
|
||||||
scratch = serial_in(up, UART_IIR) >> 5;
|
scratch = serial_in(up, UART_IIR) >> 5;
|
||||||
if (scratch == 6)
|
if (scratch == 6)
|
||||||
up->port.type = PORT_16750;
|
up->port.type = PORT_16750;
|
||||||
}
|
}
|
||||||
serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
|
||||||
}
|
}
|
||||||
serial_outp(up, UART_LCR, save_lcr);
|
serial_out(up, UART_LCR, save_lcr);
|
||||||
if (up->port.type == PORT_16450) {
|
if (up->port.type == PORT_16450) {
|
||||||
scratch = serial_in(up, UART_SCR);
|
scratch = serial_in(up, UART_SCR);
|
||||||
serial_outp(up, UART_SCR, 0xa5);
|
serial_out(up, UART_SCR, 0xa5);
|
||||||
status1 = serial_in(up, UART_SCR);
|
status1 = serial_in(up, UART_SCR);
|
||||||
serial_outp(up, UART_SCR, 0x5a);
|
serial_out(up, UART_SCR, 0x5a);
|
||||||
status2 = serial_in(up, UART_SCR);
|
status2 = serial_in(up, UART_SCR);
|
||||||
serial_outp(up, UART_SCR, scratch);
|
serial_out(up, UART_SCR, scratch);
|
||||||
|
|
||||||
if ((status1 != 0xa5) || (status2 != 0x5a))
|
if ((status1 != 0xa5) || (status2 != 0x5a))
|
||||||
up->port.type = PORT_8250;
|
up->port.type = PORT_8250;
|
||||||
|
@ -1163,15 +1139,15 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_SERIAL_8250_RSA
|
#ifdef CONFIG_SERIAL_8250_RSA
|
||||||
if (up->port.type == PORT_RSA)
|
if (up->port.type == PORT_RSA)
|
||||||
serial_outp(up, UART_RSA_FRR, 0);
|
serial_out(up, UART_RSA_FRR, 0);
|
||||||
#endif
|
#endif
|
||||||
serial_outp(up, UART_MCR, save_mcr);
|
serial_out(up, UART_MCR, save_mcr);
|
||||||
serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
|
serial_out(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
|
||||||
UART_FCR_CLEAR_RCVR |
|
UART_FCR_CLEAR_RCVR |
|
||||||
UART_FCR_CLEAR_XMIT));
|
UART_FCR_CLEAR_XMIT));
|
||||||
serial_outp(up, UART_FCR, 0);
|
serial_out(up, UART_FCR, 0);
|
||||||
(void)serial_in(up, UART_RX);
|
(void)serial_in(up, UART_RX);
|
||||||
serial_outp(up, UART_IER, 0);
|
serial_out(up, UART_IER, 0);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
uart_port_unlock_irqrestore(&up->port, flags);
|
uart_port_unlock_irqrestore(&up->port, flags);
|
||||||
|
|
625
drivers/tty/serial/tegra-utc.c
Normal file
625
drivers/tty/serial/tegra-utc.c
Normal file
|
@ -0,0 +1,625 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
// NVIDIA Tegra UTC (UART Trace Controller) driver.
|
||||||
|
|
||||||
|
#include <linux/bits.h>
|
||||||
|
#include <linux/console.h>
|
||||||
|
#include <linux/container_of.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/kfifo.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mod_devicetable.h>
|
||||||
|
#include <linux/property.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/serial.h>
|
||||||
|
#include <linux/serial_core.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/tty.h>
|
||||||
|
#include <linux/tty_flip.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#define TEGRA_UTC_ENABLE 0x000
|
||||||
|
#define TEGRA_UTC_ENABLE_CLIENT_ENABLE BIT(0)
|
||||||
|
|
||||||
|
#define TEGRA_UTC_FIFO_THRESHOLD 0x008
|
||||||
|
|
||||||
|
#define TEGRA_UTC_COMMAND 0x00c
|
||||||
|
#define TEGRA_UTC_COMMAND_RESET BIT(0)
|
||||||
|
#define TEGRA_UTC_COMMAND_FLUSH BIT(1)
|
||||||
|
|
||||||
|
#define TEGRA_UTC_DATA 0x020
|
||||||
|
|
||||||
|
#define TEGRA_UTC_FIFO_STATUS 0x100
|
||||||
|
#define TEGRA_UTC_FIFO_EMPTY BIT(0)
|
||||||
|
#define TEGRA_UTC_FIFO_FULL BIT(1)
|
||||||
|
#define TEGRA_UTC_FIFO_REQ BIT(2)
|
||||||
|
#define TEGRA_UTC_FIFO_OVERFLOW BIT(3)
|
||||||
|
#define TEGRA_UTC_FIFO_TIMEOUT BIT(4)
|
||||||
|
|
||||||
|
#define TEGRA_UTC_FIFO_OCCUPANCY 0x104
|
||||||
|
|
||||||
|
#define TEGRA_UTC_INTR_STATUS 0x108
|
||||||
|
#define TEGRA_UTC_INTR_SET 0x10c
|
||||||
|
#define TEGRA_UTC_INTR_MASK 0x110
|
||||||
|
#define TEGRA_UTC_INTR_CLEAR 0x114
|
||||||
|
#define TEGRA_UTC_INTR_EMPTY BIT(0)
|
||||||
|
#define TEGRA_UTC_INTR_FULL BIT(1)
|
||||||
|
#define TEGRA_UTC_INTR_REQ BIT(2)
|
||||||
|
#define TEGRA_UTC_INTR_OVERFLOW BIT(3)
|
||||||
|
#define TEGRA_UTC_INTR_TIMEOUT BIT(4)
|
||||||
|
|
||||||
|
#define TEGRA_UTC_UART_NR 16
|
||||||
|
|
||||||
|
#define TEGRA_UTC_INTR_COMMON (TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_FULL | TEGRA_UTC_INTR_EMPTY)
|
||||||
|
|
||||||
|
struct tegra_utc_port {
|
||||||
|
#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
|
||||||
|
struct console console;
|
||||||
|
#endif
|
||||||
|
struct uart_port port;
|
||||||
|
|
||||||
|
void __iomem *rx_base;
|
||||||
|
void __iomem *tx_base;
|
||||||
|
|
||||||
|
u32 tx_irqmask;
|
||||||
|
u32 rx_irqmask;
|
||||||
|
|
||||||
|
unsigned int fifosize;
|
||||||
|
u32 tx_threshold;
|
||||||
|
u32 rx_threshold;
|
||||||
|
};
|
||||||
|
|
||||||
|
static u32 tegra_utc_rx_readl(struct tegra_utc_port *tup, unsigned int offset)
|
||||||
|
{
|
||||||
|
void __iomem *addr = tup->rx_base + offset;
|
||||||
|
|
||||||
|
return readl_relaxed(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_rx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset)
|
||||||
|
{
|
||||||
|
void __iomem *addr = tup->rx_base + offset;
|
||||||
|
|
||||||
|
writel_relaxed(val, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 tegra_utc_tx_readl(struct tegra_utc_port *tup, unsigned int offset)
|
||||||
|
{
|
||||||
|
void __iomem *addr = tup->tx_base + offset;
|
||||||
|
|
||||||
|
return readl_relaxed(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_tx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset)
|
||||||
|
{
|
||||||
|
void __iomem *addr = tup->tx_base + offset;
|
||||||
|
|
||||||
|
writel_relaxed(val, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_enable_tx_irq(struct tegra_utc_port *tup)
|
||||||
|
{
|
||||||
|
tup->tx_irqmask = TEGRA_UTC_INTR_REQ;
|
||||||
|
|
||||||
|
tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK);
|
||||||
|
tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_disable_tx_irq(struct tegra_utc_port *tup)
|
||||||
|
{
|
||||||
|
tup->tx_irqmask = 0x0;
|
||||||
|
|
||||||
|
tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK);
|
||||||
|
tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_stop_tx(struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
|
||||||
|
|
||||||
|
tegra_utc_disable_tx_irq(tup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_init_tx(struct tegra_utc_port *tup)
|
||||||
|
{
|
||||||
|
/* Disable TX. */
|
||||||
|
tegra_utc_tx_writel(tup, 0x0, TEGRA_UTC_ENABLE);
|
||||||
|
|
||||||
|
/* Update the FIFO Threshold. */
|
||||||
|
tegra_utc_tx_writel(tup, tup->tx_threshold, TEGRA_UTC_FIFO_THRESHOLD);
|
||||||
|
|
||||||
|
/* Clear and mask all the interrupts. */
|
||||||
|
tegra_utc_tx_writel(tup, TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR);
|
||||||
|
tegra_utc_disable_tx_irq(tup);
|
||||||
|
|
||||||
|
/* Enable TX. */
|
||||||
|
tegra_utc_tx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_init_rx(struct tegra_utc_port *tup)
|
||||||
|
{
|
||||||
|
tup->rx_irqmask = TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_TIMEOUT;
|
||||||
|
|
||||||
|
tegra_utc_rx_writel(tup, TEGRA_UTC_COMMAND_RESET, TEGRA_UTC_COMMAND);
|
||||||
|
tegra_utc_rx_writel(tup, tup->rx_threshold, TEGRA_UTC_FIFO_THRESHOLD);
|
||||||
|
|
||||||
|
/* Clear all the pending interrupts. */
|
||||||
|
tegra_utc_rx_writel(tup, TEGRA_UTC_INTR_TIMEOUT | TEGRA_UTC_INTR_OVERFLOW |
|
||||||
|
TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR);
|
||||||
|
tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK);
|
||||||
|
tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET);
|
||||||
|
|
||||||
|
/* Enable RX. */
|
||||||
|
tegra_utc_rx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool tegra_utc_tx_chars(struct tegra_utc_port *tup)
|
||||||
|
{
|
||||||
|
struct uart_port *port = &tup->port;
|
||||||
|
unsigned int pending;
|
||||||
|
u8 c;
|
||||||
|
|
||||||
|
pending = uart_port_tx(port, c,
|
||||||
|
!(tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_FULL),
|
||||||
|
tegra_utc_tx_writel(tup, c, TEGRA_UTC_DATA));
|
||||||
|
|
||||||
|
return pending;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_rx_chars(struct tegra_utc_port *tup)
|
||||||
|
{
|
||||||
|
struct tty_port *port = &tup->port.state->port;
|
||||||
|
unsigned int max_chars = 256;
|
||||||
|
u32 status;
|
||||||
|
int sysrq;
|
||||||
|
u32 ch;
|
||||||
|
|
||||||
|
while (max_chars--) {
|
||||||
|
status = tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS);
|
||||||
|
if (status & TEGRA_UTC_FIFO_EMPTY)
|
||||||
|
break;
|
||||||
|
|
||||||
|
ch = tegra_utc_rx_readl(tup, TEGRA_UTC_DATA);
|
||||||
|
tup->port.icount.rx++;
|
||||||
|
|
||||||
|
if (status & TEGRA_UTC_FIFO_OVERFLOW)
|
||||||
|
tup->port.icount.overrun++;
|
||||||
|
|
||||||
|
uart_port_unlock(&tup->port);
|
||||||
|
sysrq = uart_handle_sysrq_char(&tup->port, ch);
|
||||||
|
uart_port_lock(&tup->port);
|
||||||
|
|
||||||
|
if (!sysrq)
|
||||||
|
tty_insert_flip_char(port, ch, TTY_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
tty_flip_buffer_push(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t tegra_utc_isr(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = dev_id;
|
||||||
|
unsigned int handled = 0;
|
||||||
|
u32 status;
|
||||||
|
|
||||||
|
uart_port_lock(&tup->port);
|
||||||
|
|
||||||
|
/* Process RX_REQ and RX_TIMEOUT interrupts. */
|
||||||
|
do {
|
||||||
|
status = tegra_utc_rx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->rx_irqmask;
|
||||||
|
if (status) {
|
||||||
|
tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_CLEAR);
|
||||||
|
tegra_utc_rx_chars(tup);
|
||||||
|
handled = 1;
|
||||||
|
}
|
||||||
|
} while (status);
|
||||||
|
|
||||||
|
/* Process TX_REQ interrupt. */
|
||||||
|
do {
|
||||||
|
status = tegra_utc_tx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->tx_irqmask;
|
||||||
|
if (status) {
|
||||||
|
tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_CLEAR);
|
||||||
|
tegra_utc_tx_chars(tup);
|
||||||
|
handled = 1;
|
||||||
|
}
|
||||||
|
} while (status);
|
||||||
|
|
||||||
|
uart_port_unlock(&tup->port);
|
||||||
|
|
||||||
|
return IRQ_RETVAL(handled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int tegra_utc_tx_empty(struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
|
||||||
|
|
||||||
|
return tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY) ? 0 : TIOCSER_TEMT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int tegra_utc_get_mctrl(struct uart_port *port)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_start_tx(struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
|
||||||
|
|
||||||
|
if (tegra_utc_tx_chars(tup))
|
||||||
|
tegra_utc_enable_tx_irq(tup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_stop_rx(struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
|
||||||
|
|
||||||
|
tup->rx_irqmask = 0x0;
|
||||||
|
tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK);
|
||||||
|
tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_hw_init(struct tegra_utc_port *tup)
|
||||||
|
{
|
||||||
|
tegra_utc_init_tx(tup);
|
||||||
|
tegra_utc_init_rx(tup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_utc_startup(struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
tegra_utc_hw_init(tup);
|
||||||
|
|
||||||
|
/* Interrupt is dedicated to this UTC client. */
|
||||||
|
ret = request_irq(port->irq, tegra_utc_isr, 0, dev_name(port->dev), tup);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(port->dev, "failed to register interrupt handler\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_shutdown(struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
|
||||||
|
|
||||||
|
tegra_utc_rx_writel(tup, 0x0, TEGRA_UTC_ENABLE);
|
||||||
|
free_irq(port->irq, tup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||||
|
const struct ktermios *old)
|
||||||
|
{
|
||||||
|
/* The Tegra UTC clients supports only 8-N-1 configuration without HW flow control */
|
||||||
|
termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
|
||||||
|
termios->c_cflag &= ~(CMSPAR | CRTSCTS);
|
||||||
|
termios->c_cflag |= CS8 | CLOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_CONSOLE_POLL
|
||||||
|
|
||||||
|
static int tegra_utc_poll_init(struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
|
||||||
|
|
||||||
|
tegra_utc_hw_init(tup);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_utc_get_poll_char(struct uart_port *port)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
|
||||||
|
|
||||||
|
if (tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_EMPTY)
|
||||||
|
return NO_POLL_CHAR;
|
||||||
|
|
||||||
|
return tegra_utc_rx_readl(tup, TEGRA_UTC_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_put_poll_char(struct uart_port *port, unsigned char ch)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL),
|
||||||
|
0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS);
|
||||||
|
|
||||||
|
tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct uart_ops tegra_utc_uart_ops = {
|
||||||
|
.tx_empty = tegra_utc_tx_empty,
|
||||||
|
.set_mctrl = tegra_utc_set_mctrl,
|
||||||
|
.get_mctrl = tegra_utc_get_mctrl,
|
||||||
|
.stop_tx = tegra_utc_stop_tx,
|
||||||
|
.start_tx = tegra_utc_start_tx,
|
||||||
|
.stop_rx = tegra_utc_stop_rx,
|
||||||
|
.startup = tegra_utc_startup,
|
||||||
|
.shutdown = tegra_utc_shutdown,
|
||||||
|
.set_termios = tegra_utc_set_termios,
|
||||||
|
#ifdef CONFIG_CONSOLE_POLL
|
||||||
|
.poll_init = tegra_utc_poll_init,
|
||||||
|
.poll_get_char = tegra_utc_get_poll_char,
|
||||||
|
.poll_put_char = tegra_utc_put_poll_char,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
|
||||||
|
#define TEGRA_UTC_DEFAULT_FIFO_THRESHOLD 4
|
||||||
|
#define TEGRA_UTC_EARLYCON_MAX_BURST_SIZE 128
|
||||||
|
|
||||||
|
static void tegra_utc_putc(struct uart_port *port, unsigned char c)
|
||||||
|
{
|
||||||
|
writel(c, port->membase + TEGRA_UTC_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_early_write(struct console *con, const char *s, unsigned int n)
|
||||||
|
{
|
||||||
|
struct earlycon_device *dev = con->data;
|
||||||
|
|
||||||
|
while (n) {
|
||||||
|
u32 burst_size = TEGRA_UTC_EARLYCON_MAX_BURST_SIZE;
|
||||||
|
|
||||||
|
burst_size -= readl(dev->port.membase + TEGRA_UTC_FIFO_OCCUPANCY);
|
||||||
|
if (n < burst_size)
|
||||||
|
burst_size = n;
|
||||||
|
|
||||||
|
uart_console_write(&dev->port, s, burst_size, tegra_utc_putc);
|
||||||
|
|
||||||
|
n -= burst_size;
|
||||||
|
s += burst_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init tegra_utc_early_console_setup(struct earlycon_device *device, const char *opt)
|
||||||
|
{
|
||||||
|
if (!device->port.membase)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
/* Configure TX */
|
||||||
|
writel(TEGRA_UTC_COMMAND_FLUSH | TEGRA_UTC_COMMAND_RESET,
|
||||||
|
device->port.membase + TEGRA_UTC_COMMAND);
|
||||||
|
writel(TEGRA_UTC_DEFAULT_FIFO_THRESHOLD, device->port.membase + TEGRA_UTC_FIFO_THRESHOLD);
|
||||||
|
|
||||||
|
/* Clear and mask all the interrupts. */
|
||||||
|
writel(TEGRA_UTC_INTR_COMMON, device->port.membase + TEGRA_UTC_INTR_CLEAR);
|
||||||
|
|
||||||
|
writel(0x0, device->port.membase + TEGRA_UTC_INTR_MASK);
|
||||||
|
writel(0x0, device->port.membase + TEGRA_UTC_INTR_SET);
|
||||||
|
|
||||||
|
/* Enable TX. */
|
||||||
|
writel(TEGRA_UTC_ENABLE_CLIENT_ENABLE, device->port.membase + TEGRA_UTC_ENABLE);
|
||||||
|
|
||||||
|
device->con->write = tegra_utc_early_write;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
OF_EARLYCON_DECLARE(tegra_utc, "nvidia,tegra264-utc", tegra_utc_early_console_setup);
|
||||||
|
|
||||||
|
static void tegra_utc_console_putchar(struct uart_port *port, unsigned char ch)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
|
||||||
|
|
||||||
|
tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_console_write_atomic(struct console *cons, struct nbcon_write_context *wctxt)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
|
||||||
|
unsigned int len;
|
||||||
|
char *outbuf;
|
||||||
|
|
||||||
|
if (!nbcon_enter_unsafe(wctxt))
|
||||||
|
return;
|
||||||
|
|
||||||
|
outbuf = wctxt->outbuf;
|
||||||
|
len = wctxt->len;
|
||||||
|
|
||||||
|
while (len) {
|
||||||
|
u32 burst_size = tup->fifosize;
|
||||||
|
|
||||||
|
burst_size -= tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY);
|
||||||
|
if (len < burst_size)
|
||||||
|
burst_size = len;
|
||||||
|
|
||||||
|
uart_console_write(&tup->port, outbuf, burst_size, tegra_utc_console_putchar);
|
||||||
|
|
||||||
|
outbuf += burst_size;
|
||||||
|
len -= burst_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
nbcon_exit_unsafe(wctxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_console_write_thread(struct console *cons, struct nbcon_write_context *wctxt)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
|
||||||
|
unsigned int len = READ_ONCE(wctxt->len);
|
||||||
|
unsigned int i;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (!nbcon_enter_unsafe(wctxt))
|
||||||
|
break;
|
||||||
|
|
||||||
|
read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL),
|
||||||
|
0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS);
|
||||||
|
uart_console_write(&tup->port, wctxt->outbuf + i, 1, tegra_utc_console_putchar);
|
||||||
|
|
||||||
|
if (!nbcon_exit_unsafe(wctxt))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_console_device_lock(struct console *cons, unsigned long *flags)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
|
||||||
|
struct uart_port *port = &tup->port;
|
||||||
|
|
||||||
|
__uart_port_lock_irqsave(port, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_console_device_unlock(struct console *cons, unsigned long flags)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
|
||||||
|
struct uart_port *port = &tup->port;
|
||||||
|
|
||||||
|
__uart_port_unlock_irqrestore(port, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_utc_console_setup(struct console *cons, char *options)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
|
||||||
|
|
||||||
|
tegra_utc_init_tx(tup);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct uart_driver tegra_utc_driver = {
|
||||||
|
.driver_name = "tegra-utc",
|
||||||
|
.dev_name = "ttyUTC",
|
||||||
|
.nr = TEGRA_UTC_UART_NR,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tegra_utc_setup_port(struct device *dev, struct tegra_utc_port *tup)
|
||||||
|
{
|
||||||
|
tup->port.dev = dev;
|
||||||
|
tup->port.fifosize = tup->fifosize;
|
||||||
|
tup->port.flags = UPF_BOOT_AUTOCONF;
|
||||||
|
tup->port.iotype = UPIO_MEM;
|
||||||
|
tup->port.ops = &tegra_utc_uart_ops;
|
||||||
|
tup->port.type = PORT_TEGRA_TCU;
|
||||||
|
tup->port.private_data = tup;
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
|
||||||
|
strscpy(tup->console.name, "ttyUTC", sizeof(tup->console.name));
|
||||||
|
tup->console.write_atomic = tegra_utc_console_write_atomic;
|
||||||
|
tup->console.write_thread = tegra_utc_console_write_thread;
|
||||||
|
tup->console.device_lock = tegra_utc_console_device_lock;
|
||||||
|
tup->console.device_unlock = tegra_utc_console_device_unlock;
|
||||||
|
tup->console.device = uart_console_device;
|
||||||
|
tup->console.setup = tegra_utc_console_setup;
|
||||||
|
tup->console.flags = CON_PRINTBUFFER | CON_NBCON;
|
||||||
|
tup->console.data = &tegra_utc_driver;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return uart_read_port_properties(&tup->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_utc_register_port(struct tegra_utc_port *tup)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = uart_add_one_port(&tegra_utc_driver, &tup->port);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
|
||||||
|
register_console(&tup->console);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tegra_utc_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
const unsigned int *soc_fifosize;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct tegra_utc_port *tup;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
tup = devm_kzalloc(dev, sizeof(*tup), GFP_KERNEL);
|
||||||
|
if (!tup)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = device_property_read_u32(dev, "tx-threshold", &tup->tx_threshold);
|
||||||
|
if (ret)
|
||||||
|
return dev_err_probe(dev, ret, "missing %s property\n", "tx-threshold");
|
||||||
|
|
||||||
|
ret = device_property_read_u32(dev, "rx-threshold", &tup->rx_threshold);
|
||||||
|
if (ret)
|
||||||
|
return dev_err_probe(dev, ret, "missing %s property\n", "rx-threshold");
|
||||||
|
|
||||||
|
soc_fifosize = device_get_match_data(dev);
|
||||||
|
tup->fifosize = *soc_fifosize;
|
||||||
|
|
||||||
|
tup->tx_base = devm_platform_ioremap_resource_byname(pdev, "tx");
|
||||||
|
if (IS_ERR(tup->tx_base))
|
||||||
|
return PTR_ERR(tup->tx_base);
|
||||||
|
|
||||||
|
tup->rx_base = devm_platform_ioremap_resource_byname(pdev, "rx");
|
||||||
|
if (IS_ERR(tup->rx_base))
|
||||||
|
return PTR_ERR(tup->rx_base);
|
||||||
|
|
||||||
|
ret = tegra_utc_setup_port(dev, tup);
|
||||||
|
if (ret)
|
||||||
|
dev_err_probe(dev, ret, "failed to setup uart port\n");
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, tup);
|
||||||
|
|
||||||
|
return tegra_utc_register_port(tup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tegra_utc_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct tegra_utc_port *tup = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
|
||||||
|
unregister_console(&tup->console);
|
||||||
|
#endif
|
||||||
|
uart_remove_one_port(&tegra_utc_driver, &tup->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned int tegra264_utc_soc = 128;
|
||||||
|
|
||||||
|
static const struct of_device_id tegra_utc_of_match[] = {
|
||||||
|
{ .compatible = "nvidia,tegra264-utc", .data = &tegra264_utc_soc },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, tegra_utc_of_match);
|
||||||
|
|
||||||
|
static struct platform_driver tegra_utc_platform_driver = {
|
||||||
|
.probe = tegra_utc_probe,
|
||||||
|
.remove = tegra_utc_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "tegra-utc",
|
||||||
|
.of_match_table = tegra_utc_of_match,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init tegra_utc_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = uart_register_driver(&tegra_utc_driver);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = platform_driver_register(&tegra_utc_platform_driver);
|
||||||
|
if (ret)
|
||||||
|
uart_unregister_driver(&tegra_utc_driver);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
module_init(tegra_utc_init);
|
||||||
|
|
||||||
|
static void __exit tegra_utc_exit(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&tegra_utc_platform_driver);
|
||||||
|
uart_unregister_driver(&tegra_utc_driver);
|
||||||
|
}
|
||||||
|
module_exit(tegra_utc_exit);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Kartik Rajput <kkartik@nvidia.com>");
|
||||||
|
MODULE_DESCRIPTION("Tegra UART Trace Controller");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -12,12 +12,14 @@
|
||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
|
|
||||||
|
#define TTY_AUDIT_BUF_SIZE 4096
|
||||||
|
|
||||||
struct tty_audit_buf {
|
struct tty_audit_buf {
|
||||||
struct mutex mutex; /* Protects all data below */
|
struct mutex mutex; /* Protects all data below */
|
||||||
dev_t dev; /* The TTY which the data is from */
|
dev_t dev; /* The TTY which the data is from */
|
||||||
bool icanon;
|
bool icanon;
|
||||||
size_t valid;
|
size_t valid;
|
||||||
u8 *data; /* Allocated size N_TTY_BUF_SIZE */
|
u8 *data; /* Allocated size TTY_AUDIT_BUF_SIZE */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct tty_audit_buf *tty_audit_buf_ref(void)
|
static struct tty_audit_buf *tty_audit_buf_ref(void)
|
||||||
|
@ -37,7 +39,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(void)
|
||||||
if (!buf)
|
if (!buf)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
|
buf->data = kmalloc(TTY_AUDIT_BUF_SIZE, GFP_KERNEL);
|
||||||
if (!buf->data)
|
if (!buf->data)
|
||||||
goto err_buf;
|
goto err_buf;
|
||||||
|
|
||||||
|
@ -235,14 +237,14 @@ void tty_audit_add_data(const struct tty_struct *tty, const void *data,
|
||||||
do {
|
do {
|
||||||
size_t run;
|
size_t run;
|
||||||
|
|
||||||
run = N_TTY_BUF_SIZE - buf->valid;
|
run = TTY_AUDIT_BUF_SIZE - buf->valid;
|
||||||
if (run > size)
|
if (run > size)
|
||||||
run = size;
|
run = size;
|
||||||
memcpy(buf->data + buf->valid, data, run);
|
memcpy(buf->data + buf->valid, data, run);
|
||||||
buf->valid += run;
|
buf->valid += run;
|
||||||
data += run;
|
data += run;
|
||||||
size -= run;
|
size -= run;
|
||||||
if (buf->valid == N_TTY_BUF_SIZE)
|
if (buf->valid == TTY_AUDIT_BUF_SIZE)
|
||||||
tty_audit_buf_push(buf);
|
tty_audit_buf_push(buf);
|
||||||
} while (size != 0);
|
} while (size != 0);
|
||||||
mutex_unlock(&buf->mutex);
|
mutex_unlock(&buf->mutex);
|
||||||
|
|
|
@ -3329,10 +3329,12 @@ EXPORT_SYMBOL(tty_unregister_device);
|
||||||
* __tty_alloc_driver - allocate tty driver
|
* __tty_alloc_driver - allocate tty driver
|
||||||
* @lines: count of lines this driver can handle at most
|
* @lines: count of lines this driver can handle at most
|
||||||
* @owner: module which is responsible for this driver
|
* @owner: module which is responsible for this driver
|
||||||
* @flags: some of %TTY_DRIVER_ flags, will be set in driver->flags
|
* @flags: some of enum tty_driver_flag, will be set in driver->flags
|
||||||
*
|
*
|
||||||
* This should not be called directly, some of the provided macros should be
|
* This should not be called directly, tty_alloc_driver() should be used
|
||||||
* used instead. Use IS_ERR() and friends on @retval.
|
* instead.
|
||||||
|
*
|
||||||
|
* Returns: struct tty_driver or a PTR-encoded error (use IS_ERR() and friends).
|
||||||
*/
|
*/
|
||||||
struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
|
struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
|
||||||
unsigned long flags)
|
unsigned long flags)
|
||||||
|
|
|
@ -366,23 +366,6 @@ int __sched ldsem_down_write(struct ld_semaphore *sem, long timeout)
|
||||||
return __ldsem_down_write_nested(sem, 0, timeout);
|
return __ldsem_down_write_nested(sem, 0, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* trylock for writing -- returns 1 if successful, 0 if contention
|
|
||||||
*/
|
|
||||||
int ldsem_down_write_trylock(struct ld_semaphore *sem)
|
|
||||||
{
|
|
||||||
long count = atomic_long_read(&sem->count);
|
|
||||||
|
|
||||||
while ((count & LDSEM_ACTIVE_MASK) == 0) {
|
|
||||||
if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_WRITE_BIAS)) {
|
|
||||||
rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
|
|
||||||
lock_acquired(&sem->dep_map, _RET_IP_);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* release a read lock
|
* release a read lock
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -257,7 +257,6 @@ extern void kgdb_arch_late(void);
|
||||||
* hardware breakpoints.
|
* hardware breakpoints.
|
||||||
* @correct_hw_break: Allow an architecture to specify how to correct the
|
* @correct_hw_break: Allow an architecture to specify how to correct the
|
||||||
* hardware debug registers.
|
* hardware debug registers.
|
||||||
* @enable_nmi: Manage NMI-triggered entry to KGDB
|
|
||||||
*/
|
*/
|
||||||
struct kgdb_arch {
|
struct kgdb_arch {
|
||||||
unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE];
|
unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE];
|
||||||
|
@ -270,8 +269,6 @@ struct kgdb_arch {
|
||||||
void (*disable_hw_break)(struct pt_regs *regs);
|
void (*disable_hw_break)(struct pt_regs *regs);
|
||||||
void (*remove_all_hw_break)(void);
|
void (*remove_all_hw_break)(void);
|
||||||
void (*correct_hw_break)(void);
|
void (*correct_hw_break)(void);
|
||||||
|
|
||||||
void (*enable_nmi)(bool on);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -306,14 +303,6 @@ extern const struct kgdb_arch arch_kgdb_ops;
|
||||||
|
|
||||||
extern unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs);
|
extern unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs);
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_KGDB_NMI
|
|
||||||
extern int kgdb_register_nmi_console(void);
|
|
||||||
extern int kgdb_unregister_nmi_console(void);
|
|
||||||
#else
|
|
||||||
static inline int kgdb_register_nmi_console(void) { return 0; }
|
|
||||||
static inline int kgdb_unregister_nmi_console(void) { return 0; }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
|
extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
|
||||||
extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
|
extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
|
||||||
extern struct kgdb_io *dbg_io_ops;
|
extern struct kgdb_io *dbg_io_ops;
|
||||||
|
|
|
@ -84,7 +84,6 @@ enum serdev_parity {
|
||||||
struct serdev_controller_ops {
|
struct serdev_controller_ops {
|
||||||
ssize_t (*write_buf)(struct serdev_controller *, const u8 *, size_t);
|
ssize_t (*write_buf)(struct serdev_controller *, const u8 *, size_t);
|
||||||
void (*write_flush)(struct serdev_controller *);
|
void (*write_flush)(struct serdev_controller *);
|
||||||
int (*write_room)(struct serdev_controller *);
|
|
||||||
int (*open)(struct serdev_controller *);
|
int (*open)(struct serdev_controller *);
|
||||||
void (*close)(struct serdev_controller *);
|
void (*close)(struct serdev_controller *);
|
||||||
void (*set_flow_control)(struct serdev_controller *, bool);
|
void (*set_flow_control)(struct serdev_controller *, bool);
|
||||||
|
@ -212,7 +211,6 @@ int serdev_device_break_ctl(struct serdev_device *serdev, int break_state);
|
||||||
void serdev_device_write_wakeup(struct serdev_device *);
|
void serdev_device_write_wakeup(struct serdev_device *);
|
||||||
ssize_t serdev_device_write(struct serdev_device *, const u8 *, size_t, long);
|
ssize_t serdev_device_write(struct serdev_device *, const u8 *, size_t, long);
|
||||||
void serdev_device_write_flush(struct serdev_device *);
|
void serdev_device_write_flush(struct serdev_device *);
|
||||||
int serdev_device_write_room(struct serdev_device *);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* serdev device driver functions
|
* serdev device driver functions
|
||||||
|
@ -273,10 +271,6 @@ static inline ssize_t serdev_device_write(struct serdev_device *sdev,
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
static inline void serdev_device_write_flush(struct serdev_device *sdev) {}
|
static inline void serdev_device_write_flush(struct serdev_device *sdev) {}
|
||||||
static inline int serdev_device_write_room(struct serdev_device *sdev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define serdev_device_driver_register(x)
|
#define serdev_device_driver_register(x)
|
||||||
#define serdev_device_driver_unregister(x)
|
#define serdev_device_driver_unregister(x)
|
||||||
|
|
|
@ -239,7 +239,6 @@ struct tty_struct {
|
||||||
|
|
||||||
struct list_head tty_files;
|
struct list_head tty_files;
|
||||||
|
|
||||||
#define N_TTY_BUF_SIZE 4096
|
|
||||||
struct work_struct SAK_work;
|
struct work_struct SAK_work;
|
||||||
} __randomize_layout;
|
} __randomize_layout;
|
||||||
|
|
||||||
|
@ -251,7 +250,7 @@ struct tty_file_private {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DOC: TTY Struct Flags
|
* enum tty_struct_flags - TTY Struct Flags
|
||||||
*
|
*
|
||||||
* These bits are used in the :c:member:`tty_struct.flags` field.
|
* These bits are used in the :c:member:`tty_struct.flags` field.
|
||||||
*
|
*
|
||||||
|
@ -260,62 +259,64 @@ struct tty_file_private {
|
||||||
* tty->write. Thus, you must use the inline functions set_bit() and
|
* tty->write. Thus, you must use the inline functions set_bit() and
|
||||||
* clear_bit() to make things atomic.
|
* clear_bit() to make things atomic.
|
||||||
*
|
*
|
||||||
* TTY_THROTTLED
|
* @TTY_THROTTLED:
|
||||||
* Driver input is throttled. The ldisc should call
|
* Driver input is throttled. The ldisc should call
|
||||||
* :c:member:`tty_driver.unthrottle()` in order to resume reception when
|
* :c:member:`tty_driver.unthrottle()` in order to resume reception when
|
||||||
* it is ready to process more data (at threshold min).
|
* it is ready to process more data (at threshold min).
|
||||||
*
|
*
|
||||||
* TTY_IO_ERROR
|
* @TTY_IO_ERROR:
|
||||||
* If set, causes all subsequent userspace read/write calls on the tty to
|
* If set, causes all subsequent userspace read/write calls on the tty to
|
||||||
* fail, returning -%EIO. (May be no ldisc too.)
|
* fail, returning -%EIO. (May be no ldisc too.)
|
||||||
*
|
*
|
||||||
* TTY_OTHER_CLOSED
|
* @TTY_OTHER_CLOSED:
|
||||||
* Device is a pty and the other side has closed.
|
* Device is a pty and the other side has closed.
|
||||||
*
|
*
|
||||||
* TTY_EXCLUSIVE
|
* @TTY_EXCLUSIVE:
|
||||||
* Exclusive open mode (a single opener).
|
* Exclusive open mode (a single opener).
|
||||||
*
|
*
|
||||||
* TTY_DO_WRITE_WAKEUP
|
* @TTY_DO_WRITE_WAKEUP:
|
||||||
* If set, causes the driver to call the
|
* If set, causes the driver to call the
|
||||||
* :c:member:`tty_ldisc_ops.write_wakeup()` method in order to resume
|
* :c:member:`tty_ldisc_ops.write_wakeup()` method in order to resume
|
||||||
* transmission when it can accept more data to transmit.
|
* transmission when it can accept more data to transmit.
|
||||||
*
|
*
|
||||||
* TTY_LDISC_OPEN
|
* @TTY_LDISC_OPEN:
|
||||||
* Indicates that a line discipline is open. For debugging purposes only.
|
* Indicates that a line discipline is open. For debugging purposes only.
|
||||||
*
|
*
|
||||||
* TTY_PTY_LOCK
|
* @TTY_PTY_LOCK:
|
||||||
* A flag private to pty code to implement %TIOCSPTLCK/%TIOCGPTLCK logic.
|
* A flag private to pty code to implement %TIOCSPTLCK/%TIOCGPTLCK logic.
|
||||||
*
|
*
|
||||||
* TTY_NO_WRITE_SPLIT
|
* @TTY_NO_WRITE_SPLIT:
|
||||||
* Prevent driver from splitting up writes into smaller chunks (preserve
|
* Prevent driver from splitting up writes into smaller chunks (preserve
|
||||||
* write boundaries to driver).
|
* write boundaries to driver).
|
||||||
*
|
*
|
||||||
* TTY_HUPPED
|
* @TTY_HUPPED:
|
||||||
* The TTY was hung up. This is set post :c:member:`tty_driver.hangup()`.
|
* The TTY was hung up. This is set post :c:member:`tty_driver.hangup()`.
|
||||||
*
|
*
|
||||||
* TTY_HUPPING
|
* @TTY_HUPPING:
|
||||||
* The TTY is in the process of hanging up to abort potential readers.
|
* The TTY is in the process of hanging up to abort potential readers.
|
||||||
*
|
*
|
||||||
* TTY_LDISC_CHANGING
|
* @TTY_LDISC_CHANGING:
|
||||||
* Line discipline for this TTY is being changed. I/O should not block
|
* Line discipline for this TTY is being changed. I/O should not block
|
||||||
* when this is set. Use tty_io_nonblock() to check.
|
* when this is set. Use tty_io_nonblock() to check.
|
||||||
*
|
*
|
||||||
* TTY_LDISC_HALTED
|
* @TTY_LDISC_HALTED:
|
||||||
* Line discipline for this TTY was stopped. No work should be queued to
|
* Line discipline for this TTY was stopped. No work should be queued to
|
||||||
* this ldisc.
|
* this ldisc.
|
||||||
*/
|
*/
|
||||||
#define TTY_THROTTLED 0
|
enum tty_struct_flags {
|
||||||
#define TTY_IO_ERROR 1
|
TTY_THROTTLED,
|
||||||
#define TTY_OTHER_CLOSED 2
|
TTY_IO_ERROR,
|
||||||
#define TTY_EXCLUSIVE 3
|
TTY_OTHER_CLOSED,
|
||||||
#define TTY_DO_WRITE_WAKEUP 5
|
TTY_EXCLUSIVE,
|
||||||
#define TTY_LDISC_OPEN 11
|
TTY_DO_WRITE_WAKEUP,
|
||||||
#define TTY_PTY_LOCK 16
|
TTY_LDISC_OPEN,
|
||||||
#define TTY_NO_WRITE_SPLIT 17
|
TTY_PTY_LOCK,
|
||||||
#define TTY_HUPPED 18
|
TTY_NO_WRITE_SPLIT,
|
||||||
#define TTY_HUPPING 19
|
TTY_HUPPED,
|
||||||
#define TTY_LDISC_CHANGING 20
|
TTY_HUPPING,
|
||||||
#define TTY_LDISC_HALTED 22
|
TTY_LDISC_CHANGING,
|
||||||
|
TTY_LDISC_HALTED,
|
||||||
|
};
|
||||||
|
|
||||||
static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file)
|
static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,92 @@ struct tty_driver;
|
||||||
struct serial_icounter_struct;
|
struct serial_icounter_struct;
|
||||||
struct serial_struct;
|
struct serial_struct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum tty_driver_flag -- TTY Driver Flags
|
||||||
|
*
|
||||||
|
* These are flags passed to tty_alloc_driver().
|
||||||
|
*
|
||||||
|
* @TTY_DRIVER_INSTALLED:
|
||||||
|
* Whether this driver was succesfully installed. This is a tty internal
|
||||||
|
* flag. Do not touch.
|
||||||
|
*
|
||||||
|
* @TTY_DRIVER_RESET_TERMIOS:
|
||||||
|
* Requests the tty layer to reset the termios setting when the last
|
||||||
|
* process has closed the device. Used for PTYs, in particular.
|
||||||
|
*
|
||||||
|
* @TTY_DRIVER_REAL_RAW:
|
||||||
|
* Indicates that the driver will guarantee not to set any special
|
||||||
|
* character handling flags if this is set for the tty:
|
||||||
|
*
|
||||||
|
* ``(IGNBRK || (!BRKINT && !PARMRK)) && (IGNPAR || !INPCK)``
|
||||||
|
*
|
||||||
|
* That is, if there is no reason for the driver to
|
||||||
|
* send notifications of parity and break characters up to the line
|
||||||
|
* driver, it won't do so. This allows the line driver to optimize for
|
||||||
|
* this case if this flag is set. (Note that there is also a promise, if
|
||||||
|
* the above case is true, not to signal overruns, either.)
|
||||||
|
*
|
||||||
|
* @TTY_DRIVER_DYNAMIC_DEV:
|
||||||
|
* The individual tty devices need to be registered with a call to
|
||||||
|
* tty_register_device() when the device is found in the system and
|
||||||
|
* unregistered with a call to tty_unregister_device() so the devices will
|
||||||
|
* be show up properly in sysfs. If not set, all &tty_driver.num entries
|
||||||
|
* will be created by the tty core in sysfs when tty_register_driver() is
|
||||||
|
* called. This is to be used by drivers that have tty devices that can
|
||||||
|
* appear and disappear while the main tty driver is registered with the
|
||||||
|
* tty core.
|
||||||
|
*
|
||||||
|
* @TTY_DRIVER_DEVPTS_MEM:
|
||||||
|
* Don't use the standard arrays (&tty_driver.ttys and
|
||||||
|
* &tty_driver.termios), instead use dynamic memory keyed through the
|
||||||
|
* devpts filesystem. This is only applicable to the PTY driver.
|
||||||
|
*
|
||||||
|
* @TTY_DRIVER_HARDWARE_BREAK:
|
||||||
|
* Hardware handles break signals. Pass the requested timeout to the
|
||||||
|
* &tty_operations.break_ctl instead of using a simple on/off interface.
|
||||||
|
*
|
||||||
|
* @TTY_DRIVER_DYNAMIC_ALLOC:
|
||||||
|
* Do not allocate structures which are needed per line for this driver
|
||||||
|
* (&tty_driver.ports) as it would waste memory. The driver will take
|
||||||
|
* care. This is only applicable to the PTY driver.
|
||||||
|
*
|
||||||
|
* @TTY_DRIVER_UNNUMBERED_NODE:
|
||||||
|
* Do not create numbered ``/dev`` nodes. For example, create
|
||||||
|
* ``/dev/ttyprintk`` and not ``/dev/ttyprintk0``. Applicable only when a
|
||||||
|
* driver for a single tty device is being allocated.
|
||||||
|
*/
|
||||||
|
enum tty_driver_flag {
|
||||||
|
TTY_DRIVER_INSTALLED = BIT(0),
|
||||||
|
TTY_DRIVER_RESET_TERMIOS = BIT(1),
|
||||||
|
TTY_DRIVER_REAL_RAW = BIT(2),
|
||||||
|
TTY_DRIVER_DYNAMIC_DEV = BIT(3),
|
||||||
|
TTY_DRIVER_DEVPTS_MEM = BIT(4),
|
||||||
|
TTY_DRIVER_HARDWARE_BREAK = BIT(5),
|
||||||
|
TTY_DRIVER_DYNAMIC_ALLOC = BIT(6),
|
||||||
|
TTY_DRIVER_UNNUMBERED_NODE = BIT(7),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tty_driver_type {
|
||||||
|
TTY_DRIVER_TYPE_SYSTEM,
|
||||||
|
TTY_DRIVER_TYPE_CONSOLE,
|
||||||
|
TTY_DRIVER_TYPE_SERIAL,
|
||||||
|
TTY_DRIVER_TYPE_PTY,
|
||||||
|
TTY_DRIVER_TYPE_SCC,
|
||||||
|
TTY_DRIVER_TYPE_SYSCONS,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tty_driver_subtype {
|
||||||
|
SYSTEM_TYPE_TTY = 1,
|
||||||
|
SYSTEM_TYPE_CONSOLE,
|
||||||
|
SYSTEM_TYPE_SYSCONS,
|
||||||
|
SYSTEM_TYPE_SYSPTMX,
|
||||||
|
|
||||||
|
PTY_TYPE_MASTER = 1,
|
||||||
|
PTY_TYPE_SLAVE,
|
||||||
|
|
||||||
|
SERIAL_TYPE_NORMAL = 1,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct tty_operations -- interface between driver and tty
|
* struct tty_operations -- interface between driver and tty
|
||||||
*
|
*
|
||||||
|
@ -414,8 +500,8 @@ struct tty_operations {
|
||||||
* @major: major /dev device number (zero for autoassignment)
|
* @major: major /dev device number (zero for autoassignment)
|
||||||
* @minor_start: the first minor /dev device number
|
* @minor_start: the first minor /dev device number
|
||||||
* @num: number of devices allocated
|
* @num: number of devices allocated
|
||||||
* @type: type of tty driver (%TTY_DRIVER_TYPE_)
|
* @type: type of tty driver (enum tty_driver_type)
|
||||||
* @subtype: subtype of tty driver (%SYSTEM_TYPE_, %PTY_TYPE_, %SERIAL_TYPE_)
|
* @subtype: subtype of tty driver (enum tty_driver_subtype)
|
||||||
* @init_termios: termios to set to each tty initially (e.g. %tty_std_termios)
|
* @init_termios: termios to set to each tty initially (e.g. %tty_std_termios)
|
||||||
* @flags: tty driver flags (%TTY_DRIVER_)
|
* @flags: tty driver flags (%TTY_DRIVER_)
|
||||||
* @proc_entry: proc fs entry, used internally
|
* @proc_entry: proc fs entry, used internally
|
||||||
|
@ -447,8 +533,8 @@ struct tty_driver {
|
||||||
int major;
|
int major;
|
||||||
int minor_start;
|
int minor_start;
|
||||||
unsigned int num;
|
unsigned int num;
|
||||||
short type;
|
enum tty_driver_type type;
|
||||||
short subtype;
|
enum tty_driver_subtype subtype;
|
||||||
struct ktermios init_termios;
|
struct ktermios init_termios;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct proc_dir_entry *proc_entry;
|
struct proc_dir_entry *proc_entry;
|
||||||
|
@ -478,7 +564,13 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line);
|
||||||
|
|
||||||
void tty_driver_kref_put(struct tty_driver *driver);
|
void tty_driver_kref_put(struct tty_driver *driver);
|
||||||
|
|
||||||
/* Use TTY_DRIVER_* flags below */
|
/**
|
||||||
|
* tty_alloc_driver - allocate tty driver
|
||||||
|
* @lines: count of lines this driver can handle at most
|
||||||
|
* @flags: some of enum tty_driver_flag, will be set in driver->flags
|
||||||
|
*
|
||||||
|
* Returns: struct tty_driver or a PTR-encoded error (use IS_ERR() and friends).
|
||||||
|
*/
|
||||||
#define tty_alloc_driver(lines, flags) \
|
#define tty_alloc_driver(lines, flags) \
|
||||||
__tty_alloc_driver(lines, THIS_MODULE, flags)
|
__tty_alloc_driver(lines, THIS_MODULE, flags)
|
||||||
|
|
||||||
|
@ -494,84 +586,6 @@ static inline void tty_set_operations(struct tty_driver *driver,
|
||||||
driver->ops = op;
|
driver->ops = op;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* DOC: TTY Driver Flags
|
|
||||||
*
|
|
||||||
* TTY_DRIVER_RESET_TERMIOS
|
|
||||||
* Requests the tty layer to reset the termios setting when the last
|
|
||||||
* process has closed the device. Used for PTYs, in particular.
|
|
||||||
*
|
|
||||||
* TTY_DRIVER_REAL_RAW
|
|
||||||
* Indicates that the driver will guarantee not to set any special
|
|
||||||
* character handling flags if this is set for the tty:
|
|
||||||
*
|
|
||||||
* ``(IGNBRK || (!BRKINT && !PARMRK)) && (IGNPAR || !INPCK)``
|
|
||||||
*
|
|
||||||
* That is, if there is no reason for the driver to
|
|
||||||
* send notifications of parity and break characters up to the line
|
|
||||||
* driver, it won't do so. This allows the line driver to optimize for
|
|
||||||
* this case if this flag is set. (Note that there is also a promise, if
|
|
||||||
* the above case is true, not to signal overruns, either.)
|
|
||||||
*
|
|
||||||
* TTY_DRIVER_DYNAMIC_DEV
|
|
||||||
* The individual tty devices need to be registered with a call to
|
|
||||||
* tty_register_device() when the device is found in the system and
|
|
||||||
* unregistered with a call to tty_unregister_device() so the devices will
|
|
||||||
* be show up properly in sysfs. If not set, all &tty_driver.num entries
|
|
||||||
* will be created by the tty core in sysfs when tty_register_driver() is
|
|
||||||
* called. This is to be used by drivers that have tty devices that can
|
|
||||||
* appear and disappear while the main tty driver is registered with the
|
|
||||||
* tty core.
|
|
||||||
*
|
|
||||||
* TTY_DRIVER_DEVPTS_MEM
|
|
||||||
* Don't use the standard arrays (&tty_driver.ttys and
|
|
||||||
* &tty_driver.termios), instead use dynamic memory keyed through the
|
|
||||||
* devpts filesystem. This is only applicable to the PTY driver.
|
|
||||||
*
|
|
||||||
* TTY_DRIVER_HARDWARE_BREAK
|
|
||||||
* Hardware handles break signals. Pass the requested timeout to the
|
|
||||||
* &tty_operations.break_ctl instead of using a simple on/off interface.
|
|
||||||
*
|
|
||||||
* TTY_DRIVER_DYNAMIC_ALLOC
|
|
||||||
* Do not allocate structures which are needed per line for this driver
|
|
||||||
* (&tty_driver.ports) as it would waste memory. The driver will take
|
|
||||||
* care. This is only applicable to the PTY driver.
|
|
||||||
*
|
|
||||||
* TTY_DRIVER_UNNUMBERED_NODE
|
|
||||||
* Do not create numbered ``/dev`` nodes. For example, create
|
|
||||||
* ``/dev/ttyprintk`` and not ``/dev/ttyprintk0``. Applicable only when a
|
|
||||||
* driver for a single tty device is being allocated.
|
|
||||||
*/
|
|
||||||
#define TTY_DRIVER_INSTALLED 0x0001
|
|
||||||
#define TTY_DRIVER_RESET_TERMIOS 0x0002
|
|
||||||
#define TTY_DRIVER_REAL_RAW 0x0004
|
|
||||||
#define TTY_DRIVER_DYNAMIC_DEV 0x0008
|
|
||||||
#define TTY_DRIVER_DEVPTS_MEM 0x0010
|
|
||||||
#define TTY_DRIVER_HARDWARE_BREAK 0x0020
|
|
||||||
#define TTY_DRIVER_DYNAMIC_ALLOC 0x0040
|
|
||||||
#define TTY_DRIVER_UNNUMBERED_NODE 0x0080
|
|
||||||
|
|
||||||
/* tty driver types */
|
|
||||||
#define TTY_DRIVER_TYPE_SYSTEM 0x0001
|
|
||||||
#define TTY_DRIVER_TYPE_CONSOLE 0x0002
|
|
||||||
#define TTY_DRIVER_TYPE_SERIAL 0x0003
|
|
||||||
#define TTY_DRIVER_TYPE_PTY 0x0004
|
|
||||||
#define TTY_DRIVER_TYPE_SCC 0x0005 /* scc driver */
|
|
||||||
#define TTY_DRIVER_TYPE_SYSCONS 0x0006
|
|
||||||
|
|
||||||
/* system subtypes (magic, used by tty_io.c) */
|
|
||||||
#define SYSTEM_TYPE_TTY 0x0001
|
|
||||||
#define SYSTEM_TYPE_CONSOLE 0x0002
|
|
||||||
#define SYSTEM_TYPE_SYSCONS 0x0003
|
|
||||||
#define SYSTEM_TYPE_SYSPTMX 0x0004
|
|
||||||
|
|
||||||
/* pty subtypes (magic, used by tty_io.c) */
|
|
||||||
#define PTY_TYPE_MASTER 0x0001
|
|
||||||
#define PTY_TYPE_SLAVE 0x0002
|
|
||||||
|
|
||||||
/* serial subtype definitions */
|
|
||||||
#define SERIAL_TYPE_NORMAL 1
|
|
||||||
|
|
||||||
int tty_register_driver(struct tty_driver *driver);
|
int tty_register_driver(struct tty_driver *driver);
|
||||||
void tty_unregister_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 *tty_register_device(struct tty_driver *driver, unsigned index,
|
||||||
|
|
|
@ -39,7 +39,6 @@ do { \
|
||||||
int ldsem_down_read(struct ld_semaphore *sem, long timeout);
|
int ldsem_down_read(struct ld_semaphore *sem, long timeout);
|
||||||
int ldsem_down_read_trylock(struct ld_semaphore *sem);
|
int ldsem_down_read_trylock(struct ld_semaphore *sem);
|
||||||
int ldsem_down_write(struct ld_semaphore *sem, long timeout);
|
int ldsem_down_write(struct ld_semaphore *sem, long timeout);
|
||||||
int ldsem_down_write_trylock(struct ld_semaphore *sem);
|
|
||||||
void ldsem_up_read(struct ld_semaphore *sem);
|
void ldsem_up_read(struct ld_semaphore *sem);
|
||||||
void ldsem_up_write(struct ld_semaphore *sem);
|
void ldsem_up_write(struct ld_semaphore *sem);
|
||||||
|
|
||||||
|
|
|
@ -837,10 +837,6 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct kgdb_state kgdb_var;
|
struct kgdb_state kgdb_var;
|
||||||
struct kgdb_state *ks = &kgdb_var;
|
struct kgdb_state *ks = &kgdb_var;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
if (arch_kgdb_ops.enable_nmi)
|
|
||||||
arch_kgdb_ops.enable_nmi(0);
|
|
||||||
/*
|
/*
|
||||||
* Avoid entering the debugger if we were triggered due to an oops
|
* Avoid entering the debugger if we were triggered due to an oops
|
||||||
* but panic_timeout indicates the system should automatically
|
* but panic_timeout indicates the system should automatically
|
||||||
|
@ -858,15 +854,11 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
|
||||||
ks->linux_regs = regs;
|
ks->linux_regs = regs;
|
||||||
|
|
||||||
if (kgdb_reenter_check(ks))
|
if (kgdb_reenter_check(ks))
|
||||||
goto out; /* Ouch, double exception ! */
|
return 0; /* Ouch, double exception ! */
|
||||||
if (kgdb_info[ks->cpu].enter_kgdb != 0)
|
if (kgdb_info[ks->cpu].enter_kgdb != 0)
|
||||||
goto out;
|
return 0;
|
||||||
|
|
||||||
ret = kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
|
return kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
|
||||||
out:
|
|
||||||
if (arch_kgdb_ops.enable_nmi)
|
|
||||||
arch_kgdb_ops.enable_nmi(1);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(kgdb_handle_exception);
|
NOKPROBE_SYMBOL(kgdb_handle_exception);
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
#include <linux/utsname.h>
|
#include <linux/utsname.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
#include <linux/atomic.h>
|
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -2087,32 +2086,6 @@ static int kdb_dmesg(int argc, const char **argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PRINTK */
|
#endif /* CONFIG_PRINTK */
|
||||||
|
|
||||||
/* Make sure we balance enable/disable calls, must disable first. */
|
|
||||||
static atomic_t kdb_nmi_disabled;
|
|
||||||
|
|
||||||
static int kdb_disable_nmi(int argc, const char *argv[])
|
|
||||||
{
|
|
||||||
if (atomic_read(&kdb_nmi_disabled))
|
|
||||||
return 0;
|
|
||||||
atomic_set(&kdb_nmi_disabled, 1);
|
|
||||||
arch_kgdb_ops.enable_nmi(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int kdb_param_enable_nmi(const char *val, const struct kernel_param *kp)
|
|
||||||
{
|
|
||||||
if (!atomic_add_unless(&kdb_nmi_disabled, -1, 0))
|
|
||||||
return -EINVAL;
|
|
||||||
arch_kgdb_ops.enable_nmi(1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct kernel_param_ops kdb_param_ops_enable_nmi = {
|
|
||||||
.set = kdb_param_enable_nmi,
|
|
||||||
};
|
|
||||||
module_param_cb(enable_nmi, &kdb_param_ops_enable_nmi, NULL, 0600);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* kdb_cpu - This function implements the 'cpu' command.
|
* kdb_cpu - This function implements the 'cpu' command.
|
||||||
* cpu [<cpunum>]
|
* cpu [<cpunum>]
|
||||||
|
@ -2804,20 +2777,10 @@ static kdbtab_t maintab[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static kdbtab_t nmicmd = {
|
|
||||||
.name = "disable_nmi",
|
|
||||||
.func = kdb_disable_nmi,
|
|
||||||
.usage = "",
|
|
||||||
.help = "Disable NMI entry to KDB",
|
|
||||||
.flags = KDB_ENABLE_ALWAYS_SAFE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Initialize the kdb command table. */
|
/* Initialize the kdb command table. */
|
||||||
static void __init kdb_inittab(void)
|
static void __init kdb_inittab(void)
|
||||||
{
|
{
|
||||||
kdb_register_table(maintab, ARRAY_SIZE(maintab));
|
kdb_register_table(maintab, ARRAY_SIZE(maintab));
|
||||||
if (arch_kgdb_ops.enable_nmi)
|
|
||||||
kdb_register_table(&nmicmd, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Execute any commands defined in kdb_cmds. */
|
/* Execute any commands defined in kdb_cmds. */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user