TTY/Serial driver changes for 6.2-rc1
Here is the "big" set of tty/serial driver changes for 6.2-rc1. As in previous kernel releases, nothing big here at all, just some small incremental serial/tty layer cleanups and some individual driver additions and fixes. Highlights are: - serial helper macros from Jiri Slaby to reduce the amount of duplicated code in serial drivers - api cleanups and consolidations from Ilpo Järvinen in lots of serial drivers - the usual set of n_gsm fixes from Daniel Starke as that code gets exercised more - TIOCSTI is finally able to be disabled if requested (security hardening feature from Kees Cook) - fsl_lpuart driver fixes and features added - other small serial driver additions and fixes All of these have been in linux-next for a while with no reported problems. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCY5wt5A8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ynSiACffLCC9SFnP1ClJJh73OpCN11alDAAoIfMct2A /zrJ4on7o0YQU1Ilg2+k =eD/I -----END PGP SIGNATURE----- Merge tag 'tty-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty Pull tty/serial driver updates from Greg KH: "Here is the "big" set of tty/serial driver changes for 6.2-rc1. As in previous kernel releases, nothing big here at all, just some small incremental serial/tty layer cleanups and some individual driver additions and fixes. Highlights are: - serial helper macros from Jiri Slaby to reduce the amount of duplicated code in serial drivers - api cleanups and consolidations from Ilpo Järvinen in lots of serial drivers - the usual set of n_gsm fixes from Daniel Starke as that code gets exercised more - TIOCSTI is finally able to be disabled if requested (security hardening feature from Kees Cook) - fsl_lpuart driver fixes and features added - other small serial driver additions and fixes All of these have been in linux-next for a while with no reported problems" * tag 'tty-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (97 commits) serial: atmel: don't stop the transmitter when doing PIO serial: atmel: cleanup atmel_start+stop_tx() tty: serial: fsl_lpuart: switch to new dmaengine_terminate_* API serial: sunsab: Fix error handling in sunsab_init() serial: altera_uart: fix locking in polling mode serial: pch: Fix PCI device refcount leak in pch_request_dma() tty: serial: fsl_lpuart: Use pm_ptr() to avoid need to make pm __maybe_unused tty: serial: fsl_lpuart: Add runtime pm support tty: serial: fsl_lpuart: enable wakeup source for lpuart serdev: Replace poll loop by readx_poll_timeout() macro tty: synclink_gt: unwind actions in error path of net device open serial: stm32: move dma_request_chan() before clk_prepare_enable() dt-bindings: serial: xlnx,opb-uartlite: Drop 'contains' from 'xlnx,use-parity' serial: pl011: Do not clear RX FIFO & RX interrupt in unthrottle. serial: amba-pl011: avoid SBSA UART accessing DMACR register tty: serial: altera_jtaguart: remove struct altera_jtaguart tty: serial: altera_jtaguart: use uart_port::read_status_mask tty: serial: altera_jtaguart: remove unused altera_jtaguart::sigs tty: serial: altera_jtaguart: remove flag from altera_jtaguart_rx_chars() n_tty: Rename tail to old_tail in n_tty_read() ...
This commit is contained in:
Коммит
dd6f9b17cd
|
@ -20,6 +20,7 @@ properties:
|
|||
oneOf:
|
||||
- enum:
|
||||
- ingenic,jz4740-uart
|
||||
- ingenic,jz4750-uart
|
||||
- ingenic,jz4760-uart
|
||||
- ingenic,jz4780-uart
|
||||
- ingenic,x1000-uart
|
||||
|
@ -31,6 +32,9 @@ properties:
|
|||
- items:
|
||||
- const: ingenic,jz4725b-uart
|
||||
- const: ingenic,jz4740-uart
|
||||
- items:
|
||||
- const: ingenic,jz4755-uart
|
||||
- const: ingenic,jz4750-uart
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
@ -67,6 +67,7 @@ properties:
|
|||
- enum:
|
||||
- renesas,scif-r8a779a0 # R-Car V3U
|
||||
- renesas,scif-r8a779f0 # R-Car S4-8
|
||||
- renesas,scif-r8a779g0 # R-Car V4H
|
||||
- const: renesas,rcar-gen4-scif # R-Car Gen4
|
||||
- const: renesas,scif # generic SCIF compatible UART
|
||||
|
||||
|
|
|
@ -67,8 +67,7 @@ allOf:
|
|||
- if:
|
||||
properties:
|
||||
xlnx,use-parity:
|
||||
contains:
|
||||
const: 1
|
||||
const: 1
|
||||
then:
|
||||
required:
|
||||
- xlnx,odd-parity
|
||||
|
|
|
@ -78,6 +78,9 @@ Other functions
|
|||
uart_get_lsr_info uart_handle_dcd_change uart_handle_cts_change
|
||||
uart_try_toggle_sysrq uart_get_console
|
||||
|
||||
.. kernel-doc:: include/linux/serial_core.h
|
||||
:identifiers: uart_port_tx_limited uart_port_tx
|
||||
|
||||
Other notes
|
||||
-----------
|
||||
|
||||
|
|
|
@ -29,23 +29,28 @@ RS485 Serial Communications
|
|||
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
|
||||
The Linux kernel provides the struct serial_rs485 to handle RS485
|
||||
communications. This data structure is used to set and configure RS485
|
||||
parameters in the platform data and in ioctls.
|
||||
|
||||
The device tree can also provide RS485 boot time parameters (see [2]
|
||||
for bindings). The driver is in charge of filling this data structure from
|
||||
the values given by the device tree.
|
||||
The device tree can also provide RS485 boot time parameters
|
||||
[#DT-bindings]_. The serial core fills the struct serial_rs485 from the
|
||||
values given by the device tree when the driver calls
|
||||
uart_get_rs485_mode().
|
||||
|
||||
Any driver for devices capable of working both as RS232 and RS485 should
|
||||
implement the rs485_config callback and provide rs485_supported in the
|
||||
uart_port structure. The serial core calls rs485_config to do the device
|
||||
specific part in response to TIOCSRS485 ioctl (see below). The rs485_config
|
||||
callback receives a pointer to a sanitizated serial_rs485 structure. The
|
||||
serial_rs485 userspace provides is sanitized before calling rs485_config
|
||||
using rs485_supported that indicates what RS485 features the driver supports
|
||||
for the uart_port. TIOCGRS485 ioctl can be used to read back the
|
||||
serial_rs485 structure matching to the current configuration.
|
||||
implement the ``rs485_config`` callback and provide ``rs485_supported``
|
||||
in the ``struct uart_port``. The serial core calls ``rs485_config`` to do
|
||||
the device specific part in response to TIOCSRS485 ioctl (see below). The
|
||||
``rs485_config`` callback receives a pointer to a sanitizated struct
|
||||
serial_rs485. The struct serial_rs485 userspace provides is sanitized
|
||||
before calling ``rs485_config`` using ``rs485_supported`` that indicates
|
||||
what RS485 features the driver supports for the ``struct uart_port``.
|
||||
TIOCGRS485 ioctl can be used to read back the struct serial_rs485
|
||||
matching to the current configuration.
|
||||
|
||||
.. kernel-doc:: include/uapi/linux/serial.h
|
||||
:identifiers: serial_rs485 uart_get_rs485_mode
|
||||
|
||||
4. Usage from user-level
|
||||
========================
|
||||
|
@ -103,29 +108,28 @@ RS485 Serial Communications
|
|||
========================
|
||||
|
||||
The Linux kernel provides addressing mode for multipoint RS-485 serial
|
||||
communications line. The addressing mode is enabled with SER_RS485_ADDRB
|
||||
flag in serial_rs485. Struct serial_rs485 has two additional flags and
|
||||
fields for enabling receive and destination addresses.
|
||||
communications line. The addressing mode is enabled with
|
||||
``SER_RS485_ADDRB`` flag in struct serial_rs485. The struct serial_rs485
|
||||
has two additional flags and fields for enabling receive and destination
|
||||
addresses.
|
||||
|
||||
Address mode flags:
|
||||
- SER_RS485_ADDRB: Enabled addressing mode (sets also ADDRB in termios).
|
||||
- SER_RS485_ADDR_RECV: Receive (filter) address enabled.
|
||||
- SER_RS485_ADDR_DEST: Set destination address.
|
||||
- ``SER_RS485_ADDRB``: Enabled addressing mode (sets also ADDRB in termios).
|
||||
- ``SER_RS485_ADDR_RECV``: Receive (filter) address enabled.
|
||||
- ``SER_RS485_ADDR_DEST``: Set destination address.
|
||||
|
||||
Address fields (enabled with corresponding SER_RS485_ADDR_* flag):
|
||||
- addr_recv: Receive address.
|
||||
- addr_dest: Destination address.
|
||||
Address fields (enabled with corresponding ``SER_RS485_ADDR_*`` flag):
|
||||
- ``addr_recv``: Receive address.
|
||||
- ``addr_dest``: Destination address.
|
||||
|
||||
Once a receive address is set, the communication can occur only with the
|
||||
particular device and other peers are filtered out. It is left up to the
|
||||
receiver side to enforce the filtering. Receive address will be cleared
|
||||
if SER_RS485_ADDR_RECV is not set.
|
||||
if ``SER_RS485_ADDR_RECV`` is not set.
|
||||
|
||||
Note: not all devices supporting RS485 support multipoint addressing.
|
||||
|
||||
6. References
|
||||
=============
|
||||
|
||||
[1] include/uapi/linux/serial.h
|
||||
|
||||
[2] Documentation/devicetree/bindings/serial/rs485.txt
|
||||
.. [#DT-bindings] Documentation/devicetree/bindings/serial/rs485.txt
|
||||
|
|
|
@ -149,6 +149,25 @@ config LEGACY_PTY_COUNT
|
|||
When not in use, each legacy PTY occupies 12 bytes on 32-bit
|
||||
architectures and 24 bytes on 64-bit architectures.
|
||||
|
||||
config LEGACY_TIOCSTI
|
||||
bool "Allow legacy TIOCSTI usage"
|
||||
default y
|
||||
help
|
||||
Historically the kernel has allowed TIOCSTI, which will push
|
||||
characters into a controlling TTY. This continues to be used
|
||||
as a malicious privilege escalation mechanism, and provides no
|
||||
meaningful real-world utility any more. Its use is considered
|
||||
a dangerous legacy operation, and can be disabled on most
|
||||
systems.
|
||||
|
||||
Say 'Y here only if you have confirmed that your system's
|
||||
userspace depends on this functionality to continue operating
|
||||
normally.
|
||||
|
||||
This functionality can be changed at runtime with the
|
||||
dev.tty.legacy_tiocsti sysctl. This configuration option sets
|
||||
the default value of the sysctl.
|
||||
|
||||
config LDISC_AUTOLOAD
|
||||
bool "Automatically load TTY Line Disciplines"
|
||||
default y
|
||||
|
|
|
@ -118,7 +118,7 @@ static int find_console_handle(void)
|
|||
return 0;
|
||||
|
||||
stdout_irq = irq_of_parse_and_map(np, 0);
|
||||
if (stdout_irq == NO_IRQ) {
|
||||
if (!stdout_irq) {
|
||||
pr_err("ehv-bc: no 'interrupts' property in %pOF node\n", np);
|
||||
return 0;
|
||||
}
|
||||
|
@ -696,7 +696,7 @@ static int ehv_bc_tty_probe(struct platform_device *pdev)
|
|||
|
||||
bc->rx_irq = irq_of_parse_and_map(np, 0);
|
||||
bc->tx_irq = irq_of_parse_and_map(np, 1);
|
||||
if ((bc->rx_irq == NO_IRQ) || (bc->tx_irq == NO_IRQ)) {
|
||||
if (!bc->rx_irq || !bc->tx_irq) {
|
||||
dev_err(&pdev->dev, "no 'interrupts' property in %pOFn node\n",
|
||||
np);
|
||||
ret = -ENODEV;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "hvc_console.h"
|
||||
|
||||
#define hvc_rtas_cookie 0x67781e15
|
||||
struct hvc_struct *hvc_rtas_dev;
|
||||
static struct hvc_struct *hvc_rtas_dev;
|
||||
|
||||
static int rtascons_put_char_token = RTAS_UNKNOWN_SERVICE;
|
||||
static int rtascons_get_char_token = RTAS_UNKNOWN_SERVICE;
|
||||
|
|
|
@ -38,8 +38,10 @@
|
|||
#include <linux/sched/signal.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/math.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
|
@ -75,7 +77,12 @@ module_param(debug, int, 0600);
|
|||
|
||||
#define T1 10 /* 100mS */
|
||||
#define T2 34 /* 333mS */
|
||||
#define T3 10 /* 10s */
|
||||
#define N2 3 /* Retry 3 times */
|
||||
#define K 2 /* outstanding I frames */
|
||||
|
||||
#define MAX_T3 255 /* In seconds. */
|
||||
#define MAX_WINDOW_SIZE 7 /* Limit of K in error recovery mode. */
|
||||
|
||||
/* Use long timers for testing at low speed with debug on */
|
||||
#ifdef DEBUG_TIMING
|
||||
|
@ -89,6 +96,7 @@ module_param(debug, int, 0600);
|
|||
*/
|
||||
#define MAX_MRU 1500
|
||||
#define MAX_MTU 1500
|
||||
#define MIN_MTU (PROT_OVERHEAD + 1)
|
||||
/* SOF, ADDR, CTRL, LEN1, LEN2, ..., FCS, EOF */
|
||||
#define PROT_OVERHEAD 7
|
||||
#define GSM_NET_TX_TIMEOUT (HZ*10)
|
||||
|
@ -120,6 +128,7 @@ struct gsm_msg {
|
|||
|
||||
enum gsm_dlci_state {
|
||||
DLCI_CLOSED,
|
||||
DLCI_CONFIGURE, /* Sending PN (for adaption > 1) */
|
||||
DLCI_OPENING, /* Sending SABM not seen UA */
|
||||
DLCI_OPEN, /* SABM/UA complete */
|
||||
DLCI_CLOSING, /* Sending DISC not seen UA/DM */
|
||||
|
@ -159,7 +168,12 @@ struct gsm_dlci {
|
|||
int prev_adaption;
|
||||
u32 modem_rx; /* Our incoming virtual modem lines */
|
||||
u32 modem_tx; /* Our outgoing modem lines */
|
||||
unsigned int mtu;
|
||||
bool dead; /* Refuse re-open */
|
||||
/* Configuration */
|
||||
u8 prio; /* Priority */
|
||||
u8 ftype; /* Frame type */
|
||||
u8 k; /* Window size */
|
||||
/* Flow control */
|
||||
bool throttled; /* Private copy of throttle state */
|
||||
bool constipated; /* Throttle status for outgoing */
|
||||
|
@ -172,6 +186,32 @@ struct gsm_dlci {
|
|||
struct net_device *net; /* network interface, if created */
|
||||
};
|
||||
|
||||
/*
|
||||
* Parameter bits used for parameter negotiation according to 3GPP 27.010
|
||||
* chapter 5.4.6.3.1.
|
||||
*/
|
||||
|
||||
struct gsm_dlci_param_bits {
|
||||
u8 d_bits;
|
||||
u8 i_cl_bits;
|
||||
u8 p_bits;
|
||||
u8 t_bits;
|
||||
__le16 n_bits;
|
||||
u8 na_bits;
|
||||
u8 k_bits;
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct gsm_dlci_param_bits) == 8);
|
||||
|
||||
#define PN_D_FIELD_DLCI GENMASK(5, 0)
|
||||
#define PN_I_CL_FIELD_FTYPE GENMASK(3, 0)
|
||||
#define PN_I_CL_FIELD_ADAPTION GENMASK(7, 4)
|
||||
#define PN_P_FIELD_PRIO GENMASK(5, 0)
|
||||
#define PN_T_FIELD_T1 GENMASK(7, 0)
|
||||
#define PN_N_FIELD_N1 GENMASK(15, 0)
|
||||
#define PN_NA_FIELD_N2 GENMASK(7, 0)
|
||||
#define PN_K_FIELD_K GENMASK(2, 0)
|
||||
|
||||
/* Total number of supported devices */
|
||||
#define GSM_TTY_MINORS 256
|
||||
|
||||
|
@ -282,7 +322,9 @@ struct gsm_mux {
|
|||
int adaption; /* 1 or 2 supported */
|
||||
u8 ftype; /* UI or UIH */
|
||||
int t1, t2; /* Timers in 1/100th of a sec */
|
||||
unsigned int t3; /* Power wake-up timer in seconds. */
|
||||
int n2; /* Retry count */
|
||||
u8 k; /* Window size */
|
||||
|
||||
/* Statistics (not currently exposed) */
|
||||
unsigned long bad_fcs;
|
||||
|
@ -397,6 +439,7 @@ static const u8 gsm_fcs8[256] = {
|
|||
#define INIT_FCS 0xFF
|
||||
#define GOOD_FCS 0xCF
|
||||
|
||||
static void gsm_dlci_close(struct gsm_dlci *dlci);
|
||||
static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len);
|
||||
static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk);
|
||||
static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
|
||||
|
@ -519,6 +562,57 @@ static void gsm_hex_dump_bytes(const char *fname, const u8 *data,
|
|||
kfree(prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_encode_params - encode DLCI parameters
|
||||
* @dlci: DLCI to encode from
|
||||
* @params: buffer to fill with the encoded parameters
|
||||
*
|
||||
* Encodes the parameters according to GSM 07.10 section 5.4.6.3.1
|
||||
* table 3.
|
||||
*/
|
||||
static int gsm_encode_params(const struct gsm_dlci *dlci,
|
||||
struct gsm_dlci_param_bits *params)
|
||||
{
|
||||
const struct gsm_mux *gsm = dlci->gsm;
|
||||
unsigned int i, cl;
|
||||
|
||||
switch (dlci->ftype) {
|
||||
case UIH:
|
||||
i = 0; /* UIH */
|
||||
break;
|
||||
case UI:
|
||||
i = 1; /* UI */
|
||||
break;
|
||||
default:
|
||||
pr_debug("unsupported frame type %d\n", dlci->ftype);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (dlci->adaption) {
|
||||
case 1: /* Unstructured */
|
||||
cl = 0; /* convergence layer type 1 */
|
||||
break;
|
||||
case 2: /* Unstructured with modem bits. */
|
||||
cl = 1; /* convergence layer type 2 */
|
||||
break;
|
||||
default:
|
||||
pr_debug("unsupported adaption %d\n", dlci->adaption);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
params->d_bits = FIELD_PREP(PN_D_FIELD_DLCI, dlci->addr);
|
||||
/* UIH, convergence layer type 1 */
|
||||
params->i_cl_bits = FIELD_PREP(PN_I_CL_FIELD_FTYPE, i) |
|
||||
FIELD_PREP(PN_I_CL_FIELD_ADAPTION, cl);
|
||||
params->p_bits = FIELD_PREP(PN_P_FIELD_PRIO, dlci->prio);
|
||||
params->t_bits = FIELD_PREP(PN_T_FIELD_T1, gsm->t1);
|
||||
params->n_bits = cpu_to_le16(FIELD_PREP(PN_N_FIELD_N1, dlci->mtu));
|
||||
params->na_bits = FIELD_PREP(PN_NA_FIELD_N2, gsm->n2);
|
||||
params->k_bits = FIELD_PREP(PN_K_FIELD_K, dlci->k);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_register_devices - register all tty devices for a given mux index
|
||||
*
|
||||
|
@ -1076,12 +1170,12 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
|
|||
return 0;
|
||||
|
||||
/* MTU/MRU count only the data bits but watch adaption mode */
|
||||
if ((len + h) > gsm->mtu)
|
||||
len = gsm->mtu - h;
|
||||
if ((len + h) > dlci->mtu)
|
||||
len = dlci->mtu - h;
|
||||
|
||||
size = len + h;
|
||||
|
||||
msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
|
||||
msg = gsm_data_alloc(gsm, dlci->addr, size, dlci->ftype);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
dp = msg->data;
|
||||
|
@ -1145,19 +1239,19 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
|
|||
len = dlci->skb->len + overhead;
|
||||
|
||||
/* MTU/MRU count only the data bits */
|
||||
if (len > gsm->mtu) {
|
||||
if (len > dlci->mtu) {
|
||||
if (dlci->adaption == 3) {
|
||||
/* Over long frame, bin it */
|
||||
dev_kfree_skb_any(dlci->skb);
|
||||
dlci->skb = NULL;
|
||||
return 0;
|
||||
}
|
||||
len = gsm->mtu;
|
||||
len = dlci->mtu;
|
||||
} else
|
||||
last = 1;
|
||||
|
||||
size = len + overhead;
|
||||
msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
|
||||
msg = gsm_data_alloc(gsm, dlci->addr, size, dlci->ftype);
|
||||
if (msg == NULL) {
|
||||
skb_queue_tail(&dlci->skb_list, dlci->skb);
|
||||
dlci->skb = NULL;
|
||||
|
@ -1214,7 +1308,7 @@ static int gsm_dlci_modem_output(struct gsm_mux *gsm, struct gsm_dlci *dlci,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
|
||||
msg = gsm_data_alloc(gsm, dlci->addr, size, dlci->ftype);
|
||||
if (!msg) {
|
||||
pr_err("%s: gsm_data_alloc error", __func__);
|
||||
return -ENOMEM;
|
||||
|
@ -1287,7 +1381,7 @@ static int gsm_dlci_data_sweep(struct gsm_mux *gsm)
|
|||
}
|
||||
if (!sent)
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1340,8 +1434,9 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
|
|||
static int gsm_control_command(struct gsm_mux *gsm, int cmd, const u8 *data,
|
||||
int dlen)
|
||||
{
|
||||
struct gsm_msg *msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
|
||||
struct gsm_msg *msg;
|
||||
|
||||
msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->dlci[0]->ftype);
|
||||
if (msg == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1367,7 +1462,8 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data,
|
|||
int dlen)
|
||||
{
|
||||
struct gsm_msg *msg;
|
||||
msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->ftype);
|
||||
|
||||
msg = gsm_data_alloc(gsm, 0, dlen + 2, gsm->dlci[0]->ftype);
|
||||
if (msg == NULL)
|
||||
return;
|
||||
msg->data[0] = (cmd & 0xFE) << 1 | EA; /* Clear C/R */
|
||||
|
@ -1437,6 +1533,116 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
|
|||
dlci->modem_rx = mlines;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_process_negotiation - process received parameters
|
||||
* @gsm: GSM channel
|
||||
* @addr: DLCI address
|
||||
* @cr: command/response
|
||||
* @params: encoded parameters from the parameter negotiation message
|
||||
*
|
||||
* Used when the response for our parameter negotiation command was
|
||||
* received.
|
||||
*/
|
||||
static int gsm_process_negotiation(struct gsm_mux *gsm, unsigned int addr,
|
||||
unsigned int cr,
|
||||
const struct gsm_dlci_param_bits *params)
|
||||
{
|
||||
struct gsm_dlci *dlci = gsm->dlci[addr];
|
||||
unsigned int ftype, i, adaption, prio, n1, k;
|
||||
|
||||
i = FIELD_GET(PN_I_CL_FIELD_FTYPE, params->i_cl_bits);
|
||||
adaption = FIELD_GET(PN_I_CL_FIELD_ADAPTION, params->i_cl_bits) + 1;
|
||||
prio = FIELD_GET(PN_P_FIELD_PRIO, params->p_bits);
|
||||
n1 = FIELD_GET(PN_N_FIELD_N1, get_unaligned_le16(¶ms->n_bits));
|
||||
k = FIELD_GET(PN_K_FIELD_K, params->k_bits);
|
||||
|
||||
if (n1 < MIN_MTU) {
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s N1 out of range in PN\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case 0x00:
|
||||
ftype = UIH;
|
||||
break;
|
||||
case 0x01:
|
||||
ftype = UI;
|
||||
break;
|
||||
case 0x02: /* I frames are not supported */
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s unsupported I frame request in PN\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
default:
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s i out of range in PN\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!cr && gsm->initiator) {
|
||||
if (adaption != dlci->adaption) {
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s invalid adaption %d in PN\n",
|
||||
__func__, adaption);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (prio != dlci->prio) {
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s invalid priority %d in PN",
|
||||
__func__, prio);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (n1 > gsm->mru || n1 > dlci->mtu) {
|
||||
/* We requested a frame size but the other party wants
|
||||
* to send larger frames. The standard allows only a
|
||||
* smaller response value than requested (5.4.6.3.1).
|
||||
*/
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s invalid N1 %d in PN\n", __func__,
|
||||
n1);
|
||||
return -EINVAL;
|
||||
}
|
||||
dlci->mtu = n1;
|
||||
if (ftype != dlci->ftype) {
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s invalid i %d in PN\n", __func__, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ftype != UI && ftype != UIH && k > dlci->k) {
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s invalid k %d in PN\n", __func__, k);
|
||||
return -EINVAL;
|
||||
}
|
||||
dlci->k = k;
|
||||
} else if (cr && !gsm->initiator) {
|
||||
/* Only convergence layer type 1 and 2 are supported. */
|
||||
if (adaption != 1 && adaption != 2) {
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s invalid adaption %d in PN\n",
|
||||
__func__, adaption);
|
||||
return -EINVAL;
|
||||
}
|
||||
dlci->adaption = adaption;
|
||||
if (n1 > gsm->mru) {
|
||||
/* Propose a smaller value */
|
||||
dlci->mtu = gsm->mru;
|
||||
} else if (n1 > MAX_MTU) {
|
||||
/* Propose a smaller value */
|
||||
dlci->mtu = MAX_MTU;
|
||||
} else {
|
||||
dlci->mtu = n1;
|
||||
}
|
||||
dlci->prio = prio;
|
||||
dlci->ftype = ftype;
|
||||
dlci->k = k;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_control_modem - modem status received
|
||||
* @gsm: GSM channel
|
||||
|
@ -1490,6 +1696,65 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
|
|||
gsm_control_reply(gsm, CMD_MSC, data, clen);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_control_negotiation - parameter negotiation received
|
||||
* @gsm: GSM channel
|
||||
* @cr: command/response flag
|
||||
* @data: data following command
|
||||
* @dlen: data length
|
||||
*
|
||||
* We have received a parameter negotiation message. This is used by
|
||||
* the GSM mux protocol to configure protocol parameters for a new DLCI.
|
||||
*/
|
||||
static void gsm_control_negotiation(struct gsm_mux *gsm, unsigned int cr,
|
||||
const u8 *data, unsigned int dlen)
|
||||
{
|
||||
unsigned int addr;
|
||||
struct gsm_dlci_param_bits pn_reply;
|
||||
struct gsm_dlci *dlci;
|
||||
struct gsm_dlci_param_bits *params;
|
||||
|
||||
if (dlen < sizeof(struct gsm_dlci_param_bits))
|
||||
return;
|
||||
|
||||
/* Invalid DLCI? */
|
||||
params = (struct gsm_dlci_param_bits *)data;
|
||||
addr = FIELD_GET(PN_D_FIELD_DLCI, params->d_bits);
|
||||
if (addr == 0 || addr >= NUM_DLCI || !gsm->dlci[addr])
|
||||
return;
|
||||
dlci = gsm->dlci[addr];
|
||||
|
||||
/* Too late for parameter negotiation? */
|
||||
if ((!cr && dlci->state == DLCI_OPENING) || dlci->state == DLCI_OPEN)
|
||||
return;
|
||||
|
||||
/* Process the received parameters */
|
||||
if (gsm_process_negotiation(gsm, addr, cr, params) != 0) {
|
||||
/* Negotiation failed. Close the link. */
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s PN failed\n", __func__);
|
||||
gsm_dlci_close(dlci);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cr) {
|
||||
/* Reply command with accepted parameters. */
|
||||
if (gsm_encode_params(dlci, &pn_reply) == 0)
|
||||
gsm_control_reply(gsm, CMD_PN, (const u8 *)&pn_reply,
|
||||
sizeof(pn_reply));
|
||||
else if (debug & DBG_ERRORS)
|
||||
pr_info("%s PN invalid\n", __func__);
|
||||
} else if (dlci->state == DLCI_CONFIGURE) {
|
||||
/* Proceed with link setup by sending SABM before UA */
|
||||
dlci->state = DLCI_OPENING;
|
||||
gsm_command(gsm, dlci->addr, SABM|PF);
|
||||
mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
|
||||
} else {
|
||||
if (debug & DBG_ERRORS)
|
||||
pr_info("%s PN in invalid state\n", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_control_rls - remote line status
|
||||
* @gsm: GSM channel
|
||||
|
@ -1599,8 +1864,12 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
|
|||
/* Modem wishes to enter power saving state */
|
||||
gsm_control_reply(gsm, CMD_PSC, NULL, 0);
|
||||
break;
|
||||
/* Optional commands */
|
||||
case CMD_PN:
|
||||
/* Modem sends a parameter negotiation command */
|
||||
gsm_control_negotiation(gsm, 1, data, clen);
|
||||
break;
|
||||
/* Optional unsupported commands */
|
||||
case CMD_PN: /* Parameter negotiation */
|
||||
case CMD_RPN: /* Remote port negotiation */
|
||||
case CMD_SNC: /* Service negotiation command */
|
||||
default:
|
||||
|
@ -1633,8 +1902,8 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
|
|||
spin_lock_irqsave(&gsm->control_lock, flags);
|
||||
|
||||
ctrl = gsm->pending_cmd;
|
||||
/* Does the reply match our command */
|
||||
command |= 1;
|
||||
/* Does the reply match our command */
|
||||
if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
|
||||
/* Our command was replied to, kill the retry timer */
|
||||
del_timer(&gsm->t2_timer);
|
||||
|
@ -1644,6 +1913,9 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
|
|||
ctrl->error = -EOPNOTSUPP;
|
||||
ctrl->done = 1;
|
||||
wake_up(&gsm->event);
|
||||
/* Or did we receive the PN response to our PN command */
|
||||
} else if (command == CMD_PN) {
|
||||
gsm_control_negotiation(gsm, 0, data, clen);
|
||||
}
|
||||
spin_unlock_irqrestore(&gsm->control_lock, flags);
|
||||
}
|
||||
|
@ -1821,6 +2093,32 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
|
|||
wake_up(&dlci->gsm->event);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_dlci_negotiate - start parameter negotiation
|
||||
* @dlci: DLCI to open
|
||||
*
|
||||
* Starts the parameter negotiation for the new DLCI. This needs to be done
|
||||
* before the DLCI initialized the channel via SABM.
|
||||
*/
|
||||
static int gsm_dlci_negotiate(struct gsm_dlci *dlci)
|
||||
{
|
||||
struct gsm_mux *gsm = dlci->gsm;
|
||||
struct gsm_dlci_param_bits params;
|
||||
int ret;
|
||||
|
||||
ret = gsm_encode_params(dlci, ¶ms);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* We cannot asynchronous wait for the command response with
|
||||
* gsm_command() and gsm_control_wait() at this point.
|
||||
*/
|
||||
ret = gsm_control_command(gsm, CMD_PN, (const u8 *)¶ms,
|
||||
sizeof(params));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsm_dlci_t1 - T1 timer expiry
|
||||
* @t: timer contained in the DLCI that opened
|
||||
|
@ -1842,6 +2140,14 @@ static void gsm_dlci_t1(struct timer_list *t)
|
|||
struct gsm_mux *gsm = dlci->gsm;
|
||||
|
||||
switch (dlci->state) {
|
||||
case DLCI_CONFIGURE:
|
||||
if (dlci->retries && gsm_dlci_negotiate(dlci) == 0) {
|
||||
dlci->retries--;
|
||||
mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
|
||||
} else {
|
||||
gsm_dlci_begin_close(dlci); /* prevent half open link */
|
||||
}
|
||||
break;
|
||||
case DLCI_OPENING:
|
||||
if (dlci->retries) {
|
||||
dlci->retries--;
|
||||
|
@ -1880,17 +2186,46 @@ static void gsm_dlci_t1(struct timer_list *t)
|
|||
* to the modem which should then reply with a UA or ADM, at which point
|
||||
* we will move into open state. Opening is done asynchronously with retry
|
||||
* running off timers and the responses.
|
||||
* Parameter negotiation is performed before SABM if required.
|
||||
*/
|
||||
|
||||
static void gsm_dlci_begin_open(struct gsm_dlci *dlci)
|
||||
{
|
||||
struct gsm_mux *gsm = dlci->gsm;
|
||||
if (dlci->state == DLCI_OPEN || dlci->state == DLCI_OPENING)
|
||||
struct gsm_mux *gsm = dlci ? dlci->gsm : NULL;
|
||||
bool need_pn = false;
|
||||
|
||||
if (!gsm)
|
||||
return;
|
||||
dlci->retries = gsm->n2;
|
||||
dlci->state = DLCI_OPENING;
|
||||
gsm_command(dlci->gsm, dlci->addr, SABM|PF);
|
||||
mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
|
||||
|
||||
if (dlci->addr != 0) {
|
||||
if (gsm->adaption != 1 || gsm->adaption != dlci->adaption)
|
||||
need_pn = true;
|
||||
if (dlci->prio != (roundup(dlci->addr + 1, 8) - 1))
|
||||
need_pn = true;
|
||||
if (gsm->ftype != dlci->ftype)
|
||||
need_pn = true;
|
||||
}
|
||||
|
||||
switch (dlci->state) {
|
||||
case DLCI_CLOSED:
|
||||
case DLCI_CLOSING:
|
||||
dlci->retries = gsm->n2;
|
||||
if (!need_pn) {
|
||||
dlci->state = DLCI_OPENING;
|
||||
gsm_command(gsm, dlci->addr, SABM|PF);
|
||||
} else {
|
||||
/* Configure DLCI before setup */
|
||||
dlci->state = DLCI_CONFIGURE;
|
||||
if (gsm_dlci_negotiate(dlci) != 0) {
|
||||
gsm_dlci_close(dlci);
|
||||
return;
|
||||
}
|
||||
}
|
||||
mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2078,6 +2413,13 @@ static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
|
|||
dlci->gsm = gsm;
|
||||
dlci->addr = addr;
|
||||
dlci->adaption = gsm->adaption;
|
||||
dlci->mtu = gsm->mtu;
|
||||
if (addr == 0)
|
||||
dlci->prio = 0;
|
||||
else
|
||||
dlci->prio = roundup(addr + 1, 8) - 1;
|
||||
dlci->ftype = gsm->ftype;
|
||||
dlci->k = gsm->k;
|
||||
dlci->state = DLCI_CLOSED;
|
||||
if (addr) {
|
||||
dlci->data = gsm_dlci_data;
|
||||
|
@ -2652,7 +2994,9 @@ static struct gsm_mux *gsm_alloc_mux(void)
|
|||
|
||||
gsm->t1 = T1;
|
||||
gsm->t2 = T2;
|
||||
gsm->t3 = T3;
|
||||
gsm->n2 = N2;
|
||||
gsm->k = K;
|
||||
gsm->ftype = UIH;
|
||||
gsm->adaption = 1;
|
||||
gsm->encoding = GSM_ADV_OPT;
|
||||
|
@ -2692,7 +3036,7 @@ static void gsm_copy_config_values(struct gsm_mux *gsm,
|
|||
c->initiator = gsm->initiator;
|
||||
c->t1 = gsm->t1;
|
||||
c->t2 = gsm->t2;
|
||||
c->t3 = 0; /* Not supported */
|
||||
c->t3 = gsm->t3;
|
||||
c->n2 = gsm->n2;
|
||||
if (gsm->ftype == UIH)
|
||||
c->i = 1;
|
||||
|
@ -2701,7 +3045,7 @@ static void gsm_copy_config_values(struct gsm_mux *gsm,
|
|||
pr_debug("Ftype %d i %d\n", gsm->ftype, c->i);
|
||||
c->mru = gsm->mru;
|
||||
c->mtu = gsm->mtu;
|
||||
c->k = 0;
|
||||
c->k = gsm->k;
|
||||
}
|
||||
|
||||
static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
|
||||
|
@ -2714,7 +3058,11 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
|
|||
if ((c->adaption != 1 && c->adaption != 2) || c->k)
|
||||
return -EOPNOTSUPP;
|
||||
/* Check the MRU/MTU range looks sane */
|
||||
if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8)
|
||||
if (c->mru < MIN_MTU || c->mtu < MIN_MTU)
|
||||
return -EINVAL;
|
||||
if (c->mru > MAX_MRU || c->mtu > MAX_MTU)
|
||||
return -EINVAL;
|
||||
if (c->t3 > MAX_T3)
|
||||
return -EINVAL;
|
||||
if (c->n2 > 255)
|
||||
return -EINVAL;
|
||||
|
@ -2722,6 +3070,8 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
|
|||
return -EINVAL;
|
||||
if (c->initiator > 1)
|
||||
return -EINVAL;
|
||||
if (c->k > MAX_WINDOW_SIZE)
|
||||
return -EINVAL;
|
||||
if (c->i == 0 || c->i > 2) /* UIH and UI only */
|
||||
return -EINVAL;
|
||||
/*
|
||||
|
@ -2769,6 +3119,10 @@ static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c)
|
|||
gsm->t1 = c->t1;
|
||||
if (c->t2)
|
||||
gsm->t2 = c->t2;
|
||||
if (c->t3)
|
||||
gsm->t3 = c->t3;
|
||||
if (c->k)
|
||||
gsm->k = c->k;
|
||||
|
||||
/*
|
||||
* FIXME: We need to separate activation/deactivation from adding
|
||||
|
@ -3299,9 +3653,9 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
|
|||
pr_err("alloc_netdev failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
net->mtu = dlci->gsm->mtu;
|
||||
net->min_mtu = 8;
|
||||
net->max_mtu = dlci->gsm->mtu;
|
||||
net->mtu = dlci->mtu;
|
||||
net->min_mtu = MIN_MTU;
|
||||
net->max_mtu = dlci->mtu;
|
||||
mux_net = netdev_priv(net);
|
||||
mux_net->dlci = dlci;
|
||||
kref_init(&mux_net->ref);
|
||||
|
|
|
@ -2130,7 +2130,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
|||
ssize_t retval = 0;
|
||||
long timeout;
|
||||
bool packet;
|
||||
size_t tail;
|
||||
size_t old_tail;
|
||||
|
||||
/*
|
||||
* Is this a continuation of a read started earler?
|
||||
|
@ -2193,7 +2193,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
|
|||
}
|
||||
|
||||
packet = tty->ctrl.packet;
|
||||
tail = ldata->read_tail;
|
||||
old_tail = ldata->read_tail;
|
||||
|
||||
add_wait_queue(&tty->read_wait, &wait);
|
||||
while (nr) {
|
||||
|
@ -2282,7 +2282,7 @@ more_to_be_read:
|
|||
if (time)
|
||||
timeout = time;
|
||||
}
|
||||
if (tail != ldata->read_tail)
|
||||
if (old_tail != ldata->read_tail)
|
||||
n_tty_kick_worker(tty);
|
||||
up_read(&tty->termios_rwsem);
|
||||
|
||||
|
|
|
@ -154,35 +154,13 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
|
|||
static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
|
||||
{
|
||||
struct uart_port *port = dev_id;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
int count = 256;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char) {
|
||||
*CSR_UARTDR = port->x_char;
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
goto out;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
serial21285_stop_tx(port);
|
||||
goto out;
|
||||
}
|
||||
uart_port_tx_limited(port, ch, 256,
|
||||
!(*CSR_UARTFLG & 0x20),
|
||||
*CSR_UARTDR = ch,
|
||||
({}));
|
||||
|
||||
do {
|
||||
*CSR_UARTDR = xmit->buf[xmit->tail];
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0 && !(*CSR_UARTFLG & 0x20));
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
serial21285_stop_tx(port);
|
||||
|
||||
out:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
|
|
@ -425,9 +425,7 @@ static int brcmuart_tx_dma(struct uart_8250_port *p)
|
|||
|
||||
priv->dma.tx_err = 0;
|
||||
memcpy(priv->tx_buf, &xmit->buf[xmit->tail], tx_size);
|
||||
xmit->tail += tx_size;
|
||||
xmit->tail &= UART_XMIT_SIZE - 1;
|
||||
p->port.icount.tx += tx_size;
|
||||
uart_xmit_advance(&p->port, tx_size);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&p->port);
|
||||
|
@ -1212,9 +1210,17 @@ static struct platform_driver brcmuart_platform_driver = {
|
|||
|
||||
static int __init brcmuart_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
brcmuart_debugfs_root = debugfs_create_dir(
|
||||
brcmuart_platform_driver.driver.name, NULL);
|
||||
return platform_driver_register(&brcmuart_platform_driver);
|
||||
ret = platform_driver_register(&brcmuart_platform_driver);
|
||||
if (ret) {
|
||||
debugfs_remove_recursive(brcmuart_debugfs_root);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(brcmuart_init);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/nmi.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/io.h>
|
||||
#ifdef CONFIG_SPARC
|
||||
|
@ -1175,8 +1176,8 @@ static int __init serial8250_init(void)
|
|||
|
||||
serial8250_isa_init_ports();
|
||||
|
||||
pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %sabled\n",
|
||||
nr_uarts, share_irqs ? "en" : "dis");
|
||||
pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %s\n",
|
||||
nr_uarts, str_enabled_disabled(share_irqs));
|
||||
|
||||
#ifdef CONFIG_SPARC
|
||||
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
|
||||
|
|
|
@ -38,9 +38,8 @@ static void __dma_tx_complete(void *param)
|
|||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
}
|
||||
|
||||
static void __dma_rx_complete(void *param)
|
||||
static void __dma_rx_complete(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_port *p = param;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
struct tty_port *tty_port = &p->port.state->port;
|
||||
struct dma_tx_state state;
|
||||
|
@ -57,6 +56,20 @@ static void __dma_rx_complete(void *param)
|
|||
tty_flip_buffer_push(tty_port);
|
||||
}
|
||||
|
||||
static void dma_rx_complete(void *param)
|
||||
{
|
||||
struct uart_8250_port *p = param;
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
unsigned long flags;
|
||||
|
||||
__dma_rx_complete(p);
|
||||
|
||||
spin_lock_irqsave(&p->port.lock, flags);
|
||||
if (!dma->rx_running && (serial_lsr_in(p) & UART_LSR_DR))
|
||||
p->dma->rx_dma(p);
|
||||
spin_unlock_irqrestore(&p->port.lock, flags);
|
||||
}
|
||||
|
||||
int serial8250_tx_dma(struct uart_8250_port *p)
|
||||
{
|
||||
struct uart_8250_dma *dma = p->dma;
|
||||
|
@ -130,7 +143,7 @@ int serial8250_rx_dma(struct uart_8250_port *p)
|
|||
return -EBUSY;
|
||||
|
||||
dma->rx_running = 1;
|
||||
desc->callback = __dma_rx_complete;
|
||||
desc->callback = dma_rx_complete;
|
||||
desc->callback_param = p;
|
||||
|
||||
dma->rx_cookie = dmaengine_submit(desc);
|
||||
|
|
|
@ -87,7 +87,7 @@ static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev
|
|||
dev->port.uartclk = be32_to_cpup(prop);
|
||||
}
|
||||
|
||||
static int __init ingenic_early_console_setup(struct earlycon_device *dev,
|
||||
static int __init ingenic_earlycon_setup_tail(struct earlycon_device *dev,
|
||||
const char *opt)
|
||||
{
|
||||
struct uart_port *port = &dev->port;
|
||||
|
@ -103,8 +103,6 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
|
|||
uart_parse_options(opt, &baud, &parity, &bits, &flow);
|
||||
}
|
||||
|
||||
ingenic_early_console_setup_clock(dev);
|
||||
|
||||
if (dev->baud)
|
||||
baud = dev->baud;
|
||||
divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud);
|
||||
|
@ -129,9 +127,36 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __init ingenic_early_console_setup(struct earlycon_device *dev,
|
||||
const char *opt)
|
||||
{
|
||||
ingenic_early_console_setup_clock(dev);
|
||||
|
||||
return ingenic_earlycon_setup_tail(dev, opt);
|
||||
}
|
||||
|
||||
static int __init jz4750_early_console_setup(struct earlycon_device *dev,
|
||||
const char *opt)
|
||||
{
|
||||
/*
|
||||
* JZ4750/55/60 have an optional /2 divider between the EXT
|
||||
* oscillator and some peripherals including UART, which will
|
||||
* be enabled if using a 24 MHz oscillator, and disabled when
|
||||
* using a 12 MHz oscillator.
|
||||
*/
|
||||
ingenic_early_console_setup_clock(dev);
|
||||
if (dev->port.uartclk >= 16000000)
|
||||
dev->port.uartclk /= 2;
|
||||
|
||||
return ingenic_earlycon_setup_tail(dev, opt);
|
||||
}
|
||||
|
||||
OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart",
|
||||
ingenic_early_console_setup);
|
||||
|
||||
OF_EARLYCON_DECLARE(jz4750_uart, "ingenic,jz4750-uart",
|
||||
jz4750_early_console_setup);
|
||||
|
||||
OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart",
|
||||
ingenic_early_console_setup);
|
||||
|
||||
|
@ -328,6 +353,7 @@ static const struct ingenic_uart_config x1000_uart_config = {
|
|||
|
||||
static const struct of_device_id of_match[] = {
|
||||
{ .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config },
|
||||
{ .compatible = "ingenic,jz4750-uart", .data = &jz4760_uart_config },
|
||||
{ .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config },
|
||||
{ .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config },
|
||||
{ .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config },
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#define UART_HAS_EFR2 BIT(4)
|
||||
#define UART_HAS_RHR_IT_DIS BIT(5)
|
||||
#define UART_RX_TIMEOUT_QUIRK BIT(6)
|
||||
#define UART_HAS_NATIVE_RS485 BIT(7)
|
||||
|
||||
#define OMAP_UART_FCR_RX_TRIG 6
|
||||
#define OMAP_UART_FCR_TX_TRIG 4
|
||||
|
@ -101,6 +102,11 @@
|
|||
#define UART_OMAP_IER2 0x1B
|
||||
#define UART_OMAP_IER2_RHR_IT_DIS BIT(2)
|
||||
|
||||
/* Mode Definition Register 3 */
|
||||
#define UART_OMAP_MDR3 0x20
|
||||
#define UART_OMAP_MDR3_DIR_POL BIT(3)
|
||||
#define UART_OMAP_MDR3_DIR_EN BIT(4)
|
||||
|
||||
/* Enhanced features register 2 */
|
||||
#define UART_OMAP_EFR2 0x23
|
||||
#define UART_OMAP_EFR2_TIMEOUT_BEHAVE BIT(6)
|
||||
|
@ -112,6 +118,7 @@ struct omap8250_priv {
|
|||
int line;
|
||||
u8 habit;
|
||||
u8 mdr1;
|
||||
u8 mdr3;
|
||||
u8 efr;
|
||||
u8 scr;
|
||||
u8 wer;
|
||||
|
@ -346,7 +353,10 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
|
|||
|
||||
__omap8250_set_mctrl(&up->port, up->port.mctrl);
|
||||
|
||||
if (up->port.rs485.flags & SER_RS485_ENABLED)
|
||||
serial_out(up, UART_OMAP_MDR3, priv->mdr3);
|
||||
|
||||
if (up->port.rs485.flags & SER_RS485_ENABLED &&
|
||||
up->port.rs485_config == serial8250_em485_config)
|
||||
serial8250_em485_stop_tx(up);
|
||||
}
|
||||
|
||||
|
@ -794,6 +804,74 @@ static void omap_8250_unthrottle(struct uart_port *port)
|
|||
pm_runtime_put_autosuspend(port->dev);
|
||||
}
|
||||
|
||||
static int omap8250_rs485_config(struct uart_port *port,
|
||||
struct ktermios *termios,
|
||||
struct serial_rs485 *rs485)
|
||||
{
|
||||
struct omap8250_priv *priv = port->private_data;
|
||||
struct uart_8250_port *up = up_to_u8250p(port);
|
||||
u32 fixed_delay_rts_before_send = 0;
|
||||
u32 fixed_delay_rts_after_send = 0;
|
||||
unsigned int baud;
|
||||
|
||||
/*
|
||||
* There is a fixed delay of 3 bit clock cycles after the TX shift
|
||||
* register is going empty to allow time for the stop bit to transition
|
||||
* through the transceiver before direction is changed to receive.
|
||||
*
|
||||
* Additionally there appears to be a 1 bit clock delay between writing
|
||||
* to the THR register and transmission of the start bit, per page 8783
|
||||
* of the AM65 TRM: https://www.ti.com/lit/ug/spruid7e/spruid7e.pdf
|
||||
*/
|
||||
if (priv->quot) {
|
||||
if (priv->mdr1 == UART_OMAP_MDR1_16X_MODE)
|
||||
baud = port->uartclk / (16 * priv->quot);
|
||||
else
|
||||
baud = port->uartclk / (13 * priv->quot);
|
||||
|
||||
fixed_delay_rts_after_send = 3 * MSEC_PER_SEC / baud;
|
||||
fixed_delay_rts_before_send = 1 * MSEC_PER_SEC / baud;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fall back to RS485 software emulation if the UART is missing
|
||||
* hardware support, if the device tree specifies an mctrl_gpio
|
||||
* (indicates that RTS is unavailable due to a pinmux conflict)
|
||||
* or if the requested delays exceed the fixed hardware delays.
|
||||
*/
|
||||
if (!(priv->habit & UART_HAS_NATIVE_RS485) ||
|
||||
mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS) ||
|
||||
rs485->delay_rts_after_send > fixed_delay_rts_after_send ||
|
||||
rs485->delay_rts_before_send > fixed_delay_rts_before_send) {
|
||||
priv->mdr3 &= ~UART_OMAP_MDR3_DIR_EN;
|
||||
serial_out(up, UART_OMAP_MDR3, priv->mdr3);
|
||||
|
||||
port->rs485_config = serial8250_em485_config;
|
||||
return serial8250_em485_config(port, termios, rs485);
|
||||
}
|
||||
|
||||
rs485->delay_rts_after_send = fixed_delay_rts_after_send;
|
||||
rs485->delay_rts_before_send = fixed_delay_rts_before_send;
|
||||
|
||||
if (rs485->flags & SER_RS485_ENABLED)
|
||||
priv->mdr3 |= UART_OMAP_MDR3_DIR_EN;
|
||||
else
|
||||
priv->mdr3 &= ~UART_OMAP_MDR3_DIR_EN;
|
||||
|
||||
/*
|
||||
* Retain same polarity semantics as RS485 software emulation,
|
||||
* i.e. SER_RS485_RTS_ON_SEND means driving RTS low on send.
|
||||
*/
|
||||
if (rs485->flags & SER_RS485_RTS_ON_SEND)
|
||||
priv->mdr3 &= ~UART_OMAP_MDR3_DIR_POL;
|
||||
else
|
||||
priv->mdr3 |= UART_OMAP_MDR3_DIR_POL;
|
||||
|
||||
serial_out(up, UART_OMAP_MDR3, priv->mdr3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_DMA
|
||||
static int omap_8250_rx_dma(struct uart_8250_port *p);
|
||||
|
||||
|
@ -1243,7 +1321,7 @@ static struct omap8250_dma_params am33xx_dma = {
|
|||
static struct omap8250_platdata am654_platdata = {
|
||||
.dma_params = &am654_dma,
|
||||
.habit = UART_HAS_EFR2 | UART_HAS_RHR_IT_DIS |
|
||||
UART_RX_TIMEOUT_QUIRK,
|
||||
UART_RX_TIMEOUT_QUIRK | UART_HAS_NATIVE_RS485,
|
||||
};
|
||||
|
||||
static struct omap8250_platdata am33xx_platdata = {
|
||||
|
@ -1336,7 +1414,8 @@ static int omap8250_probe(struct platform_device *pdev)
|
|||
up.port.shutdown = omap_8250_shutdown;
|
||||
up.port.throttle = omap_8250_throttle;
|
||||
up.port.unthrottle = omap_8250_unthrottle;
|
||||
up.port.rs485_config = serial8250_em485_config;
|
||||
up.port.rs485_config = omap8250_rs485_config;
|
||||
/* same rs485_supported for software emulation and native RS485 */
|
||||
up.port.rs485_supported = serial8250_em485_supported;
|
||||
up.rs485_start_tx = serial8250_em485_start_tx;
|
||||
up.rs485_stop_tx = serial8250_em485_stop_tx;
|
||||
|
|
|
@ -1842,8 +1842,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
|
|||
*/
|
||||
serial_in(up, UART_SCR);
|
||||
}
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
if ((up->capabilities & UART_CAP_HFIFO) &&
|
||||
|
|
|
@ -958,6 +958,7 @@ config SERIAL_OMAP_CONSOLE
|
|||
config SERIAL_SIFIVE
|
||||
tristate "SiFive UART support"
|
||||
depends on OF
|
||||
default SOC_SIFIVE || SOC_CANAAN
|
||||
select SERIAL_CORE
|
||||
help
|
||||
Select this option if you are building a kernel for a device that
|
||||
|
@ -967,6 +968,7 @@ config SERIAL_SIFIVE
|
|||
config SERIAL_SIFIVE_CONSOLE
|
||||
bool "Console on SiFive UART"
|
||||
depends on SERIAL_SIFIVE=y
|
||||
default SOC_SIFIVE || SOC_CANAAN
|
||||
select SERIAL_CORE_CONSOLE
|
||||
select SERIAL_EARLYCON
|
||||
help
|
||||
|
|
|
@ -50,15 +50,6 @@
|
|||
#define ALTERA_JTAGUART_CONTROL_AC_MSK 0x00000400
|
||||
#define ALTERA_JTAGUART_CONTROL_WSPACE_MSK 0xFFFF0000
|
||||
|
||||
/*
|
||||
* Local per-uart structure.
|
||||
*/
|
||||
struct altera_jtaguart {
|
||||
struct uart_port port;
|
||||
unsigned int sigs; /* Local copy of line sigs */
|
||||
unsigned long imr; /* Local IMR mirror */
|
||||
};
|
||||
|
||||
static unsigned int altera_jtaguart_tx_space(struct uart_port *port, u32 *ctlp)
|
||||
{
|
||||
u32 ctl = readl(port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
|
@ -85,29 +76,23 @@ static void altera_jtaguart_set_mctrl(struct uart_port *port, unsigned int sigs)
|
|||
|
||||
static void altera_jtaguart_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct altera_jtaguart *pp =
|
||||
container_of(port, struct altera_jtaguart, port);
|
||||
|
||||
pp->imr |= ALTERA_JTAGUART_CONTROL_WE_MSK;
|
||||
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
port->read_status_mask |= ALTERA_JTAGUART_CONTROL_WE_MSK;
|
||||
writel(port->read_status_mask,
|
||||
port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
}
|
||||
|
||||
static void altera_jtaguart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct altera_jtaguart *pp =
|
||||
container_of(port, struct altera_jtaguart, port);
|
||||
|
||||
pp->imr &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
|
||||
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
port->read_status_mask &= ~ALTERA_JTAGUART_CONTROL_WE_MSK;
|
||||
writel(port->read_status_mask,
|
||||
port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
}
|
||||
|
||||
static void altera_jtaguart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct altera_jtaguart *pp =
|
||||
container_of(port, struct altera_jtaguart, port);
|
||||
|
||||
pp->imr &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
|
||||
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
port->read_status_mask &= ~ALTERA_JTAGUART_CONTROL_RE_MSK;
|
||||
writel(port->read_status_mask,
|
||||
port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
}
|
||||
|
||||
static void altera_jtaguart_break_ctl(struct uart_port *port, int break_state)
|
||||
|
@ -123,78 +108,51 @@ static void altera_jtaguart_set_termios(struct uart_port *port,
|
|||
tty_termios_copy_hw(termios, old);
|
||||
}
|
||||
|
||||
static void altera_jtaguart_rx_chars(struct altera_jtaguart *pp)
|
||||
static void altera_jtaguart_rx_chars(struct uart_port *port)
|
||||
{
|
||||
struct uart_port *port = &pp->port;
|
||||
unsigned char ch, flag;
|
||||
unsigned char ch;
|
||||
unsigned long status;
|
||||
|
||||
while ((status = readl(port->membase + ALTERA_JTAGUART_DATA_REG)) &
|
||||
ALTERA_JTAGUART_DATA_RVALID_MSK) {
|
||||
ch = status & ALTERA_JTAGUART_DATA_DATA_MSK;
|
||||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
|
||||
if (uart_handle_sysrq_char(port, ch))
|
||||
continue;
|
||||
uart_insert_char(port, 0, 0, ch, flag);
|
||||
uart_insert_char(port, 0, 0, ch, TTY_NORMAL);
|
||||
}
|
||||
|
||||
tty_flip_buffer_push(&port->state->port);
|
||||
}
|
||||
|
||||
static void altera_jtaguart_tx_chars(struct altera_jtaguart *pp)
|
||||
static void altera_jtaguart_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct uart_port *port = &pp->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int pending, count;
|
||||
unsigned int count;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char) {
|
||||
/* Send special char - probably flow control */
|
||||
writel(port->x_char, port->membase + ALTERA_JTAGUART_DATA_REG);
|
||||
port->x_char = 0;
|
||||
port->icount.tx++;
|
||||
return;
|
||||
}
|
||||
count = altera_jtaguart_tx_space(port, NULL);
|
||||
|
||||
pending = uart_circ_chars_pending(xmit);
|
||||
if (pending > 0) {
|
||||
count = altera_jtaguart_tx_space(port, NULL);
|
||||
if (count > pending)
|
||||
count = pending;
|
||||
if (count > 0) {
|
||||
pending -= count;
|
||||
while (count--) {
|
||||
writel(xmit->buf[xmit->tail],
|
||||
port->membase + ALTERA_JTAGUART_DATA_REG);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
}
|
||||
if (pending < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
}
|
||||
|
||||
if (pending == 0)
|
||||
altera_jtaguart_stop_tx(port);
|
||||
uart_port_tx_limited(port, ch, count,
|
||||
true,
|
||||
writel(ch, port->membase + ALTERA_JTAGUART_DATA_REG),
|
||||
({}));
|
||||
}
|
||||
|
||||
static irqreturn_t altera_jtaguart_interrupt(int irq, void *data)
|
||||
{
|
||||
struct uart_port *port = data;
|
||||
struct altera_jtaguart *pp =
|
||||
container_of(port, struct altera_jtaguart, port);
|
||||
unsigned int isr;
|
||||
|
||||
isr = (readl(port->membase + ALTERA_JTAGUART_CONTROL_REG) >>
|
||||
ALTERA_JTAGUART_CONTROL_RI_OFF) & pp->imr;
|
||||
ALTERA_JTAGUART_CONTROL_RI_OFF) & port->read_status_mask;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
if (isr & ALTERA_JTAGUART_CONTROL_RE_MSK)
|
||||
altera_jtaguart_rx_chars(pp);
|
||||
altera_jtaguart_rx_chars(port);
|
||||
if (isr & ALTERA_JTAGUART_CONTROL_WE_MSK)
|
||||
altera_jtaguart_tx_chars(pp);
|
||||
altera_jtaguart_tx_chars(port);
|
||||
|
||||
spin_unlock(&port->lock);
|
||||
|
||||
|
@ -211,8 +169,6 @@ static void altera_jtaguart_config_port(struct uart_port *port, int flags)
|
|||
|
||||
static int altera_jtaguart_startup(struct uart_port *port)
|
||||
{
|
||||
struct altera_jtaguart *pp =
|
||||
container_of(port, struct altera_jtaguart, port);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
|
@ -227,8 +183,9 @@ static int altera_jtaguart_startup(struct uart_port *port)
|
|||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Enable RX interrupts now */
|
||||
pp->imr = ALTERA_JTAGUART_CONTROL_RE_MSK;
|
||||
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
port->read_status_mask = ALTERA_JTAGUART_CONTROL_RE_MSK;
|
||||
writel(port->read_status_mask,
|
||||
port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
|
@ -237,15 +194,14 @@ static int altera_jtaguart_startup(struct uart_port *port)
|
|||
|
||||
static void altera_jtaguart_shutdown(struct uart_port *port)
|
||||
{
|
||||
struct altera_jtaguart *pp =
|
||||
container_of(port, struct altera_jtaguart, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
/* Disable all interrupts now */
|
||||
pp->imr = 0;
|
||||
writel(pp->imr, port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
port->read_status_mask = 0;
|
||||
writel(port->read_status_mask,
|
||||
port->membase + ALTERA_JTAGUART_CONTROL_REG);
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
|
@ -298,7 +254,7 @@ static const struct uart_ops altera_jtaguart_ops = {
|
|||
};
|
||||
|
||||
#define ALTERA_JTAGUART_MAXPORTS 1
|
||||
static struct altera_jtaguart altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
|
||||
static struct uart_port altera_jtaguart_ports[ALTERA_JTAGUART_MAXPORTS];
|
||||
|
||||
#if defined(CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE)
|
||||
|
||||
|
@ -341,7 +297,7 @@ static void altera_jtaguart_console_putc(struct uart_port *port, unsigned char c
|
|||
static void altera_jtaguart_console_write(struct console *co, const char *s,
|
||||
unsigned int count)
|
||||
{
|
||||
struct uart_port *port = &(altera_jtaguart_ports + co->index)->port;
|
||||
struct uart_port *port = &altera_jtaguart_ports[co->index];
|
||||
|
||||
uart_console_write(port, s, count, altera_jtaguart_console_putc);
|
||||
}
|
||||
|
@ -353,7 +309,7 @@ static int __init altera_jtaguart_console_setup(struct console *co,
|
|||
|
||||
if (co->index < 0 || co->index >= ALTERA_JTAGUART_MAXPORTS)
|
||||
return -EINVAL;
|
||||
port = &altera_jtaguart_ports[co->index].port;
|
||||
port = &altera_jtaguart_ports[co->index];
|
||||
if (port->membase == NULL)
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
|
@ -433,7 +389,7 @@ static int altera_jtaguart_probe(struct platform_device *pdev)
|
|||
if (i >= ALTERA_JTAGUART_MAXPORTS)
|
||||
return -EINVAL;
|
||||
|
||||
port = &altera_jtaguart_ports[i].port;
|
||||
port = &altera_jtaguart_ports[i];
|
||||
|
||||
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res_mem)
|
||||
|
@ -477,7 +433,7 @@ static int altera_jtaguart_remove(struct platform_device *pdev)
|
|||
if (i == -1)
|
||||
i = 0;
|
||||
|
||||
port = &altera_jtaguart_ports[i].port;
|
||||
port = &altera_jtaguart_ports[i];
|
||||
uart_remove_one_port(&altera_jtaguart_driver, port);
|
||||
iounmap(port->membase);
|
||||
|
||||
|
|
|
@ -247,47 +247,29 @@ static void altera_uart_rx_chars(struct uart_port *port)
|
|||
|
||||
static void altera_uart_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char) {
|
||||
/* Send special char - probably flow control */
|
||||
altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG);
|
||||
port->x_char = 0;
|
||||
port->icount.tx++;
|
||||
return;
|
||||
}
|
||||
|
||||
while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
|
||||
ALTERA_UART_STATUS_TRDY_MSK) {
|
||||
if (xmit->head == xmit->tail)
|
||||
break;
|
||||
altera_uart_writel(port, xmit->buf[xmit->tail],
|
||||
ALTERA_UART_TXDATA_REG);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
altera_uart_stop_tx(port);
|
||||
uart_port_tx(port, ch,
|
||||
altera_uart_readl(port, ALTERA_UART_STATUS_REG) &
|
||||
ALTERA_UART_STATUS_TRDY_MSK,
|
||||
altera_uart_writel(port, ch, ALTERA_UART_TXDATA_REG));
|
||||
}
|
||||
|
||||
static irqreturn_t altera_uart_interrupt(int irq, void *data)
|
||||
{
|
||||
struct uart_port *port = data;
|
||||
struct altera_uart *pp = container_of(port, struct altera_uart, port);
|
||||
unsigned long flags;
|
||||
unsigned int isr;
|
||||
|
||||
isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
if (isr & ALTERA_UART_STATUS_RRDY_MSK)
|
||||
altera_uart_rx_chars(port);
|
||||
if (isr & ALTERA_UART_STATUS_TRDY_MSK)
|
||||
altera_uart_tx_chars(port);
|
||||
spin_unlock(&port->lock);
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
||||
return IRQ_RETVAL(isr);
|
||||
}
|
||||
|
|
|
@ -164,34 +164,12 @@ static void pl010_rx_chars(struct uart_port *port)
|
|||
|
||||
static void pl010_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
int count;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char) {
|
||||
writel(port->x_char, port->membase + UART01x_DR);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
pl010_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
count = port->fifosize >> 1;
|
||||
do {
|
||||
writel(xmit->buf[xmit->tail], port->membase + UART01x_DR);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
pl010_stop_tx(port);
|
||||
uart_port_tx_limited(port, ch, port->fifosize >> 1,
|
||||
true,
|
||||
writel(ch, port->membase + UART01x_DR),
|
||||
({}));
|
||||
}
|
||||
|
||||
static void pl010_modem_status(struct uart_amba_port *uap)
|
||||
|
|
|
@ -677,8 +677,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
|
|||
* Now we know that DMA will fire, so advance the ring buffer
|
||||
* with the stuff we just dispatched.
|
||||
*/
|
||||
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
|
||||
uap->port.icount.tx += count;
|
||||
uart_xmit_advance(&uap->port, count);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uap->port);
|
||||
|
@ -1045,6 +1044,9 @@ static void pl011_dma_rx_callback(void *data)
|
|||
*/
|
||||
static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
|
||||
{
|
||||
if (!uap->using_rx_dma)
|
||||
return;
|
||||
|
||||
/* FIXME. Just disable the DMA enable */
|
||||
uap->dmacr &= ~UART011_RXDMAE;
|
||||
pl011_write(uap->dmacr, uap, REG_DMACR);
|
||||
|
@ -1828,8 +1830,17 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
|
|||
static void pl011_unthrottle_rx(struct uart_port *port)
|
||||
{
|
||||
struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
|
||||
unsigned long flags;
|
||||
|
||||
pl011_enable_interrupts(uap);
|
||||
spin_lock_irqsave(&uap->port.lock, flags);
|
||||
|
||||
uap->im = UART011_RTIM;
|
||||
if (!pl011_dma_rx_running(uap))
|
||||
uap->im |= UART011_RXIM;
|
||||
|
||||
pl011_write(uap->im, uap, REG_IMSC);
|
||||
|
||||
spin_unlock_irqrestore(&uap->port.lock, flags);
|
||||
}
|
||||
|
||||
static int pl011_startup(struct uart_port *port)
|
||||
|
|
|
@ -122,36 +122,12 @@ static void apbuart_rx_chars(struct uart_port *port)
|
|||
|
||||
static void apbuart_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
int count;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char) {
|
||||
UART_PUT_CHAR(port, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
apbuart_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
/* amba: fill FIFO */
|
||||
count = port->fifosize >> 1;
|
||||
do {
|
||||
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
apbuart_stop_tx(port);
|
||||
uart_port_tx_limited(port, ch, port->fifosize >> 1,
|
||||
true,
|
||||
UART_PUT_CHAR(port, ch),
|
||||
({}));
|
||||
}
|
||||
|
||||
static irqreturn_t apbuart_int(int irq, void *dev_id)
|
||||
|
|
|
@ -425,8 +425,7 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
|
|||
|
||||
ar933x_uart_putc(up, xmit->buf[xmit->tail]);
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
|
|
@ -166,8 +166,7 @@ static void arc_serial_tx_chars(struct uart_port *port)
|
|||
sent = 1;
|
||||
} else if (!uart_circ_empty(xmit)) {
|
||||
ch = xmit->buf[xmit->tail];
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
while (!(UART_GET_STATUS(port) & TXEMPTY))
|
||||
cpu_relax();
|
||||
UART_SET_DATA(port, ch);
|
||||
|
|
|
@ -552,19 +552,23 @@ static u_int atmel_get_mctrl(struct uart_port *port)
|
|||
static void atmel_stop_tx(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
bool is_pdc = atmel_use_pdc_tx(port);
|
||||
bool is_dma = is_pdc || atmel_use_dma_tx(port);
|
||||
|
||||
if (atmel_use_pdc_tx(port)) {
|
||||
if (is_pdc) {
|
||||
/* disable PDC transmit */
|
||||
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable the transmitter.
|
||||
* This is mandatory when DMA is used, otherwise the DMA buffer
|
||||
* is fully transmitted.
|
||||
*/
|
||||
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
|
||||
atmel_port->tx_stopped = true;
|
||||
if (is_dma) {
|
||||
/*
|
||||
* Disable the transmitter.
|
||||
* This is mandatory when DMA is used, otherwise the DMA buffer
|
||||
* is fully transmitted.
|
||||
*/
|
||||
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
|
||||
atmel_port->tx_stopped = true;
|
||||
}
|
||||
|
||||
/* Disable interrupts */
|
||||
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
|
||||
|
@ -572,7 +576,6 @@ static void atmel_stop_tx(struct uart_port *port)
|
|||
if (atmel_uart_is_half_duplex(port))
|
||||
if (!atomic_read(&atmel_port->tasklet_shutdown))
|
||||
atmel_start_rx(port);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -581,27 +584,31 @@ static void atmel_stop_tx(struct uart_port *port)
|
|||
static void atmel_start_tx(struct uart_port *port)
|
||||
{
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
bool is_pdc = atmel_use_pdc_tx(port);
|
||||
bool is_dma = is_pdc || atmel_use_dma_tx(port);
|
||||
|
||||
if (atmel_use_pdc_tx(port) && (atmel_uart_readl(port, ATMEL_PDC_PTSR)
|
||||
if (is_pdc && (atmel_uart_readl(port, ATMEL_PDC_PTSR)
|
||||
& ATMEL_PDC_TXTEN))
|
||||
/* The transmitter is already running. Yes, we
|
||||
really need this.*/
|
||||
return;
|
||||
|
||||
if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
|
||||
if (atmel_uart_is_half_duplex(port))
|
||||
atmel_stop_rx(port);
|
||||
if (is_dma && atmel_uart_is_half_duplex(port))
|
||||
atmel_stop_rx(port);
|
||||
|
||||
if (atmel_use_pdc_tx(port))
|
||||
if (is_pdc) {
|
||||
/* re-enable PDC transmit */
|
||||
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
|
||||
}
|
||||
|
||||
/* Enable interrupts */
|
||||
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
|
||||
|
||||
/* re-enable the transmitter */
|
||||
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
|
||||
atmel_port->tx_stopped = false;
|
||||
if (is_dma) {
|
||||
/* re-enable the transmitter */
|
||||
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
|
||||
atmel_port->tx_stopped = false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -824,30 +831,14 @@ static void atmel_rx_chars(struct uart_port *port)
|
|||
*/
|
||||
static void atmel_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
|
||||
bool pending;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char &&
|
||||
(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) {
|
||||
atmel_uart_write_char(port, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
return;
|
||||
|
||||
while (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY) {
|
||||
atmel_uart_write_char(port, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (!uart_circ_empty(xmit)) {
|
||||
pending = uart_port_tx(port, ch,
|
||||
atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY,
|
||||
atmel_uart_write_char(port, ch));
|
||||
if (pending) {
|
||||
/* we still have characters to transmit, so we should continue
|
||||
* transmitting them when TX is ready, regardless of
|
||||
* mode or duplexity
|
||||
|
@ -875,10 +866,7 @@ static void atmel_complete_tx_dma(void *arg)
|
|||
|
||||
if (chan)
|
||||
dmaengine_terminate_all(chan);
|
||||
xmit->tail += atmel_port->tx_len;
|
||||
xmit->tail &= UART_XMIT_SIZE - 1;
|
||||
|
||||
port->icount.tx += atmel_port->tx_len;
|
||||
uart_xmit_advance(port, atmel_port->tx_len);
|
||||
|
||||
spin_lock_irq(&atmel_port->lock_tx);
|
||||
async_tx_ack(atmel_port->desc_tx);
|
||||
|
@ -1471,11 +1459,7 @@ static void atmel_tx_pdc(struct uart_port *port)
|
|||
/* nothing left to transmit? */
|
||||
if (atmel_uart_readl(port, ATMEL_PDC_TCR))
|
||||
return;
|
||||
|
||||
xmit->tail += pdc->ofs;
|
||||
xmit->tail &= UART_XMIT_SIZE - 1;
|
||||
|
||||
port->icount.tx += pdc->ofs;
|
||||
uart_xmit_advance(port, pdc->ofs);
|
||||
pdc->ofs = 0;
|
||||
|
||||
/* more to transmit - setup next transfer */
|
||||
|
|
|
@ -303,53 +303,24 @@ static void bcm_uart_do_rx(struct uart_port *port)
|
|||
*/
|
||||
static void bcm_uart_do_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit;
|
||||
unsigned int val, max_count;
|
||||
|
||||
if (port->x_char) {
|
||||
bcm_uart_writel(port, port->x_char, UART_FIFO_REG);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_tx_stopped(port)) {
|
||||
bcm_uart_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
xmit = &port->state->xmit;
|
||||
if (uart_circ_empty(xmit))
|
||||
goto txq_empty;
|
||||
unsigned int val;
|
||||
bool pending;
|
||||
u8 ch;
|
||||
|
||||
val = bcm_uart_readl(port, UART_MCTL_REG);
|
||||
val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT;
|
||||
max_count = port->fifosize - val;
|
||||
|
||||
while (max_count--) {
|
||||
unsigned int c;
|
||||
pending = uart_port_tx_limited(port, ch, port->fifosize - val,
|
||||
true,
|
||||
bcm_uart_writel(port, ch, UART_FIFO_REG),
|
||||
({}));
|
||||
if (pending)
|
||||
return;
|
||||
|
||||
c = xmit->buf[xmit->tail];
|
||||
bcm_uart_writel(port, c, UART_FIFO_REG);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
goto txq_empty;
|
||||
return;
|
||||
|
||||
txq_empty:
|
||||
/* nothing to send, disable transmit interrupt */
|
||||
val = bcm_uart_readl(port, UART_IR_REG);
|
||||
val &= ~UART_TX_INT_MASK;
|
||||
bcm_uart_writel(port, val, UART_IR_REG);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -166,8 +166,7 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
|
|||
u32 sysflg = 0;
|
||||
|
||||
writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
|
||||
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
|
||||
if (sysflg & SYSFLG_UTXFF)
|
||||
|
|
|
@ -684,8 +684,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
|
|||
p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
|
||||
while (count < pinfo->tx_fifosize) {
|
||||
*p++ = xmit->buf[xmit->tail];
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
count++;
|
||||
if (xmit->head == xmit->tail)
|
||||
break;
|
||||
|
|
|
@ -202,8 +202,7 @@ static void digicolor_uart_tx(struct uart_port *port)
|
|||
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
writeb(xmit->buf[xmit->tail], port->membase + UA_EMI_REC);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
|
||||
if (digicolor_uart_tx_full(port))
|
||||
break;
|
||||
|
|
|
@ -279,9 +279,8 @@ static inline void dz_transmit_chars(struct dz_mux *mux)
|
|||
* so we go one char at a time) :-<
|
||||
*/
|
||||
tmp = xmit->buf[xmit->tail];
|
||||
xmit->tail = (xmit->tail + 1) & (DZ_XMIT_SIZE - 1);
|
||||
dz_out(dport, DZ_TDR, tmp);
|
||||
dport->port.icount.tx++;
|
||||
uart_xmit_advance(&dport->port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
|
||||
uart_write_wakeup(&dport->port);
|
||||
|
|
|
@ -178,8 +178,7 @@ static inline void linflex_transmit_buffer(struct uart_port *sport)
|
|||
|
||||
while (!uart_circ_empty(xmit)) {
|
||||
linflex_put_char(sport, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
sport->icount.tx++;
|
||||
uart_xmit_advance(sport, 1);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_dma.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/serial_core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
@ -232,6 +234,7 @@
|
|||
|
||||
/* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */
|
||||
#define DMA_RX_TIMEOUT (10)
|
||||
#define UART_AUTOSUSPEND_TIMEOUT 3000
|
||||
|
||||
#define DRIVER_NAME "fsl-lpuart"
|
||||
#define DEV_NAME "ttyLP"
|
||||
|
@ -509,9 +512,7 @@ static void lpuart_dma_tx_complete(void *arg)
|
|||
dma_unmap_sg(chan->device->dev, sgl, sport->dma_tx_nents,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1);
|
||||
|
||||
sport->port.icount.tx += sport->dma_tx_bytes;
|
||||
uart_xmit_advance(&sport->port, sport->dma_tx_bytes);
|
||||
sport->dma_tx_in_progress = false;
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
|
||||
|
@ -582,7 +583,7 @@ static void lpuart_flush_buffer(struct uart_port *port)
|
|||
sport->dma_tx_nents, DMA_TO_DEVICE);
|
||||
sport->dma_tx_in_progress = false;
|
||||
}
|
||||
dmaengine_terminate_all(chan);
|
||||
dmaengine_terminate_async(chan);
|
||||
}
|
||||
|
||||
if (lpuart_is_32(sport)) {
|
||||
|
@ -716,32 +717,12 @@ static int lpuart32_poll_get_char(struct uart_port *port)
|
|||
|
||||
static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
struct uart_port *port = &sport->port;
|
||||
u8 ch;
|
||||
|
||||
if (sport->port.x_char) {
|
||||
writeb(sport->port.x_char, sport->port.membase + UARTDR);
|
||||
sport->port.icount.tx++;
|
||||
sport->port.x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (lpuart_stopped_or_empty(&sport->port)) {
|
||||
lpuart_stop_tx(&sport->port);
|
||||
return;
|
||||
}
|
||||
|
||||
while (!uart_circ_empty(xmit) &&
|
||||
(readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size)) {
|
||||
writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
sport->port.icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
lpuart_stop_tx(&sport->port);
|
||||
uart_port_tx(port, ch,
|
||||
readb(port->membase + UARTTCFIFO) < sport->txfifo_size,
|
||||
writeb(ch, port->membase + UARTDR));
|
||||
}
|
||||
|
||||
static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
|
||||
|
@ -766,8 +747,7 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
|
|||
txcnt &= UARTWATER_COUNT_MASK;
|
||||
while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) {
|
||||
lpuart32_write(&sport->port, xmit->buf[xmit->tail], UARTDATA);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
sport->port.icount.tx++;
|
||||
uart_xmit_advance(&sport->port, 1);
|
||||
txcnt = lpuart32_read(&sport->port, UARTWATER);
|
||||
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
|
||||
txcnt &= UARTWATER_COUNT_MASK;
|
||||
|
@ -815,6 +795,20 @@ static void lpuart32_start_tx(struct uart_port *port)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lpuart_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
|
||||
{
|
||||
switch (state) {
|
||||
case UART_PM_STATE_OFF:
|
||||
pm_runtime_mark_last_busy(port->dev);
|
||||
pm_runtime_put_autosuspend(port->dev);
|
||||
break;
|
||||
default:
|
||||
pm_runtime_get_sync(port->dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* return TIOCSER_TEMT when transmitter is not busy */
|
||||
static unsigned int lpuart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
|
@ -1333,7 +1327,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
|
|||
struct lpuart_port, port);
|
||||
struct dma_chan *chan = sport->dma_rx_chan;
|
||||
|
||||
dmaengine_terminate_all(chan);
|
||||
dmaengine_terminate_sync(chan);
|
||||
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
|
||||
kfree(sport->rx_ring.buf);
|
||||
sport->rx_ring.tail = 0;
|
||||
|
@ -1650,10 +1644,23 @@ err:
|
|||
sport->lpuart_dma_rx_use = false;
|
||||
}
|
||||
|
||||
static void lpuart_hw_setup(struct lpuart_port *sport)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
lpuart_setup_watermark_enable(sport);
|
||||
|
||||
lpuart_rx_dma_startup(sport);
|
||||
lpuart_tx_dma_startup(sport);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
static int lpuart_startup(struct uart_port *port)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
||||
unsigned long flags;
|
||||
unsigned char temp;
|
||||
|
||||
/* determine FIFO size and enable FIFO mode */
|
||||
|
@ -1667,15 +1674,7 @@ static int lpuart_startup(struct uart_port *port)
|
|||
UARTPFIFO_FIFOSIZE_MASK);
|
||||
|
||||
lpuart_request_dma(sport);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
lpuart_setup_watermark_enable(sport);
|
||||
|
||||
lpuart_rx_dma_startup(sport);
|
||||
lpuart_tx_dma_startup(sport);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
lpuart_hw_setup(sport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1698,10 +1697,25 @@ static void lpuart32_configure(struct lpuart_port *sport)
|
|||
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||
}
|
||||
|
||||
static void lpuart32_hw_setup(struct lpuart_port *sport)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
lpuart32_setup_watermark_enable(sport);
|
||||
|
||||
lpuart_rx_dma_startup(sport);
|
||||
lpuart_tx_dma_startup(sport);
|
||||
|
||||
lpuart32_configure(sport);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
static int lpuart32_startup(struct uart_port *port)
|
||||
{
|
||||
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
|
||||
unsigned long flags;
|
||||
unsigned long temp;
|
||||
|
||||
/* determine FIFO size */
|
||||
|
@ -1726,17 +1740,8 @@ static int lpuart32_startup(struct uart_port *port)
|
|||
}
|
||||
|
||||
lpuart_request_dma(sport);
|
||||
lpuart32_hw_setup(sport);
|
||||
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
lpuart32_setup_watermark_enable(sport);
|
||||
|
||||
lpuart_rx_dma_startup(sport);
|
||||
lpuart_tx_dma_startup(sport);
|
||||
|
||||
lpuart32_configure(sport);
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1752,7 +1757,7 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport)
|
|||
if (wait_event_interruptible_timeout(sport->dma_wait,
|
||||
!sport->dma_tx_in_progress, msecs_to_jiffies(300)) <= 0) {
|
||||
sport->dma_tx_in_progress = false;
|
||||
dmaengine_terminate_all(sport->dma_tx_chan);
|
||||
dmaengine_terminate_sync(sport->dma_tx_chan);
|
||||
}
|
||||
sport->lpuart_dma_tx_use = false;
|
||||
}
|
||||
|
@ -2240,6 +2245,7 @@ static const struct uart_ops lpuart_pops = {
|
|||
.startup = lpuart_startup,
|
||||
.shutdown = lpuart_shutdown,
|
||||
.set_termios = lpuart_set_termios,
|
||||
.pm = lpuart_uart_pm,
|
||||
.type = lpuart_type,
|
||||
.request_port = lpuart_request_port,
|
||||
.release_port = lpuart_release_port,
|
||||
|
@ -2264,6 +2270,7 @@ static const struct uart_ops lpuart32_pops = {
|
|||
.startup = lpuart32_startup,
|
||||
.shutdown = lpuart32_shutdown,
|
||||
.set_termios = lpuart32_set_termios,
|
||||
.pm = lpuart_uart_pm,
|
||||
.type = lpuart_type,
|
||||
.request_port = lpuart_request_port,
|
||||
.release_port = lpuart_release_port,
|
||||
|
@ -2744,6 +2751,11 @@ static int lpuart_probe(struct platform_device *pdev)
|
|||
handler = lpuart_int;
|
||||
}
|
||||
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = lpuart_global_reset(sport);
|
||||
if (ret)
|
||||
goto failed_reset;
|
||||
|
@ -2768,6 +2780,9 @@ failed_irq_request:
|
|||
failed_attach_port:
|
||||
failed_get_rs485:
|
||||
failed_reset:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
lpuart_disable_clks(sport);
|
||||
return ret;
|
||||
}
|
||||
|
@ -2786,100 +2801,241 @@ static int lpuart_remove(struct platform_device *pdev)
|
|||
if (sport->dma_rx_chan)
|
||||
dma_release_channel(sport->dma_rx_chan);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_dont_use_autosuspend(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused lpuart_suspend(struct device *dev)
|
||||
static int lpuart_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct lpuart_port *sport = dev_get_drvdata(dev);
|
||||
unsigned long temp;
|
||||
bool irq_wake;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct lpuart_port *sport = platform_get_drvdata(pdev);
|
||||
|
||||
lpuart_disable_clks(sport);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int lpuart_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct lpuart_port *sport = platform_get_drvdata(pdev);
|
||||
|
||||
return lpuart_enable_clks(sport);
|
||||
};
|
||||
|
||||
static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on)
|
||||
{
|
||||
unsigned int val, baud;
|
||||
|
||||
if (lpuart_is_32(sport)) {
|
||||
/* disable Rx/Tx and interrupts */
|
||||
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
|
||||
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||
} else {
|
||||
/* disable Rx/Tx and interrupts */
|
||||
temp = readb(sport->port.membase + UARTCR2);
|
||||
temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
|
||||
writeb(temp, sport->port.membase + UARTCR2);
|
||||
}
|
||||
|
||||
uart_suspend_port(&lpuart_reg, &sport->port);
|
||||
|
||||
/* uart_suspend_port() might set wakeup flag */
|
||||
irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
|
||||
|
||||
if (sport->lpuart_dma_rx_use) {
|
||||
/*
|
||||
* EDMA driver during suspend will forcefully release any
|
||||
* non-idle DMA channels. If port wakeup is enabled or if port
|
||||
* is console port or 'no_console_suspend' is set the Rx DMA
|
||||
* cannot resume as expected, hence gracefully release the
|
||||
* Rx DMA path before suspend and start Rx DMA path on resume.
|
||||
*/
|
||||
if (irq_wake) {
|
||||
del_timer_sync(&sport->lpuart_timer);
|
||||
lpuart_dma_rx_free(&sport->port);
|
||||
}
|
||||
|
||||
/* Disable Rx DMA to use UART port as wakeup source */
|
||||
if (lpuart_is_32(sport)) {
|
||||
temp = lpuart32_read(&sport->port, UARTBAUD);
|
||||
lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE,
|
||||
UARTBAUD);
|
||||
val = lpuart32_read(&sport->port, UARTCTRL);
|
||||
baud = lpuart32_read(&sport->port, UARTBAUD);
|
||||
if (on) {
|
||||
/* set rx_watermark to 0 in wakeup source mode */
|
||||
lpuart32_write(&sport->port, 0, UARTWATER);
|
||||
val |= UARTCTRL_RIE;
|
||||
/* clear RXEDGIF flag before enable RXEDGIE interrupt */
|
||||
lpuart32_write(&sport->port, UARTSTAT_RXEDGIF, UARTSTAT);
|
||||
baud |= UARTBAUD_RXEDGIE;
|
||||
} else {
|
||||
writeb(readb(sport->port.membase + UARTCR5) &
|
||||
~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
|
||||
val &= ~UARTCTRL_RIE;
|
||||
baud &= ~UARTBAUD_RXEDGIE;
|
||||
}
|
||||
lpuart32_write(&sport->port, val, UARTCTRL);
|
||||
lpuart32_write(&sport->port, baud, UARTBAUD);
|
||||
} else {
|
||||
val = readb(sport->port.membase + UARTCR2);
|
||||
if (on)
|
||||
val |= UARTCR2_RIE;
|
||||
else
|
||||
val &= ~UARTCR2_RIE;
|
||||
writeb(val, sport->port.membase + UARTCR2);
|
||||
}
|
||||
|
||||
if (sport->lpuart_dma_tx_use) {
|
||||
sport->dma_tx_in_progress = false;
|
||||
dmaengine_terminate_all(sport->dma_tx_chan);
|
||||
}
|
||||
|
||||
if (sport->port.suspended && !irq_wake)
|
||||
lpuart_disable_clks(sport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused lpuart_resume(struct device *dev)
|
||||
static bool lpuart_uport_is_active(struct lpuart_port *sport)
|
||||
{
|
||||
struct tty_port *port = &sport->port.state->port;
|
||||
struct tty_struct *tty;
|
||||
struct device *tty_dev;
|
||||
int may_wake = 0;
|
||||
|
||||
tty = tty_port_tty_get(port);
|
||||
if (tty) {
|
||||
tty_dev = tty->dev;
|
||||
may_wake = device_may_wakeup(tty_dev);
|
||||
tty_kref_put(tty);
|
||||
}
|
||||
|
||||
if ((tty_port_initialized(port) && may_wake) ||
|
||||
(!console_suspend_enabled && uart_console(&sport->port)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int lpuart_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct lpuart_port *sport = dev_get_drvdata(dev);
|
||||
bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq));
|
||||
|
||||
if (sport->port.suspended && !irq_wake)
|
||||
lpuart_enable_clks(sport);
|
||||
if (lpuart_uport_is_active(sport))
|
||||
serial_lpuart_enable_wakeup(sport, !!irq_wake);
|
||||
|
||||
if (lpuart_is_32(sport))
|
||||
lpuart32_setup_watermark_enable(sport);
|
||||
else
|
||||
lpuart_setup_watermark_enable(sport);
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
|
||||
if (sport->lpuart_dma_rx_use) {
|
||||
if (irq_wake) {
|
||||
if (!lpuart_start_rx_dma(sport))
|
||||
rx_dma_timer_init(sport);
|
||||
else
|
||||
sport->lpuart_dma_rx_use = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpuart_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct lpuart_port *sport = dev_get_drvdata(dev);
|
||||
unsigned int val;
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
if (lpuart_uport_is_active(sport)) {
|
||||
serial_lpuart_enable_wakeup(sport, false);
|
||||
|
||||
/* clear the wakeup flags */
|
||||
if (lpuart_is_32(sport)) {
|
||||
val = lpuart32_read(&sport->port, UARTSTAT);
|
||||
lpuart32_write(&sport->port, val, UARTSTAT);
|
||||
}
|
||||
}
|
||||
|
||||
lpuart_tx_dma_startup(sport);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lpuart_is_32(sport))
|
||||
lpuart32_configure(sport);
|
||||
static int lpuart_suspend(struct device *dev)
|
||||
{
|
||||
struct lpuart_port *sport = dev_get_drvdata(dev);
|
||||
unsigned long temp, flags;
|
||||
|
||||
uart_suspend_port(&lpuart_reg, &sport->port);
|
||||
|
||||
if (lpuart_uport_is_active(sport)) {
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
if (lpuart_is_32(sport)) {
|
||||
/* disable Rx/Tx and interrupts */
|
||||
temp = lpuart32_read(&sport->port, UARTCTRL);
|
||||
temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
|
||||
lpuart32_write(&sport->port, temp, UARTCTRL);
|
||||
} else {
|
||||
/* disable Rx/Tx and interrupts */
|
||||
temp = readb(sport->port.membase + UARTCR2);
|
||||
temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
|
||||
writeb(temp, sport->port.membase + UARTCR2);
|
||||
}
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
|
||||
if (sport->lpuart_dma_rx_use) {
|
||||
/*
|
||||
* EDMA driver during suspend will forcefully release any
|
||||
* non-idle DMA channels. If port wakeup is enabled or if port
|
||||
* is console port or 'no_console_suspend' is set the Rx DMA
|
||||
* cannot resume as expected, hence gracefully release the
|
||||
* Rx DMA path before suspend and start Rx DMA path on resume.
|
||||
*/
|
||||
del_timer_sync(&sport->lpuart_timer);
|
||||
lpuart_dma_rx_free(&sport->port);
|
||||
|
||||
/* Disable Rx DMA to use UART port as wakeup source */
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
if (lpuart_is_32(sport)) {
|
||||
temp = lpuart32_read(&sport->port, UARTBAUD);
|
||||
lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE,
|
||||
UARTBAUD);
|
||||
} else {
|
||||
writeb(readb(sport->port.membase + UARTCR5) &
|
||||
~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
|
||||
}
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
}
|
||||
|
||||
if (sport->lpuart_dma_tx_use) {
|
||||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
if (lpuart_is_32(sport)) {
|
||||
temp = lpuart32_read(&sport->port, UARTBAUD);
|
||||
temp &= ~UARTBAUD_TDMAE;
|
||||
lpuart32_write(&sport->port, temp, UARTBAUD);
|
||||
} else {
|
||||
temp = readb(sport->port.membase + UARTCR5);
|
||||
temp &= ~UARTCR5_TDMAS;
|
||||
writeb(temp, sport->port.membase + UARTCR5);
|
||||
}
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
sport->dma_tx_in_progress = false;
|
||||
dmaengine_terminate_sync(sport->dma_tx_chan);
|
||||
}
|
||||
} else if (pm_runtime_active(sport->port.dev)) {
|
||||
lpuart_disable_clks(sport);
|
||||
pm_runtime_disable(sport->port.dev);
|
||||
pm_runtime_set_suspended(sport->port.dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lpuart_console_fixup(struct lpuart_port *sport)
|
||||
{
|
||||
struct tty_port *port = &sport->port.state->port;
|
||||
struct uart_port *uport = &sport->port;
|
||||
struct ktermios termios;
|
||||
|
||||
/* i.MX7ULP enter VLLS mode that lpuart module power off and registers
|
||||
* all lost no matter the port is wakeup source.
|
||||
* For console port, console baud rate setting lost and print messy
|
||||
* log when enable the console port as wakeup source. To avoid the
|
||||
* issue happen, user should not enable uart port as wakeup source
|
||||
* in VLLS mode, or restore console setting here.
|
||||
*/
|
||||
if (is_imx7ulp_lpuart(sport) && lpuart_uport_is_active(sport) &&
|
||||
console_suspend_enabled && uart_console(&sport->port)) {
|
||||
|
||||
mutex_lock(&port->mutex);
|
||||
memset(&termios, 0, sizeof(struct ktermios));
|
||||
termios.c_cflag = uport->cons->cflag;
|
||||
if (port->tty && termios.c_cflag == 0)
|
||||
termios = port->tty->termios;
|
||||
uport->ops->set_termios(uport, &termios, NULL);
|
||||
mutex_unlock(&port->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static int lpuart_resume(struct device *dev)
|
||||
{
|
||||
struct lpuart_port *sport = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (lpuart_uport_is_active(sport)) {
|
||||
if (lpuart_is_32(sport))
|
||||
lpuart32_hw_setup(sport);
|
||||
else
|
||||
lpuart_hw_setup(sport);
|
||||
} else if (pm_runtime_active(sport->port.dev)) {
|
||||
ret = lpuart_enable_clks(sport);
|
||||
if (ret)
|
||||
return ret;
|
||||
pm_runtime_set_active(sport->port.dev);
|
||||
pm_runtime_enable(sport->port.dev);
|
||||
}
|
||||
|
||||
lpuart_console_fixup(sport);
|
||||
uart_resume_port(&lpuart_reg, &sport->port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(lpuart_pm_ops, lpuart_suspend, lpuart_resume);
|
||||
static const struct dev_pm_ops lpuart_pm_ops = {
|
||||
RUNTIME_PM_OPS(lpuart_runtime_suspend,
|
||||
lpuart_runtime_resume, NULL)
|
||||
NOIRQ_SYSTEM_SLEEP_PM_OPS(lpuart_suspend_noirq,
|
||||
lpuart_resume_noirq)
|
||||
SYSTEM_SLEEP_PM_OPS(lpuart_suspend, lpuart_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver lpuart_driver = {
|
||||
.probe = lpuart_probe,
|
||||
|
@ -2887,7 +3043,7 @@ static struct platform_driver lpuart_driver = {
|
|||
.driver = {
|
||||
.name = "fsl-lpuart",
|
||||
.of_match_table = lpuart_dt_ids,
|
||||
.pm = &lpuart_pm_ops,
|
||||
.pm = pm_ptr(&lpuart_pm_ops),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -489,7 +489,7 @@ static void imx_uart_stop_tx(struct uart_port *port)
|
|||
static void imx_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
u32 ucr1, ucr2, ucr4;
|
||||
u32 ucr1, ucr2, ucr4, uts;
|
||||
|
||||
ucr1 = imx_uart_readl(sport, UCR1);
|
||||
ucr2 = imx_uart_readl(sport, UCR2);
|
||||
|
@ -505,7 +505,18 @@ static void imx_uart_stop_rx(struct uart_port *port)
|
|||
imx_uart_writel(sport, ucr1, UCR1);
|
||||
imx_uart_writel(sport, ucr4, UCR4);
|
||||
|
||||
ucr2 &= ~UCR2_RXEN;
|
||||
/* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
|
||||
if (port->rs485.flags & SER_RS485_ENABLED &&
|
||||
port->rs485.flags & SER_RS485_RTS_ON_SEND &&
|
||||
sport->have_rtscts && !sport->have_rtsgpio) {
|
||||
uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
|
||||
uts |= UTS_LOOP;
|
||||
imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
|
||||
ucr2 |= UCR2_RXEN;
|
||||
} else {
|
||||
ucr2 &= ~UCR2_RXEN;
|
||||
}
|
||||
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
}
|
||||
|
||||
|
@ -563,8 +574,7 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport)
|
|||
/* send xmit->buf[xmit->tail]
|
||||
* out the port here */
|
||||
imx_uart_writel(sport, xmit->buf[xmit->tail], URTX0);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
sport->port.icount.tx++;
|
||||
uart_xmit_advance(&sport->port, 1);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
@ -590,9 +600,7 @@ static void imx_uart_dma_tx_callback(void *data)
|
|||
ucr1 &= ~UCR1_TXDMAEN;
|
||||
imx_uart_writel(sport, ucr1, UCR1);
|
||||
|
||||
/* update the stat */
|
||||
xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
|
||||
sport->port.icount.tx += sport->tx_bytes;
|
||||
uart_xmit_advance(&sport->port, sport->tx_bytes);
|
||||
|
||||
dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
|
||||
|
||||
|
@ -1393,7 +1401,7 @@ static int imx_uart_startup(struct uart_port *port)
|
|||
int retval, i;
|
||||
unsigned long flags;
|
||||
int dma_is_inited = 0;
|
||||
u32 ucr1, ucr2, ucr3, ucr4;
|
||||
u32 ucr1, ucr2, ucr3, ucr4, uts;
|
||||
|
||||
retval = clk_prepare_enable(sport->clk_per);
|
||||
if (retval)
|
||||
|
@ -1498,6 +1506,11 @@ static int imx_uart_startup(struct uart_port *port)
|
|||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
}
|
||||
|
||||
/* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
|
||||
uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
|
||||
uts &= ~UTS_LOOP;
|
||||
imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
|
||||
|
||||
spin_unlock_irqrestore(&sport->port.lock, flags);
|
||||
|
||||
return 0;
|
||||
|
@ -1507,7 +1520,7 @@ static void imx_uart_shutdown(struct uart_port *port)
|
|||
{
|
||||
struct imx_port *sport = (struct imx_port *)port;
|
||||
unsigned long flags;
|
||||
u32 ucr1, ucr2, ucr4;
|
||||
u32 ucr1, ucr2, ucr4, uts;
|
||||
|
||||
if (sport->dma_is_enabled) {
|
||||
dmaengine_terminate_sync(sport->dma_chan_tx);
|
||||
|
@ -1551,7 +1564,18 @@ static void imx_uart_shutdown(struct uart_port *port)
|
|||
spin_lock_irqsave(&sport->port.lock, flags);
|
||||
|
||||
ucr1 = imx_uart_readl(sport, UCR1);
|
||||
ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | UCR1_RXDMAEN | UCR1_ATDMAEN);
|
||||
ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_RXDMAEN | UCR1_ATDMAEN);
|
||||
/* See SER_RS485_ENABLED/UTS_LOOP comment in imx_uart_probe() */
|
||||
if (port->rs485.flags & SER_RS485_ENABLED &&
|
||||
port->rs485.flags & SER_RS485_RTS_ON_SEND &&
|
||||
sport->have_rtscts && !sport->have_rtsgpio) {
|
||||
uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
|
||||
uts |= UTS_LOOP;
|
||||
imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
|
||||
ucr1 |= UCR1_UARTEN;
|
||||
} else {
|
||||
ucr1 &= ~UCR1_UARTEN;
|
||||
}
|
||||
imx_uart_writel(sport, ucr1, UCR1);
|
||||
|
||||
ucr4 = imx_uart_readl(sport, UCR4);
|
||||
|
@ -2213,7 +2237,7 @@ static int imx_uart_probe(struct platform_device *pdev)
|
|||
void __iomem *base;
|
||||
u32 dma_buf_conf[2];
|
||||
int ret = 0;
|
||||
u32 ucr1;
|
||||
u32 ucr1, ucr2, uts;
|
||||
struct resource *res;
|
||||
int txirq, rxirq, rtsirq;
|
||||
|
||||
|
@ -2350,6 +2374,31 @@ static int imx_uart_probe(struct platform_device *pdev)
|
|||
ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_RTSDEN);
|
||||
imx_uart_writel(sport, ucr1, UCR1);
|
||||
|
||||
/*
|
||||
* In case RS485 is enabled without GPIO RTS control, the UART IP
|
||||
* is used to control CTS signal. Keep both the UART and Receiver
|
||||
* enabled, otherwise the UART IP pulls CTS signal always HIGH no
|
||||
* matter how the UCR2 CTSC and CTS bits are set. To prevent any
|
||||
* data from being fed into the RX FIFO, enable loopback mode in
|
||||
* UTS register, which disconnects the RX path from external RXD
|
||||
* pin and connects it to the Transceiver, which is disabled, so
|
||||
* no data can be fed to the RX FIFO that way.
|
||||
*/
|
||||
if (sport->port.rs485.flags & SER_RS485_ENABLED &&
|
||||
sport->have_rtscts && !sport->have_rtsgpio) {
|
||||
uts = imx_uart_readl(sport, imx_uart_uts_reg(sport));
|
||||
uts |= UTS_LOOP;
|
||||
imx_uart_writel(sport, uts, imx_uart_uts_reg(sport));
|
||||
|
||||
ucr1 = imx_uart_readl(sport, UCR1);
|
||||
ucr1 |= UCR1_UARTEN;
|
||||
imx_uart_writel(sport, ucr1, UCR1);
|
||||
|
||||
ucr2 = imx_uart_readl(sport, UCR2);
|
||||
ucr2 |= UCR2_RXEN;
|
||||
imx_uart_writel(sport, ucr2, UCR2);
|
||||
}
|
||||
|
||||
if (!imx_uart_is_imx1(sport) && sport->dte_mode) {
|
||||
/*
|
||||
* The DCEDTE bit changes the direction of DSR, DCD, DTR and RI
|
||||
|
|
|
@ -409,8 +409,7 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
|
|||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
@ -609,8 +608,7 @@ static void ip22zilog_start_tx(struct uart_port *port)
|
|||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
|
|
@ -95,7 +95,6 @@
|
|||
#define ASCFSTAT_TXFFLMASK 0x3F00
|
||||
#define ASCFSTAT_TXFREEMASK 0x3F000000
|
||||
|
||||
static void lqasc_tx_chars(struct uart_port *port);
|
||||
static struct ltq_uart_port *lqasc_port[MAXPORTS];
|
||||
static struct uart_driver lqasc_reg;
|
||||
|
||||
|
@ -151,9 +150,12 @@ lqasc_start_tx(struct uart_port *port)
|
|||
{
|
||||
unsigned long flags;
|
||||
struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
|
||||
u8 ch;
|
||||
|
||||
spin_lock_irqsave(<q_port->lock, flags);
|
||||
lqasc_tx_chars(port);
|
||||
uart_port_tx(port, ch,
|
||||
lqasc_tx_ready(port),
|
||||
writeb(ch, port->membase + LTQ_ASC_TBUF));
|
||||
spin_unlock_irqrestore(<q_port->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
@ -226,36 +228,6 @@ lqasc_rx_chars(struct uart_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
lqasc_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
if (uart_tx_stopped(port)) {
|
||||
lqasc_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
while (lqasc_tx_ready(port)) {
|
||||
if (port->x_char) {
|
||||
writeb(port->x_char, port->membase + LTQ_ASC_TBUF);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
writeb(port->state->xmit.buf[port->state->xmit.tail],
|
||||
port->membase + LTQ_ASC_TBUF);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
lqasc_tx_int(int irq, void *_port)
|
||||
{
|
||||
|
|
|
@ -136,8 +136,7 @@ static void liteuart_start_tx(struct uart_port *port)
|
|||
} else if (!uart_circ_empty(xmit)) {
|
||||
while (xmit->head != xmit->tail) {
|
||||
ch = xmit->buf[xmit->tail];
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
liteuart_putchar(port, ch);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -276,8 +276,6 @@ static void __serial_lpc32xx_rx(struct uart_port *port)
|
|||
tty_flip_buffer_push(tport);
|
||||
}
|
||||
|
||||
static void serial_lpc32xx_stop_tx(struct uart_port *port);
|
||||
|
||||
static bool serial_lpc32xx_tx_ready(struct uart_port *port)
|
||||
{
|
||||
u32 level = readl(LPC32XX_HSUART_LEVEL(port->membase));
|
||||
|
@ -287,34 +285,11 @@ static bool serial_lpc32xx_tx_ready(struct uart_port *port)
|
|||
|
||||
static void __serial_lpc32xx_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char) {
|
||||
writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase));
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
goto exit_tx;
|
||||
|
||||
/* Transfer data */
|
||||
while (serial_lpc32xx_tx_ready(port)) {
|
||||
writel((u32) xmit->buf[xmit->tail],
|
||||
LPC32XX_HSUART_FIFO(port->membase));
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
exit_tx:
|
||||
if (uart_circ_empty(xmit))
|
||||
serial_lpc32xx_stop_tx(port);
|
||||
uart_port_tx(port, ch,
|
||||
serial_lpc32xx_tx_ready(port),
|
||||
writel(ch, LPC32XX_HSUART_FIFO(port->membase)));
|
||||
}
|
||||
|
||||
static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
|
||||
|
|
|
@ -292,9 +292,7 @@ static void max3100_work(struct work_struct *w)
|
|||
} else if (!uart_circ_empty(xmit) &&
|
||||
!uart_tx_stopped(&s->port)) {
|
||||
tx = xmit->buf[xmit->tail];
|
||||
xmit->tail = (xmit->tail + 1) &
|
||||
(UART_XMIT_SIZE - 1);
|
||||
s->port.icount.tx++;
|
||||
uart_xmit_advance(&s->port, 1);
|
||||
}
|
||||
if (tx != 0xffff) {
|
||||
max3100_calc_parity(s, &tx);
|
||||
|
|
|
@ -787,10 +787,7 @@ static void max310x_handle_tx(struct uart_port *port)
|
|||
} else {
|
||||
max310x_batch_write(port, xmit->buf + xmit->tail, to_send);
|
||||
}
|
||||
|
||||
/* Add data to send */
|
||||
port->icount.tx += to_send;
|
||||
xmit->tail = (xmit->tail + to_send) & (UART_XMIT_SIZE - 1);
|
||||
uart_xmit_advance(port, to_send);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
|
|
@ -327,34 +327,16 @@ static void mcf_rx_chars(struct mcf_uart *pp)
|
|||
static void mcf_tx_chars(struct mcf_uart *pp)
|
||||
{
|
||||
struct uart_port *port = &pp->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
bool pending;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char) {
|
||||
/* Send special char - probably flow control */
|
||||
writeb(port->x_char, port->membase + MCFUART_UTB);
|
||||
port->x_char = 0;
|
||||
port->icount.tx++;
|
||||
return;
|
||||
}
|
||||
pending = uart_port_tx(port, ch,
|
||||
readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY,
|
||||
writeb(ch, port->membase + MCFUART_UTB));
|
||||
|
||||
while (readb(port->membase + MCFUART_USR) & MCFUART_USR_TXREADY) {
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
writeb(xmit->buf[xmit->tail], port->membase + MCFUART_UTB);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit)) {
|
||||
mcf_stop_tx(port);
|
||||
/* Disable TX to negate RTS automatically */
|
||||
if (port->rs485.flags & SER_RS485_ENABLED)
|
||||
writeb(MCFUART_UCR_TXDISABLE,
|
||||
port->membase + MCFUART_UCR);
|
||||
}
|
||||
/* Disable TX to negate RTS automatically */
|
||||
if (!pending && (port->rs485.flags & SER_RS485_ENABLED))
|
||||
writeb(MCFUART_UCR_TXDISABLE, port->membase + MCFUART_UCR);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
|
|
@ -352,11 +352,8 @@ static void men_z135_handle_tx(struct men_z135_port *uart)
|
|||
n = min(n, s);
|
||||
|
||||
memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n);
|
||||
xmit->tail = (xmit->tail + n) & (UART_XMIT_SIZE - 1);
|
||||
|
||||
iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL);
|
||||
|
||||
port->icount.tx += n;
|
||||
uart_xmit_advance(port, n);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
|
|
@ -162,8 +162,7 @@ static void meson_uart_start_tx(struct uart_port *port)
|
|||
|
||||
ch = xmit->buf[xmit->tail];
|
||||
writel(ch, port->membase + AML_UART_WFIFO);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
|
||||
if (!uart_circ_empty(xmit)) {
|
||||
|
|
|
@ -98,8 +98,7 @@ static void mlb_usio_tx_chars(struct uart_port *port)
|
|||
do {
|
||||
writew(xmit->buf[xmit->tail], port->membase + MLB_USIO_REG_DR);
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
|
|
|
@ -1428,42 +1428,11 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
|||
static inline bool
|
||||
mpc52xx_uart_int_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
u8 ch;
|
||||
|
||||
/* Process out of band chars */
|
||||
if (port->x_char) {
|
||||
psc_ops->write_char(port, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Nothing to do ? */
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
mpc52xx_uart_stop_tx(port);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Send chars */
|
||||
while (psc_ops->raw_tx_rdy(port)) {
|
||||
psc_ops->write_char(port, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wake up */
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
/* Maybe we're done after all */
|
||||
if (uart_circ_empty(xmit)) {
|
||||
mpc52xx_uart_stop_tx(port);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return uart_port_tx(port, ch,
|
||||
psc_ops->raw_tx_rdy(port),
|
||||
psc_ops->write_char(port, ch));
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
|
|
|
@ -129,29 +129,11 @@ static void mps2_uart_stop_tx(struct uart_port *port)
|
|||
|
||||
static void mps2_uart_tx_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
u8 ch;
|
||||
|
||||
while (!(mps2_uart_read8(port, UARTn_STATE) & UARTn_STATE_TX_FULL)) {
|
||||
if (port->x_char) {
|
||||
mps2_uart_write8(port, port->x_char, UARTn_DATA);
|
||||
port->x_char = 0;
|
||||
port->icount.tx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port))
|
||||
break;
|
||||
|
||||
mps2_uart_write8(port, xmit->buf[xmit->tail], UARTn_DATA);
|
||||
xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE;
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
mps2_uart_stop_tx(port);
|
||||
uart_port_tx(port, ch,
|
||||
mps2_uart_tx_empty(port),
|
||||
mps2_uart_write8(port, ch, UARTn_DATA));
|
||||
}
|
||||
|
||||
static void mps2_uart_start_tx(struct uart_port *port)
|
||||
|
|
|
@ -464,12 +464,9 @@ static void msm_complete_tx_dma(void *args)
|
|||
}
|
||||
|
||||
count = dma->count - state.residue;
|
||||
port->icount.tx += count;
|
||||
uart_xmit_advance(port, count);
|
||||
dma->count = 0;
|
||||
|
||||
xmit->tail += count;
|
||||
xmit->tail &= UART_XMIT_SIZE - 1;
|
||||
|
||||
/* Restore "Tx FIFO below watermark" interrupt */
|
||||
msm_port->imr |= MSM_UART_IMR_TXLEV;
|
||||
msm_write(port, msm_port->imr, MSM_UART_IMR);
|
||||
|
@ -819,7 +816,7 @@ static void msm_handle_rx(struct uart_port *port)
|
|||
port->icount.rx++;
|
||||
}
|
||||
|
||||
/* Mask conditions we're ignorning. */
|
||||
/* Mask conditions we're ignoring. */
|
||||
sr &= port->read_status_mask;
|
||||
|
||||
if (sr & MSM_UART_SR_RX_BREAK)
|
||||
|
@ -866,13 +863,11 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
|
|||
else
|
||||
num_chars = 1;
|
||||
|
||||
for (i = 0; i < num_chars; i++) {
|
||||
for (i = 0; i < num_chars; i++)
|
||||
buf[i] = xmit->buf[xmit->tail + i];
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
iowrite32_rep(tf, buf, 1);
|
||||
xmit->tail = (xmit->tail + num_chars) & (UART_XMIT_SIZE - 1);
|
||||
uart_xmit_advance(port, num_chars);
|
||||
tf_pointer += num_chars;
|
||||
}
|
||||
|
||||
|
|
|
@ -171,6 +171,13 @@ static void mux_break_ctl(struct uart_port *port, int break_state)
|
|||
{
|
||||
}
|
||||
|
||||
static void mux_tx_done(struct uart_port *port)
|
||||
{
|
||||
/* FIXME js: really needs to wait? */
|
||||
while (UART_GET_FIFO_CNT(port))
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* mux_write - Write chars to the mux fifo.
|
||||
* @port: Ptr to the uart_port.
|
||||
|
@ -180,39 +187,13 @@ static void mux_break_ctl(struct uart_port *port, int break_state)
|
|||
*/
|
||||
static void mux_write(struct uart_port *port)
|
||||
{
|
||||
int count;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
u8 ch;
|
||||
|
||||
if(port->x_char) {
|
||||
UART_PUT_CHAR(port, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
mux_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
count = (port->fifosize) - UART_GET_FIFO_CNT(port);
|
||||
do {
|
||||
UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if(uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
} while(--count > 0);
|
||||
|
||||
while(UART_GET_FIFO_CNT(port))
|
||||
udelay(1);
|
||||
|
||||
if(uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
mux_stop_tx(port);
|
||||
uart_port_tx_limited(port, ch,
|
||||
port->fifosize - UART_GET_FIFO_CNT(port),
|
||||
true,
|
||||
UART_PUT_CHAR(port, ch),
|
||||
mux_tx_done(port));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -223,8 +223,7 @@ static void mvebu_uart_start_tx(struct uart_port *port)
|
|||
|
||||
if (IS_EXTENDED(port) && !uart_circ_empty(xmit)) {
|
||||
writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port));
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
|
||||
ctl = readl(port->membase + UART_INTR(port));
|
||||
|
@ -335,40 +334,12 @@ ignore_char:
|
|||
|
||||
static void mvebu_uart_tx_chars(struct uart_port *port, unsigned int status)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int count;
|
||||
unsigned int st;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char) {
|
||||
writel(port->x_char, port->membase + UART_TSH(port));
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
mvebu_uart_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
for (count = 0; count < port->fifosize; count++) {
|
||||
writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port));
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
st = readl(port->membase + UART_STAT);
|
||||
if (st & STAT_TX_FIFO_FUL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
mvebu_uart_stop_tx(port);
|
||||
uart_port_tx_limited(port, ch, port->fifosize,
|
||||
!(readl(port->membase + UART_STAT) & STAT_TX_FIFO_FUL),
|
||||
writel(ch, port->membase + UART_TSH(port)),
|
||||
({}));
|
||||
}
|
||||
|
||||
static irqreturn_t mvebu_uart_isr(int irq, void *dev_id)
|
||||
|
|
|
@ -569,6 +569,8 @@ static int mxs_auart_dma_tx(struct mxs_auart_port *s, int size)
|
|||
static void mxs_auart_tx_chars(struct mxs_auart_port *s)
|
||||
{
|
||||
struct circ_buf *xmit = &s->port.state->xmit;
|
||||
bool pending;
|
||||
u8 ch;
|
||||
|
||||
if (auart_dma_enabled(s)) {
|
||||
u32 i = 0;
|
||||
|
@ -603,31 +605,13 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
while (!(mxs_read(s, REG_STAT) & AUART_STAT_TXFF)) {
|
||||
if (s->port.x_char) {
|
||||
s->port.icount.tx++;
|
||||
mxs_write(s->port.x_char, s, REG_DATA);
|
||||
s->port.x_char = 0;
|
||||
continue;
|
||||
}
|
||||
if (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
|
||||
s->port.icount.tx++;
|
||||
mxs_write(xmit->buf[xmit->tail], s, REG_DATA);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&s->port);
|
||||
|
||||
if (uart_circ_empty(&(s->port.state->xmit)))
|
||||
mxs_clr(AUART_INTR_TXIEN, s, REG_INTR);
|
||||
else
|
||||
pending = uart_port_tx(&s->port, ch,
|
||||
!(mxs_read(s, REG_STAT) & AUART_STAT_TXFF),
|
||||
mxs_write(ch, s, REG_DATA));
|
||||
if (pending)
|
||||
mxs_set(AUART_INTR_TXIEN, s, REG_INTR);
|
||||
|
||||
if (uart_tx_stopped(&s->port))
|
||||
mxs_auart_stop_tx(&s->port);
|
||||
else
|
||||
mxs_clr(AUART_INTR_TXIEN, s, REG_INTR);
|
||||
}
|
||||
|
||||
static void mxs_auart_rx_char(struct mxs_auart_port *s)
|
||||
|
|
|
@ -347,34 +347,12 @@ static void serial_omap_put_char(struct uart_omap_port *up, unsigned char ch)
|
|||
|
||||
static void transmit_chars(struct uart_omap_port *up, unsigned int lsr)
|
||||
{
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
int count;
|
||||
u8 ch;
|
||||
|
||||
if (up->port.x_char) {
|
||||
serial_omap_put_char(up, up->port.x_char);
|
||||
up->port.icount.tx++;
|
||||
up->port.x_char = 0;
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
|
||||
serial_omap_stop_tx(&up->port);
|
||||
return;
|
||||
}
|
||||
count = up->port.fifosize / 4;
|
||||
do {
|
||||
serial_omap_put_char(up, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
serial_omap_stop_tx(&up->port);
|
||||
uart_port_tx_limited(&up->port, ch, up->port.fifosize / 4,
|
||||
true,
|
||||
serial_omap_put_char(up, ch),
|
||||
({}));
|
||||
}
|
||||
|
||||
static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
|
||||
|
|
|
@ -181,35 +181,11 @@ static void owl_uart_start_tx(struct uart_port *port)
|
|||
|
||||
static void owl_uart_send_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
unsigned int ch;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char) {
|
||||
while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU))
|
||||
cpu_relax();
|
||||
owl_uart_write(port, port->x_char, OWL_UART_TXDAT);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
}
|
||||
|
||||
if (uart_tx_stopped(port))
|
||||
return;
|
||||
|
||||
while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)) {
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
ch = xmit->buf[xmit->tail];
|
||||
owl_uart_write(port, ch, OWL_UART_TXDAT);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
owl_uart_stop_tx(port);
|
||||
uart_port_tx(port, ch,
|
||||
!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU),
|
||||
owl_uart_write(port, ch, OWL_UART_TXDAT));
|
||||
}
|
||||
|
||||
static void owl_uart_receive_chars(struct uart_port *port)
|
||||
|
|
|
@ -694,6 +694,7 @@ static void pch_request_dma(struct uart_port *port)
|
|||
if (!chan) {
|
||||
dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Tx)\n",
|
||||
__func__);
|
||||
pci_dev_put(dma_dev);
|
||||
return;
|
||||
}
|
||||
priv->chan_tx = chan;
|
||||
|
@ -710,6 +711,7 @@ static void pch_request_dma(struct uart_port *port)
|
|||
__func__);
|
||||
dma_release_channel(priv->chan_tx);
|
||||
priv->chan_tx = NULL;
|
||||
pci_dev_put(dma_dev);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -717,6 +719,8 @@ static void pch_request_dma(struct uart_port *port)
|
|||
priv->rx_buf_virt = dma_alloc_coherent(port->dev, port->fifosize,
|
||||
&priv->rx_buf_dma, GFP_KERNEL);
|
||||
priv->chan_rx = chan;
|
||||
|
||||
pci_dev_put(dma_dev);
|
||||
}
|
||||
|
||||
static void pch_dma_rx_complete(void *arg)
|
||||
|
@ -738,15 +742,12 @@ static void pch_dma_tx_complete(void *arg)
|
|||
{
|
||||
struct eg20t_port *priv = arg;
|
||||
struct uart_port *port = &priv->port;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct scatterlist *sg = priv->sg_tx_p;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->nent; i++, sg++) {
|
||||
xmit->tail += sg_dma_len(sg);
|
||||
port->icount.tx += sg_dma_len(sg);
|
||||
}
|
||||
xmit->tail &= UART_XMIT_SIZE - 1;
|
||||
for (i = 0; i < priv->nent; i++, sg++)
|
||||
uart_xmit_advance(port, sg_dma_len(sg));
|
||||
|
||||
async_tx_ack(priv->desc_tx);
|
||||
dma_unmap_sg(port->dev, sg, priv->orig_nent, DMA_TO_DEVICE);
|
||||
priv->tx_dma_use = 0;
|
||||
|
@ -843,8 +844,7 @@ static unsigned int handle_tx(struct eg20t_port *priv)
|
|||
|
||||
while (!uart_tx_stopped(port) && !uart_circ_empty(xmit) && fifo_size) {
|
||||
iowrite8(xmit->buf[xmit->tail], priv->membase + PCH_UART_THR);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
fifo_size--;
|
||||
tx_empty = 0;
|
||||
}
|
||||
|
|
|
@ -376,8 +376,7 @@ static void pic32_uart_do_tx(struct uart_port *port)
|
|||
|
||||
pic32_uart_writel(sport, PIC32_UART_TX, c);
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
if (--max_count == 0)
|
||||
|
|
|
@ -410,8 +410,7 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
|
|||
write_zsdata(uap, xmit->buf[xmit->tail]);
|
||||
zssync(uap);
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
uap->port.icount.tx++;
|
||||
uart_xmit_advance(&uap->port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uap->port);
|
||||
|
@ -627,8 +626,7 @@ static void pmz_start_tx(struct uart_port *port)
|
|||
return;
|
||||
write_zsdata(uap, xmit->buf[xmit->tail]);
|
||||
zssync(uap);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&uap->port);
|
||||
|
|
|
@ -174,35 +174,12 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status)
|
|||
|
||||
static void transmit_chars(struct uart_pxa_port *up)
|
||||
{
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
int count;
|
||||
u8 ch;
|
||||
|
||||
if (up->port.x_char) {
|
||||
serial_out(up, UART_TX, up->port.x_char);
|
||||
up->port.icount.tx++;
|
||||
up->port.x_char = 0;
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
|
||||
serial_pxa_stop_tx(&up->port);
|
||||
return;
|
||||
}
|
||||
|
||||
count = up->port.fifosize / 2;
|
||||
do {
|
||||
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
serial_pxa_stop_tx(&up->port);
|
||||
uart_port_tx_limited(&up->port, ch, up->port.fifosize / 2,
|
||||
true,
|
||||
serial_out(up, UART_TX, ch),
|
||||
({}));
|
||||
}
|
||||
|
||||
static void serial_pxa_start_tx(struct uart_port *port)
|
||||
|
|
|
@ -924,6 +924,7 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
|
|||
false, true, true);
|
||||
geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
|
||||
geni_se_select_mode(&port->se, GENI_SE_FIFO);
|
||||
qcom_geni_serial_start_rx(uport);
|
||||
port->setup = true;
|
||||
|
||||
return 0;
|
||||
|
@ -1547,9 +1548,43 @@ static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_geni_serial_sys_hib_resume(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct uart_port *uport;
|
||||
struct qcom_geni_private_data *private_data;
|
||||
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
|
||||
|
||||
uport = &port->uport;
|
||||
private_data = uport->private_data;
|
||||
|
||||
if (uart_console(uport)) {
|
||||
geni_icc_set_tag(&port->se, 0x7);
|
||||
geni_icc_set_bw(&port->se);
|
||||
ret = uart_resume_port(private_data->drv, uport);
|
||||
/*
|
||||
* For hibernation usecase clients for
|
||||
* console UART won't call port setup during restore,
|
||||
* hence call port setup for console uart.
|
||||
*/
|
||||
qcom_geni_serial_port_setup(uport);
|
||||
} else {
|
||||
/*
|
||||
* Peripheral register settings are lost during hibernation.
|
||||
* Update setup flag such that port setup happens again
|
||||
* during next session. Clients of HS-UART will close and
|
||||
* open the port during hibernation.
|
||||
*/
|
||||
port->setup = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend,
|
||||
qcom_geni_serial_sys_resume)
|
||||
.restore = qcom_geni_serial_sys_hib_resume,
|
||||
.thaw = qcom_geni_serial_sys_hib_resume,
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_geni_serial_match_table[] = {
|
||||
|
|
|
@ -353,8 +353,7 @@ static void rda_uart_send_chars(struct uart_port *port)
|
|||
|
||||
ch = xmit->buf[xmit->tail];
|
||||
rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
|
|
@ -427,32 +427,13 @@ static void rp2_rx_chars(struct rp2_uart_port *up)
|
|||
|
||||
static void rp2_tx_chars(struct rp2_uart_port *up)
|
||||
{
|
||||
u16 max_tx = FIFO_SIZE - readw(up->base + RP2_TX_FIFO_COUNT);
|
||||
struct circ_buf *xmit = &up->port.state->xmit;
|
||||
u8 ch;
|
||||
|
||||
if (uart_tx_stopped(&up->port)) {
|
||||
rp2_uart_stop_tx(&up->port);
|
||||
return;
|
||||
}
|
||||
|
||||
for (; max_tx != 0; max_tx--) {
|
||||
if (up->port.x_char) {
|
||||
writeb(up->port.x_char, up->base + RP2_DATA_BYTE);
|
||||
up->port.x_char = 0;
|
||||
up->port.icount.tx++;
|
||||
continue;
|
||||
}
|
||||
if (uart_circ_empty(xmit)) {
|
||||
rp2_uart_stop_tx(&up->port);
|
||||
break;
|
||||
}
|
||||
writeb(xmit->buf[xmit->tail], up->base + RP2_DATA_BYTE);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
uart_port_tx_limited(&up->port, ch,
|
||||
FIFO_SIZE - readw(up->base + RP2_TX_FIFO_COUNT),
|
||||
true,
|
||||
writeb(ch, up->base + RP2_DATA_BYTE),
|
||||
({}));
|
||||
}
|
||||
|
||||
static void rp2_ch_interrupt(struct rp2_uart_port *up)
|
||||
|
|
|
@ -228,14 +228,7 @@ sa1100_rx_chars(struct sa1100_port *sport)
|
|||
|
||||
static void sa1100_tx_chars(struct sa1100_port *sport)
|
||||
{
|
||||
struct circ_buf *xmit = &sport->port.state->xmit;
|
||||
|
||||
if (sport->port.x_char) {
|
||||
UART_PUT_CHAR(sport, sport->port.x_char);
|
||||
sport->port.icount.tx++;
|
||||
sport->port.x_char = 0;
|
||||
return;
|
||||
}
|
||||
u8 ch;
|
||||
|
||||
/*
|
||||
* Check the modem control lines before
|
||||
|
@ -243,28 +236,9 @@ static void sa1100_tx_chars(struct sa1100_port *sport)
|
|||
*/
|
||||
sa1100_mctrl_check(sport);
|
||||
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
|
||||
sa1100_stop_tx(&sport->port);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tried using FIFO (not checking TNF) for fifo fill:
|
||||
* still had the '4 bytes repeated' problem.
|
||||
*/
|
||||
while (UART_GET_UTSR1(sport) & UTSR1_TNF) {
|
||||
UART_PUT_CHAR(sport, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
sport->port.icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
sa1100_stop_tx(&sport->port);
|
||||
uart_port_tx(&sport->port, ch,
|
||||
UART_GET_UTSR1(sport) & UTSR1_TNF,
|
||||
UART_PUT_CHAR(sport, ch));
|
||||
}
|
||||
|
||||
static irqreturn_t sa1100_int(int irq, void *dev_id)
|
||||
|
|
|
@ -288,7 +288,6 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
|
|||
{
|
||||
struct s3c24xx_uart_port *ourport = to_ourport(port);
|
||||
struct s3c24xx_uart_dma *dma = ourport->dma;
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
struct dma_tx_state state;
|
||||
int count;
|
||||
|
||||
|
@ -316,8 +315,7 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
|
|||
DMA_TO_DEVICE);
|
||||
async_tx_ack(dma->tx_desc);
|
||||
count = dma->tx_bytes_requested - state.residue;
|
||||
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx += count;
|
||||
uart_xmit_advance(port, count);
|
||||
}
|
||||
|
||||
ourport->tx_enabled = 0;
|
||||
|
@ -351,8 +349,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
|
|||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx += count;
|
||||
uart_xmit_advance(port, count);
|
||||
ourport->tx_in_progress = 0;
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
@ -916,8 +913,7 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
|
|||
break;
|
||||
|
||||
wr_reg(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
count--;
|
||||
}
|
||||
|
||||
|
|
|
@ -399,8 +399,7 @@ static void sbd_transmit_chars(struct sbd_port *sport)
|
|||
/* Send char. */
|
||||
if (!stop_tx) {
|
||||
write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
sport->port.icount.tx++;
|
||||
uart_xmit_advance(&sport->port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&sport->port);
|
||||
|
|
|
@ -686,13 +686,10 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
|
|||
}
|
||||
to_send = (to_send > txlen) ? txlen : to_send;
|
||||
|
||||
/* Add data to send */
|
||||
port->icount.tx += to_send;
|
||||
|
||||
/* Convert to linear buffer */
|
||||
for (i = 0; i < to_send; ++i) {
|
||||
s->buf[i] = xmit->buf[xmit->tail];
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
|
||||
sc16is7xx_fifo_write(port, to_send);
|
||||
|
|
|
@ -468,8 +468,7 @@ static void sccnxp_handle_tx(struct uart_port *port)
|
|||
break;
|
||||
|
||||
sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
|
|
@ -496,8 +496,7 @@ static void tegra_uart_fill_tx_fifo(struct tegra_uart_port *tup, int max_bytes)
|
|||
break;
|
||||
}
|
||||
tegra_uart_write(tup, xmit->buf[xmit->tail], UART_TX);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
tup->uport.icount.tx++;
|
||||
uart_xmit_advance(&tup->uport, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -619,8 +618,9 @@ static void tegra_uart_stop_tx(struct uart_port *u)
|
|||
if (tup->tx_in_progress != TEGRA_UART_TX_DMA)
|
||||
return;
|
||||
|
||||
dmaengine_terminate_all(tup->tx_dma_chan);
|
||||
dmaengine_pause(tup->tx_dma_chan);
|
||||
dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state);
|
||||
dmaengine_terminate_all(tup->tx_dma_chan);
|
||||
count = tup->tx_bytes_requested - state.residue;
|
||||
async_tx_ack(tup->tx_dma_desc);
|
||||
uart_xmit_advance(&tup->uport, count);
|
||||
|
@ -763,8 +763,9 @@ static void tegra_uart_terminate_rx_dma(struct tegra_uart_port *tup)
|
|||
return;
|
||||
}
|
||||
|
||||
dmaengine_terminate_all(tup->rx_dma_chan);
|
||||
dmaengine_pause(tup->rx_dma_chan);
|
||||
dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state);
|
||||
dmaengine_terminate_all(tup->rx_dma_chan);
|
||||
|
||||
tegra_uart_rx_buffer_push(tup, state.residue);
|
||||
tup->rx_dma_active = false;
|
||||
|
|
|
@ -321,34 +321,12 @@ receive_chars(struct uart_port *up, unsigned int *status)
|
|||
|
||||
static inline void transmit_chars(struct uart_port *up)
|
||||
{
|
||||
struct circ_buf *xmit = &up->state->xmit;
|
||||
int count;
|
||||
u8 ch;
|
||||
|
||||
if (up->x_char) {
|
||||
sio_out(up, TXX9_SITFIFO, up->x_char);
|
||||
up->icount.tx++;
|
||||
up->x_char = 0;
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(up)) {
|
||||
serial_txx9_stop_tx(up);
|
||||
return;
|
||||
}
|
||||
|
||||
count = TXX9_SIO_TX_FIFO;
|
||||
do {
|
||||
sio_out(up, TXX9_SITFIFO, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(up);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
serial_txx9_stop_tx(up);
|
||||
uart_port_tx_limited(up, ch, TXX9_SIO_TX_FIFO,
|
||||
true,
|
||||
sio_out(up, TXX9_SITFIFO, ch),
|
||||
({}));
|
||||
}
|
||||
|
||||
static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
|
||||
|
|
|
@ -1181,10 +1181,7 @@ static void sci_dma_tx_complete(void *arg)
|
|||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
||||
xmit->tail += s->tx_dma_len;
|
||||
xmit->tail &= UART_XMIT_SIZE - 1;
|
||||
|
||||
port->icount.tx += s->tx_dma_len;
|
||||
uart_xmit_advance(port, s->tx_dma_len);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
|
|
@ -288,33 +288,12 @@ static void __ssp_transmit_char(struct sifive_serial_port *ssp, int ch)
|
|||
*/
|
||||
static void __ssp_transmit_chars(struct sifive_serial_port *ssp)
|
||||
{
|
||||
struct circ_buf *xmit = &ssp->port.state->xmit;
|
||||
int count;
|
||||
u8 ch;
|
||||
|
||||
if (ssp->port.x_char) {
|
||||
__ssp_transmit_char(ssp, ssp->port.x_char);
|
||||
ssp->port.icount.tx++;
|
||||
ssp->port.x_char = 0;
|
||||
return;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(&ssp->port)) {
|
||||
sifive_serial_stop_tx(&ssp->port);
|
||||
return;
|
||||
}
|
||||
count = SIFIVE_TX_FIFO_DEPTH;
|
||||
do {
|
||||
__ssp_transmit_char(ssp, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
ssp->port.icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&ssp->port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
sifive_serial_stop_tx(&ssp->port);
|
||||
uart_port_tx_limited(&ssp->port, ch, SIFIVE_TX_FIFO_DEPTH,
|
||||
true,
|
||||
__ssp_transmit_char(ssp, ch),
|
||||
({}));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -206,7 +206,6 @@ 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;
|
||||
|
||||
|
@ -215,8 +214,7 @@ static void sprd_stop_tx_dma(struct uart_port *port)
|
|||
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;
|
||||
uart_xmit_advance(port, trans_len);
|
||||
dma_unmap_single(port->dev, sp->tx_dma.phys_addr,
|
||||
sp->tx_dma.trans_len, DMA_TO_DEVICE);
|
||||
}
|
||||
|
@ -253,8 +251,7 @@ static void sprd_complete_tx_dma(void *data)
|
|||
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;
|
||||
uart_xmit_advance(port, sp->tx_dma.trans_len);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
@ -626,35 +623,12 @@ static inline void sprd_rx(struct uart_port *port)
|
|||
|
||||
static inline void sprd_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
int count;
|
||||
u8 ch;
|
||||
|
||||
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(port);
|
||||
return;
|
||||
}
|
||||
|
||||
count = THLD_TX_EMPTY;
|
||||
do {
|
||||
serial_out(port, SPRD_TXD, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
sprd_stop_tx(port);
|
||||
uart_port_tx_limited(port, ch, THLD_TX_EMPTY,
|
||||
true,
|
||||
serial_out(port, SPRD_TXD, ch),
|
||||
({}));
|
||||
}
|
||||
|
||||
/* this handles the interrupt from one port */
|
||||
|
|
|
@ -237,50 +237,12 @@ static inline unsigned asc_hw_txroom(struct uart_port *port)
|
|||
*/
|
||||
static void asc_transmit_chars(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
int txroom;
|
||||
unsigned char c;
|
||||
u8 ch;
|
||||
|
||||
txroom = asc_hw_txroom(port);
|
||||
|
||||
if ((txroom != 0) && port->x_char) {
|
||||
c = port->x_char;
|
||||
port->x_char = 0;
|
||||
asc_out(port, ASC_TXBUF, c);
|
||||
port->icount.tx++;
|
||||
txroom = asc_hw_txroom(port);
|
||||
}
|
||||
|
||||
if (uart_tx_stopped(port)) {
|
||||
/*
|
||||
* We should try and stop the hardware here, but I
|
||||
* don't think the ASC has any way to do that.
|
||||
*/
|
||||
asc_disable_tx_interrupts(port);
|
||||
return;
|
||||
}
|
||||
|
||||
if (uart_circ_empty(xmit)) {
|
||||
asc_disable_tx_interrupts(port);
|
||||
return;
|
||||
}
|
||||
|
||||
if (txroom == 0)
|
||||
return;
|
||||
|
||||
do {
|
||||
c = xmit->buf[xmit->tail];
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
asc_out(port, ASC_TXBUF, c);
|
||||
port->icount.tx++;
|
||||
txroom--;
|
||||
} while ((txroom > 0) && (!uart_circ_empty(xmit)));
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
asc_disable_tx_interrupts(port);
|
||||
uart_port_tx_limited(port, ch, asc_hw_txroom(port),
|
||||
true,
|
||||
asc_out(port, ASC_TXBUF, ch),
|
||||
({}));
|
||||
}
|
||||
|
||||
static void asc_receive_chars(struct uart_port *port)
|
||||
|
|
|
@ -596,8 +596,7 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port)
|
|||
if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
|
||||
break;
|
||||
writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
|
||||
/* rely on TXE irq (mask or unmask) for sending remaining data */
|
||||
|
@ -673,8 +672,8 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
|
|||
|
||||
stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT);
|
||||
|
||||
xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx += count;
|
||||
uart_xmit_advance(port, count);
|
||||
|
||||
return;
|
||||
|
||||
fallback_err:
|
||||
|
@ -1681,22 +1680,10 @@ static int stm32_usart_serial_probe(struct platform_device *pdev)
|
|||
if (!stm32port->info)
|
||||
return -EINVAL;
|
||||
|
||||
ret = stm32_usart_init_port(stm32port, pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (stm32port->wakeup_src) {
|
||||
device_set_wakeup_capable(&pdev->dev, true);
|
||||
ret = dev_pm_set_wake_irq(&pdev->dev, stm32port->port.irq);
|
||||
if (ret)
|
||||
goto err_deinit_port;
|
||||
}
|
||||
|
||||
stm32port->rx_ch = dma_request_chan(&pdev->dev, "rx");
|
||||
if (PTR_ERR(stm32port->rx_ch) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto err_wakeirq;
|
||||
}
|
||||
if (PTR_ERR(stm32port->rx_ch) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
/* Fall back in interrupt mode for any non-deferral error */
|
||||
if (IS_ERR(stm32port->rx_ch))
|
||||
stm32port->rx_ch = NULL;
|
||||
|
@ -1710,6 +1697,17 @@ static int stm32_usart_serial_probe(struct platform_device *pdev)
|
|||
if (IS_ERR(stm32port->tx_ch))
|
||||
stm32port->tx_ch = NULL;
|
||||
|
||||
ret = stm32_usart_init_port(stm32port, pdev);
|
||||
if (ret)
|
||||
goto err_dma_tx;
|
||||
|
||||
if (stm32port->wakeup_src) {
|
||||
device_set_wakeup_capable(&pdev->dev, true);
|
||||
ret = dev_pm_set_wake_irq(&pdev->dev, stm32port->port.irq);
|
||||
if (ret)
|
||||
goto err_deinit_port;
|
||||
}
|
||||
|
||||
if (stm32port->rx_ch && stm32_usart_of_dma_rx_probe(stm32port, pdev)) {
|
||||
/* Fall back in interrupt mode */
|
||||
dma_release_channel(stm32port->rx_ch);
|
||||
|
@ -1746,19 +1744,11 @@ err_port:
|
|||
pm_runtime_set_suspended(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
||||
if (stm32port->tx_ch) {
|
||||
if (stm32port->tx_ch)
|
||||
stm32_usart_of_dma_tx_remove(stm32port, pdev);
|
||||
dma_release_channel(stm32port->tx_ch);
|
||||
}
|
||||
|
||||
if (stm32port->rx_ch)
|
||||
stm32_usart_of_dma_rx_remove(stm32port, pdev);
|
||||
|
||||
err_dma_rx:
|
||||
if (stm32port->rx_ch)
|
||||
dma_release_channel(stm32port->rx_ch);
|
||||
|
||||
err_wakeirq:
|
||||
if (stm32port->wakeup_src)
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
|
||||
|
@ -1768,6 +1758,14 @@ err_deinit_port:
|
|||
|
||||
stm32_usart_deinit_port(stm32port);
|
||||
|
||||
err_dma_tx:
|
||||
if (stm32port->tx_ch)
|
||||
dma_release_channel(stm32port->tx_ch);
|
||||
|
||||
err_dma_rx:
|
||||
if (stm32port->rx_ch)
|
||||
dma_release_channel(stm32port->rx_ch);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,8 +47,7 @@ static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit
|
|||
if (status != HV_EOK)
|
||||
break;
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,8 +62,7 @@ static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
|
|||
status = sun4v_con_write(ra, len, &sent);
|
||||
if (status != HV_EOK)
|
||||
break;
|
||||
xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx += sent;
|
||||
uart_xmit_advance(port, sent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -216,9 +216,7 @@ static void transmit_chars(struct uart_port *port)
|
|||
|
||||
do {
|
||||
sp_uart_put_char(port, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE;
|
||||
port->icount.tx++;
|
||||
|
||||
uart_xmit_advance(port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (sunplus_tx_buf_not_full(port));
|
||||
|
|
|
@ -266,8 +266,7 @@ static void transmit_chars(struct uart_sunsab_port *up,
|
|||
for (i = 0; i < up->port.fifosize; i++) {
|
||||
writeb(xmit->buf[xmit->tail],
|
||||
&up->regs->w.xfifo[i]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
}
|
||||
|
@ -453,8 +452,7 @@ static void sunsab_start_tx(struct uart_port *port)
|
|||
for (i = 0; i < up->port.fifosize; i++) {
|
||||
writeb(xmit->buf[xmit->tail],
|
||||
&up->regs->w.xfifo[i]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
}
|
||||
|
@ -1133,7 +1131,13 @@ static int __init sunsab_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
return platform_driver_register(&sab_driver);
|
||||
err = platform_driver_register(&sab_driver);
|
||||
if (err) {
|
||||
kfree(sunsab_ports);
|
||||
sunsab_ports = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit sunsab_exit(void)
|
||||
|
|
|
@ -417,8 +417,7 @@ static void transmit_chars(struct uart_sunsu_port *up)
|
|||
count = up->port.fifosize;
|
||||
do {
|
||||
serial_out(up, UART_TX, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
} while (--count > 0);
|
||||
|
|
|
@ -508,8 +508,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
|
|||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
up->port.icount.tx++;
|
||||
uart_xmit_advance(&up->port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
@ -709,8 +708,7 @@ static void sunzilog_start_tx(struct uart_port *port)
|
|||
ZSDELAY();
|
||||
ZS_WSYNC(channel);
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&up->port);
|
||||
|
|
|
@ -101,8 +101,7 @@ static void timbuart_tx_chars(struct uart_port *port)
|
|||
!uart_circ_empty(xmit)) {
|
||||
iowrite8(xmit->buf[xmit->tail],
|
||||
port->membase + TIMBUART_TXFIFO);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
}
|
||||
|
||||
dev_dbg(port->dev,
|
||||
|
|
|
@ -203,8 +203,7 @@ static int ulite_transmit(struct uart_port *port, int stat)
|
|||
return 0;
|
||||
|
||||
uart_out32(xmit->buf[xmit->tail], ULITE_TX, port);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
|
||||
/* wake up */
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
|
|
|
@ -372,8 +372,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
|
|||
p = qe2cpu_addr(be32_to_cpu(bdp->buf), qe_port);
|
||||
while (count < qe_port->tx_fifosize) {
|
||||
*p++ = xmit->buf[xmit->tail];
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
uart_xmit_advance(port, 1);
|
||||
count++;
|
||||
if (xmit->head == xmit->tail)
|
||||
break;
|
||||
|
|
|
@ -168,7 +168,7 @@ static void handle_rx(struct uart_port *port)
|
|||
|
||||
c = readw(port->membase + VT8500_RXFIFO) & 0x3ff;
|
||||
|
||||
/* Mask conditions we're ignorning. */
|
||||
/* Mask conditions we're ignoring. */
|
||||
c &= ~port->read_status_mask;
|
||||
|
||||
if (c & FER) {
|
||||
|
@ -196,33 +196,11 @@ static unsigned int vt8500_tx_empty(struct uart_port *port)
|
|||
|
||||
static void handle_tx(struct uart_port *port)
|
||||
{
|
||||
struct circ_buf *xmit = &port->state->xmit;
|
||||
u8 ch;
|
||||
|
||||
if (port->x_char) {
|
||||
writeb(port->x_char, port->membase + VT8500_TXFIFO);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
}
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
|
||||
vt8500_stop_tx(port);
|
||||
return;
|
||||
}
|
||||
|
||||
while (vt8500_tx_empty(port)) {
|
||||
if (uart_circ_empty(xmit))
|
||||
break;
|
||||
|
||||
writeb(xmit->buf[xmit->tail], port->membase + VT8500_TXFIFO);
|
||||
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
}
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(port);
|
||||
|
||||
if (uart_circ_empty(xmit))
|
||||
vt8500_stop_tx(port);
|
||||
uart_port_tx(port, ch,
|
||||
vt8500_tx_empty(port),
|
||||
writeb(ch, port->membase + VT8500_TXFIFO));
|
||||
}
|
||||
|
||||
static void vt8500_start_tx(struct uart_port *port)
|
||||
|
|
|
@ -326,9 +326,7 @@ static void cdns_uart_handle_tx(void *dev_id)
|
|||
!(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
|
||||
|
||||
writel(xmit->buf[xmit->tail], port->membase + CDNS_UART_FIFO);
|
||||
|
||||
port->icount.tx++;
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
uart_xmit_advance(port, 1);
|
||||
numbytes--;
|
||||
}
|
||||
|
||||
|
|
|
@ -623,8 +623,7 @@ static void zs_raw_transmit_chars(struct zs_port *zport)
|
|||
|
||||
/* Send char. */
|
||||
write_zsdata(zport, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
zport->port.icount.tx++;
|
||||
uart_xmit_advance(&zport->port, 1);
|
||||
|
||||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||||
uart_write_wakeup(&zport->port);
|
||||
|
|
|
@ -1433,16 +1433,8 @@ static int hdlcdev_open(struct net_device *dev)
|
|||
int rc;
|
||||
unsigned long flags;
|
||||
|
||||
if (!try_module_get(THIS_MODULE))
|
||||
return -EBUSY;
|
||||
|
||||
DBGINFO(("%s hdlcdev_open\n", dev->name));
|
||||
|
||||
/* generic HDLC layer open processing */
|
||||
rc = hdlc_open(dev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* arbitrate between network and tty opens */
|
||||
spin_lock_irqsave(&info->netlock, flags);
|
||||
if (info->port.count != 0 || info->netcount != 0) {
|
||||
|
@ -1461,6 +1453,16 @@ static int hdlcdev_open(struct net_device *dev)
|
|||
return rc;
|
||||
}
|
||||
|
||||
/* generic HDLC layer open processing */
|
||||
rc = hdlc_open(dev);
|
||||
if (rc) {
|
||||
shutdown(info);
|
||||
spin_lock_irqsave(&info->netlock, flags);
|
||||
info->netcount = 0;
|
||||
spin_unlock_irqrestore(&info->netlock, flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* assert RTS and DTR, apply hardware settings */
|
||||
info->signals |= SerialSignal_RTS | SerialSignal_DTR;
|
||||
program_hw(info);
|
||||
|
@ -1506,7 +1508,6 @@ static int hdlcdev_close(struct net_device *dev)
|
|||
info->netcount=0;
|
||||
spin_unlock_irqrestore(&info->netlock, flags);
|
||||
|
||||
module_put(THIS_MODULE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ void tty_ldisc_release(struct tty_struct *tty);
|
|||
int __must_check tty_ldisc_init(struct tty_struct *tty);
|
||||
void tty_ldisc_deinit(struct tty_struct *tty);
|
||||
|
||||
void tty_sysctl_init(void);
|
||||
extern int tty_ldisc_autoload;
|
||||
|
||||
/* tty_audit.c */
|
||||
#ifdef CONFIG_AUDIT
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "tty.h"
|
||||
|
||||
#define MIN_TTYB_SIZE 256
|
||||
#define TTYB_ALIGN_MASK 255
|
||||
#define TTYB_ALIGN_MASK 0xff
|
||||
|
||||
/*
|
||||
* Byte threshold to limit memory consumption for flip buffers.
|
||||
|
@ -37,7 +37,7 @@
|
|||
* logic this must match.
|
||||
*/
|
||||
|
||||
#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF)
|
||||
#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~TTYB_ALIGN_MASK)
|
||||
|
||||
/**
|
||||
* tty_buffer_lock_exclusive - gain exclusive access to buffer
|
||||
|
@ -107,7 +107,7 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size)
|
|||
p->commit = 0;
|
||||
p->lookahead = 0;
|
||||
p->read = 0;
|
||||
p->flags = 0;
|
||||
p->flags = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,7 +249,7 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
|
|||
* __tty_buffer_request_room - grow tty buffer if needed
|
||||
* @port: tty port
|
||||
* @size: size desired
|
||||
* @flags: buffer flags if new buffer allocated (default = 0)
|
||||
* @flags: buffer has to store flags along character data
|
||||
*
|
||||
* Make at least @size bytes of linear space available for the tty buffer.
|
||||
*
|
||||
|
@ -260,19 +260,19 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld)
|
|||
* Returns: the size we managed to find.
|
||||
*/
|
||||
static int __tty_buffer_request_room(struct tty_port *port, size_t size,
|
||||
int flags)
|
||||
bool flags)
|
||||
{
|
||||
struct tty_bufhead *buf = &port->buf;
|
||||
struct tty_buffer *b, *n;
|
||||
int left, change;
|
||||
|
||||
b = buf->tail;
|
||||
if (b->flags & TTYB_NORMAL)
|
||||
if (!b->flags)
|
||||
left = 2 * b->size - b->used;
|
||||
else
|
||||
left = b->size - b->used;
|
||||
|
||||
change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL);
|
||||
change = !b->flags && flags;
|
||||
if (change || left < size) {
|
||||
/* This is the slow path - looking for new buffers to use */
|
||||
n = tty_buffer_alloc(port, size);
|
||||
|
@ -300,7 +300,7 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size,
|
|||
|
||||
int tty_buffer_request_room(struct tty_port *port, size_t size)
|
||||
{
|
||||
return __tty_buffer_request_room(port, size, 0);
|
||||
return __tty_buffer_request_room(port, size, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
|
||||
|
||||
|
@ -320,17 +320,17 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port,
|
|||
const unsigned char *chars, char flag, size_t size)
|
||||
{
|
||||
int copied = 0;
|
||||
bool flags = flag != TTY_NORMAL;
|
||||
|
||||
do {
|
||||
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
|
||||
int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;
|
||||
int space = __tty_buffer_request_room(port, goal, flags);
|
||||
struct tty_buffer *tb = port->buf.tail;
|
||||
|
||||
if (unlikely(space == 0))
|
||||
break;
|
||||
memcpy(char_buf_ptr(tb, tb->used), chars, space);
|
||||
if (~tb->flags & TTYB_NORMAL)
|
||||
if (tb->flags)
|
||||
memset(flag_buf_ptr(tb, tb->used), flag, space);
|
||||
tb->used += space;
|
||||
copied += space;
|
||||
|
@ -393,13 +393,13 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags);
|
|||
int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag)
|
||||
{
|
||||
struct tty_buffer *tb;
|
||||
int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0;
|
||||
bool flags = flag != TTY_NORMAL;
|
||||
|
||||
if (!__tty_buffer_request_room(port, 1, flags))
|
||||
return 0;
|
||||
|
||||
tb = port->buf.tail;
|
||||
if (~tb->flags & TTYB_NORMAL)
|
||||
if (tb->flags)
|
||||
*flag_buf_ptr(tb, tb->used) = flag;
|
||||
*char_buf_ptr(tb, tb->used++) = ch;
|
||||
|
||||
|
@ -424,13 +424,13 @@ EXPORT_SYMBOL(__tty_insert_flip_char);
|
|||
int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
|
||||
size_t size)
|
||||
{
|
||||
int space = __tty_buffer_request_room(port, size, TTYB_NORMAL);
|
||||
int space = __tty_buffer_request_room(port, size, false);
|
||||
|
||||
if (likely(space)) {
|
||||
struct tty_buffer *tb = port->buf.tail;
|
||||
|
||||
*chars = char_buf_ptr(tb, tb->used);
|
||||
if (~tb->flags & TTYB_NORMAL)
|
||||
if (tb->flags)
|
||||
memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
|
||||
tb->used += space;
|
||||
}
|
||||
|
@ -492,7 +492,7 @@ static void lookahead_bufs(struct tty_port *port, struct tty_buffer *head)
|
|||
unsigned char *p, *f = NULL;
|
||||
|
||||
p = char_buf_ptr(head, head->lookahead);
|
||||
if (~head->flags & TTYB_NORMAL)
|
||||
if (head->flags)
|
||||
f = flag_buf_ptr(head, head->lookahead);
|
||||
|
||||
port->client_ops->lookahead_buf(port, p, f, count);
|
||||
|
@ -509,7 +509,7 @@ receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
|
|||
const char *f = NULL;
|
||||
int n;
|
||||
|
||||
if (~head->flags & TTYB_NORMAL)
|
||||
if (head->flags)
|
||||
f = flag_buf_ptr(head, head->read);
|
||||
|
||||
n = port->client_ops->receive_buf(port, p, f, count);
|
||||
|
|
|
@ -2255,6 +2255,7 @@ static int tty_fasync(int fd, struct file *filp, int on)
|
|||
return retval;
|
||||
}
|
||||
|
||||
static bool tty_legacy_tiocsti __read_mostly = IS_ENABLED(CONFIG_LEGACY_TIOCSTI);
|
||||
/**
|
||||
* tiocsti - fake input character
|
||||
* @tty: tty to fake input into
|
||||
|
@ -2273,6 +2274,9 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
|
|||
char ch, mbz = 0;
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
if (!tty_legacy_tiocsti)
|
||||
return -EIO;
|
||||
|
||||
if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
if (get_user(ch, p))
|
||||
|
@ -3588,13 +3592,51 @@ void console_sysfs_notify(void)
|
|||
sysfs_notify(&consdev->kobj, NULL, "active");
|
||||
}
|
||||
|
||||
static struct ctl_table tty_table[] = {
|
||||
{
|
||||
.procname = "legacy_tiocsti",
|
||||
.data = &tty_legacy_tiocsti,
|
||||
.maxlen = sizeof(tty_legacy_tiocsti),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dobool,
|
||||
},
|
||||
{
|
||||
.procname = "ldisc_autoload",
|
||||
.data = &tty_ldisc_autoload,
|
||||
.maxlen = sizeof(tty_ldisc_autoload),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
.extra1 = SYSCTL_ZERO,
|
||||
.extra2 = SYSCTL_ONE,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ctl_table tty_dir_table[] = {
|
||||
{
|
||||
.procname = "tty",
|
||||
.mode = 0555,
|
||||
.child = tty_table,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ctl_table tty_root_table[] = {
|
||||
{
|
||||
.procname = "dev",
|
||||
.mode = 0555,
|
||||
.child = tty_dir_table,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* Ok, now we can initialize the rest of the tty devices and can count
|
||||
* on memory allocations, interrupts etc..
|
||||
*/
|
||||
int __init tty_init(void)
|
||||
{
|
||||
tty_sysctl_init();
|
||||
register_sysctl_table(tty_root_table);
|
||||
cdev_init(&tty_cdev, &tty_fops);
|
||||
if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
|
||||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
|
||||
|
@ -3616,4 +3658,3 @@ int __init tty_init(void)
|
|||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ static void put_ldops(struct tty_ldisc_ops *ldops)
|
|||
raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags);
|
||||
}
|
||||
|
||||
static int tty_ldisc_autoload = IS_BUILTIN(CONFIG_LDISC_AUTOLOAD);
|
||||
int tty_ldisc_autoload = IS_BUILTIN(CONFIG_LDISC_AUTOLOAD);
|
||||
|
||||
/**
|
||||
* tty_ldisc_get - take a reference to an ldisc
|
||||
|
@ -817,39 +817,3 @@ void tty_ldisc_deinit(struct tty_struct *tty)
|
|||
tty_ldisc_put(tty->ldisc);
|
||||
tty->ldisc = NULL;
|
||||
}
|
||||
|
||||
static struct ctl_table tty_table[] = {
|
||||
{
|
||||
.procname = "ldisc_autoload",
|
||||
.data = &tty_ldisc_autoload,
|
||||
.maxlen = sizeof(tty_ldisc_autoload),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
.extra1 = SYSCTL_ZERO,
|
||||
.extra2 = SYSCTL_ONE,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ctl_table tty_dir_table[] = {
|
||||
{
|
||||
.procname = "tty",
|
||||
.mode = 0555,
|
||||
.child = tty_table,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct ctl_table tty_root_table[] = {
|
||||
{
|
||||
.procname = "dev",
|
||||
.mode = 0555,
|
||||
.child = tty_dir_table,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
void tty_sysctl_init(void)
|
||||
{
|
||||
register_sysctl_table(tty_root_table);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/termios.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -279,18 +280,10 @@ static inline bool serdev_device_get_cts(struct serdev_device *serdev)
|
|||
|
||||
static inline int serdev_device_wait_for_cts(struct serdev_device *serdev, bool state, int timeout_ms)
|
||||
{
|
||||
unsigned long timeout;
|
||||
bool signal;
|
||||
|
||||
timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
while (time_is_after_jiffies(timeout)) {
|
||||
signal = serdev_device_get_cts(serdev);
|
||||
if (signal == state)
|
||||
return 0;
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
return readx_poll_timeout(serdev_device_get_cts, serdev, signal, signal == state,
|
||||
2000, timeout_ms * 1000);
|
||||
}
|
||||
|
||||
static inline int serdev_device_set_rts(struct serdev_device *serdev, bool enable)
|
||||
|
|
|
@ -664,6 +664,86 @@ struct uart_driver {
|
|||
|
||||
void uart_write_wakeup(struct uart_port *port);
|
||||
|
||||
#define __uart_port_tx(uport, ch, tx_ready, put_char, tx_done, for_test, \
|
||||
for_post) \
|
||||
({ \
|
||||
struct uart_port *__port = (uport); \
|
||||
struct circ_buf *xmit = &__port->state->xmit; \
|
||||
unsigned int pending; \
|
||||
\
|
||||
for (; (for_test) && (tx_ready); (for_post), __port->icount.tx++) { \
|
||||
if (__port->x_char) { \
|
||||
(ch) = __port->x_char; \
|
||||
(put_char); \
|
||||
__port->x_char = 0; \
|
||||
continue; \
|
||||
} \
|
||||
\
|
||||
if (uart_circ_empty(xmit) || uart_tx_stopped(__port)) \
|
||||
break; \
|
||||
\
|
||||
(ch) = xmit->buf[xmit->tail]; \
|
||||
(put_char); \
|
||||
xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE; \
|
||||
} \
|
||||
\
|
||||
(tx_done); \
|
||||
\
|
||||
pending = uart_circ_chars_pending(xmit); \
|
||||
if (pending < WAKEUP_CHARS) { \
|
||||
uart_write_wakeup(__port); \
|
||||
\
|
||||
if (pending == 0) \
|
||||
__port->ops->stop_tx(__port); \
|
||||
} \
|
||||
\
|
||||
pending; \
|
||||
})
|
||||
|
||||
/**
|
||||
* uart_port_tx_limited -- transmit helper for uart_port with count limiting
|
||||
* @port: uart port
|
||||
* @ch: variable to store a character to be written to the HW
|
||||
* @count: a limit of characters to send
|
||||
* @tx_ready: can HW accept more data function
|
||||
* @put_char: function to write a character
|
||||
* @tx_done: function to call after the loop is done
|
||||
*
|
||||
* This helper transmits characters from the xmit buffer to the hardware using
|
||||
* @put_char(). It does so until @count characters are sent and while @tx_ready
|
||||
* evaluates to true.
|
||||
*
|
||||
* Returns: the number of characters in the xmit buffer when done.
|
||||
*
|
||||
* The expression in macro parameters shall be designed as follows:
|
||||
* * **tx_ready:** should evaluate to true if the HW can accept more data to
|
||||
* be sent. This parameter can be %true, which means the HW is always ready.
|
||||
* * **put_char:** shall write @ch to the device of @port.
|
||||
* * **tx_done:** when the write loop is done, this can perform arbitrary
|
||||
* action before potential invocation of ops->stop_tx() happens. If the
|
||||
* driver does not need to do anything, use e.g. ({}).
|
||||
*
|
||||
* For all of them, @port->lock is held, interrupts are locally disabled and
|
||||
* the expressions must not sleep.
|
||||
*/
|
||||
#define uart_port_tx_limited(port, ch, count, tx_ready, put_char, tx_done) ({ \
|
||||
unsigned int __count = (count); \
|
||||
__uart_port_tx(port, ch, tx_ready, put_char, tx_done, __count, \
|
||||
__count--); \
|
||||
})
|
||||
|
||||
/**
|
||||
* uart_port_tx -- transmit helper for uart_port
|
||||
* @port: uart port
|
||||
* @ch: variable to store a character to be written to the HW
|
||||
* @tx_ready: can HW accept more data function
|
||||
* @put_char: function to write a character
|
||||
*
|
||||
* See uart_port_tx_limited() for more details.
|
||||
*/
|
||||
#define uart_port_tx(port, ch, tx_ready, put_char) \
|
||||
__uart_port_tx(port, ch, tx_ready, put_char, ({}), true, ({}))
|
||||
|
||||
/*
|
||||
* Baud rate helpers.
|
||||
*/
|
||||
|
|
|
@ -17,14 +17,11 @@ struct tty_buffer {
|
|||
int commit;
|
||||
int lookahead; /* Lazy update on recv, can become less than "read" */
|
||||
int read;
|
||||
int flags;
|
||||
bool flags;
|
||||
/* Data points here */
|
||||
unsigned long data[];
|
||||
};
|
||||
|
||||
/* Values for .flags field of tty_buffer */
|
||||
#define TTYB_NORMAL 1 /* buffer has no flags buffer */
|
||||
|
||||
static inline unsigned char *char_buf_ptr(struct tty_buffer *b, int ofs)
|
||||
{
|
||||
return ((unsigned char *)b->data) + ofs;
|
||||
|
|
|
@ -25,9 +25,9 @@ static inline int tty_insert_flip_char(struct tty_port *port,
|
|||
struct tty_buffer *tb = port->buf.tail;
|
||||
int change;
|
||||
|
||||
change = (tb->flags & TTYB_NORMAL) && (flag != TTY_NORMAL);
|
||||
change = !tb->flags && (flag != TTY_NORMAL);
|
||||
if (!change && tb->used < tb->size) {
|
||||
if (~tb->flags & TTYB_NORMAL)
|
||||
if (tb->flags)
|
||||
*flag_buf_ptr(tb, tb->used) = flag;
|
||||
*char_buf_ptr(tb, tb->used++) = ch;
|
||||
return 1;
|
||||
|
|
|
@ -107,33 +107,50 @@ struct serial_icounter_struct {
|
|||
int reserved[9];
|
||||
};
|
||||
|
||||
/*
|
||||
/**
|
||||
* struct serial_rs485 - serial interface for controlling RS485 settings.
|
||||
* @flags: RS485 feature flags.
|
||||
* @delay_rts_before_send: Delay before send (milliseconds).
|
||||
* @delay_rts_after_send: Delay after send (milliseconds).
|
||||
* @addr_recv: Receive filter for RS485 addressing mode
|
||||
* (used only when %SER_RS485_ADDR_RECV is set).
|
||||
* @addr_dest: Destination address for RS485 addressing mode
|
||||
* (used only when %SER_RS485_ADDR_DEST is set).
|
||||
* @padding0: Padding (set to zero).
|
||||
* @padding1: Padding (set to zero).
|
||||
* @padding: Deprecated, use @padding0 and @padding1 instead.
|
||||
* Do not use with @addr_recv and @addr_dest (due to
|
||||
* overlap).
|
||||
*
|
||||
* Serial interface for controlling RS485 settings on chips with suitable
|
||||
* support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your
|
||||
* platform. The set function returns the new state, with any unsupported bits
|
||||
* reverted appropriately.
|
||||
*
|
||||
* The flag bits are:
|
||||
*
|
||||
* * %SER_RS485_ENABLED - RS485 enabled.
|
||||
* * %SER_RS485_RTS_ON_SEND - Logical level for RTS pin when sending.
|
||||
* * %SER_RS485_RTS_AFTER_SEND - Logical level for RTS pin after sent.
|
||||
* * %SER_RS485_RX_DURING_TX - Full-duplex RS485 line.
|
||||
* * %SER_RS485_TERMINATE_BUS - Enable bus termination (if supported).
|
||||
* * %SER_RS485_ADDRB - Enable RS485 addressing mode.
|
||||
* * %SER_RS485_ADDR_RECV - Receive address filter (enables @addr_recv). Requires %SER_RS485_ADDRB.
|
||||
* * %SER_RS485_ADDR_DEST - Destination address (enables @addr_dest). Requires %SER_RS485_ADDRB.
|
||||
*/
|
||||
|
||||
struct serial_rs485 {
|
||||
__u32 flags; /* RS485 feature flags */
|
||||
#define SER_RS485_ENABLED (1 << 0) /* If enabled */
|
||||
#define SER_RS485_RTS_ON_SEND (1 << 1) /* Logical level for
|
||||
RTS pin when
|
||||
sending */
|
||||
#define SER_RS485_RTS_AFTER_SEND (1 << 2) /* Logical level for
|
||||
RTS pin after sent*/
|
||||
__u32 flags;
|
||||
#define SER_RS485_ENABLED (1 << 0)
|
||||
#define SER_RS485_RTS_ON_SEND (1 << 1)
|
||||
#define SER_RS485_RTS_AFTER_SEND (1 << 2)
|
||||
#define SER_RS485_RX_DURING_TX (1 << 4)
|
||||
#define SER_RS485_TERMINATE_BUS (1 << 5) /* Enable bus
|
||||
termination
|
||||
(if supported) */
|
||||
#define SER_RS485_TERMINATE_BUS (1 << 5)
|
||||
#define SER_RS485_ADDRB (1 << 6)
|
||||
#define SER_RS485_ADDR_RECV (1 << 7)
|
||||
#define SER_RS485_ADDR_DEST (1 << 8)
|
||||
|
||||
/* RS-485 addressing mode */
|
||||
#define SER_RS485_ADDRB (1 << 6) /* Enable addressing mode */
|
||||
#define SER_RS485_ADDR_RECV (1 << 7) /* Receive address filter */
|
||||
#define SER_RS485_ADDR_DEST (1 << 8) /* Destination address */
|
||||
|
||||
__u32 delay_rts_before_send; /* Delay before send (milliseconds) */
|
||||
__u32 delay_rts_after_send; /* Delay after send (milliseconds) */
|
||||
__u32 delay_rts_before_send;
|
||||
__u32 delay_rts_after_send;
|
||||
|
||||
/* The fields below are defined by flags */
|
||||
union {
|
||||
|
|
Загрузка…
Ссылка в новой задаче