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:
Linus Torvalds 2022-01-12 11:21:52 -08:00
commit 342465f533
86 changed files with 3329 additions and 3015 deletions

View File

@ -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

View File

@ -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

View File

@ -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>;
};

View File

@ -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

View File

@ -9,7 +9,6 @@ Support for Serial devices
driver
tty
Serial drivers
==============

View File

@ -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>

View File

@ -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 ??
======================= =======================================================

View File

@ -137,6 +137,7 @@ needed).
misc-devices/index
scheduler/index
mhi/index
tty/index
Architecture-agnostic documentation
-----------------------------------

View 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`.

View 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:

View 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:

View 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

View 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:

View 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 wont 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:

View 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

View 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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View 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);
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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)
*/

View 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");

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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 },
};

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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 = &ltq_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 = &ltq_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;

View File

@ -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");

View File

@ -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? */

View File

@ -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" },

View File

@ -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;

View File

@ -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;

View File

@ -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
/*

View File

@ -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);
/*

View File

@ -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) {

View File

@ -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);
}

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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)
{

View File

@ -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 {

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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)
{

View 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

View File

@ -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,

View File

@ -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;

View File

@ -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 */

View File

@ -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;