diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-12 11:21:52 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-12 11:21:52 -0800 |
commit | 342465f5337f7bd5b8bd3b6f939ac12b620cbb43 (patch) | |
tree | aa116708ffedd73d6f1311489265e7b98225315f | |
parent | 22ef12195e13c5ec58320dbf99ef85059a2c0820 (diff) | |
parent | 93a770b7e16772530196674ffc79bb13fa927dc6 (diff) |
Merge tag 'tty-5.17-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 tty/serial driver updates for 5.17-rc1.
Nothing major in here, just lots of good updates and fixes, including:
- more tty core cleanups from Jiri as well as mxser driver cleanups.
This is the majority of the core diffstat
- tty documentation updates from Jiri
- platform_get_irq() updates
- various serial driver updates for new features and hardware
- fifo usage for 8250 console, reducing cpu load a lot
- LED fix for keyboards, long-time bugfix that went through many
revisions
- minor cleanups
All have been in linux-next for a while with no reported problems"
* tag 'tty-5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (119 commits)
serial: core: Keep mctrl register state and cached copy in sync
serial: stm32: correct loop for dma error handling
serial: stm32: fix flow control transfer in DMA mode
serial: stm32: rework TX DMA state condition
serial: stm32: move tx dma terminate DMA to shutdown
serial: pl011: Drop redundant DTR/RTS preservation on close/open
serial: pl011: Drop CR register reset on set_termios
serial: pl010: Drop CR register reset on set_termios
serial: liteuart: fix MODULE_ALIAS
serial: 8250_bcm7271: Fix return error code in case of dma_alloc_coherent() failure
Revert "serdev: BREAK/FRAME/PARITY/OVERRUN notification prototype V2"
tty: goldfish: Use platform_get_irq() to get the interrupt
serdev: BREAK/FRAME/PARITY/OVERRUN notification prototype V2
tty: serial: meson: Drop the legacy compatible strings and clock code
serial: pmac_zilog: Use platform_get_irq() to get the interrupt
serial: bcm63xx: Use platform_get_irq() to get the interrupt
serial: ar933x: Use platform_get_irq() to get the interrupt
serial: vt8500: Use platform_get_irq() to get the interrupt
serial: altera_jtaguart: Use platform_get_irq_optional() to get the interrupt
serial: pxa: Use platform_get_irq() to get the interrupt
...
86 files changed, 3294 insertions, 2980 deletions
diff --git a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml index 7487aa6ef849..72e8868db3e0 100644 --- a/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml +++ b/Documentation/devicetree/bindings/serial/amlogic,meson-uart.yaml @@ -29,6 +29,7 @@ properties: - amlogic,meson8-uart - amlogic,meson8b-uart - amlogic,meson-gx-uart + - amlogic,meson-s4-uart - const: amlogic,meson-ao-uart - description: Everything-Else power domain UART controller enum: @@ -36,6 +37,7 @@ properties: - amlogic,meson8-uart - amlogic,meson8b-uart - amlogic,meson-gx-uart + - amlogic,meson-s4-uart reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml b/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml index a90c971b4f1f..6e04e3848261 100644 --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.yaml @@ -21,9 +21,15 @@ properties: - fsl,ls1028a-lpuart - fsl,imx7ulp-lpuart - fsl,imx8qm-lpuart + - fsl,imxrt1050-lpuart - items: - - const: fsl,imx8qxp-lpuart + - enum: + - fsl,imx8qxp-lpuart + - fsl,imx8ulp-lpuart - const: fsl,imx7ulp-lpuart + - items: + - const: fsl,imx8qm-lpuart + - const: fsl,imx8qxp-lpuart reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/serial/renesas,sci.yaml b/Documentation/devicetree/bindings/serial/renesas,sci.yaml index 22ed2f0b1dc3..8dda4e10e09d 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,sci.yaml @@ -14,7 +14,15 @@ allOf: properties: compatible: - const: renesas,sci + oneOf: + - items: + - enum: + - renesas,r9a07g044-sci # RZ/G2{L,LC} + - renesas,r9a07g054-sci # RZ/V2L + - const: renesas,sci # generic SCI compatible UART + + - items: + - const: renesas,sci # generic SCI compatible UART reg: maxItems: 1 @@ -54,18 +62,46 @@ required: - clocks - clock-names +if: + properties: + compatible: + contains: + enum: + - renesas,r9a07g044-sci + - renesas,r9a07g054-sci +then: + properties: + resets: + maxItems: 1 + + power-domains: + maxItems: 1 + + required: + - resets + - power-domains + unevaluatedProperties: false examples: - | + #include <dt-bindings/clock/r9a07g044-cpg.h> + #include <dt-bindings/interrupt-controller/arm-gic.h> + aliases { serial0 = &sci0; }; - sci0: serial@ffff78 { - compatible = "renesas,sci"; - reg = <0xffff78 8>; - interrupts = <88 0>, <89 0>, <90 0>, <91 0>; - clocks = <&fclk>; + sci0: serial@1004d000 { + compatible = "renesas,r9a07g044-sci", "renesas,sci"; + reg = <0x1004d000 0x400>; + interrupts = <GIC_SPI 405 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 406 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 407 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 408 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "eri", "rxi", "txi", "tei"; + clocks = <&cpg CPG_MOD R9A07G044_SCI0_CLKP>; clock-names = "fck"; + power-domains = <&cpg>; + resets = <&cpg R9A07G044_SCI0_RST>; }; diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml index 6b8731f7f2fb..ba5d3e0acc63 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml @@ -66,7 +66,19 @@ properties: - items: - enum: + - renesas,scif-r8a779f0 # R-Car S4-8 + - const: renesas,rcar-gen4-scif # R-Car Gen4 + - const: renesas,scif # generic SCIF compatible UART + + - items: + - enum: - renesas,scif-r9a07g044 # RZ/G2{L,LC} + - renesas,scif-r9a07g054 # RZ/V2L + + - items: + - enum: + - renesas,scif-r9a07g054 # RZ/V2L + - const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback for RZ/V2L reg: maxItems: 1 @@ -153,6 +165,9 @@ if: enum: - renesas,rcar-gen2-scif - renesas,rcar-gen3-scif + - renesas,rcar-gen4-scif + - renesas,scif-r9a07g044 + - renesas,scif-r9a07g054 then: required: - resets diff --git a/Documentation/driver-api/serial/index.rst b/Documentation/driver-api/serial/index.rst index 8f7d7af3b90b..7eb21a695fc3 100644 --- a/Documentation/driver-api/serial/index.rst +++ b/Documentation/driver-api/serial/index.rst @@ -9,7 +9,6 @@ Support for Serial devices driver - tty Serial drivers ============== diff --git a/Documentation/driver-api/serial/n_gsm.rst b/Documentation/driver-api/serial/n_gsm.rst index 8fe723ab9c67..49956509ad73 100644 --- a/Documentation/driver-api/serial/n_gsm.rst +++ b/Documentation/driver-api/serial/n_gsm.rst @@ -18,9 +18,12 @@ How to use it 1.1 initialize the modem in 0710 mux mode (usually AT+CMUX= command) through its serial port. Depending on the modem used, you can pass more or less parameters to this command. + 1.2 switch the serial line to using the n_gsm line discipline by using TIOCSETD ioctl. + 1.3 configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl. + 1.4 obtain base gsmtty number for the used serial port. Major parts of the initialization program : @@ -95,10 +98,13 @@ Major parts of the initialization program : 2.1 receive string "AT+CMUX= command" through its serial port,initialize mux mode config + 2.2 switch the serial line to using the n_gsm line discipline by using TIOCSETD ioctl. + 2.3 configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl. -2.4 obtain base gsmtty number for the used serial port, + +2.4 obtain base gsmtty number for the used serial port:: #include <stdio.h> #include <stdint.h> diff --git a/Documentation/driver-api/serial/tty.rst b/Documentation/driver-api/serial/tty.rst deleted file mode 100644 index 4b709f392713..000000000000 --- a/Documentation/driver-api/serial/tty.rst +++ /dev/null @@ -1,328 +0,0 @@ -================= -The Lockronomicon -================= - -Your guide to the ancient and twisted locking policies of the tty layer and -the warped logic behind them. Beware all ye who read on. - - -Line Discipline ---------------- - -Line disciplines are registered with tty_register_ldisc() passing the -discipline number and the ldisc structure. At the point of registration the -discipline must be ready to use and it is possible it will get used before -the call returns success. If the call returns an error then it won't get -called. Do not re-use ldisc numbers as they are part of the userspace ABI -and writing over an existing ldisc will cause demons to eat your computer. -After the return the ldisc data has been copied so you may free your own -copy of the structure. You must not re-register over the top of the line -discipline even with the same data or your computer again will be eaten by -demons. - -In order to remove a line discipline call tty_unregister_ldisc(). -In ancient times this always worked. In modern times the function will -return -EBUSY if the ldisc is currently in use. Since the ldisc referencing -code manages the module counts this should not usually be a concern. - -Heed this warning: the reference count field of the registered copies of the -tty_ldisc structure in the ldisc table counts the number of lines using this -discipline. The reference count of the tty_ldisc structure within a tty -counts the number of active users of the ldisc at this instant. In effect it -counts the number of threads of execution within an ldisc method (plus those -about to enter and exit although this detail matters not). - -Line Discipline Methods ------------------------ - -TTY side interfaces -^^^^^^^^^^^^^^^^^^^ - -======================= ======================================================= -open() Called when the line discipline is attached to - the terminal. No other call into the line - discipline for this tty will occur until it - completes successfully. Should initialize any - state needed by the ldisc, and set receive_room - in the tty_struct to the maximum amount of data - the line discipline is willing to accept from the - driver with a single call to receive_buf(). - Returning an error will prevent the ldisc from - being attached. Can sleep. - -close() This is called on a terminal when the line - discipline is being unplugged. At the point of - execution no further users will enter the - ldisc code for this tty. Can sleep. - -hangup() Called when the tty line is hung up. - The line discipline should cease I/O to the tty. - No further calls into the ldisc code will occur. - Can sleep. - -read() (optional) A process requests reading data from - the line. Multiple read calls may occur in parallel - and the ldisc must deal with serialization issues. - If not defined, the process will receive an EIO - error. May sleep. - -write() (optional) A process requests writing data to the - line. Multiple write calls are serialized by the - tty layer for the ldisc. If not defined, the - process will receive an EIO error. May sleep. - -flush_buffer() (optional) May be called at any point between - open and close, and instructs the line discipline - to empty its input buffer. - -set_termios() (optional) Called on termios structure changes. - The caller passes the old termios data and the - current data is in the tty. Called under the - termios semaphore so allowed to sleep. Serialized - against itself only. - -poll() (optional) Check the status for the poll/select - calls. Multiple poll calls may occur in parallel. - May sleep. - -ioctl() (optional) Called when an ioctl is handed to the - tty layer that might be for the ldisc. Multiple - ioctl calls may occur in parallel. May sleep. - -compat_ioctl() (optional) Called when a 32 bit ioctl is handed - to the tty layer that might be for the ldisc. - Multiple ioctl calls may occur in parallel. - May sleep. -======================= ======================================================= - -Driver Side Interfaces -^^^^^^^^^^^^^^^^^^^^^^ - -======================= ======================================================= -receive_buf() (optional) Called by the low-level driver to hand - a buffer of received bytes to the ldisc for - processing. The number of bytes is guaranteed not - to exceed the current value of tty->receive_room. - All bytes must be processed. - -receive_buf2() (optional) Called by the low-level driver to hand - a buffer of received bytes to the ldisc for - processing. Returns the number of bytes processed. - - If both receive_buf() and receive_buf2() are - defined, receive_buf2() should be preferred. - -write_wakeup() May be called at any point between open and close. - The TTY_DO_WRITE_WAKEUP flag indicates if a call - is needed but always races versus calls. Thus the - ldisc must be careful about setting order and to - handle unexpected calls. Must not sleep. - - The driver is forbidden from calling this directly - from the ->write call from the ldisc as the ldisc - is permitted to call the driver write method from - this function. In such a situation defer it. - -dcd_change() Report to the tty line the current DCD pin status - changes and the relative timestamp. The timestamp - cannot be NULL. -======================= ======================================================= - - -Driver Access -^^^^^^^^^^^^^ - -Line discipline methods can call the following methods of the underlying -hardware driver through the function pointers within the tty->driver -structure: - -======================= ======================================================= -write() Write a block of characters to the tty device. - Returns the number of characters accepted. The - character buffer passed to this method is already - in kernel space. - -put_char() Queues a character for writing to the tty device. - If there is no room in the queue, the character is - ignored. - -flush_chars() (Optional) If defined, must be called after - queueing characters with put_char() in order to - start transmission. - -write_room() Returns the numbers of characters the tty driver - will accept for queueing to be written. - -ioctl() Invoke device specific ioctl. - Expects data pointers to refer to userspace. - Returns ENOIOCTLCMD for unrecognized ioctl numbers. - -set_termios() Notify the tty driver that the device's termios - settings have changed. New settings are in - tty->termios. Previous settings should be passed in - the "old" argument. - - The API is defined such that the driver should return - the actual modes selected. This means that the - driver function is responsible for modifying any - bits in the request it cannot fulfill to indicate - the actual modes being used. A device with no - hardware capability for change (e.g. a USB dongle or - virtual port) can provide NULL for this method. - -throttle() Notify the tty driver that input buffers for the - line discipline are close to full, and it should - somehow signal that no more characters should be - sent to the tty. - -unthrottle() Notify the tty driver that characters can now be - sent to the tty without fear of overrunning the - input buffers of the line disciplines. - -stop() Ask the tty driver to stop outputting characters - to the tty device. - -start() Ask the tty driver to resume sending characters - to the tty device. - -hangup() Ask the tty driver to hang up the tty device. - -break_ctl() (Optional) Ask the tty driver to turn on or off - BREAK status on the RS-232 port. If state is -1, - then the BREAK status should be turned on; if - state is 0, then BREAK should be turned off. - If this routine is not implemented, use ioctls - TIOCSBRK / TIOCCBRK instead. - -wait_until_sent() Waits until the device has written out all of the - characters in its transmitter FIFO. - -send_xchar() Send a high-priority XON/XOFF character to the device. -======================= ======================================================= - - -Flags -^^^^^ - -Line discipline methods have access to tty->flags field containing the -following interesting flags: - -======================= ======================================================= -TTY_THROTTLED Driver input is throttled. The ldisc should call - tty->driver->unthrottle() in order to resume - reception when it is ready to process more data. - -TTY_DO_WRITE_WAKEUP If set, causes the driver to call the ldisc's - write_wakeup() method in order to resume - transmission when it can accept more data - to transmit. - -TTY_IO_ERROR If set, causes all subsequent userspace read/write - calls on the tty to fail, returning -EIO. - -TTY_OTHER_CLOSED Device is a pty and the other side has closed. - -TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into - smaller chunks. -======================= ======================================================= - - -Locking -^^^^^^^ - -Callers to the line discipline functions from the tty layer are required to -take line discipline locks. The same is true of calls from the driver side -but not yet enforced. - -Three calls are now provided:: - - ldisc = tty_ldisc_ref(tty); - -takes a handle to the line discipline in the tty and returns it. If no ldisc -is currently attached or the ldisc is being closed and re-opened at this -point then NULL is returned. While this handle is held the ldisc will not -change or go away:: - - tty_ldisc_deref(ldisc) - -Returns the ldisc reference and allows the ldisc to be closed. Returning the -reference takes away your right to call the ldisc functions until you take -a new reference:: - - ldisc = tty_ldisc_ref_wait(tty); - -Performs the same function as tty_ldisc_ref except that it will wait for an -ldisc change to complete and then return a reference to the new ldisc. - -While these functions are slightly slower than the old code they should have -minimal impact as most receive logic uses the flip buffers and they only -need to take a reference when they push bits up through the driver. - -A caution: The ldisc->open(), ldisc->close() and driver->set_ldisc -functions are called with the ldisc unavailable. Thus tty_ldisc_ref will -fail in this situation if used within these functions. Ldisc and driver -code calling its own functions must be careful in this case. - - -Driver Interface ----------------- - -======================= ======================================================= -open() Called when a device is opened. May sleep - -close() Called when a device is closed. At the point of - return from this call the driver must make no - further ldisc calls of any kind. May sleep - -write() Called to write bytes to the device. May not - sleep. May occur in parallel in special cases. - Because this includes panic paths drivers generally - shouldn't try and do clever locking here. - -put_char() Stuff a single character onto the queue. The - driver is guaranteed following up calls to - flush_chars. - -flush_chars() Ask the kernel to write put_char queue - -write_room() Return the number of characters that can be stuffed - into the port buffers without overflow (or less). - The ldisc is responsible for being intelligent - about multi-threading of write_room/write calls - -ioctl() Called when an ioctl may be for the driver - -set_termios() Called on termios change, serialized against - itself by a semaphore. May sleep. - -set_ldisc() Notifier for discipline change. At the point this - is done the discipline is not yet usable. Can now - sleep (I think) - -throttle() Called by the ldisc to ask the driver to do flow - control. Serialization including with unthrottle - is the job of the ldisc layer. - -unthrottle() Called by the ldisc to ask the driver to stop flow - control. - -stop() Ldisc notifier to the driver to stop output. As with - throttle the serializations with start() are down - to the ldisc layer. - -start() Ldisc notifier to the driver to start output. - -hangup() Ask the tty driver to cause a hangup initiated - from the host side. [Can sleep ??] - -break_ctl() Send RS232 break. Can sleep. Can get called in - parallel, driver must serialize (for now), and - with write calls. - -wait_until_sent() Wait for characters to exit the hardware queue - of the driver. Can sleep - -send_xchar() Send XON/XOFF and if possible jump the queue with - it in order to get fast flow control responses. - Cannot sleep ?? -======================= ======================================================= diff --git a/Documentation/index.rst b/Documentation/index.rst index 54ce34fd6fbd..2b4de3926858 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -137,6 +137,7 @@ needed). misc-devices/index scheduler/index mhi/index + tty/index Architecture-agnostic documentation ----------------------------------- diff --git a/Documentation/tty/index.rst b/Documentation/tty/index.rst new file mode 100644 index 000000000000..21ea0cb21e55 --- /dev/null +++ b/Documentation/tty/index.rst @@ -0,0 +1,63 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=== +TTY +=== + +Teletypewriter (TTY) layer takes care of all those serial devices. Including +the virtual ones like pseudoterminal (PTY). + +TTY structures +============== + +There are several major TTY structures. Every TTY device in a system has a +corresponding struct tty_port. These devices are maintained by a TTY driver +which is struct tty_driver. This structure describes the driver but also +contains a reference to operations which could be performed on the TTYs. It is +struct tty_operations. Then, upon open, a struct tty_struct is allocated and +lives until the final close. During this time, several callbacks from struct +tty_operations are invoked by the TTY layer. + +Every character received by the kernel (both from devices and users) is passed +through a preselected :doc:`tty_ldisc` (in +short ldisc; in C, struct tty_ldisc_ops). Its task is to transform characters +as defined by a particular ldisc or by user too. The default one is n_tty, +implementing echoes, signal handling, jobs control, special characters +processing, and more. The transformed characters are passed further to +user/device, depending on the source. + +In-detail description of the named TTY structures is in separate documents: + +.. toctree:: + :maxdepth: 2 + + tty_driver + tty_port + tty_struct + tty_ldisc + tty_buffer + n_tty + tty_internals + +Writing TTY Driver +================== + +Before one starts writing a TTY driver, they must consider +:doc:`Serial <../driver-api/serial/driver>` and :doc:`USB Serial +<../usb/usb-serial>` layers +first. Drivers for serial devices can often use one of these specific layers to +implement a serial driver. Only special devices should be handled directly by +the TTY Layer. If you are about to write such a driver, read on. + +A *typical* sequence a TTY driver performs is as follows: + +#. Allocate and register a TTY driver (module init) +#. Create and register TTY devices as they are probed (probe function) +#. Handle TTY operations and events like interrupts (TTY core invokes the + former, the device the latter) +#. Remove devices as they are going away (remove function) +#. Unregister and free the TTY driver (module exit) + +Steps regarding driver, i.e. 1., 3., and 5. are described in detail in +:doc:`tty_driver`. For the other two (devices handling), look into +:doc:`tty_port`. diff --git a/Documentation/tty/n_tty.rst b/Documentation/tty/n_tty.rst new file mode 100644 index 000000000000..15b70faee72d --- /dev/null +++ b/Documentation/tty/n_tty.rst @@ -0,0 +1,22 @@ +.. SPDX-License-Identifier: GPL-2.0 + +===== +N_TTY +===== + +.. contents:: :local: + +The default (and fallback) :doc:`TTY line discipline <tty_ldisc>`. It tries to +handle characters as per POSIX. + +External Functions +================== + +.. kernel-doc:: drivers/tty/n_tty.c + :export: + +Internal Functions +================== + +.. kernel-doc:: drivers/tty/n_tty.c + :internal: diff --git a/Documentation/tty/tty_buffer.rst b/Documentation/tty/tty_buffer.rst new file mode 100644 index 000000000000..a39d4781e0d2 --- /dev/null +++ b/Documentation/tty/tty_buffer.rst @@ -0,0 +1,46 @@ +.. SPDX-License-Identifier: GPL-2.0 + +========== +TTY Buffer +========== + +.. contents:: :local: + +Here, we document functions for taking care of tty buffer and their flipping. +Drivers are supposed to fill the buffer by one of those functions below and +then flip the buffer, so that the data are passed to :doc:`line discipline +<tty_ldisc>` for further processing. + +Flip Buffer Management +====================== + +.. kernel-doc:: drivers/tty/tty_buffer.c + :identifiers: tty_prepare_flip_string tty_insert_flip_string_fixed_flag + tty_insert_flip_string_flags __tty_insert_flip_char + tty_flip_buffer_push tty_ldisc_receive_buf + +---- + +Other Functions +=============== + +.. kernel-doc:: drivers/tty/tty_buffer.c + :identifiers: tty_buffer_space_avail tty_buffer_set_limit + +---- + +Buffer Locking +============== + +These are used only in special circumstances. Avoid them. + +.. kernel-doc:: drivers/tty/tty_buffer.c + :identifiers: tty_buffer_lock_exclusive tty_buffer_unlock_exclusive + +---- + +Internal Functions +================== + +.. kernel-doc:: drivers/tty/tty_buffer.c + :internal: diff --git a/Documentation/tty/tty_driver.rst b/Documentation/tty/tty_driver.rst new file mode 100644 index 000000000000..cc529f863406 --- /dev/null +++ b/Documentation/tty/tty_driver.rst @@ -0,0 +1,128 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============================= +TTY Driver and TTY Operations +============================= + +.. contents:: :local: + +Allocation +========== + +The first thing a driver needs to do is to allocate a struct tty_driver. This +is done by tty_alloc_driver() (or __tty_alloc_driver()). Next, the newly +allocated structure is filled with information. See `TTY Driver Reference`_ at +the end of this document on what actually shall be filled in. + +The allocation routines expect a number of devices the driver can handle at +most and flags. Flags are those starting ``TTY_DRIVER_`` listed and described +in `TTY Driver Flags`_ below. + +When the driver is about to be freed, tty_driver_kref_put() is called on that. +It will decrements the reference count and if it reaches zero, the driver is +freed. + +For reference, both allocation and deallocation functions are explained here in +detail: + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: __tty_alloc_driver tty_driver_kref_put + +TTY Driver Flags +---------------- + +Here comes the documentation of flags accepted by tty_alloc_driver() (or +__tty_alloc_driver()): + +.. kernel-doc:: include/linux/tty_driver.h + :doc: TTY Driver Flags + +---- + +Registration +============ + +When a struct tty_driver is allocated and filled in, it can be registered using +tty_register_driver(). It is recommended to pass ``TTY_DRIVER_DYNAMIC_DEV`` in +flags of tty_alloc_driver(). If it is not passed, *all* devices are also +registered during tty_register_driver() and the following paragraph of +registering devices can be skipped for such drivers. However, the struct +tty_port part in `Registering Devices`_ is still relevant there. + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_register_driver tty_unregister_driver + +Registering Devices +------------------- + +Every TTY device shall be backed by a struct tty_port. Usually, TTY drivers +embed tty_port into device's private structures. Further details about handling +tty_port can be found in :doc:`tty_port`. The driver is also recommended to use +tty_port's reference counting by tty_port_get() and tty_port_put(). The final +put is supposed to free the tty_port including the device's private struct. + +Unless ``TTY_DRIVER_DYNAMIC_DEV`` was passed as flags to tty_alloc_driver(), +TTY driver is supposed to register every device discovered in the system +(the latter is preferred). This is performed by tty_register_device(). Or by +tty_register_device_attr() if the driver wants to expose some information +through struct attribute_group. Both of them register ``index``'th device and +upon return, the device can be opened. There are also preferred tty_port +variants described in `Linking Devices to Ports`_ later. It is up to driver to +manage free indices and choosing the right one. The TTY layer only refuses to +register more devices than passed to tty_alloc_driver(). + +When the device is opened, the TTY layer allocates struct tty_struct and starts +calling operations from :c:member:`tty_driver.ops`, see `TTY Operations +Reference`_. + +The registration routines are documented as follows: + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_register_device tty_register_device_attr + tty_unregister_device + +---- + +Linking Devices to Ports +------------------------ +As stated earlier, every TTY device shall have a struct tty_port assigned to +it. It must be known to the TTY layer at :c:member:`tty_driver.ops.install()` +at latest. There are few helpers to *link* the two. Ideally, the driver uses +tty_port_register_device() or tty_port_register_device_attr() instead of +tty_register_device() and tty_register_device_attr() at the registration time. +This way, the driver needs not care about linking later on. + +If that is not possible, the driver still can link the tty_port to a specific +index *before* the actual registration by tty_port_link_device(). If it still +does not fit, tty_port_install() can be used from the +:c:member:`tty_driver.ops.install` hook as a last resort. The last one is +dedicated mostly for in-memory devices like PTY where tty_ports are allocated +on demand. + +The linking routines are documented here: + +.. kernel-doc:: drivers/tty/tty_port.c + :identifiers: tty_port_link_device tty_port_register_device + tty_port_register_device_attr + +---- + +TTY Driver Reference +==================== + +All members of struct tty_driver are documented here. The required members are +noted at the end. struct tty_operations are documented next. + +.. kernel-doc:: include/linux/tty_driver.h + :identifiers: tty_driver + +---- + +TTY Operations Reference +======================== + +When a TTY is registered, these driver hooks can be invoked by the TTY layer: + +.. kernel-doc:: include/linux/tty_driver.h + :identifiers: tty_operations + diff --git a/Documentation/tty/tty_internals.rst b/Documentation/tty/tty_internals.rst new file mode 100644 index 000000000000..d0d415820300 --- /dev/null +++ b/Documentation/tty/tty_internals.rst @@ -0,0 +1,31 @@ +.. SPDX-License-Identifier: GPL-2.0 + +============= +TTY Internals +============= + +.. contents:: :local: + +Kopen +===== + +These functions serve for opening a TTY from the kernelspace: + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_kopen_exclusive tty_kopen_shared tty_kclose + +---- + +Exported Internal Functions +=========================== + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_release_struct tty_dev_name_to_number tty_get_icount + +---- + +Internal Functions +================== + +.. kernel-doc:: drivers/tty/tty_io.c + :internal: diff --git a/Documentation/tty/tty_ldisc.rst b/Documentation/tty/tty_ldisc.rst new file mode 100644 index 000000000000..5144751be804 --- /dev/null +++ b/Documentation/tty/tty_ldisc.rst @@ -0,0 +1,85 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=================== +TTY Line Discipline +=================== + +.. contents:: :local: + +TTY line discipline process all incoming and outgoing character from/to a tty +device. The default line discipline is :doc:`N_TTY <n_tty>`. It is also a +fallback if establishing any other discipline for a tty fails. If even N_TTY +fails, N_NULL takes over. That never fails, but also does not process any +characters -- it throws them away. + +Registration +============ + +Line disciplines are registered with tty_register_ldisc() passing the ldisc +structure. At the point of registration the discipline must be ready to use and +it is possible it will get used before the call returns success. If the call +returns an error then it won’t get called. Do not re-use ldisc numbers as they +are part of the userspace ABI and writing over an existing ldisc will cause +demons to eat your computer. You must not re-register over the top of the line +discipline even with the same data or your computer again will be eaten by +demons. In order to remove a line discipline call tty_unregister_ldisc(). + +Heed this warning: the reference count field of the registered copies of the +tty_ldisc structure in the ldisc table counts the number of lines using this +discipline. The reference count of the tty_ldisc structure within a tty counts +the number of active users of the ldisc at this instant. In effect it counts +the number of threads of execution within an ldisc method (plus those about to +enter and exit although this detail matters not). + +.. kernel-doc:: drivers/tty/tty_ldisc.c + :identifiers: tty_register_ldisc tty_unregister_ldisc + +Other Functions +=============== + +.. kernel-doc:: drivers/tty/tty_ldisc.c + :identifiers: tty_set_ldisc tty_ldisc_flush + +Line Discipline Operations Reference +==================================== + +.. kernel-doc:: include/linux/tty_ldisc.h + :identifiers: tty_ldisc_ops + +Driver Access +============= + +Line discipline methods can call the methods of the underlying hardware driver. +These are documented as a part of struct tty_operations. + +TTY Flags +========= + +Line discipline methods have access to :c:member:`tty_struct.flags` field. See +:doc:`tty_struct`. + +Locking +======= + +Callers to the line discipline functions from the tty layer are required to +take line discipline locks. The same is true of calls from the driver side +but not yet enforced. + +.. kernel-doc:: drivers/tty/tty_ldisc.c + :identifiers: tty_ldisc_ref_wait tty_ldisc_ref tty_ldisc_deref + +While these functions are slightly slower than the old code they should have +minimal impact as most receive logic uses the flip buffers and they only +need to take a reference when they push bits up through the driver. + +A caution: The :c:member:`tty_ldisc_ops.open()`, +:c:member:`tty_ldisc_ops.close()` and :c:member:`tty_driver.set_ldisc()` +functions are called with the ldisc unavailable. Thus tty_ldisc_ref() will fail +in this situation if used within these functions. Ldisc and driver code +calling its own functions must be careful in this case. + +Internal Functions +================== + +.. kernel-doc:: drivers/tty/tty_ldisc.c + :internal: diff --git a/Documentation/tty/tty_port.rst b/Documentation/tty/tty_port.rst new file mode 100644 index 000000000000..5cb90e954fcf --- /dev/null +++ b/Documentation/tty/tty_port.rst @@ -0,0 +1,70 @@ +.. SPDX-License-Identifier: GPL-2.0 + +======== +TTY Port +======== + +.. contents:: :local: + +The TTY drivers are advised to use struct tty_port helpers as much as possible. +If the drivers implement :c:member:`tty_port.ops.activate()` and +:c:member:`tty_port.ops.shutdown()`, they can use tty_port_open(), +tty_port_close(), and tty_port_hangup() in respective +:c:member:`tty_struct.ops` hooks. + +The reference and details are contained in the `TTY Port Reference`_ and `TTY +Port Operations Reference`_ sections at the bottom. + +TTY Port Functions +================== + +Init & Destroy +-------------- + +.. kernel-doc:: drivers/tty/tty_port.c + :identifiers: tty_port_init tty_port_destroy + tty_port_get tty_port_put + +Open/Close/Hangup Helpers +------------------------- + +.. kernel-doc:: drivers/tty/tty_port.c + :identifiers: tty_port_install tty_port_open tty_port_block_til_ready + tty_port_close tty_port_close_start tty_port_close_end tty_port_hangup + tty_port_shutdown + +TTY Refcounting +--------------- + +.. kernel-doc:: drivers/tty/tty_port.c + :identifiers: tty_port_tty_get tty_port_tty_set + +TTY Helpers +----------- + +.. kernel-doc:: drivers/tty/tty_port.c + :identifiers: tty_port_tty_hangup tty_port_tty_wakeup + + +Modem Signals +------------- + +.. kernel-doc:: drivers/tty/tty_port.c + :identifiers: tty_port_carrier_raised tty_port_raise_dtr_rts + tty_port_lower_dtr_rts + +---- + +TTY Port Reference +================== + +.. kernel-doc:: include/linux/tty_port.h + :identifiers: tty_port + +---- + +TTY Port Operations Reference +============================= + +.. kernel-doc:: include/linux/tty_port.h + :identifiers: tty_port_operations diff --git a/Documentation/tty/tty_struct.rst b/Documentation/tty/tty_struct.rst new file mode 100644 index 000000000000..c72f5a4293b2 --- /dev/null +++ b/Documentation/tty/tty_struct.rst @@ -0,0 +1,81 @@ +.. SPDX-License-Identifier: GPL-2.0 + +========== +TTY Struct +========== + +.. contents:: :local: + +struct tty_struct is allocated by the TTY layer upon the first open of the TTY +device and released after the last close. The TTY layer passes this structure +to most of struct tty_operation's hooks. Members of tty_struct are documented +in `TTY Struct Reference`_ at the bottom. + +Initialization +============== + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_init_termios + +Name +==== + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_name + +Reference counting +================== + +.. kernel-doc:: include/linux/tty.h + :identifiers: tty_kref_get + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_kref_put + +Install +======= + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_standard_install + +Read & Write +============ + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_put_char + +Start & Stop +============ + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: start_tty stop_tty + +Wakeup +====== + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_wakeup + +Hangup +====== + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_hangup tty_vhangup tty_hung_up_p + +Misc +==== + +.. kernel-doc:: drivers/tty/tty_io.c + :identifiers: tty_do_resize + +TTY Struct Flags +================ + +.. kernel-doc:: include/linux/tty.h + :doc: TTY Struct Flags + +TTY Struct Reference +==================== + +.. kernel-doc:: include/linux/tty.h + :identifiers: tty_struct diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index 90635ef5dafa..6dc952b0df4a 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -59,7 +59,7 @@ srmcons_do_receive_chars(struct tty_port *port) } while((result.bits.status & 1) && (++loops < 10)); if (count) - tty_schedule_flip(port); + tty_flip_buffer_push(port); return count; } diff --git a/arch/arm/include/debug/pl01x.S b/arch/arm/include/debug/pl01x.S index 0c7bfa4c10db..c7e02d0628bf 100644 --- a/arch/arm/include/debug/pl01x.S +++ b/arch/arm/include/debug/pl01x.S @@ -8,13 +8,6 @@ */ #include <linux/amba/serial.h> -#ifdef CONFIG_DEBUG_ZTE_ZX -#undef UART01x_DR -#undef UART01x_FR -#define UART01x_DR 0x04 -#define UART01x_FR 0x14 -#endif - #ifdef CONFIG_DEBUG_UART_PHYS .macro addruart, rp, rv, tmp ldr \rp, =CONFIG_DEBUG_UART_PHYS diff --git a/drivers/accessibility/speakup/spk_ttyio.c b/drivers/accessibility/speakup/spk_ttyio.c index 0d1f397cd896..08cf8a17754b 100644 --- a/drivers/accessibility/speakup/spk_ttyio.c +++ b/drivers/accessibility/speakup/spk_ttyio.c @@ -88,7 +88,7 @@ static int spk_ttyio_receive_buf2(struct tty_struct *tty, } if (!ldisc_data->buf_free) - /* ttyio_in will tty_schedule_flip */ + /* ttyio_in will tty_flip_buffer_push */ return 0; /* Make sure the consumer has read buf before we have seen @@ -312,7 +312,7 @@ static unsigned char ttyio_in(struct spk_synth *in_synth, int timeout) mb(); ldisc_data->buf_free = true; /* Let TTY push more characters */ - tty_schedule_flip(tty->port); + tty_flip_buffer_push(tty->port); return rv; } diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index ecdf8e034351..f537673ede17 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -739,14 +739,13 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) * Arguments: * * tty pointer to tty instance data - * file pointer to open file object for device * cmd IOCTL command code * arg argument for IOCTL call (cmd dependent) * * Return Value: Command dependent */ -static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int hci_uart_tty_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { struct hci_uart *hu = tty->disc_data; int err = 0; diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 17eb8f2aa48d..669a728095b8 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -207,8 +207,8 @@ static void serport_set_type(struct tty_struct *tty, unsigned long type) * serport_ldisc_ioctl() allows to set the port protocol, and device ID */ -static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int serport_ldisc_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { if (cmd == SPIOCSTYPE) { unsigned long type; @@ -226,7 +226,6 @@ static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file, #ifdef CONFIG_COMPAT #define COMPAT_SPIOCSTYPE _IOW('q', 0x01, compat_ulong_t) static int serport_ldisc_compat_ioctl(struct tty_struct *tty, - struct file *file, unsigned int cmd, unsigned long arg) { if (cmd == COMPAT_SPIOCSTYPE) { diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index d4c7ce998a34..27783fbf011f 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -673,8 +673,8 @@ static void slcan_hangup(struct tty_struct *tty) } /* Perform I/O control on an active SLCAN channel. */ -static int slcan_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int slcan_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { struct slcan *sl = (struct slcan *) tty->disc_data; unsigned int tmp; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 8a19a06b505d..b1fc153125d9 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -681,8 +681,8 @@ static void sixpack_close(struct tty_struct *tty) } /* Perform I/O control on an active 6pack channel. */ -static int sixpack_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int sixpack_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { struct sixpack *sp = sp_get(tty); struct net_device *dev; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index edde9c3ae12b..c251e04ae047 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -806,8 +806,8 @@ static void mkiss_close(struct tty_struct *tty) } /* Perform I/O control on an active ax25 channel. */ -static int mkiss_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int mkiss_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { struct mkiss *ax = mkiss_get(tty); struct net_device *dev; diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index f4429b93a9c8..15a179631903 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -281,8 +281,7 @@ ppp_asynctty_write(struct tty_struct *tty, struct file *file, */ static int -ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +ppp_asynctty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct asyncppp *ap = ap_get(tty); int err, val; diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index b3a71b409a80..18283b7b94bc 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -274,8 +274,7 @@ ppp_sync_write(struct tty_struct *tty, struct file *file, } static int -ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +ppp_synctty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct syncppp *ap = sp_get(tty); int __user *p = (int __user *)arg; diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 9f3b4c1aa5ce..98f586f910fb 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -1072,8 +1072,8 @@ static void slip_unesc6(struct slip *sl, unsigned char s) #endif /* CONFIG_SLIP_MODE_SLIP6 */ /* Perform I/O control on an active SLIP channel. */ -static int slip_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int slip_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { struct slip *sl = tty->disc_data; unsigned int tmp; diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h index c467589c7f45..c06d399b9b1f 100644 --- a/drivers/s390/char/keyboard.h +++ b/drivers/s390/char/keyboard.h @@ -56,7 +56,7 @@ static inline void kbd_put_queue(struct tty_port *port, int ch) { tty_insert_flip_char(port, ch, 0); - tty_schedule_flip(port); + tty_flip_buffer_push(port); } static inline void @@ -64,5 +64,5 @@ kbd_puts_queue(struct tty_port *port, char *cp) { while (*cp) tty_insert_flip_char(port, *cp++, 0); - tty_schedule_flip(port); + tty_flip_buffer_push(port); } diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index d24af649a8bb..5ed19a9857ad 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -151,7 +151,7 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) address = (unsigned long)(void *)buf; goldfish_tty_rw(qtty, address, count, 0); - tty_schedule_flip(&qtty->port); + tty_flip_buffer_push(&qtty->port); return IRQ_HANDLED; } @@ -298,7 +298,7 @@ static int goldfish_tty_probe(struct platform_device *pdev) struct resource *r; struct device *ttydev; void __iomem *base; - u32 irq; + int irq; unsigned int line; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -313,14 +313,12 @@ static int goldfish_tty_probe(struct platform_device *pdev) return -ENOMEM; } - r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!r) { - pr_err("goldfish_tty: No IRQ resource available!\n"); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; goto err_unmap; } - irq = r->start; - mutex_lock(&goldfish_tty_lock); if (pdev->id == PLATFORM_DEVID_NONE) diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 02c10a968de1..31dceb5039b5 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -955,19 +955,18 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) mips_ejtag_fdc_con.tty_drv = driver; init_waitqueue_head(&priv->waitqueue); - priv->thread = kthread_create(mips_ejtag_fdc_put, priv, priv->fdc_name); - if (IS_ERR(priv->thread)) { - ret = PTR_ERR(priv->thread); - dev_err(priv->dev, "Couldn't create kthread (%d)\n", ret); - goto err_destroy_ports; - } /* * Bind the writer thread to the right CPU so it can't migrate. * The channels are per-CPU and we want all channel I/O to be on a * single predictable CPU. */ - kthread_bind(priv->thread, dev->cpu); - wake_up_process(priv->thread); + priv->thread = kthread_run_on_cpu(mips_ejtag_fdc_put, priv, + dev->cpu, "ttyFDC/%u"); + if (IS_ERR(priv->thread)) { + ret = PTR_ERR(priv->thread); + dev_err(priv->dev, "Couldn't create kthread (%d)\n", ret); + goto err_destroy_ports; + } /* Look for an FDC IRQ */ priv->irq = get_c0_fdc_int(); @@ -1095,15 +1094,14 @@ static int mips_ejtag_fdc_tty_cpu_up(struct mips_cdmm_device *dev) } /* Restart the kthread */ - priv->thread = kthread_create(mips_ejtag_fdc_put, priv, priv->fdc_name); + /* Bind it back to the right CPU and set it off */ + priv->thread = kthread_run_on_cpu(mips_ejtag_fdc_put, priv, + dev->cpu, "ttyFDC/%u"); if (IS_ERR(priv->thread)) { ret = PTR_ERR(priv->thread); dev_err(priv->dev, "Couldn't re-create kthread (%d)\n", ret); goto out; } - /* Bind it back to the right CPU and set it off */ - kthread_bind(priv->thread, dev->cpu); - wake_up_process(priv->thread); out: return ret; } diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index e37683e25055..f3c72ab1476c 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -1683,7 +1683,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, if (inited && !tty_throttled(tty) && MoxaPortRxQueue(p) > 0) { /* RX */ MoxaPortReadData(p); - tty_schedule_flip(&p->port); + tty_flip_buffer_push(&p->port); } } else { clear_bit(EMPTYWAIT, &p->statusflags); @@ -1708,7 +1708,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */ tty_insert_flip_char(&p->port, 0, TTY_BREAK); - tty_schedule_flip(&p->port); + tty_flip_buffer_push(&p->port); } if (intr & IntrLine) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 93a95a135a71..c858aff721c4 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -159,14 +159,32 @@ #define MXSER_BAUD_BASE 921600 #define MXSER_CUSTOM_DIVISOR (MXSER_BAUD_BASE * 16) -#define PCI_DEVICE_ID_POS104UL 0x1044 -#define PCI_DEVICE_ID_CB108 0x1080 -#define PCI_DEVICE_ID_CP102UF 0x1023 -#define PCI_DEVICE_ID_CP112UL 0x1120 -#define PCI_DEVICE_ID_CB114 0x1142 -#define PCI_DEVICE_ID_CP114UL 0x1143 -#define PCI_DEVICE_ID_CB134I 0x1341 -#define PCI_DEVICE_ID_CP138U 0x1380 +#define PCI_DEVICE_ID_MOXA_RC7000 0x0001 +#define PCI_DEVICE_ID_MOXA_CP102 0x1020 +#define PCI_DEVICE_ID_MOXA_CP102UL 0x1021 +#define PCI_DEVICE_ID_MOXA_CP102U 0x1022 +#define PCI_DEVICE_ID_MOXA_CP102UF 0x1023 +#define PCI_DEVICE_ID_MOXA_C104 0x1040 +#define PCI_DEVICE_ID_MOXA_CP104U 0x1041 +#define PCI_DEVICE_ID_MOXA_CP104JU 0x1042 +#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043 +#define PCI_DEVICE_ID_MOXA_POS104UL 0x1044 +#define PCI_DEVICE_ID_MOXA_CB108 0x1080 +#define PCI_DEVICE_ID_MOXA_CP112UL 0x1120 +#define PCI_DEVICE_ID_MOXA_CT114 0x1140 +#define PCI_DEVICE_ID_MOXA_CP114 0x1141 +#define PCI_DEVICE_ID_MOXA_CB114 0x1142 +#define PCI_DEVICE_ID_MOXA_CP114UL 0x1143 +#define PCI_DEVICE_ID_MOXA_CP118U 0x1180 +#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181 +#define PCI_DEVICE_ID_MOXA_CP132 0x1320 +#define PCI_DEVICE_ID_MOXA_CP132U 0x1321 +#define PCI_DEVICE_ID_MOXA_CP134U 0x1340 +#define PCI_DEVICE_ID_MOXA_CB134I 0x1341 +#define PCI_DEVICE_ID_MOXA_CP138U 0x1380 +#define PCI_DEVICE_ID_MOXA_C168 0x1680 +#define PCI_DEVICE_ID_MOXA_CP168U 0x1681 +#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682 #define MXSER_NPORTS(ddata) ((ddata) & 0xffU) #define MXSER_HIGHBAUD 0x0100 @@ -194,32 +212,32 @@ static const struct { /* driver_data correspond to the lines in the structure above see also ISA probe function before you change something */ static const struct pci_device_id mxser_pcibrds[] = { - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP114), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CT114), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102), .driver_data = 2 | MXSER_HIGHBAUD }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104U), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168U), .driver_data = 8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132U), .driver_data = 2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP134U), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104JU),.driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_RC7000), .driver_data = 8 }, /* RC7000 */ - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118U), .driver_data = 8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102UL),.driver_data = 2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP102U), .driver_data = 2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP118EL),.driver_data = 8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP168EL),.driver_data = 8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP104EL),.driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB108), .driver_data = 8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB114), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CB134I), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP138U), .driver_data = 8 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_POS104UL), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP114UL), .driver_data = 4 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP102UF), .driver_data = 2 }, - { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_CP112UL), .driver_data = 2 }, + { PCI_DEVICE_DATA(MOXA, C168, 8) }, + { PCI_DEVICE_DATA(MOXA, C104, 4) }, + { PCI_DEVICE_DATA(MOXA, CP132, 2) }, + { PCI_DEVICE_DATA(MOXA, CP114, 4) }, + { PCI_DEVICE_DATA(MOXA, CT114, 4) }, + { PCI_DEVICE_DATA(MOXA, CP102, 2 | MXSER_HIGHBAUD) }, + { PCI_DEVICE_DATA(MOXA, CP104U, 4) }, + { PCI_DEVICE_DATA(MOXA, CP168U, 8) }, + { PCI_DEVICE_DATA(MOXA, CP132U, 2) }, + { PCI_DEVICE_DATA(MOXA, CP134U, 4) }, + { PCI_DEVICE_DATA(MOXA, CP104JU, 4) }, + { PCI_DEVICE_DATA(MOXA, RC7000, 8) }, /* RC7000 */ + { PCI_DEVICE_DATA(MOXA, CP118U, 8) }, + { PCI_DEVICE_DATA(MOXA, CP102UL, 2) }, + { PCI_DEVICE_DATA(MOXA, CP102U, 2) }, + { PCI_DEVICE_DATA(MOXA, CP118EL, 8) }, + { PCI_DEVICE_DATA(MOXA, CP168EL, 8) }, + { PCI_DEVICE_DATA(MOXA, CP104EL, 4) }, + { PCI_DEVICE_DATA(MOXA, CB108, 8) }, + { PCI_DEVICE_DATA(MOXA, CB114, 4) }, + { PCI_DEVICE_DATA(MOXA, CB134I, 4) }, + { PCI_DEVICE_DATA(MOXA, CP138U, 8) }, + { PCI_DEVICE_DATA(MOXA, POS104UL, 4) }, + { PCI_DEVICE_DATA(MOXA, CP114UL, 4) }, + { PCI_DEVICE_DATA(MOXA, CP102UF, 2) }, + { PCI_DEVICE_DATA(MOXA, CP112UL, 2) }, { } }; MODULE_DEVICE_TABLE(pci, mxser_pcibrds); @@ -251,8 +269,6 @@ struct mxser_port { u8 MCR; /* Modem control register */ u8 FCR; /* FIFO control register */ - bool ldisc_stop_rx; - struct async_icount icount; /* kernel counters for 4 input interrupts */ unsigned int timeout; @@ -262,7 +278,6 @@ struct mxser_port { unsigned int xmit_head; unsigned int xmit_tail; unsigned int xmit_cnt; - int closing; spinlock_t slock; }; @@ -684,27 +699,34 @@ static void mxser_change_speed(struct tty_struct *tty, struct ktermios *old_term outb(cval, info->ioaddr + UART_LCR); } -static void mxser_check_modem_status(struct tty_struct *tty, - struct mxser_port *port, int status) +static u8 mxser_check_modem_status(struct tty_struct *tty, + struct mxser_port *port) { + u8 msr = inb(port->ioaddr + UART_MSR); + + if (!(msr & UART_MSR_ANY_DELTA)) + return msr; + /* update input line counters */ - if (status & UART_MSR_TERI) + if (msr & UART_MSR_TERI) port->icount.rng++; - if (status & UART_MSR_DDSR) + if (msr & UART_MSR_DDSR) port->icount.dsr++; - if (status & UART_MSR_DDCD) + if (msr & UART_MSR_DDCD) port->icount.dcd++; - if (status & UART_MSR_DCTS) + if (msr & UART_MSR_DCTS) port->icount.cts++; wake_up_interruptible(&port->port.delta_msr_wait); - if (tty_port_check_carrier(&port->port) && (status & UART_MSR_DDCD)) { - if (status & UART_MSR_DCD) + if (tty_port_check_carrier(&port->port) && (msr & UART_MSR_DDCD)) { + if (msr & UART_MSR_DCD) wake_up_interruptible(&port->port.open_wait); } if (tty_port_cts_enabled(&port->port)) - mxser_handle_cts(tty, port, status); + mxser_handle_cts(tty, port, msr); + + return msr; } static void mxser_disable_and_clear_FIFO(struct mxser_port *info) @@ -802,6 +824,20 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty) } /* + * To stop accepting input, we disable the receive line status interrupts, and + * tell the interrupt driver to stop checking the data ready bit in the line + * status register. + */ +static void mxser_stop_rx(struct mxser_port *info) +{ + info->IER &= ~UART_IER_RLSI; + if (info->board->must_hwid) + info->IER &= ~MOXA_MUST_RECV_ISR; + + outb(info->IER, info->ioaddr + UART_IER); +} + +/* * This routine will shutdown a serial port */ static void mxser_shutdown_port(struct tty_port *port) @@ -811,6 +847,8 @@ static void mxser_shutdown_port(struct tty_port *port) spin_lock_irqsave(&info->slock, flags); + mxser_stop_rx(info); + /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up @@ -874,64 +912,9 @@ static void mxser_flush_buffer(struct tty_struct *tty) tty_wakeup(tty); } - -static void mxser_close_port(struct tty_port *port) -{ - struct mxser_port *info = container_of(port, struct mxser_port, port); - unsigned long timeout; - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - info->IER &= ~UART_IER_RLSI; - if (info->board->must_hwid) - info->IER &= ~MOXA_MUST_RECV_ISR; - - outb(info->IER, info->ioaddr + UART_IER); - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - timeout = jiffies + HZ; - while (!(inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT)) { - schedule_timeout_interruptible(5); - if (time_after(jiffies, timeout)) - break; - } -} - -/* - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - */ static void mxser_close(struct tty_struct *tty, struct file *filp) { - struct mxser_port *info = tty->driver_data; - struct tty_port *port = &info->port; - - if (info == NULL) - return; - if (tty_port_close_start(port, tty, filp) == 0) - return; - info->closing = 1; - mutex_lock(&port->mutex); - mxser_close_port(port); - mxser_flush_buffer(tty); - if (tty_port_initialized(port) && C_HUPCL(tty)) - tty_port_lower_dtr_rts(port); - mxser_shutdown_port(port); - tty_port_set_initialized(port, 0); - mutex_unlock(&port->mutex); - info->closing = 0; - /* Right now the tty_port set is done outside of the close_end helper - as we don't yet have everyone using refcounts */ - tty_port_close_end(port, tty); - tty_port_tty_set(port, NULL); + tty_port_close(tty->port, tty, filp); } static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count) @@ -940,9 +923,6 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou struct mxser_port *info = tty->driver_data; unsigned long flags; - if (!info->port.xmit_buf) - return 0; - while (1) { c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); @@ -973,9 +953,6 @@ static int mxser_put_char(struct tty_struct *tty, unsigned char ch) struct mxser_port *info = tty->driver_data; unsigned long flags; - if (!info->port.xmit_buf) - return 0; - if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) return 0; @@ -993,7 +970,7 @@ static void mxser_flush_chars(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - if (!info->xmit_cnt || tty->flow.stopped || !info->port.xmit_buf || + if (!info->xmit_cnt || tty->flow.stopped || (tty->hw_stopped && !mxser_16550A_or_MUST(info))) return; @@ -1153,25 +1130,24 @@ static int mxser_get_lsr_info(struct mxser_port *info, static int mxser_tiocmget(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - unsigned char control, status; + unsigned char control; unsigned long flags; + u8 msr; if (tty_io_error(tty)) return -EIO; spin_lock_irqsave(&info->slock, flags); control = info->MCR; - status = inb(info->ioaddr + UART_MSR); - if (status & UART_MSR_ANY_DELTA) - mxser_check_modem_status(tty, info, status); + msr = mxser_check_modem_status(tty, info); spin_unlock_irqrestore(&info->slock, flags); return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | - ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | - ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | - ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | - ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); + ((msr & UART_MSR_DCD) ? TIOCM_CAR : 0) | + ((msr & UART_MSR_RI) ? TIOCM_RNG : 0) | + ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0) | + ((msr & UART_MSR_CTS) ? TIOCM_CTS : 0); } static int mxser_tiocmset(struct tty_struct *tty, @@ -1326,11 +1302,14 @@ static int mxser_get_icount(struct tty_struct *tty, return 0; } -static void mxser_stoprx(struct tty_struct *tty) +/* + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + */ +static void mxser_throttle(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; - info->ldisc_stop_rx = true; if (I_IXOFF(tty)) { if (info->board->must_hwid) { info->IER &= ~MOXA_MUST_RECV_ISR; @@ -1349,21 +1328,11 @@ static void mxser_stoprx(struct tty_struct *tty) } } -/* - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - */ -static void mxser_throttle(struct tty_struct *tty) -{ - mxser_stoprx(tty); -} - static void mxser_unthrottle(struct tty_struct *tty) { struct mxser_port *info = tty->driver_data; /* startrx */ - info->ldisc_stop_rx = false; if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; @@ -1409,7 +1378,7 @@ static void mxser_start(struct tty_struct *tty) unsigned long flags; spin_lock_irqsave(&info->slock, flags); - if (info->xmit_cnt && info->port.xmit_buf) + if (info->xmit_cnt) __mxser_start_tx(info); spin_unlock_irqrestore(&info->slock, flags); } @@ -1442,15 +1411,25 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi } } +static bool mxser_tx_empty(struct mxser_port *info) +{ + unsigned long flags; + u8 lsr; + + spin_lock_irqsave(&info->slock, flags); + lsr = inb(info->ioaddr + UART_LSR); + spin_unlock_irqrestore(&info->slock, flags); + + return !(lsr & UART_LSR_TEMT); +} + /* * mxser_wait_until_sent() --- wait until the transmitter is empty */ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) { struct mxser_port *info = tty->driver_data; - unsigned long orig_jiffies, char_time; - unsigned long flags; - int lsr; + unsigned long expire, char_time; if (info->type == PORT_UNKNOWN) return; @@ -1458,7 +1437,6 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) if (info->xmit_fifo_size == 0) return; /* Just in case.... */ - orig_jiffies = jiffies; /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check @@ -1473,6 +1451,9 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) char_time = 1; if (timeout && timeout < char_time) char_time = timeout; + + char_time = jiffies_to_msecs(char_time); + /* * If the transmitter hasn't cleared in twice the approximate * amount of time to send the entire FIFO, it probably won't @@ -1485,18 +1466,15 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) if (!timeout || timeout > 2 * info->timeout) timeout = 2 * info->timeout; - spin_lock_irqsave(&info->slock, flags); - while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) { - spin_unlock_irqrestore(&info->slock, flags); - schedule_timeout_interruptible(char_time); - spin_lock_irqsave(&info->slock, flags); + expire = jiffies + timeout; + + while (mxser_tx_empty(info)) { + msleep_interruptible(char_time); if (signal_pending(current)) break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) + if (time_after(jiffies, expire)) break; } - spin_unlock_irqrestore(&info->slock, flags); - set_current_state(TASK_RUNNING); } /* @@ -1531,8 +1509,7 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state) return 0; } -static bool mxser_receive_chars_new(struct tty_struct *tty, - struct mxser_port *port, u8 status) +static bool mxser_receive_chars_new(struct mxser_port *port, u8 status) { enum mxser_must_hwid hwid = port->board->must_hwid; u8 gdl; @@ -1546,12 +1523,10 @@ static bool mxser_receive_chars_new(struct tty_struct *tty, if (hwid == MOXA_MUST_MU150_HWID) gdl &= MOXA_MUST_GDL_MASK; - if (gdl >= tty->receive_room && !port->ldisc_stop_rx) - mxser_stoprx(tty); - while (gdl--) { u8 ch = inb(port->ioaddr + UART_RX); - tty_insert_flip_char(&port->port, ch, 0); + if (!tty_insert_flip_char(&port->port, ch, 0)) + port->icount.buf_overrun++; } return true; @@ -1561,10 +1536,8 @@ static u8 mxser_receive_chars_old(struct tty_struct *tty, struct mxser_port *port, u8 status) { enum mxser_must_hwid hwid = port->board->must_hwid; - int recv_room = tty->receive_room; int ignored = 0; int max = 256; - int cnt = 0; u8 ch; do { @@ -1599,14 +1572,10 @@ static u8 mxser_receive_chars_old(struct tty_struct *tty, port->icount.overrun++; } } - tty_insert_flip_char(&port->port, ch, flag); - cnt++; - if (cnt >= recv_room) { - if (!port->ldisc_stop_rx) - mxser_stoprx(tty); + if (!tty_insert_flip_char(&port->port, ch, flag)) { + port->icount.buf_overrun++; break; } - } if (hwid) @@ -1621,10 +1590,7 @@ static u8 mxser_receive_chars_old(struct tty_struct *tty, static u8 mxser_receive_chars(struct tty_struct *tty, struct mxser_port *port, u8 status) { - if (tty->receive_room == 0 && !port->ldisc_stop_rx) - mxser_stoprx(tty); - - if (!mxser_receive_chars_new(tty, port, status)) + if (!mxser_receive_chars_new(port, status)) status = mxser_receive_chars_old(tty, port, status); tty_flip_buffer_push(&port->port); @@ -1634,7 +1600,7 @@ static u8 mxser_receive_chars(struct tty_struct *tty, static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port) { - int count, cnt; + int count; if (port->x_char) { outb(port->x_char, port->ioaddr + UART_TX); @@ -1643,27 +1609,22 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port return; } - if (port->port.xmit_buf == NULL) - return; - if (!port->xmit_cnt || tty->flow.stopped || (tty->hw_stopped && !mxser_16550A_or_MUST(port))) { __mxser_stop_tx(port); return; } - cnt = port->xmit_cnt; count = port->xmit_fifo_size; do { outb(port->port.xmit_buf[port->xmit_tail++], port->ioaddr + UART_TX); - port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); + port->xmit_tail &= SERIAL_XMIT_SIZE - 1; + port->icount.tx++; if (!--port->xmit_cnt) break; } while (--count > 0); - port->icount.tx += (cnt - port->xmit_cnt); - if (port->xmit_cnt < WAKEUP_CHARS) tty_wakeup(tty); @@ -1674,7 +1635,7 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port static bool mxser_port_isr(struct mxser_port *port) { struct tty_struct *tty; - u8 iir, msr, status; + u8 iir, status; bool error = false; iir = inb(port->ioaddr + UART_IIR); @@ -1683,7 +1644,7 @@ static bool mxser_port_isr(struct mxser_port *port) iir &= MOXA_MUST_IIR_MASK; tty = tty_port_tty_get(&port->port); - if (!tty || port->closing || !tty_port_initialized(&port->port)) { + if (!tty) { status = inb(port->ioaddr + UART_LSR); outb(port->FCR | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, port->ioaddr + UART_FCR); @@ -1707,9 +1668,7 @@ static bool mxser_port_isr(struct mxser_port *port) status = mxser_receive_chars(tty, port, status); } - msr = inb(port->ioaddr + UART_MSR); - if (msr & UART_MSR_ANY_DELTA) - mxser_check_modem_status(tty, port, msr); + mxser_check_modem_status(tty, port); if (port->board->must_hwid) { if (iir == 0x02 && (status & UART_LSR_THRE)) @@ -1836,7 +1795,6 @@ static void mxser_initbrd(struct mxser_board *brd, bool high_baud) tty_port_init(&info->port); info->port.ops = &mxser_port_ops; info->board = brd; - info->ldisc_stop_rx = false; /* Enhance mode enabled here */ if (brd->must_hwid != MOXA_OTHER_UART) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 0b96b14bbfe1..ba27b274c967 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2074,8 +2074,6 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) /** * gsm_error - handle tty error * @gsm: ldisc data - * @data: byte received (may be invalid) - * @flag: error received * * Handle an error in the receipt of data for a frame. Currently we just * go back to hunting for a SOF. @@ -2083,8 +2081,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) * FIXME: better diagnostics ? */ -static void gsm_error(struct gsm_mux *gsm, - unsigned char data, unsigned char flag) +static void gsm_error(struct gsm_mux *gsm) { gsm->state = GSM_SEARCH; gsm->io_error++; @@ -2504,7 +2501,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, case TTY_BREAK: case TTY_PARITY: case TTY_FRAME: - gsm_error(gsm, *cp, flags); + gsm_error(gsm); break; default: WARN_ONCE(1, "%s: unknown flag %d\n", @@ -2690,8 +2687,8 @@ static __poll_t gsmld_poll(struct tty_struct *tty, struct file *file, return mask; } -static int gsmld_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int gsmld_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { struct gsm_config c; struct gsm_mux *gsm = tty->disc_data; diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 23ba1fc99df8..94c1ec2dd754 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -593,14 +593,13 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, /** * n_hdlc_tty_ioctl - process IOCTL system call for the tty device. * @tty: pointer to tty instance data - * @file: pointer to open file object for device * @cmd: IOCTL command code * @arg: argument for IOCTL call (cmd dependent) * * Returns command dependent result. */ -static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int n_hdlc_tty_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { struct n_hdlc *n_hdlc = tty->disc_data; int error = 0; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 5be6d02dc690..a38fd65e39ab 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -186,17 +186,16 @@ static void tty_copy(struct tty_struct *tty, void *to, size_t tail, size_t n) } /** - * n_tty_kick_worker - start input worker (if required) - * @tty: terminal + * n_tty_kick_worker - start input worker (if required) + * @tty: terminal * - * Re-schedules the flip buffer work if it may have stopped + * Re-schedules the flip buffer work if it may have stopped. * - * Caller holds exclusive termios_rwsem - * or - * n_tty_read()/consumer path: - * holds non-exclusive termios_rwsem + * Locking: + * * Caller holds exclusive %termios_rwsem, or + * * n_tty_read()/consumer path: + * holds non-exclusive %termios_rwsem */ - static void n_tty_kick_worker(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; @@ -230,14 +229,12 @@ static ssize_t chars_in_buffer(struct tty_struct *tty) } /** - * n_tty_write_wakeup - asynchronous I/O notifier - * @tty: tty device + * n_tty_write_wakeup - asynchronous I/O notifier + * @tty: tty device * - * Required for the ptys, serial driver etc. since processes - * that attach themselves to the master and rely on ASYNC - * IO must be woken up + * Required for the ptys, serial driver etc. since processes that attach + * themselves to the master and rely on ASYNC IO must be woken up. */ - static void n_tty_write_wakeup(struct tty_struct *tty) { clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); @@ -300,16 +297,16 @@ static void n_tty_check_unthrottle(struct tty_struct *tty) } /** - * put_tty_queue - add character to tty - * @c: character - * @ldata: n_tty data + * put_tty_queue - add character to tty + * @c: character + * @ldata: n_tty data * - * Add a character to the tty read_buf queue. + * Add a character to the tty read_buf queue. * - * n_tty_receive_buf()/producer path: - * caller holds non-exclusive termios_rwsem + * Locking: + * * n_tty_receive_buf()/producer path: + * caller holds non-exclusive %termios_rwsem */ - static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) { *read_buf_addr(ldata, ldata->read_head) = c; @@ -317,16 +314,16 @@ static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) } /** - * reset_buffer_flags - reset buffer state - * @ldata: line disc data to reset + * reset_buffer_flags - reset buffer state + * @ldata: line disc data to reset * - * Reset the read buffer counters and clear the flags. - * Called from n_tty_open() and n_tty_flush_buffer(). + * Reset the read buffer counters and clear the flags. Called from + * n_tty_open() and n_tty_flush_buffer(). * - * Locking: caller holds exclusive termios_rwsem - * (or locking is not required) + * Locking: + * * caller holds exclusive %termios_rwsem, or + * * (locking is not required) */ - static void reset_buffer_flags(struct n_tty_data *ldata) { ldata->read_head = ldata->canon_head = ldata->read_tail = 0; @@ -351,19 +348,18 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty) } /** - * n_tty_flush_buffer - clean input queue - * @tty: terminal device + * n_tty_flush_buffer - clean input queue + * @tty: terminal device * - * Flush the input buffer. Called when the tty layer wants the - * buffer flushed (eg at hangup) or when the N_TTY line discipline - * internally has to clean the pending queue (for example some signals). + * Flush the input buffer. Called when the tty layer wants the buffer flushed + * (eg at hangup) or when the %N_TTY line discipline internally has to clean + * the pending queue (for example some signals). * - * Holds termios_rwsem to exclude producer/consumer while - * buffer indices are reset. + * Holds %termios_rwsem to exclude producer/consumer while buffer indices are + * reset. * - * Locking: ctrl.lock, exclusive termios_rwsem + * Locking: %ctrl.lock, exclusive %termios_rwsem */ - static void n_tty_flush_buffer(struct tty_struct *tty) { down_write(&tty->termios_rwsem); @@ -376,55 +372,50 @@ static void n_tty_flush_buffer(struct tty_struct *tty) } /** - * is_utf8_continuation - utf8 multibyte check - * @c: byte to check + * is_utf8_continuation - utf8 multibyte check + * @c: byte to check * - * Returns true if the utf8 character 'c' is a multibyte continuation - * character. We use this to correctly compute the on screen size - * of the character when printing + * Returns: true if the utf8 character @c is a multibyte continuation + * character. We use this to correctly compute the on-screen size of the + * character when printing. */ - static inline int is_utf8_continuation(unsigned char c) { return (c & 0xc0) == 0x80; } /** - * is_continuation - multibyte check - * @c: byte to check - * @tty: terminal device + * is_continuation - multibyte check + * @c: byte to check + * @tty: terminal device * - * Returns true if the utf8 character 'c' is a multibyte continuation - * character and the terminal is in unicode mode. + * Returns: true if the utf8 character @c is a multibyte continuation character + * and the terminal is in unicode mode. */ - static inline int is_continuation(unsigned char c, struct tty_struct *tty) { return I_IUTF8(tty) && is_utf8_continuation(c); } /** - * do_output_char - output one character - * @c: character (or partial unicode symbol) - * @tty: terminal device - * @space: space available in tty driver write buffer + * do_output_char - output one character + * @c: character (or partial unicode symbol) + * @tty: terminal device + * @space: space available in tty driver write buffer * - * This is a helper function that handles one output character - * (including special characters like TAB, CR, LF, etc.), - * doing OPOST processing and putting the results in the - * tty driver's write buffer. + * This is a helper function that handles one output character (including + * special characters like TAB, CR, LF, etc.), doing OPOST processing and + * putting the results in the tty driver's write buffer. * - * Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY - * and NLDLY. They simply aren't relevant in the world today. - * If you ever need them, add them here. + * Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY and NLDLY. + * They simply aren't relevant in the world today. If you ever need them, add + * them here. * - * Returns the number of bytes of buffer space used or -1 if - * no space left. + * Returns: the number of bytes of buffer space used or -1 if no space left. * - * Locking: should be called under the output_lock to protect - * the column state and space left in the buffer + * Locking: should be called under the %output_lock to protect the column state + * and space left in the buffer. */ - static int do_output_char(unsigned char c, struct tty_struct *tty, int space) { struct n_tty_data *ldata = tty->disc_data; @@ -487,19 +478,18 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space) } /** - * process_output - output post processor - * @c: character (or partial unicode symbol) - * @tty: terminal device + * process_output - output post processor + * @c: character (or partial unicode symbol) + * @tty: terminal device * - * Output one character with OPOST processing. - * Returns -1 when the output device is full and the character - * must be retried. + * Output one character with OPOST processing. * - * Locking: output_lock to protect column state and space left - * (also, this is called from n_tty_write under the - * tty layer write lock) + * Returns: -1 when the output device is full and the character must be + * retried. + * + * Locking: %output_lock to protect column state and space left (also, this is + *called from n_tty_write() under the tty layer write lock). */ - static int process_output(unsigned char c, struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; @@ -518,24 +508,23 @@ static int process_output(unsigned char c, struct tty_struct *tty) } /** - * process_output_block - block post processor - * @tty: terminal device - * @buf: character buffer - * @nr: number of bytes to output - * - * Output a block of characters with OPOST processing. - * Returns the number of characters output. - * - * This path is used to speed up block console writes, among other - * things when processing blocks of output data. It handles only - * the simple cases normally found and helps to generate blocks of - * symbols for the console driver and thus improve performance. - * - * Locking: output_lock to protect column state and space left - * (also, this is called from n_tty_write under the - * tty layer write lock) + * process_output_block - block post processor + * @tty: terminal device + * @buf: character buffer + * @nr: number of bytes to output + * + * Output a block of characters with OPOST processing. + * + * This path is used to speed up block console writes, among other things when + * processing blocks of output data. It handles only the simple cases normally + * found and helps to generate blocks of symbols for the console driver and + * thus improve performance. + * + * Returns: the number of characters output. + * + * Locking: %output_lock to protect column state and space left (also, this is + * called from n_tty_write() under the tty layer write lock). */ - static ssize_t process_output_block(struct tty_struct *tty, const unsigned char *buf, unsigned int nr) { @@ -596,30 +585,27 @@ break_out: } /** - * process_echoes - write pending echo characters - * @tty: terminal device + * __process_echoes - write pending echo characters + * @tty: terminal device * - * Write previously buffered echo (and other ldisc-generated) - * characters to the tty. + * Write previously buffered echo (and other ldisc-generated) characters to the + * tty. * - * Characters generated by the ldisc (including echoes) need to - * be buffered because the driver's write buffer can fill during - * heavy program output. Echoing straight to the driver will - * often fail under these conditions, causing lost characters and - * resulting mismatches of ldisc state information. + * Characters generated by the ldisc (including echoes) need to be buffered + * because the driver's write buffer can fill during heavy program output. + * Echoing straight to the driver will often fail under these conditions, + * causing lost characters and resulting mismatches of ldisc state information. * - * Since the ldisc state must represent the characters actually sent - * to the driver at the time of the write, operations like certain - * changes in column state are also saved in the buffer and executed - * here. + * Since the ldisc state must represent the characters actually sent to the + * driver at the time of the write, operations like certain changes in column + * state are also saved in the buffer and executed here. * - * A circular fifo buffer is used so that the most recent characters - * are prioritized. Also, when control characters are echoed with a - * prefixed "^", the pair is treated atomically and thus not separated. + * A circular fifo buffer is used so that the most recent characters are + * prioritized. Also, when control characters are echoed with a prefixed "^", + * the pair is treated atomically and thus not separated. * - * Locking: callers must hold output_lock + * Locking: callers must hold %output_lock. */ - static size_t __process_echoes(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; @@ -828,13 +814,12 @@ static void flush_echoes(struct tty_struct *tty) } /** - * add_echo_byte - add a byte to the echo buffer - * @c: unicode byte to echo - * @ldata: n_tty data + * add_echo_byte - add a byte to the echo buffer + * @c: unicode byte to echo + * @ldata: n_tty data * - * Add a character or operation byte to the echo buffer. + * Add a character or operation byte to the echo buffer. */ - static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata) { *echo_buf_addr(ldata, ldata->echo_head) = c; @@ -843,12 +828,11 @@ static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata) } /** - * echo_move_back_col - add operation to move back a column - * @ldata: n_tty data + * echo_move_back_col - add operation to move back a column + * @ldata: n_tty data * - * Add an operation to the echo buffer to move back one column. + * Add an operation to the echo buffer to move back one column. */ - static void echo_move_back_col(struct n_tty_data *ldata) { add_echo_byte(ECHO_OP_START, ldata); @@ -856,13 +840,12 @@ static void echo_move_back_col(struct n_tty_data *ldata) } /** - * echo_set_canon_col - add operation to set the canon column - * @ldata: n_tty data + * echo_set_canon_col - add operation to set the canon column + * @ldata: n_tty data * - * Add an operation to the echo buffer to set the canon column - * to the current column. + * Add an operation to the echo buffer to set the canon column to the current + * column. */ - static void echo_set_canon_col(struct n_tty_data *ldata) { add_echo_byte(ECHO_OP_START, ldata); @@ -870,20 +853,18 @@ static void echo_set_canon_col(struct n_tty_data *ldata) } /** - * echo_erase_tab - add operation to erase a tab - * @num_chars: number of character columns already used - * @after_tab: true if num_chars starts after a previous tab - * @ldata: n_tty data - * - * Add an operation to the echo buffer to erase a tab. - * - * Called by the eraser function, which knows how many character - * columns have been used since either a previous tab or the start - * of input. This information will be used later, along with - * canon column (if applicable), to go back the correct number - * of columns. + * echo_erase_tab - add operation to erase a tab + * @num_chars: number of character columns already used + * @after_tab: true if num_chars starts after a previous tab + * @ldata: n_tty data + * + * Add an operation to the echo buffer to erase a tab. + * + * Called by the eraser function, which knows how many character columns have + * been used since either a previous tab or the start of input. This + * information will be used later, along with canon column (if applicable), to + * go back the correct number of columns. */ - static void echo_erase_tab(unsigned int num_chars, int after_tab, struct n_tty_data *ldata) { @@ -901,16 +882,15 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab, } /** - * echo_char_raw - echo a character raw - * @c: unicode byte to echo - * @ldata: line disc data + * echo_char_raw - echo a character raw + * @c: unicode byte to echo + * @ldata: line disc data * - * Echo user input back onto the screen. This must be called only when - * L_ECHO(tty) is true. Called from the driver receive_buf path. + * Echo user input back onto the screen. This must be called only when + * L_ECHO(tty) is true. Called from the &tty_driver.receive_buf() path. * - * This variant does not treat control characters specially. + * This variant does not treat control characters specially. */ - static void echo_char_raw(unsigned char c, struct n_tty_data *ldata) { if (c == ECHO_OP_START) { @@ -922,17 +902,16 @@ static void echo_char_raw(unsigned char c, struct n_tty_data *ldata) } /** - * echo_char - echo a character - * @c: unicode byte to echo - * @tty: terminal device + * echo_char - echo a character + * @c: unicode byte to echo + * @tty: terminal device * - * Echo user input back onto the screen. This must be called only when - * L_ECHO(tty) is true. Called from the driver receive_buf path. + * Echo user input back onto the screen. This must be called only when + * L_ECHO(tty) is true. Called from the &tty_driver.receive_buf() path. * - * This variant tags control characters to be echoed as "^X" - * (where X is the letter representing the control char). + * This variant tags control characters to be echoed as "^X" (where X is the + * letter representing the control char). */ - static void echo_char(unsigned char c, struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; @@ -948,10 +927,9 @@ static void echo_char(unsigned char c, struct tty_struct *tty) } /** - * finish_erasing - complete erase - * @ldata: n_tty data + * finish_erasing - complete erase + * @ldata: n_tty data */ - static inline void finish_erasing(struct n_tty_data *ldata) { if (ldata->erasing) { @@ -961,18 +939,17 @@ static inline void finish_erasing(struct n_tty_data *ldata) } /** - * eraser - handle erase function - * @c: character input - * @tty: terminal device + * eraser - handle erase function + * @c: character input + * @tty: terminal device * - * Perform erase and necessary output when an erase character is - * present in the stream from the driver layer. Handles the complexities - * of UTF-8 multibyte symbols. + * Perform erase and necessary output when an erase character is present in the + * stream from the driver layer. Handles the complexities of UTF-8 multibyte + * symbols. * - * n_tty_receive_buf()/producer path: - * caller holds non-exclusive termios_rwsem + * Locking: n_tty_receive_buf()/producer path: + * caller holds non-exclusive %termios_rwsem */ - static void eraser(unsigned char c, struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; @@ -1091,20 +1068,6 @@ static void eraser(unsigned char c, struct tty_struct *tty) finish_erasing(ldata); } -/** - * isig - handle the ISIG optio - * @sig: signal - * @tty: terminal - * - * Called when a signal is being sent due to terminal input. - * Called from the driver receive_buf path so serialized. - * - * Performs input and output flush if !NOFLSH. In this context, the echo - * buffer is 'output'. The signal is processed first to alert any current - * readers or writers to discontinue and exit their i/o loops. - * - * Locking: ctrl.lock - */ static void __isig(int sig, struct tty_struct *tty) { @@ -1115,6 +1078,20 @@ static void __isig(int sig, struct tty_struct *tty) } } +/** + * isig - handle the ISIG optio + * @sig: signal + * @tty: terminal + * + * Called when a signal is being sent due to terminal input. Called from the + * &tty_driver.receive_buf() path, so serialized. + * + * Performs input and output flush if !NOFLSH. In this context, the echo + * buffer is 'output'. The signal is processed first to alert any current + * readers or writers to discontinue and exit their i/o loops. + * + * Locking: %ctrl.lock + */ static void isig(int sig, struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; @@ -1151,18 +1128,17 @@ static void isig(int sig, struct tty_struct *tty) } /** - * n_tty_receive_break - handle break - * @tty: terminal + * n_tty_receive_break - handle break + * @tty: terminal * - * An RS232 break event has been hit in the incoming bitstream. This - * can cause a variety of events depending upon the termios settings. + * An RS232 break event has been hit in the incoming bitstream. This can cause + * a variety of events depending upon the termios settings. * - * n_tty_receive_buf()/producer path: - * caller holds non-exclusive termios_rwsem + * Locking: n_tty_receive_buf()/producer path: + * caller holds non-exclusive termios_rwsem * - * Note: may get exclusive termios_rwsem if flushing input buffer + * Note: may get exclusive %termios_rwsem if flushing input buffer */ - static void n_tty_receive_break(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; @@ -1181,18 +1157,15 @@ static void n_tty_receive_break(struct tty_struct *tty) } /** - * n_tty_receive_overrun - handle overrun reporting - * @tty: terminal + * n_tty_receive_overrun - handle overrun reporting + * @tty: terminal * - * Data arrived faster than we could process it. While the tty - * driver has flagged this the bits that were missed are gone - * forever. + * Data arrived faster than we could process it. While the tty driver has + * flagged this the bits that were missed are gone forever. * - * Called from the receive_buf path so single threaded. Does not - * need locking as num_overrun and overrun_time are function - * private. + * Called from the receive_buf path so single threaded. Does not need locking + * as num_overrun and overrun_time are function private. */ - static void n_tty_receive_overrun(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; @@ -1207,15 +1180,15 @@ static void n_tty_receive_overrun(struct tty_struct *tty) } /** - * n_tty_receive_parity_error - error notifier - * @tty: terminal device - * @c: character + * n_tty_receive_parity_error - error notifier + * @tty: terminal device + * @c: character * - * Process a parity error and queue the right data to indicate - * the error case if necessary. + * Process a parity error and queue the right data to indicate the error case + * if necessary. * - * n_tty_receive_buf()/producer path: - * caller holds non-exclusive termios_rwsem + * Locking: n_tty_receive_buf()/producer path: + * caller holds non-exclusive %termios_rwsem */ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) { @@ -1247,19 +1220,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) process_echoes(tty); } -/** - * n_tty_receive_char - perform processing - * @tty: terminal device - * @c: character - * - * Process an individual character of input received from the driver. - * This is serialized with respect to itself by the rules for the - * driver above. - * - * n_tty_receive_buf()/producer path: - * caller holds non-exclusive termios_rwsem - * publishes canon_head if canonical mode is active - */ static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) { struct n_tty_data *ldata = tty->disc_data; @@ -1394,6 +1354,18 @@ handle_newline: put_tty_queue(c, ldata); } +/** + * n_tty_receive_char - perform processing + * @tty: terminal device + * @c: character + * + * Process an individual character of input received from the driver. This is + * serialized with respect to itself by the rules for the driver above. + * + * Locking: n_tty_receive_buf()/producer path: + * caller holds non-exclusive %termios_rwsem + * publishes canon_head if canonical mode is active + */ static void n_tty_receive_char(struct tty_struct *tty, unsigned char c) { struct n_tty_data *ldata = tty->disc_data; @@ -1594,38 +1566,37 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, } /** - * n_tty_receive_buf_common - process input - * @tty: device to receive input - * @cp: input chars - * @fp: flags for each char (if NULL, all chars are TTY_NORMAL) - * @count: number of input chars in @cp - * @flow: enable flow control - * - * Called by the terminal driver when a block of characters has - * been received. This function must be called from soft contexts - * not from interrupt context. The driver is responsible for making - * calls one at a time and in order (or using flush_to_ldisc) - * - * Returns the # of input chars from @cp which were processed. - * - * In canonical mode, the maximum line length is 4096 chars (including - * the line termination char); lines longer than 4096 chars are - * truncated. After 4095 chars, input data is still processed but - * not stored. Overflow processing ensures the tty can always - * receive more input until at least one line can be read. - * - * In non-canonical mode, the read buffer will only accept 4095 chars; - * this provides the necessary space for a newline char if the input - * mode is switched to canonical. - * - * Note it is possible for the read buffer to _contain_ 4096 chars - * in non-canonical mode: the read buffer could already contain the - * maximum canon line of 4096 chars when the mode is switched to - * non-canonical. - * - * n_tty_receive_buf()/producer path: - * claims non-exclusive termios_rwsem - * publishes commit_head or canon_head + * n_tty_receive_buf_common - process input + * @tty: device to receive input + * @cp: input chars + * @fp: flags for each char (if %NULL, all chars are %TTY_NORMAL) + * @count: number of input chars in @cp + * @flow: enable flow control + * + * Called by the terminal driver when a block of characters has been received. + * This function must be called from soft contexts not from interrupt context. + * The driver is responsible for making calls one at a time and in order (or + * using flush_to_ldisc()). + * + * Returns: the # of input chars from @cp which were processed. + * + * In canonical mode, the maximum line length is 4096 chars (including the line + * termination char); lines longer than 4096 chars are truncated. After 4095 + * chars, input data is still processed but not stored. Overflow processing + * ensures the tty can always receive more input until at least one line can be + * read. + * + * In non-canonical mode, the read buffer will only accept 4095 chars; this + * provides the necessary space for a newline char if the input mode is + * switched to canonical. + * + * Note it is possible for the read buffer to _contain_ 4096 chars in + * non-canonical mode: the read buffer could already contain the maximum canon + * line of 4096 chars when the mode is switched to non-canonical. + * + * Locking: n_tty_receive_buf()/producer path: + * claims non-exclusive %termios_rwsem + * publishes commit_head or canon_head */ static int n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp, @@ -1710,19 +1681,17 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp, } /** - * n_tty_set_termios - termios data changed - * @tty: terminal - * @old: previous data + * n_tty_set_termios - termios data changed + * @tty: terminal + * @old: previous data * - * Called by the tty layer when the user changes termios flags so - * that the line discipline can plan ahead. This function cannot sleep - * and is protected from re-entry by the tty layer. The user is - * guaranteed that this function will not be re-entered or in progress - * when the ldisc is closed. + * Called by the tty layer when the user changes termios flags so that the line + * discipline can plan ahead. This function cannot sleep and is protected from + * re-entry by the tty layer. The user is guaranteed that this function will + * not be re-entered or in progress when the ldisc is closed. * - * Locking: Caller holds tty->termios_rwsem + * Locking: Caller holds @tty->termios_rwsem */ - static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { struct n_tty_data *ldata = tty->disc_data; @@ -1808,15 +1777,13 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) } /** - * n_tty_close - close the ldisc for this tty - * @tty: device + * n_tty_close - close the ldisc for this tty + * @tty: device * - * Called from the terminal layer when this line discipline is - * being shut down, either because of a close or becsuse of a - * discipline change. The function will not be called while other - * ldisc methods are in progress. + * Called from the terminal layer when this line discipline is being shut down, + * either because of a close or becsuse of a discipline change. The function + * will not be called while other ldisc methods are in progress. */ - static void n_tty_close(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; @@ -1831,15 +1798,13 @@ static void n_tty_close(struct tty_struct *tty) } /** - * n_tty_open - open an ldisc - * @tty: terminal to open + * n_tty_open - open an ldisc + * @tty: terminal to open * - * Called when this line discipline is being attached to the - * terminal device. Can sleep. Called serialized so that no - * other events will occur in parallel. No further open will occur - * until a close. + * Called when this line discipline is being attached to the terminal device. + * Can sleep. Called serialized so that no other events will occur in parallel. + * No further open will occur until a close. */ - static int n_tty_open(struct tty_struct *tty) { struct n_tty_data *ldata; @@ -1874,24 +1839,23 @@ static inline int input_available_p(struct tty_struct *tty, int poll) } /** - * copy_from_read_buf - copy read data directly - * @tty: terminal device - * @kbp: data - * @nr: size of data - * - * Helper function to speed up n_tty_read. It is only called when - * ICANON is off; it copies characters straight from the tty queue. + * copy_from_read_buf - copy read data directly + * @tty: terminal device + * @kbp: data + * @nr: size of data * - * Called under the ldata->atomic_read_lock sem + * Helper function to speed up n_tty_read(). It is only called when %ICANON is + * off; it copies characters straight from the tty queue. * - * Returns true if it successfully copied data, but there is still - * more data to be had. + * Returns: true if it successfully copied data, but there is still more data + * to be had. * - * n_tty_read()/consumer path: - * caller holds non-exclusive termios_rwsem + * Locking: + * * called under the @ldata->atomic_read_lock sem + * * n_tty_read()/consumer path: + * caller holds non-exclusive %termios_rwsem; * read_tail published */ - static bool copy_from_read_buf(struct tty_struct *tty, unsigned char **kbp, size_t *nr) @@ -1926,28 +1890,27 @@ static bool copy_from_read_buf(struct tty_struct *tty, } /** - * canon_copy_from_read_buf - copy read data in canonical mode - * @tty: terminal device - * @kbp: data - * @nr: size of data - * - * Helper function for n_tty_read. It is only called when ICANON is on; - * it copies one line of input up to and including the line-delimiting - * character into the result buffer. - * - * NB: When termios is changed from non-canonical to canonical mode and - * the read buffer contains data, n_tty_set_termios() simulates an EOF - * push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer. - * This causes data already processed as input to be immediately available - * as input although a newline has not been received. - * - * Called under the atomic_read_lock mutex - * - * n_tty_read()/consumer path: - * caller holds non-exclusive termios_rwsem - * read_tail published + * canon_copy_from_read_buf - copy read data in canonical mode + * @tty: terminal device + * @kbp: data + * @nr: size of data + * + * Helper function for n_tty_read(). It is only called when %ICANON is on; it + * copies one line of input up to and including the line-delimiting character + * into the result buffer. + * + * Note: When termios is changed from non-canonical to canonical mode and the + * read buffer contains data, n_tty_set_termios() simulates an EOF push (as if + * C-d were input) _without_ the %DISABLED_CHAR in the buffer. This causes data + * already processed as input to be immediately available as input although a + * newline has not been received. + * + * Locking: + * * called under the %atomic_read_lock mutex + * * n_tty_read()/consumer path: + * caller holds non-exclusive %termios_rwsem; + * read_tail published */ - static bool canon_copy_from_read_buf(struct tty_struct *tty, unsigned char **kbp, size_t *nr) @@ -2015,19 +1978,19 @@ static bool canon_copy_from_read_buf(struct tty_struct *tty, } /** - * job_control - check job control - * @tty: tty - * @file: file handle - * - * Perform job control management checks on this file/tty descriptor - * and if appropriate send any needed signals and return a negative - * error code if action should be taken. - * - * Locking: redirected write test is safe - * current->signal->tty check is safe - * ctrl.lock to safely reference tty->ctrl.pgrp + * job_control - check job control + * @tty: tty + * @file: file handle + * + * Perform job control management checks on this @file/@tty descriptor and if + * appropriate send any needed signals and return a negative error code if + * action should be taken. + * + * Locking: + * * redirected write test is safe + * * current->signal->tty check is safe + * * ctrl.lock to safely reference @tty->ctrl.pgrp */ - static int job_control(struct tty_struct *tty, struct file *file) { /* Job control check -- must be done at start and after @@ -2043,24 +2006,25 @@ static int job_control(struct tty_struct *tty, struct file *file) /** - * n_tty_read - read function for tty - * @tty: tty device - * @file: file object - * @buf: userspace buffer pointer - * @nr: size of I/O - * - * Perform reads for the line discipline. We are guaranteed that the - * line discipline will not be closed under us but we may get multiple - * parallel readers and must handle this ourselves. We may also get - * a hangup. Always called in user context, may sleep. - * - * This code must be sure never to sleep through a hangup. - * - * n_tty_read()/consumer path: - * claims non-exclusive termios_rwsem - * publishes read_tail + * n_tty_read - read function for tty + * @tty: tty device + * @file: file object + * @kbuf: kernelspace buffer pointer + * @nr: size of I/O + * @cookie: if non-%NULL, this is a continuation read + * @offset: where to continue reading from (unused in n_tty) + * + * Perform reads for the line discipline. We are guaranteed that the line + * discipline will not be closed under us but we may get multiple parallel + * readers and must handle this ourselves. We may also get a hangup. Always + * called in user context, may sleep. + * + * This code must be sure never to sleep through a hangup. + * + * Locking: n_tty_read()/consumer path: + * claims non-exclusive termios_rwsem; + * publishes read_tail */ - static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, unsigned char *kbuf, size_t nr, void **cookie, unsigned long offset) @@ -2232,25 +2196,23 @@ more_to_be_read: } /** - * n_tty_write - write function for tty - * @tty: tty device - * @file: file object - * @buf: userspace buffer pointer - * @nr: size of I/O - * - * Write function of the terminal device. This is serialized with - * respect to other write callers but not to termios changes, reads - * and other such events. Since the receive code will echo characters, - * thus calling driver write methods, the output_lock is used in - * the output processing functions called here as well as in the - * echo processing function to protect the column state and space - * left in the buffer. - * - * This code must be sure never to sleep through a hangup. - * - * Locking: output_lock to protect column state and space left - * (note that the process_output*() functions take this - * lock themselves) + * n_tty_write - write function for tty + * @tty: tty device + * @file: file object + * @buf: userspace buffer pointer + * @nr: size of I/O + * + * Write function of the terminal device. This is serialized with respect to + * other write callers but not to termios changes, reads and other such events. + * Since the receive code will echo characters, thus calling driver write + * methods, the %output_lock is used in the output processing functions called + * here as well as in the echo processing function to protect the column state + * and space left in the buffer. + * + * This code must be sure never to sleep through a hangup. + * + * Locking: output_lock to protect column state and space left + * (note that the process_output*() functions take this lock themselves) */ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, @@ -2341,19 +2303,19 @@ break_out: } /** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device - * @file: file accessing it - * @wait: poll table + * n_tty_poll - poll method for N_TTY + * @tty: terminal device + * @file: file accessing it + * @wait: poll table + * + * Called when the line discipline is asked to poll() for data or for special + * events. This code is not serialized with respect to other events save + * open/close. * - * Called when the line discipline is asked to poll() for data or - * for special events. This code is not serialized with respect to - * other events save open/close. + * This code must be sure never to sleep through a hangup. * - * This code must be sure never to sleep through a hangup. - * Called without the kernel lock held - fine + * Locking: called without the kernel lock held -- fine. */ - static __poll_t n_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) { @@ -2400,8 +2362,8 @@ static unsigned long inq_canon(struct n_tty_data *ldata) return nr; } -static int n_tty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int n_tty_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { struct n_tty_data *ldata = tty->disc_data; int retval; diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h index 6473361525d1..db784ace25d8 100644 --- a/drivers/tty/serial/8250/8250.h +++ b/drivers/tty/serial/8250/8250.h @@ -241,16 +241,8 @@ static inline int serial8250_in_MCR(struct uart_8250_port *up) return mctrl; } -#if defined(__alpha__) && !defined(CONFIG_PCI) -/* - * Digital did something really horribly wrong with the OUT1 and OUT2 - * lines on at least some ALPHA's. The failure mode is that if either - * is cleared, the machine locks up with endless interrupts. - */ -#define ALPHA_KLUDGE_MCR (UART_MCR_OUT2 | UART_MCR_OUT1) -#else -#define ALPHA_KLUDGE_MCR 0 -#endif +bool alpha_jensen(void); +void alpha_jensen_set_mctrl(struct uart_port *port, unsigned int mctrl); #ifdef CONFIG_SERIAL_8250_PNP int serial8250_pnp_init(void); diff --git a/drivers/tty/serial/8250/8250_alpha.c b/drivers/tty/serial/8250/8250_alpha.c new file mode 100644 index 000000000000..58e70328aa4d --- /dev/null +++ b/drivers/tty/serial/8250/8250_alpha.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <asm/machvec.h> +#include "8250.h" + +bool alpha_jensen(void) +{ + return !strcmp(alpha_mv.vector_name, "Jensen"); +} + +void alpha_jensen_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* + * Digital did something really horribly wrong with the OUT1 and OUT2 + * lines on Alpha Jensen. The failure mode is that if either is + * cleared, the machine locks up with endless interrupts. + */ + mctrl |= TIOCM_OUT1 | TIOCM_OUT2; + + serial8250_do_set_mctrl(port, mctrl); +} diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 5163d60756b7..9b878d023dac 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -941,7 +941,7 @@ static int brcmuart_probe(struct platform_device *pdev) struct brcmuart_priv *priv; struct clk *baud_mux_clk; struct uart_8250_port up; - struct resource *irq; + int irq; void __iomem *membase = NULL; resource_size_t mapbase = 0; u32 clk_rate = 0; @@ -952,11 +952,9 @@ static int brcmuart_probe(struct platform_device *pdev) "uart", "dma_rx", "dma_tx", "dma_intr2", "dma_arb" }; - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(dev, "missing irq\n"); - return -EINVAL; - } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; priv = devm_kzalloc(dev, sizeof(struct brcmuart_priv), GFP_KERNEL); if (!priv) @@ -1044,7 +1042,7 @@ static int brcmuart_probe(struct platform_device *pdev) up.port.dev = dev; up.port.mapbase = mapbase; up.port.membase = membase; - up.port.irq = irq->start; + up.port.irq = irq; up.port.handle_irq = brcmuart_handle_irq; up.port.regshift = 2; up.port.iotype = of_device_is_big_endian(np) ? @@ -1076,14 +1074,18 @@ static int brcmuart_probe(struct platform_device *pdev) priv->rx_bufs = dma_alloc_coherent(dev, priv->rx_size, &priv->rx_addr, GFP_KERNEL); - if (!priv->rx_bufs) + if (!priv->rx_bufs) { + ret = -ENOMEM; goto err; + } priv->tx_size = UART_XMIT_SIZE; priv->tx_buf = dma_alloc_coherent(dev, priv->tx_size, &priv->tx_addr, GFP_KERNEL); - if (!priv->tx_buf) + if (!priv->tx_buf) { + ret = -ENOMEM; goto err; + } } ret = serial8250_register_8250_port(&up); @@ -1097,6 +1099,7 @@ static int brcmuart_probe(struct platform_device *pdev) if (priv->dma_enabled) { dma_irq = platform_get_irq_byname(pdev, "dma"); if (dma_irq < 0) { + ret = dma_irq; dev_err(dev, "no IRQ resource info\n"); goto err1; } @@ -1116,7 +1119,7 @@ err1: err: brcmuart_free_bufs(dev, priv); brcmuart_arbitration(priv, 0); - return -ENODEV; + return ret; } static int brcmuart_remove(struct platform_device *pdev) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 1ce193daea7f..01d30f6ed8fb 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -509,11 +509,10 @@ static void __init serial8250_isa_init_ports(void) up->ops = &univ8250_driver_ops; - /* - * ALPHA_KLUDGE_MCR needs to be killed. - */ - up->mcr_mask = ~ALPHA_KLUDGE_MCR; - up->mcr_force = ALPHA_KLUDGE_MCR; + if (IS_ENABLED(CONFIG_ALPHA_JENSEN) || + (IS_ENABLED(CONFIG_ALPHA_GENERIC) && alpha_jensen())) + port->set_mctrl = alpha_jensen_set_mctrl; + serial8250_set_defaults(up); } diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 60f8fffdfd77..e8b5469e9dfa 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1278,7 +1278,7 @@ static int pci_quatech_init(struct pci_dev *dev) outl(inl(base + 0x38) | 0x00002000, base + 0x38); tmp = inl(base + 0x3c); outl(tmp | 0x01000000, base + 0x3c); - outl(tmp &= ~0x01000000, base + 0x3c); + outl(tmp & ~0x01000000, base + 0x3c); } } return 0; @@ -1318,89 +1318,6 @@ static int pci_default_setup(struct serial_private *priv, return setup_port(priv, port, bar, offset, board->reg_shift); } -static void -pericom_do_set_divisor(struct uart_port *port, unsigned int baud, - unsigned int quot, unsigned int quot_frac) -{ - int scr; - int lcr; - - for (scr = 16; scr > 4; scr--) { - unsigned int maxrate = port->uartclk / scr; - unsigned int divisor = max(maxrate / baud, 1U); - int delta = maxrate / divisor - baud; - - if (baud > maxrate + baud / 50) - continue; - - if (delta > baud / 50) - divisor++; - - if (divisor > 0xffff) - continue; - - /* Update delta due to possible divisor change */ - delta = maxrate / divisor - baud; - if (abs(delta) < baud / 50) { - lcr = serial_port_in(port, UART_LCR); - serial_port_out(port, UART_LCR, lcr | 0x80); - serial_port_out(port, UART_DLL, divisor & 0xff); - serial_port_out(port, UART_DLM, divisor >> 8 & 0xff); - serial_port_out(port, 2, 16 - scr); - serial_port_out(port, UART_LCR, lcr); - return; - } - } -} -static int pci_pericom_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - unsigned int bar, offset = board->first_offset, maxnr; - - bar = FL_GET_BASE(board->flags); - if (board->flags & FL_BASE_BARS) - bar += idx; - else - offset += idx * board->uart_offset; - - - maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> - (board->reg_shift + 3); - - if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) - return 1; - - port->port.set_divisor = pericom_do_set_divisor; - - return setup_port(priv, port, bar, offset, board->reg_shift); -} - -static int pci_pericom_setup_four_at_eight(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - unsigned int bar, offset = board->first_offset, maxnr; - - bar = FL_GET_BASE(board->flags); - if (board->flags & FL_BASE_BARS) - bar += idx; - else - offset += idx * board->uart_offset; - - if (idx==3) - offset = 0x38; - - maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >> - (board->reg_shift + 3); - - if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) - return 1; - - port->port.set_divisor = pericom_do_set_divisor; - - return setup_port(priv, port, bar, offset, board->reg_shift); -} static int ce4100_serial_setup(struct serial_private *priv, @@ -1886,42 +1803,6 @@ pci_moxa_setup(struct serial_private *priv, #define PCIE_DEVICE_ID_WCH_CH384_8S 0x3853 #define PCIE_DEVICE_ID_WCH_CH382_2S 0x3253 -#define PCI_VENDOR_ID_ACCESIO 0x494f -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB 0x1051 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S 0x1053 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB 0x105C -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S 0x105E -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB 0x1091 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2 0x1093 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB 0x1099 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4 0x109B -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB 0x10D1 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM 0x10D3 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB 0x10DA -#define PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM 0x10DC -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1 0x1108 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2 0x1110 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2 0x1111 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4 0x1118 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4 0x1119 -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S 0x1152 -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S 0x115A -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2 0x1190 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2 0x1191 -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4 0x1198 -#define PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4 0x1199 -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM 0x11D0 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4 0x105A -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4 0x105B -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8 0x106A -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8 0x106B -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4 0x1098 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8 0x10A9 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM 0x10D9 -#define PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM 0x10E9 -#define PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM 0x11D8 - - #define PCI_DEVICE_ID_MOXA_CP102E 0x1024 #define PCI_DEVICE_ID_MOXA_CP102EL 0x1025 #define PCI_DEVICE_ID_MOXA_CP104EL_A 0x1045 @@ -2199,16 +2080,6 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .exit = pci_plx9050_exit, }, /* - * Pericom (Only 7954 - It have a offset jump for port 4) - */ - { - .vendor = PCI_VENDOR_ID_PERICOM, - .device = PCI_DEVICE_ID_PERICOM_PI7C9X7954, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - /* * PLX */ { @@ -2238,125 +2109,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .setup = pci_default_setup, .exit = pci_plx9050_exit, }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup_four_at_eight, - }, - { - .vendor = PCI_VENDOR_ID_ACCESIO, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pci_pericom_setup, - }, /* + /* * SBS Technologies, Inc., PMC-OCTALPRO 232 */ { @@ -2948,10 +2701,6 @@ enum pci_board_num_t { pbn_wch382_2, pbn_wch384_4, pbn_wch384_8, - pbn_pericom_PI7C9X7951, - pbn_pericom_PI7C9X7952, - pbn_pericom_PI7C9X7954, - pbn_pericom_PI7C9X7958, pbn_sunix_pci_1s, pbn_sunix_pci_2s, pbn_sunix_pci_4s, @@ -3696,33 +3445,6 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 8, .first_offset = 0x00, }, - /* - * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART - */ - [pbn_pericom_PI7C9X7951] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 921600, - .uart_offset = 0x8, - }, - [pbn_pericom_PI7C9X7952] = { - .flags = FL_BASE0, - .num_ports = 2, - .base_baud = 921600, - .uart_offset = 0x8, - }, - [pbn_pericom_PI7C9X7954] = { - .flags = FL_BASE0, - .num_ports = 4, - .base_baud = 921600, - .uart_offset = 0x8, - }, - [pbn_pericom_PI7C9X7958] = { - .flags = FL_BASE0, - .num_ports = 8, - .base_baud = 921600, - .uart_offset = 0x8, - }, [pbn_sunix_pci_1s] = { .num_ports = 1, .base_baud = 921600, @@ -3834,6 +3556,10 @@ static const struct pci_device_id blacklist[] = { { PCI_VDEVICE(EXAR, PCI_ANY_ID), }, { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), }, + /* Pericom devices */ + { PCI_VDEVICE(PERICOM, PCI_ANY_ID), }, + { PCI_VDEVICE(ACCESSIO, PCI_ANY_ID), }, + /* End of the black list */ { } }; @@ -5028,127 +4754,6 @@ static const struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b3_8_115200 }, /* - * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART - */ - { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7951, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_pericom_PI7C9X7951 }, - { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7952, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7954, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7958, - PCI_ANY_ID, PCI_ANY_ID, - 0, - 0, pbn_pericom_PI7C9X7958 }, - /* - * ACCES I/O Products quad - */ - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7951 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7952 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, - { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, - /* * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) */ { PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560, diff --git a/drivers/tty/serial/8250/8250_pericom.c b/drivers/tty/serial/8250/8250_pericom.c new file mode 100644 index 000000000000..025b055363c3 --- /dev/null +++ b/drivers/tty/serial/8250/8250_pericom.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Driver for Pericom UART */ + +#include <linux/bits.h> +#include <linux/module.h> +#include <linux/overflow.h> +#include <linux/pci.h> + +#include "8250.h" + +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SDB 0x1051 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2S 0x1053 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_4 0x105a +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_4 0x105b +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SDB 0x105c +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4S 0x105e +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_8 0x106a +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_8 0x106b +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_2DB 0x1091 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_2 0x1093 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4 0x1098 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4DB 0x1099 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_4 0x109b +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_8 0x10a9 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SMDB 0x10d1 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2SM 0x10d3 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SM 0x10d9 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SMDB 0x10da +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4SM 0x10dc +#define PCI_DEVICE_ID_ACCESSIO_PCIE_COM_8SM 0x10e9 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_1 0x1108 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_2 0x1110 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_2 0x1111 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_4 0x1118 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_4 0x1119 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2S 0x1152 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4S 0x115a +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_2 0x1190 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_2 0x1191 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_4 0x1198 +#define PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_4 0x1199 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2SM 0x11d0 +#define PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4SM 0x11d8 + +struct pericom8250 { + void __iomem *virt; + unsigned int nr; + int line[]; +}; + +static void pericom_do_set_divisor(struct uart_port *port, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + int scr; + + for (scr = 16; scr > 4; scr--) { + unsigned int maxrate = port->uartclk / scr; + unsigned int divisor = max(maxrate / baud, 1U); + int delta = maxrate / divisor - baud; + + if (baud > maxrate + baud / 50) + continue; + + if (delta > baud / 50) + divisor++; + + if (divisor > 0xffff) + continue; + + /* Update delta due to possible divisor change */ + delta = maxrate / divisor - baud; + if (abs(delta) < baud / 50) { + struct uart_8250_port *up = up_to_u8250p(port); + int lcr = serial_port_in(port, UART_LCR); + + serial_port_out(port, UART_LCR, lcr | 0x80); + serial_dl_write(up, divisor); + serial_port_out(port, 2, 16 - scr); + serial_port_out(port, UART_LCR, lcr); + return; + } + } +} + +static int pericom8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + unsigned int nr, i, bar = 0, maxnr; + struct pericom8250 *pericom; + struct uart_8250_port uart; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + maxnr = pci_resource_len(pdev, bar) >> 3; + + if (pdev->vendor == PCI_VENDOR_ID_PERICOM) + nr = pdev->device & 0x0f; + else if (pdev->vendor == PCI_VENDOR_ID_ACCESSIO) + nr = BIT(((pdev->device & 0x38) >> 3) - 1); + else + nr = 1; + + pericom = devm_kzalloc(&pdev->dev, struct_size(pericom, line, nr), GFP_KERNEL); + if (!pericom) + return -ENOMEM; + + pericom->virt = pcim_iomap(pdev, bar, 0); + if (!pericom->virt) + return -ENOMEM; + + memset(&uart, 0, sizeof(uart)); + + uart.port.dev = &pdev->dev; + uart.port.irq = pdev->irq; + uart.port.private_data = pericom; + uart.port.iotype = UPIO_PORT; + uart.port.uartclk = 921600 * 16; + uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ | UPF_MAGIC_MULTIPLIER; + uart.port.set_divisor = pericom_do_set_divisor; + for (i = 0; i < nr && i < maxnr; i++) { + unsigned int offset = (i == 3 && nr == 4) ? 0x38 : i * 0x8; + + uart.port.iobase = pci_resource_start(pdev, bar) + offset; + + dev_dbg(&pdev->dev, "Setup PCI port: port %lx, irq %d, type %d\n", + uart.port.iobase, uart.port.irq, uart.port.iotype); + + pericom->line[i] = serial8250_register_8250_port(&uart); + if (pericom->line[i] < 0) { + dev_err(&pdev->dev, + "Couldn't register serial port %lx, irq %d, type %d, error %d\n", + uart.port.iobase, uart.port.irq, + uart.port.iotype, pericom->line[i]); + break; + } + } + pericom->nr = i; + + pci_set_drvdata(pdev, pericom); + return 0; +} + +static void pericom8250_remove(struct pci_dev *pdev) +{ + struct pericom8250 *pericom = pci_get_drvdata(pdev); + unsigned int i; + + for (i = 0; i < pericom->nr; i++) + serial8250_unregister_port(pericom->line[i]); +} + +static const struct pci_device_id pericom8250_pci_ids[] = { + /* + * Pericom PI7C9X795[1248] Uno/Dual/Quad/Octal UART + * (Only 7954 has an offset jump for port 4) + */ + { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7951) }, + { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7952) }, + { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7954) }, + { PCI_VDEVICE(PERICOM, PCI_DEVICE_ID_PERICOM_PI7C9X7958) }, + + /* + * ACCES I/O Products quad + * (Only 7954 has an offset jump for port 4) + */ + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SDB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2S) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SDB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4S) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM422_8) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM485_8) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_2DB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_2) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_4DB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM232_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM232_8) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_2SMDB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_2SM) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SM) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_4SMDB) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_COM_4SM) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_COM_8SM) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_1) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_2) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_2) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM422_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM485_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2S) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4S) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_2) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_2) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM232_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_MPCIE_ICM232_4) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_2SM) }, + { PCI_VDEVICE(ACCESSIO, PCI_DEVICE_ID_ACCESSIO_PCIE_ICM_4SM) }, + { } +}; +MODULE_DEVICE_TABLE(pci, pericom8250_pci_ids); + +static struct pci_driver pericom8250_pci_driver = { + .name = "8250_pericom", + .id_table = pericom8250_pci_ids, + .probe = pericom8250_probe, + .remove = pericom8250_remove, +}; +module_pci_driver(pericom8250_pci_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Pericom UART driver"); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 46e2079ad1aa..2abb3de11a48 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2026,7 +2026,7 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) mcr = serial8250_TIOCM_to_MCR(mctrl); - mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; + mcr |= up->mcr; serial8250_out_MCR(up, mcr); } @@ -2056,10 +2056,7 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state) serial8250_rpm_put(up); } -/* - * Wait for transmitter & holding register to empty - */ -static void wait_for_xmitr(struct uart_8250_port *up, int bits) +static void wait_for_lsr(struct uart_8250_port *up, int bits) { unsigned int status, tmout = 10000; @@ -2076,6 +2073,16 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits) udelay(1); touch_nmi_watchdog(); } +} + +/* + * Wait for transmitter & holding register to empty + */ +static void wait_for_xmitr(struct uart_8250_port *up, int bits) +{ + unsigned int tmout; + + wait_for_lsr(up, bits); /* Wait up to 1s for flow control if necessary */ if (up->port.flags & UPF_CONS_FLOW) { @@ -3092,7 +3099,7 @@ static ssize_t rx_trig_bytes_show(struct device *dev, if (rxtrig_bytes < 0) return rxtrig_bytes; - return snprintf(buf, PAGE_SIZE, "%d\n", rxtrig_bytes); + return sysfs_emit(buf, "%d\n", rxtrig_bytes); } static int do_set_rxtrig(struct tty_port *port, unsigned char bytes) @@ -3326,6 +3333,35 @@ static void serial8250_console_restore(struct uart_8250_port *up) } /* + * Print a string to the serial port using the device FIFO + * + * It sends fifosize bytes and then waits for the fifo + * to get empty. + */ +static void serial8250_console_fifo_write(struct uart_8250_port *up, + const char *s, unsigned int count) +{ + int i; + const char *end = s + count; + unsigned int fifosize = up->port.fifosize; + bool cr_sent = false; + + while (s != end) { + wait_for_lsr(up, UART_LSR_THRE); + + for (i = 0; i < fifosize && s != end; ++i) { + if (*s == '\n' && !cr_sent) { + serial_out(up, UART_TX, '\r'); + cr_sent = true; + } else { + serial_out(up, UART_TX, *s++); + cr_sent = false; + } + } + } +} + +/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * @@ -3340,7 +3376,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, struct uart_8250_em485 *em485 = up->em485; struct uart_port *port = &up->port; unsigned long flags; - unsigned int ier; + unsigned int ier, use_fifo; int locked = 1; touch_nmi_watchdog(); @@ -3372,7 +3408,20 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, mdelay(port->rs485.delay_rts_before_send); } - uart_console_write(port, s, count, serial8250_console_putchar); + use_fifo = (up->capabilities & UART_CAP_FIFO) && + port->fifosize > 1 && + (serial_port_in(port, UART_FCR) & UART_FCR_ENABLE_FIFO) && + /* + * After we put a data in the fifo, the controller will send + * it regardless of the CTS state. Therefore, only use fifo + * if we don't use control flow. + */ + !(up->port.flags & UPF_CONS_FLOW); + + if (likely(use_fifo)) + serial8250_console_fifo_write(up, s, count); + else + uart_console_write(port, s, count, serial8250_console_putchar); /* * Finally, wait for transmitter to become empty diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 8cd11aa63ed5..9d415a38cc71 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -498,6 +498,14 @@ config SERIAL_8250_MID present on the UART found on Intel Medfield SOC and various other Intel platforms. +config SERIAL_8250_PERICOM + tristate "Support for Pericom and Acces I/O serial ports" + default SERIAL_8250 + depends on SERIAL_8250 && PCI + help + Selecting this option will enable handling of the extra features + present on the Pericom and Acces I/O UARTs. + config SERIAL_8250_PXA tristate "PXA serial port support" depends on SERIAL_8250 diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index b9bcd73c8997..bee908f99ea0 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -5,6 +5,8 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o 8250-y := 8250_core.o +8250-$(CONFIG_ALPHA_GENERIC) += 8250_alpha.o +8250-$(CONFIG_ALPHA_JENSEN) += 8250_alpha.o 8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o 8250_base-y := 8250_port.o 8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o @@ -36,6 +38,7 @@ obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o +obj-$(CONFIG_SERIAL_8250_PERICOM) += 8250_pericom.o obj-$(CONFIG_SERIAL_8250_PXA) += 8250_pxa.o obj-$(CONFIG_SERIAL_8250_TEGRA) += 8250_tegra.o obj-$(CONFIG_SERIAL_8250_BCM7271) += 8250_bcm7271.o diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index fc543ac97c13..0e5ccb25bdb1 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -263,7 +263,7 @@ config SERIAL_SAMSUNG_UARTS config SERIAL_SAMSUNG_CONSOLE bool "Support for console on Samsung SoC serial port" - depends on SERIAL_SAMSUNG=y + depends on SERIAL_SAMSUNG select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON help diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c index 23c4e0e79694..37bffe406b18 100644 --- a/drivers/tty/serial/altera_jtaguart.c +++ b/drivers/tty/serial/altera_jtaguart.c @@ -418,8 +418,9 @@ static int altera_jtaguart_probe(struct platform_device *pdev) struct altera_jtaguart_platform_uart *platp = dev_get_platdata(&pdev->dev); struct uart_port *port; - struct resource *res_irq, *res_mem; + struct resource *res_mem; int i = pdev->id; + int irq; /* -1 emphasizes that the platform must have one port, no .N suffix */ if (i == -1) @@ -438,9 +439,11 @@ static int altera_jtaguart_probe(struct platform_device *pdev) else return -ENODEV; - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res_irq) - port->irq = res_irq->start; + irq = platform_get_irq_optional(pdev, 0); + if (irq < 0 && irq != -ENXIO) + return irq; + if (irq > 0) + port->irq = irq; else if (platp) port->irq = platp->irq; else diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 7c5f4e966b59..64a352b40197 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -553,7 +553,6 @@ static int altera_uart_probe(struct platform_device *pdev) struct altera_uart_platform_uart *platp = dev_get_platdata(&pdev->dev); struct uart_port *port; struct resource *res_mem; - struct resource *res_irq; int i = pdev->id; int ret; @@ -577,9 +576,11 @@ static int altera_uart_probe(struct platform_device *pdev) else return -EINVAL; - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res_irq) - port->irq = res_irq->start; + ret = platform_get_irq_optional(pdev, 0); + if (ret < 0 && ret != -ENXIO) + return ret; + if (ret > 0) + port->irq = ret; else if (platp) port->irq = platp->irq; diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index e744b953ca34..47654073123d 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -446,14 +446,11 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, if ((termios->c_cflag & CREAD) == 0) uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX; - /* first, disable everything */ old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE; if (UART_ENABLE_MS(port, termios->c_cflag)) old_cr |= UART010_CR_MSIE; - writel(0, uap->port.membase + UART010_CR); - /* Set baud rate */ quot -= 1; writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM); diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 52518a606c06..1f1df46242f9 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -188,38 +188,6 @@ static struct vendor_data vendor_st = { .get_fifosize = get_fifosize_st, }; -static const u16 pl011_zte_offsets[REG_ARRAY_SIZE] = { - [REG_DR] = ZX_UART011_DR, - [REG_FR] = ZX_UART011_FR, - [REG_LCRH_RX] = ZX_UART011_LCRH, - [REG_LCRH_TX] = ZX_UART011_LCRH, - [REG_IBRD] = ZX_UART011_IBRD, - [REG_FBRD] = ZX_UART011_FBRD, - [REG_CR] = ZX_UART011_CR, - [REG_IFLS] = ZX_UART011_IFLS, - [REG_IMSC] = ZX_UART011_IMSC, - [REG_RIS] = ZX_UART011_RIS, - [REG_MIS] = ZX_UART011_MIS, - [REG_ICR] = ZX_UART011_ICR, - [REG_DMACR] = ZX_UART011_DMACR, -}; - -static unsigned int get_fifosize_zte(struct amba_device *dev) -{ - return 16; -} - -static struct vendor_data vendor_zte = { - .reg_offset = pl011_zte_offsets, - .access_32b = true, - .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - .fr_busy = ZX_UART01x_FR_BUSY, - .fr_dsr = ZX_UART01x_FR_DSR, - .fr_cts = ZX_UART01x_FR_CTS, - .fr_ri = ZX_UART011_FR_RI, - .get_fifosize = get_fifosize_zte, -}; - /* Deals with DMA transactions */ struct pl011_sgbuf { @@ -262,7 +230,6 @@ struct uart_amba_port { unsigned int im; /* interrupt mask */ unsigned int old_status; unsigned int fifosize; /* vendor-specific */ - unsigned int old_cr; /* state during shutdown */ unsigned int fixed_baud; /* vendor-set fixed baud rate */ char type[12]; bool rs485_tx_started; @@ -1837,8 +1804,8 @@ static int pl011_startup(struct uart_port *port) spin_lock_irq(&uap->port.lock); - /* restore RTS and DTR */ - cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); + cr = pl011_read(uap, REG_CR); + cr &= UART011_CR_RTS | UART011_CR_DTR; cr |= UART01x_CR_UARTEN | UART011_CR_RXE; if (port->rs485.flags & SER_RS485_ENABLED) { @@ -1915,7 +1882,6 @@ static void pl011_disable_uart(struct uart_amba_port *uap) uap->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); spin_lock_irq(&uap->port.lock); cr = pl011_read(uap, REG_CR); - uap->old_cr = cr; cr &= UART011_CR_RTS | UART011_CR_DTR; cr |= UART01x_CR_UARTEN | UART011_CR_TXE; pl011_write(cr, uap, REG_CR); @@ -2105,9 +2071,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, if (port->rs485.flags & SER_RS485_ENABLED) termios->c_cflag &= ~CRTSCTS; - /* first, disable everything */ old_cr = pl011_read(uap, REG_CR); - pl011_write(0, uap, REG_CR); if (termios->c_cflag & CRTSCTS) { if (old_cr & UART011_CR_RTS) @@ -2184,31 +2148,12 @@ static const char *pl011_type(struct uart_port *port) } /* - * Release the memory region(s) being used by 'port' - */ -static void pl011_release_port(struct uart_port *port) -{ - release_mem_region(port->mapbase, SZ_4K); -} - -/* - * Request the memory region(s) being used by 'port' - */ -static int pl011_request_port(struct uart_port *port) -{ - return request_mem_region(port->mapbase, SZ_4K, "uart-pl011") - != NULL ? 0 : -EBUSY; -} - -/* * Configure/autoconfigure the port. */ static void pl011_config_port(struct uart_port *port, int flags) { - if (flags & UART_CONFIG_TYPE) { + if (flags & UART_CONFIG_TYPE) port->type = PORT_AMBA; - pl011_request_port(port); - } } /* @@ -2223,6 +2168,8 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser) ret = -EINVAL; if (ser->baud_base < 9600) ret = -EINVAL; + if (port->mapbase != (unsigned long) ser->iomem_base) + ret = -EINVAL; return ret; } @@ -2275,8 +2222,6 @@ static const struct uart_ops amba_pl011_pops = { .flush_buffer = pl011_dma_flush_buffer, .set_termios = pl011_set_termios, .type = pl011_type, - .release_port = pl011_release_port, - .request_port = pl011_request_port, .config_port = pl011_config_port, .verify_port = pl011_verify_port, #ifdef CONFIG_CONSOLE_POLL @@ -2306,8 +2251,6 @@ static const struct uart_ops sbsa_uart_pops = { .shutdown = sbsa_uart_shutdown, .set_termios = sbsa_uart_set_termios, .type = pl011_type, - .release_port = pl011_release_port, - .request_port = pl011_request_port, .config_port = pl011_config_port, .verify_port = pl011_verify_port, #ifdef CONFIG_CONSOLE_POLL @@ -2754,7 +2697,6 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, index = pl011_probe_dt_alias(index, dev); - uap->old_cr = 0; uap->port.dev = dev; uap->port.mapbase = mmiobase->start; uap->port.membase = base; @@ -2975,11 +2917,6 @@ static const struct amba_id pl011_ids[] = { .mask = 0x00ffffff, .data = &vendor_st, }, - { - .id = AMBA_LINUX_ID(0x00, 0x1, 0xffe), - .mask = 0x00ffffff, - .data = &vendor_zte, - }, { 0, 0 }, }; diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index 4379ca4842ae..8cabe50c4a33 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -707,11 +707,11 @@ static int ar933x_uart_probe(struct platform_device *pdev) struct ar933x_uart_port *up; struct uart_port *port; struct resource *mem_res; - struct resource *irq_res; struct device_node *np; unsigned int baud; int id; int ret; + int irq; np = pdev->dev.of_node; if (IS_ENABLED(CONFIG_OF) && np) { @@ -730,11 +730,9 @@ static int ar933x_uart_probe(struct platform_device *pdev) if (id >= CONFIG_SERIAL_AR933X_NR_UARTS) return -EINVAL; - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq_res) { - dev_err(&pdev->dev, "no IRQ resource\n"); - return -EINVAL; - } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; up = devm_kzalloc(&pdev->dev, sizeof(struct ar933x_uart_port), GFP_KERNEL); @@ -766,7 +764,7 @@ static int ar933x_uart_probe(struct platform_device *pdev) port->mapbase = mem_res->start; port->line = id; - port->irq = irq_res->start; + port->irq = irq; port->dev = &pdev->dev; port->type = PORT_AR933X; port->iotype = UPIO_MEM32; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 2c99a47a2535..c370eddc651b 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1004,6 +1004,13 @@ static void atmel_tx_dma(struct uart_port *port) desc->callback = atmel_complete_tx_dma; desc->callback_param = atmel_port; atmel_port->cookie_tx = dmaengine_submit(desc); + if (dma_submit_error(atmel_port->cookie_tx)) { + dev_err(port->dev, "dma_submit_error %d\n", + atmel_port->cookie_tx); + return; + } + + dma_async_issue_pending(chan); } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -1258,6 +1265,13 @@ static int atmel_prepare_rx_dma(struct uart_port *port) desc->callback_param = port; atmel_port->desc_rx = desc; atmel_port->cookie_rx = dmaengine_submit(desc); + if (dma_submit_error(atmel_port->cookie_rx)) { + dev_err(port->dev, "dma_submit_error %d\n", + atmel_port->cookie_rx); + goto chan_err; + } + + dma_async_issue_pending(atmel_port->chan_rx); return 0; @@ -2479,7 +2493,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port, port->fifosize = 1; port->dev = &pdev->dev; port->mapbase = mpdev->resource[0].start; - port->irq = mpdev->resource[1].start; + port->irq = platform_get_irq(mpdev, 0); port->rs485_config = atmel_config_rs485; port->iso7816_config = atmel_config_iso7816; port->membase = NULL; diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c index 5fb0e84f7fd1..6471a54b616b 100644 --- a/drivers/tty/serial/bcm63xx_uart.c +++ b/drivers/tty/serial/bcm63xx_uart.c @@ -804,7 +804,7 @@ static struct uart_driver bcm_uart_driver = { */ static int bcm_uart_probe(struct platform_device *pdev) { - struct resource *res_mem, *res_irq; + struct resource *res_mem; struct uart_port *port; struct clk *clk; int ret; @@ -833,9 +833,10 @@ static int bcm_uart_probe(struct platform_device *pdev) if (IS_ERR(port->membase)) return PTR_ERR(port->membase); - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_irq) - return -ENODEV; + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + port->irq = ret; clk = clk_get(&pdev->dev, "refclk"); if (IS_ERR(clk) && pdev->dev.of_node) @@ -845,7 +846,6 @@ static int bcm_uart_probe(struct platform_device *pdev) return -ENODEV; port->iotype = UPIO_MEM; - port->irq = res_irq->start; port->ops = &bcm_uart_ops; port->flags = UPF_BOOT_AUTOCONF; port->dev = &pdev->dev; diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index ac5112def40d..ce3e26144689 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -247,6 +247,7 @@ enum lpuart_type { LS1028A_LPUART, IMX7ULP_LPUART, IMX8QXP_LPUART, + IMXRT1050_LPUART, }; struct lpuart_port { @@ -310,6 +311,11 @@ static struct lpuart_soc_data imx8qxp_data = { .iotype = UPIO_MEM32, .reg_off = IMX_REG_OFF, }; +static struct lpuart_soc_data imxrt1050_data = { + .devtype = IMXRT1050_LPUART, + .iotype = UPIO_MEM32, + .reg_off = IMX_REG_OFF, +}; static const struct of_device_id lpuart_dt_ids[] = { { .compatible = "fsl,vf610-lpuart", .data = &vf_data, }, @@ -317,6 +323,7 @@ static const struct of_device_id lpuart_dt_ids[] = { { .compatible = "fsl,ls1028a-lpuart", .data = &ls1028a_data, }, { .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, }, { .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, }, + { .compatible = "fsl,imxrt1050-lpuart", .data = &imxrt1050_data}, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, lpuart_dt_ids); @@ -1793,8 +1800,8 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport) } if (sport->lpuart_dma_tx_use) { - if (wait_event_interruptible(sport->dma_wait, - !sport->dma_tx_in_progress) != false) { + if (wait_event_interruptible_timeout(sport->dma_wait, + !sport->dma_tx_in_progress, msecs_to_jiffies(300)) <= 0) { sport->dma_tx_in_progress = false; dmaengine_terminate_all(sport->dma_tx_chan); } @@ -2626,6 +2633,7 @@ OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1028a-lpuart", ls1028a_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,imx8qxp-lpuart", lpuart32_imx_early_console_setup); +OF_EARLYCON_DECLARE(lpuart32, "fsl,imxrt1050-lpuart", lpuart32_imx_early_console_setup); EARLYCON_DECLARE(lpuart, lpuart_early_console_setup); EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup); diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 90f82e6c54e4..df8a0c8b8b29 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -486,18 +486,21 @@ static void imx_uart_stop_tx(struct uart_port *port) static void imx_uart_stop_rx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - u32 ucr1, ucr2; + u32 ucr1, ucr2, ucr4; ucr1 = imx_uart_readl(sport, UCR1); ucr2 = imx_uart_readl(sport, UCR2); + ucr4 = imx_uart_readl(sport, UCR4); if (sport->dma_is_enabled) { ucr1 &= ~(UCR1_RXDMAEN | UCR1_ATDMAEN); } else { ucr1 &= ~UCR1_RRDYEN; ucr2 &= ~UCR2_ATEN; + ucr4 &= ~UCR4_OREN; } imx_uart_writel(sport, ucr1, UCR1); + imx_uart_writel(sport, ucr4, UCR4); ucr2 &= ~UCR2_RXEN; imx_uart_writel(sport, ucr2, UCR2); @@ -1544,7 +1547,7 @@ static void imx_uart_shutdown(struct uart_port *port) imx_uart_writel(sport, ucr1, UCR1); ucr4 = imx_uart_readl(sport, UCR4); - ucr4 &= ~(UCR4_OREN | UCR4_TCEN); + ucr4 &= ~UCR4_TCEN; imx_uart_writel(sport, ucr4, UCR4); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -2482,10 +2485,12 @@ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) if (sport->have_rtscts) { u32 ucr1 = imx_uart_readl(sport, UCR1); - if (on) + if (on) { + imx_uart_writel(sport, USR1_RTSD, USR1); ucr1 |= UCR1_RTSDEN; - else + } else { ucr1 &= ~UCR1_RTSDEN; + } imx_uart_writel(sport, ucr1, UCR1); } } diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 497b334bc845..3e324d3f0a6d 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -16,8 +16,6 @@ #include <linux/ioport.h> #include <linux/lantiq.h> #include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> #include <linux/of_platform.h> #include <linux/serial.h> #include <linux/serial_core.h> @@ -728,19 +726,23 @@ static struct uart_driver lqasc_reg = { static int fetch_irq_lantiq(struct device *dev, struct ltq_uart_port *ltq_port) { struct uart_port *port = <q_port->port; - struct resource irqres[3]; - int ret; - - ret = of_irq_to_resource_table(dev->of_node, irqres, 3); - if (ret != 3) { - dev_err(dev, - "failed to get IRQs for serial port\n"); - return -ENODEV; - } - ltq_port->tx_irq = irqres[0].start; - ltq_port->rx_irq = irqres[1].start; - ltq_port->err_irq = irqres[2].start; - port->irq = irqres[0].start; + struct platform_device *pdev = to_platform_device(dev); + int irq; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + ltq_port->tx_irq = irq; + irq = platform_get_irq(pdev, 1); + if (irq < 0) + return irq; + ltq_port->rx_irq = irq; + irq = platform_get_irq(pdev, 2); + if (irq < 0) + return irq; + ltq_port->err_irq = irq; + + port->irq = ltq_port->tx_irq; return 0; } @@ -793,7 +795,7 @@ static int fetch_irq_intel(struct device *dev, struct ltq_uart_port *ltq_port) struct uart_port *port = <q_port->port; int ret; - ret = of_irq_get(dev->of_node, 0); + ret = platform_get_irq(to_platform_device(dev), 0); if (ret < 0) { dev_err(dev, "failed to fetch IRQ for serial port\n"); return ret; diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c index 2941659e5274..7f74bf7bdcff 100644 --- a/drivers/tty/serial/liteuart.c +++ b/drivers/tty/serial/liteuart.c @@ -436,4 +436,4 @@ module_exit(liteuart_exit); MODULE_AUTHOR("Antmicro <www.antmicro.com>"); MODULE_DESCRIPTION("LiteUART serial driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform: liteuart"); +MODULE_ALIAS("platform:liteuart"); diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index b199d7859961..07c4161eb4cc 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -341,7 +341,7 @@ static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id) LPC32XX_HSUART_IIR(port->membase)); port->icount.overrun++; tty_insert_flip_char(tport, 0, TTY_OVERRUN); - tty_schedule_flip(tport); + tty_flip_buffer_push(tport); } /* Data received? */ diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index efee3935917f..45e00d928253 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -622,10 +622,7 @@ meson_serial_early_console_setup(struct earlycon_device *device, const char *opt device->con->write = meson_serial_early_console_write; return 0; } -/* Legacy bindings, should be removed when no more used */ -OF_EARLYCON_DECLARE(meson, "amlogic,meson-uart", - meson_serial_early_console_setup); -/* Stable bindings */ + OF_EARLYCON_DECLARE(meson, "amlogic,meson-ao-uart", meson_serial_early_console_setup); @@ -668,25 +665,6 @@ static inline struct clk *meson_uart_probe_clock(struct device *dev, return clk; } -/* - * This function gets clocks in the legacy non-stable DT bindings. - * This code will be remove once all the platforms switch to the - * new DT bindings. - */ -static int meson_uart_probe_clocks_legacy(struct platform_device *pdev, - struct uart_port *port) -{ - struct clk *clk = NULL; - - clk = meson_uart_probe_clock(&pdev->dev, NULL); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - port->uartclk = clk_get_rate(clk); - - return 0; -} - static int meson_uart_probe_clocks(struct platform_device *pdev, struct uart_port *port) { @@ -713,10 +691,11 @@ static int meson_uart_probe_clocks(struct platform_device *pdev, static int meson_uart_probe(struct platform_device *pdev) { - struct resource *res_mem, *res_irq; + struct resource *res_mem; struct uart_port *port; u32 fifosize = 64; /* Default is 64, 128 for EE UART_0 */ int ret = 0; + int irq; if (pdev->dev.of_node) pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); @@ -739,9 +718,9 @@ static int meson_uart_probe(struct platform_device *pdev) if (!res_mem) return -ENODEV; - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_irq) - return -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; of_property_read_u32(pdev->dev.of_node, "fifo-size", &fifosize); @@ -754,19 +733,14 @@ static int meson_uart_probe(struct platform_device *pdev) if (!port) return -ENOMEM; - /* Use legacy way until all platforms switch to new bindings */ - if (of_device_is_compatible(pdev->dev.of_node, "amlogic,meson-uart")) - ret = meson_uart_probe_clocks_legacy(pdev, port); - else - ret = meson_uart_probe_clocks(pdev, port); - + ret = meson_uart_probe_clocks(pdev, port); if (ret) return ret; port->iotype = UPIO_MEM; port->mapbase = res_mem->start; port->mapsize = resource_size(res_mem); - port->irq = res_irq->start; + port->irq = irq; port->flags = UPF_BOOT_AUTOCONF | UPF_LOW_LATENCY; port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MESON_CONSOLE); port->dev = &pdev->dev; @@ -804,9 +778,6 @@ static int meson_uart_remove(struct platform_device *pdev) } static const struct of_device_id meson_uart_dt_match[] = { - /* Legacy bindings, should be removed when no more used */ - { .compatible = "amlogic,meson-uart" }, - /* Stable bindings */ { .compatible = "amlogic,meson6-uart" }, { .compatible = "amlogic,meson8-uart" }, { .compatible = "amlogic,meson8b-uart" }, diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 12ce150b0ad4..5359236b32d6 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1702,17 +1702,21 @@ extern struct platform_device scc_a_pdev, scc_b_pdev; static int __init pmz_init_port(struct uart_pmac_port *uap) { - struct resource *r_ports, *r_irq; + struct resource *r_ports; + int irq; r_ports = platform_get_resource(uap->pdev, IORESOURCE_MEM, 0); - r_irq = platform_get_resource(uap->pdev, IORESOURCE_IRQ, 0); - if (!r_ports || !r_irq) + if (!r_ports) return -ENODEV; + irq = platform_get_irq(uap->pdev, 0); + if (irq < 0) + return irq; + uap->port.mapbase = r_ports->start; uap->port.membase = (unsigned char __iomem *) r_ports->start; uap->port.iotype = UPIO_MEM; - uap->port.irq = r_irq->start; + uap->port.irq = irq; uap->port.uartclk = ZS_CLOCK; uap->port.fifosize = 1; uap->port.ops = &pmz_pops; diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 41319ef96fa6..30b099746a75 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -842,14 +842,18 @@ static int serial_pxa_probe_dt(struct platform_device *pdev, static int serial_pxa_probe(struct platform_device *dev) { struct uart_pxa_port *sport; - struct resource *mmres, *irqres; + struct resource *mmres; int ret; + int irq; mmres = platform_get_resource(dev, IORESOURCE_MEM, 0); - irqres = platform_get_resource(dev, IORESOURCE_IRQ, 0); - if (!mmres || !irqres) + if (!mmres) return -ENODEV; + irq = platform_get_irq(dev, 0); + if (irq < 0) + return irq; + sport = kzalloc(sizeof(struct uart_pxa_port), GFP_KERNEL); if (!sport) return -ENOMEM; @@ -869,7 +873,7 @@ static int serial_pxa_probe(struct platform_device *dev) sport->port.type = PORT_PXA; sport->port.iotype = UPIO_MEM; sport->port.mapbase = mmres->start; - sport->port.irq = irqres->start; + sport->port.irq = irq; sport->port.fifosize = 64; sport->port.ops = &serial_pxa_pops; sport->port.dev = &dev->dev; diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c index ca084c10d0bb..d002a4e48ed9 100644 --- a/drivers/tty/serial/samsung_tty.c +++ b/drivers/tty/serial/samsung_tty.c @@ -65,7 +65,6 @@ enum s3c24xx_port_type { struct s3c24xx_uart_info { char *name; enum s3c24xx_port_type type; - bool has_usi; unsigned int port_type; unsigned int fifosize; unsigned long rx_fifomask; @@ -1357,28 +1356,6 @@ static int apple_s5l_serial_startup(struct uart_port *port) return ret; } -static void exynos_usi_init(struct uart_port *port) -{ - struct s3c24xx_uart_port *ourport = to_ourport(port); - struct s3c24xx_uart_info *info = ourport->info; - unsigned int val; - - if (!info->has_usi) - return; - - /* Clear the software reset of USI block (it's set at startup) */ - val = rd_regl(port, USI_CON); - val &= ~USI_CON_RESET_MASK; - wr_regl(port, USI_CON, val); - udelay(1); - - /* Continuously provide the clock to USI IP w/o gating (for Rx mode) */ - val = rd_regl(port, USI_OPTION); - val &= ~USI_OPTION_HWACG_MASK; - val |= USI_OPTION_HWACG_CLKREQ_ON; - wr_regl(port, USI_OPTION, val); -} - /* power power management control */ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, @@ -1405,8 +1382,6 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, if (!IS_ERR(ourport->baudclk)) clk_prepare_enable(ourport->baudclk); - - exynos_usi_init(port); break; default: dev_err(port->dev, "s3c24xx_serial: unknown pm %d\n", level); @@ -1740,15 +1715,21 @@ s3c24xx_serial_verify_port(struct uart_port *port, struct serial_struct *ser) static struct console s3c24xx_serial_console; -static int __init s3c24xx_serial_console_init(void) +static void __init s3c24xx_serial_register_console(void) { register_console(&s3c24xx_serial_console); - return 0; } -console_initcall(s3c24xx_serial_console_init); + +static void s3c24xx_serial_unregister_console(void) +{ + if (s3c24xx_serial_console.flags & CON_ENABLED) + unregister_console(&s3c24xx_serial_console); +} #define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console #else +static inline void s3c24xx_serial_register_console(void) { } +static inline void s3c24xx_serial_unregister_console(void) { } #define S3C24XX_SERIAL_CONSOLE NULL #endif @@ -2130,8 +2111,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, if (ret) pr_warn("uart: failed to enable baudclk\n"); - exynos_usi_init(port); - /* Keep all interrupts masked and cleared */ switch (ourport->info->type) { case TYPE_S3C6400: @@ -2521,7 +2500,8 @@ s3c24xx_serial_console_write(struct console *co, const char *s, uart_console_write(cons_uart, s, count, s3c24xx_serial_console_putchar); } -static void __init +/* Shouldn't be __init, as it can be instantiated from other module */ +static void s3c24xx_serial_get_options(struct uart_port *port, int *baud, int *parity, int *bits) { @@ -2584,7 +2564,8 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud, } } -static int __init +/* Shouldn't be __init, as it can be instantiated from other module */ +static int s3c24xx_serial_console_setup(struct console *co, char *options) { struct uart_port *port; @@ -2780,11 +2761,10 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { #endif #if defined(CONFIG_ARCH_EXYNOS) -#define EXYNOS_COMMON_SERIAL_DRV_DATA(_has_usi) \ +#define EXYNOS_COMMON_SERIAL_DRV_DATA() \ .info = &(struct s3c24xx_uart_info) { \ .name = "Samsung Exynos UART", \ .type = TYPE_S3C6400, \ - .has_usi = _has_usi, \ .port_type = PORT_S3C6400, \ .has_divslot = 1, \ .rx_fifomask = S5PV210_UFSTAT_RXMASK, \ @@ -2805,17 +2785,17 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = { } \ static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA(false), + EXYNOS_COMMON_SERIAL_DRV_DATA(), .fifosize = { 256, 64, 16, 16 }, }; static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA(false), + EXYNOS_COMMON_SERIAL_DRV_DATA(), .fifosize = { 64, 256, 16, 256 }, }; static struct s3c24xx_serial_drv_data exynos850_serial_drv_data = { - EXYNOS_COMMON_SERIAL_DRV_DATA(true), + EXYNOS_COMMON_SERIAL_DRV_DATA(), .fifosize = { 256, 64, 64, 64 }, }; @@ -2926,7 +2906,29 @@ static struct platform_driver samsung_serial_driver = { }, }; -module_platform_driver(samsung_serial_driver); +static int __init samsung_serial_init(void) +{ + int ret; + + s3c24xx_serial_register_console(); + + ret = platform_driver_register(&samsung_serial_driver); + if (ret) { + s3c24xx_serial_unregister_console(); + return ret; + } + + return 0; +} + +static void __exit samsung_serial_exit(void) +{ + platform_driver_unregister(&samsung_serial_driver); + s3c24xx_serial_unregister_console(); +} + +module_init(samsung_serial_init); +module_exit(samsung_serial_exit); #ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE /* diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 61e3dd0222af..dc40c4155356 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -162,7 +162,7 @@ static void uart_port_dtr_rts(struct uart_port *uport, int raise) int RTS_after_send = !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND); if (raise) { - if (rs485_on && !RTS_after_send) { + if (rs485_on && RTS_after_send) { uart_set_mctrl(uport, TIOCM_DTR); uart_clear_mctrl(uport, TIOCM_RTS); } else { @@ -171,7 +171,7 @@ static void uart_port_dtr_rts(struct uart_port *uport, int raise) } else { unsigned int clear = TIOCM_DTR; - clear |= (!rs485_on || !RTS_after_send) ? TIOCM_RTS : 0; + clear |= (!rs485_on || RTS_after_send) ? TIOCM_RTS : 0; uart_clear_mctrl(uport, clear); } } @@ -1701,17 +1701,13 @@ static void uart_port_shutdown(struct tty_port *port) */ wake_up_interruptible(&port->delta_msr_wait); - /* - * Free the IRQ and disable the port. - */ - if (uport) + if (uport) { + /* Free the IRQ and disable the port. */ uport->ops->shutdown(uport); - /* - * Ensure that the IRQ handler isn't running on another CPU. - */ - if (uport) + /* Ensure that the IRQ handler isn't running on another CPU. */ synchronize_irq(uport->irq); + } } static int uart_carrier_raised(struct tty_port *port) @@ -2393,7 +2389,8 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, * We probably don't need a spinlock around this, but */ spin_lock_irqsave(&port->lock, flags); - port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR); + port->mctrl &= TIOCM_DTR; + port->ops->set_mctrl(port, port->mctrl); spin_unlock_irqrestore(&port->lock, flags); /* diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 89ee43061d3a..968967d722d4 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -37,6 +37,7 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/scatterlist.h> #include <linux/serial.h> #include <linux/serial_sci.h> @@ -895,11 +896,9 @@ static void sci_receive_chars(struct uart_port *port) if (status & SCxSR_FER(port)) { flag = TTY_FRAME; port->icount.frame++; - dev_notice(port->dev, "frame error\n"); } else if (status & SCxSR_PER(port)) { flag = TTY_PARITY; port->icount.parity++; - dev_notice(port->dev, "parity error\n"); } else flag = TTY_NORMAL; @@ -939,8 +938,6 @@ static int sci_handle_errors(struct uart_port *port) /* overrun error */ if (tty_insert_flip_char(tport, 0, TTY_OVERRUN)) copied++; - - dev_notice(port->dev, "overrun error\n"); } if (status & SCxSR_FER(port)) { @@ -949,8 +946,6 @@ static int sci_handle_errors(struct uart_port *port) if (tty_insert_flip_char(tport, 0, TTY_FRAME)) copied++; - - dev_notice(port->dev, "frame error\n"); } if (status & SCxSR_PER(port)) { @@ -959,8 +954,6 @@ static int sci_handle_errors(struct uart_port *port) if (tty_insert_flip_char(tport, 0, TTY_PARITY)) copied++; - - dev_notice(port->dev, "parity error\n"); } if (copied) @@ -990,8 +983,6 @@ static int sci_handle_fifo_overrun(struct uart_port *port) tty_insert_flip_char(tport, 0, TTY_OVERRUN); tty_flip_buffer_push(tport); - - dev_dbg(port->dev, "overrun error\n"); copied++; } @@ -1013,8 +1004,6 @@ static int sci_handle_breaks(struct uart_port *port) /* Notify of BREAK */ if (tty_insert_flip_char(tport, 0, TTY_BREAK)) copied++; - - dev_dbg(port->dev, "BREAK detected\n"); } if (copied) @@ -2778,44 +2767,29 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) clk_names[SCI_SCK] = "hsck"; for (i = 0; i < SCI_NUM_CLKS; i++) { - clk = devm_clk_get(dev, clk_names[i]); - if (PTR_ERR(clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - if (IS_ERR(clk) && i == SCI_FCK) { - /* - * "fck" used to be called "sci_ick", and we need to - * maintain DT backward compatibility. - */ - clk = devm_clk_get(dev, "sci_ick"); - if (PTR_ERR(clk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - - if (!IS_ERR(clk)) - goto found; + clk = devm_clk_get_optional(dev, clk_names[i]); + if (IS_ERR(clk)) + return PTR_ERR(clk); + if (!clk && i == SCI_FCK) { /* * Not all SH platforms declare a clock lookup entry * for SCI devices, in which case we need to get the * global "peripheral_clk" clock. */ clk = devm_clk_get(dev, "peripheral_clk"); - if (!IS_ERR(clk)) - goto found; - - dev_err(dev, "failed to get %s (%ld)\n", clk_names[i], - PTR_ERR(clk)); - return PTR_ERR(clk); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "failed to get %s\n", + clk_names[i]); } -found: - if (IS_ERR(clk)) - dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i], - PTR_ERR(clk)); + if (!clk) + dev_dbg(dev, "failed to get %s\n", clk_names[i]); else dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i], clk, clk_get_rate(clk)); - sci_port->clks[i] = IS_ERR(clk) ? NULL : clk; + sci_port->clks[i] = clk; } return 0; } @@ -3180,6 +3154,9 @@ static const struct of_device_id of_sci_match[] = { }, { .compatible = "renesas,rcar-gen3-scif", .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE), + }, { + .compatible = "renesas,rcar-gen4-scif", + .data = SCI_OF_DATA(PORT_SCIF, SCIx_SH4_SCIF_BRG_REGTYPE), }, /* Generic types */ { @@ -3203,23 +3180,47 @@ static const struct of_device_id of_sci_match[] = { }; MODULE_DEVICE_TABLE(of, of_sci_match); +static void sci_reset_control_assert(void *data) +{ + reset_control_assert(data); +} + static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) { struct device_node *np = pdev->dev.of_node; + struct reset_control *rstc; struct plat_sci_port *p; struct sci_port *sp; const void *data; - int id; + int id, ret; if (!IS_ENABLED(CONFIG_OF) || !np) - return NULL; + return ERR_PTR(-EINVAL); data = of_device_get_match_data(&pdev->dev); + rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + if (IS_ERR(rstc)) + return ERR_PTR(dev_err_probe(&pdev->dev, PTR_ERR(rstc), + "failed to get reset ctrl\n")); + + ret = reset_control_deassert(rstc); + if (ret) { + dev_err(&pdev->dev, "failed to deassert reset %d\n", ret); + return ERR_PTR(ret); + } + + ret = devm_add_action_or_reset(&pdev->dev, sci_reset_control_assert, rstc); + if (ret) { + dev_err(&pdev->dev, "failed to register assert devm action, %d\n", + ret); + return ERR_PTR(ret); + } + p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL); if (!p) - return NULL; + return ERR_PTR(-ENOMEM); /* Get the line number from the aliases node. */ id = of_alias_get_id(np, "serial"); @@ -3227,11 +3228,11 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, id = ffz(sci_ports_in_use); if (id < 0) { dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); - return NULL; + return ERR_PTR(-EINVAL); } if (id >= ARRAY_SIZE(sci_ports)) { dev_err(&pdev->dev, "serial%d out of range\n", id); - return NULL; + return ERR_PTR(-EINVAL); } sp = &sci_ports[id]; @@ -3318,8 +3319,8 @@ static int sci_probe(struct platform_device *dev) if (dev->dev.of_node) { p = sci_parse_dt(dev, &dev_id); - if (p == NULL) - return -EINVAL; + if (IS_ERR(p)) + return PTR_ERR(p); } else { p = dev->dev.platform_data; if (p == NULL) { diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 3244e7f6818c..1f89ab0e49ac 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -365,6 +365,31 @@ static unsigned int stm32_usart_receive_chars(struct uart_port *port, bool force return size; } +static void stm32_usart_tx_dma_terminate(struct stm32_port *stm32_port) +{ + dmaengine_terminate_async(stm32_port->tx_ch); + stm32_port->tx_dma_busy = false; +} + +static bool stm32_usart_tx_dma_started(struct stm32_port *stm32_port) +{ + /* + * We cannot use the function "dmaengine_tx_status" to know the + * status of DMA. This function does not show if the "dma complete" + * callback of the DMA transaction has been called. So we prefer + * to use "tx_dma_busy" flag to prevent dual DMA transaction at the + * same time. + */ + return stm32_port->tx_dma_busy; +} + +static bool stm32_usart_tx_dma_enabled(struct stm32_port *stm32_port) +{ + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + return !!(readl_relaxed(stm32_port->port.membase + ofs->cr3) & USART_CR3_DMAT); +} + static void stm32_usart_tx_dma_complete(void *arg) { struct uart_port *port = arg; @@ -372,9 +397,8 @@ static void stm32_usart_tx_dma_complete(void *arg) const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; unsigned long flags; - dmaengine_terminate_async(stm32port->tx_ch); stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32port->tx_dma_busy = false; + stm32_usart_tx_dma_terminate(stm32port); /* Let's see if we have pending data to send */ spin_lock_irqsave(&port->lock, flags); @@ -428,10 +452,8 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port) const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct circ_buf *xmit = &port->state->xmit; - if (stm32_port->tx_dma_busy) { + if (stm32_usart_tx_dma_enabled(stm32_port)) stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32_port->tx_dma_busy = false; - } while (!uart_circ_empty(xmit)) { /* Check that TDR is empty before filling FIFO */ @@ -455,12 +477,13 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port) const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; struct circ_buf *xmit = &port->state->xmit; struct dma_async_tx_descriptor *desc = NULL; - unsigned int count, i; + unsigned int count; - if (stm32port->tx_dma_busy) + if (stm32_usart_tx_dma_started(stm32port)) { + if (!stm32_usart_tx_dma_enabled(stm32port)) + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT); return; - - stm32port->tx_dma_busy = true; + } count = uart_circ_chars_pending(xmit); @@ -491,13 +514,21 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port) if (!desc) goto fallback_err; + /* + * Set "tx_dma_busy" flag. This flag will be released when + * dmaengine_terminate_async will be called. This flag helps + * transmit_chars_dma not to start another DMA transaction + * if the callback of the previous is not yet called. + */ + stm32port->tx_dma_busy = true; + desc->callback = stm32_usart_tx_dma_complete; desc->callback_param = port; /* Push current DMA TX transaction in the pending queue */ if (dma_submit_error(dmaengine_submit(desc))) { /* dma no yet started, safe to free resources */ - dmaengine_terminate_async(stm32port->tx_ch); + stm32_usart_tx_dma_terminate(stm32port); goto fallback_err; } @@ -511,8 +542,7 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port) return; fallback_err: - for (i = count; i > 0; i--) - stm32_usart_transmit_chars_pio(port); + stm32_usart_transmit_chars_pio(port); } static void stm32_usart_transmit_chars(struct uart_port *port) @@ -522,12 +552,13 @@ static void stm32_usart_transmit_chars(struct uart_port *port) struct circ_buf *xmit = &port->state->xmit; if (port->x_char) { - if (stm32_port->tx_dma_busy) + if (stm32_usart_tx_dma_started(stm32_port) && + stm32_usart_tx_dma_enabled(stm32_port)) stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); writel_relaxed(port->x_char, port->membase + ofs->tdr); port->x_char = 0; port->icount.tx++; - if (stm32_port->tx_dma_busy) + if (stm32_usart_tx_dma_started(stm32_port)) stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT); return; } @@ -675,8 +706,11 @@ static void stm32_usart_stop_tx(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); struct serial_rs485 *rs485conf = &port->rs485; + const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; stm32_usart_tx_interrupt_disable(port); + if (stm32_usart_tx_dma_started(stm32_port) && stm32_usart_tx_dma_enabled(stm32_port)) + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); if (rs485conf->flags & SER_RS485_ENABLED) { if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { @@ -719,9 +753,8 @@ static void stm32_usart_flush_buffer(struct uart_port *port) const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; if (stm32_port->tx_ch) { - dmaengine_terminate_async(stm32_port->tx_ch); + stm32_usart_tx_dma_terminate(stm32_port); stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32_port->tx_dma_busy = false; } } @@ -883,6 +916,12 @@ static void stm32_usart_shutdown(struct uart_port *port) u32 val, isr; int ret; + if (stm32_usart_tx_dma_enabled(stm32_port)) + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + + if (stm32_usart_tx_dma_started(stm32_port)) + stm32_usart_tx_dma_terminate(stm32_port); + /* Disable modem control interrupts */ stm32_usart_disable_ms(port); @@ -1419,8 +1458,6 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, struct dma_slave_config config; int ret; - stm32port->tx_dma_busy = false; - stm32port->tx_buf = dma_alloc_coherent(dev, TX_BUF_L, &stm32port->tx_dma_buf, GFP_KERNEL); @@ -1570,7 +1607,6 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) writel_relaxed(cr3, port->membase + ofs->cr3); if (stm32_port->tx_ch) { - dmaengine_terminate_async(stm32_port->tx_ch); stm32_usart_of_dma_tx_remove(stm32_port, pdev); dma_release_channel(stm32_port->tx_ch); } diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index e23916bfbb60..feab952aec16 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -264,7 +264,7 @@ struct stm32_port { u32 cr1_irq; /* USART_CR1_RXNEIE or RTOIE */ u32 cr3_irq; /* USART_CR3_RXFTIE */ int last_res; - bool tx_dma_busy; /* dma tx busy */ + bool tx_dma_busy; /* dma tx transaction in progress */ bool throttled; /* port throttled */ bool hw_flow_control; bool swap; /* swap RX & TX pins */ diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 425a016f9db7..98b2f4fb9a99 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -127,7 +127,8 @@ static void serial_out(struct uart_sunsu_port *up, int offset, int value) * gate outputs a logical one. Since we use level triggered interrupts * we have lockup and watchdog reset. We cannot mask IRQ because * keyboard shares IRQ with us (Word has it as Bob Smelik's design). - * This problem is similar to what Alpha people suffer, see serial.c. + * This problem is similar to what Alpha people suffer, see + * 8250_alpha.c. */ if (offset == UART_MCR) value |= UART_MCR_OUT2; diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index d3d9566e5dbd..e1fa52d31474 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -626,7 +626,7 @@ static struct uart_driver ulite_uart_driver = { * * Returns: 0 on success, <0 otherwise */ -static int ulite_assign(struct device *dev, int id, u32 base, int irq, +static int ulite_assign(struct device *dev, int id, phys_addr_t base, int irq, struct uartlite_data *pdata) { struct uart_port *port; diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index e15b2bf69904..9adfe3dc970f 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -621,21 +621,25 @@ static const struct of_device_id wmt_dt_ids[] = { static int vt8500_serial_probe(struct platform_device *pdev) { struct vt8500_port *vt8500_port; - struct resource *mmres, *irqres; + struct resource *mmres; struct device_node *np = pdev->dev.of_node; const unsigned int *flags; int ret; int port; + int irq; flags = of_device_get_match_data(&pdev->dev); if (!flags) return -EINVAL; mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!mmres || !irqres) + if (!mmres) return -ENODEV; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + if (np) { port = of_alias_get_id(np, "serial"); if (port >= VT8500_MAX_PORTS) @@ -688,7 +692,7 @@ static int vt8500_serial_probe(struct platform_device *pdev) vt8500_port->uart.type = PORT_VT8500; vt8500_port->uart.iotype = UPIO_MEM; vt8500_port->uart.mapbase = mmres->start; - vt8500_port->uart.irq = irqres->start; + vt8500_port->uart.irq = irq; vt8500_port->uart.fifosize = 16; vt8500_port->uart.ops = &vt8500_uart_pops; vt8500_port->uart.line = port; diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 6c7e65b1d9a1..646510476c30 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -39,20 +39,15 @@ #define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) /** - * tty_buffer_lock_exclusive - gain exclusive access to buffer - * tty_buffer_unlock_exclusive - release exclusive access + * tty_buffer_lock_exclusive - gain exclusive access to buffer + * @port: tty port owning the flip buffer * - * @port: tty port owning the flip buffer + * Guarantees safe use of the &tty_ldisc_ops.receive_buf() method by excluding + * the buffer work and any pending flush from using the flip buffer. Data can + * continue to be added concurrently to the flip buffer from the driver side. * - * Guarantees safe use of the line discipline's receive_buf() method by - * excluding the buffer work and any pending flush from using the flip - * buffer. Data can continue to be added concurrently to the flip buffer - * from the driver side. - * - * On release, the buffer work is restarted if there is data in the - * flip buffer + * See also tty_buffer_unlock_exclusive(). */ - void tty_buffer_lock_exclusive(struct tty_port *port) { struct tty_bufhead *buf = &port->buf; @@ -62,6 +57,14 @@ void tty_buffer_lock_exclusive(struct tty_port *port) } EXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive); +/** + * tty_buffer_unlock_exclusive - release exclusive access + * @port: tty port owning the flip buffer + * + * The buffer work is restarted if there is data in the flip buffer. + * + * See also tty_buffer_lock_exclusive(). + */ void tty_buffer_unlock_exclusive(struct tty_port *port) { struct tty_bufhead *buf = &port->buf; @@ -77,17 +80,16 @@ void tty_buffer_unlock_exclusive(struct tty_port *port) EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); /** - * tty_buffer_space_avail - return unused buffer space - * @port: tty port owning the flip buffer + * tty_buffer_space_avail - return unused buffer space + * @port: tty port owning the flip buffer * - * Returns the # of bytes which can be written by the driver without - * reaching the buffer limit. + * Returns: the # of bytes which can be written by the driver without reaching + * the buffer limit. * - * Note: this does not guarantee that memory is available to write - * the returned # of bytes (use tty_prepare_flip_string_xxx() to - * pre-allocate if memory guarantee is required). + * Note: this does not guarantee that memory is available to write the returned + * # of bytes (use tty_prepare_flip_string() to pre-allocate if memory + * guarantee is required). */ - unsigned int tty_buffer_space_avail(struct tty_port *port) { int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used); @@ -107,13 +109,12 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size) } /** - * tty_buffer_free_all - free buffers used by a tty - * @port: tty port to free from + * tty_buffer_free_all - free buffers used by a tty + * @port: tty port to free from * - * Remove all the buffers pending on a tty whether queued with data - * or in the free ring. Must be called when the tty is no longer in use + * Remove all the buffers pending on a tty whether queued with data or in the + * free ring. Must be called when the tty is no longer in use. */ - void tty_buffer_free_all(struct tty_port *port) { struct tty_bufhead *buf = &port->buf; @@ -142,17 +143,17 @@ void tty_buffer_free_all(struct tty_port *port) } /** - * tty_buffer_alloc - allocate a tty buffer - * @port: tty port - * @size: desired size (characters) - * - * Allocate a new tty buffer to hold the desired number of characters. - * We round our buffers off in 256 character chunks to get better - * allocation behaviour. - * Return NULL if out of memory or the allocation would exceed the - * per device queue + * tty_buffer_alloc - allocate a tty buffer + * @port: tty port + * @size: desired size (characters) + * + * Allocate a new tty buffer to hold the desired number of characters. We + * round our buffers off in 256 character chunks to get better allocation + * behaviour. + * + * Returns: %NULL if out of memory or the allocation would exceed the per + * device queue. */ - static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) { struct llist_node *free; @@ -185,14 +186,13 @@ found: } /** - * tty_buffer_free - free a tty buffer - * @port: tty port owning the buffer - * @b: the buffer to free + * tty_buffer_free - free a tty buffer + * @port: tty port owning the buffer + * @b: the buffer to free * - * Free a tty buffer, or add it to the free list according to our - * internal strategy + * Free a tty buffer, or add it to the free list according to our internal + * strategy. */ - static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) { struct tty_bufhead *buf = &port->buf; @@ -207,17 +207,15 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) } /** - * tty_buffer_flush - flush full tty buffers - * @tty: tty to flush - * @ld: optional ldisc ptr (must be referenced) + * tty_buffer_flush - flush full tty buffers + * @tty: tty to flush + * @ld: optional ldisc ptr (must be referenced) * - * flush all the buffers containing receive data. If ld != NULL, - * flush the ldisc input buffer. + * Flush all the buffers containing receive data. If @ld != %NULL, flush the + * ldisc input buffer. * - * Locking: takes buffer lock to ensure single-threaded flip buffer - * 'consumer' + * Locking: takes buffer lock to ensure single-threaded flip buffer 'consumer'. */ - void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) { struct tty_port *port = tty->port; @@ -244,17 +242,18 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) } /** - * __tty_buffer_request_room - grow tty buffer if needed - * @port: tty port - * @size: size desired - * @flags: buffer flags if new buffer allocated (default = 0) + * __tty_buffer_request_room - grow tty buffer if needed + * @port: tty port + * @size: size desired + * @flags: buffer flags if new buffer allocated (default = 0) + * + * Make at least @size bytes of linear space available for the tty buffer. * - * Make at least size bytes of linear space available for the tty - * buffer. If we fail return the size we managed to find. + * Will change over to a new buffer if the current buffer is encoded as + * %TTY_NORMAL (so has no flags buffer) and the new buffer requires a flags + * buffer. * - * Will change over to a new buffer if the current buffer is encoded as - * TTY_NORMAL (so has no flags buffer) and the new buffer requires - * a flags buffer. + * Returns: the size we managed to find. */ static int __tty_buffer_request_room(struct tty_port *port, size_t size, int flags) @@ -300,16 +299,17 @@ int tty_buffer_request_room(struct tty_port *port, size_t size) EXPORT_SYMBOL_GPL(tty_buffer_request_room); /** - * tty_insert_flip_string_fixed_flag - Add characters to the tty buffer - * @port: tty port - * @chars: characters - * @flag: flag value for each character - * @size: size - * - * Queue a series of bytes to the tty buffering. All the characters - * passed are marked with the supplied flag. Returns the number added. + * tty_insert_flip_string_fixed_flag - add characters to the tty buffer + * @port: tty port + * @chars: characters + * @flag: flag value for each character + * @size: size + * + * Queue a series of bytes to the tty buffering. All the characters passed are + * marked with the supplied flag. + * + * Returns: the number added. */ - int tty_insert_flip_string_fixed_flag(struct tty_port *port, const unsigned char *chars, char flag, size_t size) { @@ -338,17 +338,17 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port, EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); /** - * tty_insert_flip_string_flags - Add characters to the tty buffer - * @port: tty port - * @chars: characters - * @flags: flag bytes - * @size: size - * - * Queue a series of bytes to the tty buffering. For each character - * the flags array indicates the status of the character. Returns the - * number added. + * tty_insert_flip_string_flags - add characters to the tty buffer + * @port: tty port + * @chars: characters + * @flags: flag bytes + * @size: size + * + * Queue a series of bytes to the tty buffering. For each character the flags + * array indicates the status of the character. + * + * Returns: the number added. */ - int tty_insert_flip_string_flags(struct tty_port *port, const unsigned char *chars, const char *flags, size_t size) { @@ -376,13 +376,13 @@ int tty_insert_flip_string_flags(struct tty_port *port, EXPORT_SYMBOL(tty_insert_flip_string_flags); /** - * __tty_insert_flip_char - Add one character to the tty buffer - * @port: tty port - * @ch: character - * @flag: flag byte + * __tty_insert_flip_char - add one character to the tty buffer + * @port: tty port + * @ch: character + * @flag: flag byte * - * Queue a single byte to the tty buffering, with an optional flag. - * This is the slow path of tty_insert_flip_char. + * Queue a single byte @ch to the tty buffering, with an optional flag. This is + * the slow path of tty_insert_flip_char(). */ int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) { @@ -402,39 +402,19 @@ int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) EXPORT_SYMBOL(__tty_insert_flip_char); /** - * tty_schedule_flip - push characters to ldisc - * @port: tty port to push from + * tty_prepare_flip_string - make room for characters + * @port: tty port + * @chars: return pointer for character write area + * @size: desired size * - * Takes any pending buffers and transfers their ownership to the - * ldisc side of the queue. It then schedules those characters for - * processing by the line discipline. - */ - -void tty_schedule_flip(struct tty_port *port) -{ - struct tty_bufhead *buf = &port->buf; - - /* paired w/ acquire in flush_to_ldisc(); ensures - * flush_to_ldisc() sees buffer data. - */ - smp_store_release(&buf->tail->commit, buf->tail->used); - queue_work(system_unbound_wq, &buf->work); -} -EXPORT_SYMBOL(tty_schedule_flip); - -/** - * tty_prepare_flip_string - make room for characters - * @port: tty port - * @chars: return pointer for character write area - * @size: desired size - * - * Prepare a block of space in the buffer for data. Returns the length - * available and buffer pointer to the space which is now allocated and - * accounted for as ready for normal characters. This is used for drivers - * that need their own block copy routines into the buffer. There is no - * guarantee the buffer is a DMA target! + * Prepare a block of space in the buffer for data. + * + * This is used for drivers that need their own block copy routines into the + * buffer. There is no guarantee the buffer is a DMA target! + * + * Returns: the length available and buffer pointer (@chars) to the space which + * is now allocated and accounted for as ready for normal characters. */ - int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, size_t size) { @@ -453,16 +433,16 @@ int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, EXPORT_SYMBOL_GPL(tty_prepare_flip_string); /** - * tty_ldisc_receive_buf - forward data to line discipline - * @ld: line discipline to process input - * @p: char buffer - * @f: TTY_* flags buffer - * @count: number of bytes to process + * tty_ldisc_receive_buf - forward data to line discipline + * @ld: line discipline to process input + * @p: char buffer + * @f: %TTY_NORMAL, %TTY_BREAK, etc. flags buffer + * @count: number of bytes to process * - * Callers other than flush_to_ldisc() need to exclude the kworker - * from concurrent use of the line discipline, see paste_selection(). + * Callers other than flush_to_ldisc() need to exclude the kworker from + * concurrent use of the line discipline, see paste_selection(). * - * Returns the number of bytes processed + * Returns: the number of bytes processed. */ int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p, const char *f, int count) @@ -495,18 +475,16 @@ receive_buf(struct tty_port *port, struct tty_buffer *head, int count) } /** - * flush_to_ldisc - * @work: tty structure passed from work queue. + * flush_to_ldisc - flush data from buffer to ldisc + * @work: tty structure passed from work queue. * - * This routine is called out of the software interrupt to flush data - * from the buffer chain to the line discipline. + * This routine is called out of the software interrupt to flush data from the + * buffer chain to the line discipline. * - * The receive_buf method is single threaded for each tty instance. + * The receive_buf() method is single threaded for each tty instance. * - * Locking: takes buffer lock to ensure single-threaded flip buffer - * 'consumer' + * Locking: takes buffer lock to ensure single-threaded flip buffer 'consumer'. */ - static void flush_to_ldisc(struct work_struct *work) { struct tty_port *port = container_of(work, struct tty_port, buf.work); @@ -554,30 +532,35 @@ static void flush_to_ldisc(struct work_struct *work) } /** - * tty_flip_buffer_push - terminal - * @port: tty port to push + * tty_flip_buffer_push - push terminal buffers + * @port: tty port to push * - * Queue a push of the terminal flip buffers to the line discipline. - * Can be called from IRQ/atomic context. + * Queue a push of the terminal flip buffers to the line discipline. Can be + * called from IRQ/atomic context. * - * In the event of the queue being busy for flipping the work will be - * held off and retried later. + * In the event of the queue being busy for flipping the work will be held off + * and retried later. */ - void tty_flip_buffer_push(struct tty_port *port) { - tty_schedule_flip(port); + struct tty_bufhead *buf = &port->buf; + + /* + * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees + * buffer data. + */ + smp_store_release(&buf->tail->commit, buf->tail->used); + queue_work(system_unbound_wq, &buf->work); } EXPORT_SYMBOL(tty_flip_buffer_push); /** - * tty_buffer_init - prepare a tty buffer structure - * @port: tty port to initialise + * tty_buffer_init - prepare a tty buffer structure + * @port: tty port to initialise * - * Set up the initial state of the buffer management for a tty device. - * Must be called before the other tty buffer functions are used. + * Set up the initial state of the buffer management for a tty device. Must be + * called before the other tty buffer functions are used. */ - void tty_buffer_init(struct tty_port *port) { struct tty_bufhead *buf = &port->buf; @@ -594,14 +577,14 @@ void tty_buffer_init(struct tty_port *port) } /** - * tty_buffer_set_limit - change the tty buffer memory limit - * @port: tty port to change - * @limit: memory limit to set + * tty_buffer_set_limit - change the tty buffer memory limit + * @port: tty port to change + * @limit: memory limit to set * - * Change the tty buffer memory limit. - * Must be called before the other tty buffer functions are used. + * Change the tty buffer memory limit. + * + * Must be called before the other tty buffer functions are used. */ - int tty_buffer_set_limit(struct tty_port *port, int limit) { if (limit < MIN_TTYB_SIZE) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 6616d4a0d41d..7e8b3bd59c7b 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -158,19 +158,18 @@ static int tty_fasync(int fd, struct file *filp, int on); static void release_tty(struct tty_struct *tty, int idx); /** - * free_tty_struct - free a disused tty - * @tty: tty struct to free + * free_tty_struct - free a disused tty + * @tty: tty struct to free * - * Free the write buffers, tty queue and tty memory itself. + * Free the write buffers, tty queue and tty memory itself. * - * Locking: none. Must be called after tty is definitely unused + * Locking: none. Must be called after tty is definitely unused */ - static void free_tty_struct(struct tty_struct *tty) { tty_ldisc_deinit(tty); put_device(tty->dev); - kfree(tty->write_buf); + kvfree(tty->write_buf); tty->magic = 0xDEADDEAD; kfree(tty); } @@ -206,8 +205,9 @@ void tty_add_file(struct tty_struct *tty, struct file *file) spin_unlock(&tty->files_lock); } -/* +/** * tty_free_file - free file->private_data + * @file: to free private_data of * * This shall be used only for fail path handling when tty_add_file was not * called yet. @@ -233,15 +233,14 @@ static void tty_del_file(struct file *file) } /** - * tty_name - return tty naming - * @tty: tty structure + * tty_name - return tty naming + * @tty: tty structure * - * Convert a tty structure into a name. The name reflects the kernel - * naming policy and if udev is in use may not reflect user space + * Convert a tty structure into a name. The name reflects the kernel naming + * policy and if udev is in use may not reflect user space * - * Locking: none + * Locking: none */ - const char *tty_name(const struct tty_struct *tty) { if (!tty) /* Hmm. NULL pointer. That's fun. */ @@ -303,16 +302,15 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) } /** - * get_tty_driver - find device of a tty - * @device: device identifier - * @index: returns the index of the tty + * get_tty_driver - find device of a tty + * @device: device identifier + * @index: returns the index of the tty * - * This routine returns a tty driver structure, given a device number - * and also passes back the index number. + * This routine returns a tty driver structure, given a device number and also + * passes back the index number. * - * Locking: caller must hold tty_mutex + * Locking: caller must hold tty_mutex */ - static struct tty_driver *get_tty_driver(dev_t device, int *index) { struct tty_driver *p; @@ -329,17 +327,17 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) } /** - * tty_dev_name_to_number - return dev_t for device name - * @name: user space name of device under /dev - * @number: pointer to dev_t that this function will populate + * tty_dev_name_to_number - return dev_t for device name + * @name: user space name of device under /dev + * @number: pointer to dev_t that this function will populate * - * This function converts device names like ttyS0 or ttyUSB1 into dev_t - * like (4, 64) or (188, 1). If no corresponding driver is registered then - * the function returns -ENODEV. + * This function converts device names like ttyS0 or ttyUSB1 into dev_t like + * (4, 64) or (188, 1). If no corresponding driver is registered then the + * function returns -%ENODEV. * - * Locking: this acquires tty_mutex to protect the tty_drivers list from - * being modified while we are traversing it, and makes sure to - * release it before exiting. + * Locking: this acquires tty_mutex to protect the tty_drivers list from + * being modified while we are traversing it, and makes sure to + * release it before exiting. */ int tty_dev_name_to_number(const char *name, dev_t *number) { @@ -381,13 +379,12 @@ EXPORT_SYMBOL_GPL(tty_dev_name_to_number); #ifdef CONFIG_CONSOLE_POLL /** - * tty_find_polling_driver - find device of a polled tty - * @name: name string to match - * @line: pointer to resulting tty line nr + * tty_find_polling_driver - find device of a polled tty + * @name: name string to match + * @line: pointer to resulting tty line nr * - * This routine returns a tty driver structure, given a name - * and the condition that the tty driver is capable of polled - * operation. + * This routine returns a tty driver structure, given a name and the condition + * that the tty driver is capable of polled operation. */ struct tty_driver *tty_find_polling_driver(char *name, int *line) { @@ -515,14 +512,13 @@ static DEFINE_SPINLOCK(redirect_lock); static struct file *redirect; /** - * tty_wakeup - request more data - * @tty: terminal + * tty_wakeup - request more data + * @tty: terminal * - * Internal and external helper for wakeups of tty. This function - * informs the line discipline if present that the driver is ready - * to receive more output data. + * Internal and external helper for wakeups of tty. This function informs the + * line discipline if present that the driver is ready to receive more output + * data. */ - void tty_wakeup(struct tty_struct *tty) { struct tty_ldisc *ld; @@ -540,11 +536,11 @@ void tty_wakeup(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_wakeup); /** - * tty_release_redirect - Release a redirect on a pty if present - * @tty: tty device + * tty_release_redirect - Release a redirect on a pty if present + * @tty: tty device * - * This is available to the pty code so if the master closes, if the - * slave is a redirect it can release the redirect. + * This is available to the pty code so if the master closes, if the slave is a + * redirect it can release the redirect. */ static struct file *tty_release_redirect(struct tty_struct *tty) { @@ -561,27 +557,29 @@ static struct file *tty_release_redirect(struct tty_struct *tty) } /** - * __tty_hangup - actual handler for hangup events - * @tty: tty device - * @exit_session: if non-zero, signal all foreground group processes + * __tty_hangup - actual handler for hangup events + * @tty: tty device + * @exit_session: if non-zero, signal all foreground group processes + * + * This can be called by a "kworker" kernel thread. That is process synchronous + * but doesn't hold any locks, so we need to make sure we have the appropriate + * locks for what we're doing. + * + * The hangup event clears any pending redirections onto the hung up device. It + * ensures future writes will error and it does the needed line discipline + * hangup and signal delivery. The tty object itself remains intact. + * + * Locking: + * * BTM * - * This can be called by a "kworker" kernel thread. That is process - * synchronous but doesn't hold any locks, so we need to make sure we - * have the appropriate locks for what we're doing. + * * redirect lock for undoing redirection + * * file list lock for manipulating list of ttys + * * tty_ldiscs_lock from called functions + * * termios_rwsem resetting termios data + * * tasklist_lock to walk task list for hangup event * - * The hangup event clears any pending redirections onto the hung up - * device. It ensures future writes will error and it does the needed - * line discipline hangup and signal delivery. The tty object itself - * remains intact. + * * ->siglock to protect ->signal/->sighand * - * Locking: - * BTM - * redirect lock for undoing redirection - * file list lock for manipulating list of ttys - * tty_ldiscs_lock from called functions - * termios_rwsem resetting termios data - * tasklist_lock to walk task list for hangup event - * ->siglock to protect ->signal/->sighand */ static void __tty_hangup(struct tty_struct *tty, int exit_session) { @@ -682,13 +680,12 @@ static void do_tty_hangup(struct work_struct *work) } /** - * tty_hangup - trigger a hangup event - * @tty: tty to hangup + * tty_hangup - trigger a hangup event + * @tty: tty to hangup * - * A carrier loss (virtual or otherwise) has occurred on this like - * schedule a hangup sequence to run after this event. + * A carrier loss (virtual or otherwise) has occurred on @tty. Schedule a + * hangup sequence to run after this event. */ - void tty_hangup(struct tty_struct *tty) { tty_debug_hangup(tty, "hangup\n"); @@ -697,14 +694,13 @@ void tty_hangup(struct tty_struct *tty) EXPORT_SYMBOL(tty_hangup); /** - * tty_vhangup - process vhangup - * @tty: tty to hangup + * tty_vhangup - process vhangup + * @tty: tty to hangup * - * The user has asked via system call for the terminal to be hung up. - * We do this synchronously so that when the syscall returns the process - * is complete. That guarantee is necessary for security reasons. + * The user has asked via system call for the terminal to be hung up. We do + * this synchronously so that when the syscall returns the process is complete. + * That guarantee is necessary for security reasons. */ - void tty_vhangup(struct tty_struct *tty) { tty_debug_hangup(tty, "vhangup\n"); @@ -714,11 +710,10 @@ EXPORT_SYMBOL(tty_vhangup); /** - * tty_vhangup_self - process vhangup for own ctty + * tty_vhangup_self - process vhangup for own ctty * - * Perform a vhangup on the current controlling tty + * Perform a vhangup on the current controlling tty */ - void tty_vhangup_self(void) { struct tty_struct *tty; @@ -731,16 +726,15 @@ void tty_vhangup_self(void) } /** - * tty_vhangup_session - hangup session leader exit - * @tty: tty to hangup + * tty_vhangup_session - hangup session leader exit + * @tty: tty to hangup * - * The session leader is exiting and hanging up its controlling terminal. - * Every process in the foreground process group is signalled SIGHUP. + * The session leader is exiting and hanging up its controlling terminal. + * Every process in the foreground process group is signalled %SIGHUP. * - * We do this synchronously so that when the syscall returns the process - * is complete. That guarantee is necessary for security reasons. + * We do this synchronously so that when the syscall returns the process is + * complete. That guarantee is necessary for security reasons. */ - void tty_vhangup_session(struct tty_struct *tty) { tty_debug_hangup(tty, "session hangup\n"); @@ -748,13 +742,11 @@ void tty_vhangup_session(struct tty_struct *tty) } /** - * tty_hung_up_p - was tty hung up - * @filp: file pointer of tty + * tty_hung_up_p - was tty hung up + * @filp: file pointer of tty * - * Return true if the tty has been subject to a vhangup or a carrier - * loss + * Return: true if the tty has been subject to a vhangup or a carrier loss */ - int tty_hung_up_p(struct file *filp) { return (filp && filp->f_op == &hung_up_tty_fops); @@ -771,20 +763,18 @@ void __stop_tty(struct tty_struct *tty) } /** - * stop_tty - propagate flow control - * @tty: tty to stop + * stop_tty - propagate flow control + * @tty: tty to stop * - * Perform flow control to the driver. May be called - * on an already stopped device and will not re-call the driver - * method. + * Perform flow control to the driver. May be called on an already stopped + * device and will not re-call the &tty_driver->stop() method. * - * This functionality is used by both the line disciplines for - * halting incoming flow and by the driver. It may therefore be - * called from any context, may be under the tty atomic_write_lock - * but not always. + * This functionality is used by both the line disciplines for halting incoming + * flow and by the driver. It may therefore be called from any context, may be + * under the tty %atomic_write_lock but not always. * - * Locking: - * flow.lock + * Locking: + * flow.lock */ void stop_tty(struct tty_struct *tty) { @@ -807,15 +797,15 @@ void __start_tty(struct tty_struct *tty) } /** - * start_tty - propagate flow control - * @tty: tty to start + * start_tty - propagate flow control + * @tty: tty to start * - * Start a tty that has been stopped if at all possible. If this - * tty was previous stopped and is now being started, the driver - * start method is invoked and the line discipline woken. + * Start a tty that has been stopped if at all possible. If @tty was previously + * stopped and is now being started, the &tty_driver->start() method is invoked + * and the line discipline woken. * - * Locking: - * flow.lock + * Locking: + * flow.lock */ void start_tty(struct tty_struct *tty) { @@ -908,18 +898,17 @@ static int iterate_tty_read(struct tty_ldisc *ld, struct tty_struct *tty, /** - * tty_read - read method for tty device files - * @iocb: kernel I/O control block - * @to: destination for the data read + * tty_read - read method for tty device files + * @iocb: kernel I/O control block + * @to: destination for the data read * - * Perform the read system call function on this terminal device. Checks - * for hung up devices before calling the line discipline method. + * Perform the read system call function on this terminal device. Checks + * for hung up devices before calling the line discipline method. * - * Locking: - * Locks the line discipline internally while needed. Multiple - * read calls may be outstanding in parallel. + * Locking: + * Locks the line discipline internally while needed. Multiple read calls + * may be outstanding in parallel. */ - static ssize_t tty_read(struct kiocb *iocb, struct iov_iter *to) { int i; @@ -997,9 +986,6 @@ static inline ssize_t do_tty_write( * layer has problems with bigger chunks. It will * claim to be able to handle more characters than * it actually does. - * - * FIXME: This can probably go away now except that 64K chunks - * are too likely to fail unless switched to vmalloc... */ chunk = 2048; if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags)) @@ -1014,12 +1000,12 @@ static inline ssize_t do_tty_write( if (chunk < 1024) chunk = 1024; - buf_chunk = kmalloc(chunk, GFP_KERNEL); + buf_chunk = kvmalloc(chunk, GFP_KERNEL | __GFP_RETRY_MAYFAIL); if (!buf_chunk) { ret = -ENOMEM; goto out; } - kfree(tty->write_buf); + kvfree(tty->write_buf); tty->write_cnt = chunk; tty->write_buf = buf_chunk; } @@ -1069,13 +1055,12 @@ out: * @tty: the destination tty_struct * @msg: the message to write * - * This is used for messages that need to be redirected to a specific tty. - * We don't put it into the syslog queue right now maybe in the future if - * really needed. + * This is used for messages that need to be redirected to a specific tty. We + * don't put it into the syslog queue right now maybe in the future if really + * needed. * * We must still hold the BTM and test the CLOSING flag for the moment. */ - void tty_write_message(struct tty_struct *tty, char *msg) { if (tty) { @@ -1113,18 +1098,18 @@ static ssize_t file_tty_write(struct file *file, struct kiocb *iocb, struct iov_ } /** - * tty_write - write method for tty device file - * @iocb: kernel I/O control block - * @from: iov_iter with data to write + * tty_write - write method for tty device file + * @iocb: kernel I/O control block + * @from: iov_iter with data to write * - * Write data to a tty device via the line discipline. + * Write data to a tty device via the line discipline. * - * Locking: - * Locks the line discipline as required - * Writes to the tty driver are serialized by the atomic_write_lock - * and are then processed in chunks to the device. The line - * discipline write method will not be invoked in parallel for - * each device. + * Locking: + * Locks the line discipline as required + * Writes to the tty driver are serialized by the atomic_write_lock + * and are then processed in chunks to the device. The line + * discipline write method will not be invoked in parallel for + * each device. */ static ssize_t tty_write(struct kiocb *iocb, struct iov_iter *from) { @@ -1154,14 +1139,15 @@ ssize_t redirected_tty_write(struct kiocb *iocb, struct iov_iter *iter) return tty_write(iocb, iter); } -/* - * tty_send_xchar - send priority character +/** + * tty_send_xchar - send priority character + * @tty: the tty to send to + * @ch: xchar to send * - * Send a high priority character to the tty even if stopped + * Send a high priority character to the tty even if stopped. * - * Locking: none for xchar method, write ordering for write method. + * Locking: none for xchar method, write ordering for write method. */ - int tty_send_xchar(struct tty_struct *tty, char ch) { bool was_stopped = tty->flow.stopped; @@ -1188,15 +1174,15 @@ int tty_send_xchar(struct tty_struct *tty, char ch) } /** - * pty_line_name - generate name for a pty - * @driver: the tty driver in use - * @index: the minor number - * @p: output buffer of at least 6 bytes + * pty_line_name - generate name for a pty + * @driver: the tty driver in use + * @index: the minor number + * @p: output buffer of at least 6 bytes * - * Generate a name from a driver reference and write it to the output - * buffer. + * Generate a name from a @driver reference and write it to the output buffer + * @p. * - * Locking: None + * Locking: None */ static void pty_line_name(struct tty_driver *driver, int index, char *p) { @@ -1209,15 +1195,15 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) } /** - * tty_line_name - generate name for a tty - * @driver: the tty driver in use - * @index: the minor number - * @p: output buffer of at least 7 bytes + * tty_line_name - generate name for a tty + * @driver: the tty driver in use + * @index: the minor number + * @p: output buffer of at least 7 bytes * - * Generate a name from a driver reference and write it to the output - * buffer. + * Generate a name from a @driver reference and write it to the output buffer + * @p. * - * Locking: None + * Locking: None */ static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p) { @@ -1229,15 +1215,15 @@ static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p) } /** - * tty_driver_lookup_tty() - find an existing tty, if any - * @driver: the driver for the tty - * @file: file object - * @idx: the minor number + * tty_driver_lookup_tty() - find an existing tty, if any + * @driver: the driver for the tty + * @file: file object + * @idx: the minor number * - * Return the tty, if found. If not found, return NULL or ERR_PTR() if the - * driver lookup() method returns an error. + * Return: the tty, if found. If not found, return %NULL or ERR_PTR() if the + * driver lookup() method returns an error. * - * Locking: tty_mutex must be held. If the tty is found, bump the tty kref. + * Locking: tty_mutex must be held. If the tty is found, bump the tty kref. */ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, struct file *file, int idx) @@ -1258,13 +1244,12 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, } /** - * tty_init_termios - helper for termios setup - * @tty: the tty to set up + * tty_init_termios - helper for termios setup + * @tty: the tty to set up * - * Initialise the termios structure for this tty. This runs under - * the tty_mutex currently so we can be relaxed about ordering. + * Initialise the termios structure for this tty. This runs under the + * %tty_mutex currently so we can be relaxed about ordering. */ - void tty_init_termios(struct tty_struct *tty) { struct ktermios *tp; @@ -1287,6 +1272,14 @@ void tty_init_termios(struct tty_struct *tty) } EXPORT_SYMBOL_GPL(tty_init_termios); +/** + * tty_standard_install - usual tty->ops->install + * @driver: the driver for the tty + * @tty: the tty + * + * If the @driver overrides @tty->ops->install, it still can call this function + * to perform the standard install operations. + */ int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty) { tty_init_termios(tty); @@ -1298,16 +1291,15 @@ int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_standard_install); /** - * tty_driver_install_tty() - install a tty entry in the driver - * @driver: the driver for the tty - * @tty: the tty + * tty_driver_install_tty() - install a tty entry in the driver + * @driver: the driver for the tty + * @tty: the tty * - * Install a tty object into the driver tables. The tty->index field - * will be set by the time this is called. This method is responsible - * for ensuring any need additional structures are allocated and - * configured. + * Install a tty object into the driver tables. The @tty->index field will be + * set by the time this is called. This method is responsible for ensuring any + * need additional structures are allocated and configured. * - * Locking: tty_mutex for now + * Locking: tty_mutex for now */ static int tty_driver_install_tty(struct tty_driver *driver, struct tty_struct *tty) @@ -1317,14 +1309,14 @@ static int tty_driver_install_tty(struct tty_driver *driver, } /** - * tty_driver_remove_tty() - remove a tty from the driver tables - * @driver: the driver for the tty - * @tty: tty to remove + * tty_driver_remove_tty() - remove a tty from the driver tables + * @driver: the driver for the tty + * @tty: tty to remove * - * Remvoe a tty object from the driver tables. The tty->index field - * will be set by the time this is called. + * Remove a tty object from the driver tables. The tty->index field will be set + * by the time this is called. * - * Locking: tty_mutex for now + * Locking: tty_mutex for now */ static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty) { @@ -1335,13 +1327,13 @@ static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct * } /** - * tty_reopen() - fast re-open of an open tty - * @tty: the tty to open + * tty_reopen() - fast re-open of an open tty + * @tty: the tty to open * - * Return 0 on success, -errno on error. - * Re-opens on master ptys are not allowed and return -EIO. + * Re-opens on master ptys are not allowed and return -%EIO. * - * Locking: Caller must hold tty_lock + * Locking: Caller must hold tty_lock + * Return: 0 on success, -errno on error. */ static int tty_reopen(struct tty_struct *tty) { @@ -1379,30 +1371,28 @@ static int tty_reopen(struct tty_struct *tty) } /** - * tty_init_dev - initialise a tty device - * @driver: tty driver we are opening a device on - * @idx: device index + * tty_init_dev - initialise a tty device + * @driver: tty driver we are opening a device on + * @idx: device index * - * Prepare a tty device. This may not be a "new" clean device but - * could also be an active device. The pty drivers require special - * handling because of this. + * Prepare a tty device. This may not be a "new" clean device but could also be + * an active device. The pty drivers require special handling because of this. * - * Locking: - * The function is called under the tty_mutex, which - * protects us from the tty struct or driver itself going away. + * Locking: + * The function is called under the tty_mutex, which protects us from the + * tty struct or driver itself going away. * - * On exit the tty device has the line discipline attached and - * a reference count of 1. If a pair was created for pty/tty use - * and the other was a pty master then it too has a reference count of 1. + * On exit the tty device has the line discipline attached and a reference + * count of 1. If a pair was created for pty/tty use and the other was a pty + * master then it too has a reference count of 1. * - * WSH 06/09/97: Rewritten to remove races and properly clean up after a - * failed open. The new code protects the open with a mutex, so it's - * really quite straightforward. The mutex locking can probably be - * relaxed for the (most common) case of reopening a tty. + * WSH 06/09/97: Rewritten to remove races and properly clean up after a failed + * open. The new code protects the open with a mutex, so it's really quite + * straightforward. The mutex locking can probably be relaxed for the (most + * common) case of reopening a tty. * - * Return: returned tty structure + * Return: new tty structure */ - struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) { struct tty_struct *tty; @@ -1503,10 +1493,10 @@ void tty_save_termios(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_save_termios); /** - * tty_flush_works - flush all works of a tty/pty pair - * @tty: tty device to flush works for (or either end of a pty pair) + * tty_flush_works - flush all works of a tty/pty pair + * @tty: tty device to flush works for (or either end of a pty pair) * - * Sync flush all works belonging to @tty (and the 'other' tty). + * Sync flush all works belonging to @tty (and the 'other' tty). */ static void tty_flush_works(struct tty_struct *tty) { @@ -1519,19 +1509,19 @@ static void tty_flush_works(struct tty_struct *tty) } /** - * release_one_tty - release tty structure memory - * @work: work of tty we are obliterating + * release_one_tty - release tty structure memory + * @work: work of tty we are obliterating * - * Releases memory associated with a tty structure, and clears out the - * driver table slots. This function is called when a device is no longer - * in use. It also gets called when setup of a device fails. + * Releases memory associated with a tty structure, and clears out the + * driver table slots. This function is called when a device is no longer + * in use. It also gets called when setup of a device fails. * - * Locking: - * takes the file list lock internally when working on the list - * of ttys that the driver keeps. + * Locking: + * takes the file list lock internally when working on the list of ttys + * that the driver keeps. * - * This method gets called from a work queue so that the driver private - * cleanup ops can sleep (needed for USB at least) + * This method gets called from a work queue so that the driver private + * cleanup ops can sleep (needed for USB at least) */ static void release_one_tty(struct work_struct *work) { @@ -1568,13 +1558,12 @@ static void queue_release_one_tty(struct kref *kref) } /** - * tty_kref_put - release a tty kref - * @tty: tty device + * tty_kref_put - release a tty kref + * @tty: tty device * - * Release a reference to a tty device and if need be let the kref - * layer destruct the object for us + * Release a reference to the @tty device and if need be let the kref layer + * destruct the object for us. */ - void tty_kref_put(struct tty_struct *tty) { if (tty) @@ -1583,18 +1572,17 @@ void tty_kref_put(struct tty_struct *tty) EXPORT_SYMBOL(tty_kref_put); /** - * release_tty - release tty structure memory - * @tty: tty device release - * @idx: index of the tty device release + * release_tty - release tty structure memory + * @tty: tty device release + * @idx: index of the tty device release * - * Release both @tty and a possible linked partner (think pty pair), - * and decrement the refcount of the backing module. - * - * Locking: - * tty_mutex - * takes the file list lock internally when working on the list - * of ttys that the driver keeps. + * Release both @tty and a possible linked partner (think pty pair), + * and decrement the refcount of the backing module. * + * Locking: + * tty_mutex + * takes the file list lock internally when working on the list of ttys + * that the driver keeps. */ static void release_tty(struct tty_struct *tty, int idx) { @@ -1619,12 +1607,12 @@ static void release_tty(struct tty_struct *tty, int idx) } /** - * tty_release_checks - check a tty before real release - * @tty: tty to check - * @idx: index of the tty + * tty_release_checks - check a tty before real release + * @tty: tty to check + * @idx: index of the tty * - * Performs some paranoid checking before true release of the @tty. - * This is a no-op unless TTY_PARANOIA_CHECK is defined. + * Performs some paranoid checking before true release of the @tty. This is a + * no-op unless %TTY_PARANOIA_CHECK is defined. */ static int tty_release_checks(struct tty_struct *tty, int idx) { @@ -1661,12 +1649,12 @@ static int tty_release_checks(struct tty_struct *tty, int idx) } /** - * tty_kclose - closes tty opened by tty_kopen - * @tty: tty device + * tty_kclose - closes tty opened by tty_kopen + * @tty: tty device * - * Performs the final steps to release and free a tty device. It is the - * same as tty_release_struct except that it also resets TTY_PORT_KOPENED - * flag on tty->port. + * Performs the final steps to release and free a tty device. It is the same as + * tty_release_struct() except that it also resets %TTY_PORT_KOPENED flag on + * @tty->port. */ void tty_kclose(struct tty_struct *tty) { @@ -1691,12 +1679,12 @@ void tty_kclose(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_kclose); /** - * tty_release_struct - release a tty struct - * @tty: tty device - * @idx: index of the tty + * tty_release_struct - release a tty struct + * @tty: tty device + * @idx: index of the tty * - * Performs the final steps to release and free a tty device. It is - * roughly the reverse of tty_init_dev. + * Performs the final steps to release and free a tty device. It is roughly the + * reverse of tty_init_dev(). */ void tty_release_struct(struct tty_struct *tty, int idx) { @@ -1720,24 +1708,23 @@ void tty_release_struct(struct tty_struct *tty, int idx) EXPORT_SYMBOL_GPL(tty_release_struct); /** - * tty_release - vfs callback for close - * @inode: inode of tty - * @filp: file pointer for handle to tty + * tty_release - vfs callback for close + * @inode: inode of tty + * @filp: file pointer for handle to tty * - * Called the last time each file handle is closed that references - * this tty. There may however be several such references. + * Called the last time each file handle is closed that references this tty. + * There may however be several such references. * - * Locking: - * Takes bkl. See tty_release_dev + * Locking: + * Takes BKL. See tty_release_dev(). * - * Even releasing the tty structures is a tricky business.. We have - * to be very careful that the structures are all released at the - * same time, as interrupts might otherwise get the wrong pointers. + * Even releasing the tty structures is a tricky business. We have to be very + * careful that the structures are all released at the same time, as interrupts + * might otherwise get the wrong pointers. * * WSH 09/09/97: rewritten to avoid some nasty race conditions that could * lead to double frees or releasing memory still in use. */ - int tty_release(struct inode *inode, struct file *filp) { struct tty_struct *tty = file_tty(filp); @@ -1880,15 +1867,15 @@ int tty_release(struct inode *inode, struct file *filp) } /** - * tty_open_current_tty - get locked tty of current task - * @device: device number - * @filp: file pointer to tty - * @return: locked tty of the current task iff @device is /dev/tty + * tty_open_current_tty - get locked tty of current task + * @device: device number + * @filp: file pointer to tty + * @return: locked tty of the current task iff @device is /dev/tty * - * Performs a re-open of the current task's controlling tty. + * Performs a re-open of the current task's controlling tty. * - * We cannot return driver and index like for the other nodes because - * devpts will not work then. It expects inodes to be from devpts FS. + * We cannot return driver and index like for the other nodes because devpts + * will not work then. It expects inodes to be from devpts FS. */ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) { @@ -1916,16 +1903,17 @@ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) } /** - * tty_lookup_driver - lookup a tty driver for a given device file - * @device: device number - * @filp: file pointer to tty - * @index: index for the device in the @return driver - * @return: driver for this inode (with increased refcount) + * tty_lookup_driver - lookup a tty driver for a given device file + * @device: device number + * @filp: file pointer to tty + * @index: index for the device in the @return driver + * + * If returned value is not erroneous, the caller is responsible to decrement + * the refcount by tty_driver_kref_put(). * - * If @return is not erroneous, the caller is responsible to decrement the - * refcount by tty_driver_kref_put. + * Locking: %tty_mutex protects get_tty_driver() * - * Locking: tty_mutex protects get_tty_driver + * Return: driver for this inode (with increased refcount) */ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, int *index) @@ -2001,19 +1989,18 @@ out: } /** - * tty_kopen_exclusive - open a tty device for kernel - * @device: dev_t of device to open + * tty_kopen_exclusive - open a tty device for kernel + * @device: dev_t of device to open * - * Opens tty exclusively for kernel. Performs the driver lookup, - * makes sure it's not already opened and performs the first-time - * tty initialization. + * Opens tty exclusively for kernel. Performs the driver lookup, makes sure + * it's not already opened and performs the first-time tty initialization. * - * Returns the locked initialized &tty_struct + * Claims the global %tty_mutex to serialize: + * * concurrent first-time tty initialization + * * concurrent tty driver removal w/ lookup + * * concurrent tty removal from driver table * - * Claims the global tty_mutex to serialize: - * - concurrent first-time tty initialization - * - concurrent tty driver removal w/ lookup - * - concurrent tty removal from driver table + * Return: the locked initialized &tty_struct */ struct tty_struct *tty_kopen_exclusive(dev_t device) { @@ -2022,13 +2009,13 @@ struct tty_struct *tty_kopen_exclusive(dev_t device) EXPORT_SYMBOL_GPL(tty_kopen_exclusive); /** - * tty_kopen_shared - open a tty device for shared in-kernel use - * @device: dev_t of device to open + * tty_kopen_shared - open a tty device for shared in-kernel use + * @device: dev_t of device to open * - * Opens an already existing tty for in-kernel use. Compared to - * tty_kopen_exclusive() above it doesn't ensure to be the only user. + * Opens an already existing tty for in-kernel use. Compared to + * tty_kopen_exclusive() above it doesn't ensure to be the only user. * - * Locking is identical to tty_kopen() above. + * Locking: identical to tty_kopen() above. */ struct tty_struct *tty_kopen_shared(dev_t device) { @@ -2037,19 +2024,20 @@ struct tty_struct *tty_kopen_shared(dev_t device) EXPORT_SYMBOL_GPL(tty_kopen_shared); /** - * tty_open_by_driver - open a tty device - * @device: dev_t of device to open - * @filp: file pointer to tty + * tty_open_by_driver - open a tty device + * @device: dev_t of device to open + * @filp: file pointer to tty * - * Performs the driver lookup, checks for a reopen, or otherwise - * performs the first-time tty initialization. + * Performs the driver lookup, checks for a reopen, or otherwise performs the + * first-time tty initialization. * - * Returns the locked initialized or re-opened &tty_struct * - * Claims the global tty_mutex to serialize: - * - concurrent first-time tty initialization - * - concurrent tty driver removal w/ lookup - * - concurrent tty removal from driver table + * Claims the global tty_mutex to serialize: + * * concurrent first-time tty initialization + * * concurrent tty driver removal w/ lookup + * * concurrent tty removal from driver table + * + * Return: the locked initialized or re-opened &tty_struct */ static struct tty_struct *tty_open_by_driver(dev_t device, struct file *filp) @@ -2104,29 +2092,28 @@ out: } /** - * tty_open - open a tty device - * @inode: inode of device file - * @filp: file pointer to tty + * tty_open - open a tty device + * @inode: inode of device file + * @filp: file pointer to tty * - * tty_open and tty_release keep up the tty count that contains the - * number of opens done on a tty. We cannot use the inode-count, as - * different inodes might point to the same tty. + * tty_open() and tty_release() keep up the tty count that contains the number + * of opens done on a tty. We cannot use the inode-count, as different inodes + * might point to the same tty. * - * Open-counting is needed for pty masters, as well as for keeping - * track of serial lines: DTR is dropped when the last close happens. - * (This is not done solely through tty->count, now. - Ted 1/27/92) + * Open-counting is needed for pty masters, as well as for keeping track of + * serial lines: DTR is dropped when the last close happens. + * (This is not done solely through tty->count, now. - Ted 1/27/92) * - * The termios state of a pty is reset on first open so that - * settings don't persist across reuse. + * The termios state of a pty is reset on the first open so that settings don't + * persist across reuse. * - * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev. - * tty->count should protect the rest. - * ->siglock protects ->signal/->sighand + * Locking: + * * %tty_mutex protects tty, tty_lookup_driver() and tty_init_dev(). + * * @tty->count should protect the rest. + * * ->siglock protects ->signal/->sighand * - * Note: the tty_unlock/lock cases without a ref are only safe due to - * tty_mutex + * Note: the tty_unlock/lock cases without a ref are only safe due to %tty_mutex */ - static int tty_open(struct inode *inode, struct file *filp) { struct tty_struct *tty; @@ -2198,19 +2185,17 @@ retry_open: } - /** - * tty_poll - check tty status - * @filp: file being polled - * @wait: poll wait structures to update + * tty_poll - check tty status + * @filp: file being polled + * @wait: poll wait structures to update * - * Call the line discipline polling method to obtain the poll - * status of the device. + * Call the line discipline polling method to obtain the poll status of the + * device. * - * Locking: locks called line discipline but ldisc poll method - * may be re-entered freely by other callers. + * Locking: locks called line discipline but ldisc poll method may be + * re-entered freely by other callers. */ - static __poll_t tty_poll(struct file *filp, poll_table *wait) { struct tty_struct *tty = file_tty(filp); @@ -2278,20 +2263,18 @@ static int tty_fasync(int fd, struct file *filp, int on) } /** - * tiocsti - fake input character - * @tty: tty to fake input into - * @p: pointer to character + * tiocsti - fake input character + * @tty: tty to fake input into + * @p: pointer to character * - * Fake input to a tty device. Does the necessary locking and - * input management. + * Fake input to a tty device. Does the necessary locking and input management. * - * FIXME: does not honour flow control ?? + * FIXME: does not honour flow control ?? * - * Locking: - * Called functions take tty_ldiscs_lock - * current->signal->tty check is safe without locks + * Locking: + * * Called functions take tty_ldiscs_lock + * * current->signal->tty check is safe without locks */ - static int tiocsti(struct tty_struct *tty, char __user *p) { char ch, mbz = 0; @@ -2314,16 +2297,15 @@ static int tiocsti(struct tty_struct *tty, char __user *p) } /** - * tiocgwinsz - implement window query ioctl - * @tty: tty - * @arg: user buffer for result + * tiocgwinsz - implement window query ioctl + * @tty: tty + * @arg: user buffer for result * - * Copies the kernel idea of the window size into the user buffer. + * Copies the kernel idea of the window size into the user buffer. * - * Locking: tty->winsize_mutex is taken to ensure the winsize data - * is consistent. + * Locking: @tty->winsize_mutex is taken to ensure the winsize data is + * consistent. */ - static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) { int err; @@ -2336,14 +2318,13 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) } /** - * tty_do_resize - resize event - * @tty: tty being resized - * @ws: new dimensions + * tty_do_resize - resize event + * @tty: tty being resized + * @ws: new dimensions * - * Update the termios variables and send the necessary signals to - * peform a terminal resize correctly + * Update the termios variables and send the necessary signals to peform a + * terminal resize correctly. */ - int tty_do_resize(struct tty_struct *tty, struct winsize *ws) { struct pid *pgrp; @@ -2367,20 +2348,19 @@ done: EXPORT_SYMBOL(tty_do_resize); /** - * tiocswinsz - implement window size set ioctl - * @tty: tty side of tty - * @arg: user buffer for result + * tiocswinsz - implement window size set ioctl + * @tty: tty side of tty + * @arg: user buffer for result * - * Copies the user idea of the window size to the kernel. Traditionally - * this is just advisory information but for the Linux console it - * actually has driver level meaning and triggers a VC resize. + * Copies the user idea of the window size to the kernel. Traditionally this is + * just advisory information but for the Linux console it actually has driver + * level meaning and triggers a VC resize. * - * Locking: - * Driver dependent. The default do_resize method takes the - * tty termios mutex and ctrl.lock. The console takes its own lock - * then calls into the default method. + * Locking: + * Driver dependent. The default do_resize method takes the tty termios + * mutex and ctrl.lock. The console takes its own lock then calls into the + * default method. */ - static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg) { struct winsize tmp_ws; @@ -2395,14 +2375,13 @@ static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg) } /** - * tioccons - allow admin to move logical console - * @file: the file to become console + * tioccons - allow admin to move logical console + * @file: the file to become console * - * Allow the administrator to move the redirected console device + * Allow the administrator to move the redirected console device. * - * Locking: uses redirect_lock to guard the redirect information + * Locking: uses redirect_lock to guard the redirect information */ - static int tioccons(struct file *file) { if (!capable(CAP_SYS_ADMIN)) @@ -2435,15 +2414,14 @@ static int tioccons(struct file *file) } /** - * tiocsetd - set line discipline - * @tty: tty device - * @p: pointer to user data + * tiocsetd - set line discipline + * @tty: tty device + * @p: pointer to user data * - * Set the line discipline according to user request. + * Set the line discipline according to user request. * - * Locking: see tty_set_ldisc, this function is just a helper + * Locking: see tty_set_ldisc(), this function is just a helper */ - static int tiocsetd(struct tty_struct *tty, int __user *p) { int disc; @@ -2458,16 +2436,15 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) } /** - * tiocgetd - get line discipline - * @tty: tty device - * @p: pointer to user data + * tiocgetd - get line discipline + * @tty: tty device + * @p: pointer to user data * - * Retrieves the line discipline id directly from the ldisc. + * Retrieves the line discipline id directly from the ldisc. * - * Locking: waits for ldisc reference (in case the line discipline - * is changing or the tty is being hungup) + * Locking: waits for ldisc reference (in case the line discipline is changing + * or the @tty is being hungup) */ - static int tiocgetd(struct tty_struct *tty, int __user *p) { struct tty_ldisc *ld; @@ -2482,18 +2459,16 @@ static int tiocgetd(struct tty_struct *tty, int __user *p) } /** - * send_break - performed time break - * @tty: device to break on - * @duration: timeout in mS - * - * Perform a timed break on hardware that lacks its own driver level - * timed break functionality. + * send_break - performed time break + * @tty: device to break on + * @duration: timeout in mS * - * Locking: - * atomic_write_lock serializes + * Perform a timed break on hardware that lacks its own driver level timed + * break functionality. * + * Locking: + * @tty->atomic_write_lock serializes */ - static int send_break(struct tty_struct *tty, unsigned int duration) { int retval; @@ -2522,16 +2497,15 @@ out: } /** - * tty_tiocmget - get modem status - * @tty: tty device - * @p: pointer to result + * tty_tiocmget - get modem status + * @tty: tty device + * @p: pointer to result * - * Obtain the modem status bits from the tty driver if the feature - * is supported. Return -ENOTTY if it is not available. + * Obtain the modem status bits from the tty driver if the feature is + * supported. Return -%ENOTTY if it is not available. * - * Locking: none (up to the driver) + * Locking: none (up to the driver) */ - static int tty_tiocmget(struct tty_struct *tty, int __user *p) { int retval = -ENOTTY; @@ -2546,17 +2520,16 @@ static int tty_tiocmget(struct tty_struct *tty, int __user *p) } /** - * tty_tiocmset - set modem status - * @tty: tty device - * @cmd: command - clear bits, set bits or set all - * @p: pointer to desired bits + * tty_tiocmset - set modem status + * @tty: tty device + * @cmd: command - clear bits, set bits or set all + * @p: pointer to desired bits * - * Set the modem status bits from the tty driver if the feature - * is supported. Return -ENOTTY if it is not available. + * Set the modem status bits from the tty driver if the feature + * is supported. Return -%ENOTTY if it is not available. * - * Locking: none (up to the driver) + * Locking: none (up to the driver) */ - static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd, unsigned __user *p) { @@ -2588,13 +2561,13 @@ static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd, } /** - * tty_get_icount - get tty statistics - * @tty: tty device - * @icount: output parameter + * tty_get_icount - get tty statistics + * @tty: tty device + * @icount: output parameter * - * Gets a copy of the tty's icount statistics. + * Gets a copy of the @tty's icount statistics. * - * Locking: none (up to the driver) + * Locking: none (up to the driver) */ int tty_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount) @@ -2811,7 +2784,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return hung_up_tty_ioctl(file, cmd, arg); retval = -EINVAL; if (ld->ops->ioctl) { - retval = ld->ops->ioctl(tty, file, cmd, arg); + retval = ld->ops->ioctl(tty, cmd, arg); if (retval == -ENOIOCTLCMD) retval = -ENOTTY; } @@ -2990,10 +2963,10 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, if (!ld) return hung_up_tty_compat_ioctl(file, cmd, arg); if (ld->ops->compat_ioctl) - retval = ld->ops->compat_ioctl(tty, file, cmd, arg); + retval = ld->ops->compat_ioctl(tty, cmd, arg); if (retval == -ENOIOCTLCMD && ld->ops->ioctl) - retval = ld->ops->ioctl(tty, file, - (unsigned long)compat_ptr(cmd), arg); + retval = ld->ops->ioctl(tty, (unsigned long)compat_ptr(cmd), + arg); tty_ldisc_deref(ld); return retval; @@ -3028,17 +3001,11 @@ static int this_tty(const void *t, struct file *file, unsigned fd) */ void __do_SAK(struct tty_struct *tty) { -#ifdef TTY_SOFT_SAK - tty_hangup(tty); -#else struct task_struct *g, *p; struct pid *session; - int i; + int i; unsigned long flags; - if (!tty) - return; - spin_lock_irqsave(&tty->ctrl.lock, flags); session = get_pid(tty->ctrl.session); spin_unlock_irqrestore(&tty->ctrl.lock, flags); @@ -3060,7 +3027,8 @@ void __do_SAK(struct tty_struct *tty) if (p->signal->tty == tty) { tty_notice(tty, "SAK: killed process %d (%s): by controlling tty\n", task_pid_nr(p), p->comm); - group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID); + group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, + PIDTYPE_SID); continue; } task_lock(p); @@ -3068,13 +3036,13 @@ void __do_SAK(struct tty_struct *tty) if (i != 0) { tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n", task_pid_nr(p), p->comm, i - 1); - group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, PIDTYPE_SID); + group_send_sig_info(SIGKILL, SEND_SIG_PRIV, p, + PIDTYPE_SID); } task_unlock(p); } while_each_thread(g, p); read_unlock(&tasklist_lock); put_pid(session); -#endif } static void do_SAK_work(struct work_struct *work) @@ -3107,14 +3075,15 @@ static struct device *tty_get_device(struct tty_struct *tty) } -/* - * alloc_tty_struct +/** + * alloc_tty_struct - allocate a new tty + * @driver: driver which will handle the returned tty + * @idx: minor of the tty * - * This subroutine allocates and initializes a tty structure. + * This subroutine allocates and initializes a tty structure. * - * Locking: none - tty in question is not exposed at this point + * Locking: none - @tty in question is not exposed at this point */ - struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) { struct tty_struct *tty; @@ -3156,17 +3125,18 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) } /** - * tty_put_char - write one character to a tty - * @tty: tty - * @ch: character + * tty_put_char - write one character to a tty + * @tty: tty + * @ch: character to write + * + * Write one byte to the @tty using the provided @tty->ops->put_char() method + * if present. * - * Write one byte to the tty using the provided put_char method - * if present. Returns the number of characters successfully output. + * Note: the specific put_char operation in the driver layer may go + * away soon. Don't call it directly, use this method * - * Note: the specific put_char operation in the driver layer may go - * away soon. Don't call it directly, use this method + * Return: the number of characters successfully output. */ - int tty_put_char(struct tty_struct *tty, unsigned char ch) { if (tty->ops->put_char) @@ -3195,24 +3165,23 @@ static int tty_cdev_add(struct tty_driver *driver, dev_t dev, } /** - * tty_register_device - register a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * @device: a struct device that is associated with this tty device. - * This field is optional, if there is no known struct device - * for this tty device it can be set to NULL safely. + * tty_register_device - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device + * for this tty device it can be set to NULL safely. * - * Returns a pointer to the struct device for this tty device - * (or ERR_PTR(-EFOO) on error). + * This call is required to be made to register an individual tty device + * if the tty driver's flags have the %TTY_DRIVER_DYNAMIC_DEV bit set. If + * that bit is not set, this function should not be called by a tty + * driver. * - * This call is required to be made to register an individual tty device - * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If - * that bit is not set, this function should not be called by a tty - * driver. + * Locking: ?? * - * Locking: ?? + * Return: A pointer to the struct device for this tty device (or + * ERR_PTR(-EFOO) on error). */ - struct device *tty_register_device(struct tty_driver *driver, unsigned index, struct device *device) { @@ -3227,24 +3196,23 @@ static void tty_device_create_release(struct device *dev) } /** - * tty_register_device_attr - register a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * @device: a struct device that is associated with this tty device. - * This field is optional, if there is no known struct device - * for this tty device it can be set to NULL safely. - * @drvdata: Driver data to be set to device. - * @attr_grp: Attribute group to be set on device. + * tty_register_device_attr - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device + * for this tty device it can be set to %NULL safely. + * @drvdata: Driver data to be set to device. + * @attr_grp: Attribute group to be set on device. * - * Returns a pointer to the struct device for this tty device - * (or ERR_PTR(-EFOO) on error). + * This call is required to be made to register an individual tty device if the + * tty driver's flags have the %TTY_DRIVER_DYNAMIC_DEV bit set. If that bit is + * not set, this function should not be called by a tty driver. * - * This call is required to be made to register an individual tty device - * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If - * that bit is not set, this function should not be called by a tty - * driver. + * Locking: ?? * - * Locking: ?? + * Return: A pointer to the struct device for this tty device (or + * ERR_PTR(-EFOO) on error). */ struct device *tty_register_device_attr(struct tty_driver *driver, unsigned index, struct device *device, @@ -3317,16 +3285,15 @@ err_put: EXPORT_SYMBOL_GPL(tty_register_device_attr); /** - * tty_unregister_device - unregister a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device + * tty_unregister_device - unregister a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device * - * If a tty device is registered with a call to tty_register_device() then - * this function must be called when the tty device is gone. + * If a tty device is registered with a call to tty_register_device() then + * this function must be called when the tty device is gone. * - * Locking: ?? + * Locking: ?? */ - void tty_unregister_device(struct tty_driver *driver, unsigned index) { device_destroy(tty_class, @@ -3342,10 +3309,10 @@ EXPORT_SYMBOL(tty_unregister_device); * __tty_alloc_driver -- allocate tty driver * @lines: count of lines this driver can handle at most * @owner: module which is responsible for this driver - * @flags: some of TTY_DRIVER_* flags, will be set in driver->flags + * @flags: some of %TTY_DRIVER_ flags, will be set in driver->flags * * This should not be called directly, some of the provided macros should be - * used instead. Use IS_ERR and friends on @retval. + * used instead. Use IS_ERR() and friends on @retval. */ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, unsigned long flags) @@ -3432,13 +3399,22 @@ static void destruct_tty_driver(struct kref *kref) kfree(driver); } +/** + * tty_driver_kref_put -- drop a reference to a tty driver + * @driver: driver of which to drop the reference + * + * The final put will destroy and free up the driver. + */ void tty_driver_kref_put(struct tty_driver *driver) { kref_put(&driver->kref, destruct_tty_driver); } EXPORT_SYMBOL(tty_driver_kref_put); -/* +/** + * tty_register_driver -- register a tty driver + * @driver: driver to register + * * Called by a tty driver to register itself. */ int tty_register_driver(struct tty_driver *driver) @@ -3500,7 +3476,10 @@ err: } EXPORT_SYMBOL(tty_register_driver); -/* +/** + * tty_unregister_driver -- unregister a tty driver + * @driver: driver to unregister + * * Called by a tty driver to unregister itself. */ void tty_unregister_driver(struct tty_driver *driver) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 3e4e0b20b4bb..776d8a62f77c 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -47,17 +47,14 @@ static DEFINE_RAW_SPINLOCK(tty_ldiscs_lock); static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; /** - * tty_register_ldisc - install a line discipline - * @new_ldisc: pointer to the ldisc object + * tty_register_ldisc - install a line discipline + * @new_ldisc: pointer to the ldisc object * - * Installs a new line discipline into the kernel. The discipline - * is set up as unreferenced and then made available to the kernel - * from this point onwards. + * Installs a new line discipline into the kernel. The discipline is set up as + * unreferenced and then made available to the kernel from this point onwards. * - * Locking: - * takes tty_ldiscs_lock to guard against ldisc races + * Locking: takes %tty_ldiscs_lock to guard against ldisc races */ - int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc) { unsigned long flags; @@ -75,14 +72,13 @@ int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc) EXPORT_SYMBOL(tty_register_ldisc); /** - * tty_unregister_ldisc - unload a line discipline - * @ldisc: ldisc number + * tty_unregister_ldisc - unload a line discipline + * @ldisc: ldisc number * - * Remove a line discipline from the kernel providing it is not - * currently in use. + * Remove a line discipline from the kernel providing it is not currently in + * use. * - * Locking: - * takes tty_ldiscs_lock to guard against ldisc races + * Locking: takes %tty_ldiscs_lock to guard against ldisc races */ void tty_unregister_ldisc(struct tty_ldisc_ops *ldisc) @@ -122,27 +118,25 @@ static void put_ldops(struct tty_ldisc_ops *ldops) } static int tty_ldisc_autoload = IS_BUILTIN(CONFIG_LDISC_AUTOLOAD); + /** - * tty_ldisc_get - take a reference to an ldisc - * @tty: tty device - * @disc: ldisc number - * - * Takes a reference to a line discipline. Deals with refcounts and - * module locking counts. - * - * Returns: -EINVAL if the discipline index is not [N_TTY..NR_LDISCS] or - * if the discipline is not registered - * -EAGAIN if request_module() failed to load or register the - * discipline - * -ENOMEM if allocation failure - * - * Otherwise, returns a pointer to the discipline and bumps the - * ref count - * - * Locking: - * takes tty_ldiscs_lock to guard against ldisc races + * tty_ldisc_get - take a reference to an ldisc + * @tty: tty device + * @disc: ldisc number + * + * Takes a reference to a line discipline. Deals with refcounts and module + * locking counts. If the discipline is not available, its module loaded, if + * possible. + * + * Returns: + * * -%EINVAL if the discipline index is not [%N_TTY .. %NR_LDISCS] or if the + * discipline is not registered + * * -%EAGAIN if request_module() failed to load or register the discipline + * * -%ENOMEM if allocation failure + * * Otherwise, returns a pointer to the discipline and bumps the ref count + * + * Locking: takes %tty_ldiscs_lock to guard against ldisc races */ - static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) { struct tty_ldisc *ld; @@ -176,10 +170,11 @@ static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) return ld; } -/* - * tty_ldisc_put - release the ldisc +/** + * tty_ldisc_put - release the ldisc + * @ld: lisdsc to release * - * Complement of tty_ldisc_get(). + * Complement of tty_ldisc_get(). */ static void tty_ldisc_put(struct tty_ldisc *ld) { @@ -226,25 +221,22 @@ const struct seq_operations tty_ldiscs_seq_ops = { }; /** - * tty_ldisc_ref_wait - wait for the tty ldisc - * @tty: tty device + * tty_ldisc_ref_wait - wait for the tty ldisc + * @tty: tty device * - * Dereference the line discipline for the terminal and take a - * reference to it. If the line discipline is in flux then - * wait patiently until it changes. + * Dereference the line discipline for the terminal and take a reference to it. + * If the line discipline is in flux then wait patiently until it changes. * - * Returns: NULL if the tty has been hungup and not re-opened with - * a new file descriptor, otherwise valid ldisc reference + * Returns: %NULL if the tty has been hungup and not re-opened with a new file + * descriptor, otherwise valid ldisc reference * - * Note 1: Must not be called from an IRQ/timer context. The caller - * must also be careful not to hold other locks that will deadlock - * against a discipline change, such as an existing ldisc reference - * (which we check for) + * Note 1: Must not be called from an IRQ/timer context. The caller must also + * be careful not to hold other locks that will deadlock against a discipline + * change, such as an existing ldisc reference (which we check for). * - * Note 2: a file_operations routine (read/poll/write) should use this - * function to wait for any ldisc lifetime events to finish. + * Note 2: a file_operations routine (read/poll/write) should use this function + * to wait for any ldisc lifetime events to finish. */ - struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) { struct tty_ldisc *ld; @@ -258,14 +250,13 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); /** - * tty_ldisc_ref - get the tty ldisc - * @tty: tty device + * tty_ldisc_ref - get the tty ldisc + * @tty: tty device * - * Dereference the line discipline for the terminal and take a - * reference to it. If the line discipline is in flux then - * return NULL. Can be called from IRQ and timer functions. + * Dereference the line discipline for the terminal and take a reference to it. + * If the line discipline is in flux then return %NULL. Can be called from IRQ + * and timer functions. */ - struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) { struct tty_ldisc *ld = NULL; @@ -280,13 +271,12 @@ struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_ldisc_ref); /** - * tty_ldisc_deref - free a tty ldisc reference - * @ld: reference to free up + * tty_ldisc_deref - free a tty ldisc reference + * @ld: reference to free up * - * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May - * be called in IRQ context. + * Undoes the effect of tty_ldisc_ref() or tty_ldisc_ref_wait(). May be called + * in IRQ context. */ - void tty_ldisc_deref(struct tty_ldisc *ld) { ldsem_up_read(&ld->tty->ldisc_sem); @@ -386,13 +376,12 @@ static void tty_ldisc_unlock_pair(struct tty_struct *tty, } /** - * tty_ldisc_flush - flush line discipline queue - * @tty: tty + * tty_ldisc_flush - flush line discipline queue + * @tty: tty to flush ldisc for * - * Flush the line discipline queue (if any) and the tty flip buffers - * for this tty. + * Flush the line discipline queue (if any) and the tty flip buffers for this + * @tty. */ - void tty_ldisc_flush(struct tty_struct *tty) { struct tty_ldisc *ld = tty_ldisc_ref(tty); @@ -404,21 +393,18 @@ void tty_ldisc_flush(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_ldisc_flush); /** - * tty_set_termios_ldisc - set ldisc field - * @tty: tty structure - * @disc: line discipline number + * tty_set_termios_ldisc - set ldisc field + * @tty: tty structure + * @disc: line discipline number * - * This is probably overkill for real world processors but - * they are not on hot paths so a little discipline won't do - * any harm. + * This is probably overkill for real world processors but they are not on hot + * paths so a little discipline won't do any harm. * - * The line discipline-related tty_struct fields are reset to - * prevent the ldisc driver from re-using stale information for - * the new ldisc instance. + * The line discipline-related tty_struct fields are reset to prevent the ldisc + * driver from re-using stale information for the new ldisc instance. * - * Locking: takes termios_rwsem + * Locking: takes termios_rwsem */ - static void tty_set_termios_ldisc(struct tty_struct *tty, int disc) { down_write(&tty->termios_rwsem); @@ -430,16 +416,14 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int disc) } /** - * tty_ldisc_open - open a line discipline - * @tty: tty we are opening the ldisc on - * @ld: discipline to open + * tty_ldisc_open - open a line discipline + * @tty: tty we are opening the ldisc on + * @ld: discipline to open * - * A helper opening method. Also a convenient debugging and check - * point. + * A helper opening method. Also a convenient debugging and check point. * - * Locking: always called with BTM already held. + * Locking: always called with BTM already held. */ - static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) { WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); @@ -457,14 +441,12 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) } /** - * tty_ldisc_close - close a line discipline - * @tty: tty we are opening the ldisc on - * @ld: discipline to close + * tty_ldisc_close - close a line discipline + * @tty: tty we are opening the ldisc on + * @ld: discipline to close * - * A helper close method. Also a convenient debugging and check - * point. + * A helper close method. Also a convenient debugging and check point. */ - static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) { lockdep_assert_held_write(&tty->ldisc_sem); @@ -476,14 +458,13 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) } /** - * tty_ldisc_failto - helper for ldisc failback - * @tty: tty to open the ldisc on - * @ld: ldisc we are trying to fail back to + * tty_ldisc_failto - helper for ldisc failback + * @tty: tty to open the ldisc on + * @ld: ldisc we are trying to fail back to * - * Helper to try and recover a tty when switching back to the old - * ldisc fails and we need something attached. + * Helper to try and recover a tty when switching back to the old ldisc fails + * and we need something attached. */ - static int tty_ldisc_failto(struct tty_struct *tty, int ld) { struct tty_ldisc *disc = tty_ldisc_get(tty, ld); @@ -501,14 +482,13 @@ static int tty_ldisc_failto(struct tty_struct *tty, int ld) } /** - * tty_ldisc_restore - helper for tty ldisc change - * @tty: tty to recover - * @old: previous ldisc + * tty_ldisc_restore - helper for tty ldisc change + * @tty: tty to recover + * @old: previous ldisc * - * Restore the previous line discipline or N_TTY when a line discipline - * change fails due to an open error + * Restore the previous line discipline or %N_TTY when a line discipline change + * fails due to an open error */ - static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) { /* There is an outstanding reference here so this is safe */ @@ -528,16 +508,15 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) } /** - * tty_set_ldisc - set line discipline - * @tty: the terminal to set - * @disc: the line discipline number - * - * Set the discipline of a tty line. Must be called from a process - * context. The ldisc change logic has to protect itself against any - * overlapping ldisc change (including on the other end of pty pairs), - * the close of one side of a tty/pty pair, and eventually hangup. + * tty_set_ldisc - set line discipline + * @tty: the terminal to set + * @disc: the line discipline number + * + * Set the discipline of a tty line. Must be called from a process context. The + * ldisc change logic has to protect itself against any overlapping ldisc + * change (including on the other end of pty pairs), the close of one side of a + * tty/pty pair, and eventually hangup. */ - int tty_set_ldisc(struct tty_struct *tty, int disc) { int retval; @@ -613,10 +592,10 @@ err: EXPORT_SYMBOL_GPL(tty_set_ldisc); /** - * tty_ldisc_kill - teardown ldisc - * @tty: tty being released + * tty_ldisc_kill - teardown ldisc + * @tty: tty being released * - * Perform final close of the ldisc and reset tty->ldisc + * Perform final close of the ldisc and reset @tty->ldisc */ static void tty_ldisc_kill(struct tty_struct *tty) { @@ -633,12 +612,11 @@ static void tty_ldisc_kill(struct tty_struct *tty) } /** - * tty_reset_termios - reset terminal state - * @tty: tty to reset + * tty_reset_termios - reset terminal state + * @tty: tty to reset * - * Restore a terminal to the driver default state. + * Restore a terminal to the driver default state. */ - static void tty_reset_termios(struct tty_struct *tty) { down_write(&tty->termios_rwsem); @@ -650,19 +628,17 @@ static void tty_reset_termios(struct tty_struct *tty) /** - * tty_ldisc_reinit - reinitialise the tty ldisc - * @tty: tty to reinit - * @disc: line discipline to reinitialize + * tty_ldisc_reinit - reinitialise the tty ldisc + * @tty: tty to reinit + * @disc: line discipline to reinitialize * - * Completely reinitialize the line discipline state, by closing the - * current instance, if there is one, and opening a new instance. If - * an error occurs opening the new non-N_TTY instance, the instance - * is dropped and tty->ldisc reset to NULL. The caller can then retry - * with N_TTY instead. + * Completely reinitialize the line discipline state, by closing the current + * instance, if there is one, and opening a new instance. If an error occurs + * opening the new non-%N_TTY instance, the instance is dropped and @tty->ldisc + * reset to %NULL. The caller can then retry with %N_TTY instead. * - * Returns 0 if successful, otherwise error code < 0 + * Returns: 0 if successful, otherwise error code < 0 */ - int tty_ldisc_reinit(struct tty_struct *tty, int disc) { struct tty_ldisc *ld; @@ -692,21 +668,20 @@ int tty_ldisc_reinit(struct tty_struct *tty, int disc) } /** - * tty_ldisc_hangup - hangup ldisc reset - * @tty: tty being hung up - * @reinit: whether to re-initialise the tty + * tty_ldisc_hangup - hangup ldisc reset + * @tty: tty being hung up + * @reinit: whether to re-initialise the tty * - * Some tty devices reset their termios when they receive a hangup - * event. In that situation we must also switch back to N_TTY properly - * before we reset the termios data. + * Some tty devices reset their termios when they receive a hangup event. In + * that situation we must also switch back to %N_TTY properly before we reset + * the termios data. * - * Locking: We can take the ldisc mutex as the rest of the code is - * careful to allow for this. + * Locking: We can take the ldisc mutex as the rest of the code is careful to + * allow for this. * - * In the pty pair case this occurs in the close() path of the - * tty itself so we must be careful about locking rules. + * In the pty pair case this occurs in the close() path of the tty itself so we + * must be careful about locking rules. */ - void tty_ldisc_hangup(struct tty_struct *tty, bool reinit) { struct tty_ldisc *ld; @@ -752,15 +727,14 @@ void tty_ldisc_hangup(struct tty_struct *tty, bool reinit) } /** - * tty_ldisc_setup - open line discipline - * @tty: tty being shut down - * @o_tty: pair tty for pty/tty pairs + * tty_ldisc_setup - open line discipline + * @tty: tty being shut down + * @o_tty: pair tty for pty/tty pairs * - * Called during the initial open of a tty/pty pair in order to set up the - * line disciplines and bind them to the tty. This has no locking issues - * as the device isn't yet active. + * Called during the initial open of a tty/pty pair in order to set up the line + * disciplines and bind them to the @tty. This has no locking issues as the + * device isn't yet active. */ - int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) { int retval = tty_ldisc_open(tty, tty->ldisc); @@ -783,13 +757,12 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) } /** - * tty_ldisc_release - release line discipline - * @tty: tty being shut down (or one end of pty pair) + * tty_ldisc_release - release line discipline + * @tty: tty being shut down (or one end of pty pair) * - * Called during the final close of a tty or a pty pair in order to shut - * down the line discpline layer. On exit, each tty's ldisc is NULL. + * Called during the final close of a tty or a pty pair in order to shut down + * the line discpline layer. On exit, each tty's ldisc is %NULL. */ - void tty_ldisc_release(struct tty_struct *tty) { struct tty_struct *o_tty = tty->link; @@ -814,13 +787,12 @@ void tty_ldisc_release(struct tty_struct *tty) } /** - * tty_ldisc_init - ldisc setup for new tty - * @tty: tty being allocated + * tty_ldisc_init - ldisc setup for new tty + * @tty: tty being allocated * - * Set up the line discipline objects for a newly allocated tty. Note that - * the tty structure is not completely set up when this call is made. + * Set up the line discipline objects for a newly allocated tty. Note that the + * tty structure is not completely set up when this call is made. */ - int tty_ldisc_init(struct tty_struct *tty) { struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY); @@ -832,11 +804,11 @@ int tty_ldisc_init(struct tty_struct *tty) } /** - * tty_ldisc_deinit - ldisc cleanup for new tty - * @tty: tty that was allocated recently + * tty_ldisc_deinit - ldisc cleanup for new tty + * @tty: tty that was allocated recently * - * The tty structure must not becompletely set up (tty_ldisc_setup) when - * this call is made. + * The tty structure must not be completely set up (tty_ldisc_setup()) when + * this call is made. */ void tty_ldisc_deinit(struct tty_struct *tty) { diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c index ce8291053af3..3be428c16260 100644 --- a/drivers/tty/tty_ldsem.c +++ b/drivers/tty/tty_ldsem.c @@ -163,7 +163,7 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout) /* * Try to reverse the lock attempt but if the count has changed - * so that reversing fails, check if there are are no waiters, + * so that reversing fails, check if there are no waiters, * and early-out if not */ do { diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 2f1061a9d926..7709ce655f44 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -59,6 +59,15 @@ const struct tty_port_client_operations tty_port_default_client_ops = { }; EXPORT_SYMBOL_GPL(tty_port_default_client_ops); +/** + * tty_port_init -- initialize tty_port + * @port: tty_port to initialize + * + * Initializes the state of struct tty_port. When a port was initialized using + * this function, one has to destroy the port by tty_port_destroy(). Either + * indirectly by using &tty_port refcounting (tty_port_put()) or directly if + * refcounting is not used. + */ void tty_port_init(struct tty_port *port) { memset(port, 0, sizeof(*port)); @@ -82,9 +91,9 @@ EXPORT_SYMBOL(tty_port_init); * @index: index of the tty * * Provide the tty layer with a link from a tty (specified by @index) to a - * tty_port (@port). Use this only if neither tty_port_register_device nor - * tty_port_install is used in the driver. If used, this has to be called before - * tty_register_driver. + * tty_port (@port). Use this only if neither tty_port_register_device() nor + * tty_port_install() is used in the driver. If used, this has to be called + * before tty_register_driver(). */ void tty_port_link_device(struct tty_port *port, struct tty_driver *driver, unsigned index) @@ -102,9 +111,9 @@ EXPORT_SYMBOL_GPL(tty_port_link_device); * @index: index of the tty * @device: parent if exists, otherwise NULL * - * It is the same as tty_register_device except the provided @port is linked to - * a concrete tty specified by @index. Use this or tty_port_install (or both). - * Call tty_port_link_device as a last resort. + * It is the same as tty_register_device() except the provided @port is linked + * to a concrete tty specified by @index. Use this or tty_port_install() (or + * both). Call tty_port_link_device() as a last resort. */ struct device *tty_port_register_device(struct tty_port *port, struct tty_driver *driver, unsigned index, @@ -123,9 +132,9 @@ EXPORT_SYMBOL_GPL(tty_port_register_device); * @drvdata: Driver data to be set to device. * @attr_grp: Attribute group to be set on device. * - * It is the same as tty_register_device_attr except the provided @port is - * linked to a concrete tty specified by @index. Use this or tty_port_install - * (or both). Call tty_port_link_device as a last resort. + * It is the same as tty_register_device_attr() except the provided @port is + * linked to a concrete tty specified by @index. Use this or tty_port_install() + * (or both). Call tty_port_link_device() as a last resort. */ struct device *tty_port_register_device_attr(struct tty_port *port, struct tty_driver *driver, unsigned index, @@ -240,9 +249,9 @@ EXPORT_SYMBOL(tty_port_free_xmit_buf); * tty_port_destroy -- destroy inited port * @port: tty port to be destroyed * - * When a port was initialized using tty_port_init, one has to destroy the - * port by this function. Either indirectly by using tty_port refcounting - * (tty_port_put) or directly if refcounting is not used. + * When a port was initialized using tty_port_init(), one has to destroy the + * port by this function. Either indirectly by using &tty_port refcounting + * (tty_port_put()) or directly if refcounting is not used. */ void tty_port_destroy(struct tty_port *port) { @@ -267,6 +276,13 @@ static void tty_port_destructor(struct kref *kref) kfree(port); } +/** + * tty_port_put -- drop a reference to tty_port + * @port: port to drop a reference of (can be NULL) + * + * The final put will destroy and free up the @port using + * @port->ops->destruct() hook, or using kfree() if not provided. + */ void tty_port_put(struct tty_port *port) { if (port) @@ -275,11 +291,11 @@ void tty_port_put(struct tty_port *port) EXPORT_SYMBOL(tty_port_put); /** - * tty_port_tty_get - get a tty reference - * @port: tty port + * tty_port_tty_get - get a tty reference + * @port: tty port * - * Return a refcount protected tty instance or NULL if the port is not - * associated with a tty (eg due to close or hangup) + * Return a refcount protected tty instance or %NULL if the port is not + * associated with a tty (eg due to close or hangup). */ struct tty_struct *tty_port_tty_get(struct tty_port *port) { @@ -294,12 +310,12 @@ struct tty_struct *tty_port_tty_get(struct tty_port *port) EXPORT_SYMBOL(tty_port_tty_get); /** - * tty_port_tty_set - set the tty of a port - * @port: tty port - * @tty: the tty + * tty_port_tty_set - set the tty of a port + * @port: tty port + * @tty: the tty * - * Associate the port and tty pair. Manages any internal refcounts. - * Pass NULL to deassociate a port + * Associate the port and tty pair. Manages any internal refcounts. Pass %NULL + * to deassociate a port. */ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) { @@ -312,6 +328,16 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) } EXPORT_SYMBOL(tty_port_tty_set); +/** + * tty_port_shutdown - internal helper to shutdown the device + * @port: tty port to be shut down + * @tty: the associated tty + * + * It is used by tty_port_hangup() and tty_port_close(). Its task is to + * shutdown the device if it was initialized (note consoles remain + * functioning). It lowers DTR/RTS (if @tty has HUPCL set) and invokes + * @port->ops->shutdown(). + */ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) { mutex_lock(&port->mutex); @@ -335,13 +361,13 @@ out: } /** - * tty_port_hangup - hangup helper - * @port: tty port + * tty_port_hangup - hangup helper + * @port: tty port * - * Perform port level tty hangup flag and count changes. Drop the tty - * reference. + * Perform port level tty hangup flag and count changes. Drop the tty + * reference. * - * Caller holds tty lock. + * Caller holds tty lock. */ void tty_port_hangup(struct tty_port *port) { @@ -365,9 +391,8 @@ EXPORT_SYMBOL(tty_port_hangup); /** * tty_port_tty_hangup - helper to hang up a tty - * * @port: tty port - * @check_clocal: hang only ttys with CLOCAL unset? + * @check_clocal: hang only ttys with %CLOCAL unset? */ void tty_port_tty_hangup(struct tty_port *port, bool check_clocal) { @@ -381,7 +406,6 @@ EXPORT_SYMBOL_GPL(tty_port_tty_hangup); /** * tty_port_tty_wakeup - helper to wake up a tty - * * @port: tty port */ void tty_port_tty_wakeup(struct tty_port *port) @@ -391,12 +415,12 @@ void tty_port_tty_wakeup(struct tty_port *port) EXPORT_SYMBOL_GPL(tty_port_tty_wakeup); /** - * tty_port_carrier_raised - carrier raised check - * @port: tty port + * tty_port_carrier_raised - carrier raised check + * @port: tty port * - * Wrapper for the carrier detect logic. For the moment this is used - * to hide some internal details. This will eventually become entirely - * internal to the tty port. + * Wrapper for the carrier detect logic. For the moment this is used + * to hide some internal details. This will eventually become entirely + * internal to the tty port. */ int tty_port_carrier_raised(struct tty_port *port) { @@ -407,12 +431,12 @@ int tty_port_carrier_raised(struct tty_port *port) EXPORT_SYMBOL(tty_port_carrier_raised); /** - * tty_port_raise_dtr_rts - Raise DTR/RTS - * @port: tty port + * tty_port_raise_dtr_rts - Raise DTR/RTS + * @port: tty port * - * Wrapper for the DTR/RTS raise logic. For the moment this is used - * to hide some internal details. This will eventually become entirely - * internal to the tty port. + * Wrapper for the DTR/RTS raise logic. For the moment this is used to hide + * some internal details. This will eventually become entirely internal to the + * tty port. */ void tty_port_raise_dtr_rts(struct tty_port *port) { @@ -422,12 +446,12 @@ void tty_port_raise_dtr_rts(struct tty_port *port) EXPORT_SYMBOL(tty_port_raise_dtr_rts); /** - * tty_port_lower_dtr_rts - Lower DTR/RTS - * @port: tty port + * tty_port_lower_dtr_rts - Lower DTR/RTS + * @port: tty port * - * Wrapper for the DTR/RTS raise logic. For the moment this is used - * to hide some internal details. This will eventually become entirely - * internal to the tty port. + * Wrapper for the DTR/RTS raise logic. For the moment this is used to hide + * some internal details. This will eventually become entirely internal to the + * tty port. */ void tty_port_lower_dtr_rts(struct tty_port *port) { @@ -437,28 +461,29 @@ void tty_port_lower_dtr_rts(struct tty_port *port) EXPORT_SYMBOL(tty_port_lower_dtr_rts); /** - * tty_port_block_til_ready - Waiting logic for tty open - * @port: the tty port being opened - * @tty: the tty device being bound - * @filp: the file pointer of the opener or NULL - * - * Implement the core POSIX/SuS tty behaviour when opening a tty device. - * Handles: - * - hangup (both before and during) - * - non blocking open - * - rts/dtr/dcd - * - signals - * - port flags and counts - * - * The passed tty_port must implement the carrier_raised method if it can - * do carrier detect and the dtr_rts method if it supports software - * management of these lines. Note that the dtr/rts raise is done each - * iteration as a hangup may have previously dropped them while we wait. - * - * Caller holds tty lock. - * - * NB: May drop and reacquire tty lock when blocking, so tty and tty_port - * may have changed state (eg., may have been hung up). + * tty_port_block_til_ready - Waiting logic for tty open + * @port: the tty port being opened + * @tty: the tty device being bound + * @filp: the file pointer of the opener or %NULL + * + * Implement the core POSIX/SuS tty behaviour when opening a tty device. + * Handles: + * + * - hangup (both before and during) + * - non blocking open + * - rts/dtr/dcd + * - signals + * - port flags and counts + * + * The passed @port must implement the @port->ops->carrier_raised method if it + * can do carrier detect and the @port->ops->dtr_rts method if it supports + * software management of these lines. Note that the dtr/rts raise is done each + * iteration as a hangup may have previously dropped them while we wait. + * + * Caller holds tty lock. + * + * Note: May drop and reacquire tty lock when blocking, so @tty and @port may + * have changed state (eg., may have been hung up). */ int tty_port_block_til_ready(struct tty_port *port, struct tty_struct *tty, struct file *filp) @@ -560,7 +585,21 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty) schedule_timeout_interruptible(timeout); } -/* Caller holds tty lock. */ +/** + * tty_port_close_start - helper for tty->ops->close, part 1/2 + * @port: tty_port of the device + * @tty: tty being closed + * @filp: passed file pointer + * + * Decrements and checks open count. Flushes the port if this is the last + * close. That means, dropping the data from the outpu buffer on the device and + * waiting for sending logic to finish. The rest of close handling is performed + * in tty_port_close_end(). + * + * Locking: Caller holds tty lock. + * + * Return: 1 if this is the last close, otherwise 0 + */ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp) { @@ -606,7 +645,17 @@ int tty_port_close_start(struct tty_port *port, } EXPORT_SYMBOL(tty_port_close_start); -/* Caller holds tty lock */ +/** + * tty_port_close_end - helper for tty->ops->close, part 2/2 + * @port: tty_port of the device + * @tty: tty being closed + * + * This is a continuation of the first part: tty_port_close_start(). This + * should be called after turning off the device. It flushes the data from the + * line discipline and delays the close by @port->close_delay. + * + * Locking: Caller holds tty lock. + */ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) { unsigned long flags; @@ -628,10 +677,18 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) } EXPORT_SYMBOL(tty_port_close_end); -/* - * tty_port_close +/** + * tty_port_close - generic tty->ops->close handler + * @port: tty_port of the device + * @tty: tty being closed + * @filp: passed file pointer + * + * It is a generic helper to be used in driver's @tty->ops->close. It wraps a + * sequence of tty_port_close_start(), tty_port_shutdown(), and + * tty_port_close_end(). The latter two are called only if this is the last + * close. See the respective functions for the details. * - * Caller holds tty lock + * Locking: Caller holds tty lock */ void tty_port_close(struct tty_port *port, struct tty_struct *tty, struct file *filp) @@ -652,9 +709,9 @@ EXPORT_SYMBOL(tty_port_close); * @driver: tty_driver for this device * @tty: tty to be installed * - * It is the same as tty_standard_install except the provided @port is linked - * to a concrete tty specified by @tty. Use this or tty_port_register_device - * (or both). Call tty_port_link_device as a last resort. + * It is the same as tty_standard_install() except the provided @port is linked + * to a concrete tty specified by @tty. Use this or tty_port_register_device() + * (or both). Call tty_port_link_device() as a last resort. */ int tty_port_install(struct tty_port *port, struct tty_driver *driver, struct tty_struct *tty) @@ -664,13 +721,21 @@ int tty_port_install(struct tty_port *port, struct tty_driver *driver, } EXPORT_SYMBOL_GPL(tty_port_install); -/* - * tty_port_open +/** + * tty_port_open - generic tty->ops->open handler + * @port: tty_port of the device + * @tty: tty to be opened + * @filp: passed file pointer * - * Caller holds tty lock. + * It is a generic helper to be used in driver's @tty->ops->open. It activates + * the devices using @port->ops->activate if not active already. And waits for + * the device to be ready using tty_port_block_til_ready() (e.g. raises + * DTR/CTS and waits for carrier). + * + * Locking: Caller holds tty lock. * - * NB: may drop and reacquire tty lock (in tty_port_block_til_ready()) so - * tty and tty_port may have changed state (eg., may be hung up now) + * Note: may drop and reacquire tty lock (in tty_port_block_til_ready()) so + * @tty and @port may have changed state (eg., may be hung up now). */ int tty_port_open(struct tty_port *port, struct tty_struct *tty, struct file *filp) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index c7fbbcdcc346..be8313cdbac3 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -153,6 +153,7 @@ static int shift_state = 0; static unsigned int ledstate = -1U; /* undefined */ static unsigned char ledioctl; +static bool vt_switch; /* * Notifier list for console keyboard events @@ -324,13 +325,13 @@ int kbd_rate(struct kbd_repeat *rpt) static void put_queue(struct vc_data *vc, int ch) { tty_insert_flip_char(&vc->port, ch, 0); - tty_schedule_flip(&vc->port); + tty_flip_buffer_push(&vc->port); } static void puts_queue(struct vc_data *vc, const char *cp) { tty_insert_flip_string(&vc->port, cp, strlen(cp)); - tty_schedule_flip(&vc->port); + tty_flip_buffer_push(&vc->port); } static void applkey(struct vc_data *vc, int key, char mode) @@ -414,6 +415,12 @@ void vt_set_leds_compute_shiftstate(void) { unsigned long flags; + /* + * When VT is switched, the keyboard led needs to be set once. + * Ensure that after the switch is completed, the state of the + * keyboard LED is consistent with the state of the keyboard lock. + */ + vt_switch = true; set_leds(); spin_lock_irqsave(&kbd_event_lock, flags); @@ -584,7 +591,7 @@ static void fn_inc_console(struct vc_data *vc) static void fn_send_intr(struct vc_data *vc) { tty_insert_flip_char(&vc->port, 0, TTY_BREAK); - tty_schedule_flip(&vc->port); + tty_flip_buffer_push(&vc->port); } static void fn_scroll_forw(struct vc_data *vc) @@ -1255,6 +1262,11 @@ static void kbd_bh(struct tasklet_struct *unused) leds |= (unsigned int)kbd->lockstate << 8; spin_unlock_irqrestore(&led_lock, flags); + if (vt_switch) { + ledstate = ~leds; + vt_switch = false; + } + if (leds != ledstate) { kbd_propagate_led_state(ledstate, leds); ledstate = leds; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 7359c3e80d63..f8c87c4d7399 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1833,7 +1833,7 @@ static void csi_m(struct vc_data *vc) static void respond_string(const char *p, size_t len, struct tty_port *port) { tty_insert_flip_string(port, p, len); - tty_schedule_flip(port); + tty_flip_buffer_push(port); } static void cursor_report(struct vc_data *vc, struct tty_struct *tty) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index b3ce7338cb6b..9b9aea24d58c 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -685,10 +685,6 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) if (retval) goto error_get_interface; - /* - * FIXME: Why do we need this? Allocating 64K of physically contiguous - * memory is really nasty... - */ set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); acm->control->needs_remote_wakeup = 1; diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h index edfcf7a14dcd..6c7f47846971 100644 --- a/include/linux/amba/bus.h +++ b/include/linux/amba/bus.h @@ -90,14 +90,8 @@ enum amba_vendor { AMBA_VENDOR_ST = 0x80, AMBA_VENDOR_QCOM = 0x51, AMBA_VENDOR_LSI = 0xb6, - AMBA_VENDOR_LINUX = 0xfe, /* This value is not official */ }; -/* This is used to generate pseudo-ID for AMBA device */ -#define AMBA_LINUX_ID(conf, rev, part) \ - (((conf) & 0xff) << 24 | ((rev) & 0xf) << 20 | \ - AMBA_VENDOR_LINUX << 12 | ((part) & 0xfff)) - extern struct bus_type amba_bustype; #define to_amba_device(d) container_of(d, struct amba_device, dev) diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index b5248f27910e..86678588d191 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1965,24 +1965,6 @@ #define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 #define PCI_VENDOR_ID_MOXA 0x1393 -#define PCI_DEVICE_ID_MOXA_RC7000 0x0001 -#define PCI_DEVICE_ID_MOXA_CP102 0x1020 -#define PCI_DEVICE_ID_MOXA_CP102UL 0x1021 -#define PCI_DEVICE_ID_MOXA_CP102U 0x1022 -#define PCI_DEVICE_ID_MOXA_C104 0x1040 -#define PCI_DEVICE_ID_MOXA_CP104U 0x1041 -#define PCI_DEVICE_ID_MOXA_CP104JU 0x1042 -#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043 -#define PCI_DEVICE_ID_MOXA_CT114 0x1140 -#define PCI_DEVICE_ID_MOXA_CP114 0x1141 -#define PCI_DEVICE_ID_MOXA_CP118U 0x1180 -#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181 -#define PCI_DEVICE_ID_MOXA_CP132 0x1320 -#define PCI_DEVICE_ID_MOXA_CP132U 0x1321 -#define PCI_DEVICE_ID_MOXA_CP134U 0x1340 -#define PCI_DEVICE_ID_MOXA_C168 0x1680 -#define PCI_DEVICE_ID_MOXA_CP168U 0x1681 -#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682 #define PCI_DEVICE_ID_MOXA_CP204J 0x2040 #define PCI_DEVICE_ID_MOXA_C218 0x2180 #define PCI_DEVICE_ID_MOXA_C320 0x3200 diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 5db211f43b29..ff84a3ed10ea 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -104,8 +104,6 @@ struct uart_8250_port { unsigned char ier; unsigned char lcr; unsigned char mcr; - unsigned char mcr_mask; /* mask of user bits */ - unsigned char mcr_force; /* mask of forced bits */ unsigned char cur_iotype; /* Running I/O type */ unsigned int rpm_tx_active; unsigned char canary; /* non-zero during system sleep diff --git a/include/linux/serial_s3c.h b/include/linux/serial_s3c.h index cf0de4a86640..f6c3323fc4c5 100644 --- a/include/linux/serial_s3c.h +++ b/include/linux/serial_s3c.h @@ -27,15 +27,6 @@ #define S3C2410_UERSTAT (0x14) #define S3C2410_UFSTAT (0x18) #define S3C2410_UMSTAT (0x1C) -#define USI_CON (0xC4) -#define USI_OPTION (0xC8) - -#define USI_CON_RESET (1<<0) -#define USI_CON_RESET_MASK (1<<0) - -#define USI_OPTION_HWACG_CLKREQ_ON (1<<1) -#define USI_OPTION_HWACG_CLKSTOP_ON (1<<2) -#define USI_OPTION_HWACG_MASK (3<<1) #define S3C2410_LCON_CFGMASK ((0xF<<3)|(0x3)) diff --git a/include/linux/tty.h b/include/linux/tty.h index 5dbd7c5afac7..7b0a5d478ef6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -122,33 +122,84 @@ struct tty_operations; /** * struct tty_struct - state associated with a tty while open * - * @flow.lock: lock for flow members - * @flow.stopped: tty stopped/started by tty_stop/tty_start - * @flow.tco_stopped: tty stopped/started by TCOOFF/TCOON ioctls (it has - * precedense over @flow.stopped) + * @magic: magic value set early in @alloc_tty_struct to %TTY_MAGIC, for + * debugging purposes + * @kref: reference counting by tty_kref_get() and tty_kref_put(), reaching zero + * frees the structure + * @dev: class device or %NULL (e.g. ptys, serdev) + * @driver: &struct tty_driver operating this tty + * @ops: &struct tty_operations of @driver for this tty (open, close, etc.) + * @index: index of this tty (e.g. to construct @name like tty12) + * @ldisc_sem: protects line discipline changes (@ldisc) -- lock tty not pty + * @ldisc: the current line discipline for this tty (n_tty by default) + * @atomic_write_lock: protects against concurrent writers, i.e. locks + * @write_cnt, @write_buf and similar + * @legacy_mutex: leftover from history (BKL -> BTM -> @legacy_mutex), + * protecting several operations on this tty + * @throttle_mutex: protects against concurrent tty_throttle_safe() and + * tty_unthrottle_safe() (but not tty_unthrottle()) + * @termios_rwsem: protects @termios and @termios_locked + * @winsize_mutex: protects @winsize + * @termios: termios for the current tty, copied from/to @driver.termios + * @termios_locked: locked termios (by %TIOCGLCKTRMIOS and %TIOCSLCKTRMIOS + * ioctls) + * @name: name of the tty constructed by tty_line_name() (e.g. ttyS3) + * @flags: bitwise OR of %TTY_THROTTLED, %TTY_IO_ERROR, ... + * @count: count of open processes, reaching zero cancels all the work for + * this tty and drops a @kref too (but does not free this tty) + * @winsize: size of the terminal "window" (cf. @winsize_mutex) + * @flow: flow settings grouped together, see also @flow.unused + * @flow.lock: lock for @flow members + * @flow.stopped: tty stopped/started by stop_tty()/start_tty() + * @flow.tco_stopped: tty stopped/started by %TCOOFF/%TCOON ioctls (it has + * precedence over @flow.stopped) * @flow.unused: alignment for Alpha, so that no members other than @flow.* are * modified by the same 64b word store. The @flow's __aligned is * there for the very same reason. - * @ctrl.lock: lock for ctrl members + * @ctrl: control settings grouped together, see also @ctrl.unused + * @ctrl.lock: lock for @ctrl members * @ctrl.pgrp: process group of this tty (setpgrp(2)) * @ctrl.session: session of this tty (setsid(2)). Writes are protected by both - * @ctrl.lock and legacy mutex, readers must use at least one of + * @ctrl.lock and @legacy_mutex, readers must use at least one of * them. - * @ctrl.pktstatus: packet mode status (bitwise OR of TIOCPKT_* constants) + * @ctrl.pktstatus: packet mode status (bitwise OR of %TIOCPKT_ constants) * @ctrl.packet: packet mode enabled + * @ctrl.unused: alignment for Alpha, see @flow.unused for explanation + * @hw_stopped: not controlled by the tty layer, under @driver's control for CTS + * handling + * @receive_room: bytes permitted to feed to @ldisc without any being lost + * @flow_change: controls behavior of throttling, see tty_throttle_safe() and + * tty_unthrottle_safe() + * @link: link to another pty (master -> slave and vice versa) + * @fasync: state for %O_ASYNC (for %SIGIO); managed by fasync_helper() + * @write_wait: concurrent writers are waiting in this queue until they are + * allowed to write + * @read_wait: readers wait for data in this queue + * @hangup_work: normally a work to perform a hangup (do_tty_hangup()); while + * freeing the tty, (re)used to release_one_tty() + * @disc_data: pointer to @ldisc's private data (e.g. to &struct n_tty_data) + * @driver_data: pointer to @driver's private data (e.g. &struct uart_state) + * @files_lock: protects @tty_files list + * @tty_files: list of (re)openers of this tty (i.e. linked &struct + * tty_file_private) + * @closing: when set during close, n_tty processes only START & STOP chars + * @write_buf: temporary buffer used during tty_write() to copy user data to + * @write_cnt: count of bytes written in tty_write() to @write_buf + * @SAK_work: if the tty has a pending do_SAK, it is queued here + * @port: persistent storage for this device (i.e. &struct tty_port) * * All of the state associated with a tty while the tty is open. Persistent - * storage for tty devices is referenced here as @port in struct tty_port. + * storage for tty devices is referenced here as @port and is documented in + * &struct tty_port. */ struct tty_struct { int magic; struct kref kref; - struct device *dev; /* class device or NULL (e.g. ptys, serdev) */ + struct device *dev; struct tty_driver *driver; const struct tty_operations *ops; int index; - /* Protects ldisc changes: Lock tty not pty */ struct ld_semaphore ldisc_sem; struct tty_ldisc *ldisc; @@ -157,12 +208,11 @@ struct tty_struct { struct mutex throttle_mutex; struct rw_semaphore termios_rwsem; struct mutex winsize_mutex; - /* Termios values are protected by the termios rwsem */ struct ktermios termios, termios_locked; char name[64]; unsigned long flags; int count; - struct winsize winsize; /* winsize_mutex */ + struct winsize winsize; struct { spinlock_t lock; @@ -181,7 +231,7 @@ struct tty_struct { } __aligned(sizeof(unsigned long)) ctrl; int hw_stopped; - unsigned int receive_room; /* Bytes free for queue */ + unsigned int receive_room; int flow_change; struct tty_struct *link; @@ -191,7 +241,7 @@ struct tty_struct { struct work_struct hangup_work; void *disc_data; void *driver_data; - spinlock_t files_lock; /* protects tty_files list */ + spinlock_t files_lock; struct list_head tty_files; #define N_TTY_BUF_SIZE 4096 @@ -199,7 +249,6 @@ struct tty_struct { int closing; unsigned char *write_buf; int write_cnt; - /* If the tty has a pending do_SAK, queue it here - akpm */ struct work_struct SAK_work; struct tty_port *port; } __randomize_layout; @@ -214,26 +263,72 @@ struct tty_file_private { /* tty magic number */ #define TTY_MAGIC 0x5401 -/* - * These bits are used in the flags field of the tty structure. +/** + * DOC: TTY Struct Flags + * + * These bits are used in the :c:member:`tty_struct.flags` field. * * So that interrupts won't be able to mess up the queues, * copy_to_cooked must be atomic with respect to itself, as must * tty->write. Thus, you must use the inline functions set_bit() and * clear_bit() to make things atomic. + * + * TTY_THROTTLED + * Driver input is throttled. The ldisc should call + * :c:member:`tty_driver.unthrottle()` in order to resume reception when + * it is ready to process more data (at threshold min). + * + * TTY_IO_ERROR + * If set, causes all subsequent userspace read/write calls on the tty to + * fail, returning -%EIO. (May be no ldisc too.) + * + * TTY_OTHER_CLOSED + * Device is a pty and the other side has closed. + * + * TTY_EXCLUSIVE + * Exclusive open mode (a single opener). + * + * TTY_DO_WRITE_WAKEUP + * If set, causes the driver to call the + * :c:member:`tty_ldisc_ops.write_wakeup()` method in order to resume + * transmission when it can accept more data to transmit. + * + * TTY_LDISC_OPEN + * Indicates that a line discipline is open. For debugging purposes only. + * + * TTY_PTY_LOCK + * A flag private to pty code to implement %TIOCSPTLCK/%TIOCGPTLCK logic. + * + * TTY_NO_WRITE_SPLIT + * Prevent driver from splitting up writes into smaller chunks (preserve + * write boundaries to driver). + * + * TTY_HUPPED + * The TTY was hung up. This is set post :c:member:`tty_driver.hangup()`. + * + * TTY_HUPPING + * The TTY is in the process of hanging up to abort potential readers. + * + * TTY_LDISC_CHANGING + * Line discipline for this TTY is being changed. I/O should not block + * when this is set. Use tty_io_nonblock() to check. + * + * TTY_LDISC_HALTED + * Line discipline for this TTY was stopped. No work should be queued to + * this ldisc. */ -#define TTY_THROTTLED 0 /* Call unthrottle() at threshold min */ -#define TTY_IO_ERROR 1 /* Cause an I/O error (may be no ldisc too) */ -#define TTY_OTHER_CLOSED 2 /* Other side (if any) has closed */ -#define TTY_EXCLUSIVE 3 /* Exclusive open mode */ -#define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ -#define TTY_LDISC_OPEN 11 /* Line discipline is open */ -#define TTY_PTY_LOCK 16 /* pty private */ -#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ -#define TTY_HUPPED 18 /* Post driver->hangup() */ -#define TTY_HUPPING 19 /* Hangup in progress */ -#define TTY_LDISC_CHANGING 20 /* Change pending - non-block IO */ -#define TTY_LDISC_HALTED 22 /* Line discipline is halted */ +#define TTY_THROTTLED 0 +#define TTY_IO_ERROR 1 +#define TTY_OTHER_CLOSED 2 +#define TTY_EXCLUSIVE 3 +#define TTY_DO_WRITE_WAKEUP 5 +#define TTY_LDISC_OPEN 11 +#define TTY_PTY_LOCK 16 +#define TTY_NO_WRITE_SPLIT 17 +#define TTY_HUPPED 18 +#define TTY_HUPPING 19 +#define TTY_LDISC_CHANGING 20 +#define TTY_LDISC_HALTED 22 static inline bool tty_io_nonblock(struct tty_struct *tty, struct file *file) { diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 795b94ccdeb6..4841d8069c07 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -2,248 +2,350 @@ #ifndef _LINUX_TTY_DRIVER_H #define _LINUX_TTY_DRIVER_H -/* - * This structure defines the interface between the low-level tty - * driver and the tty routines. The following routines can be - * defined; unless noted otherwise, they are optional, and can be - * filled in with a null pointer. +#include <linux/export.h> +#include <linux/fs.h> +#include <linux/kref.h> +#include <linux/list.h> +#include <linux/cdev.h> +#include <linux/termios.h> +#include <linux/seq_file.h> + +struct tty_struct; +struct tty_driver; +struct serial_icounter_struct; +struct serial_struct; + +/** + * struct tty_operations -- interface between driver and tty + * + * @lookup: ``struct tty_struct *()(struct tty_driver *self, struct file *, + * int idx)`` * - * struct tty_struct * (*lookup)(struct tty_driver *self, struct file *, int idx) + * Return the tty device corresponding to @idx, %NULL if there is not + * one currently in use and an %ERR_PTR value on error. Called under + * %tty_mutex (for now!) * - * Return the tty device corresponding to idx, NULL if there is not - * one currently in use and an ERR_PTR value on error. Called under - * tty_mutex (for now!) + * Optional method. Default behaviour is to use the @self->ttys array. * - * Optional method. Default behaviour is to use the ttys array + * @install: ``int ()(struct tty_driver *self, struct tty_struct *tty)`` * - * int (*install)(struct tty_driver *self, struct tty_struct *tty) + * Install a new @tty into the @self's internal tables. Used in + * conjunction with @lookup and @remove methods. * - * Install a new tty into the tty driver internal tables. Used in - * conjunction with lookup and remove methods. + * Optional method. Default behaviour is to use the @self->ttys array. * - * Optional method. Default behaviour is to use the ttys array + * @remove: ``void ()(struct tty_driver *self, struct tty_struct *tty)`` * - * void (*remove)(struct tty_driver *self, struct tty_struct *tty) + * Remove a closed @tty from the @self's internal tables. Used in + * conjunction with @lookup and @remove methods. * - * Remove a closed tty from the tty driver internal tables. Used in - * conjunction with lookup and remove methods. + * Optional method. Default behaviour is to use the @self->ttys array. * - * Optional method. Default behaviour is to use the ttys array + * @open: ``int ()(struct tty_struct *tty, struct file *)`` * - * int (*open)(struct tty_struct * tty, struct file * filp); + * This routine is called when a particular @tty device is opened. This + * routine is mandatory; if this routine is not filled in, the attempted + * open will fail with %ENODEV. * - * This routine is called when a particular tty device is opened. - * This routine is mandatory; if this routine is not filled in, - * the attempted open will fail with ENODEV. + * Required method. Called with tty lock held. May sleep. * - * Required method. Called with tty lock held. + * @close: ``void ()(struct tty_struct *tty, struct file *)`` * - * void (*close)(struct tty_struct * tty, struct file * filp); + * This routine is called when a particular @tty device is closed. At the + * point of return from this call the driver must make no further ldisc + * calls of any kind. * - * This routine is called when a particular tty device is closed. - * Note: called even if the corresponding open() failed. + * Remark: called even if the corresponding @open() failed. * - * Required method. Called with tty lock held. + * Required method. Called with tty lock held. May sleep. * - * void (*shutdown)(struct tty_struct * tty); + * @shutdown: ``void ()(struct tty_struct *tty)`` * - * This routine is called under the tty lock when a particular tty device - * is closed for the last time. It executes before the tty resources - * are freed so may execute while another function holds a tty kref. + * This routine is called under the tty lock when a particular @tty device + * is closed for the last time. It executes before the @tty resources + * are freed so may execute while another function holds a @tty kref. * - * void (*cleanup)(struct tty_struct * tty); + * @cleanup: ``void ()(struct tty_struct *tty)`` * - * This routine is called asynchronously when a particular tty device + * This routine is called asynchronously when a particular @tty device * is closed for the last time freeing up the resources. This is * actually the second part of shutdown for routines that might sleep. * + * @write: ``int ()(struct tty_struct *tty, const unsigned char *buf, + * int count)`` * - * int (*write)(struct tty_struct * tty, - * const unsigned char *buf, int count); - * - * This routine is called by the kernel to write a series of - * characters to the tty device. The characters may come from - * user space or kernel space. This routine will return the + * This routine is called by the kernel to write a series (@count) of + * characters (@buf) to the @tty device. The characters may come from + * user space or kernel space. This routine will return the * number of characters actually accepted for writing. * - * Optional: Required for writable devices. + * May occur in parallel in special cases. Because this includes panic + * paths drivers generally shouldn't try and do clever locking here. * - * int (*put_char)(struct tty_struct *tty, unsigned char ch); + * Optional: Required for writable devices. May not sleep. * - * This routine is called by the kernel to write a single - * character to the tty device. If the kernel uses this routine, - * it must call the flush_chars() routine (if defined) when it is - * done stuffing characters into the driver. If there is no room - * in the queue, the character is ignored. + * @put_char: ``int ()(struct tty_struct *tty, unsigned char ch)`` * - * Optional: Kernel will use the write method if not provided. + * This routine is called by the kernel to write a single character @ch to + * the @tty device. If the kernel uses this routine, it must call the + * @flush_chars() routine (if defined) when it is done stuffing characters + * into the driver. If there is no room in the queue, the character is + * ignored. * - * Note: Do not call this function directly, call tty_put_char + * Optional: Kernel will use the @write method if not provided. Do not + * call this function directly, call tty_put_char(). * - * void (*flush_chars)(struct tty_struct *tty); + * @flush_chars: ``void ()(struct tty_struct *tty)`` * - * This routine is called by the kernel after it has written a - * series of characters to the tty device using put_char(). + * This routine is called by the kernel after it has written a + * series of characters to the tty device using @put_char(). * - * Optional: + * Optional. Do not call this function directly, call + * tty_driver_flush_chars(). * - * Note: Do not call this function directly, call tty_driver_flush_chars - * - * unsigned int (*write_room)(struct tty_struct *tty); + * @write_room: ``unsigned int ()(struct tty_struct *tty)`` * - * This routine returns the numbers of characters the tty driver - * will accept for queuing to be written. This number is subject - * to change as output buffers get emptied, or if the output flow + * This routine returns the numbers of characters the @tty driver + * will accept for queuing to be written. This number is subject + * to change as output buffers get emptied, or if the output flow * control is acted. * - * Required if write method is provided else not needed. + * The ldisc is responsible for being intelligent about multi-threading of + * write_room/write calls + * + * Required if @write method is provided else not needed. Do not call this + * function directly, call tty_write_room() + * + * @chars_in_buffer: ``unsigned int ()(struct tty_struct *tty)`` + * + * This routine returns the number of characters in the device private + * output queue. Used in tty_wait_until_sent() and for poll() + * implementation. * - * Note: Do not call this function directly, call tty_write_room - * - * int (*ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg); + * Optional: if not provided, it is assumed there is no queue on the + * device. Do not call this function directly, call tty_chars_in_buffer(). * - * This routine allows the tty driver to implement - * device-specific ioctls. If the ioctl number passed in cmd - * is not recognized by the driver, it should return ENOIOCTLCMD. + * @ioctl: ``int ()(struct tty_struct *tty, unsigned int cmd, + * unsigned long arg)`` * - * Optional + * This routine allows the @tty driver to implement device-specific + * ioctls. If the ioctl number passed in @cmd is not recognized by the + * driver, it should return %ENOIOCTLCMD. * - * long (*compat_ioctl)(struct tty_struct *tty,, - * unsigned int cmd, unsigned long arg); + * Optional. * - * implement ioctl processing for 32 bit process on 64 bit system + * @compat_ioctl: ``long ()(struct tty_struct *tty, unsigned int cmd, + * unsigned long arg)`` * - * Optional - * - * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); + * Implement ioctl processing for 32 bit process on 64 bit system. * - * This routine allows the tty driver to be notified when - * device's termios settings have changed. + * Optional. * - * Optional: Called under the termios lock + * @set_termios: ``void ()(struct tty_struct *tty, struct ktermios *old)`` * + * This routine allows the @tty driver to be notified when device's + * termios settings have changed. New settings are in @tty->termios. + * Previous settings are passed in the @old argument. * - * void (*set_ldisc)(struct tty_struct *tty); + * The API is defined such that the driver should return the actual modes + * selected. This means that the driver is responsible for modifying any + * bits in @tty->termios it cannot fulfill to indicate the actual modes + * being used. * - * This routine allows the tty driver to be notified when the - * device's termios settings have changed. + * Optional. Called under the @tty->termios_rwsem. May sleep. * - * Optional: Called under BKL (currently) - * - * void (*throttle)(struct tty_struct * tty); + * @set_ldisc: ``void ()(struct tty_struct *tty)`` * - * This routine notifies the tty driver that input buffers for - * the line discipline are close to full, and it should somehow - * signal that no more characters should be sent to the tty. + * This routine allows the @tty driver to be notified when the device's + * line discipline is being changed. At the point this is done the + * discipline is not yet usable. * - * Optional: Always invoke via tty_throttle_safe(), called under the - * termios lock. - * - * void (*unthrottle)(struct tty_struct * tty); + * Optional. Called under the @tty->ldisc_sem and @tty->termios_rwsem. * - * This routine notifies the tty drivers that it should signals - * that characters can now be sent to the tty without fear of - * overrunning the input buffers of the line disciplines. - * - * Optional: Always invoke via tty_unthrottle(), called under the - * termios lock. + * @throttle: ``void ()(struct tty_struct *tty)`` * - * void (*stop)(struct tty_struct *tty); + * This routine notifies the @tty driver that input buffers for the line + * discipline are close to full, and it should somehow signal that no more + * characters should be sent to the @tty. * - * This routine notifies the tty driver that it should stop - * outputting characters to the tty device. + * Serialization including with @unthrottle() is the job of the ldisc + * layer. * - * Called with ->flow.lock held. Serialized with start() method. + * Optional: Always invoke via tty_throttle_safe(). Called under the + * @tty->termios_rwsem. * - * Optional: + * @unthrottle: ``void ()(struct tty_struct *tty)`` * - * Note: Call stop_tty not this method. - * - * void (*start)(struct tty_struct *tty); + * This routine notifies the @tty driver that it should signal that + * characters can now be sent to the @tty without fear of overrunning the + * input buffers of the line disciplines. * - * This routine notifies the tty driver that it resume sending + * Optional. Always invoke via tty_unthrottle(). Called under the + * @tty->termios_rwsem. + * + * @stop: ``void ()(struct tty_struct *tty)`` + * + * This routine notifies the @tty driver that it should stop outputting * characters to the tty device. * - * Called with ->flow.lock held. Serialized with stop() method. + * Called with @tty->flow.lock held. Serialized with @start() method. + * + * Optional. Always invoke via stop_tty(). + * + * @start: ``void ()(struct tty_struct *tty)`` + * + * This routine notifies the @tty driver that it resumed sending + * characters to the @tty device. + * + * Called with @tty->flow.lock held. Serialized with stop() method. + * + * Optional. Always invoke via start_tty(). + * + * @hangup: ``void ()(struct tty_struct *tty)`` + * + * This routine notifies the @tty driver that it should hang up the @tty + * device. * - * Optional: + * Optional. Called with tty lock held. * - * Note: Call start_tty not this method. - * - * void (*hangup)(struct tty_struct *tty); + * @break_ctl: ``int ()(struct tty_struct *tty, int state)`` * - * This routine notifies the tty driver that it should hang up the - * tty device. + * This optional routine requests the @tty driver to turn on or off BREAK + * status on the RS-232 port. If @state is -1, then the BREAK status + * should be turned on; if @state is 0, then BREAK should be turned off. * - * Optional: + * If this routine is implemented, the high-level tty driver will handle + * the following ioctls: %TCSBRK, %TCSBRKP, %TIOCSBRK, %TIOCCBRK. * - * Called with tty lock held. + * If the driver sets %TTY_DRIVER_HARDWARE_BREAK in tty_alloc_driver(), + * then the interface will also be called with actual times and the + * hardware is expected to do the delay work itself. 0 and -1 are still + * used for on/off. * - * int (*break_ctl)(struct tty_struct *tty, int state); + * Optional: Required for %TCSBRK/%BRKP/etc. handling. May sleep. * - * This optional routine requests the tty driver to turn on or - * off BREAK status on the RS-232 port. If state is -1, - * then the BREAK status should be turned on; if state is 0, then - * BREAK should be turned off. + * @flush_buffer: ``void ()(struct tty_struct *tty)`` * - * If this routine is implemented, the high-level tty driver will - * handle the following ioctls: TCSBRK, TCSBRKP, TIOCSBRK, - * TIOCCBRK. + * This routine discards device private output buffer. Invoked on close, + * hangup, to implement %TCOFLUSH ioctl and similar. * - * If the driver sets TTY_DRIVER_HARDWARE_BREAK then the interface - * will also be called with actual times and the hardware is expected - * to do the delay work itself. 0 and -1 are still used for on/off. + * Optional: if not provided, it is assumed there is no queue on the + * device. Do not call this function directly, call + * tty_driver_flush_buffer(). * - * Optional: Required for TCSBRK/BRKP/etc handling. + * @wait_until_sent: ``void ()(struct tty_struct *tty, int timeout)`` * - * void (*wait_until_sent)(struct tty_struct *tty, int timeout); - * - * This routine waits until the device has written out all of the - * characters in its transmitter FIFO. + * This routine waits until the device has written out all of the + * characters in its transmitter FIFO. Or until @timeout (in jiffies) is + * reached. * - * Optional: If not provided the device is assumed to have no FIFO + * Optional: If not provided, the device is assumed to have no FIFO. + * Usually correct to invoke via tty_wait_until_sent(). May sleep. * - * Note: Usually correct to call tty_wait_until_sent + * @send_xchar: ``void ()(struct tty_struct *tty, char ch)`` * - * void (*send_xchar)(struct tty_struct *tty, char ch); + * This routine is used to send a high-priority XON/XOFF character (@ch) + * to the @tty device. * - * This routine is used to send a high-priority XON/XOFF - * character to the device. + * Optional: If not provided, then the @write method is called under + * the @tty->atomic_write_lock to keep it serialized with the ldisc. * - * Optional: If not provided then the write method is called under - * the atomic write lock to keep it serialized with the ldisc. + * @tiocmget: ``int ()(struct tty_struct *tty)`` * - * int (*resize)(struct tty_struct *tty, struct winsize *ws) + * This routine is used to obtain the modem status bits from the @tty + * driver. * - * Called when a termios request is issued which changes the - * requested terminal geometry. + * Optional: If not provided, then %ENOTTY is returned from the %TIOCMGET + * ioctl. Do not call this function directly, call tty_tiocmget(). + * + * @tiocmset: ``int ()(struct tty_struct *tty, + * unsigned int set, unsigned int clear)`` + * + * This routine is used to set the modem status bits to the @tty driver. + * First, @clear bits should be cleared, then @set bits set. + * + * Optional: If not provided, then %ENOTTY is returned from the %TIOCMSET + * ioctl. Do not call this function directly, call tty_tiocmset(). + * + * @resize: ``int ()(struct tty_struct *tty, struct winsize *ws)`` + * + * Called when a termios request is issued which changes the requested + * terminal geometry to @ws. * * Optional: the default action is to update the termios structure * without error. This is usually the correct behaviour. Drivers should - * not force errors here if they are not resizable objects (eg a serial + * not force errors here if they are not resizable objects (e.g. a serial * line). See tty_do_resize() if you need to wrap the standard method - * in your own logic - the usual case. + * in your own logic -- the usual case. + * + * @get_icount: ``int ()(struct tty_struct *tty, + * struct serial_icounter *icount)`` + * + * Called when the @tty device receives a %TIOCGICOUNT ioctl. Passed a + * kernel structure @icount to complete. + * + * Optional: called only if provided, otherwise %ENOTTY will be returned. * - * int (*get_icount)(struct tty_struct *tty, struct serial_icounter *icount); + * @get_serial: ``int ()(struct tty_struct *tty, struct serial_struct *p)`` * - * Called when the device receives a TIOCGICOUNT ioctl. Passed a kernel - * structure to complete. This method is optional and will only be called - * if provided (otherwise ENOTTY will be returned). + * Called when the @tty device receives a %TIOCGSERIAL ioctl. Passed a + * kernel structure @p (&struct serial_struct) to complete. + * + * Optional: called only if provided, otherwise %ENOTTY will be returned. + * Do not call this function directly, call tty_tiocgserial(). + * + * @set_serial: ``int ()(struct tty_struct *tty, struct serial_struct *p)`` + * + * Called when the @tty device receives a %TIOCSSERIAL ioctl. Passed a + * kernel structure @p (&struct serial_struct) to set the values from. + * + * Optional: called only if provided, otherwise %ENOTTY will be returned. + * Do not call this function directly, call tty_tiocsserial(). + * + * @show_fdinfo: ``void ()(struct tty_struct *tty, struct seq_file *m)`` + * + * Called when the @tty device file descriptor receives a fdinfo request + * from VFS (to show in /proc/<pid>/fdinfo/). @m should be filled with + * information. + * + * Optional: called only if provided, otherwise nothing is written to @m. + * Do not call this function directly, call tty_show_fdinfo(). + * + * @poll_init: ``int ()(struct tty_driver *driver, int line, char *options)`` + * + * kgdboc support (Documentation/dev-tools/kgdb.rst). This routine is + * called to initialize the HW for later use by calling @poll_get_char or + * @poll_put_char. + * + * Optional: called only if provided, otherwise skipped as a non-polling + * driver. + * + * @poll_get_char: ``int ()(struct tty_driver *driver, int line)`` + * + * kgdboc support (see @poll_init). @driver should read a character from a + * tty identified by @line and return it. + * + * Optional: called only if @poll_init provided. + * + * @poll_put_char: ``void ()(struct tty_driver *driver, int line, char ch)`` + * + * kgdboc support (see @poll_init). @driver should write character @ch to + * a tty identified by @line. + * + * Optional: called only if @poll_init provided. + * + * @proc_show: ``int ()(struct seq_file *m, void *driver)`` + * + * Driver @driver (cast to &struct tty_driver) can show additional info in + * /proc/tty/driver/<driver_name>. It is enough to fill in the information + * into @m. + * + * Optional: called only if provided, otherwise no /proc entry created. + * + * This structure defines the interface between the low-level tty driver and + * the tty routines. These routines can be defined. Unless noted otherwise, + * they are optional, and can be filled in with a %NULL pointer. */ - -#include <linux/export.h> -#include <linux/fs.h> -#include <linux/kref.h> -#include <linux/list.h> -#include <linux/cdev.h> -#include <linux/termios.h> -#include <linux/seq_file.h> - -struct tty_struct; -struct tty_driver; -struct serial_icounter_struct; -struct serial_struct; - struct tty_operations { struct tty_struct * (*lookup)(struct tty_driver *driver, struct file *filp, int idx); @@ -288,26 +390,64 @@ struct tty_operations { int (*poll_get_char)(struct tty_driver *driver, int line); void (*poll_put_char)(struct tty_driver *driver, int line, char ch); #endif - int (*proc_show)(struct seq_file *, void *); + int (*proc_show)(struct seq_file *m, void *driver); } __randomize_layout; +/** + * struct tty_driver -- driver for TTY devices + * + * @magic: set to %TTY_DRIVER_MAGIC in __tty_alloc_driver() + * @kref: reference counting. Reaching zero frees all the internals and the + * driver. + * @cdevs: allocated/registered character /dev devices + * @owner: modules owning this driver. Used drivers cannot be rmmod'ed. + * Automatically set by tty_alloc_driver(). + * @driver_name: name of the driver used in /proc/tty + * @name: used for constructing /dev node name + * @name_base: used as a number base for constructing /dev node name + * @major: major /dev device number (zero for autoassignment) + * @minor_start: the first minor /dev device number + * @num: number of devices allocated + * @type: type of tty driver (%TTY_DRIVER_TYPE_) + * @subtype: subtype of tty driver (%SYSTEM_TYPE_, %PTY_TYPE_, %SERIAL_TYPE_) + * @init_termios: termios to set to each tty initially (e.g. %tty_std_termios) + * @flags: tty driver flags (%TTY_DRIVER_) + * @proc_entry: proc fs entry, used internally + * @other: driver of the linked tty; only used for the PTY driver + * @ttys: array of active &struct tty_struct, set by tty_standard_install() + * @ports: array of &struct tty_port; can be set during initialization by + * tty_port_link_device() and similar + * @termios: storage for termios at each TTY close for the next open + * @driver_state: pointer to driver's arbitrary data + * @ops: driver hooks for TTYs. Set them using tty_set_operations(). Use &struct + * tty_port helpers in them as much as possible. + * @tty_drivers: used internally to link tty_drivers together + * + * The usual handling of &struct tty_driver is to allocate it by + * tty_alloc_driver(), set up all the necessary members, and register it by + * tty_register_driver(). At last, the driver is torn down by calling + * tty_unregister_driver() followed by tty_driver_kref_put(). + * + * The fields required to be set before calling tty_register_driver() include + * @driver_name, @name, @type, @subtype, @init_termios, and @ops. + */ struct tty_driver { - int magic; /* magic number for this structure */ - struct kref kref; /* Reference management */ + int magic; + struct kref kref; struct cdev **cdevs; struct module *owner; const char *driver_name; const char *name; - int name_base; /* offset of printed name */ - int major; /* major device number */ - int minor_start; /* start of minor device number */ - unsigned int num; /* number of devices allocated */ - short type; /* type of tty driver */ - short subtype; /* subtype of tty driver */ - struct ktermios init_termios; /* Initial termios */ - unsigned long flags; /* tty driver flags */ - struct proc_dir_entry *proc_entry; /* /proc fs entry */ - struct tty_driver *other; /* only used for the PTY driver */ + int name_base; + int major; + int minor_start; + unsigned int num; + short type; + short subtype; + struct ktermios init_termios; + unsigned long flags; + struct proc_dir_entry *proc_entry; + struct tty_driver *other; /* * Pointer to the tty data structures @@ -352,49 +492,53 @@ static inline void tty_set_operations(struct tty_driver *driver, /* tty driver magic number */ #define TTY_DRIVER_MAGIC 0x5402 -/* - * 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 PTY's, in particular. - * - * TTY_DRIVER_REAL_RAW --- if set, indicates that the driver will - * guarantee never to set any special character handling - * flags if ((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 --- if set, 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, 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, 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 caller instead of using a simple - * on/off interface. - * - * TTY_DRIVER_DYNAMIC_ALLOC -- do not allocate structures which are - * needed per line for this driver as it would waste memory. - * The driver will take care. - * - * TTY_DRIVER_UNNUMBERED_NODE -- do not create numbered /dev nodes. In - * other words create /dev/ttyprintk and not /dev/ttyprintk0. - * Applicable only when a driver for a single tty device is - * being allocated. +/** + * 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 diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index 9916acb5de49..483d41cbcbb7 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -17,7 +17,6 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port, int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, size_t size); void tty_flip_buffer_push(struct tty_port *port); -void tty_schedule_flip(struct tty_port *port); int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag); static inline int tty_insert_flip_char(struct tty_port *port, diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index b85d84fb5f49..e85002b56752 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -4,127 +4,6 @@ struct tty_struct; -/* - * This structure defines the interface between the tty line discipline - * implementation and the tty routines. The following routines can be - * defined; unless noted otherwise, they are optional, and can be - * filled in with a null pointer. - * - * int (*open)(struct tty_struct *); - * - * This function is called when the line discipline is associated - * with the tty. The line discipline can use this as an - * opportunity to initialize any state needed by the ldisc routines. - * - * void (*close)(struct tty_struct *); - * - * This function is called when the line discipline is being - * shutdown, either because the tty is being closed or because - * the tty is being changed to use a new line discipline - * - * void (*flush_buffer)(struct tty_struct *tty); - * - * This function instructs the line discipline to clear its - * buffers of any input characters it may have queued to be - * delivered to the user mode process. - * - * ssize_t (*read)(struct tty_struct * tty, struct file * file, - * unsigned char * buf, size_t nr); - * - * This function is called when the user requests to read from - * the tty. The line discipline will return whatever characters - * it has buffered up for the user. If this function is not - * defined, the user will receive an EIO error. - * - * ssize_t (*write)(struct tty_struct * tty, struct file * file, - * const unsigned char * buf, size_t nr); - * - * This function is called when the user requests to write to the - * tty. The line discipline will deliver the characters to the - * low-level tty device for transmission, optionally performing - * some processing on the characters first. If this function is - * not defined, the user will receive an EIO error. - * - * int (*ioctl)(struct tty_struct * tty, struct file * file, - * unsigned int cmd, unsigned long arg); - * - * This function is called when the user requests an ioctl which - * is not handled by the tty layer or the low-level tty driver. - * It is intended for ioctls which affect line discpline - * operation. Note that the search order for ioctls is (1) tty - * layer, (2) tty low-level driver, (3) line discpline. So a - * low-level driver can "grab" an ioctl request before the line - * discpline has a chance to see it. - * - * int (*compat_ioctl)(struct tty_struct * tty, struct file * file, - * unsigned int cmd, unsigned long arg); - * - * Process ioctl calls from 32-bit process on 64-bit system - * - * NOTE: only ioctls that are neither "pointer to compatible - * structure" nor tty-generic. Something private that takes - * an integer or a pointer to wordsize-sensitive structure - * belongs here, but most of ldiscs will happily leave - * it NULL. - * - * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); - * - * This function notifies the line discpline that a change has - * been made to the termios structure. - * - * int (*poll)(struct tty_struct * tty, struct file * file, - * poll_table *wait); - * - * This function is called when a user attempts to select/poll on a - * tty device. It is solely the responsibility of the line - * discipline to handle poll requests. - * - * void (*receive_buf)(struct tty_struct *, const unsigned char *cp, - * char *fp, int count); - * - * This function is called by the low-level tty driver to send - * characters received by the hardware to the line discpline for - * processing. <cp> is a pointer to the buffer of input - * character received by the device. <fp> is a pointer to a - * pointer of flag bytes which indicate whether a character was - * received with a parity error, etc. <fp> may be NULL to indicate - * all data received is TTY_NORMAL. - * - * void (*write_wakeup)(struct tty_struct *); - * - * This function is called by the low-level tty driver to signal - * that line discpline should try to send more characters to the - * low-level driver for transmission. If the line discpline does - * not have any more data to send, it can just return. If the line - * discipline does have some data to send, please arise a tasklet - * or workqueue to do the real data transfer. Do not send data in - * this hook, it may leads to a deadlock. - * - * int (*hangup)(struct tty_struct *) - * - * Called on a hangup. Tells the discipline that it should - * cease I/O to the tty driver. Can sleep. The driver should - * seek to perform this action quickly but should wait until - * any pending driver I/O is completed. - * - * void (*dcd_change)(struct tty_struct *tty, unsigned int status) - * - * Tells the discipline that the DCD pin has changed its status. - * Used exclusively by the N_PPS (Pulse-Per-Second) line discipline. - * - * int (*receive_buf2)(struct tty_struct *, const unsigned char *cp, - * char *fp, int count); - * - * This function is called by the low-level tty driver to send - * characters received by the hardware to the line discpline for - * processing. <cp> is a pointer to the buffer of input - * character received by the device. <fp> is a pointer to a - * pointer of flag bytes which indicate whether a character was - * received with a parity error, etc. <fp> may be NULL to indicate - * all data received is TTY_NORMAL. - * If assigned, prefer this function for automatic flow control. - */ - #include <linux/fs.h> #include <linux/wait.h> #include <linux/atomic.h> @@ -176,7 +55,147 @@ int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, ldsem_down_write(sem, timeout) #endif - +/** + * struct tty_ldisc_ops - ldisc operations + * + * @name: name of this ldisc rendered in /proc/tty/ldiscs + * @num: ``N_*`` number (%N_TTY, %N_HDLC, ...) reserved to this ldisc + * + * @open: [TTY] ``int ()(struct tty_struct *tty)`` + * + * This function is called when the line discipline is associated with the + * @tty. No other call into the line discipline for this tty will occur + * until it completes successfully. It should initialize any state needed + * by the ldisc, and set @tty->receive_room to the maximum amount of data + * the line discipline is willing to accept from the driver with a single + * call to @receive_buf(). Returning an error will prevent the ldisc from + * being attached. + * + * Can sleep. + * + * @close: [TTY] ``void ()(struct tty_struct *tty)`` + * + * This function is called when the line discipline is being shutdown, + * either because the @tty is being closed or because the @tty is being + * changed to use a new line discipline. At the point of execution no + * further users will enter the ldisc code for this tty. + * + * Can sleep. + * + * @flush_buffer: [TTY] ``void ()(struct tty_struct *tty)`` + * + * This function instructs the line discipline to clear its buffers of any + * input characters it may have queued to be delivered to the user mode + * process. It may be called at any point between open and close. + * + * @read: [TTY] ``ssize_t ()(struct tty_struct *tty, struct file *file, + * unsigned char *buf, size_t nr)`` + * + * This function is called when the user requests to read from the @tty. + * The line discipline will return whatever characters it has buffered up + * for the user. If this function is not defined, the user will receive + * an %EIO error. Multiple read calls may occur in parallel and the ldisc + * must deal with serialization issues. + * + * Can sleep. + * + * @write: [TTY] ``ssize_t ()(struct tty_struct *tty, struct file *file, + * const unsigned char *buf, size_t nr)`` + * + * This function is called when the user requests to write to the @tty. + * The line discipline will deliver the characters to the low-level tty + * device for transmission, optionally performing some processing on the + * characters first. If this function is not defined, the user will + * receive an %EIO error. + * + * Can sleep. + * + * @ioctl: [TTY] ``int ()(struct tty_struct *tty, unsigned int cmd, + * unsigned long arg)`` + * + * This function is called when the user requests an ioctl which is not + * handled by the tty layer or the low-level tty driver. It is intended + * for ioctls which affect line discpline operation. Note that the search + * order for ioctls is (1) tty layer, (2) tty low-level driver, (3) line + * discpline. So a low-level driver can "grab" an ioctl request before + * the line discpline has a chance to see it. + * + * @compat_ioctl: [TTY] ``int ()(struct tty_struct *tty, unsigned int cmd, + * unsigned long arg)`` + * + * Process ioctl calls from 32-bit process on 64-bit system. + * + * Note that only ioctls that are neither "pointer to compatible + * structure" nor tty-generic. Something private that takes an integer or + * a pointer to wordsize-sensitive structure belongs here, but most of + * ldiscs will happily leave it %NULL. + * + * @set_termios: [TTY] ``void ()(struct tty_struct *tty, struct ktermios *old)`` + * + * This function notifies the line discpline that a change has been made + * to the termios structure. + * + * @poll: [TTY] ``int ()(struct tty_struct *tty, struct file *file, + * struct poll_table_struct *wait)`` + * + * This function is called when a user attempts to select/poll on a @tty + * device. It is solely the responsibility of the line discipline to + * handle poll requests. + * + * @hangup: [TTY] ``void ()(struct tty_struct *tty)`` + * + * Called on a hangup. Tells the discipline that it should cease I/O to + * the tty driver. The driver should seek to perform this action quickly + * but should wait until any pending driver I/O is completed. No further + * calls into the ldisc code will occur. + * + * Can sleep. + * + * @receive_buf: [DRV] ``void ()(struct tty_struct *tty, + * const unsigned char *cp, const char *fp, int count)`` + * + * This function is called by the low-level tty driver to send characters + * received by the hardware to the line discpline for processing. @cp is + * a pointer to the buffer of input character received by the device. @fp + * is a pointer to an array of flag bytes which indicate whether a + * character was received with a parity error, etc. @fp may be %NULL to + * indicate all data received is %TTY_NORMAL. + * + * @write_wakeup: [DRV] ``void ()(struct tty_struct *tty)`` + * + * This function is called by the low-level tty driver to signal that line + * discpline should try to send more characters to the low-level driver + * for transmission. If the line discpline does not have any more data to + * send, it can just return. If the line discipline does have some data to + * send, please arise a tasklet or workqueue to do the real data transfer. + * Do not send data in this hook, it may lead to a deadlock. + * + * @dcd_change: [DRV] ``void ()(struct tty_struct *tty, unsigned int status)`` + * + * Tells the discipline that the DCD pin has changed its status. Used + * exclusively by the %N_PPS (Pulse-Per-Second) line discipline. + * + * @receive_buf2: [DRV] ``int ()(struct tty_struct *tty, + * const unsigned char *cp, const char *fp, int count)`` + * + * This function is called by the low-level tty driver to send characters + * received by the hardware to the line discpline for processing. @cp is a + * pointer to the buffer of input character received by the device. @fp + * is a pointer to an array of flag bytes which indicate whether a + * character was received with a parity error, etc. @fp may be %NULL to + * indicate all data received is %TTY_NORMAL. If assigned, prefer this + * function for automatic flow control. + * + * @owner: module containting this ldisc (for reference counting) + * + * This structure defines the interface between the tty line discipline + * implementation and the tty routines. The above routines can be defined. + * Unless noted otherwise, they are optional, and can be filled in with a %NULL + * pointer. + * + * Hooks marked [TTY] are invoked from the TTY core, the [DRV] ones from the + * tty_driver side. + */ struct tty_ldisc_ops { char *name; int num; @@ -184,31 +203,31 @@ struct tty_ldisc_ops { /* * The following routines are called from above. */ - int (*open)(struct tty_struct *); - void (*close)(struct tty_struct *); + int (*open)(struct tty_struct *tty); + void (*close)(struct tty_struct *tty); void (*flush_buffer)(struct tty_struct *tty); ssize_t (*read)(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr, void **cookie, unsigned long offset); ssize_t (*write)(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr); - int (*ioctl)(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); - int (*compat_ioctl)(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); + int (*ioctl)(struct tty_struct *tty, unsigned int cmd, + unsigned long arg); + int (*compat_ioctl)(struct tty_struct *tty, unsigned int cmd, + unsigned long arg); void (*set_termios)(struct tty_struct *tty, struct ktermios *old); - __poll_t (*poll)(struct tty_struct *, struct file *, - struct poll_table_struct *); + __poll_t (*poll)(struct tty_struct *tty, struct file *file, + struct poll_table_struct *wait); void (*hangup)(struct tty_struct *tty); /* * The following routines are called from below. */ - void (*receive_buf)(struct tty_struct *, const unsigned char *cp, + void (*receive_buf)(struct tty_struct *tty, const unsigned char *cp, const char *fp, int count); - void (*write_wakeup)(struct tty_struct *); - void (*dcd_change)(struct tty_struct *, unsigned int); - int (*receive_buf2)(struct tty_struct *, const unsigned char *cp, + void (*write_wakeup)(struct tty_struct *tty); + void (*dcd_change)(struct tty_struct *tty, unsigned int status); + int (*receive_buf2)(struct tty_struct *tty, const unsigned char *cp, const char *fp, int count); struct module *owner; diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h index 6e86e9e118b6..d3ea9ed0b98e 100644 --- a/include/linux/tty_port.h +++ b/include/linux/tty_port.h @@ -7,37 +7,33 @@ #include <linux/tty_buffer.h> #include <linux/wait.h> -/* - * Port level information. Each device keeps its own port level information - * so provide a common structure for those ports wanting to use common support - * routines. - * - * The tty port has a different lifetime to the tty so must be kept apart. - * In addition be careful as tty -> port mappings are valid for the life - * of the tty object but in many cases port -> tty mappings are valid only - * until a hangup so don't use the wrong path. - */ - struct attribute_group; struct tty_driver; struct tty_port; struct tty_struct; +/** + * struct tty_port_operations -- operations on tty_port + * @carrier_raised: return 1 if the carrier is raised on @port + * @dtr_rts: raise the DTR line if @raise is nonzero, otherwise lower DTR + * @shutdown: called when the last close completes or a hangup finishes IFF the + * port was initialized. Do not use to free resources. Turn off the device + * only. Called under the port mutex to serialize against @activate and + * @shutdown. + * @activate: called under the port mutex from tty_port_open(), serialized using + * the port mutex. Supposed to turn on the device. + * + * FIXME: long term getting the tty argument *out* of this would be good + * for consoles. + * + * @destruct: called on the final put of a port. Free resources, possibly incl. + * the port itself. + */ struct tty_port_operations { - /* Return 1 if the carrier is raised */ int (*carrier_raised)(struct tty_port *port); - /* Control the DTR line */ void (*dtr_rts)(struct tty_port *port, int raise); - /* Called when the last close completes or a hangup finishes - IFF the port was initialized. Do not use to free resources. Called - under the port mutex to serialize against activate/shutdowns */ void (*shutdown)(struct tty_port *port); - /* Called under the port mutex from tty_port_open, serialized using - the port mutex */ - /* FIXME: long term getting the tty argument *out* of this would be - good for consoles */ int (*activate)(struct tty_port *port, struct tty_struct *tty); - /* Called on the final put of a port */ void (*destruct)(struct tty_port *port); }; @@ -48,30 +44,77 @@ struct tty_port_client_operations { extern const struct tty_port_client_operations tty_port_default_client_ops; +/** + * struct tty_port -- port level information + * + * @buf: buffer for this port, locked internally + * @tty: back pointer to &struct tty_struct, valid only if the tty is open. Use + * tty_port_tty_get() to obtain it (and tty_kref_put() to release). + * @itty: internal back pointer to &struct tty_struct. Avoid this. It should be + * eliminated in the long term. + * @ops: tty port operations (like activate, shutdown), see &struct + * tty_port_operations + * @client_ops: tty port client operations (like receive_buf, write_wakeup). + * By default, tty_port_default_client_ops is used. + * @lock: lock protecting @tty + * @blocked_open: # of procs waiting for open in tty_port_block_til_ready() + * @count: usage count + * @open_wait: open waiters queue (waiting e.g. for a carrier) + * @delta_msr_wait: modem status change queue (waiting for MSR changes) + * @flags: user TTY flags (%ASYNC_) + * @iflags: internal flags (%TTY_PORT_) + * @console: when set, the port is a console + * @mutex: locking, for open, shutdown and other port operations + * @buf_mutex: @xmit_buf alloc lock + * @xmit_buf: optional xmit buffer used by some drivers + * @close_delay: delay in jiffies to wait when closing the port + * @closing_wait: delay in jiffies for output to be sent before closing + * @drain_delay: set to zero if no pure time based drain is needed else set to + * size of fifo + * @kref: references counter. Reaching zero calls @ops->destruct() if non-%NULL + * or frees the port otherwise. + * @client_data: pointer to private data, for @client_ops + * + * Each device keeps its own port level information. &struct tty_port was + * introduced as a common structure for such information. As every TTY device + * shall have a backing tty_port structure, every driver can use these members. + * + * The tty port has a different lifetime to the tty so must be kept apart. + * In addition be careful as tty -> port mappings are valid for the life + * of the tty object but in many cases port -> tty mappings are valid only + * until a hangup so don't use the wrong path. + * + * Tty port shall be initialized by tty_port_init() and shut down either by + * tty_port_destroy() (refcounting not used), or tty_port_put() (refcounting). + * + * There is a lot of helpers around &struct tty_port too. To name the most + * significant ones: tty_port_open(), tty_port_close() (or + * tty_port_close_start() and tty_port_close_end() separately if need be), and + * tty_port_hangup(). These call @ops->activate() and @ops->shutdown() as + * needed. + */ struct tty_port { - struct tty_bufhead buf; /* Locked internally */ - struct tty_struct *tty; /* Back pointer */ - struct tty_struct *itty; /* internal back ptr */ - const struct tty_port_operations *ops; /* Port operations */ - const struct tty_port_client_operations *client_ops; /* Port client operations */ - spinlock_t lock; /* Lock protecting tty field */ - int blocked_open; /* Waiting to open */ - int count; /* Usage count */ - wait_queue_head_t open_wait; /* Open waiters */ - wait_queue_head_t delta_msr_wait; /* Modem status change */ - unsigned long flags; /* User TTY flags ASYNC_ */ - unsigned long iflags; /* Internal flags TTY_PORT_ */ - unsigned char console:1; /* port is a console */ - struct mutex mutex; /* Locking */ - struct mutex buf_mutex; /* Buffer alloc lock */ - unsigned char *xmit_buf; /* Optional buffer */ - unsigned int close_delay; /* Close port delay */ - unsigned int closing_wait; /* Delay for output */ - int drain_delay; /* Set to zero if no pure time - based drain is needed else - set to size of fifo */ - struct kref kref; /* Ref counter */ - void *client_data; + struct tty_bufhead buf; + struct tty_struct *tty; + struct tty_struct *itty; + const struct tty_port_operations *ops; + const struct tty_port_client_operations *client_ops; + spinlock_t lock; + int blocked_open; + int count; + wait_queue_head_t open_wait; + wait_queue_head_t delta_msr_wait; + unsigned long flags; + unsigned long iflags; + unsigned char console:1; + struct mutex mutex; + struct mutex buf_mutex; + unsigned char *xmit_buf; + unsigned int close_delay; + unsigned int closing_wait; + int drain_delay; + struct kref kref; + void *client_data; }; /* tty_port::iflags bits -- use atomic bit ops */ diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c index c027c76d493c..cc8fa9e36159 100644 --- a/net/nfc/nci/uart.c +++ b/net/nfc/nci/uart.c @@ -317,14 +317,13 @@ static void nci_uart_tty_receive(struct tty_struct *tty, const u8 *data, * Arguments: * * tty pointer to tty instance data - * file pointer to open file object for device * cmd IOCTL command code * arg argument for IOCTL call (cmd dependent) * * Return Value: Command dependent */ -static int nci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int nci_uart_tty_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) { struct nci_uart *nu = (void *)tty->disc_data; int err = 0; |