Skip to content

Commit d8fc3bb

Browse files
committed
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
2 parents 548b1af + eebb0f4 commit d8fc3bb

2 files changed

Lines changed: 42 additions & 22 deletions

File tree

drivers/tty/n_gsm.c

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
439439
modembits |= MDM_RTR;
440440
if (dlci->modem_tx & TIOCM_RI)
441441
modembits |= MDM_IC;
442-
if (dlci->modem_tx & TIOCM_CD)
442+
if (dlci->modem_tx & TIOCM_CD || dlci->gsm->initiator)
443443
modembits |= MDM_DV;
444444
return modembits;
445445
}
@@ -448,7 +448,7 @@ static u8 gsm_encode_modem(const struct gsm_dlci *dlci)
448448
* gsm_print_packet - display a frame for debug
449449
* @hdr: header to print before decode
450450
* @addr: address EA from the frame
451-
* @cr: C/R bit from the frame
451+
* @cr: C/R bit seen as initiator
452452
* @control: control including PF bit
453453
* @data: following data bytes
454454
* @dlen: length of data
@@ -548,7 +548,7 @@ static int gsm_stuff_frame(const u8 *input, u8 *output, int len)
548548
* gsm_send - send a control frame
549549
* @gsm: our GSM mux
550550
* @addr: address for control frame
551-
* @cr: command/response bit
551+
* @cr: command/response bit seen as initiator
552552
* @control: control byte including PF bit
553553
*
554554
* 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)
563563
int len;
564564
u8 cbuf[10];
565565
u8 ibuf[3];
566+
int ocr;
567+
568+
/* toggle C/R coding if not initiator */
569+
ocr = cr ^ (gsm->initiator ? 0 : 1);
566570

567571
switch (gsm->encoding) {
568572
case 0:
569573
cbuf[0] = GSM0_SOF;
570-
cbuf[1] = (addr << 2) | (cr << 1) | EA;
574+
cbuf[1] = (addr << 2) | (ocr << 1) | EA;
571575
cbuf[2] = control;
572576
cbuf[3] = EA; /* Length of data = 0 */
573577
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)
577581
case 1:
578582
case 2:
579583
/* Control frame + packing (but not frame stuffing) in mode 1 */
580-
ibuf[0] = (addr << 2) | (cr << 1) | EA;
584+
ibuf[0] = (addr << 2) | (ocr << 1) | EA;
581585
ibuf[1] = control;
582586
ibuf[2] = 0xFF - gsm_fcs_add_block(INIT_FCS, ibuf, 2);
583587
/* 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)
611615

612616
static inline void gsm_response(struct gsm_mux *gsm, int addr, int control)
613617
{
614-
gsm_send(gsm, addr, 1, control);
618+
gsm_send(gsm, addr, 0, control);
615619
}
616620

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

10261030
static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
1027-
u32 modem, int clen)
1031+
u32 modem, int slen)
10281032
{
10291033
int mlines = 0;
10301034
u8 brk = 0;
10311035
int fc;
10321036

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

1038-
if (clen == 2)
1042+
if (slen == 1)
10391043
modem = modem & 0x7f;
10401044
else {
10411045
brk = modem & 0x7f;
@@ -1092,6 +1096,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
10921096
unsigned int brk = 0;
10931097
struct gsm_dlci *dlci;
10941098
int len = clen;
1099+
int slen;
10951100
const u8 *dp = data;
10961101
struct tty_struct *tty;
10971102

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

1119+
slen = len;
11141120
while (gsm_read_ea(&modem, *dp++) == 0) {
11151121
len--;
11161122
if (len == 0)
@@ -1127,7 +1133,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen)
11271133
modem |= (brk & 0x7f);
11281134
}
11291135
tty = tty_port_tty_get(&dlci->port);
1130-
gsm_process_modem(tty, dlci, modem, clen);
1136+
gsm_process_modem(tty, dlci, modem, slen);
11311137
if (tty) {
11321138
tty_wakeup(tty);
11331139
tty_kref_put(tty);
@@ -1451,6 +1457,9 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
14511457
if (dlci->addr != 0) {
14521458
tty_port_tty_hangup(&dlci->port, false);
14531459
kfifo_reset(&dlci->fifo);
1460+
/* Ensure that gsmtty_open() can return. */
1461+
tty_port_set_initialized(&dlci->port, 0);
1462+
wake_up_interruptible(&dlci->port.open_wait);
14541463
} else
14551464
dlci->gsm->dead = true;
14561465
/* Unregister gsmtty driver,report gsmtty dev remove uevent for user */
@@ -1514,7 +1523,7 @@ static void gsm_dlci_t1(struct timer_list *t)
15141523
dlci->mode = DLCI_MODE_ADM;
15151524
gsm_dlci_open(dlci);
15161525
} else {
1517-
gsm_dlci_close(dlci);
1526+
gsm_dlci_begin_close(dlci); /* prevent half open link */
15181527
}
15191528

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

