[PATCH v3 3/5] tty: Add lookahead param to receive_buf

From: Ilpo Järvinen
Date: Mon Apr 11 2022 - 05:50:11 EST


After lookahead for XON/XOFF characters is added by the next
patch, the receive side needs to ensure the flow-control
actions are not retaken later on when those same characters
get received by TTY.

Thus, pass lookahead count to receive_buf and skip
flow-control character actions if already taken for the
character in question. Lookahead count will become live after
the next patch.

The logic in n_tty_receive_char_closing is bit tricky.
The lookahead_done checks cannot be combined with the main
conditions because doing so would give chance for the part
after || in the else if condition to execute when lookahead
done is set (rather than just skipping the flow-control
character like it should).

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>
---
drivers/accessibility/speakup/spk_ttyio.c | 2 +-
drivers/bluetooth/hci_ldisc.c | 2 +-
drivers/char/pcmcia/synclink_cs.c | 2 +-
drivers/input/serio/serport.c | 4 +-
drivers/isdn/capi/capi.c | 2 +-
drivers/misc/ti-st/st_core.c | 2 +-
drivers/net/caif/caif_serial.c | 4 +-
drivers/net/can/slcan.c | 2 +-
drivers/net/hamradio/6pack.c | 4 +-
drivers/net/hamradio/mkiss.c | 2 +-
drivers/net/mctp/mctp-serial.c | 2 +-
drivers/net/ppp/ppp_async.c | 2 +-
drivers/net/ppp/ppp_synctty.c | 2 +-
drivers/net/slip/slip.c | 2 +-
drivers/tty/n_gsm.c | 2 +-
drivers/tty/n_hdlc.c | 2 +-
drivers/tty/n_null.c | 2 +-
drivers/tty/n_tty.c | 53 ++++++++++++++---------
drivers/tty/serdev/serdev-ttyport.c | 3 +-
drivers/tty/synclink_gt.c | 2 +-
drivers/tty/tty_buffer.c | 8 ++--
drivers/tty/tty_io.c | 2 +-
drivers/tty/tty_port.c | 5 ++-
drivers/tty/vt/selection.c | 2 +-
include/linux/tty_flip.h | 2 +-
include/linux/tty_ldisc.h | 20 ++++++---
include/linux/tty_port.h | 3 +-
net/nfc/nci/uart.c | 2 +-
sound/soc/codecs/cx20442.c | 2 +-
sound/soc/ti/ams-delta.c | 2 +-
30 files changed, 83 insertions(+), 63 deletions(-)

diff --git a/drivers/accessibility/speakup/spk_ttyio.c b/drivers/accessibility/speakup/spk_ttyio.c
index 08cf8a17754b..b33536eea1d3 100644
--- a/drivers/accessibility/speakup/spk_ttyio.c
+++ b/drivers/accessibility/speakup/spk_ttyio.c
@@ -73,7 +73,7 @@ static void spk_ttyio_ldisc_close(struct tty_struct *tty)

