[SCSI] pm80xx: WWN Modification for PM8081/88/89 controllers
[cascardo/linux.git] / drivers / tty / n_tty.c
index 68865d9..d655416 100644 (file)
@@ -153,6 +153,12 @@ static void n_tty_set_room(struct tty_struct *tty)
        if (left && !old_left) {
                WARN_RATELIMIT(tty->port->itty == NULL,
                                "scheduling with invalid itty\n");
+               /* see if ldisc has been killed - if so, this means that
+                * even though the ldisc has been halted and ->buf.work
+                * cancelled, ->buf.work is about to be rescheduled
+                */
+               WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
+                              "scheduling buffer work for halted ldisc\n");
                schedule_work(&tty->port->buf.work);
        }
 }
@@ -192,16 +198,14 @@ static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
  *     reset_buffer_flags      -       reset buffer state
  *     @tty: terminal to reset
  *
- *     Reset the read buffer counters, clear the flags,
- *     and make sure the driver is unthrottled. Called
- *     from n_tty_open() and n_tty_flush_buffer().
+ *     Reset the read buffer counters and clear the flags.
+ *     Called from n_tty_open() and n_tty_flush_buffer().
  *
  *     Locking: tty_read_lock for read fields.
  */
 
-static void reset_buffer_flags(struct tty_struct *tty)
+static void reset_buffer_flags(struct n_tty_data *ldata)
 {
-       struct n_tty_data *ldata = tty->disc_data;
        unsigned long flags;
 
        raw_spin_lock_irqsave(&ldata->read_lock, flags);
@@ -214,36 +218,38 @@ static void reset_buffer_flags(struct tty_struct *tty)
 
        ldata->canon_head = ldata->canon_data = ldata->erasing = 0;
        bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);
-       n_tty_set_room(tty);
+}
+
+static void n_tty_packet_mode_flush(struct tty_struct *tty)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       if (tty->link->packet) {
+               tty->ctrl_status |= TIOCPKT_FLUSHREAD;
+               wake_up_interruptible(&tty->link->read_wait);
+       }
+       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 }
 
 /**
  *     n_tty_flush_buffer      -       clean input queue
  *     @tty:   terminal device
  *
- *     Flush the input buffer. Called when the line discipline is
- *     being closed, when the tty layer wants the buffer flushed (eg
- *     at hangup) or when the N_TTY line discipline internally has to
- *     clean the pending queue (for example some signals).
+ *     Flush the input buffer. Called when the tty layer wants the
+ *     buffer flushed (eg at hangup) or when the N_TTY line discipline
+ *     internally has to clean the pending queue (for example some signals).
  *
  *     Locking: ctrl_lock, read_lock.
  */
 
 static void n_tty_flush_buffer(struct tty_struct *tty)
 {
-       unsigned long flags;
-       /* clear everything and unthrottle the driver */
-       reset_buffer_flags(tty);
-
-       if (!tty->link)
-               return;
+       reset_buffer_flags(tty->disc_data);
+       n_tty_set_room(tty);
 
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
-       if (tty->link->packet) {
-               tty->ctrl_status |= TIOCPKT_FLUSHREAD;
-               wake_up_interruptible(&tty->link->read_wait);
-       }
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       if (tty->link)
+               n_tty_packet_mode_flush(tty);
 }
 
 /**
@@ -1586,7 +1592,9 @@ static void n_tty_close(struct tty_struct *tty)
 {
        struct n_tty_data *ldata = tty->disc_data;
 
-       n_tty_flush_buffer(tty);
+       if (tty->link)
+               n_tty_packet_mode_flush(tty);
+
        kfree(ldata->read_buf);
        kfree(ldata->echo_buf);
        kfree(ldata);
@@ -1624,12 +1632,14 @@ static int n_tty_open(struct tty_struct *tty)
                goto err_free_bufs;
 
        tty->disc_data = ldata;
-       reset_buffer_flags(tty);
-       tty_unthrottle(tty);
+       reset_buffer_flags(tty->disc_data);
        ldata->column = 0;
-       n_tty_set_termios(tty, NULL);
        tty->minimum_to_wake = 1;
        tty->closing = 0;
+       /* indicate buffer work may resume */
+       clear_bit(TTY_LDISC_HALTED, &tty->flags);
+       n_tty_set_termios(tty, NULL);
+       tty_unthrottle(tty);
 
        return 0;
 err_free_bufs: