forked from Minki/linux
TTY/Serial driver updates for 5.17-rc1
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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYd7Q0g8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yn3FACgoFZEFY04TU+Cd9mrlRq/mazZm/IAniJfPxOF U0s57L5o1dlnmawh8mmV =HSOB -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
342465f533
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>;
|
||||
};
|
||||
|
@ -64,9 +64,21 @@ properties:
|
||||
- const: renesas,rcar-gen3-scif # R-Car Gen3 and RZ/G2
|
||||
- const: renesas,scif # generic SCIF compatible UART
|
||||
|
||||
- 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
|
||||
|
@ -9,7 +9,6 @@ Support for Serial devices
|
||||
|
||||
|
||||
driver
|
||||
tty
|
||||
|
||||
Serial drivers
|
||||
==============
|
||||
|
@ -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>
|
||||
|
@ -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 ??
|
||||
======================= =======================================================
|
@ -137,6 +137,7 @@ needed).
|
||||
misc-devices/index
|
||||
scheduler/index
|
||||
mhi/index
|
||||
tty/index
|
||||
|
||||
Architecture-agnostic documentation
|
||||
-----------------------------------
|
||||
|
63
Documentation/tty/index.rst
Normal file
63
Documentation/tty/index.rst
Normal file
@ -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`.
|
22
Documentation/tty/n_tty.rst
Normal file
22
Documentation/tty/n_tty.rst
Normal file
@ -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:
|
46
Documentation/tty/tty_buffer.rst
Normal file
46
Documentation/tty/tty_buffer.rst
Normal file
@ -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:
|
128
Documentation/tty/tty_driver.rst
Normal file
128
Documentation/tty/tty_driver.rst
Normal file
@ -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
|
||||
|
31
Documentation/tty/tty_internals.rst
Normal file
31
Documentation/tty/tty_internals.rst
Normal file
@ -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:
|
85
Documentation/tty/tty_ldisc.rst
Normal file
85
Documentation/tty/tty_ldisc.rst
Normal file
@ -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:
|
70
Documentation/tty/tty_port.rst
Normal file
70
Documentation/tty/tty_port.rst
Normal file
@ -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
|
81
Documentation/tty/tty_struct.rst
Normal file
81
Documentation/tty/tty_struct.rst
Normal file
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
@ -801,6 +823,20 @@ static int mxser_activate(struct tty_port *port, struct tty_struct *tty)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
* 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.
|
||||
* 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.
|
||||
* 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)
|
||||
* 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
|
||||
* 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.
|
||||
* 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.
|
||||
* 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
|
||||
* 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)
|
||||
* 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.
|
||||
* 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 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.
|
||||
* 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.
|
||||
* 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
|
||||
* 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
|
||||
* 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.
|
||||
* Helper function to speed up n_tty_read(). It is only called when %ICANON is
|
||||
* off; it copies characters straight from the tty queue.
|
||||
*
|
||||
* Called under the ldata->atomic_read_lock sem
|
||||
* 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
|
||||
* 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.
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* Called under the atomic_read_lock mutex
|
||||
*
|
||||
* n_tty_read()/consumer path:
|
||||
* caller holds non-exclusive termios_rwsem
|
||||
* read_tail published
|
||||
* 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
|
||||
* 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.
|
||||
* 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
|
||||
* 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
|
||||
* 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.
|
||||
* 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.
|
||||
* This code must be sure never to sleep through a hangup.
|
||||
*
|
||||
* n_tty_read()/consumer path:
|
||||
* claims non-exclusive termios_rwsem
|
||||
* publishes read_tail
|
||||
* 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
|
||||
* 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.
|
||||
* 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.
|
||||
* 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)
|
||||
* 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.
|
||||
* Called without the kernel lock held - fine
|
||||
* This code must be sure never to sleep through a hangup.
|
||||
*
|
||||
* 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;
|
||||
|
@ -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);
|
||||
|
21
drivers/tty/serial/8250/8250_alpha.c
Normal file
21
drivers/tty/serial/8250/8250_alpha.c
Normal file
@ -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);
|
||||
}
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
@ -2198,16 +2079,6 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
|
||||
.setup = pci_default_setup,
|
||||
.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 */
|
||||
{ }
|
||||
};
|
||||
@ -5027,127 +4753,6 @@ static const struct pci_device_id serial_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
|
||||
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)
|
||||
*/
|
||||
|
214
drivers/tty/serial/8250/8250_pericom.c
Normal file
214
drivers/tty/serial/8250/8250_pericom.c
Normal file
@ -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");
|
@ -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)
|
||||
@ -3325,6 +3332,35 @@ static void serial8250_console_restore(struct uart_8250_port *up)
|
||||
serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
@ -2183,32 +2147,13 @@ static const char *pl011_type(struct uart_port *port)
|
||||
return uap->port.type == PORT_AMBA ? uap->type : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 },
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
int irq;
|
||||
|
||||
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;
|
||||
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;
|
||||
|
@ -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");
|
||||
|
@ -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? */
|
||||
|
@ -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" },
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
/*
|
||||
|
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
* 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
|
||||
* 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. If we fail return the size we managed to find.
|
||||
* Make at least @size bytes of linear space available for the tty 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.
|
||||
* 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
|
||||
* 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.
|
||||
* 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
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* 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!
|
||||
* 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)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
* 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.
|
||||
* 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)
|
||||
{
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
* 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
|
||||
* Implement the core POSIX/SuS tty behaviour when opening a tty device.
|
||||
* Handles:
|
||||
*
|
||||
* 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.
|
||||
* - hangup (both before and during)
|
||||
* - non blocking open
|
||||
* - rts/dtr/dcd
|
||||
* - signals
|
||||
* - port flags and counts
|
||||
*
|
||||
* Caller holds tty lock.
|
||||
* 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.
|
||||
*
|
||||
* NB: May drop and reacquire tty lock when blocking, so tty and tty_port
|
||||
* may have changed state (eg., may have been hung up).
|
||||
* 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
|
||||
*
|
||||
* Caller holds tty lock
|
||||
* 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.
|
||||
*
|
||||
* 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).
|
||||
*
|
||||
* 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)
|
||||
* Locking: Caller holds tty lock.
|
||||
*
|
||||
* 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)
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -2,235 +2,6 @@
|
||||
#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.
|
||||
*
|
||||
* 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!)
|
||||
*
|
||||
* Optional method. Default behaviour is to use the ttys array
|
||||
*
|
||||
* int (*install)(struct tty_driver *self, struct tty_struct *tty)
|
||||
*
|
||||
* 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 ttys array
|
||||
*
|
||||
* void (*remove)(struct tty_driver *self, struct tty_struct *tty)
|
||||
*
|
||||
* 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 ttys array
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Required method. Called with tty lock held.
|
||||
*
|
||||
* void (*close)(struct tty_struct * tty, struct file * filp);
|
||||
*
|
||||
* This routine is called when a particular tty device is closed.
|
||||
* Note: called even if the corresponding open() failed.
|
||||
*
|
||||
* Required method. Called with tty lock held.
|
||||
*
|
||||
* void (*shutdown)(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.
|
||||
*
|
||||
* void (*cleanup)(struct tty_struct * tty);
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*
|
||||
* 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
|
||||
* number of characters actually accepted for writing.
|
||||
*
|
||||
* Optional: Required for writable devices.
|
||||
*
|
||||
* int (*put_char)(struct tty_struct *tty, unsigned char ch);
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Optional: Kernel will use the write method if not provided.
|
||||
*
|
||||
* Note: Do not call this function directly, call tty_put_char
|
||||
*
|
||||
* void (*flush_chars)(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().
|
||||
*
|
||||
* Optional:
|
||||
*
|
||||
* Note: Do not call this function directly, call tty_driver_flush_chars
|
||||
*
|
||||
* unsigned int (*write_room)(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
|
||||
* control is acted.
|
||||
*
|
||||
* Required if write method is provided else not needed.
|
||||
*
|
||||
* Note: Do not call this function directly, call tty_write_room
|
||||
*
|
||||
* int (*ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg);
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Optional
|
||||
*
|
||||
* long (*compat_ioctl)(struct tty_struct *tty,,
|
||||
* unsigned int cmd, unsigned long arg);
|
||||
*
|
||||
* implement ioctl processing for 32 bit process on 64 bit system
|
||||
*
|
||||
* Optional
|
||||
*
|
||||
* void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
|
||||
*
|
||||
* This routine allows the tty driver to be notified when
|
||||
* device's termios settings have changed.
|
||||
*
|
||||
* Optional: Called under the termios lock
|
||||
*
|
||||
*
|
||||
* void (*set_ldisc)(struct tty_struct *tty);
|
||||
*
|
||||
* This routine allows the tty driver to be notified when the
|
||||
* device's termios settings have changed.
|
||||
*
|
||||
* Optional: Called under BKL (currently)
|
||||
*
|
||||
* void (*throttle)(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.
|
||||
*
|
||||
* Optional: Always invoke via tty_throttle_safe(), called under the
|
||||
* termios lock.
|
||||
*
|
||||
* void (*unthrottle)(struct tty_struct * tty);
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* void (*stop)(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 start() method.
|
||||
*
|
||||
* Optional:
|
||||
*
|
||||
* Note: Call stop_tty not this method.
|
||||
*
|
||||
* void (*start)(struct tty_struct *tty);
|
||||
*
|
||||
* This routine notifies the tty driver that it resume sending
|
||||
* characters to the tty device.
|
||||
*
|
||||
* Called with ->flow.lock held. Serialized with stop() method.
|
||||
*
|
||||
* Optional:
|
||||
*
|
||||
* Note: Call start_tty not this method.
|
||||
*
|
||||
* void (*hangup)(struct tty_struct *tty);
|
||||
*
|
||||
* This routine notifies the tty driver that it should hang up the
|
||||
* tty device.
|
||||
*
|
||||
* Optional:
|
||||
*
|
||||
* Called with tty lock held.
|
||||
*
|
||||
* int (*break_ctl)(struct tty_struct *tty, int state);
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* If this routine is implemented, the high-level tty driver will
|
||||
* handle the following ioctls: TCSBRK, TCSBRKP, TIOCSBRK,
|
||||
* TIOCCBRK.
|
||||
*
|
||||
* 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: Required for TCSBRK/BRKP/etc handling.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Optional: If not provided the device is assumed to have no FIFO
|
||||
*
|
||||
* Note: Usually correct to call tty_wait_until_sent
|
||||
*
|
||||
* void (*send_xchar)(struct tty_struct *tty, char ch);
|
||||
*
|
||||
* 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 atomic write lock to keep it serialized with the ldisc.
|
||||
*
|
||||
* int (*resize)(struct tty_struct *tty, struct winsize *ws)
|
||||
*
|
||||
* Called when a termios request is issued which changes the
|
||||
* requested terminal geometry.
|
||||
*
|
||||
* 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
|
||||
* line). See tty_do_resize() if you need to wrap the standard method
|
||||
* in your own logic - the usual case.
|
||||
*
|
||||
* int (*get_icount)(struct tty_struct *tty, struct serial_icounter *icount);
|
||||
*
|
||||
* 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).
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kref.h>
|
||||
@ -244,6 +15,337 @@ 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)``
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @install: ``int ()(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.
|
||||
*
|
||||
* Optional method. Default behaviour is to use the @self->ttys array.
|
||||
*
|
||||
* @remove: ``void ()(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.
|
||||
*
|
||||
* Optional method. Default behaviour is to use the @self->ttys array.
|
||||
*
|
||||
* @open: ``int ()(struct tty_struct *tty, struct file *)``
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @close: ``void ()(struct tty_struct *tty, struct file *)``
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Remark: called even if the corresponding @open() failed.
|
||||
*
|
||||
* Required method. Called with tty lock held. May sleep.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @cleanup: ``void ()(struct tty_struct *tty)``
|
||||
*
|
||||
* 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)``
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* May occur in parallel in special cases. Because this includes panic
|
||||
* paths drivers generally shouldn't try and do clever locking here.
|
||||
*
|
||||
* Optional: Required for writable devices. May not sleep.
|
||||
*
|
||||
* @put_char: ``int ()(struct tty_struct *tty, unsigned char ch)``
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Optional: Kernel will use the @write method if not provided. Do not
|
||||
* call this function directly, call tty_put_char().
|
||||
*
|
||||
* @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().
|
||||
*
|
||||
* Optional. Do not call this function directly, call
|
||||
* tty_driver_flush_chars().
|
||||
*
|
||||
* @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
|
||||
* control is acted.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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().
|
||||
*
|
||||
* @ioctl: ``int ()(struct tty_struct *tty, unsigned int cmd,
|
||||
* unsigned long arg)``
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Optional.
|
||||
*
|
||||
* @compat_ioctl: ``long ()(struct tty_struct *tty, unsigned int cmd,
|
||||
* unsigned long arg)``
|
||||
*
|
||||
* Implement ioctl processing for 32 bit process on 64 bit system.
|
||||
*
|
||||
* Optional.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Optional. Called under the @tty->termios_rwsem. May sleep.
|
||||
*
|
||||
* @set_ldisc: ``void ()(struct tty_struct *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. Called under the @tty->ldisc_sem and @tty->termios_rwsem.
|
||||
*
|
||||
* @throttle: ``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.
|
||||
*
|
||||
* Serialization including with @unthrottle() is the job of the ldisc
|
||||
* layer.
|
||||
*
|
||||
* Optional: Always invoke via tty_throttle_safe(). Called under the
|
||||
* @tty->termios_rwsem.
|
||||
*
|
||||
* @unthrottle: ``void ()(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.
|
||||
*
|
||||
* 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 @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. Called with tty lock held.
|
||||
*
|
||||
* @break_ctl: ``int ()(struct tty_struct *tty, int state)``
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* If this routine is implemented, the high-level tty driver will handle
|
||||
* the following ioctls: %TCSBRK, %TCSBRKP, %TIOCSBRK, %TIOCCBRK.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Optional: Required for %TCSBRK/%BRKP/etc. handling. May sleep.
|
||||
*
|
||||
* @flush_buffer: ``void ()(struct tty_struct *tty)``
|
||||
*
|
||||
* This routine discards device private output buffer. Invoked on close,
|
||||
* hangup, to implement %TCOFLUSH ioctl and similar.
|
||||
*
|
||||
* 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().
|
||||
*
|
||||
* @wait_until_sent: ``void ()(struct tty_struct *tty, int timeout)``
|
||||
*
|
||||
* 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.
|
||||
* Usually correct to invoke via tty_wait_until_sent(). May sleep.
|
||||
*
|
||||
* @send_xchar: ``void ()(struct tty_struct *tty, char ch)``
|
||||
*
|
||||
* This routine is used to send a high-priority XON/XOFF character (@ch)
|
||||
* to the @tty device.
|
||||
*
|
||||
* Optional: If not provided, then the @write method is called under
|
||||
* the @tty->atomic_write_lock to keep it serialized with the ldisc.
|
||||
*
|
||||
* @tiocmget: ``int ()(struct tty_struct *tty)``
|
||||
*
|
||||
* This routine is used to obtain the modem status bits from the @tty
|
||||
* driver.
|
||||
*
|
||||
* 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 (e.g. a serial
|
||||
* line). See tty_do_resize() if you need to wrap the standard method
|
||||
* 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.
|
||||
*
|
||||
* @get_serial: ``int ()(struct tty_struct *tty, struct serial_struct *p)``
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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.)
|
||||
/**
|
||||
* DOC: TTY Driver Flags
|
||||
*
|
||||
* 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_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_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_REAL_RAW
|
||||
* Indicates that the driver will guarantee not to set any special
|
||||
* character handling flags if this is set for the tty:
|
||||
*
|
||||
* TTY_DRIVER_HARDWARE_BREAK -- hardware handles break signals. Pass
|
||||
* the requested timeout to the caller instead of using a simple
|
||||
* on/off interface.
|
||||
* ``(IGNBRK || (!BRKINT && !PARMRK)) && (IGNPAR || !INPCK)``
|
||||
*
|
||||
* 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.
|
||||
* 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_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.
|
||||
* 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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user