📄 isdn_tty.c
字号:
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 { int tmp; tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di));#ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n", isdn_map_eaz2msn(emu->msn, di), tmp);#endif return tmp; }}/* * An incoming call-request has arrived. * Search the tty-devices for an appropriate device and bind * it to the ISDN-Channel. * Return: * * 0 = No matching device found. * 1 = A matching device found. * 3 = No match found, but eventually would match, if * CID is longer. */intisdn_tty_find_icall(int di, int ch, setup_parm *setup){ char *eaz; int i; int wret; int idx; int si1; int si2; char *nr; ulong flags; if (!setup->phone[0]) { nr = "0"; printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n"); } else nr = setup->phone; si1 = (int) setup->si1; si2 = (int) setup->si2; if (!setup->eazmsn[0]) { printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n"); eaz = "0"; } else eaz = setup->eazmsn;#ifdef ISDN_DEBUG_MODEM_ICALL printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2);#endif wret = 0; spin_lock_irqsave(&dev->lock, flags); for (i = 0; i < ISDN_MAX_CHANNELS; i++) { modem_info *info = &dev->mdm.info[i]; if (info->count == 0) continue; 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 wret=%d\n", wret); printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx, info->flags, info->isdn_driver, info->isdn_channel, dev->usage[idx]);#endif if (#ifndef FIX_FILE_TRANSFER (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) &&#endif (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] |= 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]; info->emu.mdmreg[REG_PLAN] = setup->plan; info->emu.mdmreg[REG_SCREEN] = setup->screen; isdn_info_update(); spin_unlock_irqrestore(&dev->lock, 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(RESULT_RING, info); isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); return 1; } } } } spin_unlock_irqrestore(&dev->lock, flags); 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) \ (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE))intisdn_tty_stat_callback(int i, isdn_ctrl *c){ int mi; modem_info *info; char *e; if (i < 0) return 0; if ((mi = dev->m_idx[i]) >= 0) { info = &dev->mdm.info[mi]; switch (c->command) { 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 == (char *)c->parm.num) info->emu.charge = 0; break; 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_DISPLAY:#ifdef ISDN_TTY_STAT_DEBUG printk(KERN_DEBUG "tty_STAT_DISPLAY ttyI%d\n", info->line);#endif /* Signal display to tty-device */ if ((info->emu.mdmreg[REG_DISPLAY] & BIT_DISPLAY) && !(info->emu.mdmreg[REG_RESPNUM] & BIT_RESPNUM)) { isdn_tty_at_cout("\r\n", info); isdn_tty_at_cout("DISPLAY: ", info); isdn_tty_at_cout(c->parm.display, info); isdn_tty_at_cout("\r\n", info); } 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) isdn_tty_modem_result(RESULT_BUSY, info); if (info->dialing > 1) isdn_tty_modem_result(RESULT_NO_CARRIER, info); info->dialing = 0;#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 /* Wake up any processes waiting * for incoming call of this device when * DCD follow the state of incoming carrier */ if (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD)) { wake_up_interruptible(&info->open_wait); } /* Schedule CONNECT-Message to any tty * waiting for it and * set DCD-bit of its modem-status. */ if (TTY_IS_ACTIVE(info) || (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) { info->msr |= UART_MSR_DCD; info->emu.charge = 0; if (info->dialing & 0xf) info->last_dir = 1; else info->last_dir = 0; info->dialing = 0; info->rcvsched = 1; 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(RESULT_CONNECT, info); } else isdn_tty_modem_result(RESULT_CONNECT64000, info); } if (USG_VOICE(dev->usage[i])) isdn_tty_modem_result(RESULT_VCON, 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(RESULT_NO_DIALTONE, info); } isdn_tty_modem_hup(info, 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;#ifdef CONFIG_ISDN_TTY_FAX case ISDN_STAT_FAXIND: if (TTY_IS_ACTIVE(info)) { isdn_tty_fax_command(info, c); } break;#endif#ifdef CONFIG_ISDN_AUDIO case ISDN_STAT_AUDIO: if (TTY_IS_ACTIVE(info)) { switch(c->parm.num[0]) { case ISDN_AUDIO_DTMF: if (info->vonline) { isdn_audio_put_dle_code(info, c->parm.num[1]); } break; } } break;#endif } } return 0;}/********************************************************************* Modem-Emulator-Routines *********************************************************************/#define cmdchar(c) ((c>=' ')&&(c<=0x7f))/* * Put a message from the AT-emulator into receive-buffer of tty, * convert CR, LF, and BS to values in modem-registers 3, 4 and 5. */voidisdn_tty_at_cout(char *msg, modem_info * info){ struct tty_struct *tty; atemu *m = &info->emu; char *p; char c; u_long flags; struct sk_buff *skb = NULL; char *sp = NULL; if (!msg) { printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n"); return; } spin_lock_irqsave(&info->readlock, flags); tty = info->tty; if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) { spin_unlock_irqrestore(&info->readlock, flags); return; } /* use queue instead of direct flip, if online and */ /* data is in queue or flip buffer is full */ if ((info->online) && (((tty->flip.count + strlen(msg)) >= TTY_FLIPBUF_SIZE) || (!skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel])))) { skb = alloc_skb(strlen(msg), GFP_ATOMIC); if (!skb) { spin_unlock_irqrestore(&info->readlock, flags); return; } sp = skb_put(skb, strlen(msg));#ifdef CONFIG_ISDN_AUDIO ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; ISDN_AUDIO_SKB_LOCK(skb) = 0;#endif } for (p = msg; *p; p++) { switch (*p) { case '\r': c = m->mdmreg[REG_CR]; break; case '\n': c = m->mdmreg[REG_LF]; break; case '\b': c = m->mdmreg[REG_BS]; break; default: c = *p; } if (skb) { *sp++ = c; } else { if (tty->flip.count >= TTY_FLIPBUF_SIZE) break; tty_insert_flip_char(tty, c, 0); } } if (skb) { __skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb); dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len; spin_unlock_irqrestore(&info->readlock, flags); /* Schedule dequeuing */ if ((dev->modempoll) && (info->rcvsched)) isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); } else { spin_unlock_irqrestore(&info->readlock, flags); schedule_delayed_work(&tty->flip.work, 1); }}/* * Perform ATH Hangup */static voidisdn_tty_on_hook(modem_info * info){ if (info->isdn_channel >= 0) {#ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n");#endif isdn_tty_modem_hup(info, 1); }}static voidisdn_tty_off_hook(void){ printk(KERN_DEBUG "isdn_tty_off_hook\n");}#define PLUSWAIT1 (HZ/2) /* 0.5 sec. */#define PLUSWAIT2 (HZ*3/2) /* 1.5 sec *//* * Check Buffer for Modem-escape-sequence, activate timer-callback to * isdn_tty_modem_escape() if sequence found. * * Parameters: * p pointer to databuffer * plus escape-character * count length of buffer * pluscount count of valid escape-characters so far * lastplus timestamp of last character */static voidisdn_tty_check_esc(const u_char * p, u_char plus, int count, int *pluscount, u_long *lastplus){ if (plus > 127) return; if (count > 3) { p += count - 3; count = 3; *pluscount = 0; } while (count > 0) { if (*(p++) == plus) { if ((*pluscount)++) { /* Time since last '+' > 0.5 sec. ? */ if (time_after(jiffies, *lastplus + PLUSWAIT1)) *pluscount = 1; } else { /* Time since last non-'+' < 1.5 sec. ? */ if (time_before(jiffies, *lastplus + PLUSWAIT2)) *pluscount = 0; } if ((*pluscount == 3) && (count == 1)) isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1); if (*pluscount > 3) *pluscount = 1; } else *pluscount = 0; *lastplus = jiffies; count--; }}/* * Return result of AT-emulator to tty-receive-buffer, depending on * modem-register 12, bit 0 and 1. * For CONNECT-messages also switch to online-mode. * For RING-message handle auto-ATA if register 0 != 0 */static voidisdn_tty_modem_result(int code, modem_info * info){ atemu *m = &info->emu; static char *msg[] = {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR", "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER", "RINGING", "NO MSN/EAZ", "VCON", "RUNG"}; char s[ISDN_MSNLEN+10]; switch (code) { case RESULT_RING: m->mdmreg[REG_RINGCNT]++; if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA]) /* Automatically accept incoming call */ isdn_tty_cmd_ATA(info); break; case RESULT_NO_CARRIER:#ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", (info->flags & ISDN_ASYNC_CLOSING), (!info->tty));#endif m->mdmreg[REG_RINGCNT] = 0; del_timer(&info->nc_timer); info->ncarrier = 0; if ((info->flags & ISDN_ASYNC_CLOSING) || (!info->tty)) { return; }#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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -