📄 isdn_tty.c
字号:
intisdn_tty_modem_init(void){ modem *m; int i; modem_info *info; m = &dev->mdm; memset(&m->tty_modem, 0, sizeof(struct tty_driver)); m->tty_modem.magic = TTY_DRIVER_MAGIC; m->tty_modem.name = isdn_ttyname_ttyI; m->tty_modem.major = ISDN_TTY_MAJOR; m->tty_modem.minor_start = 0; m->tty_modem.num = ISDN_MAX_CHANNELS; m->tty_modem.type = TTY_DRIVER_TYPE_SERIAL; m->tty_modem.subtype = ISDN_SERIAL_TYPE_NORMAL; m->tty_modem.init_termios = tty_std_termios; m->tty_modem.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; m->tty_modem.flags = TTY_DRIVER_REAL_RAW; m->tty_modem.refcount = &m->refcount; m->tty_modem.table = m->modem_table; m->tty_modem.termios = m->modem_termios; m->tty_modem.termios_locked = m->modem_termios_locked; m->tty_modem.open = isdn_tty_open; m->tty_modem.close = isdn_tty_close; m->tty_modem.write = isdn_tty_write; m->tty_modem.put_char = NULL; m->tty_modem.flush_chars = isdn_tty_flush_chars; m->tty_modem.write_room = isdn_tty_write_room; m->tty_modem.chars_in_buffer = isdn_tty_chars_in_buffer; m->tty_modem.flush_buffer = isdn_tty_flush_buffer; m->tty_modem.ioctl = isdn_tty_ioctl; m->tty_modem.throttle = isdn_tty_throttle; m->tty_modem.unthrottle = isdn_tty_unthrottle; m->tty_modem.set_termios = isdn_tty_set_termios; m->tty_modem.stop = NULL; m->tty_modem.start = NULL; m->tty_modem.hangup = isdn_tty_hangup; m->tty_modem.driver_name = "isdn_tty"; /* * The callout device is just like normal device except for * major number and the subtype code. */ m->cua_modem = m->tty_modem; m->cua_modem.name = isdn_ttyname_cui; m->cua_modem.major = ISDN_TTYAUX_MAJOR; m->tty_modem.minor_start = 0; m->cua_modem.subtype = ISDN_SERIAL_TYPE_CALLOUT; if (tty_register_driver(&m->tty_modem)) { printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n"); return -1; } if (tty_register_driver(&m->cua_modem)) { printk(KERN_WARNING "isdn_tty: Couldn't register modem-callout-device\n"); return -2; } 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 init_MUTEX(&info->write_sem); sprintf(info->last_cause, "0000"); sprintf(info->last_num, "none"); info->last_dir = 0; info->last_lhup = 1; info->last_l2 = -1; info->last_si = 0; isdn_tty_reset_profile(&info->emu); isdn_tty_modem_reset_regs(info, 1); info->magic = ISDN_ASYNC_MAGIC; info->line = i; info->tty = 0; info->x_char = 0; info->count = 0; info->blocked_open = 0; info->callout_termios = m->cua_modem.init_termios; info->normal_termios = m->tty_modem.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); info->isdn_driver = -1; info->isdn_channel = -1; info->drv_index = -1; info->xmit_size = ISDN_SERIAL_XMIT_SIZE; skb_queue_head_init(&info->xmit_queue);#ifdef CONFIG_ISDN_AUDIO skb_queue_head_init(&info->dtmf_queue);#endif if (!(info->xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, GFP_KERNEL))) { printk(KERN_ERR "Could not allocate modem xmit-buffer\n"); return -3; } /* Make room for T.70 header */ info->xmit_buf += 4; } return 0;}/* * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx) * match the MSN against the MSNs (glob patterns) defined for tty_emulator, * and return 0 for match, 1 for no match, 2 if MSN could match if longer. */static intisdn_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_msncmp(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 { 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; save_flags(flags); cli(); 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(); 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(RESULT_RING, info); isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); return 1; } } } } restore_flags(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; ulong flags; struct sk_buff *skb = 0; char *sp = 0; if (!msg) { printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n"); return; } save_flags(flags); cli(); tty = info->tty; if ((info->flags & ISDN_ASYNC_CLOSING) || (!tty)) { restore_flags(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)#ifdef CONFIG_ISDN_AUDIO + sizeof(isdn_audio_skb)#endif , GFP_ATOMIC); if (!skb) { restore_flags(flags); return; }#ifdef CONFIG_ISDN_AUDIO skb_reserve(skb, sizeof(isdn_audio_skb));#endif 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];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -