summaryrefslogtreecommitdiff
path: root/drivers/tty/n_gsm.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-10-26 15:11:09 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2011-10-26 15:11:09 +0200
commitefb8d21b2c6db3497655cc6a033ae8a9883e4063 (patch)
treea14a0dbb9fec3a6db5e542ba7ed4a49681706420 /drivers/tty/n_gsm.c
parent3cb603284b3d256ae9ae9e65887cee8416bfef15 (diff)
parentd208a3bf77f902283894f546b6b5383202cf7882 (diff)
Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (79 commits) TTY: serial_core: Fix crash if DCD drop during suspend tty/serial: atmel_serial: bootconsole removed from auto-enumerates Revert "TTY: call tty_driver_lookup_tty unconditionally" tty/serial: atmel_serial: add device tree support tty/serial: atmel_serial: auto-enumerate ports tty/serial: atmel_serial: whitespace and braces modifications tty/serial: atmel_serial: change platform_data variable name tty/serial: RS485 bindings for device tree TTY: call tty_driver_lookup_tty unconditionally TTY: pty, release tty in all ptmx_open fail paths TTY: make tty_add_file non-failing TTY: drop driver reference in tty_open fail path 8250_pci: Fix kernel panic when pch_uart is disabled h8300: drivers/serial/Kconfig was moved parport_pc: release IO region properly if unsupported ITE887x card is found tty: Support compat_ioctl get/set termios_locked hvc_console: display printk messages on console. TTY: snyclinkmp: forever loop in tx_load_dma_buffer() tty/n_gsm: avoid fifo overflow in gsm_dlci_data_output tty/n_gsm: fix a bug in gsm_dlci_data_output (adaption = 2 case) ... Fix up Conflicts in: - drivers/tty/serial/8250_pci.c Trivial conflict with removed duplicate device ID - drivers/tty/serial/atmel_serial.c Annoying silly conflict between "specify the port num via platform_data" and other changes to atmel_console_init
Diffstat (limited to 'drivers/tty/n_gsm.c')
-rw-r--r--drivers/tty/n_gsm.c70
1 files changed, 40 insertions, 30 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 8a50e4eebf18..4cb0d0a3e57b 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -21,7 +21,6 @@
* Mostly done: ioctls for setting modes/timing
* Partly done: hooks so you can pull off frames to non tty devs
* Restart DLCI 0 when it closes ?
- * Test basic encoding
* Improve the tx engine
* Resolve tx side locking by adding a queue_head and routing
* all control traffic via it
@@ -810,38 +809,41 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
{
struct gsm_msg *msg;
u8 *dp;
- int len, size;
+ int len, total_size, size;
int h = dlci->adaption - 1;
- len = kfifo_len(dlci->fifo);
- if (len == 0)
- return 0;
-
- /* MTU/MRU count only the data bits */
- if (len > gsm->mtu)
- len = gsm->mtu;
-
- size = len + h;
-
- msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
- /* FIXME: need a timer or something to kick this so it can't
- get stuck with no work outstanding and no buffer free */
- if (msg == NULL)
- return -ENOMEM;
- dp = msg->data;
- switch (dlci->adaption) {
- case 1: /* Unstructured */
- break;
- case 2: /* Unstructed with modem bits. Always one byte as we never
- send inline break data */
- *dp += gsm_encode_modem(dlci);
- len--;
- break;
+ total_size = 0;
+ while(1) {
+ len = kfifo_len(dlci->fifo);
+ if (len == 0)
+ return total_size;
+
+ /* MTU/MRU count only the data bits */
+ if (len > gsm->mtu)
+ len = gsm->mtu;
+
+ size = len + h;
+
+ msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype);
+ /* FIXME: need a timer or something to kick this so it can't
+ get stuck with no work outstanding and no buffer free */
+ if (msg == NULL)
+ return -ENOMEM;
+ dp = msg->data;
+ switch (dlci->adaption) {
+ case 1: /* Unstructured */
+ break;
+ case 2: /* Unstructed with modem bits. Always one byte as we never
+ send inline break data */
+ *dp++ = gsm_encode_modem(dlci);
+ break;
+ }
+ WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
+ __gsm_data_queue(dlci, msg);
+ total_size += size;
}
- WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len);
- __gsm_data_queue(dlci, msg);
/* Bytes of data we used up */
- return size;
+ return total_size;
}
/**
@@ -2004,6 +2006,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
int i;
struct gsm_dlci *dlci = gsm->dlci[0];
struct gsm_msg *txq;
+ struct gsm_control *gc;
gsm->dead = 1;
@@ -2017,6 +2020,13 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
spin_unlock(&gsm_mux_lock);
WARN_ON(i == MAX_MUX);
+ /* In theory disconnecting DLCI 0 is sufficient but for some
+ modems this is apparently not the case. */
+ if (dlci) {
+ gc = gsm_control_send(gsm, CMD_CLD, NULL, 0);
+ if (gc)
+ gsm_control_wait(gsm, gc);
+ }
del_timer_sync(&gsm->t2_timer);
/* Now we are sure T2 has stopped */
if (dlci) {
@@ -2982,7 +2992,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty,
struct gsm_dlci *dlci = tty->driver_data;
unsigned int modem_tx = dlci->modem_tx;
- modem_tx &= clear;
+ modem_tx &= ~clear;
modem_tx |= set;
if (modem_tx != dlci->modem_tx) {