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