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:
commit
bcee63488e
52 changed files with 753 additions and 1369 deletions
|
@ -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>,
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/console.h>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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(¤t->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;
|
||||
|
|
|
@ -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) },
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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");
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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(). */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
|
|
Loading…
Reference in a new issue