![Julia Lawall](/assets/img/avatar_default.png)
In commit e6bafba5b4
("wmi: (!x & y)
strikes again"), a bug was fixed that involved converting !x & y to !(x
& y). The code below shows the same pattern, and thus should perhaps be
fixed in the same way.
This is not tested and clearly changes the semantics, so it is only
something to consider.
The semantic patch that makes this change is as follows:
(http://www.emn.fr/x-info/coccinelle/)
// <smpl>
@@ expression E1,E2; @@
(
!E1 & !E2
|
- !E1 & E2
+ !(E1 & E2)
)
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Cc: Karsten Keil <kkeil@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1124 lines
25 KiB
C
1124 lines
25 KiB
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 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[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 int
|
|
isdn_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);
|
|
}
|
|
|
|
int
|
|
isdn_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);
|
|
}
|
|
|
|
|
|
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 1 commands
|
|
*/
|
|
|
|
static int
|
|
isdn_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 int
|
|
isdn_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;
|
|
}
|
|
/* 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;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* 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
|
|
strcpy(rss, isdn_tty_fax_revision);
|
|
sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
|
|
isdn_tty_at_cout(rs, info);
|
|
return 0;
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
int
|
|
isdn_tty_cmd_PLUSF_FAX(char **p, modem_info * info)
|
|
{
|
|
if (TTY_IS_FCLASS2(info))
|
|
return (isdn_tty_cmd_FCLASS2(p, info));
|
|
else if (TTY_IS_FCLASS1(info))
|
|
return (isdn_tty_cmd_FCLASS1(p, info));
|
|
PARSE_ERROR1;
|
|
}
|