tty: make receive_buf() return the amout of bytes received
authorFelipe Balbi <balbi@ti.com>
Mon, 21 Mar 2011 10:25:08 +0000 (12:25 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Sat, 23 Apr 2011 00:31:53 +0000 (17:31 -0700)
it makes it simpler to keep track of the amount of
bytes received and simplifies how flush_to_ldisc counts
the remaining bytes. It also fixes a bug of lost bytes
on n_tty when flushing too many bytes via the USB
serial gadget driver.

Tested-by: Stefan Bigler <stefan.bigler@keymile.com>
Tested-by: Toby Gray <toby.gray@realvnc.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
20 files changed:
drivers/bluetooth/hci_ldisc.c
drivers/input/serio/serport.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/misc/ti-st/st_core.c
drivers/net/caif/caif_serial.c
drivers/net/can/slcan.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/mkiss.c
drivers/net/irda/irtty-sir.c
drivers/net/ppp_async.c
drivers/net/ppp_synctty.c
drivers/net/slip.c
drivers/net/wan/x25_asy.c
drivers/tty/n_gsm.c
drivers/tty/n_hdlc.c
drivers/tty/n_r3964.c
drivers/tty/n_tty.c
drivers/tty/tty_buffer.c
drivers/tty/vt/selection.c
include/linux/tty_ldisc.h

index 48ad2a7..0d4da5e 100644 (file)
@@ -357,22 +357,26 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
  *     
  * Return Value:    None
  */
-static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
+static unsigned int hci_uart_tty_receive(struct tty_struct *tty,
+               const u8 *data, char *flags, int count)
 {
        struct hci_uart *hu = (void *)tty->disc_data;
+       int received;
 
        if (!hu || tty != hu->tty)
-               return;
+               return -ENODEV;
 
        if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
-               return;
+               return -EINVAL;
 
        spin_lock(&hu->rx_lock);
-       hu->proto->recv(hu, (void *) data, count);
+       received = hu->proto->recv(hu, (void *) data, count);
        hu->hdev->stat.byte_rx += count;
        spin_unlock(&hu->rx_lock);
 
        tty_unthrottle(tty);
+
+       return received;
 }
 
 static int hci_uart_register_dev(struct hci_uart *hu)
index 8755f5f..f369896 100644 (file)
@@ -120,17 +120,21 @@ static void serport_ldisc_close(struct tty_struct *tty)
  * 'interrupt' routine.
  */
 
-static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+static unsigned int serport_ldisc_receive(struct tty_struct *tty,
+               const unsigned char *cp, char *fp, int count)
 {
        struct serport *serport = (struct serport*) tty->disc_data;
        unsigned long flags;
        unsigned int ch_flags;
+       int ret = 0;
        int i;
 
        spin_lock_irqsave(&serport->lock, flags);
 
-       if (!test_bit(SERPORT_ACTIVE, &serport->flags))
+       if (!test_bit(SERPORT_ACTIVE, &serport->flags)) {
+               ret = -EINVAL;
                goto out;
+       }
 
        for (i = 0; i < count; i++) {
                switch (fp[i]) {
@@ -152,6 +156,8 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
 
 out:
        spin_unlock_irqrestore(&serport->lock, flags);
+
+       return ret == 0 ? count : ret;
 }
 
 /*
index 86a5c4f..1d44d47 100644 (file)
@@ -674,7 +674,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
  *     cflags  buffer containing error flags for received characters (ignored)
  *     count   number of received characters
  */
-static void
+static unsigned int
 gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
                    char *cflags, int count)
 {
@@ -683,12 +683,12 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
        struct inbuf_t *inbuf;
 
        if (!cs)
-               return;
+               return -ENODEV;
        inbuf = cs->inbuf;
        if (!inbuf) {
                dev_err(cs->dev, "%s: no inbuf\n", __func__);
                cs_put(cs);
-               return;
+               return -EINVAL;
        }
 
        tail = inbuf->tail;
@@ -725,6 +725,8 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
        gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
        gigaset_schedule_event(cs);
        cs_put(cs);
+
+       return count;
 }
 
 /*
index 486117f..cb98a7d 100644 (file)
@@ -744,8 +744,8 @@ static void st_tty_close(struct tty_struct *tty)
        pr_debug("%s: done ", __func__);
 }
 
-static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
-                          char *tty_flags, int count)
+static unsigned int st_tty_receive(struct tty_struct *tty,
+               const unsigned char *data, char *tty_flags, int count)
 {
 #ifdef VERBOSE
        print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
@@ -758,6 +758,8 @@ static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
         */
        st_recv(tty->disc_data, data, count);
        pr_debug("done %s", __func__);
+
+       return count;
 }
 
 /* wake-up function called in from the TTY layer
index 3df0c0f..73c7e03 100644 (file)
@@ -167,8 +167,8 @@ static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)
 
 #endif
 
-static void ldisc_receive(struct tty_struct *tty, const u8 *data,
-                       char *flags, int count)
+static unsigned int ldisc_receive(struct tty_struct *tty,
+               const u8 *data, char *flags, int count)
 {
        struct sk_buff *skb = NULL;
        struct ser_device *ser;
@@ -215,6 +215,8 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data,
        } else
                ++ser->dev->stats.rx_dropped;
        update_tty_status(ser);
+
+       return count;
 }
 
 static int handle_tx(struct ser_device *ser)
index b423965..c600954 100644 (file)
@@ -425,16 +425,17 @@ static void slc_setup(struct net_device *dev)
  * in parallel
  */
 
-static void slcan_receive_buf(struct tty_struct *tty,
+static unsigned int slcan_receive_buf(struct tty_struct *tty,
                              const unsigned char *cp, char *fp, int count)
 {
        struct slcan *sl = (struct slcan *) tty->disc_data;
+       int bytes = count;
 
        if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
-               return;
+               return -ENODEV;
 
        /* Read the characters out of the buffer */
-       while (count--) {
+       while (bytes--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
                                sl->dev->stats.rx_errors++;
@@ -443,6 +444,8 @@ static void slcan_receive_buf(struct tty_struct *tty,
                }
                slcan_unesc(sl, *cp++);
        }
+
+       return count;
 }
 
 /************************************
index 3e5d0b6..9920896 100644 (file)
@@ -456,7 +456,7 @@ out:
  * a block of 6pack data has been received, which can now be decapsulated
  * and sent on to some IP layer for further processing.
  */
-static void sixpack_receive_buf(struct tty_struct *tty,
+static unsigned int sixpack_receive_buf(struct tty_struct *tty,
        const unsigned char *cp, char *fp, int count)
 {
        struct sixpack *sp;
@@ -464,11 +464,11 @@ static void sixpack_receive_buf(struct tty_struct *tty,
        int count1;
 
        if (!count)
-               return;
+               return 0;
 
        sp = sp_get(tty);
        if (!sp)
-               return;
+               return -ENODEV;
 
        memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf));
 
@@ -487,6 +487,8 @@ static void sixpack_receive_buf(struct tty_struct *tty,
 
        sp_put(sp);
        tty_unthrottle(tty);
+
+       return count1;
 }
 
 /*
index 4c62839..0e4f235 100644 (file)
@@ -923,13 +923,14 @@ static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file,
  * a block of data has been received, which can now be decapsulated
  * and sent on to the AX.25 layer for further processing.
  */
-static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-       char *fp, int count)
+static unsigned int mkiss_receive_buf(struct tty_struct *tty,
+               const unsigned char *cp, char *fp, int count)
 {
        struct mkiss *ax = mkiss_get(tty);
+       int bytes = count;
 
        if (!ax)
-               return;
+               return -ENODEV;
 
        /*
         * Argh! mtu change time! - costs us the packet part received
@@ -939,7 +940,7 @@ static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                ax_changedmtu(ax);
 
        /* Read the characters out of the buffer */
-       while (count--) {
+       while (bytes--) {
                if (fp != NULL && *fp++) {
                        if (!test_and_set_bit(AXF_ERROR, &ax->flags))
                                ax->dev->stats.rx_errors++;
@@ -952,6 +953,8 @@ static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 
        mkiss_put(ax);
        tty_unthrottle(tty);
+
+       return count;
 }
 
 /*
index 3352b24..035861d 100644 (file)
@@ -216,23 +216,23 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
  * usbserial:  urb-complete-interrupt / softint
  */
 
-static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count) 
+static unsigned int irtty_receive_buf(struct tty_struct *tty,
+               const unsigned char *cp, char *fp, int count)
 {
        struct sir_dev *dev;
        struct sirtty_cb *priv = tty->disc_data;
        int     i;
 
-       IRDA_ASSERT(priv != NULL, return;);
-       IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
+       IRDA_ASSERT(priv != NULL, return -ENODEV;);
+       IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EINVAL;);
 
        if (unlikely(count==0))         /* yes, this happens */
-               return;
+               return 0;
 
        dev = priv->dev;
        if (!dev) {
                IRDA_WARNING("%s(), not ready yet!\n", __func__);
-               return;
+               return -ENODEV;
        }
 
        for (i = 0; i < count; i++) {
@@ -242,11 +242,13 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                if (fp && *fp++) { 
                        IRDA_DEBUG(0, "Framing or parity error!\n");
                        sirdev_receive(dev, NULL, 0);   /* notify sir_dev (updating stats) */
-                       return;
+                       return -EINVAL;
                }
        }
 
        sirdev_receive(dev, cp, count);
+
+       return count;
 }
 
 /*
index a1b82c9..53872d7 100644 (file)
@@ -340,7 +340,7 @@ ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
 }
 
 /* May sleep, don't call from interrupt level or with interrupts disabled */
-static void
+static unsigned int
 ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
                  char *cflags, int count)
 {
@@ -348,7 +348,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
        unsigned long flags;
 
        if (!ap)
-               return;
+               return -ENODEV;
        spin_lock_irqsave(&ap->recv_lock, flags);
        ppp_async_input(ap, buf, cflags, count);
        spin_unlock_irqrestore(&ap->recv_lock, flags);
@@ -356,6 +356,8 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
                tasklet_schedule(&ap->tsk);
        ap_put(ap);
        tty_unthrottle(tty);
+
+       return count;
 }
 
 static void
index 2573f52..0815790 100644 (file)
@@ -381,7 +381,7 @@ ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
 }
 
 /* May sleep, don't call from interrupt level or with interrupts disabled */
-static void
+static unsigned int
 ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
                  char *cflags, int count)
 {
@@ -389,7 +389,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
        unsigned long flags;
 
        if (!ap)
-               return;
+               return -ENODEV;
        spin_lock_irqsave(&ap->recv_lock, flags);
        ppp_sync_input(ap, buf, cflags, count);
        spin_unlock_irqrestore(&ap->recv_lock, flags);
@@ -397,6 +397,8 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
                tasklet_schedule(&ap->tsk);
        sp_put(ap);
        tty_unthrottle(tty);
+
+       return count;
 }
 
 static void
index 86cbb9e..86718d3 100644 (file)
@@ -670,16 +670,17 @@ static void sl_setup(struct net_device *dev)
  * in parallel
  */
 
-static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                                                       char *fp, int count)
+static unsigned int slip_receive_buf(struct tty_struct *tty,
+               const unsigned char *cp, char *fp, int count)
 {
        struct slip *sl = tty->disc_data;
+       int bytes = count;
 
        if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
-               return;
+               return -ENODEV;
 
        /* Read the characters out of the buffer */
-       while (count--) {
+       while (bytes--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
                                sl->dev->stats.rx_errors++;
@@ -693,6 +694,8 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 #endif
                        slip_unesc(sl, *cp++);
        }
+
+       return count;
 }
 
 /************************************
index 24297b2..40398bf 100644 (file)
@@ -517,17 +517,18 @@ static int x25_asy_close(struct net_device *dev)
  * and sent on to some IP layer for further processing.
  */
 
-static void x25_asy_receive_buf(struct tty_struct *tty,
+static unsigned int x25_asy_receive_buf(struct tty_struct *tty,
                                const unsigned char *cp, char *fp, int count)
 {
        struct x25_asy *sl = tty->disc_data;
+       int bytes = count;
 
        if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
                return;
 
 
        /* Read the characters out of the buffer */
-       while (count--) {
+       while (bytes--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
                                sl->dev->stats.rx_errors++;
@@ -536,6 +537,8 @@ static void x25_asy_receive_buf(struct tty_struct *tty,
                }
                x25_asy_unesc(sl, *cp++);
        }
+
+       return count;
 }
 
 /*
index 47f8cdb..6abc735 100644 (file)
@@ -2138,8 +2138,8 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
        gsm->tty = NULL;
 }
 
-static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count)
+static unsigned int gsmld_receive_buf(struct tty_struct *tty,
+               const unsigned char *cp, char *fp, int count)
 {
        struct gsm_mux *gsm = tty->disc_data;
        const unsigned char *dp;
@@ -2173,6 +2173,8 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
        }
        /* FASYNC if needed ? */
        /* If clogged call tty_throttle(tty); */
+
+       return count;
 }
 
 /**
index cea5603..cac6663 100644 (file)
@@ -188,8 +188,8 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
                                    poll_table *wait);
 static int n_hdlc_tty_open(struct tty_struct *tty);
 static void n_hdlc_tty_close(struct tty_struct *tty);
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
-                              char *fp, int count);
+static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
+               const __u8 *cp, char *fp, int count);
 static void n_hdlc_tty_wakeup(struct tty_struct *tty);
 
 #define bset(p,b)      ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
@@ -509,8 +509,8 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
  * Called by tty low level driver when receive data is available. Data is
  * interpreted as one HDLC frame.
  */
-static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
-                              char *flags, int count)
+static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
+               const __u8 *data, char *flags, int count)
 {
        register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
        register struct n_hdlc_buf *buf;
@@ -521,20 +521,20 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
                
        /* This can happen if stuff comes in on the backup tty */
        if (!n_hdlc || tty != n_hdlc->tty)
-               return;
+               return -ENODEV;
                
        /* verify line is using HDLC discipline */
        if (n_hdlc->magic != HDLC_MAGIC) {
                printk("%s(%d) line not using HDLC discipline\n",
                        __FILE__,__LINE__);
-               return;
+               return -EINVAL;
        }
        
        if ( count>maxframe ) {
                if (debuglevel >= DEBUG_LEVEL_INFO)     
                        printk("%s(%d) rx count>maxframesize, data discarded\n",
                               __FILE__,__LINE__);
-               return;
+               return -EINVAL;
        }
 
        /* get a free HDLC buffer */    
@@ -550,7 +550,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
                if (debuglevel >= DEBUG_LEVEL_INFO)     
                        printk("%s(%d) no more rx buffers, data discarded\n",
                               __FILE__,__LINE__);
-               return;
+               return -EINVAL;
        }
                
        /* copy received data to HDLC buffer */
