- 0x01 - tty->warned is on.
- 0x04 - tty->packed is on.
- - 0x08 - tty->flow_stopped is on.
+ - 0x08 - tty->flow.tco_stopped is on.
- 0x10 - tty->hw_stopped is on.
- - 0x20 - tty->stopped is on.
+ - 0x20 - tty->flow.stopped is on.
* last_tx_msg: Binary blob Prints the last transmitted frame.
else
#endif
{
- if (tty && (tty->stopped || tty->hw_stopped)) {
+ if (tty && (tty->flow.stopped || tty->hw_stopped)) {
tx_stop(info);
return;
}
if (!info->tx_active)
return;
} else {
- if (tty && (tty->stopped || tty->hw_stopped)) {
+ if (tty && (tty->flow.stopped || tty->hw_stopped)) {
tx_stop(info);
return;
}
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_flush_chars"))
return;
- if (info->tx_count <= 0 || tty->stopped ||
+ if (info->tx_count <= 0 || tty->flow.stopped ||
tty->hw_stopped || !info->tx_buf)
return;
ret += c;
}
start:
- if (info->tx_count && !tty->stopped && !tty->hw_stopped) {
+ if (info->tx_count && !tty->flow.stopped && !tty->hw_stopped) {
spin_lock_irqsave(&info->lock, flags);
if (!info->tx_active)
tx_start(info, tty);
tty = tty_port_tty_get(&port->port);
if (tty == NULL || !kfifo_len(xmit) ||
- tty->stopped || tty->hw_stopped) {
+ tty->flow.stopped || tty->hw_stopped) {
sdio_uart_stop_tx(port);
tty_kref_put(tty);
return;
static inline void update_tty_status(struct ser_device *ser)
{
ser->tty_status =
- ser->tty->stopped << 5 |
- ser->tty->flow_stopped << 3 |
+ ser->tty->flow.stopped << 5 |
+ ser->tty->flow.tco_stopped << 3 |
ser->tty->packet << 2;
}
static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
int i_msg, i;
spin_lock_bh(&tp->view.lock);
- for (i_msg = 0; !tty->stopped && i_msg < count; i_msg++) {
+ for (i_msg = 0; !tty->flow.stopped && i_msg < count; i_msg++) {
if (tp->esc_state != 0) {
/* Continue escape sequence. */
tty3270_escape_sequence(tp, buf[i_msg]);
/* try to write as many dma transactions out as possible */
n = -EAGAIN;
- while (!tty->stopped && !tty->hw_stopped &&
+ while (!tty->flow.stopped && !tty->hw_stopped &&
!test_bit(STOP_TX, &port->flags)) {
txn = kmem_cache_alloc(fwtty_txn_cache, GFP_ATOMIC);
if (!txn) {
* ------------------------------------------------------------
* rs_stop() and rs_start()
*
- * This routines are called before setting or resetting tty->stopped.
+ * This routines are called before setting or resetting tty->flow.stopped.
* They enable or disable transmitter interrupts, as necessary.
* ------------------------------------------------------------
*/
return;
}
if (info->xmit.head == info->xmit.tail
- || info->tport.tty->stopped
+ || info->tport.tty->flow.stopped
|| info->tport.tty->hw_stopped) {
info->IER &= ~UART_IER_THRI;
custom.intena = IF_TBE;
unsigned long flags;
if (info->xmit.head == info->xmit.tail
- || tty->stopped
+ || tty->flow.stopped
|| tty->hw_stopped
|| !info->xmit.buf)
return;
local_irq_restore(flags);
if (info->xmit.head != info->xmit.tail
- && !tty->stopped
+ && !tty->flow.stopped
&& !tty->hw_stopped
&& !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
{
struct moxa_port *ch;
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
ch = tty->driver_data;
if (ch == NULL)
clear_bit(EMPTYWAIT, &p->statusflags);
tty_wakeup(tty);
}
- if (test_bit(LOWWAIT, &p->statusflags) && !tty->stopped &&
+ if (test_bit(LOWWAIT, &p->statusflags) && !tty->flow.stopped &&
MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
clear_bit(LOWWAIT, &p->statusflags);
tty_wakeup(tty);
total += c;
}
- if (info->xmit_cnt && !tty->stopped) {
+ if (info->xmit_cnt && !tty->flow.stopped) {
if (!tty->hw_stopped ||
(info->type == PORT_16550A) ||
(info->board->chip_flag)) {
info->xmit_head &= SERIAL_XMIT_SIZE - 1;
info->xmit_cnt++;
spin_unlock_irqrestore(&info->slock, flags);
- if (!tty->stopped) {
+ if (!tty->flow.stopped) {
if (!tty->hw_stopped ||
(info->type == PORT_16550A) ||
info->board->chip_flag) {
struct mxser_port *info = tty->driver_data;
unsigned long flags;
- if (info->xmit_cnt <= 0 || tty->stopped || !info->port.xmit_buf ||
+ if (info->xmit_cnt <= 0 || tty->flow.stopped || !info->port.xmit_buf ||
(tty->hw_stopped && info->type != PORT_16550A &&
!info->board->chip_flag))
return;
/*
* mxser_stop() and mxser_start()
*
- * This routines are called before setting or resetting tty->stopped.
+ * This routines are called before setting or resetting tty->flow.stopped.
* They enable or disable transmitter interrupts, as necessary.
*/
static void mxser_stop(struct tty_struct *tty)
/* Handle sw stopped */
if ((old_termios->c_iflag & IXON) && !I_IXON(tty)) {
- tty->stopped = 0;
+ tty->flow.stopped = 0;
if (info->board->chip_flag) {
spin_lock_irqsave(&info->slock, flags);
if (port->port.xmit_buf == NULL)
return;
- if (port->xmit_cnt <= 0 || tty->stopped ||
+ if (port->xmit_cnt <= 0 || tty->flow.stopped ||
(tty->hw_stopped &&
(port->type != PORT_16550A) &&
(!port->board->chip_flag))) {
}
}
- if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+ if (tty->flow.stopped && !tty->flow.tco_stopped && I_IXON(tty) && I_IXANY(tty)) {
start_tty(tty);
process_echoes(tty);
}
{
struct n_tty_data *ldata = tty->disc_data;
- if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
+ if (tty->flow.stopped && !tty->flow.tco_stopped && I_IXON(tty) && I_IXANY(tty)) {
start_tty(tty);
process_echoes(tty);
}
if (c == STOP_CHAR(tty))
stop_tty(tty);
else if (c == START_CHAR(tty) ||
- (tty->stopped && !tty->flow_stopped && I_IXANY(tty) &&
+ (tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) &&
c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) &&
c != SUSP_CHAR(tty))) {
start_tty(tty);
* Fix tty hang when I_IXON(tty) is cleared, but the tty
* been stopped by STOP_CHAR(tty) before it.
*/
- if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) {
+ if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow.tco_stopped) {
start_tty(tty);
process_echoes(tty);
}
struct tty_struct *to = tty->link;
unsigned long flags;
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
if (c > 0) {
static int pty_write_room(struct tty_struct *tty)
{
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
return tty_buffer_space_avail(tty->link->port);
}
/*
* Driver internal routine, used by both tty(serial core) as well as tx-isr
* -Called under spinlock in either cases
- * -also tty->stopped has already been checked
+ * -also tty->flow.stopped has already been checked
* = by uart_start( ) before calling us
* = tx_ist checks that too before calling
*/
* rs_stop () and rs_start ()
*
* These routines are called before setting or resetting
- * tty->stopped. They enable or disable transmitter interrupts,
+ * tty->flow.stopped. They enable or disable transmitter interrupts,
* as necessary.
* ------------------------------------------------------------
*/
if (!info->tx_buf || (count > info->max_frame_size))
return -EIO;
- if (!count || tty->stopped || tty->hw_stopped)
+ if (!count || tty->flow.stopped || tty->hw_stopped)
return 0;
spin_lock_irqsave(&info->lock, flags);
return;
DBGINFO(("%s flush_chars entry tx_count=%d\n", info->device_name, info->tx_count));
- if (info->tx_count <= 0 || tty->stopped ||
+ if (info->tx_count <= 0 || tty->flow.stopped ||
tty->hw_stopped || !info->tx_buf)
return;
else
#endif
{
- if (info->port.tty && (info->port.tty->stopped || info->port.tty->hw_stopped)) {
+ if (info->port.tty && (info->port.tty->flow.stopped || info->port.tty->hw_stopped)) {
tx_stop(info);
return;
}
* but not always.
*
* Locking:
- * flow_lock
+ * flow.lock
*/
void __stop_tty(struct tty_struct *tty)
{
- if (tty->stopped)
+ if (tty->flow.stopped)
return;
- tty->stopped = 1;
+ tty->flow.stopped = true;
if (tty->ops->stop)
tty->ops->stop(tty);
}
{
unsigned long flags;
- spin_lock_irqsave(&tty->flow_lock, flags);
+ spin_lock_irqsave(&tty->flow.lock, flags);
__stop_tty(tty);
- spin_unlock_irqrestore(&tty->flow_lock, flags);
+ spin_unlock_irqrestore(&tty->flow.lock, flags);
}
EXPORT_SYMBOL(stop_tty);
* start method is invoked and the line discipline woken.
*
* Locking:
- * flow_lock
+ * flow.lock
*/
void __start_tty(struct tty_struct *tty)
{
- if (!tty->stopped || tty->flow_stopped)
+ if (!tty->flow.stopped || tty->flow.tco_stopped)
return;
- tty->stopped = 0;
+ tty->flow.stopped = false;
if (tty->ops->start)
tty->ops->start(tty);
tty_wakeup(tty);
{
unsigned long flags;
- spin_lock_irqsave(&tty->flow_lock, flags);
+ spin_lock_irqsave(&tty->flow.lock, flags);
__start_tty(tty);
- spin_unlock_irqrestore(&tty->flow_lock, flags);
+ spin_unlock_irqrestore(&tty->flow.lock, flags);
}
EXPORT_SYMBOL(start_tty);
int tty_send_xchar(struct tty_struct *tty, char ch)
{
- int was_stopped = tty->stopped;
+ bool was_stopped = tty->flow.stopped;
if (tty->ops->send_xchar) {
down_read(&tty->termios_rwsem);
INIT_WORK(&tty->hangup_work, do_tty_hangup);
mutex_init(&tty->atomic_write_lock);
spin_lock_init(&tty->ctrl_lock);
- spin_lock_init(&tty->flow_lock);
+ spin_lock_init(&tty->flow.lock);
spin_lock_init(&tty->files_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
return retval;
switch (arg) {
case TCOOFF:
- spin_lock_irq(&tty->flow_lock);
- if (!tty->flow_stopped) {
- tty->flow_stopped = 1;
+ spin_lock_irq(&tty->flow.lock);
+ if (!tty->flow.tco_stopped) {
+ tty->flow.tco_stopped = true;
__stop_tty(tty);
}
- spin_unlock_irq(&tty->flow_lock);
+ spin_unlock_irq(&tty->flow.lock);
break;
case TCOON:
- spin_lock_irq(&tty->flow_lock);
- if (tty->flow_stopped) {
- tty->flow_stopped = 0;
+ spin_lock_irq(&tty->flow.lock);
+ if (tty->flow.tco_stopped) {
+ tty->flow.tco_stopped = false;
__start_tty(tty);
}
- spin_unlock_irq(&tty->flow_lock);
+ spin_unlock_irq(&tty->flow.lock);
break;
case TCIOFF:
if (STOP_CHAR(tty) != __DISABLED_CHAR)
if (tty_port_initialized(port)) {
/* Don't block on a stalled port, just pull the chain */
- if (tty->flow_stopped)
+ if (tty->flow.tco_stopped)
tty_driver_flush_buffer(tty);
if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, port->closing_wait);
* these routines are also activated by ^S/^Q.
* (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
*/
- if (tty->stopped)
+ if (tty->flow.stopped)
start_tty(tty);
else
stop_tty(tty);
param.vc = vc;
- while (!tty->stopped && count) {
+ while (!tty->flow.stopped && count) {
int orig = *buf;
buf++;
n++;
static int con_write_room(struct tty_struct *tty)
{
- if (tty->stopped)
+ if (tty->flow.stopped)
return 0;
return 32768; /* No limit, really; we're not buffering */
}
static inline int uart_tx_stopped(struct uart_port *port)
{
struct tty_struct *tty = port->state->port.tty;
- if ((tty && tty->stopped) || port->hw_stopped)
+ if ((tty && tty->flow.stopped) || port->hw_stopped)
return 1;
return 0;
}
#define TTY_PORT_KOPENED 5 /* device exclusively opened by
kernel */
-/*
- * Where all of the state associated with a tty is kept while the tty
- * is open. Since the termios state should be kept even if the tty
- * has been closed --- for things like the baud rate, etc --- it is
- * not stored here, but rather a pointer to the real state is stored
- * here. Possible the winsize structure should have the same
- * treatment, but (1) the default 80x24 is usually right and (2) it's
- * most often used by a windowing system, which will set the correct
- * size each time the window is created or resized anyway.
- * - TYT, 9/14/92
- */
-
struct tty_operations;
+/**
+ * struct tty_struct - state associated with a tty while open
+ *
+ * @flow.lock: lock for flow members
+ * @flow.stopped: tty stopped/started by tty_stop/tty_start
+ * @flow.tco_stopped: tty stopped/started by TCOOFF/TCOON ioctls (it has
+ * precedense over @flow.stopped)
+ * @flow.unused: alignment for Alpha, so that no members other than @flow.* are
+ * modified by the same 64b word store. The @flow's __aligned is
+ * there for the very same reason.
+ *
+ * All of the state associated with a tty while the tty is open. Persistent
+ * storage for tty devices is referenced here as @port in struct tty_port.
+ */
struct tty_struct {
int magic;
struct kref kref;
struct rw_semaphore termios_rwsem;
struct mutex winsize_mutex;
spinlock_t ctrl_lock;
- spinlock_t flow_lock;
/* Termios values are protected by the termios rwsem */
struct ktermios termios, termios_locked;
char name[64];
unsigned long flags;
int count;
struct winsize winsize; /* winsize_mutex */
- unsigned long stopped:1, /* flow_lock */
- flow_stopped:1,
- unused:BITS_PER_LONG - 2;
+
+ struct {
+ spinlock_t lock;
+ bool stopped;
+ bool tco_stopped;
+ unsigned long unused[0];
+ } __aligned(sizeof(unsigned long)) flow;
+
int hw_stopped;
unsigned long ctrl_status:8, /* ctrl_lock */
packet:1,
* This routine notifies the tty driver that it should stop
* outputting characters to the tty device.
*
- * Called with ->flow_lock held. Serialized with start() method.
+ * Called with ->flow.lock held. Serialized with start() method.
*
* Optional:
*
* This routine notifies the tty driver that it resume sending
* characters to the tty device.
*
- * Called with ->flow_lock held. Serialized with stop() method.
+ * Called with ->flow.lock held. Serialized with stop() method.
*
* Optional:
*