TTY/Serial driver patches for 3.14-rc1

Here's the big tty/serial driver pull request for 3.14-rc1
 
 There are a number of n_tty fixes and cleanups, and some serial driver
 bugfixes, and we got rid of one obsolete driver, making this series
 remove more lines than added, always a nice surprise.
 
 All of these have been in linux-next with no reports of issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iEYEABECAAYFAlLdiiAACgkQMUfUDdst+ymInACgu+gjm0q6sua8Zsk9HN3Ko0jK
 Zy0AoI7jieqSxZfvZD84US98HTiWtumH
 =z6GV
 -----END PGP SIGNATURE-----

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

Pull tty/serial driver updates from Greg KH:
 "Here's the big tty/serial driver pull request for 3.14-rc1

  There are a number of n_tty fixes and cleanups, and some serial driver
  bugfixes, and we got rid of one obsolete driver, making this series
  remove more lines than added, always a nice surprise.

  All of these have been in linux-next with no reports of issues"

* tag 'tty-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (60 commits)
  tty/serial: at91: disable uart timer at start of shutdown
  serial: 8250: enable UART_BUG_NOMSR for Tegra
  tty/serial: at91: reset rx_ring when port is shutdown
  tty/serial: at91: fix race condition in atmel_serial_remove
  tty/serial: at91: Handle shutdown more safely
  serial: sirf: correct condition for fetching dma buffer into tty
  serial: sirf: provide pm entries of uart_ops
  serial: sirf: use PM macro initialize PM functions
  serial: clps711x: Enable driver compilation with COMPILE_TEST
  serial: clps711x: Add support for N_IRDA line discipline
  tty: synclink: avoid sleep_on race
  tty/amiserial: avoid interruptible_sleep_on
  tty: delete non-required instances of include <linux/init.h>
  tty: an overflow of multiplication in drivers/tty/cyclades.c
  serial: Remove old SC26XX driver
  serial: add support for 200 v3 series Titan card
  serial: 8250: Fix initialisation of Quatech cards with the AMCC PCI chip
  tty: Removing the deprecated function tty_vhangup_locked()
  TTY/n_gsm: Removing the wrong tty_unlock/lock() in gsm_dlci_release()
  tty/serial: at91: document clock properties
  ...
This commit is contained in:
Linus Torvalds 2014-01-20 16:05:23 -08:00
commit bcee63488e
52 changed files with 753 additions and 1369 deletions

View file

@ -6,6 +6,9 @@ Required properties:
additional mode or an USART new feature.
- reg: Should contain registers location and length
- interrupts: Should contain interrupt
- clock-names: tuple listing input clock names.
Required elements: "usart"
- clocks: phandles to input clocks.
Optional properties:
- atmel,use-dma-rx: use of PDC or DMA for receiving data
@ -26,6 +29,8 @@ Example:
compatible = "atmel,at91sam9260-usart";
reg = <0xfff8c000 0x4000>;
interrupts = <7>;
clocks = <&usart0_clk>;
clock-names = "usart";
atmel,use-dma-rx;
atmel,use-dma-tx;
};
@ -35,6 +40,8 @@ Example:
compatible = "atmel,at91sam9260-usart";
reg = <0xf001c000 0x100>;
interrupts = <12 4 5>;
clocks = <&usart0_clk>;
clock-names = "usart";
atmel,use-dma-rx;
atmel,use-dma-tx;
dmas = <&dma0 2 0x3>,

View file

@ -0,0 +1,28 @@
* Cirrus Logic CLPS711X Universal Asynchronous Receiver/Transmitter (UART)
Required properties:
- compatible: Should be "cirrus,clps711x-uart".
- reg: Address and length of the register set for the device.
- interrupts: Should contain UART TX and RX interrupt.
- clocks: Should contain UART core clock number.
- syscon: Phandle to SYSCON node, which contain UART control bits.
Optional properties:
- uart-use-ms: Indicate the UART has modem signal (DCD, DSR, CTS).
Note: Each UART port should have an alias correctly numbered
in "aliases" node.
Example:
aliases {
serial0 = &uart1;
};
uart1: uart@80000480 {
compatible = "cirrus,clps711x-uart";
reg = <0x80000480 0x80>;
interrupts = <12 13>;
clocks = <&clks 11>;
syscon = <&syscon1>;
uart-use-ms;
};

View file

@ -61,8 +61,29 @@ static void __init clps711x_add_syscon(void)
&clps711x_syscon_res[i], 1);
}
static const struct resource clps711x_uart1_res[] __initconst = {
DEFINE_RES_MEM(CLPS711X_PHYS_BASE + UARTDR1, SZ_128),
DEFINE_RES_IRQ(IRQ_UTXINT1),
DEFINE_RES_IRQ(IRQ_URXINT1),
};
static const struct resource clps711x_uart2_res[] __initconst = {
DEFINE_RES_MEM(CLPS711X_PHYS_BASE + UARTDR2, SZ_128),
DEFINE_RES_IRQ(IRQ_UTXINT2),
DEFINE_RES_IRQ(IRQ_URXINT2),
};
static void __init clps711x_add_uart(void)
{
platform_device_register_simple("clps711x-uart", 0, clps711x_uart1_res,
ARRAY_SIZE(clps711x_uart1_res));
platform_device_register_simple("clps711x-uart", 1, clps711x_uart2_res,
ARRAY_SIZE(clps711x_uart2_res));
};
void __init clps711x_devices_init(void)
{
clps711x_add_gpio();
clps711x_add_syscon();
clps711x_add_uart();
}

View file

@ -2511,8 +2511,8 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp)
/* If port is closing, signal caller to try again */
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING){
if (port->flags & ASYNC_CLOSING)
interruptible_sleep_on(&port->close_wait);
wait_event_interruptible_tty(tty, port->close_wait,
!(port->flags & ASYNC_CLOSING));
retval = ((port->flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
goto cleanup;

View file

@ -124,7 +124,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
{
struct serport *serport = (struct serport*) tty->disc_data;
unsigned long flags;
unsigned int ch_flags;
unsigned int ch_flags = 0;
int i;
spin_lock_irqsave(&serport->lock, flags);
@ -133,18 +133,20 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
goto out;
for (i = 0; i < count; i++) {
switch (fp[i]) {
case TTY_FRAME:
ch_flags = SERIO_FRAME;
break;
if (fp) {
switch (fp[i]) {
case TTY_FRAME:
ch_flags = SERIO_FRAME;
break;
case TTY_PARITY:
ch_flags = SERIO_PARITY;
break;
case TTY_PARITY:
ch_flags = SERIO_PARITY;
break;
default:
ch_flags = 0;
break;
default:
ch_flags = 0;
break;
}
}
serio_interrupt(serport->serio, cp[i], ch_flags);

View file

@ -596,13 +596,11 @@ static int parport_serial_pci_probe(struct pci_dev *dev,
err = pci_enable_device (dev);
if (err) {
pci_set_drvdata (dev, NULL);
kfree (priv);
return err;
}
if (parport_register (dev, id)) {
pci_set_drvdata (dev, NULL);
kfree (priv);
return -ENODEV;
}
@ -611,7 +609,6 @@ static int parport_serial_pci_probe(struct pci_dev *dev,
int i;
for (i = 0; i < priv->num_par; i++)
parport_pc_unregister_port (priv->port[i]);
pci_set_drvdata (dev, NULL);
kfree (priv);
return -ENODEV;
}
@ -624,8 +621,6 @@ static void parport_serial_pci_remove(struct pci_dev *dev)
struct parport_serial_private *priv = pci_get_drvdata (dev);
int i;
pci_set_drvdata(dev, NULL);
// Serial ports
if (priv->serial)
pciserial_remove_ports(priv->serial);

View file

@ -9,3 +9,23 @@ config FIREWIRE_SERIAL
To compile this driver as a module, say M here: the module will
be called firewire-serial.
if FIREWIRE_SERIAL
config FWTTY_MAX_TOTAL_PORTS
int "Maximum number of serial ports supported"
default "64"
help
Set this to the maximum number of serial ports you want the
firewire-serial driver to support.
config FWTTY_MAX_CARD_PORTS
int "Maximum number of serial ports supported per adapter"
range 0 FWTTY_MAX_TOTAL_PORTS
default "32"
help
Set this to the maximum number of serial ports each firewire
adapter supports. The actual number of serial ports registered
is set with the module parameter "ttys".
endif

View file

@ -136,14 +136,14 @@ static struct fwtty_peer *__fwserial_peer_by_node_id(struct fw_card *card,
#ifdef FWTTY_PROFILING
static void profile_fifo_avail(struct fwtty_port *port, unsigned *stat)
static void fwtty_profile_fifo(struct fwtty_port *port, unsigned *stat)
{
spin_lock_bh(&port->lock);
profile_size_distrib(stat, dma_fifo_avail(&port->tx_fifo));
fwtty_profile_data(stat, dma_fifo_avail(&port->tx_fifo));
spin_unlock_bh(&port->lock);
}
static void dump_profile(struct seq_file *m, struct stats *stats)
static void fwtty_dump_profile(struct seq_file *m, struct stats *stats)
{
/* for each stat, print sum of 0 to 2^k, then individually */
int k = 4;
@ -183,8 +183,8 @@ static void dump_profile(struct seq_file *m, struct stats *stats)
}
#else
#define profile_fifo_avail(port, stat)
#define dump_profile(m, stats)
#define fwtty_profile_fifo(port, stat)
#define fwtty_dump_profile(m, stats)
#endif
/*
@ -456,16 +456,27 @@ static int fwtty_write_port_status(struct fwtty_port *port)
return err;
}
static void __fwtty_throttle(struct fwtty_port *port, struct tty_struct *tty)
static void fwtty_throttle_port(struct fwtty_port *port)
{
struct tty_struct *tty;
unsigned old;
tty = tty_port_tty_get(&port->port);
if (!tty)
return;
spin_lock_bh(&port->lock);
old = port->mctrl;
port->mctrl |= OOB_RX_THROTTLE;
if (C_CRTSCTS(tty))
port->mctrl &= ~TIOCM_RTS;
if (~old & OOB_RX_THROTTLE)
__fwtty_write_port_status(port);
spin_unlock_bh(&port->lock);
tty_kref_put(tty);
}
/**
@ -532,80 +543,14 @@ static void fwtty_emit_breaks(struct work_struct *work)
port->icount.brk += brk;
}
static void fwtty_pushrx(struct work_struct *work)
{
struct fwtty_port *port = to_port(work, push);
struct tty_struct *tty;
struct buffered_rx *buf, *next;
int n, c = 0;
spin_lock_bh(&port->lock);
list_for_each_entry_safe(buf, next, &port->buf_list, list) {
n = tty_insert_flip_string_fixed_flag(&port->port, buf->data,
TTY_NORMAL, buf->n);
c += n;
port->buffered -= n;
if (n < buf->n) {
if (n > 0) {
memmove(buf->data, buf->data + n, buf->n - n);
buf->n -= n;
}
tty = tty_port_tty_get(&port->port);
if (tty) {
__fwtty_throttle(port, tty);
tty_kref_put(tty);
}
break;
} else {
list_del(&buf->list);
kfree(buf);
}
}
if (c > 0)
tty_flip_buffer_push(&port->port);
if (list_empty(&port->buf_list))
clear_bit(BUFFERING_RX, &port->flags);
spin_unlock_bh(&port->lock);
}
static int fwtty_buffer_rx(struct fwtty_port *port, unsigned char *d, size_t n)
{
struct buffered_rx *buf;
size_t size = (n + sizeof(struct buffered_rx) + 0xFF) & ~0xFF;
if (port->buffered + n > HIGH_WATERMARK) {
fwtty_err_ratelimited(port, "overflowed rx buffer: buffered: %d new: %zu wtrmk: %d\n",
port->buffered, n, HIGH_WATERMARK);
return 0;
}
buf = kmalloc(size, GFP_ATOMIC);
if (!buf)
return 0;
INIT_LIST_HEAD(&buf->list);
buf->n = n;
memcpy(buf->data, d, n);
spin_lock_bh(&port->lock);
list_add_tail(&buf->list, &port->buf_list);
port->buffered += n;
if (port->buffered > port->stats.watermark)
port->stats.watermark = port->buffered;
set_bit(BUFFERING_RX, &port->flags);
spin_unlock_bh(&port->lock);
return n;
}
static int fwtty_rx(struct fwtty_port *port, unsigned char *data, size_t len)
{
struct tty_struct *tty;
int c, n = len;
unsigned lsr;
int err = 0;
fwtty_dbg(port, "%d\n", n);
profile_size_distrib(port->stats.reads, n);
fwtty_profile_data(port->stats.reads, n);
if (port->write_only) {
n = 0;
@ -636,31 +581,24 @@ static int fwtty_rx(struct fwtty_port *port, unsigned char *data, size_t len)
goto out;
}
if (!test_bit(BUFFERING_RX, &port->flags)) {
c = tty_insert_flip_string_fixed_flag(&port->port, data,
TTY_NORMAL, n);
if (c > 0)
tty_flip_buffer_push(&port->port);
n -= c;
if (n) {
/* start buffering and throttling */
n -= fwtty_buffer_rx(port, &data[c], n);
tty = tty_port_tty_get(&port->port);
if (tty) {
spin_lock_bh(&port->lock);
__fwtty_throttle(port, tty);
spin_unlock_bh(&port->lock);
tty_kref_put(tty);
}
}
} else
n -= fwtty_buffer_rx(port, data, n);
c = tty_insert_flip_string_fixed_flag(&port->port, data, TTY_NORMAL, n);
if (c > 0)
tty_flip_buffer_push(&port->port);
n -= c;
if (n) {
port->overrun = true;
err = -EIO;
fwtty_err_ratelimited(port, "flip buffer overrun\n");
} else {
/* throttle the sender if remaining flip buffer space has
* reached high watermark to avoid losing data which may be
* in-flight. Since the AR request context is 32k, that much
* data may have _already_ been acked.
*/
if (tty_buffer_space_avail(&port->port) < HIGH_WATERMARK)
fwtty_throttle_port(port);
}
out:
@ -821,7 +759,7 @@ static int fwtty_tx(struct fwtty_port *port, bool drain)
if (n == -EAGAIN)
++port->stats.tx_stall;
else if (n == -ENODATA)
profile_size_distrib(port->stats.txns, 0);
fwtty_profile_data(port->stats.txns, 0);
else {
++port->stats.fifo_errs;
fwtty_err_ratelimited(port, "fifo err: %d\n",
@ -830,7 +768,7 @@ static int fwtty_tx(struct fwtty_port *port, bool drain)
break;
}
profile_size_distrib(port->stats.txns, txn->dma_pended.len);
fwtty_profile_data(port->stats.txns, txn->dma_pended.len);
fwtty_send_txn_async(peer, txn, TCODE_WRITE_BLOCK_REQUEST,
peer->fifo_addr, txn->dma_pended.data,
@ -1101,20 +1039,13 @@ static int fwtty_port_activate(struct tty_port *tty_port,
static void fwtty_port_shutdown(struct tty_port *tty_port)
{
struct fwtty_port *port = to_port(tty_port, port);
struct buffered_rx *buf, *next;
/* TODO: cancel outstanding transactions */
cancel_delayed_work_sync(&port->emit_breaks);
cancel_delayed_work_sync(&port->drain);
cancel_work_sync(&port->push);
spin_lock_bh(&port->lock);
list_for_each_entry_safe(buf, next, &port->buf_list, list) {
list_del(&buf->list);
kfree(buf);
}
port->buffered = 0;
port->flags = 0;
port->break_ctl = 0;
port->overrun = 0;
@ -1184,7 +1115,7 @@ static int fwtty_write(struct tty_struct *tty, const unsigned char *buf, int c)
int n, len;
fwtty_dbg(port, "%d\n", c);
profile_size_distrib(port->stats.writes, c);
fwtty_profile_data(port->stats.writes, c);
spin_lock_bh(&port->lock);
n = dma_fifo_in(&port->tx_fifo, buf, c);
@ -1262,9 +1193,7 @@ static void fwtty_unthrottle(struct tty_struct *tty)
fwtty_dbg(port, "CRTSCTS: %d\n", (C_CRTSCTS(tty) != 0));
profile_fifo_avail(port, port->stats.unthrottle);
schedule_work(&port->push);
fwtty_profile_fifo(port, port->stats.unthrottle);
spin_lock_bh(&port->lock);
port->mctrl &= ~OOB_RX_THROTTLE;
@ -1523,15 +1452,14 @@ static void fwtty_debugfs_show_port(struct seq_file *m, struct fwtty_port *port)
seq_printf(m, " dr:%d st:%d err:%d lost:%d", stats.dropped,
stats.tx_stall, stats.fifo_errs, stats.lost);
seq_printf(m, " pkts:%d thr:%d wtrmk:%d", stats.sent, stats.throttled,
stats.watermark);
seq_printf(m, " pkts:%d thr:%d", stats.sent, stats.throttled);
if (port->port.console) {
seq_puts(m, "\n ");
(*port->fwcon_ops->proc_show)(m, port->con_data);
}
dump_profile(m, &port->stats);
fwtty_dump_profile(m, &port->stats);
}
static void fwtty_debugfs_show_peer(struct seq_file *m, struct fwtty_peer *peer)
@ -2297,13 +2225,12 @@ static int fwserial_create(struct fw_unit *unit)
port->index = FWTTY_INVALID_INDEX;
port->port.ops = &fwtty_port_ops;
port->serial = serial;
tty_buffer_set_limit(&port->port, 128 * 1024);
spin_lock_init(&port->lock);
INIT_DELAYED_WORK(&port->drain, fwtty_drain_tx);
INIT_DELAYED_WORK(&port->emit_breaks, fwtty_emit_breaks);
INIT_WORK(&port->hangup, fwtty_do_hangup);
INIT_WORK(&port->push, fwtty_pushrx);
INIT_LIST_HEAD(&port->buf_list);
init_waitqueue_head(&port->wait_tx);
port->max_payload = link_speed_to_max_payload(SCODE_100);
dma_fifo_init(&port->tx_fifo);

View file

@ -22,14 +22,14 @@
#ifdef FWTTY_PROFILING
#define DISTRIBUTION_MAX_SIZE 8192
#define DISTRIBUTION_MAX_INDEX (ilog2(DISTRIBUTION_MAX_SIZE) + 1)
static inline void profile_size_distrib(unsigned stat[], unsigned val)
static inline void fwtty_profile_data(unsigned stat[], unsigned val)
{
int n = (val) ? min(ilog2(val) + 1, DISTRIBUTION_MAX_INDEX) : 0;
++stat[n];
}
#else
#define DISTRIBUTION_MAX_INDEX 0
#define profile_size_distrib(st, n)
#define fwtty_profile_data(st, n)
#endif
/* Parameters for both VIRT_CABLE_PLUG & VIRT_CABLE_PLUG_RSP mgmt codes */
@ -166,7 +166,6 @@ struct stats {
unsigned sent;
unsigned lost;
unsigned throttled;
unsigned watermark;
unsigned reads[DISTRIBUTION_MAX_INDEX + 1];
unsigned writes[DISTRIBUTION_MAX_INDEX + 1];
unsigned txns[DISTRIBUTION_MAX_INDEX + 1];
@ -183,12 +182,6 @@ struct fwconsole_ops {
#define FWCON_NOTIFY_ATTACH 1
#define FWCON_NOTIFY_DETACH 2
struct buffered_rx {
struct list_head list;
size_t n;
unsigned char data[0];
};
/**
* fwtty_port: structure used to track/represent underlying tty_port
* @port: underlying tty_port
@ -223,11 +216,6 @@ struct buffered_rx {
* The work can race with the writer but concurrent sending is
* prevented with the IN_TX flag. Scheduled under lock to
* limit scheduling when fifo has just been drained.
* @push: work responsible for pushing buffered rx to the ldisc.
* rx can become buffered if the tty buffer is filled before the
* ldisc throttles the sender.
* @buf_list: list of buffered rx yet to be sent to ldisc
* @buffered: byte count of buffered rx
* @tx_fifo: fifo used to store & block-up writes for dma to remote
* @max_payload: max bytes transmissable per dma (based on peer's max_payload)
* @status_mask: UART_LSR_* bitmask significant to rx (based on termios)
@ -267,9 +255,6 @@ struct fwtty_port {
spinlock_t lock;
unsigned mctrl;
struct delayed_work drain;
struct work_struct push;
struct list_head buf_list;
int buffered;
struct dma_fifo tx_fifo;
int max_payload;
unsigned status_mask;
@ -291,7 +276,6 @@ struct fwtty_port {
/* bit #s for flags field */
#define IN_TX 0
#define STOP_TX 1
#define BUFFERING_RX 2
/* bitmasks for special mctrl/mstatus bits */
#define OOB_RX_THROTTLE 0x00010000
@ -307,8 +291,8 @@ struct fwtty_port {
#define FREQ_BREAKS (HZ / 50)
/* Ports are allocated in blocks of num_ports for each fw_card */
#define MAX_CARD_PORTS 32 /* max # of ports per card */
#define MAX_TOTAL_PORTS 64 /* max # of ports total */
#define MAX_CARD_PORTS CONFIG_FWTTY_MAX_CARD_PORTS
#define MAX_TOTAL_PORTS CONFIG_FWTTY_MAX_TOTAL_PORTS
/* tuning parameters */
#define FWTTY_PORT_TXFIFO_LEN 4096

View file

@ -1248,6 +1248,8 @@ static int rs_ioctl(struct tty_struct *tty,
struct async_icount cprev, cnow; /* kernel counter temps */
void __user *argp = (void __user *)arg;
unsigned long flags;
DEFINE_WAIT(wait);
int ret;
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
return -ENODEV;
@ -1288,25 +1290,33 @@ static int rs_ioctl(struct tty_struct *tty,
cprev = info->icount;
local_irq_restore(flags);
while (1) {
interruptible_sleep_on(&info->tport.delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
prepare_to_wait(&info->tport.delta_msr_wait,
&wait, TASK_INTERRUPTIBLE);
local_irq_save(flags);
cnow = info->icount; /* atomic copy */
local_irq_restore(flags);
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
return -EIO; /* no change => error */
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
ret = -EIO; /* no change => error */
break;
}
if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
return 0;
ret = 0;
break;
}
schedule();
/* see if a signal did it */
if (signal_pending(current)) {
ret = -ERESTARTSYS;
break;
}
cprev = cnow;
}
/* NOTREACHED */
finish_wait(&info->tport.delta_msr_wait, &wait);
return ret;
case TIOCSERGWILD:
case TIOCSERSWILD:

View file

@ -2709,6 +2709,8 @@ cy_ioctl(struct tty_struct *tty,
break;
#ifndef CONFIG_CYZ_INTR
case CYZSETPOLLCYCLE:
if (arg > LONG_MAX / HZ)
return -ENODEV;
cyz_polling_cycle = (arg * HZ) / 1000;
break;
case CYZGETPOLLCYCLE:

View file

@ -14,7 +14,6 @@
*/
#include <linux/console.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/tty.h>

View file

@ -788,7 +788,7 @@ static int hvc_tiocmset(struct tty_struct *tty,
}
#ifdef CONFIG_CONSOLE_POLL
int hvc_poll_init(struct tty_driver *driver, int line, char *options)
static int hvc_poll_init(struct tty_driver *driver, int line, char *options)
{
return 0;
}

View file

@ -1,5 +1,4 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/console.h>

View file

@ -15,7 +15,6 @@
* Copyright (C) 2007 David Sterba
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>

View file

@ -194,6 +194,7 @@ struct gsm_control {
struct gsm_mux {
struct tty_struct *tty; /* The tty our ldisc is bound to */
spinlock_t lock;
struct mutex mutex;
unsigned int num;
struct kref ref;
@ -1704,11 +1705,8 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)
gsm_destroy_network(dlci);
mutex_unlock(&dlci->mutex);
/* tty_vhangup needs the tty_lock, so unlock and
relock after doing the hangup. */
tty_unlock(tty);
tty_vhangup(tty);
tty_lock(tty);
tty_port_tty_set(&dlci->port, NULL);
tty_kref_put(tty);
}
@ -2019,7 +2017,7 @@ static void gsm_error(struct gsm_mux *gsm,
* and then shut down each device hanging up the channels as we go.
*/
void gsm_cleanup_mux(struct gsm_mux *gsm)
static void gsm_cleanup_mux(struct gsm_mux *gsm)
{
int i;
struct gsm_dlci *dlci = gsm->dlci[0];
@ -2054,15 +2052,16 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
dlci->state == DLCI_CLOSED);
}
/* Free up any link layer users */
mutex_lock(&gsm->mutex);
for (i = 0; i < NUM_DLCI; i++)
if (gsm->dlci[i])
gsm_dlci_release(gsm->dlci[i]);
mutex_unlock(&gsm->mutex);
/* Now wipe the queues */
list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
kfree(txq);
INIT_LIST_HEAD(&gsm->tx_list);
}
EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
/**
* gsm_activate_mux - generic GSM setup
@ -2073,7 +2072,7 @@ EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
* finally kick off connecting to DLCI 0 on the modem.
*/
int gsm_activate_mux(struct gsm_mux *gsm)
static int gsm_activate_mux(struct gsm_mux *gsm)
{
struct gsm_dlci *dlci;
int i = 0;
@ -2109,7 +2108,6 @@ int gsm_activate_mux(struct gsm_mux *gsm)
gsm->dead = 0; /* Tty opens are now permissible */
return 0;
}
EXPORT_SYMBOL_GPL(gsm_activate_mux);
/**
* gsm_free_mux - free up a mux
@ -2117,13 +2115,12 @@ EXPORT_SYMBOL_GPL(gsm_activate_mux);
*
* Dispose of allocated resources for a dead mux
*/
void gsm_free_mux(struct gsm_mux *gsm)
static void gsm_free_mux(struct gsm_mux *gsm)
{
kfree(gsm->txframe);
kfree(gsm->buf);
kfree(gsm);
}
EXPORT_SYMBOL_GPL(gsm_free_mux);
/**
* gsm_free_muxr - free up a mux
@ -2153,7 +2150,7 @@ static inline void mux_put(struct gsm_mux *gsm)
* Creates a new mux ready for activation.
*/
struct gsm_mux *gsm_alloc_mux(void)
static struct gsm_mux *gsm_alloc_mux(void)
{
struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
if (gsm == NULL)
@ -2170,6 +2167,7 @@ struct gsm_mux *gsm_alloc_mux(void)
return NULL;
}
spin_lock_init(&gsm->lock);
mutex_init(&gsm->mutex);
kref_init(&gsm->ref);
INIT_LIST_HEAD(&gsm->tx_list);
@ -2185,7 +2183,6 @@ struct gsm_mux *gsm_alloc_mux(void)
return gsm;
}
EXPORT_SYMBOL_GPL(gsm_alloc_mux);
/**
* gsmld_output - write to link
@ -2269,14 +2266,15 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *f;
int i;
char buf[64];
char flags;
char flags = TTY_NORMAL;
if (debug & 4)
print_hex_dump_bytes("gsmld_receive: ", DUMP_PREFIX_OFFSET,
cp, count);
for (i = count, dp = cp, f = fp; i; i--, dp++) {
flags = *f++;
if (f)
flags = *f++;
switch (flags) {
case TTY_NORMAL:
gsm->receive(gsm, *dp);
@ -2711,7 +2709,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
return;
}
int gsm_change_mtu(struct net_device *net, int new_mtu)
static int gsm_change_mtu(struct net_device *net, int new_mtu)
{
struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
if ((new_mtu < 8) || (new_mtu > mux_net->dlci->gsm->mtu))
@ -2909,23 +2907,33 @@ static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
This is ok from a locking
perspective as we don't have to worry about this
if DLCI0 is lost */
if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN)
mutex_lock(&gsm->mutex);
if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) {
mutex_unlock(&gsm->mutex);
return -EL2NSYNC;
}
dlci = gsm->dlci[line];
if (dlci == NULL) {
alloc = true;
dlci = gsm_dlci_alloc(gsm, line);
}
if (dlci == NULL)
if (dlci == NULL) {
mutex_unlock(&gsm->mutex);
return -ENOMEM;
}
ret = tty_port_install(&dlci->port, driver, tty);
if (ret) {
if (alloc)
dlci_put(dlci);
mutex_unlock(&gsm->mutex);
return ret;
}
dlci_get(dlci);
dlci_get(gsm->dlci[0]);
mux_get(gsm);
tty->driver_data = dlci;
mutex_unlock(&gsm->mutex);
return 0;
}
@ -2936,9 +2944,6 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
struct tty_port *port = &dlci->port;
port->count++;
dlci_get(dlci);
dlci_get(dlci->gsm->dlci[0]);
mux_get(dlci->gsm);
tty_port_tty_set(port, tty);
dlci->modem_rx = 0;
@ -2965,7 +2970,7 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
mutex_unlock(&dlci->mutex);
gsm = dlci->gsm;
if (tty_port_close_start(&dlci->port, tty, filp) == 0)
goto out;
return;
gsm_dlci_begin_close(dlci);
if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) {
if (C_HUPCL(tty))
@ -2973,10 +2978,7 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
}
tty_port_close_end(&dlci->port, tty);
tty_port_tty_set(&dlci->port, NULL);
out:
dlci_put(dlci);
dlci_put(gsm->dlci[0]);
mux_put(gsm);
return;
}
static void gsmtty_hangup(struct tty_struct *tty)
@ -3153,6 +3155,16 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
return gsmtty_modem_update(dlci, encode);
}
static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty)
{
struct gsm_dlci *dlci = tty->driver_data;
struct gsm_mux *gsm = dlci->gsm;
dlci_put(dlci);
dlci_put(gsm->dlci[0]);
mux_put(gsm);
driver->ttys[tty->index] = NULL;
}
/* Virtual ttys for the demux */
static const struct tty_operations gsmtty_ops = {
@ -3172,6 +3184,7 @@ static const struct tty_operations gsmtty_ops = {
.tiocmget = gsmtty_tiocmget,
.tiocmset = gsmtty_tiocmset,
.break_ctl = gsmtty_break_ctl,
.remove = gsmtty_remove,
};

View file

@ -1244,7 +1244,7 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
{
struct r3964_info *pInfo = tty->disc_data;
const unsigned char *p;
char *f, flags = 0;
char *f, flags = TTY_NORMAL;
int i;
for (i = count, p = cp, f = fp; i; i--, p++) {

View file

@ -105,6 +105,7 @@ struct n_tty_data {
/* must hold exclusive termios_rwsem to reset these */
unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
unsigned char push:1;
/* shared by producer and consumer */
char read_buf[N_TTY_BUF_SIZE];
@ -275,7 +276,8 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
return;
n_tty_set_room(tty);
n_tty_write_wakeup(tty->link);
wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
if (waitqueue_active(&tty->link->write_wait))
wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
return;
}
@ -342,6 +344,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata)
ldata->erasing = 0;
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
ldata->push = 0;
}
static void n_tty_packet_mode_flush(struct tty_struct *tty)
@ -351,7 +354,8 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)
spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
wake_up_interruptible(&tty->link->read_wait);
if (waitqueue_active(&tty->link->read_wait))
wake_up_interruptible(&tty->link->read_wait);
}
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
@ -1162,7 +1166,8 @@ static void n_tty_receive_break(struct tty_struct *tty)
put_tty_queue('\0', ldata);
}
put_tty_queue('\0', ldata);
wake_up_interruptible(&tty->read_wait);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
}
/**
@ -1220,7 +1225,8 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
put_tty_queue('\0', ldata);
else
put_tty_queue(c, ldata);
wake_up_interruptible(&tty->read_wait);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
}
static void
@ -1264,7 +1270,6 @@ static int
n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
int parmrk;
if (I_IXON(tty)) {
if (c == START_CHAR(tty)) {
@ -1349,8 +1354,6 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
}
if ((c == EOL_CHAR(tty)) ||
(c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
? 1 : 0;
/*
* XXX are EOL_CHAR and EOL2_CHAR echoed?!?
*/
@ -1365,7 +1368,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
* XXX does PARMRK doubling happen for
* EOL_CHAR and EOL2_CHAR?
*/
if (parmrk)
if (c == (unsigned char) '\377' && I_PARMRK(tty))
put_tty_queue(c, ldata);
handle_newline:
@ -1379,7 +1382,6 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
}
}
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
if (L_ECHO(tty)) {
finish_erasing(ldata);
if (c == '\n')
@ -1393,7 +1395,8 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
commit_echoes(tty);
}
if (parmrk)
/* PARMRK doubling check */
if (c == (unsigned char) '\377' && I_PARMRK(tty))
put_tty_queue(c, ldata);
put_tty_queue(c, ldata);
@ -1404,7 +1407,6 @@ static inline void
n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
{
struct n_tty_data *ldata = tty->disc_data;
int parmrk;
if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
start_tty(tty);
@ -1418,13 +1420,13 @@ n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c)
echo_char(c, tty);
commit_echoes(tty);
}
parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
if (parmrk)
/* PARMRK doubling check */
if (c == (unsigned char) '\377' && I_PARMRK(tty))
put_tty_queue(c, ldata);
put_tty_queue(c, ldata);
}
static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{
n_tty_receive_char_inline(tty, c);
}
@ -1449,8 +1451,7 @@ n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)
put_tty_queue(c, ldata);
}
static inline void
n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
{
if (I_ISTRIP(tty))
c &= 0x7f;
@ -1681,32 +1682,9 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
}
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
int room, n;
down_read(&tty->termios_rwsem);
while (1) {
room = receive_room(tty);
n = min(count, room);
if (!n)
break;
__receive_buf(tty, cp, fp, n);
cp += n;
if (fp)
fp += n;
count -= n;
}
tty->receive_room = room;
n_tty_check_throttle(tty);
up_read(&tty->termios_rwsem);
}
static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
static int
n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count, int flow)
{
struct n_tty_data *ldata = tty->disc_data;
int room, n, rcvd = 0;
@ -1717,7 +1695,7 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
room = receive_room(tty);
n = min(count, room);
if (!n) {
if (!room)
if (flow && !room)
ldata->no_room = 1;
break;
}
@ -1736,6 +1714,18 @@ static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
return rcvd;
}
static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
n_tty_receive_buf_common(tty, cp, fp, count, 0);
}
static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
{
return n_tty_receive_buf_common(tty, cp, fp, count, 1);
}
int is_ignored(int sig)
{
return (sigismember(&current->blocked, sig) ||
@ -1762,7 +1752,16 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) {
bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
ldata->line_start = ldata->canon_head = ldata->read_tail;
ldata->line_start = ldata->read_tail;
if (!L_ICANON(tty) || !read_cnt(ldata)) {
ldata->canon_head = ldata->read_tail;
ldata->push = 0;
} else {
set_bit((ldata->read_head - 1) & (N_TTY_BUF_SIZE - 1),
ldata->read_flags);
ldata->canon_head = ldata->read_head;
ldata->push = 1;
}
ldata->erasing = 0;
ldata->lnext = 0;
}
@ -1825,8 +1824,10 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
start_tty(tty);
/* The termios change make the tty ready for I/O */
wake_up_interruptible(&tty->write_wait);
wake_up_interruptible(&tty->read_wait);
if (waitqueue_active(&tty->write_wait))
wake_up_interruptible(&tty->write_wait);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
}
/**
@ -1892,14 +1893,15 @@ static int n_tty_open(struct tty_struct *tty)
return -ENOMEM;
}
static inline int input_available_p(struct tty_struct *tty, int amt)
static inline int input_available_p(struct tty_struct *tty, int poll)
{
struct n_tty_data *ldata = tty->disc_data;
int amt = poll && !TIME_CHAR(tty) ? MIN_CHAR(tty) : 1;
if (ldata->icanon && !L_EXTPROC(tty)) {
if (ldata->canon_head != ldata->read_tail)
return 1;
} else if (read_cnt(ldata) >= (amt ? amt : 1))
} else if (read_cnt(ldata) >= amt)
return 1;
return 0;
@ -1965,6 +1967,12 @@ static int copy_from_read_buf(struct tty_struct *tty,
* it copies one line of input up to and including the line-delimiting
* character into the user-space buffer.
*
* NB: When termios is changed from non-canonical to canonical mode and
* the read buffer contains data, n_tty_set_termios() simulates an EOF
* push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer.
* This causes data already processed as input to be immediately available
* as input although a newline has not been received.
*
* Called under the atomic_read_lock mutex
*
* n_tty_read()/consumer path:
@ -2011,7 +2019,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
n += found;
c = n;
if (found && read_buf(ldata, eol) == __DISABLED_CHAR) {
if (found && !ldata->push && read_buf(ldata, eol) == __DISABLED_CHAR) {
n--;
eof_push = !n && ldata->read_tail != ldata->line_start;
}
@ -2038,7 +2046,10 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
ldata->read_tail += c;
if (found) {
ldata->line_start = ldata->read_tail;
if (!ldata->push)
ldata->line_start = ldata->read_tail;
else
ldata->push = 0;
tty_audit_push(tty);
}
return eof_push ? -EAGAIN : 0;
@ -2398,7 +2409,7 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
poll_wait(file, &tty->read_wait, wait);
poll_wait(file, &tty->write_wait, wait);
if (input_available_p(tty, TIME_CHAR(tty) ? 0 : MIN_CHAR(tty)))
if (input_available_p(tty, 1))
mask |= POLLIN | POLLRDNORM;
if (tty->packet && tty->link->ctrl_status)
mask |= POLLPRI | POLLIN | POLLRDNORM;

View file

@ -1744,7 +1744,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
#ifdef CONFIG_PCI
static DEFINE_PCI_DEVICE_TABLE(rocket_pci_ids) = {
static const struct pci_device_id rocket_pci_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP4QUAD) },
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA) },
{ PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_URP8OCTA) },

View file

@ -2670,6 +2670,10 @@ static void serial8250_config_port(struct uart_port *port, int flags)
if (port->type == PORT_16550A && port->iotype == UPIO_AU)
up->bugs |= UART_BUG_NOMSR;
/* HW bugs may trigger IRQ while IIR == NO_INT */
if (port->type == PORT_TEGRA)
up->bugs |= UART_BUG_NOMSR;
if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
autoconfig_irq(up);