static int spk_ttyio_receive_buf2(struct tty_struct *tty,
const unsigned char *cp,
- const char *fp, int count)
+ const char *fp, int count, unsigned int lookahead_count)
{
struct spk_ldisc_data *ldisc_data = tty->disc_data;
struct spk_synth *synth = ldisc_data->synth;
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index f537673ede17..08c329a4cdcc 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -596,7 +596,7 @@ 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,
- const char *flags, int count)
+ const char *flags, int count, unsigned int lookahead_count)
{
struct hci_uart *hu = tty->disc_data;

diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 78baba55a8b5..de9c151cfb12 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -501,7 +501,7 @@ static void ldisc_receive_buf(struct tty_struct *tty,
ld = tty_ldisc_ref(tty);
if (ld) {
if (ld->ops->receive_buf)
- ld->ops->receive_buf(tty, data, flags, count);
+ ld->ops->receive_buf(tty, data, flags, count, 0);
tty_ldisc_deref(ld);
}
}
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 669a728095b8..f0f19b5a2059 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -114,8 +114,8 @@ static void serport_ldisc_close(struct tty_struct *tty)
* 'interrupt' routine.
*/

-static void serport_ldisc_receive(struct tty_struct *tty,
- const unsigned char *cp, const char *fp, int count)
+static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp,
+ const char *fp, int count, unsigned int lookahead_count)
{
struct serport *serport = (struct serport*) tty->disc_data;
unsigned long flags;
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 0f00be62438d..beb4c78a7219 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -454,7 +454,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
skb_pull(skb, CAPIMSG_LEN(skb->data));
pr_debug("capi: DATA_B3_RESP %u len=%d => ldisc\n",
datahandle, skb->len);
- ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
+ ld->ops->receive_buf(tty, skb->data, NULL, skb->len, 0);
} else {
printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
errcode);
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 7f6976a9f508..b2c96d72c0e3 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -797,7 +797,7 @@ static void st_tty_close(struct tty_struct *tty)
}

static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
- const char *tty_flags, int count)
+ const char *tty_flags, int count, unsigned int lookahead_count)
{
#ifdef VERBOSE
print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 688075859ae4..cc97c436ec88 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -159,7 +159,7 @@ 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,
- const char *flags, int count)
+ const char *flags, int count, unsigned int lookahead_count)
{
struct sk_buff *skb = NULL;
struct ser_device *ser;
@@ -237,7 +237,7 @@ static int handle_tx(struct ser_device *ser)
update_tty_status(ser);
} else {
tty_wr = len;
- ldisc_receive(tty, skb->data, NULL, len);
+ ldisc_receive(tty, skb->data, NULL, len, 0);
}
ser->dev->stats.tx_packets++;
ser->dev->stats.tx_bytes += tty_wr;
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index ec294d0c5722..5e03e14c2d99 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -471,7 +471,7 @@ static void slc_setup(struct net_device *dev)

static void slcan_receive_buf(struct tty_struct *tty,
const unsigned char *cp, const char *fp,
- int count)
+ int count, unsigned int lookahead_count)
{
struct slcan *sl = (struct slcan *) tty->disc_data;

diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 45c3c4a1101b..6ba4b05dff78 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -426,8 +426,8 @@ static void sixpack_write_wakeup(struct tty_struct *tty)
* 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,
- const unsigned char *cp, const char *fp, int count)
+static void sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+ const char *fp, int count, unsigned int lookahead_count)
{
struct sixpack *sp;
int count1;
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index c251e04ae047..498997ef429a 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -875,7 +875,7 @@ static int mkiss_ioctl(struct tty_struct *tty, unsigned int cmd,
* and sent on to the AX.25 layer for further processing.
*/
static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count)
+ const char *fp, int count, unsigned int lookahead_count)
{
struct mkiss *ax = mkiss_get(tty);

diff --git a/drivers/net/mctp/mctp-serial.c b/drivers/net/mctp/mctp-serial.c
index 7cd103fd34ef..f1dfab4c54cb 100644
--- a/drivers/net/mctp/mctp-serial.c
+++ b/drivers/net/mctp/mctp-serial.c
@@ -390,7 +390,7 @@ static void mctp_serial_push(struct mctp_serial *dev, unsigned char c)

static void mctp_serial_tty_receive_buf(struct tty_struct *tty,
const unsigned char *c,
- const char *f, int len)
+ const char *f, int len, unsigned int lookahead_count)
{
struct mctp_serial *dev = tty->disc_data;
int i;
diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c
index 15a179631903..87c205a02984 100644
--- a/drivers/net/ppp/ppp_async.c
+++ b/drivers/net/ppp/ppp_async.c
@@ -338,7 +338,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
ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
- const char *cflags, int count)
+ const char *cflags, int count, unsigned int lookahead_count)
{
struct asyncppp *ap = ap_get(tty);
unsigned long flags;
diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c
index 18283b7b94bc..b82f4bd82b21 100644
--- a/drivers/net/ppp/ppp_synctty.c
+++ b/drivers/net/ppp/ppp_synctty.c
@@ -331,7 +331,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
ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
- const char *cflags, int count)
+ const char *cflags, int count, unsigned int lookahead_count)
{
struct syncppp *ap = sp_get(tty);
unsigned long flags;
diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
index 88396ff99f03..7fccf28256a8 100644
--- a/drivers/net/slip/slip.c
+++ b/drivers/net/slip/slip.c
@@ -686,7 +686,7 @@ static void sl_setup(struct net_device *dev)
*/

static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count)
+ const char *fp, int count, unsigned int lookahead_count)
{
struct slip *sl = tty->disc_data;

diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index fa92f727fdf8..45f022892b28 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -2500,7 +2500,7 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
}

static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count)
+ const char *fp, int count, unsigned int lookahead_count)
{
struct gsm_mux *gsm = tty->disc_data;
char flags = TTY_NORMAL;
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index 94c1ec2dd754..2d7c94a38a92 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -379,7 +379,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
* interpreted as one HDLC frame.
*/
static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
- const char *flags, int count)
+ const char *flags, int count, unsigned int lookahead_count)
{
register struct n_hdlc *n_hdlc = tty->disc_data;
register struct n_hdlc_buf *buf;
diff --git a/drivers/tty/n_null.c b/drivers/tty/n_null.c
index f913b665af72..6bce76b5bb1c 100644
--- a/drivers/tty/n_null.c
+++ b/drivers/tty/n_null.c
@@ -34,7 +34,7 @@ static ssize_t n_null_write(struct tty_struct *tty, struct file *file,

static void n_null_receivebuf(struct tty_struct *tty,
const unsigned char *cp, const char *fp,
- int cnt)
+ int cnt, unsigned int lookahead_count)
{
}

diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 90b3e06cbeb1..708cc85ac43d 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -1226,11 +1226,15 @@ static bool n_tty_is_char_flow_ctrl(struct tty_struct *tty, unsigned char c)
}

/* Returns true if c is consumed as flow-control character */
-static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c)
+static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c,
+ bool lookahead_done)
{
if (!n_tty_is_char_flow_ctrl(tty, c))
return false;

+ if (lookahead_done)
+ return true;
+
if (c == START_CHAR(tty)) {
start_tty(tty);
process_echoes(tty);
@@ -1241,11 +1245,12 @@ static bool n_tty_receive_char_flow_ctrl(struct tty_struct *tty, unsigned char c
return true;
}

-static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
+static void n_tty_receive_char_special(struct tty_struct *tty, unsigned char c,
+ bool lookahead_done)
{
struct n_tty_data *ldata = tty->disc_data;

- if (I_IXON(tty) && n_tty_receive_char_flow_ctrl(tty, c))
+ if (I_IXON(tty) && n_tty_receive_char_flow_ctrl(tty, c, lookahead_done))
return;

if (L_ISIG(tty)) {
@@ -1400,7 +1405,8 @@ static void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
put_tty_queue(c, ldata);
}

-static 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,
+ bool lookahead_done)
{
if (I_ISTRIP(tty))
c &= 0x7f;
@@ -1408,9 +1414,12 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
c = tolower(c);

if (I_IXON(tty)) {
- if (c == STOP_CHAR(tty))
- stop_tty(tty);
- else if (c == START_CHAR(tty) ||
+ if (c == STOP_CHAR(tty)) {
+ if (!lookahead_done)
+ stop_tty(tty);
+ } else if (c == START_CHAR(tty) && lookahead_done) {
+ return;
+ } else if (c == START_CHAR(tty) ||
(tty->flow.stopped && !tty->flow.tco_stopped && I_IXANY(tty) &&
c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) &&
c != SUSP_CHAR(tty))) {
@@ -1495,22 +1504,24 @@ n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp,

static void
n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count)
+ const char *fp, int count, unsigned int lookahead_count)
{
+ int lookahead_thres = count - lookahead_count;
char flag = TTY_NORMAL;

while (count--) {
if (fp)
flag = *fp++;
if (likely(flag == TTY_NORMAL))
- n_tty_receive_char_closing(tty, *cp++);
+ n_tty_receive_char_closing(tty, *cp++, count >= lookahead_thres);
}
}

-static void n_tty_receive_buf_standard(struct tty_struct *tty,
- const unsigned char *cp, const char *fp, int count)
+static void n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp,
+ const char *fp, int count, unsigned int lookahead_count)
{
struct n_tty_data *ldata = tty->disc_data;
+ int lookahead_thres = count - lookahead_count;
char flag = TTY_NORMAL;

while (count--) {
@@ -1539,14 +1550,14 @@ static void n_tty_receive_buf_standard(struct tty_struct *tty,
}

if (test_bit(c, ldata->char_map))
- n_tty_receive_char_special(tty, c);
+ n_tty_receive_char_special(tty, c, count >= lookahead_thres);
else
n_tty_receive_char(tty, c);
}
}

static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count)
+ const char *fp, int count, unsigned int lookahead_count)
{
struct n_tty_data *ldata = tty->disc_data;
bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));
@@ -1556,9 +1567,9 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
else if (ldata->raw || (L_EXTPROC(tty) && !preops))
n_tty_receive_buf_raw(tty, cp, fp, count);
else if (tty->closing && !L_EXTPROC(tty))
- n_tty_receive_buf_closing(tty, cp, fp, count);
+ n_tty_receive_buf_closing(tty, cp, fp, count, lookahead_count);
else {
- n_tty_receive_buf_standard(tty, cp, fp, count);
+ n_tty_receive_buf_standard(tty, cp, fp, count, lookahead_count);

flush_echoes(tty);
if (tty->ops->flush_chars)
@@ -1612,7 +1623,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
*/
static int
n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count, int flow)
+ const char *fp, int count, unsigned int lookahead_count, int flow)
{
struct n_tty_data *ldata = tty->disc_data;
int room, n, rcvd = 0, overflow;
@@ -1654,7 +1665,7 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,

/* ignore parity errors if handling overflow */
if (!overflow || !fp || *fp != TTY_PARITY)
- __receive_buf(tty, cp, fp, n);
+ __receive_buf(tty, cp, fp, n, lookahead_count);

cp += n;
if (fp)
@@ -1681,15 +1692,15 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
}

