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