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} 1124