static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count)
+ const char *fp, int count, unsigned int lookahead_count)
{
- n_tty_receive_buf_common(tty, cp, fp, count, 0);
+ n_tty_receive_buf_common(tty, cp, fp, count, lookahead_count, 0);
}

static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count)
+ const char *fp, int count, unsigned int lookahead_count)
{
- return n_tty_receive_buf_common(tty, cp, fp, count, 1);
+ return n_tty_receive_buf_common(tty, cp, fp, count, lookahead_count, 1);
}

/**
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index d367803e2044..087e081e8e59 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -23,7 +23,8 @@ struct serport {
*/

static int ttyport_receive_buf(struct tty_port *port, const unsigned char *cp,
- const unsigned char *fp, size_t count)
+ const unsigned char *fp, size_t count,
+ unsigned int lookahead_count)
{
struct serdev_controller *ctrl = port->client_data;
struct serport *serport = serdev_controller_get_drvdata(ctrl);
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 25c558e65ece..a669e6e13f90 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -582,7 +582,7 @@ static void ldisc_receive_buf(struct tty_struct *tty,
ld = tty_ldisc_ref(tty);
if (ld) {
if (ld->ops->receive_buf)
- ld->ops->receive_buf(tty, data, flags, count);
+ ld->ops->receive_buf(tty, data, flags, count, 0);
tty_ldisc_deref(ld);
}
}
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 646510476c30..c561110c7d4d 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -445,14 +445,14 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
* Returns: the number of bytes processed.
*/
int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
- const char *f, int count)
+ const char *f, int count, unsigned int lookahead_count)
{
if (ld->ops->receive_buf2)
- count = ld->ops->receive_buf2(ld->tty, p, f, count);
+ count = ld->ops->receive_buf2(ld->tty, p, f, count, lookahead_count);
else {
count = min_t(int, count, ld->tty->receive_room);
if (count && ld->ops->receive_buf)
- ld->ops->receive_buf(ld->tty, p, f, count);
+ ld->ops->receive_buf(ld->tty, p, f, count, lookahead_count);
}
return count;
}
@@ -468,7 +468,7 @@ receive_buf(struct tty_port *port, struct tty_buffer *head, int count)
if (~head->flags & TTYB_NORMAL)
f = flag_buf_ptr(head, head->read);

