From 4c0212ad90d9578ec37cb2aa9fa2bd1008561971 Mon Sep 17 00:00:00 2001 From: Armin Schindler Date: Sat, 31 Jul 1999 13:00:02 +0000 Subject: [PATCH] Added tty fax capabilities. --- Documentation/Configure.help.eicon.diff | 33 + Documentation/isdn/README.fax | 36 + drivers/isdn/Config.in | 3 + drivers/isdn/Makefile | 6 + drivers/isdn/isdn_common.c | 11 + drivers/isdn/isdn_tty.c | 284 +++--- drivers/isdn/isdn_tty.h | 17 + drivers/isdn/isdn_ttyfax.c | 1194 +++++++++++++++++++++++ drivers/isdn/isdn_ttyfax.h | 30 + include/linux/isdn.h | 7 + include/linux/isdnif.h | 84 ++ std2kern | 6 + 12 files changed, 1587 insertions(+), 124 deletions(-) create mode 100644 Documentation/Configure.help.eicon.diff create mode 100644 Documentation/isdn/README.fax create mode 100644 drivers/isdn/isdn_ttyfax.c create mode 100644 drivers/isdn/isdn_ttyfax.h diff --git a/Documentation/Configure.help.eicon.diff b/Documentation/Configure.help.eicon.diff new file mode 100644 index 00000000..edbc92c3 --- /dev/null +++ b/Documentation/Configure.help.eicon.diff @@ -0,0 +1,33 @@ +--- Configure.org Sat Jul 31 14:01:20 1999 ++++ Configure.help Sat Jul 31 14:17:49 1999 +@@ -9820,6 +9820,30 @@ + you need to have access to a machine on the Internet that has a + program like lynx or netscape). + ++Eicon.Diehl active card support ++CONFIG_ISDN_DRV_EICON ++ Say Y here if you have an Eicon active ISDN card. In order to use ++ this card, additional firmware is necessary, which has to be loaded ++ into the card using the eiconctrl utility which is part of the latest ++ isdn4k-utils package. Please read the file ++ Documentation/isdn/README.eicon for more information. ++ ++Eicon old-type card support ++CONFIG_ISDN_DRV_EICON_ISA ++ Say Y here if you have an old-type Eicon active ISDN card. In order to ++ use this card, additional firmware is necessary, which has to be loaded ++ into the card using the eiconctrl utility which is part of the latest ++ isdn4k-utils package. Please read the file ++ Documentation/isdn/README.eicon for more information. ++ ++Support AT-Fax Class 2 commands ++CONFIG_ISDN_TTY_FAX ++ If you say Y here, the modem-emulator will support a subset of the ++ Fax Class 2 commands. Using a getty with fax-support ++ (mgetty+sendfax, hylafax), you will be able to use your Linux box ++ as an ISDN-fax-machine. This must be supported by the lowlevel driver ++ also. See Documentation/isdn/README.fax for more information. ++ + AVM-B1 with CAPI2.0 support + CONFIG_ISDN_DRV_AVMB1 + This enables support for the AVM B1 ISDN networking cards. In diff --git a/Documentation/isdn/README.fax b/Documentation/isdn/README.fax new file mode 100644 index 00000000..7d07b7da --- /dev/null +++ b/Documentation/isdn/README.fax @@ -0,0 +1,36 @@ + +Fax with isdn4linux +=================== + +When enabled during kernel configuration, the tty emulator +of the ISDN subsystem is capable of the Fax Class 2 commands. + +This only makes sense under the following conditions : + +- You need the commands as dummy, because you are using + hylafax (with patch) for AVM capi. +- You want to use the fax capabillities of your isdn-card. + (supported cards are listed below) + + +NOTE: This implementation does *not* support fax with passive + ISDN-cards (known as softfax). The low-level driver of + the ISDN-card and/or the card itself must support this. + + +Supported ISDN-Cards +-------------------- + +Eicon DIVA Server BRI/PCI (will be ready soon) +Eicon DIVA Server PRI/PCI (will be ready soon) + + + +The command set is known as Class 2 (not Class 2.0) and +can be activated by AT+FCLASS=2 + + + +Armin +mac@melware.de + diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index 7c33830b..5ad37728 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -9,6 +9,9 @@ if [ "$CONFIG_INET" != "n" ]; then fi fi bool 'Support audio via ISDN' CONFIG_ISDN_AUDIO +if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then + bool 'Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX +fi bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION if [ "$CONFIG_X25" != "n" ]; then bool 'X.25 PLP on top of ISDN (EXPERIMENTAL)' CONFIG_ISDN_X25 diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index 32ed9d6a..04be19f9 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -24,6 +24,9 @@ ifeq ($(CONFIG_ISDN),y) endif ifdef CONFIG_ISDN_AUDIO L_OBJS += isdn_audio.o + ifdef CONFIG_ISDN_TTY_FAX + L_OBJS += isdn_ttyfax.o + endif endif else ifeq ($(CONFIG_ISDN),m) @@ -41,6 +44,9 @@ else endif ifdef CONFIG_ISDN_AUDIO O_OBJS += isdn_audio.o + ifdef CONFIG_ISDN_TTY_FAX + O_OBJS += isdn_ttyfax.o + endif endif endif endif diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index 38fbb77b..949fd6e3 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log$ + * Revision 1.85 1999/07/29 16:58:35 armin + * Bugfix: DLE handling in isdn_readbchan() + * * Revision 1.84 1999/07/25 16:21:10 keil * fix number matching * @@ -1046,6 +1049,11 @@ isdn_status_callback(isdn_ctrl * c) break; case CAPI_PUT_MESSAGE: return(isdn_capi_rec_hl_msg(&c->parm.cmsg)); +#ifdef CONFIG_ISDN_TTY_FAX + case ISDN_STAT_FAXIND: + isdn_tty_stat_callback(i, c); + break; +#endif #ifdef CONFIG_ISDN_AUDIO case ISDN_STAT_AUDIO: isdn_tty_stat_callback(i, c); @@ -2610,6 +2618,9 @@ cleanup_module(void) for (i = 0; i < ISDN_MAX_CHANNELS; i++) { isdn_tty_cleanup_xmit(&dev->mdm.info[i]); kfree(dev->mdm.info[i].xmit_buf - 4); +#ifdef CONFIG_ISDN_TTY_FAX + kfree(dev->mdm.info[i].fax); +#endif } if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) { printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n"); diff --git a/drivers/isdn/isdn_tty.c b/drivers/isdn/isdn_tty.c index 6b23c2a4..5db0b4d6 100644 --- a/drivers/isdn/isdn_tty.c +++ b/drivers/isdn/isdn_tty.c @@ -20,6 +20,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log$ + * Revision 1.71 1999/07/27 10:34:34 armin + * Fixed last change. Did not compile with AUDIO support off. + * * Revision 1.70 1999/07/25 16:17:58 keil * Fix Suspend/Resume * @@ -542,6 +545,15 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb) ISDN_AUDIO_SKB_DLECOUNT(skb) = isdn_tty_countDLE(skb->data, skb->len); } +#ifdef CONFIG_ISDN_TTY_FAX + else { + if (info->faxonline & 2) { + isdn_tty_fax_bitorder(info, skb); + ISDN_AUDIO_SKB_DLECOUNT(skb) = + isdn_tty_countDLE(skb->data, skb->len); + } + } +#endif #endif /* Try to deliver directly via tty-flip-buf if queue is empty */ save_flags(flags); @@ -871,6 +883,35 @@ isdn_tty_modem_ncarrier(modem_info * info) } } +/* + * return the usage calculated by si and layer 2 protocol + */ +int +isdn_calc_usage(int si, int l2) +{ + int usg = ISDN_USAGE_MODEM; + +#ifdef CONFIG_ISDN_AUDIO + if (si == 1) { + switch(l2) { + case ISDN_PROTO_L2_MODEM: + usg = ISDN_USAGE_MODEM; + break; +#ifdef CONFIG_ISDN_TTY_FAX + case ISDN_PROTO_L2_FAX: + usg = ISDN_USAGE_FAX; + break; +#endif + case ISDN_PROTO_L2_TRANS: + default: + usg = ISDN_USAGE_VOICE; + break; + } + } +#endif + return(usg); +} + /* isdn_tty_dial() performs dialing of a tty an the necessary * setup of the lower levels before that. */ @@ -890,8 +931,14 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m) si = bit2si[j]; break; } + usg = isdn_calc_usage(si, l2); #ifdef CONFIG_ISDN_AUDIO - if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) { + if ((si == 1) && + (l2 != ISDN_PROTO_L2_MODEM) +#ifdef CONFIG_ISDN_TTY_FAX + && (l2 != ISDN_PROTO_L2_FAX) +#endif + ) { l2 = ISDN_PROTO_L2_TRANS; usg = ISDN_USAGE_VOICE; } @@ -929,6 +976,12 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m) cmd.driver = info->isdn_driver; cmd.command = ISDN_CMD_SETL3; cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); +#ifdef CONFIG_ISDN_TTY_FAX + if (l2 == ISDN_PROTO_L2_FAX) { + cmd.parm.fax = info->fax; + info->fax->direction = ISDN_TTY_FAX_CONN_OUT; + } +#endif isdn_command(&cmd); cmd.driver = info->isdn_driver; cmd.arg = info->isdn_channel; @@ -951,7 +1004,7 @@ isdn_tty_dial(char *n, modem_info * info, atemu * m) * ISDN-line (hangup). The usage-status is cleared * and some cleanup is done also. */ -static void +void isdn_tty_modem_hup(modem_info * info, int local) { isdn_ctrl cmd; @@ -972,6 +1025,10 @@ isdn_tty_modem_hup(modem_info * info, int local) } #ifdef CONFIG_ISDN_AUDIO info->vonline = 0; +#ifdef CONFIG_ISDN_TTY_FAX + info->faxonline = 0; + info->fax->phase = ISDN_FAX_PHASE_IDLE; +#endif info->emu.vpar[4] = 0; info->emu.vpar[5] = 8; if (info->dtmf_state) { @@ -1005,9 +1062,8 @@ isdn_tty_modem_hup(modem_info * info, int local) } isdn_all_eaz(info->isdn_driver, info->isdn_channel); info->emu.mdmreg[REG_RINGCNT] = 0; - usage = ((info->emu.mdmreg[REG_SI1I] != 1) || - (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) ? - ISDN_USAGE_MODEM : ISDN_USAGE_VOICE; + usage = isdn_calc_usage(info->emu.mdmreg[REG_SI1I], + info->emu.mdmreg[REG_L2PROT]); isdn_free_channel(info->isdn_driver, info->isdn_channel, usage); } @@ -1094,8 +1150,14 @@ isdn_tty_resume(char *id, modem_info * info, atemu * m) si = bit2si[j]; break; } + usg = isdn_calc_usage(si, l2); #ifdef CONFIG_ISDN_AUDIO - if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) { + if ((si == 1) && + (l2 != ISDN_PROTO_L2_MODEM) +#ifdef CONFIG_ISDN_TTY_FAX + && (l2 != ISDN_PROTO_L2_FAX) +#endif + ) { l2 = ISDN_PROTO_L2_TRANS; usg = ISDN_USAGE_VOICE; } @@ -1182,8 +1244,14 @@ isdn_tty_send_msg(modem_info * info, atemu * m, char *msg) si = bit2si[j]; break; } + usg = isdn_calc_usage(si, l2); #ifdef CONFIG_ISDN_AUDIO - if ((si == 1) && (l2 != ISDN_PROTO_L2_MODEM)) { + if ((si == 1) && + (l2 != ISDN_PROTO_L2_MODEM) +#ifdef CONFIG_ISDN_TTY_FAX + && (l2 != ISDN_PROTO_L2_FAX) +#endif + ) { l2 = ISDN_PROTO_L2_TRANS; usg = ISDN_USAGE_VOICE; } @@ -2168,8 +2236,42 @@ isdn_tty_modem_reset_vpar(atemu * m) m->vpar[1] = 0; /* Silence detection level (0 = none ) */ m->vpar[2] = 70; /* Silence interval (7 sec. ) */ m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */ - m->vpar[4] = 0; /* DTMF detection level (0 = softcode ) */ - m->vpar[5] = 8; /* DTMF interval (8 * 5 ms. ) */ + m->vpar[4] = 0; /* DTMF detection level (0 = softcode ) */ + m->vpar[5] = 8; /* DTMF interval (8 * 5 ms. ) */ +} +#endif + +#ifdef CONFIG_ISDN_TTY_FAX +static void +isdn_tty_modem_reset_faxpar(modem_info * info) +{ + T30_s *f = info->fax; + + f->code = 0; + f->phase = ISDN_FAX_PHASE_IDLE; + f->direction = 0; + f->resolution = 1; /* fine */ + f->rate = 5; /* 14400 bit/s */ + f->width = 0; + f->length = 0; + f->compression = 0; + f->ecm = 0; + f->binary = 0; + f->scantime = 0; + memset(&f->id[0], 32, FAXIDLEN - 1); + f->id[FAXIDLEN - 1] = 0; + f->badlin = 0; + f->badmul = 0; + f->bor = 0; + f->nbc = 0; + f->cq = 0; + f->cr = 0; + f->ctcrty = 0; + f->minsp = 0; + f->phcto = 30; + f->rel = 0; + memset(&f->pollid[0], 32, FAXIDLEN - 1); + f->pollid[FAXIDLEN - 1] = 0; } #endif @@ -2185,6 +2287,9 @@ isdn_tty_modem_reset_regs(modem_info * info, int force) } #ifdef CONFIG_ISDN_AUDIO isdn_tty_modem_reset_vpar(m); +#endif +#ifdef CONFIG_ISDN_TTY_FAX + isdn_tty_modem_reset_faxpar(info); #endif m->mdmcmdl = 0; } @@ -2258,6 +2363,12 @@ isdn_tty_modem_init(void) } for (i = 0; i < ISDN_MAX_CHANNELS; i++) { info = &m->info[i]; +#ifdef CONFIG_ISDN_TTY_FAX + if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) { + printk(KERN_ERR "Could not allocate fax t30-buffer\n"); + return -3; + } +#endif #ifdef COMPAT_HAS_NEW_WAITQ init_MUTEX(&info->write_sem); #else @@ -2420,8 +2531,7 @@ isdn_tty_find_icall(int di, int ch, setup_parm setup) 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; + dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]); strcpy(dev->num[idx], nr); strcpy(info->emu.cpn, eaz); info->emu.mdmreg[REG_SI1I] = si2bit[si1]; @@ -2599,6 +2709,13 @@ isdn_tty_stat_callback(int i, isdn_ctrl * c) } } return 1; +#ifdef CONFIG_ISDN_TTY_FAX + case ISDN_STAT_FAXIND: + if (TTY_IS_ACTIVE(info)) { + isdn_tty_fax_command(info); + } + break; +#endif #ifdef CONFIG_ISDN_AUDIO case ISDN_STAT_AUDIO: if (TTY_IS_ACTIVE(info)) { @@ -3383,7 +3500,7 @@ isdn_tty_cmd_ATA(modem_info * info) /* 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) { - if (l2 != ISDN_PROTO_L2_MODEM) + if ((l2 != ISDN_PROTO_L2_MODEM) && (l2 != ISDN_PROTO_L2_FAX)) l2 = ISDN_PROTO_L2_TRANS; } else l2 = ISDN_PROTO_L2_X75I; @@ -3397,6 +3514,12 @@ isdn_tty_cmd_ATA(modem_info * info) cmd.driver = info->isdn_driver; cmd.command = ISDN_CMD_SETL3; cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); +#ifdef CONFIG_ISDN_TTY_FAX + if (l2 == ISDN_PROTO_L2_FAX) { + cmd.parm.fax = info->fax; + info->fax->direction = ISDN_TTY_FAX_CONN_IN; + } +#endif isdn_command(&cmd); cmd.driver = info->isdn_driver; cmd.arg = info->isdn_channel; @@ -3417,7 +3540,6 @@ static int isdn_tty_cmd_PLUSF(char **p, modem_info * info) { atemu *m = &info->emu; - int par; char rs[20]; if (!strncmp(p[0], "CLASS", 5)) { @@ -3427,6 +3549,10 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info) p[0]++; sprintf(rs, "\r\n%d", (m->mdmreg[REG_SI1] & 1) ? 8 : 0); +#ifdef CONFIG_ISDN_TTY_FAX + if (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) + sprintf(rs, "\r\n2"); +#endif isdn_tty_at_cout(rs, info); break; case '=': @@ -3434,23 +3560,37 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info) switch (*p[0]) { case '0': p[0]++; + m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; + m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS; m->mdmreg[REG_SI1] = 4; info->xmit_size = m->mdmreg[REG_PSIZE] * 16; break; +#ifdef CONFIG_ISDN_TTY_FAX case '2': - printk(KERN_DEBUG "isdn_tty: FCLASS=2\n"); p[0]++; + m->mdmreg[REG_SI1] = 1; + m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX; + m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FAX; + info->xmit_size = + m->mdmreg[REG_PSIZE] * 16; break; +#endif case '8': p[0]++; + /* L2 will change on dialout with si=1 */ + m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; + m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS; m->mdmreg[REG_SI1] = 5; info->xmit_size = VBUF; break; case '?': p[0]++; - isdn_tty_at_cout("\r\n0,2,8", - info); +#ifdef CONFIG_ISDN_TTY_FAX + isdn_tty_at_cout("\r\n0,2,8", info); +#else + isdn_tty_at_cout("\r\n0,8", info); +#endif break; default: PARSE_ERROR1; @@ -3461,115 +3601,11 @@ isdn_tty_cmd_PLUSF(char **p, modem_info * info) } return 0; } - if (!strncmp(p[0], "AA", 2)) { - p[0] += 2; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", - m->mdmreg[REG_RINGATA]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - m->mdmreg[REG_RINGATA] = par; - break; - default: - PARSE_ERROR1; - } - return 0; - } - if (!strncmp(p[0], "TBC=", 4)) { /* UNKLAR !! */ - p[0] += 4; - printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]); - switch (*p[0]) { - case '0': - p[0]++; - break; - default: - PARSE_ERROR1; - } - return 0; - } - if (!strncmp(p[0], "BOR=", 4)) { /* UNKLAR !! */ - p[0] += 4; - printk(KERN_DEBUG "isdn_tty: Fax FBOR=%c\n", *p[0]); - switch (*p[0]) { - case '0': - p[0]++; - break; - default: - PARSE_ERROR1; - } - return 0; - } - if (!strncmp(p[0], "DCC=", 4)) { /* SETUP irgendwie !! */ - int i, val[]={0,0,0,0,0,0,0,0}; - - p[0] += 4; - if (*p[0] == '?') { - isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0,1),(0),(0),(0-7)",info); - p[0]++; - } else { - for (i=0; (*p[0]>='0') && (*p[0]<='9'); i++) { - val[i] = *p[0] - 48; - p[0]++; - if (*p[0] == ',') - p[0]++; - } - printk(KERN_DEBUG "isdn_tty: Fax Setup values=%d,%d,%d,%d,%d,%d,%d,%d\n", - val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]); - } - return 0; - } - if (!strncmp(p[0], "LID=", 4)) { /* set sender ID !! */ - char senderID[80]; - int i; - - p[0] += 4; - if (*p[0] =='"') - p[0]++; - for(i=0; (*p[0]) && (*p[0] != '"'); i++) - senderID[i] = *p[0]++; - senderID[i] = 0; - if (*p[0] =='"') - p[0]++; - printk(KERN_DEBUG "isdn_tty: Fax sender=>%s<\n", senderID); - return 0; - } - if (!strncmp(p[0], "MFR?", 4)) { - p[0] += 4; - printk(KERN_DEBUG "isdn_tty: FMFR?\n"); - isdn_tty_at_cout("\r\nISDNfax", info); - return 0; - } - if (!strncmp(p[0], "MDL?", 4)) { - p[0] += 4; - printk(KERN_DEBUG "isdn_tty: FMDL?\n"); - isdn_tty_at_cout("\r\nAVM-B1", info); - return 0; - } - if (!strncmp(p[0], "AP=?", 4)) { - p[0] += 4; - printk(KERN_DEBUG "isdn_tty: FAP=?\n"); - return 0; - } - if (!strncmp(p[0], "PHCTO=", 6)) { - /* beim trace mit dem zyxel folgt der wert 30 ;*/ - p[0] += 6; - printk(KERN_DEBUG "isdn_tty: FPHCTO=%s\n", p[0]); - return 0; - } - if (!strncmp(p[0], "CR=", 3)) { - p[0] += 3; - printk(KERN_DEBUG "isdn_tty: FCR=%s\n", p[0]); - return 0; - } - printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]); +#ifdef CONFIG_ISDN_TTY_FAX + return (isdn_tty_cmd_PLUSF_FAX(p, info)); +#else PARSE_ERROR1; +#endif } /* diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h index 51aa8629..e2a81242 100644 --- a/drivers/isdn/isdn_tty.h +++ b/drivers/isdn/isdn_tty.h @@ -20,6 +20,17 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log$ + * Revision 1.14 1999/07/11 17:14:15 armin + * Added new layer 2 and 3 protocols for Fax and DSP functions. + * Moved "Add CPN to RING message" to new register S23, + * "Display message" is now correct on register S13 bit 7. + * New audio command AT+VDD implemented (deactivate DTMF decoder and + * activate possible existing hardware/DSP decoder). + * Moved some tty defines to .h file. + * Made whitespace possible in AT command line. + * Some AT-emulator output bugfixes. + * First Fax G3 implementations. + * * Revision 1.13 1999/04/12 12:33:46 fritz * Changes from 2.0 tree. * @@ -146,3 +157,9 @@ extern int isdn_tty_stat_callback(int, isdn_ctrl *); extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *); extern int isdn_tty_capi_facility(capi_msg *cm); extern void isdn_tty_at_cout(char *, modem_info *); +extern void isdn_tty_modem_hup(modem_info *, int); +#ifdef CONFIG_ISDN_TTY_FAX +extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *); +extern int isdn_tty_fax_command(modem_info *); +extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *); +#endif diff --git a/drivers/isdn/isdn_ttyfax.c b/drivers/isdn/isdn_ttyfax.c new file mode 100644 index 00000000..589aabca --- /dev/null +++ b/drivers/isdn/isdn_ttyfax.c @@ -0,0 +1,1194 @@ +/* $Id$ + * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel). + * + * Copyright 1999 by Armin Schindler (mac@melware.de) + * Copyright 1999 by Ralf Spachmann (mel@melware.de) + * Copyright 1999 by Cytronics & Melware + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log$ + * + */ + +#undef ISDN_TTY_FAX_STAT_DEBUG +#undef ISDN_TTY_FAX_CMD_DEBUG + +#define __NO_VERSION__ +#include +#include +#include +#include "isdn_common.h" +#include "isdn_tty.h" +#include "isdn_ttyfax.h" + + +static char *isdn_tty_fax_revision = "$Revision$"; + +#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; } + +static char * +isdn_getrev(const char *revision) +{ + char *rev; + char *p; + + if ((p = strchr(revision, ':'))) { + rev = p + 2; + p = strchr(rev, '$'); + *--p = 0; + } else + rev = "???"; + return rev; +} + + +/* + * Fax Class 2 Modem results + * + */ +static void isdn_tty_fax_modem_result(int code, modem_info * info) +{ + atemu *m = &info->emu; + T30_s *f = info->fax; + char rs[50]; + char rss[20]; + char *rp; + int i; + static char *msg[] = + {"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:", + "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:", + "+FCFR", "+FPTS:", "+FET:" }; + + + isdn_tty_at_cout("\r\n", info); + isdn_tty_at_cout(msg[code], info); + +#ifdef ISDN_TTY_FAX_CMD_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax send %s on ttyI%d\n", + msg[code], info->line); +#endif + switch (code) { + case 0: /* OK */ + break; + case 1: /* ERROR */ + break; + case 2: /* +FCON */ + /* Append CPN, if enabled */ + if ((m->mdmreg[REG_CPN] & BIT_CPN) && + (!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) { + sprintf(rs, "/%s", m->cpn); + isdn_tty_at_cout(rs, info); + } + info->online = 1; + f->fet = 0; + if (f->phase == ISDN_FAX_PHASE_A) + f->phase = ISDN_FAX_PHASE_B; + break; + case 3: /* +FCSI */ + case 8: /* +FTSI */ + sprintf(rs, "\"%s\"", f->r_id); + isdn_tty_at_cout(rs, info); + break; + case 4: /* +FDIS */ + rs[0] = 0; + rp = &f->r_resolution; + for(i = 0; i < 8; i++) { + sprintf(rss, "%c%s", rp[i] + 48, + (i < 7) ? "," : ""); + strcat(rs, rss); + } + isdn_tty_at_cout(rs, info); +#ifdef ISDN_TTY_FAX_CMD_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n", + rs, info->line); +#endif + break; + case 5: /* +FHNG */ + sprintf(rs, "%d", f->code); + isdn_tty_at_cout(rs, info); + info->faxonline = 0; + break; + case 6: /* +FDCS */ + rs[0] = 0; + rp = &f->r_resolution; + for(i = 0; i < 8; i++) { + sprintf(rss, "%c%s", rp[i] + 48, + (i < 7) ? "," : ""); + strcat(rs, rss); + } + isdn_tty_at_cout(rs, info); +#ifdef ISDN_TTY_FAX_CMD_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n", + rs, info->line); +#endif + break; + case 7: /* CONNECT */ + info->faxonline |= 2; + break; + case 9: /* FCFR */ + break; + case 10: /* FPTS */ + isdn_tty_at_cout("1", info); + break; + case 11: /* FET */ + sprintf(rs, "%d", f->fet); + isdn_tty_at_cout(rs, info); + break; + } + + isdn_tty_at_cout("\r\n", info); + + switch (code) { + case 7: /* CONNECT */ + info->online = 2; + if (info->faxonline & 1) { + sprintf(rs, "%c", XON); + isdn_tty_at_cout(rs, info); + } + break; + } +} + +int +isdn_tty_fax_command(modem_info * info) +{ + T30_s *f = info->fax; + char rs[10]; + +#ifdef ISDN_TTY_FAX_CMD_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n", + f->r_code, info->line); +#endif + switch(f->r_code) { + case ISDN_TTY_FAX_FCON: + info->faxonline = 1; + isdn_tty_fax_modem_result(2, info); /* +FCON */ + return(0); + case ISDN_TTY_FAX_FCON_I: + info->faxonline = 16; + isdn_tty_fax_modem_result(2, info); /* +FCON */ + return(0); + case ISDN_TTY_FAX_RID: + if (info->faxonline & 1) + isdn_tty_fax_modem_result(3, info); /* +FCSI */ + if (info->faxonline & 16) + isdn_tty_fax_modem_result(8, info); /* +FTSI */ + return(0); + case ISDN_TTY_FAX_DIS: + isdn_tty_fax_modem_result(4, info); /* +FDIS */ + return(0); + case ISDN_TTY_FAX_HNG: + if (f->phase == ISDN_FAX_PHASE_C) { + if (f->direction == ISDN_TTY_FAX_CONN_IN) { + sprintf(rs, "%c%c", DLE, ETX); + isdn_tty_at_cout(rs, info); + } else { + sprintf(rs, "%c", 0x18); + isdn_tty_at_cout(rs, info); + } + info->faxonline &= ~2; /* leave data mode */ + info->online = 1; + } + f->phase = ISDN_FAX_PHASE_E; + isdn_tty_fax_modem_result(5, info); /* +FHNG */ + isdn_tty_fax_modem_result(0, info); /* OK */ + return(0); + case ISDN_TTY_FAX_DCS: + isdn_tty_fax_modem_result(6, info); /* +FDCS */ + isdn_tty_fax_modem_result(7, info); /* CONNECT */ + f->phase = ISDN_FAX_PHASE_C; + return(0); + case ISDN_TTY_FAX_TRAIN_OK: + isdn_tty_fax_modem_result(6, info); /* +FDCS */ + isdn_tty_fax_modem_result(0, info); /* OK */ + return(0); + case ISDN_TTY_FAX_SENT: + isdn_tty_fax_modem_result(0, info); /* OK */ + return(0); + case ISDN_TTY_FAX_CFR: + isdn_tty_fax_modem_result(9, info); /* +FCFR */ + return(0); + case ISDN_TTY_FAX_ET: + sprintf(rs, "%c%c", DLE, ETX); + isdn_tty_at_cout(rs, info); + isdn_tty_fax_modem_result(10, info); /* +FPTS */ + isdn_tty_fax_modem_result(11, info); /* +FET */ + isdn_tty_fax_modem_result(0, info); /* OK */ + info->faxonline &= ~2; /* leave data mode */ + info->online = 1; + f->phase = ISDN_FAX_PHASE_D; + return(0); + case ISDN_TTY_FAX_PTS: + isdn_tty_fax_modem_result(10, info); /* +FPTS */ + if (f->direction == ISDN_TTY_FAX_CONN_OUT) { + if (f->fet == 1) + f->phase = ISDN_FAX_PHASE_B; + if (f->fet == 0) + isdn_tty_fax_modem_result(0, info); /* OK */ + } + return(0); + case ISDN_TTY_FAX_EOP: + info->faxonline &= ~2; /* leave data mode */ + info->online = 1; + f->phase = ISDN_FAX_PHASE_D; + return(0); + + } + return(-1); +} + + +void +isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb) +{ + __u8 LeftMask; + __u8 RightMask; + __u8 fBit; + __u8 Data; + int i; + + if (!info->fax->bor) { + for(i = 0; i < skb->len; i++) { + Data = skb->data[i]; + for ( + LeftMask = 0x80, RightMask = 0x01; + LeftMask > RightMask; + LeftMask >>= 1, RightMask <<= 1 + ) { + fBit = (Data & LeftMask); + if (Data & RightMask) + Data |= LeftMask; + else + Data &= ~LeftMask; + if (fBit) + Data |= RightMask; + else + Data &= ~RightMask; + + } + skb->data[i] = Data; + } + } +} + +/* + * Parse AT+F.. FAX class 2 commands + */ + +int isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info) +{ + atemu *m = &info->emu; + T30_s *f = info->fax; + isdn_ctrl cmd; + int par; + char rs[50]; + char rss[20]; + int maxdccval[]={1,5,2,2,3,2,0,7}; + + /* FAA still unchanged */ + if (!strncmp(p[0], "AA", 2)) { /* TODO */ + p[0] += 2; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d", 0); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */ + if (!strncmp(p[0], "BADLIN", 6)) { + p[0] += 6; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d",f->badlin); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0-255"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + f->badlin = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* BADMUL=value - dummy 0=disable errorchk disabled (treshold multiplier) */ + if (!strncmp(p[0], "BADMUL", 6)){ + p[0] +=6; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d", f->badmul); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0-255"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + f->badmul = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* BOR=n - Phase C bit order, 0=direct, 1=reverse */ + if (!strncmp(p[0], "BOR", 3)){ + p[0] +=3; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d", f->bor); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0,1"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 1)) + PARSE_ERROR1; + f->bor = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* NBC=n - No Best Capabilities */ + if (!strncmp(p[0], "NBC", 3)){ + p[0] +=3; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d", f->nbc); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0,1"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 1)) + PARSE_ERROR1; + f->nbc = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* BUF? - Readonly buffersize readout */ + if (!strncmp(p[0], "BUF?", 4)) { + p[0] += 4; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE])); +#endif + p[0]++; + sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE])); + isdn_tty_at_cout(rs, info); + return 0; + } + + /* CIG=string - local fax station id string for polling rx */ + if (!strncmp(p[0], "CIG", 3)) { + int i, r; + p[0] += 3; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n\"%s\"", f->pollid); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n\"STRING\""); + isdn_tty_at_cout(rs, info); + } + else + { + if (*p[0] =='"') + p[0]++; + for(i=0; (*p[0]) && i < (FAXIDLEN-1) && (*p[0] != '"'); i++) + { + f->pollid[i] = *p[0]++; + } + if (*p[0] =='"') + p[0]++; + for(r=i; r < FAXIDLEN; r++) + { + f->pollid[r] = 32; + } + f->pollid[FAXIDLEN-1] = 0; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */ + if (!strncmp(p[0], "CQ", 2)) { + p[0] += 2; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d", f->cq); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0,1,2"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 2)) + PARSE_ERROR1; + f->cq = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */ + if (!strncmp(p[0], "CR", 2)) { + p[0] += 2; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */ + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0,1"); /* display online help */ + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 1)) + PARSE_ERROR1; + f->cr = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* CTCRTY=value - ECM retry count */ + if (!strncmp(p[0], "CTCRTY", 6)){ + p[0] +=6; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d",f->ctcrty); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0-255"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + f->ctcrty = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */ + if (!strncmp(p[0], "DCC", 3)) { + char *rp = &f->resolution; + int i; + + p[0] += 3; + switch(*p[0]) { + case '?': + p[0]++; + strcpy(rs, "\r\n"); + for(i = 0; i < 8; i++) { + sprintf(rss, "%c%s", rp[i] + 48, + (i < 7) ? "," : ""); + strcat(rs, rss); + } + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') { + isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)",info); + p[0]++; + } else { + for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<8); i++) { + if (*p[0] != ',') { + if ((*p[0] - 48) > maxdccval[i]) { + PARSE_ERROR1; + } + rp[i] = *p[0] - 48; + p[0]++; + if (*p[0] == ',') + p[0]++; + } else p[0]++; + } +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n", + rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */ + if (!strncmp(p[0], "DIS", 3)) { + char *rp = &f->resolution; + int i; + + p[0] += 3; + switch(*p[0]) { + case '?': + p[0]++; + strcpy(rs, "\r\n"); + for(i = 0; i < 8; i++) { + sprintf(rss, "%c%s", rp[i] + 48, + (i < 7) ? "," : ""); + strcat(rs, rss); + } + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') { + isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)",info); + p[0]++; + } else { + for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<8); i++) { + if (*p[0] != ',') { + if ((*p[0] - 48) > maxdccval[i]) { + PARSE_ERROR1; + } + rp[i] = *p[0] - 48; + p[0]++; + if (*p[0] == ',') + p[0]++; + } else p[0]++; + } +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n", + rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* DR - Receive Phase C data command, initiates document reception */ + if (!strncmp(p[0], "DR", 2)) { + p[0] += 2; + if ((info->faxonline & 16) && /* incoming connection */ + ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) { +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FDR\n"); +#endif + f->code = ISDN_TTY_FAX_DR; + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_FAXCMD; + isdn_command(&cmd); + if (f->phase == ISDN_FAX_PHASE_B) { + f->phase = ISDN_FAX_PHASE_C; + } else if (f->phase == ISDN_FAX_PHASE_D) { + switch(f->fet) { + case 0: /* next page will be received */ + f->phase = ISDN_FAX_PHASE_C; + isdn_tty_fax_modem_result(7, info); /* CONNECT */ + break; + case 1: /* next doc will be received */ + f->phase = ISDN_FAX_PHASE_B; + break; + case 2: /* fax session is terminating */ + f->phase = ISDN_FAX_PHASE_E; + break; + default: + PARSE_ERROR1; + } + } + } else { + PARSE_ERROR1; + } + return 1; + } + + /* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */ + if (!strncmp(p[0], "DT", 2)) { + int i, val[]={4,0,2,3}; + char *rp = &f->resolution; + + p[0] += 2; + if (!info->faxonline & 1) /* not outgoing connection */ + PARSE_ERROR1; + + for (i=0; (((*p[0]>='0')&&(*p[0]<='9'))||(*p[0]==','))&&(i<4); i++) { + if (*p[0] != ',') { + if ((*p[0] - 48) > maxdccval[val[i]]) { + PARSE_ERROR1; + } + rp[val[i]] = *p[0] - 48; + p[0]++; + if (*p[0] == ',') + p[0]++; + } else p[0]++; + } +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n", + rp[4], rp[0], rp[2], rp[3]); +#endif + if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) { + f->code = ISDN_TTY_FAX_DT; + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_FAXCMD; + isdn_command(&cmd); + if (f->phase == ISDN_FAX_PHASE_D) { + f->phase = ISDN_FAX_PHASE_C; + isdn_tty_fax_modem_result(7, info); /* CONNECT */ + } + } else { + PARSE_ERROR1; + } + return 1; + } + + /* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */ + if (!strncmp(p[0], "ECM", 3)) { + p[0] += 3; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d",f->ecm); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0,2"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par != 0) && (par != 2)) + PARSE_ERROR1; + f->ecm = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* ET=n - End of page or document */ + if (!strncmp(p[0], "ET=", 3)) { + p[0] += 3; + if (*p[0] == '?') { + p[0]++; + sprintf(rs, "\r\n0-2"); + isdn_tty_at_cout(rs, info); + } else { + if ((f->phase != ISDN_FAX_PHASE_D) || (!info->faxonline & 1)) + PARSE_ERROR1; + par = isdn_getnum(p); + if ((par < 0) || (par > 2)) + PARSE_ERROR1; + f->fet = par; + f->code = ISDN_TTY_FAX_ET; + cmd.driver = info->isdn_driver; + cmd.arg = info->isdn_channel; + cmd.command = ISDN_CMD_FAXCMD; + isdn_command(&cmd); +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par); +#endif + return 1; + } + return 0; + } + + /* K - terminate */ + if (!strncmp(p[0], "K", 1)) { + p[0] += 1; + if ((f->phase == ISDN_FAX_PHASE_IDLE) || (f->phase == ISDN_FAX_PHASE_E)) + PARSE_ERROR1; + isdn_tty_modem_hup(info, 1); + return 1; + } + + /* LID=string - local fax ID */ + if (!strncmp(p[0], "LID", 3)) { + int i, r; + p[0] += 3; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n\"%s\"", f->id); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n\"STRING\""); + isdn_tty_at_cout(rs, info); + } + else + { + if (*p[0] =='"') + p[0]++; + for(i=0; (*p[0]) && i < (FAXIDLEN-1) && (*p[0] != '"'); i++) + { + f->id[i] = *p[0]++; + } + if (*p[0] =='"') + p[0]++; + for(r=i; r < FAXIDLEN; r++) + { + f->id[r] = 32; + } + f->id[FAXIDLEN-1] = 0; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + +#if 0 + /* LO=n - Flow control opts */ + if (!strncmp(p[0], "LO", 2)) { /* TODO */ + p[0] += 2; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d",f->lo); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0,1,2"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 2)) + PARSE_ERROR1; + f->lo = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FLO=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } +#endif +#if 0 + /* LPL=n - Doc for polling cmd */ + if (!strncmp(p[0], "LPL", 3)) { /* TODO */ + p[0] += 3; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d",f->lpl); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0,1"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 1)) + PARSE_ERROR1; + f->lpl = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FLPL=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } +#endif + + /* MDL? - DCE Model */ + if (!strncmp(p[0], "MDL?", 4)) { + p[0] += 4; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: FMDL?\n"); +#endif + isdn_tty_at_cout("\r\nisdn4linux", info); + return 0; + } + + /* MFR? - DCE Manufacturer */ + if (!strncmp(p[0], "MFR?", 4)) { + p[0] += 4; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: FMFR?\n"); +#endif + isdn_tty_at_cout("\r\nisdn4linux", info); + return 0; + } + + /* MINSP=n - Minimum Speed for Phase C */ + if (!strncmp(p[0], "MINSP", 5)) { + p[0] += 5; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d",f->minsp); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0-5"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 5)) + PARSE_ERROR1; + f->minsp = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* PHCTO=value - DTE phase C timeout */ + if (!strncmp(p[0], "PHCTO", 5)){ + p[0] +=5; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d",f->phcto); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0-255"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 255)) + PARSE_ERROR1; + f->phcto = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + +#if 0 + /* PTS=n - Page transfer status */ + if (!strncmp(p[0], "PTS", 3)) { /* TODO */ + p[0] += 3; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d",f->pts); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0-5"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 5)) + PARSE_ERROR1; + f->pts = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FPTS=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } +#endif + + /* REL=n - Phase C received EOL alignment */ + if (!strncmp(p[0], "REL", 3)) { + p[0] += 3; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d",f->rel); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0,1"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 1)) + PARSE_ERROR1; + f->rel = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } + + /* REV? - DCE Revision */ + if (!strncmp(p[0], "REV?", 4)) { + p[0] += 4; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: FREV?\n"); +#endif + sprintf(rs, "\r\nRev: %s", isdn_getrev(isdn_tty_fax_revision)); + isdn_tty_at_cout(rs, info); + return 0; + } + +#if 0 + /* SPL=n - Enable polling */ + if (!strncmp(p[0], "SPL", 3)) { /* TODO */ + p[0] += 3; + switch (*p[0]) { + case '?': + p[0]++; + sprintf(rs, "\r\n%d", f->spl); + isdn_tty_at_cout(rs, info); + break; + case '=': + p[0]++; + if (*p[0] == '?') + { + p[0]++; + sprintf(rs, "\r\n0,1"); + isdn_tty_at_cout(rs, info); + } + else + { + par = isdn_getnum(p); + if ((par < 0) || (par > 1)) + PARSE_ERROR1; + f->spl = par; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FSPL=%d\n", par); +#endif + } + break; + default: + PARSE_ERROR1; + } + return 0; + } +#endif + + /* Phase C Transmit Data Block Size */ + if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */ + p[0] += 4; +#ifdef ISDN_TTY_FAX_STAT_DEBUG + printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]); +#endif + switch (*p[0]) { + case '0': + p[0]++; + break; + default: + PARSE_ERROR1; + } + return 0; + } + + printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]); + PARSE_ERROR1; +} + diff --git a/drivers/isdn/isdn_ttyfax.h b/drivers/isdn/isdn_ttyfax.h new file mode 100644 index 00000000..30369635 --- /dev/null +++ b/drivers/isdn/isdn_ttyfax.h @@ -0,0 +1,30 @@ +/* $Id$ + * header for Linux ISDN subsystem, tty_fax related functions (linklevel). + * + * Copyright 1999 by Armin Schindler (mac@melware.de) + * Copyright 1999 by Ralf Spachmann (mel@melware.de) + * Copyright 1999 by Cytronics & Melware + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Log$ + * + */ + + +#define XON 0x11 +#define XOFF 0x13 +#define DC2 0x12 + diff --git a/include/linux/isdn.h b/include/linux/isdn.h index cb92c937..14b6911a 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log$ + * Revision 1.69 1999/07/13 20:47:53 werner + * added channel bit ISDN_USAGE_DISABLED for limiting b-channel access. + * * Revision 1.68 1999/07/11 17:07:37 armin * Added tty modem register S23. * Added new layer 2 and 3 protocols for Fax and DSP functions. @@ -728,6 +731,10 @@ typedef struct modem_info { void *adpcmr; /* state for adpcm compression */ void *dtmf_state; /* state for dtmf decoder */ void *silence_state; /* state for silence detection */ +#endif +#ifdef CONFIG_ISDN_TTY_FAX + struct T30_s *fax; /* T30 Fax Group 3 data/interface */ + int faxonline; /* Fax-channel status */ #endif struct tty_struct *tty; /* Pointer to corresponding tty */ atemu emu; /* AT-emulator data */ diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h index 13054d18..b0071398 100644 --- a/include/linux/isdnif.h +++ b/include/linux/isdnif.h @@ -22,6 +22,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log$ + * Revision 1.28 1999/07/13 20:57:48 werner + * added callback ISDN_STAT_DISCH for limiting b-channel resources. + * * Revision 1.27 1999/07/11 17:07:39 armin * Added tty modem register S23. * Added new layer 2 and 3 protocols for Fax and DSP functions. @@ -370,6 +373,84 @@ typedef struct setup_parm { unsigned char screen; /* Screening info */ } setup_parm; + +#ifdef CONFIG_ISDN_TTY_FAX +/* T.30 Fax G3 */ + +#define FAXIDLEN 21 + +typedef struct T30_s { + /* session parameters */ + __u8 resolution __attribute__ ((packed)); + __u8 rate __attribute__ ((packed)); + __u8 width __attribute__ ((packed)); + __u8 length __attribute__ ((packed)); + __u8 compression __attribute__ ((packed)); + __u8 ecm __attribute__ ((packed)); + __u8 binary __attribute__ ((packed)); + __u8 scantime __attribute__ ((packed)); + __u8 id[FAXIDLEN] __attribute__ ((packed)); + /* additional parameters */ + __u8 phase __attribute__ ((packed)); + __u8 direction __attribute__ ((packed)); + __u8 code __attribute__ ((packed)); + __u8 badlin __attribute__ ((packed)); + __u8 badmul __attribute__ ((packed)); + __u8 bor __attribute__ ((packed)); + __u8 fet __attribute__ ((packed)); + __u8 pollid[FAXIDLEN] __attribute__ ((packed)); + __u8 cq __attribute__ ((packed)); + __u8 cr __attribute__ ((packed)); + __u8 ctcrty __attribute__ ((packed)); + __u8 minsp __attribute__ ((packed)); + __u8 phcto __attribute__ ((packed)); + __u8 rel __attribute__ ((packed)); + __u8 nbc __attribute__ ((packed)); + /* remote station parameters */ + __u8 r_resolution __attribute__ ((packed)); + __u8 r_rate __attribute__ ((packed)); + __u8 r_width __attribute__ ((packed)); + __u8 r_length __attribute__ ((packed)); + __u8 r_compression __attribute__ ((packed)); + __u8 r_ecm __attribute__ ((packed)); + __u8 r_binary __attribute__ ((packed)); + __u8 r_scantime __attribute__ ((packed)); + __u8 r_id[FAXIDLEN] __attribute__ ((packed)); + __u8 r_code __attribute__ ((packed)); +} T30_s; + +#define ISDN_TTY_FAX_CONN_IN 0 +#define ISDN_TTY_FAX_CONN_OUT 1 + +#define ISDN_TTY_FAX_FCON 0 +#define ISDN_TTY_FAX_DIS 1 +#define ISDN_TTY_FAX_FTT 2 +#define ISDN_TTY_FAX_MCF 3 +#define ISDN_TTY_FAX_DCS 4 +#define ISDN_TTY_FAX_TRAIN_OK 5 +#define ISDN_TTY_FAX_EOP 6 +#define ISDN_TTY_FAX_EOM 7 +#define ISDN_TTY_FAX_MPS 8 +#define ISDN_TTY_FAX_DTC 9 +#define ISDN_TTY_FAX_RID 10 +#define ISDN_TTY_FAX_HNG 11 +#define ISDN_TTY_FAX_DT 12 +#define ISDN_TTY_FAX_FCON_I 13 +#define ISDN_TTY_FAX_DR 14 +#define ISDN_TTY_FAX_ET 15 +#define ISDN_TTY_FAX_CFR 16 +#define ISDN_TTY_FAX_PTS 17 +#define ISDN_TTY_FAX_SENT 18 + +#define ISDN_FAX_PHASE_IDLE 0 +#define ISDN_FAX_PHASE_A 1 +#define ISDN_FAX_PHASE_B 2 +#define ISDN_FAX_PHASE_C 3 +#define ISDN_FAX_PHASE_D 4 +#define ISDN_FAX_PHASE_E 5 + +#endif /* TTY_FAX */ + /* CAPI structs */ /* this is compatible to the old union size */ @@ -408,6 +489,9 @@ typedef struct { capi_msg cmsg; /* For CAPI like messages */ char display[85];/* display message data */ dss1_cmd_stat dss1_io; /* DSS1 IO-parameter/result */ +#ifdef CONFIG_ISDN_TTY_FAX + T30_s *fax; /* Pointer to ttys fax struct */ +#endif } parm; } isdn_ctrl; diff --git a/std2kern b/std2kern index bd8e3001..023fbcc0 100755 --- a/std2kern +++ b/std2kern @@ -124,6 +124,12 @@ else patch -d $KERNELDIR/Documentation < Documentation/Configure.help.divert.diff fi fi + if [ -f $KERNELDIR/Documentation/Configure.help ] ; then + grep -q CONFIG_ISDN_DRV_EICON $KERNELDIR/Documentation/Configure.help + if [ $? != 0 ] ; then + patch -d $KERNELDIR/Documentation < Documentation/Configure.help.eicon.diff + fi + fi mkdir -p -m 755 $KERNELDIR/drivers/isdn/eicon for i in drivers/isdn/eicon/*.[ch] ; do $DOCP $i $KERNELDIR/$i