mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 09:16:33 +00:00
TTY / Serial driver changes for 6.0-rc1
Here is the big set of tty and serial driver changes for 6.0-rc1. It was delayed from last week as I wanted to make sure the last commit here got some good testing in linux-next and elsewhere as it seemed to show up only late in testing for some reason. Nothing major here, just lots of cleanups from Jiri and Ilpo to make the tty core cleaner (Jiri) and the rs485 code simpler to use (Ilpo). Also included in here is the obligatory n_gsm updates from Daniel Starke and lots of tiny driver updates and minor fixes and tweaks for other smaller serial drivers. Full details are in the shortlog. All of these have been in linux-next for a while with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYvD8qA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylfEQCdGiYLQkWUUarhnlocHo+kSm5vkvsAnicZg7Sl IQBeAidA3dZEQO0lLlM5 =t7Yh -----END PGP SIGNATURE----- Merge tag 'tty-6.0-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 and serial driver changes for 6.0-rc1. It was delayed from last week as I wanted to make sure the last commit here got some good testing in linux-next and elsewhere as it seemed to show up only late in testing for some reason. Nothing major here, just lots of cleanups from Jiri and Ilpo to make the tty core cleaner (Jiri) and the rs485 code simpler to use (Ilpo). Also included in here is the obligatory n_gsm updates from Daniel Starke and lots of tiny driver updates and minor fixes and tweaks for other smaller serial drivers. All of these have been in linux-next for a while with no reported problems" * tag 'tty-6.0-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (186 commits) tty: serial: qcom-geni-serial: Fix %lu -> %u in print statements tty: amiserial: Fix comment typo tty: serial: document uart_get_console() tty: serial: serial_core, reformat kernel-doc for functions Documentation: serial: link uart_ops properly Documentation: serial: move GPIO kernel-doc to the functions Documentation: serial: dedup kernel-doc for uart functions Documentation: serial: move uart_ops documentation to the struct dt-bindings: serial: snps-dw-apb-uart: Document Rockchip RV1126 serial: mvebu-uart: uart2 error bits clearing tty: serial: fsl_lpuart: correct the count of break characters serial: stm32: make info structs static to avoid sparse warnings serial: fsl_lpuart: zero out parity bit in CS7 mode tty: serial: qcom-geni-serial: Fix get_clk_div_rate() which otherwise could return a sub-optimal clock rate. serial: 8250_bcm2835aux: Add missing clk_disable_unprepare() tty: vt: initialize unicode screen buffer serial: remove VR41XX serial driver serial: 8250: lpc18xx: Remove redundant sanity check for RS485 flags serial: 8250_dwlib: remove redundant sanity check for RS485 flags dt_bindings: rs485: Correct delay values ...
This commit is contained in:
commit
607ca0f742
@ -62,6 +62,7 @@ properties:
|
||||
- const: mrvl,pxa-uart
|
||||
- const: nuvoton,wpcm450-uart
|
||||
- const: nuvoton,npcm750-uart
|
||||
- const: nuvoton,npcm845-uart
|
||||
- const: nvidia,tegra20-uart
|
||||
- const: nxp,lpc3220-uart
|
||||
- items:
|
||||
|
120
Documentation/devicetree/bindings/serial/mediatek,uart.yaml
Normal file
120
Documentation/devicetree/bindings/serial/mediatek,uart.yaml
Normal file
@ -0,0 +1,120 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/serial/mediatek,uart.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: MediaTek Universal Asynchronous Receiver/Transmitter (UART)
|
||||
|
||||
maintainers:
|
||||
- Matthias Brugger <matthias.bgg@gmail.com>
|
||||
|
||||
allOf:
|
||||
- $ref: serial.yaml#
|
||||
|
||||
description: |
|
||||
The MediaTek UART is based on the basic 8250 UART and compatible
|
||||
with 16550A, with enhancements for high speed baud rates and
|
||||
support for DMA.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: mediatek,mt6577-uart
|
||||
- items:
|
||||
- enum:
|
||||
- mediatek,mt2701-uart
|
||||
- mediatek,mt2712-uart
|
||||
- mediatek,mt6580-uart
|
||||
- mediatek,mt6582-uart
|
||||
- mediatek,mt6589-uart
|
||||
- mediatek,mt6755-uart
|
||||
- mediatek,mt6765-uart
|
||||
- mediatek,mt6779-uart
|
||||
- mediatek,mt6795-uart
|
||||
- mediatek,mt6797-uart
|
||||
- mediatek,mt7622-uart
|
||||
- mediatek,mt7623-uart
|
||||
- mediatek,mt7629-uart
|
||||
- mediatek,mt7986-uart
|
||||
- mediatek,mt8127-uart
|
||||
- mediatek,mt8135-uart
|
||||
- mediatek,mt8173-uart
|
||||
- mediatek,mt8183-uart
|
||||
- mediatek,mt8186-uart
|
||||
- mediatek,mt8192-uart
|
||||
- mediatek,mt8195-uart
|
||||
- mediatek,mt8516-uart
|
||||
- const: mediatek,mt6577-uart
|
||||
|
||||
reg:
|
||||
description: The base address of the UART register bank
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
items:
|
||||
- description: The clock the baudrate is derived from
|
||||
- description: The bus clock for register accesses
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: baud
|
||||
- const: bus
|
||||
|
||||
dmas:
|
||||
items:
|
||||
- description: phandle to TX DMA
|
||||
- description: phandle to RX DMA
|
||||
|
||||
dma-names:
|
||||
items:
|
||||
- const: tx
|
||||
- const: rx
|
||||
|
||||
interrupts:
|
||||
minItems: 1
|
||||
maxItems: 2
|
||||
|
||||
interrupt-names:
|
||||
description:
|
||||
The UART interrupt and optionally the RX in-band wakeup interrupt.
|
||||
minItems: 1
|
||||
items:
|
||||
- const: uart
|
||||
- const: wakeup
|
||||
|
||||
pinctrl-0: true
|
||||
pinctrl-1: true
|
||||
|
||||
pinctrl-names:
|
||||
minItems: 1
|
||||
items:
|
||||
- const: default
|
||||
- const: sleep
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
serial@11006000 {
|
||||
compatible = "mediatek,mt6589-uart", "mediatek,mt6577-uart";
|
||||
reg = <0x11006000 0x400>;
|
||||
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 52 IRQ_TYPE_EDGE_FALLING>;
|
||||
interrupt-names = "uart", "wakeup";
|
||||
clocks = <&uart_clk>, <&bus_clk>;
|
||||
clock-names = "baud", "bus";
|
||||
pinctrl-0 = <&uart_pin>;
|
||||
pinctrl-1 = <&uart_pin_sleep>;
|
||||
pinctrl-names = "default", "sleep";
|
||||
};
|
@ -1,59 +0,0 @@
|
||||
* MediaTek Universal Asynchronous Receiver/Transmitter (UART)
|
||||
|
||||
Required properties:
|
||||
- compatible should contain:
|
||||
* "mediatek,mt2701-uart" for MT2701 compatible UARTS
|
||||
* "mediatek,mt2712-uart" for MT2712 compatible UARTS
|
||||
* "mediatek,mt6580-uart" for MT6580 compatible UARTS
|
||||
* "mediatek,mt6582-uart" for MT6582 compatible UARTS
|
||||
* "mediatek,mt6589-uart" for MT6589 compatible UARTS
|
||||
* "mediatek,mt6755-uart" for MT6755 compatible UARTS
|
||||
* "mediatek,mt6765-uart" for MT6765 compatible UARTS
|
||||
* "mediatek,mt6779-uart" for MT6779 compatible UARTS
|
||||
* "mediatek,mt6795-uart" for MT6795 compatible UARTS
|
||||
* "mediatek,mt6797-uart" for MT6797 compatible UARTS
|
||||
* "mediatek,mt7622-uart" for MT7622 compatible UARTS
|
||||
* "mediatek,mt7623-uart" for MT7623 compatible UARTS
|
||||
* "mediatek,mt7629-uart" for MT7629 compatible UARTS
|
||||
* "mediatek,mt7986-uart", "mediatek,mt6577-uart" for MT7986 compatible UARTS
|
||||
* "mediatek,mt8127-uart" for MT8127 compatible UARTS
|
||||
* "mediatek,mt8135-uart" for MT8135 compatible UARTS
|
||||
* "mediatek,mt8173-uart" for MT8173 compatible UARTS
|
||||
* "mediatek,mt8183-uart", "mediatek,mt6577-uart" for MT8183 compatible UARTS
|
||||
* "mediatek,mt8186-uart", "mediatek,mt6577-uart" for MT8183 compatible UARTS
|
||||
* "mediatek,mt8192-uart", "mediatek,mt6577-uart" for MT8192 compatible UARTS
|
||||
* "mediatek,mt8195-uart", "mediatek,mt6577-uart" for MT8195 compatible UARTS
|
||||
* "mediatek,mt8516-uart" for MT8516 compatible UARTS
|
||||
* "mediatek,mt6577-uart" for MT6577 and all of the above
|
||||
|
||||
- reg: The base address of the UART register bank.
|
||||
|
||||
- interrupts:
|
||||
index 0: an interrupt specifier for the UART controller itself
|
||||
index 1: optional, an interrupt specifier with edge sensitivity on Rx pin to
|
||||
support Rx in-band wake up. If one would like to use this feature,
|
||||
one must create an addtional pinctrl to reconfigure Rx pin to normal
|
||||
GPIO before suspend.
|
||||
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
- clock-names:
|
||||
- "baud": The clock the baudrate is derived from
|
||||
- "bus": The bus clock for register accesses (optional)
|
||||
|
||||
For compatibility with older device trees an unnamed clock is used for the
|
||||
baud clock if the baudclk does not exist. Do not use this for new designs.
|
||||
|
||||
Example:
|
||||
|
||||
uart0: serial@11006000 {
|
||||
compatible = "mediatek,mt6589-uart", "mediatek,mt6577-uart";
|
||||
reg = <0x11006000 0x400>;
|
||||
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>,
|
||||
<GIC_SPI 52 IRQ_TYPE_EDGE_FALLING>;
|
||||
clocks = <&uart_clk>, <&bus_clk>;
|
||||
clock-names = "baud", "bus";
|
||||
pinctrl-names = "default", "sleep";
|
||||
pinctrl-0 = <&uart_pin>;
|
||||
pinctrl-1 = <&uart_pin_sleep>;
|
||||
};
|
@ -57,6 +57,7 @@ properties:
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,hscif-r8a779a0 # R-Car V3U
|
||||
- renesas,hscif-r8a779f0 # R-Car S4-8
|
||||
- renesas,hscif-r8a779g0 # R-Car V4H
|
||||
- const: renesas,rcar-gen4-hscif # R-Car Gen4
|
||||
- const: renesas,hscif # generic HSCIF compatible UART
|
||||
|
@ -22,12 +22,12 @@ properties:
|
||||
- description: Delay between rts signal and beginning of data sent in
|
||||
milliseconds. It corresponds to the delay before sending data.
|
||||
default: 0
|
||||
maximum: 1000
|
||||
maximum: 100
|
||||
- description: Delay between end of data sent and rts signal in milliseconds.
|
||||
It corresponds to the delay after sending data and actual release
|
||||
of the line.
|
||||
default: 0
|
||||
maximum: 1000
|
||||
maximum: 100
|
||||
|
||||
rs485-rts-active-low:
|
||||
description: drive RTS low when sending (default is high).
|
||||
|
@ -33,7 +33,9 @@ properties:
|
||||
- rockchip,rk3368-uart
|
||||
- rockchip,rk3399-uart
|
||||
- rockchip,rk3568-uart
|
||||
- rockchip,rk3588-uart
|
||||
- rockchip,rv1108-uart
|
||||
- rockchip,rv1126-uart
|
||||
- const: snps,dw-apb-uart
|
||||
- items:
|
||||
- enum:
|
||||
|
@ -25,10 +25,10 @@ Console Support
|
||||
---------------
|
||||
|
||||
The serial core provides a few helper functions. This includes identifing
|
||||
the correct port structure (via uart_get_console) and decoding command line
|
||||
arguments (uart_parse_options).
|
||||
the correct port structure (via uart_get_console()) and decoding command line
|
||||
arguments (uart_parse_options()).
|
||||
|
||||
There is also a helper function (uart_console_write) which performs a
|
||||
There is also a helper function (uart_console_write()) which performs a
|
||||
character by character write, translating newlines to CRLF sequences.
|
||||
Driver writers are recommended to use this function rather than implementing
|
||||
their own version.
|
||||
@ -39,7 +39,7 @@ Locking
|
||||
|
||||
It is the responsibility of the low level hardware driver to perform the
|
||||
necessary locking using port->lock. There are some exceptions (which
|
||||
are described in the uart_ops listing below.)
|
||||
are described in the struct uart_ops listing below.)
|
||||
|
||||
There are two locks. A per-port spinlock, and an overall semaphore.
|
||||
|
||||
@ -63,442 +63,20 @@ commonly referred to as the port mutex.
|
||||
uart_ops
|
||||
--------
|
||||
|
||||
The uart_ops structure is the main interface between serial_core and the
|
||||
hardware specific driver. It contains all the methods to control the
|
||||
hardware.
|
||||
|
||||
tx_empty(port)
|
||||
This function tests whether the transmitter fifo and shifter
|
||||
for the port described by 'port' is empty. If it is empty,
|
||||
this function should return TIOCSER_TEMT, otherwise return 0.
|
||||
If the port does not support this operation, then it should
|
||||
return TIOCSER_TEMT.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
set_mctrl(port, mctrl)
|
||||
This function sets the modem control lines for port described
|
||||
by 'port' to the state described by mctrl. The relevant bits
|
||||
of mctrl are:
|
||||
|
||||
- TIOCM_RTS RTS signal.
|
||||
- TIOCM_DTR DTR signal.
|
||||
- TIOCM_OUT1 OUT1 signal.
|
||||
- TIOCM_OUT2 OUT2 signal.
|
||||
- TIOCM_LOOP Set the port into loopback mode.
|
||||
|
||||
If the appropriate bit is set, the signal should be driven
|
||||
active. If the bit is clear, the signal should be driven
|
||||
inactive.
|
||||
|
||||
Locking: port->lock taken.
|
||||
|
||||
Interrupts: locally disabled.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
get_mctrl(port)
|
||||
Returns the current state of modem control inputs. The state
|
||||
of the outputs should not be returned, since the core keeps
|
||||
track of their state. The state information should include:
|
||||
|
||||
- TIOCM_CAR state of DCD signal
|
||||
- TIOCM_CTS state of CTS signal
|
||||
- TIOCM_DSR state of DSR signal
|
||||
- TIOCM_RI state of RI signal
|
||||
|
||||
The bit is set if the signal is currently driven active. If
|
||||
the port does not support CTS, DCD or DSR, the driver should
|
||||
indicate that the signal is permanently active. If RI is
|
||||
not available, the signal should not be indicated as active.
|
||||
|
||||
Locking: port->lock taken.
|
||||
|
||||
Interrupts: locally disabled.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
stop_tx(port)
|
||||
Stop transmitting characters. This might be due to the CTS
|
||||
line becoming inactive or the tty layer indicating we want
|
||||
to stop transmission due to an XOFF character.
|
||||
|
||||
The driver should stop transmitting characters as soon as
|
||||
possible.
|
||||
|
||||
Locking: port->lock taken.
|
||||
|
||||
Interrupts: locally disabled.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
start_tx(port)
|
||||
Start transmitting characters.
|
||||
|
||||
Locking: port->lock taken.
|
||||
|
||||
Interrupts: locally disabled.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
throttle(port)
|
||||
Notify the serial 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 serial port.
|
||||
This will be called only if hardware assisted flow control is enabled.
|
||||
|
||||
Locking: serialized with .unthrottle() and termios modification by the
|
||||
tty layer.
|
||||
|
||||
unthrottle(port)
|
||||
Notify the serial driver that characters can now be sent to the serial
|
||||
port without fear of overrunning the input buffers of the line
|
||||
disciplines.
|
||||
|
||||
This will be called only if hardware assisted flow control is enabled.
|
||||
|
||||
Locking: serialized with .throttle() and termios modification by the
|
||||
tty layer.
|
||||
|
||||
send_xchar(port,ch)
|
||||
Transmit a high priority character, even if the port is stopped.
|
||||
This is used to implement XON/XOFF flow control and tcflow(). If
|
||||
the serial driver does not implement this function, the tty core
|
||||
will append the character to the circular buffer and then call
|
||||
start_tx() / stop_tx() to flush the data out.
|
||||
|
||||
Do not transmit if ch == '\0' (__DISABLED_CHAR).
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
stop_rx(port)
|
||||
Stop receiving characters; the port is in the process of
|
||||
being closed.
|
||||
|
||||
Locking: port->lock taken.
|
||||
|
||||
Interrupts: locally disabled.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
enable_ms(port)
|
||||
Enable the modem status interrupts.
|
||||
|
||||
This method may be called multiple times. Modem status
|
||||
interrupts should be disabled when the shutdown method is
|
||||
called.
|
||||
|
||||
Locking: port->lock taken.
|
||||
|
||||
Interrupts: locally disabled.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
break_ctl(port,ctl)
|
||||
Control the transmission of a break signal. If ctl is
|
||||
nonzero, the break signal should be transmitted. The signal
|
||||
should be terminated when another call is made with a zero
|
||||
ctl.
|
||||
|
||||
Locking: caller holds tty_port->mutex
|
||||
|
||||
startup(port)
|
||||
Grab any interrupt resources and initialise any low level driver
|
||||
state. Enable the port for reception. It should not activate
|
||||
RTS nor DTR; this will be done via a separate call to set_mctrl.
|
||||
|
||||
This method will only be called when the port is initially opened.
|
||||
|
||||
Locking: port_sem taken.
|
||||
|
||||
Interrupts: globally disabled.
|
||||
|
||||
shutdown(port)
|
||||
Disable the port, disable any break condition that may be in
|
||||
effect, and free any interrupt resources. It should not disable
|
||||
RTS nor DTR; this will have already been done via a separate
|
||||
call to set_mctrl.
|
||||
|
||||
Drivers must not access port->state once this call has completed.
|
||||
|
||||
This method will only be called when there are no more users of
|
||||
this port.
|
||||
|
||||
Locking: port_sem taken.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
flush_buffer(port)
|
||||
Flush any write buffers, reset any DMA state and stop any
|
||||
ongoing DMA transfers.
|
||||
|
||||
This will be called whenever the port->state->xmit circular
|
||||
buffer is cleared.
|
||||
|
||||
Locking: port->lock taken.
|
||||
|
||||
Interrupts: locally disabled.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
set_termios(port,termios,oldtermios)
|
||||
Change the port parameters, including word length, parity, stop
|
||||
bits. Update read_status_mask and ignore_status_mask to indicate
|
||||
the types of events we are interested in receiving. Relevant
|
||||
termios->c_cflag bits are:
|
||||
|
||||
CSIZE
|
||||
- word size
|
||||
CSTOPB
|
||||
- 2 stop bits
|
||||
PARENB
|
||||
- parity enable
|
||||
PARODD
|
||||
- odd parity (when PARENB is in force)
|
||||
CREAD
|
||||
- enable reception of characters (if not set,
|
||||
still receive characters from the port, but
|
||||
throw them away.
|
||||
CRTSCTS
|
||||
- if set, enable CTS status change reporting
|
||||
CLOCAL
|
||||
- if not set, enable modem status change
|
||||
reporting.
|
||||
|
||||
Relevant termios->c_iflag bits are:
|
||||
|
||||
INPCK
|
||||
- enable frame and parity error events to be
|
||||
passed to the TTY layer.
|
||||
BRKINT / PARMRK
|
||||
- both of these enable break events to be
|
||||
passed to the TTY layer.
|
||||
|
||||
IGNPAR
|
||||
- ignore parity and framing errors
|
||||
IGNBRK
|
||||
- ignore break errors, If IGNPAR is also
|
||||
set, ignore overrun errors as well.
|
||||
|
||||
The interaction of the iflag bits is as follows (parity error
|
||||
given as an example):
|
||||
|
||||
=============== ======= ====== =============================
|
||||
Parity error INPCK IGNPAR
|
||||
=============== ======= ====== =============================
|
||||
n/a 0 n/a character received, marked as
|
||||
TTY_NORMAL
|
||||
None 1 n/a character received, marked as
|
||||
TTY_NORMAL
|
||||
Yes 1 0 character received, marked as
|
||||
TTY_PARITY
|
||||
Yes 1 1 character discarded
|
||||
=============== ======= ====== =============================
|
||||
|
||||
Other flags may be used (eg, xon/xoff characters) if your
|
||||
hardware supports hardware "soft" flow control.
|
||||
|
||||
Locking: caller holds tty_port->mutex
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
set_ldisc(port,termios)
|
||||
Notifier for discipline change. See ../tty/tty_ldisc.rst.
|
||||
|
||||
Locking: caller holds tty_port->mutex
|
||||
|
||||
pm(port,state,oldstate)
|
||||
Perform any power management related activities on the specified
|
||||
port. State indicates the new state (defined by
|
||||
enum uart_pm_state), oldstate indicates the previous state.
|
||||
|
||||
This function should not be used to grab any resources.
|
||||
|
||||
This will be called when the port is initially opened and finally
|
||||
closed, except when the port is also the system console. This
|
||||
will occur even if CONFIG_PM is not set.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
type(port)
|
||||
Return a pointer to a string constant describing the specified
|
||||
port, or return NULL, in which case the string 'unknown' is
|
||||
substituted.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
release_port(port)
|
||||
Release any memory and IO region resources currently in use by
|
||||
the port.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
request_port(port)
|
||||
Request any memory and IO region resources required by the port.
|
||||
If any fail, no resources should be registered when this function
|
||||
returns, and it should return -EBUSY on failure.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
config_port(port,type)
|
||||
Perform any autoconfiguration steps required for the port. `type`
|
||||
contains a bit mask of the required configuration. UART_CONFIG_TYPE
|
||||
indicates that the port requires detection and identification.
|
||||
port->type should be set to the type found, or PORT_UNKNOWN if
|
||||
no port was detected.
|
||||
|
||||
UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal,
|
||||
which should be probed using standard kernel autoprobing techniques.
|
||||
This is not necessary on platforms where ports have interrupts
|
||||
internally hard wired (eg, system on a chip implementations).
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
verify_port(port,serinfo)
|
||||
Verify the new serial port information contained within serinfo is
|
||||
suitable for this port type.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
ioctl(port,cmd,arg)
|
||||
Perform any port specific IOCTLs. IOCTL commands must be defined
|
||||
using the standard numbering system found in <asm/ioctl.h>
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
poll_init(port)
|
||||
Called by kgdb to perform the minimal hardware initialization needed
|
||||
to support poll_put_char() and poll_get_char(). Unlike ->startup()
|
||||
this should not request interrupts.
|
||||
|
||||
Locking: tty_mutex and tty_port->mutex taken.
|
||||
|
||||
Interrupts: n/a.
|
||||
|
||||
poll_put_char(port,ch)
|
||||
Called by kgdb to write a single character directly to the serial
|
||||
port. It can and should block until there is space in the TX FIFO.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
poll_get_char(port)
|
||||
Called by kgdb to read a single character directly from the serial
|
||||
port. If data is available, it should be returned; otherwise
|
||||
the function should return NO_POLL_CHAR immediately.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
This call must not sleep
|
||||
.. kernel-doc:: include/linux/serial_core.h
|
||||
:identifiers: uart_ops
|
||||
|
||||
Other functions
|
||||
---------------
|
||||
|
||||
uart_update_timeout(port,cflag,baud)
|
||||
Update the FIFO drain timeout, port->timeout, according to the
|
||||
number of bits, parity, stop bits and baud rate.
|
||||
|
||||
Locking: caller is expected to take port->lock
|
||||
|
||||
Interrupts: n/a
|
||||
|
||||
uart_get_baud_rate(port,termios,old,min,max)
|
||||
Return the numeric baud rate for the specified termios, taking
|
||||
account of the special 38400 baud "kludge". The B0 baud rate
|
||||
is mapped to 9600 baud.
|
||||
|
||||
If the baud rate is not within min..max, then if old is non-NULL,
|
||||
the original baud rate will be tried. If that exceeds the
|
||||
min..max constraint, 9600 baud will be returned. termios will
|
||||
be updated to the baud rate in use.
|
||||
|
||||
Note: min..max must always allow 9600 baud to be selected.
|
||||
|
||||
Locking: caller dependent.
|
||||
|
||||
Interrupts: n/a
|
||||
|
||||
uart_get_divisor(port,baud)
|
||||
Return the divisor (baud_base / baud) for the specified baud
|
||||
rate, appropriately rounded.
|
||||
|
||||
If 38400 baud and custom divisor is selected, return the
|
||||
custom divisor instead.
|
||||
|
||||
Locking: caller dependent.
|
||||
|
||||
Interrupts: n/a
|
||||
|
||||
uart_match_port(port1,port2)
|
||||
This utility function can be used to determine whether two
|
||||
uart_port structures describe the same port.
|
||||
|
||||
Locking: n/a
|
||||
|
||||
Interrupts: n/a
|
||||
|
||||
uart_write_wakeup(port)
|
||||
A driver is expected to call this function when the number of
|
||||
characters in the transmit buffer have dropped below a threshold.
|
||||
|
||||
Locking: port->lock should be held.
|
||||
|
||||
Interrupts: n/a
|
||||
|
||||
uart_register_driver(drv)
|
||||
Register a uart driver with the core driver. We in turn register
|
||||
with the tty layer, and initialise the core driver per-port state.
|
||||
|
||||
drv->port should be NULL, and the per-port structures should be
|
||||
registered using uart_add_one_port after this call has succeeded.
|
||||
|
||||
Locking: none
|
||||
|
||||
Interrupts: enabled
|
||||
|
||||
uart_unregister_driver()
|
||||
Remove all references to a driver from the core driver. The low
|
||||
level driver must have removed all its ports via the
|
||||
uart_remove_one_port() if it registered them with uart_add_one_port().
|
||||
|
||||
Locking: none
|
||||
|
||||
Interrupts: enabled
|
||||
|
||||
**uart_suspend_port()**
|
||||
|
||||
**uart_resume_port()**
|
||||
|
||||
**uart_add_one_port()**
|
||||
|
||||
**uart_remove_one_port()**
|
||||
.. kernel-doc:: drivers/tty/serial/serial_core.c
|
||||
:identifiers: uart_update_timeout uart_get_baud_rate uart_get_divisor
|
||||
uart_match_port uart_write_wakeup uart_register_driver
|
||||
uart_unregister_driver uart_suspend_port uart_resume_port
|
||||
uart_add_one_port uart_remove_one_port uart_console_write
|
||||
uart_parse_earlycon uart_parse_options uart_set_options
|
||||
uart_get_lsr_info uart_handle_dcd_change uart_handle_cts_change
|
||||
uart_try_toggle_sysrq uart_get_console
|
||||
|
||||
Other notes
|
||||
-----------
|
||||
@ -519,31 +97,7 @@ Modem control lines via GPIO
|
||||
|
||||
Some helpers are provided in order to set/get modem control lines via GPIO.
|
||||
|
||||
mctrl_gpio_init(port, idx):
|
||||
This will get the {cts,rts,...}-gpios from device tree if they are
|
||||
present and request them, set direction etc, and return an
|
||||
allocated structure. `devm_*` functions are used, so there's no need
|
||||
to call mctrl_gpio_free().
|
||||
As this sets up the irq handling make sure to not handle changes to the
|
||||
gpio input lines in your driver, too.
|
||||
|
||||
mctrl_gpio_free(dev, gpios):
|
||||
This will free the requested gpios in mctrl_gpio_init().
|
||||
As `devm_*` functions are used, there's generally no need to call
|
||||
this function.
|
||||
|
||||
mctrl_gpio_to_gpiod(gpios, gidx)
|
||||
This returns the gpio_desc structure associated to the modem line
|
||||
index.
|
||||
|
||||
mctrl_gpio_set(gpios, mctrl):
|
||||
This will sets the gpios according to the mctrl state.
|
||||
|
||||
mctrl_gpio_get(gpios, mctrl):
|
||||
This will update mctrl with the gpios values.
|
||||
|
||||
mctrl_gpio_enable_ms(gpios):
|
||||
Enables irqs and handling of changes to the ms lines.
|
||||
|
||||
mctrl_gpio_disable_ms(gpios):
|
||||
Disables irqs and handling of changes to the ms lines.
|
||||
.. kernel-doc:: drivers/tty/serial/serial_mctrl_gpio.c
|
||||
:identifiers: mctrl_gpio_init mctrl_gpio_free mctrl_gpio_to_gpiod
|
||||
mctrl_gpio_set mctrl_gpio_get mctrl_gpio_enable_ms
|
||||
mctrl_gpio_disable_ms
|
||||
|
@ -38,10 +38,14 @@ RS485 Serial Communications
|
||||
the values given by the device tree.
|
||||
|
||||
Any driver for devices capable of working both as RS232 and RS485 should
|
||||
implement the rs485_config callback in the uart_port structure. The
|
||||
serial_core calls rs485_config to do the device specific part in response
|
||||
to TIOCSRS485 and TIOCGRS485 ioctls (see below). The rs485_config callback
|
||||
receives a pointer to struct serial_rs485.
|
||||
implement the rs485_config callback and provide rs485_supported in the
|
||||
uart_port structure. The serial core calls rs485_config to do the device
|
||||
specific part in response to TIOCSRS485 ioctl (see below). The rs485_config
|
||||
callback receives a pointer to a sanitizated serial_rs485 structure. The
|
||||
serial_rs485 userspace provides is sanitized before calling rs485_config
|
||||
using rs485_supported that indicates what RS485 features the driver supports
|
||||
for the uart_port. TIOCGRS485 ioctl can be used to read back the
|
||||
serial_rs485 structure matching to the current configuration.
|
||||
|
||||
4. Usage from user-level
|
||||
========================
|
||||
@ -95,7 +99,31 @@ RS485 Serial Communications
|
||||
/* Error handling. See errno. */
|
||||
}
|
||||
|
||||
5. References
|
||||
5. Multipoint Addressing
|
||||
========================
|
||||
|
||||
The Linux kernel provides addressing mode for multipoint RS-485 serial
|
||||
communications line. The addressing mode is enabled with SER_RS485_ADDRB
|
||||
flag in serial_rs485. Struct serial_rs485 has two additional flags and
|
||||
fields for enabling receive and destination addresses.
|
||||
|
||||
Address mode flags:
|
||||
- SER_RS485_ADDRB: Enabled addressing mode (sets also ADDRB in termios).
|
||||
- SER_RS485_ADDR_RECV: Receive (filter) address enabled.
|
||||
- SER_RS485_ADDR_DEST: Set destination address.
|
||||
|
||||
Address fields (enabled with corresponding SER_RS485_ADDR_* flag):
|
||||
- addr_recv: Receive address.
|
||||
- addr_dest: Destination address.
|
||||
|
||||
Once a receive address is set, the communication can occur only with the
|
||||
particular device and other peers are filtered out. It is left up to the
|
||||
receiver side to enforce the filtering. Receive address will be cleared
|
||||
if SER_RS485_ADDR_RECV is not set.
|
||||
|
||||
Note: not all devices supporting RS485 support multipoint addressing.
|
||||
|
||||
6. References
|
||||
=============
|
||||
|
||||
[1] include/uapi/linux/serial.h
|
||||
|
@ -19622,8 +19622,9 @@ F: Documentation/devicetree/bindings/gpio/snps,creg-gpio.txt
|
||||
F: drivers/gpio/gpio-creg-snps.c
|
||||
|
||||
SYNOPSYS DESIGNWARE 8250 UART DRIVER
|
||||
M: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
|
||||
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
S: Maintained
|
||||
S: Supported
|
||||
F: drivers/tty/serial/8250/8250_dw.c
|
||||
F: drivers/tty/serial/8250/8250_dwlib.*
|
||||
F: drivers/tty/serial/8250/8250_lpss.c
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <asm/addrspace.h>
|
||||
#include <asm/setup.h>
|
||||
@ -18,38 +19,34 @@
|
||||
|
||||
static void (*_prom_putchar)(char);
|
||||
|
||||
static inline void prom_putchar_wait(void __iomem *reg, u32 mask, u32 val)
|
||||
static inline void prom_putchar_wait(void __iomem *reg, u32 val)
|
||||
{
|
||||
u32 t;
|
||||
|
||||
do {
|
||||
t = __raw_readl(reg);
|
||||
if ((t & mask) == val)
|
||||
if ((t & val) == val)
|
||||
break;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
static void prom_putchar_ar71xx(char ch)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)(KSEG1ADDR(AR71XX_UART_BASE));
|
||||
|
||||
prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY);
|
||||
prom_putchar_wait(base + UART_LSR * 4, UART_LSR_BOTH_EMPTY);
|
||||
__raw_writel((unsigned char)ch, base + UART_TX * 4);
|
||||
prom_putchar_wait(base + UART_LSR * 4, BOTH_EMPTY, BOTH_EMPTY);
|
||||
prom_putchar_wait(base + UART_LSR * 4, UART_LSR_BOTH_EMPTY);
|
||||
}
|
||||
|
||||
static void prom_putchar_ar933x(char ch)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)(KSEG1ADDR(AR933X_UART_BASE));
|
||||
|
||||
prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR,
|
||||
AR933X_UART_DATA_TX_CSR);
|
||||
prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR);
|
||||
__raw_writel(AR933X_UART_DATA_TX_CSR | (unsigned char)ch,
|
||||
base + AR933X_UART_DATA_REG);
|
||||
prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR,
|
||||
AR933X_UART_DATA_TX_CSR);
|
||||
prom_putchar_wait(base + AR933X_UART_DATA_REG, AR933X_UART_DATA_TX_CSR);
|
||||
}
|
||||
|
||||
static void prom_putchar_dummy(char ch)
|
||||
|
@ -131,7 +131,7 @@ static void vc_refresh(struct vc_data *vc)
|
||||
for (i = 0; i < WIDTH; i++) {
|
||||
u16 glyph = screen_glyph(vc,
|
||||
2 * (vc_x + i) + vc_y * vc->vc_size_row);
|
||||
buf[i] = inverse_translate(vc, glyph, 1);
|
||||
buf[i] = inverse_translate(vc, glyph, true);
|
||||
}
|
||||
braille_write(buf);
|
||||
}
|
||||
|
@ -470,7 +470,7 @@ static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
|
||||
c |= 0x100;
|
||||
}
|
||||
|
||||
ch = inverse_translate(vc, c, 1);
|
||||
ch = inverse_translate(vc, c, true);
|
||||
*attribs = (w & 0xff00) >> 8;
|
||||
}
|
||||
return ch;
|
||||
|
@ -33,9 +33,8 @@ struct old_serial_port {
|
||||
#define NUM_DISABLE_TIMEOUTS 3
|
||||
/* buffer timeout in ms */
|
||||
#define SPK_TIMEOUT 100
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
#define spk_serial_tx_busy() \
|
||||
((inb(speakup_info.port_tts + UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
|
||||
(!uart_lsr_tx_empty(inb(speakup_info.port_tts + UART_LSR)))
|
||||
|
||||
#endif
|
||||
|
@ -1024,6 +1024,7 @@ int __init early_init_dt_scan_chosen_stdout(void)
|
||||
int l;
|
||||
const struct earlycon_id *match;
|
||||
const void *fdt = initial_boot_params;
|
||||
int ret;
|
||||
|
||||
offset = fdt_path_offset(fdt, "/chosen");
|
||||
if (offset < 0)
|
||||
@ -1056,7 +1057,8 @@ int __init early_init_dt_scan_chosen_stdout(void)
|
||||
if (fdt_node_check_compatible(fdt, offset, match->compatible))
|
||||
continue;
|
||||
|
||||
if (of_setup_earlycon(match, offset, options) == 0)
|
||||
ret = of_setup_earlycon(match, offset, options);
|
||||
if (!ret || ret == -EALREADY)
|
||||
return 0;
|
||||
}
|
||||
return -ENODEV;
|
||||
|
@ -12,7 +12,7 @@
|
||||
* (non hardware specific) changes to serial.c.
|
||||
*
|
||||
* The port is registered with the tty driver as minor device 64, and
|
||||
* therefore other ports should should only use 65 upwards.
|
||||
* therefore other ports should only use 65 upwards.
|
||||
*
|
||||
* Richard Lucock 28/12/99
|
||||
*
|
||||
@ -51,6 +51,7 @@
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/slab.h>
|
||||
@ -283,12 +284,12 @@ static void transmit_chars(struct serial_state *info)
|
||||
|
||||
amiga_custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100;
|
||||
mb();
|
||||
info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1);
|
||||
info->xmit.tail = info->xmit.tail & (UART_XMIT_SIZE - 1);
|
||||
info->icount.tx++;
|
||||
|
||||
if (CIRC_CNT(info->xmit.head,
|
||||
info->xmit.tail,
|
||||
SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
|
||||
UART_XMIT_SIZE) < WAKEUP_CHARS)
|
||||
tty_wakeup(info->tport.tty);
|
||||
|
||||
#ifdef SERIAL_DEBUG_INTR
|
||||
@ -708,13 +709,13 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)
|
||||
local_irq_save(flags);
|
||||
if (CIRC_SPACE(info->xmit.head,
|
||||
info->xmit.tail,
|
||||
SERIAL_XMIT_SIZE) == 0) {
|
||||
UART_XMIT_SIZE) == 0) {
|
||||
local_irq_restore(flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
info->xmit.buf[info->xmit.head++] = ch;
|
||||
info->xmit.head &= SERIAL_XMIT_SIZE-1;
|
||||
info->xmit.head &= UART_XMIT_SIZE - 1;
|
||||
local_irq_restore(flags);
|
||||
return 1;
|
||||
}
|
||||
@ -753,15 +754,14 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
|
||||
while (1) {
|
||||
c = CIRC_SPACE_TO_END(info->xmit.head,
|
||||
info->xmit.tail,
|
||||
SERIAL_XMIT_SIZE);
|
||||
UART_XMIT_SIZE);
|
||||
if (count < c)
|
||||
c = count;
|
||||
if (c <= 0) {
|
||||
break;
|
||||
}
|
||||
memcpy(info->xmit.buf + info->xmit.head, buf, c);
|
||||
info->xmit.head = ((info->xmit.head + c) &
|
||||
(SERIAL_XMIT_SIZE-1));
|
||||
info->xmit.head = (info->xmit.head + c) & (UART_XMIT_SIZE - 1);
|
||||
buf += c;
|
||||
count -= c;
|
||||
ret += c;
|
||||
@ -788,14 +788,14 @@ static unsigned int rs_write_room(struct tty_struct *tty)
|
||||
{
|
||||
struct serial_state *info = tty->driver_data;
|
||||
|
||||
return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
|
||||
return CIRC_SPACE(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE);
|
||||
}
|
||||
|
||||
static unsigned int rs_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
struct serial_state *info = tty->driver_data;
|
||||
|
||||
return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
|
||||
return CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE);
|
||||
}
|
||||
|
||||
static void rs_flush_buffer(struct tty_struct *tty)
|
||||
|
@ -916,7 +916,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev)
|
||||
mips_ejtag_fdc_write(priv, REG_FDCFG, cfg);
|
||||
|
||||
/* Make each port's xmit FIFO big enough to fill FDC TX FIFO */
|
||||
priv->xmit_size = min(tx_fifo * 4, (unsigned int)SERIAL_XMIT_SIZE);
|
||||
priv->xmit_size = min(tx_fifo * 4, (unsigned int)UART_XMIT_SIZE);
|
||||
|
||||
driver = tty_alloc_driver(NUM_TTY_CHANNELS, TTY_DRIVER_REAL_RAW);
|
||||
if (IS_ERR(driver))
|
||||
@ -1222,7 +1222,7 @@ static void kgdbfdc_push_one(void)
|
||||
|
||||
/* Construct a word from any data in buffer */
|
||||
word = mips_ejtag_fdc_encode(bufs, &kgdbfdc_wbuflen, 1);
|
||||
/* Relocate any remaining data to beginnning of buffer */
|
||||
/* Relocate any remaining data to beginning of buffer */
|
||||
kgdbfdc_wbuflen -= word.bytes;
|
||||
for (i = 0; i < kgdbfdc_wbuflen; ++i)
|
||||
kgdbfdc_wbuf[i] = kgdbfdc_wbuf[i + word.bytes];
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -118,6 +118,9 @@ struct n_tty_data {
|
||||
size_t read_tail;
|
||||
size_t line_start;
|
||||
|
||||
/* # of chars looked ahead (to find software flow control chars) */
|
||||
size_t lookahead_count;
|
||||
|
||||
/* protected by output lock */
|
||||
unsigned int column;
|
||||
unsigned int canon_column;
|
||||
@ -333,6 +336,8 @@ static void reset_buffer_flags(struct n_tty_data *ldata)
|
||||
ldata->erasing = 0;
|
||||
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
|
||||
ldata->push = 0;
|
||||
|
||||
ldata->lookahead_count = 0;
|
||||
}
|
||||
|
||||
static void n_tty_packet_mode_flush(struct tty_struct *tty)
|
||||
@ -1225,12 +1230,30 @@ static bool n_tty_is_char_flow_ctrl(struct tty_struct *tty, unsigned char c)
|
||||
return c == START_CHAR(tty) || c == STOP_CHAR(tty);
|
||||
}
|
||||
|
||||
/* Returns true if c is consumed as flow-control character */
|
||||
static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c)
|
||||
/**
|
||||
* n_tty_receive_char_flow_ctrl - receive flow control chars
|
||||
* @tty: terminal device
|
||||
* @c: character
|
||||
* @lookahead_done: lookahead has processed this character already
|
||||
*
|
||||
* Receive and process flow control character actions.
|
||||
*
|
||||
* In case lookahead for flow control chars already handled the character in
|
||||
* advance to the normal receive, the actions are skipped during normal
|
||||
* receive.
|
||||
*
|
||||
* Returns true if @c is consumed as flow-control character, the character
|
||||
* must not be treated as normal character.
|
||||
*/
|
||||
static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c,
|
||||
bool lookahead_done)
|
||||
{
|
||||
if (!n_tty_is_char_flow_ctrl(tty, c))
|
||||
return false;
|
||||
|
||||
if (lookahead_done)
|
||||
return true;
|
||||
|
||||
if (c == START_CHAR(tty)) {
|
||||
start_tty(tty);
|
||||
process_echoes(tty);
|
||||
@ -1242,11 +1265,12 @@ static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c
|
||||
return true;
|
||||
}
|
||||
|
||||
static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
|
||||
static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c,
|
||||
bool lookahead_done)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
|
||||
if (I_IXON(tty) && n_tty_receive_char_flow_ctrl(tty, c))
|
||||
if (I_IXON(tty) && n_tty_receive_char_flow_ctrl(tty, c, lookahead_done))
|
||||
return;
|
||||
|
||||
if (L_ISIG(tty)) {
|
||||
@ -1401,7 +1425,8 @@ static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
|
||||
put_tty_queue(c, ldata);
|
||||
}
|
||||
|
||||
static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
|
||||
static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c,
|
||||
bool lookahead_done)
|
||||
{
|
||||
if (I_ISTRIP(tty))
|
||||
c &= 0x7f;
|
||||
@ -1409,12 +1434,10 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
|
||||
c = tolower(c);
|
||||
|
||||
if (I_IXON(tty)) {
|
||||
if (c == STOP_CHAR(tty))
|
||||
stop_tty(tty);
|
||||
else if (c == START_CHAR(tty) ||
|
||||
(tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) &&
|
||||
c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) &&
|
||||
c != SUSP_CHAR(tty))) {
|
||||
if (!n_tty_receive_char_flow_ctrl(tty, c, lookahead_done) &&
|
||||
tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) &&
|
||||
c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) &&
|
||||
c != SUSP_CHAR(tty)) {
|
||||
start_tty(tty);
|
||||
process_echoes(tty);
|
||||
}
|
||||
@ -1457,6 +1480,27 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
|
||||
n_tty_receive_char_flagged(tty, c, flag);
|
||||
}
|
||||
|
||||
/* Caller must ensure count > 0 */
|
||||
static void n_tty_lookahead_flow_ctrl(struct tty_struct *tty, const unsigned char *cp,
|
||||
const unsigned char *fp, unsigned int count)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
unsigned char flag = TTY_NORMAL;
|
||||
|
||||
ldata->lookahead_count += count;
|
||||
|
||||
if (!I_IXON(tty))
|
||||
return;
|
||||
|
||||
while (count--) {
|
||||
if (fp)
|
||||
flag = *fp++;
|
||||
if (likely(flag == TTY_NORMAL))
|
||||
n_tty_receive_char_flow_ctrl(tty, *cp, false);
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
|
||||
const char *fp, int count)
|
||||
@ -1496,7 +1540,7 @@ n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp,
|
||||
|
||||
static void
|
||||
n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
|
||||
const char *fp, int count)
|
||||
const char *fp, int count, bool lookahead_done)
|
||||
{
|
||||
char flag = TTY_NORMAL;
|
||||
|
||||
@ -1504,12 +1548,12 @@ n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
|
||||
if (fp)
|
||||
flag = *fp++;
|
||||
if (likely(flag == TTY_NORMAL))
|
||||
n_tty_receive_char_closing(tty, *cp++);
|
||||
n_tty_receive_char_closing(tty, *cp++, lookahead_done);
|
||||
}
|
||||
}
|
||||
|
||||
static void n_tty_receive_buf_standard(struct tty_struct *tty,
|
||||
const unsigned char *cp, const char *fp, int count)
|
||||
const unsigned char *cp, const char *fp, int count, bool lookahead_done)
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
char flag = TTY_NORMAL;
|
||||
@ -1540,7 +1584,7 @@ static void n_tty_receive_buf_standard(struct tty_struct *tty,
|
||||
}
|
||||
|
||||
if (test_bit(c, ldata->char_map))
|
||||
n_tty_receive_char_special(tty, c);
|
||||
n_tty_receive_char_special(tty, c, lookahead_done);
|
||||
else
|
||||
n_tty_receive_char(tty, c);
|
||||
}
|
||||
@ -1551,21 +1595,30 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
|
||||
{
|
||||
struct n_tty_data *ldata = tty->disc_data;
|
||||
bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
|
||||
size_t la_count = min_t(size_t, ldata->lookahead_count, count);
|
||||
|
||||
if (ldata->real_raw)
|
||||
n_tty_receive_buf_real_raw(tty, cp, fp, count);
|
||||
else if (ldata->raw || (L_EXTPROC(tty) && !preops))
|
||||
n_tty_receive_buf_raw(tty, cp, fp, count);
|
||||
else if (tty->closing && !L_EXTPROC(tty))
|
||||
n_tty_receive_buf_closing(tty, cp, fp, count);
|
||||
else {
|
||||
n_tty_receive_buf_standard(tty, cp, fp, count);
|
||||
else if (tty->closing && !L_EXTPROC(tty)) {
|
||||
if (la_count > 0)
|
||||
n_tty_receive_buf_closing(tty, cp, fp, la_count, true);
|
||||
if (count > la_count)
|
||||
n_tty_receive_buf_closing(tty, cp, fp, count - la_count, false);
|
||||
} else {
|
||||
if (la_count > 0)
|
||||
n_tty_receive_buf_standard(tty, cp, fp, la_count, true);
|
||||
if (count > la_count)
|
||||
n_tty_receive_buf_standard(tty, cp, fp, count - la_count, false);
|
||||
|
||||
flush_echoes(tty);
|
||||
if (tty->ops->flush_chars)
|
||||
tty->ops->flush_chars(tty);
|
||||
}
|
||||
|
||||
ldata->lookahead_count -= la_count;
|
||||
|
||||
if (ldata->icanon && !L_EXTPROC(tty))
|
||||
return;
|
||||
|
||||
@ -2446,6 +2499,7 @@ static struct tty_ldisc_ops n_tty_ops = {
|
||||
.receive_buf = n_tty_receive_buf,
|
||||
.write_wakeup = n_tty_write_wakeup,
|
||||
.receive_buf2 = n_tty_receive_buf2,
|
||||
.lookahead_buf = n_tty_lookahead_flow_ctrl,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -123,6 +123,26 @@ static inline void serial_out(struct uart_8250_port *up, int offset, int value)
|
||||
up->port.serial_out(&up->port, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* serial_lsr_in - Read LSR register and preserve flags across reads
|
||||
* @up: uart 8250 port
|
||||
*
|
||||
* Read LSR register and handle saving non-preserved flags across reads.
|
||||
* The flags that are not preserved across reads are stored into
|
||||
* up->lsr_saved_flags.
|
||||
*
|
||||
* Returns LSR value or'ed with the preserved flags (if any).
|
||||
*/
|
||||
static inline u16 serial_lsr_in(struct uart_8250_port *up)
|
||||
{
|
||||
u16 lsr = up->lsr_saved_flags;
|
||||
|
||||
lsr |= serial_in(up, UART_LSR);
|
||||
up->lsr_saved_flags = lsr & up->lsr_save_mask;
|
||||
|
||||
return lsr;
|
||||
}
|
||||
|
||||
/*
|
||||
* For the 16C950
|
||||
*/
|
||||
@ -183,10 +203,12 @@ void serial8250_rpm_put(struct uart_8250_port *p);
|
||||
void serial8250_rpm_get_tx(struct uart_8250_port *p);
|
||||
void serial8250_rpm_put_tx(struct uart_8250_port *p);
|
||||
|
||||
int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485);
|
||||
int serial8250_em485_config(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485);
|
||||
void serial8250_em485_start_tx(struct uart_8250_port *p);
|
||||
void serial8250_em485_stop_tx(struct uart_8250_port *p);
|
||||
void serial8250_em485_destroy(struct uart_8250_port *p);
|
||||
extern struct serial_rs485 serial8250_em485_supported;
|
||||
|
||||
/* MCR <-> TIOCM conversion */
|
||||
static inline int serial8250_TIOCM_to_MCR(int tiocm)
|
||||
|
@ -108,6 +108,7 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
||||
up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
|
||||
UPF_SKIP_TEST | UPF_IOREMAP;
|
||||
up.port.rs485_config = serial8250_em485_config;
|
||||
up.port.rs485_supported = serial8250_em485_supported;
|
||||
up.rs485_start_tx = bcm2835aux_rs485_start_tx;
|
||||
up.rs485_stop_tx = bcm2835aux_rs485_stop_tx;
|
||||
|
||||
@ -166,8 +167,10 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
|
||||
uartclk = clk_get_rate(data->clk);
|
||||
if (!uartclk) {
|
||||
ret = device_property_read_u32(&pdev->dev, "clock-frequency", &uartclk);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "could not get clk rate\n");
|
||||
if (ret) {
|
||||
dev_err_probe(&pdev->dev, ret, "could not get clk rate\n");
|
||||
goto dis_clk;
|
||||
}
|
||||
}
|
||||
|
||||
/* the HW-clock divider for bcm2835aux is 8,
|
||||
|
@ -1139,16 +1139,19 @@ static int __maybe_unused brcmuart_suspend(struct device *dev)
|
||||
struct brcmuart_priv *priv = dev_get_drvdata(dev);
|
||||
struct uart_8250_port *up = serial8250_get_port(priv->line);
|
||||
struct uart_port *port = &up->port;
|
||||
|
||||
serial8250_suspend_port(priv->line);
|
||||
clk_disable_unprepare(priv->baud_mux_clk);
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* This will prevent resume from enabling RTS before the
|
||||
* baud rate has been resored.
|
||||
* baud rate has been restored.
|
||||
*/
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
priv->saved_mctrl = port->mctrl;
|
||||
port->mctrl = 0;
|
||||
port->mctrl &= ~TIOCM_RTS;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
serial8250_suspend_port(priv->line);
|
||||
clk_disable_unprepare(priv->baud_mux_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1158,6 +1161,7 @@ static int __maybe_unused brcmuart_resume(struct device *dev)
|
||||
struct brcmuart_priv *priv = dev_get_drvdata(dev);
|
||||
struct uart_8250_port *up = serial8250_get_port(priv->line);
|
||||
struct uart_port *port = &up->port;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->baud_mux_clk);
|
||||
@ -1180,7 +1184,15 @@ static int __maybe_unused brcmuart_resume(struct device *dev)
|
||||
start_rx_dma(serial8250_get_port(priv->line));
|
||||
}
|
||||
serial8250_resume_port(priv->line);
|
||||
port->mctrl = priv->saved_mctrl;
|
||||
|
||||
if (priv->saved_mctrl & TIOCM_RTS) {
|
||||
/* Restore RTS */
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
port->mctrl |= TIOCM_RTS;
|
||||
port->ops->set_mctrl(port, port->mctrl);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -277,8 +277,7 @@ static void serial8250_backup_timeout(struct timer_list *t)
|
||||
* the "Diva" UART used on the management processor on many HP
|
||||
* ia64 and parisc boxes.
|
||||
*/
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
||||
lsr = serial_lsr_in(up);
|
||||
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
|
||||
(!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
|
||||
(lsr & UART_LSR_THRE)) {
|
||||
@ -1008,9 +1007,11 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
|
||||
uart->port.throttle = up->port.throttle;
|
||||
uart->port.unthrottle = up->port.unthrottle;
|
||||
uart->port.rs485_config = up->port.rs485_config;
|
||||
uart->port.rs485_supported = up->port.rs485_supported;
|
||||
uart->port.rs485 = up->port.rs485;
|
||||
uart->rs485_start_tx = up->rs485_start_tx;
|
||||
uart->rs485_stop_tx = up->rs485_stop_tx;
|
||||
uart->lsr_save_mask = up->lsr_save_mask;
|
||||
uart->dma = up->dma;
|
||||
|
||||
/* Take tx_loadsz from fifosize if it wasn't set separately */
|
||||
@ -1098,6 +1099,9 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!uart->lsr_save_mask)
|
||||
uart->lsr_save_mask = LSR_SAVE_FLAGS; /* Use default LSR mask */
|
||||
|
||||
/* Initialise interrupt backoff work if required */
|
||||
if (up->overrun_backoff_time_ms > 0) {
|
||||
uart->overrun_backoff_time_ms =
|
||||
|
@ -9,26 +9,27 @@
|
||||
* LCR is written whilst busy. If it is, then a busy detect interrupt is
|
||||
* raised, the LCR needs to be rewritten and the uart status register read.
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_reg.h>
|
||||
|
||||
#include "8250_dwlib.h"
|
||||
|
||||
/* Offsets for the DesignWare specific registers */
|
||||
@ -82,8 +83,21 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
|
||||
static void dw8250_force_idle(struct uart_port *p)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(p);
|
||||
unsigned int lsr;
|
||||
|
||||
serial8250_clear_and_reinit_fifos(up);
|
||||
|
||||
/*
|
||||
* With PSLVERR_RESP_EN parameter set to 1, the device generates an
|
||||
* error response when an attempt to read an empty RBR with FIFO
|
||||
* enabled.
|
||||
*/
|
||||
if (up->fcr & UART_FCR_ENABLE_FIFO) {
|
||||
lsr = p->serial_in(p, UART_LSR);
|
||||
if (!(lsr & UART_LSR_DR))
|
||||
return;
|
||||
}
|
||||
|
||||
(void)p->serial_in(p, UART_RX);
|
||||
}
|
||||
|
||||
@ -122,12 +136,15 @@ static void dw8250_check_lcr(struct uart_port *p, int value)
|
||||
/* Returns once the transmitter is empty or we run out of retries */
|
||||
static void dw8250_tx_wait_empty(struct uart_port *p)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(p);
|
||||
unsigned int tries = 20000;
|
||||
unsigned int delay_threshold = tries - 1000;
|
||||
unsigned int lsr;
|
||||
|
||||
while (tries--) {
|
||||
lsr = readb (p->membase + (UART_LSR << p->regshift));
|
||||
up->lsr_saved_flags |= lsr & up->lsr_save_mask;
|
||||
|
||||
if (lsr & UART_LSR_TEMT)
|
||||
break;
|
||||
|
||||
@ -140,21 +157,6 @@ static void dw8250_tx_wait_empty(struct uart_port *p)
|
||||
}
|
||||
}
|
||||
|
||||
static void dw8250_serial_out38x(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
|
||||
/* Allow the TX to drain before we reconfigure */
|
||||
if (offset == UART_LCR)
|
||||
dw8250_tx_wait_empty(p);
|
||||
|
||||
writeb(value, p->membase + (offset << p->regshift));
|
||||
|
||||
if (offset == UART_LCR && !d->uart_16550_compatible)
|
||||
dw8250_check_lcr(p, value);
|
||||
}
|
||||
|
||||
|
||||
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
struct dw8250_data *d = to_dw8250_data(p->private_data);
|
||||
@ -165,6 +167,15 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
|
||||
dw8250_check_lcr(p, value);
|
||||
}
|
||||
|
||||
static void dw8250_serial_out38x(struct uart_port *p, int offset, int value)
|
||||
{
|
||||
/* Allow the TX to drain before we reconfigure */
|
||||
if (offset == UART_LCR)
|
||||
dw8250_tx_wait_empty(p);
|
||||
|
||||
dw8250_serial_out(p, offset, value);
|
||||
}
|
||||
|
||||
static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
|
||||
{
|
||||
unsigned int value = readb(p->membase + (offset << p->regshift));
|
||||
@ -253,7 +264,7 @@ static int dw8250_handle_irq(struct uart_port *p)
|
||||
*/
|
||||
if (!up->dma && rx_timeout) {
|
||||
spin_lock_irqsave(&p->lock, flags);
|
||||
status = p->serial_in(p, UART_LSR);
|
||||
status = serial_lsr_in(up);
|
||||
|
||||
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
|
||||
(void) p->serial_in(p, UART_RX);
|
||||
@ -263,7 +274,10 @@ static int dw8250_handle_irq(struct uart_port *p)
|
||||
|
||||
/* Manually stop the Rx DMA transfer when acting as flow controller */
|
||||
if (quirks & DW_UART_QUIRK_IS_DMA_FC && up->dma && up->dma->rx_running && rx_timeout) {
|
||||
status = p->serial_in(p, UART_LSR);
|
||||
spin_lock_irqsave(&p->lock, flags);
|
||||
status = serial_lsr_in(up);
|
||||
spin_unlock_irqrestore(&p->lock, flags);
|
||||
|
||||
if (status & (UART_LSR_DR | UART_LSR_BI)) {
|
||||
dw8250_writel_ext(p, RZN1_UART_RDMACR, 0);
|
||||
dw8250_writel_ext(p, DW_UART_DMASA, 1);
|
||||
@ -688,7 +702,6 @@ static int dw8250_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int dw8250_suspend(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
@ -706,9 +719,7 @@ static int dw8250_resume(struct device *dev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int dw8250_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct dw8250_data *data = dev_get_drvdata(dev);
|
||||
@ -730,11 +741,10 @@ static int dw8250_runtime_resume(struct device *dev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops dw8250_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
|
||||
SET_RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume)
|
||||
RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct dw8250_platform_data dw8250_dw_apb = {
|
||||
@ -792,7 +802,7 @@ MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
|
||||
static struct platform_driver dw8250_platform_driver = {
|
||||
.driver = {
|
||||
.name = "dw-apb-uart",
|
||||
.pm = &dw8250_pm_ops,
|
||||
.pm = pm_ptr(&dw8250_pm_ops),
|
||||
.of_match_table = dw8250_of_match,
|
||||
.acpi_match_table = dw8250_acpi_match,
|
||||
},
|
||||
|
@ -3,8 +3,10 @@
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/serial_8250.h>
|
||||
#include <linux/serial_core.h>
|
||||
@ -16,9 +18,18 @@
|
||||
#define DW_UART_DE_EN 0xb0 /* Driver Output Enable Register */
|
||||
#define DW_UART_RE_EN 0xb4 /* Receiver Output Enable Register */
|
||||
#define DW_UART_DLF 0xc0 /* Divisor Latch Fraction Register */
|
||||
#define DW_UART_RAR 0xc4 /* Receive Address Register */
|
||||
#define DW_UART_TAR 0xc8 /* Transmit Address Register */
|
||||
#define DW_UART_LCR_EXT 0xcc /* Line Extended Control Register */
|
||||
#define DW_UART_CPR 0xf4 /* Component Parameter Register */
|
||||
#define DW_UART_UCV 0xf8 /* UART Component Version */
|
||||
|
||||
/* Receive / Transmit Address Register bits */
|
||||
#define DW_UART_ADDR_MASK GENMASK(7, 0)
|
||||
|
||||
/* Line Status Register bits */
|
||||
#define DW_UART_LSR_ADDR_RCVD BIT(8)
|
||||
|
||||
/* Transceiver Control Register bits */
|
||||
#define DW_UART_TCR_RS485_EN BIT(0)
|
||||
#define DW_UART_TCR_RE_POL BIT(1)
|
||||
@ -28,22 +39,28 @@
|
||||
#define DW_UART_TCR_XFER_MODE_SW_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 1)
|
||||
#define DW_UART_TCR_XFER_MODE_DE_OR_RE FIELD_PREP(DW_UART_TCR_XFER_MODE, 2)
|
||||
|
||||
/* Line Extended Control Register bits */
|
||||
#define DW_UART_LCR_EXT_DLS_E BIT(0)
|
||||
#define DW_UART_LCR_EXT_ADDR_MATCH BIT(1)
|
||||
#define DW_UART_LCR_EXT_SEND_ADDR BIT(2)
|
||||
#define DW_UART_LCR_EXT_TRANSMIT_MODE BIT(3)
|
||||
|
||||
/* Component Parameter Register bits */
|
||||
#define DW_UART_CPR_ABP_DATA_WIDTH (3 << 0)
|
||||
#define DW_UART_CPR_AFCE_MODE (1 << 4)
|
||||
#define DW_UART_CPR_THRE_MODE (1 << 5)
|
||||
#define DW_UART_CPR_SIR_MODE (1 << 6)
|
||||
#define DW_UART_CPR_SIR_LP_MODE (1 << 7)
|
||||
#define DW_UART_CPR_ADDITIONAL_FEATURES (1 << 8)
|
||||
#define DW_UART_CPR_FIFO_ACCESS (1 << 9)
|
||||
#define DW_UART_CPR_FIFO_STAT (1 << 10)
|
||||
#define DW_UART_CPR_SHADOW (1 << 11)
|
||||
#define DW_UART_CPR_ENCODED_PARMS (1 << 12)
|
||||
#define DW_UART_CPR_DMA_EXTRA (1 << 13)
|
||||
#define DW_UART_CPR_FIFO_MODE (0xff << 16)
|
||||
#define DW_UART_CPR_ABP_DATA_WIDTH GENMASK(1, 0)
|
||||
#define DW_UART_CPR_AFCE_MODE BIT(4)
|
||||
#define DW_UART_CPR_THRE_MODE BIT(5)
|
||||
#define DW_UART_CPR_SIR_MODE BIT(6)
|
||||
#define DW_UART_CPR_SIR_LP_MODE BIT(7)
|
||||
#define DW_UART_CPR_ADDITIONAL_FEATURES BIT(8)
|
||||
#define DW_UART_CPR_FIFO_ACCESS BIT(9)
|
||||
#define DW_UART_CPR_FIFO_STAT BIT(10)
|
||||
#define DW_UART_CPR_SHADOW BIT(11)
|
||||
#define DW_UART_CPR_ENCODED_PARMS BIT(12)
|
||||
#define DW_UART_CPR_DMA_EXTRA BIT(13)
|
||||
#define DW_UART_CPR_FIFO_MODE GENMASK(23, 16)
|
||||
|
||||
/* Helper for FIFO size calculation */
|
||||
#define DW_UART_CPR_FIFO_SIZE(a) (((a >> 16) & 0xff) * 16)
|
||||
#define DW_UART_CPR_FIFO_SIZE(a) (FIELD_GET(DW_UART_CPR_FIFO_MODE, (a)) * 16)
|
||||
|
||||
/*
|
||||
* divisor = div(I) + div(F)
|
||||
@ -82,10 +99,85 @@ void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct
|
||||
p->status |= UPSTAT_AUTOCTS;
|
||||
|
||||
serial8250_do_set_termios(p, termios, old);
|
||||
|
||||
/* Filter addresses which have 9th bit set */
|
||||
p->ignore_status_mask |= DW_UART_LSR_ADDR_RCVD;
|
||||
p->read_status_mask |= DW_UART_LSR_ADDR_RCVD;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw8250_do_set_termios);
|
||||
|
||||
static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485)
|
||||
/*
|
||||
* Wait until re is de-asserted for sure. An ongoing receive will keep
|
||||
* re asserted until end of frame. Without BUSY indication available,
|
||||
* only available course of action is to wait for the time it takes to
|
||||
* receive one frame (there might nothing to receive but w/o BUSY the
|
||||
* driver cannot know).
|
||||
*/
|
||||
static void dw8250_wait_re_deassert(struct uart_port *p)
|
||||
{
|
||||
ndelay(p->frame_time);
|
||||
}
|
||||
|
||||
static void dw8250_update_rar(struct uart_port *p, u32 addr)
|
||||
{
|
||||
u32 re_en = dw8250_readl_ext(p, DW_UART_RE_EN);
|
||||
|
||||
/*
|
||||
* RAR shouldn't be changed while receiving. Thus, de-assert RE_EN
|
||||
* if asserted and wait.
|
||||
*/
|
||||
if (re_en)
|
||||
dw8250_writel_ext(p, DW_UART_RE_EN, 0);
|
||||
dw8250_wait_re_deassert(p);
|
||||
dw8250_writel_ext(p, DW_UART_RAR, addr);
|
||||
if (re_en)
|
||||
dw8250_writel_ext(p, DW_UART_RE_EN, re_en);
|
||||
}
|
||||
|
||||
static void dw8250_rs485_set_addr(struct uart_port *p, struct serial_rs485 *rs485,
|
||||
struct ktermios *termios)
|
||||
{
|
||||
u32 lcr = dw8250_readl_ext(p, DW_UART_LCR_EXT);
|
||||
|
||||
if (rs485->flags & SER_RS485_ADDRB) {
|
||||
lcr |= DW_UART_LCR_EXT_DLS_E;
|
||||
if (termios)
|
||||
termios->c_cflag |= ADDRB;
|
||||
|
||||
if (rs485->flags & SER_RS485_ADDR_RECV) {
|
||||
u32 delta = p->rs485.flags ^ rs485->flags;
|
||||
|
||||
/*
|
||||
* rs485 (param) is equal to uart_port's rs485 only during init
|
||||
* (during init, delta is not yet applicable).
|
||||
*/
|
||||
if (unlikely(&p->rs485 == rs485))
|
||||
delta = rs485->flags;
|
||||
|
||||
if ((delta & SER_RS485_ADDR_RECV) ||
|
||||
(p->rs485.addr_recv != rs485->addr_recv))
|
||||
dw8250_update_rar(p, rs485->addr_recv);
|
||||
lcr |= DW_UART_LCR_EXT_ADDR_MATCH;
|
||||
} else {
|
||||
lcr &= ~DW_UART_LCR_EXT_ADDR_MATCH;
|
||||
}
|
||||
if (rs485->flags & SER_RS485_ADDR_DEST) {
|
||||
/*
|
||||
* Don't skip writes here as another endpoint could
|
||||
* have changed communication line's destination
|
||||
* address in between.
|
||||
*/
|
||||
dw8250_writel_ext(p, DW_UART_TAR, rs485->addr_dest);
|
||||
lcr |= DW_UART_LCR_EXT_SEND_ADDR;
|
||||
}
|
||||
} else {
|
||||
lcr = 0;
|
||||
}
|
||||
dw8250_writel_ext(p, DW_UART_LCR_EXT, lcr);
|
||||
}
|
||||
|
||||
static int dw8250_rs485_config(struct uart_port *p, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
u32 tcr;
|
||||
|
||||
@ -93,25 +185,17 @@ static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485)
|
||||
tcr &= ~DW_UART_TCR_XFER_MODE;
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
/* Clear unsupported flags. */
|
||||
rs485->flags &= SER_RS485_ENABLED | SER_RS485_RX_DURING_TX |
|
||||
SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND;
|
||||
tcr |= DW_UART_TCR_RS485_EN;
|
||||
|
||||
if (rs485->flags & SER_RS485_RX_DURING_TX) {
|
||||
if (rs485->flags & SER_RS485_RX_DURING_TX)
|
||||
tcr |= DW_UART_TCR_XFER_MODE_DE_DURING_RE;
|
||||
} else {
|
||||
/* HW does not support same DE level for tx and rx */
|
||||
if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
|
||||
!(rs485->flags & SER_RS485_RTS_AFTER_SEND))
|
||||
return -EINVAL;
|
||||
|
||||
else
|
||||
tcr |= DW_UART_TCR_XFER_MODE_DE_OR_RE;
|
||||
}
|
||||
dw8250_writel_ext(p, DW_UART_DE_EN, 1);
|
||||
dw8250_writel_ext(p, DW_UART_RE_EN, 1);
|
||||
} else {
|
||||
rs485->flags = 0;
|
||||
if (termios)
|
||||
termios->c_cflag &= ~ADDRB;
|
||||
|
||||
tcr &= ~DW_UART_TCR_RS485_EN;
|
||||
}
|
||||
@ -127,10 +211,9 @@ static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485)
|
||||
|
||||
dw8250_writel_ext(p, DW_UART_TCR, tcr);
|
||||
|
||||
rs485->delay_rts_before_send = 0;
|
||||
rs485->delay_rts_after_send = 0;
|
||||
|
||||
p->rs485 = *rs485;
|
||||
/* Addressing mode can only be set up after TCR */
|
||||
if (rs485->flags & SER_RS485_ENABLED)
|
||||
dw8250_rs485_set_addr(p, rs485, termios);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -149,6 +232,12 @@ static bool dw8250_detect_rs485_hw(struct uart_port *p)
|
||||
return reg;
|
||||
}
|
||||
|
||||
static const struct serial_rs485 dw8250_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_RTS_ON_SEND |
|
||||
SER_RS485_RTS_AFTER_SEND | SER_RS485_ADDRB | SER_RS485_ADDR_RECV |
|
||||
SER_RS485_ADDR_DEST,
|
||||
};
|
||||
|
||||
void dw8250_setup_port(struct uart_port *p)
|
||||
{
|
||||
struct dw8250_port_data *pd = p->private_data;
|
||||
@ -159,8 +248,11 @@ void dw8250_setup_port(struct uart_port *p)
|
||||
pd->hw_rs485_support = dw8250_detect_rs485_hw(p);
|
||||
if (pd->hw_rs485_support) {
|
||||
p->rs485_config = dw8250_rs485_config;
|
||||
up->lsr_save_mask = LSR_SAVE_FLAGS | DW_UART_LSR_ADDR_RCVD;
|
||||
p->rs485_supported = dw8250_rs485_supported;
|
||||
} else {
|
||||
p->rs485_config = serial8250_em485_config;
|
||||
p->rs485_supported = serial8250_em485_supported;
|
||||
up->rs485_start_tx = serial8250_em485_start_tx;
|
||||
up->rs485_stop_tx = serial8250_em485_stop_tx;
|
||||
}
|
||||
|
@ -84,8 +84,6 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value)
|
||||
}
|
||||
}
|
||||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
static void serial_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
unsigned int status;
|
||||
@ -94,7 +92,7 @@ static void serial_putc(struct uart_port *port, unsigned char c)
|
||||
|
||||
for (;;) {
|
||||
status = serial8250_early_in(port, UART_LSR);
|
||||
if ((status & BOTH_EMPTY) == BOTH_EMPTY)
|
||||
if (uart_lsr_tx_empty(status))
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
|
@ -112,7 +112,9 @@
|
||||
struct exar8250;
|
||||
|
||||
struct exar8250_platform {
|
||||
int (*rs485_config)(struct uart_port *, struct serial_rs485 *);
|
||||
int (*rs485_config)(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485);
|
||||
const struct serial_rs485 *rs485_supported;
|
||||
int (*register_gpio)(struct pci_dev *, struct uart_8250_port *);
|
||||
void (*unregister_gpio)(struct uart_8250_port *);
|
||||
};
|
||||
@ -194,11 +196,11 @@ static int xr17v35x_startup(struct uart_port *port)
|
||||
|
||||
static void exar_shutdown(struct uart_port *port)
|
||||
{
|
||||
unsigned char lsr;
|
||||
bool tx_complete = false;
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
int i = 0;
|
||||
u16 lsr;
|
||||
|
||||
do {
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
@ -408,7 +410,7 @@ static void xr17v35x_unregister_gpio(struct uart_8250_port *port)
|
||||
port->port.private_data = NULL;
|
||||
}
|
||||
|
||||
static int generic_rs485_config(struct uart_port *port,
|
||||
static int generic_rs485_config(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
|
||||
@ -426,18 +428,21 @@ static int generic_rs485_config(struct uart_port *port,
|
||||
if (is_rs485)
|
||||
writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR);
|
||||
|
||||
port->rs485 = *rs485;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct serial_rs485 generic_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED,
|
||||
};
|
||||
|
||||
static const struct exar8250_platform exar8250_default_platform = {
|
||||
.register_gpio = xr17v35x_register_gpio,
|
||||
.unregister_gpio = xr17v35x_unregister_gpio,
|
||||
.rs485_config = generic_rs485_config,
|
||||
.rs485_supported = &generic_rs485_supported,
|
||||
};
|
||||
|
||||
static int iot2040_rs485_config(struct uart_port *port,
|
||||
static int iot2040_rs485_config(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
|
||||
@ -467,9 +472,13 @@ static int iot2040_rs485_config(struct uart_port *port,
|
||||
value |= mode;
|
||||
writeb(value, p + UART_EXAR_MPIOLVL_7_0);
|
||||
|
||||
return generic_rs485_config(port, rs485);
|
||||
return generic_rs485_config(port, termios, rs485);
|
||||
}
|
||||
|
||||
static const struct serial_rs485 iot2040_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_TERMINATE_BUS,
|
||||
};
|
||||
|
||||
static const struct property_entry iot2040_gpio_properties[] = {
|
||||
PROPERTY_ENTRY_U32("exar,first-pin", 10),
|
||||
PROPERTY_ENTRY_U32("ngpios", 1),
|
||||
@ -498,6 +507,7 @@ static int iot2040_register_gpio(struct pci_dev *pcidev,
|
||||
|
||||
static const struct exar8250_platform iot2040_platform = {
|
||||
.rs485_config = iot2040_rs485_config,
|
||||
.rs485_supported = &iot2040_rs485_supported,
|
||||
.register_gpio = iot2040_register_gpio,
|
||||
.unregister_gpio = xr17v35x_unregister_gpio,
|
||||
};
|
||||
@ -540,6 +550,7 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,
|
||||
|
||||
port->port.uartclk = baud * 16;
|
||||
port->port.rs485_config = platform->rs485_config;
|
||||
port->port.rs485_supported = *(platform->rs485_supported);
|
||||
|
||||
/*
|
||||
* Setup the UART clock for the devices on expansion slot to
|
||||
|
@ -191,7 +191,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int fintek_8250_rs485_config(struct uart_port *port,
|
||||
static int fintek_8250_rs485_config(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
uint8_t config = 0;
|
||||
@ -206,19 +206,7 @@ static int fintek_8250_rs485_config(struct uart_port *port,
|
||||
if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
|
||||
!(rs485->flags & SER_RS485_RTS_AFTER_SEND))
|
||||
return -EINVAL;
|
||||
memset(rs485->padding, 0, sizeof(rs485->padding));
|
||||
config |= RS485_URA;
|
||||
} else {
|
||||
memset(rs485, 0, sizeof(*rs485));
|
||||
}
|
||||
|
||||
rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
|
||||
SER_RS485_RTS_AFTER_SEND;
|
||||
|
||||
/* Only the first port supports delays */
|
||||
if (pdata->index) {
|
||||
rs485->delay_rts_before_send = 0;
|
||||
rs485->delay_rts_after_send = 0;
|
||||
}
|
||||
|
||||
if (rs485->delay_rts_before_send) {
|
||||
@ -241,8 +229,6 @@ static int fintek_8250_rs485_config(struct uart_port *port,
|
||||
sio_write_reg(pdata, RS485, config);
|
||||
fintek_8250_exit_key(pdata->base_port);
|
||||
|
||||
port->rs485 = *rs485;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -424,6 +410,17 @@ static int probe_setup_port(struct fintek_8250 *pdata,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Only the first port supports delays */
|
||||
static const struct serial_rs485 fintek_8250_rs485_supported_port0 = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
|
||||
.delay_rts_before_send = 1,
|
||||
.delay_rts_after_send = 1,
|
||||
};
|
||||
|
||||
static const struct serial_rs485 fintek_8250_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
|
||||
};
|
||||
|
||||
static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart)
|
||||
{
|
||||
struct fintek_8250 *pdata = uart->port.private_data;
|
||||
@ -435,6 +432,10 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart)
|
||||
case CHIP_ID_F81866:
|
||||
case CHIP_ID_F81865:
|
||||
uart->port.rs485_config = fintek_8250_rs485_config;
|
||||
if (!pdata->index)
|
||||
uart->port.rs485_supported = fintek_8250_rs485_supported_port0;
|
||||
else
|
||||
uart->port.rs485_supported = fintek_8250_rs485_supported;
|
||||
break;
|
||||
|
||||
default: /* No RS485 Auto direction functional */
|
||||
|
@ -25,8 +25,8 @@
|
||||
|
||||
int fsl8250_handle_irq(struct uart_port *port)
|
||||
{
|
||||
unsigned char lsr, orig_lsr;
|
||||
unsigned long flags;
|
||||
u16 lsr, orig_lsr;
|
||||
unsigned int iir;
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
@ -77,7 +77,7 @@ int fsl8250_handle_irq(struct uart_port *port)
|
||||
if ((lsr & UART_LSR_THRE) && (up->ier & UART_IER_THRI))
|
||||
serial8250_tx_chars(up);
|
||||
|
||||
up->lsr_saved_flags = orig_lsr;
|
||||
up->lsr_saved_flags |= orig_lsr & UART_LSR_BI;
|
||||
|
||||
uart_unlock_and_check_sysrq_irqrestore(&up->port, flags);
|
||||
|
||||
|
@ -54,7 +54,7 @@ static void early_out(struct uart_port *port, int offset, uint8_t value)
|
||||
|
||||
static void ingenic_early_console_putc(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
uint8_t lsr;
|
||||
u16 lsr;
|
||||
|
||||
do {
|
||||
lsr = early_in(port, UART_LSR);
|
||||
|
@ -32,7 +32,7 @@ struct lpc18xx_uart_data {
|
||||
int line;
|
||||
};
|
||||
|
||||
static int lpc18xx_rs485_config(struct uart_port *port,
|
||||
static int lpc18xx_rs485_config(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
@ -40,24 +40,12 @@ static int lpc18xx_rs485_config(struct uart_port *port,
|
||||
u32 rs485_dly_reg = 0;
|
||||
unsigned baud_clk;
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED)
|
||||
memset(rs485->padding, 0, sizeof(rs485->padding));
|
||||
else
|
||||
memset(rs485, 0, sizeof(*rs485));
|
||||
|
||||
rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
|
||||
SER_RS485_RTS_AFTER_SEND;
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN |
|
||||
LPC18XX_UART_RS485CTRL_DCTRL;
|
||||
|
||||
if (rs485->flags & SER_RS485_RTS_ON_SEND) {
|
||||
if (rs485->flags & SER_RS485_RTS_ON_SEND)
|
||||
rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV;
|
||||
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
|
||||
} else {
|
||||
rs485->flags |= SER_RS485_RTS_AFTER_SEND;
|
||||
}
|
||||
}
|
||||
|
||||
if (rs485->delay_rts_after_send) {
|
||||
@ -73,14 +61,9 @@ static int lpc18xx_rs485_config(struct uart_port *port,
|
||||
/ baud_clk;
|
||||
}
|
||||
|
||||
/* Delay RTS before send not supported */
|
||||
rs485->delay_rts_before_send = 0;
|
||||
|
||||
serial_out(up, LPC18XX_UART_RS485CTRL, rs485_ctrl_reg);
|
||||
serial_out(up, LPC18XX_UART_RS485DLY, rs485_dly_reg);
|
||||
|
||||
port->rs485 = *rs485;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -98,6 +81,12 @@ static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value)
|
||||
writel(value, p->membase + offset);
|
||||
}
|
||||
|
||||
static const struct serial_rs485 lpc18xx_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
|
||||
.delay_rts_after_send = 1,
|
||||
/* Delay RTS before send is not supported */
|
||||
};
|
||||
|
||||
static int lpc18xx_serial_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct lpc18xx_uart_data *data;
|
||||
@ -168,6 +157,7 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
|
||||
uart.port.uartclk = clk_get_rate(data->clk_uart);
|
||||
uart.port.private_data = data;
|
||||
uart.port.rs485_config = lpc18xx_rs485_config;
|
||||
uart.port.rs485_supported = lpc18xx_rs485_supported;
|
||||
uart.port.serial_out = lpc18xx_uart_serial_out;
|
||||
|
||||
uart.dma = &data->dma;
|
||||
|
@ -330,7 +330,7 @@ static int lpss8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
uart.port.irq = pci_irq_vector(pdev, 0);
|
||||
uart.port.private_data = &lpss->data;
|
||||
uart.port.type = PORT_16550A;
|
||||
uart.port.iotype = UPIO_MEM;
|
||||
uart.port.iotype = UPIO_MEM32;
|
||||
uart.port.regshift = 2;
|
||||
uart.port.uartclk = lpss->board->base_baud * 16;
|
||||
uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
|
||||
|
@ -165,6 +165,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
|
||||
|
||||
port->dev = &ofdev->dev;
|
||||
port->rs485_config = serial8250_em485_config;
|
||||
port->rs485_supported = serial8250_em485_supported;
|
||||
up->rs485_start_tx = serial8250_em485_start_tx;
|
||||
up->rs485_stop_tx = serial8250_em485_stop_tx;
|
||||
|
||||
|
@ -1115,8 +1115,7 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
|
||||
return omap_8250_rx_dma(up);
|
||||
}
|
||||
|
||||
static unsigned char omap_8250_handle_rx_dma(struct uart_8250_port *up,
|
||||
u8 iir, unsigned char status)
|
||||
static u16 omap_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, u16 status)
|
||||
{
|
||||
if ((status & (UART_LSR_DR | UART_LSR_BI)) &&
|
||||
(iir & UART_IIR_RDI)) {
|
||||
@ -1130,7 +1129,7 @@ static unsigned char omap_8250_handle_rx_dma(struct uart_8250_port *up,
|
||||
}
|
||||
|
||||
static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
|
||||
unsigned char status)
|
||||
u16 status)
|
||||
{
|
||||
/*
|
||||
* Queue a new transfer if FIFO has data.
|
||||
@ -1164,7 +1163,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct omap8250_priv *priv = up->port.private_data;
|
||||
unsigned char status;
|
||||
u16 status;
|
||||
u8 iir;
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
|
@ -1553,7 +1553,7 @@ pci_brcm_trumanage_setup(struct serial_private *priv,
|
||||
#define FINTEK_RTS_INVERT BIT(5)
|
||||
|
||||
/* We should do proper H/W transceiver setting before change to RS485 mode */
|
||||
static int pci_fintek_rs485_config(struct uart_port *port,
|
||||
static int pci_fintek_rs485_config(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct pci_dev *pci_dev = to_pci_dev(port->dev);
|
||||
@ -1562,16 +1562,6 @@ static int pci_fintek_rs485_config(struct uart_port *port,
|
||||
|
||||
pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting);
|
||||
|
||||
if (!rs485)
|
||||
rs485 = &port->rs485;
|
||||
else if (rs485->flags & SER_RS485_ENABLED)
|
||||
memset(rs485->padding, 0, sizeof(rs485->padding));
|
||||
else
|
||||
memset(rs485, 0, sizeof(*rs485));
|
||||
|
||||
/* F81504/508/512 not support RTS delay before or after send */
|
||||
rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
/* Enable RTS H/W control mode */
|
||||
setting |= FINTEK_RTS_CONTROL_BY_HW;
|
||||
@ -1583,9 +1573,6 @@ static int pci_fintek_rs485_config(struct uart_port *port,
|
||||
/* RTS driving low on TX */
|
||||
setting |= FINTEK_RTS_INVERT;
|
||||
}
|
||||
|
||||
rs485->delay_rts_after_send = 0;
|
||||
rs485->delay_rts_before_send = 0;
|
||||
} else {
|
||||
/* Disable RTS H/W control mode */
|
||||
setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT);
|
||||
@ -1593,12 +1580,14 @@ static int pci_fintek_rs485_config(struct uart_port *port,
|
||||
|
||||
pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting);
|
||||
|
||||
if (rs485 != &port->rs485)
|
||||
port->rs485 = *rs485;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct serial_rs485 pci_fintek_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
|
||||
/* F81504/508/512 does not support RTS delay before or after send */
|
||||
};
|
||||
|
||||
static int pci_fintek_setup(struct serial_private *priv,
|
||||
const struct pciserial_board *board,
|
||||
struct uart_8250_port *port, int idx)
|
||||
@ -1618,6 +1607,7 @@ static int pci_fintek_setup(struct serial_private *priv,
|
||||
port->port.iotype = UPIO_PORT;
|
||||
port->port.iobase = iobase;
|
||||
port->port.rs485_config = pci_fintek_rs485_config;
|
||||
port->port.rs485_supported = pci_fintek_rs485_supported;
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(u8), GFP_KERNEL);
|
||||
if (!data)
|
||||
@ -1689,7 +1679,7 @@ static int pci_fintek_init(struct pci_dev *dev)
|
||||
* pciserial_resume_ports()
|
||||
*/
|
||||
port = serial8250_get_port(priv->line[i]);
|
||||
pci_fintek_rs485_config(&port->port, NULL);
|
||||
uart_rs485_config(&port->port);
|
||||
} else {
|
||||
/* First init without port data
|
||||
* force init to RS232 Mode
|
||||
@ -5076,6 +5066,115 @@ static const struct pci_device_id serial_pci_tbl[] = {
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_b2_4_115200 },
|
||||
/*
|
||||
* Brainboxes PX-101
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4005,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_b0_2_115200 },
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4019,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_2_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-235/246
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4004,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_b0_1_115200 },
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4016,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_1_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-203/PX-257
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4006,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_b0_2_115200 },
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4015,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_4_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-260/PX-701
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x400A,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_4_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-310
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x400E,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_2_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-313
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x400C,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_2_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-320/324/PX-376/PX-387
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x400B,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_1_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-335/346
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x400F,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_4_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-368
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4010,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_4_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-420
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4000,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_b0_4_115200 },
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4011,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_4_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-803
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4009,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_b0_1_115200 },
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x401E,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_1_15625000 },
|
||||
/*
|
||||
* Brainboxes PX-846
|
||||
*/
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4008,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_b0_1_115200 },
|
||||
{ PCI_VENDOR_ID_INTASHIELD, 0x4017,
|
||||
PCI_ANY_ID, PCI_ANY_ID,
|
||||
0, 0,
|
||||
pbn_oxsemi_1_15625000 },
|
||||
|
||||
/*
|
||||
* Perle PCI-RAS cards
|
||||
*/
|
||||
|
@ -73,7 +73,7 @@ static void pericom_do_set_divisor(struct uart_port *port, unsigned int baud,
|
||||
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_port_out(port, UART_LCR, lcr | UART_LCR_DLAB);
|
||||
serial_dl_write(up, divisor);
|
||||
serial_port_out(port, 2, 16 - scr);
|
||||
serial_port_out(port, UART_LCR, lcr);
|
||||
|
@ -50,8 +50,6 @@
|
||||
#define DEBUG_AUTOCONF(fmt...) do { } while (0)
|
||||
#endif
|
||||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
/*
|
||||
* Here we define the default xmit fifo size used for each type of UART.
|
||||
*/
|
||||
@ -336,27 +334,29 @@ static void default_serial_dl_write(struct uart_8250_port *up, int value)
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_RT288X
|
||||
|
||||
#define UART_REG_UNMAPPED -1
|
||||
|
||||
/* Au1x00/RT288x UART hardware has a weird register layout */
|
||||
static const s8 au_io_in_map[8] = {
|
||||
0, /* UART_RX */
|
||||
2, /* UART_IER */
|
||||
3, /* UART_IIR */
|
||||
5, /* UART_LCR */
|
||||
6, /* UART_MCR */
|
||||
7, /* UART_LSR */
|
||||
8, /* UART_MSR */
|
||||
-1, /* UART_SCR (unmapped) */
|
||||
[UART_RX] = 0,
|
||||
[UART_IER] = 2,
|
||||
[UART_IIR] = 3,
|
||||
[UART_LCR] = 5,
|
||||
[UART_MCR] = 6,
|
||||
[UART_LSR] = 7,
|
||||
[UART_MSR] = 8,
|
||||
[UART_SCR] = UART_REG_UNMAPPED,
|
||||
};
|
||||
|
||||
static const s8 au_io_out_map[8] = {
|
||||
1, /* UART_TX */
|
||||
2, /* UART_IER */
|
||||
4, /* UART_FCR */
|
||||
5, /* UART_LCR */
|
||||
6, /* UART_MCR */
|
||||
-1, /* UART_LSR (unmapped) */
|
||||
-1, /* UART_MSR (unmapped) */
|
||||
-1, /* UART_SCR (unmapped) */
|
||||
[UART_TX] = 1,
|
||||
[UART_IER] = 2,
|
||||
[UART_FCR] = 4,
|
||||
[UART_LCR] = 5,
|
||||
[UART_MCR] = 6,
|
||||
[UART_LSR] = UART_REG_UNMAPPED,
|
||||
[UART_MSR] = UART_REG_UNMAPPED,
|
||||
[UART_SCR] = UART_REG_UNMAPPED,
|
||||
};
|
||||
|
||||
unsigned int au_serial_in(struct uart_port *p, int offset)
|
||||
@ -364,7 +364,7 @@ unsigned int au_serial_in(struct uart_port *p, int offset)
|
||||
if (offset >= ARRAY_SIZE(au_io_in_map))
|
||||
return UINT_MAX;
|
||||
offset = au_io_in_map[offset];
|
||||
if (offset < 0)
|
||||
if (offset == UART_REG_UNMAPPED)
|
||||
return UINT_MAX;
|
||||
return __raw_readl(p->membase + (offset << p->regshift));
|
||||
}
|
||||
@ -374,7 +374,7 @@ void au_serial_out(struct uart_port *p, int offset, int value)
|
||||
if (offset >= ARRAY_SIZE(au_io_out_map))
|
||||
return;
|
||||
offset = au_io_out_map[offset];
|
||||
if (offset < 0)
|
||||
if (offset == UART_REG_UNMAPPED)
|
||||
return;
|
||||
__raw_writel(value, p->membase + (offset << p->regshift));
|
||||
}
|
||||
@ -647,6 +647,14 @@ void serial8250_em485_destroy(struct uart_8250_port *p)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
|
||||
|
||||
struct serial_rs485 serial8250_em485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
|
||||
SER_RS485_TERMINATE_BUS | SER_RS485_RX_DURING_TX,
|
||||
.delay_rts_before_send = 1,
|
||||
.delay_rts_after_send = 1,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(serial8250_em485_supported);
|
||||
|
||||
/**
|
||||
* serial8250_em485_config() - generic ->rs485_config() callback
|
||||
* @port: uart port
|
||||
@ -656,7 +664,8 @@ EXPORT_SYMBOL_GPL(serial8250_em485_destroy);
|
||||
* if the uart is incapable of driving RTS as a Transmit Enable signal in
|
||||
* hardware, relying on software emulation instead.
|
||||
*/
|
||||
int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
int serial8250_em485_config(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
|
||||
@ -667,29 +676,12 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
|
||||
}
|
||||
|
||||
/* clamp the delays to [0, 100ms] */
|
||||
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
|
||||
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
|
||||
|
||||
memset(rs485->padding, 0, sizeof(rs485->padding));
|
||||
port->rs485 = *rs485;
|
||||
|
||||
gpiod_set_value(port->rs485_term_gpio,
|
||||
rs485->flags & SER_RS485_TERMINATE_BUS);
|
||||
|
||||
/*
|
||||
* Both serial8250_em485_init() and serial8250_em485_destroy()
|
||||
* are idempotent.
|
||||
*/
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
int ret = serial8250_em485_init(up);
|
||||
|
||||
if (ret) {
|
||||
rs485->flags &= ~SER_RS485_ENABLED;
|
||||
port->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
if (rs485->flags & SER_RS485_ENABLED)
|
||||
return serial8250_em485_init(up);
|
||||
|
||||
serial8250_em485_destroy(up);
|
||||
return 0;
|
||||
@ -849,7 +841,7 @@ static int size_fifo(struct uart_8250_port *up)
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
|
||||
old_dl = serial_dl_read(up);
|
||||
serial_dl_write(up, 0x0001);
|
||||
serial_out(up, UART_LCR, 0x03);
|
||||
serial_out(up, UART_LCR, UART_LCR_WLEN8);
|
||||
for (count = 0; count < 256; count++)
|
||||
serial_out(up, UART_TX, count);
|
||||
mdelay(20);/* FIXME - schedule_timeout */
|
||||
@ -1503,18 +1495,12 @@ static void __stop_tx_rs485(struct uart_8250_port *p, u64 stop_delay)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void __do_stop_tx(struct uart_8250_port *p)
|
||||
{
|
||||
if (serial8250_clear_THRI(p))
|
||||
serial8250_rpm_put_tx(p);
|
||||
}
|
||||
|
||||
static inline void __stop_tx(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_em485 *em485 = p->em485;
|
||||
|
||||
if (em485) {
|
||||
unsigned char lsr = serial_in(p, UART_LSR);
|
||||
u16 lsr = serial_lsr_in(p);
|
||||
u64 stop_delay = 0;
|
||||
|
||||
p->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
||||
@ -1522,7 +1508,7 @@ static inline void __stop_tx(struct uart_8250_port *p)
|
||||
if (!(lsr & UART_LSR_THRE))
|
||||
return;
|
||||
/*
|
||||
* To provide required timeing and allow FIFO transfer,
|
||||
* To provide required timing and allow FIFO transfer,
|
||||
* __stop_tx_rs485() must be called only when both FIFO and
|
||||
* shift register are empty. The device driver should either
|
||||
* enable interrupt on TEMT or set UART_CAP_NOTEMT that will
|
||||
@ -1544,7 +1530,9 @@ static inline void __stop_tx(struct uart_8250_port *p)
|
||||
|
||||
__stop_tx_rs485(p, stop_delay);
|
||||
}
|
||||
__do_stop_tx(p);
|
||||
|
||||
if (serial8250_clear_THRI(p))
|
||||
serial8250_rpm_put_tx(p);
|
||||
}
|
||||
|
||||
static void serial8250_stop_tx(struct uart_port *port)
|
||||
@ -1573,10 +1561,8 @@ static inline void __start_tx(struct uart_port *port)
|
||||
|
||||
if (serial8250_set_THRI(up)) {
|
||||
if (up->bugs & UART_BUG_TXEN) {
|
||||
unsigned char lsr;
|
||||
u16 lsr = serial_lsr_in(up);
|
||||
|
||||
lsr = serial_in(up, UART_LSR);
|
||||
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
||||
if (lsr & UART_LSR_THRE)
|
||||
serial8250_tx_chars(up);
|
||||
}
|
||||
@ -1616,7 +1602,8 @@ void serial8250_em485_start_tx(struct uart_8250_port *up)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(serial8250_em485_start_tx);
|
||||
|
||||
static inline void start_tx_rs485(struct uart_port *port)
|
||||
/* Returns false, if start_tx_timer was setup to defer TX start */
|
||||
static bool start_tx_rs485(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
struct uart_8250_em485 *em485 = up->em485;
|
||||
@ -1644,11 +1631,11 @@ static inline void start_tx_rs485(struct uart_port *port)
|
||||
em485->active_timer = &em485->start_tx_timer;
|
||||
start_hrtimer_ms(&em485->start_tx_timer,
|
||||
up->port.rs485.delay_rts_before_send);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
__start_tx(port);
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t)
|
||||
@ -1678,14 +1665,12 @@ static void serial8250_start_tx(struct uart_port *port)
|
||||
|
||||
serial8250_rpm_get_tx(up);
|
||||
|
||||
if (em485 &&
|
||||
em485->active_timer == &em485->start_tx_timer)
|
||||
return;
|
||||
|
||||
if (em485)
|
||||
start_tx_rs485(port);
|
||||
else
|
||||
__start_tx(port);
|
||||
if (em485) {
|
||||
if ((em485->active_timer == &em485->start_tx_timer) ||
|
||||
!start_tx_rs485(port))
|
||||
return;
|
||||
}
|
||||
__start_tx(port);
|
||||
}
|
||||
|
||||
static void serial8250_throttle(struct uart_port *port)
|
||||
@ -1729,7 +1714,7 @@ static void serial8250_enable_ms(struct uart_port *port)
|
||||
serial8250_rpm_put(up);
|
||||
}
|
||||
|
||||
void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
|
||||
void serial8250_read_char(struct uart_8250_port *up, u16 lsr)
|
||||
{
|
||||
struct uart_port *port = &up->port;
|
||||
unsigned char ch;
|
||||
@ -1792,11 +1777,13 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr)
|
||||
EXPORT_SYMBOL_GPL(serial8250_read_char);
|
||||
|
||||
/*
|
||||
* serial8250_rx_chars: processes according to the passed in LSR
|
||||
* value, and returns the remaining LSR bits not handled
|
||||
* by this Rx routine.
|
||||
* serial8250_rx_chars - Read characters. The first LSR value must be passed in.
|
||||
*
|
||||
* Returns LSR bits. The caller should rely only on non-Rx related LSR bits
|
||||
* (such as THRE) because the LSR value might come from an already consumed
|
||||
* character.
|
||||
*/
|
||||
unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
|
||||
u16 serial8250_rx_chars(struct uart_8250_port *up, u16 lsr)
|
||||
{
|
||||
struct uart_port *port = &up->port;
|
||||
int max_count = 256;
|
||||
@ -1852,7 +1839,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
if ((up->capabilities & UART_CAP_HFIFO) &&
|
||||
(serial_in(up, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY)
|
||||
!uart_lsr_tx_empty(serial_in(up, UART_LSR)))
|
||||
break;
|
||||
/* The BCM2835 MINI UART THRE bit is really a not-full bit. */
|
||||
if ((up->capabilities & UART_CAP_MINI) &&
|
||||
@ -1916,17 +1903,17 @@ static bool handle_rx_dma(struct uart_8250_port *up, unsigned int iir)
|
||||
*/
|
||||
int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
|
||||
{
|
||||
unsigned char status;
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
bool skip_rx = false;
|
||||
unsigned long flags;
|
||||
u16 status;
|
||||
|
||||
if (iir & UART_IIR_NO_INT)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
status = serial_port_in(port, UART_LSR);
|
||||
status = serial_lsr_in(up);
|
||||
|
||||
/*
|
||||
* If port is stopped and there are no error conditions in the
|
||||
@ -2002,18 +1989,17 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned long flags;
|
||||
unsigned int lsr;
|
||||
u16 lsr;
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
lsr = serial_port_in(port, UART_LSR);
|
||||
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
|
||||
lsr = serial_lsr_in(up);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
serial8250_rpm_put(up);
|
||||
|
||||
return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0;
|
||||
return uart_lsr_tx_empty(lsr) ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
unsigned int serial8250_do_get_mctrl(struct uart_port *port)
|
||||
@ -2084,9 +2070,7 @@ static void wait_for_lsr(struct uart_8250_port *up, int bits)
|
||||
|
||||
/* Wait up to 10ms for the character(s) to be sent. */
|
||||
for (;;) {
|
||||
status = serial_in(up, UART_LSR);
|
||||
|
||||
up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;
|
||||
status = serial_lsr_in(up);
|
||||
|
||||
if ((status & bits) == bits)
|
||||
break;
|
||||
@ -2128,8 +2112,8 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
|
||||
static int serial8250_get_poll_char(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned char lsr;
|
||||
int status;
|
||||
u16 lsr;
|
||||
|
||||
serial8250_rpm_get(up);
|
||||
|
||||
@ -2163,7 +2147,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
|
||||
else
|
||||
serial_port_out(port, UART_IER, 0);
|
||||
|
||||
wait_for_xmitr(up, BOTH_EMPTY);
|
||||
wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
|
||||
/*
|
||||
* Send the character out.
|
||||
*/
|
||||
@ -2173,7 +2157,7 @@ static void serial8250_put_poll_char(struct uart_port *port,
|
||||
* Finally, wait for transmitter to become empty
|
||||
* and restore the IER
|
||||
*/
|
||||
wait_for_xmitr(up, BOTH_EMPTY);
|
||||
wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
|
||||
serial_port_out(port, UART_IER, ier);
|
||||
serial8250_rpm_put(up);
|
||||
}
|
||||
@ -2184,8 +2168,9 @@ int serial8250_do_startup(struct uart_port *port)
|
||||
{
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned long flags;
|
||||
unsigned char lsr, iir;
|
||||
unsigned char iir;
|
||||
int retval;
|
||||
u16 lsr;
|
||||
|
||||
if (!port->fifosize)
|
||||
port->fifosize = uart_config[port->type].fifo_size;
|
||||
@ -2810,7 +2795,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
port->read_status_mask |= UART_LSR_BI;
|
||||
|
||||
/*
|
||||
* Characteres to ignore
|
||||
* Characters to ignore
|
||||
*/
|
||||
port->ignore_status_mask = 0;
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
@ -3203,7 +3188,7 @@ static void serial8250_config_port(struct uart_port *port, int flags)
|
||||
autoconfig(up);
|
||||
|
||||
if (port->rs485.flags & SER_RS485_ENABLED)
|
||||
port->rs485_config(port, &port->rs485);
|
||||
uart_rs485_config(port);
|
||||
|
||||
/* if access method is AU, it is a 16550 with a quirk */
|
||||
if (port->type == PORT_16550A && port->iotype == UPIO_AU)
|
||||
@ -3445,7 +3430,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
|
||||
* Finally, wait for transmitter to become empty
|
||||
* and restore the IER
|
||||
*/
|
||||
wait_for_xmitr(up, BOTH_EMPTY);
|
||||
wait_for_xmitr(up, UART_LSR_BOTH_EMPTY);
|
||||
|
||||
if (em485) {
|
||||
mdelay(port->rs485.delay_rts_after_send);
|
||||
|
@ -254,6 +254,7 @@ config SERIAL_8250_ASPEED_VUART
|
||||
depends on SERIAL_8250
|
||||
depends on OF
|
||||
depends on REGMAP && MFD_SYSCON
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
help
|
||||
If you want to use the virtual UART (VUART) device on Aspeed
|
||||
BMC platforms, enable this option. This enables the 16550A-
|
||||
|
@ -324,6 +324,7 @@ config SERIAL_MAX310X
|
||||
depends on SPI_MASTER
|
||||
select SERIAL_CORE
|
||||
select REGMAP_SPI if SPI_MASTER
|
||||
select REGMAP_I2C if I2C
|
||||
help
|
||||
This selects support for an advanced UART from Maxim (Dallas).
|
||||
Supported ICs are MAX3107, MAX3108, MAX3109, MAX14830.
|
||||
@ -889,23 +890,6 @@ config SERIAL_TXX9_STDSERIAL
|
||||
bool "TX39XX/49XX SIO act as standard serial"
|
||||
depends on !SERIAL_8250 && SERIAL_TXX9
|
||||
|
||||
config SERIAL_VR41XX
|
||||
tristate "NEC VR4100 series Serial Interface Unit support"
|
||||
depends on CPU_VR41XX
|
||||
select SERIAL_CORE
|
||||
help
|
||||
If you have a NEC VR4100 series processor and you want to use
|
||||
Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU)
|
||||
(not include VR4111/VR4121 DSIU), say Y. Otherwise, say N.
|
||||
|
||||
config SERIAL_VR41XX_CONSOLE
|
||||
bool "Enable NEC VR4100 series Serial Interface Unit console"
|
||||
depends on SERIAL_VR41XX=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
help
|
||||
If you have a NEC VR4100 series processor and you want to use
|
||||
a console on a serial port, say Y. Otherwise, say N.
|
||||
|
||||
config SERIAL_JSM
|
||||
tristate "Digi International NEO and Classic PCI Support"
|
||||
depends on PCI
|
||||
|
@ -51,7 +51,6 @@ obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
|
||||
obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o
|
||||
obj-$(CONFIG_SERIAL_JSM) += jsm/
|
||||
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
|
||||
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
|
||||
obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
|
||||
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
|
||||
obj-$(CONFIG_SERIAL_MSM) += msm_serial.o
|
||||
|
@ -2214,7 +2214,7 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pl011_rs485_config(struct uart_port *port,
|
||||
static int pl011_rs485_config(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct uart_amba_port *uap =
|
||||
@ -2700,17 +2700,12 @@ static int pl011_find_free_port(void)
|
||||
static int pl011_get_rs485_mode(struct uart_amba_port *uap)
|
||||
{
|
||||
struct uart_port *port = &uap->port;
|
||||
struct serial_rs485 *rs485 = &port->rs485;
|
||||
int ret;
|
||||
|
||||
ret = uart_get_rs485_mode(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* clamp the delays to [0, 100ms] */
|
||||
rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
|
||||
rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2770,6 +2765,13 @@ static int pl011_register_port(struct uart_amba_port *uap)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct serial_rs485 pl011_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
|
||||
SER_RS485_RX_DURING_TX,
|
||||
.delay_rts_before_send = 1,
|
||||
.delay_rts_after_send = 1,
|
||||
};
|
||||
|
||||
static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
||||
{
|
||||
struct uart_amba_port *uap;
|
||||
@ -2796,6 +2798,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
||||
uap->port.irq = dev->irq[0];
|
||||
uap->port.ops = &amba_pl011_pops;
|
||||
uap->port.rs485_config = pl011_rs485_config;
|
||||
uap->port.rs485_supported = pl011_rs485_supported;
|
||||
snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));
|
||||
|
||||
ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
|
||||
|
@ -580,18 +580,9 @@ static const struct uart_ops ar933x_uart_ops = {
|
||||
.verify_port = ar933x_uart_verify_port,
|
||||
};
|
||||
|
||||
static int ar933x_config_rs485(struct uart_port *port,
|
||||
static int ar933x_config_rs485(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485conf)
|
||||
{
|
||||
struct ar933x_uart_port *up =
|
||||
container_of(port, struct ar933x_uart_port, port);
|
||||
|
||||
if ((rs485conf->flags & SER_RS485_ENABLED) &&
|
||||
!up->rts_gpiod) {
|
||||
dev_err(port->dev, "RS485 needs rts-gpio\n");
|
||||
return 1;
|
||||
}
|
||||
port->rs485 = *rs485conf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -702,6 +693,11 @@ static struct uart_driver ar933x_uart_driver = {
|
||||
.cons = NULL, /* filled in runtime */
|
||||
};
|
||||
|
||||
static const struct serial_rs485 ar933x_no_rs485 = {};
|
||||
static const struct serial_rs485 ar933x_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
|
||||
};
|
||||
|
||||
static int ar933x_uart_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ar933x_uart_port *up;
|
||||
@ -773,6 +769,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
|
||||
port->fifosize = AR933X_UART_FIFO_SIZE;
|
||||
port->ops = &ar933x_uart_ops;
|
||||
port->rs485_config = ar933x_config_rs485;
|
||||
port->rs485_supported = ar933x_rs485_supported;
|
||||
|
||||
baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
|
||||
up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
|
||||
@ -792,10 +789,12 @@ static int ar933x_uart_probe(struct platform_device *pdev)
|
||||
|
||||
up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS);
|
||||
|
||||
if ((port->rs485.flags & SER_RS485_ENABLED) &&
|
||||
!up->rts_gpiod) {
|
||||
dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
|
||||
port->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
if (!up->rts_gpiod) {
|
||||
port->rs485_supported = ar933x_no_rs485;
|
||||
if (port->rs485.flags & SER_RS485_ENABLED) {
|
||||
dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
|
||||
port->rs485.flags &= ~SER_RS485_ENABLED;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_AR933X_CONSOLE
|
||||
|
@ -166,7 +166,6 @@ struct atmel_uart_port {
|
||||
unsigned int fidi_min;
|
||||
unsigned int fidi_max;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct {
|
||||
u32 cr;
|
||||
u32 mr;
|
||||
@ -177,7 +176,6 @@ struct atmel_uart_port {
|
||||
u32 fmr;
|
||||
u32 fimr;
|
||||
} cache;
|
||||
#endif
|
||||
|
||||
int (*prepare_rx)(struct uart_port *port);
|
||||
int (*prepare_tx)(struct uart_port *port);
|
||||
@ -285,7 +283,7 @@ static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port,
|
||||
}
|
||||
|
||||
/* Enable or disable the rs485 support */
|
||||
static int atmel_config_rs485(struct uart_port *port,
|
||||
static int atmel_config_rs485(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485conf)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
@ -2473,6 +2471,12 @@ static const struct uart_ops atmel_pops = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct serial_rs485 atmel_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX,
|
||||
.delay_rts_before_send = 1,
|
||||
.delay_rts_after_send = 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Configure the port from the platform device resource info.
|
||||
*/
|
||||
@ -2494,6 +2498,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
||||
port->mapbase = mpdev->resource[0].start;
|
||||
port->irq = platform_get_irq(mpdev, 0);
|
||||
port->rs485_config = atmel_config_rs485;
|
||||
port->rs485_supported = atmel_rs485_supported;
|
||||
port->iso7816_config = atmel_config_iso7816;
|
||||
port->membase = NULL;
|
||||
|
||||
@ -2503,24 +2508,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* for console, the clock could already be configured */
|
||||
if (!atmel_port->clk) {
|
||||
atmel_port->clk = clk_get(&mpdev->dev, "usart");
|
||||
if (IS_ERR(atmel_port->clk)) {
|
||||
ret = PTR_ERR(atmel_port->clk);
|
||||
atmel_port->clk = NULL;
|
||||
return ret;
|
||||
}
|
||||
ret = clk_prepare_enable(atmel_port->clk);
|
||||
if (ret) {
|
||||
clk_put(atmel_port->clk);
|
||||
atmel_port->clk = NULL;
|
||||
return ret;
|
||||
}
|
||||
port->uartclk = clk_get_rate(atmel_port->clk);
|
||||
clk_disable_unprepare(atmel_port->clk);
|
||||
/* only enable clock when USART is in use */
|
||||
}
|
||||
port->uartclk = clk_get_rate(atmel_port->clk);
|
||||
|
||||
/*
|
||||
* Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or
|
||||
@ -2629,7 +2617,6 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud,
|
||||
|
||||
static int __init atmel_console_setup(struct console *co, char *options)
|
||||
{
|
||||
int ret;
|
||||
struct uart_port *port = &atmel_ports[co->index].uart;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
int baud = 115200;
|
||||
@ -2642,10 +2629,6 @@ static int __init atmel_console_setup(struct console *co, char *options)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(atmel_ports[co->index].clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
atmel_uart_writel(port, ATMEL_US_IDR, -1);
|
||||
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
|
||||
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
|
||||
@ -2711,7 +2694,6 @@ static struct uart_driver atmel_uart = {
|
||||
.cons = ATMEL_CONSOLE_DEVICE,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static bool atmel_serial_clk_will_stop(void)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_AT91
|
||||
@ -2721,10 +2703,9 @@ static bool atmel_serial_clk_will_stop(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int atmel_serial_suspend(struct platform_device *pdev,
|
||||
pm_message_t state)
|
||||
static int __maybe_unused atmel_serial_suspend(struct device *dev)
|
||||
{
|
||||
struct uart_port *port = platform_get_drvdata(pdev);
|
||||
struct uart_port *port = dev_get_drvdata(dev);
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
|
||||
if (uart_console(port) && console_suspend_enabled) {
|
||||
@ -2749,14 +2730,14 @@ static int atmel_serial_suspend(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
/* we can not wake up if we're running on slow clock */
|
||||
atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
|
||||
atmel_port->may_wakeup = device_may_wakeup(dev);
|
||||
if (atmel_serial_clk_will_stop()) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&atmel_port->lock_suspended, flags);
|
||||
atmel_port->suspended = true;
|
||||
spin_unlock_irqrestore(&atmel_port->lock_suspended, flags);
|
||||
device_set_wakeup_enable(&pdev->dev, 0);
|
||||
device_set_wakeup_enable(dev, 0);
|
||||
}
|
||||
|
||||
uart_suspend_port(&atmel_uart, port);
|
||||
@ -2764,9 +2745,9 @@ static int atmel_serial_suspend(struct platform_device *pdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int atmel_serial_resume(struct platform_device *pdev)
|
||||
static int __maybe_unused atmel_serial_resume(struct device *dev)
|
||||
{
|
||||
struct uart_port *port = platform_get_drvdata(pdev);
|
||||
struct uart_port *port = dev_get_drvdata(dev);
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
unsigned long flags;
|
||||
|
||||
@ -2801,14 +2782,10 @@ static int atmel_serial_resume(struct platform_device *pdev)
|
||||
spin_unlock_irqrestore(&atmel_port->lock_suspended, flags);
|
||||
|
||||
uart_resume_port(&atmel_uart, port);
|
||||
device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
|
||||
device_set_wakeup_enable(dev, atmel_port->may_wakeup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define atmel_serial_suspend NULL
|
||||
#define atmel_serial_resume NULL
|
||||
#endif
|
||||
|
||||
static void atmel_serial_probe_fifos(struct atmel_uart_port *atmel_port,
|
||||
struct platform_device *pdev)
|
||||
@ -2897,14 +2874,23 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
||||
atomic_set(&atmel_port->tasklet_shutdown, 0);
|
||||
spin_lock_init(&atmel_port->lock_suspended);
|
||||
|
||||
atmel_port->clk = devm_clk_get(&pdev->dev, "usart");
|
||||
if (IS_ERR(atmel_port->clk)) {
|
||||
ret = PTR_ERR(atmel_port->clk);
|
||||
goto err;
|
||||
}
|
||||
ret = clk_prepare_enable(atmel_port->clk);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = atmel_init_port(atmel_port, pdev);
|
||||
if (ret)
|
||||
goto err_clear_bit;
|
||||
goto err_clk_disable_unprepare;
|
||||
|
||||
atmel_port->gpios = mctrl_gpio_init(&atmel_port->uart, 0);
|
||||
if (IS_ERR(atmel_port->gpios)) {
|
||||
ret = PTR_ERR(atmel_port->gpios);
|
||||
goto err_clear_bit;
|
||||
goto err_clk_disable_unprepare;
|
||||
}
|
||||
|
||||
if (!atmel_use_pdc_rx(&atmel_port->uart)) {
|
||||
@ -2913,7 +2899,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
||||
sizeof(struct atmel_uart_char),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
goto err_alloc_ring;
|
||||
goto err_clk_disable_unprepare;
|
||||
atmel_port->rx_ring.buf = data;
|
||||
}
|
||||
|
||||
@ -2923,26 +2909,9 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err_add_port;
|
||||
|
||||
#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
|
||||
if (uart_console(&atmel_port->uart)
|
||||
&& ATMEL_CONSOLE_DEVICE->flags & CON_ENABLED) {
|
||||
/*
|
||||
* The serial core enabled the clock for us, so undo
|
||||
* the clk_prepare_enable() in atmel_console_setup()
|
||||
*/
|
||||
clk_disable_unprepare(atmel_port->clk);
|
||||
}
|
||||
#endif
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
platform_set_drvdata(pdev, atmel_port);
|
||||
|
||||
/*
|
||||
* The peripheral clock has been disabled by atmel_init_port():
|
||||
* enable it before accessing I/O registers
|
||||
*/
|
||||
clk_prepare_enable(atmel_port->clk);
|
||||
|
||||
if (rs485_enabled) {
|
||||
atmel_uart_writel(&atmel_port->uart, ATMEL_US_MR,
|
||||
ATMEL_US_USMODE_NORMAL);
|
||||
@ -2966,12 +2935,8 @@ static int atmel_serial_probe(struct platform_device *pdev)
|
||||
err_add_port:
|
||||
kfree(atmel_port->rx_ring.buf);
|
||||
atmel_port->rx_ring.buf = NULL;
|
||||
err_alloc_ring:
|
||||
if (!uart_console(&atmel_port->uart)) {
|
||||
clk_put(atmel_port->clk);
|
||||
atmel_port->clk = NULL;
|
||||
}
|
||||
err_clear_bit:
|
||||
err_clk_disable_unprepare:
|
||||
clk_disable_unprepare(atmel_port->clk);
|
||||
clear_bit(atmel_port->uart.line, atmel_ports_in_use);
|
||||
err:
|
||||
return ret;
|
||||
@ -3005,21 +2970,21 @@ static int atmel_serial_remove(struct platform_device *pdev)
|
||||
|
||||
clear_bit(port->line, atmel_ports_in_use);
|
||||
|
||||
clk_put(atmel_port->clk);
|
||||
atmel_port->clk = NULL;
|
||||
pdev->dev.of_node = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend,
|
||||
atmel_serial_resume);
|
||||
|
||||
static struct platform_driver atmel_serial_driver = {
|
||||
.probe = atmel_serial_probe,
|
||||
.remove = atmel_serial_remove,
|
||||
.suspend = atmel_serial_suspend,
|
||||
.resume = atmel_serial_resume,
|
||||
.driver = {
|
||||
.name = "atmel_usart_serial",
|
||||
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
|
||||
.pm = pm_ptr(&atmel_serial_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -253,6 +253,9 @@ int __init of_setup_earlycon(const struct earlycon_id *match,
|
||||
bool big_endian;
|
||||
u64 addr;
|
||||
|
||||
if (early_con.flags & CON_ENABLED)
|
||||
return -EALREADY;
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
port->iotype = UPIO_MEM;
|
||||
addr = of_flat_dt_translate_address(node);
|
||||
|
@ -274,6 +274,8 @@ struct lpuart_port {
|
||||
int rx_dma_rng_buf_len;
|
||||
unsigned int dma_tx_nents;
|
||||
wait_queue_head_t dma_wait;
|
||||
bool is_cs7; /* Set to true when character size is 7 */
|
||||
/* and the parity is enabled */
|
||||
};
|
||||
|
||||
struct lpuart_soc_data {
|
||||
@ -990,12 +992,12 @@ static void lpuart32_rxint(struct lpuart_port *sport)
|
||||
|
||||
if (sr & (UARTSTAT_PE | UARTSTAT_OR | UARTSTAT_FE)) {
|
||||
if (sr & UARTSTAT_PE) {
|
||||
sport->port.icount.parity++;
|
||||
} else if (sr & UARTSTAT_FE) {
|
||||
if (is_break)
|
||||
sport->port.icount.brk++;
|
||||
else
|
||||
sport->port.icount.parity++;
|
||||
} else if (sr & UARTSTAT_FE) {
|
||||
sport->port.icount.frame++;
|
||||
sport->port.icount.frame++;
|
||||
}
|
||||
|
||||
if (sr & UARTSTAT_OR)
|
||||
@ -1010,18 +1012,21 @@ static void lpuart32_rxint(struct lpuart_port *sport)
|
||||
sr &= sport->port.read_status_mask;
|
||||
|
||||
if (sr & UARTSTAT_PE) {
|
||||
flg = TTY_PARITY;
|
||||
} else if (sr & UARTSTAT_FE) {
|
||||
if (is_break)
|
||||
flg = TTY_BREAK;
|
||||
else
|
||||
flg = TTY_PARITY;
|
||||
} else if (sr & UARTSTAT_FE) {
|
||||
flg = TTY_FRAME;
|
||||
flg = TTY_FRAME;
|
||||
}
|
||||
|
||||
if (sr & UARTSTAT_OR)
|
||||
flg = TTY_OVERRUN;
|
||||
}
|
||||
|
||||
if (sport->is_cs7)
|
||||
rx &= 0x7F;
|
||||
|
||||
if (tty_insert_flip_char(port, rx, flg) == 0)
|
||||
sport->port.icount.buf_overrun++;
|
||||
}
|
||||
@ -1107,6 +1112,17 @@ static void lpuart_handle_sysrq(struct lpuart_port *sport)
|
||||
}
|
||||
}
|
||||
|
||||
static int lpuart_tty_insert_flip_string(struct tty_port *port,
|
||||
unsigned char *chars, size_t size, bool is_cs7)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (is_cs7)
|
||||
for (i = 0; i < size; i++)
|
||||
chars[i] &= 0x7F;
|
||||
return tty_insert_flip_string(port, chars, size);
|
||||
}
|
||||
|
||||
static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
||||
{
|
||||
struct tty_port *port = &sport->port.state->port;
|
||||
@ -1217,7 +1233,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
||||
if (ring->head < ring->tail) {
|
||||
count = sport->rx_sgl.length - ring->tail;
|
||||
|
||||
copied = tty_insert_flip_string(port, ring->buf + ring->tail, count);
|
||||
copied = lpuart_tty_insert_flip_string(port, ring->buf + ring->tail,
|
||||
count, sport->is_cs7);
|
||||
if (copied != count)
|
||||
sport->port.icount.buf_overrun++;
|
||||
ring->tail = 0;
|
||||
@ -1227,7 +1244,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
|
||||
/* Finally we read data from tail to head */
|
||||
if (ring->tail < ring->head) {
|
||||
count = ring->head - ring->tail;
|
||||
copied = tty_insert_flip_string(port, ring->buf + ring->tail, count);
|
||||
copied = lpuart_tty_insert_flip_string(port, ring->buf + ring->tail,
|
||||
count, sport->is_cs7);
|
||||
if (copied != count)
|
||||
sport->port.icount.buf_overrun++;
|
||||
/* Wrap ring->head if needed */
|
||||
@ -1355,7 +1373,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
|
||||
sport->dma_rx_cookie = -EINVAL;
|
||||
}
|
||||
|
||||
static int lpuart_config_rs485(struct uart_port *port,
|
||||
static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port,
|
||||
@ -1365,11 +1383,6 @@ static int lpuart_config_rs485(struct uart_port *port,
|
||||
~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE);
|
||||
writeb(modem, sport->port.membase + UARTMODEM);
|
||||
|
||||
/* clear unsupported configurations */
|
||||
rs485->delay_rts_before_send = 0;
|
||||
rs485->delay_rts_after_send = 0;
|
||||
rs485->flags &= ~SER_RS485_RX_DURING_TX;
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
/* Enable auto RS-485 RTS mode */
|
||||
modem |= UARTMODEM_TXRTSE;
|
||||
@ -1390,7 +1403,7 @@ static int lpuart_config_rs485(struct uart_port *port,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpuart32_config_rs485(struct uart_port *port,
|
||||
static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port,
|
||||
@ -1400,11 +1413,6 @@ static int lpuart32_config_rs485(struct uart_port *port,
|
||||
& ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE);
|
||||
lpuart32_write(&sport->port, modem, UARTMODIR);
|
||||
|
||||
/* clear unsupported configurations */
|
||||
rs485->delay_rts_before_send = 0;
|
||||
rs485->delay_rts_after_send = 0;
|
||||
rs485->flags &= ~SER_RS485_RX_DURING_TX;
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED) {
|
||||
/* Enable auto RS-485 RTS mode */
|
||||
modem |= UARTMODEM_TXRTSE;
|
||||
@ -2076,6 +2084,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL);
|
||||
bd = lpuart32_read(&sport->port, UARTBAUD);
|
||||
modem = lpuart32_read(&sport->port, UARTMODIR);
|
||||
sport->is_cs7 = false;
|
||||
/*
|
||||
* only support CS8 and CS7, and for CS7 must enable PE.
|
||||
* supported mode:
|
||||
@ -2194,6 +2203,9 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
lpuart32_write(&sport->port, ctrl, UARTCTRL);
|
||||
/* restore control register */
|
||||
|
||||
if ((ctrl & (UARTCTRL_PE | UARTCTRL_M)) == UARTCTRL_PE)
|
||||
sport->is_cs7 = true;
|
||||
|
||||
if (old && sport->lpuart_dma_rx_use) {
|
||||
if (!lpuart_start_rx_dma(sport))
|
||||
rx_dma_timer_init(sport);
|
||||
@ -2621,6 +2633,11 @@ static struct uart_driver lpuart_reg = {
|
||||
.cons = LPUART_CONSOLE,
|
||||
};
|
||||
|
||||
static const struct serial_rs485 lpuart_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
|
||||
/* delay_rts_* and RX_DURING_TX are not supported */
|
||||
};
|
||||
|
||||
static int lpuart_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct lpuart_soc_data *sdata = of_device_get_match_data(&pdev->dev);
|
||||
@ -2660,6 +2677,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
||||
sport->port.rs485_config = lpuart32_config_rs485;
|
||||
else
|
||||
sport->port.rs485_config = lpuart_config_rs485;
|
||||
sport->port.rs485_supported = lpuart_rs485_supported;
|
||||
|
||||
sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
|
||||
if (IS_ERR(sport->ipg_clk)) {
|
||||
@ -2717,14 +2735,7 @@ static int lpuart_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto failed_get_rs485;
|
||||
|
||||
if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX)
|
||||
dev_err(&pdev->dev, "driver doesn't support RX during TX\n");
|
||||
|
||||
if (sport->port.rs485.delay_rts_before_send ||
|
||||
sport->port.rs485.delay_rts_after_send)
|
||||
dev_err(&pdev->dev, "driver doesn't support RTS delays\n");
|
||||
|
||||
sport->port.rs485_config(&sport->port, &sport->port.rs485);
|
||||
uart_rs485_config(&sport->port);
|
||||
|
||||
ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0,
|
||||
DRIVER_NAME, sport);
|
||||
|
@ -1907,16 +1907,12 @@ static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c)
|
||||
#endif
|
||||
|
||||
/* called with port.lock taken and irqs off or from .probe without locking */
|
||||
static int imx_uart_rs485_config(struct uart_port *port,
|
||||
static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485conf)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
u32 ucr2;
|
||||
|
||||
/* RTS is required to control the transmitter */
|
||||
if (!sport->have_rtscts && !sport->have_rtsgpio)
|
||||
rs485conf->flags &= ~SER_RS485_ENABLED;
|
||||
|
||||
if (rs485conf->flags & SER_RS485_ENABLED) {
|
||||
/* Enable receiver if low-active RTS signal is requested */
|
||||
if (sport->have_rtscts && !sport->have_rtsgpio &&
|
||||
@ -2200,6 +2196,14 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t)
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static const struct serial_rs485 imx_no_rs485 = {}; /* No RS485 if no RTS */
|
||||
static const struct serial_rs485 imx_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
|
||||
SER_RS485_RX_DURING_TX,
|
||||
.delay_rts_before_send = 1,
|
||||
.delay_rts_after_send = 1,
|
||||
};
|
||||
|
||||
/* Default RX DMA buffer configuration */
|
||||
#define RX_DMA_PERIODS 16
|
||||
#define RX_DMA_PERIOD_LEN (PAGE_SIZE / 4)
|
||||
@ -2279,6 +2283,11 @@ static int imx_uart_probe(struct platform_device *pdev)
|
||||
sport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE);
|
||||
sport->port.ops = &imx_uart_pops;
|
||||
sport->port.rs485_config = imx_uart_rs485_config;
|
||||
/* RTS is required to control the RS485 transmitter */
|
||||
if (sport->have_rtscts || sport->have_rtsgpio)
|
||||
sport->port.rs485_supported = imx_rs485_supported;
|
||||
else
|
||||
sport->port.rs485_supported = imx_no_rs485;
|
||||
sport->port.flags = UPF_BOOT_AUTOCONF;
|
||||
timer_setup(&sport->timer, imx_uart_timeout, 0);
|
||||
|
||||
@ -2338,7 +2347,7 @@ static int imx_uart_probe(struct platform_device *pdev)
|
||||
dev_err(&pdev->dev,
|
||||
"low-active RTS not possible when receiver is off, enabling receiver\n");
|
||||
|
||||
imx_uart_rs485_config(&sport->port, &sport->port.rs485);
|
||||
uart_rs485_config(&sport->port);
|
||||
|
||||
/* Disable interrupts before requesting them */
|
||||
ucr1 = imx_uart_readl(sport, UCR1);
|
||||
|
@ -342,7 +342,7 @@ static int param_set_kgdboc_var(const char *kmessage,
|
||||
/*
|
||||
* Configure with the new params as long as init already ran.
|
||||
* Note that we can get called before init if someone loads us
|
||||
* with "modprobe kgdboc kgdboc=..." or if they happen to use the
|
||||
* with "modprobe kgdboc kgdboc=..." or if they happen to use
|
||||
* the odd syntax of "kgdboc.kgdboc=..." on the kernel command.
|
||||
*/
|
||||
if (configured >= 0)
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/property.h>
|
||||
@ -72,7 +73,8 @@
|
||||
#define MAX310X_GLOBALCMD_REG MAX310X_REG_1F /* Global Command (WO) */
|
||||
|
||||
/* Extended registers */
|
||||
#define MAX310X_REVID_EXTREG MAX310X_REG_05 /* Revision ID */
|
||||
#define MAX310X_SPI_REVID_EXTREG MAX310X_REG_05 /* Revision ID */
|
||||
#define MAX310X_I2C_REVID_EXTREG (0x25) /* Revision ID */
|
||||
|
||||
/* IRQ register bits */
|
||||
#define MAX310X_IRQ_LSR_BIT (1 << 0) /* LSR interrupt */
|
||||
@ -245,7 +247,17 @@
|
||||
#define MAX14830_BRGCFG_CLKDIS_BIT (1 << 6) /* Clock Disable */
|
||||
#define MAX14830_REV_ID (0xb0)
|
||||
|
||||
struct max310x_if_cfg {
|
||||
int (*extended_reg_enable)(struct device *dev, bool enable);
|
||||
|
||||
unsigned int rev_id_reg;
|
||||
};
|
||||
|
||||
struct max310x_devtype {
|
||||
struct {
|
||||
unsigned short min;
|
||||
unsigned short max;
|
||||
} slave_addr;
|
||||
char name[9];
|
||||
int nr;
|
||||
u8 mode1;
|
||||
@ -258,9 +270,8 @@ struct max310x_one {
|
||||
struct work_struct tx_work;
|
||||
struct work_struct md_work;
|
||||
struct work_struct rs_work;
|
||||
struct regmap *regmap;
|
||||
|
||||
u8 wr_header;
|
||||
u8 rd_header;
|
||||
u8 rx_buf[MAX310X_FIFO_SIZE];
|
||||
};
|
||||
#define to_max310x_port(_port) \
|
||||
@ -268,6 +279,7 @@ struct max310x_one {
|
||||
|
||||
struct max310x_port {
|
||||
const struct max310x_devtype *devtype;
|
||||
const struct max310x_if_cfg *if_cfg;
|
||||
struct regmap *regmap;
|
||||
struct clk *clk;
|
||||
#ifdef CONFIG_GPIOLIB
|
||||
@ -289,26 +301,26 @@ static DECLARE_BITMAP(max310x_lines, MAX310X_UART_NRMAX);
|
||||
|
||||
static u8 max310x_port_read(struct uart_port *port, u8 reg)
|
||||
{
|
||||
struct max310x_port *s = dev_get_drvdata(port->dev);
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
unsigned int val = 0;
|
||||
|
||||
regmap_read(s->regmap, port->iobase + reg, &val);
|
||||
regmap_read(one->regmap, reg, &val);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void max310x_port_write(struct uart_port *port, u8 reg, u8 val)
|
||||
{
|
||||
struct max310x_port *s = dev_get_drvdata(port->dev);
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
|
||||
regmap_write(s->regmap, port->iobase + reg, val);
|
||||
regmap_write(one->regmap, reg, val);
|
||||
}
|
||||
|
||||
static void max310x_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val)
|
||||
{
|
||||
struct max310x_port *s = dev_get_drvdata(port->dev);
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
|
||||
regmap_update_bits(s->regmap, port->iobase + reg, mask, val);
|
||||
regmap_update_bits(one->regmap, reg, mask, val);
|
||||
}
|
||||
|
||||
static int max3107_detect(struct device *dev)
|
||||
@ -357,13 +369,12 @@ static int max3109_detect(struct device *dev)
|
||||
unsigned int val = 0;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG,
|
||||
MAX310X_EXTREG_ENBL);
|
||||
ret = s->if_cfg->extended_reg_enable(dev, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val);
|
||||
regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL);
|
||||
regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val);
|
||||
s->if_cfg->extended_reg_enable(dev, false);
|
||||
if (((val & MAX310x_REV_MASK) != MAX3109_REV_ID)) {
|
||||
dev_err(dev,
|
||||
"%s ID 0x%02x does not match\n", s->devtype->name, val);
|
||||
@ -388,13 +399,12 @@ static int max14830_detect(struct device *dev)
|
||||
unsigned int val = 0;
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(s->regmap, MAX310X_GLOBALCMD_REG,
|
||||
MAX310X_EXTREG_ENBL);
|
||||
ret = s->if_cfg->extended_reg_enable(dev, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
regmap_read(s->regmap, MAX310X_REVID_EXTREG, &val);
|
||||
regmap_write(s->regmap, MAX310X_GLOBALCMD_REG, MAX310X_EXTREG_DSBL);
|
||||
regmap_read(s->regmap, s->if_cfg->rev_id_reg, &val);
|
||||
s->if_cfg->extended_reg_enable(dev, false);
|
||||
if (((val & MAX310x_REV_MASK) != MAX14830_REV_ID)) {
|
||||
dev_err(dev,
|
||||
"%s ID 0x%02x does not match\n", s->devtype->name, val);
|
||||
@ -419,6 +429,10 @@ static const struct max310x_devtype max3107_devtype = {
|
||||
.mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT,
|
||||
.detect = max3107_detect,
|
||||
.power = max310x_power,
|
||||
.slave_addr = {
|
||||
.min = 0x2c,
|
||||
.max = 0x2f,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct max310x_devtype max3108_devtype = {
|
||||
@ -427,6 +441,10 @@ static const struct max310x_devtype max3108_devtype = {
|
||||
.mode1 = MAX310X_MODE1_AUTOSLEEP_BIT,
|
||||
.detect = max3108_detect,
|
||||
.power = max310x_power,
|
||||
.slave_addr = {
|
||||
.min = 0x60,
|
||||
.max = 0x6f,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct max310x_devtype max3109_devtype = {
|
||||
@ -435,6 +453,10 @@ static const struct max310x_devtype max3109_devtype = {
|
||||
.mode1 = MAX310X_MODE1_AUTOSLEEP_BIT,
|
||||
.detect = max3109_detect,
|
||||
.power = max310x_power,
|
||||
.slave_addr = {
|
||||
.min = 0x60,
|
||||
.max = 0x6f,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct max310x_devtype max14830_devtype = {
|
||||
@ -443,11 +465,15 @@ static const struct max310x_devtype max14830_devtype = {
|
||||
.mode1 = MAX310X_MODE1_IRQSEL_BIT,
|
||||
.detect = max14830_detect,
|
||||
.power = max14830_power,
|
||||
.slave_addr = {
|
||||
.min = 0x60,
|
||||
.max = 0x6f,
|
||||
},
|
||||
};
|
||||
|
||||
static bool max310x_reg_writeable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg & 0x1f) {
|
||||
switch (reg) {
|
||||
case MAX310X_IRQSTS_REG:
|
||||
case MAX310X_LSR_IRQSTS_REG:
|
||||
case MAX310X_SPCHR_IRQSTS_REG:
|
||||
@ -464,7 +490,7 @@ static bool max310x_reg_writeable(struct device *dev, unsigned int reg)
|
||||
|
||||
static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg & 0x1f) {
|
||||
switch (reg) {
|
||||
case MAX310X_RHR_REG:
|
||||
case MAX310X_IRQSTS_REG:
|
||||
case MAX310X_LSR_IRQSTS_REG:
|
||||
@ -486,7 +512,7 @@ static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
|
||||
|
||||
static bool max310x_reg_precious(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg & 0x1f) {
|
||||
switch (reg) {
|
||||
case MAX310X_RHR_REG:
|
||||
case MAX310X_IRQSTS_REG:
|
||||
case MAX310X_SPCHR_IRQSTS_REG:
|
||||
@ -624,31 +650,15 @@ static u32 max310x_set_ref_clk(struct device *dev, struct max310x_port *s,
|
||||
static void max310x_batch_write(struct uart_port *port, u8 *txbuf, unsigned int len)
|
||||
{
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
struct spi_transfer xfer[] = {
|
||||
{
|
||||
.tx_buf = &one->wr_header,
|
||||
.len = sizeof(one->wr_header),
|
||||
}, {
|
||||
.tx_buf = txbuf,
|
||||
.len = len,
|
||||
}
|
||||
};
|
||||
spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer));
|
||||
|
||||
regmap_raw_write(one->regmap, MAX310X_THR_REG, txbuf, len);
|
||||
}
|
||||
|
||||
static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int len)
|
||||
{
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
struct spi_transfer xfer[] = {
|
||||
{
|
||||
.tx_buf = &one->rd_header,
|
||||
.len = sizeof(one->rd_header),
|
||||
}, {
|
||||
.rx_buf = rxbuf,
|
||||
.len = len,
|
||||
}
|
||||
};
|
||||
spi_sync_transfer(to_spi_device(port->dev), xfer, ARRAY_SIZE(xfer));
|
||||
|
||||
regmap_raw_read(one->regmap, MAX310X_RHR_REG, rxbuf, len);
|
||||
}
|
||||
|
||||
static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
|
||||
@ -1026,7 +1036,7 @@ static void max310x_rs_proc(struct work_struct *ws)
|
||||
MAX310X_MODE2_ECHOSUPR_BIT, mode2);
|
||||
}
|
||||
|
||||
static int max310x_rs485_config(struct uart_port *port,
|
||||
static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct max310x_one *one = to_max310x_port(port);
|
||||
@ -1035,8 +1045,6 @@ static int max310x_rs485_config(struct uart_port *port,
|
||||
(rs485->delay_rts_after_send > 0x0f))
|
||||
return -ERANGE;
|
||||
|
||||
rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX |
|
||||
SER_RS485_ENABLED;
|
||||
port->rs485 = *rs485;
|
||||
|
||||
schedule_work(&one->rs_work);
|
||||
@ -1249,16 +1257,24 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct serial_rs485 max310x_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX,
|
||||
.delay_rts_before_send = 1,
|
||||
.delay_rts_after_send = 1,
|
||||
};
|
||||
|
||||
static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype,
|
||||
struct regmap *regmap, int irq)
|
||||
const struct max310x_if_cfg *if_cfg,
|
||||
struct regmap *regmaps[], int irq)
|
||||
{
|
||||
int i, ret, fmin, fmax, freq;
|
||||
struct max310x_port *s;
|
||||
u32 uartclk = 0;
|
||||
bool xtal;
|
||||
|
||||
if (IS_ERR(regmap))
|
||||
return PTR_ERR(regmap);
|
||||
for (i = 0; i < devtype->nr; i++)
|
||||
if (IS_ERR(regmaps[i]))
|
||||
return PTR_ERR(regmaps[i]);
|
||||
|
||||
/* Alloc port structure */
|
||||
s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL);
|
||||
@ -1305,8 +1321,9 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
|
||||
goto out_clk;
|
||||
}
|
||||
|
||||
s->regmap = regmap;
|
||||
s->regmap = regmaps[0];
|
||||
s->devtype = devtype;
|
||||
s->if_cfg = if_cfg;
|
||||
dev_set_drvdata(dev, s);
|
||||
|
||||
/* Check device to ensure we are talking to what we expect */
|
||||
@ -1315,22 +1332,18 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
|
||||
goto out_clk;
|
||||
|
||||
for (i = 0; i < devtype->nr; i++) {
|
||||
unsigned int offs = i << 5;
|
||||
|
||||
/* Reset port */
|
||||
regmap_write(s->regmap, MAX310X_MODE2_REG + offs,
|
||||
regmap_write(regmaps[i], MAX310X_MODE2_REG,
|
||||
MAX310X_MODE2_RST_BIT);
|
||||
/* Clear port reset */
|
||||
regmap_write(s->regmap, MAX310X_MODE2_REG + offs, 0);
|
||||
regmap_write(regmaps[i], MAX310X_MODE2_REG, 0);
|
||||
|
||||
/* Wait for port startup */
|
||||
do {
|
||||
regmap_read(s->regmap,
|
||||
MAX310X_BRGDIVLSB_REG + offs, &ret);
|
||||
regmap_read(regmaps[i], MAX310X_BRGDIVLSB_REG, &ret);
|
||||
} while (ret != 0x01);
|
||||
|
||||
regmap_write(s->regmap, MAX310X_MODE1_REG + offs,
|
||||
devtype->mode1);
|
||||
regmap_write(regmaps[i], MAX310X_MODE1_REG, devtype->mode1);
|
||||
}
|
||||
|
||||
uartclk = max310x_set_ref_clk(dev, s, freq, xtal);
|
||||
@ -1353,11 +1366,14 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
|
||||
s->p[i].port.fifosize = MAX310X_FIFO_SIZE;
|
||||
s->p[i].port.flags = UPF_FIXED_TYPE | UPF_LOW_LATENCY;
|
||||
s->p[i].port.iotype = UPIO_PORT;
|
||||
s->p[i].port.iobase = i * 0x20;
|
||||
s->p[i].port.iobase = i;
|
||||
s->p[i].port.membase = (void __iomem *)~0;
|
||||
s->p[i].port.uartclk = uartclk;
|
||||
s->p[i].port.rs485_config = max310x_rs485_config;
|
||||
s->p[i].port.rs485_supported = max310x_rs485_supported;
|
||||
s->p[i].port.ops = &max310x_ops;
|
||||
s->p[i].regmap = regmaps[i];
|
||||
|
||||
/* Disable all interrupts */
|
||||
max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0);
|
||||
/* Clear IRQ status register */
|
||||
@ -1368,10 +1384,6 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
|
||||
INIT_WORK(&s->p[i].md_work, max310x_md_proc);
|
||||
/* Initialize queue for changing RS485 mode */
|
||||
INIT_WORK(&s->p[i].rs_work, max310x_rs_proc);
|
||||
/* Initialize SPI-transfer buffers */
|
||||
s->p[i].wr_header = (s->p[i].port.iobase + MAX310X_THR_REG) |
|
||||
MAX310X_WRITE_BIT;
|
||||
s->p[i].rd_header = (s->p[i].port.iobase + MAX310X_RHR_REG);
|
||||
|
||||
/* Register port */
|
||||
ret = uart_add_one_port(&max310x_uart, &s->p[i].port);
|
||||
@ -1456,16 +1468,31 @@ static struct regmap_config regcfg = {
|
||||
.val_bits = 8,
|
||||
.write_flag_mask = MAX310X_WRITE_BIT,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.max_register = MAX310X_REG_1F,
|
||||
.writeable_reg = max310x_reg_writeable,
|
||||
.volatile_reg = max310x_reg_volatile,
|
||||
.precious_reg = max310x_reg_precious,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SPI_MASTER
|
||||
static int max310x_spi_extended_reg_enable(struct device *dev, bool enable)
|
||||
{
|
||||
struct max310x_port *s = dev_get_drvdata(dev);
|
||||
|
||||
return regmap_write(s->regmap, MAX310X_GLOBALCMD_REG,
|
||||
enable ? MAX310X_EXTREG_ENBL : MAX310X_EXTREG_DSBL);
|
||||
}
|
||||
|
||||
static const struct max310x_if_cfg __maybe_unused max310x_spi_if_cfg = {
|
||||
.extended_reg_enable = max310x_spi_extended_reg_enable,
|
||||
.rev_id_reg = MAX310X_SPI_REVID_EXTREG,
|
||||
};
|
||||
|
||||
static int max310x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct max310x_devtype *devtype;
|
||||
struct regmap *regmap;
|
||||
struct regmap *regmaps[4];
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/* Setup SPI bus */
|
||||
@ -1480,10 +1507,14 @@ static int max310x_spi_probe(struct spi_device *spi)
|
||||
if (!devtype)
|
||||
devtype = (struct max310x_devtype *)spi_get_device_id(spi)->driver_data;
|
||||
|
||||
regcfg.max_register = devtype->nr * 0x20 - 1;
|
||||
regmap = devm_regmap_init_spi(spi, ®cfg);
|
||||
for (i = 0; i < devtype->nr; i++) {
|
||||
u8 port_mask = i * 0x20;
|
||||
regcfg.read_flag_mask = port_mask;
|
||||
regcfg.write_flag_mask = port_mask | MAX310X_WRITE_BIT;
|
||||
regmaps[i] = devm_regmap_init_spi(spi, ®cfg);
|
||||
}
|
||||
|
||||
return max310x_probe(&spi->dev, devtype, regmap, spi->irq);
|
||||
return max310x_probe(&spi->dev, devtype, &max310x_spi_if_cfg, regmaps, spi->irq);
|
||||
}
|
||||
|
||||
static void max310x_spi_remove(struct spi_device *spi)
|
||||
@ -1512,6 +1543,97 @@ static struct spi_driver max310x_spi_driver = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_I2C
|
||||
static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regmap_config regcfg_i2c = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.writeable_reg = max310x_reg_writeable,
|
||||
.volatile_reg = max310x_reg_volatile,
|
||||
.precious_reg = max310x_reg_precious,
|
||||
.max_register = MAX310X_I2C_REVID_EXTREG,
|
||||
};
|
||||
|
||||
static const struct max310x_if_cfg max310x_i2c_if_cfg = {
|
||||
.extended_reg_enable = max310x_i2c_extended_reg_enable,
|
||||
.rev_id_reg = MAX310X_I2C_REVID_EXTREG,
|
||||
};
|
||||
|
||||
static unsigned short max310x_i2c_slave_addr(unsigned short addr,
|
||||
unsigned int nr)
|
||||
{
|
||||
/*
|
||||
* For MAX14830 and MAX3109, the slave address depends on what the
|
||||
* A0 and A1 pins are tied to.
|
||||
* See Table I2C Address Map of the datasheet.
|
||||
* Based on that table, the following formulas were determined.
|
||||
* UART1 - UART0 = 0x10
|
||||
* UART2 - UART1 = 0x20 + 0x10
|
||||
* UART3 - UART2 = 0x10
|
||||
*/
|
||||
|
||||
addr -= nr * 0x10;
|
||||
|
||||
if (nr >= 2)
|
||||
addr -= 0x20;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static int max310x_i2c_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct max310x_devtype *devtype =
|
||||
device_get_match_data(&client->dev);
|
||||
struct i2c_client *port_client;
|
||||
struct regmap *regmaps[4];
|
||||
unsigned int i;
|
||||
u8 port_addr;
|
||||
|
||||
if (client->addr < devtype->slave_addr.min ||
|
||||
client->addr > devtype->slave_addr.max)
|
||||
return dev_err_probe(&client->dev, -EINVAL,
|
||||
"Slave addr 0x%x outside of range [0x%x, 0x%x]\n",
|
||||
client->addr, devtype->slave_addr.min,
|
||||
devtype->slave_addr.max);
|
||||
|
||||
regmaps[0] = devm_regmap_init_i2c(client, ®cfg_i2c);
|
||||
|
||||
for (i = 1; i < devtype->nr; i++) {
|
||||
port_addr = max310x_i2c_slave_addr(client->addr, i);
|
||||
port_client = devm_i2c_new_dummy_device(&client->dev,
|
||||
client->adapter,
|
||||
port_addr);
|
||||
|
||||
regmaps[i] = devm_regmap_init_i2c(port_client, ®cfg_i2c);
|
||||
}
|
||||
|
||||
return max310x_probe(&client->dev, devtype, &max310x_i2c_if_cfg,
|
||||
regmaps, client->irq);
|
||||
}
|
||||
|
||||
static int max310x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
max310x_remove(&client->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver max310x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = MAX310X_NAME,
|
||||
.of_match_table = max310x_dt_ids,
|
||||
.pm = &max310x_pm_ops,
|
||||
},
|
||||
.probe_new = max310x_i2c_probe,
|
||||
.remove = max310x_i2c_remove,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init max310x_uart_init(void)
|
||||
{
|
||||
int ret;
|
||||
@ -1525,15 +1647,35 @@ static int __init max310x_uart_init(void)
|
||||
#ifdef CONFIG_SPI_MASTER
|
||||
ret = spi_register_driver(&max310x_spi_driver);
|
||||
if (ret)
|
||||
uart_unregister_driver(&max310x_uart);
|
||||
goto err_spi_register;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_I2C
|
||||
ret = i2c_add_driver(&max310x_i2c_driver);
|
||||
if (ret)
|
||||
goto err_i2c_register;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_I2C
|
||||
err_i2c_register:
|
||||
spi_unregister_driver(&max310x_spi_driver);
|
||||
#endif
|
||||
|
||||
err_spi_register:
|
||||
uart_unregister_driver(&max310x_uart);
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(max310x_uart_init);
|
||||
|
||||
static void __exit max310x_uart_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_I2C
|
||||
i2c_del_driver(&max310x_i2c_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPI_MASTER
|
||||
spi_unregister_driver(&max310x_spi_driver);
|
||||
#endif
|
||||
|
@ -431,7 +431,8 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
/****************************************************************************/
|
||||
|
||||
/* Enable or disable the RS485 support */
|
||||
static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
static int mcf_config_rs485(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
unsigned char mr1, mr2;
|
||||
|
||||
@ -448,11 +449,14 @@ static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
}
|
||||
writeb(mr1, port->membase + MCFUART_UMR);
|
||||
writeb(mr2, port->membase + MCFUART_UMR);
|
||||
port->rs485 = *rs485;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct serial_rs485 mcf_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
@ -502,6 +506,7 @@ int __init early_mcf_setup(struct mcf_platform_uart *platp)
|
||||
port->uartclk = MCF_BUSCLK;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->rs485_config = mcf_config_rs485;
|
||||
port->rs485_supported = mcf_rs485_supported;
|
||||
port->ops = &mcf_uart_ops;
|
||||
}
|
||||
|
||||
@ -629,6 +634,7 @@ static int mcf_probe(struct platform_device *pdev)
|
||||
port->ops = &mcf_uart_ops;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->rs485_config = mcf_config_rs485;
|
||||
port->rs485_supported = mcf_rs485_supported;
|
||||
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MCF_CONSOLE);
|
||||
|
||||
uart_add_one_port(&mcf_driver, port);
|
||||
|
@ -162,7 +162,7 @@ static void meson_uart_start_tx(struct uart_port *port)
|
||||
|
||||
ch = xmit->buf[xmit->tail];
|
||||
writel(ch, port->membase + AML_UART_WFIFO);
|
||||
xmit->tail = (xmit->tail+1) & (SERIAL_XMIT_SIZE - 1);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -481,12 +481,6 @@ static int __init mux_probe(struct parisc_device *dev)
|
||||
port->line = port_cnt;
|
||||
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MUX_CONSOLE);
|
||||
|
||||
/* The port->timeout needs to match what is present in
|
||||
* uart_wait_until_sent in serial_core.c. Otherwise
|
||||
* the time spent in msleep_interruptable will be very
|
||||
* long, causing the appearance of a console hang.
|
||||
*/
|
||||
port->timeout = HZ / 50;
|
||||
spin_lock_init(&port->lock);
|
||||
|
||||
status = uart_add_one_port(&mux_driver, port);
|
||||
|
@ -265,6 +265,7 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status)
|
||||
struct tty_port *tport = &port->state->port;
|
||||
unsigned char ch = 0;
|
||||
char flag = 0;
|
||||
int ret;
|
||||
|
||||
do {
|
||||
if (status & STAT_RX_RDY(port)) {
|
||||
@ -277,6 +278,16 @@ static void mvebu_uart_rx_chars(struct uart_port *port, unsigned int status)
|
||||
port->icount.parity++;
|
||||
}
|
||||
|
||||
/*
|
||||
* For UART2, error bits are not cleared on buffer read.
|
||||
* This causes interrupt loop and system hang.
|
||||
*/
|
||||
if (IS_EXTENDED(port) && (status & STAT_BRK_ERR)) {
|
||||
ret = readl(port->membase + UART_STAT);
|
||||
ret |= STAT_BRK_ERR;
|
||||
writel(ret, port->membase + UART_STAT);
|
||||
}
|
||||
|
||||
if (status & STAT_BRK_DET) {
|
||||
port->icount.brk++;
|
||||
status &= ~(STAT_FRM_ERR | STAT_PAR_ERR);
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
@ -1102,8 +1103,6 @@ serial_omap_type(struct uart_port *port)
|
||||
return up->name;
|
||||
}
|
||||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up)
|
||||
{
|
||||
unsigned int status, tmout = 10000;
|
||||
@ -1118,7 +1117,7 @@ static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up)
|
||||
if (--tmout == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
|
||||
} while (!uart_lsr_tx_empty(status));
|
||||
|
||||
/* Wait up to 1s for flow control if necessary */
|
||||
if (up->port.flags & UPF_CONS_FLOW) {
|
||||
@ -1186,7 +1185,7 @@ static void omap_serial_early_putc(struct uart_port *port, unsigned char c)
|
||||
|
||||
for (;;) {
|
||||
status = omap_serial_early_in(port, UART_LSR);
|
||||
if ((status & BOTH_EMPTY) == BOTH_EMPTY)
|
||||
if (uart_lsr_tx_empty(status))
|
||||
break;
|
||||
cpu_relax();
|
||||
}
|
||||
@ -1325,7 +1324,8 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up)
|
||||
|
||||
/* Enable or disable the rs485 support */
|
||||
static int
|
||||
serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
serial_omap_config_rs485(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct uart_omap_port *up = to_uart_omap_port(port);
|
||||
unsigned int mode;
|
||||
@ -1559,6 +1559,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct serial_rs485 serial_omap_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
|
||||
SER_RS485_RX_DURING_TX,
|
||||
.delay_rts_before_send = 1,
|
||||
.delay_rts_after_send = 1,
|
||||
};
|
||||
|
||||
static int serial_omap_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
|
||||
@ -1636,6 +1643,7 @@ static int serial_omap_probe(struct platform_device *pdev)
|
||||
up->port.flags = omap_up_info->flags;
|
||||
up->port.uartclk = omap_up_info->uartclk;
|
||||
up->port.rs485_config = serial_omap_config_rs485;
|
||||
up->port.rs485_supported = serial_omap_rs485_supported;
|
||||
if (!up->port.uartclk) {
|
||||
up->port.uartclk = DEFAULT_CLK_SPEED;
|
||||
dev_warn(&pdev->dev,
|
||||
|
@ -201,7 +201,7 @@ static void owl_uart_send_chars(struct uart_port *port)
|
||||
|
||||
ch = xmit->buf[xmit->tail];
|
||||
owl_uart_write(port, ch, OWL_UART_TXDAT);
|
||||
xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
*Copyright (C) 2011 LAPIS Semiconductor Co., Ltd.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
@ -189,8 +190,6 @@ enum {
|
||||
#define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP)
|
||||
#define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE)
|
||||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
#define DEFAULT_UARTCLK 1843200 /* 1.8432 MHz */
|
||||
#define CMITC_UARTCLK 192000000 /* 192.0000 MHz */
|
||||
#define FRI2_64_UARTCLK 64000000 /* 64.0000 MHz */
|
||||
@ -1516,7 +1515,7 @@ static void pch_uart_put_poll_char(struct uart_port *port,
|
||||
* Finally, wait for transmitter to become empty
|
||||
* and restore the IER
|
||||
*/
|
||||
wait_for_xmitr(priv, BOTH_EMPTY);
|
||||
wait_for_xmitr(priv, UART_LSR_BOTH_EMPTY);
|
||||
iowrite8(ier, priv->membase + UART_IER);
|
||||
}
|
||||
#endif /* CONFIG_CONSOLE_POLL */
|
||||
@ -1602,7 +1601,7 @@ pch_console_write(struct console *co, const char *s, unsigned int count)
|
||||
* Finally, wait for transmitter to become empty
|
||||
* and restore the IER
|
||||
*/
|
||||
wait_for_xmitr(priv, BOTH_EMPTY);
|
||||
wait_for_xmitr(priv, UART_LSR_BOTH_EMPTY);
|
||||
iowrite8(ier, priv->membase + UART_IER);
|
||||
|
||||
if (port_locked)
|
||||
|
@ -503,7 +503,7 @@ static int pic32_uart_startup(struct uart_port *port)
|
||||
if (!sport->irq_fault_name) {
|
||||
dev_err(port->dev, "%s: kasprintf err!", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto out_done;
|
||||
goto out_disable_clk;
|
||||
}
|
||||
irq_set_status_flags(sport->irq_fault, IRQ_NOAUTOEN);
|
||||
ret = request_irq(sport->irq_fault, pic32_uart_fault_interrupt,
|
||||
@ -579,6 +579,8 @@ static int pic32_uart_startup(struct uart_port *port)
|
||||
out_f:
|
||||
free_irq(sport->irq_fault, port);
|
||||
kfree(sport->irq_fault_name);
|
||||
out_disable_clk:
|
||||
clk_disable_unprepare(sport->clk);
|
||||
out_done:
|
||||
return ret;
|
||||
}
|
||||
|
@ -52,7 +52,6 @@
|
||||
#ifdef CONFIG_PPC_PMAC
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/pmac_feature.h>
|
||||
#include <asm/dbdma.h>
|
||||
#include <asm/macio.h>
|
||||
#else
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/delay.h>
|
||||
@ -575,8 +576,6 @@ static struct uart_driver serial_pxa_reg;
|
||||
|
||||
#ifdef CONFIG_SERIAL_PXA_CONSOLE
|
||||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
/*
|
||||
* Wait for transmitter & holding register to empty
|
||||
*/
|
||||
@ -594,7 +593,7 @@ static void wait_for_xmitr(struct uart_pxa_port *up)
|
||||
if (--tmout == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
|
||||
} while (!uart_lsr_tx_empty(status));
|
||||
|
||||
/* Wait up to 1s for flow control if necessary */
|
||||
if (up->port.flags & UPF_CONS_FLOW) {
|
||||
|
@ -943,52 +943,63 @@ static int qcom_geni_serial_startup(struct uart_port *uport)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long find_clk_rate_in_tol(struct clk *clk, unsigned int desired_clk,
|
||||
unsigned int *clk_div, unsigned int percent_tol)
|
||||
{
|
||||
unsigned long freq;
|
||||
unsigned long div, maxdiv;
|
||||
u64 mult;
|
||||
unsigned long offset, abs_tol, achieved;
|
||||
|
||||
abs_tol = div_u64((u64)desired_clk * percent_tol, 100);
|
||||
maxdiv = CLK_DIV_MSK >> CLK_DIV_SHFT;
|
||||
div = 1;
|
||||
while (div <= maxdiv) {
|
||||
mult = (u64)div * desired_clk;
|
||||
if (mult != (unsigned long)mult)
|
||||
break;
|
||||
|
||||
offset = div * abs_tol;
|
||||
freq = clk_round_rate(clk, mult - offset);
|
||||
|
||||
/* Can only get lower if we're done */
|
||||
if (freq < mult - offset)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Re-calculate div in case rounding skipped rates but we
|
||||
* ended up at a good one, then check for a match.
|
||||
*/
|
||||
div = DIV_ROUND_CLOSEST(freq, desired_clk);
|
||||
achieved = DIV_ROUND_CLOSEST(freq, div);
|
||||
if (achieved <= desired_clk + abs_tol &&
|
||||
achieved >= desired_clk - abs_tol) {
|
||||
*clk_div = div;
|
||||
return freq;
|
||||
}
|
||||
|
||||
div = DIV_ROUND_UP(freq, desired_clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long get_clk_div_rate(struct clk *clk, unsigned int baud,
|
||||
unsigned int sampling_rate, unsigned int *clk_div)
|
||||
{
|
||||
unsigned long ser_clk;
|
||||
unsigned long desired_clk;
|
||||
unsigned long freq, prev;
|
||||
unsigned long div, maxdiv;
|
||||
int64_t mult;
|
||||
|
||||
desired_clk = baud * sampling_rate;
|
||||
if (!desired_clk) {
|
||||
pr_err("%s: Invalid frequency\n", __func__);
|
||||
if (!desired_clk)
|
||||
return 0;
|
||||
}
|
||||
|
||||
maxdiv = CLK_DIV_MSK >> CLK_DIV_SHFT;
|
||||
prev = 0;
|
||||
|
||||
for (div = 1; div <= maxdiv; div++) {
|
||||
mult = div * desired_clk;
|
||||
if (mult > ULONG_MAX)
|
||||
break;
|
||||
|
||||
freq = clk_round_rate(clk, (unsigned long)mult);
|
||||
if (!(freq % desired_clk)) {
|
||||
ser_clk = freq;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!prev)
|
||||
ser_clk = freq;
|
||||
else if (prev == freq)
|
||||
break;
|
||||
|
||||
prev = freq;
|
||||
}
|
||||
|
||||
if (!ser_clk) {
|
||||
pr_err("%s: Can't find matching DFS entry for baud %d\n",
|
||||
__func__, baud);
|
||||
return ser_clk;
|
||||
}
|
||||
|
||||
*clk_div = ser_clk / desired_clk;
|
||||
if (!(*clk_div))
|
||||
*clk_div = 1;
|
||||
/*
|
||||
* try to find a clock rate within 2% tolerance, then within 5%
|
||||
*/
|
||||
ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 2);
|
||||
if (!ser_clk)
|
||||
ser_clk = find_clk_rate_in_tol(clk, desired_clk, clk_div, 5);
|
||||
|
||||
return ser_clk;
|
||||
}
|
||||
@ -1023,8 +1034,15 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
|
||||
|
||||
clk_rate = get_clk_div_rate(port->se.clk, baud,
|
||||
sampling_rate, &clk_div);
|
||||
if (!clk_rate)
|
||||
if (!clk_rate) {
|
||||
dev_err(port->se.dev,
|
||||
"Couldn't find suitable clock rate for %u\n",
|
||||
baud * sampling_rate);
|
||||
goto out_restart_rx;
|
||||
}
|
||||
|
||||
dev_dbg(port->se.dev, "desired_rate-%u, clk_rate-%lu, clk_div-%u\n",
|
||||
baud * sampling_rate, clk_rate, clk_div);
|
||||
|
||||
uport->uartclk = clk_rate;
|
||||
dev_pm_opp_set_rate(uport->dev, clk_rate);
|
||||
|
@ -353,7 +353,7 @@ static void rda_uart_send_chars(struct uart_port *port)
|
||||
|
||||
ch = xmit->buf[xmit->tail];
|
||||
rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER);
|
||||
xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,12 @@
|
||||
#define S3C24XX_SERIAL_MAJOR 204
|
||||
#define S3C24XX_SERIAL_MINOR 64
|
||||
|
||||
#ifdef CONFIG_ARM64
|
||||
#define UART_NR 12
|
||||
#else
|
||||
#define UART_NR CONFIG_SERIAL_SAMSUNG_UARTS
|
||||
#endif
|
||||
|
||||
#define S3C24XX_TX_PIO 1
|
||||
#define S3C24XX_TX_DMA 2
|
||||
#define S3C24XX_RX_PIO 1
|
||||
@ -87,7 +93,7 @@ struct s3c24xx_uart_info {
|
||||
struct s3c24xx_serial_drv_data {
|
||||
const struct s3c24xx_uart_info info;
|
||||
const struct s3c2410_uartcfg def_cfg;
|
||||
const unsigned int fifosize[CONFIG_SERIAL_SAMSUNG_UARTS];
|
||||
const unsigned int fifosize[UART_NR];
|
||||
};
|
||||
|
||||
struct s3c24xx_uart_dma {
|
||||
@ -1011,6 +1017,7 @@ static unsigned int s3c24xx_serial_get_mctrl(struct uart_port *port)
|
||||
static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
unsigned int umcon = rd_regl(port, S3C2410_UMCON);
|
||||
unsigned int ucon = rd_regl(port, S3C2410_UCON);
|
||||
|
||||
if (mctrl & TIOCM_RTS)
|
||||
umcon |= S3C2410_UMCOM_RTS_LOW;
|
||||
@ -1018,6 +1025,13 @@ static void s3c24xx_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
umcon &= ~S3C2410_UMCOM_RTS_LOW;
|
||||
|
||||
wr_regl(port, S3C2410_UMCON, umcon);
|
||||
|
||||
if (mctrl & TIOCM_LOOP)
|
||||
ucon |= S3C2410_UCON_LOOPBACK;
|
||||
else
|
||||
ucon &= ~S3C2410_UCON_LOOPBACK;
|
||||
|
||||
wr_regl(port, S3C2410_UCON, ucon);
|
||||
}
|
||||
|
||||
static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
|
||||
@ -1801,67 +1815,27 @@ static const struct uart_ops apple_s5l_serial_ops = {
|
||||
static struct uart_driver s3c24xx_uart_drv = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "s3c2410_serial",
|
||||
.nr = CONFIG_SERIAL_SAMSUNG_UARTS,
|
||||
.nr = UART_NR,
|
||||
.cons = S3C24XX_SERIAL_CONSOLE,
|
||||
.dev_name = S3C24XX_SERIAL_NAME,
|
||||
.major = S3C24XX_SERIAL_MAJOR,
|
||||
.minor = S3C24XX_SERIAL_MINOR,
|
||||
};
|
||||
|
||||
#define __PORT_LOCK_UNLOCKED(i) \
|
||||
__SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[i].port.lock)
|
||||
static struct s3c24xx_uart_port
|
||||
s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
|
||||
[0] = {
|
||||
.port = {
|
||||
.lock = __PORT_LOCK_UNLOCKED(0),
|
||||
.iotype = UPIO_MEM,
|
||||
.uartclk = 0,
|
||||
.fifosize = 16,
|
||||
.ops = &s3c24xx_serial_ops,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 0,
|
||||
}
|
||||
},
|
||||
[1] = {
|
||||
.port = {
|
||||
.lock = __PORT_LOCK_UNLOCKED(1),
|
||||
.iotype = UPIO_MEM,
|
||||
.uartclk = 0,
|
||||
.fifosize = 16,
|
||||
.ops = &s3c24xx_serial_ops,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 1,
|
||||
}
|
||||
},
|
||||
#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
|
||||
[2] = {
|
||||
.port = {
|
||||
.lock = __PORT_LOCK_UNLOCKED(2),
|
||||
.iotype = UPIO_MEM,
|
||||
.uartclk = 0,
|
||||
.fifosize = 16,
|
||||
.ops = &s3c24xx_serial_ops,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 2,
|
||||
}
|
||||
},
|
||||
#endif
|
||||
#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
|
||||
[3] = {
|
||||
.port = {
|
||||
.lock = __PORT_LOCK_UNLOCKED(3),
|
||||
.iotype = UPIO_MEM,
|
||||
.uartclk = 0,
|
||||
.fifosize = 16,
|
||||
.ops = &s3c24xx_serial_ops,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.line = 3,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
#undef __PORT_LOCK_UNLOCKED
|
||||
static struct s3c24xx_uart_port s3c24xx_serial_ports[UART_NR];
|
||||
|
||||
static void s3c24xx_serial_init_port_default(int index) {
|
||||
struct uart_port *port = &s3c24xx_serial_ports[index].port;
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
|
||||
port->iotype = UPIO_MEM;
|
||||
port->uartclk = 0;
|
||||
port->fifosize = 16;
|
||||
port->ops = &s3c24xx_serial_ops;
|
||||
port->flags = UPF_BOOT_AUTOCONF;
|
||||
port->line = index;
|
||||
}
|
||||
|
||||
/* s3c24xx_serial_resetport
|
||||
*
|
||||
@ -2177,6 +2151,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
|
||||
}
|
||||
ourport = &s3c24xx_serial_ports[index];
|
||||
|
||||
s3c24xx_serial_init_port_default(index);
|
||||
|
||||
ourport->drv_data = s3c24xx_get_driver_data(pdev);
|
||||
if (!ourport->drv_data) {
|
||||
dev_err(&pdev->dev, "could not find driver data\n");
|
||||
@ -2575,7 +2551,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options)
|
||||
|
||||
/* is this a valid port */
|
||||
|
||||
if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
|
||||
if (co->index == -1 || co->index >= UART_NR)
|
||||
co->index = 0;
|
||||
|
||||
port = &s3c24xx_serial_ports[co->index].port;
|
||||
|
@ -1127,7 +1127,7 @@ static void sc16is7xx_set_termios(struct uart_port *port,
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static int sc16is7xx_config_rs485(struct uart_port *port,
|
||||
static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
|
||||
@ -1143,7 +1143,6 @@ static int sc16is7xx_config_rs485(struct uart_port *port,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
port->rs485 = *rs485;
|
||||
one->config.flags |= SC16IS7XX_RECONF_RS485;
|
||||
kthread_queue_work(&s->kworker, &one->reg_work);
|
||||
|
||||
@ -1354,6 +1353,12 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip,
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct serial_rs485 sc16is7xx_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND,
|
||||
.delay_rts_before_send = 1,
|
||||
.delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */
|
||||
};
|
||||
|
||||
static int sc16is7xx_probe(struct device *dev,
|
||||
const struct sc16is7xx_devtype *devtype,
|
||||
struct regmap *regmap, int irq)
|
||||
@ -1456,6 +1461,7 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
s->p[i].port.iotype = UPIO_PORT;
|
||||
s->p[i].port.uartclk = freq;
|
||||
s->p[i].port.rs485_config = sc16is7xx_config_rs485;
|
||||
s->p[i].port.rs485_supported = sc16is7xx_rs485_supported;
|
||||
s->p[i].port.ops = &sc16is7xx_ops;
|
||||
s->p[i].old_mctrl = 0;
|
||||
s->p[i].port.line = sc16is7xx_alloc_line();
|
||||
|
@ -441,7 +441,7 @@ static char tegra_uart_decode_rx_error(struct tegra_uart_port *tup,
|
||||
|
||||
if (unlikely(lsr & TEGRA_UART_LSR_ANY)) {
|
||||
if (lsr & UART_LSR_OE) {
|
||||
/* Overrrun error */
|
||||
/* Overrun error */
|
||||
flag = TTY_OVERRUN;
|
||||
tup->uport.icount.overrun++;
|
||||
dev_dbg(tup->uport.dev, "Got overrun errors\n");
|
||||
@ -1080,7 +1080,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup)
|
||||
tup->rx_in_progress = 1;
|
||||
|
||||
/*
|
||||
* Enable IE_RXS for the receive status interrupts like line errros.
|
||||
* Enable IE_RXS for the receive status interrupts like line errors.
|
||||
* Enable IE_RX_TIMEOUT to get the bytes which cannot be DMA'd.
|
||||
*
|
||||
* EORD is different interrupt than RX_TIMEOUT - RX_TIMEOUT occurs when
|
||||
@ -1667,6 +1667,7 @@ static int __init tegra_uart_init(void)
|
||||
node = of_find_matching_node(NULL, tegra_uart_of_match);
|
||||
if (node)
|
||||
match = of_match_node(tegra_uart_of_match, node);
|
||||
of_node_put(node);
|
||||
if (match)
|
||||
cdata = match->data;
|
||||
if (cdata)
|
||||
|
@ -97,9 +97,16 @@ static inline struct uart_port *uart_port_check(struct uart_state *state)
|
||||
return state->uart_port;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is used by the interrupt handler to schedule processing in
|
||||
* the software interrupt portion of the driver.
|
||||
/**
|
||||
* uart_write_wakeup - schedule write processing
|
||||
* @port: port to be processed
|
||||
*
|
||||
* This routine is used by the interrupt handler to schedule processing in the
|
||||
* software interrupt portion of the driver. A driver is expected to call this
|
||||
* function when the number of characters in the transmit buffer have dropped
|
||||
* below a threshold.
|
||||
*
|
||||
* Locking: @port->lock should be held
|
||||
*/
|
||||
void uart_write_wakeup(struct uart_port *port)
|
||||
{
|
||||
@ -327,13 +334,16 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
|
||||
}
|
||||
|
||||
/**
|
||||
* uart_update_timeout - update per-port FIFO timeout.
|
||||
* @port: uart_port structure describing the port
|
||||
* @cflag: termios cflag value
|
||||
* @baud: speed of the port
|
||||
* uart_update_timeout - update per-port frame timing information
|
||||
* @port: uart_port structure describing the port
|
||||
* @cflag: termios cflag value
|
||||
* @baud: speed of the port
|
||||
*
|
||||
* Set the port FIFO timeout value. The @cflag value should
|
||||
* reflect the actual hardware settings.
|
||||
* Set the @port frame timing information from which the FIFO timeout value is
|
||||
* derived. The @cflag value should reflect the actual hardware settings as
|
||||
* number of bits, parity, stop bits and baud rate is taken into account here.
|
||||
*
|
||||
* Locking: caller is expected to take @port->lock
|
||||
*/
|
||||
void
|
||||
uart_update_timeout(struct uart_port *port, unsigned int cflag,
|
||||
@ -343,35 +353,30 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag,
|
||||
u64 frame_time;
|
||||
|
||||
frame_time = (u64)size * NSEC_PER_SEC;
|
||||
size *= port->fifosize;
|
||||
|
||||
/*
|
||||
* Figure the timeout to send the above number of bits.
|
||||
* Add .02 seconds of slop
|
||||
*/
|
||||
port->timeout = (HZ * size) / baud + HZ/50;
|
||||
port->frame_time = DIV64_U64_ROUND_UP(frame_time, baud);
|
||||
}
|
||||
EXPORT_SYMBOL(uart_update_timeout);
|
||||
|
||||
/**
|
||||
* uart_get_baud_rate - return baud rate for a particular port
|
||||
* @port: uart_port structure describing the port in question.
|
||||
* @termios: desired termios settings.
|
||||
* @old: old termios (or NULL)
|
||||
* @min: minimum acceptable baud rate
|
||||
* @max: maximum acceptable baud rate
|
||||
* uart_get_baud_rate - return baud rate for a particular port
|
||||
* @port: uart_port structure describing the port in question.
|
||||
* @termios: desired termios settings
|
||||
* @old: old termios (or %NULL)
|
||||
* @min: minimum acceptable baud rate
|
||||
* @max: maximum acceptable baud rate
|
||||
*
|
||||
* Decode the termios structure into a numeric baud rate,
|
||||
* taking account of the magic 38400 baud rate (with spd_*
|
||||
* flags), and mapping the %B0 rate to 9600 baud.
|
||||
* Decode the termios structure into a numeric baud rate, taking account of the
|
||||
* magic 38400 baud rate (with spd_* flags), and mapping the %B0 rate to 9600
|
||||
* baud.
|
||||
*
|
||||
* If the new baud rate is invalid, try the old termios setting.
|
||||
* If it's still invalid, we try 9600 baud.
|
||||
* If the new baud rate is invalid, try the @old termios setting. If it's still
|
||||
* invalid, we try 9600 baud.
|
||||
*
|
||||
* Update the @termios structure to reflect the baud rate
|
||||
* we're actually going to be using. Don't do this for the case
|
||||
* where B0 is requested ("hang up").
|
||||
* The @termios structure is updated to reflect the baud rate we're actually
|
||||
* going to be using. Don't do this for the case where B0 is requested ("hang
|
||||
* up").
|
||||
*
|
||||
* Locking: caller dependent
|
||||
*/
|
||||
unsigned int
|
||||
uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
|
||||
@ -456,11 +461,17 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios,
|
||||
EXPORT_SYMBOL(uart_get_baud_rate);
|
||||
|
||||
/**
|
||||
* uart_get_divisor - return uart clock divisor
|
||||
* @port: uart_port structure describing the port.
|
||||
* @baud: desired baud rate
|
||||
* uart_get_divisor - return uart clock divisor
|
||||
* @port: uart_port structure describing the port
|
||||
* @baud: desired baud rate
|
||||
*
|
||||
* Calculate the uart clock divisor for the port.
|
||||
* Calculate the divisor (baud_base / baud) for the specified @baud,
|
||||
* appropriately rounded.
|
||||
*
|
||||
* If 38400 baud and custom divisor is selected, return the custom divisor
|
||||
* instead.
|
||||
*
|
||||
* Locking: caller dependent
|
||||
*/
|
||||
unsigned int
|
||||
uart_get_divisor(struct uart_port *port, unsigned int baud)
|
||||
@ -1023,10 +1034,10 @@ static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss)
|
||||
}
|
||||
|
||||
/**
|
||||
* uart_get_lsr_info - get line status register info
|
||||
* @tty: tty associated with the UART
|
||||
* @state: UART being queried
|
||||
* @value: returned modem value
|
||||
* uart_get_lsr_info - get line status register info
|
||||
* @tty: tty associated with the UART
|
||||
* @state: UART being queried
|
||||
* @value: returned modem value
|
||||
*/
|
||||
static int uart_get_lsr_info(struct tty_struct *tty,
|
||||
struct uart_state *state, unsigned int __user *value)
|
||||
@ -1276,6 +1287,126 @@ static int uart_get_icount(struct tty_struct *tty,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SER_RS485_LEGACY_FLAGS (SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | \
|
||||
SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX | \
|
||||
SER_RS485_TERMINATE_BUS)
|
||||
|
||||
static int uart_check_rs485_flags(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
{
|
||||
u32 flags = rs485->flags;
|
||||
|
||||
/* Don't return -EINVAL for unsupported legacy flags */
|
||||
flags &= ~SER_RS485_LEGACY_FLAGS;
|
||||
|
||||
/*
|
||||
* For any bit outside of the legacy ones that is not supported by
|
||||
* the driver, return -EINVAL.
|
||||
*/
|
||||
if (flags & ~port->rs485_supported.flags)
|
||||
return -EINVAL;
|
||||
|
||||
/* Asking for address w/o addressing mode? */
|
||||
if (!(rs485->flags & SER_RS485_ADDRB) &&
|
||||
(rs485->flags & (SER_RS485_ADDR_RECV|SER_RS485_ADDR_DEST)))
|
||||
return -EINVAL;
|
||||
|
||||
/* Address given but not enabled? */
|
||||
if (!(rs485->flags & SER_RS485_ADDR_RECV) && rs485->addr_recv)
|
||||
return -EINVAL;
|
||||
if (!(rs485->flags & SER_RS485_ADDR_DEST) && rs485->addr_dest)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uart_sanitize_serial_rs485_delays(struct uart_port *port,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
if (!port->rs485_supported.delay_rts_before_send) {
|
||||
if (rs485->delay_rts_before_send) {
|
||||
dev_warn_ratelimited(port->dev,
|
||||
"%s (%d): RTS delay before sending not supported\n",
|
||||
port->name, port->line);
|
||||
}
|
||||
rs485->delay_rts_before_send = 0;
|
||||
} else if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
|
||||
rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY;
|
||||
dev_warn_ratelimited(port->dev,
|
||||
"%s (%d): RTS delay before sending clamped to %u ms\n",
|
||||
port->name, port->line, rs485->delay_rts_before_send);
|
||||
}
|
||||
|
||||
if (!port->rs485_supported.delay_rts_after_send) {
|
||||
if (rs485->delay_rts_after_send) {
|
||||
dev_warn_ratelimited(port->dev,
|
||||
"%s (%d): RTS delay after sending not supported\n",
|
||||
port->name, port->line);
|
||||
}
|
||||
rs485->delay_rts_after_send = 0;
|
||||
} else if (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) {
|
||||
rs485->delay_rts_after_send = RS485_MAX_RTS_DELAY;
|
||||
dev_warn_ratelimited(port->dev,
|
||||
"%s (%d): RTS delay after sending clamped to %u ms\n",
|
||||
port->name, port->line, rs485->delay_rts_after_send);
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485)
|
||||
{
|
||||
u32 supported_flags = port->rs485_supported.flags;
|
||||
|
||||
if (!(rs485->flags & SER_RS485_ENABLED)) {
|
||||
memset(rs485, 0, sizeof(*rs485));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pick sane settings if the user hasn't */
|
||||
if ((supported_flags & (SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND)) &&
|
||||
!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
|
||||
!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
|
||||
dev_warn_ratelimited(port->dev,
|
||||
"%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
|
||||
port->name, port->line);
|
||||
rs485->flags |= SER_RS485_RTS_ON_SEND;
|
||||
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
|
||||
supported_flags |= SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND;
|
||||
}
|
||||
|
||||
rs485->flags &= supported_flags;
|
||||
|
||||
uart_sanitize_serial_rs485_delays(port, rs485);
|
||||
|
||||
/* Return clean padding area to userspace */
|
||||
memset(rs485->padding0, 0, sizeof(rs485->padding0));
|
||||
memset(rs485->padding1, 0, sizeof(rs485->padding1));
|
||||
}
|
||||
|
||||
static void uart_set_rs485_termination(struct uart_port *port,
|
||||
const struct serial_rs485 *rs485)
|
||||
{
|
||||
if (!(rs485->flags & SER_RS485_ENABLED))
|
||||
return;
|
||||
|
||||
gpiod_set_value_cansleep(port->rs485_term_gpio,
|
||||
!!(rs485->flags & SER_RS485_TERMINATE_BUS));
|
||||
}
|
||||
|
||||
int uart_rs485_config(struct uart_port *port)
|
||||
{
|
||||
struct serial_rs485 *rs485 = &port->rs485;
|
||||
int ret;
|
||||
|
||||
uart_sanitize_serial_rs485(port, rs485);
|
||||
uart_set_rs485_termination(port, rs485);
|
||||
|
||||
ret = port->rs485_config(port, NULL, rs485);
|
||||
if (ret)
|
||||
memset(rs485, 0, sizeof(*rs485));
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_rs485_config);
|
||||
|
||||
static int uart_get_rs485_config(struct uart_port *port,
|
||||
struct serial_rs485 __user *rs485)
|
||||
{
|
||||
@ -1292,7 +1423,7 @@ static int uart_get_rs485_config(struct uart_port *port,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uart_set_rs485_config(struct uart_port *port,
|
||||
static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
|
||||
struct serial_rs485 __user *rs485_user)
|
||||
{
|
||||
struct serial_rs485 rs485;
|
||||
@ -1305,34 +1436,14 @@ static int uart_set_rs485_config(struct uart_port *port,
|
||||
if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user)))
|
||||
return -EFAULT;
|
||||
|
||||
/* pick sane settings if the user hasn't */
|
||||
if (!(rs485.flags & SER_RS485_RTS_ON_SEND) ==
|
||||
!(rs485.flags & SER_RS485_RTS_AFTER_SEND)) {
|
||||
dev_warn_ratelimited(port->dev,
|
||||
"%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
|
||||
port->name, port->line);
|
||||
rs485.flags |= SER_RS485_RTS_ON_SEND;
|
||||
rs485.flags &= ~SER_RS485_RTS_AFTER_SEND;
|
||||
}
|
||||
|
||||
if (rs485.delay_rts_before_send > RS485_MAX_RTS_DELAY) {
|
||||
rs485.delay_rts_before_send = RS485_MAX_RTS_DELAY;
|
||||
dev_warn_ratelimited(port->dev,
|
||||
"%s (%d): RTS delay before sending clamped to %u ms\n",
|
||||
port->name, port->line, rs485.delay_rts_before_send);
|
||||
}
|
||||
|
||||
if (rs485.delay_rts_after_send > RS485_MAX_RTS_DELAY) {
|
||||
rs485.delay_rts_after_send = RS485_MAX_RTS_DELAY;
|
||||
dev_warn_ratelimited(port->dev,
|
||||
"%s (%d): RTS delay after sending clamped to %u ms\n",
|
||||
port->name, port->line, rs485.delay_rts_after_send);
|
||||
}
|
||||
/* Return clean padding area to userspace */
|
||||
memset(rs485.padding, 0, sizeof(rs485.padding));
|
||||
ret = uart_check_rs485_flags(port, &rs485);
|
||||
if (ret)
|
||||
return ret;
|
||||
uart_sanitize_serial_rs485(port, &rs485);
|
||||
uart_set_rs485_termination(port, &rs485);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
ret = port->rs485_config(port, &rs485);
|
||||
ret = port->rs485_config(port, &tty->termios, &rs485);
|
||||
if (!ret)
|
||||
port->rs485 = rs485;
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
@ -1441,6 +1552,10 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
||||
if (ret != -ENOIOCTLCMD)
|
||||
goto out;
|
||||
|
||||
/* rs485_config requires more locking than others */
|
||||
if (cmd == TIOCGRS485)
|
||||
down_write(&tty->termios_rwsem);
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
uport = uart_port_check(state);
|
||||
|
||||
@ -1464,7 +1579,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
||||
break;
|
||||
|
||||
case TIOCSRS485:
|
||||
ret = uart_set_rs485_config(uport, uarg);
|
||||
ret = uart_set_rs485_config(tty, uport, uarg);
|
||||
break;
|
||||
|
||||
case TIOCSISO7816:
|
||||
@ -1481,6 +1596,8 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
||||
}
|
||||
out_up:
|
||||
mutex_unlock(&port->mutex);
|
||||
if (cmd == TIOCGRS485)
|
||||
up_write(&tty->termios_rwsem);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@ -1628,7 +1745,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
{
|
||||
struct uart_state *state = tty->driver_data;
|
||||
struct uart_port *port;
|
||||
unsigned long char_time, expire;
|
||||
unsigned long char_time, expire, fifo_timeout;
|
||||
|
||||
port = uart_port_ref(state);
|
||||
if (!port)
|
||||
@ -1658,12 +1775,13 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
* amount of time to send the entire FIFO, it probably won't
|
||||
* ever clear. This assumes the UART isn't doing flow
|
||||
* control, which is currently the case. Hence, if it ever
|
||||
* takes longer than port->timeout, this is probably due to a
|
||||
* takes longer than FIFO timeout, this is probably due to a
|
||||
* UART bug of some kind. So, we clamp the timeout parameter at
|
||||
* 2*port->timeout.
|
||||
* 2 * FIFO timeout.
|
||||
*/
|
||||
if (timeout == 0 || timeout > 2 * port->timeout)
|
||||
timeout = 2 * port->timeout;
|
||||
fifo_timeout = uart_fifo_timeout(port);
|
||||
if (timeout == 0 || timeout > 2 * fifo_timeout)
|
||||
timeout = 2 * fifo_timeout;
|
||||
}
|
||||
|
||||
expire = jiffies + timeout;
|
||||
@ -1949,11 +2067,11 @@ static void uart_port_spin_lock_init(struct uart_port *port)
|
||||
|
||||
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
|
||||
/**
|
||||
* uart_console_write - write a console message to a serial port
|
||||
* @port: the port to write the message
|
||||
* @s: array of characters
|
||||
* @count: number of characters in string to write
|
||||
* @putchar: function to write character to port
|
||||
* uart_console_write - write a console message to a serial port
|
||||
* @port: the port to write the message
|
||||
* @s: array of characters
|
||||
* @count: number of characters in string to write
|
||||
* @putchar: function to write character to port
|
||||
*/
|
||||
void uart_console_write(struct uart_port *port, const char *s,
|
||||
unsigned int count,
|
||||
@ -1969,10 +2087,15 @@ void uart_console_write(struct uart_port *port, const char *s,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_console_write);
|
||||
|
||||
/*
|
||||
* Check whether an invalid uart number has been specified, and
|
||||
* if so, search for the first available port that does have
|
||||
* console support.
|
||||
/**
|
||||
* uart_get_console - get uart port for console
|
||||
* @ports: ports to search in
|
||||
* @nr: number of @ports
|
||||
* @co: console to search for
|
||||
* Returns: uart_port for the console @co
|
||||
*
|
||||
* Check whether an invalid uart number has been specified (as @co->index), and
|
||||
* if so, search for the first available port that does have console support.
|
||||
*/
|
||||
struct uart_port * __init
|
||||
uart_get_console(struct uart_port *ports, int nr, struct console *co)
|
||||
@ -1992,24 +2115,23 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co)
|
||||
}
|
||||
|
||||
/**
|
||||
* uart_parse_earlycon - Parse earlycon options
|
||||
* @p: ptr to 2nd field (ie., just beyond '<name>,')
|
||||
* @iotype: ptr for decoded iotype (out)
|
||||
* @addr: ptr for decoded mapbase/iobase (out)
|
||||
* @options: ptr for <options> field; NULL if not present (out)
|
||||
* uart_parse_earlycon - Parse earlycon options
|
||||
* @p: ptr to 2nd field (ie., just beyond '<name>,')
|
||||
* @iotype: ptr for decoded iotype (out)
|
||||
* @addr: ptr for decoded mapbase/iobase (out)
|
||||
* @options: ptr for <options> field; %NULL if not present (out)
|
||||
*
|
||||
* Decodes earlycon kernel command line parameters of the form
|
||||
* earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
|
||||
* console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
|
||||
* Decodes earlycon kernel command line parameters of the form:
|
||||
* * earlycon=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
|
||||
* * console=<name>,io|mmio|mmio16|mmio32|mmio32be|mmio32native,<addr>,<options>
|
||||
*
|
||||
* The optional form
|
||||
* The optional form:
|
||||
* * earlycon=<name>,0x<addr>,<options>
|
||||
* * console=<name>,0x<addr>,<options>
|
||||
*
|
||||
* earlycon=<name>,0x<addr>,<options>
|
||||
* console=<name>,0x<addr>,<options>
|
||||
* is also accepted; the returned @iotype will be %UPIO_MEM.
|
||||
*
|
||||
* is also accepted; the returned @iotype will be UPIO_MEM.
|
||||
*
|
||||
* Returns 0 on success or -EINVAL on failure
|
||||
* Returns: 0 on success or -%EINVAL on failure
|
||||
*/
|
||||
int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
|
||||
char **options)
|
||||
@ -2054,16 +2176,16 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
|
||||
EXPORT_SYMBOL_GPL(uart_parse_earlycon);
|
||||
|
||||
/**
|
||||
* uart_parse_options - Parse serial port baud/parity/bits/flow control.
|
||||
* @options: pointer to option string
|
||||
* @baud: pointer to an 'int' variable for the baud rate.
|
||||
* @parity: pointer to an 'int' variable for the parity.
|
||||
* @bits: pointer to an 'int' variable for the number of data bits.
|
||||
* @flow: pointer to an 'int' variable for the flow control character.
|
||||
* uart_parse_options - Parse serial port baud/parity/bits/flow control.
|
||||
* @options: pointer to option string
|
||||
* @baud: pointer to an 'int' variable for the baud rate.
|
||||
* @parity: pointer to an 'int' variable for the parity.
|
||||
* @bits: pointer to an 'int' variable for the number of data bits.
|
||||
* @flow: pointer to an 'int' variable for the flow control character.
|
||||
*
|
||||
* uart_parse_options decodes a string containing the serial console
|
||||
* options. The format of the string is <baud><parity><bits><flow>,
|
||||
* eg: 115200n8r
|
||||
* uart_parse_options() decodes a string containing the serial console
|
||||
* options. The format of the string is <baud><parity><bits><flow>,
|
||||
* eg: 115200n8r
|
||||
*/
|
||||
void
|
||||
uart_parse_options(const char *options, int *baud, int *parity,
|
||||
@ -2084,13 +2206,13 @@ uart_parse_options(const char *options, int *baud, int *parity,
|
||||
EXPORT_SYMBOL_GPL(uart_parse_options);
|
||||
|
||||
/**
|
||||
* uart_set_options - setup the serial console parameters
|
||||
* @port: pointer to the serial ports uart_port structure
|
||||
* @co: console pointer
|
||||
* @baud: baud rate
|
||||
* @parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
|
||||
* @bits: number of data bits
|
||||
* @flow: flow control character - 'r' (rts)
|
||||
* uart_set_options - setup the serial console parameters
|
||||
* @port: pointer to the serial ports uart_port structure
|
||||
* @co: console pointer
|
||||
* @baud: baud rate
|
||||
* @parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
|
||||
* @bits: number of data bits
|
||||
* @flow: flow control character - 'r' (rts)
|
||||
*/
|
||||
int
|
||||
uart_set_options(struct uart_port *port, struct console *co,
|
||||
@ -2577,17 +2699,19 @@ static const struct tty_port_operations uart_port_ops = {
|
||||
};
|
||||
|
||||
/**
|
||||
* uart_register_driver - register a driver with the uart core layer
|
||||
* @drv: low level driver structure
|
||||
* uart_register_driver - register a driver with the uart core layer
|
||||
* @drv: low level driver structure
|
||||
*
|
||||
* Register a uart driver with the core driver. We in turn register
|
||||
* with the tty layer, and initialise the core driver per-port state.
|
||||
* Register a uart driver with the core driver. We in turn register with the
|
||||
* tty layer, and initialise the core driver per-port state.
|
||||
*
|
||||
* We have a proc file in /proc/tty/driver which is named after the
|
||||
* normal driver.
|
||||
* We have a proc file in /proc/tty/driver which is named after the normal
|
||||
* driver.
|
||||
*
|
||||
* drv->port should be NULL, and the per-port structures should be
|
||||
* registered using uart_add_one_port after this call has succeeded.
|
||||
* @drv->port should be %NULL, and the per-port structures should be registered
|
||||
* using uart_add_one_port() after this call has succeeded.
|
||||
*
|
||||
* Locking: none, Interrupts: enabled
|
||||
*/
|
||||
int uart_register_driver(struct uart_driver *drv)
|
||||
{
|
||||
@ -2651,13 +2775,14 @@ int uart_register_driver(struct uart_driver *drv)
|
||||
EXPORT_SYMBOL(uart_register_driver);
|
||||
|
||||
/**
|
||||
* uart_unregister_driver - remove a driver from the uart core layer
|
||||
* @drv: low level driver structure
|
||||
* uart_unregister_driver - remove a driver from the uart core layer
|
||||
* @drv: low level driver structure
|
||||
*
|
||||
* Remove all references to a driver from the core driver. The low
|
||||
* level driver must have removed all its ports via the
|
||||
* uart_remove_one_port() if it registered them with uart_add_one_port().
|
||||
* (ie, drv->port == NULL)
|
||||
* Remove all references to a driver from the core driver. The low level
|
||||
* driver must have removed all its ports via the uart_remove_one_port() if it
|
||||
* registered them with uart_add_one_port(). (I.e. @drv->port is %NULL.)
|
||||
*
|
||||
* Locking: none, Interrupts: enabled
|
||||
*/
|
||||
void uart_unregister_driver(struct uart_driver *drv)
|
||||
{
|
||||
@ -2906,16 +3031,15 @@ static const struct attribute_group tty_dev_attr_group = {
|
||||
};
|
||||
|
||||
/**
|
||||
* uart_add_one_port - attach a driver-defined port structure
|
||||
* @drv: pointer to the uart low level driver structure for this port
|
||||
* @uport: uart port structure to use for this port.
|
||||
* uart_add_one_port - attach a driver-defined port structure
|
||||
* @drv: pointer to the uart low level driver structure for this port
|
||||
* @uport: uart port structure to use for this port.
|
||||
*
|
||||
* Context: task context, might sleep
|
||||
* Context: task context, might sleep
|
||||
*
|
||||
* This allows the driver to register its own uart_port structure
|
||||
* with the core driver. The main purpose is to allow the low
|
||||
* level uart drivers to expand uart_port, rather than having yet
|
||||
* more levels of structures.
|
||||
* This allows the driver @drv to register its own uart_port structure with the
|
||||
* core driver. The main purpose is to allow the low level uart drivers to
|
||||
* expand uart_port, rather than having yet more levels of structures.
|
||||
*/
|
||||
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
{
|
||||
@ -3010,15 +3134,14 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
EXPORT_SYMBOL(uart_add_one_port);
|
||||
|
||||
/**
|
||||
* uart_remove_one_port - detach a driver defined port structure
|
||||
* @drv: pointer to the uart low level driver structure for this port
|
||||
* @uport: uart port structure for this port
|
||||
* uart_remove_one_port - detach a driver defined port structure
|
||||
* @drv: pointer to the uart low level driver structure for this port
|
||||
* @uport: uart port structure for this port
|
||||
*
|
||||
* Context: task context, might sleep
|
||||
* Context: task context, might sleep
|
||||
*
|
||||
* This unhooks (and hangs up) the specified port structure from the
|
||||
* core driver. No further calls will be made to the low-level code
|
||||
* for this port.
|
||||
* This unhooks (and hangs up) the specified port structure from the core
|
||||
* driver. No further calls will be made to the low-level code for this port.
|
||||
*/
|
||||
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
{
|
||||
@ -3090,8 +3213,13 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
|
||||
}
|
||||
EXPORT_SYMBOL(uart_remove_one_port);
|
||||
|
||||
/*
|
||||
* Are the two ports equivalent?
|
||||
/**
|
||||
* uart_match_port - are the two ports equivalent?
|
||||
* @port1: first port
|
||||
* @port2: second port
|
||||
*
|
||||
* This utility function can be used to determine whether two uart_port
|
||||
* structures describe the same port.
|
||||
*/
|
||||
bool uart_match_port(const struct uart_port *port1,
|
||||
const struct uart_port *port2)
|
||||
@ -3119,11 +3247,11 @@ bool uart_match_port(const struct uart_port *port1,
|
||||
EXPORT_SYMBOL(uart_match_port);
|
||||
|
||||
/**
|
||||
* uart_handle_dcd_change - handle a change of carrier detect state
|
||||
* @uport: uart_port structure for the open port
|
||||
* @status: new carrier detect status, nonzero if active
|
||||
* uart_handle_dcd_change - handle a change of carrier detect state
|
||||
* @uport: uart_port structure for the open port
|
||||
* @status: new carrier detect status, nonzero if active
|
||||
*
|
||||
* Caller must hold uport->lock
|
||||
* Caller must hold uport->lock.
|
||||
*/
|
||||
void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
|
||||
{
|
||||
@ -3154,11 +3282,11 @@ void uart_handle_dcd_change(struct uart_port *uport, unsigned int status)
|
||||
EXPORT_SYMBOL_GPL(uart_handle_dcd_change);
|
||||
|
||||
/**
|
||||
* uart_handle_cts_change - handle a change of clear-to-send state
|
||||
* @uport: uart_port structure for the open port
|
||||
* @status: new clear to send status, nonzero if active
|
||||
* uart_handle_cts_change - handle a change of clear-to-send state
|
||||
* @uport: uart_port structure for the open port
|
||||
* @status: new clear to send status, nonzero if active
|
||||
*
|
||||
* Caller must hold uport->lock
|
||||
* Caller must hold uport->lock.
|
||||
*/
|
||||
void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
|
||||
{
|
||||
@ -3229,15 +3357,15 @@ static void uart_sysrq_on(struct work_struct *w)
|
||||
static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on);
|
||||
|
||||
/**
|
||||
* uart_try_toggle_sysrq - Enables SysRq from serial line
|
||||
* @port: uart_port structure where char(s) after BREAK met
|
||||
* @ch: new character in the sequence after received BREAK
|
||||
* uart_try_toggle_sysrq - Enables SysRq from serial line
|
||||
* @port: uart_port structure where char(s) after BREAK met
|
||||
* @ch: new character in the sequence after received BREAK
|
||||
*
|
||||
* Enables magic SysRq when the required sequence is met on port
|
||||
* (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE).
|
||||
* Enables magic SysRq when the required sequence is met on port
|
||||
* (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE).
|
||||
*
|
||||
* Returns false if @ch is out of enabling sequence and should be
|
||||
* handled some other way, true if @ch was consumed.
|
||||
* Returns: %false if @ch is out of enabling sequence and should be
|
||||
* handled some other way, %true if @ch was consumed.
|
||||
*/
|
||||
bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
|
||||
{
|
||||
@ -3289,6 +3417,8 @@ int uart_get_rs485_mode(struct uart_port *port)
|
||||
rs485conf->delay_rts_after_send = 0;
|
||||
}
|
||||
|
||||
uart_sanitize_serial_rs485_delays(port, rs485conf);
|
||||
|
||||
/*
|
||||
* Clear full-duplex and enabled flags, set RTS polarity to active high
|
||||
* to get to a defined state with the following properties:
|
||||
@ -3321,10 +3451,20 @@ int uart_get_rs485_mode(struct uart_port *port)
|
||||
port->rs485_term_gpio = NULL;
|
||||
return dev_err_probe(dev, ret, "Cannot get rs485-term-gpios\n");
|
||||
}
|
||||
if (port->rs485_term_gpio)
|
||||
port->rs485_supported.flags |= SER_RS485_TERMINATE_BUS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(uart_get_rs485_mode);
|
||||
|
||||
/* Compile-time assertions for serial_rs485 layout */
|
||||
static_assert(offsetof(struct serial_rs485, padding) ==
|
||||
(offsetof(struct serial_rs485, delay_rts_after_send) + sizeof(__u32)));
|
||||
static_assert(offsetof(struct serial_rs485, padding1) ==
|
||||
offsetof(struct serial_rs485, padding[1]));
|
||||
static_assert((offsetof(struct serial_rs485, padding[4]) + sizeof(__u32)) ==
|
||||
sizeof(struct serial_rs485));
|
||||
|
||||
MODULE_DESCRIPTION("Serial driver core");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -42,6 +42,13 @@ static bool mctrl_gpio_flags_is_dir_out(unsigned int idx)
|
||||
return mctrl_gpios_desc[idx].flags & GPIOD_FLAGS_BIT_DIR_OUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* mctrl_gpio_set - set gpios according to mctrl state
|
||||
* @gpios: gpios to set
|
||||
* @mctrl: state to set
|
||||
*
|
||||
* Set the gpios according to the mctrl state.
|
||||
*/
|
||||
void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
@ -63,6 +70,12 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_set);
|
||||
|
||||
/**
|
||||
* mctrl_gpio_to_gpiod - obtain gpio_desc of modem line index
|
||||
* @gpios: gpios to look into
|
||||
* @gidx: index of the modem line
|
||||
* Returns: the gpio_desc structure associated to the modem line index
|
||||
*/
|
||||
struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||
enum mctrl_gpio_idx gidx)
|
||||
{
|
||||
@ -73,6 +86,14 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_to_gpiod);
|
||||
|
||||
/**
|
||||
* mctrl_gpio_get - update mctrl with the gpios values.
|
||||
* @gpios: gpios to get the info from
|
||||
* @mctrl: mctrl to set
|
||||
* Returns: modified mctrl (the same value as in @mctrl)
|
||||
*
|
||||
* Update mctrl with the gpios values.
|
||||
*/
|
||||
unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
@ -189,6 +210,17 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* mctrl_gpio_init - initialize uart gpios
|
||||
* @port: port to initialize gpios for
|
||||
* @idx: index of the gpio in the @port's device
|
||||
*
|
||||
* This will get the {cts,rts,...}-gpios from device tree if they are present
|
||||
* and request them, set direction etc, and return an allocated structure.
|
||||
* `devm_*` functions are used, so there's no need to call mctrl_gpio_free().
|
||||
* As this sets up the irq handling, make sure to not handle changes to the
|
||||
* gpio input lines in your driver, too.
|
||||
*/
|
||||
struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
|
||||
{
|
||||
struct mctrl_gpios *gpios;
|
||||
@ -235,6 +267,14 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
|
||||
|
||||
/**
|
||||
* mctrl_gpio_free - explicitly free uart gpios
|
||||
* @dev: uart port's device
|
||||
* @gpios: gpios structure to be freed
|
||||
*
|
||||
* This will free the requested gpios in mctrl_gpio_init(). As `devm_*`
|
||||
* functions are used, there's generally no need to call this function.
|
||||
*/
|
||||
void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
@ -253,6 +293,10 @@ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_free);
|
||||
|
||||
/**
|
||||
* mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines
|
||||
* @gpios: gpios to enable
|
||||
*/
|
||||
void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
@ -278,6 +322,10 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
|
||||
|
||||
/**
|
||||
* mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines
|
||||
* @gpios: gpios to disable
|
||||
*/
|
||||
void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
|
||||
{
|
||||
enum mctrl_gpio_idx i;
|
||||
|
@ -4,16 +4,6 @@
|
||||
* Copyright (C) 2018 Paul Walmsley <paul@pwsan.com>
|
||||
* Copyright (C) 2018-2019 SiFive
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Based partially on:
|
||||
* - drivers/tty/serial/pxa.c
|
||||
* - drivers/tty/serial/amba-pl011.c
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
@ -35,6 +35,75 @@
|
||||
#include "serial_mctrl_gpio.h"
|
||||
#include "stm32-usart.h"
|
||||
|
||||
|
||||
/* Register offsets */
|
||||
static struct stm32_usart_info stm32f4_info = {
|
||||
.ofs = {
|
||||
.isr = 0x00,
|
||||
.rdr = 0x04,
|
||||
.tdr = 0x04,
|
||||
.brr = 0x08,
|
||||
.cr1 = 0x0c,
|
||||
.cr2 = 0x10,
|
||||
.cr3 = 0x14,
|
||||
.gtpr = 0x18,
|
||||
.rtor = UNDEF_REG,
|
||||
.rqr = UNDEF_REG,
|
||||
.icr = UNDEF_REG,
|
||||
},
|
||||
.cfg = {
|
||||
.uart_enable_bit = 13,
|
||||
.has_7bits_data = false,
|
||||
.fifosize = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct stm32_usart_info stm32f7_info = {
|
||||
.ofs = {
|
||||
.cr1 = 0x00,
|
||||
.cr2 = 0x04,
|
||||
.cr3 = 0x08,
|
||||
.brr = 0x0c,
|
||||
.gtpr = 0x10,
|
||||
.rtor = 0x14,
|
||||
.rqr = 0x18,
|
||||
.isr = 0x1c,
|
||||
.icr = 0x20,
|
||||
.rdr = 0x24,
|
||||
.tdr = 0x28,
|
||||
},
|
||||
.cfg = {
|
||||
.uart_enable_bit = 0,
|
||||
.has_7bits_data = true,
|
||||
.has_swap = true,
|
||||
.fifosize = 1,
|
||||
}
|
||||
};
|
||||
|
||||
static struct stm32_usart_info stm32h7_info = {
|
||||
.ofs = {
|
||||
.cr1 = 0x00,
|
||||
.cr2 = 0x04,
|
||||
.cr3 = 0x08,
|
||||
.brr = 0x0c,
|
||||
.gtpr = 0x10,
|
||||
.rtor = 0x14,
|
||||
.rqr = 0x18,
|
||||
.isr = 0x1c,
|
||||
.icr = 0x20,
|
||||
.rdr = 0x24,
|
||||
.tdr = 0x28,
|
||||
},
|
||||
.cfg = {
|
||||
.uart_enable_bit = 0,
|
||||
.has_7bits_data = true,
|
||||
.has_swap = true,
|
||||
.has_wakeup = true,
|
||||
.has_fifo = true,
|
||||
.fifosize = 16,
|
||||
}
|
||||
};
|
||||
|
||||
static void stm32_usart_stop_tx(struct uart_port *port);
|
||||
static void stm32_usart_transmit_chars(struct uart_port *port);
|
||||
static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, unsigned char ch);
|
||||
@ -99,7 +168,7 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
|
||||
*cr1 |= rs485_deat_dedt;
|
||||
}
|
||||
|
||||
static int stm32_usart_config_rs485(struct uart_port *port,
|
||||
static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *termios,
|
||||
struct serial_rs485 *rs485conf)
|
||||
{
|
||||
struct stm32_port *stm32_port = to_stm32_port(port);
|
||||
@ -1377,6 +1446,13 @@ static void stm32_usart_deinit_port(struct stm32_port *stm32port)
|
||||
clk_disable_unprepare(stm32port->clk);
|
||||
}
|
||||
|
||||
static const struct serial_rs485 stm32_rs485_supported = {
|
||||
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
|
||||
SER_RS485_RX_DURING_TX,
|
||||
.delay_rts_before_send = 1,
|
||||
.delay_rts_after_send = 1,
|
||||
};
|
||||
|
||||
static int stm32_usart_init_port(struct stm32_port *stm32port,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
@ -1396,6 +1472,7 @@ static int stm32_usart_init_port(struct stm32_port *stm32port,
|
||||
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE);
|
||||
port->irq = irq;
|
||||
port->rs485_config = stm32_usart_config_rs485;
|
||||
port->rs485_supported = stm32_rs485_supported;
|
||||
|
||||
ret = stm32_usart_init_rs485(port, pdev);
|
||||
if (ret)
|
||||
|
@ -38,74 +38,6 @@ struct stm32_usart_info {
|
||||
|
||||
#define UNDEF_REG 0xff
|
||||
|
||||
/* Register offsets */
|
||||
struct stm32_usart_info stm32f4_info = {
|
||||
.ofs = {
|
||||
.isr = 0x00,
|
||||
.rdr = 0x04,
|
||||
.tdr = 0x04,
|
||||
.brr = 0x08,
|
||||
.cr1 = 0x0c,
|
||||
.cr2 = 0x10,
|
||||
.cr3 = 0x14,
|
||||
.gtpr = 0x18,
|
||||
.rtor = UNDEF_REG,
|
||||
.rqr = UNDEF_REG,
|
||||
.icr = UNDEF_REG,
|
||||
},
|
||||
.cfg = {
|
||||
.uart_enable_bit = 13,
|
||||
.has_7bits_data = false,
|
||||
.fifosize = 1,
|
||||
}
|
||||
};
|
||||
|
||||
struct stm32_usart_info stm32f7_info = {
|
||||
.ofs = {
|
||||
.cr1 = 0x00,
|
||||
.cr2 = 0x04,
|
||||
.cr3 = 0x08,
|
||||
.brr = 0x0c,
|
||||
.gtpr = 0x10,
|
||||
.rtor = 0x14,
|
||||
.rqr = 0x18,
|
||||
.isr = 0x1c,
|
||||
.icr = 0x20,
|
||||
.rdr = 0x24,
|
||||
.tdr = 0x28,
|
||||
},
|
||||
.cfg = {
|
||||
.uart_enable_bit = 0,
|
||||
.has_7bits_data = true,
|
||||
.has_swap = true,
|
||||
.fifosize = 1,
|
||||
}
|
||||
};
|
||||
|
||||
struct stm32_usart_info stm32h7_info = {
|
||||
.ofs = {
|
||||
.cr1 = 0x00,
|
||||
.cr2 = 0x04,
|
||||
.cr3 = 0x08,
|
||||
.brr = 0x0c,
|
||||
.gtpr = 0x10,
|
||||
.rtor = 0x14,
|
||||
.rqr = 0x18,
|
||||
.isr = 0x1c,
|
||||
.icr = 0x20,
|
||||
.rdr = 0x24,
|
||||
.tdr = 0x28,
|
||||
},
|
||||
.cfg = {
|
||||
.uart_enable_bit = 0,
|
||||
.has_7bits_data = true,
|
||||
.has_swap = true,
|
||||
.has_wakeup = true,
|
||||
.has_fifo = true,
|
||||
.fifosize = 16,
|
||||
}
|
||||
};
|
||||
|
||||
/* USART_SR (F4) / USART_ISR (F7) */
|
||||
#define USART_SR_PE BIT(0)
|
||||
#define USART_SR_FE BIT(1)
|
||||
|
@ -1249,8 +1249,6 @@ static int sunsu_kbd_ms_init(struct uart_sunsu_port *up)
|
||||
|
||||
#ifdef CONFIG_SERIAL_SUNSU_CONSOLE
|
||||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
/*
|
||||
* Wait for transmitter & holding register to empty
|
||||
*/
|
||||
@ -1268,7 +1266,7 @@ static void wait_for_xmitr(struct uart_sunsu_port *up)
|
||||
if (--tmout == 0)
|
||||
break;
|
||||
udelay(1);
|
||||
} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
|
||||
} while (!uart_lsr_tx_empty(status));
|
||||
|
||||
/* Wait up to 1s for flow control if necessary */
|
||||
if (up->port.flags & UPF_CONS_FLOW) {
|
||||
|
@ -1137,6 +1137,8 @@ static unsigned int soc_info(unsigned int *rev_h, unsigned int *rev_l)
|
||||
/* No compatible property, so try the name. */
|
||||
soc_string = np->name;
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
/* Extract the SOC number from the "PowerPC," string */
|
||||
if ((sscanf(soc_string, "PowerPC,%u", &soc) != 1) || !soc)
|
||||
return 0;
|
||||
|
@ -1,934 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Driver for NEC VR4100 series Serial Interface Unit.
|
||||
*
|
||||
* Copyright (C) 2004-2008 Yoichi Yuasa <yuasa@linux-mips.org>
|
||||
*
|
||||
* Based on drivers/serial/8250.c, by Russell King.
|
||||
*/
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial_reg.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <asm/vr41xx/siu.h>
|
||||
#include <asm/vr41xx/vr41xx.h>
|
||||
|
||||
#define SIU_BAUD_BASE 1152000
|
||||
#define SIU_MAJOR 204
|
||||
#define SIU_MINOR_BASE 82
|
||||
|
||||
#define RX_MAX_COUNT 256
|
||||
#define TX_MAX_COUNT 15
|
||||
|
||||
#define SIUIRSEL 0x08
|
||||
#define TMICMODE 0x20
|
||||
#define TMICTX 0x10
|
||||
#define IRMSEL 0x0c
|
||||
#define IRMSEL_HP 0x08
|
||||
#define IRMSEL_TEMIC 0x04
|
||||
#define IRMSEL_SHARP 0x00
|
||||
#define IRUSESEL 0x02
|
||||
#define SIRSEL 0x01
|
||||
|
||||
static struct uart_port siu_uart_ports[SIU_PORTS_MAX] = {
|
||||
[0 ... SIU_PORTS_MAX-1] = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(siu_uart_ports->lock),
|
||||
.irq = 0,
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
|
||||
static uint8_t lsr_break_flag[SIU_PORTS_MAX];
|
||||
#endif
|
||||
|
||||
#define siu_read(port, offset) readb((port)->membase + (offset))
|
||||
#define siu_write(port, offset, value) writeb((value), (port)->membase + (offset))
|
||||
|
||||
void vr41xx_select_siu_interface(siu_interface_t interface)
|
||||
{
|
||||
struct uart_port *port;
|
||||
unsigned long flags;
|
||||
uint8_t irsel;
|
||||
|
||||
port = &siu_uart_ports[0];
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
irsel = siu_read(port, SIUIRSEL);
|
||||
if (interface == SIU_INTERFACE_IRDA)
|
||||
irsel |= SIRSEL;
|
||||
else
|
||||
irsel &= ~SIRSEL;
|
||||
siu_write(port, SIUIRSEL, irsel);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vr41xx_select_siu_interface);
|
||||
|
||||
void vr41xx_use_irda(irda_use_t use)
|
||||
{
|
||||
struct uart_port *port;
|
||||
unsigned long flags;
|
||||
uint8_t irsel;
|
||||
|
||||
port = &siu_uart_ports[0];
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
irsel = siu_read(port, SIUIRSEL);
|
||||
if (use == FIR_USE_IRDA)
|
||||
irsel |= IRUSESEL;
|
||||
else
|
||||
irsel &= ~IRUSESEL;
|
||||
siu_write(port, SIUIRSEL, irsel);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vr41xx_use_irda);
|
||||
|
||||
void vr41xx_select_irda_module(irda_module_t module, irda_speed_t speed)
|
||||
{
|
||||
struct uart_port *port;
|
||||
unsigned long flags;
|
||||
uint8_t irsel;
|
||||
|
||||
port = &siu_uart_ports[0];
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
irsel = siu_read(port, SIUIRSEL);
|
||||
irsel &= ~(IRMSEL | TMICTX | TMICMODE);
|
||||
switch (module) {
|
||||
case SHARP_IRDA:
|
||||
irsel |= IRMSEL_SHARP;
|
||||
break;
|
||||
case TEMIC_IRDA:
|
||||
irsel |= IRMSEL_TEMIC | TMICMODE;
|
||||
if (speed == IRDA_TX_4MBPS)
|
||||
irsel |= TMICTX;
|
||||
break;
|
||||
case HP_IRDA:
|
||||
irsel |= IRMSEL_HP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
siu_write(port, SIUIRSEL, irsel);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vr41xx_select_irda_module);
|
||||
|
||||
static inline void siu_clear_fifo(struct uart_port *port)
|
||||
{
|
||||
siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO);
|
||||
siu_write(port, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
|
||||
UART_FCR_CLEAR_XMIT);
|
||||
siu_write(port, UART_FCR, 0);
|
||||
}
|
||||
|
||||
static inline unsigned long siu_port_size(struct uart_port *port)
|
||||
{
|
||||
switch (port->type) {
|
||||
case PORT_VR41XX_SIU:
|
||||
return 11UL;
|
||||
case PORT_VR41XX_DSIU:
|
||||
return 8UL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int siu_check_type(struct uart_port *port)
|
||||
{
|
||||
if (port->line == 0)
|
||||
return PORT_VR41XX_SIU;
|
||||
if (port->line == 1 && port->irq)
|
||||
return PORT_VR41XX_DSIU;
|
||||
|
||||
return PORT_UNKNOWN;
|
||||
}
|
||||
|
||||
static inline const char *siu_type_name(struct uart_port *port)
|
||||
{
|
||||
switch (port->type) {
|
||||
case PORT_VR41XX_SIU:
|
||||
return "SIU";
|
||||
case PORT_VR41XX_DSIU:
|
||||
return "DSIU";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int siu_tx_empty(struct uart_port *port)
|
||||
{
|
||||
uint8_t lsr;
|
||||
|
||||
lsr = siu_read(port, UART_LSR);
|
||||
if (lsr & UART_LSR_TEMT)
|
||||
return TIOCSER_TEMT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void siu_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
uint8_t mcr = 0;
|
||||
|
||||
if (mctrl & TIOCM_DTR)
|
||||
mcr |= UART_MCR_DTR;
|
||||
if (mctrl & TIOCM_RTS)
|
||||
mcr |= UART_MCR_RTS;
|
||||
if (mctrl & TIOCM_OUT1)
|
||||
mcr |= UART_MCR_OUT1;
|
||||
if (mctrl & TIOCM_OUT2)
|
||||
mcr |= UART_MCR_OUT2;
|
||||
if (mctrl & TIOCM_LOOP)
|
||||
mcr |= UART_MCR_LOOP;
|
||||
|
||||
siu_write(port, UART_MCR, mcr);
|
||||
}
|
||||
|
||||
static unsigned int siu_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
uint8_t msr;
|
||||
unsigned int mctrl = 0;
|
||||
|
||||
msr = siu_read(port, UART_MSR);
|
||||
if (msr & UART_MSR_DCD)
|
||||
mctrl |= TIOCM_CAR;
|
||||
if (msr & UART_MSR_RI)
|
||||
mctrl |= TIOCM_RNG;
|
||||
if (msr & UART_MSR_DSR)
|
||||
mctrl |= TIOCM_DSR;
|
||||
if (msr & UART_MSR_CTS)
|
||||
mctrl |= TIOCM_CTS;
|
||||
|
||||
return mctrl;
|
||||
}
|
||||
|
||||
static void siu_stop_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
uint8_t ier;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
ier = siu_read(port, UART_IER);
|
||||
ier &= ~UART_IER_THRI;
|
||||
siu_write(port, UART_IER, ier);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void siu_start_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
uint8_t ier;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
ier = siu_read(port, UART_IER);
|
||||
ier |= UART_IER_THRI;
|
||||
siu_write(port, UART_IER, ier);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void siu_stop_rx(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
uint8_t ier;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
ier = siu_read(port, UART_IER);
|
||||
ier &= ~UART_IER_RLSI;
|
||||
siu_write(port, UART_IER, ier);
|
||||
|
||||
port->read_status_mask &= ~UART_LSR_DR;
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void siu_enable_ms(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
uint8_t ier;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
ier = siu_read(port, UART_IER);
|
||||
ier |= UART_IER_MSI;
|
||||
siu_write(port, UART_IER, ier);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void siu_break_ctl(struct uart_port *port, int ctl)
|
||||
{
|
||||
unsigned long flags;
|
||||
uint8_t lcr;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
lcr = siu_read(port, UART_LCR);
|
||||
if (ctl == -1)
|
||||
lcr |= UART_LCR_SBC;
|
||||
else
|
||||
lcr &= ~UART_LCR_SBC;
|
||||
siu_write(port, UART_LCR, lcr);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static inline void receive_chars(struct uart_port *port, uint8_t *status)
|
||||
{
|
||||
uint8_t lsr, ch;
|
||||
char flag;
|
||||
int max_count = RX_MAX_COUNT;
|
||||
|
||||
lsr = *status;
|
||||
|
||||
do {
|
||||
ch = siu_read(port, UART_RX);
|
||||
port->icount.rx++;
|
||||
flag = TTY_NORMAL;
|
||||
|
||||
#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
|
||||
lsr |= lsr_break_flag[port->line];
|
||||
lsr_break_flag[port->line] = 0;
|
||||
#endif
|
||||
if (unlikely(lsr & (UART_LSR_BI | UART_LSR_FE |
|
||||
UART_LSR_PE | UART_LSR_OE))) {
|
||||
if (lsr & UART_LSR_BI) {
|
||||
lsr &= ~(UART_LSR_FE | UART_LSR_PE);
|
||||
port->icount.brk++;
|
||||
|
||||
if (uart_handle_break(port))
|
||||
goto ignore_char;
|
||||
}
|
||||
|
||||
if (lsr & UART_LSR_FE)
|
||||
port->icount.frame++;
|
||||
if (lsr & UART_LSR_PE)
|
||||
port->icount.parity++;
|
||||
if (lsr & UART_LSR_OE)
|
||||
port->icount.overrun++;
|
||||
|
||||
lsr &= port->read_status_mask;
|
||||
if (lsr & UART_LSR_BI)
|
||||
flag = TTY_BREAK;
|
||||
if (lsr & UART_LSR_FE)
|
||||
flag = TTY_FRAME;
|
||||
if (lsr & UART_LSR_PE)
|
||||
flag = TTY_PARITY;
|
||||
}
|
||||
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
goto ignore_char;
|
||||
|
||||
uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
|
||||
|
||||
ignore_char:
|
||||
lsr = siu_read(port, UART_LSR);
|
||||
} while ((lsr & UART_LSR_DR) && (max_count-- > 0));
|
||||
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
|
||||
*status = lsr;
|
||||
}
|
||||
|
||||
static inline void check_modem_status(struct uart_port *port)
|
||||
{
|
||||
uint8_t msr;
|
||||
|
||||
msr = siu_read(port, UART_MSR);
|
||||
if ((msr & UART_MSR_ANY_DELTA) == 0)
|
||||
return;
|
||||
if (msr & UART_MSR_DDCD)
|
||||
uart_handle_dcd_change(port, msr & UART_MSR_DCD);
|
||||
if (msr & UART_MSR_TERI)
|
||||
port->icount.rng++;
|
||||
if (msr & UART_MSR_DDSR)
|
||||
port->icount.dsr++;
|
||||
if (msr & UART_MSR_DCTS)
|
||||
uart_handle_cts_change(port, msr & UART_MSR_CTS);
|
||||
|
||||
wake_up_interruptible(&port->state->port.delta_msr_wait);
|
||||
}
|
||||
|
||||
static inline void transmit_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit;
|
||||
int max_count = TX_MAX_COUNT;
|
||||
|
||||
xmit = &port->state->xmit;
|
||||
|
||||
if (port->x_char) {
|
||||
siu_write(port, UART_TX, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
siu_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
siu_write(port, UART_TX, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (max_count-- > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
siu_stop_tx(port);
|
||||
}
|
||||
|
||||
static irqreturn_t siu_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port;
|
||||
uint8_t iir, lsr;
|
||||
|
||||
port = (struct uart_port *)dev_id;
|
||||
|
||||
iir = siu_read(port, UART_IIR);
|
||||
if (iir & UART_IIR_NO_INT)
|
||||
return IRQ_NONE;
|
||||
|
||||
lsr = siu_read(port, UART_LSR);
|
||||
if (lsr & UART_LSR_DR)
|
||||
receive_chars(port, &lsr);
|
||||
|
||||
check_modem_status(port);
|
||||
|
||||
if (lsr & UART_LSR_THRE)
|
||||
transmit_chars(port);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int siu_startup(struct uart_port *port)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (port->membase == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
siu_clear_fifo(port);
|
||||
|
||||
(void)siu_read(port, UART_LSR);
|
||||
(void)siu_read(port, UART_RX);
|
||||
(void)siu_read(port, UART_IIR);
|
||||
(void)siu_read(port, UART_MSR);
|
||||
|
||||
if (siu_read(port, UART_LSR) == 0xff)
|
||||
return -ENODEV;
|
||||
|
||||
retval = request_irq(port->irq, siu_interrupt, 0, siu_type_name(port), port);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (port->type == PORT_VR41XX_DSIU)
|
||||
vr41xx_enable_dsiuint(DSIUINT_ALL);
|
||||
|
||||
siu_write(port, UART_LCR, UART_LCR_WLEN8);
|
||||
|
||||
spin_lock_irq(&port->lock);
|
||||
siu_set_mctrl(port, port->mctrl);
|
||||
spin_unlock_irq(&port->lock);
|
||||
|
||||
siu_write(port, UART_IER, UART_IER_RLSI | UART_IER_RDI);
|
||||
|
||||
(void)siu_read(port, UART_LSR);
|
||||
(void)siu_read(port, UART_RX);
|
||||
(void)siu_read(port, UART_IIR);
|
||||
(void)siu_read(port, UART_MSR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void siu_shutdown(struct uart_port *port)
|
||||
{
|
||||
unsigned long flags;
|
||||
uint8_t lcr;
|
||||
|
||||
siu_write(port, UART_IER, 0);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
port->mctrl &= ~TIOCM_OUT2;
|
||||
siu_set_mctrl(port, port->mctrl);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
lcr = siu_read(port, UART_LCR);
|
||||
lcr &= ~UART_LCR_SBC;
|
||||
siu_write(port, UART_LCR, lcr);
|
||||
|
||||
siu_clear_fifo(port);
|
||||
|
||||
(void)siu_read(port, UART_RX);
|
||||
|
||||
if (port->type == PORT_VR41XX_DSIU)
|
||||
vr41xx_disable_dsiuint(DSIUINT_ALL);
|
||||
|
||||
free_irq(port->irq, port);
|
||||
}
|
||||
|
||||
static void siu_set_termios(struct uart_port *port, struct ktermios *new,
|
||||
struct ktermios *old)
|
||||
{
|
||||
tcflag_t c_cflag, c_iflag;
|
||||
uint8_t lcr, fcr, ier;
|
||||
unsigned int baud, quot;
|
||||
unsigned long flags;
|
||||
|
||||
c_cflag = new->c_cflag;
|
||||
lcr = UART_LCR_WLEN(tty_get_char_size(c_cflag));
|
||||
|
||||
if (c_cflag & CSTOPB)
|
||||
lcr |= UART_LCR_STOP;
|
||||
if (c_cflag & PARENB)
|
||||
lcr |= UART_LCR_PARITY;
|
||||
if ((c_cflag & PARODD) != PARODD)
|
||||
lcr |= UART_LCR_EPAR;
|
||||
if (c_cflag & CMSPAR)
|
||||
lcr |= UART_LCR_SPAR;
|
||||
|
||||
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
|
||||
quot = uart_get_divisor(port, baud);
|
||||
|
||||
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
uart_update_timeout(port, c_cflag, baud);
|
||||
|
||||
c_iflag = new->c_iflag;
|
||||
|
||||
port->read_status_mask = UART_LSR_THRE | UART_LSR_OE | UART_LSR_DR;
|
||||
if (c_iflag & INPCK)
|
||||
port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
|
||||
if (c_iflag & (IGNBRK | BRKINT | PARMRK))
|
||||
port->read_status_mask |= UART_LSR_BI;
|
||||
|
||||
port->ignore_status_mask = 0;
|
||||
if (c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
|
||||
if (c_iflag & IGNBRK) {
|
||||
port->ignore_status_mask |= UART_LSR_BI;
|
||||
if (c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |= UART_LSR_OE;
|
||||
}
|
||||
|
||||
if ((c_cflag & CREAD) == 0)
|
||||
port->ignore_status_mask |= UART_LSR_DR;
|
||||
|
||||
ier = siu_read(port, UART_IER);
|
||||
ier &= ~UART_IER_MSI;
|
||||
if (UART_ENABLE_MS(port, c_cflag))
|
||||
ier |= UART_IER_MSI;
|
||||
siu_write(port, UART_IER, ier);
|
||||
|
||||
siu_write(port, UART_LCR, lcr | UART_LCR_DLAB);
|
||||
|
||||
siu_write(port, UART_DLL, (uint8_t)quot);
|
||||
siu_write(port, UART_DLM, (uint8_t)(quot >> 8));
|
||||
|
||||
siu_write(port, UART_LCR, lcr);
|
||||
|
||||
siu_write(port, UART_FCR, fcr);
|
||||
|
||||
siu_set_mctrl(port, port->mctrl);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static void siu_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
|
||||
{
|
||||
switch (state) {
|
||||
case 0:
|
||||
switch (port->type) {
|
||||
case PORT_VR41XX_SIU:
|
||||
vr41xx_supply_clock(SIU_CLOCK);
|
||||
break;
|
||||
case PORT_VR41XX_DSIU:
|
||||
vr41xx_supply_clock(DSIU_CLOCK);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (port->type) {
|
||||
case PORT_VR41XX_SIU:
|
||||
vr41xx_mask_clock(SIU_CLOCK);
|
||||
break;
|
||||
case PORT_VR41XX_DSIU:
|
||||
vr41xx_mask_clock(DSIU_CLOCK);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *siu_type(struct uart_port *port)
|
||||
{
|
||||
return siu_type_name(port);
|
||||
}
|
||||
|
||||
static void siu_release_port(struct uart_port *port)
|
||||
{
|
||||
unsigned long size;
|
||||
|
||||
if (port->flags & UPF_IOREMAP) {
|
||||
iounmap(port->membase);
|
||||
port->membase = NULL;
|
||||
}
|
||||
|
||||
size = siu_port_size(port);
|
||||
release_mem_region(port->mapbase, size);
|
||||
}
|
||||
|
||||
static int siu_request_port(struct uart_port *port)
|
||||
{
|
||||
unsigned long size;
|
||||
struct resource *res;
|
||||
|
||||
size = siu_port_size(port);
|
||||
res = request_mem_region(port->mapbase, size, siu_type_name(port));
|
||||
if (res == NULL)
|
||||
return -EBUSY;
|
||||
|
||||
if (port->flags & UPF_IOREMAP) {
|
||||
port->membase = ioremap(port->mapbase, size);
|
||||
if (port->membase == NULL) {
|
||||
release_resource(res);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void siu_config_port(struct uart_port *port, int flags)
|
||||
{
|
||||
if (flags & UART_CONFIG_TYPE) {
|
||||
port->type = siu_check_type(port);
|
||||
(void)siu_request_port(port);
|
||||
}
|
||||
}
|
||||
|
||||
static int siu_verify_port(struct uart_port *port, struct serial_struct *serial)
|
||||
{
|
||||
if (port->type != PORT_VR41XX_SIU && port->type != PORT_VR41XX_DSIU)
|
||||
return -EINVAL;
|
||||
if (port->irq != serial->irq)
|
||||
return -EINVAL;
|
||||
if (port->iotype != serial->io_type)
|
||||
return -EINVAL;
|
||||
if (port->mapbase != (unsigned long)serial->iomem_base)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct uart_ops siu_uart_ops = {
|
||||
.tx_empty = siu_tx_empty,
|
||||
.set_mctrl = siu_set_mctrl,
|
||||
.get_mctrl = siu_get_mctrl,
|
||||
.stop_tx = siu_stop_tx,
|
||||
.start_tx = siu_start_tx,
|
||||
.stop_rx = siu_stop_rx,
|
||||
.enable_ms = siu_enable_ms,
|
||||
.break_ctl = siu_break_ctl,
|
||||
.startup = siu_startup,
|
||||
.shutdown = siu_shutdown,
|
||||
.set_termios = siu_set_termios,
|
||||
.pm = siu_pm,
|
||||
.type = siu_type,
|
||||
.release_port = siu_release_port,
|
||||
.request_port = siu_request_port,
|
||||
.config_port = siu_config_port,
|
||||
.verify_port = siu_verify_port,
|
||||
};
|
||||
|
||||
static int siu_init_ports(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_port *port;
|
||||
struct resource *res;
|
||||
int *type = dev_get_platdata(&pdev->dev);
|
||||
int i;
|
||||
|
||||
if (!type)
|
||||
return 0;
|
||||
|
||||
port = siu_uart_ports;
|
||||
for (i = 0; i < SIU_PORTS_MAX; i++) {
|
||||
port->type = type[i];
|
||||
if (port->type == PORT_UNKNOWN)
|
||||
continue;
|
||||
port->irq = platform_get_irq(pdev, i);
|
||||
port->uartclk = SIU_BAUD_BASE * 16;
|
||||
port->fifosize = 16;
|
||||
port->regshift = 0;
|
||||
port->iotype = UPIO_MEM;
|
||||
port->flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF;
|
||||
port->line = i;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
|
||||
port->mapbase = res->start;
|
||||
port++;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
|
||||
|
||||
#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
static void wait_for_xmitr(struct uart_port *port)
|
||||
{
|
||||
int timeout = 10000;
|
||||
uint8_t lsr, msr;
|
||||
|
||||
do {
|
||||
lsr = siu_read(port, UART_LSR);
|
||||
if (lsr & UART_LSR_BI)
|
||||
lsr_break_flag[port->line] = UART_LSR_BI;
|
||||
|
||||
if ((lsr & BOTH_EMPTY) == BOTH_EMPTY)
|
||||
break;
|
||||
} while (timeout-- > 0);
|
||||
|
||||
if (port->flags & UPF_CONS_FLOW) {
|
||||
timeout = 1000000;
|
||||
|
||||
do {
|
||||
msr = siu_read(port, UART_MSR);
|
||||
if ((msr & UART_MSR_CTS) != 0)
|
||||
break;
|
||||
} while (timeout-- > 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void siu_console_putchar(struct uart_port *port, unsigned char ch)
|
||||
{
|
||||
wait_for_xmitr(port);
|
||||
siu_write(port, UART_TX, ch);
|
||||
}
|
||||
|
||||
static void siu_console_write(struct console *con, const char *s, unsigned count)
|
||||
{
|
||||
struct uart_port *port;
|
||||
uint8_t ier;
|
||||
|
||||
port = &siu_uart_ports[con->index];
|
||||
|
||||
ier = siu_read(port, UART_IER);
|
||||
siu_write(port, UART_IER, 0);
|
||||
|
||||
uart_console_write(port, s, count, siu_console_putchar);
|
||||
|
||||
wait_for_xmitr(port);
|
||||
siu_write(port, UART_IER, ier);
|
||||
}
|
||||
|
||||
static int __init siu_console_setup(struct console *con, char *options)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int baud = 9600;
|
||||
int parity = 'n';
|
||||
int bits = 8;
|
||||
int flow = 'n';
|
||||
|
||||
if (con->index >= SIU_PORTS_MAX)
|
||||
con->index = 0;
|
||||
|
||||
port = &siu_uart_ports[con->index];
|
||||
if (port->membase == NULL) {
|
||||
if (port->mapbase == 0)
|
||||
return -ENODEV;
|
||||
port->membase = ioremap(port->mapbase, siu_port_size(port));
|
||||
}
|
||||
|
||||
if (port->type == PORT_VR41XX_SIU)
|
||||
vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
|
||||
|
||||
if (options != NULL)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
||||
return uart_set_options(port, con, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
static struct uart_driver siu_uart_driver;
|
||||
|
||||
static struct console siu_console = {
|
||||
.name = "ttyVR",
|
||||
.write = siu_console_write,
|
||||
.device = uart_console_device,
|
||||
.setup = siu_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &siu_uart_driver,
|
||||
};
|
||||
|
||||
static int siu_console_init(void)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SIU_PORTS_MAX; i++) {
|
||||
port = &siu_uart_ports[i];
|
||||
port->ops = &siu_uart_ops;
|
||||
}
|
||||
|
||||
register_console(&siu_console);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
console_initcall(siu_console_init);
|
||||
|
||||
void __init vr41xx_siu_early_setup(struct uart_port *port)
|
||||
{
|
||||
if (port->type == PORT_UNKNOWN)
|
||||
return;
|
||||
|
||||
siu_uart_ports[port->line].line = port->line;
|
||||
siu_uart_ports[port->line].type = port->type;
|
||||
siu_uart_ports[port->line].uartclk = SIU_BAUD_BASE * 16;
|
||||
siu_uart_ports[port->line].mapbase = port->mapbase;
|
||||
siu_uart_ports[port->line].ops = &siu_uart_ops;
|
||||
}
|
||||
|
||||
#define SERIAL_VR41XX_CONSOLE &siu_console
|
||||
#else
|
||||
#define SERIAL_VR41XX_CONSOLE NULL
|
||||
#endif
|
||||
|
||||
static struct uart_driver siu_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = "SIU",
|
||||
.dev_name = "ttyVR",
|
||||
.major = SIU_MAJOR,
|
||||
.minor = SIU_MINOR_BASE,
|
||||
.cons = SERIAL_VR41XX_CONSOLE,
|
||||
};
|
||||
|
||||
static int siu_probe(struct platform_device *dev)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int num, i, retval;
|
||||
|
||||
num = siu_init_ports(dev);
|
||||
if (num <= 0)
|
||||
return -ENODEV;
|
||||
|
||||
siu_uart_driver.nr = num;
|
||||
retval = uart_register_driver(&siu_uart_driver);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
port = &siu_uart_ports[i];
|
||||
port->ops = &siu_uart_ops;
|
||||
port->dev = &dev->dev;
|
||||
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_VR41XX_CONSOLE);
|
||||
|
||||
retval = uart_add_one_port(&siu_uart_driver, port);
|
||||
if (retval < 0) {
|
||||
port->dev = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0 && retval < 0) {
|
||||
uart_unregister_driver(&siu_uart_driver);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int siu_remove(struct platform_device *dev)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < siu_uart_driver.nr; i++) {
|
||||
port = &siu_uart_ports[i];
|
||||
if (port->dev == &dev->dev) {
|
||||
uart_remove_one_port(&siu_uart_driver, port);
|
||||
port->dev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uart_unregister_driver(&siu_uart_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int siu_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < siu_uart_driver.nr; i++) {
|
||||
port = &siu_uart_ports[i];
|
||||
if ((port->type == PORT_VR41XX_SIU ||
|
||||
port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
|
||||
uart_suspend_port(&siu_uart_driver, port);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int siu_resume(struct platform_device *dev)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < siu_uart_driver.nr; i++) {
|
||||
port = &siu_uart_ports[i];
|
||||
if ((port->type == PORT_VR41XX_SIU ||
|
||||
port->type == PORT_VR41XX_DSIU) && port->dev == &dev->dev)
|
||||
uart_resume_port(&siu_uart_driver, port);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver siu_device_driver = {
|
||||
.probe = siu_probe,
|
||||
.remove = siu_remove,
|
||||
.suspend = siu_suspend,
|
||||
.resume = siu_resume,
|
||||
.driver = {
|
||||
.name = "SIU",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(siu_device_driver);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:SIU");
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
@ -104,6 +105,7 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size)
|
||||
p->size = size;
|
||||
p->next = NULL;
|
||||
p->commit = 0;
|
||||
p->lookahead = 0;
|
||||
p->read = 0;
|
||||
p->flags = 0;
|
||||
}
|
||||
@ -234,6 +236,7 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
buf->head = next;
|
||||
}
|
||||
buf->head->read = buf->head->commit;
|
||||
buf->head->lookahead = buf->head->read;
|
||||
|
||||
if (ld && ld->ops->flush_buffer)
|
||||
ld->ops->flush_buffer(tty);
|
||||
@ -276,13 +279,15 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
|
||||
if (n != NULL) {
|
||||
n->flags = flags;
|
||||
buf->tail = n;
|
||||
/* paired w/ acquire in flush_to_ldisc(); ensures
|
||||
* flush_to_ldisc() sees buffer data.
|
||||
/*
|
||||
* Paired w/ acquire in flush_to_ldisc() and lookahead_bufs()
|
||||
* ensures they see all buffer data.
|
||||
*/
|
||||
smp_store_release(&b->commit, b->used);
|
||||
/* paired w/ acquire in flush_to_ldisc(); ensures the
|
||||
* latest commit value can be read before the head is
|
||||
* advanced to the next buffer
|
||||
/*
|
||||
* Paired w/ acquire in flush_to_ldisc() and lookahead_bufs()
|
||||
* ensures the latest commit value can be read before the head
|
||||
* is advanced to the next buffer.
|
||||
*/
|
||||
smp_store_release(&b->next, n);
|
||||
} else if (change)
|
||||
@ -459,6 +464,40 @@ int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf);
|
||||
|
||||
static void lookahead_bufs(struct tty_port *port, struct tty_buffer *head)
|
||||
{
|
||||
head->lookahead = max(head->lookahead, head->read);
|
||||
|
||||
while (head) {
|
||||
struct tty_buffer *next;
|
||||
unsigned char *p, *f = NULL;
|
||||
unsigned int count;
|
||||
|
||||
/*
|
||||
* Paired w/ release in __tty_buffer_request_room();
|
||||
* ensures commit value read is not stale if the head
|
||||
* is advancing to the next buffer.
|
||||
*/
|
||||
next = smp_load_acquire(&head->next);
|
||||
/*
|
||||
* Paired w/ release in __tty_buffer_request_room() or in
|
||||
* tty_buffer_flush(); ensures we see the committed buffer data.
|
||||
*/
|
||||
count = smp_load_acquire(&head->commit) - head->lookahead;
|
||||
if (!count) {
|
||||
head = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
p = char_buf_ptr(head, head->lookahead);
|
||||
if (~head->flags & TTYB_NORMAL)
|
||||
f = flag_buf_ptr(head, head->lookahead);
|
||||
|
||||
port->client_ops->lookahead_buf(port, p, f, count);
|
||||
head->lookahead += count;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
|
||||
{
|
||||
@ -496,7 +535,7 @@ static void flush_to_ldisc(struct work_struct *work)
|
||||
while (1) {
|
||||
struct tty_buffer *head = buf->head;
|
||||
struct tty_buffer *next;
|
||||
int count;
|
||||
int count, rcvd;
|
||||
|
||||
/* Ldisc or user is trying to gain exclusive access */
|
||||
if (atomic_read(&buf->priority))
|
||||
@ -519,10 +558,12 @@ static void flush_to_ldisc(struct work_struct *work)
|
||||
continue;
|
||||
}
|
||||
|
||||
count = receive_buf(port, head, count);
|
||||
if (!count)
|
||||
rcvd = receive_buf(port, head, count);
|
||||
head->read += rcvd;
|
||||
if (rcvd < count)
|
||||
lookahead_bufs(port, head);
|
||||
if (!rcvd)
|
||||
break;
|
||||
head->read += count;
|
||||
|
||||
if (need_resched())
|
||||
cond_resched();
|
||||
|
@ -1663,7 +1663,7 @@ void tty_kclose(struct tty_struct *tty)
|
||||
*/
|
||||
tty_ldisc_release(tty);
|
||||
|
||||
/* Wait for pending work before tty destruction commmences */
|
||||
/* Wait for pending work before tty destruction commences */
|
||||
tty_flush_works(tty);
|
||||
|
||||
tty_debug_hangup(tty, "freeing structure\n");
|
||||
|
@ -319,6 +319,8 @@ unsigned char tty_get_frame_size(unsigned int cflag)
|
||||
bits++;
|
||||
if (cflag & PARENB)
|
||||
bits++;
|
||||
if (cflag & ADDRB)
|
||||
bits++;
|
||||
|
||||
return bits;
|
||||
}
|
||||
@ -353,6 +355,8 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
|
||||
old_termios = tty->termios;
|
||||
tty->termios = *new_termios;
|
||||
unset_locked_termios(tty, &old_termios);
|
||||
/* Reset any ADDRB changes, ADDRB is changed through ->rs485_config() */
|
||||
tty->termios.c_cflag ^= (tty->termios.c_cflag ^ old_termios.c_cflag) & ADDRB;
|
||||
|
||||
if (tty->ops->set_termios)
|
||||
tty->ops->set_termios(tty, &old_termios);
|
||||
|
@ -43,6 +43,26 @@ static int tty_port_default_receive_buf(struct tty_port *port,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tty_port_default_lookahead_buf(struct tty_port *port, const unsigned char *p,
|
||||
const unsigned char *f, unsigned int count)
|
||||
{
|
||||
struct tty_struct *tty;
|
||||
struct tty_ldisc *disc;
|
||||
|
||||
tty = READ_ONCE(port->itty);
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
disc = tty_ldisc_ref(tty);
|
||||
if (!disc)
|
||||
return;
|
||||
|
||||
if (disc->ops->lookahead_buf)
|
||||
disc->ops->lookahead_buf(disc->tty, p, f, count);
|
||||
|
||||
tty_ldisc_deref(disc);
|
||||
}
|
||||
|
||||
static void tty_port_default_wakeup(struct tty_port *port)
|
||||
{
|
||||
struct tty_struct *tty = tty_port_tty_get(port);
|
||||
@ -55,6 +75,7 @@ static void tty_port_default_wakeup(struct tty_port *port)
|
||||
|
||||
const struct tty_port_client_operations tty_port_default_client_ops = {
|
||||
.receive_buf = tty_port_default_receive_buf,
|
||||
.lookahead_buf = tty_port_default_lookahead_buf,
|
||||
.write_wakeup = tty_port_default_wakeup,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(tty_port_default_client_ops);
|
||||
|
@ -30,6 +30,6 @@ $(obj)/defkeymap.o: $(obj)/defkeymap.c
|
||||
ifdef GENERATE_KEYMAP
|
||||
|
||||
$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
|
||||
loadkeys --mktable $< > $@
|
||||
loadkeys --mktable --unicode $< > $@
|
||||
|
||||
endif
|
||||
|
@ -23,6 +23,8 @@
|
||||
* stack overflow.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kd.h>
|
||||
#include <linux/errno.h>
|
||||
@ -36,9 +38,9 @@
|
||||
#include <linux/vt_kern.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
static unsigned short translations[][256] = {
|
||||
static unsigned short translations[][E_TABSZ] = {
|
||||
/* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
|
||||
{
|
||||
[LAT1_MAP] = {
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||
0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
|
||||
@ -71,9 +73,9 @@ static unsigned short translations[][256] = {
|
||||
0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
|
||||
0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
|
||||
0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
|
||||
},
|
||||
},
|
||||
/* VT100 graphics mapped to Unicode */
|
||||
{
|
||||
[GRAF_MAP] = {
|
||||
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
||||
0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
|
||||
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
|
||||
@ -108,8 +110,8 @@ static unsigned short translations[][256] = {
|
||||
0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
|
||||
},
|
||||
/* IBM Codepage 437 mapped to Unicode */
|
||||
{
|
||||
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
|
||||
[IBMPC_MAP] = {
|
||||
0x0000, 0x263a, 0x263b, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
|
||||
0x25d8, 0x25cb, 0x25d9, 0x2642, 0x2640, 0x266a, 0x266b, 0x263c,
|
||||
0x25b6, 0x25c0, 0x2195, 0x203c, 0x00b6, 0x00a7, 0x25ac, 0x21a8,
|
||||
0x2191, 0x2193, 0x2192, 0x2190, 0x221f, 0x2194, 0x25b2, 0x25bc,
|
||||
@ -141,9 +143,9 @@ static unsigned short translations[][256] = {
|
||||
0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
|
||||
0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
|
||||
0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
|
||||
},
|
||||
},
|
||||
/* User mapping -- default to codes for direct font mapping */
|
||||
{
|
||||
[USER_MAP] = {
|
||||
0xf000, 0xf001, 0xf002, 0xf003, 0xf004, 0xf005, 0xf006, 0xf007,
|
||||
0xf008, 0xf009, 0xf00a, 0xf00b, 0xf00c, 0xf00d, 0xf00e, 0xf00f,
|
||||
0xf010, 0xf011, 0xf012, 0xf013, 0xf014, 0xf015, 0xf016, 0xf017,
|
||||
@ -184,78 +186,105 @@ static unsigned short translations[][256] = {
|
||||
|
||||
#define MAX_GLYPH 512 /* Max possible glyph value */
|
||||
|
||||
static int inv_translate[MAX_NR_CONSOLES];
|
||||
static enum translation_map inv_translate[MAX_NR_CONSOLES];
|
||||
|
||||
struct uni_pagedir {
|
||||
u16 **uni_pgdir[32];
|
||||
#define UNI_DIRS 32U
|
||||
#define UNI_DIR_ROWS 32U
|
||||
#define UNI_ROW_GLYPHS 64U
|
||||
|
||||
#define UNI_DIR_BITS GENMASK(15, 11)
|
||||
#define UNI_ROW_BITS GENMASK(10, 6)
|
||||
#define UNI_GLYPH_BITS GENMASK( 5, 0)
|
||||
|
||||
#define UNI_DIR(uni) FIELD_GET(UNI_DIR_BITS, (uni))
|
||||
#define UNI_ROW(uni) FIELD_GET(UNI_ROW_BITS, (uni))
|
||||
#define UNI_GLYPH(uni) FIELD_GET(UNI_GLYPH_BITS, (uni))
|
||||
|
||||
#define UNI(dir, row, glyph) (FIELD_PREP(UNI_DIR_BITS, (dir)) | \
|
||||
FIELD_PREP(UNI_ROW_BITS, (row)) | \
|
||||
FIELD_PREP(UNI_GLYPH_BITS, (glyph)))
|
||||
|
||||
/**
|
||||
* struct uni_pagedict -- unicode directory
|
||||
*
|
||||
* @uni_pgdir: 32*32*64 table with glyphs
|
||||
* @refcount: reference count of this structure
|
||||
* @sum: checksum
|
||||
* @inverse_translations: best-effort inverse mapping
|
||||
* @inverse_trans_unicode: best-effort inverse mapping to unicode
|
||||
*/
|
||||
struct uni_pagedict {
|
||||
u16 **uni_pgdir[UNI_DIRS];
|
||||
unsigned long refcount;
|
||||
unsigned long sum;
|
||||
unsigned char *inverse_translations[4];
|
||||
unsigned char *inverse_translations[LAST_MAP + 1];
|
||||
u16 *inverse_trans_unicode;
|
||||
};
|
||||
|
||||
static struct uni_pagedir *dflt;
|
||||
static struct uni_pagedict *dflt;
|
||||
|
||||
static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int i)
|
||||
static void set_inverse_transl(struct vc_data *conp, struct uni_pagedict *dict,
|
||||
enum translation_map m)
|
||||
{
|
||||
int j, glyph;
|
||||
unsigned short *t = translations[i];
|
||||
unsigned char *q;
|
||||
|
||||
if (!p) return;
|
||||
q = p->inverse_translations[i];
|
||||
unsigned short *t = translations[m];
|
||||
unsigned char *inv;
|
||||
|
||||
if (!q) {
|
||||
q = p->inverse_translations[i] = kmalloc(MAX_GLYPH, GFP_KERNEL);
|
||||
if (!q) return;
|
||||
if (!dict)
|
||||
return;
|
||||
inv = dict->inverse_translations[m];
|
||||
|
||||
if (!inv) {
|
||||
inv = dict->inverse_translations[m] = kmalloc(MAX_GLYPH,
|
||||
GFP_KERNEL);
|
||||
if (!inv)
|
||||
return;
|
||||
}
|
||||
memset(q, 0, MAX_GLYPH);
|
||||
memset(inv, 0, MAX_GLYPH);
|
||||
|
||||
for (j = 0; j < E_TABSZ; j++) {
|
||||
glyph = conv_uni_to_pc(conp, t[j]);
|
||||
if (glyph >= 0 && glyph < MAX_GLYPH && q[glyph] < 32) {
|
||||
for (unsigned int ch = 0; ch < ARRAY_SIZE(translations[m]); ch++) {
|
||||
int glyph = conv_uni_to_pc(conp, t[ch]);
|
||||
if (glyph >= 0 && glyph < MAX_GLYPH && inv[glyph] < 32) {
|
||||
/* prefer '-' above SHY etc. */
|
||||
q[glyph] = j;
|
||||
inv[glyph] = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void set_inverse_trans_unicode(struct vc_data *conp,
|
||||
struct uni_pagedir *p)
|
||||
static void set_inverse_trans_unicode(struct uni_pagedict *dict)
|
||||
{
|
||||
int i, j, k, glyph;
|
||||
u16 **p1, *p2;
|
||||
u16 *q;
|
||||
unsigned int d, r, g;
|
||||
u16 *inv;
|
||||
|
||||
if (!p) return;
|
||||
q = p->inverse_trans_unicode;
|
||||
if (!q) {
|
||||
q = p->inverse_trans_unicode =
|
||||
kmalloc_array(MAX_GLYPH, sizeof(u16), GFP_KERNEL);
|
||||
if (!q)
|
||||
if (!dict)
|
||||
return;
|
||||
|
||||
inv = dict->inverse_trans_unicode;
|
||||
if (!inv) {
|
||||
inv = dict->inverse_trans_unicode = kmalloc_array(MAX_GLYPH,
|
||||
sizeof(*inv), GFP_KERNEL);
|
||||
if (!inv)
|
||||
return;
|
||||
}
|
||||
memset(q, 0, MAX_GLYPH * sizeof(u16));
|
||||
memset(inv, 0, MAX_GLYPH * sizeof(*inv));
|
||||
|
||||
for (i = 0; i < 32; i++) {
|
||||
p1 = p->uni_pgdir[i];
|
||||
if (!p1)
|
||||
for (d = 0; d < UNI_DIRS; d++) {
|
||||
u16 **dir = dict->uni_pgdir[d];
|
||||
if (!dir)
|
||||
continue;
|
||||
for (j = 0; j < 32; j++) {
|
||||
p2 = p1[j];
|
||||
if (!p2)
|
||||
for (r = 0; r < UNI_DIR_ROWS; r++) {
|
||||
u16 *row = dir[r];
|
||||
if (!row)
|
||||
continue;
|
||||
for (k = 0; k < 64; k++) {
|
||||
glyph = p2[k];
|
||||
if (glyph >= 0 && glyph < MAX_GLYPH
|
||||
&& q[glyph] < 32)
|
||||
q[glyph] = (i << 11) + (j << 6) + k;
|
||||
for (g = 0; g < UNI_ROW_GLYPHS; g++) {
|
||||
u16 glyph = row[g];
|
||||
if (glyph < MAX_GLYPH && inv[glyph] < 32)
|
||||
inv[glyph] = UNI(d, r, g);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short *set_translate(int m, struct vc_data *vc)
|
||||
unsigned short *set_translate(enum translation_map m, struct vc_data *vc)
|
||||
{
|
||||
inv_translate[vc->vc_num] = m;
|
||||
return translations[m];
|
||||
@ -268,44 +297,45 @@ unsigned short *set_translate(int m, struct vc_data *vc)
|
||||
* was active.
|
||||
* Still, it is now possible to a certain extent to cut and paste non-ASCII.
|
||||
*/
|
||||
u16 inverse_translate(const struct vc_data *conp, int glyph, int use_unicode)
|
||||
u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode)
|
||||
{
|
||||
struct uni_pagedir *p;
|
||||
int m;
|
||||
if (glyph < 0 || glyph >= MAX_GLYPH)
|
||||
struct uni_pagedict *p;
|
||||
enum translation_map m;
|
||||
|
||||
if (glyph >= MAX_GLYPH)
|
||||
return 0;
|
||||
else {
|
||||
p = *conp->vc_uni_pagedir_loc;
|
||||
if (!p)
|
||||
|
||||
p = *conp->uni_pagedict_loc;
|
||||
if (!p)
|
||||
return glyph;
|
||||
|
||||
if (use_unicode) {
|
||||
if (!p->inverse_trans_unicode)
|
||||
return glyph;
|
||||
else if (use_unicode) {
|
||||
if (!p->inverse_trans_unicode)
|
||||
return glyph;
|
||||
else
|
||||
return p->inverse_trans_unicode[glyph];
|
||||
} else {
|
||||
m = inv_translate[conp->vc_num];
|
||||
if (!p->inverse_translations[m])
|
||||
return glyph;
|
||||
else
|
||||
return p->inverse_translations[m][glyph];
|
||||
}
|
||||
|
||||
return p->inverse_trans_unicode[glyph];
|
||||
}
|
||||
|
||||
m = inv_translate[conp->vc_num];
|
||||
if (!p->inverse_translations[m])
|
||||
return glyph;
|
||||
|
||||
return p->inverse_translations[m][glyph];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(inverse_translate);
|
||||
|
||||
static void update_user_maps(void)
|
||||
{
|
||||
int i;
|
||||
struct uni_pagedir *p, *q = NULL;
|
||||
|
||||
struct uni_pagedict *p, *q = NULL;
|
||||
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
if (!vc_cons_allocated(i))
|
||||
continue;
|
||||
p = *vc_cons[i].d->vc_uni_pagedir_loc;
|
||||
p = *vc_cons[i].d->uni_pagedict_loc;
|
||||
if (p && p != q) {
|
||||
set_inverse_transl(vc_cons[i].d, p, USER_MAP);
|
||||
set_inverse_trans_unicode(vc_cons[i].d, p);
|
||||
set_inverse_trans_unicode(p);
|
||||
q = p;
|
||||
}
|
||||
}
|
||||
@ -321,15 +351,15 @@ static void update_user_maps(void)
|
||||
*/
|
||||
int con_set_trans_old(unsigned char __user * arg)
|
||||
{
|
||||
int i;
|
||||
unsigned short inbuf[E_TABSZ];
|
||||
unsigned char ubuf[E_TABSZ];
|
||||
unsigned int i;
|
||||
unsigned char ch;
|
||||
|
||||
if (copy_from_user(ubuf, arg, E_TABSZ))
|
||||
return -EFAULT;
|
||||
|
||||
for (i = 0; i < E_TABSZ ; i++)
|
||||
inbuf[i] = UNI_DIRECT_BASE | ubuf[i];
|
||||
for (i = 0; i < ARRAY_SIZE(inbuf); i++) {
|
||||
if (get_user(ch, &arg[i]))
|
||||
return -EFAULT;
|
||||
inbuf[i] = UNI_DIRECT_BASE | ch;
|
||||
}
|
||||
|
||||
console_lock();
|
||||
memcpy(translations[USER_MAP], inbuf, sizeof(inbuf));
|
||||
@ -345,7 +375,7 @@ int con_get_trans_old(unsigned char __user * arg)
|
||||
unsigned char outbuf[E_TABSZ];
|
||||
|
||||
console_lock();
|
||||
for (i = 0; i < E_TABSZ ; i++)
|
||||
for (i = 0; i < ARRAY_SIZE(outbuf); i++)
|
||||
{
|
||||
ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
|
||||
outbuf[i] = (ch & ~0xff) ? 0 : ch;
|
||||
@ -381,7 +411,7 @@ int con_get_trans_new(ushort __user * arg)
|
||||
}
|
||||
|
||||
/*
|
||||
* Unicode -> current font conversion
|
||||
* Unicode -> current font conversion
|
||||
*
|
||||
* A font has at most 512 chars, usually 256.
|
||||
* But one font position may represent several Unicode chars.
|
||||
@ -393,78 +423,82 @@ int con_get_trans_new(ushort __user * arg)
|
||||
extern u8 dfont_unicount[]; /* Defined in console_defmap.c */
|
||||
extern u16 dfont_unitable[];
|
||||
|
||||
static void con_release_unimap(struct uni_pagedir *p)
|
||||
static void con_release_unimap(struct uni_pagedict *dict)
|
||||
{
|
||||
u16 **p1;
|
||||
int i, j;
|
||||
unsigned int d, r;
|
||||
|
||||
if (p == dflt) dflt = NULL;
|
||||
for (i = 0; i < 32; i++) {
|
||||
p1 = p->uni_pgdir[i];
|
||||
if (p1 != NULL) {
|
||||
for (j = 0; j < 32; j++)
|
||||
kfree(p1[j]);
|
||||
kfree(p1);
|
||||
if (dict == dflt)
|
||||
dflt = NULL;
|
||||
|
||||
for (d = 0; d < UNI_DIRS; d++) {
|
||||
u16 **dir = dict->uni_pgdir[d];
|
||||
if (dir != NULL) {
|
||||
for (r = 0; r < UNI_DIR_ROWS; r++)
|
||||
kfree(dir[r]);
|
||||
kfree(dir);
|
||||
}
|
||||
p->uni_pgdir[i] = NULL;
|
||||
dict->uni_pgdir[d] = NULL;
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
kfree(p->inverse_translations[i]);
|
||||
p->inverse_translations[i] = NULL;
|
||||
|
||||
for (r = 0; r < ARRAY_SIZE(dict->inverse_translations); r++) {
|
||||
kfree(dict->inverse_translations[r]);
|
||||
dict->inverse_translations[r] = NULL;
|
||||
}
|
||||
kfree(p->inverse_trans_unicode);
|
||||
p->inverse_trans_unicode = NULL;
|
||||
|
||||
kfree(dict->inverse_trans_unicode);
|
||||
dict->inverse_trans_unicode = NULL;
|
||||
}
|
||||
|
||||
/* Caller must hold the console lock */
|
||||
void con_free_unimap(struct vc_data *vc)
|
||||
{
|
||||
struct uni_pagedir *p;
|
||||
struct uni_pagedict *p;
|
||||
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
p = *vc->uni_pagedict_loc;
|
||||
if (!p)
|
||||
return;
|
||||
*vc->vc_uni_pagedir_loc = NULL;
|
||||
*vc->uni_pagedict_loc = NULL;
|
||||
if (--p->refcount)
|
||||
return;
|
||||
con_release_unimap(p);
|
||||
kfree(p);
|
||||
}
|
||||
|
||||
static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
|
||||
|
||||
static int con_unify_unimap(struct vc_data *conp, struct uni_pagedict *dict1)
|
||||
{
|
||||
int i, j, k;
|
||||
struct uni_pagedir *q;
|
||||
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++) {
|
||||
if (!vc_cons_allocated(i))
|
||||
struct uni_pagedict *dict2;
|
||||
unsigned int cons, d, r;
|
||||
|
||||
for (cons = 0; cons < MAX_NR_CONSOLES; cons++) {
|
||||
if (!vc_cons_allocated(cons))
|
||||
continue;
|
||||
q = *vc_cons[i].d->vc_uni_pagedir_loc;
|
||||
if (!q || q == p || q->sum != p->sum)
|
||||
dict2 = *vc_cons[cons].d->uni_pagedict_loc;
|
||||
if (!dict2 || dict2 == dict1 || dict2->sum != dict1->sum)
|
||||
continue;
|
||||
for (j = 0; j < 32; j++) {
|
||||
u16 **p1, **q1;
|
||||
p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j];
|
||||
if (!p1 && !q1)
|
||||
for (d = 0; d < UNI_DIRS; d++) {
|
||||
u16 **dir1 = dict1->uni_pgdir[d];
|
||||
u16 **dir2 = dict2->uni_pgdir[d];
|
||||
if (!dir1 && !dir2)
|
||||
continue;
|
||||
if (!p1 || !q1)
|
||||
if (!dir1 || !dir2)
|
||||
break;
|
||||
for (k = 0; k < 32; k++) {
|
||||
if (!p1[k] && !q1[k])
|
||||
for (r = 0; r < UNI_DIR_ROWS; r++) {
|
||||
if (!dir1[r] && !dir2[r])
|
||||
continue;
|
||||
if (!p1[k] || !q1[k])
|
||||
if (!dir1[r] || !dir2[r])
|
||||
break;
|
||||
if (memcmp(p1[k], q1[k], 64*sizeof(u16)))
|
||||
if (memcmp(dir1[r], dir2[r], UNI_ROW_GLYPHS *
|
||||
sizeof(*dir1[r])))
|
||||
break;
|
||||
}
|
||||
if (k < 32)
|
||||
if (r < UNI_DIR_ROWS)
|
||||
break;
|
||||
}
|
||||
if (j == 32) {
|
||||
q->refcount++;
|
||||
*conp->vc_uni_pagedir_loc = q;
|
||||
con_release_unimap(p);
|
||||
kfree(p);
|
||||
if (d == UNI_DIRS) {
|
||||
dict2->refcount++;
|
||||
*conp->uni_pagedict_loc = dict2;
|
||||
con_release_unimap(dict1);
|
||||
kfree(dict1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@ -472,55 +506,66 @@ static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p)
|
||||
}
|
||||
|
||||
static int
|
||||
con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
|
||||
con_insert_unipair(struct uni_pagedict *p, u_short unicode, u_short fontpos)
|
||||
{
|
||||
int i, n;
|
||||
u16 **p1, *p2;
|
||||
u16 **dir, *row;
|
||||
unsigned int n;
|
||||
|
||||
p1 = p->uni_pgdir[n = unicode >> 11];
|
||||
if (!p1) {
|
||||
p1 = p->uni_pgdir[n] = kmalloc_array(32, sizeof(u16 *),
|
||||
GFP_KERNEL);
|
||||
if (!p1) return -ENOMEM;
|
||||
for (i = 0; i < 32; i++)
|
||||
p1[i] = NULL;
|
||||
n = UNI_DIR(unicode);
|
||||
dir = p->uni_pgdir[n];
|
||||
if (!dir) {
|
||||
dir = p->uni_pgdir[n] = kcalloc(UNI_DIR_ROWS, sizeof(*dir),
|
||||
GFP_KERNEL);
|
||||
if (!dir)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
p2 = p1[n = (unicode >> 6) & 0x1f];
|
||||
if (!p2) {
|
||||
p2 = p1[n] = kmalloc_array(64, sizeof(u16), GFP_KERNEL);
|
||||
if (!p2) return -ENOMEM;
|
||||
memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */
|
||||
n = UNI_ROW(unicode);
|
||||
row = dir[n];
|
||||
if (!row) {
|
||||
row = dir[n] = kmalloc_array(UNI_ROW_GLYPHS, sizeof(*row),
|
||||
GFP_KERNEL);
|
||||
if (!row)
|
||||
return -ENOMEM;
|
||||
/* No glyphs for the characters (yet) */
|
||||
memset(row, 0xff, UNI_ROW_GLYPHS * sizeof(*row));
|
||||
}
|
||||
|
||||
p2[unicode & 0x3f] = fontpos;
|
||||
|
||||
row[UNI_GLYPH(unicode)] = fontpos;
|
||||
|
||||
p->sum += (fontpos << 20U) + unicode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int con_allocate_new(struct vc_data *vc)
|
||||
{
|
||||
struct uni_pagedict *new, *old = *vc->uni_pagedict_loc;
|
||||
|
||||
new = kzalloc(sizeof(*new), GFP_KERNEL);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
new->refcount = 1;
|
||||
*vc->uni_pagedict_loc = new;
|
||||
|
||||
if (old)
|
||||
old->refcount--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Caller must hold the lock */
|
||||
static int con_do_clear_unimap(struct vc_data *vc)
|
||||
{
|
||||
struct uni_pagedir *p, *q;
|
||||
struct uni_pagedict *old = *vc->uni_pagedict_loc;
|
||||
|
||||
if (!old || old->refcount > 1)
|
||||
return con_allocate_new(vc);
|
||||
|
||||
old->sum = 0;
|
||||
con_release_unimap(old);
|
||||
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
if (!p || --p->refcount) {
|
||||
q = kzalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (!q) {
|
||||
if (p)
|
||||
p->refcount++;
|
||||
return -ENOMEM;
|
||||
}
|
||||
q->refcount=1;
|
||||
*vc->vc_uni_pagedir_loc = q;
|
||||
} else {
|
||||
if (p == dflt) dflt = NULL;
|
||||
p->refcount++;
|
||||
p->sum = 0;
|
||||
con_release_unimap(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -532,91 +577,93 @@ int con_clear_unimap(struct vc_data *vc)
|
||||
console_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct uni_pagedict *con_unshare_unimap(struct vc_data *vc,
|
||||
struct uni_pagedict *old)
|
||||
{
|
||||
struct uni_pagedict *new;
|
||||
unsigned int d, r, g;
|
||||
int ret;
|
||||
u16 uni = 0;
|
||||
|
||||
ret = con_allocate_new(vc);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
new = *vc->uni_pagedict_loc;
|
||||
|
||||
/*
|
||||
* uni_pgdir is a 32*32*64 table with rows allocated when its first
|
||||
* entry is added. The unicode value must still be incremented for
|
||||
* empty rows. We are copying entries from "old" to "new".
|
||||
*/
|
||||
for (d = 0; d < UNI_DIRS; d++) {
|
||||
u16 **dir = old->uni_pgdir[d];
|
||||
if (!dir) {
|
||||
/* Account for empty table */
|
||||
uni += UNI_DIR_ROWS * UNI_ROW_GLYPHS;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (r = 0; r < UNI_DIR_ROWS; r++) {
|
||||
u16 *row = dir[r];
|
||||
if (!row) {
|
||||
/* Account for row of 64 empty entries */
|
||||
uni += UNI_ROW_GLYPHS;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (g = 0; g < UNI_ROW_GLYPHS; g++, uni++) {
|
||||
if (row[g] == 0xffff)
|
||||
continue;
|
||||
/*
|
||||
* Found one, copy entry for unicode uni with
|
||||
* fontpos value row[g].
|
||||
*/
|
||||
ret = con_insert_unipair(new, uni, row[g]);
|
||||
if (ret) {
|
||||
old->refcount++;
|
||||
*vc->uni_pagedict_loc = old;
|
||||
con_release_unimap(new);
|
||||
kfree(new);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
{
|
||||
int err = 0, err1, i;
|
||||
struct uni_pagedir *p, *q;
|
||||
int err = 0, err1;
|
||||
struct uni_pagedict *dict;
|
||||
struct unipair *unilist, *plist;
|
||||
|
||||
if (!ct)
|
||||
return 0;
|
||||
|
||||
unilist = vmemdup_user(list, array_size(sizeof(struct unipair), ct));
|
||||
unilist = vmemdup_user(list, array_size(sizeof(*unilist), ct));
|
||||
if (IS_ERR(unilist))
|
||||
return PTR_ERR(unilist);
|
||||
|
||||
console_lock();
|
||||
|
||||
/* Save original vc_unipagdir_loc in case we allocate a new one */
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
|
||||
if (!p) {
|
||||
dict = *vc->uni_pagedict_loc;
|
||||
if (!dict) {
|
||||
err = -EINVAL;
|
||||
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (p->refcount > 1) {
|
||||
int j, k;
|
||||
u16 **p1, *p2, l;
|
||||
|
||||
err1 = con_do_clear_unimap(vc);
|
||||
if (err1) {
|
||||
err = err1;
|
||||
|
||||
if (dict->refcount > 1) {
|
||||
dict = con_unshare_unimap(vc, dict);
|
||||
if (IS_ERR(dict)) {
|
||||
err = PTR_ERR(dict);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since refcount was > 1, con_clear_unimap() allocated a
|
||||
* a new uni_pagedir for this vc. Re: p != q
|
||||
*/
|
||||
q = *vc->vc_uni_pagedir_loc;
|
||||
|
||||
/*
|
||||
* uni_pgdir is a 32*32*64 table with rows allocated
|
||||
* when its first entry is added. The unicode value must
|
||||
* still be incremented for empty rows. We are copying
|
||||
* entries from "p" (old) to "q" (new).
|
||||
*/
|
||||
l = 0; /* unicode value */
|
||||
for (i = 0; i < 32; i++) {
|
||||
p1 = p->uni_pgdir[i];
|
||||
if (p1)
|
||||
for (j = 0; j < 32; j++) {
|
||||
p2 = p1[j];
|
||||
if (p2) {
|
||||
for (k = 0; k < 64; k++, l++)
|
||||
if (p2[k] != 0xffff) {
|
||||
/*
|
||||
* Found one, copy entry for unicode
|
||||
* l with fontpos value p2[k].
|
||||
*/
|
||||
err1 = con_insert_unipair(q, l, p2[k]);
|
||||
if (err1) {
|
||||
p->refcount++;
|
||||
*vc->vc_uni_pagedir_loc = p;
|
||||
con_release_unimap(q);
|
||||
kfree(q);
|
||||
err = err1;
|
||||
goto out_unlock;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Account for row of 64 empty entries */
|
||||
l += 64;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* Account for empty table */
|
||||
l += 32 * 64;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finished copying font table, set vc_uni_pagedir to new table
|
||||
*/
|
||||
p = q;
|
||||
} else if (p == dflt) {
|
||||
} else if (dict == dflt) {
|
||||
dflt = NULL;
|
||||
}
|
||||
|
||||
@ -624,20 +671,20 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
* Insert user specified unicode pairs into new table.
|
||||
*/
|
||||
for (plist = unilist; ct; ct--, plist++) {
|
||||
err1 = con_insert_unipair(p, plist->unicode, plist->fontpos);
|
||||
err1 = con_insert_unipair(dict, plist->unicode, plist->fontpos);
|
||||
if (err1)
|
||||
err = err1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Merge with fontmaps of any other virtual consoles.
|
||||
*/
|
||||
if (con_unify_unimap(vc, p))
|
||||
if (con_unify_unimap(vc, dict))
|
||||
goto out_unlock;
|
||||
|
||||
for (i = 0; i <= 3; i++)
|
||||
set_inverse_transl(vc, p, i); /* Update inverse translations */
|
||||
set_inverse_trans_unicode(vc, p);
|
||||
for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++)
|
||||
set_inverse_transl(vc, dict, m);
|
||||
set_inverse_trans_unicode(dict);
|
||||
|
||||
out_unlock:
|
||||
console_unlock();
|
||||
@ -652,55 +699,56 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
|
||||
* The representation used was the most compact I could come up
|
||||
* with. This routine is executed at video setup, and when the
|
||||
* PIO_FONTRESET ioctl is called.
|
||||
* PIO_FONTRESET ioctl is called.
|
||||
*
|
||||
* The caller must hold the console lock
|
||||
*/
|
||||
int con_set_default_unimap(struct vc_data *vc)
|
||||
{
|
||||
int i, j, err = 0, err1;
|
||||
u16 *q;
|
||||
struct uni_pagedir *p;
|
||||
struct uni_pagedict *dict;
|
||||
unsigned int fontpos, count;
|
||||
int err = 0, err1;
|
||||
u16 *dfont;
|
||||
|
||||
if (dflt) {
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
if (p == dflt)
|
||||
dict = *vc->uni_pagedict_loc;
|
||||
if (dict == dflt)
|
||||
return 0;
|
||||
|
||||
dflt->refcount++;
|
||||
*vc->vc_uni_pagedir_loc = dflt;
|
||||
if (p && !--p->refcount) {
|
||||
con_release_unimap(p);
|
||||
kfree(p);
|
||||
*vc->uni_pagedict_loc = dflt;
|
||||
if (dict && !--dict->refcount) {
|
||||
con_release_unimap(dict);
|
||||
kfree(dict);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The default font is always 256 characters */
|
||||
|
||||
err = con_do_clear_unimap(vc);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
q = dfont_unitable;
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
for (j = dfont_unicount[i]; j; j--) {
|
||||
err1 = con_insert_unipair(p, *(q++), i);
|
||||
|
||||
dict = *vc->uni_pagedict_loc;
|
||||
dfont = dfont_unitable;
|
||||
|
||||
for (fontpos = 0; fontpos < 256U; fontpos++)
|
||||
for (count = dfont_unicount[fontpos]; count; count--) {
|
||||
err1 = con_insert_unipair(dict, *(dfont++), fontpos);
|
||||
if (err1)
|
||||
err = err1;
|
||||
}
|
||||
|
||||
if (con_unify_unimap(vc, p)) {
|
||||
dflt = *vc->vc_uni_pagedir_loc;
|
||||
|
||||
if (con_unify_unimap(vc, dict)) {
|
||||
dflt = *vc->uni_pagedict_loc;
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i <= 3; i++)
|
||||
set_inverse_transl(vc, p, i); /* Update all inverse translations */
|
||||
set_inverse_trans_unicode(vc, p);
|
||||
dflt = p;
|
||||
for (enum translation_map m = FIRST_MAP; m <= LAST_MAP; m++)
|
||||
set_inverse_transl(vc, dict, m);
|
||||
set_inverse_trans_unicode(dict);
|
||||
dflt = dict;
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(con_set_default_unimap);
|
||||
@ -714,16 +762,16 @@ EXPORT_SYMBOL(con_set_default_unimap);
|
||||
*/
|
||||
int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
|
||||
{
|
||||
struct uni_pagedir *q;
|
||||
struct uni_pagedict *src;
|
||||
|
||||
if (!*src_vc->vc_uni_pagedir_loc)
|
||||
if (!*src_vc->uni_pagedict_loc)
|
||||
return -EINVAL;
|
||||
if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc)
|
||||
if (*dst_vc->uni_pagedict_loc == *src_vc->uni_pagedict_loc)
|
||||
return 0;
|
||||
con_free_unimap(dst_vc);
|
||||
q = *src_vc->vc_uni_pagedir_loc;
|
||||
q->refcount++;
|
||||
*dst_vc->vc_uni_pagedir_loc = q;
|
||||
src = *src_vc->uni_pagedict_loc;
|
||||
src->refcount++;
|
||||
*dst_vc->uni_pagedict_loc = src;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(con_copy_unimap);
|
||||
@ -734,46 +782,53 @@ EXPORT_SYMBOL(con_copy_unimap);
|
||||
* Read the console unicode data for this console. Called from the ioctl
|
||||
* handlers.
|
||||
*/
|
||||
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
|
||||
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct,
|
||||
struct unipair __user *list)
|
||||
{
|
||||
int i, j, k, ret = 0;
|
||||
ushort ect;
|
||||
u16 **p1, *p2;
|
||||
struct uni_pagedir *p;
|
||||
struct uni_pagedict *dict;
|
||||
struct unipair *unilist;
|
||||
unsigned int d, r, g;
|
||||
int ret = 0;
|
||||
|
||||
unilist = kvmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
|
||||
unilist = kvmalloc_array(ct, sizeof(*unilist), GFP_KERNEL);
|
||||
if (!unilist)
|
||||
return -ENOMEM;
|
||||
|
||||
console_lock();
|
||||
|
||||
ect = 0;
|
||||
if (*vc->vc_uni_pagedir_loc) {
|
||||
p = *vc->vc_uni_pagedir_loc;
|
||||
for (i = 0; i < 32; i++) {
|
||||
p1 = p->uni_pgdir[i];
|
||||
if (p1)
|
||||
for (j = 0; j < 32; j++) {
|
||||
p2 = *(p1++);
|
||||
if (p2)
|
||||
for (k = 0; k < 64; k++, p2++) {
|
||||
if (*p2 >= MAX_GLYPH)
|
||||
continue;
|
||||
if (ect < ct) {
|
||||
unilist[ect].unicode =
|
||||
(i<<11)+(j<<6)+k;
|
||||
unilist[ect].fontpos = *p2;
|
||||
}
|
||||
ect++;
|
||||
dict = *vc->uni_pagedict_loc;
|
||||
if (!dict)
|
||||
goto unlock;
|
||||
|
||||
for (d = 0; d < UNI_DIRS; d++) {
|
||||
u16 **dir = dict->uni_pgdir[d];
|
||||
if (!dir)
|
||||
continue;
|
||||
|
||||
for (r = 0; r < UNI_DIR_ROWS; r++) {
|
||||
u16 *row = dir[r];
|
||||
if (!row)
|
||||
continue;
|
||||
|
||||
for (g = 0; g < UNI_ROW_GLYPHS; g++, row++) {
|
||||
if (*row >= MAX_GLYPH)
|
||||
continue;
|
||||
if (ect < ct) {
|
||||
unilist[ect].unicode = UNI(d, r, g);
|
||||
unilist[ect].fontpos = *row;
|
||||
}
|
||||
ect++;
|
||||
}
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
console_unlock();
|
||||
if (copy_to_user(list, unilist, min(ect, ct) * sizeof(struct unipair)))
|
||||
if (copy_to_user(list, unilist, min(ect, ct) * sizeof(*unilist)))
|
||||
ret = -EFAULT;
|
||||
if (put_user(ect, uct))
|
||||
ret = -EFAULT;
|
||||
put_user(ect, uct);
|
||||
kvfree(unilist);
|
||||
return ret ? ret : (ect <= ct) ? 0 : -ENOMEM;
|
||||
}
|
||||
@ -798,20 +853,18 @@ u32 conv_8bit_to_uni(unsigned char c)
|
||||
int conv_uni_to_8bit(u32 uni)
|
||||
{
|
||||
int c;
|
||||
for (c = 0; c < 0x100; c++)
|
||||
for (c = 0; c < ARRAY_SIZE(translations[USER_MAP]); c++)
|
||||
if (translations[USER_MAP][c] == uni ||
|
||||
(translations[USER_MAP][c] == (c | 0xf000) && uni == c))
|
||||
return c;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
conv_uni_to_pc(struct vc_data *conp, long ucs)
|
||||
int conv_uni_to_pc(struct vc_data *conp, long ucs)
|
||||
{
|
||||
int h;
|
||||
u16 **p1, *p2;
|
||||
struct uni_pagedir *p;
|
||||
|
||||
struct uni_pagedict *dict;
|
||||
u16 **dir, *row, glyph;
|
||||
|
||||
/* Only 16-bit codes supported at this time */
|
||||
if (ucs > 0xffff)
|
||||
return -4; /* Not found */
|
||||
@ -826,17 +879,24 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)
|
||||
*/
|
||||
else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE)
|
||||
return ucs & UNI_DIRECT_MASK;
|
||||
|
||||
if (!*conp->vc_uni_pagedir_loc)
|
||||
|
||||
dict = *conp->uni_pagedict_loc;
|
||||
if (!dict)
|
||||
return -3;
|
||||
|
||||
p = *conp->vc_uni_pagedir_loc;
|
||||
if ((p1 = p->uni_pgdir[ucs >> 11]) &&
|
||||
(p2 = p1[(ucs >> 6) & 0x1f]) &&
|
||||
(h = p2[ucs & 0x3f]) < MAX_GLYPH)
|
||||
return h;
|
||||
dir = dict->uni_pgdir[UNI_DIR(ucs)];
|
||||
if (!dir)
|
||||
return -4;
|
||||
|
||||
return -4; /* not found */
|
||||
row = dir[UNI_ROW(ucs)];
|
||||
if (!row)
|
||||
return -4;
|
||||
|
||||
glyph = row[UNI_GLYPH(ucs)];
|
||||
if (glyph >= MAX_GLYPH)
|
||||
return -4;
|
||||
|
||||
return glyph;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -844,13 +904,13 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)
|
||||
* initialized. It must be possible to call kmalloc(..., GFP_KERNEL)
|
||||
* from this function, hence the call from sys_setup.
|
||||
*/
|
||||
void __init
|
||||
void __init
|
||||
console_map_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
for (i = 0; i < MAX_NR_CONSOLES; i++)
|
||||
if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc)
|
||||
if (vc_cons_allocated(i) && !*vc_cons[i].d->uni_pagedict_loc)
|
||||
con_set_default_unimap(vc_cons[i].d);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Do not edit this file! It was automatically generated by */
|
||||
/* loadkeys --mktable defkeymap.map > defkeymap.c */
|
||||
/* Do not edit this file! It was automatically generated by */
|
||||
/* loadkeys --mktable --unicode defkeymap.map > defkeymap.c */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/keyboard.h>
|
||||
@ -139,7 +139,7 @@ static unsigned short ctrl_alt_map[NR_KEYS] = {
|
||||
0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
|
||||
};
|
||||
|
||||
ushort *key_maps[MAX_NR_KEYMAPS] = {
|
||||
unsigned short *key_maps[MAX_NR_KEYMAPS] = {
|
||||
plain_map, shift_map, altgr_map, NULL,
|
||||
ctrl_map, shift_ctrl_map, NULL, NULL,
|
||||
alt_map, NULL, NULL, NULL,
|
||||
|
@ -68,7 +68,8 @@ sel_pos(int n, bool unicode)
|
||||
{
|
||||
if (unicode)
|
||||
return screen_glyph_unicode(vc_sel.cons, n / 2);
|
||||
return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n), 0);
|
||||
return inverse_translate(vc_sel.cons, screen_glyph(vc_sel.cons, n),
|
||||
false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -344,7 +344,7 @@ static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows)
|
||||
/* allocate everything in one go */
|
||||
memsize = cols * rows * sizeof(char32_t);
|
||||
memsize += rows * sizeof(char32_t *);
|
||||
p = vmalloc(memsize);
|
||||
p = vzalloc(memsize);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
@ -1063,10 +1063,10 @@ static void visual_init(struct vc_data *vc, int num, int init)
|
||||
__module_get(vc->vc_sw->owner);
|
||||
vc->vc_num = num;
|
||||
vc->vc_display_fg = &master_display_fg;
|
||||
if (vc->vc_uni_pagedir_loc)
|
||||
if (vc->uni_pagedict_loc)
|
||||
con_free_unimap(vc);
|
||||
vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir;
|
||||
vc->vc_uni_pagedir = NULL;
|
||||
vc->uni_pagedict_loc = &vc->uni_pagedict;
|
||||
vc->uni_pagedict = NULL;
|
||||
vc->vc_hi_font_mask = 0;
|
||||
vc->vc_complement_mask = 0;
|
||||
vc->vc_can_do_color = 0;
|
||||
@ -1136,7 +1136,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
|
||||
|
||||
visual_init(vc, currcons, 1);
|
||||
|
||||
if (!*vc->vc_uni_pagedir_loc)
|
||||
if (!*vc->uni_pagedict_loc)
|
||||
con_set_default_unimap(vc);
|
||||
|
||||
err = -EINVAL;
|
||||
@ -3939,7 +3939,7 @@ static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
|
||||
bind = con_is_bound(con->con);
|
||||
console_unlock();
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%i\n", bind);
|
||||
return sysfs_emit(buf, "%i\n", bind);
|
||||
}
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute *attr,
|
||||
@ -3947,7 +3947,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct con_driver *con = dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s %s\n",
|
||||
return sysfs_emit(buf, "%s %s\n",
|
||||
(con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
|
||||
con->desc);
|
||||
|
||||
@ -4741,7 +4741,7 @@ u32 screen_glyph_unicode(const struct vc_data *vc, int n)
|
||||
|
||||
if (uniscr)
|
||||
return uniscr->lines[n / vc->vc_cols][n % vc->vc_cols];
|
||||
return inverse_translate(vc, screen_glyph(vc, n * 2), 1);
|
||||
return inverse_translate(vc, screen_glyph(vc, n * 2), true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(screen_glyph_unicode);
|
||||
|
||||
|
@ -248,7 +248,7 @@ sisusbcon_init(struct vc_data *c, int init)
|
||||
*/
|
||||
kref_get(&sisusb->kref);
|
||||
|
||||
if (!*c->vc_uni_pagedir_loc)
|
||||
if (!*c->uni_pagedict_loc)
|
||||
con_set_default_unimap(c);
|
||||
|
||||
mutex_unlock(&sisusb->lock);
|
||||
|
@ -75,7 +75,7 @@ static void vgacon_scrolldelta(struct vc_data *c, int lines);
|
||||
static int vgacon_set_origin(struct vc_data *c);
|
||||
static void vgacon_save_screen(struct vc_data *c);
|
||||
static void vgacon_invert_region(struct vc_data *c, u16 * p, int count);
|
||||
static struct uni_pagedir *vgacon_uni_pagedir;
|
||||
static struct uni_pagedict *vgacon_uni_pagedir;
|
||||
static int vgacon_refcount;
|
||||
|
||||
/* Description of the hardware situation */
|
||||
@ -342,7 +342,7 @@ static const char *vgacon_startup(void)
|
||||
|
||||
static void vgacon_init(struct vc_data *c, int init)
|
||||
{
|
||||
struct uni_pagedir *p;
|
||||
struct uni_pagedict *p;
|
||||
|
||||
/*
|
||||
* We cannot be loaded as a module, therefore init will be 1
|
||||
@ -367,10 +367,10 @@ static void vgacon_init(struct vc_data *c, int init)
|
||||
c->vc_complement_mask = 0x7700;
|
||||
if (vga_512_chars)
|
||||
c->vc_hi_font_mask = 0x0800;
|
||||
p = *c->vc_uni_pagedir_loc;
|
||||
if (c->vc_uni_pagedir_loc != &vgacon_uni_pagedir) {
|
||||
p = *c->uni_pagedict_loc;
|
||||
if (c->uni_pagedict_loc != &vgacon_uni_pagedir) {
|
||||
con_free_unimap(c);
|
||||
c->vc_uni_pagedir_loc = &vgacon_uni_pagedir;
|
||||
c->uni_pagedict_loc = &vgacon_uni_pagedir;
|
||||
vgacon_refcount++;
|
||||
}
|
||||
if (!vgacon_uni_pagedir && p)
|
||||
@ -392,7 +392,7 @@ static void vgacon_deinit(struct vc_data *c)
|
||||
|
||||
if (!--vgacon_refcount)
|
||||
con_free_unimap(c);
|
||||
c->vc_uni_pagedir_loc = &c->vc_uni_pagedir;
|
||||
c->uni_pagedict_loc = &c->uni_pagedict;
|
||||
con_set_default_unimap(c);
|
||||
}
|
||||
|
||||
|
@ -1060,9 +1060,9 @@ static void fbcon_init(struct vc_data *vc, int init)
|
||||
vc->vc_complement_mask <<= 1;
|
||||
}
|
||||
|
||||
if (!*svc->vc_uni_pagedir_loc)
|
||||
if (!*svc->uni_pagedict_loc)
|
||||
con_set_default_unimap(svc);
|
||||
if (!*vc->vc_uni_pagedir_loc)
|
||||
if (!*vc->uni_pagedict_loc)
|
||||
con_copy_unimap(vc, svc);
|
||||
|
||||
ops = info->fbcon_par;
|
||||
@ -1384,9 +1384,9 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
|
||||
vc->vc_complement_mask <<= 1;
|
||||
}
|
||||
|
||||
if (!*svc->vc_uni_pagedir_loc)
|
||||
if (!*svc->uni_pagedict_loc)
|
||||
con_set_default_unimap(svc);
|
||||
if (!*vc->vc_uni_pagedir_loc)
|
||||
if (!*vc->uni_pagedict_loc)
|
||||
con_copy_unimap(vc, svc);
|
||||
|
||||
cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include <linux/vt.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct uni_pagedir;
|
||||
struct uni_pagedict;
|
||||
struct uni_screen;
|
||||
|
||||
#define NPAR 16
|
||||
@ -157,8 +157,8 @@ struct vc_data {
|
||||
unsigned int vc_bell_duration; /* Console bell duration */
|
||||
unsigned short vc_cur_blink_ms; /* Cursor blink duration */
|
||||
struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */
|
||||
struct uni_pagedir *vc_uni_pagedir;
|
||||
struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */
|
||||
struct uni_pagedict *uni_pagedict;
|
||||
struct uni_pagedict **uni_pagedict_loc; /* [!] Location of uni_pagedict variable for this console */
|
||||
struct uni_screen *vc_uni_screen; /* unicode screen content */
|
||||
/* additional information is in vt_kern.h */
|
||||
};
|
||||
|
@ -7,30 +7,56 @@
|
||||
#ifndef __LINUX_CONSOLEMAP_H__
|
||||
#define __LINUX_CONSOLEMAP_H__
|
||||
|
||||
#define LAT1_MAP 0
|
||||
#define GRAF_MAP 1
|
||||
#define IBMPC_MAP 2
|
||||
#define USER_MAP 3
|
||||
enum translation_map {
|
||||
LAT1_MAP,
|
||||
GRAF_MAP,
|
||||
IBMPC_MAP,
|
||||
USER_MAP,
|
||||
|
||||
FIRST_MAP = LAT1_MAP,
|
||||
LAST_MAP = USER_MAP,
|
||||
};
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef CONFIG_CONSOLE_TRANSLATIONS
|
||||
struct vc_data;
|
||||
|
||||
extern u16 inverse_translate(const struct vc_data *conp, int glyph,
|
||||
int use_unicode);
|
||||
extern unsigned short *set_translate(int m, struct vc_data *vc);
|
||||
extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
|
||||
extern u32 conv_8bit_to_uni(unsigned char c);
|
||||
extern int conv_uni_to_8bit(u32 uni);
|
||||
#ifdef CONFIG_CONSOLE_TRANSLATIONS
|
||||
u16 inverse_translate(const struct vc_data *conp, u16 glyph, bool use_unicode);
|
||||
unsigned short *set_translate(enum translation_map m, struct vc_data *vc);
|
||||
int conv_uni_to_pc(struct vc_data *conp, long ucs);
|
||||
u32 conv_8bit_to_uni(unsigned char c);
|
||||
int conv_uni_to_8bit(u32 uni);
|
||||
void console_map_init(void);
|
||||
#else
|
||||
#define inverse_translate(conp, glyph, uni) ((uint16_t)glyph)
|
||||
#define set_translate(m, vc) ((unsigned short *)NULL)
|
||||
#define conv_uni_to_pc(conp, ucs) ((int) (ucs > 0xff ? -1: ucs))
|
||||
#define conv_8bit_to_uni(c) ((uint32_t)(c))
|
||||
#define conv_uni_to_8bit(c) ((int) ((c) & 0xff))
|
||||
#define console_map_init(c) do { ; } while (0)
|
||||
static inline u16 inverse_translate(const struct vc_data *conp, u16 glyph,
|
||||
bool use_unicode)
|
||||
{
|
||||
return glyph;
|
||||
}
|
||||
|
||||
static inline unsigned short *set_translate(enum translation_map m,
|
||||
struct vc_data *vc)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int conv_uni_to_pc(struct vc_data *conp, long ucs)
|
||||
{
|
||||
return ucs > 0xff ? -1 : ucs;
|
||||
}
|
||||
|
||||
static inline u32 conv_8bit_to_uni(unsigned char c)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline int conv_uni_to_8bit(u32 uni)
|
||||
{
|
||||
return uni & 0xff;
|
||||
}
|
||||
|
||||
static inline void console_map_init(void) { }
|
||||
#endif /* CONFIG_CONSOLE_TRANSLATIONS */
|
||||
|
||||
#endif /* __LINUX_CONSOLEMAP_H__ */
|
||||
|
@ -9,12 +9,20 @@
|
||||
#ifndef _LINUX_SERIAL_H
|
||||
#define _LINUX_SERIAL_H
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <uapi/linux/serial.h>
|
||||
#include <uapi/linux/serial_reg.h>
|
||||
|
||||
/* Helper for dealing with UART_LCR_WLEN* defines */
|
||||
#define UART_LCR_WLEN(x) ((x) - 5)
|
||||
|
||||
/* FIFO and shifting register empty */
|
||||
#define UART_LSR_BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
|
||||
|
||||
static inline bool uart_lsr_tx_empty(u16 lsr)
|
||||
{
|
||||
return (lsr & UART_LSR_BOTH_EMPTY) == UART_LSR_BOTH_EMPTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* Counters of the input lines (CTS, DSR, RI, CD) interrupts
|
||||
*/
|
||||
@ -25,11 +33,6 @@ struct async_icount {
|
||||
__u32 buf_overrun;
|
||||
};
|
||||
|
||||
/*
|
||||
* The size of the serial xmit buffer is 1 page, or 4096 bytes
|
||||
*/
|
||||
#define SERIAL_XMIT_SIZE PAGE_SIZE
|
||||
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#endif /* _LINUX_SERIAL_H */
|
||||
|
@ -119,7 +119,8 @@ struct uart_8250_port {
|
||||
* be immediately processed.
|
||||
*/
|
||||
#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
|
||||
unsigned char lsr_saved_flags;
|
||||
u16 lsr_saved_flags;
|
||||
u16 lsr_save_mask;
|
||||
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
|
||||
unsigned char msr_saved_flags;
|
||||
|
||||
@ -170,8 +171,8 @@ extern void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
|
||||
unsigned int quot_frac);
|
||||
extern int fsl8250_handle_irq(struct uart_port *port);
|
||||
int serial8250_handle_irq(struct uart_port *port, unsigned int iir);
|
||||
unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr);
|
||||
void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr);
|
||||
u16 serial8250_rx_chars(struct uart_8250_port *up, u16 lsr);
|
||||
void serial8250_read_char(struct uart_8250_port *up, u16 lsr);
|
||||
void serial8250_tx_chars(struct uart_8250_port *up);
|
||||
unsigned int serial8250_modem_status(struct uart_8250_port *up);
|
||||
void serial8250_init_port(struct uart_8250_port *up);
|
||||
|
@ -31,9 +31,336 @@ struct serial_struct;
|
||||
struct device;
|
||||
struct gpio_desc;
|
||||
|
||||
/*
|
||||
/**
|
||||
* struct uart_ops -- interface between serial_core and the driver
|
||||
*
|
||||
* This structure describes all the operations that can be done on the
|
||||
* physical hardware. See Documentation/driver-api/serial/driver.rst for details.
|
||||
* physical hardware.
|
||||
*
|
||||
* @tx_empty: ``unsigned int ()(struct uart_port *port)``
|
||||
*
|
||||
* This function tests whether the transmitter fifo and shifter for the
|
||||
* @port is empty. If it is empty, this function should return
|
||||
* %TIOCSER_TEMT, otherwise return 0. If the port does not support this
|
||||
* operation, then it should return %TIOCSER_TEMT.
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
* This call must not sleep
|
||||
*
|
||||
* @set_mctrl: ``void ()(struct uart_port *port, unsigned int mctrl)``
|
||||
*
|
||||
* This function sets the modem control lines for @port to the state
|
||||
* described by @mctrl. The relevant bits of @mctrl are:
|
||||
*
|
||||
* - %TIOCM_RTS RTS signal.
|
||||
* - %TIOCM_DTR DTR signal.
|
||||
* - %TIOCM_OUT1 OUT1 signal.
|
||||
* - %TIOCM_OUT2 OUT2 signal.
|
||||
* - %TIOCM_LOOP Set the port into loopback mode.
|
||||
*
|
||||
* If the appropriate bit is set, the signal should be driven
|
||||
* active. If the bit is clear, the signal should be driven
|
||||
* inactive.
|
||||
*
|
||||
* Locking: @port->lock taken.
|
||||
* Interrupts: locally disabled.
|
||||
* This call must not sleep
|
||||
*
|
||||
* @get_mctrl: ``unsigned int ()(struct uart_port *port)``
|
||||
*
|
||||
* Returns the current state of modem control inputs of @port. The state
|
||||
* of the outputs should not be returned, since the core keeps track of
|
||||
* their state. The state information should include:
|
||||
*
|
||||
* - %TIOCM_CAR state of DCD signal
|
||||
* - %TIOCM_CTS state of CTS signal
|
||||
* - %TIOCM_DSR state of DSR signal
|
||||
* - %TIOCM_RI state of RI signal
|
||||
*
|
||||
* The bit is set if the signal is currently driven active. If
|
||||
* the port does not support CTS, DCD or DSR, the driver should
|
||||
* indicate that the signal is permanently active. If RI is
|
||||
* not available, the signal should not be indicated as active.
|
||||
*
|
||||
* Locking: @port->lock taken.
|
||||
* Interrupts: locally disabled.
|
||||
* This call must not sleep
|
||||
*
|
||||
* @stop_tx: ``void ()(struct uart_port *port)``
|
||||
*
|
||||
* Stop transmitting characters. This might be due to the CTS line
|
||||
* becoming inactive or the tty layer indicating we want to stop
|
||||
* transmission due to an %XOFF character.
|
||||
*
|
||||
* The driver should stop transmitting characters as soon as possible.
|
||||
*
|
||||
* Locking: @port->lock taken.
|
||||
* Interrupts: locally disabled.
|
||||
* This call must not sleep
|
||||
*
|
||||
* @start_tx: ``void ()(struct uart_port *port)``
|
||||
*
|
||||
* Start transmitting characters.
|
||||
*
|
||||
* Locking: @port->lock taken.
|
||||
* Interrupts: locally disabled.
|
||||
* This call must not sleep
|
||||
*
|
||||
* @throttle: ``void ()(struct uart_port *port)``
|
||||
*
|
||||
* Notify the serial 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 serial port.
|
||||
* This will be called only if hardware assisted flow control is enabled.
|
||||
*
|
||||
* Locking: serialized with @unthrottle() and termios modification by the
|
||||
* tty layer.
|
||||
*
|
||||
* @unthrottle: ``void ()(struct uart_port *port)``
|
||||
*
|
||||
* Notify the serial driver that characters can now be sent to the serial
|
||||
* port without fear of overrunning the input buffers of the line
|
||||
* disciplines.
|
||||
*
|
||||
* This will be called only if hardware assisted flow control is enabled.
|
||||
*
|
||||
* Locking: serialized with @throttle() and termios modification by the
|
||||
* tty layer.
|
||||
*
|
||||
* @send_xchar: ``void ()(struct uart_port *port, char ch)``
|
||||
*
|
||||
* Transmit a high priority character, even if the port is stopped. This
|
||||
* is used to implement XON/XOFF flow control and tcflow(). If the serial
|
||||
* driver does not implement this function, the tty core will append the
|
||||
* character to the circular buffer and then call start_tx() / stop_tx()
|
||||
* to flush the data out.
|
||||
*
|
||||
* Do not transmit if @ch == '\0' (%__DISABLED_CHAR).
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
*
|
||||
* @stop_rx: ``void ()(struct uart_port *port)``
|
||||
*
|
||||
* Stop receiving characters; the @port is in the process of being closed.
|
||||
*
|
||||
* Locking: @port->lock taken.
|
||||
* Interrupts: locally disabled.
|
||||
* This call must not sleep
|
||||
*
|
||||
* @enable_ms: ``void ()(struct uart_port *port)``
|
||||
*
|
||||
* Enable the modem status interrupts.
|
||||
*
|
||||
* This method may be called multiple times. Modem status interrupts
|
||||
* should be disabled when the @shutdown() method is called.
|
||||
*
|
||||
* Locking: @port->lock taken.
|
||||
* Interrupts: locally disabled.
|
||||
* This call must not sleep
|
||||
*
|
||||
* @break_ctl: ``void ()(struct uart_port *port, int ctl)``
|
||||
*
|
||||
* Control the transmission of a break signal. If @ctl is nonzero, the
|
||||
* break signal should be transmitted. The signal should be terminated
|
||||
* when another call is made with a zero @ctl.
|
||||
*
|
||||
* Locking: caller holds tty_port->mutex
|
||||
*
|
||||
* @startup: ``int ()(struct uart_port *port)``
|
||||
*
|
||||
* Grab any interrupt resources and initialise any low level driver state.
|
||||
* Enable the port for reception. It should not activate RTS nor DTR;
|
||||
* this will be done via a separate call to @set_mctrl().
|
||||
*
|
||||
* This method will only be called when the port is initially opened.
|
||||
*
|
||||
* Locking: port_sem taken.
|
||||
* Interrupts: globally disabled.
|
||||
*
|
||||
* @shutdown: ``void ()(struct uart_port *port)``
|
||||
*
|
||||
* Disable the @port, disable any break condition that may be in effect,
|
||||
* and free any interrupt resources. It should not disable RTS nor DTR;
|
||||
* this will have already been done via a separate call to @set_mctrl().
|
||||
*
|
||||
* Drivers must not access @port->state once this call has completed.
|
||||
*
|
||||
* This method will only be called when there are no more users of this
|
||||
* @port.
|
||||
*
|
||||
* Locking: port_sem taken.
|
||||
* Interrupts: caller dependent.
|
||||
*
|
||||
* @flush_buffer: ``void ()(struct uart_port *port)``
|
||||
*
|
||||
* Flush any write buffers, reset any DMA state and stop any ongoing DMA
|
||||
* transfers.
|
||||
*
|
||||
* This will be called whenever the @port->state->xmit circular buffer is
|
||||
* cleared.
|
||||
*
|
||||
* Locking: @port->lock taken.
|
||||
* Interrupts: locally disabled.
|
||||
* This call must not sleep
|
||||
*
|
||||
* @set_termios: ``void ()(struct uart_port *port, struct ktermios *new,
|
||||
* struct ktermios *old)``
|
||||
*
|
||||
* Change the @port parameters, including word length, parity, stop bits.
|
||||
* Update @port->read_status_mask and @port->ignore_status_mask to
|
||||
* indicate the types of events we are interested in receiving. Relevant
|
||||
* ktermios::c_cflag bits are:
|
||||
*
|
||||
* - %CSIZE - word size
|
||||
* - %CSTOPB - 2 stop bits
|
||||
* - %PARENB - parity enable
|
||||
* - %PARODD - odd parity (when %PARENB is in force)
|
||||
* - %ADDRB - address bit (changed through uart_port::rs485_config()).
|
||||
* - %CREAD - enable reception of characters (if not set, still receive
|
||||
* characters from the port, but throw them away).
|
||||
* - %CRTSCTS - if set, enable CTS status change reporting.
|
||||
* - %CLOCAL - if not set, enable modem status change reporting.
|
||||
*
|
||||
* Relevant ktermios::c_iflag bits are:
|
||||
*
|
||||
* - %INPCK - enable frame and parity error events to be passed to the TTY
|
||||
* layer.
|
||||
* - %BRKINT / %PARMRK - both of these enable break events to be passed to
|
||||
* the TTY layer.
|
||||
* - %IGNPAR - ignore parity and framing errors.
|
||||
* - %IGNBRK - ignore break errors. If %IGNPAR is also set, ignore overrun
|
||||
* errors as well.
|
||||
*
|
||||
* The interaction of the ktermios::c_iflag bits is as follows (parity
|
||||
* error given as an example):
|
||||
*
|
||||
* ============ ======= ======= =========================================
|
||||
* Parity error INPCK IGNPAR
|
||||
* ============ ======= ======= =========================================
|
||||
* n/a 0 n/a character received, marked as %TTY_NORMAL
|
||||
* None 1 n/a character received, marked as %TTY_NORMAL
|
||||
* Yes 1 0 character received, marked as %TTY_PARITY
|
||||
* Yes 1 1 character discarded
|
||||
* ============ ======= ======= =========================================
|
||||
*
|
||||
* Other flags may be used (eg, xon/xoff characters) if your hardware
|
||||
* supports hardware "soft" flow control.
|
||||
*
|
||||
* Locking: caller holds tty_port->mutex
|
||||
* Interrupts: caller dependent.
|
||||
* This call must not sleep
|
||||
*
|
||||
* @set_ldisc: ``void ()(struct uart_port *port, struct ktermios *termios)``
|
||||
*
|
||||
* Notifier for discipline change. See
|
||||
* Documentation/driver-api/tty/tty_ldisc.rst.
|
||||
*
|
||||
* Locking: caller holds tty_port->mutex
|
||||
*
|
||||
* @pm: ``void ()(struct uart_port *port, unsigned int state,
|
||||
* unsigned int oldstate)``
|
||||
*
|
||||
* Perform any power management related activities on the specified @port.
|
||||
* @state indicates the new state (defined by enum uart_pm_state),
|
||||
* @oldstate indicates the previous state.
|
||||
*
|
||||
* This function should not be used to grab any resources.
|
||||
*
|
||||
* This will be called when the @port is initially opened and finally
|
||||
* closed, except when the @port is also the system console. This will
|
||||
* occur even if %CONFIG_PM is not set.
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
*
|
||||
* @type: ``const char *()(struct uart_port *port)``
|
||||
*
|
||||
* Return a pointer to a string constant describing the specified @port,
|
||||
* or return %NULL, in which case the string 'unknown' is substituted.
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
*
|
||||
* @release_port: ``void ()(struct uart_port *port)``
|
||||
*
|
||||
* Release any memory and IO region resources currently in use by the
|
||||
* @port.
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
*
|
||||
* @request_port: ``int ()(struct uart_port *port)``
|
||||
*
|
||||
* Request any memory and IO region resources required by the port. If any
|
||||
* fail, no resources should be registered when this function returns, and
|
||||
* it should return -%EBUSY on failure.
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
*
|
||||
* @config_port: ``void ()(struct uart_port *port, int type)``
|
||||
*
|
||||
* Perform any autoconfiguration steps required for the @port. @type
|
||||
* contains a bit mask of the required configuration. %UART_CONFIG_TYPE
|
||||
* indicates that the port requires detection and identification.
|
||||
* @port->type should be set to the type found, or %PORT_UNKNOWN if no
|
||||
* port was detected.
|
||||
*
|
||||
* %UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal,
|
||||
* which should be probed using standard kernel autoprobing techniques.
|
||||
* This is not necessary on platforms where ports have interrupts
|
||||
* internally hard wired (eg, system on a chip implementations).
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
*
|
||||
* @verify_port: ``int ()(struct uart_port *port,
|
||||
* struct serial_struct *serinfo)``
|
||||
*
|
||||
* Verify the new serial port information contained within @serinfo is
|
||||
* suitable for this port type.
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
*
|
||||
* @ioctl: ``int ()(struct uart_port *port, unsigned int cmd,
|
||||
* unsigned long arg)``
|
||||
*
|
||||
* Perform any port specific IOCTLs. IOCTL commands must be defined using
|
||||
* the standard numbering system found in <asm/ioctl.h>.
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
*
|
||||
* @poll_init: ``int ()(struct uart_port *port)``
|
||||
*
|
||||
* Called by kgdb to perform the minimal hardware initialization needed to
|
||||
* support @poll_put_char() and @poll_get_char(). Unlike @startup(), this
|
||||
* should not request interrupts.
|
||||
*
|
||||
* Locking: %tty_mutex and tty_port->mutex taken.
|
||||
* Interrupts: n/a.
|
||||
*
|
||||
* @poll_put_char: ``void ()(struct uart_port *port, unsigned char ch)``
|
||||
*
|
||||
* Called by kgdb to write a single character @ch directly to the serial
|
||||
* @port. It can and should block until there is space in the TX FIFO.
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
* This call must not sleep
|
||||
*
|
||||
* @poll_get_char: ``int ()(struct uart_port *port)``
|
||||
*
|
||||
* Called by kgdb to read a single character directly from the serial
|
||||
* port. If data is available, it should be returned; otherwise the
|
||||
* function should return %NO_POLL_CHAR immediately.
|
||||
*
|
||||
* Locking: none.
|
||||
* Interrupts: caller dependent.
|
||||
* This call must not sleep
|
||||
*/
|
||||
struct uart_ops {
|
||||
unsigned int (*tx_empty)(struct uart_port *);
|
||||
@ -56,22 +383,8 @@ struct uart_ops {
|
||||
void (*set_ldisc)(struct uart_port *, struct ktermios *);
|
||||
void (*pm)(struct uart_port *, unsigned int state,
|
||||
unsigned int oldstate);
|
||||
|
||||
/*
|
||||
* Return a string describing the type of the port
|
||||
*/
|
||||
const char *(*type)(struct uart_port *);
|
||||
|
||||
/*
|
||||
* Release IO and memory resources used by the port.
|
||||
* This includes iounmap if necessary.
|
||||
*/
|
||||
void (*release_port)(struct uart_port *);
|
||||
|
||||
/*
|
||||
* Request IO and memory resources used by the port.
|
||||
* This includes iomapping the port if necessary.
|
||||
*/
|
||||
int (*request_port)(struct uart_port *);
|
||||
void (*config_port)(struct uart_port *, int);
|
||||
int (*verify_port)(struct uart_port *, struct serial_struct *);
|
||||
@ -133,6 +446,7 @@ struct uart_port {
|
||||
unsigned int old);
|
||||
void (*handle_break)(struct uart_port *);
|
||||
int (*rs485_config)(struct uart_port *,
|
||||
struct ktermios *termios,
|
||||
struct serial_rs485 *rs485);
|
||||
int (*iso7816_config)(struct uart_port *,
|
||||
struct serial_iso7816 *iso7816);
|
||||
@ -232,7 +546,6 @@ struct uart_port {
|
||||
|
||||
int hw_stopped; /* sw-assisted CTS flow state */
|
||||
unsigned int mctrl; /* current modem ctrl settings */
|
||||
unsigned int timeout; /* character-based timeout */
|
||||
unsigned int frame_time; /* frame timing in ns */
|
||||
unsigned int type; /* port type */
|
||||
const struct uart_ops *ops;
|
||||
@ -255,6 +568,7 @@ struct uart_port {
|
||||
struct attribute_group *attr_group; /* port specific attributes */
|
||||
const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
|
||||
struct serial_rs485 rs485;
|
||||
struct serial_rs485 rs485_supported; /* Supported mask for serial_rs485 */
|
||||
struct gpio_desc *rs485_term_gpio; /* enable RS485 bus termination */
|
||||
struct serial_iso7816 iso7816;
|
||||
void *private_data; /* generic platform data pointer */
|
||||
@ -334,10 +648,23 @@ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios
|
||||
unsigned int max);
|
||||
unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud);
|
||||
|
||||
/*
|
||||
* Calculates FIFO drain time.
|
||||
*/
|
||||
static inline unsigned long uart_fifo_timeout(struct uart_port *port)
|
||||
{
|
||||
u64 fifo_timeout = (u64)READ_ONCE(port->frame_time) * port->fifosize;
|
||||
|
||||
/* Add .02 seconds of slop */
|
||||
fifo_timeout += 20 * NSEC_PER_MSEC;
|
||||
|
||||
return max(nsecs_to_jiffies(fifo_timeout), 1UL);
|
||||
}
|
||||
|
||||
/* Base timer interval for polling */
|
||||
static inline int uart_poll_timeout(struct uart_port *port)
|
||||
{
|
||||
int timeout = port->timeout;
|
||||
int timeout = uart_fifo_timeout(port);
|
||||
|
||||
return timeout > 6 ? (timeout / 2 - 2) : 1;
|
||||
}
|
||||
@ -598,4 +925,5 @@ static inline int uart_handle_break(struct uart_port *port)
|
||||
!((cflag) & CLOCAL))
|
||||
|
||||
int uart_get_rs485_mode(struct uart_port *port);
|
||||
int uart_rs485_config(struct uart_port *port);
|
||||
#endif /* LINUX_SERIAL_CORE_H */
|
||||
|
@ -83,7 +83,7 @@
|
||||
#define S3C2410_UCON_RXIRQMODE (1<<0)
|
||||
#define S3C2410_UCON_RXFIFO_TOI (1<<7)
|
||||
#define S3C2443_UCON_RXERR_IRQEN (1<<6)
|
||||
#define S3C2443_UCON_LOOPBACK (1<<5)
|
||||
#define S3C2410_UCON_LOOPBACK (1<<5)
|
||||
|
||||
#define S3C2410_UCON_DEFAULT (S3C2410_UCON_TXILEVEL | \
|
||||
S3C2410_UCON_RXILEVEL | \
|
||||
|
@ -15,6 +15,7 @@ struct tty_buffer {
|
||||
int used;
|
||||
int size;
|
||||
int commit;
|
||||
int lookahead; /* Lazy update on recv, can become less than "read" */
|
||||
int read;
|
||||
int flags;
|
||||
/* Data points here */
|
||||
|
@ -186,6 +186,18 @@ int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
|
||||
* indicate all data received is %TTY_NORMAL. If assigned, prefer this
|
||||
* function for automatic flow control.
|
||||
*
|
||||
* @lookahead_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 for characters
|
||||
* not eaten by ->receive_buf() or ->receive_buf2(). It is useful for
|
||||
* processing high-priority characters such as software flow-control
|
||||
* characters that could otherwise get stuck into the intermediate
|
||||
* buffer until tty has room to receive them. Ldisc must be able to
|
||||
* handle later a ->receive_buf() or ->receive_buf2() call for the
|
||||
* same characters (e.g. by skipping the actions for high-priority
|
||||
* characters already handled by ->lookahead_buf()).
|
||||
*
|
||||
* @owner: module containting this ldisc (for reference counting)
|
||||
*
|
||||
* This structure defines the interface between the tty line discipline
|
||||
@ -229,6 +241,8 @@ struct tty_ldisc_ops {
|
||||
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);
|
||||
void (*lookahead_buf)(struct tty_struct *tty, const unsigned char *cp,
|
||||
const unsigned char *fp, unsigned int count);
|
||||
|
||||
struct module *owner;
|
||||
};
|
||||
|
@ -40,6 +40,8 @@ struct tty_port_operations {
|
||||
|
||||
struct tty_port_client_operations {
|
||||
int (*receive_buf)(struct tty_port *port, const unsigned char *, const unsigned char *, size_t);
|
||||
void (*lookahead_buf)(struct tty_port *port, const unsigned char *cp,
|
||||
const unsigned char *fp, unsigned int count);
|
||||
void (*write_wakeup)(struct tty_port *port);
|
||||
};
|
||||
|
||||
|
@ -46,6 +46,7 @@ typedef unsigned int speed_t;
|
||||
#define EXTA B19200
|
||||
#define EXTB B38400
|
||||
|
||||
#define ADDRB 0x20000000 /* address bit */
|
||||
#define CMSPAR 0x40000000 /* mark or space (stick) parity */
|
||||
#define CRTSCTS 0x80000000 /* flow control */
|
||||
|
||||
|
@ -126,10 +126,26 @@ struct serial_rs485 {
|
||||
#define SER_RS485_TERMINATE_BUS (1 << 5) /* Enable bus
|
||||
termination
|
||||
(if supported) */
|
||||
|
||||
/* RS-485 addressing mode */
|
||||
#define SER_RS485_ADDRB (1 << 6) /* Enable addressing mode */
|
||||
#define SER_RS485_ADDR_RECV (1 << 7) /* Receive address filter */
|
||||
#define SER_RS485_ADDR_DEST (1 << 8) /* Destination address */
|
||||
|
||||
__u32 delay_rts_before_send; /* Delay before send (milliseconds) */
|
||||
__u32 delay_rts_after_send; /* Delay after send (milliseconds) */
|
||||
__u32 padding[5]; /* Memory is cheap, new structs
|
||||
are a royal PITA .. */
|
||||
|
||||
/* The fields below are defined by flags */
|
||||
union {
|
||||
__u32 padding[5]; /* Memory is cheap, new structs are a pain */
|
||||
|
||||
struct {
|
||||
__u8 addr_recv;
|
||||
__u8 addr_dest;
|
||||
__u8 padding0[2];
|
||||
__u32 padding1[4];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -124,10 +124,6 @@
|
||||
/* TXX9 type number */
|
||||
#define PORT_TXX9 64
|
||||
|
||||
/* NEC VR4100 series SIU/DSIU */
|
||||
#define PORT_VR41XX_SIU 65
|
||||
#define PORT_VR41XX_DSIU 66
|
||||
|
||||
/* Samsung S3C2400 SoC */
|
||||
#define PORT_S3C2400 67
|
||||
|
||||
|
@ -139,7 +139,7 @@
|
||||
#define UART_LSR_PE 0x04 /* Parity error indicator */
|
||||
#define UART_LSR_OE 0x02 /* Overrun error indicator */
|
||||
#define UART_LSR_DR 0x01 /* Receiver data ready */
|
||||
#define UART_LSR_BRK_ERROR_BITS 0x1E /* BI, FE, PE, OE bits */
|
||||
#define UART_LSR_BRK_ERROR_BITS (UART_LSR_BI|UART_LSR_FE|UART_LSR_PE|UART_LSR_OE)
|
||||
|
||||
#define UART_MSR 6 /* In: Modem Status Register */
|
||||
#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
|
||||
@ -150,7 +150,7 @@
|
||||
#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
|
||||
#define UART_MSR_DDSR 0x02 /* Delta DSR */
|
||||
#define UART_MSR_DCTS 0x01 /* Delta CTS */
|
||||
#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
|
||||
#define UART_MSR_ANY_DELTA (UART_MSR_DDCD|UART_MSR_TERI|UART_MSR_DDSR|UART_MSR_DCTS)
|
||||
|
||||
#define UART_SCR 7 /* I/O: Scratch Register */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user