File: /usr/src/linux/drivers/isdn/isdn_ttyfax.c
1 /* $Id: isdn_ttyfax.c,v 1.7.6.1 2001/08/14 14:12:18 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.6.1 $";
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_CPNFCON] & 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 }
1136