Commit d8fc3bb6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'tty-5.17-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

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
...@@ -439,7 +439,7 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci) ...@@ -439,7 +439,7 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
modembits |= MDM_RTR; modembits |= MDM_RTR;
if (dlci->modem_tx & TIOCM_RI) if (dlci->modem_tx & TIOCM_RI)
modembits |= MDM_IC; modembits |= MDM_IC;
if (dlci->modem_tx & TIOCM_CD) if (dlci->modem_tx & TIOCM_CD || dlci->gsm->initiator)
modembits |= MDM_DV; modembits |= MDM_DV;
return modembits; return modembits;
} }
...@@ -448,7 +448,7 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci) ...@@ -448,7 +448,7 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
* gsm_print_packet - display a frame for debug * gsm_print_packet - display a frame for debug
* @hdr: header to print before decode * @hdr: header to print before decode
* @addr: address EA from the frame * @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 * @control: control including PF bit
* @data: following data bytes * @data: following data bytes
* @dlen: length of data * @dlen: length of data
...@@ -548,7 +548,7 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len) ...@@ -548,7 +548,7 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
* gsm_send - send a control frame * gsm_send - send a control frame
* @gsm: our GSM mux * @gsm: our GSM mux
* @addr: address for control frame * @addr: address for control frame
* @cr: command/response bit * @cr: command/response bit seen as initiator
* @control: control byte including PF bit * @control: control byte including PF bit
* *
* Format up and transmit a control frame. These do not go via the * 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) ...@@ -563,11 +563,15 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
int len; int len;
u8 cbuf[10]; u8 cbuf[10];
u8 ibuf[3]; u8 ibuf[3];
int ocr;
/* toggle C/R coding if not initiator */
ocr = cr ^ (gsm->initiator ? 0 : 1);
switch (gsm->encoding) { switch (gsm->encoding) {
case 0: case 0:
cbuf[0] = GSM0_SOF; cbuf[0] = GSM0_SOF;
cbuf[1] = (addr << 2) | (cr << 1) | EA; cbuf[1] = (addr << 2) | (ocr << 1) | EA;
cbuf[2] = control; cbuf[2] = control;
cbuf[3] = EA; /* Length of data = 0 */ cbuf[3] = EA; /* Length of data = 0 */
cbuf[4] = 0xFF - gsm_fcs_add_block(INIT_FCS, cbuf + 1, 3); 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) ...@@ -577,7 +581,7 @@ static void gsm_send(struct gsm_mux *gsm, int addr, int cr, int control)
case 1: case 1:
case 2: case 2:
/* Control frame + packing (but not frame stuffing) in mode 1 */ /* 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[1] = control;
ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2); ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
/* Stuffing may double the size worst case */ /* 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) ...@@ -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) 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, ...@@ -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 * @tty: virtual tty bound to the DLCI
* @dlci: DLCI to affect * @dlci: DLCI to affect
* @modem: modem bits (full EA) * @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 * Used when a modem control message or line state inline in adaption
* layer 2 is processed. Sort out the local modem state and throttles * 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, static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
u32 modem, int clen) u32 modem, int slen)
{ {
int mlines = 0; int mlines = 0;
u8 brk = 0; u8 brk = 0;
int fc; int fc;
/* The modem status command can either contain one octet (v.24 signals) /* The modem status command can either contain one octet (V.24 signals)
or two octets (v.24 signals + break signals). The length field will * or two octets (V.24 signals + break signals). This is specified in
either be 2 or 3 respectively. This is specified in section * section 5.4.6.3.7 of the 07.10 mux spec.
5.4.6.3.7 of the 27.010 mux spec. */ */
if (clen == 2) if (slen == 1)
modem = modem & 0x7f; modem = modem & 0x7f;
else { else {
brk = modem & 0x7f; brk = modem & 0x7f;
...@@ -1092,6 +1096,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen) ...@@ -1092,6 +1096,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
unsigned int brk = 0; unsigned int brk = 0;
struct gsm_dlci *dlci; struct gsm_dlci *dlci;
int len = clen; int len = clen;
int slen;
const u8 *dp = data; const u8 *dp = data;
struct tty_struct *tty; struct tty_struct *tty;
...@@ -1111,6 +1116,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen) ...@@ -1111,6 +1116,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
return; return;
dlci = gsm->dlci[addr]; dlci = gsm->dlci[addr];
slen = len;
while (gsm_read_ea(&modem, *dp++) == 0) { while (gsm_read_ea(&modem, *dp++) == 0) {
len--; len--;
if (len == 0) if (len == 0)
...@@ -1127,7 +1133,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen) ...@@ -1127,7 +1133,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
modem |= (brk & 0x7f); modem |= (brk & 0x7f);
} }
tty = tty_port_tty_get(&dlci->port); tty = tty_port_tty_get(&dlci->port);
gsm_process_modem(tty, dlci, modem, clen); gsm_process_modem(tty, dlci, modem, slen);
if (tty) { if (tty) {
tty_wakeup(tty); tty_wakeup(tty);
tty_kref_put(tty); tty_kref_put(tty);
...@@ -1451,6 +1457,9 @@ static void gsm_dlci_close(struct gsm_dlci *dlci) ...@@ -1451,6 +1457,9 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
if (dlci->addr != 0) { if (dlci->addr != 0) {
tty_port_tty_hangup(&dlci->port, false); tty_port_tty_hangup(&dlci->port, false);
kfifo_reset(&dlci->fifo); 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 } else
dlci->gsm->dead = true; dlci->gsm->dead = true;
/* Unregister gsmtty driver,report gsmtty dev remove uevent for user */ /* Unregister gsmtty driver,report gsmtty dev remove uevent for user */
...@@ -1514,7 +1523,7 @@ static void gsm_dlci_t1(struct timer_list *t) ...@@ -1514,7 +1523,7 @@ static void gsm_dlci_t1(struct timer_list *t)
dlci->mode = DLCI_MODE_ADM; dlci->mode = DLCI_MODE_ADM;
gsm_dlci_open(dlci); gsm_dlci_open(dlci);
} else { } else {
gsm_dlci_close(dlci); gsm_dlci_begin_close(dlci); /* prevent half open link */
} }
break; break;
...@@ -1593,6 +1602,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen) ...@@ -1593,6 +1602,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen)
struct tty_struct *tty; struct tty_struct *tty;
unsigned int modem = 0; unsigned int modem = 0;
int len = clen; int len = clen;
int slen = 0;
if (debug & 16) if (debug & 16)
pr_debug("%d bytes for tty\n", len); 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) ...@@ -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 */ case 2: /* Asynchronous serial with line state in each frame */
while (gsm_read_ea(&modem, *data++) == 0) { while (gsm_read_ea(&modem, *data++) == 0) {
len--; len--;
slen++;
if (len == 0) if (len == 0)
return; return;
} }
slen++;
tty = tty_port_tty_get(port); tty = tty_port_tty_get(port);
if (tty) { if (tty) {
gsm_process_modem(tty, dlci, modem, clen); gsm_process_modem(tty, dlci, modem, slen);
tty_kref_put(tty); tty_kref_put(tty);
} }
fallthrough; fallthrough;
...@@ -1748,7 +1760,12 @@ static void gsm_dlci_release(struct gsm_dlci *dlci) ...@@ -1748,7 +1760,12 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)
gsm_destroy_network(dlci); gsm_destroy_network(dlci);
mutex_unlock(&dlci->mutex); 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_port_tty_set(&dlci->port, NULL);
tty_kref_put(tty); tty_kref_put(tty);
...@@ -1800,10 +1817,10 @@ static void gsm_queue(struct gsm_mux *gsm) ...@@ -1800,10 +1817,10 @@ static void gsm_queue(struct gsm_mux *gsm)
goto invalid; goto invalid;
cr = gsm->address & 1; /* C/R bit */ 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); 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]; dlci = gsm->dlci[address];
switch (gsm->control) { switch (gsm->control) {
...@@ -3234,9 +3251,9 @@ static void gsmtty_throttle(struct tty_struct *tty) ...@@ -3234,9 +3251,9 @@ static void gsmtty_throttle(struct tty_struct *tty)
if (dlci->state == DLCI_CLOSED) if (dlci->state == DLCI_CLOSED)
return; return;
if (C_CRTSCTS(tty)) if (C_CRTSCTS(tty))
dlci->modem_tx &= ~TIOCM_DTR; dlci->modem_tx &= ~TIOCM_RTS;
dlci->throttled = true; dlci->throttled = true;
/* Send an MSC with DTR cleared */ /* Send an MSC with RTS cleared */
gsmtty_modem_update(dlci, 0); gsmtty_modem_update(dlci, 0);
} }
...@@ -3246,9 +3263,9 @@ static void gsmtty_unthrottle(struct tty_struct *tty) ...@@ -3246,9 +3263,9 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
if (dlci->state == DLCI_CLOSED) if (dlci->state == DLCI_CLOSED)
return; return;
if (C_CRTSCTS(tty)) if (C_CRTSCTS(tty))
dlci->modem_tx |= TIOCM_DTR; dlci->modem_tx |= TIOCM_RTS;
dlci->throttled = false; dlci->throttled = false;
/* Send an MSC with DTR set */ /* Send an MSC with RTS set */
gsmtty_modem_update(dlci, 0); gsmtty_modem_update(dlci, 0);
} }
......
...@@ -734,12 +734,15 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) ...@@ -734,12 +734,15 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
static void sc16is7xx_tx_proc(struct kthread_work *ws) static void sc16is7xx_tx_proc(struct kthread_work *ws)
{ {
struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port); 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) && if ((port->rs485.flags & SER_RS485_ENABLED) &&
(port->rs485.delay_rts_before_send > 0)) (port->rs485.delay_rts_before_send > 0))
msleep(port->rs485.delay_rts_before_send); msleep(port->rs485.delay_rts_before_send);
mutex_lock(&s->efr_lock);
sc16is7xx_handle_tx(port); sc16is7xx_handle_tx(port);
mutex_unlock(&s->efr_lock);
} }
static void sc16is7xx_reconf_rs485(struct uart_port *port) static void sc16is7xx_reconf_rs485(struct uart_port *port)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment