patch-2.3.4 linux/drivers/isdn/isdn_tty.c
Next file: linux/drivers/isdn/isdn_tty.h
Previous file: linux/drivers/isdn/isdn_ppp.h
Back to the patch index
Back to the overall index
- Lines: 1098
- Date:
Sun May 23 10:03:42 1999
- Orig file:
v2.3.3/linux/drivers/isdn/isdn_tty.c
- Orig date:
Fri May 14 18:55:19 1999
diff -u --recursive --new-file v2.3.3/linux/drivers/isdn/isdn_tty.c linux/drivers/isdn/isdn_tty.c
@@ -1,8 +1,8 @@
-/* $Id: isdn_tty.c,v 1.47 1998/02/22 19:44:14 fritz Exp $
+/* $Id: isdn_tty.c,v 1.63 1999/04/12 12:33:39 fritz Exp $
* Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
*
- * Copyright 1994,95,96 by Fritz Elfert (fritz@wuemaus.franken.de)
+ * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
* Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,73 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Log: isdn_tty.c,v $
+ * Revision 1.63 1999/04/12 12:33:39 fritz
+ * Changes from 2.0 tree.
+ *
+ * Revision 1.62 1999/03/02 12:04:48 armin
+ * -added ISDN_STAT_ADDCH to increase supported channels after
+ * register_isdn().
+ * -ttyI now goes on-hook on ATZ when B-Ch is connected.
+ * -added timer-function for register S7 (Wait for Carrier).
+ * -analog modem (ISDN_PROTO_L2_MODEM) implementations.
+ * -on L2_MODEM a string will be appended to the CONNECT-Message,
+ * which is provided by the HL-Driver in parm.num in ISDN_STAT_BCONN.
+ * -variable "dialing" used for ATA also, for interrupting call
+ * establishment and register S7.
+ *
+ * Revision 1.61 1999/01/27 22:53:11 he
+ * minor updates (spellings, jiffies wrap around in isdn_tty)
+ *
+ * Revision 1.60 1998/11/15 23:57:32 keil
+ * changes for 2.1.127
+ *
+ * Revision 1.59 1998/08/20 13:50:15 keil
+ * More support for hybrid modem (not working yet)
+ *
+ * Revision 1.58 1998/07/26 18:48:45 armin
+ * Added silence detection in voice receive mode.
+ *
+ * Revision 1.57 1998/06/26 15:12:36 fritz
+ * Added handling of STAT_ICALL with incomplete CPN.
+ * Added AT&L for ttyI emulator.
+ * Added more locking stuff in tty_write.
+ *
+ * Revision 1.56 1998/06/18 23:31:51 fritz
+ * Replaced cli()/restore_flags() in isdn_tty_write() by locking.
+ * Removed direct-senddown feature in isdn_tty_write because it will
+ * never succeed with locking and is useless anyway.
+ *
+ * Revision 1.55 1998/06/17 19:50:55 he
+ * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
+ * brute force fix to avoid Ugh's in isdn_tty_write()
+ * cleaned up some dead code
+ *
+ * Revision 1.54 1998/06/07 00:20:13 fritz
+ * abc cleanup.
+ *
+ * Revision 1.53 1998/06/02 12:10:16 detabc
+ * wegen einer einstweiliger verfuegung gegen DW ist zur zeit
+ * die abc-extension bis zur klaerung der rechtslage nicht verfuegbar
+ *
+ * Revision 1.52 1998/03/19 13:18:21 keil
+ * Start of a CAPI like interface for supplementary Service
+ * first service: SUSPEND
+ *
+ * Revision 1.51 1998/03/08 14:26:11 detabc
+ * change kfree_skb to dev_kfree_skb
+ * remove SET_SKB_FREE
+ *
+ * Revision 1.50 1998/03/08 13:14:28 detabc
+ * abc-extension support for kernels > 2.1.x
+ * first try (sorry experimental)
+ *
+ * Revision 1.49 1998/03/08 00:01:59 fritz
+ * Bugfix: Lowlevel module usage and channel usage were not
+ * reset on NO DCHANNEL.
+ *
+ * Revision 1.48 1998/03/07 12:28:15 tsbogend
+ * fixed kernel unaligned traps on Linux/Alpha
+ *
* Revision 1.47 1998/02/22 19:44:14 fritz
* Bugfixes and improvements regarding V.110, V.110 now running.
*
@@ -254,7 +321,7 @@
static int si2bit[8] =
{4, 1, 4, 4, 4, 4, 4, 4};
-char *isdn_tty_revision = "$Revision: 1.47 $";
+char *isdn_tty_revision = "$Revision: 1.63 $";
#define DLE 0x10
#define ETX 0x03
@@ -270,6 +337,8 @@
#define REG_LF 4
#define REG_BS 5
+#define REG_WAITC 7
+
#define REG_RESP 12
#define BIT_RESP 1
#define REG_RESPNUM 12
@@ -287,8 +356,6 @@
#define REG_CPPP 12
#define BIT_CPPP 128
-#define REG_DELXMT 13
-#define BIT_DELXMT 1
#define REG_T70 13
#define BIT_T70 2
#define BIT_T70_EXT 32
@@ -300,6 +367,8 @@
#define BIT_CIDONCE 16
#define REG_RUNG 13
#define BIT_RUNG 64
+#define REG_RESRXT 13
+#define BIT_RESRXT 128
#define REG_L2PROT 14
#define REG_L3PROT 15
@@ -389,6 +458,8 @@
r = 0;
#ifdef CONFIG_ISDN_AUDIO
isdn_audio_eval_dtmf(info);
+ if ((info->vonline & 1) && (info->emu.vpar[1]))
+ isdn_audio_eval_silence(info);
#endif
if ((tty = info->tty)) {
if (info->mcr & UART_MCR_RTS) {
@@ -445,6 +516,8 @@
if (info->vonline)
isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt);
+ if ((info->vonline & 1) && (info->emu.vpar[1]))
+ isdn_audio_calc_silence(info, skb->data, skb->len, ifmt);
#endif
if ((info->online < 2)
#ifdef CONFIG_ISDN_AUDIO
@@ -566,8 +639,8 @@
info->isdn_channel, 1, skb)) == len) {
struct tty_struct *tty = info->tty;
info->send_outstanding++;
- info->msr |= UART_MSR_CTS;
- info->lsr |= UART_LSR_TEMT;
+ info->msr &= ~UART_MSR_CTS;
+ info->lsr &= ~UART_LSR_TEMT;
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup) (tty);
@@ -579,8 +652,6 @@
dev_kfree_skb(skb);
return;
}
- if (slen)
- skb_pull(skb, slen);
skb_queue_head(&info->xmit_queue, skb);
}
@@ -702,7 +773,6 @@
int audio_len;
#endif
struct sk_buff *skb;
- unsigned long flags;
#ifdef CONFIG_ISDN_AUDIO
if (info->vonline & 4) {
@@ -717,18 +787,20 @@
}
}
#endif
- save_flags(flags);
- cli();
- if (!(buflen = info->xmit_count)) {
- restore_flags(flags);
+ if (!(buflen = info->xmit_count))
return;
- }
- if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
+ if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0)
info->msr &= ~UART_MSR_CTS;
- info->lsr &= ~UART_LSR_TEMT;
+ info->lsr &= ~UART_LSR_TEMT;
+ /* info->xmit_count is modified here and in isdn_tty_write().
+ * So we return here if isdn_tty_write() is in the
+ * critical section.
+ */
+ atomic_inc(&info->xmit_lock);
+ if (!(atomic_dec_and_test(&info->xmit_lock)))
+ return;
if (info->isdn_driver < 0) {
info->xmit_count = 0;
- restore_flags(flags);
return;
}
skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4;
@@ -742,7 +814,6 @@
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);
@@ -751,7 +822,6 @@
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
@@ -859,7 +929,7 @@
break;
}
#ifdef CONFIG_ISDN_AUDIO
- if (si == 1) {
+ if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
l2 = ISDN_PROTO_L2_TRANS;
usg = ISDN_USAGE_VOICE;
}
@@ -907,9 +977,11 @@
cmd.parm.setup.si2 = m->mdmreg[REG_SI2];
cmd.command = ISDN_CMD_DIAL;
info->dialing = 1;
+ info->emu.carrierwait = 0;
strcpy(dev->num[i], n);
isdn_info_update();
isdn_command(&cmd);
+ isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
}
}
@@ -942,6 +1014,10 @@
kfree(info->dtmf_state);
info->dtmf_state = NULL;
}
+ if (info->silence_state) {
+ kfree(info->silence_state);
+ info->silence_state = NULL;
+ }
if (info->adpcms) {
kfree(info->adpcms);
info->adpcms = NULL;
@@ -965,8 +1041,9 @@
}
isdn_all_eaz(info->isdn_driver, info->isdn_channel);
info->emu.mdmreg[REG_RINGCNT] = 0;
- usage = (info->emu.mdmreg[REG_SI1I] == 1) ?
- ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
+ usage = ((info->emu.mdmreg[REG_SI1I] != 1) ||
+ (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ?
+ ISDN_USAGE_MODEM : ISDN_USAGE_VOICE;
isdn_free_channel(info->isdn_driver, info->isdn_channel,
usage);
}
@@ -978,6 +1055,226 @@
}
}
+/*
+ * Begin of a CAPI like interface, currently used only for
+ * supplementary service (CAPI 2.0 part III)
+ */
+#include "avmb1/capicmd.h" /* this should be moved in a common place */
+
+int
+isdn_tty_capi_facility(capi_msg *cm) {
+ return(-1); /* dummy */
+}
+
+/* isdn_tty_suspend() tries to suspend the current tty connection
+ */
+static void
+isdn_tty_suspend(char *id, modem_info * info, atemu * m)
+{
+ isdn_ctrl cmd;
+
+ int l;
+
+ if (!info)
+ return;
+
+#ifdef ISDN_DEBUG_MODEM_SERVICES
+ printk(KERN_DEBUG "Msusp ttyI%d\n", info->line);
+#endif
+ l = strlen(id);
+ if ((info->isdn_driver >= 0) && l) {
+ cmd.parm.cmsg.Length = l+17;
+ cmd.parm.cmsg.Command = CAPI_FACILITY;
+ cmd.parm.cmsg.Subcommand = CAPI_REQ;
+ cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
+ cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
+ cmd.parm.cmsg.para[1] = 0;
+ cmd.parm.cmsg.para[2] = l + 3;
+ cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */
+ cmd.parm.cmsg.para[4] = 0;
+ cmd.parm.cmsg.para[5] = l;
+ strncpy(&cmd.parm.cmsg.para[6], id, l);
+ cmd.command = CAPI_PUT_MESSAGE;
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ isdn_command(&cmd);
+ }
+}
+
+/* isdn_tty_resume() tries to resume a suspended call
+ * setup of the lower levels before that. unfortunatly here is no
+ * checking for compatibility of used protocols implemented by Q931
+ * It does the same things like isdn_tty_dial, the last command
+ * is different, may be we can merge it.
+ */
+
+static void
+isdn_tty_resume(char *id, modem_info * info, atemu * m)
+{
+ int usg = ISDN_USAGE_MODEM;
+ int si = 7;
+ int l2 = m->mdmreg[REG_L2PROT];
+ isdn_ctrl cmd;
+ ulong flags;
+ int i;
+ int j;
+ int l;
+
+ l = strlen(id);
+ if (!l) {
+ isdn_tty_modem_result(4, info);
+ return;
+ }
+ for (j = 7; j >= 0; j--)
+ if (m->mdmreg[REG_SI1] & (1 << j)) {
+ si = bit2si[j];
+ break;
+ }
+#ifdef CONFIG_ISDN_AUDIO
+ if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
+ l2 = ISDN_PROTO_L2_TRANS;
+ usg = ISDN_USAGE_VOICE;
+ }
+#endif
+ m->mdmreg[REG_SI1I] = si2bit[si];
+ save_flags(flags);
+ cli();
+ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+ if (i < 0) {
+ restore_flags(flags);
+ isdn_tty_modem_result(6, info);
+ } else {
+ info->isdn_driver = dev->drvmap[i];
+ info->isdn_channel = dev->chanmap[i];
+ info->drv_index = i;
+ dev->m_idx[i] = info->line;
+ dev->usage[i] |= ISDN_USAGE_OUTGOING;
+ info->last_dir = 1;
+// strcpy(info->last_num, n);
+ isdn_info_update();
+ restore_flags(flags);
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ cmd.command = ISDN_CMD_CLREAZ;
+ isdn_command(&cmd);
+ strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETEAZ;
+ isdn_command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETL2;
+ info->last_l2 = l2;
+ cmd.arg = info->isdn_channel + (l2 << 8);
+ isdn_command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETL3;
+ cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+ isdn_command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ cmd.parm.cmsg.Length = l+17;
+ cmd.parm.cmsg.Command = CAPI_FACILITY;
+ cmd.parm.cmsg.Subcommand = CAPI_REQ;
+ cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
+ cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */
+ cmd.parm.cmsg.para[1] = 0;
+ cmd.parm.cmsg.para[2] = l+3;
+ cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */
+ cmd.parm.cmsg.para[4] = 0;
+ cmd.parm.cmsg.para[5] = l;
+ strncpy(&cmd.parm.cmsg.para[6], id, l);
+ cmd.command =CAPI_PUT_MESSAGE;
+/* info->dialing = 1;
+ strcpy(dev->num[i], n);
+ isdn_info_update();
+*/
+ isdn_command(&cmd);
+ }
+}
+
+/* isdn_tty_send_msg() sends a message to a HL driver
+ * This is used for hybrid modem cards to send AT commands to it
+ */
+
+static void
+isdn_tty_send_msg(modem_info * info, atemu * m, char *msg)
+{
+ int usg = ISDN_USAGE_MODEM;
+ int si = 7;
+ int l2 = m->mdmreg[REG_L2PROT];
+ isdn_ctrl cmd;
+ ulong flags;
+ int i;
+ int j;
+ int l;
+
+ l = strlen(msg);
+ if (!l) {
+ isdn_tty_modem_result(4, info);
+ return;
+ }
+ for (j = 7; j >= 0; j--)
+ if (m->mdmreg[REG_SI1] & (1 << j)) {
+ si = bit2si[j];
+ break;
+ }
+#ifdef CONFIG_ISDN_AUDIO
+ if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) {
+ l2 = ISDN_PROTO_L2_TRANS;
+ usg = ISDN_USAGE_VOICE;
+ }
+#endif
+ m->mdmreg[REG_SI1I] = si2bit[si];
+ save_flags(flags);
+ cli();
+ i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1);
+ if (i < 0) {
+ restore_flags(flags);
+ isdn_tty_modem_result(6, info);
+ } else {
+ info->isdn_driver = dev->drvmap[i];
+ info->isdn_channel = dev->chanmap[i];
+ info->drv_index = i;
+ dev->m_idx[i] = info->line;
+ dev->usage[i] |= ISDN_USAGE_OUTGOING;
+ info->last_dir = 1;
+ isdn_info_update();
+ restore_flags(flags);
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ cmd.command = ISDN_CMD_CLREAZ;
+ isdn_command(&cmd);
+ strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver));
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETEAZ;
+ isdn_command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETL2;
+ info->last_l2 = l2;
+ cmd.arg = info->isdn_channel + (l2 << 8);
+ isdn_command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.command = ISDN_CMD_SETL3;
+ cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8);
+ isdn_command(&cmd);
+ cmd.driver = info->isdn_driver;
+ cmd.arg = info->isdn_channel;
+ cmd.parm.cmsg.Length = l+14;
+ cmd.parm.cmsg.Command = CAPI_MANUFACTURER;
+ cmd.parm.cmsg.Subcommand = CAPI_REQ;
+ cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1;
+ cmd.parm.cmsg.para[0] = l+1;
+ strncpy(&cmd.parm.cmsg.para[1], msg, l);
+ cmd.parm.cmsg.para[l+1] = 0xd;
+ cmd.command =CAPI_PUT_MESSAGE;
+/* info->dialing = 1;
+ strcpy(dev->num[i], n);
+ isdn_info_update();
+*/
+ isdn_command(&cmd);
+ }
+}
+
static inline int
isdn_tty_paranoia_check(modem_info * info, kdev_t device, const char *routine)
{
@@ -1138,15 +1435,16 @@
{
int c;
int total = 0;
- ulong flags;
modem_info *info = (modem_info *) tty->driver_data;
if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write"))
return 0;
if (!tty)
return 0;
- save_flags(flags);
- cli();
+ if (from_user)
+ down(&info->write_sem);
+ /* See isdn_tty_senddown() */
+ atomic_inc(&info->xmit_lock);
while (1) {
c = MIN(count, info->xmit_size - info->xmit_count);
if (info->isdn_driver >= 0)
@@ -1205,10 +1503,6 @@
} else
#endif
info->xmit_count += c;
- if (m->mdmreg[REG_DELXMT] & BIT_DELXMT) {
- isdn_tty_senddown(info);
- isdn_tty_tint(info);
- }
} else {
info->msr |= UART_MSR_CTS;
info->lsr |= UART_LSR_TEMT;
@@ -1228,7 +1522,9 @@
}
if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
- restore_flags(flags);
+ atomic_dec(&info->xmit_lock);
+ if (from_user)
+ up(&info->write_sem);
return total;
}
@@ -1359,7 +1655,7 @@
status = info->lsr;
restore_flags(flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- put_user(result, (ulong *) value);
+ put_user(result, (uint *) value);
return 0;
}
@@ -1383,7 +1679,7 @@
| ((status & UART_MSR_RI) ? TIOCM_RNG : 0)
| ((status & UART_MSR_DSR) ? TIOCM_DSR : 0)
| ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
- put_user(result, (ulong *) value);
+ put_user(result, (uint *) value);
return 0;
}
@@ -1567,7 +1863,12 @@
static int
isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
{
- DECLARE_WAITQUEUE(wait, current);
+#if LINUX_VERSION_CODE < 131841
+ struct wait_queue wait =
+ {current, NULL};
+#else
+ DECLARE_WAITQUEUE(wait, NULL);
+#endif
int do_clocal = 0;
unsigned long flags;
int retval;
@@ -1891,6 +2192,7 @@
m->profile[19] = 0;
m->profile[20] = 0;
m->pmsn[0] = '\0';
+ m->plmsn[0] = '\0';
}
#ifdef CONFIG_ISDN_AUDIO
@@ -1911,6 +2213,7 @@
if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) {
memcpy(m->mdmreg, m->profile, ISDN_MODEM_ANZREG);
memcpy(m->msn, m->pmsn, ISDN_MSNLEN);
+ memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN);
info->xmit_size = m->mdmreg[REG_PSIZE] * 16;
}
#ifdef CONFIG_ISDN_AUDIO
@@ -1924,6 +2227,7 @@
{
memcpy(m->profile, m->mdmreg, ISDN_MODEM_ANZREG);
memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
+ memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
if (dev->profd)
send_sig(SIGIO, dev->profd, 1);
}
@@ -1987,6 +2291,11 @@
}
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
info = &m->info[i];
+#if LINUX_VERSION_CODE < 131841
+ info->write_sem = MUTEX;
+#else
+ init_MUTEX(&info->write_sem);
+#endif
sprintf(info->last_cause, "0000");
sprintf(info->last_num, "none");
info->last_dir = 0;
@@ -2003,8 +2312,13 @@
info->blocked_open = 0;
info->callout_termios = m->cua_modem.init_termios;
info->normal_termios = m->tty_modem.init_termios;
+#if LINUX_VERSION_CODE < 131841
+ info->open_wait = 0;
+ info->close_wait = 0;
+#else
init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait);
+#endif
info->isdn_driver = -1;
info->isdn_channel = -1;
info->drv_index = -1;
@@ -2023,25 +2337,67 @@
return 0;
}
+static int
+isdn_tty_match_icall(char *cid, atemu *emu, int di)
+{
+#ifdef ISDN_DEBUG_MODEM_ICALL
+ printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n",
+ emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di),
+ emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]);
+#endif
+ if (strlen(emu->lmsn)) {
+ char *p = emu->lmsn;
+ char *q;
+ int tmp;
+ int ret = 0;
+
+ while (1) {
+ if ((q = strchr(p, ';')))
+ *q = '\0';
+ if ((tmp = isdn_wildmat(cid, isdn_map_eaz2msn(p, di))) > ret)
+ ret = tmp;
+#ifdef ISDN_DEBUG_MODEM_ICALL
+ printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n",
+ p, isdn_map_eaz2msn(emu->msn, di), tmp);
+#endif
+ if (q) {
+ *q = ';';
+ p = q;
+ p++;
+ }
+ if (!tmp)
+ return 0;
+ if (!q)
+ break;
+ }
+ return ret;
+ } else
+ return isdn_wildmat(cid, isdn_map_eaz2msn(emu->msn, di));
+}
+
/*
* An incoming call-request has arrived.
* Search the tty-devices for an appropriate device and bind
* it to the ISDN-Channel.
- * Return Index to dev->mdm or -1 if none found.
+ * Return:
+ *
+ * 0 = No matching device found.
+ * 1 = A matching device found.
+ * 3 = No match found, but eventually would match, if
+ * CID is longer.
*/
int
isdn_tty_find_icall(int di, int ch, setup_parm setup)
{
char *eaz;
int i;
+ int wret;
int idx;
int si1;
int si2;
char nr[32];
ulong flags;
- save_flags(flags);
- cli();
if (!setup.phone[0]) {
nr[0] = '0';
nr[1] = '\0';
@@ -2058,17 +2414,14 @@
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);
#endif
+ wret = 0;
+ save_flags(flags);
+ cli();
for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
modem_info *info = &dev->mdm.info[i];
-#ifdef ISDN_DEBUG_MODEM_ICALL
- printk(KERN_DEBUG "m_fi: i=%d msn=%s mmsn=%s mreg18=%d mreg19=%d\n", i,
- info->emu.msn, isdn_map_eaz2msn(info->emu.msn, di),
- info->emu.mdmreg[REG_SI1], info->emu.mdmreg[REG_SI2]);
-#endif
- if ((!strcmp(isdn_map_eaz2msn(info->emu.msn, di),
- eaz)) && /* EAZ is matching */
- (info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
- (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
+
+ if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */
+ (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */
idx = isdn_dc2minor(di, ch);
#ifdef ISDN_DEBUG_MODEM_ICALL
printk(KERN_DEBUG "m_fi: match1\n");
@@ -2080,34 +2433,42 @@
#ifndef FIX_FILE_TRANSFER
(info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&
#endif
- (info->isdn_driver == -1) &&
- (info->isdn_channel == -1) &&
- (USG_NONE(dev->usage[idx]))) {
- info->isdn_driver = di;
- info->isdn_channel = ch;
- info->drv_index = idx;
- dev->m_idx[idx] = info->line;
- dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
- dev->usage[idx] |= (si1 == 1) ? ISDN_USAGE_VOICE : ISDN_USAGE_MODEM;
- strcpy(dev->num[idx], nr);
- info->emu.mdmreg[REG_SI1I] = si2bit[si1];
- info->emu.mdmreg[REG_PLAN] = setup.plan;
- info->emu.mdmreg[REG_SCREEN] = setup.screen;
- isdn_info_update();
- 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;
+ (info->isdn_driver == -1) &&
+ (info->isdn_channel == -1) &&
+ (USG_NONE(dev->usage[idx]))) {
+ int matchret;
+
+ if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret)
+ wret = matchret;
+ if (!matchret) { /* EAZ is matching */
+ info->isdn_driver = di;
+ info->isdn_channel = ch;
+ info->drv_index = idx;
+ dev->m_idx[idx] = info->line;
+ dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE;
+ dev->usage[idx] |= ((si1 != 1) || (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ?
+ ISDN_USAGE_MODEM : ISDN_USAGE_VOICE;
+ strcpy(dev->num[idx], nr);
+ strcpy(info->emu.cpn, eaz);
+ info->emu.mdmreg[REG_SI1I] = si2bit[si1];
+ info->emu.mdmreg[REG_PLAN] = setup.plan;
+ info->emu.mdmreg[REG_SCREEN] = setup.screen;
+ isdn_info_update();
+ 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 1;
+ }
}
}
}
- printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
- dev->drv[di]->reject_bus ? "rejected" : "ignored");
restore_flags(flags);
- return -1;
+ printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz,
+ ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2))? "rejected" : "ignored");
+ return (wret == 2)?3:0;
}
#define TTY_IS_ACTIVE(info) \
@@ -2128,7 +2489,7 @@
case ISDN_STAT_CINF:
printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num);
info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10);
- if (e == c->parm.num)
+ if (e == (char *)c->parm.num)
info->emu.charge = 0;
break;
@@ -2169,10 +2530,11 @@
printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line);
#endif
if (TTY_IS_ACTIVE(info)) {
- if (info->dialing == 1) {
- info->dialing = 0;
+ if (info->dialing == 1)
isdn_tty_modem_result(7, info);
- }
+ if (info->dialing > 1)
+ isdn_tty_modem_result(3, info);
+ info->dialing = 0;
#ifdef ISDN_DEBUG_MODEM_HUP
printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n");
#endif
@@ -2191,14 +2553,20 @@
if (TTY_IS_ACTIVE(info)) {
info->msr |= UART_MSR_DCD;
info->emu.charge = 0;
- if (info->dialing) {
- info->dialing = 0;
+ if (info->dialing & 0xf)
info->last_dir = 1;
- } else
+ else
info->last_dir = 0;
+ info->dialing = 0;
info->rcvsched = 1;
- if (USG_MODEM(dev->usage[i]))
- isdn_tty_modem_result(5, info);
+ if (USG_MODEM(dev->usage[i])) {
+ if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) {
+ strcpy(info->emu.connmsg, c->parm.num);
+ isdn_tty_modem_result(1, info);
+ }
+ else
+ isdn_tty_modem_result(5, info);
+ }
if (USG_VOICE(dev->usage[i]))
isdn_tty_modem_result(11, info);
return 1;
@@ -2228,11 +2596,7 @@
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;
- }
+ isdn_tty_modem_hup(info, 0);
return 1;
}
break;
@@ -2393,7 +2757,7 @@
"CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER",
"RINGING", "NO MSN/EAZ", "VCON", "RUNG"};
ulong flags;
- char s[10];
+ char s[ISDN_MSNLEN+10];
switch (code) {
case 2:
@@ -2473,7 +2837,20 @@
}
isdn_tty_at_cout(msg[code], info);
switch (code) {
+ case 1:
+ switch (m->mdmreg[REG_L2PROT]) {
+ case ISDN_PROTO_L2_MODEM:
+ isdn_tty_at_cout(" ", info);
+ isdn_tty_at_cout(m->connmsg, info);
+ break;
+ }
+ break;
case 2:
+ /* Append CPN, if enabled */
+ if ((m->mdmreg[REG_RESRXT] & BIT_RESRXT)) {
+ sprintf(s, "/%s", m->cpn);
+ isdn_tty_at_cout(s, info);
+ }
/* Print CID only once, _after_ 1.st RING */
if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) &&
(m->mdmreg[REG_RINGCNT] == 1)) {
@@ -2560,7 +2937,9 @@
static void
isdn_tty_get_msnstr(char *n, char **p)
{
- while ((*p[0] >= '0' && *p[0] <= '9') || (*p[0] == ','))
+ while ((*p[0] >= '0' && *p[0] <= '9') ||
+ /* Why a comma ??? */
+ (*p[0] == ','))
*n++ = *p[0]++;
*n = '\0';
}
@@ -2626,6 +3005,9 @@
case ISDN_PROTO_L2_TRANS:
isdn_tty_at_cout("transparent", info);
break;
+ case ISDN_PROTO_L2_MODEM:
+ isdn_tty_at_cout("modem", info);
+ break;
default:
isdn_tty_at_cout("unknown", info);
break;
@@ -2668,6 +3050,8 @@
int i;
char rb[100];
+#define MAXRB (sizeof(rb) - 1)
+
switch (*p[0]) {
case 'B':
/* &B - Set Buffersize */
@@ -2719,6 +3103,15 @@
isdn_tty_reset_profile(m);
isdn_tty_modem_reset_regs(info, 1);
break;
+ case 'L':
+ /* &L -Set Numbers to listen on */
+ p[0]++;
+ i = 0;
+ while ((strchr("0123456789,*[]?;", *p[0])) &&
+ (i < ISDN_LMSNLEN))
+ m->lmsn[i++] = *p[0]++;
+ m->lmsn[i] = '\0';
+ break;
case 'R':
/* &R - Set V.110 bitrate adaption */
p[0]++;
@@ -2774,6 +3167,11 @@
sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n",
strlen(m->msn) ? m->msn : "None");
isdn_tty_at_cout(rb, info);
+ if (strlen(m->lmsn)) {
+ isdn_tty_at_cout("\r\nListen: ", info);
+ isdn_tty_at_cout(m->lmsn, info);
+ isdn_tty_at_cout("\r\n", info);
+ }
break;
case 'W':
/* &W - Write Profile */
@@ -2939,9 +3337,10 @@
#ifdef CONFIG_ISDN_AUDIO
/* If more than one bit set in reg18, autoselect Layer2 */
if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) {
- if (m->mdmreg[REG_SI1I] == 1)
- l2 = ISDN_PROTO_L2_TRANS;
- else
+ if (m->mdmreg[REG_SI1I] == 1) {
+ if (l2 != ISDN_PROTO_L2_MODEM)
+ l2 = ISDN_PROTO_L2_TRANS;
+ } else
l2 = ISDN_PROTO_L2_X75I;
}
#endif
@@ -2957,7 +3356,10 @@
cmd.driver = info->isdn_driver;
cmd.arg = info->isdn_channel;
cmd.command = ISDN_CMD_ACCEPTD;
+ info->dialing = 16;
+ info->emu.carrierwait = 0;
isdn_command(&cmd);
+ isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1);
} else
isdn_tty_modem_result(8, info);
}
@@ -3221,6 +3623,11 @@
printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n");
PARSE_ERROR1;
}
+ info->silence_state = isdn_audio_silence_init(info->silence_state);
+ if (!info->silence_state) {
+ printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n");
+ PARSE_ERROR1;
+ }
if (m->vpar[3] < 5) {
info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]);
if (!info->adpcmr) {
@@ -3247,31 +3654,27 @@
break;
case '=':
p[0]++;
- switch (*p[0]) {
- case '0':
- case '1':
- case '2':
- case '3':
- par1 = isdn_getnum(p);
- if ((par1 < 0) || (par1 > 31))
- PARSE_ERROR1;
- if (*p[0] != ',')
- PARSE_ERROR1;
- p[0]++;
- par2 = isdn_getnum(p);
- if ((par2 < 0) || (par2 > 255))
- PARSE_ERROR1;
- m->vpar[1] = par1;
- m->vpar[2] = par2;
- break;
- case '?':
- p[0]++;
- isdn_tty_at_cout("\r\n<0-31>,<0-255>",
- info);
- break;
- default:
+ if ((*p[0]>='0') && (*p[0]<='9')) {
+ par1 = isdn_getnum(p);
+ if ((par1 < 0) || (par1 > 31))
PARSE_ERROR1;
- }
+ if (*p[0] != ',')
+ PARSE_ERROR1;
+ p[0]++;
+ par2 = isdn_getnum(p);
+ if ((par2 < 0) || (par2 > 255))
+ PARSE_ERROR1;
+ m->vpar[1] = par1;
+ m->vpar[2] = par2;
+ break;
+ } else
+ if (*p[0] == '?') {
+ p[0]++;
+ isdn_tty_at_cout("\r\n<0-31>,<0-255>",
+ info);
+ break;
+ } else
+ PARSE_ERROR1;
break;
default:
PARSE_ERROR1;
@@ -3445,7 +3848,7 @@
p++;
if (info->msr & UART_MSR_DCD)
/* if B-Channel is up */
- isdn_tty_modem_result(5, info);
+ isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? 1:5, info);
else
isdn_tty_modem_result(3, info);
return;
@@ -3486,29 +3889,46 @@
case 'Z':
/* Z - Load Registers from Profile */
p++;
+ if (info->msr & UART_MSR_DCD) {
+ info->online = 0;
+ isdn_tty_on_hook(info);
+ }
isdn_tty_modem_reset_regs(info, 1);
break;
-#ifdef CONFIG_ISDN_AUDIO
case '+':
p++;
switch (*p) {
+#ifdef CONFIG_ISDN_AUDIO
case 'F':
p++;
if (isdn_tty_cmd_PLUSF(&p, info))
return;
break;
case 'V':
- if (!(m->mdmreg[REG_SI1] & 1))
+ if ((!(m->mdmreg[REG_SI1] & 1)) ||
+ (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM))
PARSE_ERROR;
p++;
if (isdn_tty_cmd_PLUSV(&p, info))
return;
break;
+#endif /* CONFIG_ISDN_AUDIO */
+ case 'S': /* SUSPEND */
+ p++;
+ isdn_tty_get_msnstr(ds, &p);
+ isdn_tty_suspend(ds, info, m);
+ break;
+ case 'R': /* RESUME */
+ isdn_tty_get_msnstr(ds, &p);
+ isdn_tty_resume(ds, info, m);
+ case 'M': /* MESSAGE */
+ p++;
+ isdn_tty_send_msg(info, m, p);
+ break;
default:
PARSE_ERROR;
}
break;
-#endif /* CONFIG_ISDN_AUDIO */
case '&':
p++;
if (isdn_tty_cmd_ATand(&p, info))
@@ -3672,4 +4092,29 @@
}
}
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton);
+}
+
+/*
+ * Check all channels if we have a 'no carrier' timeout.
+ * Timeout value is set by Register S7.
+ */
+void
+isdn_tty_carrier_timeout(void)
+{
+ int ton = 0;
+ int i;
+
+ for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
+ modem_info *info = &dev->mdm.info[i];
+ if (info->dialing) {
+ if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) {
+ info->dialing = 0;
+ isdn_tty_modem_result(3, info);
+ isdn_tty_modem_hup(info, 1);
+ }
+ else
+ ton = 1;
+ }
+ }
+ isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)