View file

@ -14,7 +14,6 @@
* raised, the LCR needs to be rewritten and the uart status register read.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>
@ -274,7 +273,6 @@ static int dw8250_probe_of(struct uart_port *p,
return 0;
}
#ifdef CONFIG_ACPI
static int dw8250_probe_acpi(struct uart_8250_port *up,
struct dw8250_data *data)
{
@ -302,13 +300,6 @@ static int dw8250_probe_acpi(struct uart_8250_port *up,
return 0;
}
#else
static inline int dw8250_probe_acpi(struct uart_8250_port *up,
struct dw8250_data *data)
{
return -ENODEV;
}
#endif /* CONFIG_ACPI */
static int dw8250_probe(struct platform_device *pdev)
{

View file

@ -18,7 +18,6 @@
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/serial_8250.h>

View file

@ -11,7 +11,6 @@
*/
#undef DEBUG
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/kernel.h>
@ -1259,10 +1258,10 @@ static int pci_quatech_init(struct pci_dev *dev)
unsigned long base = pci_resource_start(dev, 0);
if (base) {
u32 tmp;
outl(inl(base + 0x38), base + 0x38);
outl(inl(base + 0x38) | 0x00002000, base + 0x38);
tmp = inl(base + 0x3c);
outl(tmp | 0x01000000, base + 0x3c);
outl(tmp, base + 0x3c);
outl(tmp &= ~0x01000000, base + 0x3c);
}
}
return 0;
@ -1744,6 +1743,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
#define PCI_DEVICE_ID_TITAN_800E 0xA014
#define PCI_DEVICE_ID_TITAN_200EI 0xA016
#define PCI_DEVICE_ID_TITAN_200EISI 0xA017
#define PCI_DEVICE_ID_TITAN_200V3 0xA306
#define PCI_DEVICE_ID_TITAN_400V3 0xA310
#define PCI_DEVICE_ID_TITAN_410V3 0xA312
#define PCI_DEVICE_ID_TITAN_800V3 0xA314
@ -4427,6 +4427,9 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_oxsemi_2_4000000 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200V3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_2_921600 },
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400V3,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_4_921600 },

View file

@ -12,7 +12,6 @@
* the Free Software Foundation; either version 2 of the License.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pnp.h>
#include <linux/string.h>

View file

@ -34,7 +34,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>

View file