- n = port->client_ops->receive_buf(port, p, f, count);
+ n = port->client_ops->receive_buf(port, p, f, count, 0);
if (n > 0)
memset(p, 0, n);
return n;
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 8fec1d8648f5..cd0b74a5ceb2 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -2290,7 +2290,7 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
return -EIO;
tty_buffer_lock_exclusive(tty->port);
if (ld->ops->receive_buf)
- ld->ops->receive_buf(tty, &ch, &mbz, 1);
+ ld->ops->receive_buf(tty, &ch, &mbz, 1, 0);
tty_buffer_unlock_exclusive(tty->port);
tty_ldisc_deref(ld);
return 0;
diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 880608a65773..45cbbf338f24 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -22,7 +22,8 @@

static int tty_port_default_receive_buf(struct tty_port *port,
const unsigned char *p,
- const unsigned char *f, size_t count)
+ const unsigned char *f, size_t count,
+ unsigned int lookahead_count)
{
int ret;
struct tty_struct *tty;
@@ -36,7 +37,7 @@ static int tty_port_default_receive_buf(struct tty_port *port,
if (!disc)
return 0;

- ret = tty_ldisc_receive_buf(disc, p, (char *)f, count);
+ ret = tty_ldisc_receive_buf(disc, p, (char *)f, count, lookahead_count);

tty_ldisc_deref(disc);

diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index f7755e73696e..abc3890ecc18 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -406,7 +406,7 @@ int paste_selection(struct tty_struct *tty)
__set_current_state(TASK_RUNNING);
count = vc_sel.buf_len - pasted;
count = tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL,
- count);
+ count, 0);
pasted += count;
}
mutex_unlock(&vc_sel.lock);
diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h
index 483d41cbcbb7..53725f6312c0 100644
--- a/include/linux/tty_flip.h
+++ b/include/linux/tty_flip.h
@@ -42,7 +42,7 @@ static inline int tty_insert_flip_string(struct tty_port *port,
}

int tty_ldisc_receive_buf(struct tty_ldisc *ld, const unsigned char *p,
- const char *f, int count);
+ const char *f, int count, unsigned int lookahead_count);

void tty_buffer_lock_exclusive(struct tty_port *port);
void tty_buffer_unlock_exclusive(struct tty_port *port);
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index e85002b56752..d81a39cff9e2 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -152,14 +152,17 @@ int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
* Can sleep.
*
* @receive_buf: [DRV] ``void ()(struct tty_struct *tty,
- * const unsigned char *cp, const char *fp, int count)``
+ * const unsigned char *cp, const char *fp, int count,
+ * unsigned int lookahead_count)``
*
* This function is called by the low-level tty driver to send characters
* received by the hardware to the line discpline for processing. @cp is
* a pointer to the buffer of input character received by the device. @fp
* is a pointer to an array of flag bytes which indicate whether a
* character was received with a parity error, etc. @fp may be %NULL to
- * indicate all data received is %TTY_NORMAL.
+ * indicate all data received is %TTY_NORMAL. The number of characters is
+ * indicated with @count and characters for which lookahead was already
+ * performed with @lookahead_count.
*
* @write_wakeup: [DRV] ``void ()(struct tty_struct *tty)``
*
@@ -176,15 +179,18 @@ int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
* exclusively by the %N_PPS (Pulse-Per-Second) line discipline.
*
* @receive_buf2: [DRV] ``int ()(struct tty_struct *tty,
- * const unsigned char *cp, const char *fp, int count)``
+ * const unsigned char *cp, const char *fp, int count,
+ * unsigned int lookahead_count)``
*
* This function is called by the low-level tty driver to send characters
* received by the hardware to the line discpline for processing. @cp is a
* pointer to the buffer of input character received by the device. @fp
* is a pointer to an array of flag bytes which indicate whether a
* character was 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.
+ * indicate all data received is %TTY_NORMAL. The number of characters is
+ * indicated with @count and characters for which lookahead was already
+ * performed with @lookahead_count. If assigned, prefer this function for
+ * automatic flow control.
*
* @owner: module containting this ldisc (for reference counting)
*
@@ -224,11 +230,11 @@ struct tty_ldisc_ops {
* The following routines are called from below.
*/
void (*receive_buf)(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count);
+ const char *fp, int count, unsigned int lookahead_count);
void (*write_wakeup)(struct tty_struct *tty);
void (*dcd_change)(struct tty_struct *tty, unsigned int status);
int (*receive_buf2)(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count);
+ const char *fp, int count, unsigned int lookahead_count);

struct module *owner;
};
diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h
index 58e9619116b7..402470962d23 100644
--- a/include/linux/tty_port.h
+++ b/include/linux/tty_port.h
@@ -39,7 +39,8 @@ struct tty_port_operations {
};

struct tty_port_client_operations {
- int (*receive_buf)(struct tty_port *port, const unsigned char *, const unsigned char *, size_t);
+ int (*receive_buf)(struct tty_port *port, const unsigned char *,
+ const unsigned char *, size_t, unsigned int lookahead_count);
void (*write_wakeup)(struct tty_port *port);
};

diff --git a/net/nfc/nci/uart.c b/net/nfc/nci/uart.c
index cc8fa9e36159..1daa9cf7eec8 100644
--- a/net/nfc/nci/uart.c
+++ b/net/nfc/nci/uart.c
@@ -296,7 +296,7 @@ static int nci_uart_default_recv_buf(struct nci_uart *nu, const u8 *data,
* Return Value: None
*/
static void nci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
- const char *flags, int count)
+ const char *flags, int count, unsigned int lookahead_count)
{
struct nci_uart *nu = (void *)tty->disc_data;

diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index 1af0bf5f1e2f..ad86970ad369 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -259,7 +259,7 @@ static void v253_hangup(struct tty_struct *tty)

/* Line discipline .receive_buf() */
static void v253_receive(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count)
+ const char *fp, int count, unsigned int lookahead_count)
{
struct snd_soc_component *component = tty->disc_data;
struct cx20442_priv *cx20442;
diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c
index b1a32545babd..fd9694377e3b 100644
--- a/sound/soc/ti/ams-delta.c
+++ b/sound/soc/ti/ams-delta.c
@@ -337,7 +337,7 @@ static void cx81801_hangup(struct tty_struct *tty)

/* Line discipline .receive_buf() */
static void cx81801_receive(struct tty_struct *tty, const unsigned char *cp,
- const char *fp, int count)
+ const char *fp, int count, unsigned int lookahead_count)
{
struct snd_soc_component *component = tty->disc_data;
const unsigned char *c;
--
2.30.2