15971607
if (debug & 16)
15981608
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)
16051615
case 2: /* Asynchronous serial with line state in each frame */
16061616
while (gsm_read_ea(&modem, *data++) == 0) {
16071617
len--;
1618+
slen++;
16081619
if (len == 0)
16091620
return;
16101621
}
1622+
slen++;
16111623
tty = tty_port_tty_get(port);
16121624
if (tty) {
1613-
gsm_process_modem(tty, dlci, modem, clen);
1625+
gsm_process_modem(tty, dlci, modem, slen);
16141626
tty_kref_put(tty);
16151627
}
16161628
fallthrough;
@@ -1748,7 +1760,12 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)
17481760
gsm_destroy_network(dlci);
17491761
mutex_unlock(&dlci->mutex);
17501762

1751-
tty_hangup(tty);
1763+
/* We cannot use tty_hangup() because in tty_kref_put() the tty
1764+
* driver assumes that the hangup queue is free and reuses it to
1765+
* queue release_one_tty() -> NULL pointer panic in
1766+
* process_one_work().
1767+
*/
1768+
tty_vhangup(tty);
17521769

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

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

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

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

18091826
switch (gsm->control) {
@@ -3234,9 +3251,9 @@ static void gsmtty_throttle(struct tty_struct *tty)
32343251
if (dlci->state == DLCI_CLOSED)
32353252
return;
32363253
if (C_CRTSCTS(tty))
3237-
dlci->modem_tx &= ~TIOCM_DTR;
3254+
dlci->modem_tx &= ~TIOCM_RTS;
32383255
dlci->throttled = true;
3239-
/* Send an MSC with DTR cleared */
3256+
/* Send an MSC with RTS cleared */
32403257
gsmtty_modem_update(dlci, 0);
32413258
}
32423259

@@ -3246,9 +3263,9 @@ static void gsmtty_unthrottle(struct tty_struct *tty)
32463263
if (dlci->state == DLCI_CLOSED)
32473264
return;
32483265
if (C_CRTSCTS(tty))
3249-
dlci->modem_tx |= TIOCM_DTR;
3266+
dlci->modem_tx |= TIOCM_RTS;
32503267
dlci->throttled = false;
3251-
/* Send an MSC with DTR set */
3268+
/* Send an MSC with RTS set */
32523269
gsmtty_modem_update(dlci, 0);
32533270
}
32543271

drivers/tty/serial/sc16is7xx.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,12 +734,15 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
734734
static void sc16is7xx_tx_proc(struct kthread_work *ws)
735735
{
736736
struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
737+
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
737738

738739
if ((port->rs485.flags & SER_RS485_ENABLED) &&
739740
(port->rs485.delay_rts_before_send > 0))
740741
msleep(port->rs485.delay_rts_before_send);
741742

743+
mutex_lock(&s->efr_lock);
742744
sc16is7xx_handle_tx(port);
745+
mutex_unlock(&s->efr_lock);
743746
}
744747

745748
static void sc16is7xx_reconf_rs485(struct uart_port *port)

0 commit comments

Comments
 (0)