@@ -565,6 +565,8 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
        if (n_hdlc->tty->fasync != NULL)
                kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
 
+       return count;
+
 }      /* end of n_hdlc_tty_receive() */
 
 /**
index 5c6c314..a4bc39c 100644 (file)
@@ -139,8 +139,8 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file,
 static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
 static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
                struct poll_table_struct *wait);
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-               char *fp, int count);
+static unsigned int r3964_receive_buf(struct tty_struct *tty,
+               const unsigned char *cp, char *fp, int count);
 
 static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
        .owner = THIS_MODULE,
@@ -1239,8 +1239,8 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
        return result;
 }
 
-static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                       char *fp, int count)
+static unsigned int r3964_receive_buf(struct tty_struct *tty,
+               const unsigned char *cp, char *fp, int count)
 {
        struct r3964_info *pInfo = tty->disc_data;
        const unsigned char *p;
@@ -1257,6 +1257,8 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                }
 
        }
+
+       return count;
 }
 
 MODULE_LICENSE("GPL");
index 0ad3288..95d0a9c 100644 (file)
@@ -81,38 +81,6 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
        return put_user(x, ptr);
 }
 
-/**
- *     n_tty_set__room -       receive space
- *     @tty: terminal
- *
- *     Called by the driver to find out how much data it is
- *     permitted to feed to the line discipline without any being lost
- *     and thus to manage flow control. Not serialized. Answers for the
- *     "instant".
- */
-
-static void n_tty_set_room(struct tty_struct *tty)
-{
-       /* tty->read_cnt is not read locked ? */
-       int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-       int old_left;
-
-       /*
-        * If we are doing input canonicalization, and there are no
-        * pending newlines, let characters through without limit, so
-        * that erase characters will be handled.  Other excess
-        * characters will be beeped.
-        */
-       if (left <= 0)
-               left = tty->icanon && !tty->canon_data;
-       old_left = tty->receive_room;
-       tty->receive_room = left;
-
-       /* Did this open up the receive buffer? We may need to flip */
-       if (left && !old_left)
-               schedule_work(&tty->buf.work);
-}
-
 static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
 {
        if (tty->read_cnt < N_TTY_BUF_SIZE) {
@@ -184,7 +152,6 @@ static void reset_buffer_flags(struct tty_struct *tty)
 
        tty->canon_head = tty->canon_data = tty->erasing = 0;
        memset(&tty->read_flags, 0, sizeof tty->read_flags);
-       n_tty_set_room(tty);
        check_unthrottle(tty);
 }
 
@@ -1360,17 +1327,19 @@ static void n_tty_write_wakeup(struct tty_struct *tty)
  *     calls one at a time and in order (or using flush_to_ldisc)
  */
 
-static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
-                             char *fp, int count)
+static unsigned int n_tty_receive_buf(struct tty_struct *tty,
+               const unsigned char *cp, char *fp, int count)
 {
        const unsigned char *p;
        char *f, flags = TTY_NORMAL;
        int     i;
        char    buf[64];
        unsigned long cpuflags;
+       int left;
+       int ret = 0;
 
        if (!tty->read_buf)
-               return;
+               return 0;
 
        if (tty->real_raw) {
                spin_lock_irqsave(&tty->read_lock, cpuflags);
@@ -1380,6 +1349,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                memcpy(tty->read_buf + tty->read_head, cp, i);
                tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
                tty->read_cnt += i;
+               ret += i;
                cp += i;
                count -= i;
 
@@ -1389,8 +1359,10 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                memcpy(tty->read_buf + tty->read_head, cp, i);
                tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
                tty->read_cnt += i;
+               ret += i;
                spin_unlock_irqrestore(&tty->read_lock, cpuflags);
        } else {
+               ret = count;
                for (i = count, p = cp, f = fp; i; i--, p++) {
                        if (f)
                                flags = *f++;
@@ -1418,8 +1390,6 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                        tty->ops->flush_chars(tty);
        }
 
-       n_tty_set_room(tty);
-
        if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
                L_EXTPROC(tty)) {
                kill_fasync(&tty->fasync, SIGIO, POLL_IN);
@@ -1432,8 +1402,12 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
         * mode.  We don't want to throttle the driver if we're in
         * canonical mode and don't have a newline yet!
         */
-       if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
+       left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
+       if (left < TTY_THRESHOLD_THROTTLE)
                tty_throttle(tty);
+
+       return ret;
 }
 
 int is_ignored(int sig)
@@ -1477,7 +1451,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
        if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
                tty->raw = 1;
                tty->real_raw = 1;
-               n_tty_set_room(tty);
                return;
        }
        if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
@@ -1530,7 +1503,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
                else
                        tty->real_raw = 0;
        }
-       n_tty_set_room(tty);
        /* The termios change make the tty ready for I/O */
        wake_up_interruptible(&tty->write_wait);
        wake_up_interruptible(&tty->read_wait);
@@ -1812,8 +1784,6 @@ do_it_again:
                                retval = -ERESTARTSYS;
                                break;
                        }
-                       /* FIXME: does n_tty_set_room need locking ? */
-                       n_tty_set_room(tty);
                        timeout = schedule_timeout(timeout);
                        continue;
                }
@@ -1885,10 +1855,8 @@ do_it_again:
                 * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
                 * we won't get any more characters.
                 */
-               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
-                       n_tty_set_room(tty);
+               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE)
                        check_unthrottle(tty);
-               }
 
                if (b - buf >= minimum)
                        break;
@@ -1910,7 +1878,6 @@ do_it_again:
        } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
                 goto do_it_again;
 
-       n_tty_set_room(tty);
        return retval;
 }
 
index f1a7918..46de2e0 100644 (file)
@@ -416,6 +416,7 @@ static void flush_to_ldisc(struct work_struct *work)
                struct tty_buffer *head, *tail = tty->buf.tail;
                int seen_tail = 0;
                while ((head = tty->buf.head) != NULL) {
+                       int copied;
                        int count;
                        char *char_buf;
                        unsigned char *flag_buf;
@@ -442,17 +443,19 @@ static void flush_to_ldisc(struct work_struct *work)
                           line discipline as we want to empty the queue */
                        if (test_bit(TTY_FLUSHPENDING, &tty->flags))
                                break;
-                       if (!tty->receive_room || seen_tail)
-                               break;
-                       if (count > tty->receive_room)
-                               count = tty->receive_room;
                        char_buf = head->char_buf_ptr + head->read;
                        flag_buf = head->flag_buf_ptr + head->read;
-                       head->read += count;
                        spin_unlock_irqrestore(&tty->buf.lock, flags);
-                       disc->ops->receive_buf(tty, char_buf,
+                       copied = disc->ops->receive_buf(tty, char_buf,
                                                        flag_buf, count);
                        spin_lock_irqsave(&tty->buf.lock, flags);
+
+                       head->read += copied;
+
+                       if (copied == 0 || seen_tail) {
+                               schedule_work(&tty->buf.work);
+                               break;
+                       }
                }
                clear_bit(TTY_FLUSHING, &tty->flags);
        }
