📄 isdn_ttyfax.c
字号:
/* $Id: isdn_ttyfax.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ * * 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 software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */#undef ISDN_TTY_FAX_STAT_DEBUG#undef ISDN_TTY_FAX_CMD_DEBUG#include <linux/isdn.h>#include "isdn_common.h"#include "isdn_tty.h"#include "isdn_ttyfax.h"static char *isdn_tty_fax_revision = "$Revision: 1.1.2.2 $";#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 voidisdn_tty_fax_modem_result(int code, modem_info * info){ atemu *m = &info->emu; T30_s *f = info->fax; char rs[50]; char rss[50]; 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_CPNFCON] & BIT_CPNFCON) && (!(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; }}static intisdn_tty_fax_command1(modem_info * info, isdn_ctrl * c){ static char *msg[] = {"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"};#ifdef ISDN_TTY_FAX_CMD_DEBUG printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd);#endif if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) { if (info->online) info->online = 1; isdn_tty_at_cout("\r\n", info); isdn_tty_at_cout(msg[c->parm.aux.cmd], info); isdn_tty_at_cout("\r\n", info); } switch (c->parm.aux.cmd) { case ISDN_FAX_CLASS1_CONNECT: info->online = 2; break; case ISDN_FAX_CLASS1_OK: case ISDN_FAX_CLASS1_FCERROR: case ISDN_FAX_CLASS1_ERROR: case ISDN_FAX_CLASS1_NOCARR: break; case ISDN_FAX_CLASS1_QUERY: isdn_tty_at_cout("\r\n", info); if (!c->parm.aux.para[0]) { isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info); isdn_tty_at_cout("\r\n", info); } else { isdn_tty_at_cout(c->parm.aux.para, info); isdn_tty_at_cout("\r\nOK\r\n", info); } break; } return (0);}intisdn_tty_fax_command(modem_info * info, isdn_ctrl * c){ T30_s *f = info->fax; char rs[10]; if (TTY_IS_FCLASS1(info)) return (isdn_tty_fax_command1(info, c));#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);}voidisdn_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 1 commands */static intisdn_tty_cmd_FCLASS1(char **p, modem_info * info){ static char *cmd[] = {"AE", "TS", "RS", "TM", "RM", "TH", "RH"}; isdn_ctrl c; int par, i; u_long flags; for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++) if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2)) break;#ifdef ISDN_TTY_FAX_CMD_DEBUG printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd);#endif if (c.parm.aux.cmd == 7) PARSE_ERROR1; p[0] += 2; switch (*p[0]) { case '?': p[0]++; c.parm.aux.subcmd = AT_QUERY; break; case '=': p[0]++; if (*p[0] == '?') { p[0]++; c.parm.aux.subcmd = AT_EQ_QUERY; } else { par = isdn_getnum(p); if ((par < 0) || (par > 255)) PARSE_ERROR1; c.parm.aux.subcmd = AT_EQ_VALUE; c.parm.aux.para[0] = par; } break; case 0: c.parm.aux.subcmd = AT_COMMAND; break; default: PARSE_ERROR1; } c.command = ISDN_CMD_FAXCMD;#ifdef ISDN_TTY_FAX_CMD_DEBUG printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n", c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);#endif if (info->isdn_driver < 0) { if ((c.parm.aux.subcmd == AT_EQ_VALUE) || (c.parm.aux.subcmd == AT_COMMAND)) { PARSE_ERROR1; } spin_lock_irqsave(&dev->lock, flags); /* get a temporary connection to the first free fax driver */ i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX, ISDN_PROTO_L3_FCLASS1, -1, -1, "00"); if (i < 0) { spin_unlock_irqrestore(&dev->lock, flags); PARSE_ERROR1; } info->isdn_driver = dev->drvmap[i]; info->isdn_channel = dev->chanmap[i]; info->drv_index = i; dev->m_idx[i] = info->line; spin_unlock_irqrestore(&dev->lock, flags); c.driver = info->isdn_driver; c.arg = info->isdn_channel; isdn_command(&c); spin_lock_irqsave(&dev->lock, flags); isdn_free_channel(info->isdn_driver, info->isdn_channel, ISDN_USAGE_FAX); info->isdn_driver = -1; info->isdn_channel = -1; if (info->drv_index >= 0) { dev->m_idx[info->drv_index] = -1; info->drv_index = -1; } spin_unlock_irqrestore(&dev->lock, flags); } else { c.driver = info->isdn_driver; c.arg = info->isdn_channel; isdn_command(&c); } return 1;}/* * Parse AT+F.. FAX class 2 commands */static intisdn_tty_cmd_FCLASS2(char **p, modem_info * info){ atemu *m = &info->emu; T30_s *f = info->fax; isdn_ctrl cmd; int par; char rs[50]; char rss[50]; 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -