1
0
Fork 0

TTY/Serial patches for 4.20-rc1

Here is the big tty and serial pull request for 4.20-rc1
 
 Lots of little things here, including a merge from the SPI tree in order
 to keep things simpler for everyone to sync around for one platform.
 
 Major stuff is:
 	- tty buffer clearing after use
 	- atmel_serial fixes and additions
 	- xilinx uart driver updates
 and of course, lots of tiny fixes and additions to individual serial
 drivers.
 
 All of these have been in linux-next with no reported issues for a
 while.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCW9bW0w8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ymYhgCfbxr0T+4lF/rpGxNXNnV4u5boRJUAn2L8R+1y
 URbAWHvKfaby2AVfQ1z0
 =qTHH
 -----END PGP SIGNATURE-----

Merge tag 'tty-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial updates from Greg KH:
 "Here is the big tty and serial pull request for 4.20-rc1

  Lots of little things here, including a merge from the SPI tree in
  order to keep things simpler for everyone to sync around for one
  platform.

  Major stuff is:

   - tty buffer clearing after use

   - atmel_serial fixes and additions

   - xilinx uart driver updates

  and of course, lots of tiny fixes and additions to individual serial
  drivers.

  All of these have been in linux-next with no reported issues for a
  while"

* tag 'tty-4.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (66 commits)
  of: base: Change logic in of_alias_get_alias_list()
  of: base: Fix english spelling in of_alias_get_alias_list()
  serial: sh-sci: do not warn if DMA transfers are not supported
  serial: uartps: Do not allow use aliases >= MAX_UART_INSTANCES
  tty: check name length in tty_find_polling_driver()
  serial: sh-sci: Add r8a77990 support
  tty: wipe buffer if not echoing data
  tty: wipe buffer.
  serial: fsl_lpuart: Remove the alias node dependence
  TTY: sn_console: Replace spin_is_locked() with spin_trylock()
  Revert "serial:serial_core: Allow use of CTS for PPS line discipline"
  serial: 8250_uniphier: add auto-flow-control support
  serial: 8250_uniphier: flatten probe function
  serial: 8250_uniphier: remove unused "fifo-size" property
  dt-bindings: serial: sh-sci: Document r8a7744 bindings
  serial: uartps: Fix missing unlock on error in cdns_get_id()
  tty/serial: atmel: add ISO7816 support
  tty/serial_core: add ISO7816 infrastructure
  serial:serial_core: Allow use of CTS for PPS line discipline
  serial: docs: Fix filename for serial reference implementation
  ...
hifive-unleashed-5.1
Linus Torvalds 2018-10-29 10:42:20 -07:00
commit 5bd4af34a0
43 changed files with 975 additions and 378 deletions

View File

@ -14,6 +14,10 @@ Required properties:
- "renesas,scifa-r8a7743" for R8A7743 (RZ/G1M) SCIFA compatible UART.
- "renesas,scifb-r8a7743" for R8A7743 (RZ/G1M) SCIFB compatible UART.
- "renesas,hscif-r8a7743" for R8A7743 (RZ/G1M) HSCIF compatible UART.
- "renesas,scif-r8a7744" for R8A7744 (RZ/G1N) SCIF compatible UART.
- "renesas,scifa-r8a7744" for R8A7744 (RZ/G1N) SCIFA compatible UART.
- "renesas,scifb-r8a7744" for R8A7744 (RZ/G1N) SCIFB compatible UART.
- "renesas,hscif-r8a7744" for R8A7744 (RZ/G1N) HSCIF compatible UART.
- "renesas,scif-r8a7745" for R8A7745 (RZ/G1E) SCIF compatible UART.
- "renesas,scifa-r8a7745" for R8A7745 (RZ/G1E) SCIFA compatible UART.
- "renesas,scifb-r8a7745" for R8A7745 (RZ/G1E) SCIFB compatible UART.
@ -50,6 +54,8 @@ Required properties:
- "renesas,hscif-r8a77970" for R8A77970 (R-Car V3M) HSCIF compatible UART.
- "renesas,scif-r8a77980" for R8A77980 (R-Car V3H) SCIF compatible UART.
- "renesas,hscif-r8a77980" for R8A77980 (R-Car V3H) HSCIF compatible UART.
- "renesas,scif-r8a77990" for R8A77990 (R-Car E3) SCIF compatible UART.
- "renesas,hscif-r8a77990" for R8A77990 (R-Car E3) HSCIF compatible UART.
- "renesas,scif-r8a77995" for R8A77995 (R-Car D3) SCIF compatible UART.
- "renesas,hscif-r8a77995" for R8A77995 (R-Car D3) HSCIF compatible UART.
- "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART.

View File

@ -7,7 +7,7 @@ Required properties:
- clocks: phandle to the input clock.
Optional properties:
- fifo-size: the RX/TX FIFO size. Defaults to 64 if not specified.
-auto-flow-control: enable automatic flow control support.
Example:
aliases {
@ -19,5 +19,4 @@ Example:
reg = <0x54006800 0x40>;
interrupts = <0 33 4>;
clocks = <&uart_clk>;
fifo-size = <64>;
};

View File

@ -7,7 +7,7 @@ This document is meant as a brief overview of some aspects of the new serial
driver. It is not complete, any questions you have should be directed to
<rmk@arm.linux.org.uk>
The reference implementation is contained within amba_pl011.c.
The reference implementation is contained within amba-pl011.c.

View File

@ -0,0 +1,83 @@
ISO7816 SERIAL COMMUNICATIONS
1. INTRODUCTION
ISO/IEC7816 is a series of standards specifying integrated circuit cards (ICC)
also known as smart cards.
2. HARDWARE-RELATED CONSIDERATIONS
Some CPUs/UARTs (e.g., Microchip AT91) contain a built-in mode capable of
handling communication with a smart card.
For these microcontrollers, the Linux driver should be made capable of
working in both modes, and proper ioctls (see later) should be made
available at user-level to allow switching from one mode to the other, and
vice versa.
3. DATA STRUCTURES ALREADY AVAILABLE IN THE KERNEL
The Linux kernel provides the serial_iso7816 structure (see [1]) to handle
ISO7816 communications. This data structure is used to set and configure
ISO7816 parameters in ioctls.
Any driver for devices capable of working both as RS232 and ISO7816 should
implement the iso7816_config callback in the uart_port structure. The
serial_core calls iso7816_config to do the device specific part in response
to TIOCGISO7816 and TIOCSISO7816 ioctls (see below). The iso7816_config
callback receives a pointer to struct serial_iso7816.
4. USAGE FROM USER-LEVEL
From user-level, ISO7816 configuration can be get/set using the previous
ioctls. For instance, to set ISO7816 you can use the following code:
#include <linux/serial.h>
/* Include definition for ISO7816 ioctls: TIOCSISO7816 and TIOCGISO7816 */
#include <sys/ioctl.h>
/* Open your specific device (e.g., /dev/mydevice): */
int fd = open ("/dev/mydevice", O_RDWR);
if (fd < 0) {
/* Error handling. See errno. */
}
struct serial_iso7816 iso7816conf;
/* Reserved fields as to be zeroed */
memset(&iso7816conf, 0, sizeof(iso7816conf));
/* Enable ISO7816 mode: */
iso7816conf.flags |= SER_ISO7816_ENABLED;
/* Select the protocol: */
/* T=0 */
iso7816conf.flags |= SER_ISO7816_T(0);
/* or T=1 */
iso7816conf.flags |= SER_ISO7816_T(1);
/* Set the guard time: */
iso7816conf.tg = 2;
/* Set the clock frequency*/
iso7816conf.clk = 3571200;
/* Set transmission factors: */
iso7816conf.sc_fi = 372;
iso7816conf.sc_di = 1;
if (ioctl(fd_usart, TIOCSISO7816, &iso7816conf) < 0) {
/* Error handling. See errno. */
}
/* Use read() and write() syscalls here... */
/* Close the device when finished: */
if (close (fd) < 0) {
/* Error handling. See errno. */
}
5. REFERENCES
[1] include/uapi/linux/serial.h

View File

@ -102,6 +102,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define TIOCSERCONFIG 0x5453
#define TIOCSERGWILD 0x5454

View File

@ -93,6 +93,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
/* I hope the range from 0x5480 on is free ... */
#define TIOCSCTTY 0x5480 /* become controlling tty */

View File

@ -62,6 +62,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */
#define FIOCLEX 0x5451

View File

@ -102,6 +102,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define TIOCSERCONFIG 0x5453
#define TIOCSERGWILD 0x5454

View File

@ -95,6 +95,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */
#define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */

View File

@ -27,6 +27,8 @@
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGRS485 _IOR('T', 0x41, struct serial_rs485)
#define TIOCSRS485 _IOWR('T', 0x42, struct serial_rs485)
#define TIOCGISO7816 _IOR('T', 0x43, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x44, struct serial_iso7816)
/* Note that all the ioctls that are not available in Linux have a
* double underscore on the front to: a) avoid some programs to

View File

@ -107,6 +107,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define TIOCSERCONFIG _IO('T', 83)
#define TIOCSERGWILD _IOR('T', 84, int)

View File

@ -16,6 +16,7 @@
#define pr_fmt(fmt) "OF: " fmt
#include <linux/bitmap.h>
#include <linux/console.h>
#include <linux/ctype.h>
#include <linux/cpu.h>
@ -1985,6 +1986,59 @@ int of_alias_get_id(struct device_node *np, const char *stem)
}
EXPORT_SYMBOL_GPL(of_alias_get_id);
/**
* of_alias_get_alias_list - Get alias list for the given device driver
* @matches: Array of OF device match structures to search in
* @stem: Alias stem of the given device_node
* @bitmap: Bitmap field pointer
* @nbits: Maximum number of alias IDs which can be recorded in bitmap
*
* The function travels the lookup table to record alias ids for the given
* device match structures and alias stem.
*
* Return: 0 or -ENOSYS when !CONFIG_OF or
* -EOVERFLOW if alias ID is greater then allocated nbits
*/
int of_alias_get_alias_list(const struct of_device_id *matches,
const char *stem, unsigned long *bitmap,
unsigned int nbits)
{
struct alias_prop *app;
int ret = 0;
/* Zero bitmap field to make sure that all the time it is clean */
bitmap_zero(bitmap, nbits);
mutex_lock(&of_mutex);
pr_debug("%s: Looking for stem: %s\n", __func__, stem);
list_for_each_entry(app, &aliases_lookup, link) {
pr_debug("%s: stem: %s, id: %d\n",
__func__, app->stem, app->id);
if (strcmp(app->stem, stem) != 0) {
pr_debug("%s: stem comparison didn't pass %s\n",
__func__, app->stem);
continue;
}
if (of_match_node(matches, app->np)) {
pr_debug("%s: Allocated ID %d\n", __func__, app->id);
if (app->id >= nbits) {
pr_warn("%s: ID %d >= than bitmap field %d\n",
__func__, app->id, nbits);
ret = -EOVERFLOW;
} else {
set_bit(app->id, bitmap);
}
}
}
mutex_unlock(&of_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(of_alias_get_alias_list);
/**
* of_alias_get_highest_id - Get highest alias id for the given stem
* @stem: Alias stem to be examined

View File

@ -128,8 +128,8 @@ static int find_console_handle(void)
*/
iprop = of_get_property(np, "hv-handle", NULL);
if (!iprop) {
pr_err("ehv-bc: no 'hv-handle' property in %s node\n",
np->name);
pr_err("ehv-bc: no 'hv-handle' property in %pOFn node\n",
np);
return 0;
}
stdout_bc = be32_to_cpu(*iprop);
@ -661,8 +661,8 @@ static int ehv_bc_tty_probe(struct platform_device *pdev)
iprop = of_get_property(np, "hv-handle", NULL);
if (!iprop) {
dev_err(&pdev->dev, "no 'hv-handle' property in %s node\n",
np->name);
dev_err(&pdev->dev, "no 'hv-handle' property in %pOFn node\n",
np);
return -ENODEV;
}
@ -682,8 +682,8 @@ 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)) {
dev_err(&pdev->dev, "no 'interrupts' property in %s node\n",
np->name);
dev_err(&pdev->dev, "no 'interrupts' property in %pOFn node\n",
np);
ret = -ENODEV;
goto error;
}

View File

@ -152,17 +152,28 @@ static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i)
return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)];
}
/* If we are not echoing the data, perhaps this is a secret so erase it */
static void zero_buffer(struct tty_struct *tty, u8 *buffer, int size)
{
bool icanon = !!L_ICANON(tty);
bool no_echo = !L_ECHO(tty);
if (icanon && no_echo)
memset(buffer, 0x00, size);
}
static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
size_t tail, size_t n)
{
struct n_tty_data *ldata = tty->disc_data;
size_t size = N_TTY_BUF_SIZE - tail;
const void *from = read_buf_addr(ldata, tail);
void *from = read_buf_addr(ldata, tail);
int uncopied;
if (n > size) {
tty_audit_add_data(tty, from, size);
uncopied = copy_to_user(to, from, size);
zero_buffer(tty, from, size - uncopied);
if (uncopied)
return uncopied;
to += size;
@ -171,7 +182,9 @@ static int tty_copy_to_user(struct tty_struct *tty, void __user *to,
}
tty_audit_add_data(tty, from, n);
return copy_to_user(to, from, n);
uncopied = copy_to_user(to, from, n);
zero_buffer(tty, from, n - uncopied);
return uncopied;
}
/**
@ -1960,11 +1973,12 @@ static int copy_from_read_buf(struct tty_struct *tty,
n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
n = min(*nr, n);
if (n) {
const unsigned char *from = read_buf_addr(ldata, tail);
unsigned char *from = read_buf_addr(ldata, tail);
retval = copy_to_user(*b, from, n);
n -= retval;
is_eof = n == 1 && *from == EOF_CHAR(tty);
tty_audit_add_data(tty, from, n);
zero_buffer(tty, from, n);
smp_store_release(&ldata->read_tail, ldata->read_tail + n);
/* Turn single EOF into zero-length read */
if (L_EXTPROC(tty) && ldata->icanon && is_eof &&

View File

@ -130,12 +130,8 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
l = l->next;
if (l == i->head && pass_counter++ > PASS_LIMIT) {
/* If we hit this, we're dead. */
printk_ratelimited(KERN_ERR
"serial8250: too much work for irq%d\n", irq);
if (l == i->head && pass_counter++ > PASS_LIMIT)
break;
}
} while (l != end);
spin_unlock(&i->lock);

View File

@ -58,7 +58,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
struct resource resource;
struct device_node *np = ofdev->dev.of_node;
u32 clk, spd, prop;
int ret;
int ret, irq;
memset(port, 0, sizeof *port);
@ -143,21 +143,27 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (ret >= 0)
port->line = ret;
port->irq = irq_of_parse_and_map(np, 0);
if (!port->irq) {
ret = -EPROBE_DEFER;
goto err_unprepare;
irq = of_irq_get(np, 0);
if (irq < 0) {
if (irq == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto err_unprepare;
}
/* IRQ support not mandatory */
irq = 0;
}
port->irq = irq;
info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
if (IS_ERR(info->rst)) {
ret = PTR_ERR(info->rst);
goto err_dispose;
goto err_unprepare;
}
ret = reset_control_deassert(info->rst);
if (ret)
goto err_dispose;
goto err_unprepare;
port->type = type;
port->uartclk = clk;
@ -184,8 +190,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
port->handle_irq = fsl8250_handle_irq;
return 0;
err_dispose:
irq_dispose_mapping(port->irq);
err_unprepare:
clk_disable_unprepare(info->clk);
err_pmruntime:

View File

@ -552,11 +552,30 @@ static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
*/
static void serial8250_clear_fifos(struct uart_8250_port *p)
{
unsigned char fcr;
unsigned char clr_mask = UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
if (p->capabilities & UART_CAP_FIFO) {
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
serial_out(p, UART_FCR, 0);
/*
* Make sure to avoid changing FCR[7:3] and ENABLE_FIFO bits.
* In case ENABLE_FIFO is not set, there is nothing to flush
* so just return. Furthermore, on certain implementations of
* the 8250 core, the FCR[7:3] bits may only be changed under
* specific conditions and changing them if those conditions
* are not met can have nasty side effects. One such core is
* the 8250-omap present in TI AM335x.
*/
fcr = serial_in(p, UART_FCR);
/* FIFO is not enabled, there's nothing to clear. */
if (!(fcr & UART_FCR_ENABLE_FIFO))
return;
fcr |= clr_mask;
serial_out(p, UART_FCR, fcr);
fcr &= ~clr_mask;
serial_out(p, UART_FCR, fcr);
}
}
@ -1448,7 +1467,7 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p)
* Enable previously disabled RX interrupts.
*/
if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
serial8250_clear_and_reinit_fifos(p);
serial8250_clear_fifos(p);
p->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_port_out(&p->port, UART_IER, p->ier);

View File

@ -12,9 +12,6 @@
#include "8250.h"
/* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */
#define UNIPHIER_UART_DEFAULT_FIFO_SIZE 64
/*
* This hardware is similar to 8250, but its register map is a bit different:
* - MMIO32 (regshift = 2)
@ -158,42 +155,6 @@ static void uniphier_serial_dl_write(struct uart_8250_port *up, int value)
writel(value, up->port.membase + UNIPHIER_UART_DLR);
}
static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
struct uniphier8250_priv *priv)
{
int ret;
u32 prop;
struct device_node *np = dev->of_node;
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
dev_err(dev, "failed to get alias id\n");
return ret;
}
port->line = ret;
/* Get clk rate through clk driver */
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get clock\n");
return PTR_ERR(priv->clk);
}
ret = clk_prepare_enable(priv->clk);
if (ret < 0)
return ret;
port->uartclk = clk_get_rate(priv->clk);
/* Check for fifo size */
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
port->fifosize = prop;
else
port->fifosize = UNIPHIER_UART_DEFAULT_FIFO_SIZE;
return 0;
}
static int uniphier_uart_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@ -226,9 +187,24 @@ static int uniphier_uart_probe(struct platform_device *pdev)
memset(&up, 0, sizeof(up));
ret = uniphier_of_serial_setup(dev, &up.port, priv);
if (ret < 0)
ret = of_alias_get_id(dev->of_node, "serial");
if (ret < 0) {
dev_err(dev, "failed to get alias id\n");
return ret;
}
up.port.line = ret;
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "failed to get clock\n");
return PTR_ERR(priv->clk);
}
ret = clk_prepare_enable(priv->clk);
if (ret)
return ret;
up.port.uartclk = clk_get_rate(priv->clk);
spin_lock_init(&priv->atomic_write_lock);
@ -241,10 +217,14 @@ static int uniphier_uart_probe(struct platform_device *pdev)
up.port.type = PORT_16550A;
up.port.iotype = UPIO_MEM32;
up.port.fifosize = 64;
up.port.regshift = UNIPHIER_UART_REGSHIFT;
up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE;
up.capabilities = UART_CAP_FIFO;
if (of_property_read_bool(dev->of_node, "auto-flow-control"))
up.capabilities |= UART_CAP_AFE;
up.port.serial_in = uniphier_serial_in;
up.port.serial_out = uniphier_serial_out;
up.dl_read = uniphier_serial_dl_read;

View File

@ -375,7 +375,7 @@ config SERIAL_8250_RT288X
config SERIAL_8250_OMAP
tristate "Support for OMAP internal UART (8250 based driver)"
depends on SERIAL_8250 && ARCH_OMAP2PLUS
depends on SERIAL_8250 && (ARCH_OMAP2PLUS || ARCH_K3)
help
If you have a machine based on an Texas Instruments OMAP CPU you
can enable its onboard serial ports by enabling this option.

View File

@ -34,6 +34,7 @@
#include <linux/suspend.h>
#include <linux/mm.h>
#include <asm/div64.h>
#include <asm/io.h>
#include <asm/ioctls.h>
@ -147,6 +148,8 @@ struct atmel_uart_port {
struct circ_buf rx_ring;
struct mctrl_gpios *gpios;
u32 backup_mode; /* MR saved during iso7816 operations */
u32 backup_brgr; /* BRGR saved during iso7816 operations */
unsigned int tx_done_mask;
u32 fifo_size;
u32 rts_high;
@ -163,6 +166,10 @@ struct atmel_uart_port {
unsigned int pending_status;
spinlock_t lock_suspended;
/* ISO7816 */
unsigned int fidi_min;
unsigned int fidi_max;
#ifdef CONFIG_PM
struct {
u32 cr;
@ -361,6 +368,127 @@ static int atmel_config_rs485(struct uart_port *port,
return 0;
}
static unsigned int atmel_calc_cd(struct uart_port *port,
struct serial_iso7816 *iso7816conf)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int cd;
u64 mck_rate;
mck_rate = (u64)clk_get_rate(atmel_port->clk);
do_div(mck_rate, iso7816conf->clk);
cd = mck_rate;
return cd;
}
static unsigned int atmel_calc_fidi(struct uart_port *port,
struct serial_iso7816 *iso7816conf)
{
u64 fidi = 0;
if (iso7816conf->sc_fi && iso7816conf->sc_di) {
fidi = (u64)iso7816conf->sc_fi;
do_div(fidi, iso7816conf->sc_di);
}
return (u32)fidi;
}
/* Enable or disable the iso7816 support */
/* Called with interrupts disabled */
static int atmel_config_iso7816(struct uart_port *port,
struct serial_iso7816 *iso7816conf)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int mode;
unsigned int cd, fidi;
int ret = 0;
/* Disable interrupts */
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
mode = atmel_uart_readl(port, ATMEL_US_MR);
if (iso7816conf->flags & SER_ISO7816_ENABLED) {
mode &= ~ATMEL_US_USMODE;
if (iso7816conf->tg > 255) {
dev_err(port->dev, "ISO7816: Timeguard exceeding 255\n");
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
ret = -EINVAL;
goto err_out;
}
if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
== SER_ISO7816_T(0)) {
mode |= ATMEL_US_USMODE_ISO7816_T0 | ATMEL_US_DSNACK;
} else if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
== SER_ISO7816_T(1)) {
mode |= ATMEL_US_USMODE_ISO7816_T1 | ATMEL_US_INACK;
} else {
dev_err(port->dev, "ISO7816: Type not supported\n");
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
ret = -EINVAL;
goto err_out;
}
mode &= ~(ATMEL_US_USCLKS | ATMEL_US_NBSTOP | ATMEL_US_PAR);
/* select mck clock, and output */
mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
/* set parity for normal/inverse mode + max iterations */
mode |= ATMEL_US_PAR_EVEN | ATMEL_US_NBSTOP_1 | ATMEL_US_MAX_ITER(3);
cd = atmel_calc_cd(port, iso7816conf);
fidi = atmel_calc_fidi(port, iso7816conf);
if (fidi == 0) {
dev_warn(port->dev, "ISO7816 fidi = 0, Generator generates no signal\n");
} else if (fidi < atmel_port->fidi_min
|| fidi > atmel_port->fidi_max) {
dev_err(port->dev, "ISO7816 fidi = %u, value not supported\n", fidi);
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
ret = -EINVAL;
goto err_out;
}
if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) {
/* port not yet in iso7816 mode: store configuration */
atmel_port->backup_mode = atmel_uart_readl(port, ATMEL_US_MR);
atmel_port->backup_brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
}
atmel_uart_writel(port, ATMEL_US_TTGR, iso7816conf->tg);
atmel_uart_writel(port, ATMEL_US_BRGR, cd);
atmel_uart_writel(port, ATMEL_US_FIDI, fidi);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXEN);
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY | ATMEL_US_NACK | ATMEL_US_ITERATION;
} else {
dev_dbg(port->dev, "Setting UART back to RS232\n");
/* back to last RS232 settings */
mode = atmel_port->backup_mode;
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
atmel_uart_writel(port, ATMEL_US_TTGR, 0);
atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->backup_brgr);
atmel_uart_writel(port, ATMEL_US_FIDI, 0x174);
if (atmel_use_pdc_tx(port))
atmel_port->tx_done_mask = ATMEL_US_ENDTX |
ATMEL_US_TXBUFE;
else
atmel_port->tx_done_mask = ATMEL_US_TXRDY;
}
port->iso7816 = *iso7816conf;
atmel_uart_writel(port, ATMEL_US_MR, mode);
err_out:
/* Enable interrupts */
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
return ret;
}
/*
* Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
*/
@ -480,8 +608,9 @@ static void atmel_stop_tx(struct uart_port *port)
/* Disable interrupts */
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
if ((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
if (((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_start_rx(port);
}
@ -499,8 +628,9 @@ static void atmel_start_tx(struct uart_port *port)
return;
if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
if ((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
if (((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_stop_rx(port);
if (atmel_use_pdc_tx(port))
@ -798,8 +928,9 @@ static void atmel_complete_tx_dma(void *arg)
*/
if (!uart_circ_empty(xmit))
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
else if ((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
else if (((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
port->iso7816.flags & SER_ISO7816_ENABLED) {
/* DMA done, stop TX, start RX for RS485 */
atmel_start_rx(port);
}
@ -1282,6 +1413,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
wake_up_interruptible(&port->state->port.delta_msr_wait);
}
}
if (pending & (ATMEL_US_NACK | ATMEL_US_ITERATION))
dev_dbg(port->dev, "ISO7816 ERROR (0x%08x)\n", pending);
}
/*
@ -1374,8 +1508,9 @@ static void atmel_tx_pdc(struct uart_port *port)
atmel_uart_writel(port, ATMEL_US_IER,
atmel_port->tx_done_mask);
} else {
if ((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
if (((port->rs485.flags & SER_RS485_ENABLED) &&
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
port->iso7816.flags & SER_ISO7816_ENABLED) {
/* DMA done, stop TX, start RX for RS485 */
atmel_start_rx(port);
}
@ -1727,6 +1862,22 @@ static void atmel_get_ip_name(struct uart_port *port)
atmel_port->has_frac_baudrate = true;
atmel_port->has_hw_timer = true;
atmel_port->rtor = ATMEL_US_RTOR;
version = atmel_uart_readl(port, ATMEL_US_VERSION);
switch (version) {
case 0x814: /* sama5d2 */
/* fall through */
case 0x701: /* sama5d4 */
atmel_port->fidi_min = 3;
atmel_port->fidi_max = 65535;
break;
case 0x502: /* sam9x5, sama5d3 */
atmel_port->fidi_min = 3;
atmel_port->fidi_max = 2047;
break;
default:
atmel_port->fidi_min = 1;
atmel_port->fidi_max = 2047;
}
} else if (name == dbgu_uart) {
dev_dbg(port->dev, "Dbgu or uart without hw timer\n");
} else {
@ -2100,6 +2251,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
atmel_uart_writel(port, ATMEL_US_TTGR,
port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
} else if (port->iso7816.flags & SER_ISO7816_ENABLED) {
atmel_uart_writel(port, ATMEL_US_TTGR, port->iso7816.tg);
/* select mck clock, and output */
mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
/* set max iterations */
mode |= ATMEL_US_MAX_ITER(3);
if ((port->iso7816.flags & SER_ISO7816_T_PARAM)
== SER_ISO7816_T(0))
mode |= ATMEL_US_USMODE_ISO7816_T0;
else
mode |= ATMEL_US_USMODE_ISO7816_T1;
} else if (termios->c_cflag & CRTSCTS) {
/* RS232 with hardware handshake (RTS/CTS) */
if (atmel_use_fifo(port) &&
@ -2176,7 +2338,8 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
}
quot = cd | fp << ATMEL_US_FP_OFFSET;
atmel_uart_writel(port, ATMEL_US_BRGR, quot);
if (!(port->iso7816.flags & SER_ISO7816_ENABLED))
atmel_uart_writel(port, ATMEL_US_BRGR, quot);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
atmel_port->tx_stopped = false;
@ -2357,6 +2520,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
port->mapbase = mpdev->resource[0].start;
port->irq = mpdev->resource[1].start;
port->rs485_config = atmel_config_rs485;
port->iso7816_config = atmel_config_iso7816;
port->membase = NULL;
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
@ -2380,8 +2544,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
/* only enable clock when USART is in use */
}
/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
if (port->rs485.flags & SER_RS485_ENABLED)
/*
* Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or
* ENDTX|TXBUFE
*/
if (port->rs485.flags & SER_RS485_ENABLED ||
port->iso7816.flags & SER_ISO7816_ENABLED)
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
else if (atmel_use_pdc_tx(port)) {
port->fifosize = PDC_BUFFER_SIZE;

View File

@ -78,7 +78,8 @@
#define ATMEL_US_OVER BIT(19) /* Oversampling Mode */
#define ATMEL_US_INACK BIT(20) /* Inhibit Non Acknowledge */
#define ATMEL_US_DSNACK BIT(21) /* Disable Successive NACK */
#define ATMEL_US_MAX_ITER GENMASK(26, 24) /* Max Iterations */
#define ATMEL_US_MAX_ITER_MASK GENMASK(26, 24) /* Max Iterations */
#define ATMEL_US_MAX_ITER(n) (((n) << 24) & ATMEL_US_MAX_ITER_MASK)
#define ATMEL_US_FILTER BIT(28) /* Infrared Receive Line Filter */
#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */

View File

@ -1155,8 +1155,8 @@ static int cpm_uart_init_port(struct device_node *np,
if (!pinfo->clk) {
data = of_get_property(np, "fsl,cpm-brg", &len);
if (!data || len != 4) {
printk(KERN_ERR "CPM UART %s has no/invalid "
"fsl,cpm-brg property.\n", np->name);
printk(KERN_ERR "CPM UART %pOFn has no/invalid "
"fsl,cpm-brg property.\n", np);
return -EINVAL;
}
pinfo->brg = *data;
@ -1164,8 +1164,8 @@ static int cpm_uart_init_port(struct device_node *np,
data = of_get_property(np, "fsl,cpm-command", &len);
if (!data || len != 4) {
printk(KERN_ERR "CPM UART %s has no/invalid "
"fsl,cpm-command property.\n", np->name);
printk(KERN_ERR "CPM UART %pOFn has no/invalid "
"fsl,cpm-command property.\n", np);
return -EINVAL;
}
pinfo->command = *data;

View File

@ -232,6 +232,8 @@
/* IMX lpuart has four extra unused regs located at the beginning */
#define IMX_REG_OFF 0x10
static DEFINE_IDA(fsl_lpuart_ida);
struct lpuart_port {
struct uart_port port;
struct clk *clk;
@ -2143,8 +2145,11 @@ static int lpuart_probe(struct platform_device *pdev)
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
return ret;
ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL);
if (ret < 0) {
dev_err(&pdev->dev, "port line is full, add device failed\n");
return ret;
}
}
if (ret >= ARRAY_SIZE(lpuart_ports)) {
dev_err(&pdev->dev, "serial%d out of range\n", ret);
@ -2246,6 +2251,8 @@ static int lpuart_remove(struct platform_device *pdev)
uart_remove_one_port(&lpuart_reg, &sport->port);
ida_simple_remove(&fsl_lpuart_ida, sport->port.line);
clk_disable_unprepare(sport->clk);
if (sport->dma_tx_chan)
@ -2384,6 +2391,7 @@ static int __init lpuart_serial_init(void)
static void __exit lpuart_serial_exit(void)
{
ida_destroy(&fsl_lpuart_ida);
platform_driver_unregister(&lpuart_driver);
uart_unregister_driver(&lpuart_reg);
}

View File

@ -24,6 +24,7 @@
#include <linux/serial.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pinctrl/consumer.h>
#include <linux/rational.h>
#include <linux/slab.h>
#include <linux/of.h>
@ -706,27 +707,25 @@ static irqreturn_t imx_uart_rtsint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
u32 usr1;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
spin_lock(&sport->port.lock);
imx_uart_writel(sport, USR1_RTSD, USR1);
usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
uart_handle_cts_change(&sport->port, !!usr1);
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
spin_unlock_irqrestore(&sport->port.lock, flags);
spin_unlock(&sport->port.lock);
return IRQ_HANDLED;
}
static irqreturn_t imx_uart_txint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
spin_lock(&sport->port.lock);
imx_uart_transmit_buffer(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
spin_unlock(&sport->port.lock);
return IRQ_HANDLED;
}
@ -735,9 +734,8 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
struct imx_port *sport = dev_id;
unsigned int rx, flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
spin_lock(&sport->port.lock);
while (imx_uart_readl(sport, USR2) & USR2_RDR) {
u32 usr2;
@ -797,7 +795,7 @@ static irqreturn_t imx_uart_rxint(int irq, void *dev_id)
}
out:
spin_unlock_irqrestore(&sport->port.lock, flags);
spin_unlock(&sport->port.lock);
tty_flip_buffer_push(port);
return IRQ_HANDLED;
}
@ -903,13 +901,11 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id)
}
if (usr1 & USR1_DTRD) {
unsigned long flags;
imx_uart_writel(sport, USR1_DTRD, USR1);
spin_lock_irqsave(&sport->port.lock, flags);
spin_lock(&sport->port.lock);
imx_uart_mctrl_check(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
spin_unlock(&sport->port.lock);
ret = IRQ_HANDLED;
}
@ -2384,8 +2380,13 @@ static int imx_uart_remove(struct platform_device *pdev)
static void imx_uart_restore_context(struct imx_port *sport)
{
if (!sport->context_saved)
unsigned long flags;
spin_lock_irqsave(&sport->port.lock, flags);
if (!sport->context_saved) {
spin_unlock_irqrestore(&sport->port.lock, flags);
return;
}
imx_uart_writel(sport, sport->saved_reg[4], UFCR);
imx_uart_writel(sport, sport->saved_reg[5], UESC);
@ -2398,11 +2399,15 @@ static void imx_uart_restore_context(struct imx_port *sport)
imx_uart_writel(sport, sport->saved_reg[2], UCR3);
imx_uart_writel(sport, sport->saved_reg[3], UCR4);
sport->context_saved = false;
spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void imx_uart_save_context(struct imx_port *sport)
{
unsigned long flags;
/* Save necessary regs */
spin_lock_irqsave(&sport->port.lock, flags);
sport->saved_reg[0] = imx_uart_readl(sport, UCR1);
sport->saved_reg[1] = imx_uart_readl(sport, UCR2);
sport->saved_reg[2] = imx_uart_readl(sport, UCR3);
@ -2414,6 +2419,7 @@ static void imx_uart_save_context(struct imx_port *sport)
sport->saved_reg[8] = imx_uart_readl(sport, UBMR);
sport->saved_reg[9] = imx_uart_readl(sport, IMX21_UTS);
sport->context_saved = true;
spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
@ -2447,6 +2453,8 @@ static int imx_uart_suspend_noirq(struct device *dev)
clk_disable(sport->clk_ipg);
pinctrl_pm_select_sleep_state(dev);
return 0;
}
@ -2455,6 +2463,8 @@ static int imx_uart_resume_noirq(struct device *dev)
struct imx_port *sport = dev_get_drvdata(dev);
int ret;
pinctrl_pm_select_default_state(dev);
ret = clk_enable(sport->clk_ipg);
if (ret)
return ret;

View File

@ -8,6 +8,9 @@
*
* 2007-2008 (c) Jason Wessel - Wind River Systems, Inc.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/kgdb.h>
@ -128,19 +131,6 @@ static void kgdboc_unregister_kbd(void)
#define kgdboc_restore_input()
#endif /* ! CONFIG_KDB_KEYBOARD */
static int kgdboc_option_setup(char *opt)
{
if (strlen(opt) >= MAX_CONFIG_LEN) {
printk(KERN_ERR "kgdboc: config string too long\n");
return -ENOSPC;
}
strcpy(config, opt);
return 0;
}
__setup("kgdboc=", kgdboc_option_setup);
static void cleanup_kgdboc(void)
{
if (kgdb_unregister_nmi_console())
@ -154,15 +144,13 @@ static int configure_kgdboc(void)
{
struct tty_driver *p;
int tty_line = 0;
int err;
int err = -ENODEV;
char *cptr = config;
struct console *cons;
err = kgdboc_option_setup(config);
if (err || !strlen(config) || isspace(config[0]))
if (!strlen(config) || isspace(config[0]))
goto noconfig;
err = -ENODEV;
kgdboc_io_ops.is_console = 0;
kgdb_tty_driver = NULL;
@ -248,7 +236,7 @@ static int param_set_kgdboc_var(const char *kmessage,
int len = strlen(kmessage);
if (len >= MAX_CONFIG_LEN) {
printk(KERN_ERR "kgdboc: config string too long\n");
pr_err("config string too long\n");
return -ENOSPC;
}
@ -259,8 +247,7 @@ static int param_set_kgdboc_var(const char *kmessage,
}
if (kgdb_connected) {
printk(KERN_ERR
"kgdboc: Cannot reconfigure while KGDB is connected.\n");
pr_err("Cannot reconfigure while KGDB is connected.\n");
return -EBUSY;
}
@ -311,6 +298,25 @@ static struct kgdb_io kgdboc_io_ops = {
};
#ifdef CONFIG_KGDB_SERIAL_CONSOLE
static int kgdboc_option_setup(char *opt)
{
if (!opt) {
pr_err("config string not provided\n");
return -EINVAL;
}
if (strlen(opt) >= MAX_CONFIG_LEN) {
pr_err("config string too long\n");
return -ENOSPC;
}
strcpy(config, opt);
return 0;
}
__setup("kgdboc=", kgdboc_option_setup);
/* This is only available if kgdboc is a built in for early debugging */
static int __init kgdboc_early_init(char *opt)
{

View File

@ -1634,8 +1634,9 @@ static int mxs_auart_request_gpio_irq(struct mxs_auart_port *s)
/*
* If something went wrong, rollback.
* Be careful: i may be unsigned.
*/
while (err && (--i >= 0))
while (err && (i-- > 0))
if (irq[i] >= 0)
free_irq(irq[i], s);

View File

@ -219,7 +219,7 @@ static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
static bool pmz_receive_chars(struct uart_pmac_port *uap)
{
struct tty_port *port;
unsigned char ch, r1, drop, error, flag;
unsigned char ch, r1, drop, flag;
int loops = 0;
/* Sanity check, make sure the old bug is no longer happening */
@ -231,7 +231,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
port = &uap->port.state->port;
while (1) {
error = 0;
drop = 0;
r1 = read_zsreg(uap, R1);
@ -273,7 +272,6 @@ static bool pmz_receive_chars(struct uart_pmac_port *uap)
uap->port.icount.rx++;
if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
error = 1;
if (r1 & BRK_ABRT) {
pmz_debug("pmz: got break !\n");
r1 &= ~(PAR_ERR | CRC_ERR);
@ -1566,9 +1564,9 @@ static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
* to work around bugs in ancient Apple device-trees
*/
if (macio_request_resources(uap->dev, "pmac_zilog"))
printk(KERN_WARNING "%s: Failed to request resource"
printk(KERN_WARNING "%pOFn: Failed to request resource"
", port still active\n",
uap->node->name);
uap->node);
else
uap->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;

View File

@ -851,6 +851,23 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
{
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
u32 proto;
if (uart_console(uport))
port->tx_bytes_pw = 1;
else
port->tx_bytes_pw = 4;
port->rx_bytes_pw = RX_BYTES_PW;
proto = geni_se_read_proto(&port->se);
if (proto != GENI_SE_UART) {
dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
return -ENXIO;
}
qcom_geni_serial_stop_rx(uport);
get_tx_fifo_size(port);
set_rfr_wm(port);
writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT);
@ -874,30 +891,19 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
return -ENOMEM;
}
port->setup = true;
return 0;
}
static int qcom_geni_serial_startup(struct uart_port *uport)
{
int ret;
u32 proto;
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
scnprintf(port->name, sizeof(port->name),
"qcom_serial_%s%d",
(uart_console(uport) ? "console" : "uart"), uport->line);
if (!uart_console(uport)) {
port->tx_bytes_pw = 4;
port->rx_bytes_pw = RX_BYTES_PW;
}
proto = geni_se_read_proto(&port->se);
if (proto != GENI_SE_UART) {
dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto);
return -ENXIO;
}
get_tx_fifo_size(port);
if (!port->setup) {
ret = qcom_geni_serial_port_setup(uport);
if (ret)
@ -1056,6 +1062,7 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
int bits = 8;
int parity = 'n';
int flow = 'n';
int ret;
if (co->index >= GENI_UART_CONS_PORTS || co->index < 0)
return -ENXIO;
@ -1071,21 +1078,10 @@ static int __init qcom_geni_console_setup(struct console *co, char *options)
if (unlikely(!uport->membase))
return -ENXIO;
if (geni_se_resources_on(&port->se)) {
dev_err(port->se.dev, "Error turning on resources\n");
return -ENXIO;
}
if (unlikely(geni_se_read_proto(&port->se) != GENI_SE_UART)) {
geni_se_resources_off(&port->se);
return -ENXIO;
}
if (!port->setup) {
port->tx_bytes_pw = 1;
port->rx_bytes_pw = RX_BYTES_PW;
qcom_geni_serial_stop_rx(uport);
qcom_geni_serial_port_setup(uport);
ret = qcom_geni_serial_port_setup(uport);
if (ret)
return ret;
}
if (options)
@ -1203,11 +1199,12 @@ static void qcom_geni_serial_pm(struct uart_port *uport,
{
struct qcom_geni_serial_port *port = to_dev_port(uport, uport);
/* If we've never been called, treat it as off */
if (old_state == UART_PM_STATE_UNDEFINED)
old_state = UART_PM_STATE_OFF;
if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF)
geni_se_resources_on(&port->se);
else if (!uart_console(uport) && (new_state == UART_PM_STATE_ON &&
old_state == UART_PM_STATE_UNDEFINED))
geni_se_resources_on(&port->se);
else if (new_state == UART_PM_STATE_OFF &&
old_state == UART_PM_STATE_ON)
geni_se_resources_off(&port->se);
@ -1263,14 +1260,12 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
if (of_device_is_compatible(pdev->dev.of_node, "qcom,geni-debug-uart"))
console = true;
if (pdev->dev.of_node) {
if (console) {
drv = &qcom_geni_console_driver;
line = of_alias_get_id(pdev->dev.of_node, "serial");
} else {
drv = &qcom_geni_uart_driver;
line = of_alias_get_id(pdev->dev.of_node, "hsuart");
}
if (console) {
drv = &qcom_geni_console_driver;
line = of_alias_get_id(pdev->dev.of_node, "serial");
} else {
drv = &qcom_geni_uart_driver;
line = of_alias_get_id(pdev->dev.of_node, "hsuart");
}
port = get_port_from_line(line, console);

View File

@ -1941,7 +1941,11 @@ static int s3c24xx_serial_resume(struct device *dev)
if (port) {
clk_prepare_enable(ourport->clk);
if (!IS_ERR(ourport->baudclk))
clk_prepare_enable(ourport->baudclk);
s3c24xx_serial_resetport(port, s3c24xx_port_to_cfg(port));
if (!IS_ERR(ourport->baudclk))
clk_disable_unprepare(ourport->baudclk);
clk_disable_unprepare(ourport->clk);
uart_resume_port(&s3c24xx_uart_drv, port);
@ -1964,7 +1968,11 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
if (rx_enabled(port))
uintm &= ~S3C64XX_UINTM_RXD_MSK;
clk_prepare_enable(ourport->clk);
if (!IS_ERR(ourport->baudclk))
clk_prepare_enable(ourport->baudclk);
wr_regl(port, S3C64XX_UINTM, uintm);
if (!IS_ERR(ourport->baudclk))
clk_disable_unprepare(ourport->baudclk);
clk_disable_unprepare(ourport->clk);
}
}

View File

@ -328,6 +328,7 @@ struct sc16is7xx_port {
struct kthread_worker kworker;
struct task_struct *kworker_task;
struct kthread_work irq_work;
struct mutex efr_lock;
struct sc16is7xx_one p[0];
};
@ -499,6 +500,21 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
div /= 4;
}
/* In an amazing feat of design, the Enhanced Features Register shares
* the address of the Interrupt Identification Register, and is
* switched in by writing a magic value (0xbf) to the Line Control
* Register. Any interrupt firing during this time will see the EFR
* where it expects the IIR to be, leading to "Unexpected interrupt"
* messages.
*
* Prevent this possibility by claiming a mutex while accessing the
* EFR, and claiming the same mutex from within the interrupt handler.
* This is similar to disabling the interrupt, but that doesn't work
* because the bulk of the interrupt processing is run as a workqueue
* job in thread context.
*/
mutex_lock(&s->efr_lock);
lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
/* Open the LCR divisors for configuration */
@ -514,6 +530,8 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
/* Put LCR back to the normal mode */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
mutex_unlock(&s->efr_lock);
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_CLKSEL_BIT,
prescaler);
@ -657,7 +675,7 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
uart_write_wakeup(port);
}
static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
static bool sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
{
struct uart_port *port = &s->p[portno].port;
@ -666,7 +684,7 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
iir = sc16is7xx_port_read(port, SC16IS7XX_IIR_REG);
if (iir & SC16IS7XX_IIR_NO_INT_BIT)
break;
return false;
iir &= SC16IS7XX_IIR_ID_MASK;
@ -688,16 +706,27 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno)
port->line, iir);
break;
}
} while (1);
} while (0);
return true;
}
static void sc16is7xx_ist(struct kthread_work *ws)
{
struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work);
int i;
for (i = 0; i < s->devtype->nr_uart; ++i)
sc16is7xx_port_irq(s, i);
mutex_lock(&s->efr_lock);
while (1) {
bool keep_polling = false;
int i;
for (i = 0; i < s->devtype->nr_uart; ++i)
keep_polling |= sc16is7xx_port_irq(s, i);
if (!keep_polling)
break;
}
mutex_unlock(&s->efr_lock);
}
static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
@ -892,6 +921,9 @@ static void sc16is7xx_set_termios(struct uart_port *port,
if (!(termios->c_cflag & CREAD))
port->ignore_status_mask |= SC16IS7XX_LSR_BRK_ERROR_MASK;
/* As above, claim the mutex while accessing the EFR. */
mutex_lock(&s->efr_lock);
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG,
SC16IS7XX_LCR_CONF_MODE_B);
@ -913,6 +945,8 @@ static void sc16is7xx_set_termios(struct uart_port *port,
/* Update LCR register */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
mutex_unlock(&s->efr_lock);
/* Get baud rate generator configuration */
baud = uart_get_baud_rate(port, termios, old,
port->uartclk / 16 / 4 / 0xffff,
@ -1178,6 +1212,7 @@ static int sc16is7xx_probe(struct device *dev,
s->regmap = regmap;
s->devtype = devtype;
dev_set_drvdata(dev, s);
mutex_init(&s->efr_lock);
kthread_init_worker(&s->kworker);
kthread_init_work(&s->irq_work, sc16is7xx_ist);

View File

@ -1302,6 +1302,58 @@ static int uart_set_rs485_config(struct uart_port *port,
return 0;
}
static int uart_get_iso7816_config(struct uart_port *port,
struct serial_iso7816 __user *iso7816)
{
unsigned long flags;
struct serial_iso7816 aux;
if (!port->iso7816_config)
return -ENOIOCTLCMD;
spin_lock_irqsave(&port->lock, flags);
aux = port->iso7816;
spin_unlock_irqrestore(&port->lock, flags);
if (copy_to_user(iso7816, &aux, sizeof(aux)))
return -EFAULT;
return 0;
}
static int uart_set_iso7816_config(struct uart_port *port,
struct serial_iso7816 __user *iso7816_user)
{
struct serial_iso7816 iso7816;
int i, ret;
unsigned long flags;
if (!port->iso7816_config)
return -ENOIOCTLCMD;
if (copy_from_user(&iso7816, iso7816_user, sizeof(*iso7816_user)))
return -EFAULT;
/*
* There are 5 words reserved for future use. Check that userspace
* doesn't put stuff in there to prevent breakages in the future.
*/
for (i = 0; i < 5; i++)
if (iso7816.reserved[i])
return -EINVAL;
spin_lock_irqsave(&port->lock, flags);
ret = port->iso7816_config(port, &iso7816);
spin_unlock_irqrestore(&port->lock, flags);
if (ret)
return ret;
if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816)))
return -EFAULT;
return 0;
}
/*
* Called via sys_ioctl. We can use spin_lock_irq() here.
*/
@ -1371,6 +1423,14 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
case TIOCSRS485:
ret = uart_set_rs485_config(uport, uarg);
break;
case TIOCSISO7816:
ret = uart_set_iso7816_config(state->uart_port, uarg);
break;
case TIOCGISO7816:
ret = uart_get_iso7816_config(state->uart_port, uarg);
break;
default:
if (uport->ops->ioctl)
ret = uport->ops->ioctl(uport, cmd, arg);

View File

@ -1516,7 +1516,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
chan = dma_request_slave_channel(port->dev,
dir == DMA_MEM_TO_DEV ? "tx" : "rx");
if (!chan) {
dev_warn(port->dev, "dma_request_slave_channel failed\n");
dev_dbg(port->dev, "dma_request_slave_channel failed\n");
return NULL;
}
@ -3414,6 +3414,12 @@ static int __init scif_early_console_setup(struct earlycon_device *device,
{
return early_console_setup(device, PORT_SCIF);
}
static int __init rzscifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
port_cfg.regtype = SCIx_RZ_SCIFA_REGTYPE;
return early_console_setup(device, PORT_SCIF);
}
static int __init scifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
@ -3432,6 +3438,7 @@ static int __init hscif_early_console_setup(struct earlycon_device *device,
OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup);
OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);

View File

@ -888,7 +888,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
/* somebody really wants this output, might be an
* oops, kdb, panic, etc. make sure they get it. */
if (spin_is_locked(&port->sc_port.lock)) {
if (!spin_trylock_irqsave(&port->sc_port.lock, flags)) {
int lhead = port->sc_port.state->xmit.head;
int ltail = port->sc_port.state->xmit.tail;
int counter, got_lock = 0;
@ -905,13 +905,11 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
*/
for (counter = 0; counter < 150; mdelay(125), counter++) {
if (!spin_is_locked(&port->sc_port.lock)
|| stole_lock) {
if (!stole_lock) {
spin_lock_irqsave(&port->sc_port.lock,
flags);
got_lock = 1;
}
if (stole_lock)
break;
if (spin_trylock_irqsave(&port->sc_port.lock, flags)) {
got_lock = 1;
break;
} else {
/* still locked */
@ -938,7 +936,6 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count)
puts_raw_fixed(port->sc_ops->sal_puts_raw, s, count);
} else {
stole_lock = 0;
spin_lock_irqsave(&port->sc_port.lock, flags);
sn_transmit_chars(port, 1);
spin_unlock_irqrestore(&port->sc_port.lock, flags);

View File

@ -45,6 +45,8 @@
/* data number in TX and RX fifo */
#define SPRD_STS1 0x000C
#define SPRD_RX_FIFO_CNT_MASK GENMASK(7, 0)
#define SPRD_TX_FIFO_CNT_MASK GENMASK(15, 8)
/* interrupt enable register and its BITs */
#define SPRD_IEN 0x0010
@ -66,67 +68,62 @@
#define SPRD_LCR_DATA_LEN6 0x4
#define SPRD_LCR_DATA_LEN7 0x8
#define SPRD_LCR_DATA_LEN8 0xc
#define SPRD_LCR_PARITY (BIT(0) | BIT(1))
#define SPRD_LCR_PARITY (BIT(0) | BIT(1))
#define SPRD_LCR_PARITY_EN 0x2
#define SPRD_LCR_EVEN_PAR 0x0
#define SPRD_LCR_ODD_PAR 0x1
/* control register 1 */
#define SPRD_CTL1 0x001C
#define SPRD_CTL1 0x001C
#define RX_HW_FLOW_CTL_THLD BIT(6)
#define RX_HW_FLOW_CTL_EN BIT(7)
#define TX_HW_FLOW_CTL_EN BIT(8)
#define RX_TOUT_THLD_DEF 0x3E00
#define RX_HFC_THLD_DEF 0x40
#define RX_HFC_THLD_DEF 0x40
/* fifo threshold register */
#define SPRD_CTL2 0x0020
#define THLD_TX_EMPTY 0x40
#define THLD_RX_FULL 0x40
#define THLD_TX_EMPTY 0x40
#define THLD_TX_EMPTY_SHIFT 8
#define THLD_RX_FULL 0x40
/* config baud rate register */
#define SPRD_CLKD0 0x0024
#define SPRD_CLKD0_MASK GENMASK(15, 0)
#define SPRD_CLKD1 0x0028
#define SPRD_CLKD1_MASK GENMASK(20, 16)
#define SPRD_CLKD1_SHIFT 16
/* interrupt mask status register */
#define SPRD_IMSR 0x002C
#define SPRD_IMSR_RX_FIFO_FULL BIT(0)
#define SPRD_IMSR 0x002C
#define SPRD_IMSR_RX_FIFO_FULL BIT(0)
#define SPRD_IMSR_TX_FIFO_EMPTY BIT(1)
#define SPRD_IMSR_BREAK_DETECT BIT(7)
#define SPRD_IMSR_TIMEOUT BIT(13)
struct reg_backup {
u32 ien;
u32 ctrl0;
u32 ctrl1;
u32 ctrl2;
u32 clkd0;
u32 clkd1;
u32 dspwait;
};
#define SPRD_IMSR_BREAK_DETECT BIT(7)
#define SPRD_IMSR_TIMEOUT BIT(13)
struct sprd_uart_port {
struct uart_port port;
struct reg_backup reg_bak;
char name[16];
};
static struct sprd_uart_port *sprd_port[UART_NR_MAX];
static int sprd_ports_num;
static inline unsigned int serial_in(struct uart_port *port, int offset)
static inline unsigned int serial_in(struct uart_port *port,
unsigned int offset)
{
return readl_relaxed(port->membase + offset);
}
static inline void serial_out(struct uart_port *port, int offset, int value)
static inline void serial_out(struct uart_port *port, unsigned int offset,
int value)
{
writel_relaxed(value, port->membase + offset);
}
static unsigned int sprd_tx_empty(struct uart_port *port)
{
if (serial_in(port, SPRD_STS1) & 0xff00)
if (serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK)
return 0;
else
return TIOCSER_TEMT;
@ -224,14 +221,15 @@ static inline void sprd_rx(struct uart_port *port)
struct tty_port *tty = &port->state->port;
unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT;
while ((serial_in(port, SPRD_STS1) & 0x00ff) && max_count--) {
while ((serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK) &&
max_count--) {
lsr = serial_in(port, SPRD_LSR);
ch = serial_in(port, SPRD_RXD);
flag = TTY_NORMAL;
port->icount.rx++;
if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE |
SPRD_LSR_FE | SPRD_LSR_OE))
SPRD_LSR_FE | SPRD_LSR_OE))
if (handle_lsr_errors(port, &lsr, &flag))
continue;
if (uart_handle_sysrq_char(port, ch))
@ -294,8 +292,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
if (ims & SPRD_IMSR_TIMEOUT)
serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT);
if (ims & (SPRD_IMSR_RX_FIFO_FULL |
SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT))
if (ims & (SPRD_IMSR_RX_FIFO_FULL | SPRD_IMSR_BREAK_DETECT |
SPRD_IMSR_TIMEOUT))
sprd_rx(port);
if (ims & SPRD_IMSR_TX_FIFO_EMPTY)
@ -314,16 +312,17 @@ static int sprd_startup(struct uart_port *port)
struct sprd_uart_port *sp;
unsigned long flags;
serial_out(port, SPRD_CTL2, ((THLD_TX_EMPTY << 8) | THLD_RX_FULL));
serial_out(port, SPRD_CTL2,
THLD_TX_EMPTY << THLD_TX_EMPTY_SHIFT | THLD_RX_FULL);
/* clear rx fifo */
timeout = SPRD_TIMEOUT;
while (timeout-- && serial_in(port, SPRD_STS1) & 0x00ff)
while (timeout-- && serial_in(port, SPRD_STS1) & SPRD_RX_FIFO_CNT_MASK)
serial_in(port, SPRD_RXD);
/* clear tx fifo */
timeout = SPRD_TIMEOUT;
while (timeout-- && serial_in(port, SPRD_STS1) & 0xff00)
while (timeout-- && serial_in(port, SPRD_STS1) & SPRD_TX_FIFO_CNT_MASK)
cpu_relax();
/* clear interrupt */
@ -334,7 +333,7 @@ static int sprd_startup(struct uart_port *port)
sp = container_of(port, struct sprd_uart_port, port);
snprintf(sp->name, sizeof(sp->name), "sprd_serial%d", port->line);
ret = devm_request_irq(port->dev, port->irq, sprd_handle_irq,
IRQF_SHARED, sp->name, port);
IRQF_SHARED, sp->name, port);
if (ret) {
dev_err(port->dev, "fail to request serial irq %d, ret=%d\n",
port->irq, ret);
@ -362,8 +361,8 @@ static void sprd_shutdown(struct uart_port *port)
}
static void sprd_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud, quot;
unsigned int lcr = 0, fc;
@ -444,10 +443,11 @@ static void sprd_set_termios(struct uart_port *port,
}
/* clock divider bit0~bit15 */
serial_out(port, SPRD_CLKD0, quot & 0xffff);
serial_out(port, SPRD_CLKD0, quot & SPRD_CLKD0_MASK);
/* clock divider bit16~bit20 */
serial_out(port, SPRD_CLKD1, (quot & 0x1f0000) >> 16);
serial_out(port, SPRD_CLKD1,
(quot & SPRD_CLKD1_MASK) >> SPRD_CLKD1_SHIFT);
serial_out(port, SPRD_LCR, lcr);
fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
serial_out(port, SPRD_CTL1, fc);
@ -480,8 +480,7 @@ static void sprd_config_port(struct uart_port *port, int flags)
port->type = PORT_SPRD;
}
static int sprd_verify_port(struct uart_port *port,
struct serial_struct *ser)
static int sprd_verify_port(struct uart_port *port, struct serial_struct *ser)
{
if (ser->type != PORT_SPRD)
return -EINVAL;
@ -521,7 +520,7 @@ static void wait_for_xmitr(struct uart_port *port)
if (--tmout == 0)
break;
udelay(1);
} while (status & 0xff00);
} while (status & SPRD_TX_FIFO_CNT_MASK);
}
static void sprd_console_putchar(struct uart_port *port, int ch)
@ -531,7 +530,7 @@ static void sprd_console_putchar(struct uart_port *port, int ch)
}
static void sprd_console_write(struct console *co, const char *s,
unsigned int count)
unsigned int count)
{
struct uart_port *port = &sprd_port[co->index]->port;
int locked = 1;
@ -594,23 +593,21 @@ static void sprd_putc(struct uart_port *port, int c)
unsigned int timeout = SPRD_TIMEOUT;
while (timeout-- &&
!(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
!(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
cpu_relax();
writeb(c, port->membase + SPRD_TXD);
}
static void sprd_early_write(struct console *con, const char *s,
unsigned n)
static void sprd_early_write(struct console *con, const char *s, unsigned int n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, sprd_putc);
}
static int __init sprd_early_console_setup(
struct earlycon_device *device,
const char *opt)
static int __init sprd_early_console_setup(struct earlycon_device *device,
const char *opt)
{
if (!device->port.membase)
return -ENODEV;
@ -692,8 +689,8 @@ static int sprd_probe(struct platform_device *pdev)
index = sprd_probe_dt_alias(index, &pdev->dev);
sprd_port[index] = devm_kzalloc(&pdev->dev,
sizeof(*sprd_port[index]), GFP_KERNEL);
sprd_port[index] = devm_kzalloc(&pdev->dev, sizeof(*sprd_port[index]),
GFP_KERNEL);
if (!sprd_port[index])
return -ENOMEM;
@ -712,15 +709,12 @@ static int sprd_probe(struct platform_device *pdev)
up->uartclk = clk_get_rate(clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "not provide mem resource\n");
return -ENODEV;
}
up->mapbase = res->start;
up->membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(up->membase))
return PTR_ERR(up->membase);
up->mapbase = res->start;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "not provide irq resource: %d\n", irq);

View File

@ -55,6 +55,11 @@
#define ULITE_CONTROL_RST_RX 0x02
#define ULITE_CONTROL_IE 0x10
/* Static pointer to console port */
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
static struct uart_port *console_port;
#endif
struct uartlite_data {
const struct uartlite_reg_ops *reg_ops;
struct clk *clk;
@ -472,7 +477,7 @@ static void ulite_console_putchar(struct uart_port *port, int ch)
static void ulite_console_write(struct console *co, const char *s,
unsigned int count)
{
struct uart_port *port = &ulite_ports[co->index];
struct uart_port *port = console_port;
unsigned long flags;
unsigned int ier;
int locked = 1;
@ -506,10 +511,8 @@ static int ulite_console_setup(struct console *co, char *options)
int parity = 'n';
int flow = 'n';
if (co->index < 0 || co->index >= ULITE_NR_UARTS)
return -EINVAL;
port = &ulite_ports[co->index];
port = console_port;
/* Has the device been initialized yet? */
if (!port->mapbase) {
@ -541,14 +544,6 @@ static struct console ulite_console = {
.data = &ulite_uart_driver,
};
static int __init ulite_console_init(void)
{
register_console(&ulite_console);
return 0;
}
console_initcall(ulite_console_init);
static void early_uartlite_putc(struct uart_port *port, int c)
{
/*
@ -660,6 +655,17 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
dev_set_drvdata(dev, port);
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
/*
* If console hasn't been found yet try to assign this port
* because it is required to be assigned for console setup function.
* If register_console() don't assign value, then console_port pointer
* is cleanup.
*/
if (ulite_uart_driver.cons->index == -1)
console_port = port;
#endif
/* Register the port */
rc = uart_add_one_port(&ulite_uart_driver, port);
if (rc) {
@ -669,6 +675,12 @@ static int ulite_assign(struct device *dev, int id, u32 base, int irq,
return rc;
}
#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
/* This is not port which is used for console that's why clean it up */
if (ulite_uart_driver.cons->index == -1)
console_port = NULL;
#endif
return 0;
}
@ -776,13 +788,26 @@ static int ulite_probe(struct platform_device *pdev)
pdata->clk = NULL;
}
ret = clk_prepare(pdata->clk);
ret = clk_prepare_enable(pdata->clk);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare clock\n");
return ret;
}
return ulite_assign(&pdev->dev, id, res->start, irq, pdata);
if (!ulite_uart_driver.state) {
dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n");
ret = uart_register_driver(&ulite_uart_driver);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register driver\n");
return ret;
}
}
ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata);
clk_disable(pdata->clk);
return ret;
}
static int ulite_remove(struct platform_device *pdev)
@ -813,25 +838,9 @@ static struct platform_driver ulite_platform_driver = {
static int __init ulite_init(void)
{
int ret;
pr_debug("uartlite: calling uart_register_driver()\n");
ret = uart_register_driver(&ulite_uart_driver);
if (ret)
goto err_uart;
pr_debug("uartlite: calling platform_driver_register()\n");
ret = platform_driver_register(&ulite_platform_driver);
if (ret)
goto err_plat;
return 0;
err_plat:
uart_unregister_driver(&ulite_uart_driver);
err_uart:
pr_err("registering uartlite driver failed: err=%i\n", ret);
return ret;
return platform_driver_register(&ulite_platform_driver);
}
static void __exit ulite_exit(void)

View File

@ -30,8 +30,6 @@
#define CDNS_UART_TTY_NAME "ttyPS"
#define CDNS_UART_NAME "xuartps"
#define CDNS_UART_MAJOR 0 /* use dynamic node allocation */
#define CDNS_UART_MINOR 0 /* works best with devtmpfs */
#define CDNS_UART_NR_PORTS 2
#define CDNS_UART_FIFO_SIZE 64 /* FIFO size */
#define CDNS_UART_REGISTER_SPACE 0x1000
@ -180,7 +178,9 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
* @port: Pointer to the UART port
* @uartclk: Reference clock
* @pclk: APB clock
* @cdns_uart_driver: Pointer to UART driver
* @baud: Current baud rate
* @id: Port ID
* @clk_rate_change_nb: Notifier block for clock changes
* @quirks: Flags for RXBS support.
*/
@ -188,7 +188,9 @@ struct cdns_uart {
struct uart_port *port;
struct clk *uartclk;
struct clk *pclk;
struct uart_driver *cdns_uart_driver;
unsigned int baud;
int id;
struct notifier_block clk_rate_change_nb;
u32 quirks;
};
@ -1003,13 +1005,12 @@ static void cdns_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
val = readl(port->membase + CDNS_UART_MODEMCR);
mode_reg = readl(port->membase + CDNS_UART_MR);
val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR);
val &= ~(CDNS_UART_MODEMCR_RTS | CDNS_UART_MODEMCR_DTR |
CDNS_UART_MODEMCR_FCM);
mode_reg &= ~CDNS_UART_MR_CHMODE_MASK;
if (mctrl & TIOCM_RTS)
val |= CDNS_UART_MODEMCR_RTS;
if (mctrl & TIOCM_DTR)
val |= CDNS_UART_MODEMCR_DTR;
if (mctrl & TIOCM_RTS || mctrl & TIOCM_DTR)
val |= CDNS_UART_MODEMCR_FCM;
if (mctrl & TIOCM_LOOP)
mode_reg |= CDNS_UART_MR_CHMODE_L_LOOP;
else
@ -1217,7 +1218,7 @@ static void cdns_uart_console_write(struct console *co, const char *s,
*
* Return: 0 on success, negative errno otherwise.
*/
static int __init cdns_uart_console_setup(struct console *co, char *options)
static int cdns_uart_console_setup(struct console *co, char *options)
{
struct uart_port *port = console_port;
@ -1237,32 +1238,8 @@ static int __init cdns_uart_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
static struct uart_driver cdns_uart_uart_driver;
static struct console cdns_uart_console = {
.name = CDNS_UART_TTY_NAME,
.write = cdns_uart_console_write,
.device = uart_console_device,
.setup = cdns_uart_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1, /* Specified on the cmdline (e.g. console=ttyPS ) */
.data = &cdns_uart_uart_driver,
};
#endif /* CONFIG_SERIAL_XILINX_PS_UART_CONSOLE */
static struct uart_driver cdns_uart_uart_driver = {
.owner = THIS_MODULE,
.driver_name = CDNS_UART_NAME,
.dev_name = CDNS_UART_TTY_NAME,
.major = CDNS_UART_MAJOR,
.minor = CDNS_UART_MINOR,
.nr = CDNS_UART_NR_PORTS,
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
.cons = &cdns_uart_console,
#endif
};
#ifdef CONFIG_PM_SLEEP
/**
* cdns_uart_suspend - suspend event
@ -1273,24 +1250,12 @@ static struct uart_driver cdns_uart_uart_driver = {
static int cdns_uart_suspend(struct device *device)
{
struct uart_port *port = dev_get_drvdata(device);
struct tty_struct *tty;
struct device *tty_dev;
int may_wake = 0;
struct cdns_uart *cdns_uart = port->private_data;
int may_wake;
/* Get the tty which could be NULL so don't assume it's valid */
tty = tty_port_tty_get(&port->state->port);
if (tty) {
tty_dev = tty->dev;
may_wake = device_may_wakeup(tty_dev);
tty_kref_put(tty);
}
may_wake = device_may_wakeup(device);
/*
* Call the API provided in serial_core.c file which handles
* the suspend.
*/
uart_suspend_port(&cdns_uart_uart_driver, port);
if (!(console_suspend_enabled && !may_wake)) {
if (console_suspend_enabled && may_wake) {
unsigned long flags = 0;
spin_lock_irqsave(&port->lock, flags);
@ -1305,7 +1270,11 @@ static int cdns_uart_suspend(struct device *device)
spin_unlock_irqrestore(&port->lock, flags);
}
return 0;
/*
* Call the API provided in serial_core.c file which handles
* the suspend.
*/
return uart_suspend_port(cdns_uart->cdns_uart_driver, port);
}
/**
@ -1317,23 +1286,14 @@ static int cdns_uart_suspend(struct device *device)
static int cdns_uart_resume(struct device *device)
{
struct uart_port *port = dev_get_drvdata(device);
struct cdns_uart *cdns_uart = port->private_data;
unsigned long flags = 0;
u32 ctrl_reg;
struct tty_struct *tty;
struct device *tty_dev;
int may_wake = 0;
int may_wake;
/* Get the tty which could be NULL so don't assume it's valid */
tty = tty_port_tty_get(&port->state->port);
if (tty) {
tty_dev = tty->dev;
may_wake = device_may_wakeup(tty_dev);
tty_kref_put(tty);
}
may_wake = device_may_wakeup(device);
if (console_suspend_enabled && !may_wake) {
struct cdns_uart *cdns_uart = port->private_data;
clk_enable(cdns_uart->pclk);
clk_enable(cdns_uart->uartclk);
@ -1367,7 +1327,7 @@ static int cdns_uart_resume(struct device *device)
spin_unlock_irqrestore(&port->lock, flags);
}
return uart_resume_port(&cdns_uart_uart_driver, port);
return uart_resume_port(cdns_uart->cdns_uart_driver, port);
}
#endif /* ! CONFIG_PM_SLEEP */
static int __maybe_unused cdns_runtime_suspend(struct device *dev)
@ -1409,6 +1369,90 @@ static const struct of_device_id cdns_uart_of_match[] = {
};
MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
/*
* Maximum number of instances without alias IDs but if there is alias
* which target "< MAX_UART_INSTANCES" range this ID can't be used.
*/
#define MAX_UART_INSTANCES 32
/* Stores static aliases list */
static DECLARE_BITMAP(alias_bitmap, MAX_UART_INSTANCES);
static int alias_bitmap_initialized;
/* Stores actual bitmap of allocated IDs with alias IDs together */
static DECLARE_BITMAP(bitmap, MAX_UART_INSTANCES);
/* Protect bitmap operations to have unique IDs */
static DEFINE_MUTEX(bitmap_lock);
static int cdns_get_id(struct platform_device *pdev)
{
int id, ret;
mutex_lock(&bitmap_lock);
/* Alias list is stable that's why get alias bitmap only once */
if (!alias_bitmap_initialized) {
ret = of_alias_get_alias_list(cdns_uart_of_match, "serial",
alias_bitmap, MAX_UART_INSTANCES);
if (ret && ret != -EOVERFLOW) {
mutex_unlock(&bitmap_lock);
return ret;
}
alias_bitmap_initialized++;
}
/* Make sure that alias ID is not taken by instance without alias */
bitmap_or(bitmap, bitmap, alias_bitmap, MAX_UART_INSTANCES);
dev_dbg(&pdev->dev, "Alias bitmap: %*pb\n",
MAX_UART_INSTANCES, bitmap);
/* Look for a serialN alias */
id = of_alias_get_id(pdev->dev.of_node, "serial");
if (id < 0) {
dev_warn(&pdev->dev,
"No serial alias passed. Using the first free id\n");
/*
* Start with id 0 and check if there is no serial0 alias
* which points to device which is compatible with this driver.
* If alias exists then try next free position.
*/
id = 0;
for (;;) {
dev_info(&pdev->dev, "Checking id %d\n", id);
id = find_next_zero_bit(bitmap, MAX_UART_INSTANCES, id);
/* No free empty instance */
if (id == MAX_UART_INSTANCES) {
dev_err(&pdev->dev, "No free ID\n");
mutex_unlock(&bitmap_lock);
return -EINVAL;
}
dev_dbg(&pdev->dev, "The empty id is %d\n", id);
/* Check if ID is empty */
if (!test_and_set_bit(id, bitmap)) {
/* Break the loop if bit is taken */
dev_dbg(&pdev->dev,
"Selected ID %d allocation passed\n",
id);
break;
}
dev_dbg(&pdev->dev,
"Selected ID %d allocation failed\n", id);
/* if taking bit fails then try next one */
id++;
}
}
mutex_unlock(&bitmap_lock);
return id;
}
/**
* cdns_uart_probe - Platform driver probe
* @pdev: Pointer to the platform device structure
@ -1417,11 +1461,16 @@ MODULE_DEVICE_TABLE(of, cdns_uart_of_match);
*/
static int cdns_uart_probe(struct platform_device *pdev)
{
int rc, id, irq;
int rc, irq;
struct uart_port *port;
struct resource *res;
struct cdns_uart *cdns_uart_data;
const struct of_device_id *match;
struct uart_driver *cdns_uart_uart_driver;
char *driver_name;
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
struct console *cdns_uart_console;
#endif
cdns_uart_data = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_data),
GFP_KERNEL);
@ -1431,6 +1480,63 @@ static int cdns_uart_probe(struct platform_device *pdev)
if (!port)
return -ENOMEM;
cdns_uart_uart_driver = devm_kzalloc(&pdev->dev,
sizeof(*cdns_uart_uart_driver),
GFP_KERNEL);
if (!cdns_uart_uart_driver)
return -ENOMEM;
cdns_uart_data->id = cdns_get_id(pdev);
if (cdns_uart_data->id < 0)
return cdns_uart_data->id;
/* There is a need to use unique driver name */
driver_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s%d",
CDNS_UART_NAME, cdns_uart_data->id);
if (!driver_name) {
rc = -ENOMEM;
goto err_out_id;
}
cdns_uart_uart_driver->owner = THIS_MODULE;
cdns_uart_uart_driver->driver_name = driver_name;
cdns_uart_uart_driver->dev_name = CDNS_UART_TTY_NAME;
cdns_uart_uart_driver->major = CDNS_UART_MAJOR;
cdns_uart_uart_driver->minor = cdns_uart_data->id;
cdns_uart_uart_driver->nr = 1;
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console),
GFP_KERNEL);
if (!cdns_uart_console)
return -ENOMEM;
strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME,
sizeof(cdns_uart_console->name));
cdns_uart_console->index = cdns_uart_data->id;
cdns_uart_console->write = cdns_uart_console_write;
cdns_uart_console->device = uart_console_device;
cdns_uart_console->setup = cdns_uart_console_setup;
cdns_uart_console->flags = CON_PRINTBUFFER;
cdns_uart_console->data = cdns_uart_uart_driver;
cdns_uart_uart_driver->cons = cdns_uart_console;
#endif
rc = uart_register_driver(cdns_uart_uart_driver);
if (rc < 0) {
dev_err(&pdev->dev, "Failed to register driver\n");
goto err_out_id;
}
cdns_uart_data->cdns_uart_driver = cdns_uart_uart_driver;
/*
* Setting up proper name_base needs to be done after uart
* registration because tty_driver structure is not filled.
* name_base is 0 by default.
*/
cdns_uart_uart_driver->tty_driver->name_base = cdns_uart_data->id;
match = of_match_node(cdns_uart_of_match, pdev->dev.of_node);
if (match && match->data) {
const struct cdns_platform_data *data = match->data;
@ -1446,7 +1552,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
}
if (IS_ERR(cdns_uart_data->pclk)) {
dev_err(&pdev->dev, "pclk clock not found.\n");
return PTR_ERR(cdns_uart_data->pclk);
rc = PTR_ERR(cdns_uart_data->pclk);
goto err_out_unregister_driver;
}
cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk");
@ -1457,13 +1564,14 @@ static int cdns_uart_probe(struct platform_device *pdev)
}
if (IS_ERR(cdns_uart_data->uartclk)) {
dev_err(&pdev->dev, "uart_clk clock not found.\n");
return PTR_ERR(cdns_uart_data->uartclk);
rc = PTR_ERR(cdns_uart_data->uartclk);
goto err_out_unregister_driver;
}
rc = clk_prepare_enable(cdns_uart_data->pclk);
if (rc) {
dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
return rc;
goto err_out_unregister_driver;
}
rc = clk_prepare_enable(cdns_uart_data->uartclk);
if (rc) {
@ -1490,28 +1598,14 @@ static int cdns_uart_probe(struct platform_device *pdev)
&cdns_uart_data->clk_rate_change_nb))
dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
#endif
/* Look for a serialN alias */
id = of_alias_get_id(pdev->dev.of_node, "serial");
if (id < 0)
id = 0;
if (id >= CDNS_UART_NR_PORTS) {
dev_err(&pdev->dev, "Cannot get uart_port structure\n");
rc = -ENODEV;
goto err_out_notif_unreg;
}
/* At this point, we've got an empty uart_port struct, initialize it */
spin_lock_init(&port->lock);
port->membase = NULL;
port->irq = 0;
port->type = PORT_UNKNOWN;
port->iotype = UPIO_MEM32;
port->flags = UPF_BOOT_AUTOCONF;
port->ops = &cdns_uart_ops;
port->fifosize = CDNS_UART_FIFO_SIZE;
port->line = id;
port->dev = NULL;
/*
* Register the port.
@ -1538,11 +1632,11 @@ static int cdns_uart_probe(struct platform_device *pdev)
* If register_console() don't assign value, then console_port pointer
* is cleanup.
*/
if (cdns_uart_uart_driver.cons->index == -1)
if (!console_port)
console_port = port;
#endif
rc = uart_add_one_port(&cdns_uart_uart_driver, port);
rc = uart_add_one_port(cdns_uart_uart_driver, port);
if (rc) {
dev_err(&pdev->dev,
"uart_add_one_port() failed; err=%i\n", rc);
@ -1551,7 +1645,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
/* This is not port which is used for console that's why clean it up */
if (cdns_uart_uart_driver.cons->index == -1)
if (console_port == port &&
!(cdns_uart_uart_driver->cons->flags & CON_ENABLED))
console_port = NULL;
#endif
@ -1561,7 +1656,6 @@ err_out_pm_disable:
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
err_out_notif_unreg:
#ifdef CONFIG_COMMON_CLK
clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb);
@ -1570,7 +1664,13 @@ err_out_clk_disable:
clk_disable_unprepare(cdns_uart_data->uartclk);
err_out_clk_dis_pclk:
clk_disable_unprepare(cdns_uart_data->pclk);
err_out_unregister_driver:
uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
err_out_id:
mutex_lock(&bitmap_lock);
if (cdns_uart_data->id < MAX_UART_INSTANCES)
clear_bit(cdns_uart_data->id, bitmap);
mutex_unlock(&bitmap_lock);
return rc;
}
@ -1591,13 +1691,24 @@ static int cdns_uart_remove(struct platform_device *pdev)
clk_notifier_unregister(cdns_uart_data->uartclk,
&cdns_uart_data->clk_rate_change_nb);
#endif
rc = uart_remove_one_port(&cdns_uart_uart_driver, port);
rc = uart_remove_one_port(cdns_uart_data->cdns_uart_driver, port);
port->mapbase = 0;
mutex_lock(&bitmap_lock);
if (cdns_uart_data->id < MAX_UART_INSTANCES)
clear_bit(cdns_uart_data->id, bitmap);
mutex_unlock(&bitmap_lock);
clk_disable_unprepare(cdns_uart_data->uartclk);
clk_disable_unprepare(cdns_uart_data->pclk);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
#ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
if (console_port == port)
console_port = NULL;
#endif
uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
return rc;
}
@ -1613,28 +1724,14 @@ static struct platform_driver cdns_uart_platform_driver = {
static int __init cdns_uart_init(void)
{
int retval = 0;
/* Register the cdns_uart driver with the serial core */
retval = uart_register_driver(&cdns_uart_uart_driver);
if (retval)
return retval;
/* Register the platform driver */
retval = platform_driver_register(&cdns_uart_platform_driver);
if (retval)
uart_unregister_driver(&cdns_uart_uart_driver);
return retval;
return platform_driver_register(&cdns_uart_platform_driver);
}
static void __exit cdns_uart_exit(void)
{
/* Unregister the platform driver */
platform_driver_unregister(&cdns_uart_platform_driver);
/* Unregister the cdns_uart driver */
uart_unregister_driver(&cdns_uart_uart_driver);
}
arch_initcall(cdns_uart_init);

View File

@ -118,9 +118,12 @@ void tty_buffer_free_all(struct tty_port *port)
struct tty_bufhead *buf = &port->buf;
struct tty_buffer *p, *next;
struct llist_node *llist;
unsigned int freed = 0;
int still_used;
while ((p = buf->head) != NULL) {
buf->head = p->next;
freed += p->size;
if (p->size > 0)
kfree(p);
}
@ -132,7 +135,9 @@ void tty_buffer_free_all(struct tty_port *port)
buf->head = &buf->sentinel;
buf->tail = &buf->sentinel;
atomic_set(&buf->mem_used, 0);
still_used = atomic_xchg(&buf->mem_used, 0);
WARN(still_used != freed, "we still have not freed %d bytes!",
still_used - freed);
}
/**
@ -468,11 +473,15 @@ receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
{
unsigned char *p = char_buf_ptr(head, head->read);
char *f = NULL;
int n;
if (~head->flags & TTYB_NORMAL)
f = flag_buf_ptr(head, head->read);
return port->client_ops->receive_buf(port, p, f, count);
n = port->client_ops->receive_buf(port, p, f, count);
if (n > 0)
memset(p, 0, n);
return n;
}
/**

View File

@ -409,7 +409,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
mutex_lock(&tty_mutex);
/* Search through the tty devices to look for a match */
list_for_each_entry(p, &tty_drivers, tty_drivers) {
if (strncmp(name, p->name, len) != 0)
if (!len || strncmp(name, p->name, len) != 0)
continue;
stp = str;
if (*stp == ',')

View File

@ -279,7 +279,6 @@ EXPORT_SYMBOL(tty_port_put);
* Return a refcount protected tty instance or NULL if the port is not
* associated with a tty (eg due to close or hangup)
*/
struct tty_struct *tty_port_tty_get(struct tty_port *port)
{
unsigned long flags;
@ -300,7 +299,6 @@ EXPORT_SYMBOL(tty_port_tty_get);
* Associate the port and tty pair. Manages any internal refcounts.
* Pass NULL to deassociate a port
*/
void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty)
{
unsigned long flags;
@ -343,7 +341,6 @@ out:
*
* Caller holds tty lock.
*/
void tty_port_hangup(struct tty_port *port)
{
struct tty_struct *tty;
@ -399,7 +396,6 @@ EXPORT_SYMBOL_GPL(tty_port_tty_wakeup);
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
int tty_port_carrier_raised(struct tty_port *port)
{
if (port->ops->carrier_raised == NULL)
@ -416,7 +412,6 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
void tty_port_raise_dtr_rts(struct tty_port *port)
{
if (port->ops->dtr_rts)
@ -432,7 +427,6 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
* to hide some internal details. This will eventually become entirely
* internal to the tty port.
*/
void tty_port_lower_dtr_rts(struct tty_port *port)
{
if (port->ops->dtr_rts)
@ -464,7 +458,6 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts);
* NB: May drop and reacquire tty lock when blocking, so tty and tty_port
* may have changed state (eg., may have been hung up).
*/
int tty_port_block_til_ready(struct tty_port *port,
struct tty_struct *tty, struct file *filp)
{

View File

@ -388,6 +388,9 @@ extern int of_phandle_iterator_args(struct of_phandle_iterator *it,
extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
extern int of_alias_get_id(struct device_node *np, const char *stem);
extern int of_alias_get_highest_id(const char *stem);
extern int of_alias_get_alias_list(const struct of_device_id *matches,
const char *stem, unsigned long *bitmap,
unsigned int nbits);
extern int of_machine_is_compatible(const char *compat);
@ -898,6 +901,13 @@ static inline int of_alias_get_highest_id(const char *stem)
return -ENOSYS;
}
static inline int of_alias_get_alias_list(const struct of_device_id *matches,
const char *stem, unsigned long *bitmap,
unsigned int nbits)
{
return -ENOSYS;
}
static inline int of_machine_is_compatible(const char *compat)
{
return 0;

View File

@ -144,6 +144,8 @@ struct uart_port {
void (*handle_break)(struct uart_port *);
int (*rs485_config)(struct uart_port *,
struct serial_rs485 *rs485);
int (*iso7816_config)(struct uart_port *,
struct serial_iso7816 *iso7816);
unsigned int irq; /* irq number */
unsigned long irqflags; /* irq flags */
unsigned int uartclk; /* base uart clock */
@ -260,6 +262,7 @@ struct uart_port {
struct attribute_group *attr_group; /* port specific attributes */
const struct attribute_group **tty_groups; /* all attributes (serial core use only) */
struct serial_rs485 rs485;
struct serial_iso7816 iso7816;
void *private_data; /* generic platform data pointer */
};

View File

@ -79,6 +79,8 @@
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
#define FIONCLEX 0x5450
#define FIOCLEX 0x5451

View File

@ -132,4 +132,21 @@ struct serial_rs485 {
are a royal PITA .. */
};
/*
* Serial interface for controlling ISO7816 settings on chips with suitable
* support. Set with TIOCSISO7816 and get with TIOCGISO7816 if supported by
* your platform.
*/
struct serial_iso7816 {
__u32 flags; /* ISO7816 feature flags */
#define SER_ISO7816_ENABLED (1 << 0)
#define SER_ISO7816_T_PARAM (0x0f << 4)
#define SER_ISO7816_T(t) (((t) & 0x0f) << 4)
__u32 tg;
__u32 sc_fi;
__u32 sc_di;
__u32 clk;
__u32 reserved[5];
};
#endif /* _UAPI_LINUX_SERIAL_H */