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