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:
Linus Torvalds 2022-12-16 03:31:56 -08:00
Родитель b83a7080d3 6373ab4dfe
Коммит dd6f9b17cd
92 изменённых файлов: 1454 добавлений и 1253 удалений

Просмотреть файл

@ -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(&params->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, &params);
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 *)&params,
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(&ltq_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(&ltq_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 {