index fb864e7..67b1d0d 100644 (file)
@@ -332,8 +332,7 @@ int paste_selection(struct tty_struct *tty)
                        continue;
                }
                count = sel_buffer_lth - pasted;
-               count = min(count, tty->receive_room);
-               tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
+               count = tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
                                                                NULL, count);
                pasted += count;
        }
index ff7dc08..5b07792 100644 (file)
@@ -76,7 +76,7 @@
  *     tty device.  It is solely the responsibility of the line
  *     discipline to handle poll requests.
  *
- * void        (*receive_buf)(struct tty_struct *, const unsigned char *cp,
+ * unsigned int (*receive_buf)(struct tty_struct *, const unsigned char *cp,
  *                    char *fp, int count);
  *
  *     This function is called by the low-level tty driver to send
@@ -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. Returns the amount of bytes
+ *     received.
  * 
  * void        (*write_wakeup)(struct tty_struct *);
  *
@@ -140,8 +141,8 @@ struct tty_ldisc_ops {
        /*
         * The following routines are called from below.
         */
-       void    (*receive_buf)(struct tty_struct *, const unsigned char *cp,
-                              char *fp, int count);
+       unsigned int (*receive_buf)(struct tty_struct *,
+                       const unsigned char *cp, char *fp, int count);
        void    (*write_wakeup)(struct tty_struct *);
        void    (*dcd_change)(struct tty_struct *, unsigned int,
                                struct pps_event_time *);