patch-2.1.42 linux/drivers/isdn/isdn_tty.c
Next file: linux/drivers/isdn/isdn_tty.h
Previous file: linux/drivers/isdn/isdn_ppp.c
Back to the patch index
Back to the overall index
- Lines: 1114
- Date:
Wed May 28 10:49:09 1997
- Orig file:
v2.1.41/linux/drivers/isdn/isdn_tty.c
- Orig date:
Thu Feb 27 10:57:30 1997
diff -u --recursive --new-file v2.1.41/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.29 1997/02/16 12:11:51 fritz Exp $
+/* $Id: isdn_tty.c,v 1.41 1997/05/27 15:17:31 fritz Exp $
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
@@ -20,6 +20,55 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.c,v $
+ * Revision 1.41 1997/05/27 15:17:31 fritz
+ * Added changes for recent 2.1.x kernels:
+ * changed return type of isdn_close
+ * queue_task_* -> queue_task
+ * clear/set_bit -> test_and_... where apropriate.
+ * changed type of hard_header_cache parameter.
+ *
+ * Revision 1.40 1997/03/24 22:55:27 fritz
+ * Added debug code for status callbacks.
+ *
+ * Revision 1.39 1997/03/21 18:25:56 fritz
+ * Corrected CTS handling.
+ *
+ * Revision 1.38 1997/03/07 12:13:35 fritz
+ * Bugfix: Send audio in adpcm format was broken.
+ * Bugfix: CTS handling was wrong.
+ *
+ * Revision 1.37 1997/03/07 01:37:34 fritz
+ * Bugfix: Did not compile with CONFIG_ISDN_AUDIO disabled.
+ * Bugfix: isdn_tty_tint() did not handle lowlevel errors correctly.
+ * Bugfix: conversion was wrong when sending ulaw audio.
+ * Added proper ifdef's for CONFIG_ISDN_AUDIO
+ *
+ * Revision 1.36 1997/03/04 21:41:55 fritz
+ * Fix: Excessive stack usage of isdn_tty_senddown()
+ * and isdn_tty_end_vrx() could lead to problems.
+ *
+ * Revision 1.35 1997/03/02 19:05:52 fritz
+ * Bugfix: Avoid recursion.
+ *
+ * Revision 1.34 1997/03/02 14:29:22 fritz
+ * More ttyI related cleanup.
+ *
+ * Revision 1.33 1997/02/28 02:32:45 fritz
+ * Cleanup: Moved some tty related stuff from isdn_common.c
+ * to isdn_tty.c
+ * Bugfix: Bisync protocol did not behave like documented.
+ *
+ * Revision 1.32 1997/02/23 15:43:03 fritz
+ * Small change in handling of incoming calls
+ * documented in newest version of ttyI.4
+ *
+ * Revision 1.31 1997/02/21 13:05:57 fritz
+ * Bugfix: Remote hangup did not set location-info on ttyI's
+ *
+ * Revision 1.30 1997/02/18 09:41:05 fritz
+ * Added support for bitwise access to modem registers (ATSx.y=n, ATSx.y?).
+ * Beautified output of AT&V.
+ *
* Revision 1.29 1997/02/16 12:11:51 fritz
* Added S13,Bit4 option.
*
@@ -136,6 +185,7 @@
* Initial revision
*
*/
+#undef ISDN_TTY_STAT_DEBUG
#define __NO_VERSION__
#include <linux/config.h>
@@ -157,6 +207,10 @@
static void isdn_tty_cmd_ATA(modem_info *);
static void isdn_tty_at_cout(char *, modem_info *);
static void isdn_tty_flush_buffer(struct tty_struct *);
+static void isdn_tty_modem_result(int, modem_info *);
+#ifdef CONFIG_ISDN_AUDIO
+static int isdn_tty_countDLE(unsigned char *, int);
+#endif
/* Leave this unchanged unless you know what you do! */
#define MODEM_PARANOIA_CHECK
@@ -169,13 +223,13 @@
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.29 $";
+char *isdn_tty_revision = "$Revision: 1.41 $";
#define DLE 0x10
#define ETX 0x03
#define DC4 0x14
-/* isdn_tty_try_read() is called from within isdn_receive_callback()
+/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
* to stuff incoming data directly into a tty's flip-buffer. This
* is done to speed up tty-receiving if the receive-queue is empty.
* This routine MUST be called with interrupts off.
@@ -184,7 +238,7 @@
* 0 = Failure, data has to be buffered and later processed by
* isdn_tty_readmodem().
*/
-int
+static int
isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
{
int c;
@@ -195,24 +249,32 @@
if ((tty = info->tty)) {
if (info->mcr & UART_MCR_RTS) {
c = TTY_FLIPBUF_SIZE - tty->flip.count;
- len = skb->len + ISDN_AUDIO_SKB_DLECOUNT(skb);
+ len = skb->len
+#ifdef CONFIG_ISDN_AUDIO
+ + ISDN_AUDIO_SKB_DLECOUNT(skb)
+#endif
+ ;
if (c >= len) {
+#ifdef CONFIG_ISDN_AUDIO
if (ISDN_AUDIO_SKB_DLECOUNT(skb))
while (skb->len--) {
if (*skb->data == DLE)
tty_insert_flip_char(tty, DLE, 0);
tty_insert_flip_char(tty, *skb->data++, 0);
} else {
+#endif
memcpy(tty->flip.char_buf_ptr,
skb->data, len);
tty->flip.count += len;
tty->flip.char_buf_ptr += len;
memset(tty->flip.flag_buf_ptr, 0, len);
tty->flip.flag_buf_ptr += len;
+#ifdef CONFIG_ISDN_AUDIO
}
+#endif
if (info->emu.mdmreg[12] & 128)
tty->flip.flag_buf_ptr[len - 1] = 0xff;
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+ queue_task(&tty->flip.tqueue, &tq_timer);
SET_SKB_FREE(skb);
kfree_skb(skb, FREE_READ);
return 1;
@@ -263,7 +325,7 @@
tty->flip.flag_buf_ptr += r;
tty->flip.char_buf_ptr += r;
if (r)
- queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+ queue_task(&tty->flip.tqueue, &tq_timer);
restore_flags(flags);
}
} else
@@ -282,6 +344,107 @@
isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0);
}
+int
+isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
+{
+ ulong flags;
+ int midx;
+#ifdef CONFIG_ISDN_AUDIO
+ int ifmt;
+#endif
+ modem_info *info;
+
+ if ((midx = dev->m_idx[i]) < 0) {
+ /* if midx is invalid, packet is not for tty */
+ return 0;
+ }
+ info = &dev->mdm.info[midx];
+#ifdef CONFIG_ISDN_AUDIO
+ ifmt = 1;
+
+ if (info->vonline)
+ isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
+#endif
+ if ((info->online < 2)
+#ifdef CONFIG_ISDN_AUDIO
+ && (!(info->vonline & 1))
+#endif
+ ) {
+ /* If Modem not listening, drop data */
+ SET_SKB_FREE(skb);
+ kfree_skb(skb, FREE_READ);
+ return 1;
+ }
+ if (info->emu.mdmreg[13] & 2)
+ /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */
+ if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1)))
+ skb_pull(skb, 4);
+#ifdef CONFIG_ISDN_AUDIO
+ if (skb_headroom(skb) < sizeof(isdn_audio_skb)) {
+ printk(KERN_WARNING
+ "isdn_audio: insufficient skb_headroom, dropping\n");
+ SET_SKB_FREE(skb);
+ kfree_skb(skb, FREE_READ);
+ return 1;
+ }
+ ISDN_AUDIO_SKB_DLECOUNT(skb) = 0;
+ ISDN_AUDIO_SKB_LOCK(skb) = 0;
+ if (info->vonline & 1) {
+ /* voice conversion/compression */
+ switch (info->emu.vpar[3]) {
+ case 2:
+ case 3:
+ case 4:
+ /* adpcm
+ * Since compressed data takes less
+ * space, we can overwrite the buffer.
+ */
+ skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr,
+ ifmt,
+ skb->data,
+ skb->data,
+ skb->len));
+ break;
+ case 5:
+ /* a-law */
+ if (!ifmt)
+ isdn_audio_ulaw2alaw(skb->data, skb->len);
+ break;
+ case 6:
+ /* u-law */
+ if (ifmt)
+ isdn_audio_alaw2ulaw(skb->data, skb->len);
+ break;
+ }
+ ISDN_AUDIO_SKB_DLECOUNT(skb) =
+ isdn_tty_countDLE(skb->data, skb->len);
+ }
+#endif
+ /* Try to deliver directly via tty-flip-buf if queue is empty */
+ save_flags(flags);
+ cli();
+ if (skb_queue_empty(&dev->drv[di]->rpqueue[channel]))
+ if (isdn_tty_try_read(info, skb)) {
+ restore_flags(flags);
+ return 1;
+ }
+ /* Direct deliver failed or queue wasn't empty.
+ * Queue up for later dequeueing via timer-irq.
+ */
+ __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb);
+ dev->drv[di]->rcvcount[channel] +=
+ (skb->len
+#ifdef CONFIG_ISDN_AUDIO
+ + ISDN_AUDIO_SKB_DLECOUNT(skb)
+#endif
+ );
+ restore_flags(flags);
+ /* Schedule dequeuing */
+ if ((dev->modempoll) && (info->rcvsched))
+ isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1);
+ return 1;
+}
+
void
isdn_tty_cleanup_xmit(modem_info * info)
{
@@ -295,11 +458,13 @@
SET_SKB_FREE(skb);
kfree_skb(skb, FREE_WRITE);
}
+#ifdef CONFIG_ISDN_AUDIO
if (skb_queue_len(&info->dtmf_queue))
while ((skb = skb_dequeue(&info->dtmf_queue))) {
SET_SKB_FREE(skb);
kfree_skb(skb, FREE_WRITE);
}
+#endif
restore_flags(flags);
}
@@ -314,7 +479,7 @@
return;
len = skb->len;
if ((slen = isdn_writebuf_skb_stub(info->isdn_driver,
- info->isdn_channel, skb)) == len) {
+ info->isdn_channel, skb)) == len) {
struct tty_struct *tty = info->tty;
info->send_outstanding++;
info->msr |= UART_MSR_CTS;
@@ -325,13 +490,19 @@
wake_up_interruptible(&tty->write_wait);
return;
}
- if (slen > 0)
+ if (slen < 0) {
+ /* Error: no channel, already shutdown, or wrong parameter */
+ SET_SKB_FREE(skb);
+ dev_kfree_skb(skb, FREE_WRITE);
+ return;
+ }
+ if (slen)
skb_pull(skb, slen);
skb_queue_head(&info->xmit_queue, skb);
}
#ifdef CONFIG_ISDN_AUDIO
-int
+static int
isdn_tty_countDLE(unsigned char *buf, int len)
{
int count = 0;
@@ -369,9 +540,20 @@
case DC4:
/* Abort RX */
info->vonline &= ~1;
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG
+ "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n",
+ info->line);
+#endif
isdn_tty_at_cout("\020\003", info);
- if (!info->vonline)
+ if (!info->vonline) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG
+ "DLEdown: send VCON on ttyI%d\n",
+ info->line);
+#endif
isdn_tty_at_cout("\r\nVCON\r\n", info);
+ }
/* Fall through */
case 'q':
case 's':
@@ -404,28 +586,22 @@
static int
isdn_tty_end_vrx(const char *buf, int c, int from_user)
{
- char tmpbuf[VBUF];
- char *p;
+ char ch;
- if (c > VBUF) {
- printk(KERN_ERR "isdn_tty: (end_vrx) BUFFER OVERFLOW!!!\n");
- return 1;
- }
- if (from_user) {
- copy_from_user(tmpbuf, buf, c);
- p = tmpbuf;
- } else
- p = (char *) buf;
while (c--) {
- if ((*p != 0x11) && (*p != 0x13))
+ if (from_user)
+ GET_USER(ch, buf);
+ else
+ ch = *buf;
+ if ((ch != 0x11) && (ch != 0x13))
return 1;
- p++;
+ buf++;
}
return 0;
}
static int voice_cf[7] =
-{1, 1, 4, 3, 2, 1, 1};
+{0, 0, 4, 3, 2, 0, 0};
#endif /* CONFIG_ISDN_AUDIO */
@@ -437,18 +613,36 @@
static void
isdn_tty_senddown(modem_info * info)
{
- unsigned char *buf = info->xmit_buf;
int buflen;
int skb_res;
+#ifdef CONFIG_ISDN_AUDIO
+ int audio_len;
+#endif
struct sk_buff *skb;
unsigned long flags;
+#ifdef CONFIG_ISDN_AUDIO
+ if (info->vonline & 4) {
+ info->vonline &= ~6;
+ if (!info->vonline) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG
+ "senddown: send VCON on ttyI%d\n",
+ info->line);
+#endif
+ isdn_tty_at_cout("\r\nVCON\r\n", info);
+ }
+ }
+#endif
save_flags(flags);
cli();
if (!(buflen = info->xmit_count)) {
restore_flags(flags);
return;
}
+ if ((info->emu.mdmreg[12] & 0x10) != 0)
+ info->msr &= ~UART_MSR_CTS;
+ info->lsr &= ~UART_LSR_TEMT;
if (info->isdn_driver < 0) {
info->xmit_count = 0;
restore_flags(flags);
@@ -456,6 +650,26 @@
}
skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
#ifdef CONFIG_ISDN_AUDIO
+ if (info->vonline & 2)
+ audio_len = buflen * voice_cf[info->emu.vpar[3]];
+ else
+ audio_len = 0;
+ skb = dev_alloc_skb(skb_res + buflen + audio_len);
+#else
+ skb = dev_alloc_skb(skb_res + buflen);
+#endif
+ if (!skb) {
+ restore_flags(flags);
+ printk(KERN_WARNING
+ "isdn_tty: Out of memory in ttyI%d senddown\n",
+ info->line);
+ return;
+ }
+ skb_reserve(skb, skb_res);
+ memcpy(skb_put(skb, buflen), info->xmit_buf, buflen);
+ info->xmit_count = 0;
+ restore_flags(flags);
+#ifdef CONFIG_ISDN_AUDIO
if (info->vonline & 2) {
/* For now, ifmt is fixed to 1 (alaw), since this
* is used with ISDN everywhere in the world, except
@@ -464,21 +678,8 @@
* this setting will depend on the D-channel protocol.
*/
int ifmt = 1;
- int skb_len;
- unsigned char hbuf[VBUF];
- memcpy(hbuf, info->xmit_buf, buflen);
- info->xmit_count = 0;
- restore_flags(flags);
/* voice conversion/decompression */
- skb_len = buflen * voice_cf[info->emu.vpar[3]];
- skb = dev_alloc_skb(skb_len + skb_res);
- if (!skb) {
- printk(KERN_WARNING
- "isdn_tty: Out of memory in ttyI%d senddown\n", info->line);
- return;
- }
- skb_reserve(skb, skb_res);
switch (info->emu.vpar[3]) {
case 2:
case 3:
@@ -486,55 +687,34 @@
/* adpcm, compatible to ZyXel 1496 modem
* with ROM revision 6.01
*/
- buflen = isdn_audio_adpcm2xlaw(info->adpcms,
- ifmt,
- hbuf,
- skb_put(skb, skb_len),
- buflen);
- skb_trim(skb, buflen);
+ audio_len = isdn_audio_adpcm2xlaw(info->adpcms,
+ ifmt,
+ skb->data,
+ skb_put(skb, audio_len),
+ buflen);
+ skb_pull(skb, buflen);
+ skb_trim(skb, audio_len);
break;
case 5:
/* a-law */
if (!ifmt)
- isdn_audio_alaw2ulaw(hbuf, buflen);
- memcpy(skb_put(skb, buflen), hbuf, buflen);
+ isdn_audio_alaw2ulaw(skb->data,
+ buflen);
break;
case 6:
/* u-law */
if (ifmt)
- isdn_audio_ulaw2alaw(hbuf, buflen);
- memcpy(skb_put(skb, buflen), hbuf, buflen);
+ isdn_audio_ulaw2alaw(skb->data,
+ buflen);
break;
}
- if (info->vonline & 4) {
- info->vonline &= ~6;
- if (!info->vonline)
- isdn_tty_at_cout("\r\nVCON\r\n", info);
- }
- } else {
-#endif /* CONFIG_ISDN_AUDIO */
- skb = dev_alloc_skb(buflen + skb_res);
- if (!skb) {
- printk(KERN_WARNING
- "isdn_tty: Out of memory in ttyI%d senddown\n", info->line);
- restore_flags(flags);
- return;
- }
- skb_reserve(skb, skb_res);
- memcpy(skb_put(skb, buflen), buf, buflen);
- info->xmit_count = 0;
- restore_flags(flags);
-#ifdef CONFIG_ISDN_AUDIO
}
-#endif
+#endif /* CONFIG_ISDN_AUDIO */
SET_SKB_FREE(skb);
if (info->emu.mdmreg[13] & 2)
/* Add T.70 simplified header */
memcpy(skb_push(skb, 4), "\1\0\1\0", 4);
skb_queue_tail(&info->xmit_queue, skb);
- if ((info->emu.mdmreg[12] & 0x10) != 0)
- info->msr &= UART_MSR_CTS;
- info->lsr &= UART_LSR_TEMT;
}
/************************************************************
@@ -566,7 +746,6 @@
isdn_tty_modem_ncarrier(modem_info * info)
{
if (info->ncarrier) {
- info->ncarrier = 0;
info->nc_timer.expires = jiffies + HZ;
info->nc_timer.function = isdn_tty_modem_do_ncarrier;
info->nc_timer.data = (unsigned long) info;
@@ -652,7 +831,7 @@
* ISDN-line (hangup). The usage-status is cleared
* and some cleanup is done also.
*/
-void
+static void
isdn_tty_modem_hup(modem_info * info, int local)
{
isdn_ctrl cmd;
@@ -664,20 +843,15 @@
printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);
#endif
info->rcvsched = 0;
- info->online = 0;
- if (info->online || info->vonline)
- info->last_lhup = local;
isdn_tty_flush_buffer(info->tty);
- if (info->vonline & 1) {
- /* voice-recording, add DLE-ETX */
- isdn_tty_at_cout("\020\003", info);
- }
- if (info->vonline & 2) {
- /* voice-playing, add DLE-DC4 */
- isdn_tty_at_cout("\020\024", info);
+ if (info->online) {
+ info->last_lhup = local;
+ info->online = 0;
+ /* NO CARRIER message */
+ isdn_tty_modem_result(3, info);
}
- info->vonline = 0;
#ifdef CONFIG_ISDN_AUDIO
+ info->vonline = 0;
if (info->dtmf_state) {
kfree(info->dtmf_state);
info->dtmf_state = NULL;
@@ -694,10 +868,12 @@
info->msr &= ~(UART_MSR_DCD | UART_MSR_RI);
info->lsr |= UART_LSR_TEMT;
if (info->isdn_driver >= 0) {
- cmd.driver = info->isdn_driver;
- cmd.command = ISDN_CMD_HANGUP;
- cmd.arg = info->isdn_channel;
- dev->drv[info->isdn_driver]->interface->command(&cmd);
+ if (local) {
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_HANGUP;
+ cmd.arg = info->isdn_channel;
+ dev->drv[info->isdn_driver]->interface->command(&cmd);
+ }
isdn_all_eaz(info->isdn_driver, info->isdn_channel);
info->emu.mdmreg[1] = 0;
usage = (info->emu.mdmreg[20] == 1) ?
@@ -888,11 +1064,16 @@
c = MIN(c, dev->drv[info->isdn_driver]->maxbufsize);
if (c <= 0)
break;
- if ((info->online > 1) ||
- (info->vonline & 2)) {
+ if ((info->online > 1)
+#ifdef CONFIG_ISDN_AUDIO
+ || (info->vonline & 3)
+#endif
+ ) {
atemu *m = &info->emu;
- if (!(info->vonline & 2))
+#ifdef CONFIG_ISDN_AUDIO
+ if (!info->vonline)
+#endif
isdn_tty_check_esc(buf, m->mdmreg[2], c,
&(m->pluscount),
&(m->lastplus),
@@ -902,21 +1083,36 @@
else
memcpy(&(info->xmit_buf[info->xmit_count]), buf, c);
#ifdef CONFIG_ISDN_AUDIO
- if (info->vonline & 2) {
- int cc;
-
- if (!(cc = isdn_tty_handleDLEdown(info, m, c))) {
- /* If DLE decoding results in zero-transmit, but
- * c originally was non-zero, do a wakeup.
+ if (info->vonline) {
+ int cc = isdn_tty_handleDLEdown(info, m, c);
+ if (info->vonline & 2) {
+ if (!cc) {
+ /* If DLE decoding results in zero-transmit, but
+ * c originally was non-zero, do a wakeup.
+ */
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup) (tty);
+ wake_up_interruptible(&tty->write_wait);
+ info->msr |= UART_MSR_CTS;
+ info->lsr |= UART_LSR_TEMT;
+ }
+ info->xmit_count += cc;
+ }
+ if ((info->vonline & 3) == 1) {
+ /* Do NOT handle Ctrl-Q or Ctrl-S
+ * when in full-duplex audio mode.
*/
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
- wake_up_interruptible(&tty->write_wait);
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
+ if (isdn_tty_end_vrx(buf, c, from_user)) {
+ info->vonline &= ~1;
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG
+ "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n",
+ info->line);
+#endif
+ isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
+ }
}
- info->xmit_count += cc;
} else
#endif
info->xmit_count += c;
@@ -927,17 +1123,6 @@
} else {
info->msr |= UART_MSR_CTS;
info->lsr |= UART_LSR_TEMT;
-#ifdef CONFIG_ISDN_AUDIO
- if ((info->vonline & 3) == 1) {
- /* Do NOT handle Ctrl-Q or Ctrl-S
- * when in full-duplex audio mode.
- */
- if (isdn_tty_end_vrx(buf, c, from_user)) {
- info->vonline &= ~1;
- isdn_tty_at_cout("\020\003\r\nVCON\r\n", info);
- }
- } else
-#endif
if (info->dialing) {
info->dialing = 0;
#ifdef ISDN_DEBUG_MODEM_HUP
@@ -1623,6 +1808,7 @@
m->pmsn[0] = '\0';
}
+#ifdef CONFIG_ISDN_AUDIO
static void
isdn_tty_modem_reset_vpar(atemu * m)
{
@@ -1631,6 +1817,7 @@
m->vpar[2] = 70; /* Silence interval (7 sec. ) */
m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */
}
+#endif
static void
isdn_tty_modem_reset_regs(modem_info * info, int force)
@@ -1641,7 +1828,9 @@
memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
info->xmit_size = m->mdmreg[16] * 16;
}
+#ifdef CONFIG_ISDN_AUDIO
isdn_tty_modem_reset_vpar(m);
+#endif
m->mdmcmdl = 0;
}
@@ -1735,7 +1924,9 @@
info->drv_index = -1;
info->xmit_size = ISDN_SERIAL_XMIT_SIZE;
skb_queue_head_init(&info->xmit_queue);
+#ifdef CONFIG_ISDN_AUDIO
skb_queue_head_init(&info->dtmf_queue);
+#endif
if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_SIZE + 5, GFP_KERNEL))) {
printk(KERN_ERR "Could not allocate modem xmit-buffer\n");
return -3;
@@ -1817,6 +2008,9 @@
restore_flags(flags);
printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr,
info->line);
+ info->msr |= UART_MSR_RI;
+ isdn_tty_modem_result(2, info);
+ isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1);
return info->line;
}
}
@@ -1827,6 +2021,140 @@
return -1;
}
+#define TTY_IS_ACTIVE(info) \
+ (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))
+
+int
+isdn_tty_stat_callback(int i, isdn_ctrl * c)
+{
+ int mi;
+ modem_info *info;
+
+ if (i < 0)
+ return 0;
+ if ((mi = dev->m_idx[i]) >= 0) {
+ info = &dev->mdm.info[mi];
+ switch (c->command) {
+ case ISDN_STAT_BSENT:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line);
+#endif
+ if ((info->isdn_driver == c->driver) &&
+ (info->isdn_channel == c->arg)) {
+ info->msr |= UART_MSR_CTS;
+ if (info->send_outstanding)
+ if (!(--info->send_outstanding))
+ info->lsr |= UART_LSR_TEMT;
+ isdn_tty_tint(info);
+ return 1;
+ }
+ break;
+ case ISDN_STAT_CAUSE:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line);
+#endif
+ /* Signal cause to tty-device */
+ strncpy(info->last_cause, c->parm.num, 5);
+ return 1;
+ case ISDN_STAT_DCONN:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line);
+#endif
+ if (TTY_IS_ACTIVE(info)) {
+ if (info->dialing == 1) {
+ info->dialing = 2;
+ return 1;
+ }
+ }
+ break;
+ case ISDN_STAT_DHUP:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
+#endif
+ if (TTY_IS_ACTIVE(info)) {
+ if (info->dialing == 1) {
+ info->dialing = 0;
+ isdn_tty_modem_result(7, info);
+ }
+#ifdef ISDN_DEBUG_MODEM_HUP
+ printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
+#endif
+ isdn_tty_modem_hup(info, 0);
+ return 1;
+ }
+ break;
+ case ISDN_STAT_BCONN:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
+#endif
+ /* Schedule CONNECT-Message to any tty
+ * waiting for it and
+ * set DCD-bit of its modem-status.
+ */
+ if (TTY_IS_ACTIVE(info)) {
+ info->msr |= UART_MSR_DCD;
+ if (info->dialing) {
+ info->dialing = 0;
+ info->last_dir = 1;
+ } else
+ info->last_dir = 0;
+ info->rcvsched = 1;
+ if (USG_MODEM(dev->usage[i]))
+ isdn_tty_modem_result(5, info);
+ if (USG_VOICE(dev->usage[i]))
+ isdn_tty_modem_result(11, info);
+ return 1;
+ }
+ break;
+ case ISDN_STAT_BHUP:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line);
+#endif
+ if (TTY_IS_ACTIVE(info)) {
+#ifdef ISDN_DEBUG_MODEM_HUP
+ printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n");
+#endif
+ isdn_tty_modem_hup(info, 0);
+ return 1;
+ }
+ break;
+ case ISDN_STAT_NODCH:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line);
+#endif
+ if (TTY_IS_ACTIVE(info)) {
+ if (info->dialing) {
+ info->dialing = 0;
+ info->last_l2 = -1;
+ info->last_si = 0;
+ sprintf(info->last_cause, "0000");
+ isdn_tty_modem_result(6, info);
+ }
+ info->msr &= ~UART_MSR_DCD;
+ if (info->online) {
+ isdn_tty_modem_result(3, info);
+ info->online = 0;
+ }
+ return 1;
+ }
+ break;
+ case ISDN_STAT_UNLOAD:
+#ifdef ISDN_TTY_STAT_DEBUG
+ printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line);
+#endif
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ info = &dev->mdm.info[i];
+ if (info->isdn_driver == c->driver) {
+ if (info->online)
+ isdn_tty_modem_hup(info, 1);
+ }
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*********************************************************************
Modem-Emulator-Routines
*********************************************************************/
@@ -1889,7 +2217,6 @@
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");
#endif
- isdn_tty_modem_result(3, info);
isdn_tty_modem_hup(info, 1);
}
}
@@ -1959,7 +2286,7 @@
* For CONNECT-messages also switch to online-mode.
* For RING-message handle auto-ATA if register 0 != 0
*/
-void
+static void
isdn_tty_modem_result(int code, modem_info * info)
{
atemu *m = &info->emu;
@@ -1979,27 +2306,39 @@
break;
case 3:
/* NO CARRIER */
- save_flags(flags);
- cli();
- m->mdmreg[1] = 0;
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n",
(info->flags & ISDN_ASYNC_CLOSING),
(!info->tty));
#endif
+ save_flags(flags);
+ cli();
+ m->mdmreg[1] = 0;
+ del_timer(&info->nc_timer);
+ info->ncarrier = 0;
if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) {
restore_flags(flags);
return;
}
restore_flags(flags);
+#ifdef CONFIG_ISDN_AUDIO
if (info->vonline & 1) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n",
+ info->line);
+#endif
/* voice-recording, add DLE-ETX */
isdn_tty_at_cout("\020\003", info);
}
if (info->vonline & 2) {
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n",
+ info->line);
+#endif
/* voice-playing, add DLE-DC4 */
isdn_tty_at_cout("\020\024", info);
}
+#endif
break;
case 1:
case 5:
@@ -2008,6 +2347,10 @@
info->online = 2;
break;
case 11:
+#ifdef ISDN_DEBUG_MODEM_VOICE
+ printk(KERN_DEBUG "res3: send VCON on ttyI%d\n",
+ info->line);
+#endif
sprintf(info->last_cause, "0000");
if (!info->online)
info->online = 1;
@@ -2240,9 +2583,10 @@
case 'V':
/* &V - Show registers */
p[0]++;
+ isdn_tty_at_cout("\r\n", info);
for (i = 0; i < ISDN_MODEM_ANZREG; i++) {
- sprintf(rb, "S%d=%d%s", i,
- m->mdmreg[i], (i == 6) ? "\r\n" : " ");
+ sprintf(rb, "S%02d=%03d%s", i,
+ m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
isdn_tty_at_cout(rb, info);
}
sprintf(rb, "\r\nEAZ/MSN: %s\r\n",
@@ -2286,6 +2630,33 @@
return 0;
}
+static int
+isdn_tty_check_ats(int mreg, int mval, modem_info * info, atemu * m)
+{
+ /* Some plausibility checks */
+ switch (mreg) {
+ case 14:
+ if (mval > ISDN_PROTO_L2_TRANS)
+ return 1;
+ break;
+ case 16:
+ if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)
+ return 1;
+#ifdef CONFIG_ISDN_AUDIO
+ if ((m->mdmreg[18] & 1) && (mval > VBUFX))
+ return 1;
+#endif
+ info->xmit_size = mval * 16;
+ break;
+ case 20:
+ case 21:
+ case 22:
+ /* readonly registers */
+ return 1;
+ }
+ return 0;
+}
+
/*
* Perform ATS command
*/
@@ -2293,8 +2664,10 @@
isdn_tty_cmd_ATS(char **p, modem_info * info)
{
atemu *m = &info->emu;
+ int bitpos;
int mreg;
int mval;
+ int bval;
mreg = isdn_getnum(p);
if (mreg < 0 || mreg > ISDN_MODEM_ANZREG)
@@ -2305,25 +2678,39 @@
mval = isdn_getnum(p);
if (mval < 0 || mval > 255)
PARSE_ERROR1;
- switch (mreg) {
- /* Some plausibility checks */
- case 14:
- if (mval > ISDN_PROTO_L2_TRANS)
- PARSE_ERROR1;
- break;
- case 16:
- if ((mval * 16) > ISDN_SERIAL_XMIT_SIZE)
+ if (isdn_tty_check_ats(mreg, mval, info, m))
+ PARSE_ERROR1;
+ m->mdmreg[mreg] = mval;
+ break;
+ case '.':
+ /* Set/Clear a single bit */
+ p[0]++;
+ bitpos = isdn_getnum(p);
+ if ((bitpos < 0) || (bitpos > 7))
+ PARSE_ERROR1;
+ switch (*p[0]) {
+ case '=':
+ p[0]++;
+ bval = isdn_getnum(p);
+ if (bval < 0 || bval > 1)
PARSE_ERROR1;
-#ifdef CONFIG_ISDN_AUDIO
- if ((m->mdmreg[18] & 1) && (mval > VBUFX))
+ if (bval)
+ mval = m->mdmreg[mreg] | (1 << bitpos);
+ else
+ mval = m->mdmreg[mreg] & ~(1 << bitpos);
+ if (isdn_tty_check_ats(mreg, mval, info, m))
PARSE_ERROR1;
-#endif
- info->xmit_size = mval * 16;
+ m->mdmreg[mreg] = mval;
break;
- case 20:
+ case '?':
+ p[0]++;
+ isdn_tty_at_cout("\r\n", info);
+ isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0",
+ info);
+ break;
+ default:
PARSE_ERROR1;
}
- m->mdmreg[mreg] = mval;
break;
case '?':
p[0]++;
@@ -2355,9 +2742,12 @@
l2 = m->mdmreg[14];
#ifdef CONFIG_ISDN_AUDIO
/* If more than one bit set in reg18, autoselect Layer2 */
- if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18])
+ if ((m->mdmreg[18] & m->mdmreg[20]) != m->mdmreg[18]) {
if (m->mdmreg[20] == 1)
l2 = 4;
+ else
+ l2 = 0;
+ }
#endif
cmd.driver = info->isdn_driver;
cmd.command = ISDN_CMD_SETL2;
@@ -2709,7 +3099,7 @@
else if (strlen(ds))
isdn_tty_dial(ds, info, m);
else
- isdn_tty_modem_result(4, info);
+ PARSE_ERROR;
return;
case 'E':
/* E - Turn Echo on/off */
@@ -2822,6 +3212,8 @@
if (isdn_tty_cmd_PLUSV(&p, info))
return;
break;
+ default:
+ PARSE_ERROR;
}
break;
#endif /* CONFIG_ISDN_AUDIO */
@@ -2831,11 +3223,13 @@
return;
break;
default:
- isdn_tty_modem_result(4, info);
- return;
+ PARSE_ERROR;
}
}
- isdn_tty_modem_result(0, info);
+#ifdef CONFIG_ISDN_AUDIO
+ if (!info->vonline)
+#endif
+ isdn_tty_modem_result(0, info);
}
/* Need own toupper() because standard-toupper is not available
@@ -2986,28 +3380,4 @@
}
}
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
-}
-
-/*
- * A packet has been output successfully.
- * Search the tty-devices for an appropriate device, decrement its
- * counter for outstanding packets, and set CTS.
- */
-void
-isdn_tty_bsent(int drv, int chan)
-{
- int i;
-
- for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
- modem_info *info = &dev->mdm.info[i];
- if ((info->isdn_driver == drv) &&
- (info->isdn_channel == chan)) {
- info->msr |= UART_MSR_CTS;
- if (info->send_outstanding)
- if (!(--info->send_outstanding))
- info->lsr |= UART_LSR_TEMT;
- isdn_tty_tint(info);
- }
- }
- return;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov