PageRenderTime 97ms CodeModel.GetById 12ms app.highlight 73ms RepoModel.GetById 5ms app.codeStats 0ms

/drivers/isdn/i4l/isdn_ttyfax.c

http://github.com/mirrors/linux
C | 1123 lines | 1049 code | 36 blank | 38 comment | 127 complexity | 66774ef43f5f85d20c8de2f75e85a5ea MD5 | raw file
   1/* $Id: isdn_ttyfax.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $
   2 *
   3 * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel).
   4 *
   5 * Copyright 1999    by Armin Schindler (mac@melware.de)
   6 * Copyright 1999    by Ralf Spachmann (mel@melware.de)
   7 * Copyright 1999    by Cytronics & Melware
   8 *
   9 * This software may be used and distributed according to the terms
  10 * of the GNU General Public License, incorporated herein by reference.
  11 *
  12 */
  13
  14#undef ISDN_TTY_FAX_STAT_DEBUG
  15#undef ISDN_TTY_FAX_CMD_DEBUG
  16
  17#include <linux/isdn.h>
  18#include "isdn_common.h"
  19#include "isdn_tty.h"
  20#include "isdn_ttyfax.h"
  21
  22
  23static char *isdn_tty_fax_revision = "$Revision: 1.1.2.2 $";
  24
  25#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; }
  26
  27static char *
  28isdn_getrev(const char *revision)
  29{
  30	char *rev;
  31	char *p;
  32
  33	if ((p = strchr(revision, ':'))) {
  34		rev = p + 2;
  35		p = strchr(rev, '$');
  36		*--p = 0;
  37	} else
  38		rev = "???";
  39	return rev;
  40}
  41
  42/*
  43 * Fax Class 2 Modem results
  44 *
  45 */
  46
  47static void
  48isdn_tty_fax_modem_result(int code, modem_info *info)
  49{
  50	atemu *m = &info->emu;
  51	T30_s *f = info->fax;
  52	char rs[50];
  53	char rss[50];
  54	char *rp;
  55	int i;
  56	static char *msg[] =
  57		{"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:",
  58		 "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:",
  59		 "+FCFR", "+FPTS:", "+FET:"};
  60
  61
  62	isdn_tty_at_cout("\r\n", info);
  63	isdn_tty_at_cout(msg[code], info);
  64
  65#ifdef ISDN_TTY_FAX_CMD_DEBUG
  66	printk(KERN_DEBUG "isdn_tty: Fax send %s on ttyI%d\n",
  67	       msg[code], info->line);
  68#endif
  69	switch (code) {
  70	case 0: /* OK */
  71		break;
  72	case 1: /* ERROR */
  73		break;
  74	case 2:	/* +FCON */
  75		/* Append CPN, if enabled */
  76		if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) &&
  77		    (!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) {
  78			sprintf(rs, "/%s", m->cpn);
  79			isdn_tty_at_cout(rs, info);
  80		}
  81		info->online = 1;
  82		f->fet = 0;
  83		if (f->phase == ISDN_FAX_PHASE_A)
  84			f->phase = ISDN_FAX_PHASE_B;
  85		break;
  86	case 3:	/* +FCSI */
  87	case 8:	/* +FTSI */
  88		sprintf(rs, "\"%s\"", f->r_id);
  89		isdn_tty_at_cout(rs, info);
  90		break;
  91	case 4:	/* +FDIS */
  92		rs[0] = 0;
  93		rp = &f->r_resolution;
  94		for (i = 0; i < 8; i++) {
  95			sprintf(rss, "%c%s", rp[i] + 48,
  96				(i < 7) ? "," : "");
  97			strcat(rs, rss);
  98		}
  99		isdn_tty_at_cout(rs, info);
 100#ifdef ISDN_TTY_FAX_CMD_DEBUG
 101		printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n",
 102		       rs, info->line);
 103#endif
 104		break;
 105	case 5:	/* +FHNG */
 106		sprintf(rs, "%d", f->code);
 107		isdn_tty_at_cout(rs, info);
 108		info->faxonline = 0;
 109		break;
 110	case 6:	/* +FDCS */
 111		rs[0] = 0;
 112		rp = &f->r_resolution;
 113		for (i = 0; i < 8; i++) {
 114			sprintf(rss, "%c%s", rp[i] + 48,
 115				(i < 7) ? "," : "");
 116			strcat(rs, rss);
 117		}
 118		isdn_tty_at_cout(rs, info);
 119#ifdef ISDN_TTY_FAX_CMD_DEBUG
 120		printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n",
 121		       rs, info->line);
 122#endif
 123		break;
 124	case 7:	/* CONNECT */
 125		info->faxonline |= 2;
 126		break;
 127	case 9:	/* FCFR */
 128		break;
 129	case 10:	/* FPTS */
 130		isdn_tty_at_cout("1", info);
 131		break;
 132	case 11:	/* FET */
 133		sprintf(rs, "%d", f->fet);
 134		isdn_tty_at_cout(rs, info);
 135		break;
 136	}
 137
 138	isdn_tty_at_cout("\r\n", info);
 139
 140	switch (code) {
 141	case 7:	/* CONNECT */
 142		info->online = 2;
 143		if (info->faxonline & 1) {
 144			sprintf(rs, "%c", XON);
 145			isdn_tty_at_cout(rs, info);
 146		}
 147		break;
 148	}
 149}
 150
 151static int
 152isdn_tty_fax_command1(modem_info *info, isdn_ctrl *c)
 153{
 154	static char *msg[] =
 155		{"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"};
 156
 157#ifdef ISDN_TTY_FAX_CMD_DEBUG
 158	printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd);
 159#endif
 160	if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) {
 161		if (info->online)
 162			info->online = 1;
 163		isdn_tty_at_cout("\r\n", info);
 164		isdn_tty_at_cout(msg[c->parm.aux.cmd], info);
 165		isdn_tty_at_cout("\r\n", info);
 166	}
 167	switch (c->parm.aux.cmd) {
 168	case ISDN_FAX_CLASS1_CONNECT:
 169		info->online = 2;
 170		break;
 171	case ISDN_FAX_CLASS1_OK:
 172	case ISDN_FAX_CLASS1_FCERROR:
 173	case ISDN_FAX_CLASS1_ERROR:
 174	case ISDN_FAX_CLASS1_NOCARR:
 175		break;
 176	case ISDN_FAX_CLASS1_QUERY:
 177		isdn_tty_at_cout("\r\n", info);
 178		if (!c->parm.aux.para[0]) {
 179			isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info);
 180			isdn_tty_at_cout("\r\n", info);
 181		} else {
 182			isdn_tty_at_cout(c->parm.aux.para, info);
 183			isdn_tty_at_cout("\r\nOK\r\n", info);
 184		}
 185		break;
 186	}
 187	return (0);
 188}
 189
 190int
 191isdn_tty_fax_command(modem_info *info, isdn_ctrl *c)
 192{
 193	T30_s *f = info->fax;
 194	char rs[10];
 195
 196	if (TTY_IS_FCLASS1(info))
 197		return (isdn_tty_fax_command1(info, c));
 198
 199#ifdef ISDN_TTY_FAX_CMD_DEBUG
 200	printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n",
 201	       f->r_code, info->line);
 202#endif
 203	switch (f->r_code) {
 204	case ISDN_TTY_FAX_FCON:
 205		info->faxonline = 1;
 206		isdn_tty_fax_modem_result(2, info);	/* +FCON */
 207		return (0);
 208	case ISDN_TTY_FAX_FCON_I:
 209		info->faxonline = 16;
 210		isdn_tty_fax_modem_result(2, info);	/* +FCON */
 211		return (0);
 212	case ISDN_TTY_FAX_RID:
 213		if (info->faxonline & 1)
 214			isdn_tty_fax_modem_result(3, info);	/* +FCSI */
 215		if (info->faxonline & 16)
 216			isdn_tty_fax_modem_result(8, info);	/* +FTSI */
 217		return (0);
 218	case ISDN_TTY_FAX_DIS:
 219		isdn_tty_fax_modem_result(4, info);	/* +FDIS */
 220		return (0);
 221	case ISDN_TTY_FAX_HNG:
 222		if (f->phase == ISDN_FAX_PHASE_C) {
 223			if (f->direction == ISDN_TTY_FAX_CONN_IN) {
 224				sprintf(rs, "%c%c", DLE, ETX);
 225				isdn_tty_at_cout(rs, info);
 226			} else {
 227				sprintf(rs, "%c", 0x18);
 228				isdn_tty_at_cout(rs, info);
 229			}
 230			info->faxonline &= ~2;	/* leave data mode */
 231			info->online = 1;
 232		}
 233		f->phase = ISDN_FAX_PHASE_E;
 234		isdn_tty_fax_modem_result(5, info);	/* +FHNG */
 235		isdn_tty_fax_modem_result(0, info);	/* OK */
 236		return (0);
 237	case ISDN_TTY_FAX_DCS:
 238		isdn_tty_fax_modem_result(6, info);	/* +FDCS */
 239		isdn_tty_fax_modem_result(7, info);	/* CONNECT */
 240		f->phase = ISDN_FAX_PHASE_C;
 241		return (0);
 242	case ISDN_TTY_FAX_TRAIN_OK:
 243		isdn_tty_fax_modem_result(6, info);	/* +FDCS */
 244		isdn_tty_fax_modem_result(0, info);	/* OK */
 245		return (0);
 246	case ISDN_TTY_FAX_SENT:
 247		isdn_tty_fax_modem_result(0, info);	/* OK */
 248		return (0);
 249	case ISDN_TTY_FAX_CFR:
 250		isdn_tty_fax_modem_result(9, info);	/* +FCFR */
 251		return (0);
 252	case ISDN_TTY_FAX_ET:
 253		sprintf(rs, "%c%c", DLE, ETX);
 254		isdn_tty_at_cout(rs, info);
 255		isdn_tty_fax_modem_result(10, info);	/* +FPTS */
 256		isdn_tty_fax_modem_result(11, info);	/* +FET */
 257		isdn_tty_fax_modem_result(0, info);	/* OK */
 258		info->faxonline &= ~2;	/* leave data mode */
 259		info->online = 1;
 260		f->phase = ISDN_FAX_PHASE_D;
 261		return (0);
 262	case ISDN_TTY_FAX_PTS:
 263		isdn_tty_fax_modem_result(10, info);	/* +FPTS */
 264		if (f->direction == ISDN_TTY_FAX_CONN_OUT) {
 265			if (f->fet == 1)
 266				f->phase = ISDN_FAX_PHASE_B;
 267			if (f->fet == 0)
 268				isdn_tty_fax_modem_result(0, info);	/* OK */
 269		}
 270		return (0);
 271	case ISDN_TTY_FAX_EOP:
 272		info->faxonline &= ~2;	/* leave data mode */
 273		info->online = 1;
 274		f->phase = ISDN_FAX_PHASE_D;
 275		return (0);
 276
 277	}
 278	return (-1);
 279}
 280
 281
 282void
 283isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb)
 284{
 285	__u8 LeftMask;
 286	__u8 RightMask;
 287	__u8 fBit;
 288	__u8 Data;
 289	int i;
 290
 291	if (!info->fax->bor) {
 292		for (i = 0; i < skb->len; i++) {
 293			Data = skb->data[i];
 294			for (
 295				LeftMask = 0x80, RightMask = 0x01;
 296				LeftMask > RightMask;
 297				LeftMask >>= 1, RightMask <<= 1
 298				) {
 299				fBit = (Data & LeftMask);
 300				if (Data & RightMask)
 301					Data |= LeftMask;
 302				else
 303					Data &= ~LeftMask;
 304				if (fBit)
 305					Data |= RightMask;
 306				else
 307					Data &= ~RightMask;
 308
 309			}
 310			skb->data[i] = Data;
 311		}
 312	}
 313}
 314
 315/*
 316 * Parse AT+F.. FAX class 1 commands
 317 */
 318
 319static int
 320isdn_tty_cmd_FCLASS1(char **p, modem_info *info)
 321{
 322	static char *cmd[] =
 323		{"AE", "TS", "RS", "TM", "RM", "TH", "RH"};
 324	isdn_ctrl c;
 325	int par, i;
 326	u_long flags;
 327
 328	for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
 329		if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2))
 330			break;
 331
 332#ifdef ISDN_TTY_FAX_CMD_DEBUG
 333	printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd);
 334#endif
 335	if (c.parm.aux.cmd == 7)
 336		PARSE_ERROR1;
 337
 338	p[0] += 2;
 339	switch (*p[0]) {
 340	case '?':
 341		p[0]++;
 342		c.parm.aux.subcmd = AT_QUERY;
 343		break;
 344	case '=':
 345		p[0]++;
 346		if (*p[0] == '?') {
 347			p[0]++;
 348			c.parm.aux.subcmd = AT_EQ_QUERY;
 349		} else {
 350			par = isdn_getnum(p);
 351			if ((par < 0) || (par > 255))
 352				PARSE_ERROR1;
 353			c.parm.aux.subcmd = AT_EQ_VALUE;
 354			c.parm.aux.para[0] = par;
 355		}
 356		break;
 357	case 0:
 358		c.parm.aux.subcmd = AT_COMMAND;
 359		break;
 360	default:
 361		PARSE_ERROR1;
 362	}
 363	c.command = ISDN_CMD_FAXCMD;
 364#ifdef ISDN_TTY_FAX_CMD_DEBUG
 365	printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n",
 366	       c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]);
 367#endif
 368	if (info->isdn_driver < 0) {
 369		if ((c.parm.aux.subcmd == AT_EQ_VALUE) ||
 370		    (c.parm.aux.subcmd == AT_COMMAND)) {
 371			PARSE_ERROR1;
 372		}
 373		spin_lock_irqsave(&dev->lock, flags);
 374		/* get a temporary connection to the first free fax driver */
 375		i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX,
 376					  ISDN_PROTO_L3_FCLASS1, -1, -1, "00");
 377		if (i < 0) {
 378			spin_unlock_irqrestore(&dev->lock, flags);
 379			PARSE_ERROR1;
 380		}
 381		info->isdn_driver = dev->drvmap[i];
 382		info->isdn_channel = dev->chanmap[i];
 383		info->drv_index = i;
 384		dev->m_idx[i] = info->line;
 385		spin_unlock_irqrestore(&dev->lock, flags);
 386		c.driver = info->isdn_driver;
 387		c.arg = info->isdn_channel;
 388		isdn_command(&c);
 389		spin_lock_irqsave(&dev->lock, flags);
 390		isdn_free_channel(info->isdn_driver, info->isdn_channel,
 391				  ISDN_USAGE_FAX);
 392		info->isdn_driver = -1;
 393		info->isdn_channel = -1;
 394		if (info->drv_index >= 0) {
 395			dev->m_idx[info->drv_index] = -1;
 396			info->drv_index = -1;
 397		}
 398		spin_unlock_irqrestore(&dev->lock, flags);
 399	} else {
 400		c.driver = info->isdn_driver;
 401		c.arg = info->isdn_channel;
 402		isdn_command(&c);
 403	}
 404	return 1;
 405}
 406
 407/*
 408 * Parse AT+F.. FAX class 2 commands
 409 */
 410
 411static int
 412isdn_tty_cmd_FCLASS2(char **p, modem_info *info)
 413{
 414	atemu *m = &info->emu;
 415	T30_s *f = info->fax;
 416	isdn_ctrl cmd;
 417	int par;
 418	char rs[50];
 419	char rss[50];
 420	int maxdccval[] =
 421		{1, 5, 2, 2, 3, 2, 0, 7};
 422
 423	/* FAA still unchanged */
 424	if (!strncmp(p[0], "AA", 2)) {	/* TODO */
 425		p[0] += 2;
 426		switch (*p[0]) {
 427		case '?':
 428			p[0]++;
 429			sprintf(rs, "\r\n%d", 0);
 430			isdn_tty_at_cout(rs, info);
 431			break;
 432		case '=':
 433			p[0]++;
 434			par = isdn_getnum(p);
 435			if ((par < 0) || (par > 255))
 436				PARSE_ERROR1;
 437			break;
 438		default:
 439			PARSE_ERROR1;
 440		}
 441		return 0;
 442	}
 443	/* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */
 444	if (!strncmp(p[0], "BADLIN", 6)) {
 445		p[0] += 6;
 446		switch (*p[0]) {
 447		case '?':
 448			p[0]++;
 449			sprintf(rs, "\r\n%d", f->badlin);
 450			isdn_tty_at_cout(rs, info);
 451			break;
 452		case '=':
 453			p[0]++;
 454			if (*p[0] == '?') {
 455				p[0]++;
 456				sprintf(rs, "\r\n0-255");
 457				isdn_tty_at_cout(rs, info);
 458			} else {
 459				par = isdn_getnum(p);
 460				if ((par < 0) || (par > 255))
 461					PARSE_ERROR1;
 462				f->badlin = par;
 463#ifdef ISDN_TTY_FAX_STAT_DEBUG
 464				printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par);
 465#endif
 466			}
 467			break;
 468		default:
 469			PARSE_ERROR1;
 470		}
 471		return 0;
 472	}
 473	/* BADMUL=value - dummy 0=disable errorchk disabled (threshold multiplier) */
 474	if (!strncmp(p[0], "BADMUL", 6)) {
 475		p[0] += 6;
 476		switch (*p[0]) {
 477		case '?':
 478			p[0]++;
 479			sprintf(rs, "\r\n%d", f->badmul);
 480			isdn_tty_at_cout(rs, info);
 481			break;
 482		case '=':
 483			p[0]++;
 484			if (*p[0] == '?') {
 485				p[0]++;
 486				sprintf(rs, "\r\n0-255");
 487				isdn_tty_at_cout(rs, info);
 488			} else {
 489				par = isdn_getnum(p);
 490				if ((par < 0) || (par > 255))
 491					PARSE_ERROR1;
 492				f->badmul = par;
 493#ifdef ISDN_TTY_FAX_STAT_DEBUG
 494				printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par);
 495#endif
 496			}
 497			break;
 498		default:
 499			PARSE_ERROR1;
 500		}
 501		return 0;
 502	}
 503	/* BOR=n - Phase C bit order, 0=direct, 1=reverse */
 504	if (!strncmp(p[0], "BOR", 3)) {
 505		p[0] += 3;
 506		switch (*p[0]) {
 507		case '?':
 508			p[0]++;
 509			sprintf(rs, "\r\n%d", f->bor);
 510			isdn_tty_at_cout(rs, info);
 511			break;
 512		case '=':
 513			p[0]++;
 514			if (*p[0] == '?') {
 515				p[0]++;
 516				sprintf(rs, "\r\n0,1");
 517				isdn_tty_at_cout(rs, info);
 518			} else {
 519				par = isdn_getnum(p);
 520				if ((par < 0) || (par > 1))
 521					PARSE_ERROR1;
 522				f->bor = par;
 523#ifdef ISDN_TTY_FAX_STAT_DEBUG
 524				printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par);
 525#endif
 526			}
 527			break;
 528		default:
 529			PARSE_ERROR1;
 530		}
 531		return 0;
 532	}
 533	/* NBC=n - No Best Capabilities */
 534	if (!strncmp(p[0], "NBC", 3)) {
 535		p[0] += 3;
 536		switch (*p[0]) {
 537		case '?':
 538			p[0]++;
 539			sprintf(rs, "\r\n%d", f->nbc);
 540			isdn_tty_at_cout(rs, info);
 541			break;
 542		case '=':
 543			p[0]++;
 544			if (*p[0] == '?') {
 545				p[0]++;
 546				sprintf(rs, "\r\n0,1");
 547				isdn_tty_at_cout(rs, info);
 548			} else {
 549				par = isdn_getnum(p);
 550				if ((par < 0) || (par > 1))
 551					PARSE_ERROR1;
 552				f->nbc = par;
 553#ifdef ISDN_TTY_FAX_STAT_DEBUG
 554				printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par);
 555#endif
 556			}
 557			break;
 558		default:
 559			PARSE_ERROR1;
 560		}
 561		return 0;
 562	}
 563	/* BUF? - Readonly buffersize readout  */
 564	if (!strncmp(p[0], "BUF?", 4)) {
 565		p[0] += 4;
 566#ifdef ISDN_TTY_FAX_STAT_DEBUG
 567		printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE]));
 568#endif
 569		p[0]++;
 570		sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE]));
 571		isdn_tty_at_cout(rs, info);
 572		return 0;
 573	}
 574	/* CIG=string - local fax station id string for polling rx */
 575	if (!strncmp(p[0], "CIG", 3)) {
 576		int i, r;
 577		p[0] += 3;
 578		switch (*p[0]) {
 579		case '?':
 580			p[0]++;
 581			sprintf(rs, "\r\n\"%s\"", f->pollid);
 582			isdn_tty_at_cout(rs, info);
 583			break;
 584		case '=':
 585			p[0]++;
 586			if (*p[0] == '?') {
 587				p[0]++;
 588				sprintf(rs, "\r\n\"STRING\"");
 589				isdn_tty_at_cout(rs, info);
 590			} else {
 591				if (*p[0] == '"')
 592					p[0]++;
 593				for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
 594					f->pollid[i] = *p[0]++;
 595				}
 596				if (*p[0] == '"')
 597					p[0]++;
 598				for (r = i; r < FAXIDLEN; r++) {
 599					f->pollid[r] = 32;
 600				}
 601				f->pollid[FAXIDLEN - 1] = 0;
 602#ifdef ISDN_TTY_FAX_STAT_DEBUG
 603				printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid);
 604#endif
 605			}
 606			break;
 607		default:
 608			PARSE_ERROR1;
 609		}
 610		return 0;
 611	}
 612	/* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */
 613	if (!strncmp(p[0], "CQ", 2)) {
 614		p[0] += 2;
 615		switch (*p[0]) {
 616		case '?':
 617			p[0]++;
 618			sprintf(rs, "\r\n%d", f->cq);
 619			isdn_tty_at_cout(rs, info);
 620			break;
 621		case '=':
 622			p[0]++;
 623			if (*p[0] == '?') {
 624				p[0]++;
 625				sprintf(rs, "\r\n0,1,2");
 626				isdn_tty_at_cout(rs, info);
 627			} else {
 628				par = isdn_getnum(p);
 629				if ((par < 0) || (par > 2))
 630					PARSE_ERROR1;
 631				f->cq = par;
 632#ifdef ISDN_TTY_FAX_STAT_DEBUG
 633				printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par);
 634#endif
 635			}
 636			break;
 637		default:
 638			PARSE_ERROR1;
 639		}
 640		return 0;
 641	}
 642	/* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */
 643	if (!strncmp(p[0], "CR", 2)) {
 644		p[0] += 2;
 645		switch (*p[0]) {
 646		case '?':
 647			p[0]++;
 648			sprintf(rs, "\r\n%d", f->cr);	/* read actual value from struct and print */
 649			isdn_tty_at_cout(rs, info);
 650			break;
 651		case '=':
 652			p[0]++;
 653			if (*p[0] == '?') {
 654				p[0]++;
 655				sprintf(rs, "\r\n0,1");		/* display online help */
 656				isdn_tty_at_cout(rs, info);
 657			} else {
 658				par = isdn_getnum(p);
 659				if ((par < 0) || (par > 1))
 660					PARSE_ERROR1;
 661				f->cr = par;
 662#ifdef ISDN_TTY_FAX_STAT_DEBUG
 663				printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par);
 664#endif
 665			}
 666			break;
 667		default:
 668			PARSE_ERROR1;
 669		}
 670		return 0;
 671	}
 672	/* CTCRTY=value - ECM retry count */
 673	if (!strncmp(p[0], "CTCRTY", 6)) {
 674		p[0] += 6;
 675		switch (*p[0]) {
 676		case '?':
 677			p[0]++;
 678			sprintf(rs, "\r\n%d", f->ctcrty);
 679			isdn_tty_at_cout(rs, info);
 680			break;
 681		case '=':
 682			p[0]++;
 683			if (*p[0] == '?') {
 684				p[0]++;
 685				sprintf(rs, "\r\n0-255");
 686				isdn_tty_at_cout(rs, info);
 687			} else {
 688				par = isdn_getnum(p);
 689				if ((par < 0) || (par > 255))
 690					PARSE_ERROR1;
 691				f->ctcrty = par;
 692#ifdef ISDN_TTY_FAX_STAT_DEBUG
 693				printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par);
 694#endif
 695			}
 696			break;
 697		default:
 698			PARSE_ERROR1;
 699		}
 700		return 0;
 701	}
 702	/* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */
 703	if (!strncmp(p[0], "DCC", 3)) {
 704		char *rp = &f->resolution;
 705		int i;
 706
 707		p[0] += 3;
 708		switch (*p[0]) {
 709		case '?':
 710			p[0]++;
 711			strcpy(rs, "\r\n");
 712			for (i = 0; i < 8; i++) {
 713				sprintf(rss, "%c%s", rp[i] + 48,
 714					(i < 7) ? "," : "");
 715				strcat(rs, rss);
 716			}
 717			isdn_tty_at_cout(rs, info);
 718			break;
 719		case '=':
 720			p[0]++;
 721			if (*p[0] == '?') {
 722				isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
 723				p[0]++;
 724			} else {
 725				for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
 726					if (*p[0] != ',') {
 727						if ((*p[0] - 48) > maxdccval[i]) {
 728							PARSE_ERROR1;
 729						}
 730						rp[i] = *p[0] - 48;
 731						p[0]++;
 732						if (*p[0] == ',')
 733							p[0]++;
 734					} else
 735						p[0]++;
 736				}
 737#ifdef ISDN_TTY_FAX_STAT_DEBUG
 738				printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n",
 739				       rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
 740#endif
 741			}
 742			break;
 743		default:
 744			PARSE_ERROR1;
 745		}
 746		return 0;
 747	}
 748	/* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */
 749	if (!strncmp(p[0], "DIS", 3)) {
 750		char *rp = &f->resolution;
 751		int i;
 752
 753		p[0] += 3;
 754		switch (*p[0]) {
 755		case '?':
 756			p[0]++;
 757			strcpy(rs, "\r\n");
 758			for (i = 0; i < 8; i++) {
 759				sprintf(rss, "%c%s", rp[i] + 48,
 760					(i < 7) ? "," : "");
 761				strcat(rs, rss);
 762			}
 763			isdn_tty_at_cout(rs, info);
 764			break;
 765		case '=':
 766			p[0]++;
 767			if (*p[0] == '?') {
 768				isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info);
 769				p[0]++;
 770			} else {
 771				for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) {
 772					if (*p[0] != ',') {
 773						if ((*p[0] - 48) > maxdccval[i]) {
 774							PARSE_ERROR1;
 775						}
 776						rp[i] = *p[0] - 48;
 777						p[0]++;
 778						if (*p[0] == ',')
 779							p[0]++;
 780					} else
 781						p[0]++;
 782				}
 783#ifdef ISDN_TTY_FAX_STAT_DEBUG
 784				printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n",
 785				       rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]);
 786#endif
 787			}
 788			break;
 789		default:
 790			PARSE_ERROR1;
 791		}
 792		return 0;
 793	}
 794	/* DR - Receive Phase C data command, initiates document reception */
 795	if (!strncmp(p[0], "DR", 2)) {
 796		p[0] += 2;
 797		if ((info->faxonline & 16) &&	/* incoming connection */
 798		    ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) {
 799#ifdef ISDN_TTY_FAX_STAT_DEBUG
 800			printk(KERN_DEBUG "isdn_tty: Fax FDR\n");
 801#endif
 802			f->code = ISDN_TTY_FAX_DR;
 803			cmd.driver = info->isdn_driver;
 804			cmd.arg = info->isdn_channel;
 805			cmd.command = ISDN_CMD_FAXCMD;
 806			isdn_command(&cmd);
 807			if (f->phase == ISDN_FAX_PHASE_B) {
 808				f->phase = ISDN_FAX_PHASE_C;
 809			} else if (f->phase == ISDN_FAX_PHASE_D) {
 810				switch (f->fet) {
 811				case 0:	/* next page will be received */
 812					f->phase = ISDN_FAX_PHASE_C;
 813					isdn_tty_fax_modem_result(7, info);	/* CONNECT */
 814					break;
 815				case 1:	/* next doc will be received */
 816					f->phase = ISDN_FAX_PHASE_B;
 817					break;
 818				case 2:	/* fax session is terminating */
 819					f->phase = ISDN_FAX_PHASE_E;
 820					break;
 821				default:
 822					PARSE_ERROR1;
 823				}
 824			}
 825		} else {
 826			PARSE_ERROR1;
 827		}
 828		return 1;
 829	}
 830	/* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */
 831	if (!strncmp(p[0], "DT", 2)) {
 832		int i, val[] =
 833			{4, 0, 2, 3};
 834		char *rp = &f->resolution;
 835
 836		p[0] += 2;
 837		if (!(info->faxonline & 1))	/* not outgoing connection */
 838			PARSE_ERROR1;
 839
 840		for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) {
 841			if (*p[0] != ',') {
 842				if ((*p[0] - 48) > maxdccval[val[i]]) {
 843					PARSE_ERROR1;
 844				}
 845				rp[val[i]] = *p[0] - 48;
 846				p[0]++;
 847				if (*p[0] == ',')
 848					p[0]++;
 849			} else
 850				p[0]++;
 851		}
 852#ifdef ISDN_TTY_FAX_STAT_DEBUG
 853		printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n",
 854		       rp[4], rp[0], rp[2], rp[3]);
 855#endif
 856		if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) {
 857			f->code = ISDN_TTY_FAX_DT;
 858			cmd.driver = info->isdn_driver;
 859			cmd.arg = info->isdn_channel;
 860			cmd.command = ISDN_CMD_FAXCMD;
 861			isdn_command(&cmd);
 862			if (f->phase == ISDN_FAX_PHASE_D) {
 863				f->phase = ISDN_FAX_PHASE_C;
 864				isdn_tty_fax_modem_result(7, info);	/* CONNECT */
 865			}
 866		} else {
 867			PARSE_ERROR1;
 868		}
 869		return 1;
 870	}
 871	/* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */
 872	if (!strncmp(p[0], "ECM", 3)) {
 873		p[0] += 3;
 874		switch (*p[0]) {
 875		case '?':
 876			p[0]++;
 877			sprintf(rs, "\r\n%d", f->ecm);
 878			isdn_tty_at_cout(rs, info);
 879			break;
 880		case '=':
 881			p[0]++;
 882			if (*p[0] == '?') {
 883				p[0]++;
 884				sprintf(rs, "\r\n0,2");
 885				isdn_tty_at_cout(rs, info);
 886			} else {
 887				par = isdn_getnum(p);
 888				if ((par != 0) && (par != 2))
 889					PARSE_ERROR1;
 890				f->ecm = par;
 891#ifdef ISDN_TTY_FAX_STAT_DEBUG
 892				printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par);
 893#endif
 894			}
 895			break;
 896		default:
 897			PARSE_ERROR1;
 898		}
 899		return 0;
 900	}
 901	/* ET=n - End of page or document */
 902	if (!strncmp(p[0], "ET=", 3)) {
 903		p[0] += 3;
 904		if (*p[0] == '?') {
 905			p[0]++;
 906			sprintf(rs, "\r\n0-2");
 907			isdn_tty_at_cout(rs, info);
 908		} else {
 909			if ((f->phase != ISDN_FAX_PHASE_D) ||
 910			    (!(info->faxonline & 1)))
 911				PARSE_ERROR1;
 912			par = isdn_getnum(p);
 913			if ((par < 0) || (par > 2))
 914				PARSE_ERROR1;
 915			f->fet = par;
 916			f->code = ISDN_TTY_FAX_ET;
 917			cmd.driver = info->isdn_driver;
 918			cmd.arg = info->isdn_channel;
 919			cmd.command = ISDN_CMD_FAXCMD;
 920			isdn_command(&cmd);
 921#ifdef ISDN_TTY_FAX_STAT_DEBUG
 922			printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par);
 923#endif
 924			return 1;
 925		}
 926		return 0;
 927	}
 928	/* K - terminate */
 929	if (!strncmp(p[0], "K", 1)) {
 930		p[0] += 1;
 931		if ((f->phase == ISDN_FAX_PHASE_IDLE) || (f->phase == ISDN_FAX_PHASE_E))
 932			PARSE_ERROR1;
 933		isdn_tty_modem_hup(info, 1);
 934		return 1;
 935	}
 936	/* LID=string - local fax ID */
 937	if (!strncmp(p[0], "LID", 3)) {
 938		int i, r;
 939		p[0] += 3;
 940		switch (*p[0]) {
 941		case '?':
 942			p[0]++;
 943			sprintf(rs, "\r\n\"%s\"", f->id);
 944			isdn_tty_at_cout(rs, info);
 945			break;
 946		case '=':
 947			p[0]++;
 948			if (*p[0] == '?') {
 949				p[0]++;
 950				sprintf(rs, "\r\n\"STRING\"");
 951				isdn_tty_at_cout(rs, info);
 952			} else {
 953				if (*p[0] == '"')
 954					p[0]++;
 955				for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) {
 956					f->id[i] = *p[0]++;
 957				}
 958				if (*p[0] == '"')
 959					p[0]++;
 960				for (r = i; r < FAXIDLEN; r++) {
 961					f->id[r] = 32;
 962				}
 963				f->id[FAXIDLEN - 1] = 0;
 964#ifdef ISDN_TTY_FAX_STAT_DEBUG
 965				printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id);
 966#endif
 967			}
 968			break;
 969		default:
 970			PARSE_ERROR1;
 971		}
 972		return 0;
 973	}
 974
 975	/* MDL? - DCE Model       */
 976	if (!strncmp(p[0], "MDL?", 4)) {
 977		p[0] += 4;
 978#ifdef ISDN_TTY_FAX_STAT_DEBUG
 979		printk(KERN_DEBUG "isdn_tty: FMDL?\n");
 980#endif
 981		isdn_tty_at_cout("\r\nisdn4linux", info);
 982		return 0;
 983	}
 984	/* MFR? - DCE Manufacturer */
 985	if (!strncmp(p[0], "MFR?", 4)) {
 986		p[0] += 4;
 987#ifdef ISDN_TTY_FAX_STAT_DEBUG
 988		printk(KERN_DEBUG "isdn_tty: FMFR?\n");
 989#endif
 990		isdn_tty_at_cout("\r\nisdn4linux", info);
 991		return 0;
 992	}
 993	/* MINSP=n - Minimum Speed for Phase C */
 994	if (!strncmp(p[0], "MINSP", 5)) {
 995		p[0] += 5;
 996		switch (*p[0]) {
 997		case '?':
 998			p[0]++;
 999			sprintf(rs, "\r\n%d", f->minsp);
1000			isdn_tty_at_cout(rs, info);
1001			break;
1002		case '=':
1003			p[0]++;
1004			if (*p[0] == '?') {
1005				p[0]++;
1006				sprintf(rs, "\r\n0-5");
1007				isdn_tty_at_cout(rs, info);
1008			} else {
1009				par = isdn_getnum(p);
1010				if ((par < 0) || (par > 5))
1011					PARSE_ERROR1;
1012				f->minsp = par;
1013#ifdef ISDN_TTY_FAX_STAT_DEBUG
1014				printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par);
1015#endif
1016			}
1017			break;
1018		default:
1019			PARSE_ERROR1;
1020		}
1021		return 0;
1022	}
1023	/* PHCTO=value - DTE phase C timeout */
1024	if (!strncmp(p[0], "PHCTO", 5)) {
1025		p[0] += 5;
1026		switch (*p[0]) {
1027		case '?':
1028			p[0]++;
1029			sprintf(rs, "\r\n%d", f->phcto);
1030			isdn_tty_at_cout(rs, info);
1031			break;
1032		case '=':
1033			p[0]++;
1034			if (*p[0] == '?') {
1035				p[0]++;
1036				sprintf(rs, "\r\n0-255");
1037				isdn_tty_at_cout(rs, info);
1038			} else {
1039				par = isdn_getnum(p);
1040				if ((par < 0) || (par > 255))
1041					PARSE_ERROR1;
1042				f->phcto = par;
1043#ifdef ISDN_TTY_FAX_STAT_DEBUG
1044				printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par);
1045#endif
1046			}
1047			break;
1048		default:
1049			PARSE_ERROR1;
1050		}
1051		return 0;
1052	}
1053
1054	/* REL=n - Phase C received EOL alignment */
1055	if (!strncmp(p[0], "REL", 3)) {
1056		p[0] += 3;
1057		switch (*p[0]) {
1058		case '?':
1059			p[0]++;
1060			sprintf(rs, "\r\n%d", f->rel);
1061			isdn_tty_at_cout(rs, info);
1062			break;
1063		case '=':
1064			p[0]++;
1065			if (*p[0] == '?') {
1066				p[0]++;
1067				sprintf(rs, "\r\n0,1");
1068				isdn_tty_at_cout(rs, info);
1069			} else {
1070				par = isdn_getnum(p);
1071				if ((par < 0) || (par > 1))
1072					PARSE_ERROR1;
1073				f->rel = par;
1074#ifdef ISDN_TTY_FAX_STAT_DEBUG
1075				printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par);
1076#endif
1077			}
1078			break;
1079		default:
1080			PARSE_ERROR1;
1081		}
1082		return 0;
1083	}
1084	/* REV? - DCE Revision */
1085	if (!strncmp(p[0], "REV?", 4)) {
1086		p[0] += 4;
1087#ifdef ISDN_TTY_FAX_STAT_DEBUG
1088		printk(KERN_DEBUG "isdn_tty: FREV?\n");
1089#endif
1090		strcpy(rss, isdn_tty_fax_revision);
1091		sprintf(rs, "\r\nRev: %s", isdn_getrev(rss));
1092		isdn_tty_at_cout(rs, info);
1093		return 0;
1094	}
1095
1096	/* Phase C Transmit Data Block Size */
1097	if (!strncmp(p[0], "TBC=", 4)) {	/* dummy, not used */
1098		p[0] += 4;
1099#ifdef ISDN_TTY_FAX_STAT_DEBUG
1100		printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]);
1101#endif
1102		switch (*p[0]) {
1103		case '0':
1104			p[0]++;
1105			break;
1106		default:
1107			PARSE_ERROR1;
1108		}
1109		return 0;
1110	}
1111	printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]);
1112	PARSE_ERROR1;
1113}
1114
1115int
1116isdn_tty_cmd_PLUSF_FAX(char **p, modem_info *info)
1117{
1118	if (TTY_IS_FCLASS2(info))
1119		return (isdn_tty_cmd_FCLASS2(p, info));
1120	else if (TTY_IS_FCLASS1(info))
1121		return (isdn_tty_cmd_FCLASS1(p, info));
1122	PARSE_ERROR1;
1123}