Commit d8fc3bb6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull tty/serial driver fixes from Greg KH:
 "Here are some small n_gsm and sc16is7xx serial driver fixes for
  5.17-rc6.

  The n_gsm fixes are from Siemens as it seems they are using the line
  discipline and fixing up a number of issues they found in their
  testing. The sc16is7xx serial driver fix is for a reported problem
  with that chip.

  All of these have been in linux-next with no reported problems"

* tag 'tty-5.17-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  sc16is7xx: Fix for incorrect data being transmitted
  tty: n_gsm: fix deadlock in gsmtty_open()
  tty: n_gsm: fix wrong modem processing in convergence layer type 2
  tty: n_gsm: fix wrong tty control line for flow control
  tty: n_gsm: fix NULL pointer access due to DLCI release
  tty: n_gsm: fix proper link termination after failed open
  tty: n_gsm: fix encoding of command/response bit
  tty: n_gsm: fix encoding of control signal octet bit DV
parents 548b1af4 eebb0f4e
Loading
Loading
Loading
Loading
+39 −22
Original line number Diff line number Diff line
@@ -439,7 +439,7 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
		modembits |= MDM_RTR;
	if (dlci->modem_tx & TIOCM_RI)
		modembits |= MDM_IC;
	if (dlci->modem_tx & TIOCM_CD)
	if (dlci->modem_tx & TIOCM_CD || dlci->gsm->initiator)
		modembits |= MDM_DV;
	return modembits;
}
@@ -448,7 +448,7 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
 *	gsm_print_packet	-	display a frame for debug
 *	@hdr: header to print before decode
 *	@addr: address EA from the frame
 *	@cr: C/R bit from the frame
 *	@cr: C/R bit seen as initiator
 *	@control: control including PF bit
 *	@data: following data bytes
 *	@dlen: length of data
@@ -548,7 +548,7 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
 *	gsm_send	-	send a control frame
 *	@gsm: our GSM mux
 *	@addr: address for control frame
 *	@cr: command/response bit
 *	@cr: command/response bit seen as initiator
 *	@control:  control byte including PF bit
 *
 *	Format up and transmit a control frame. These do not go via the
@@ -563,11 +563,15 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
	int len;
	u8 cbuf[10];
	u8 ibuf[3];
	int ocr;

	/* toggle C/R coding if not initiator */
	ocr = cr ^ (gsm->initiator ? 0 : 1);

	switch (gsm->encoding) {
	case 0:
		cbuf[0] = GSM0_SOF;
		cbuf[1] = (addr << 2) | (cr << 1) | EA;
		cbuf[1] = (addr << 2) | (ocr << 1) | EA;
		cbuf[2] = control;
		cbuf[3] = EA;	/* Length of data = 0 */
		cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3);
@@ -577,7 +581,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
	case 1:
	case 2:
		/* Control frame + packing (but not frame stuffing) in mode 1 */
		ibuf[0] = (addr << 2) | (cr << 1) | EA;
		ibuf[0] = (addr << 2) | (ocr << 1) | EA;
		ibuf[1] = control;
		ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
		/* Stuffing may double the size worst case */
@@ -611,7 +615,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)

static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
{
	gsm_send(gsm, addr, 1, control);
	gsm_send(gsm, addr, 0, control);
}

/**
@@ -1017,25 +1021,25 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data,
 *	@tty: virtual tty bound to the DLCI
 *	@dlci: DLCI to affect
 *	@modem: modem bits (full EA)
 *	@clen: command length
 *	@slen: number of signal octets
 *
 *	Used when a modem control message or line state inline in adaption
 *	layer 2 is processed. Sort out the local modem state and throttles
 */

static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
							u32 modem, int clen)
							u32 modem, int slen)
{
	int  mlines = 0;
	u8 brk = 0;
	int fc;

	/* The modem status command can either contain one octet (v.24 signals)
	   or two octets (v.24 signals + break signals). The length field will
	   either be 2 or 3 respectively. This is specified in section
	   5.4.6.3.7 of the  27.010 mux spec. */
	/* The modem status command can either contain one octet (V.24 signals)
	 * or two octets (V.24 signals + break signals). This is specified in
	 * section 5.4.6.3.7 of the 07.10 mux spec.
	 */

	if (clen == 2)
	if (slen == 1)
		modem = modem & 0x7f;
	else {
		brk = modem & 0x7f;
@@ -1092,6 +1096,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
	unsigned int brk = 0;
	struct gsm_dlci *dlci;
	int len = clen;
	int slen;
	const u8 *dp = data;
	struct tty_struct *tty;

@@ -1111,6 +1116,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
		return;
	dlci = gsm->dlci[addr];

	slen = len;
	while (gsm_read_ea(&modem, *dp++) == 0) {
		len--;
		if (len == 0)
@@ -1127,7 +1133,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
		modem |= (brk & 0x7f);
	}
	tty = tty_port_tty_get(&dlci->port);
	gsm_process_modem(tty, dlci, modem, clen);
	gsm_process_modem(tty, dlci, modem, slen);
	if (tty) {
		tty_wakeup(tty);
		tty_kref_put(tty);
@@ -1451,6 +1457,9 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
	if (dlci->addr != 0) {
		tty_port_tty_hangup(&dlci->port, false);
		kfifo_reset(&dlci->fifo);
		/* Ensure that gsmtty_open() can return. */
		tty_port_set_initialized(&dlci->port, 0);
		wake_up_interruptible(&dlci->port.open_wait);
	} else
		dlci->gsm->dead = true;
	/* Unregister gsmtty driver,report gsmtty dev remove uevent for user */
@@ -1514,7 +1523,7 @@ static void gsm_dlci_t1(struct timer_list *t)
			dlci->mode = DLCI_MODE_ADM;
			gsm_dlci_open(dlci);
		} else {
			gsm_dlci_close(dlci);
			gsm_dlci_begin_close(dlci); /* prevent half open link */
		}

		break;
@@ -1593,6 +1602,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
	struct tty_struct *tty;
	unsigned int modem = 0;
	int len = clen;
	int slen = 0;

	if (debug & 16)
		pr_debug("%d bytes for tty\n", len);
@@ -1605,12 +1615,14 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
	case 2:		/* Asynchronous serial with line state in each frame */
		while (gsm_read_ea(&modem, *data++) == 0) {
			len--;
			slen++;
			if (len == 0)
				return;
		}
		slen++;
		tty = tty_port_tty_get(port);
		if (tty) {
			gsm_process_modem(tty, dlci, modem, clen);
			gsm_process_modem(tty, dlci, modem, slen);
			tty_kref_put(tty);
		}
		fallthrough;
@@ -1748,7 +1760,12 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)
		gsm_destroy_network(dlci);
		mutex_unlock(&dlci->mutex);

		tty_hangup(tty);
		/* We cannot use tty_hangup() because in tty_kref_put() the tty
		 * driver assumes that the hangup queue is free and reuses it to
		 * queue release_one_tty() -> NULL pointer panic in
		 * process_one_work().
		 */
		tty_vhangup(tty);

		tty_port_tty_set(&dlci->port, NULL);
		tty_kref_put(tty);
@@ -1800,10 +1817,10 @@ static void gsm_queue(struct gsm_mux *gsm)
		goto invalid;

	cr = gsm->address & 1;		/* C/R bit */
	cr ^= gsm->initiator ? 0 : 1;	/* Flip so 1 always means command */

	gsm_print_packet("<--", address, cr, gsm->control, gsm->buf, gsm->len);

	cr ^= 1 - gsm->initiator;	/* Flip so 1 always means command */
	dlci = gsm->dlci[address];

	switch (gsm->control) {
@@ -3234,9 +3251,9 @@ static void gsmtty_throttle(struct tty_struct *tty)
	if (dlci->state == DLCI_CLOSED)
		return;
	if (C_CRTSCTS(tty))
		dlci->modem_tx &= ~TIOCM_DTR;
		dlci->modem_tx &= ~TIOCM_RTS;
	dlci->throttled = true;
	/* Send an MSC with DTR cleared */
	/* Send an MSC with RTS cleared */
	gsmtty_modem_update(dlci, 0);
}

@@ -3246,9 +3263,9 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
	if (dlci->state == DLCI_CLOSED)
		return;
	if (C_CRTSCTS(tty))
		dlci->modem_tx |= TIOCM_DTR;
		dlci->modem_tx |= TIOCM_RTS;
	dlci->throttled = false;
	/* Send an MSC with DTR set */
	/* Send an MSC with RTS set */
	gsmtty_modem_update(dlci, 0);
}

+3 −0
Original line number Diff line number Diff line
@@ -734,12 +734,15 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
static void sc16is7xx_tx_proc(struct kthread_work *ws)
{
	struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
	struct sc16is7xx_port *s = dev_get_drvdata(port->dev);

	if ((port->rs485.flags & SER_RS485_ENABLED) &&
	    (port->rs485.delay_rts_before_send > 0))
		msleep(port->rs485.delay_rts_before_send);

	mutex_lock(&s->efr_lock);
	sc16is7xx_handle_tx(port);
	mutex_unlock(&s->efr_lock);
}

static void sc16is7xx_reconf_rs485(struct uart_port *port)