TTY/Serial patches for 5.2-rc1
Here is the "big" set of tty/serial driver patches for 5.2-rc1. It's really pretty small, not much happening in this portion of the kernel at the moment. When the "highlight" is the movement of the documentation from .txt to .rst files, it's a good merge window. There's a number of small fixes and updates over the various serial drivers, and a new "tty null" driver for those embedded systems that like to make things even smaller and not break things. All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXNKvrw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ynR2wCfTrWM9Qm7oA1hgWeYZiLTrnYnOtsAoK4a629W o7AAyVf8RJ4jdWaSgOqx =9Dy/ -----END PGP SIGNATURE----- Merge tag 'tty-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial updates from Greg KH: "Here is the "big" set of tty/serial driver patches for 5.2-rc1. It's really pretty small, not much happening in this portion of the kernel at the moment. When the "highlight" is the movement of the documentation from .txt to .rst files, it's a good merge window. There's a number of small fixes and updates over the various serial drivers, and a new "tty null" driver for those embedded systems that like to make things even smaller and not break things. All of these have been in linux-next for a while with no reported issues" * tag 'tty-5.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (45 commits) tty: serial: add driver for the SiFive UART dt-bindings: serial: add documentation for the SiFive UART driver serial: uartps: Add support for cts-override dt-bindings: xilinx-uartps: Add support for cts-override serial: milbeaut_usio: Fix error handling in probe and remove tty: rocket: deprecate the rp_ioctl tty: rocket: Remove RCPK_GET_STRUCT ioctl tty: update obsolete termios comment tty: serial_core: fix error code returned by uart_register_driver() serial: 8250-mtk: modify baudrate setting serial: 8250-mtk: add follow control docs: serial: convert docs to ReST and rename to *.rst serial: 8250_exar: Adjust IOT2000 matching TTY: serial_core, add ->install serial: Fix using plain integer instead of Null pointer tty:serial_core: Spelling mistake tty: Add NULL TTY driver tty: vt: keyboard: Allow Unicode compose base char Revert "tty: fix NULL pointer issue when tty_port ops is not set" serial: Add Milbeaut serial control ...
This commit is contained in:
commit
b3a5e648f5
@ -12,6 +12,11 @@ Required properties:
|
||||
See ../clocks/clock-bindings.txt for details.
|
||||
|
||||
|
||||
Optional properties:
|
||||
- cts-override : Override the CTS modem status signal. This signal will
|
||||
always be reported as active instead of being obtained from the modem status
|
||||
register. Define this if your serial port does not use this pin
|
||||
|
||||
Example:
|
||||
uart@e0000000 {
|
||||
compatible = "cdns,uart-r1p8";
|
||||
|
@ -12,6 +12,8 @@ Required properties:
|
||||
- reg: I2C address of the SC16IS7xx device.
|
||||
- interrupts: Should contain the UART interrupt
|
||||
- clocks: Reference to the IC source clock.
|
||||
OR (when there is no clock provider visible to the platform)
|
||||
- clock-frequency: The source clock frequency for the IC.
|
||||
|
||||
Optional properties:
|
||||
- gpio-controller: Marks the device node as a GPIO controller.
|
||||
|
33
Documentation/devicetree/bindings/serial/sifive-serial.txt
Normal file
33
Documentation/devicetree/bindings/serial/sifive-serial.txt
Normal file
@ -0,0 +1,33 @@
|
||||
SiFive asynchronous serial interface (UART)
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be something similar to
|
||||
"sifive,<chip>-uart" for the UART as integrated
|
||||
on a particular chip, and "sifive,uart<version>" for the
|
||||
general UART IP block programming model. Supported
|
||||
compatible strings as of the date of this writing are:
|
||||
"sifive,fu540-c000-uart" for the SiFive UART v0 as
|
||||
integrated onto the SiFive FU540 chip, or "sifive,uart0"
|
||||
for the SiFive UART v0 IP block with no chip integration
|
||||
tweaks (if any)
|
||||
- reg: address and length of the register space
|
||||
- interrupts: Should contain the UART interrupt identifier
|
||||
- clocks: Should contain a clock identifier for the UART's parent clock
|
||||
|
||||
|
||||
UART HDL that corresponds to the IP block version numbers can be found
|
||||
here:
|
||||
|
||||
https://github.com/sifive/sifive-blocks/tree/master/src/main/scala/devices/uart
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
uart0: serial@10010000 {
|
||||
compatible = "sifive,fu540-c000-uart", "sifive,uart0";
|
||||
interrupt-parent = <&plic0>;
|
||||
interrupts = <80>;
|
||||
reg = <0x0 0x10010000 0x0 0x1000>;
|
||||
clocks = <&prci PRCI_CLK_TLCLK>;
|
||||
};
|
@ -7,7 +7,17 @@ Required properties:
|
||||
|
||||
- reg: offset and length of the register set for the device
|
||||
- interrupts: exactly one interrupt specifier
|
||||
- clocks: phandles to input clocks.
|
||||
- clock-names: Should contain following entries:
|
||||
"enable" for UART module enable clock,
|
||||
"uart" for UART clock,
|
||||
"source" for UART source (parent) clock.
|
||||
- clocks: Should contain a clock specifier for each entry in clock-names.
|
||||
UART clock and source clock are optional properties, but enable clock
|
||||
is required.
|
||||
|
||||
Optional properties:
|
||||
- dma-names: Should contain "rx" for receive and "tx" for transmit channels.
|
||||
- dmas: A list of dma specifiers, one for each entry in dma-names.
|
||||
|
||||
Example:
|
||||
uart0: serial@0 {
|
||||
@ -15,5 +25,8 @@ Example:
|
||||
"sprd,sc9836-uart";
|
||||
reg = <0x0 0x100>;
|
||||
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ext_26m>;
|
||||
dma-names = "rx", "tx";
|
||||
dmas = <&ap_dma 19>, <&ap_dma 20>;
|
||||
clock-names = "enable", "uart", "source";
|
||||
clocks = <&clk_ap_apb_gates 9>, <&clk_uart0>, <&ext_26m>;
|
||||
};
|
||||
|
@ -1,8 +1,11 @@
|
||||
================
|
||||
Cyclades-Z notes
|
||||
================
|
||||
|
||||
The Cyclades-Z must have firmware loaded onto the card before it will
|
||||
operate. This operation should be performed during system startup,
|
||||
|
||||
The firmware, loader program and the latest device driver code are
|
||||
available from Cyclades at
|
||||
ftp://ftp.cyclades.com/pub/cyclades/cyclades-z/linux/
|
||||
|
||||
ftp://ftp.cyclades.com/pub/cyclades/cyclades-z/linux/
|
@ -1,6 +1,6 @@
|
||||
|
||||
Low Level Serial API
|
||||
--------------------
|
||||
====================
|
||||
Low Level Serial API
|
||||
====================
|
||||
|
||||
|
||||
This document is meant as a brief overview of some aspects of the new serial
|
||||
@ -44,7 +44,7 @@ are described in the uart_ops listing below.)
|
||||
There are two locks. A per-port spinlock, and an overall semaphore.
|
||||
|
||||
From the core driver perspective, the port->lock locks the following
|
||||
data:
|
||||
data::
|
||||
|
||||
port->mctrl
|
||||
port->icount
|
||||
@ -75,41 +75,51 @@ hardware.
|
||||
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)
|
||||
@ -121,14 +131,18 @@ hardware.
|
||||
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)
|
||||
@ -138,16 +152,17 @@ hardware.
|
||||
This will be called only if hardware assisted flow control is enabled.
|
||||
|
||||
Locking: serialized with .unthrottle() and termios modification by the
|
||||
tty layer.
|
||||
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.
|
||||
tty layer.
|
||||
|
||||
send_xchar(port,ch)
|
||||
Transmit a high priority character, even if the port is stopped.
|
||||
@ -159,6 +174,7 @@ hardware.
|
||||
Do not transmit if ch == '\0' (__DISABLED_CHAR).
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
stop_rx(port)
|
||||
@ -166,7 +182,9 @@ hardware.
|
||||
being closed.
|
||||
|
||||
Locking: port->lock taken.
|
||||
|
||||
Interrupts: locally disabled.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
enable_ms(port)
|
||||
@ -177,7 +195,9 @@ hardware.
|
||||
called.
|
||||
|
||||
Locking: port->lock taken.
|
||||
|
||||
Interrupts: locally disabled.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
break_ctl(port,ctl)
|
||||
@ -196,6 +216,7 @@ hardware.
|
||||
This method will only be called when the port is initially opened.
|
||||
|
||||
Locking: port_sem taken.
|
||||
|
||||
Interrupts: globally disabled.
|
||||
|
||||
shutdown(port)
|
||||
@ -210,6 +231,7 @@ hardware.
|
||||
this port.
|
||||
|
||||
Locking: port_sem taken.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
flush_buffer(port)
|
||||
@ -220,7 +242,9 @@ hardware.
|
||||
buffer is cleared.
|
||||
|
||||
Locking: port->lock taken.
|
||||
|
||||
Interrupts: locally disabled.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
set_termios(port,termios,oldtermios)
|
||||
@ -228,29 +252,46 @@ hardware.
|
||||
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,
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
INPCK
|
||||
- enable frame and parity error events to be
|
||||
passed to the TTY layer.
|
||||
BRKINT
|
||||
PARMRK - both of these enable break events to be
|
||||
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
|
||||
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
|
||||
@ -258,16 +299,19 @@ hardware.
|
||||
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 Documentation/serial/tty.txt.
|
||||
Notifier for discipline change. See Documentation/serial/tty.rst.
|
||||
|
||||
Locking: caller holds tty_port->mutex
|
||||
|
||||
@ -283,6 +327,7 @@ hardware.
|
||||
will occur even if CONFIG_PM is not set.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
type(port)
|
||||
@ -291,6 +336,7 @@ hardware.
|
||||
substituted.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
release_port(port)
|
||||
@ -298,6 +344,7 @@ hardware.
|
||||
the port.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
request_port(port)
|
||||
@ -306,6 +353,7 @@ hardware.
|
||||
returns, and it should return -EBUSY on failure.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
config_port(port,type)
|
||||
@ -321,6 +369,7 @@ hardware.
|
||||
internally hard wired (eg, system on a chip implementations).
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
verify_port(port,serinfo)
|
||||
@ -328,6 +377,7 @@ hardware.
|
||||
suitable for this port type.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
ioctl(port,cmd,arg)
|
||||
@ -335,6 +385,7 @@ hardware.
|
||||
using the standard numbering system found in <asm/ioctl.h>
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
poll_init(port)
|
||||
@ -343,6 +394,7 @@ hardware.
|
||||
this should not request interrupts.
|
||||
|
||||
Locking: tty_mutex and tty_port->mutex taken.
|
||||
|
||||
Interrupts: n/a.
|
||||
|
||||
poll_put_char(port,ch)
|
||||
@ -350,7 +402,9 @@ hardware.
|
||||
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)
|
||||
@ -359,7 +413,9 @@ hardware.
|
||||
the function should return NO_POLL_CHAR immediately.
|
||||
|
||||
Locking: none.
|
||||
|
||||
Interrupts: caller dependent.
|
||||
|
||||
This call must not sleep
|
||||
|
||||
Other functions
|
||||
@ -370,6 +426,7 @@ uart_update_timeout(port,cflag,baud)
|
||||
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)
|
||||
@ -385,6 +442,7 @@ uart_get_baud_rate(port,termios,old,min,max)
|
||||
Note: min..max must always allow 9600 baud to be selected.
|
||||
|
||||
Locking: caller dependent.
|
||||
|
||||
Interrupts: n/a
|
||||
|
||||
uart_get_divisor(port,baud)
|
||||
@ -395,6 +453,7 @@ uart_get_divisor(port,baud)
|
||||
custom divisor instead.
|
||||
|
||||
Locking: caller dependent.
|
||||
|
||||
Interrupts: n/a
|
||||
|
||||
uart_match_port(port1,port2)
|
||||
@ -402,6 +461,7 @@ uart_match_port(port1,port2)
|
||||
uart_port structures describe the same port.
|
||||
|
||||
Locking: n/a
|
||||
|
||||
Interrupts: n/a
|
||||
|
||||
uart_write_wakeup(port)
|
||||
@ -409,6 +469,7 @@ uart_write_wakeup(port)
|
||||
characters in the transmit buffer have dropped below a threshold.
|
||||
|
||||
Locking: port->lock should be held.
|
||||
|
||||
Interrupts: n/a
|
||||
|
||||
uart_register_driver(drv)
|
||||
@ -419,6 +480,7 @@ uart_register_driver(drv)
|
||||
registered using uart_add_one_port after this call has succeeded.
|
||||
|
||||
Locking: none
|
||||
|
||||
Interrupts: enabled
|
||||
|
||||
uart_unregister_driver()
|
||||
@ -427,15 +489,16 @@ uart_unregister_driver()
|
||||
uart_remove_one_port() if it registered them with uart_add_one_port().
|
||||
|
||||
Locking: none
|
||||
|
||||
Interrupts: enabled
|
||||
|
||||
uart_suspend_port()
|
||||
**uart_suspend_port()**
|
||||
|
||||
uart_resume_port()
|
||||
**uart_resume_port()**
|
||||
|
||||
uart_add_one_port()
|
||||
**uart_add_one_port()**
|
||||
|
||||
uart_remove_one_port()
|
||||
**uart_remove_one_port()**
|
||||
|
||||
Other notes
|
||||
-----------
|
||||
@ -444,7 +507,7 @@ It is intended some day to drop the 'unused' entries from uart_port, and
|
||||
allow low level drivers to register their own individual uart_port's with
|
||||
the core. This will allow drivers to use uart_port as a pointer to a
|
||||
structure containing both the uart_port entry with their own extensions,
|
||||
thus:
|
||||
thus::
|
||||
|
||||
struct my_port {
|
||||
struct uart_port port;
|
||||
@ -459,14 +522,14 @@ 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
|
||||
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
|
||||
As `devm_*` functions are used, there's generally no need to call
|
||||
this function.
|
||||
|
||||
mctrl_gpio_to_gpiod(gpios, gidx)
|
32
Documentation/serial/index.rst
Normal file
32
Documentation/serial/index.rst
Normal file
@ -0,0 +1,32 @@
|
||||
:orphan:
|
||||
|
||||
==========================
|
||||
Support for Serial devices
|
||||
==========================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
|
||||
driver
|
||||
tty
|
||||
|
||||
Serial drivers
|
||||
==============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
cyclades_z
|
||||
moxa-smartio
|
||||
n_gsm
|
||||
rocket
|
||||
serial-iso7816
|
||||
serial-rs485
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
@ -1,523 +0,0 @@
|
||||
=============================================================================
|
||||
MOXA Smartio/Industio Family Device Driver Installation Guide
|
||||
for Linux Kernel 2.4.x, 2.6.x
|
||||
Copyright (C) 2008, Moxa Inc.
|
||||
=============================================================================
|
||||
Date: 01/21/2008
|
||||
|
||||
Content
|
||||
|
||||
1. Introduction
|
||||
2. System Requirement
|
||||
3. Installation
|
||||
3.1 Hardware installation
|
||||
3.2 Driver files
|
||||
3.3 Device naming convention
|
||||
3.4 Module driver configuration
|
||||
3.5 Static driver configuration for Linux kernel 2.4.x and 2.6.x.
|
||||
3.6 Custom configuration
|
||||
3.7 Verify driver installation
|
||||
4. Utilities
|
||||
5. Setserial
|
||||
6. Troubleshooting
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
1. Introduction
|
||||
|
||||
The Smartio/Industio/UPCI family Linux driver supports following multiport
|
||||
boards.
|
||||
|
||||
- 2 ports multiport board
|
||||
CP-102U, CP-102UL, CP-102UF
|
||||
CP-132U-I, CP-132UL,
|
||||
CP-132, CP-132I, CP132S, CP-132IS,
|
||||
CI-132, CI-132I, CI-132IS,
|
||||
(C102H, C102HI, C102HIS, C102P, CP-102, CP-102S)
|
||||
|
||||
- 4 ports multiport board
|
||||
CP-104EL,
|
||||
CP-104UL, CP-104JU,
|
||||
CP-134U, CP-134U-I,
|
||||
C104H/PCI, C104HS/PCI,
|
||||
CP-114, CP-114I, CP-114S, CP-114IS, CP-114UL,
|
||||
C104H, C104HS,
|
||||
CI-104J, CI-104JS,
|
||||
CI-134, CI-134I, CI-134IS,
|
||||
(C114HI, CT-114I, C104P)
|
||||
POS-104UL,
|
||||
CB-114,
|
||||
CB-134I
|
||||
|
||||
- 8 ports multiport board
|
||||
CP-118EL, CP-168EL,
|
||||
CP-118U, CP-168U,
|
||||
C168H/PCI,
|
||||
C168H, C168HS,
|
||||
(C168P),
|
||||
CB-108
|
||||
|
||||
This driver and installation procedure have been developed upon Linux Kernel
|
||||
2.4.x and 2.6.x. This driver supports Intel x86 hardware platform. In order
|
||||
to maintain compatibility, this version has also been properly tested with
|
||||
RedHat, Mandrake, Fedora and S.u.S.E Linux. However, if compatibility problem
|
||||
occurs, please contact Moxa at support@moxa.com.tw.
|
||||
|
||||
In addition to device driver, useful utilities are also provided in this
|
||||
version. They are
|
||||
- msdiag Diagnostic program for displaying installed Moxa
|
||||
Smartio/Industio boards.
|
||||
- msmon Monitor program to observe data count and line status signals.
|
||||
- msterm A simple terminal program which is useful in testing serial
|
||||
ports.
|
||||
- io-irq.exe Configuration program to setup ISA boards. Please note that
|
||||
this program can only be executed under DOS.
|
||||
|
||||
All the drivers and utilities are published in form of source code under
|
||||
GNU General Public License in this version. Please refer to GNU General
|
||||
Public License announcement in each source code file for more detail.
|
||||
|
||||
In Moxa's Web sites, you may always find latest driver at http://www.moxa.com/.
|
||||
|
||||
This version of driver can be installed as Loadable Module (Module driver)
|
||||
or built-in into kernel (Static driver). You may refer to following
|
||||
installation procedure for suitable one. Before you install the driver,
|
||||
please refer to hardware installation procedure in the User's Manual.
|
||||
|
||||
We assume the user should be familiar with following documents.
|
||||
- Serial-HOWTO
|
||||
- Kernel-HOWTO
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
2. System Requirement
|
||||
- Hardware platform: Intel x86 machine
|
||||
- Kernel version: 2.4.x or 2.6.x
|
||||
- gcc version 2.72 or later
|
||||
- Maximum 4 boards can be installed in combination
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
3. Installation
|
||||
|
||||
3.1 Hardware installation
|
||||
3.2 Driver files
|
||||
3.3 Device naming convention
|
||||
3.4 Module driver configuration
|
||||
3.5 Static driver configuration for Linux kernel 2.4.x, 2.6.x.
|
||||
3.6 Custom configuration
|
||||
3.7 Verify driver installation
|
||||
|
||||
|
||||
3.1 Hardware installation
|
||||
|
||||
There are two types of buses, ISA and PCI, for Smartio/Industio
|
||||
family multiport board.
|
||||
|
||||
ISA board
|
||||
---------
|
||||
You'll have to configure CAP address, I/O address, Interrupt Vector
|
||||
as well as IRQ before installing this driver. Please refer to hardware
|
||||
installation procedure in User's Manual before proceed any further.
|
||||
Please make sure the JP1 is open after the ISA board is set properly.
|
||||
|
||||
PCI/UPCI board
|
||||
--------------
|
||||
You may need to adjust IRQ usage in BIOS to avoid from IRQ conflict
|
||||
with other ISA devices. Please refer to hardware installation
|
||||
procedure in User's Manual in advance.
|
||||
|
||||
PCI IRQ Sharing
|
||||
-----------
|
||||
Each port within the same multiport board shares the same IRQ. Up to
|
||||
4 Moxa Smartio/Industio PCI Family multiport boards can be installed
|
||||
together on one system and they can share the same IRQ.
|
||||
|
||||
|
||||
3.2 Driver files
|
||||
|
||||
The driver file may be obtained from ftp, CD-ROM or floppy disk. The
|
||||
first step, anyway, is to copy driver file "mxser.tgz" into specified
|
||||
directory. e.g. /moxa. The execute commands as below.
|
||||
|
||||
# cd /
|
||||
# mkdir moxa
|
||||
# cd /moxa
|
||||
# tar xvf /dev/fd0
|
||||
|
||||
or
|
||||
|
||||
# cd /
|
||||
# mkdir moxa
|
||||
# cd /moxa
|
||||
# cp /mnt/cdrom/<driver directory>/mxser.tgz .
|
||||
# tar xvfz mxser.tgz
|
||||
|
||||
|
||||
3.3 Device naming convention
|
||||
|
||||
You may find all the driver and utilities files in /moxa/mxser.
|
||||
Following installation procedure depends on the model you'd like to
|
||||
run the driver. If you prefer module driver, please refer to 3.4.
|
||||
If static driver is required, please refer to 3.5.
|
||||
|
||||
Dialin and callout port
|
||||
-----------------------
|
||||
This driver remains traditional serial device properties. There are
|
||||
two special file name for each serial port. One is dial-in port
|
||||
which is named "ttyMxx". For callout port, the naming convention
|
||||
is "cumxx".
|
||||
|
||||
Device naming when more than 2 boards installed
|
||||
-----------------------------------------------
|
||||
Naming convention for each Smartio/Industio multiport board is
|
||||
pre-defined as below.
|
||||
|
||||
Board Num. Dial-in Port Callout port
|
||||
1st board ttyM0 - ttyM7 cum0 - cum7
|
||||
2nd board ttyM8 - ttyM15 cum8 - cum15
|
||||
3rd board ttyM16 - ttyM23 cum16 - cum23
|
||||
4th board ttyM24 - ttym31 cum24 - cum31
|
||||
|
||||
|
||||
!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
Under Kernel 2.6 the cum Device is Obsolete. So use ttyM*
|
||||
device instead.
|
||||
!!!!!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
Board sequence
|
||||
--------------
|
||||
This driver will activate ISA boards according to the parameter set
|
||||
in the driver. After all specified ISA board activated, PCI board
|
||||
will be installed in the system automatically driven.
|
||||
Therefore the board number is sorted by the CAP address of ISA boards.
|
||||
For PCI boards, their sequence will be after ISA boards and C168H/PCI
|
||||
has higher priority than C104H/PCI boards.
|
||||
|
||||
3.4 Module driver configuration
|
||||
Module driver is easiest way to install. If you prefer static driver
|
||||
installation, please skip this paragraph.
|
||||
|
||||
|
||||
------------- Prepare to use the MOXA driver--------------------
|
||||
3.4.1 Create tty device with correct major number
|
||||
Before using MOXA driver, your system must have the tty devices
|
||||
which are created with driver's major number. We offer one shell
|
||||
script "msmknod" to simplify the procedure.
|
||||
This step is only needed to be executed once. But you still
|
||||
need to do this procedure when:
|
||||
a. You change the driver's major number. Please refer the "3.7"
|
||||
section.
|
||||
b. Your total installed MOXA boards number is changed. Maybe you
|
||||
add/delete one MOXA board.
|
||||
c. You want to change the tty name. This needs to modify the
|
||||
shell script "msmknod"
|
||||
|
||||
The procedure is:
|
||||
# cd /moxa/mxser/driver
|
||||
# ./msmknod
|
||||
|
||||
This shell script will require the major number for dial-in
|
||||
device and callout device to create tty device. You also need
|
||||
to specify the total installed MOXA board number. Default major
|
||||
numbers for dial-in device and callout device are 30, 35. If
|
||||
you need to change to other number, please refer section "3.7"
|
||||
for more detailed procedure.
|
||||
Msmknod will delete any special files occupying the same device
|
||||
naming.
|
||||
|
||||
3.4.2 Build the MOXA driver and utilities
|
||||
Before using the MOXA driver and utilities, you need compile the
|
||||
all the source code. This step is only need to be executed once.
|
||||
But you still re-compile the source code if you modify the source
|
||||
code. For example, if you change the driver's major number (see
|
||||
"3.7" section), then you need to do this step again.
|
||||
|
||||
Find "Makefile" in /moxa/mxser, then run
|
||||
|
||||
# make clean; make install
|
||||
|
||||
!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!
|
||||
For Red Hat 9, Red Hat Enterprise Linux AS3/ES3/WS3 & Fedora Core1:
|
||||
# make clean; make installsp1
|
||||
|
||||
For Red Hat Enterprise Linux AS4/ES4/WS4:
|
||||
# make clean; make installsp2
|
||||
!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!
|
||||
|
||||
The driver files "mxser.o" and utilities will be properly compiled
|
||||
and copied to system directories respectively.
|
||||
|
||||
------------- Load MOXA driver--------------------
|
||||
3.4.3 Load the MOXA driver
|
||||
|
||||
# modprobe mxser <argument>
|
||||
|
||||
will activate the module driver. You may run "lsmod" to check
|
||||
if "mxser" is activated. If the MOXA board is ISA board, the
|
||||
<argument> is needed. Please refer to section "3.4.5" for more
|
||||
information.
|
||||
|
||||
|
||||
------------- Load MOXA driver on boot --------------------
|
||||
3.4.4 For the above description, you may manually execute
|
||||
"modprobe mxser" to activate this driver and run
|
||||
"rmmod mxser" to remove it.
|
||||
However, it's better to have a boot time configuration to
|
||||
eliminate manual operation. Boot time configuration can be
|
||||
achieved by rc file. We offer one "rc.mxser" file to simplify
|
||||
the procedure under "moxa/mxser/driver".
|
||||
|
||||
But if you use ISA board, please modify the "modprobe ..." command
|
||||
to add the argument (see "3.4.5" section). After modifying the
|
||||
rc.mxser, please try to execute "/moxa/mxser/driver/rc.mxser"
|
||||
manually to make sure the modification is ok. If any error
|
||||
encountered, please try to modify again. If the modification is
|
||||
completed, follow the below step.
|
||||
|
||||
Run following command for setting rc files.
|
||||
|
||||
# cd /moxa/mxser/driver
|
||||
# cp ./rc.mxser /etc/rc.d
|
||||
# cd /etc/rc.d
|
||||
|
||||
Check "rc.serial" is existed or not. If "rc.serial" doesn't exist,
|
||||
create it by vi, run "chmod 755 rc.serial" to change the permission.
|
||||
Add "/etc/rc.d/rc.mxser" in last line,
|
||||
|
||||
Reboot and check if moxa.o activated by "lsmod" command.
|
||||
|
||||
3.4.5. If you'd like to drive Smartio/Industio ISA boards in the system,
|
||||
you'll have to add parameter to specify CAP address of given
|
||||
board while activating "mxser.o". The format for parameters are
|
||||
as follows.
|
||||
|
||||
modprobe mxser ioaddr=0x???,0x???,0x???,0x???
|
||||
| | | |
|
||||
| | | +- 4th ISA board
|
||||
| | +------ 3rd ISA board
|
||||
| +------------ 2nd ISA board
|
||||
+------------------- 1st ISA board
|
||||
|
||||
3.5 Static driver configuration for Linux kernel 2.4.x and 2.6.x
|
||||
|
||||
Note: To use static driver, you must install the linux kernel
|
||||
source package.
|
||||
|
||||
3.5.1 Backup the built-in driver in the kernel.
|
||||
# cd /usr/src/linux/drivers/char
|
||||
# mv mxser.c mxser.c.old
|
||||
|
||||
For Red Hat 7.x user, you need to create link:
|
||||
# cd /usr/src
|
||||
# ln -s linux-2.4 linux
|
||||
|
||||
3.5.2 Create link
|
||||
# cd /usr/src/linux/drivers/char
|
||||
# ln -s /moxa/mxser/driver/mxser.c mxser.c
|
||||
|
||||
3.5.3 Add CAP address list for ISA boards. For PCI boards user,
|
||||
please skip this step.
|
||||
|
||||
In module mode, the CAP address for ISA board is given by
|
||||
parameter. In static driver configuration, you'll have to
|
||||
assign it within driver's source code. If you will not
|
||||
install any ISA boards, you may skip to next portion.
|
||||
The instructions to modify driver source code are as
|
||||
below.
|
||||
a. # cd /moxa/mxser/driver
|
||||
# vi mxser.c
|
||||
b. Find the array mxserBoardCAP[] as below.
|
||||
|
||||
static int mxserBoardCAP[]
|
||||
= {0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
c. Change the address within this array using vi. For
|
||||
example, to driver 2 ISA boards with CAP address
|
||||
0x280 and 0x180 as 1st and 2nd board. Just to change
|
||||
the source code as follows.
|
||||
|
||||
static int mxserBoardCAP[]
|
||||
= {0x280, 0x180, 0x00, 0x00};
|
||||
|
||||
3.5.4 Setup kernel configuration
|
||||
|
||||
Configure the kernel:
|
||||
|
||||
# cd /usr/src/linux
|
||||
# make menuconfig
|
||||
|
||||
You will go into a menu-driven system. Please select [Character
|
||||
devices][Non-standard serial port support], enable the [Moxa
|
||||
SmartIO support] driver with "[*]" for built-in (not "[M]"), then
|
||||
select [Exit] to exit this program.
|
||||
|
||||
3.5.5 Rebuild kernel
|
||||
The following are for Linux kernel rebuilding, for your
|
||||
reference only.
|
||||
For appropriate details, please refer to the Linux document.
|
||||
|
||||
a. cd /usr/src/linux
|
||||
b. make clean /* take a few minutes */
|
||||
c. make dep /* take a few minutes */
|
||||
d. make bzImage /* take probably 10-20 minutes */
|
||||
e. make install /* copy boot image to correct position */
|
||||
f. Please make sure the boot kernel (vmlinuz) is in the
|
||||
correct position.
|
||||
g. If you use 'lilo' utility, you should check /etc/lilo.conf
|
||||
'image' item specified the path which is the 'vmlinuz' path,
|
||||
or you will load wrong (or old) boot kernel image (vmlinuz).
|
||||
After checking /etc/lilo.conf, please run "lilo".
|
||||
|
||||
Note that if the result of "make bzImage" is ERROR, then you have to
|
||||
go back to Linux configuration Setup. Type "make menuconfig" in
|
||||
directory /usr/src/linux.
|
||||
|
||||
|
||||
3.5.6 Make tty device and special file
|
||||
# cd /moxa/mxser/driver
|
||||
# ./msmknod
|
||||
|
||||
3.5.7 Make utility
|
||||
# cd /moxa/mxser/utility
|
||||
# make clean; make install
|
||||
|
||||
3.5.8 Reboot
|
||||
|
||||
|
||||
|
||||
3.6 Custom configuration
|
||||
Although this driver already provides you default configuration, you
|
||||
still can change the device name and major number. The instruction to
|
||||
change these parameters are shown as below.
|
||||
|
||||
Change Device name
|
||||
------------------
|
||||
If you'd like to use other device names instead of default naming
|
||||
convention, all you have to do is to modify the internal code
|
||||
within the shell script "msmknod". First, you have to open "msmknod"
|
||||
by vi. Locate each line contains "ttyM" and "cum" and change them
|
||||
to the device name you desired. "msmknod" creates the device names
|
||||
you need next time executed.
|
||||
|
||||
Change Major number
|
||||
-------------------
|
||||
If major number 30 and 35 had been occupied, you may have to select
|
||||
2 free major numbers for this driver. There are 3 steps to change
|
||||
major numbers.
|
||||
|
||||
3.6.1 Find free major numbers
|
||||
In /proc/devices, you may find all the major numbers occupied
|
||||
in the system. Please select 2 major numbers that are available.
|
||||
e.g. 40, 45.
|
||||
3.6.2 Create special files
|
||||
Run /moxa/mxser/driver/msmknod to create special files with
|
||||
specified major numbers.
|
||||
3.6.3 Modify driver with new major number
|
||||
Run vi to open /moxa/mxser/driver/mxser.c. Locate the line
|
||||
contains "MXSERMAJOR". Change the content as below.
|
||||
#define MXSERMAJOR 40
|
||||
#define MXSERCUMAJOR 45
|
||||
3.6.4 Run "make clean; make install" in /moxa/mxser/driver.
|
||||
|
||||
3.7 Verify driver installation
|
||||
You may refer to /var/log/messages to check the latest status
|
||||
log reported by this driver whenever it's activated.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
4. Utilities
|
||||
There are 3 utilities contained in this driver. They are msdiag, msmon and
|
||||
msterm. These 3 utilities are released in form of source code. They should
|
||||
be compiled into executable file and copied into /usr/bin.
|
||||
|
||||
Before using these utilities, please load driver (refer 3.4 & 3.5) and
|
||||
make sure you had run the "msmknod" utility.
|
||||
|
||||
msdiag - Diagnostic
|
||||
--------------------
|
||||
This utility provides the function to display what Moxa Smartio/Industio
|
||||
board found by driver in the system.
|
||||
|
||||
msmon - Port Monitoring
|
||||
-----------------------
|
||||
This utility gives the user a quick view about all the MOXA ports'
|
||||
activities. One can easily learn each port's total received/transmitted
|
||||
(Rx/Tx) character count since the time when the monitoring is started.
|
||||
Rx/Tx throughputs per second are also reported in interval basis (e.g.
|
||||
the last 5 seconds) and in average basis (since the time the monitoring
|
||||
is started). You can reset all ports' count by <HOME> key. <+> <->
|
||||
(plus/minus) keys to change the displaying time interval. Press <ENTER>
|
||||
on the port, that cursor stay, to view the port's communication
|
||||
parameters, signal status, and input/output queue.
|
||||
|
||||
msterm - Terminal Emulation
|
||||
---------------------------
|
||||
This utility provides data sending and receiving ability of all tty ports,
|
||||
especially for MOXA ports. It is quite useful for testing simple
|
||||
application, for example, sending AT command to a modem connected to the
|
||||
port or used as a terminal for login purpose. Note that this is only a
|
||||
dumb terminal emulation without handling full screen operation.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
5. Setserial
|
||||
|
||||
Supported Setserial parameters are listed as below.
|
||||
|
||||
uart set UART type(16450-->disable FIFO, 16550A-->enable FIFO)
|
||||
close_delay set the amount of time(in 1/100 of a second) that DTR
|
||||
should be kept low while being closed.
|
||||
closing_wait set the amount of time(in 1/100 of a second) that the
|
||||
serial port should wait for data to be drained while
|
||||
being closed, before the receiver is disable.
|
||||
spd_hi Use 57.6kb when the application requests 38.4kb.
|
||||
spd_vhi Use 115.2kb when the application requests 38.4kb.
|
||||
spd_shi Use 230.4kb when the application requests 38.4kb.
|
||||
spd_warp Use 460.8kb when the application requests 38.4kb.
|
||||
spd_normal Use 38.4kb when the application requests 38.4kb.
|
||||
spd_cust Use the custom divisor to set the speed when the
|
||||
application requests 38.4kb.
|
||||
divisor This option set the custom division.
|
||||
baud_base This option set the base baud rate.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
6. Troubleshooting
|
||||
|
||||
The boot time error messages and solutions are stated as clearly as
|
||||
possible. If all the possible solutions fail, please contact our technical
|
||||
support team to get more help.
|
||||
|
||||
|
||||
Error msg: More than 4 Moxa Smartio/Industio family boards found. Fifth board
|
||||
and after are ignored.
|
||||
Solution:
|
||||
To avoid this problem, please unplug fifth and after board, because Moxa
|
||||
driver supports up to 4 boards.
|
||||
|
||||
Error msg: Request_irq fail, IRQ(?) may be conflict with another device.
|
||||
Solution:
|
||||
Other PCI or ISA devices occupy the assigned IRQ. If you are not sure
|
||||
which device causes the situation, please check /proc/interrupts to find
|
||||
free IRQ and simply change another free IRQ for Moxa board.
|
||||
|
||||
Error msg: Board #: C1xx Series(CAP=xxx) interrupt number invalid.
|
||||
Solution:
|
||||
Each port within the same multiport board shares the same IRQ. Please set
|
||||
one IRQ (IRQ doesn't equal to zero) for one Moxa board.
|
||||
|
||||
Error msg: No interrupt vector be set for Moxa ISA board(CAP=xxx).
|
||||
Solution:
|
||||
Moxa ISA board needs an interrupt vector.Please refer to user's manual
|
||||
"Hardware Installation" chapter to set interrupt vector.
|
||||
|
||||
Error msg: Couldn't install MOXA Smartio/Industio family driver!
|
||||
Solution:
|
||||
Load Moxa driver fail, the major number may conflict with other devices.
|
||||
Please refer to previous section 3.7 to change a free major number for
|
||||
Moxa driver.
|
||||
|
||||
Error msg: Couldn't install MOXA Smartio/Industio family callout driver!
|
||||
Solution:
|
||||
Load Moxa callout driver fail, the callout device major number may
|
||||
conflict with other devices. Please refer to previous section 3.7 to
|
||||
change a free callout device major number for Moxa driver.
|
||||
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
615
Documentation/serial/moxa-smartio.rst
Normal file
615
Documentation/serial/moxa-smartio.rst
Normal file
@ -0,0 +1,615 @@
|
||||
=============================================================
|
||||
MOXA Smartio/Industio Family Device Driver Installation Guide
|
||||
=============================================================
|
||||
|
||||
.. note::
|
||||
|
||||
This file is outdated. It needs some care in order to make it
|
||||
updated to Kernel 5.0 and upper
|
||||
|
||||
Copyright (C) 2008, Moxa Inc.
|
||||
|
||||
Date: 01/21/2008
|
||||
|
||||
.. Content
|
||||
|
||||
1. Introduction
|
||||
2. System Requirement
|
||||
3. Installation
|
||||
3.1 Hardware installation
|
||||
3.2 Driver files
|
||||
3.3 Device naming convention
|
||||
3.4 Module driver configuration
|
||||
3.5 Static driver configuration for Linux kernel 2.4.x and 2.6.x.
|
||||
3.6 Custom configuration
|
||||
3.7 Verify driver installation
|
||||
4. Utilities
|
||||
5. Setserial
|
||||
6. Troubleshooting
|
||||
|
||||
1. Introduction
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
The Smartio/Industio/UPCI family Linux driver supports following multiport
|
||||
boards.
|
||||
|
||||
- 2 ports multiport board
|
||||
CP-102U, CP-102UL, CP-102UF
|
||||
CP-132U-I, CP-132UL,
|
||||
CP-132, CP-132I, CP132S, CP-132IS,
|
||||
CI-132, CI-132I, CI-132IS,
|
||||
(C102H, C102HI, C102HIS, C102P, CP-102, CP-102S)
|
||||
|
||||
- 4 ports multiport board
|
||||
CP-104EL,
|
||||
CP-104UL, CP-104JU,
|
||||
CP-134U, CP-134U-I,
|
||||
C104H/PCI, C104HS/PCI,
|
||||
CP-114, CP-114I, CP-114S, CP-114IS, CP-114UL,
|
||||
C104H, C104HS,
|
||||
CI-104J, CI-104JS,
|
||||
CI-134, CI-134I, CI-134IS,
|
||||
(C114HI, CT-114I, C104P),
|
||||
POS-104UL,
|
||||
CB-114,
|
||||
CB-134I
|
||||
|
||||
- 8 ports multiport board
|
||||
CP-118EL, CP-168EL,
|
||||
CP-118U, CP-168U,
|
||||
C168H/PCI,
|
||||
C168H, C168HS,
|
||||
(C168P),
|
||||
CB-108
|
||||
|
||||
This driver and installation procedure have been developed upon Linux Kernel
|
||||
2.4.x and 2.6.x. This driver supports Intel x86 hardware platform. In order
|
||||
to maintain compatibility, this version has also been properly tested with
|
||||
RedHat, Mandrake, Fedora and S.u.S.E Linux. However, if compatibility problem
|
||||
occurs, please contact Moxa at support@moxa.com.tw.
|
||||
|
||||
In addition to device driver, useful utilities are also provided in this
|
||||
version. They are:
|
||||
|
||||
- msdiag
|
||||
Diagnostic program for displaying installed Moxa
|
||||
Smartio/Industio boards.
|
||||
- msmon
|
||||
Monitor program to observe data count and line status signals.
|
||||
- msterm A simple terminal program which is useful in testing serial
|
||||
ports.
|
||||
- io-irq.exe
|
||||
Configuration program to setup ISA boards. Please note that
|
||||
this program can only be executed under DOS.
|
||||
|
||||
All the drivers and utilities are published in form of source code under
|
||||
GNU General Public License in this version. Please refer to GNU General
|
||||
Public License announcement in each source code file for more detail.
|
||||
|
||||
In Moxa's Web sites, you may always find latest driver at http://www.moxa.com/.
|
||||
|
||||
This version of driver can be installed as Loadable Module (Module driver)
|
||||
or built-in into kernel (Static driver). You may refer to following
|
||||
installation procedure for suitable one. Before you install the driver,
|
||||
please refer to hardware installation procedure in the User's Manual.
|
||||
|
||||
We assume the user should be familiar with following documents.
|
||||
|
||||
- Serial-HOWTO
|
||||
- Kernel-HOWTO
|
||||
|
||||
2. System Requirement
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Hardware platform: Intel x86 machine
|
||||
- Kernel version: 2.4.x or 2.6.x
|
||||
- gcc version 2.72 or later
|
||||
- Maximum 4 boards can be installed in combination
|
||||
|
||||
3. Installation
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
3.1 Hardware installation
|
||||
=========================
|
||||
|
||||
There are two types of buses, ISA and PCI, for Smartio/Industio
|
||||
family multiport board.
|
||||
|
||||
ISA board
|
||||
---------
|
||||
|
||||
You'll have to configure CAP address, I/O address, Interrupt Vector
|
||||
as well as IRQ before installing this driver. Please refer to hardware
|
||||
installation procedure in User's Manual before proceed any further.
|
||||
Please make sure the JP1 is open after the ISA board is set properly.
|
||||
|
||||
PCI/UPCI board
|
||||
--------------
|
||||
|
||||
You may need to adjust IRQ usage in BIOS to avoid from IRQ conflict
|
||||
with other ISA devices. Please refer to hardware installation
|
||||
procedure in User's Manual in advance.
|
||||
|
||||
PCI IRQ Sharing
|
||||
---------------
|
||||
|
||||
Each port within the same multiport board shares the same IRQ. Up to
|
||||
4 Moxa Smartio/Industio PCI Family multiport boards can be installed
|
||||
together on one system and they can share the same IRQ.
|
||||
|
||||
|
||||
3.2 Driver files
|
||||
================
|
||||
|
||||
The driver file may be obtained from ftp, CD-ROM or floppy disk. The
|
||||
first step, anyway, is to copy driver file "mxser.tgz" into specified
|
||||
directory. e.g. /moxa. The execute commands as below::
|
||||
|
||||
# cd /
|
||||
# mkdir moxa
|
||||
# cd /moxa
|
||||
# tar xvf /dev/fd0
|
||||
|
||||
or::
|
||||
|
||||
# cd /
|
||||
# mkdir moxa
|
||||
# cd /moxa
|
||||
# cp /mnt/cdrom/<driver directory>/mxser.tgz .
|
||||
# tar xvfz mxser.tgz
|
||||
|
||||
|
||||
3.3 Device naming convention
|
||||
============================
|
||||
|
||||
You may find all the driver and utilities files in /moxa/mxser.
|
||||
Following installation procedure depends on the model you'd like to
|
||||
run the driver. If you prefer module driver, please refer to 3.4.
|
||||
If static driver is required, please refer to 3.5.
|
||||
|
||||
Dialin and callout port
|
||||
-----------------------
|
||||
|
||||
This driver remains traditional serial device properties. There are
|
||||
two special file name for each serial port. One is dial-in port
|
||||
which is named "ttyMxx". For callout port, the naming convention
|
||||
is "cumxx".
|
||||
|
||||
Device naming when more than 2 boards installed
|
||||
-----------------------------------------------
|
||||
|
||||
Naming convention for each Smartio/Industio multiport board is
|
||||
pre-defined as below.
|
||||
|
||||
============ =============== ==============
|
||||
Board Num. Dial-in Port Callout port
|
||||
1st board ttyM0 - ttyM7 cum0 - cum7
|
||||
2nd board ttyM8 - ttyM15 cum8 - cum15
|
||||
3rd board ttyM16 - ttyM23 cum16 - cum23
|
||||
4th board ttyM24 - ttym31 cum24 - cum31
|
||||
============ =============== ==============
|
||||
|
||||
.. note::
|
||||
|
||||
Under Kernel 2.6 and upper, the cum Device is Obsolete. So use ttyM*
|
||||
device instead.
|
||||
|
||||
Board sequence
|
||||
--------------
|
||||
|
||||
This driver will activate ISA boards according to the parameter set
|
||||
in the driver. After all specified ISA board activated, PCI board
|
||||
will be installed in the system automatically driven.
|
||||
Therefore the board number is sorted by the CAP address of ISA boards.
|
||||
For PCI boards, their sequence will be after ISA boards and C168H/PCI
|
||||
has higher priority than C104H/PCI boards.
|
||||
|
||||
3.4 Module driver configuration
|
||||
===============================
|
||||
|
||||
Module driver is easiest way to install. If you prefer static driver
|
||||
installation, please skip this paragraph.
|
||||
|
||||
|
||||
------------- Prepare to use the MOXA driver --------------------
|
||||
|
||||
3.4.1 Create tty device with correct major number
|
||||
-------------------------------------------------
|
||||
|
||||
Before using MOXA driver, your system must have the tty devices
|
||||
which are created with driver's major number. We offer one shell
|
||||
script "msmknod" to simplify the procedure.
|
||||
This step is only needed to be executed once. But you still
|
||||
need to do this procedure when:
|
||||
|
||||
a. You change the driver's major number. Please refer the "3.7"
|
||||
section.
|
||||
b. Your total installed MOXA boards number is changed. Maybe you
|
||||
add/delete one MOXA board.
|
||||
c. You want to change the tty name. This needs to modify the
|
||||
shell script "msmknod"
|
||||
|
||||
The procedure is::
|
||||
|
||||
# cd /moxa/mxser/driver
|
||||
# ./msmknod
|
||||
|
||||
This shell script will require the major number for dial-in
|
||||
device and callout device to create tty device. You also need
|
||||
to specify the total installed MOXA board number. Default major
|
||||
numbers for dial-in device and callout device are 30, 35. If
|
||||
you need to change to other number, please refer section "3.7"
|
||||
for more detailed procedure.
|
||||
Msmknod will delete any special files occupying the same device
|
||||
naming.
|
||||
|
||||
3.4.2 Build the MOXA driver and utilities
|
||||
-----------------------------------------
|
||||
|
||||
Before using the MOXA driver and utilities, you need compile the
|
||||
all the source code. This step is only need to be executed once.
|
||||
But you still re-compile the source code if you modify the source
|
||||
code. For example, if you change the driver's major number (see
|
||||
"3.7" section), then you need to do this step again.
|
||||
|
||||
Find "Makefile" in /moxa/mxser, then run
|
||||
|
||||
# make clean; make install
|
||||
|
||||
..note::
|
||||
|
||||
For Red Hat 9, Red Hat Enterprise Linux AS3/ES3/WS3 & Fedora Core1:
|
||||
# make clean; make installsp1
|
||||
|
||||
For Red Hat Enterprise Linux AS4/ES4/WS4:
|
||||
# make clean; make installsp2
|
||||
|
||||
The driver files "mxser.o" and utilities will be properly compiled
|
||||
and copied to system directories respectively.
|
||||
|
||||
------------- Load MOXA driver--------------------
|
||||
|
||||
3.4.3 Load the MOXA driver
|
||||
--------------------------
|
||||
|
||||
::
|
||||
|
||||
# modprobe mxser <argument>
|
||||
|
||||
will activate the module driver. You may run "lsmod" to check
|
||||
if "mxser" is activated. If the MOXA board is ISA board, the
|
||||
<argument> is needed. Please refer to section "3.4.5" for more
|
||||
information.
|
||||
|
||||
------------- Load MOXA driver on boot --------------------
|
||||
|
||||
3.4.4 Load the mxser driver
|
||||
---------------------------
|
||||
|
||||
|
||||
For the above description, you may manually execute
|
||||
"modprobe mxser" to activate this driver and run
|
||||
"rmmod mxser" to remove it.
|
||||
|
||||
However, it's better to have a boot time configuration to
|
||||
eliminate manual operation. Boot time configuration can be
|
||||
achieved by rc file. We offer one "rc.mxser" file to simplify
|
||||
the procedure under "moxa/mxser/driver".
|
||||
|
||||
But if you use ISA board, please modify the "modprobe ..." command
|
||||
to add the argument (see "3.4.5" section). After modifying the
|
||||
rc.mxser, please try to execute "/moxa/mxser/driver/rc.mxser"
|
||||
manually to make sure the modification is ok. If any error
|
||||
encountered, please try to modify again. If the modification is
|
||||
completed, follow the below step.
|
||||
|
||||
Run following command for setting rc files::
|
||||
|
||||
# cd /moxa/mxser/driver
|
||||
# cp ./rc.mxser /etc/rc.d
|
||||
# cd /etc/rc.d
|
||||
|
||||
Check "rc.serial" is existed or not. If "rc.serial" doesn't exist,
|
||||
create it by vi, run "chmod 755 rc.serial" to change the permission.
|
||||
|
||||
Add "/etc/rc.d/rc.mxser" in last line.
|
||||
|
||||
Reboot and check if moxa.o activated by "lsmod" command.
|
||||
|
||||
3.4.5. specify CAP address
|
||||
--------------------------
|
||||
|
||||
If you'd like to drive Smartio/Industio ISA boards in the system,
|
||||
you'll have to add parameter to specify CAP address of given
|
||||
board while activating "mxser.o". The format for parameters are
|
||||
as follows.::
|
||||
|
||||
modprobe mxser ioaddr=0x???,0x???,0x???,0x???
|
||||
| | | |
|
||||
| | | +- 4th ISA board
|
||||
| | +------ 3rd ISA board
|
||||
| +------------ 2nd ISA board
|
||||
+-------------------1st ISA board
|
||||
|
||||
3.5 Static driver configuration for Linux kernel 2.4.x and 2.6.x
|
||||
================================================================
|
||||
|
||||
Note:
|
||||
To use static driver, you must install the linux kernel
|
||||
source package.
|
||||
|
||||
3.5.1 Backup the built-in driver in the kernel
|
||||
----------------------------------------------
|
||||
|
||||
::
|
||||
|
||||
# cd /usr/src/linux/drivers/char
|
||||
# mv mxser.c mxser.c.old
|
||||
|
||||
For Red Hat 7.x user, you need to create link:
|
||||
# cd /usr/src
|
||||
# ln -s linux-2.4 linux
|
||||
|
||||
3.5.2 Create link
|
||||
-----------------
|
||||
::
|
||||
|
||||
# cd /usr/src/linux/drivers/char
|
||||
# ln -s /moxa/mxser/driver/mxser.c mxser.c
|
||||
|
||||
3.5.3 Add CAP address list for ISA boards.
|
||||
------------------------------------------
|
||||
|
||||
For PCI boards user, please skip this step.
|
||||
|
||||
In module mode, the CAP address for ISA board is given by
|
||||
parameter. In static driver configuration, you'll have to
|
||||
assign it within driver's source code. If you will not
|
||||
install any ISA boards, you may skip to next portion.
|
||||
The instructions to modify driver source code are as
|
||||
below.
|
||||
|
||||
a. run::
|
||||
|
||||
# cd /moxa/mxser/driver
|
||||
# vi mxser.c
|
||||
|
||||
b. Find the array mxserBoardCAP[] as below::
|
||||
|
||||
static int mxserBoardCAP[] = {0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
c. Change the address within this array using vi. For
|
||||
example, to driver 2 ISA boards with CAP address
|
||||
0x280 and 0x180 as 1st and 2nd board. Just to change
|
||||
the source code as follows::
|
||||
|
||||
static int mxserBoardCAP[] = {0x280, 0x180, 0x00, 0x00};
|
||||
|
||||
3.5.4 Setup kernel configuration
|
||||
--------------------------------
|
||||
|
||||
Configure the kernel::
|
||||
|
||||
# cd /usr/src/linux
|
||||
# make menuconfig
|
||||
|
||||
You will go into a menu-driven system. Please select [Character
|
||||
devices][Non-standard serial port support], enable the [Moxa
|
||||
SmartIO support] driver with "[*]" for built-in (not "[M]"), then
|
||||
select [Exit] to exit this program.
|
||||
|
||||
3.5.5 Rebuild kernel
|
||||
--------------------
|
||||
|
||||
The following are for Linux kernel rebuilding, for your
|
||||
reference only.
|
||||
|
||||
For appropriate details, please refer to the Linux document:
|
||||
|
||||
a. Run the following commands::
|
||||
|
||||
cd /usr/src/linux
|
||||
make clean # take a few minutes
|
||||
make dep # take a few minutes
|
||||
make bzImage # take probably 10-20 minutes
|
||||
make install # copy boot image to correct position
|
||||
|
||||
f. Please make sure the boot kernel (vmlinuz) is in the
|
||||
correct position.
|
||||
g. If you use 'lilo' utility, you should check /etc/lilo.conf
|
||||
'image' item specified the path which is the 'vmlinuz' path,
|
||||
or you will load wrong (or old) boot kernel image (vmlinuz).
|
||||
After checking /etc/lilo.conf, please run "lilo".
|
||||
|
||||
Note that if the result of "make bzImage" is ERROR, then you have to
|
||||
go back to Linux configuration Setup. Type "make menuconfig" in
|
||||
directory /usr/src/linux.
|
||||
|
||||
|
||||
3.5.6 Make tty device and special file
|
||||
--------------------------------------
|
||||
|
||||
::
|
||||
# cd /moxa/mxser/driver
|
||||
# ./msmknod
|
||||
|
||||
3.5.7 Make utility
|
||||
------------------
|
||||
|
||||
::
|
||||
|
||||
# cd /moxa/mxser/utility
|
||||
# make clean; make install
|
||||
|
||||
3.5.8 Reboot
|
||||
------------
|
||||
|
||||
|
||||
|
||||
3.6 Custom configuration
|
||||
========================
|
||||
|
||||
Although this driver already provides you default configuration, you
|
||||
still can change the device name and major number. The instruction to
|
||||
change these parameters are shown as below.
|
||||
|
||||
a. Change Device name
|
||||
|
||||
If you'd like to use other device names instead of default naming
|
||||
convention, all you have to do is to modify the internal code
|
||||
within the shell script "msmknod". First, you have to open "msmknod"
|
||||
by vi. Locate each line contains "ttyM" and "cum" and change them
|
||||
to the device name you desired. "msmknod" creates the device names
|
||||
you need next time executed.
|
||||
|
||||
b. Change Major number
|
||||
|
||||
If major number 30 and 35 had been occupied, you may have to select
|
||||
2 free major numbers for this driver. There are 3 steps to change
|
||||
major numbers.
|
||||
|
||||
3.6.1 Find free major numbers
|
||||
-----------------------------
|
||||
|
||||
In /proc/devices, you may find all the major numbers occupied
|
||||
in the system. Please select 2 major numbers that are available.
|
||||
e.g. 40, 45.
|
||||
|
||||
3.6.2 Create special files
|
||||
--------------------------
|
||||
|
||||
Run /moxa/mxser/driver/msmknod to create special files with
|
||||
specified major numbers.
|
||||
|
||||
3.6.3 Modify driver with new major number
|
||||
-----------------------------------------
|
||||
|
||||
Run vi to open /moxa/mxser/driver/mxser.c. Locate the line
|
||||
contains "MXSERMAJOR". Change the content as below::
|
||||
|
||||
#define MXSERMAJOR 40
|
||||
#define MXSERCUMAJOR 45
|
||||
|
||||
3.6.4 Run "make clean; make install" in /moxa/mxser/driver.
|
||||
|
||||
3.7 Verify driver installation
|
||||
==============================
|
||||
|
||||
You may refer to /var/log/messages to check the latest status
|
||||
log reported by this driver whenever it's activated.
|
||||
|
||||
4. Utilities
|
||||
^^^^^^^^^^^^
|
||||
|
||||
There are 3 utilities contained in this driver. They are msdiag, msmon and
|
||||
msterm. These 3 utilities are released in form of source code. They should
|
||||
be compiled into executable file and copied into /usr/bin.
|
||||
|
||||
Before using these utilities, please load driver (refer 3.4 & 3.5) and
|
||||
make sure you had run the "msmknod" utility.
|
||||
|
||||
msdiag - Diagnostic
|
||||
===================
|
||||
|
||||
This utility provides the function to display what Moxa Smartio/Industio
|
||||
board found by driver in the system.
|
||||
|
||||
msmon - Port Monitoring
|
||||
=======================
|
||||
|
||||
This utility gives the user a quick view about all the MOXA ports'
|
||||
activities. One can easily learn each port's total received/transmitted
|
||||
(Rx/Tx) character count since the time when the monitoring is started.
|
||||
|
||||
Rx/Tx throughputs per second are also reported in interval basis (e.g.
|
||||
the last 5 seconds) and in average basis (since the time the monitoring
|
||||
is started). You can reset all ports' count by <HOME> key. <+> <->
|
||||
(plus/minus) keys to change the displaying time interval. Press <ENTER>
|
||||
on the port, that cursor stay, to view the port's communication
|
||||
parameters, signal status, and input/output queue.
|
||||
|
||||
msterm - Terminal Emulation
|
||||
===========================
|
||||
|
||||
This utility provides data sending and receiving ability of all tty ports,
|
||||
especially for MOXA ports. It is quite useful for testing simple
|
||||
application, for example, sending AT command to a modem connected to the
|
||||
port or used as a terminal for login purpose. Note that this is only a
|
||||
dumb terminal emulation without handling full screen operation.
|
||||
|
||||
5. Setserial
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Supported Setserial parameters are listed as below.
|
||||
|
||||
============== =========================================================
|
||||
uart set UART type(16450-->disable FIFO, 16550A-->enable FIFO)
|
||||
close_delay set the amount of time(in 1/100 of a second) that DTR
|
||||
should be kept low while being closed.
|
||||
closing_wait set the amount of time(in 1/100 of a second) that the
|
||||
serial port should wait for data to be drained while
|
||||
being closed, before the receiver is disable.
|
||||
spd_hi Use 57.6kb when the application requests 38.4kb.
|
||||
spd_vhi Use 115.2kb when the application requests 38.4kb.
|
||||
spd_shi Use 230.4kb when the application requests 38.4kb.
|
||||
spd_warp Use 460.8kb when the application requests 38.4kb.
|
||||
spd_normal Use 38.4kb when the application requests 38.4kb.
|
||||
spd_cust Use the custom divisor to set the speed when the
|
||||
application requests 38.4kb.
|
||||
divisor This option set the custom division.
|
||||
baud_base This option set the base baud rate.
|
||||
============== =========================================================
|
||||
|
||||
6. Troubleshooting
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The boot time error messages and solutions are stated as clearly as
|
||||
possible. If all the possible solutions fail, please contact our technical
|
||||
support team to get more help.
|
||||
|
||||
|
||||
Error msg:
|
||||
More than 4 Moxa Smartio/Industio family boards found. Fifth board
|
||||
and after are ignored.
|
||||
|
||||
Solution:
|
||||
To avoid this problem, please unplug fifth and after board, because Moxa
|
||||
driver supports up to 4 boards.
|
||||
|
||||
Error msg:
|
||||
Request_irq fail, IRQ(?) may be conflict with another device.
|
||||
|
||||
Solution:
|
||||
Other PCI or ISA devices occupy the assigned IRQ. If you are not sure
|
||||
which device causes the situation, please check /proc/interrupts to find
|
||||
free IRQ and simply change another free IRQ for Moxa board.
|
||||
|
||||
Error msg:
|
||||
Board #: C1xx Series(CAP=xxx) interrupt number invalid.
|
||||
|
||||
Solution:
|
||||
Each port within the same multiport board shares the same IRQ. Please set
|
||||
one IRQ (IRQ doesn't equal to zero) for one Moxa board.
|
||||
|
||||
Error msg:
|
||||
No interrupt vector be set for Moxa ISA board(CAP=xxx).
|
||||
|
||||
Solution:
|
||||
Moxa ISA board needs an interrupt vector.Please refer to user's manual
|
||||
"Hardware Installation" chapter to set interrupt vector.
|
||||
|
||||
Error msg:
|
||||
Couldn't install MOXA Smartio/Industio family driver!
|
||||
|
||||
Solution:
|
||||
Load Moxa driver fail, the major number may conflict with other devices.
|
||||
Please refer to previous section 3.7 to change a free major number for
|
||||
Moxa driver.
|
||||
|
||||
Error msg:
|
||||
Couldn't install MOXA Smartio/Industio family callout driver!
|
||||
|
||||
Solution:
|
||||
Load Moxa callout driver fail, the callout device major number may
|
||||
conflict with other devices. Please refer to previous section 3.7 to
|
||||
change a free callout device major number for Moxa driver.
|
103
Documentation/serial/n_gsm.rst
Normal file
103
Documentation/serial/n_gsm.rst
Normal file
@ -0,0 +1,103 @@
|
||||
==============================
|
||||
GSM 0710 tty multiplexor HOWTO
|
||||
==============================
|
||||
|
||||
This line discipline implements the GSM 07.10 multiplexing protocol
|
||||
detailed in the following 3GPP document:
|
||||
|
||||
http://www.3gpp.org/ftp/Specs/archive/07_series/07.10/0710-720.zip
|
||||
|
||||
This document give some hints on how to use this driver with GPRS and 3G
|
||||
modems connected to a physical serial port.
|
||||
|
||||
How to use it
|
||||
-------------
|
||||
1. initialize the modem in 0710 mux mode (usually AT+CMUX= command) through
|
||||
its serial port. Depending on the modem used, you can pass more or less
|
||||
parameters to this command,
|
||||
2. switch the serial line to using the n_gsm line discipline by using
|
||||
TIOCSETD ioctl,
|
||||
3. configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl,
|
||||
|
||||
Major parts of the initialization program :
|
||||
(a good starting point is util-linux-ng/sys-utils/ldattach.c)::
|
||||
|
||||
#include <linux/gsmmux.h>
|
||||
#define N_GSM0710 21 /* GSM 0710 Mux */
|
||||
#define DEFAULT_SPEED B115200
|
||||
#define SERIAL_PORT /dev/ttyS0
|
||||
|
||||
int ldisc = N_GSM0710;
|
||||
struct gsm_config c;
|
||||
struct termios configuration;
|
||||
|
||||
/* open the serial port connected to the modem */
|
||||
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
|
||||
/* configure the serial port : speed, flow control ... */
|
||||
|
||||
/* send the AT commands to switch the modem to CMUX mode
|
||||
and check that it's successful (should return OK) */
|
||||
write(fd, "AT+CMUX=0\r", 10);
|
||||
|
||||
/* experience showed that some modems need some time before
|
||||
being able to answer to the first MUX packet so a delay
|
||||
may be needed here in some case */
|
||||
sleep(3);
|
||||
|
||||
/* use n_gsm line discipline */
|
||||
ioctl(fd, TIOCSETD, &ldisc);
|
||||
|
||||
/* get n_gsm configuration */
|
||||
ioctl(fd, GSMIOC_GETCONF, &c);
|
||||
/* we are initiator and need encoding 0 (basic) */
|
||||
c.initiator = 1;
|
||||
c.encapsulation = 0;
|
||||
/* our modem defaults to a maximum size of 127 bytes */
|
||||
c.mru = 127;
|
||||
c.mtu = 127;
|
||||
/* set the new configuration */
|
||||
ioctl(fd, GSMIOC_SETCONF, &c);
|
||||
|
||||
/* and wait for ever to keep the line discipline enabled */
|
||||
daemon(0,0);
|
||||
pause();
|
||||
|
||||
4. create the devices corresponding to the "virtual" serial ports (take care,
|
||||
each modem has its configuration and some DLC have dedicated functions,
|
||||
for example GPS), starting with minor 1 (DLC0 is reserved for the management
|
||||
of the mux)::
|
||||
|
||||
MAJOR=`cat /proc/devices |grep gsmtty | awk '{print $1}`
|
||||
for i in `seq 1 4`; do
|
||||
mknod /dev/ttygsm$i c $MAJOR $i
|
||||
done
|
||||
|
||||
5. use these devices as plain serial ports.
|
||||
|
||||
for example, it's possible:
|
||||
|
||||
- and to use gnokii to send / receive SMS on ttygsm1
|
||||
- to use ppp to establish a datalink on ttygsm2
|
||||
|
||||
6. first close all virtual ports before closing the physical port.
|
||||
|
||||
Note that after closing the physical port the modem is still in multiplexing
|
||||
mode. This may prevent a successful re-opening of the port later. To avoid
|
||||
this situation either reset the modem if your hardware allows that or send
|
||||
a disconnect command frame manually before initializing the multiplexing mode
|
||||
for the second time. The byte sequence for the disconnect command frame is::
|
||||
|
||||
0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9.
|
||||
|
||||
Additional Documentation
|
||||
------------------------
|
||||
More practical details on the protocol and how it's supported by industrial
|
||||
modems can be found in the following documents :
|
||||
|
||||
- http://www.telit.com/module/infopool/download.php?id=616
|
||||
- http://www.u-blox.com/images/downloads/Product_Docs/LEON-G100-G200-MuxImplementation_ApplicationNote_%28GSM%20G1-CS-10002%29.pdf
|
||||
- http://www.sierrawireless.com/Support/Downloads/AirPrime/WMP_Series/~/media/Support_Downloads/AirPrime/Application_notes/CMUX_Feature_Application_Note-Rev004.ashx
|
||||
- http://wm.sim.com/sim/News/photo/2010721161442.pdf
|
||||
|
||||
11-03-08 - Eric Bénard - <eric@eukrea.com>
|
@ -1,96 +0,0 @@
|
||||
n_gsm.c GSM 0710 tty multiplexor HOWTO
|
||||
===================================================
|
||||
|
||||
This line discipline implements the GSM 07.10 multiplexing protocol
|
||||
detailed in the following 3GPP document :
|
||||
http://www.3gpp.org/ftp/Specs/archive/07_series/07.10/0710-720.zip
|
||||
|
||||
This document give some hints on how to use this driver with GPRS and 3G
|
||||
modems connected to a physical serial port.
|
||||
|
||||
How to use it
|
||||
-------------
|
||||
1- initialize the modem in 0710 mux mode (usually AT+CMUX= command) through
|
||||
its serial port. Depending on the modem used, you can pass more or less
|
||||
parameters to this command,
|
||||
2- switch the serial line to using the n_gsm line discipline by using
|
||||
TIOCSETD ioctl,
|
||||
3- configure the mux using GSMIOC_GETCONF / GSMIOC_SETCONF ioctl,
|
||||
|
||||
Major parts of the initialization program :
|
||||
(a good starting point is util-linux-ng/sys-utils/ldattach.c)
|
||||
#include <linux/gsmmux.h>
|
||||
#define N_GSM0710 21 /* GSM 0710 Mux */
|
||||
#define DEFAULT_SPEED B115200
|
||||
#define SERIAL_PORT /dev/ttyS0
|
||||
|
||||
int ldisc = N_GSM0710;
|
||||
struct gsm_config c;
|
||||
struct termios configuration;
|
||||
|
||||
/* open the serial port connected to the modem */
|
||||
fd = open(SERIAL_PORT, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
|
||||
/* configure the serial port : speed, flow control ... */
|
||||
|
||||
/* send the AT commands to switch the modem to CMUX mode
|
||||
and check that it's successful (should return OK) */
|
||||
write(fd, "AT+CMUX=0\r", 10);
|
||||
|
||||
/* experience showed that some modems need some time before
|
||||
being able to answer to the first MUX packet so a delay
|
||||
may be needed here in some case */
|
||||
sleep(3);
|
||||
|
||||
/* use n_gsm line discipline */
|
||||
ioctl(fd, TIOCSETD, &ldisc);
|
||||
|
||||
/* get n_gsm configuration */
|
||||
ioctl(fd, GSMIOC_GETCONF, &c);
|
||||
/* we are initiator and need encoding 0 (basic) */
|
||||
c.initiator = 1;
|
||||
c.encapsulation = 0;
|
||||
/* our modem defaults to a maximum size of 127 bytes */
|
||||
c.mru = 127;
|
||||
c.mtu = 127;
|
||||
/* set the new configuration */
|
||||
ioctl(fd, GSMIOC_SETCONF, &c);
|
||||
|
||||
/* and wait for ever to keep the line discipline enabled */
|
||||
daemon(0,0);
|
||||
pause();
|
||||
|
||||
4- create the devices corresponding to the "virtual" serial ports (take care,
|
||||
each modem has its configuration and some DLC have dedicated functions,
|
||||
for example GPS), starting with minor 1 (DLC0 is reserved for the management
|
||||
of the mux)
|
||||
|
||||
MAJOR=`cat /proc/devices |grep gsmtty | awk '{print $1}`
|
||||
for i in `seq 1 4`; do
|
||||
mknod /dev/ttygsm$i c $MAJOR $i
|
||||
done
|
||||
|
||||
5- use these devices as plain serial ports.
|
||||
for example, it's possible :
|
||||
- and to use gnokii to send / receive SMS on ttygsm1
|
||||
- to use ppp to establish a datalink on ttygsm2
|
||||
|
||||
6- first close all virtual ports before closing the physical port.
|
||||
|
||||
Note that after closing the physical port the modem is still in multiplexing
|
||||
mode. This may prevent a successful re-opening of the port later. To avoid
|
||||
this situation either reset the modem if your hardware allows that or send
|
||||
a disconnect command frame manually before initializing the multiplexing mode
|
||||
for the second time. The byte sequence for the disconnect command frame is:
|
||||
0xf9, 0x03, 0xef, 0x03, 0xc3, 0x16, 0xf9.
|
||||
|
||||
Additional Documentation
|
||||
------------------------
|
||||
More practical details on the protocol and how it's supported by industrial
|
||||
modems can be found in the following documents :
|
||||
http://www.telit.com/module/infopool/download.php?id=616
|
||||
http://www.u-blox.com/images/downloads/Product_Docs/LEON-G100-G200-MuxImplementation_ApplicationNote_%28GSM%20G1-CS-10002%29.pdf
|
||||
http://www.sierrawireless.com/Support/Downloads/AirPrime/WMP_Series/~/media/Support_Downloads/AirPrime/Application_notes/CMUX_Feature_Application_Note-Rev004.ashx
|
||||
http://wm.sim.com/sim/News/photo/2010721161442.pdf
|
||||
|
||||
11-03-08 - Eric Bénard - <eric@eukrea.com>
|
@ -1,20 +1,22 @@
|
||||
Comtrol(tm) RocketPort(R)/RocketModem(TM) Series
|
||||
================================================
|
||||
Comtrol(tm) RocketPort(R)/RocketModem(TM) Series
|
||||
================================================
|
||||
|
||||
Device Driver for the Linux Operating System
|
||||
============================================
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
PRODUCT OVERVIEW
|
||||
Product overview
|
||||
----------------
|
||||
|
||||
This driver provides a loadable kernel driver for the Comtrol RocketPort
|
||||
and RocketModem PCI boards. These boards provide, 2, 4, 8, 16, or 32
|
||||
and RocketModem PCI boards. These boards provide, 2, 4, 8, 16, or 32
|
||||
high-speed serial ports or modems. This driver supports up to a combination
|
||||
of four RocketPort or RocketModems boards in one machine simultaneously.
|
||||
This file assumes that you are using the RocketPort driver which is
|
||||
integrated into the kernel sources.
|
||||
integrated into the kernel sources.
|
||||
|
||||
The driver can also be installed as an external module using the usual
|
||||
"make;make install" routine. This external module driver, obtainable
|
||||
The driver can also be installed as an external module using the usual
|
||||
"make;make install" routine. This external module driver, obtainable
|
||||
from the Comtrol website listed below, is useful for updating the driver
|
||||
or installing it into kernels which do not have the driver configured
|
||||
into them. Installations instructions for the external module
|
||||
@ -29,57 +31,59 @@ information on how to set the DIP switches.
|
||||
|
||||
You pass the I/O port to the driver using the following module parameters:
|
||||
|
||||
board1 : I/O port for the first ISA board
|
||||
board2 : I/O port for the second ISA board
|
||||
board3 : I/O port for the third ISA board
|
||||
board4 : I/O port for the fourth ISA board
|
||||
board1:
|
||||
I/O port for the first ISA board
|
||||
board2:
|
||||
I/O port for the second ISA board
|
||||
board3:
|
||||
I/O port for the third ISA board
|
||||
board4:
|
||||
I/O port for the fourth ISA board
|
||||
|
||||
There is a set of utilities and scripts provided with the external driver
|
||||
( downloadable from http://www.comtrol.com ) that ease the configuration and
|
||||
(downloadable from http://www.comtrol.com) that ease the configuration and
|
||||
setup of the ISA cards.
|
||||
|
||||
The RocketModem II PCI boards require firmware to be loaded into the card
|
||||
before it will function. The driver has only been tested as a module for this
|
||||
board.
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
INSTALLATION PROCEDURES
|
||||
Installation Procedures
|
||||
-----------------------
|
||||
|
||||
RocketPort/RocketModem PCI cards require no driver configuration, they are
|
||||
RocketPort/RocketModem PCI cards require no driver configuration, they are
|
||||
automatically detected and configured.
|
||||
|
||||
The RocketPort driver can be installed as a module (recommended) or built
|
||||
The RocketPort driver can be installed as a module (recommended) or built
|
||||
into the kernel. This is selected, as for other drivers, through the `make config`
|
||||
command from the root of the Linux source tree during the kernel build process.
|
||||
command from the root of the Linux source tree during the kernel build process.
|
||||
|
||||
The RocketPort/RocketModem serial ports installed by this driver are assigned
|
||||
device major number 46, and will be named /dev/ttyRx, where x is the port number
|
||||
device major number 46, and will be named /dev/ttyRx, where x is the port number
|
||||
starting at zero (ex. /dev/ttyR0, /devttyR1, ...). If you have multiple cards
|
||||
installed in the system, the mapping of port names to serial ports is displayed
|
||||
in the system log at /var/log/messages.
|
||||
|
||||
If installed as a module, the module must be loaded. This can be done
|
||||
manually by entering "modprobe rocket". To have the module loaded automatically
|
||||
upon system boot, edit a /etc/modprobe.d/*.conf file and add the line
|
||||
upon system boot, edit a `/etc/modprobe.d/*.conf` file and add the line
|
||||
"alias char-major-46 rocket".
|
||||
|
||||
In order to use the ports, their device names (nodes) must be created with mknod.
|
||||
This is only required once, the system will retain the names once created. To
|
||||
create the RocketPort/RocketModem device names, use the command
|
||||
"mknod /dev/ttyRx c 46 x" where x is the port number starting at zero. For example:
|
||||
This is only required once, the system will retain the names once created. To
|
||||
create the RocketPort/RocketModem device names, use the command
|
||||
"mknod /dev/ttyRx c 46 x" where x is the port number starting at zero.
|
||||
|
||||
>mknod /dev/ttyR0 c 46 0
|
||||
>mknod /dev/ttyR1 c 46 1
|
||||
>mknod /dev/ttyR2 c 46 2
|
||||
For example::
|
||||
|
||||
> mknod /dev/ttyR0 c 46 0
|
||||
> mknod /dev/ttyR1 c 46 1
|
||||
> mknod /dev/ttyR2 c 46 2
|
||||
|
||||
The Linux script MAKEDEV will create the first 16 ttyRx device names (nodes)
|
||||
for you:
|
||||
for you::
|
||||
|
||||
>/dev/MAKEDEV ttyR
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
>/dev/MAKEDEV ttyR
|
||||
|
||||
ISA Rocketport Boards
|
||||
---------------------
|
||||
@ -89,7 +93,7 @@ card before installing and using it. This is done by setting a set of DIP
|
||||
switches on the Rocketport board.
|
||||
|
||||
|
||||
SETTING THE I/O ADDRESS
|
||||
Setting the I/O address
|
||||
-----------------------
|
||||
|
||||
Before installing RocketPort(R) or RocketPort RA boards, you must find
|
||||
@ -130,40 +134,36 @@ the first 4 bytes of that range are used by the first board. You would
|
||||
need to set the second, third, or fourth board to one of the next available
|
||||
blocks such as 0x180.
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
RocketPort and RocketPort RA SW1 Settings::
|
||||
|
||||
RocketPort and RocketPort RA SW1 Settings:
|
||||
+-------------------------------+
|
||||
| 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
||||
+-------+-------+---------------+
|
||||
| Unused| Card | I/O Port Block|
|
||||
+-------------------------------+
|
||||
|
||||
+-------------------------------+
|
||||
| 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
||||
+-------+-------+---------------+
|
||||
| Unused| Card | I/O Port Block|
|
||||
+-------------------------------+
|
||||
DIP Switches DIP Switches
|
||||
7 8 6 5
|
||||
=================== ===================
|
||||
On On UNUSED, MUST BE ON. On On First Card <==== Default
|
||||
On Off Second Card
|
||||
Off On Third Card
|
||||
Off Off Fourth Card
|
||||
|
||||
DIP Switches DIP Switches
|
||||
7 8 6 5
|
||||
=================== ===================
|
||||
On On UNUSED, MUST BE ON. On On First Card <==== Default
|
||||
On Off Second Card
|
||||
Off On Third Card
|
||||
Off Off Fourth Card
|
||||
DIP Switches I/O Address Range
|
||||
4 3 2 1 Used by the First Card
|
||||
=====================================
|
||||
On Off On Off 100-143
|
||||
On Off Off On 140-183
|
||||
On Off Off Off 180-1C3 <==== Default
|
||||
Off On On Off 200-243
|
||||
Off On Off On 240-283
|
||||
Off On Off Off 280-2C3
|
||||
Off Off On Off 300-343
|
||||
Off Off Off On 340-383
|
||||
Off Off Off Off 380-3C3
|
||||
|
||||
DIP Switches I/O Address Range
|
||||
4 3 2 1 Used by the First Card
|
||||
=====================================
|
||||
On Off On Off 100-143
|
||||
On Off Off On 140-183
|
||||
On Off Off Off 180-1C3 <==== Default
|
||||
Off On On Off 200-243
|
||||
Off On Off On 240-283
|
||||
Off On Off Off 280-2C3
|
||||
Off Off On Off 300-343
|
||||
Off Off Off On 340-383
|
||||
Off Off Off Off 380-3C3
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
REPORTING BUGS
|
||||
Reporting Bugs
|
||||
--------------
|
||||
|
||||
For technical support, please provide the following
|
||||
@ -171,19 +171,15 @@ information: Driver version, kernel release, distribution of
|
||||
kernel, and type of board you are using. Error messages and log
|
||||
printouts port configuration details are especially helpful.
|
||||
|
||||
USA
|
||||
Phone: (612) 494-4100
|
||||
FAX: (612) 494-4199
|
||||
email: support@comtrol.com
|
||||
USA:
|
||||
:Phone: (612) 494-4100
|
||||
:FAX: (612) 494-4199
|
||||
:email: support@comtrol.com
|
||||
|
||||
Comtrol Europe
|
||||
Phone: +44 (0) 1 869 323-220
|
||||
FAX: +44 (0) 1 869 323-211
|
||||
email: support@comtrol.co.uk
|
||||
Comtrol Europe:
|
||||
:Phone: +44 (0) 1 869 323-220
|
||||
:FAX: +44 (0) 1 869 323-211
|
||||
:email: support@comtrol.co.uk
|
||||
|
||||
Web: http://www.comtrol.com
|
||||
FTP: ftp.comtrol.com
|
||||
|
||||
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
ISO7816 SERIAL COMMUNICATIONS
|
||||
=============================
|
||||
ISO7816 Serial Communications
|
||||
=============================
|
||||
|
||||
1. INTRODUCTION
|
||||
1. Introduction
|
||||
===============
|
||||
|
||||
ISO/IEC7816 is a series of standards specifying integrated circuit cards (ICC)
|
||||
also known as smart cards.
|
||||
|
||||
2. HARDWARE-RELATED CONSIDERATIONS
|
||||
2. Hardware-related considerations
|
||||
==================================
|
||||
|
||||
Some CPUs/UARTs (e.g., Microchip AT91) contain a built-in mode capable of
|
||||
handling communication with a smart card.
|
||||
@ -15,7 +19,8 @@
|
||||
available at user-level to allow switching from one mode to the other, and
|
||||
vice versa.
|
||||
|
||||
3. DATA STRUCTURES ALREADY AVAILABLE IN THE KERNEL
|
||||
3. Data Structures Already Available in the Kernel
|
||||
==================================================
|
||||
|
||||
The Linux kernel provides the serial_iso7816 structure (see [1]) to handle
|
||||
ISO7816 communications. This data structure is used to set and configure
|
||||
@ -27,10 +32,11 @@
|
||||
to TIOCGISO7816 and TIOCSISO7816 ioctls (see below). The iso7816_config
|
||||
callback receives a pointer to struct serial_iso7816.
|
||||
|
||||
4. USAGE FROM USER-LEVEL
|
||||
4. Usage from user-level
|
||||
========================
|
||||
|
||||
From user-level, ISO7816 configuration can be get/set using the previous
|
||||
ioctls. For instance, to set ISO7816 you can use the following code:
|
||||
ioctls. For instance, to set ISO7816 you can use the following code::
|
||||
|
||||
#include <linux/serial.h>
|
||||
|
||||
@ -78,6 +84,7 @@
|
||||
/* Error handling. See errno. */
|
||||
}
|
||||
|
||||
5. REFERENCES
|
||||
5. References
|
||||
=============
|
||||
|
||||
[1] include/uapi/linux/serial.h
|
@ -1,6 +1,9 @@
|
||||
RS485 SERIAL COMMUNICATIONS
|
||||
===========================
|
||||
RS485 Serial Communications
|
||||
===========================
|
||||
|
||||
1. INTRODUCTION
|
||||
1. Introduction
|
||||
===============
|
||||
|
||||
EIA-485, also known as TIA/EIA-485 or RS-485, is a standard defining the
|
||||
electrical characteristics of drivers and receivers for use in balanced
|
||||
@ -9,7 +12,8 @@
|
||||
because it can be used effectively over long distances and in electrically
|
||||
noisy environments.
|
||||
|
||||
2. HARDWARE-RELATED CONSIDERATIONS
|
||||
2. Hardware-related Considerations
|
||||
==================================
|
||||
|
||||
Some CPUs/UARTs (e.g., Atmel AT91 or 16C950 UART) contain a built-in
|
||||
half-duplex mode capable of automatically controlling line direction by
|
||||
@ -22,7 +26,8 @@
|
||||
available at user-level to allow switching from one mode to the other, and
|
||||
vice versa.
|
||||
|
||||
3. DATA STRUCTURES ALREADY AVAILABLE IN THE KERNEL
|
||||
3. Data Structures Already Available in the Kernel
|
||||
==================================================
|
||||
|
||||
The Linux kernel provides the serial_rs485 structure (see [1]) to handle
|
||||
RS485 communications. This data structure is used to set and configure RS485
|
||||
@ -38,10 +43,11 @@
|
||||
to TIOCSRS485 and TIOCGRS485 ioctls (see below). The rs485_config callback
|
||||
receives a pointer to struct serial_rs485.
|
||||
|
||||
4. USAGE FROM USER-LEVEL
|
||||
4. Usage from user-level
|
||||
========================
|
||||
|
||||
From user-level, RS485 configuration can be get/set using the previous
|
||||
ioctls. For instance, to set RS485 you can use the following code:
|
||||
ioctls. For instance, to set RS485 you can use the following code::
|
||||
|
||||
#include <linux/serial.h>
|
||||
|
||||
@ -89,7 +95,9 @@
|
||||
/* Error handling. See errno. */
|
||||
}
|
||||
|
||||
5. REFERENCES
|
||||
5. References
|
||||
=============
|
||||
|
||||
[1] include/uapi/linux/serial.h
|
||||
|
||||
[2] Documentation/devicetree/bindings/serial/rs485.txt
|
@ -1,5 +1,6 @@
|
||||
|
||||
The Lockronomicon
|
||||
=================
|
||||
The Lockronomicon
|
||||
=================
|
||||
|
||||
Your guide to the ancient and twisted locking policies of the tty layer and
|
||||
the warped logic behind them. Beware all ye who read on.
|
||||
@ -9,12 +10,12 @@ Line Discipline
|
||||
---------------
|
||||
|
||||
Line disciplines are registered with tty_register_ldisc() passing the
|
||||
discipline number and the ldisc structure. At the point of registration the
|
||||
discipline number and the ldisc structure. At the point of registration the
|
||||
discipline must be ready to use and it is possible it will get used before
|
||||
the call returns success. If the call returns an error then it won't get
|
||||
called. Do not re-use ldisc numbers as they are part of the userspace ABI
|
||||
and writing over an existing ldisc will cause demons to eat your computer.
|
||||
After the return the ldisc data has been copied so you may free your own
|
||||
After the return the ldisc data has been copied so you may free your own
|
||||
copy of the structure. You must not re-register over the top of the line
|
||||
discipline even with the same data or your computer again will be eaten by
|
||||
demons.
|
||||
@ -26,7 +27,7 @@ code manages the module counts this should not usually be a concern.
|
||||
|
||||
Heed this warning: the reference count field of the registered copies of the
|
||||
tty_ldisc structure in the ldisc table counts the number of lines using this
|
||||
discipline. The reference count of the tty_ldisc structure within a tty
|
||||
discipline. The reference count of the tty_ldisc structure within a tty
|
||||
counts the number of active users of the ldisc at this instant. In effect it
|
||||
counts the number of threads of execution within an ldisc method (plus those
|
||||
about to enter and exit although this detail matters not).
|
||||
@ -34,9 +35,11 @@ about to enter and exit although this detail matters not).
|
||||
Line Discipline Methods
|
||||
-----------------------
|
||||
|
||||
TTY side interfaces:
|
||||
TTY side interfaces
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
open() - Called when the line discipline is attached to
|
||||
======================= =======================================================
|
||||
open() Called when the line discipline is attached to
|
||||
the terminal. No other call into the line
|
||||
discipline for this tty will occur until it
|
||||
completes successfully. Should initialize any
|
||||
@ -47,66 +50,69 @@ open() - Called when the line discipline is attached to
|
||||
Returning an error will prevent the ldisc from
|
||||
being attached. Can sleep.
|
||||
|
||||
close() - This is called on a terminal when the line
|
||||
close() This is called on a terminal when the line
|
||||
discipline is being unplugged. At the point of
|
||||
execution no further users will enter the
|
||||
ldisc code for this tty. Can sleep.
|
||||
|
||||
hangup() - Called when the tty line is hung up.
|
||||
hangup() Called when the tty line is hung up.
|
||||
The line discipline should cease I/O to the tty.
|
||||
No further calls into the ldisc code will occur.
|
||||
The return value is ignored. Can sleep.
|
||||
|
||||
read() - (optional) A process requests reading data from
|
||||
read() (optional) A process requests reading data from
|
||||
the line. Multiple read calls may occur in parallel
|
||||
and the ldisc must deal with serialization issues.
|
||||
If not defined, the process will receive an EIO
|
||||
error. May sleep.
|
||||
|
||||
write() - (optional) A process requests writing data to the
|
||||
write() (optional) A process requests writing data to the
|
||||
line. Multiple write calls are serialized by the
|
||||
tty layer for the ldisc. If not defined, the
|
||||
process will receive an EIO error. May sleep.
|
||||
|
||||
flush_buffer() - (optional) May be called at any point between
|
||||
flush_buffer() (optional) May be called at any point between
|
||||
open and close, and instructs the line discipline
|
||||
to empty its input buffer.
|
||||
|
||||
set_termios() - (optional) Called on termios structure changes.
|
||||
set_termios() (optional) Called on termios structure changes.
|
||||
The caller passes the old termios data and the
|
||||
current data is in the tty. Called under the
|
||||
termios semaphore so allowed to sleep. Serialized
|
||||
against itself only.
|
||||
|
||||
poll() - (optional) Check the status for the poll/select
|
||||
poll() (optional) Check the status for the poll/select
|
||||
calls. Multiple poll calls may occur in parallel.
|
||||
May sleep.
|
||||
|
||||
ioctl() - (optional) Called when an ioctl is handed to the
|
||||
ioctl() (optional) Called when an ioctl is handed to the
|
||||
tty layer that might be for the ldisc. Multiple
|
||||
ioctl calls may occur in parallel. May sleep.
|
||||
|
||||
compat_ioctl() - (optional) Called when a 32 bit ioctl is handed
|
||||
compat_ioctl() (optional) Called when a 32 bit ioctl is handed
|
||||
to the tty layer that might be for the ldisc.
|
||||
Multiple ioctl calls may occur in parallel.
|
||||
May sleep.
|
||||
======================= =======================================================
|
||||
|
||||
Driver Side Interfaces:
|
||||
Driver Side Interfaces
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
receive_buf() - (optional) Called by the low-level driver to hand
|
||||
======================= =======================================================
|
||||
receive_buf() (optional) Called by the low-level driver to hand
|
||||
a buffer of received bytes to the ldisc for
|
||||
processing. The number of bytes is guaranteed not
|
||||
to exceed the current value of tty->receive_room.
|
||||
All bytes must be processed.
|
||||
|
||||
receive_buf2() - (optional) Called by the low-level driver to hand
|
||||
receive_buf2() (optional) Called by the low-level driver to hand
|
||||
a buffer of received bytes to the ldisc for
|
||||
processing. Returns the number of bytes processed.
|
||||
|
||||
If both receive_buf() and receive_buf2() are
|
||||
defined, receive_buf2() should be preferred.
|
||||
|
||||
write_wakeup() - May be called at any point between open and close.
|
||||
write_wakeup() May be called at any point between open and close.
|
||||
The TTY_DO_WRITE_WAKEUP flag indicates if a call
|
||||
is needed but always races versus calls. Thus the
|
||||
ldisc must be careful about setting order and to
|
||||
@ -117,17 +123,20 @@ write_wakeup() - May be called at any point between open and close.
|
||||
is permitted to call the driver write method from
|
||||
this function. In such a situation defer it.
|
||||
|
||||
dcd_change() - Report to the tty line the current DCD pin status
|
||||
dcd_change() Report to the tty line the current DCD pin status
|
||||
changes and the relative timestamp. The timestamp
|
||||
cannot be NULL.
|
||||
======================= =======================================================
|
||||
|
||||
|
||||
Driver Access
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Line discipline methods can call the following methods of the underlying
|
||||
hardware driver through the function pointers within the tty->driver
|
||||
structure:
|
||||
|
||||
======================= =======================================================
|
||||
write() Write a block of characters to the tty device.
|
||||
Returns the number of characters accepted. The
|
||||
character buffer passed to this method is already
|
||||
@ -189,13 +198,16 @@ wait_until_sent() Waits until the device has written out all of the
|
||||
characters in its transmitter FIFO.
|
||||
|
||||
send_xchar() Send a high-priority XON/XOFF character to the device.
|
||||
======================= =======================================================
|
||||
|
||||
|
||||
Flags
|
||||
^^^^^
|
||||
|
||||
Line discipline methods have access to tty->flags field containing the
|
||||
following interesting flags:
|
||||
|
||||
======================= =======================================================
|
||||
TTY_THROTTLED Driver input is throttled. The ldisc should call
|
||||
tty->driver->unthrottle() in order to resume
|
||||
reception when it is ready to process more data.
|
||||
@ -212,102 +224,105 @@ TTY_OTHER_CLOSED Device is a pty and the other side has closed.
|
||||
|
||||
TTY_NO_WRITE_SPLIT Prevent driver from splitting up writes into
|
||||
smaller chunks.
|
||||
======================= =======================================================
|
||||
|
||||
|
||||
Locking
|
||||
^^^^^^^
|
||||
|
||||
Callers to the line discipline functions from the tty layer are required to
|
||||
take line discipline locks. The same is true of calls from the driver side
|
||||
but not yet enforced.
|
||||
|
||||
Three calls are now provided
|
||||
Three calls are now provided::
|
||||
|
||||
ldisc = tty_ldisc_ref(tty);
|
||||
|
||||
takes a handle to the line discipline in the tty and returns it. If no ldisc
|
||||
is currently attached or the ldisc is being closed and re-opened at this
|
||||
point then NULL is returned. While this handle is held the ldisc will not
|
||||
change or go away.
|
||||
change or go away::
|
||||
|
||||
tty_ldisc_deref(ldisc)
|
||||
|
||||
Returns the ldisc reference and allows the ldisc to be closed. Returning the
|
||||
reference takes away your right to call the ldisc functions until you take
|
||||
a new reference.
|
||||
a new reference::
|
||||
|
||||
ldisc = tty_ldisc_ref_wait(tty);
|
||||
|
||||
Performs the same function as tty_ldisc_ref except that it will wait for an
|
||||
ldisc change to complete and then return a reference to the new ldisc.
|
||||
ldisc change to complete and then return a reference to the new ldisc.
|
||||
|
||||
While these functions are slightly slower than the old code they should have
|
||||
minimal impact as most receive logic uses the flip buffers and they only
|
||||
need to take a reference when they push bits up through the driver.
|
||||
|
||||
A caution: The ldisc->open(), ldisc->close() and driver->set_ldisc
|
||||
A caution: The ldisc->open(), ldisc->close() and driver->set_ldisc
|
||||
functions are called with the ldisc unavailable. Thus tty_ldisc_ref will
|
||||
fail in this situation if used within these functions. Ldisc and driver
|
||||
code calling its own functions must be careful in this case.
|
||||
code calling its own functions must be careful in this case.
|
||||
|
||||
|
||||
Driver Interface
|
||||
----------------
|
||||
|
||||
open() - Called when a device is opened. May sleep
|
||||
======================= =======================================================
|
||||
open() Called when a device is opened. May sleep
|
||||
|
||||
close() - Called when a device is closed. At the point of
|
||||
return from this call the driver must make no
|
||||
close() Called when a device is closed. At the point of
|
||||
return from this call the driver must make no
|
||||
further ldisc calls of any kind. May sleep
|
||||
|
||||
write() - Called to write bytes to the device. May not
|
||||
sleep. May occur in parallel in special cases.
|
||||
write() Called to write bytes to the device. May not
|
||||
sleep. May occur in parallel in special cases.
|
||||
Because this includes panic paths drivers generally
|
||||
shouldn't try and do clever locking here.
|
||||
|
||||
put_char() - Stuff a single character onto the queue. The
|
||||
put_char() Stuff a single character onto the queue. The
|
||||
driver is guaranteed following up calls to
|
||||
flush_chars.
|
||||
|
||||
flush_chars() - Ask the kernel to write put_char queue
|
||||
flush_chars() Ask the kernel to write put_char queue
|
||||
|
||||
write_room() - Return the number of characters that can be stuffed
|
||||
write_room() Return the number of characters that can be stuffed
|
||||
into the port buffers without overflow (or less).
|
||||
The ldisc is responsible for being intelligent
|
||||
about multi-threading of write_room/write calls
|
||||
about multi-threading of write_room/write calls
|
||||
|
||||
ioctl() - Called when an ioctl may be for the driver
|
||||
ioctl() Called when an ioctl may be for the driver
|
||||
|
||||
set_termios() - Called on termios change, serialized against
|
||||
set_termios() Called on termios change, serialized against
|
||||
itself by a semaphore. May sleep.
|
||||
|
||||
set_ldisc() - Notifier for discipline change. At the point this
|
||||
set_ldisc() Notifier for discipline change. At the point this
|
||||
is done the discipline is not yet usable. Can now
|
||||
sleep (I think)
|
||||
|
||||
throttle() - Called by the ldisc to ask the driver to do flow
|
||||
throttle() Called by the ldisc to ask the driver to do flow
|
||||
control. Serialization including with unthrottle
|
||||
is the job of the ldisc layer.
|
||||
|
||||
unthrottle() - Called by the ldisc to ask the driver to stop flow
|
||||
unthrottle() Called by the ldisc to ask the driver to stop flow
|
||||
control.
|
||||
|
||||
stop() - Ldisc notifier to the driver to stop output. As with
|
||||
stop() Ldisc notifier to the driver to stop output. As with
|
||||
throttle the serializations with start() are down
|
||||
to the ldisc layer.
|
||||
|
||||
start() - Ldisc notifier to the driver to start output.
|
||||
start() Ldisc notifier to the driver to start output.
|
||||
|
||||
hangup() - Ask the tty driver to cause a hangup initiated
|
||||
hangup() Ask the tty driver to cause a hangup initiated
|
||||
from the host side. [Can sleep ??]
|
||||
|
||||
break_ctl() - Send RS232 break. Can sleep. Can get called in
|
||||
break_ctl() Send RS232 break. Can sleep. Can get called in
|
||||
parallel, driver must serialize (for now), and
|
||||
with write calls.
|
||||
|
||||
wait_until_sent() - Wait for characters to exit the hardware queue
|
||||
wait_until_sent() Wait for characters to exit the hardware queue
|
||||
of the driver. Can sleep
|
||||
|
||||
send_xchar() - Send XON/XOFF and if possible jump the queue with
|
||||
send_xchar() Send XON/XOFF and if possible jump the queue with
|
||||
it in order to get fast flow control responses.
|
||||
Cannot sleep ??
|
||||
|
||||
======================= =======================================================
|
@ -10466,7 +10466,7 @@ F: include/uapi/linux/meye.h
|
||||
MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
|
||||
M: Jiri Slaby <jirislaby@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/serial/moxa-smartio
|
||||
F: Documentation/serial/moxa-smartio.rst
|
||||
F: drivers/tty/mxser.*
|
||||
|
||||
MR800 AVERMEDIA USB FM RADIO DRIVER
|
||||
@ -13376,7 +13376,7 @@ ROCKETPORT DRIVER
|
||||
P: Comtrol Corp.
|
||||
W: http://www.comtrol.com
|
||||
S: Maintained
|
||||
F: Documentation/serial/rocket.txt
|
||||
F: Documentation/serial/rocket.rst
|
||||
F: drivers/tty/rocket*
|
||||
|
||||
ROCKETPORT EXPRESS/INFINITY DRIVER
|
||||
|
@ -75,7 +75,7 @@ struct ports_driver_data {
|
||||
/* All the console devices handled by this driver */
|
||||
struct list_head consoles;
|
||||
};
|
||||
static struct ports_driver_data pdrvdata;
|
||||
static struct ports_driver_data pdrvdata = { .next_vtermno = 1};
|
||||
|
||||
static DEFINE_SPINLOCK(pdrvdata_lock);
|
||||
static DECLARE_COMPLETION(early_console_added);
|
||||
@ -1394,6 +1394,7 @@ static int add_port(struct ports_device *portdev, u32 id)
|
||||
port->async_queue = NULL;
|
||||
|
||||
port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
|
||||
port->cons.vtermno = 0;
|
||||
|
||||
port->host_connected = port->guest_connected = false;
|
||||
port->stats = (struct port_stats) { 0 };
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
config TTY
|
||||
bool "Enable TTY" if EXPERT
|
||||
default y
|
||||
@ -83,7 +84,6 @@ config HW_CONSOLE
|
||||
config VT_HW_CONSOLE_BINDING
|
||||
bool "Support for binding and unbinding console drivers"
|
||||
depends on HW_CONSOLE
|
||||
default n
|
||||
---help---
|
||||
The virtual terminal is the device that interacts with the physical
|
||||
terminal through console drivers. On these systems, at least one
|
||||
@ -175,7 +175,7 @@ config ROCKETPORT
|
||||
This driver supports Comtrol RocketPort and RocketModem PCI boards.
|
||||
These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or
|
||||
modems. For information about the RocketPort/RocketModem boards
|
||||
and this driver read <file:Documentation/serial/rocket.txt>.
|
||||
and this driver read <file:Documentation/serial/rocket.rst>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called rocket.
|
||||
@ -193,7 +193,7 @@ config CYCLADES
|
||||
your Linux box, for instance in order to become a dial-in server.
|
||||
|
||||
For information about the Cyclades-Z card, read
|
||||
<file:Documentation/serial/README.cycladesZ>.
|
||||
<file:Documentation/serial/cyclades_z.rst>.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cyclades.
|
||||
@ -312,7 +312,6 @@ config N_GSM
|
||||
config TRACE_ROUTER
|
||||
tristate "Trace data router for MIPI P1149.7 cJTAG standard"
|
||||
depends on TRACE_SINK
|
||||
default n
|
||||
help
|
||||
The trace router uses the Linux tty line discipline framework to
|
||||
route trace data coming from a tty port (say UART for example) to
|
||||
@ -328,7 +327,6 @@ config TRACE_ROUTER
|
||||
|
||||
config TRACE_SINK
|
||||
tristate "Trace data sink for MIPI P1149.7 cJTAG standard"
|
||||
default n
|
||||
help
|
||||
The trace sink uses the Linux line discipline framework to receive
|
||||
trace data coming from the trace router line discipline driver
|
||||
@ -376,6 +374,20 @@ config PPC_EARLY_DEBUG_EHV_BC_HANDLE
|
||||
there simply will be no early console output. This is true also
|
||||
if you don't boot under a hypervisor at all.
|
||||
|
||||
config NULL_TTY
|
||||
tristate "NULL TTY driver"
|
||||
help
|
||||
Say Y here if you want a NULL TTY which simply discards messages.
|
||||
|
||||
This is useful to allow userspace applications which expect a console
|
||||
device to work without modifications even when no console is
|
||||
available or desired.
|
||||
|
||||
In order to use this driver, you should redirect the console to this
|
||||
TTY, or boot the kernel with console=ttynull.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config GOLDFISH_TTY
|
||||
tristate "Goldfish TTY Driver"
|
||||
depends on GOLDFISH
|
||||
|
@ -25,6 +25,7 @@ obj-$(CONFIG_ISI) += isicom.o
|
||||
obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
|
||||
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
|
||||
obj-$(CONFIG_NOZOMI) += nozomi.o
|
||||
obj-$(CONFIG_NULL_TTY) += ttynull.o
|
||||
obj-$(CONFIG_ROCKETPORT) += rocket.o
|
||||
obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o
|
||||
obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
if TTY
|
||||
|
||||
config HVC_DRIVER
|
||||
@ -24,7 +25,6 @@ config HVC_CONSOLE
|
||||
config HVC_OLD_HVSI
|
||||
bool "Old driver for pSeries serial port (/dev/hvsi*)"
|
||||
depends on HVC_CONSOLE
|
||||
default n
|
||||
|
||||
config HVC_OPAL
|
||||
bool "OPAL Console support"
|
||||
@ -73,7 +73,6 @@ config HVC_UDBG
|
||||
bool "udbg based fake hypervisor console"
|
||||
depends on PPC
|
||||
select HVC_DRIVER
|
||||
default n
|
||||
help
|
||||
This is meant to be used during HW bring up or debugging when
|
||||
no other console mechanism exist but udbg, to get you a quick
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the IPWireless driver
|
||||
#
|
||||
|
@ -114,6 +114,10 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
|
||||
|
||||
ipw->common_memory = ioremap(p_dev->resource[2]->start,
|
||||
resource_size(p_dev->resource[2]));
|
||||
if (!ipw->common_memory) {
|
||||
ret = -ENOMEM;
|
||||
goto exit1;
|
||||
}
|
||||
if (!request_mem_region(p_dev->resource[2]->start,
|
||||
resource_size(p_dev->resource[2]),
|
||||
IPWIRELESS_PCCARD_NAME)) {
|
||||
@ -134,6 +138,10 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
|
||||
|
||||
ipw->attr_memory = ioremap(p_dev->resource[3]->start,
|
||||
resource_size(p_dev->resource[3]));
|
||||
if (!ipw->attr_memory) {
|
||||
ret = -ENOMEM;
|
||||
goto exit3;
|
||||
}
|
||||
if (!request_mem_region(p_dev->resource[3]->start,
|
||||
resource_size(p_dev->resource[3]),
|
||||
IPWIRELESS_PCCARD_NAME)) {
|
||||
|
@ -550,9 +550,9 @@ static ssize_t process_output_block(struct tty_struct *tty,
|
||||
mutex_lock(&ldata->output_lock);
|
||||
|
||||
space = tty_write_room(tty);
|
||||
if (!space) {
|
||||
if (space <= 0) {
|
||||
mutex_unlock(&ldata->output_lock);
|
||||
return 0;
|
||||
return space;
|
||||
}
|
||||
if (nr > space)
|
||||
nr = space;
|
||||
|
@ -1283,23 +1283,29 @@ static int rp_ioctl(struct tty_struct *tty,
|
||||
return -ENXIO;
|
||||
|
||||
switch (cmd) {
|
||||
case RCKP_GET_STRUCT:
|
||||
if (copy_to_user(argp, info, sizeof (struct r_port)))
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
case RCKP_GET_CONFIG:
|
||||
dev_warn_ratelimited(tty->dev,
|
||||
"RCKP_GET_CONFIG option is deprecated\n");
|
||||
ret = get_config(info, argp);
|
||||
break;
|
||||
case RCKP_SET_CONFIG:
|
||||
dev_warn_ratelimited(tty->dev,
|
||||
"RCKP_SET_CONFIG option is deprecated\n");
|
||||
ret = set_config(tty, info, argp);
|
||||
break;
|
||||
case RCKP_GET_PORTS:
|
||||
dev_warn_ratelimited(tty->dev,
|
||||
"RCKP_GET_PORTS option is deprecated\n");
|
||||
ret = get_ports(info, argp);
|
||||
break;
|
||||
case RCKP_RESET_RM2:
|
||||
dev_warn_ratelimited(tty->dev,
|
||||
"RCKP_RESET_RM2 option is deprecated\n");
|
||||
ret = reset_rm2(info, argp);
|
||||
break;
|
||||
case RCKP_GET_VERSION:
|
||||
dev_warn_ratelimited(tty->dev,
|
||||
"RCKP_GET_VERSION option is deprecated\n");
|
||||
ret = get_version(info, argp);
|
||||
break;
|
||||
default:
|
||||
|
@ -71,7 +71,6 @@ struct rocket_version {
|
||||
/*
|
||||
* Rocketport ioctls -- "RP"
|
||||
*/
|
||||
#define RCKP_GET_STRUCT 0x00525001
|
||||
#define RCKP_GET_CONFIG 0x00525002
|
||||
#define RCKP_SET_CONFIG 0x00525003
|
||||
#define RCKP_GET_PORTS 0x00525004
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Serial bus device driver configuration
|
||||
#
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
serdev-objs := core.o
|
||||
|
||||
obj-$(CONFIG_SERIAL_DEV_BUS) += serdev.o
|
||||
|
@ -361,12 +361,15 @@ static const struct exar8250_platform iot2040_platform = {
|
||||
.register_gpio = iot2040_register_gpio,
|
||||
};
|
||||
|
||||
/*
|
||||
* For SIMATIC IOT2000, only IOT2040 and its variants have the Exar device,
|
||||
* IOT2020 doesn't have. Therefore it is sufficient to match on the common
|
||||
* board name after the device was found.
|
||||
*/
|
||||
static const struct dmi_system_id exar_platforms[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
|
||||
"6ES7647-0AA00-1YA2"),
|
||||
},
|
||||
.driver_data = (void *)&iot2040_platform,
|
||||
},
|
||||
|
@ -303,8 +303,9 @@ static void fintek_8250_goto_highspeed(struct uart_8250_port *uart,
|
||||
}
|
||||
}
|
||||
|
||||
void fintek_8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
static void fintek_8250_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
struct fintek_8250 *pdata = port->private_data;
|
||||
unsigned int baud = tty_termios_baud_rate(termios);
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
@ -21,15 +21,32 @@
|
||||
|
||||
#include "8250.h"
|
||||
|
||||
#define UART_MTK_HIGHS 0x09 /* Highspeed register */
|
||||
#define UART_MTK_SAMPLE_COUNT 0x0a /* Sample count register */
|
||||
#define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */
|
||||
#define MTK_UART_HIGHS 0x09 /* Highspeed register */
|
||||
#define MTK_UART_SAMPLE_COUNT 0x0a /* Sample count register */
|
||||
#define MTK_UART_SAMPLE_POINT 0x0b /* Sample point register */
|
||||
#define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */
|
||||
|
||||
#define MTK_UART_ESCAPE_DAT 0x10 /* Escape Character register */
|
||||
#define MTK_UART_ESCAPE_EN 0x11 /* Escape Enable register */
|
||||
#define MTK_UART_DMA_EN 0x13 /* DMA Enable register */
|
||||
#define MTK_UART_RXTRI_AD 0x14 /* RX Trigger address */
|
||||
#define MTK_UART_FRACDIV_L 0x15 /* Fractional divider LSB address */
|
||||
#define MTK_UART_FRACDIV_M 0x16 /* Fractional divider MSB address */
|
||||
#define MTK_UART_IER_XOFFI 0x20 /* Enable XOFF character interrupt */
|
||||
#define MTK_UART_IER_RTSI 0x40 /* Enable RTS Modem status interrupt */
|
||||
#define MTK_UART_IER_CTSI 0x80 /* Enable CTS Modem status interrupt */
|
||||
|
||||
#define MTK_UART_EFR_EN 0x10 /* Enable enhancement feature */
|
||||
#define MTK_UART_EFR_RTS 0x40 /* Enable hardware rx flow control */
|
||||
#define MTK_UART_EFR_CTS 0x80 /* Enable hardware tx flow control */
|
||||
#define MTK_UART_EFR_NO_SW_FC 0x0 /* no sw flow control */
|
||||
#define MTK_UART_EFR_XON1_XOFF1 0xa /* XON1/XOFF1 as sw flow control */
|
||||
#define MTK_UART_EFR_XON2_XOFF2 0x5 /* XON2/XOFF2 as sw flow control */
|
||||
#define MTK_UART_EFR_SW_FC_MASK 0xf /* Enable CTS Modem status interrupt */
|
||||
#define MTK_UART_EFR_HW_FC (MTK_UART_EFR_RTS | MTK_UART_EFR_CTS)
|
||||
#define MTK_UART_DMA_EN_TX 0x2
|
||||
#define MTK_UART_DMA_EN_RX 0x5
|
||||
|
||||
#define MTK_UART_ESCAPE_CHAR 0x77 /* Escape char added under sw fc */
|
||||
#define MTK_UART_TX_SIZE UART_XMIT_SIZE
|
||||
#define MTK_UART_RX_SIZE 0x8000
|
||||
#define MTK_UART_TX_TRIGGER 1
|
||||
@ -46,6 +63,7 @@ enum dma_rx_status {
|
||||
struct mtk8250_data {
|
||||
int line;
|
||||
unsigned int rx_pos;
|
||||
unsigned int clk_count;
|
||||
struct clk *uart_clk;
|
||||
struct clk *bus_clk;
|
||||
struct uart_8250_dma *dma;
|
||||
@ -54,6 +72,13 @@ struct mtk8250_data {
|
||||
#endif
|
||||
};
|
||||
|
||||
/* flow control mode */
|
||||
enum {
|
||||
MTK_UART_FC_NONE,
|
||||
MTK_UART_FC_SW,
|
||||
MTK_UART_FC_HW,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static void mtk8250_rx_dma(struct uart_8250_port *up);
|
||||
|
||||
@ -192,13 +217,89 @@ static void mtk8250_shutdown(struct uart_port *port)
|
||||
return serial8250_do_shutdown(port);
|
||||
}
|
||||
|
||||
static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask)
|
||||
{
|
||||
serial_out(up, UART_IER, serial_in(up, UART_IER) & (~mask));
|
||||
}
|
||||
|
||||
static void mtk8250_enable_intrs(struct uart_8250_port *up, int mask)
|
||||
{
|
||||
serial_out(up, UART_IER, serial_in(up, UART_IER) | mask);
|
||||
}
|
||||
|
||||
static void mtk8250_set_flow_ctrl(struct uart_8250_port *up, int mode)
|
||||
{
|
||||
struct uart_port *port = &up->port;
|
||||
int lcr = serial_in(up, UART_LCR);
|
||||
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
serial_out(up, UART_EFR, UART_EFR_ECB);
|
||||
serial_out(up, UART_LCR, lcr);
|
||||
lcr = serial_in(up, UART_LCR);
|
||||
|
||||
switch (mode) {
|
||||
case MTK_UART_FC_NONE:
|
||||
serial_out(up, MTK_UART_ESCAPE_DAT, MTK_UART_ESCAPE_CHAR);
|
||||
serial_out(up, MTK_UART_ESCAPE_EN, 0x00);
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
serial_out(up, UART_EFR, serial_in(up, UART_EFR) &
|
||||
(~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK)));
|
||||
serial_out(up, UART_LCR, lcr);
|
||||
mtk8250_disable_intrs(up, MTK_UART_IER_XOFFI |
|
||||
MTK_UART_IER_RTSI | MTK_UART_IER_CTSI);
|
||||
break;
|
||||
|
||||
case MTK_UART_FC_HW:
|
||||
serial_out(up, MTK_UART_ESCAPE_DAT, MTK_UART_ESCAPE_CHAR);
|
||||
serial_out(up, MTK_UART_ESCAPE_EN, 0x00);
|
||||
serial_out(up, UART_MCR, UART_MCR_RTS);
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
|
||||
/*enable hw flow control*/
|
||||
serial_out(up, UART_EFR, MTK_UART_EFR_HW_FC |
|
||||
(serial_in(up, UART_EFR) &
|
||||
(~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK))));
|
||||
|
||||
serial_out(up, UART_LCR, lcr);
|
||||
mtk8250_disable_intrs(up, MTK_UART_IER_XOFFI);
|
||||
mtk8250_enable_intrs(up, MTK_UART_IER_CTSI | MTK_UART_IER_RTSI);
|
||||
break;
|
||||
|
||||
case MTK_UART_FC_SW: /*MTK software flow control */
|
||||
serial_out(up, MTK_UART_ESCAPE_DAT, MTK_UART_ESCAPE_CHAR);
|
||||
serial_out(up, MTK_UART_ESCAPE_EN, 0x01);
|
||||
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
|
||||
|
||||
/*enable sw flow control */
|
||||
serial_out(up, UART_EFR, MTK_UART_EFR_XON1_XOFF1 |
|
||||
(serial_in(up, UART_EFR) &
|
||||
(~(MTK_UART_EFR_HW_FC | MTK_UART_EFR_SW_FC_MASK))));
|
||||
|
||||
serial_out(up, UART_XON1, START_CHAR(port->state->port.tty));
|
||||
serial_out(up, UART_XOFF1, STOP_CHAR(port->state->port.tty));
|
||||
serial_out(up, UART_LCR, lcr);
|
||||
mtk8250_disable_intrs(up, MTK_UART_IER_CTSI|MTK_UART_IER_RTSI);
|
||||
mtk8250_enable_intrs(up, MTK_UART_IER_XOFFI);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
struct ktermios *old)
|
||||
{
|
||||
unsigned short fraction_L_mapping[] = {
|
||||
0, 1, 0x5, 0x15, 0x55, 0x57, 0x57, 0x77, 0x7F, 0xFF, 0xFF
|
||||
};
|
||||
unsigned short fraction_M_mapping[] = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 3
|
||||
};
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
unsigned int baud, quot, fraction;
|
||||
unsigned long flags;
|
||||
unsigned int baud, quot;
|
||||
int mode;
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
if (up->dma) {
|
||||
@ -214,7 +315,7 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
serial8250_do_set_termios(port, termios, old);
|
||||
|
||||
/*
|
||||
* Mediatek UARTs use an extra highspeed register (UART_MTK_HIGHS)
|
||||
* Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS)
|
||||
*
|
||||
* We need to recalcualte the quot register, as the claculation depends
|
||||
* on the vaule in the highspeed register.
|
||||
@ -230,18 +331,11 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
port->uartclk / 16 / UART_DIV_MAX,
|
||||
port->uartclk);
|
||||
|
||||
if (baud <= 115200) {
|
||||
serial_port_out(port, UART_MTK_HIGHS, 0x0);
|
||||
if (baud < 115200) {
|
||||
serial_port_out(port, MTK_UART_HIGHS, 0x0);
|
||||
quot = uart_get_divisor(port, baud);
|
||||
} else if (baud <= 576000) {
|
||||
serial_port_out(port, UART_MTK_HIGHS, 0x2);
|
||||
|
||||
/* Set to next lower baudrate supported */
|
||||
if ((baud == 500000) || (baud == 576000))
|
||||
baud = 460800;
|
||||
quot = DIV_ROUND_UP(port->uartclk, 4 * baud);
|
||||
} else {
|
||||
serial_port_out(port, UART_MTK_HIGHS, 0x3);
|
||||
serial_port_out(port, MTK_UART_HIGHS, 0x3);
|
||||
quot = DIV_ROUND_UP(port->uartclk, 256 * baud);
|
||||
}
|
||||
|
||||
@ -258,18 +352,40 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
|
||||
/* reset DLAB */
|
||||
serial_port_out(port, UART_LCR, up->lcr);
|
||||
|
||||
if (baud > 460800) {
|
||||
if (baud >= 115200) {
|
||||
unsigned int tmp;
|
||||
|
||||
tmp = DIV_ROUND_CLOSEST(port->uartclk, quot * baud);
|
||||
serial_port_out(port, UART_MTK_SAMPLE_COUNT, tmp - 1);
|
||||
serial_port_out(port, UART_MTK_SAMPLE_POINT,
|
||||
(tmp - 2) >> 1);
|
||||
tmp = (port->uartclk / (baud * quot)) - 1;
|
||||
serial_port_out(port, MTK_UART_SAMPLE_COUNT, tmp);
|
||||
serial_port_out(port, MTK_UART_SAMPLE_POINT,
|
||||
(tmp >> 1) - 1);
|
||||
|
||||
/*count fraction to set fractoin register */
|
||||
fraction = ((port->uartclk * 100) / baud / quot) % 100;
|
||||
fraction = DIV_ROUND_CLOSEST(fraction, 10);
|
||||
serial_port_out(port, MTK_UART_FRACDIV_L,
|
||||
fraction_L_mapping[fraction]);
|
||||
serial_port_out(port, MTK_UART_FRACDIV_M,
|
||||
fraction_M_mapping[fraction]);
|
||||
} else {
|
||||
serial_port_out(port, UART_MTK_SAMPLE_COUNT, 0x00);
|
||||
serial_port_out(port, UART_MTK_SAMPLE_POINT, 0xff);
|
||||
serial_port_out(port, MTK_UART_SAMPLE_COUNT, 0x00);
|
||||
serial_port_out(port, MTK_UART_SAMPLE_POINT, 0xff);
|
||||
serial_port_out(port, MTK_UART_FRACDIV_L, 0x00);
|
||||
serial_port_out(port, MTK_UART_FRACDIV_M, 0x00);
|
||||
}
|
||||
|
||||
if ((termios->c_cflag & CRTSCTS) && (!(termios->c_iflag & CRTSCTS)))
|
||||
mode = MTK_UART_FC_HW;
|
||||
else if (termios->c_iflag & CRTSCTS)
|
||||
mode = MTK_UART_FC_SW;
|
||||
else
|
||||
mode = MTK_UART_FC_NONE;
|
||||
|
||||
mtk8250_set_flow_ctrl(up, mode);
|
||||
|
||||
if (uart_console(port))
|
||||
up->port.cons->cflag = termios->c_cflag;
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
/* Don't rewrite B0 */
|
||||
if (tty_termios_baud_rate(termios))
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# The 8250/16550 serial drivers. You shouldn't be in this list unless
|
||||
# you somehow have an implicit or explicit dependency on SERIAL_8250.
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Serial device configuration
|
||||
#
|
||||
@ -369,7 +370,6 @@ config SERIAL_MAX310X
|
||||
depends on SPI_MASTER
|
||||
select SERIAL_CORE
|
||||
select REGMAP_SPI if SPI_MASTER
|
||||
default n
|
||||
help
|
||||
This selects support for an advanced UART from Maxim (Dallas).
|
||||
Supported ICs are MAX3107, MAX3108, MAX3109, MAX14830.
|
||||
@ -652,7 +652,6 @@ config SERIAL_MUX_CONSOLE
|
||||
config PDC_CONSOLE
|
||||
bool "PDC software console support"
|
||||
depends on PARISC && !SERIAL_MUX && VT
|
||||
default n
|
||||
help
|
||||
Saying Y here will enable the software based PDC console to be
|
||||
used as the system console. This is useful for machines in
|
||||
@ -1095,6 +1094,30 @@ config SERIAL_OMAP_CONSOLE
|
||||
your boot loader about how to pass options to the kernel at
|
||||
boot time.)
|
||||
|
||||
config SERIAL_SIFIVE
|
||||
tristate "SiFive UART support"
|
||||
depends on OF
|
||||
select SERIAL_CORE
|
||||
help
|
||||
Select this option if you are building a kernel for a device that
|
||||
contains a SiFive UART IP block. This type of UART is present on
|
||||
SiFive FU540 SoCs, among others.
|
||||
|
||||
config SERIAL_SIFIVE_CONSOLE
|
||||
bool "Console on SiFive UART"
|
||||
depends on SERIAL_SIFIVE=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
help
|
||||
Select this option if you would like to use a SiFive UART as the
|
||||
system console.
|
||||
|
||||
Even if you say Y here, the currently visible virtual console
|
||||
(/dev/tty0) will still be used as the system console by default, but
|
||||
you can alter that using a kernel command line option such as
|
||||
"console=ttySIFx". (Try "man bootparam" or see the documentation of
|
||||
your boot loader about how to pass options to the kernel at
|
||||
boot time.)
|
||||
|
||||
config SERIAL_LANTIQ
|
||||
bool "Lantiq serial driver"
|
||||
depends on LANTIQ
|
||||
@ -1109,7 +1132,6 @@ config SERIAL_QE
|
||||
depends on QUICC_ENGINE
|
||||
select SERIAL_CORE
|
||||
select FW_LOADER
|
||||
default n
|
||||
help
|
||||
This driver supports the QE serial ports on Freescale embedded
|
||||
PowerPC that contain a QUICC Engine.
|
||||
@ -1582,6 +1604,32 @@ config SERIAL_RDA_CONSOLE
|
||||
Say 'Y' here if you wish to use the RDA8810PL UART as the system
|
||||
console. Only earlycon is implemented currently.
|
||||
|
||||
config SERIAL_MILBEAUT_USIO
|
||||
tristate "Milbeaut USIO/UART serial port support"
|
||||
depends on ARCH_MILBEAUT || (COMPILE_TEST && OF)
|
||||
default ARCH_MILBEAUT
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This selects the USIO/UART IP found in Socionext Milbeaut SoCs.
|
||||
|
||||
config SERIAL_MILBEAUT_USIO_PORTS
|
||||
int "Maximum number of CSIO/UART ports (1-8)"
|
||||
range 1 8
|
||||
depends on SERIAL_MILBEAUT_USIO
|
||||
default "4"
|
||||
|
||||
config SERIAL_MILBEAUT_USIO_CONSOLE
|
||||
bool "Support for console on MILBEAUT USIO/UART serial port"
|
||||
depends on SERIAL_MILBEAUT_USIO=y
|
||||
default y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
Say 'Y' here if you wish to use a USIO/UART of Socionext Milbeaut
|
||||
SoCs as the system console (the system console is the device which
|
||||
receives all kernel messages and warnings and which allows logins in
|
||||
single user mode).
|
||||
|
||||
endmenu
|
||||
|
||||
config SERIAL_MCTRL_GPIO
|
||||
|
@ -92,6 +92,8 @@ obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o
|
||||
obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o
|
||||
obj-$(CONFIG_SERIAL_OWL) += owl-uart.o
|
||||
obj-$(CONFIG_SERIAL_RDA) += rda-uart.o
|
||||
obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o
|
||||
obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o
|
||||
|
||||
# GPIOLIB helpers for modem control lines
|
||||
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the Motorola 8xx FEC ethernet controller
|
||||
#
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for Jasmine adapter
|
||||
#
|
||||
|
614
drivers/tty/serial/milbeaut_usio.c
Normal file
614
drivers/tty/serial/milbeaut_usio.c
Normal file
@ -0,0 +1,614 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018 Socionext Inc.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_SERIAL_MILBEAUT_USIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
#define SUPPORT_SYSRQ
|
||||
#endif
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
#define USIO_NAME "mlb-usio-uart"
|
||||
#define USIO_UART_DEV_NAME "ttyUSI"
|
||||
|
||||
static struct uart_port mlb_usio_ports[CONFIG_SERIAL_MILBEAUT_USIO_PORTS];
|
||||
|
||||
#define RX 0
|
||||
#define TX 1
|
||||
static int mlb_usio_irq[CONFIG_SERIAL_MILBEAUT_USIO_PORTS][2];
|
||||
|
||||
#define MLB_USIO_REG_SMR 0
|
||||
#define MLB_USIO_REG_SCR 1
|
||||
#define MLB_USIO_REG_ESCR 2
|
||||
#define MLB_USIO_REG_SSR 3
|
||||
#define MLB_USIO_REG_DR 4
|
||||
#define MLB_USIO_REG_BGR 6
|
||||
#define MLB_USIO_REG_FCR 12
|
||||
#define MLB_USIO_REG_FBYTE 14
|
||||
|
||||
#define MLB_USIO_SMR_SOE BIT(0)
|
||||
#define MLB_USIO_SMR_SBL BIT(3)
|
||||
#define MLB_USIO_SCR_TXE BIT(0)
|
||||
#define MLB_USIO_SCR_RXE BIT(1)
|
||||
#define MLB_USIO_SCR_TBIE BIT(2)
|
||||
#define MLB_USIO_SCR_TIE BIT(3)
|
||||
#define MLB_USIO_SCR_RIE BIT(4)
|
||||
#define MLB_USIO_SCR_UPCL BIT(7)
|
||||
#define MLB_USIO_ESCR_L_8BIT 0
|
||||
#define MLB_USIO_ESCR_L_5BIT 1
|
||||
#define MLB_USIO_ESCR_L_6BIT 2
|
||||
#define MLB_USIO_ESCR_L_7BIT 3
|
||||
#define MLB_USIO_ESCR_P BIT(3)
|
||||
#define MLB_USIO_ESCR_PEN BIT(4)
|
||||
#define MLB_USIO_ESCR_FLWEN BIT(7)
|
||||
#define MLB_USIO_SSR_TBI BIT(0)
|
||||
#define MLB_USIO_SSR_TDRE BIT(1)
|
||||
#define MLB_USIO_SSR_RDRF BIT(2)
|
||||
#define MLB_USIO_SSR_ORE BIT(3)
|
||||
#define MLB_USIO_SSR_FRE BIT(4)
|
||||
#define MLB_USIO_SSR_PE BIT(5)
|
||||
#define MLB_USIO_SSR_REC BIT(7)
|
||||
#define MLB_USIO_SSR_BRK BIT(8)
|
||||
#define MLB_USIO_FCR_FE1 BIT(0)
|
||||
#define MLB_USIO_FCR_FE2 BIT(1)
|
||||
#define MLB_USIO_FCR_FCL1 BIT(2)
|
||||
#define MLB_USIO_FCR_FCL2 BIT(3)
|
||||
#define MLB_USIO_FCR_FSET BIT(4)
|
||||
#define MLB_USIO_FCR_FTIE BIT(9)
|
||||
#define MLB_USIO_FCR_FDRQ BIT(10)
|
||||
#define MLB_USIO_FCR_FRIIE BIT(11)
|
||||
|
||||
static void mlb_usio_stop_tx(struct uart_port *port)
|
||||
{
|
||||
writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FTIE,
|
||||
port->membase + MLB_USIO_REG_FCR);
|
||||
writeb(readb(port->membase + MLB_USIO_REG_SCR) & ~MLB_USIO_SCR_TBIE,
|
||||
port->membase + MLB_USIO_REG_SCR);
|
||||
}
|
||||
|
||||
static void mlb_usio_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
int count;
|
||||
|
||||
writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FTIE,
|
||||
port->membase + MLB_USIO_REG_FCR);
|
||||
writeb(readb(port->membase + MLB_USIO_REG_SCR) &
|
||||
~(MLB_USIO_SCR_TIE | MLB_USIO_SCR_TBIE),
|
||||
port->membase + MLB_USIO_REG_SCR);
|
||||
|
||||
if (port->x_char) {
|
||||
writew(port->x_char, port->membase + MLB_USIO_REG_DR);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
mlb_usio_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
count = port->fifosize -
|
||||
(readw(port->membase + MLB_USIO_REG_FBYTE) & 0xff);
|
||||
|
||||
do {
|
||||
writew(xmit->buf[xmit->tail], port->membase + MLB_USIO_REG_DR);
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
} while (--count > 0);
|
||||
|
||||
writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FDRQ,
|
||||
port->membase + MLB_USIO_REG_FCR);
|
||||
|
||||
writeb(readb(port->membase + MLB_USIO_REG_SCR) | MLB_USIO_SCR_TBIE,
|
||||
port->membase + MLB_USIO_REG_SCR);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
mlb_usio_stop_tx(port);
|
||||
}
|
||||
|
||||
static void mlb_usio_start_tx(struct uart_port *port)
|
||||
{
|
||||
u16 fcr = readw(port->membase + MLB_USIO_REG_FCR);
|
||||
|
||||
writew(fcr | MLB_USIO_FCR_FTIE, port->membase + MLB_USIO_REG_FCR);
|
||||
if (!(fcr & MLB_USIO_FCR_FDRQ))
|
||||
return;
|
||||
|
||||
writeb(readb(port->membase + MLB_USIO_REG_SCR) | MLB_USIO_SCR_TBIE,
|
||||
port->membase + MLB_USIO_REG_SCR);
|
||||
|
||||
if (readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TBI)
|
||||
mlb_usio_tx_chars(port);
|
||||
}
|
||||
|
||||
static void mlb_usio_stop_rx(struct uart_port *port)
|
||||
{
|
||||
writeb(readb(port->membase + MLB_USIO_REG_SCR) & ~MLB_USIO_SCR_RIE,
|
||||
port->membase + MLB_USIO_REG_SCR);
|
||||
}
|
||||
|
||||
static void mlb_usio_enable_ms(struct uart_port *port)
|
||||
{
|
||||
writeb(readb(port->membase + MLB_USIO_REG_SCR) |
|
||||
MLB_USIO_SCR_RIE | MLB_USIO_SCR_RXE,
|
||||
port->membase + MLB_USIO_REG_SCR);
|
||||
}
|
||||
|
||||
static void mlb_usio_rx_chars(struct uart_port *port)
|
||||
{
|
||||
struct tty_port *ttyport = &port->state->port;
|
||||
unsigned long flag = 0;
|
||||
char ch = 0;
|
||||
u8 status;
|
||||
int max_count = 2;
|
||||
|
||||
while (max_count--) {
|
||||
status = readb(port->membase + MLB_USIO_REG_SSR);
|
||||
|
||||
if (!(status & MLB_USIO_SSR_RDRF))
|
||||
break;
|
||||
|
||||
if (!(status & (MLB_USIO_SSR_ORE | MLB_USIO_SSR_FRE |
|
||||
MLB_USIO_SSR_PE))) {
|
||||
ch = readw(port->membase + MLB_USIO_REG_DR);
|
||||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
continue;
|
||||
uart_insert_char(port, status, MLB_USIO_SSR_ORE,
|
||||
ch, flag);
|
||||
continue;
|
||||
}
|
||||
if (status & MLB_USIO_SSR_PE)
|
||||
port->icount.parity++;
|
||||
if (status & MLB_USIO_SSR_ORE)
|
||||
port->icount.overrun++;
|
||||
status &= port->read_status_mask;
|
||||
if (status & MLB_USIO_SSR_BRK) {
|
||||
flag = TTY_BREAK;
|
||||
ch = 0;
|
||||
} else
|
||||
if (status & MLB_USIO_SSR_PE) {
|
||||
flag = TTY_PARITY;
|
||||
ch = 0;
|
||||
} else
|
||||
if (status & MLB_USIO_SSR_FRE) {
|
||||
flag = TTY_FRAME;
|
||||
ch = 0;
|
||||
}
|
||||
if (flag)
|
||||
uart_insert_char(port, status, MLB_USIO_SSR_ORE,
|
||||
ch, flag);
|
||||
|
||||
writeb(readb(port->membase + MLB_USIO_REG_SSR) |
|
||||
MLB_USIO_SSR_REC,
|
||||
port->membase + MLB_USIO_REG_SSR);
|
||||
|
||||
max_count = readw(port->membase + MLB_USIO_REG_FBYTE) >> 8;
|
||||
writew(readw(port->membase + MLB_USIO_REG_FCR) |
|
||||
MLB_USIO_FCR_FE2 | MLB_USIO_FCR_FRIIE,
|
||||
port->membase + MLB_USIO_REG_FCR);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(ttyport);
|
||||
}
|
||||
|
||||
static irqreturn_t mlb_usio_rx_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
mlb_usio_rx_chars(port);
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t mlb_usio_tx_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
if (readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TBI)
|
||||
mlb_usio_tx_chars(port);
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static unsigned int mlb_usio_tx_empty(struct uart_port *port)
|
||||
{
|
||||
return (readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TBI) ?
|
||||
TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
static void mlb_usio_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
}
|
||||
|
||||
static unsigned int mlb_usio_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
|
||||
|
||||
}
|
||||
|
||||
static void mlb_usio_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
}
|
||||
|
||||
static int mlb_usio_startup(struct uart_port *port)
|
||||
{
|
||||
const char *portname = to_platform_device(port->dev)->name;
|
||||
unsigned long flags;
|
||||
int ret, index = port->line;
|
||||
unsigned char escr;
|
||||
|
||||
ret = request_irq(mlb_usio_irq[index][RX], mlb_usio_rx_irq,
|
||||
0, portname, port);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = request_irq(mlb_usio_irq[index][TX], mlb_usio_tx_irq,
|
||||
0, portname, port);
|
||||
if (ret) {
|
||||
free_irq(mlb_usio_irq[index][RX], port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
escr = readb(port->membase + MLB_USIO_REG_ESCR);
|
||||
if (of_property_read_bool(port->dev->of_node, "auto-flow-control"))
|
||||
escr |= MLB_USIO_ESCR_FLWEN;
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
writeb(0, port->membase + MLB_USIO_REG_SCR);
|
||||
writeb(escr, port->membase + MLB_USIO_REG_ESCR);
|
||||
writeb(MLB_USIO_SCR_UPCL, port->membase + MLB_USIO_REG_SCR);
|
||||
writeb(MLB_USIO_SSR_REC, port->membase + MLB_USIO_REG_SSR);
|
||||
writew(0, port->membase + MLB_USIO_REG_FCR);
|
||||
writew(MLB_USIO_FCR_FCL1 | MLB_USIO_FCR_FCL2,
|
||||
port->membase + MLB_USIO_REG_FCR);
|
||||
writew(MLB_USIO_FCR_FE1 | MLB_USIO_FCR_FE2 | MLB_USIO_FCR_FRIIE,
|
||||
port->membase + MLB_USIO_REG_FCR);
|
||||
writew(0, port->membase + MLB_USIO_REG_FBYTE);
|
||||
writew(BIT(12), port->membase + MLB_USIO_REG_FBYTE);
|
||||
|
||||
writeb(MLB_USIO_SCR_TXE | MLB_USIO_SCR_RIE | MLB_USIO_SCR_TBIE |
|
||||
MLB_USIO_SCR_RXE, port->membase + MLB_USIO_REG_SCR);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mlb_usio_shutdown(struct uart_port *port)
|
||||
{
|
||||
int index = port->line;
|
||||
|
||||
free_irq(mlb_usio_irq[index][RX], port);
|
||||
free_irq(mlb_usio_irq[index][TX], port);
|
||||
}
|
||||
|
||||
static void mlb_usio_set_termios(struct uart_port *port,
|
||||
struct ktermios *termios, struct ktermios *old)
|
||||
{
|
||||
unsigned int escr, smr = MLB_USIO_SMR_SOE;
|
||||
unsigned long flags, baud, quot;
|
||||
|
||||
switch (termios->c_cflag & CSIZE) {
|
||||
case CS5:
|
||||
escr = MLB_USIO_ESCR_L_5BIT;
|
||||
break;
|
||||
case CS6:
|
||||
escr = MLB_USIO_ESCR_L_6BIT;
|
||||
break;
|
||||
case CS7:
|
||||
escr = MLB_USIO_ESCR_L_7BIT;
|
||||
break;
|
||||
case CS8:
|
||||
default:
|
||||
escr = MLB_USIO_ESCR_L_8BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (termios->c_cflag & CSTOPB)
|
||||
smr |= MLB_USIO_SMR_SBL;
|
||||
|
||||
if (termios->c_cflag & PARENB) {
|
||||
escr |= MLB_USIO_ESCR_PEN;
|
||||
if (termios->c_cflag & PARODD)
|
||||
escr |= MLB_USIO_ESCR_P;
|
||||
}
|
||||
/* Set hard flow control */
|
||||
if (of_property_read_bool(port->dev->of_node, "auto-flow-control") ||
|
||||
(termios->c_cflag & CRTSCTS))
|
||||
escr |= MLB_USIO_ESCR_FLWEN;
|
||||
|
||||
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk);
|
||||
if (baud > 1)
|
||||
quot = port->uartclk / baud - 1;
|
||||
else
|
||||
quot = 0;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
uart_update_timeout(port, termios->c_cflag, baud);
|
||||
port->read_status_mask = MLB_USIO_SSR_ORE | MLB_USIO_SSR_RDRF |
|
||||
MLB_USIO_SSR_TDRE;
|
||||
if (termios->c_iflag & INPCK)
|
||||
port->read_status_mask |= MLB_USIO_SSR_FRE | MLB_USIO_SSR_PE;
|
||||
|
||||
port->ignore_status_mask = 0;
|
||||
if (termios->c_iflag & IGNPAR)
|
||||
port->ignore_status_mask |= MLB_USIO_SSR_FRE | MLB_USIO_SSR_PE;
|
||||
if ((termios->c_iflag & IGNBRK) && (termios->c_iflag & IGNPAR))
|
||||
port->ignore_status_mask |= MLB_USIO_SSR_ORE;
|
||||
if ((termios->c_cflag & CREAD) == 0)
|
||||
port->ignore_status_mask |= MLB_USIO_SSR_RDRF;
|
||||
|
||||
writeb(0, port->membase + MLB_USIO_REG_SCR);
|
||||
writeb(MLB_USIO_SCR_UPCL, port->membase + MLB_USIO_REG_SCR);
|
||||
writeb(MLB_USIO_SSR_REC, port->membase + MLB_USIO_REG_SSR);
|
||||
writew(0, port->membase + MLB_USIO_REG_FCR);
|
||||
writeb(smr, port->membase + MLB_USIO_REG_SMR);
|
||||
writeb(escr, port->membase + MLB_USIO_REG_ESCR);
|
||||
writew(quot, port->membase + MLB_USIO_REG_BGR);
|
||||
writew(0, port->membase + MLB_USIO_REG_FCR);
|
||||
writew(MLB_USIO_FCR_FCL1 | MLB_USIO_FCR_FCL2 | MLB_USIO_FCR_FE1 |
|
||||
MLB_USIO_FCR_FE2 | MLB_USIO_FCR_FRIIE,
|
||||
port->membase + MLB_USIO_REG_FCR);
|
||||
writew(0, port->membase + MLB_USIO_REG_FBYTE);
|
||||
writew(BIT(12), port->membase + MLB_USIO_REG_FBYTE);
|
||||
writeb(MLB_USIO_SCR_RIE | MLB_USIO_SCR_RXE | MLB_USIO_SCR_TBIE |
|
||||
MLB_USIO_SCR_TXE, port->membase + MLB_USIO_REG_SCR);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static const char *mlb_usio_type(struct uart_port *port)
|
||||
{
|
||||
return ((port->type == PORT_MLB_USIO) ? USIO_NAME : NULL);
|
||||
}
|
||||
|
||||
static void mlb_usio_config_port(struct uart_port *port, int flags)
|
||||
{
|
||||
if (flags & UART_CONFIG_TYPE)
|
||||
port->type = PORT_MLB_USIO;
|
||||
}
|
||||
|
||||
static const struct uart_ops mlb_usio_ops = {
|
||||
.tx_empty = mlb_usio_tx_empty,
|
||||
.set_mctrl = mlb_usio_set_mctrl,
|
||||
.get_mctrl = mlb_usio_get_mctrl,
|
||||
.stop_tx = mlb_usio_stop_tx,
|
||||
.start_tx = mlb_usio_start_tx,
|
||||
.stop_rx = mlb_usio_stop_rx,
|
||||
.enable_ms = mlb_usio_enable_ms,
|
||||
.break_ctl = mlb_usio_break_ctl,
|
||||
.startup = mlb_usio_startup,
|
||||
.shutdown = mlb_usio_shutdown,
|
||||
.set_termios = mlb_usio_set_termios,
|
||||
.type = mlb_usio_type,
|
||||
.config_port = mlb_usio_config_port,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_MILBEAUT_USIO_CONSOLE
|
||||
|
||||
static void mlb_usio_console_putchar(struct uart_port *port, int c)
|
||||
{
|
||||
while (!(readb(port->membase + MLB_USIO_REG_SSR) & MLB_USIO_SSR_TDRE))
|
||||
cpu_relax();
|
||||
|
||||
writew(c, port->membase + MLB_USIO_REG_DR);
|
||||
}
|
||||
|
||||
static void mlb_usio_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
struct uart_port *port = &mlb_usio_ports[co->index];
|
||||
|
||||
uart_console_write(port, s, count, mlb_usio_console_putchar);
|
||||
}
|
||||
|
||||
static int __init mlb_usio_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct uart_port *port;
|
||||
int baud = 115200;
|
||||
int parity = 'n';
|
||||
int flow = 'n';
|
||||
int bits = 8;
|
||||
|
||||
if (co->index >= CONFIG_SERIAL_MILBEAUT_USIO_PORTS)
|
||||
return -ENODEV;
|
||||
|
||||
port = &mlb_usio_ports[co->index];
|
||||
if (!port->membase)
|
||||
return -ENODEV;
|
||||
|
||||
|
||||
if (options)
|
||||
uart_parse_options(options, &baud, &parity, &bits, &flow);
|
||||
|
||||
if (of_property_read_bool(port->dev->of_node, "auto-flow-control"))
|
||||
flow = 'r';
|
||||
|
||||
return uart_set_options(port, co, baud, parity, bits, flow);
|
||||
}
|
||||
|
||||
|
||||
static struct uart_driver mlb_usio_uart_driver;
|
||||
static struct console mlb_usio_console = {
|
||||
.name = USIO_UART_DEV_NAME,
|
||||
.write = mlb_usio_console_write,
|
||||
.device = uart_console_device,
|
||||
.setup = mlb_usio_console_setup,
|
||||
.flags = CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
.data = &mlb_usio_uart_driver,
|
||||
};
|
||||
|
||||
static int __init mlb_usio_console_init(void)
|
||||
{
|
||||
register_console(&mlb_usio_console);
|
||||
return 0;
|
||||
}
|
||||
console_initcall(mlb_usio_console_init);
|
||||
|
||||
|
||||
static void mlb_usio_early_console_write(struct console *co, const char *s,
|
||||
u_int count)
|
||||
{
|
||||
struct earlycon_device *dev = co->data;
|
||||
|
||||
uart_console_write(&dev->port, s, count, mlb_usio_console_putchar);
|
||||
}
|
||||
|
||||
static int __init mlb_usio_early_console_setup(struct earlycon_device *device,
|
||||
const char *opt)
|
||||
{
|
||||
if (!device->port.membase)
|
||||
return -ENODEV;
|
||||
device->con->write = mlb_usio_early_console_write;
|
||||
return 0;
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(mlb_usio, "socionext,milbeaut-usio-uart",
|
||||
mlb_usio_early_console_setup);
|
||||
|
||||
#define USIO_CONSOLE (&mlb_usio_console)
|
||||
#else
|
||||
#define USIO_CONSOLE NULL
|
||||
#endif
|
||||
|
||||
static struct uart_driver mlb_usio_uart_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.driver_name = USIO_NAME,
|
||||
.dev_name = USIO_UART_DEV_NAME,
|
||||
.cons = USIO_CONSOLE,
|
||||
.nr = CONFIG_SERIAL_MILBEAUT_USIO_PORTS,
|
||||
};
|
||||
|
||||
static int mlb_usio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct clk *clk = devm_clk_get(&pdev->dev, NULL);
|
||||
struct uart_port *port;
|
||||
struct resource *res;
|
||||
int index = 0;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "Missing clock\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Clock enable failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
of_property_read_u32(pdev->dev.of_node, "index", &index);
|
||||
port = &mlb_usio_ports[index];
|
||||
|
||||
port->private_data = (void *)clk;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "Missing regs\n");
|
||||
ret = -ENODEV;
|
||||
goto failed;
|
||||
}
|
||||
port->membase = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
|
||||
ret = platform_get_irq_byname(pdev, "rx");
|
||||
mlb_usio_irq[index][RX] = ret;
|
||||
|
||||
ret = platform_get_irq_byname(pdev, "tx");
|
||||
mlb_usio_irq[index][TX] = ret;
|
||||
|
||||
port->irq = mlb_usio_irq[index][RX];
|
||||
port->uartclk = clk_get_rate(clk);
|
||||
port->fifosize = 128;
|
||||
port->iotype = UPIO_MEM32;
|
||||
port->flags = UPF_BOOT_AUTOCONF | UPF_SPD_VHI;
|
||||
port->line = index;
|
||||
port->ops = &mlb_usio_ops;
|
||||
port->dev = &pdev->dev;
|
||||
|
||||
ret = uart_add_one_port(&mlb_usio_uart_driver, port);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Adding port failed: %d\n", ret);
|
||||
goto failed;
|
||||
}
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
clk_disable_unprepare(clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mlb_usio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uart_port *port = &mlb_usio_ports[pdev->id];
|
||||
struct clk *clk = port->private_data;
|
||||
|
||||
uart_remove_one_port(&mlb_usio_uart_driver, port);
|
||||
clk_disable_unprepare(clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mlb_usio_dt_ids[] = {
|
||||
{ .compatible = "socionext,milbeaut-usio-uart" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mlb_usio_dt_ids);
|
||||
|
||||
static struct platform_driver mlb_usio_driver = {
|
||||
.probe = mlb_usio_probe,
|
||||
.remove = mlb_usio_remove,
|
||||
.driver = {
|
||||
.name = USIO_NAME,
|
||||
.of_match_table = mlb_usio_dt_ids,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mlb_usio_init(void)
|
||||
{
|
||||
int ret = uart_register_driver(&mlb_usio_uart_driver);
|
||||
|
||||
if (ret) {
|
||||
pr_err("%s: uart registration failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
ret = platform_driver_register(&mlb_usio_driver);
|
||||
if (ret) {
|
||||
uart_unregister_driver(&mlb_usio_uart_driver);
|
||||
pr_err("%s: drv registration failed: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit mlb_usio_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mlb_usio_driver);
|
||||
uart_unregister_driver(&mlb_usio_uart_driver);
|
||||
}
|
||||
|
||||
module_init(mlb_usio_init);
|
||||
module_exit(mlb_usio_exit);
|
||||
|
||||
MODULE_AUTHOR("SOCIONEXT");
|
||||
MODULE_DESCRIPTION("MILBEAUT_USIO/UART Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -14,9 +14,9 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/serial.h>
|
||||
@ -1179,7 +1179,8 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
struct regmap *regmap, int irq, unsigned long flags)
|
||||
{
|
||||
struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 };
|
||||
unsigned long freq, *pfreq = dev_get_platdata(dev);
|
||||
unsigned long freq = 0, *pfreq = dev_get_platdata(dev);
|
||||
u32 uartclk = 0;
|
||||
int i, ret;
|
||||
struct sc16is7xx_port *s;
|
||||
|
||||
@ -1193,10 +1194,17 @@ static int sc16is7xx_probe(struct device *dev,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Always ask for fixed clock rate from a property. */
|
||||
device_property_read_u32(dev, "clock-frequency", &uartclk);
|
||||
|
||||
s->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(s->clk)) {
|
||||
if (uartclk)
|
||||
freq = uartclk;
|
||||
if (pfreq)
|
||||
freq = *pfreq;
|
||||
if (freq)
|
||||
dev_dbg(dev, "Clock frequency: %luHz\n", freq);
|
||||
else
|
||||
return PTR_ERR(s->clk);
|
||||
} else {
|
||||
@ -1384,13 +1392,9 @@ static int sc16is7xx_spi_probe(struct spi_device *spi)
|
||||
return ret;
|
||||
|
||||
if (spi->dev.of_node) {
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(sc16is7xx_dt_ids, &spi->dev);
|
||||
|
||||
if (!of_id)
|
||||
devtype = device_get_match_data(&spi->dev);
|
||||
if (!devtype)
|
||||
return -ENODEV;
|
||||
|
||||
devtype = (struct sc16is7xx_devtype *)of_id->data;
|
||||
} else {
|
||||
const struct spi_device_id *id_entry = spi_get_device_id(spi);
|
||||
|
||||
@ -1426,7 +1430,7 @@ MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table);
|
||||
static struct spi_driver sc16is7xx_spi_uart_driver = {
|
||||
.driver = {
|
||||
.name = SC16IS7XX_NAME,
|
||||
.of_match_table = of_match_ptr(sc16is7xx_dt_ids),
|
||||
.of_match_table = sc16is7xx_dt_ids,
|
||||
},
|
||||
.probe = sc16is7xx_spi_probe,
|
||||
.remove = sc16is7xx_spi_remove,
|
||||
@ -1445,13 +1449,9 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c,
|
||||
struct regmap *regmap;
|
||||
|
||||
if (i2c->dev.of_node) {
|
||||
const struct of_device_id *of_id =
|
||||
of_match_device(sc16is7xx_dt_ids, &i2c->dev);
|
||||
|
||||
if (!of_id)
|
||||
devtype = device_get_match_data(&i2c->dev);
|
||||
if (!devtype)
|
||||
return -ENODEV;
|
||||
|
||||
devtype = (struct sc16is7xx_devtype *)of_id->data;
|
||||
} else {
|
||||
devtype = (struct sc16is7xx_devtype *)id->driver_data;
|
||||
flags = IRQF_TRIGGER_FALLING;
|
||||
@ -1484,7 +1484,7 @@ MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table);
|
||||
static struct i2c_driver sc16is7xx_i2c_uart_driver = {
|
||||
.driver = {
|
||||
.name = SC16IS7XX_NAME,
|
||||
.of_match_table = of_match_ptr(sc16is7xx_dt_ids),
|
||||
.of_match_table = sc16is7xx_dt_ids,
|
||||
},
|
||||
.probe = sc16is7xx_i2c_probe,
|
||||
.remove = sc16is7xx_i2c_remove,
|
||||
|
@ -130,9 +130,6 @@ static void uart_start(struct tty_struct *tty)
|
||||
struct uart_port *port;
|
||||
unsigned long flags;
|
||||
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
port = uart_port_lock(state, flags);
|
||||
__uart_start(tty);
|
||||
uart_port_unlock(port, flags);
|
||||
@ -730,9 +727,6 @@ static void uart_unthrottle(struct tty_struct *tty)
|
||||
upstat_t mask = UPSTAT_SYNC_FIFO;
|
||||
struct uart_port *port;
|
||||
|
||||
if (!state)
|
||||
return;
|
||||
|
||||
port = uart_port_ref(state);
|
||||
if (!port)
|
||||
return;
|
||||
@ -1514,7 +1508,7 @@ static void uart_set_termios(struct tty_struct *tty,
|
||||
}
|
||||
|
||||
uart_change_speed(tty, state, old_termios);
|
||||
/* reload cflag from termios; port driver may have overriden flags */
|
||||
/* reload cflag from termios; port driver may have overridden flags */
|
||||
cflag = tty->termios.c_cflag;
|
||||
|
||||
/* Handle transition to B0 status */
|
||||
@ -1747,6 +1741,16 @@ static void uart_dtr_rts(struct tty_port *port, int raise)
|
||||
uart_port_deref(uport);
|
||||
}
|
||||
|
||||
static int uart_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||
{
|
||||
struct uart_driver *drv = driver->driver_state;
|
||||
struct uart_state *state = drv->state + tty->index;
|
||||
|
||||
tty->driver_data = state;
|
||||
|
||||
return tty_standard_install(driver, tty);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calls to uart_open are serialised by the tty_lock in
|
||||
* drivers/tty/tty_io.c:tty_open()
|
||||
@ -1759,11 +1763,8 @@ static void uart_dtr_rts(struct tty_port *port, int raise)
|
||||
*/
|
||||
static int uart_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct uart_driver *drv = tty->driver->driver_state;
|
||||
int retval, line = tty->index;
|
||||
struct uart_state *state = drv->state + line;
|
||||
|
||||
tty->driver_data = state;
|
||||
struct uart_state *state = tty->driver_data;
|
||||
int retval;
|
||||
|
||||
retval = tty_port_open(&state->port, tty, filp);
|
||||
if (retval > 0)
|
||||
@ -2448,6 +2449,7 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch)
|
||||
#endif
|
||||
|
||||
static const struct tty_operations uart_ops = {
|
||||
.install = uart_install,
|
||||
.open = uart_open,
|
||||
.close = uart_close,
|
||||
.write = uart_write,
|
||||
@ -2505,7 +2507,7 @@ static const struct tty_port_operations uart_port_ops = {
|
||||
int uart_register_driver(struct uart_driver *drv)
|
||||
{
|
||||
struct tty_driver *normal;
|
||||
int i, retval;
|
||||
int i, retval = -ENOMEM;
|
||||
|
||||
BUG_ON(drv->state);
|
||||
|
||||
@ -2557,7 +2559,7 @@ int uart_register_driver(struct uart_driver *drv)
|
||||
out_kfree:
|
||||
kfree(drv->state);
|
||||
out:
|
||||
return -ENOMEM;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
|
1056
drivers/tty/serial/sifive.c
Normal file
1056
drivers/tty/serial/sifive.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* C-Brick Serial Port (and console) driver for SGI Altix machines.
|
||||
*
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dma/sprd-dma.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -75,6 +78,7 @@
|
||||
|
||||
/* control register 1 */
|
||||
#define SPRD_CTL1 0x001C
|
||||
#define SPRD_DMA_EN BIT(15)
|
||||
#define RX_HW_FLOW_CTL_THLD BIT(6)
|
||||
#define RX_HW_FLOW_CTL_EN BIT(7)
|
||||
#define TX_HW_FLOW_CTL_EN BIT(8)
|
||||
@ -86,6 +90,7 @@
|
||||
#define THLD_TX_EMPTY 0x40
|
||||
#define THLD_TX_EMPTY_SHIFT 8
|
||||
#define THLD_RX_FULL 0x40
|
||||
#define THLD_RX_FULL_MASK GENMASK(6, 0)
|
||||
|
||||
/* config baud rate register */
|
||||
#define SPRD_CLKD0 0x0024
|
||||
@ -100,15 +105,38 @@
|
||||
#define SPRD_IMSR_TX_FIFO_EMPTY BIT(1)
|
||||
#define SPRD_IMSR_BREAK_DETECT BIT(7)
|
||||
#define SPRD_IMSR_TIMEOUT BIT(13)
|
||||
#define SPRD_DEFAULT_SOURCE_CLK 26000000
|
||||
|
||||
#define SPRD_RX_DMA_STEP 1
|
||||
#define SPRD_RX_FIFO_FULL 1
|
||||
#define SPRD_TX_FIFO_FULL 0x20
|
||||
#define SPRD_UART_RX_SIZE (UART_XMIT_SIZE / 4)
|
||||
|
||||
struct sprd_uart_dma {
|
||||
struct dma_chan *chn;
|
||||
unsigned char *virt;
|
||||
dma_addr_t phys_addr;
|
||||
dma_cookie_t cookie;
|
||||
u32 trans_len;
|
||||
bool enable;
|
||||
};
|
||||
|
||||
struct sprd_uart_port {
|
||||
struct uart_port port;
|
||||
char name[16];
|
||||
struct clk *clk;
|
||||
struct sprd_uart_dma tx_dma;
|
||||
struct sprd_uart_dma rx_dma;
|
||||
dma_addr_t pos;
|
||||
unsigned char *rx_buf_tail;
|
||||
};
|
||||
|
||||
static struct sprd_uart_port *sprd_port[UART_NR_MAX];
|
||||
static int sprd_ports_num;
|
||||
|
||||
static int sprd_start_dma_rx(struct uart_port *port);
|
||||
static int sprd_tx_dma_config(struct uart_port *port);
|
||||
|
||||
static inline unsigned int serial_in(struct uart_port *port,
|
||||
unsigned int offset)
|
||||
{
|
||||
@ -139,35 +167,15 @@ static void sprd_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
/* nothing to do */
|
||||
}
|
||||
|
||||
static void sprd_stop_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned int ien, iclr;
|
||||
|
||||
iclr = serial_in(port, SPRD_ICLR);
|
||||
ien = serial_in(port, SPRD_IEN);
|
||||
|
||||
iclr |= SPRD_IEN_TX_EMPTY;
|
||||
ien &= ~SPRD_IEN_TX_EMPTY;
|
||||
|
||||
serial_out(port, SPRD_ICLR, iclr);
|
||||
serial_out(port, SPRD_IEN, ien);
|
||||
}
|
||||
|
||||
static void sprd_start_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned int ien;
|
||||
|
||||
ien = serial_in(port, SPRD_IEN);
|
||||
if (!(ien & SPRD_IEN_TX_EMPTY)) {
|
||||
ien |= SPRD_IEN_TX_EMPTY;
|
||||
serial_out(port, SPRD_IEN, ien);
|
||||
}
|
||||
}
|
||||
|
||||
static void sprd_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
unsigned int ien, iclr;
|
||||
|
||||
if (sp->rx_dma.enable)
|
||||
dmaengine_terminate_all(sp->rx_dma.chn);
|
||||
|
||||
iclr = serial_in(port, SPRD_ICLR);
|
||||
ien = serial_in(port, SPRD_IEN);
|
||||
|
||||
@ -178,6 +186,370 @@ static void sprd_stop_rx(struct uart_port *port)
|
||||
serial_out(port, SPRD_ICLR, iclr);
|
||||
}
|
||||
|
||||
static void sprd_uart_dma_enable(struct uart_port *port, bool enable)
|
||||
{
|
||||
u32 val = serial_in(port, SPRD_CTL1);
|
||||
|
||||
if (enable)
|
||||
val |= SPRD_DMA_EN;
|
||||
else
|
||||
val &= ~SPRD_DMA_EN;
|
||||
|
||||
serial_out(port, SPRD_CTL1, val);
|
||||
}
|
||||
|
||||
static void sprd_stop_tx_dma(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct dma_tx_state state;
|
||||
u32 trans_len;
|
||||
|
||||
dmaengine_pause(sp->tx_dma.chn);
|
||||
|
||||
dmaengine_tx_status(sp->tx_dma.chn, sp->tx_dma.cookie, &state);
|
||||
if (state.residue) {
|
||||
trans_len = state.residue - sp->tx_dma.phys_addr;
|
||||
xmit->tail = (xmit->tail + trans_len) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx += trans_len;
|
||||
dma_unmap_single(port->dev, sp->tx_dma.phys_addr,
|
||||
sp->tx_dma.trans_len, DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
dmaengine_terminate_all(sp->tx_dma.chn);
|
||||
sp->tx_dma.trans_len = 0;
|
||||
}
|
||||
|
||||
static int sprd_tx_buf_remap(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
|
||||
sp->tx_dma.trans_len =
|
||||
CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
|
||||
|
||||
sp->tx_dma.phys_addr = dma_map_single(port->dev,
|
||||
(void *)&(xmit->buf[xmit->tail]),
|
||||
sp->tx_dma.trans_len,
|
||||
DMA_TO_DEVICE);
|
||||
return dma_mapping_error(port->dev, sp->tx_dma.phys_addr);
|
||||
}
|
||||
|
||||
static void sprd_complete_tx_dma(void *data)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *)data;
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
dma_unmap_single(port->dev, sp->tx_dma.phys_addr,
|
||||
sp->tx_dma.trans_len, DMA_TO_DEVICE);
|
||||
|
||||
xmit->tail = (xmit->tail + sp->tx_dma.trans_len) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx += sp->tx_dma.trans_len;
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit) || sprd_tx_buf_remap(port) ||
|
||||
sprd_tx_dma_config(port))
|
||||
sp->tx_dma.trans_len = 0;
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static int sprd_uart_dma_submit(struct uart_port *port,
|
||||
struct sprd_uart_dma *ud, u32 trans_len,
|
||||
enum dma_transfer_direction direction,
|
||||
dma_async_tx_callback callback)
|
||||
{
|
||||
struct dma_async_tx_descriptor *dma_des;
|
||||
unsigned long flags;
|
||||
|
||||
flags = SPRD_DMA_FLAGS(SPRD_DMA_CHN_MODE_NONE,
|
||||
SPRD_DMA_NO_TRG,
|
||||
SPRD_DMA_FRAG_REQ,
|
||||
SPRD_DMA_TRANS_INT);
|
||||
|
||||
dma_des = dmaengine_prep_slave_single(ud->chn, ud->phys_addr, trans_len,
|
||||
direction, flags);
|
||||
if (!dma_des)
|
||||
return -ENODEV;
|
||||
|
||||
dma_des->callback = callback;
|
||||
dma_des->callback_param = port;
|
||||
|
||||
ud->cookie = dmaengine_submit(dma_des);
|
||||
if (dma_submit_error(ud->cookie))
|
||||
return dma_submit_error(ud->cookie);
|
||||
|
||||
dma_async_issue_pending(ud->chn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sprd_tx_dma_config(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
u32 burst = sp->tx_dma.trans_len > SPRD_TX_FIFO_FULL ?
|
||||
SPRD_TX_FIFO_FULL : sp->tx_dma.trans_len;
|
||||
int ret;
|
||||
struct dma_slave_config cfg = {
|
||||
.dst_addr = port->mapbase + SPRD_TXD,
|
||||
.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
|
||||
.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
|
||||
.src_maxburst = burst,
|
||||
};
|
||||
|
||||
ret = dmaengine_slave_config(sp->tx_dma.chn, &cfg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprd_uart_dma_submit(port, &sp->tx_dma, sp->tx_dma.trans_len,
|
||||
DMA_MEM_TO_DEV, sprd_complete_tx_dma);
|
||||
}
|
||||
|
||||
static void sprd_start_tx_dma(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
|
||||
if (port->x_char) {
|
||||
serial_out(port, SPRD_TXD, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
sprd_stop_tx_dma(port);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sp->tx_dma.trans_len)
|
||||
return;
|
||||
|
||||
if (sprd_tx_buf_remap(port) || sprd_tx_dma_config(port))
|
||||
sp->tx_dma.trans_len = 0;
|
||||
}
|
||||
|
||||
static void sprd_rx_full_thld(struct uart_port *port, u32 thld)
|
||||
{
|
||||
u32 val = serial_in(port, SPRD_CTL2);
|
||||
|
||||
val &= ~THLD_RX_FULL_MASK;
|
||||
val |= thld & THLD_RX_FULL_MASK;
|
||||
serial_out(port, SPRD_CTL2, val);
|
||||
}
|
||||
|
||||
static int sprd_rx_alloc_buf(struct sprd_uart_port *sp)
|
||||
{
|
||||
sp->rx_dma.virt = dma_alloc_coherent(sp->port.dev, SPRD_UART_RX_SIZE,
|
||||
&sp->rx_dma.phys_addr, GFP_KERNEL);
|
||||
if (!sp->rx_dma.virt)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sprd_rx_free_buf(struct sprd_uart_port *sp)
|
||||
{
|
||||
if (sp->rx_dma.virt)
|
||||
dma_free_coherent(sp->port.dev, SPRD_UART_RX_SIZE,
|
||||
sp->rx_dma.virt, sp->rx_dma.phys_addr);
|
||||
|
||||
}
|
||||
|
||||
static int sprd_rx_dma_config(struct uart_port *port, u32 burst)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct dma_slave_config cfg = {
|
||||
.src_addr = port->mapbase + SPRD_RXD,
|
||||
.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
|
||||
.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE,
|
||||
.src_maxburst = burst,
|
||||
};
|
||||
|
||||
return dmaengine_slave_config(sp->rx_dma.chn, &cfg);
|
||||
}
|
||||
|
||||
static void sprd_uart_dma_rx(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct tty_port *tty = &port->state->port;
|
||||
|
||||
port->icount.rx += sp->rx_dma.trans_len;
|
||||
tty_insert_flip_string(tty, sp->rx_buf_tail, sp->rx_dma.trans_len);
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
|
||||
static void sprd_uart_dma_irq(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct dma_tx_state state;
|
||||
enum dma_status status;
|
||||
|
||||
status = dmaengine_tx_status(sp->rx_dma.chn,
|
||||
sp->rx_dma.cookie, &state);
|
||||
if (status == DMA_ERROR)
|
||||
sprd_stop_rx(port);
|
||||
|
||||
if (!state.residue && sp->pos == sp->rx_dma.phys_addr)
|
||||
return;
|
||||
|
||||
if (!state.residue) {
|
||||
sp->rx_dma.trans_len = SPRD_UART_RX_SIZE +
|
||||
sp->rx_dma.phys_addr - sp->pos;
|
||||
sp->pos = sp->rx_dma.phys_addr;
|
||||
} else {
|
||||
sp->rx_dma.trans_len = state.residue - sp->pos;
|
||||
sp->pos = state.residue;
|
||||
}
|
||||
|
||||
sprd_uart_dma_rx(port);
|
||||
sp->rx_buf_tail += sp->rx_dma.trans_len;
|
||||
}
|
||||
|
||||
static void sprd_complete_rx_dma(void *data)
|
||||
{
|
||||
struct uart_port *port = (struct uart_port *)data;
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
struct dma_tx_state state;
|
||||
enum dma_status status;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
status = dmaengine_tx_status(sp->rx_dma.chn,
|
||||
sp->rx_dma.cookie, &state);
|
||||
if (status != DMA_COMPLETE) {
|
||||
sprd_stop_rx(port);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sp->pos != sp->rx_dma.phys_addr) {
|
||||
sp->rx_dma.trans_len = SPRD_UART_RX_SIZE +
|
||||
sp->rx_dma.phys_addr - sp->pos;
|
||||
sprd_uart_dma_rx(port);
|
||||
sp->rx_buf_tail += sp->rx_dma.trans_len;
|
||||
}
|
||||
|
||||
if (sprd_start_dma_rx(port))
|
||||
sprd_stop_rx(port);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
static int sprd_start_dma_rx(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
int ret;
|
||||
|
||||
if (!sp->rx_dma.enable)
|
||||
return 0;
|
||||
|
||||
sp->pos = sp->rx_dma.phys_addr;
|
||||
sp->rx_buf_tail = sp->rx_dma.virt;
|
||||
sprd_rx_full_thld(port, SPRD_RX_FIFO_FULL);
|
||||
ret = sprd_rx_dma_config(port, SPRD_RX_DMA_STEP);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return sprd_uart_dma_submit(port, &sp->rx_dma, SPRD_UART_RX_SIZE,
|
||||
DMA_DEV_TO_MEM, sprd_complete_rx_dma);
|
||||
}
|
||||
|
||||
static void sprd_release_dma(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
|
||||
sprd_uart_dma_enable(port, false);
|
||||
|
||||
if (sp->rx_dma.enable)
|
||||
dma_release_channel(sp->rx_dma.chn);
|
||||
|
||||
if (sp->tx_dma.enable)
|
||||
dma_release_channel(sp->tx_dma.chn);
|
||||
|
||||
sp->tx_dma.enable = false;
|
||||
sp->rx_dma.enable = false;
|
||||
}
|
||||
|
||||
static void sprd_request_dma(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
|
||||
sp->tx_dma.enable = true;
|
||||
sp->rx_dma.enable = true;
|
||||
|
||||
sp->tx_dma.chn = dma_request_chan(port->dev, "tx");
|
||||
if (IS_ERR(sp->tx_dma.chn)) {
|
||||
dev_err(port->dev, "request TX DMA channel failed, ret = %ld\n",
|
||||
PTR_ERR(sp->tx_dma.chn));
|
||||
sp->tx_dma.enable = false;
|
||||
}
|
||||
|
||||
sp->rx_dma.chn = dma_request_chan(port->dev, "rx");
|
||||
if (IS_ERR(sp->rx_dma.chn)) {
|
||||
dev_err(port->dev, "request RX DMA channel failed, ret = %ld\n",
|
||||
PTR_ERR(sp->rx_dma.chn));
|
||||
sp->rx_dma.enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void sprd_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port,
|
||||
port);
|
||||
unsigned int ien, iclr;
|
||||
|
||||
if (sp->tx_dma.enable) {
|
||||
sprd_stop_tx_dma(port);
|
||||
return;
|
||||
}
|
||||
|
||||
iclr = serial_in(port, SPRD_ICLR);
|
||||
ien = serial_in(port, SPRD_IEN);
|
||||
|
||||
iclr |= SPRD_IEN_TX_EMPTY;
|
||||
ien &= ~SPRD_IEN_TX_EMPTY;
|
||||
|
||||
serial_out(port, SPRD_IEN, ien);
|
||||
serial_out(port, SPRD_ICLR, iclr);
|
||||
}
|
||||
|
||||
static void sprd_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port,
|
||||
port);
|
||||
unsigned int ien;
|
||||
|
||||
if (sp->tx_dma.enable) {
|
||||
sprd_start_tx_dma(port);
|
||||
return;
|
||||
}
|
||||
|
||||
ien = serial_in(port, SPRD_IEN);
|
||||
if (!(ien & SPRD_IEN_TX_EMPTY)) {
|
||||
ien |= SPRD_IEN_TX_EMPTY;
|
||||
serial_out(port, SPRD_IEN, ien);
|
||||
}
|
||||
}
|
||||
|
||||
/* The Sprd serial does not support this function. */
|
||||
static void sprd_break_ctl(struct uart_port *port, int break_state)
|
||||
{
|
||||
@ -218,9 +590,16 @@ static int handle_lsr_errors(struct uart_port *port,
|
||||
|
||||
static inline void sprd_rx(struct uart_port *port)
|
||||
{
|
||||
struct sprd_uart_port *sp = container_of(port, struct sprd_uart_port,
|
||||
port);
|
||||
struct tty_port *tty = &port->state->port;
|
||||
unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT;
|
||||
|
||||
if (sp->rx_dma.enable) {
|
||||
sprd_uart_dma_irq(port);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK) &&
|
||||
max_count--) {
|
||||
lsr = serial_in(port, SPRD_LSR);
|
||||
@ -304,6 +683,25 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void sprd_uart_dma_startup(struct uart_port *port,
|
||||
struct sprd_uart_port *sp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sprd_request_dma(port);
|
||||
if (!(sp->rx_dma.enable || sp->tx_dma.enable))
|
||||
return;
|
||||
|
||||
ret = sprd_start_dma_rx(port);
|
||||
if (ret) {
|
||||
sp->rx_dma.enable = false;
|
||||
dma_release_channel(sp->rx_dma.chn);
|
||||
dev_warn(port->dev, "fail to start RX dma mode\n");
|
||||
}
|
||||
|
||||
sprd_uart_dma_enable(port, true);
|
||||
}
|
||||
|
||||
static int sprd_startup(struct uart_port *port)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -332,6 +730,9 @@ static int sprd_startup(struct uart_port *port)
|
||||
/* allocate irq */
|
||||
sp = container_of(port, struct sprd_uart_port, port);
|
||||
snprintf(sp->name, sizeof(sp->name), "sprd_serial%d", port->line);
|
||||
|
||||
sprd_uart_dma_startup(port, sp);
|
||||
|
||||
ret = devm_request_irq(port->dev, port->irq, sprd_handle_irq,
|
||||
IRQF_SHARED, sp->name, port);
|
||||
if (ret) {
|
||||
@ -346,7 +747,9 @@ static int sprd_startup(struct uart_port *port)
|
||||
/* enable interrupt */
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
ien = serial_in(port, SPRD_IEN);
|
||||
ien |= SPRD_IEN_RX_FULL | SPRD_IEN_BREAK_DETECT | SPRD_IEN_TIMEOUT;
|
||||
ien |= SPRD_IEN_BREAK_DETECT | SPRD_IEN_TIMEOUT;
|
||||
if (!sp->rx_dma.enable)
|
||||
ien |= SPRD_IEN_RX_FULL;
|
||||
serial_out(port, SPRD_IEN, ien);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
@ -355,6 +758,7 @@ static int sprd_startup(struct uart_port *port)
|
||||
|
||||
static void sprd_shutdown(struct uart_port *port)
|
||||
{
|
||||
sprd_release_dma(port);
|
||||
serial_out(port, SPRD_IEN, 0);
|
||||
serial_out(port, SPRD_ICLR, ~0);
|
||||
devm_free_irq(port->dev, port->irq, port);
|
||||
@ -491,6 +895,22 @@ static int sprd_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sprd_pm(struct uart_port *port, unsigned int state,
|
||||
unsigned int oldstate)
|
||||
{
|
||||
struct sprd_uart_port *sup =
|
||||
container_of(port, struct sprd_uart_port, port);
|
||||
|
||||
switch (state) {
|
||||
case UART_PM_STATE_ON:
|
||||
clk_prepare_enable(sup->clk);
|
||||
break;
|
||||
case UART_PM_STATE_OFF:
|
||||
clk_disable_unprepare(sup->clk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct uart_ops serial_sprd_ops = {
|
||||
.tx_empty = sprd_tx_empty,
|
||||
.get_mctrl = sprd_get_mctrl,
|
||||
@ -507,6 +927,7 @@ static const struct uart_ops serial_sprd_ops = {
|
||||
.request_port = sprd_request_port,
|
||||
.config_port = sprd_config_port,
|
||||
.verify_port = sprd_verify_port,
|
||||
.pm = sprd_pm,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SERIAL_SPRD_CONSOLE
|
||||
@ -668,6 +1089,43 @@ static int sprd_remove(struct platform_device *dev)
|
||||
if (!sprd_ports_num)
|
||||
uart_unregister_driver(&sprd_uart_driver);
|
||||
|
||||
sprd_rx_free_buf(sup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sprd_clk_init(struct uart_port *uport)
|
||||
{
|
||||
struct clk *clk_uart, *clk_parent;
|
||||
struct sprd_uart_port *u = sprd_port[uport->line];
|
||||
|
||||
clk_uart = devm_clk_get(uport->dev, "uart");
|
||||
if (IS_ERR(clk_uart)) {
|
||||
dev_warn(uport->dev, "uart%d can't get uart clock\n",
|
||||
uport->line);
|
||||
clk_uart = NULL;
|
||||
}
|
||||
|
||||
clk_parent = devm_clk_get(uport->dev, "source");
|
||||
if (IS_ERR(clk_parent)) {
|
||||
dev_warn(uport->dev, "uart%d can't get source clock\n",
|
||||
uport->line);
|
||||
clk_parent = NULL;
|
||||
}
|
||||
|
||||
if (!clk_uart || clk_set_parent(clk_uart, clk_parent))
|
||||
uport->uartclk = SPRD_DEFAULT_SOURCE_CLK;
|
||||
else
|
||||
uport->uartclk = clk_get_rate(clk_uart);
|
||||
|
||||
u->clk = devm_clk_get(uport->dev, "enable");
|
||||
if (IS_ERR(u->clk)) {
|
||||
if (PTR_ERR(u->clk) != -EPROBE_DEFER)
|
||||
dev_err(uport->dev, "uart%d can't get enable clock\n",
|
||||
uport->line);
|
||||
return PTR_ERR(u->clk);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -675,7 +1133,6 @@ static int sprd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
struct uart_port *up;
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
int index;
|
||||
int ret;
|
||||
@ -704,9 +1161,9 @@ static int sprd_probe(struct platform_device *pdev)
|
||||
up->ops = &serial_sprd_ops;
|
||||
up->flags = UPF_BOOT_AUTOCONF;
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (!IS_ERR_OR_NULL(clk))
|
||||
up->uartclk = clk_get_rate(clk);
|
||||
ret = sprd_clk_init(up);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
up->membase = devm_ioremap_resource(&pdev->dev, res);
|
||||
@ -722,6 +1179,14 @@ static int sprd_probe(struct platform_device *pdev)
|
||||
}
|
||||
up->irq = irq;
|
||||
|
||||
/*
|
||||
* Allocate one dma buffer to prepare for receive transfer, in case
|
||||
* memory allocation failure at runtime.
|
||||
*/
|
||||
ret = sprd_rx_alloc_buf(sprd_port[index]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!sprd_ports_num) {
|
||||
ret = uart_register_driver(&sprd_uart_driver);
|
||||
if (ret < 0) {
|
||||
|
@ -1081,7 +1081,7 @@ static int qe_uart_verify_port(struct uart_port *port,
|
||||
}
|
||||
/* UART operations
|
||||
*
|
||||
* Details on these functions can be found in Documentation/serial/driver
|
||||
* Details on these functions can be found in Documentation/serial/driver.rst
|
||||
*/
|
||||
static const struct uart_ops qe_uart_pops = {
|
||||
.tx_empty = qe_uart_tx_empty,
|
||||
|
@ -193,6 +193,7 @@ struct cdns_uart {
|
||||
int id;
|
||||
struct notifier_block clk_rate_change_nb;
|
||||
u32 quirks;
|
||||
bool cts_override;
|
||||
};
|
||||
struct cdns_platform_data {
|
||||
u32 quirks;
|
||||
@ -1000,6 +1001,11 @@ static void cdns_uart_config_port(struct uart_port *port, int flags)
|
||||
*/
|
||||
static unsigned int cdns_uart_get_mctrl(struct uart_port *port)
|
||||
{
|
||||
struct cdns_uart *cdns_uart_data = port->private_data;
|
||||
|
||||
if (cdns_uart_data->cts_override)
|
||||
return 0;
|
||||
|
||||
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
|
||||
}
|
||||
|
||||
@ -1007,6 +1013,10 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||||
{
|
||||
u32 val;
|
||||
u32 mode_reg;
|
||||
struct cdns_uart *cdns_uart_data = port->private_data;
|
||||
|
||||
if (cdns_uart_data->cts_override)
|
||||
return;
|
||||
|
||||
val = readl(port->membase + CDNS_UART_MODEMCR);
|
||||
mode_reg = readl(port->membase + CDNS_UART_MR);
|
||||
@ -1665,6 +1675,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
|
||||
console_port = NULL;
|
||||
#endif
|
||||
|
||||
cdns_uart_data->cts_override = of_property_read_bool(pdev->dev.of_node,
|
||||
"cts-override");
|
||||
return 0;
|
||||
|
||||
err_out_pm_disable:
|
||||
|
@ -208,7 +208,7 @@ static struct sysrq_key_op sysrq_showlocks_op = {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static DEFINE_SPINLOCK(show_lock);
|
||||
static DEFINE_RAW_SPINLOCK(show_lock);
|
||||
|
||||
static void showacpu(void *dummy)
|
||||
{
|
||||
@ -218,10 +218,10 @@ static void showacpu(void *dummy)
|
||||
if (idle_cpu(smp_processor_id()))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&show_lock, flags);
|
||||
raw_spin_lock_irqsave(&show_lock, flags);
|
||||
pr_info("CPU%d:\n", smp_processor_id());
|
||||
show_stack(NULL, NULL);
|
||||
spin_unlock_irqrestore(&show_lock, flags);
|
||||
raw_spin_unlock_irqrestore(&show_lock, flags);
|
||||
}
|
||||
|
||||
static void sysrq_showregs_othercpus(struct work_struct *dummy)
|
||||
|
@ -1173,7 +1173,7 @@ static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver,
|
||||
* tty_init_termios - helper for termios setup
|
||||
* @tty: the tty to set up
|
||||
*
|
||||
* Initialise the termios structures for this tty. Thus runs under
|
||||
* Initialise the termios structure for this tty. This runs under
|
||||
* the tty_mutex currently so we can be relaxed about ordering.
|
||||
*/
|
||||
|
||||
|
@ -44,7 +44,7 @@ int __tty_check_change(struct tty_struct *tty, int sig)
|
||||
tty_pgrp = tty->pgrp;
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
|
||||
if (tty_pgrp && pgrp != tty->pgrp) {
|
||||
if (tty_pgrp && pgrp != tty_pgrp) {
|
||||
if (is_ignored(sig)) {
|
||||
if (sig == SIGTTIN)
|
||||
ret = -EIO;
|
||||
@ -313,7 +313,7 @@ void disassociate_ctty(int on_exit)
|
||||
read_unlock(&tasklist_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
*
|
||||
* no_tty - Ensure the current process does not have a controlling tty
|
||||
*/
|
||||
|
@ -325,7 +325,7 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty)
|
||||
if (tty && C_HUPCL(tty))
|
||||
tty_port_lower_dtr_rts(port);
|
||||
|
||||
if (port->ops && port->ops->shutdown)
|
||||
if (port->ops->shutdown)
|
||||
port->ops->shutdown(port);
|
||||
}
|
||||
out:
|
||||
@ -398,7 +398,7 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
|
||||
*/
|
||||
int tty_port_carrier_raised(struct tty_port *port)
|
||||
{
|
||||
if (!port->ops || !port->ops->carrier_raised)
|
||||
if (port->ops->carrier_raised == NULL)
|
||||
return 1;
|
||||
return port->ops->carrier_raised(port);
|
||||
}
|
||||
@ -414,7 +414,7 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
|
||||
*/
|
||||
void tty_port_raise_dtr_rts(struct tty_port *port)
|
||||
{
|
||||
if (port->ops && port->ops->dtr_rts)
|
||||
if (port->ops->dtr_rts)
|
||||
port->ops->dtr_rts(port, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_raise_dtr_rts);
|
||||
@ -429,7 +429,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
|
||||
*/
|
||||
void tty_port_lower_dtr_rts(struct tty_port *port)
|
||||
{
|
||||
if (port->ops && port->ops->dtr_rts)
|
||||
if (port->ops->dtr_rts)
|
||||
port->ops->dtr_rts(port, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_lower_dtr_rts);
|
||||
@ -684,7 +684,7 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty,
|
||||
|
||||
if (!tty_port_initialized(port)) {
|
||||
clear_bit(TTY_IO_ERROR, &tty->flags);
|
||||
if (port->ops && port->ops->activate) {
|
||||
if (port->ops->activate) {
|
||||
int retval = port->ops->activate(port, tty);
|
||||
if (retval) {
|
||||
mutex_unlock(&port->mutex);
|
||||
|
109
drivers/tty/ttynull.c
Normal file
109
drivers/tty/ttynull.c
Normal file
@ -0,0 +1,109 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2019 Axis Communications AB
|
||||
*
|
||||
* Based on ttyprintk.c:
|
||||
* Copyright (C) 2010 Samo Pogacnik
|
||||
*/
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/tty.h>
|
||||
|
||||
static const struct tty_port_operations ttynull_port_ops;
|
||||
static struct tty_driver *ttynull_driver;
|
||||
static struct tty_port ttynull_port;
|
||||
|
||||
static int ttynull_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
return tty_port_open(&ttynull_port, tty, filp);
|
||||
}
|
||||
|
||||
static void ttynull_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
tty_port_close(&ttynull_port, tty, filp);
|
||||
}
|
||||
|
||||
static void ttynull_hangup(struct tty_struct *tty)
|
||||
{
|
||||
tty_port_hangup(&ttynull_port);
|
||||
}
|
||||
|
||||
static int ttynull_write(struct tty_struct *tty, const unsigned char *buf,
|
||||
int count)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
static int ttynull_write_room(struct tty_struct *tty)
|
||||
{
|
||||
return 65536;
|
||||
}
|
||||
|
||||
static const struct tty_operations ttynull_ops = {
|
||||
.open = ttynull_open,
|
||||
.close = ttynull_close,
|
||||
.hangup = ttynull_hangup,
|
||||
.write = ttynull_write,
|
||||
.write_room = ttynull_write_room,
|
||||
};
|
||||
|
||||
static struct tty_driver *ttynull_device(struct console *c, int *index)
|
||||
{
|
||||
*index = 0;
|
||||
return ttynull_driver;
|
||||
}
|
||||
|
||||
static struct console ttynull_console = {
|
||||
.name = "ttynull",
|
||||
.device = ttynull_device,
|
||||
};
|
||||
|
||||
static int __init ttynull_init(void)
|
||||
{
|
||||
struct tty_driver *driver;
|
||||
int ret;
|
||||
|
||||
driver = tty_alloc_driver(1,
|
||||
TTY_DRIVER_RESET_TERMIOS |
|
||||
TTY_DRIVER_REAL_RAW |
|
||||
TTY_DRIVER_UNNUMBERED_NODE);
|
||||
if (IS_ERR(driver))
|
||||
return PTR_ERR(driver);
|
||||
|
||||
tty_port_init(&ttynull_port);
|
||||
ttynull_port.ops = &ttynull_port_ops;
|
||||
|
||||
driver->driver_name = "ttynull";
|
||||
driver->name = "ttynull";
|
||||
driver->type = TTY_DRIVER_TYPE_CONSOLE;
|
||||
driver->init_termios = tty_std_termios;
|
||||
driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
|
||||
tty_set_operations(driver, &ttynull_ops);
|
||||
tty_port_link_device(&ttynull_port, driver, 0);
|
||||
|
||||
ret = tty_register_driver(driver);
|
||||
if (ret < 0) {
|
||||
put_tty_driver(driver);
|
||||
tty_port_destroy(&ttynull_port);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ttynull_driver = driver;
|
||||
register_console(&ttynull_console);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ttynull_exit(void)
|
||||
{
|
||||
unregister_console(&ttynull_console);
|
||||
tty_unregister_driver(ttynull_driver);
|
||||
put_tty_driver(ttynull_driver);
|
||||
tty_port_destroy(&ttynull_port);
|
||||
}
|
||||
|
||||
module_init(ttynull_init);
|
||||
module_exit(ttynull_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* vcc.c: sun4v virtual channel concentrator
|
||||
*
|
||||
* Copyright (C) 2017 Oracle. All rights reserved.
|
||||
|
1
drivers/tty/vt/.gitignore
vendored
1
drivers/tty/vt/.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
consolemap_deftbl.c
|
||||
defkeymap.c
|
||||
|
@ -542,7 +542,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
if (!ct)
|
||||
return 0;
|
||||
|
||||
unilist = memdup_user(list, ct * sizeof(struct unipair));
|
||||
unilist = vmemdup_user(list, ct * sizeof(struct unipair));
|
||||
if (IS_ERR(unilist))
|
||||
return PTR_ERR(unilist);
|
||||
|
||||
@ -641,7 +641,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
|
||||
|
||||
out_unlock:
|
||||
console_unlock();
|
||||
kfree(unilist);
|
||||
kvfree(unilist);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -743,7 +743,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
|
||||
struct uni_pagedir *p;
|
||||
struct unipair *unilist;
|
||||
|
||||
unilist = kmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
|
||||
unilist = kvmalloc_array(ct, sizeof(struct unipair), GFP_KERNEL);
|
||||
if (!unilist)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -775,7 +775,7 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
|
||||
if (copy_to_user(list, unilist, min(ect, ct) * sizeof(struct unipair)))
|
||||
ret = -EFAULT;
|
||||
put_user(ect, uct);
|
||||
kfree(unilist);
|
||||
kvfree(unilist);
|
||||
return ret ? ret : (ect <= ct) ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Unicode table for IBM Codepage 437. Note that there are many more
|
||||
# substitutions that could be conceived (for example, thick-line
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Do not edit this file! It was automatically generated by */
|
||||
/* loadkeys --mktable defkeymap.map > defkeymap.c */
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Default kernel keymap. This uses 7 modifier combinations.
|
||||
keymaps 0-2,4-5,8,12
|
||||
# Change the above line into
|
||||
|
@ -123,6 +123,7 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals);
|
||||
static struct input_handler kbd_handler;
|
||||
static DEFINE_SPINLOCK(kbd_event_lock);
|
||||
static DEFINE_SPINLOCK(led_lock);
|
||||
static DEFINE_SPINLOCK(func_buf_lock); /* guard 'func_buf' and friends */
|
||||
static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
|
||||
static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
|
||||
static bool dead_key_next;
|
||||
@ -1449,7 +1450,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
|
||||
KBD_UNICODE, ¶m);
|
||||
if (rc != NOTIFY_STOP)
|
||||
if (down && !raw_mode)
|
||||
to_utf8(vc, keysym);
|
||||
k_unicode(vc, keysym, !down);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1990,11 +1991,12 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
||||
char *p;
|
||||
u_char *q;
|
||||
u_char __user *up;
|
||||
int sz;
|
||||
int sz, fnw_sz;
|
||||
int delta;
|
||||
char *first_free, *fj, *fnw;
|
||||
int i, j, k;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
if (!capable(CAP_SYS_TTY_CONFIG))
|
||||
perm = 0;
|
||||
@ -2037,7 +2039,14 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
||||
goto reterr;
|
||||
}
|
||||
|
||||
fnw = NULL;
|
||||
fnw_sz = 0;
|
||||
/* race aginst other writers */
|
||||
again:
|
||||
spin_lock_irqsave(&func_buf_lock, flags);
|
||||
q = func_table[i];
|
||||
|
||||
/* fj pointer to next entry after 'q' */
|
||||
first_free = funcbufptr + (funcbufsize - funcbufleft);
|
||||
for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++)
|
||||
;
|
||||
@ -2045,10 +2054,12 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
||||
fj = func_table[j];
|
||||
else
|
||||
fj = first_free;
|
||||
|
||||
/* buffer usage increase by new entry */
|
||||
delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string);
|
||||
|
||||
if (delta <= funcbufleft) { /* it fits in current buf */
|
||||
if (j < MAX_NR_FUNC) {
|
||||
/* make enough space for new entry at 'fj' */
|
||||
memmove(fj + delta, fj, first_free - fj);
|
||||
for (k = j; k < MAX_NR_FUNC; k++)
|
||||
if (func_table[k])
|
||||
@ -2061,20 +2072,28 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
||||
sz = 256;
|
||||
while (sz < funcbufsize - funcbufleft + delta)
|
||||
sz <<= 1;
|
||||
fnw = kmalloc(sz, GFP_KERNEL);
|
||||
if(!fnw) {
|
||||
ret = -ENOMEM;
|
||||
goto reterr;
|
||||
if (fnw_sz != sz) {
|
||||
spin_unlock_irqrestore(&func_buf_lock, flags);
|
||||
kfree(fnw);
|
||||
fnw = kmalloc(sz, GFP_KERNEL);
|
||||
fnw_sz = sz;
|
||||
if (!fnw) {
|
||||
ret = -ENOMEM;
|
||||
goto reterr;
|
||||
}
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (!q)
|
||||
func_table[i] = fj;
|
||||
/* copy data before insertion point to new location */
|
||||
if (fj > funcbufptr)
|
||||
memmove(fnw, funcbufptr, fj - funcbufptr);
|
||||
for (k = 0; k < j; k++)
|
||||
if (func_table[k])
|
||||
func_table[k] = fnw + (func_table[k] - funcbufptr);
|
||||
|
||||
/* copy data after insertion point to new location */
|
||||
if (first_free > fj) {
|
||||
memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj);
|
||||
for (k = j; k < MAX_NR_FUNC; k++)
|
||||
@ -2087,7 +2106,9 @@ int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm)
|
||||
funcbufleft = funcbufleft - delta + sz - funcbufsize;
|
||||
funcbufsize = sz;
|
||||
}
|
||||
/* finally insert item itself */
|
||||
strcpy(func_table[i], kbs->kb_string);
|
||||
spin_unlock_irqrestore(&func_buf_lock, flags);
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Provide access to virtual console memory.
|
||||
* /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
|
||||
* /dev/vcs: the screen as it is being viewed right now (possibly scrolled)
|
||||
* /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
|
||||
* [minor: N]
|
||||
*
|
||||
|
@ -4180,8 +4180,6 @@ void do_blank_screen(int entering_gfx)
|
||||
return;
|
||||
}
|
||||
|
||||
if (blank_state != blank_normal_wait)
|
||||
return;
|
||||
blank_state = blank_off;
|
||||
|
||||
/* don't blank graphics */
|
||||
|
@ -45,7 +45,7 @@ struct device;
|
||||
|
||||
/*
|
||||
* This structure describes all the operations that can be done on the
|
||||
* physical hardware. See Documentation/serial/driver for details.
|
||||
* physical hardware. See Documentation/serial/driver.rst for details.
|
||||
*/
|
||||
struct uart_ops {
|
||||
unsigned int (*tx_empty)(struct uart_port *);
|
||||
|
@ -287,4 +287,10 @@
|
||||
/* RDA UART */
|
||||
#define PORT_RDA 118
|
||||
|
||||
/* Socionext Milbeaut UART */
|
||||
#define PORT_MLB_USIO 119
|
||||
|
||||
/* SiFive UART */
|
||||
#define PORT_SIFIVE_V0 120
|
||||
|
||||
#endif /* _UAPILINUX_SERIAL_CORE_H */
|
||||
|
Loading…
Reference in New Issue
Block a user