@ -181,9 +181,8 @@ config SERIAL_KS8695_CONSOLE
config SERIAL_CLPS711X
tristate "CLPS711X serial port support"
depends on ARCH_CLPS711X
depends on ARCH_CLPS711X || COMPILE_TEST
select SERIAL_CORE
default y
help
This enables the driver for the on-chip UARTs of the Cirrus
Logic EP711x/EP721x/EP731x processors.
@ -1146,31 +1145,13 @@ config SERIAL_QE
This driver supports the QE serial ports on Freescale embedded
PowerPC that contain a QUICC Engine.
config SERIAL_SC26XX
tristate "SC2681/SC2692 serial port support"
depends on SNI_RM
select SERIAL_CORE
help
This is a driver for the onboard serial ports of
older RM400 machines.
config SERIAL_SC26XX_CONSOLE
bool "Console on SC2681/SC2692 serial port"
depends on SERIAL_SC26XX=y
select SERIAL_CORE_CONSOLE
help
Support for Console on SC2681/SC2692 serial ports.
config SERIAL_SCCNXP
tristate "SCCNXP serial port support"
depends on !SERIAL_SC26XX
select SERIAL_CORE
default n
help
This selects support for an advanced UART from NXP (Philips).
Supported ICs are SCC2681, SCC2691, SCC2692, SC28L91, SC28L92,
SC28L202, SCC68681 and SCC68692.
Positioned as a replacement for the driver SC26XX.
config SERIAL_SCCNXP_CONSOLE
bool "Console on SCCNXP serial port"

View file

@ -47,7 +47,6 @@ obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o

View file

@ -756,9 +756,10 @@ static int pl010_remove(struct amba_device *dev)
return 0;
}
static int pl010_suspend(struct amba_device *dev, pm_message_t state)
#ifdef CONFIG_PM_SLEEP
static int pl010_suspend(struct device *dev)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
struct uart_amba_port *uap = dev_get_drvdata(dev);
if (uap)
uart_suspend_port(&amba_reg, &uap->port);
@ -766,15 +767,18 @@ static int pl010_suspend(struct amba_device *dev, pm_message_t state)
return 0;
}
static int pl010_resume(struct amba_device *dev)
static int pl010_resume(struct device *dev)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
struct uart_amba_port *uap = dev_get_drvdata(dev);
if (uap)
uart_resume_port(&amba_reg, &uap->port);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(pl010_dev_pm_ops, pl010_suspend, pl010_resume);
static struct amba_id pl010_ids[] = {
{
@ -789,12 +793,11 @@ MODULE_DEVICE_TABLE(amba, pl010_ids);
static struct amba_driver pl010_driver = {
.drv = {
.name = "uart-pl010",
.pm = &pl010_dev_pm_ops,
},
.id_table = pl010_ids,
.probe = pl010_probe,
.remove = pl010_remove,
.suspend = pl010_suspend,
.resume = pl010_resume,
};
static int __init pl010_init(void)

View file

@ -112,8 +112,6 @@ static struct vendor_data vendor_st = {
.get_fifosize = get_fifosize_st,
};
static struct uart_amba_port *amba_ports[UART_NR];
/* Deals with DMA transactions */
struct pl011_sgbuf {
@ -969,6 +967,8 @@ static void pl011_dma_rx_poll(unsigned long args)
spin_lock_irqsave(&uap->port.lock, flags);
pl011_dma_rx_stop(uap);
uap->im |= UART011_RXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
spin_unlock_irqrestore(&uap->port.lock, flags);
uap->dmarx.running = false;
@ -1216,8 +1216,8 @@ __acquires(&uap->port.lock)
dev_dbg(uap->port.dev, "could not trigger RX DMA job "
"fall back to interrupt mode again\n");
uap->im |= UART011_RXIM;
writew(uap->im, uap->port.membase + UART011_IMSC);
} else {
uap->im &= ~UART011_RXIM;
#ifdef CONFIG_DMA_ENGINE
/* Start Rx DMA poll */
if (uap->dmarx.poll_rate) {
@ -1229,8 +1229,6 @@ __acquires(&uap->port.lock)
}
#endif
}
writew(uap->im, uap->port.membase + UART011_IMSC);
}
spin_lock(&uap->port.lock);
}
@ -1513,10 +1511,25 @@ static int pl011_hwinit(struct uart_port *port)
return retval;
}
static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h)
{
writew(lcr_h, uap->port.membase + uap->lcrh_rx);
if (uap->lcrh_rx != uap->lcrh_tx) {
int i;
/*
* Wait 10 PCLKs before writing LCRH_TX register,
* to get this delay write read only register 10 times
*/
for (i = 0; i < 10; ++i)
writew(0xff, uap->port.membase + UART011_MIS);
writew(lcr_h, uap->port.membase + uap->lcrh_tx);
}
}
static int pl011_startup(struct uart_port *port)
{
struct uart_amba_port *uap = (struct uart_amba_port *)port;
unsigned int cr;
unsigned int cr, lcr_h, fbrd, ibrd;
int retval;
retval = pl011_hwinit(port);
@ -1535,32 +1548,36 @@ static int pl011_startup(struct uart_port *port)
writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS);
/*
* Provoke TX FIFO interrupt into asserting.
* Provoke TX FIFO interrupt into asserting. Taking care to preserve
* baud rate and data format specified by FBRD, IBRD and LCRH as the
* UART may already be in use as a console.
*/
spin_lock_irq(&uap->port.lock);
fbrd = readw(uap->port.membase + UART011_FBRD);
ibrd = readw(uap->port.membase + UART011_IBRD);
lcr_h = readw(uap->port.membase + uap->lcrh_rx);
cr = UART01x_CR_UARTEN | UART011_CR_TXE | UART011_CR_LBE;
writew(cr, uap->port.membase + UART011_CR);
writew(0, uap->port.membase + UART011_FBRD);
writew(1, uap->port.membase + UART011_IBRD);
writew(0, uap->port.membase + uap->lcrh_rx);
if (uap->lcrh_tx != uap->lcrh_rx) {
int i;
/*
* Wait 10 PCLKs before writing LCRH_TX register,
* to get this delay write read only register 10 times
*/
for (i = 0; i < 10; ++i)
writew(0xff, uap->port.membase + UART011_MIS);
writew(0, uap->port.membase + uap->lcrh_tx);
}
pl011_write_lcr_h(uap, 0);
writew(0, uap->port.membase + UART01x_DR);
while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY)
barrier();
writew(fbrd, uap->port.membase + UART011_FBRD);
writew(ibrd, uap->port.membase + UART011_IBRD);
pl011_write_lcr_h(uap, lcr_h);
/* restore RTS and DTR */
cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR);
cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE;
writew(cr, uap->port.membase + UART011_CR);
spin_unlock_irq(&uap->port.lock);
/*
* initialise the old status of the modem signals
*/
@ -1629,11 +1646,13 @@ static void pl011_shutdown(struct uart_port *port)
* it during startup().
*/
uap->autorts = false;
spin_lock_irq(&uap->port.lock);
cr = readw(uap->port.membase + UART011_CR);
uap->old_cr = cr;
cr &= UART011_CR_RTS | UART011_CR_DTR;
cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
writew(cr, uap->port.membase + UART011_CR);
spin_unlock_irq(&uap->port.lock);
/*
* disable break condition and fifos
@ -1797,17 +1816,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
* UART011_FBRD & UART011_IBRD.
* ----------^----------^----------^----------^-----
*/
writew(lcr_h, port->membase + uap->lcrh_rx);
if (uap->lcrh_rx != uap->lcrh_tx) {
int i;
/*
* Wait 10 PCLKs before writing LCRH_TX register,
* to get this delay write read only register 10 times
*/
for (i = 0; i < 10; ++i)
writew(0xff, uap->port.membase + UART011_MIS);
writew(lcr_h, port->membase + uap->lcrh_tx);
}
pl011_write_lcr_h(uap, lcr_h);
writew(old_cr, port->membase + UART011_CR);
spin_unlock_irqrestore(&port->lock, flags);
@ -2169,10 +2178,10 @@ static int pl011_remove(struct amba_device *dev)
return 0;
}
#ifdef CONFIG_PM
static int pl011_suspend(struct amba_device *dev, pm_message_t state)
#ifdef CONFIG_PM_SLEEP
static int pl011_suspend(struct device *dev)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
struct uart_amba_port *uap = dev_get_drvdata(dev);
if (!uap)
return -EINVAL;
@ -2180,9 +2189,9 @@ static int pl011_suspend(struct amba_device *dev, pm_message_t state)
return uart_suspend_port(&amba_reg, &uap->port);
}
static int pl011_resume(struct amba_device *dev)
static int pl011_resume(struct device *dev)
{
struct uart_amba_port *uap = amba_get_drvdata(dev);
struct uart_amba_port *uap = dev_get_drvdata(dev);
if (!uap)
return -EINVAL;
@ -2191,6 +2200,8 @@ static int pl011_resume(struct amba_device *dev)
}
#endif
static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume);
static struct amba_id pl011_ids[] = {
{
.id = 0x00041011,
@ -2210,14 +2221,11 @@ MODULE_DEVICE_TABLE(amba, pl011_ids);
static struct amba_driver pl011_driver = {
.drv = {
.name = "uart-pl011",
.pm = &pl011_dev_pm_ops,
},
.id_table = pl011_ids,
.probe = pl011_probe,
.remove = pl011_remove,
#ifdef CONFIG_PM
.suspend = pl011_suspend,
.resume = pl011_resume,
#endif
};
static int __init pl011_init(void)

View file

@ -825,9 +825,6 @@ static void atmel_release_rx_dma(struct uart_port *port)
atmel_port->desc_rx = NULL;
atmel_port->chan_rx = NULL;
atmel_port->cookie_rx = -EINVAL;
if (!atmel_port->is_usart)
del_timer_sync(&atmel_port->uart_timer);
}
static void atmel_rx_from_dma(struct uart_port *port)
@ -1229,9 +1226,6 @@ static void atmel_release_rx_pdc(struct uart_port *port)
DMA_FROM_DEVICE);
kfree(pdc->buf);
}
if (!atmel_port->is_usart)
del_timer_sync(&atmel_port->uart_timer);
}
static void atmel_rx_from_pdc(struct uart_port *port)
@ -1604,12 +1598,13 @@ static int atmel_startup(struct uart_port *port)
/* enable xmit & rcvr */
UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
setup_timer(&atmel_port->uart_timer,
atmel_uart_timer_callback,
(unsigned long)port);
if (atmel_use_pdc_rx(port)) {
/* set UART timeout */
if (!atmel_port->is_usart) {
setup_timer(&atmel_port->uart_timer,
atmel_uart_timer_callback,
(unsigned long)port);
mod_timer(&atmel_port->uart_timer,
jiffies + uart_poll_timeout(port));
/* set USART timeout */
@ -1624,9 +1619,6 @@ static int atmel_startup(struct uart_port *port)
} else if (atmel_use_dma_rx(port)) {
/* set UART timeout */
if (!atmel_port->is_usart) {
setup_timer(&atmel_port->uart_timer,
atmel_uart_timer_callback,
(unsigned long)port);
mod_timer(&atmel_port->uart_timer,
jiffies + uart_poll_timeout(port));
/* set USART timeout */
@ -1650,12 +1642,30 @@ static int atmel_startup(struct uart_port *port)
static void atmel_shutdown(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
/*
* Ensure everything is stopped.
* Prevent any tasklets being scheduled during
* cleanup
*/
del_timer_sync(&atmel_port->uart_timer);
/*
* Clear out any scheduled tasklets before
* we destroy the buffers
*/
tasklet_kill(&atmel_port->tasklet);
/*
* Ensure everything is stopped and
* disable all interrupts, port and break condition.
*/
atmel_stop_rx(port);
atmel_stop_tx(port);
UART_PUT_CR(port, ATMEL_US_RSTSTA);
UART_PUT_IDR(port, -1);
/*
* Shut-down the DMA.
*/
@ -1665,10 +1675,10 @@ static void atmel_shutdown(struct uart_port *port)
atmel_port->release_tx(port);
/*
* Disable all interrupts, port and break condition.
* Reset ring buffer pointers
*/
UART_PUT_CR(port, ATMEL_US_RSTSTA);
UART_PUT_IDR(port, -1);
atmel_port->rx_ring.head = 0;
atmel_port->rx_ring.tail = 0;
/*
* Free the interrupt
@ -2441,11 +2451,12 @@ static int atmel_serial_remove(struct platform_device *pdev)
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
int ret = 0;
tasklet_kill(&atmel_port->tasklet);
device_init_wakeup(&pdev->dev, 0);
ret = uart_remove_one_port(&atmel_uart, port);
tasklet_kill(&atmel_port->tasklet);
kfree(atmel_port->rx_ring.buf);
/* "port" is allocated statically, so we shouldn't free it */

View file

@ -21,44 +21,66 @@
#include <linux/console.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <mach/hardware.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon/clps711x.h>
#define UART_CLPS711X_NAME "uart-clps711x"
#define UART_CLPS711X_DEVNAME "ttyCL"
#define UART_CLPS711X_NR 2
#define UART_CLPS711X_MAJOR 204
#define UART_CLPS711X_MINOR 40
#define UBRLCR(port) ((port)->line ? UBRLCR2 : UBRLCR1)
#define UARTDR(port) ((port)->line ? UARTDR2 : UARTDR1)
#define SYSFLG(port) ((port)->line ? SYSFLG2 : SYSFLG1)
#define SYSCON(port) ((port)->line ? SYSCON2 : SYSCON1)
#define TX_IRQ(port) ((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1)
#define RX_IRQ(port) ((port)->line ? IRQ_URXINT2 : IRQ_URXINT1)
#define UARTDR_OFFSET (0x00)
#define UBRLCR_OFFSET (0x40)
#define UARTDR_FRMERR (1 << 8)
#define UARTDR_PARERR (1 << 9)
#define UARTDR_OVERR (1 << 10)
#define UBRLCR_BAUD_MASK ((1 << 12) - 1)
#define UBRLCR_BREAK (1 << 12)
#define UBRLCR_PRTEN (1 << 13)
#define UBRLCR_EVENPRT (1 << 14)
#define UBRLCR_XSTOP (1 << 15)
#define UBRLCR_FIFOEN (1 << 16)
#define UBRLCR_WRDLEN5 (0 << 17)
#define UBRLCR_WRDLEN6 (1 << 17)
#define UBRLCR_WRDLEN7 (2 << 17)
#define UBRLCR_WRDLEN8 (3 << 17)
#define UBRLCR_WRDLEN_MASK (3 << 17)
struct clps711x_port {
struct uart_driver uart;
struct clk *uart_clk;
struct uart_port port[UART_CLPS711X_NR];
int tx_enabled[UART_CLPS711X_NR];
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
struct console console;
#endif
struct uart_port port;
unsigned int tx_enabled;
int rx_irq;
struct regmap *syscon;
bool use_ms;
};
static struct uart_driver clps711x_uart = {
.owner = THIS_MODULE,
.driver_name = UART_CLPS711X_DEVNAME,
.dev_name = UART_CLPS711X_DEVNAME,
.major = UART_CLPS711X_MAJOR,
.minor = UART_CLPS711X_MINOR,
.nr = UART_CLPS711X_NR,
};
static void uart_clps711x_stop_tx(struct uart_port *port)
{
struct clps711x_port *s = dev_get_drvdata(port->dev);
if (s->tx_enabled[port->line]) {
disable_irq(TX_IRQ(port));
s->tx_enabled[port->line] = 0;
if (s->tx_enabled) {
disable_irq(port->irq);
s->tx_enabled = 0;
}
}
@ -66,33 +88,27 @@ static void uart_clps711x_start_tx(struct uart_port *port)
{
struct clps711x_port *s = dev_get_drvdata(port->dev);
if (!s->tx_enabled[port->line]) {
enable_irq(TX_IRQ(port));
s->tx_enabled[port->line] = 1;
if (!s->tx_enabled) {
s->tx_enabled = 1;
enable_irq(port->irq);
}
}
static void uart_clps711x_stop_rx(struct uart_port *port)
{
disable_irq(RX_IRQ(port));
}
static void uart_clps711x_enable_ms(struct uart_port *port)
{
/* Do nothing */
}
static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
unsigned int status, ch, flg;
struct clps711x_port *s = dev_get_drvdata(port->dev);
unsigned int status, flg;
u16 ch;
for (;;) {
status = clps_readl(SYSFLG(port));
if (status & SYSFLG_URXFE)
u32 sysflg = 0;
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
if (sysflg & SYSFLG_URXFE)
break;
ch = clps_readw(UARTDR(port));
ch = readw(port->membase + UARTDR_OFFSET);
status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR);
ch &= 0xff;
@ -138,23 +154,29 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
struct circ_buf *xmit = &port->state->xmit;
if (port->x_char) {
clps_writew(port->x_char, UARTDR(port));
writew(port->x_char, port->membase + UARTDR_OFFSET);
port->icount.tx++;
port->x_char = 0;
return IRQ_HANDLED;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
disable_irq_nosync(TX_IRQ(port));
s->tx_enabled[port->line] = 0;
if (s->tx_enabled) {
disable_irq_nosync(port->irq);
s->tx_enabled = 0;
}
return IRQ_HANDLED;
}
while (!uart_circ_empty(xmit)) {
clps_writew(xmit->buf[xmit->tail], UARTDR(port));
u32 sysflg = 0;
writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
if (clps_readl(SYSFLG(port) & SYSFLG_UTXFF))
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
if (sysflg & SYSFLG_UTXFF)
break;
}
@ -166,20 +188,28 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
static unsigned int uart_clps711x_tx_empty(struct uart_port *port)
{
return (clps_readl(SYSFLG(port) & SYSFLG_UBUSY)) ? 0 : TIOCSER_TEMT;
struct clps711x_port *s = dev_get_drvdata(port->dev);
u32 sysflg = 0;
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
return (sysflg & SYSFLG_UBUSY) ? 0 : TIOCSER_TEMT;
}
static unsigned int uart_clps711x_get_mctrl(struct uart_port *port)
{
unsigned int status, result = 0;
struct clps711x_port *s = dev_get_drvdata(port->dev);
unsigned int result = 0;
if (port->line == 0) {
status = clps_readl(SYSFLG1);
if (status & SYSFLG1_DCD)
if (s->use_ms) {
u32 sysflg = 0;
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
if (sysflg & SYSFLG1_DCD)
result |= TIOCM_CAR;
if (status & SYSFLG1_DSR)
if (sysflg & SYSFLG1_DSR)
result |= TIOCM_DSR;
if (status & SYSFLG1_CTS)
if (sysflg & SYSFLG1_CTS)
result |= TIOCM_CTS;
} else
result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
@ -194,65 +224,53 @@ static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void uart_clps711x_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
unsigned int ubrlcr;
spin_lock_irqsave(&port->lock, flags);
ubrlcr = clps_readl(UBRLCR(port));
ubrlcr = readl(port->membase + UBRLCR_OFFSET);
if (break_state)
ubrlcr |= UBRLCR_BREAK;
else
ubrlcr &= ~UBRLCR_BREAK;
clps_writel(ubrlcr, UBRLCR(port));
writel(ubrlcr, port->membase + UBRLCR_OFFSET);
}
spin_unlock_irqrestore(&port->lock, flags);
static void uart_clps711x_set_ldisc(struct uart_port *port, int ld)
{
if (!port->line) {
struct clps711x_port *s = dev_get_drvdata(port->dev);
regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON1_SIREN,
(ld == N_IRDA) ? SYSCON1_SIREN : 0);
}
}
static int uart_clps711x_startup(struct uart_port *port)
{
struct clps711x_port *s = dev_get_drvdata(port->dev);
int ret;
s->tx_enabled[port->line] = 1;
/* Allocate the IRQs */
ret = devm_request_irq(port->dev, TX_IRQ(port), uart_clps711x_int_tx,
0, UART_CLPS711X_NAME " TX", port);
if (ret)
return ret;
ret = devm_request_irq(port->dev, RX_IRQ(port), uart_clps711x_int_rx,
0, UART_CLPS711X_NAME " RX", port);
if (ret) {
devm_free_irq(port->dev, TX_IRQ(port), port);
return ret;
}
/* Disable break */
clps_writel(clps_readl(UBRLCR(port)) & ~UBRLCR_BREAK, UBRLCR(port));
writel(readl(port->membase + UBRLCR_OFFSET) & ~UBRLCR_BREAK,
port->membase + UBRLCR_OFFSET);
/* Enable the port */
clps_writel(clps_readl(SYSCON(port)) | SYSCON_UARTEN, SYSCON(port));
return 0;
return regmap_update_bits(s->syscon, SYSCON_OFFSET,
SYSCON_UARTEN, SYSCON_UARTEN);
}
static void uart_clps711x_shutdown(struct uart_port *port)
{
/* Free the interrupts */
devm_free_irq(port->dev, TX_IRQ(port), port);
devm_free_irq(port->dev, RX_IRQ(port), port);
struct clps711x_port *s = dev_get_drvdata(port->dev);
/* Disable the port */
clps_writel(clps_readl(SYSCON(port)) & ~SYSCON_UARTEN, SYSCON(port));
regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON_UARTEN, 0);
}
static void uart_clps711x_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
unsigned int ubrlcr, baud, quot;
unsigned long flags;
u32 ubrlcr;
unsigned int baud, quot;
/* Mask termios capabilities we don't support */
termios->c_cflag &= ~CMSPAR;
@ -291,8 +309,6 @@ static void uart_clps711x_set_termios(struct uart_port *port,
/* Enable FIFO */
ubrlcr |= UBRLCR_FIFOEN;
spin_lock_irqsave(&port->lock, flags);
/* Set read status mask */
port->read_status_mask = UARTDR_OVERR;
if (termios->c_iflag & INPCK)
@ -306,9 +322,7 @@ static void uart_clps711x_set_termios(struct uart_port *port,
uart_update_timeout(port, termios->c_cflag, baud);
clps_writel(ubrlcr | (quot - 1), UBRLCR(port));
spin_unlock_irqrestore(&port->lock, flags);
writel(ubrlcr | (quot - 1), port->membase + UBRLCR_OFFSET);
}
static const char *uart_clps711x_type(struct uart_port *port)
@ -322,14 +336,12 @@ static void uart_clps711x_config_port(struct uart_port *port, int flags)
port->type = PORT_CLPS711X;
}
static void uart_clps711x_release_port(struct uart_port *port)
static void uart_clps711x_nop_void(struct uart_port *port)
{
/* Do nothing */
}
static int uart_clps711x_request_port(struct uart_port *port)
static int uart_clps711x_nop_int(struct uart_port *port)
{
/* Do nothing */
return 0;
}
@ -339,181 +351,237 @@ static const struct uart_ops uart_clps711x_ops = {
.get_mctrl = uart_clps711x_get_mctrl,
.stop_tx = uart_clps711x_stop_tx,
.start_tx = uart_clps711x_start_tx,
.stop_rx = uart_clps711x_stop_rx,
.enable_ms = uart_clps711x_enable_ms,
.stop_rx = uart_clps711x_nop_void,
.enable_ms = uart_clps711x_nop_void,
.break_ctl = uart_clps711x_break_ctl,
.set_ldisc = uart_clps711x_set_ldisc,
.startup = uart_clps711x_startup,
.shutdown = uart_clps711x_shutdown,
.set_termios = uart_clps711x_set_termios,
.type = uart_clps711x_type,
.config_port = uart_clps711x_config_port,
.release_port = uart_clps711x_release_port,
.request_port = uart_clps711x_request_port,
.release_port = uart_clps711x_nop_void,
.request_port = uart_clps711x_nop_int,
};
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
static void uart_clps711x_console_putchar(struct uart_port *port, int ch)
{
while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF)
barrier();
struct clps711x_port *s = dev_get_drvdata(port->dev);
u32 sysflg = 0;
clps_writew(ch, UARTDR(port));
do {
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
} while (sysflg & SYSFLG_UTXFF);
writew(ch, port->membase + UARTDR_OFFSET);
}
static void uart_clps711x_console_write(struct console *co, const char *c,
unsigned n)
{
struct clps711x_port *s = (struct clps711x_port *)co->data;
struct uart_port *port = &s->port[co->index];
u32 syscon;
/* Ensure that the port is enabled */
syscon = clps_readl(SYSCON(port));
clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
struct uart_port *port = clps711x_uart.state[co->index].uart_port;
struct clps711x_port *s = dev_get_drvdata(port->dev);
u32 sysflg = 0;
uart_console_write(port, c, n, uart_clps711x_console_putchar);
/* Wait for transmitter to become empty */
while (clps_readl(SYSFLG(port)) & SYSFLG_UBUSY)
barrier();
/* Restore the uart state */
clps_writel(syscon, SYSCON(port));
}
static void uart_clps711x_console_get_options(struct uart_port *port,
int *baud, int *parity,
int *bits)
{
if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
unsigned int ubrlcr, quot;
ubrlcr = clps_readl(UBRLCR(port));
*parity = 'n';
if (ubrlcr & UBRLCR_PRTEN) {
if (ubrlcr & UBRLCR_EVENPRT)
*parity = 'e';
else
*parity = 'o';
}
if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
*bits = 7;
else
*bits = 8;
quot = ubrlcr & UBRLCR_BAUD_MASK;
*baud = port->uartclk / (16 * (quot + 1));
}
do {
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
} while (sysflg & SYSFLG_UBUSY);
}
static int uart_clps711x_console_setup(struct console *co, char *options)
{
int baud = 38400, bits = 8, parity = 'n', flow = 'n';
struct clps711x_port *s = (struct clps711x_port *)co->data;
struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0];
int ret, index = co->index;
struct clps711x_port *s;
struct uart_port *port;
unsigned int quot;
u32 ubrlcr;
if (options)
if (index < 0 || index >= UART_CLPS711X_NR)
return -EINVAL;
port = clps711x_uart.state[index].uart_port;
if (!port)
return -ENODEV;
s = dev_get_drvdata(port->dev);
if (!options) {
u32 syscon = 0;
regmap_read(s->syscon, SYSCON_OFFSET, &syscon);
if (syscon & SYSCON_UARTEN) {
ubrlcr = readl(port->membase + UBRLCR_OFFSET);
if (ubrlcr & UBRLCR_PRTEN) {
if (ubrlcr & UBRLCR_EVENPRT)
parity = 'e';
else
parity = 'o';
}
if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
bits = 7;
quot = ubrlcr & UBRLCR_BAUD_MASK;
baud = port->uartclk / (16 * (quot + 1));
}
} else
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
uart_clps711x_console_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
ret = uart_set_options(port, co, baud, parity, bits, flow);
if (ret)
return ret;
return regmap_update_bits(s->syscon, SYSCON_OFFSET,
SYSCON_UARTEN, SYSCON_UARTEN);
}
static struct console clps711x_console = {
.name = UART_CLPS711X_DEVNAME,
.device = uart_console_device,
.write = uart_clps711x_console_write,
.setup = uart_clps711x_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
};
#endif
static int uart_clps711x_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
int ret, index = np ? of_alias_get_id(np, "serial") : pdev->id;
struct clps711x_port *s;
int ret, i;
struct resource *res;
struct clk *uart_clk;
s = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_port), GFP_KERNEL);
if (!s) {
dev_err(&pdev->dev, "Error allocating port structure\n");
if (index < 0 || index >= UART_CLPS711X_NR)
return -EINVAL;
s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
if (!s)
return -ENOMEM;
uart_clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(uart_clk))
return PTR_ERR(uart_clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
s->port.membase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(s->port.membase))
return PTR_ERR(s->port.membase);
s->port.irq = platform_get_irq(pdev, 0);
if (IS_ERR_VALUE(s->port.irq))
return s->port.irq;
s->rx_irq = platform_get_irq(pdev, 1);
if (IS_ERR_VALUE(s->rx_irq))
return s->rx_irq;
if (!np) {
char syscon_name[9];
sprintf(syscon_name, "syscon.%i", index + 1);
s->syscon = syscon_regmap_lookup_by_pdevname(syscon_name);
if (IS_ERR(s->syscon))
return PTR_ERR(s->syscon);
s->use_ms = !index;
} else {
s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR(s->syscon))
return PTR_ERR(s->syscon);
if (!index)
s->use_ms = of_property_read_bool(np, "uart-use-ms");
}
s->port.line = index;
s->port.dev = &pdev->dev;
s->port.iotype = UPIO_MEM32;
s->port.mapbase = res->start;
s->port.type = PORT_CLPS711X;
s->port.fifosize = 16;
s->port.flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
s->port.uartclk = clk_get_rate(uart_clk);
s->port.ops = &uart_clps711x_ops;
platform_set_drvdata(pdev, s);
s->uart_clk = devm_clk_get(&pdev->dev, "uart");
if (IS_ERR(s->uart_clk)) {
dev_err(&pdev->dev, "Can't get UART clocks\n");
return PTR_ERR(s->uart_clk);
}
ret = uart_add_one_port(&clps711x_uart, &s->port);
if (ret)
return ret;
s->uart.owner = THIS_MODULE;
s->uart.dev_name = "ttyCL";
s->uart.major = UART_CLPS711X_MAJOR;
s->uart.minor = UART_CLPS711X_MINOR;
s->uart.nr = UART_CLPS711X_NR;
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
s->uart.cons = &s->console;
s->uart.cons->device = uart_console_device;
s->uart.cons->write = uart_clps711x_console_write;
s->uart.cons->setup = uart_clps711x_console_setup;
s->uart.cons->flags = CON_PRINTBUFFER;
s->uart.cons->index = -1;
s->uart.cons->data = s;
strcpy(s->uart.cons->name, "ttyCL");
#endif
ret = uart_register_driver(&s->uart);
/* Disable port */
if (!uart_console(&s->port))
regmap_update_bits(s->syscon, SYSCON_OFFSET, SYSCON_UARTEN, 0);
s->tx_enabled = 1;
ret = devm_request_irq(&pdev->dev, s->port.irq, uart_clps711x_int_tx, 0,
dev_name(&pdev->dev), &s->port);
if (ret) {
dev_err(&pdev->dev, "Registering UART driver failed\n");
uart_remove_one_port(&clps711x_uart, &s->port);
return ret;
}
for (i = 0; i < UART_CLPS711X_NR; i++) {
s->port[i].line = i;
s->port[i].dev = &pdev->dev;
s->port[i].irq = TX_IRQ(&s->port[i]);
s->port[i].iobase = SYSCON(&s->port[i]);
s->port[i].type = PORT_CLPS711X;
s->port[i].fifosize = 16;
s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
s->port[i].uartclk = clk_get_rate(s->uart_clk);
s->port[i].ops = &uart_clps711x_ops;
WARN_ON(uart_add_one_port(&s->uart, &s->port[i]));
}
ret = devm_request_irq(&pdev->dev, s->rx_irq, uart_clps711x_int_rx, 0,
dev_name(&pdev->dev), &s->port);
if (ret)
uart_remove_one_port(&clps711x_uart, &s->port);
return 0;
return ret;
}
static int uart_clps711x_remove(struct platform_device *pdev)
{
struct clps711x_port *s = platform_get_drvdata(pdev);
int i;
for (i = 0; i < UART_CLPS711X_NR; i++)
uart_remove_one_port(&s->uart, &s->port[i]);
uart_unregister_driver(&s->uart);
return 0;
return uart_remove_one_port(&clps711x_uart, &s->port);
}
static struct platform_driver clps711x_uart_driver = {
static const struct of_device_id __maybe_unused clps711x_uart_dt_ids[] = {
{ .compatible = "cirrus,clps711x-uart", },
{ }
};
MODULE_DEVICE_TABLE(of, clps711x_uart_dt_ids);
static struct platform_driver clps711x_uart_platform = {
.driver = {
.name = UART_CLPS711X_NAME,
.owner = THIS_MODULE,
.name = "clps711x-uart",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(clps711x_uart_dt_ids),
},
.probe = uart_clps711x_probe,
.remove = uart_clps711x_remove,
};
module_platform_driver(clps711x_uart_driver);
static struct platform_device clps711x_uart_device = {
.name = UART_CLPS711X_NAME,
};
static int __init uart_clps711x_init(void)
{
return platform_device_register(&clps711x_uart_device);
int ret;
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
clps711x_uart.cons = &clps711x_console;
clps711x_console.data = &clps711x_uart;
#endif
ret = uart_register_driver(&clps711x_uart);
if (ret)
return ret;
return platform_driver_register(&clps711x_uart_platform);
}
module_init(uart_clps711x_init);
static void __exit uart_clps711x_exit(void)
{
platform_device_unregister(&clps711x_uart_device);
platform_driver_unregister(&clps711x_uart_platform);
uart_unregister_driver(&clps711x_uart);
}
module_exit(uart_clps711x_exit);

View file

@ -29,7 +29,6 @@
#include <linux/tty.h>
#include <linux/gfp.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>

View file

@ -29,7 +29,6 @@
#include <linux/tty.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>

View file

@ -806,6 +806,9 @@ static unsigned int imx_get_mctrl(struct uart_port *port)
if (readl(sport->port.membase + UCR2) & UCR2_CTS)
tmp |= TIOCM_RTS;
if (readl(sport->port.membase + uts_reg(sport)) & UTS_LOOP)
tmp |= TIOCM_LOOP;
return tmp;
}
@ -821,6 +824,11 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
temp |= UCR2_CTS;
writel(temp, sport->port.membase + UCR2);
temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP;
if (mctrl & TIOCM_LOOP)
temp |= UTS_LOOP;
writel(temp, sport->port.membase + uts_reg(sport));
}
/*

View file

@ -15,7 +15,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/compiler.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/atomic.h>

View file

@ -734,9 +734,12 @@ static void mxs_auart_reset(struct uart_port *u)
static int mxs_auart_startup(struct uart_port *u)
{
int ret;
struct mxs_auart_port *s = to_auart_port(u);
clk_prepare_enable(s->clk);
ret = clk_prepare_enable(s->clk);
if (ret)
return ret;
writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR);
@ -957,7 +960,9 @@ auart_console_setup(struct console *co, char *options)
if (!s)
return -ENODEV;
clk_prepare_enable(s->clk);
ret = clk_prepare_enable(s->clk);
if (ret)
return ret;
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);

View file

@ -9,7 +9,6 @@
* 2 of the License, or (at your option) any later version.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>

View file

@ -1853,7 +1853,6 @@ static void pch_uart_exit_port(struct eg20t_port *priv)
debugfs_remove(priv->debugfs);
#endif
uart_remove_one_port(&pch_uart_driver, &priv->port);
pci_set_drvdata(priv->pdev, NULL);
free_page((unsigned long)priv->rxbuf.buf);
}
@ -1907,7 +1906,7 @@ static int pch_uart_pci_resume(struct pci_dev *pdev)
#define pch_uart_pci_resume NULL
#endif
static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = {
static const struct pci_device_id pch_uart_pci_id[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8811),
.driver_data = pch_et20t_uart0},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8812),

View file

@ -810,7 +810,7 @@ static void rp2_remove(struct pci_dev *pdev)
rp2_remove_ports(card);
}
static DEFINE_PCI_DEVICE_TABLE(rp2_pci_tbl) = {
static const struct pci_device_id rp2_pci_tbl[] = {
/* RocketPort INFINITY cards */

View file

@ -1,749 +0,0 @@
/*
* SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
*
* Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
#include <linux/circ_buf.h>
#include <linux/serial.h>
#include <linux/sysrq.h>
#include <linux/console.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/io.h>
#warning "Please try migrate to use new driver SCCNXP and report the status" \
"in the linux-serial mailing list."
#if defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include <linux/serial_core.h>
#define SC26XX_MAJOR 204
#define SC26XX_MINOR_START 205
#define SC26XX_NR 2
struct uart_sc26xx_port {
struct uart_port port[2];
u8 dsr_mask[2];
u8 cts_mask[2];
u8 dcd_mask[2];
u8 ri_mask[2];
u8 dtr_mask[2];
u8 rts_mask[2];
u8 imr;
};
/* register common to both ports */
#define RD_ISR 0x14
#define RD_IPR 0x34
#define WR_ACR 0x10
#define WR_IMR 0x14
#define WR_OPCR 0x34
#define WR_OPR_SET 0x38
#define WR_OPR_CLR 0x3C
/* access common register */
#define READ_SC(p, r) readb((p)->membase + RD_##r)
#define WRITE_SC(p, r, v) writeb((v), (p)->membase + WR_##r)
/* register per port */
#define RD_PORT_MRx 0x00
#define RD_PORT_SR 0x04
#define RD_PORT_RHR 0x0c
#define WR_PORT_MRx 0x00
#define WR_PORT_CSR 0x04
#define WR_PORT_CR 0x08
#define WR_PORT_THR 0x0c
/* SR bits */
#define SR_BREAK (1 << 7)
#define SR_FRAME (1 << 6)
#define SR_PARITY (1 << 5)
#define SR_OVERRUN (1 << 4)
#define SR_TXRDY (1 << 2)
#define SR_RXRDY (1 << 0)
#define CR_RES_MR (1 << 4)
#define CR_RES_RX (2 << 4)
#define CR_RES_TX (3 << 4)
#define CR_STRT_BRK (6 << 4)
#define CR_STOP_BRK (7 << 4)
#define CR_DIS_TX (1 << 3)
#define CR_ENA_TX (1 << 2)
#define CR_DIS_RX (1 << 1)
#define CR_ENA_RX (1 << 0)
/* ISR bits */
#define ISR_RXRDYB (1 << 5)
#define ISR_TXRDYB (1 << 4)
#define ISR_RXRDYA (1 << 1)
#define ISR_TXRDYA (1 << 0)
/* IMR bits */
#define IMR_RXRDY (1 << 1)
#define IMR_TXRDY (1 << 0)
/* access port register */
static inline u8 read_sc_port(struct uart_port *p, u8 reg)
{
return readb(p->membase + p->line * 0x20 + reg);
}
static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val)
{
writeb(val, p->membase + p->line * 0x20 + reg);
}
#define READ_SC_PORT(p, r) read_sc_port(p, RD_PORT_##r)
#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v)
static void sc26xx_enable_irq(struct uart_port *port, int mask)
{
struct uart_sc26xx_port *up;
int line = port->line;
port -= line;
up = container_of(port, struct uart_sc26xx_port, port[0]);
up->imr |= mask << (line * 4);
WRITE_SC(port, IMR, up->imr);
}
static void sc26xx_disable_irq(struct uart_port *port, int mask)
{
struct uart_sc26xx_port *up;
int line = port->line;
port -= line;
up = container_of(port, struct uart_sc26xx_port, port[0]);
up->imr &= ~(mask << (line * 4));
WRITE_SC(port, IMR, up->imr);
}
static bool receive_chars(struct uart_port *port)
{
struct tty_port *tport = NULL;
int limit = 10000;
unsigned char ch;
char flag;
u8 status;
/* FIXME what is this trying to achieve? */
if (port->state != NULL) /* Unopened serial console */
tport = &port->state->port;
while (limit-- > 0) {
status = READ_SC_PORT(port, SR);
if (!(status & SR_RXRDY))
break;
ch = READ_SC_PORT(port, RHR);
flag = TTY_NORMAL;
port->icount.rx++;
if (unlikely(status & (SR_BREAK | SR_FRAME |
SR_PARITY | SR_OVERRUN))) {
if (status & SR_BREAK) {
status &= ~(SR_PARITY | SR_FRAME);
port->icount.brk++;
if (uart_handle_break(port))
continue;
} else if (status & SR_PARITY)
port->icount.parity++;
else if (status & SR_FRAME)
port->icount.frame++;
if (status & SR_OVERRUN)
port->icount.overrun++;
status &= port->read_status_mask;
if (status & SR_BREAK)
flag = TTY_BREAK;
else if (status & SR_PARITY)
flag = TTY_PARITY;
else if (status & SR_FRAME)
flag = TTY_FRAME;
}
if (uart_handle_sysrq_char(port, ch))
continue;
if (status & port->ignore_status_mask)
continue;
tty_insert_flip_char(tport, ch, flag);
}
return !!tport;
}
static void transmit_chars(struct uart_port *port)
{
struct circ_buf *xmit;
if (!port->state)
return;
xmit = &port->state->xmit;
if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
sc26xx_disable_irq(port, IMR_TXRDY);
return;
}
while (!uart_circ_empty(xmit)) {
if (!(READ_SC_PORT(port, SR) & SR_TXRDY))
break;
WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
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 sc26xx_interrupt(int irq, void *dev_id)
{
struct uart_sc26xx_port *up = dev_id;
unsigned long flags;
bool push;
u8 isr;
spin_lock_irqsave(&up->port[0].lock, flags);
push = false;
isr = READ_SC(&up->port[0], ISR);
if (isr & ISR_TXRDYA)
transmit_chars(&up->port[0]);
if (isr & ISR_RXRDYA)
push = receive_chars(&up->port[0]);
spin_unlock(&up->port[0].lock);
if (push)
tty_flip_buffer_push(&up->port[0].state->port);
spin_lock(&up->port[1].lock);
push = false;
if (isr & ISR_TXRDYB)
transmit_chars(&up->port[1]);
if (isr & ISR_RXRDYB)
push = receive_chars(&up->port[1]);
spin_unlock_irqrestore(&up->port[1].lock, flags);
if (push)
tty_flip_buffer_push(&up->port[1].state->port);
return IRQ_HANDLED;
}
/* port->lock is not held. */
static unsigned int sc26xx_tx_empty(struct uart_port *port)
{
return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
}
/* port->lock held by caller. */
static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_sc26xx_port *up;
int line = port->line;
port -= line;
up = container_of(port, struct uart_sc26xx_port, port[0]);
if (up->dtr_mask[line]) {
if (mctrl & TIOCM_DTR)
WRITE_SC(port, OPR_SET, up->dtr_mask[line]);
else
WRITE_SC(port, OPR_CLR, up->dtr_mask[line]);
}
if (up->rts_mask[line]) {
if (mctrl & TIOCM_RTS)
WRITE_SC(port, OPR_SET, up->rts_mask[line]);
else
WRITE_SC(port, OPR_CLR, up->rts_mask[line]);
}
}
/* port->lock is held by caller and interrupts are disabled. */
static unsigned int sc26xx_get_mctrl(struct uart_port *port)
{
struct uart_sc26xx_port *up;
int line = port->line;
unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
u8 ipr;
port -= line;
up = container_of(port, struct uart_sc26xx_port, port[0]);
ipr = READ_SC(port, IPR) ^ 0xff;
if (up->dsr_mask[line]) {
mctrl &= ~TIOCM_DSR;
mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0;
}
if (up->cts_mask[line]) {
mctrl &= ~TIOCM_CTS;
mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0;
}
if (up->dcd_mask[line]) {
mctrl &= ~TIOCM_CAR;
mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0;
}
if (up->ri_mask[line]) {
mctrl &= ~TIOCM_RNG;
mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0;
}
return mctrl;
}
/* port->lock held by caller. */
static void sc26xx_stop_tx(struct uart_port *port)
{
return;
}
/* port->lock held by caller. */
static void sc26xx_start_tx(struct uart_port *port)
{
struct circ_buf *xmit = &port->state->xmit;
while (!uart_circ_empty(xmit)) {
if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) {
sc26xx_enable_irq(port, IMR_TXRDY);
break;
}
WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]);
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
}
}
/* port->lock held by caller. */
static void sc26xx_stop_rx(struct uart_port *port)
{
}
/* port->lock held by caller. */
static void sc26xx_enable_ms(struct uart_port *port)
{
}
/* port->lock is not held. */
static void sc26xx_break_ctl(struct uart_port *port, int break_state)
{
if (break_state == -1)
WRITE_SC_PORT(port, CR, CR_STRT_BRK);
else
WRITE_SC_PORT(port, CR, CR_STOP_BRK);
}
/* port->lock is not held. */
static int sc26xx_startup(struct uart_port *port)
{
sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
WRITE_SC(port, OPCR, 0);
/* reset tx and rx */
WRITE_SC_PORT(port, CR, CR_RES_RX);
WRITE_SC_PORT(port, CR, CR_RES_TX);
/* start rx/tx */
WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
/* enable irqs */
sc26xx_enable_irq(port, IMR_RXRDY);
return 0;
}
/* port->lock is not held. */
static void sc26xx_shutdown(struct uart_port *port)
{
/* disable interrupst */
sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY);
/* stop tx/rx */
WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
}
/* port->lock is not held. */
static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000);
unsigned int quot = uart_get_divisor(port, baud);
unsigned int iflag, cflag;
unsigned long flags;
u8 mr1, mr2, csr;
spin_lock_irqsave(&port->lock, flags);
while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
udelay(2);
WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX);
iflag = termios->c_iflag;
cflag = termios->c_cflag;
port->read_status_mask = SR_OVERRUN;
if (iflag & INPCK)
port->read_status_mask |= SR_PARITY | SR_FRAME;
if (iflag & (BRKINT | PARMRK))
port->read_status_mask |= SR_BREAK;
port->ignore_status_mask = 0;
if (iflag & IGNBRK)
port->ignore_status_mask |= SR_BREAK;
if ((cflag & CREAD) == 0)
port->ignore_status_mask |= SR_BREAK | SR_FRAME |
SR_PARITY | SR_OVERRUN;
switch (cflag & CSIZE) {
case CS5:
mr1 = 0x00;
break;
case CS6:
mr1 = 0x01;
break;
case CS7:
mr1 = 0x02;
break;
default:
case CS8:
mr1 = 0x03;
break;
}
mr2 = 0x07;
if (cflag & CSTOPB)
mr2 = 0x0f;
if (cflag & PARENB) {
if (cflag & PARODD)
mr1 |= (1 << 2);
} else
mr1 |= (2 << 3);
switch (baud) {
case 50:
csr = 0x00;
break;
case 110:
csr = 0x11;
break;
case 134:
csr = 0x22;
break;
case 200:
csr = 0x33;
break;
case 300:
csr = 0x44;
break;
case 600:
csr = 0x55;
break;
case 1200:
csr = 0x66;
break;
case 2400:
csr = 0x88;
break;
case 4800:
csr = 0x99;
break;
default:
case 9600:
csr = 0xbb;
break;
case 19200:
csr = 0xcc;
break;
}
WRITE_SC_PORT(port, CR, CR_RES_MR);
WRITE_SC_PORT(port, MRx, mr1);
WRITE_SC_PORT(port, MRx, mr2);
WRITE_SC(port, ACR, 0x80);
WRITE_SC_PORT(port, CSR, csr);
/* reset tx and rx */
WRITE_SC_PORT(port, CR, CR_RES_RX);
WRITE_SC_PORT(port, CR, CR_RES_TX);
WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX);
while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc)
udelay(2);
/* XXX */
uart_update_timeout(port, cflag,
(port->uartclk / (16 * quot)));
spin_unlock_irqrestore(&port->lock, flags);
}
static const char *sc26xx_type(struct uart_port *port)
{
return "SC26XX";
}
static void sc26xx_release_port(struct uart_port *port)
{
}
static int sc26xx_request_port(struct uart_port *port)
{
return 0;
}
static void sc26xx_config_port(struct uart_port *port, int flags)
{
}
static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser)
{
return -EINVAL;
}
static struct uart_ops sc26xx_ops = {
.tx_empty = sc26xx_tx_empty,
.set_mctrl = sc26xx_set_mctrl,
.get_mctrl = sc26xx_get_mctrl,
.stop_tx = sc26xx_stop_tx,
.start_tx = sc26xx_start_tx,
.stop_rx = sc26xx_stop_rx,
.enable_ms = sc26xx_enable_ms,
.break_ctl = sc26xx_break_ctl,
.startup = sc26xx_startup,
.shutdown = sc26xx_shutdown,
.set_termios = sc26xx_set_termios,
.type = sc26xx_type,
.release_port = sc26xx_release_port,
.request_port = sc26xx_request_port,
.config_port = sc26xx_config_port,
.verify_port = sc26xx_verify_port,
};
static struct uart_port *sc26xx_port;
#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
static void sc26xx_console_putchar(struct uart_port *port, char c)
{
unsigned long flags;
int limit = 1000000;
spin_lock_irqsave(&port->lock, flags);
while (limit-- > 0) {
if (READ_SC_PORT(port, SR) & SR_TXRDY) {
WRITE_SC_PORT(port, THR, c);
break;
}
udelay(2);
}
spin_unlock_irqrestore(&port->lock, flags);
}
static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
{
struct uart_port *port = sc26xx_port;
int i;
for (i = 0; i < n; i++) {
if (*s == '\n')
sc26xx_console_putchar(port, '\r');
sc26xx_console_putchar(port, *s++);
}
}
static int __init sc26xx_console_setup(struct console *con, char *options)
{
struct uart_port *port = sc26xx_port;
int baud = 9600;
int bits = 8;
int parity = 'n';
int flow = 'n';
if (port->type != PORT_SC26XX)
return -1;
printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
return uart_set_options(port, con, baud, parity, bits, flow);
}
static struct uart_driver sc26xx_reg;
static struct console sc26xx_console = {
.name = "ttySC",
.write = sc26xx_console_write,
.device = uart_console_device,
.setup = sc26xx_console_setup,
.flags = CON_PRINTBUFFER,
.index = -1,
.data = &sc26xx_reg,
};
#define SC26XX_CONSOLE &sc26xx_console
#else
#define SC26XX_CONSOLE NULL
#endif
static struct uart_driver sc26xx_reg = {
.owner = THIS_MODULE,
.driver_name = "SC26xx",
.dev_name = "ttySC",
.major = SC26XX_MAJOR,
.minor = SC26XX_MINOR_START,
.nr = SC26XX_NR,
.cons = SC26XX_CONSOLE,
};
static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
{
unsigned int bit = (flags >> bitpos) & 15;
return bit ? (1 << (bit - 1)) : 0;
}
static void sc26xx_init_masks(struct uart_sc26xx_port *up,
int line, unsigned int data)
{
up->dtr_mask[line] = sc26xx_flags2mask(data, 0);
up->rts_mask[line] = sc26xx_flags2mask(data, 4);
up->dsr_mask[line] = sc26xx_flags2mask(data, 8);
up->cts_mask[line] = sc26xx_flags2mask(data, 12);
up->dcd_mask[line] = sc26xx_flags2mask(data, 16);
up->ri_mask[line] = sc26xx_flags2mask(data, 20);
}
static int sc26xx_probe(struct platform_device *dev)
{
struct resource *res;
struct uart_sc26xx_port *up;
unsigned int *sc26xx_data = dev_get_platdata(&dev->dev);
int err;
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
up = kzalloc(sizeof *up, GFP_KERNEL);
if (unlikely(!up))
return -ENOMEM;
up->port[0].line = 0;
up->port[0].ops = &sc26xx_ops;
up->port[0].type = PORT_SC26XX;
up->port[0].uartclk = (29491200 / 16); /* arbitrary */
up->port[0].mapbase = res->start;
up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40);
up->port[0].iotype = UPIO_MEM;
up->port[0].irq = platform_get_irq(dev, 0);
up->port[0].dev = &dev->dev;
sc26xx_init_masks(up, 0, sc26xx_data[0]);
sc26xx_port = &up->port[0];
up->port[1].line = 1;
up->port[1].ops = &sc26xx_ops;
up->port[1].type = PORT_SC26XX;
up->port[1].uartclk = (29491200 / 16); /* arbitrary */
up->port[1].mapbase = up->port[0].mapbase;
up->port[1].membase = up->port[0].membase;
up->port[1].iotype = UPIO_MEM;
up->port[1].irq = up->port[0].irq;
up->port[1].dev = &dev->dev;
sc26xx_init_masks(up, 1, sc26xx_data[1]);
err = uart_register_driver(&sc26xx_reg);
if (err)
goto out_free_port;
sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor;
err = uart_add_one_port(&sc26xx_reg, &up->port[0]);
if (err)
goto out_unregister_driver;
err = uart_add_one_port(&sc26xx_reg, &up->port[1]);
if (err)
goto out_remove_port0;
err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up);
if (err)
goto out_remove_ports;
platform_set_drvdata(dev, up);
return 0;
out_remove_ports:
uart_remove_one_port(&sc26xx_reg, &up->port[1]);
out_remove_port0:
uart_remove_one_port(&sc26xx_reg, &up->port[0]);
out_unregister_driver:
uart_unregister_driver(&sc26xx_reg);
out_free_port:
kfree(up);
sc26xx_port = NULL;
return err;
}
static int __exit sc26xx_driver_remove(struct platform_device *dev)
{
struct uart_sc26xx_port *up = platform_get_drvdata(dev);
free_irq(up->port[0].irq, up);
uart_remove_one_port(&sc26xx_reg, &up->port[0]);
uart_remove_one_port(&sc26xx_reg, &up->port[1]);
uart_unregister_driver(&sc26xx_reg);
kfree(up);
sc26xx_port = NULL;
return 0;
}
static struct platform_driver sc26xx_driver = {
.probe = sc26xx_probe,
.remove = sc26xx_driver_remove,
.driver = {
.name = "SC26xx",
.owner = THIS_MODULE,
},
};
module_platform_driver(sc26xx_driver);
MODULE_AUTHOR("Thomas Bogendörfer");
MODULE_DESCRIPTION("SC681/SC2692 serial driver");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:SC26xx");

