mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
TTY/Serial driver fixes for 5.17-rc6
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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYhjWlA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ylUvgCeKicl7AbY+7/eYmRhaCisJhgzf8UAmQHA7RWB HwcKv7yb49UYJHhbTyis =F9Sx -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
d8fc3bb606
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user