📄 isdn_tty.c
字号:
info->xmit_count = 0;#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 * US, Canada and Japan. * Later, when US-ISDN protocols are implemented, * this setting will depend on the D-channel protocol. */ int ifmt = 1; /* voice conversion/decompression */ switch (info->emu.vpar[3]) { case 2: case 3: case 4: /* adpcm, compatible to ZyXel 1496 modem * with ROM revision 6.01 */ 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(skb->data, buflen); break; case 6: /* u-law */ if (ifmt) isdn_audio_ulaw2alaw(skb->data, buflen); break; } }#endif /* CONFIG_ISDN_AUDIO */ if (info->emu.mdmreg[REG_T70] & BIT_T70) { /* Add T.70 simplified header */ if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) memcpy(skb_push(skb, 2), "\1\0", 2); else memcpy(skb_push(skb, 4), "\1\0\1\0", 4); } skb_queue_tail(&info->xmit_queue, skb);}/************************************************************ * * Modem-functions * * mostly "stolen" from original Linux-serial.c and friends. * ************************************************************//* The next routine is called once from within timer-interrupt * triggered within isdn_tty_modem_ncarrier(). It calls * isdn_tty_modem_result() to stuff a "NO CARRIER" Message * into the tty's flip-buffer. */static voidisdn_tty_modem_do_ncarrier(unsigned long data){ modem_info *info = (modem_info *) data; isdn_tty_modem_result(RESULT_NO_CARRIER, info);}/* Next routine is called, whenever the DTR-signal is raised. * It checks the ncarrier-flag, and triggers the above routine * when necessary. The ncarrier-flag is set, whenever DTR goes * low. */static voidisdn_tty_modem_ncarrier(modem_info * info){ if (info->ncarrier) { info->nc_timer.expires = jiffies + HZ; info->nc_timer.function = isdn_tty_modem_do_ncarrier; info->nc_timer.data = (unsigned long) info; add_timer(&info->nc_timer); }}/* * return the usage calculated by si and layer 2 protocol */intisdn_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. */static voidisdn_tty_dial(char *n, 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; for (j = 7; j >= 0; j--) if (m->mdmreg[REG_SI1] & (1 << j)) { si = bit2si[j]; break; } usg = isdn_calc_usage(si, l2);#ifdef CONFIG_ISDN_AUDIO 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; }#endif m->mdmreg[REG_SI1I] = si2bit[si]; save_flags(flags); cli(); i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); isdn_tty_modem_result(RESULT_NO_DIALTONE, 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);#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; sprintf(cmd.parm.setup.phone, "%s", n); sprintf(cmd.parm.setup.eazmsn, "%s", isdn_map_eaz2msn(m->msn, info->isdn_driver)); cmd.parm.setup.si1 = si; 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); }}/* isdn_tty_hangup() disassociates a tty from the real * ISDN-line (hangup). The usage-status is cleared * and some cleanup is done also. */voidisdn_tty_modem_hup(modem_info * info, int local){ isdn_ctrl cmd; int di, ch; if (!info) return; di = info->isdn_driver; ch = info->isdn_channel; if (di < 0 || ch < 0) return; info->isdn_driver = -1; info->isdn_channel = -1;#ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup ttyI%d\n", info->line);#endif info->rcvsched = 0; isdn_tty_flush_buffer(info->tty); if (info->online) { info->last_lhup = local; info->online = 0; isdn_tty_modem_result(RESULT_NO_CARRIER, info); }#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) { 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; } if (info->adpcmr) { kfree(info->adpcmr); info->adpcmr = NULL; }#endif if ((info->msr & UART_MSR_RI) && (info->emu.mdmreg[REG_RUNG] & BIT_RUNG)) isdn_tty_modem_result(RESULT_RUNG, info); info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); info->lsr |= UART_LSR_TEMT; if (local) { cmd.driver = di; cmd.command = ISDN_CMD_HANGUP; cmd.arg = ch; isdn_command(&cmd); } isdn_all_eaz(di, ch); info->emu.mdmreg[REG_RINGCNT] = 0; isdn_free_channel(di, ch, 0); if (info->drv_index >= 0) { dev->m_idx[info->drv_index] = -1; info->drv_index = -1; }}/* * Begin of a CAPI like interface, currently used only for * supplementary service (CAPI 2.0 part III) */#include <linux/isdn/capicmd.h>intisdn_tty_capi_facility(capi_msg *cm) { return(-1); /* dummy */}/* isdn_tty_suspend() tries to suspend the current tty connection */static voidisdn_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)) { cmd.parm.cmsg.Length = l+18; 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 voidisdn_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); for (j = 7; j >= 0; j--) if (m->mdmreg[REG_SI1] & (1 << j)) { si = bit2si[j]; break; } usg = isdn_calc_usage(si, l2);#ifdef CONFIG_ISDN_AUDIO 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; }#endif m->mdmreg[REG_SI1I] = si2bit[si]; save_flags(flags); cli(); i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); isdn_tty_modem_result(RESULT_NO_DIALTONE, 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+18; 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_timer_ctrl(ISDN_TIMER_CARRIER, 1); }}/* 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 voidisdn_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(RESULT_ERROR, info); return; } for (j = 7; j >= 0; j--) if (m->mdmreg[REG_SI1] & (1 << j)) { si = bit2si[j]; break; } usg = isdn_calc_usage(si, l2);#ifdef CONFIG_ISDN_AUDIO 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; }#endif m->mdmreg[REG_SI1I] = si2bit[si]; save_flags(flags); cli(); i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); if (i < 0) { restore_flags(flags); isdn_tty_modem_result(RESULT_NO_DIALTONE, 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -