diff options
author | Tilman Schmidt <tilman@imap.cc> | 2010-09-30 09:35:31 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-10-01 03:33:36 -0400 |
commit | 4cb5e42f6132bf2d2851f8dd67bd8499979c7ebc (patch) | |
tree | e10706e5895042010a63959dd3c48412b1c22a8b /drivers/isdn | |
parent | 60798c68bebf6009df9da634e79ebdd8c8227238 (diff) |
isdn/gigaset: unclog bas_gigaset AT response pipe
Recover from a lost HD_RECEIVEATDATA_ACK message by sending a
zero-length HD_READ_ATMESSAGE command when ev_layer sends "+++".
Signed-off-by: Tilman Schmidt <tilman@imap.cc>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn')
-rw-r--r-- | drivers/isdn/gigaset/bas-gigaset.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 7520bc6f3871..540f6d0bb754 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c | |||
@@ -1896,6 +1896,28 @@ static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb) | |||
1896 | * The next command will reopen the AT channel automatically. | 1896 | * The next command will reopen the AT channel automatically. |
1897 | */ | 1897 | */ |
1898 | if (cb->len == 3 && !memcmp(cb->buf, "+++", 3)) { | 1898 | if (cb->len == 3 && !memcmp(cb->buf, "+++", 3)) { |
1899 | /* If an HD_RECEIVEATDATA_ACK message remains unhandled | ||
1900 | * because of an error, the base never sends another one. | ||
1901 | * The response channel is thus effectively blocked. | ||
1902 | * Closing and reopening the AT channel does *not* clear | ||
1903 | * this condition. | ||
1904 | * As a stopgap measure, submit a zero-length AT read | ||
1905 | * before closing the AT channel. This has the undocumented | ||
1906 | * effect of triggering a new HD_RECEIVEATDATA_ACK message | ||
1907 | * from the base if necessary. | ||
1908 | * The subsequent AT channel close then discards any pending | ||
1909 | * messages. | ||
1910 | */ | ||
1911 | spin_lock_irqsave(&cs->lock, flags); | ||
1912 | if (!(cs->hw.bas->basstate & BS_ATRDPEND)) { | ||
1913 | kfree(cs->hw.bas->rcvbuf); | ||
1914 | cs->hw.bas->rcvbuf = NULL; | ||
1915 | cs->hw.bas->rcvbuf_size = 0; | ||
1916 | cs->hw.bas->retry_cmd_in = 0; | ||
1917 | atread_submit(cs, 0); | ||
1918 | } | ||
1919 | spin_unlock_irqrestore(&cs->lock, flags); | ||
1920 | |||
1899 | rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT); | 1921 | rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT); |
1900 | if (cb->wake_tasklet) | 1922 | if (cb->wake_tasklet) |
1901 | tasklet_schedule(cb->wake_tasklet); | 1923 | tasklet_schedule(cb->wake_tasklet); |