diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/serio/serport.c | 28 | ||||
-rw-r--r-- | drivers/parport/parport_serial.c | 5 | ||||
-rw-r--r-- | drivers/staging/fwserial/Kconfig | 20 | ||||
-rw-r--r-- | drivers/staging/fwserial/fwserial.c | 151 | ||||
-rw-r--r-- | drivers/staging/fwserial/fwserial.h | 24 | ||||
-rw-r--r-- | drivers/tty/n_gsm.c | 44 | ||||
-rw-r--r-- | drivers/tty/n_r3964.c | 2 | ||||
-rw-r--r-- | drivers/tty/n_tty.c | 87 | ||||
-rw-r--r-- | drivers/tty/rocket.c | 2 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 8 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl010.c | 15 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 21 | ||||
-rw-r--r-- | drivers/tty/serial/imx.c | 8 | ||||
-rw-r--r-- | drivers/tty/serial/mxs-auart.c | 9 | ||||
-rw-r--r-- | drivers/tty/serial/pch_uart.c | 3 | ||||
-rw-r--r-- | drivers/tty/serial/rp2.c | 2 | ||||
-rw-r--r-- | drivers/tty/serial/serial_core.c | 8 | ||||
-rw-r--r-- | drivers/tty/tty_buffer.c | 110 |
18 files changed, 254 insertions, 293 deletions
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 8755f5f3ad37..0cb7ef59071b 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -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; - - case TTY_PARITY: - ch_flags = SERIO_PARITY; - break; - - default: - ch_flags = 0; - break; + if (fp) { + switch (fp[i]) { + case TTY_FRAME: + ch_flags = SERIO_FRAME; + break; + + case TTY_PARITY: + ch_flags = SERIO_PARITY; + break; + + default: + ch_flags = 0; + break; + } } serio_interrupt(serport->serio, cp[i], ch_flags); diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index 1b8bdb7e9bf4..ff53314100f6 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -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); diff --git a/drivers/staging/fwserial/Kconfig b/drivers/staging/fwserial/Kconfig index a0812d99136f..9c7c9267d52c 100644 --- a/drivers/staging/fwserial/Kconfig +++ b/drivers/staging/fwserial/Kconfig @@ -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 diff --git a/drivers/staging/fwserial/fwserial.c b/drivers/staging/fwserial/fwserial.c index 62df009e5ac7..8af136e9c9dc 100644 --- a/drivers/staging/fwserial/fwserial.c +++ b/drivers/staging/fwserial/fwserial.c @@ -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); diff --git a/drivers/staging/fwserial/fwserial.h b/drivers/staging/fwserial/fwserial.h index 24635014a2ac..54f7f9b9b212 100644 --- a/drivers/staging/fwserial/fwserial.h +++ b/drivers/staging/fwserial/fwserial.h @@ -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 diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c0f76da55304..679294b37653 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -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; @@ -2054,9 +2055,11 @@ 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); @@ -2170,6 +2173,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); @@ -2269,14 +2273,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); @@ -2909,23 +2914,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 +2951,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 +2977,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 +2985,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 +3162,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 +3191,7 @@ static const struct tty_operations gsmtty_ops = { .tiocmget = gsmtty_tiocmget, .tiocmset = gsmtty_tiocmset, .break_ctl = gsmtty_break_ctl, + .remove = gsmtty_remove, }; diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 1e6405070ce6..8b157d68a03e 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -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++) { diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 268b62768f2b..fdc2ecde5ac2 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -274,7 +274,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; } @@ -349,7 +350,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); } @@ -1157,7 +1159,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); } /** @@ -1215,7 +1218,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 @@ -1259,7 +1263,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)) { @@ -1344,8 +1347,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?!? */ @@ -1360,7 +1361,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: @@ -1374,7 +1375,6 @@ handle_newline: } } - parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0; if (L_ECHO(tty)) { finish_erasing(ldata); if (c == '\n') @@ -1388,7 +1388,8 @@ handle_newline: 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); @@ -1399,7 +1400,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); @@ -1413,13 +1413,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); } @@ -1444,8 +1444,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; @@ -1676,32 +1675,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; @@ -1712,7 +1688,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; } @@ -1731,6 +1707,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) || @@ -1820,8 +1808,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); } /** @@ -1887,14 +1877,15 @@ err: 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; @@ -2393,7 +2384,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; diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c index 354564ea47c5..383c4c796637 100644 --- a/drivers/tty/rocket.c +++ b/drivers/tty/rocket.c @@ -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) }, diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 4658e3e0ec42..816ec88a0d7f 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -272,7 +272,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) { @@ -300,13 +299,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) { diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 33bd8606be62..01c9e72433e1 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -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) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 7203864992a5..c8cc8f02b092 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -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 { @@ -327,7 +325,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * dmaengine_slave_config(chan, &rx_conf); uap->dmarx.chan = chan; - if (plat && plat->dma_rx_poll_enable) { + if (plat) { /* Set poll rate if specified. */ if (plat->dma_rx_poll_rate) { uap->dmarx.auto_poll_rate = false; @@ -2169,10 +2167,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 +2178,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 +2189,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 +2210,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) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index b2cfdb661947..d799140e53b6 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -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)); } /* diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index d8b6fee77a03..aa97fd845b4d 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -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); diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 0aa2b528ef3d..9cbd3acaf37f 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -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), diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c index 328d6deb6b08..056f91b3a4ca 100644 --- a/drivers/tty/serial/rp2.c +++ b/drivers/tty/serial/rp2.c @@ -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 */ diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 0f02351c9239..ece2049bd270 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -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)); diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index c043136fbe51..3002e20e10d7 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -26,7 +26,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 +89,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 +101,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 +131,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 +164,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 +172,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 +190,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 +202,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 +230,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 +292,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 +382,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 +529,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); |