View file

@ -1830,9 +1830,13 @@ uart_set_options(struct uart_port *port, struct console *co,
/*
* Ensure that the serial console lock is initialised
* early.
* If this port is a console, then the spinlock is already
* initialised.
*/
spin_lock_init(&port->lock);
lockdep_set_class(&port->lock, &port_lock_key);
if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
spin_lock_init(&port->lock);
lockdep_set_class(&port->lock, &port_lock_key);
}
memset(&termios, 0, sizeof(struct ktermios));

View file

@ -524,9 +524,11 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st;
unsigned int count;
unsigned long flags;
struct dma_tx_state tx_state;
spin_lock_irqsave(&sirfport->rx_lock, flags);
while (sirfport->rx_completed != sirfport->rx_issued) {
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
SIRFSOC_RX_DMA_BUF_SIZE);
sirfport->rx_completed++;
@ -709,8 +711,10 @@ static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param)
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
unsigned long flags;
struct dma_tx_state tx_state;
spin_lock_irqsave(&sirfport->rx_lock, flags);
while (sirfport->rx_completed != sirfport->rx_issued) {
while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan,
sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) {
sirfsoc_uart_insert_rx_buf_to_tty(sirfport,
SIRFSOC_RX_DMA_BUF_SIZE);
if (rd_regl(port, ureg->sirfsoc_int_en_reg) &
@ -1033,6 +1037,16 @@ static void sirfsoc_uart_set_termios(struct uart_port *port,
spin_unlock_irqrestore(&port->lock, flags);
}
static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
if (!state)
clk_prepare_enable(sirfport->clk);
else
clk_disable_unprepare(sirfport->clk);
}
static unsigned int sirfsoc_uart_init_tx_dma(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
@ -1264,6 +1278,7 @@ static struct uart_ops sirfsoc_uart_ops = {
.startup = sirfsoc_uart_startup,
.shutdown = sirfsoc_uart_shutdown,
.set_termios = sirfsoc_uart_set_termios,
.pm = sirfsoc_uart_pm,
.type = sirfsoc_uart_type,
.release_port = sirfsoc_uart_release_port,
.request_port = sirfsoc_uart_request_port,
@ -1486,7 +1501,6 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
ret = PTR_ERR(sirfport->clk);
goto err;
}
clk_prepare_enable(sirfport->clk);
port->uartclk = clk_get_rate(sirfport->clk);
port->ops = &sirfsoc_uart_ops;
@ -1502,7 +1516,6 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
return 0;
port_err:
clk_disable_unprepare(sirfport->clk);
clk_put(sirfport->clk);
err:
return ret;
@ -1512,38 +1525,42 @@ static int sirfsoc_uart_remove(struct platform_device *pdev)
{
struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
struct uart_port *port = &sirfport->port;
clk_disable_unprepare(sirfport->clk);
clk_put(sirfport->clk);
uart_remove_one_port(&sirfsoc_uart_drv, port);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int
sirfsoc_uart_suspend(struct platform_device *pdev, pm_message_t state)
sirfsoc_uart_suspend(struct device *pdev)
{
struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev);
struct uart_port *port = &sirfport->port;
uart_suspend_port(&sirfsoc_uart_drv, port);
return 0;
}
static int sirfsoc_uart_resume(struct platform_device *pdev)
static int sirfsoc_uart_resume(struct device *pdev)
{
struct sirfsoc_uart_port *sirfport = platform_get_drvdata(pdev);
struct sirfsoc_uart_port *sirfport = dev_get_drvdata(pdev);
struct uart_port *port = &sirfport->port;
uart_resume_port(&sirfsoc_uart_drv, port);
return 0;
}
#endif
static const struct dev_pm_ops sirfsoc_uart_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_uart_suspend, sirfsoc_uart_resume)
};
static struct platform_driver sirfsoc_uart_driver = {
.probe = sirfsoc_uart_probe,
.remove = sirfsoc_uart_remove,
.suspend = sirfsoc_uart_suspend,
.resume = sirfsoc_uart_resume,
.driver = {
.name = SIRFUART_PORT_NAME,
.owner = THIS_MODULE,
.of_match_table = sirfsoc_uart_ids,
.pm = &sirfsoc_uart_pm_ops,
},
};

