linux/drivers/isdn/i4l/isdn_ttyfax.c
<<
>>
Prefs
   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