View file

@ -3404,8 +3404,8 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp)
/* If port is closing, signal caller to try again */
if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
if (info->port.flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->port.close_wait);
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
goto cleanup;

View file

@ -674,8 +674,8 @@ static int open(struct tty_struct *tty, struct file *filp)
/* If port is closing, signal caller to try again */
if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
if (info->port.flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->port.close_wait);
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
goto cleanup;

View file

@ -754,8 +754,8 @@ static int open(struct tty_struct *tty, struct file *filp)
/* If port is closing, signal caller to try again */
if (tty_hung_up_p(filp) || info->port.flags & ASYNC_CLOSING){
if (info->port.flags & ASYNC_CLOSING)
interruptible_sleep_on(&info->port.close_wait);
wait_event_interruptible_tty(tty, info->port.close_wait,
!(info->port.flags & ASYNC_CLOSING));
retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ?
-EAGAIN : -ERESTARTSYS);
goto cleanup;

View file

@ -11,7 +11,6 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/delay.h>
@ -26,7 +25,7 @@
* Byte threshold to limit memory consumption for flip buffers.
* The actual memory limit is > 2x this amount.
*/
#define TTYB_MEM_LIMIT 65536
#define TTYB_DEFAULT_MEM_LIMIT 65536
/*
* We default to dicing tty buffer allocations to this many characters
@ -89,9 +88,10 @@ void tty_buffer_unlock_exclusive(struct tty_port *port)
int tty_buffer_space_avail(struct tty_port *port)
{
int space = TTYB_MEM_LIMIT - atomic_read(&port->buf.memory_used);
int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used);
return max(space, 0);
}
EXPORT_SYMBOL_GPL(tty_buffer_space_avail);
static void tty_buffer_reset(struct tty_buffer *p, size_t size)
{
@ -100,6 +100,7 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size)
p->next = NULL;
p->commit = 0;
p->read = 0;
p->flags = 0;
}
/**
@ -129,7 +130,7 @@ void tty_buffer_free_all(struct tty_port *port)
buf->head = &buf->sentinel;
buf->tail = &buf->sentinel;
atomic_set(&buf->memory_used, 0);
atomic_set(&buf->mem_used, 0);
}
/**
@ -162,7 +163,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
/* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */
if (atomic_read(&port->buf.memory_used) > TTYB_MEM_LIMIT)
if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit)
return NULL;
p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
if (p == NULL)
@ -170,7 +171,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size)
found:
tty_buffer_reset(p, size);
atomic_add(size, &port->buf.memory_used);
atomic_add(size, &port->buf.mem_used);
return p;
}
@ -188,7 +189,7 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
struct tty_bufhead *buf = &port->buf;
/* Dumb strategy for now - should keep some stats */
WARN_ON(atomic_sub_return(b->size, &buf->memory_used) < 0);
WARN_ON(atomic_sub_return(b->size, &buf->mem_used) < 0);
if (b->size > MIN_TTYB_SIZE)
kfree(b);
@ -200,9 +201,7 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
* tty_buffer_flush - flush full tty buffers
* @tty: tty to flush
*
* flush all the buffers containing receive data. If the buffer is
* being processed by flush_to_ldisc then we defer the processing
* to that function
* flush all the buffers containing receive data.
*
* Locking: takes buffer lock to ensure single-threaded flip buffer
* 'consumer'
@ -230,31 +229,49 @@ void tty_buffer_flush(struct tty_struct *tty)
* tty_buffer_request_room - grow tty buffer if needed
* @tty: tty structure
* @size: size desired
* @flags: buffer flags if new buffer allocated (default = 0)
*
* Make at least size bytes of linear space available for the tty
* buffer. If we fail return the size we managed to find.
*
* Will change over to a new buffer if the current buffer is encoded as
* TTY_NORMAL (so has no flags buffer) and the new buffer requires
* a flags buffer.
*/
int tty_buffer_request_room(struct tty_port *port, size_t size)
static int __tty_buffer_request_room(struct tty_port *port, size_t size,
int flags)
{
struct tty_bufhead *buf = &port->buf;
struct tty_buffer *b, *n;
int left;
int left, change;
b = buf->tail;
left = b->size - b->used;
if (b->flags & TTYB_NORMAL)
left = 2 * b->size - b->used;
else
left = b->size - b->used;
if (left < size) {
change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL);
if (change || left < size) {
/* This is the slow path - looking for new buffers to use */
if ((n = tty_buffer_alloc(port, size)) != NULL) {
n->flags = flags;
buf->tail = n;
b->commit = b->used;
smp_mb();
b->next = n;
} else
} else if (change)
size = 0;
else
size = left;
}
return size;
}
int tty_buffer_request_room(struct tty_port *port, size_t size)
{
return __tty_buffer_request_room(port, size, 0);
}
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
/**
@ -274,12 +291,14 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port,
int copied = 0;
do {
int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
int space = tty_buffer_request_room(port, goal);
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);
memset(flag_buf_ptr(tb, tb->used), flag, space);
if (~tb->flags & TTYB_NORMAL)
memset(flag_buf_ptr(tb, tb->used), flag, space);
tb->used += space;
copied += space;
chars += space;
@ -362,52 +381,28 @@ EXPORT_SYMBOL(tty_schedule_flip);
int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars,
size_t size)
{
int space = tty_buffer_request_room(port, size);
int space = __tty_buffer_request_room(port, size, TTYB_NORMAL);
if (likely(space)) {
struct tty_buffer *tb = port->buf.tail;
*chars = char_buf_ptr(tb, tb->used);
memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
if (~tb->flags & TTYB_NORMAL)
memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space);
tb->used += space;
}
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
/**
* tty_prepare_flip_string_flags - make room for characters
* @port: tty port
* @chars: return pointer for character write area
* @flags: return pointer for status flag write area
* @size: desired size
*
* Prepare a block of space in the buffer for data. Returns the length
* available and buffer pointer to the space which is now allocated and
* accounted for as ready for characters. This is used for drivers
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
*/
int tty_prepare_flip_string_flags(struct tty_port *port,
unsigned char **chars, char **flags, size_t size)
{
int space = tty_buffer_request_room(port, size);
if (likely(space)) {
struct tty_buffer *tb = port->buf.tail;
*chars = char_buf_ptr(tb, tb->used);
*flags = flag_buf_ptr(tb, tb->used);
tb->used += space;
}
return space;
}
EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
static int
receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
{
struct tty_ldisc *disc = tty->ldisc;
unsigned char *p = char_buf_ptr(head, head->read);
char *f = flag_buf_ptr(head, head->read);
char *f = NULL;
if (~head->flags & TTYB_NORMAL)
f = flag_buf_ptr(head, head->read);
if (disc->ops->receive_buf2)
count = disc->ops->receive_buf2(tty, p, f, count);
@ -533,7 +528,25 @@ void tty_buffer_init(struct tty_port *port)
buf->head = &buf->sentinel;
buf->tail = &buf->sentinel;
init_llist_head(&buf->free);
atomic_set(&buf->memory_used, 0);
atomic_set(&buf->mem_used, 0);
atomic_set(&buf->priority, 0);
INIT_WORK(&buf->work, flush_to_ldisc);
buf->mem_limit = TTYB_DEFAULT_MEM_LIMIT;
}
/**
* tty_buffer_set_limit - change the tty buffer memory limit
* @port: tty port to change
*
* Change the tty buffer memory limit.
* Must be called before the other tty buffer functions are used.
*/
int tty_buffer_set_limit(struct tty_port *port, int limit)
{
if (limit < MIN_TTYB_SIZE)
return -EINVAL;
port->buf.mem_limit = limit;
return 0;
}
EXPORT_SYMBOL_GPL(tty_buffer_set_limit);

View file

@ -11,7 +11,6 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/wait.h>

View file

@ -12,7 +12,6 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/delay.h>

View file

@ -286,9 +286,11 @@ void __init parse_early_options(char *cmdline);
#define arch_initcall(fn) module_init(fn)
#define subsys_initcall(fn) module_init(fn)
#define fs_initcall(fn) module_init(fn)
#define rootfs_initcall(fn) module_init(fn)
#define device_initcall(fn) module_init(fn)
#define late_initcall(fn) module_init(fn)
#define console_initcall(fn) module_init(fn)
#define security_initcall(fn) module_init(fn)
/* Each module must use one module_init(). */

View file

@ -39,10 +39,14 @@ struct tty_buffer {
int size;
int commit;
int read;
int flags;
/* Data points here */
unsigned long data[0];
};
/* 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;
@ -60,7 +64,8 @@ struct tty_bufhead {
atomic_t priority;
struct tty_buffer sentinel;
struct llist_head free; /* Free queue head */
atomic_t memory_used; /* In-use buffers excluding free list */
atomic_t mem_used; /* In-use buffers excluding free list */
int mem_limit;
struct tty_buffer *tail; /* Active buffer */
};
/*
@ -422,7 +427,6 @@ extern int is_ignored(int sig);
extern int tty_signal(int sig, struct tty_struct *tty);
extern void tty_hangup(struct tty_struct *tty);
extern void tty_vhangup(struct tty_struct *tty);
extern void tty_vhangup_locked(struct tty_struct *tty);
extern void tty_unhangup(struct file *filp);
extern int tty_hung_up_p(struct file *filp);
extern void do_SAK(struct tty_struct *tty);

View file

@ -1,6 +1,7 @@
#ifndef _LINUX_TTY_FLIP_H
#define _LINUX_TTY_FLIP_H
extern int tty_buffer_set_limit(struct tty_port *port, int limit);
extern int tty_buffer_space_avail(struct tty_port *port);
extern int tty_buffer_request_room(struct tty_port *port, size_t size);
extern int tty_insert_flip_string_flags(struct tty_port *port,
@ -9,8 +10,6 @@ extern int tty_insert_flip_string_fixed_flag(struct tty_port *port,
const unsigned char *chars, char flag, size_t size);
extern int tty_prepare_flip_string(struct tty_port *port,
unsigned char **chars, size_t size);
extern int tty_prepare_flip_string_flags(struct tty_port *port,
unsigned char **chars, char **flags, size_t size);
extern void tty_flip_buffer_push(struct tty_port *port);
void tty_schedule_flip(struct tty_port *port);
@ -18,8 +17,12 @@ static inline int tty_insert_flip_char(struct tty_port *port,
unsigned char ch, char flag)
{
struct tty_buffer *tb = port->buf.tail;
if (tb && tb->used < tb->size) {
*flag_buf_ptr(tb, tb->used) = flag;
int change;
change = (tb->flags & TTYB_NORMAL) && (flag != TTY_NORMAL);
if (!change && tb->used < tb->size) {
if (~tb->flags & TTYB_NORMAL)
*flag_buf_ptr(tb, tb->used) = flag;
*char_buf_ptr(tb, tb->used++) = ch;
return 1;
}

View file

@ -84,7 +84,8 @@
* processing. <cp> is a pointer to the buffer of input
* character received by the device. <fp> is a pointer to a
* pointer of flag bytes which indicate whether a character was
* received with a parity error, etc.
* received with a parity error, etc. <fp> may be NULL to indicate
* all data received is TTY_NORMAL.
*
* void (*write_wakeup)(struct tty_struct *);
*
@ -118,7 +119,8 @@
* processing. <cp> is a pointer to the buffer of input
* character received by the device. <fp> is a pointer to a
* pointer of flag bytes which indicate whether a character was
* received with a parity error, etc.
* received with a parity error, etc. <fp> may be NULL to indicate
* all data received is TTY_NORMAL.
* If assigned, prefer this function for automatic flow control.
*/