dahdi_cfg: Make -S option based on spannumber instead of order in config file.
[dahdi/tools.git] / dahdi_cfg.c
1 /*
2  * Configuration program for DAHDI Telephony Interface
3  *
4  * Written by Mark Spencer <markster@digium.com>
5  * Based on previous works, designs, and architectures conceived and
6  * written by Jim Dixon <jim@lambdatel.com>.
7  *
8  * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
9  * Copyright (C) 2001-2008 Digium, Inc.
10  *
11  * All rights reserved.
12  *
13  * Primary Author: Mark Spencer <markster@digium.com>
14  * Radio Support by Jim Dixon <jim@lambdatel.com>
15  */
16
17 /*
18  * See http://www.asterisk.org for more information about
19  * the Asterisk project. Please do not directly contact
20  * any of the maintainers of this project for assistance;
21  * the project provides a web site, mailing lists and IRC
22  * channels for your use.
23  *
24  * This program is free software, distributed under the terms of
25  * the GNU General Public License Version 2 as published by the
26  * Free Software Foundation. See the LICENSE file included with
27  * this program for more details.
28  */
29
30 #include <stdio.h> 
31 #include <getopt.h>
32 #include <string.h>
33 #include <stdarg.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <sys/ioctl.h>
37 #include <fcntl.h>
38 #include <errno.h>
39
40 #include <dahdi/user.h>
41 #include "tonezone.h"
42 #include "dahdi_tools_version.h"
43
44 #define CONFIG_FILENAME "/etc/dahdi/system.conf"
45 #define MASTER_DEVICE   "/dev/dahdi/ctl"
46
47 #define NUM_SPANS DAHDI_MAX_SPANS
48
49 #define NUM_TONES 15
50
51 /*! A sanity check for the timing parameter of the span. 
52  *
53  * Note that each driver using it is still responsible for validating
54  * that value.
55  */
56 #define MAX_TIMING 255 
57
58 /* Assume no more than 1024 dynamics */
59 #define NUM_DYNAMIC     1024
60
61 static int lineno=0;
62
63 static FILE *cf;
64
65 static char *filename=CONFIG_FILENAME;
66
67 int rxtones[NUM_TONES + 1],rxtags[NUM_TONES + 1],txtones[NUM_TONES + 1];
68 int bursttime = 0, debouncetime = 0, invertcor = 0, exttone = 0, corthresh = 0;
69 int txgain = 0, rxgain = 0, deemp = 0, preemp = 0;
70
71 int corthreshes[] = {3125,6250,9375,12500,15625,18750,21875,25000,0} ;
72
73 static int toneindex = 1;
74
75 #define DEBUG_READER (1 << 0)
76 #define DEBUG_PARSER (1 << 1)
77 #define DEBUG_APPLY  (1 << 2)
78 static int debug = 0;
79
80 static int errcnt = 0;
81
82 static int deftonezone = -1;
83
84 static struct dahdi_lineconfig lc[DAHDI_MAX_SPANS];
85
86 static struct dahdi_chanconfig cc[DAHDI_MAX_CHANNELS];
87
88 static int current_span = 0;
89 static int only_span = 0;
90 static int restrict_channels = 0;
91 static int selected_channels[DAHDI_MAX_CHANNELS];
92 static int chan2span[DAHDI_MAX_CHANNELS];
93 static int declared_spans[DAHDI_MAX_SPANS];
94
95 static struct dahdi_attach_echocan ae[DAHDI_MAX_CHANNELS];
96
97 static struct dahdi_dynamic_span zds[NUM_DYNAMIC];
98
99 static const char *sig[DAHDI_MAX_CHANNELS];             /* Signalling */
100
101 static int slineno[DAHDI_MAX_CHANNELS]; /* Line number where signalling specified */
102
103 static int fiftysixkhdlc[DAHDI_MAX_CHANNELS];
104
105 static int spans=0;
106
107 static int fo_real = 1;
108
109 static int verbose = 0;
110
111 static int force = 0;
112
113 static int stopmode = 0;
114
115 static int numdynamic = 0;
116
117 static char zonestoload[DAHDI_TONE_ZONE_MAX][10];
118
119 static int numzones = 0;
120
121 static int fd = -1;
122
123 static const char *lbostr[] = {
124 "0 db (CSU)/0-133 feet (DSX-1)",
125 "133-266 feet (DSX-1)",
126 "266-399 feet (DSX-1)",
127 "399-533 feet (DSX-1)",
128 "533-655 feet (DSX-1)",
129 "-7.5db (CSU)",
130 "-15db (CSU)",
131 "-22.5db (CSU)"
132 };
133
134 static const char *laws[] = {
135         "Default",
136         "Mu-law",
137         "A-law"
138 };
139
140 static const char *sigtype_to_str(const int sig)
141 {
142         switch (sig) {
143         case 0:
144                 return "Unused";
145         case DAHDI_SIG_EM:
146                 return "E & M";
147         case DAHDI_SIG_EM_E1:
148                 return "E & M E1";
149         case DAHDI_SIG_FXSLS:
150                 return "FXS Loopstart";
151         case DAHDI_SIG_FXSGS:
152                 return "FXS Groundstart";
153         case DAHDI_SIG_FXSKS:
154                 return "FXS Kewlstart";
155         case DAHDI_SIG_FXOLS:
156                 return "FXO Loopstart";
157         case DAHDI_SIG_FXOGS:
158                 return "FXO Groundstart";
159         case DAHDI_SIG_FXOKS:
160                 return "FXO Kewlstart";
161         case DAHDI_SIG_CAS:
162                 return "CAS / User";
163         case DAHDI_SIG_DACS:
164                 return "DACS";
165         case DAHDI_SIG_DACS_RBS:
166                 return "DACS w/RBS";
167         case DAHDI_SIG_CLEAR:
168                 return "Clear channel";
169         case DAHDI_SIG_SLAVE:
170                 return "Slave channel";
171         case DAHDI_SIG_HDLCRAW:
172                 return "Raw HDLC";
173         case DAHDI_SIG_HDLCNET:
174                 return "Network HDLC";
175         case DAHDI_SIG_HDLCFCS:
176                 return "HDLC with FCS check";
177         case DAHDI_SIG_HARDHDLC:
178                 return "Hardware assisted D-channel";
179         case DAHDI_SIG_MTP2:
180                 return "MTP2";
181         default:
182                 return "Unknown";
183         }
184 }
185
186 static void clear_fields()
187 {
188
189         memset(rxtones,0,sizeof(rxtones));
190         memset(rxtags,0,sizeof(rxtags));
191         memset(txtones,0,sizeof(txtones));
192         bursttime = 0;
193         debouncetime = 0;
194         invertcor = 0;
195         exttone = 0;
196         txgain = 0;
197         rxgain = 0;
198         deemp = 0;
199         preemp = 0;
200 }
201
202 static int error(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
203
204 static int error(char *fmt, ...)
205 {
206         int res;
207         static int shown=0;
208         va_list ap;
209         if (!shown) {
210                 fprintf(stderr, "Notice: Configuration file is %s\n", filename);
211                 shown++;
212         }
213         res = fprintf(stderr, "line %d: ", lineno);
214         va_start(ap, fmt);
215         vfprintf(stderr, fmt, ap);
216         va_end(ap);
217         errcnt++;
218         return res;
219 }
220
221 static char *trim(char *buf)
222 {
223         size_t len;
224
225         while (*buf && (*buf < 33)) {
226                 buf++;
227         }
228
229         len = strlen(buf);
230
231         while (len && buf[len-1] < 33) {
232                 buf[--len] = '\0';
233         }
234
235         return buf;
236 }
237
238 static int skip_channel(int x)
239 {
240         int     spanno = chan2span[x];
241
242         if (restrict_channels) {
243                 if (!selected_channels[x])
244                         return 1;
245                 /* sanity check */
246                 if (only_span) {
247                         if (spanno != 0 && only_span != spanno) {
248                                 fprintf(stderr,
249                                         "Only span %d. Skip selected channel %d from span %d\n",
250                                         only_span, x, spanno);
251                                 return 1;
252                         }
253                 }
254         } else {
255                 if (only_span && !declared_spans[only_span]) {
256                         fprintf(stderr,
257                                 "Error: analog span %d given to '-S', without '-C' restriction.\n",
258                                 only_span);
259                         exit(1);
260                 }
261                 if (only_span && only_span != spanno)
262                         return 1;
263         }
264         return 0;
265 }
266
267 static int parseargs(char *input, char *output[], int maxargs, char sep)
268 {
269         char *c;
270         int pos=0;
271         c = input;
272         output[pos++] = c;
273         while(*c) {
274                 while(*c && (*c != sep)) c++;
275                 if (*c) {
276                         *c = '\0';
277                         c++;
278                         while(*c && (*c < 33)) c++;
279                         if (*c)  {
280                                 if (pos >= maxargs)
281                                         return -1;
282                                 output[pos] = c;
283                                 trim(output[pos]);
284                                 pos++;
285                                 output[pos] = NULL;
286                                 /* Return error if we have too many */
287                         } else
288                                 return pos;
289                 }
290         }
291         return pos;
292 }
293
294 int dspanconfig(char *keyword, char *args)
295 {
296         static char *realargs[10];
297         int res;
298         int chans;
299         int timing;
300         res = parseargs(args, realargs, 4, ',');
301         if (res != 4) {
302                 error("Incorrect number of arguments to 'dynamic' (should be <driver>,<address>,<num channels>, <timing>)\n");
303                 return -1;
304         }
305         res = sscanf(realargs[2], "%d", &chans);
306         if ((res == 1) && (chans < 1))
307                 res = -1;
308         if (res != 1) {
309                 error("Invalid number of channels '%s', should be a number > 0.\n", realargs[2]);
310                 return -1;
311         }
312
313         res = sscanf(realargs[3], "%d", &timing);
314         if ((res == 1) && (timing < 0))
315                 res = -1;
316         if (res != 1) {
317                 error("Invalid timing '%s', should be a number > 0.\n", realargs[3]);
318                 return -1;
319         }
320
321
322         dahdi_copy_string(zds[numdynamic].driver, realargs[0], sizeof(zds[numdynamic].driver));
323         dahdi_copy_string(zds[numdynamic].addr, realargs[1], sizeof(zds[numdynamic].addr));
324         zds[numdynamic].numchans = chans;
325         zds[numdynamic].timing = timing;
326         
327         numdynamic++;
328         return 0;
329 }
330
331 int spanconfig(char *keyword, char *args)
332 {
333         static char *realargs[10];
334         int res;
335         int argc;
336         int span;
337         int timing;
338         int i;
339         argc = res = parseargs(args, realargs, 9, ',');
340         if ((res < 5) || (res > 9)) {
341                 error("Incorrect number of arguments to 'span' (should be <spanno>,<timing>,<lbo>,<framing>,<coding>[, crc4 | yellow [, yellow]])\n");
342                 return -1;
343         }
344         res = sscanf(realargs[0], "%d", &span);
345         if (res != 1) {
346                 error("Span number should be a valid span number, not '%s'\n", realargs[0]);
347                 return -1;
348         }
349         current_span = span;
350         declared_spans[span] = 1;
351         res = sscanf(realargs[1], "%d", &timing);
352         if ((res != 1) || (timing < 0) || (timing > MAX_TIMING)) {
353                 error("Timing should be a number from 0 to %d, not '%s'\n", 
354                                 MAX_TIMING,  realargs[1]);
355                 return -1;
356         }
357         res = sscanf(realargs[2], "%d", &lc[spans].lbo);
358         if (res != 1) {
359                 error("Line build-out (LBO) should be a number from 0 to 7 (usually 0) not '%s'\n", realargs[2]);
360                 return -1;
361         }
362         if ((lc[spans].lbo < 0) || (lc[spans].lbo > 7)) {
363                 error("Line build-out should be in the range 0 to 7, not %d\n", lc[spans].lbo);
364                 return -1;
365         }
366         if (!strcasecmp(realargs[3], "d4")) {
367                 lc[spans].lineconfig |= DAHDI_CONFIG_D4;
368                 lc[spans].lineconfig &= ~DAHDI_CONFIG_ESF;
369                 lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
370         } else if (!strcasecmp(realargs[3], "esf")) {
371                 lc[spans].lineconfig |= DAHDI_CONFIG_ESF;
372                 lc[spans].lineconfig &= ~DAHDI_CONFIG_D4;
373                 lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
374         } else if (!strcasecmp(realargs[3], "ccs")) {
375                 lc[spans].lineconfig |= DAHDI_CONFIG_CCS;
376                 lc[spans].lineconfig &= ~(DAHDI_CONFIG_ESF | DAHDI_CONFIG_D4);
377         } else if (!strcasecmp(realargs[3], "cas")) {
378                 lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
379                 lc[spans].lineconfig &= ~(DAHDI_CONFIG_ESF | DAHDI_CONFIG_D4);
380         } else {
381                 error("Framing(T1)/Signalling(E1) must be one of 'd4', 'esf', 'cas' or 'ccs', not '%s'\n", realargs[3]);
382                 return -1;
383         }
384         if (!strcasecmp(realargs[4], "ami")) {
385                 lc[spans].lineconfig &= ~(DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_HDB3);
386                 lc[spans].lineconfig |= DAHDI_CONFIG_AMI;
387         } else if (!strcasecmp(realargs[4], "b8zs")) {
388                 lc[spans].lineconfig |= DAHDI_CONFIG_B8ZS;
389                 lc[spans].lineconfig &= ~(DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3);
390         } else if (!strcasecmp(realargs[4], "hdb3")) {
391                 lc[spans].lineconfig |= DAHDI_CONFIG_HDB3;
392                 lc[spans].lineconfig &= ~(DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS);
393         } else {
394                 error("Coding must be one of 'ami', 'b8zs' or 'hdb3', not '%s'\n", realargs[4]);
395                 return -1;
396         }
397         for (i = 5; i < argc; i++) {
398                 if (!strcasecmp(realargs[i], "yellow"))
399                         lc[spans].lineconfig |= DAHDI_CONFIG_NOTOPEN;
400                 else if (!strcasecmp(realargs[i], "crc4"))
401                         lc[spans].lineconfig |= DAHDI_CONFIG_CRC4;
402                 else if (!strcasecmp(realargs[i], "nt"))
403                         lc[spans].lineconfig |= DAHDI_CONFIG_NTTE;
404                 else if (!strcasecmp(realargs[i], "te"))
405                         lc[spans].lineconfig &= ~DAHDI_CONFIG_NTTE;
406                 else if (!strcasecmp(realargs[i], "term"))
407                         lc[spans].lineconfig |= DAHDI_CONFIG_TERM;
408                 else {
409                         error("Remaining arguments may be any of: 'yellow', 'crc4', 'nt', 'te', 'term', not '%s'\n", realargs[i]);
410                         return -1;
411                 }
412
413         }
414         lc[spans].span = span;
415         lc[spans].sync = timing;
416         /* Valid span */
417         spans++;
418         return 0;
419 }
420
421 int apply_channels(int chans[], char *argstr)
422 {
423         char *args[DAHDI_MAX_CHANNELS+1];
424         char *range[3];
425         int res,x, res2,y;
426         int chan;
427         int start, finish;
428         char argcopy[256];
429         res = parseargs(argstr, args, DAHDI_MAX_CHANNELS, ',');
430         if (res < 0) {
431                 error("Too many arguments...  Max is %d\n", DAHDI_MAX_CHANNELS);
432                 return -1;
433         }
434         for (x=0;x<res;x++) {
435                 if (strchr(args[x], '-')) {
436                         /* It's a range */
437                         dahdi_copy_string(argcopy, args[x], sizeof(argcopy));
438                         res2 = parseargs(argcopy, range, 2, '-');
439                         if (res2 != 2) {
440                                 error("Syntax error in range '%s'.  Should be <val1>-<val2>.\n", args[x]);
441                                 return -1;
442                         }
443                         res2 =sscanf(range[0], "%d", &start);
444                         if (res2 != 1) {
445                                 error("Syntax error.  Start of range '%s' should be a number from 1 to %d\n", args[x], DAHDI_MAX_CHANNELS - 1);
446                                 return -1;
447                         } else if ((start < 1) || (start >= DAHDI_MAX_CHANNELS)) {
448                                 error("Start of range '%s' must be between 1 and %d (not '%d')\n", args[x], DAHDI_MAX_CHANNELS - 1, start);
449                                 return -1;
450                         }
451                         res2 =sscanf(range[1], "%d", &finish);
452                         if (res2 != 1) {
453                                 error("Syntax error.  End of range '%s' should be a number from 1 to %d\n", args[x], DAHDI_MAX_CHANNELS - 1);
454                                 return -1;
455                         } else if ((finish < 1) || (finish >= DAHDI_MAX_CHANNELS)) {
456                                 error("end of range '%s' must be between 1 and %d (not '%d')\n", args[x], DAHDI_MAX_CHANNELS - 1, finish);
457                                 return -1;
458                         }
459                         if (start > finish) {
460                                 error("Range '%s' should start before it ends\n", args[x]);
461                                 return -1;
462                         }
463                         for (y=start;y<=finish;y++)
464                                 chans[y]=1;
465                 } else {
466                         /* It's a single channel */
467                         res2 =sscanf(args[x], "%d", &chan);
468                         if (res2 != 1) {
469                                 error("Syntax error.  Channel should be a number from 1 to %d, not '%s'\n", DAHDI_MAX_CHANNELS - 1, args[x]);
470                                 return -1;
471                         } else if ((chan < 1) || (chan >= DAHDI_MAX_CHANNELS)) {
472                                 error("Channel must be between 1 and %d (not '%d')\n", DAHDI_MAX_CHANNELS - 1, chan);
473                                 return -1;
474                         }
475                         chans[chan]=1;
476                 }               
477         }
478         return res;
479 }
480
481 int parse_idle(int *i, char *s)
482 {
483         char a,b,c,d;
484         if (s) {
485                 if (sscanf(s, "%c%c%c%c", &a,&b,&c,&d) == 4) {
486                         if (((a == '0') || (a == '1')) && ((b == '0') || (b == '1')) && ((c == '0') || (c == '1')) && ((d == '0') || (d == '1'))) {
487                                 *i = 0;
488                                 if (a == '1') 
489                                         *i |= DAHDI_ABIT;
490                                 if (b == '1')
491                                         *i |= DAHDI_BBIT;
492                                 if (c == '1')
493                                         *i |= DAHDI_CBIT;
494                                 if (d == '1')
495                                         *i |= DAHDI_DBIT;
496                                 return 0;
497                         }
498                 }
499         }
500         error("CAS Signalling requires idle definition in the form ':xxxx' at the end of the channel definition, where xxxx represent the a, b, c, and d bits\n");
501         return -1;
502 }
503
504 static int parse_channel(char *channel, int *startchan)
505 {
506         if (!channel || (sscanf(channel, "%d", startchan) != 1) || 
507                 (*startchan < 1)) {
508                 error("DACS requires a starting channel in the form ':x' where x is the channel\n");
509                 return -1;
510         }
511         return 0;
512 }
513
514 static int chanconfig(char *keyword, char *args)
515 {
516         int chans[DAHDI_MAX_CHANNELS];
517         int res = 0;
518         int x;
519         int master=0;
520         int dacschan = 0;
521         char *idle;
522         int is_digital;
523         bzero(chans, sizeof(chans));
524         strtok(args, ":");
525         idle = strtok(NULL, ":");
526         if (!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) {
527                 res = parse_channel(idle, &dacschan);
528         }
529         if (!res)
530                 res = apply_channels(chans, args);
531         if (res <= 0)
532                 return -1;
533         for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
534                 is_digital = 0;
535                 if (chans[x]) {
536                         if (slineno[x]) {
537                                 error("Channel %d already configured as '%s' at line %d\n", x, sig[x], slineno[x]);
538                                 continue;
539                         }
540                         if ((!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) && slineno[dacschan]) {
541                                 error("DACS Destination channel %d already configured as '%s' at line %d\n", dacschan, sig[dacschan], slineno[dacschan]);
542                                 continue;
543                         } else {
544                                 cc[dacschan].chan = dacschan;
545                                 cc[dacschan].master = dacschan;
546                                 slineno[dacschan] = lineno;
547                         }
548                         cc[x].chan = x;
549                         cc[x].master = x;
550                         slineno[x] = lineno;
551                         if (!strcasecmp(keyword, "e&m")) {
552                                 cc[x].sigtype = DAHDI_SIG_EM;
553                                 sig[x] = sigtype_to_str(cc[x].sigtype);
554                         } else if (!strcasecmp(keyword, "e&me1")) {
555                                 cc[x].sigtype = DAHDI_SIG_EM_E1;
556                                 sig[x] = sigtype_to_str(cc[x].sigtype);
557                         } else if (!strcasecmp(keyword, "fxsls")) {
558                                 cc[x].sigtype = DAHDI_SIG_FXSLS;
559                                 sig[x] = sigtype_to_str(cc[x].sigtype);
560                         } else if (!strcasecmp(keyword, "fxsgs")) {
561                                 cc[x].sigtype = DAHDI_SIG_FXSGS;
562                                 sig[x] = sigtype_to_str(cc[x].sigtype);
563                         } else if (!strcasecmp(keyword, "fxsks")) {
564                                 cc[x].sigtype = DAHDI_SIG_FXSKS;
565                                 sig[x] = sigtype_to_str(cc[x].sigtype);
566                         } else if (!strcasecmp(keyword, "fxols")) {
567                                 cc[x].sigtype = DAHDI_SIG_FXOLS;
568                                 sig[x] = sigtype_to_str(cc[x].sigtype);
569                         } else if (!strcasecmp(keyword, "fxogs")) {
570                                 cc[x].sigtype = DAHDI_SIG_FXOGS;
571                                 sig[x] = sigtype_to_str(cc[x].sigtype);
572                         } else if (!strcasecmp(keyword, "fxoks")) {
573                                 cc[x].sigtype = DAHDI_SIG_FXOKS;
574                                 sig[x] = sigtype_to_str(cc[x].sigtype);
575                         } else if (!strcasecmp(keyword, "cas") || !strcasecmp(keyword, "user")) {
576                                 if (parse_idle(&cc[x].idlebits, idle))
577                                         return -1;
578                                 cc[x].sigtype = DAHDI_SIG_CAS;
579                                 sig[x] = sigtype_to_str(cc[x].sigtype);
580                                 is_digital = 1;
581                         } else if (!strcasecmp(keyword, "dacs")) {
582                                 /* Setup channel for monitor */
583                                 cc[x].idlebits = dacschan;
584                                 cc[x].sigtype = DAHDI_SIG_DACS;
585                                 sig[x] = sigtype_to_str(cc[x].sigtype);
586                                 /* Setup inverse */
587                                 cc[dacschan].idlebits = x;
588                                 cc[dacschan].sigtype = DAHDI_SIG_DACS;
589                                 sig[x] = sigtype_to_str(cc[dacschan].sigtype);
590                                 dacschan++;
591                                 is_digital = 1;
592                         } else if (!strcasecmp(keyword, "dacsrbs")) {
593                                 /* Setup channel for monitor */
594                                 cc[x].idlebits = dacschan;
595                                 cc[x].sigtype = DAHDI_SIG_DACS_RBS;
596                                 sig[x] = sigtype_to_str(cc[x].sigtype);
597                                 /* Setup inverse */
598                                 cc[dacschan].idlebits = x;
599                                 cc[dacschan].sigtype = DAHDI_SIG_DACS_RBS;
600                                 sig[x] = sigtype_to_str(cc[dacschan].sigtype);
601                                 is_digital = 1;
602                                 dacschan++;
603                         } else if (!strcasecmp(keyword, "unused")) {
604                                 cc[x].sigtype = 0;
605                                 sig[x] = sigtype_to_str(cc[x].sigtype);
606                         } else if (!strcasecmp(keyword, "indclear") || !strcasecmp(keyword, "bchan")) {
607                                 cc[x].sigtype = DAHDI_SIG_CLEAR;
608                                 sig[x] = sigtype_to_str(cc[x].sigtype);
609                                 is_digital = 1;
610                         } else if (!strcasecmp(keyword, "clear")) {
611                                 sig[x] = sigtype_to_str(DAHDI_SIG_CLEAR);
612                                 if (master) {
613                                         cc[x].sigtype = DAHDI_SIG_SLAVE;
614                                         cc[x].master = master;
615                                 } else {
616                                         cc[x].sigtype = DAHDI_SIG_CLEAR;
617                                         master = x;
618                                 }
619                                 is_digital = 1;
620                         } else if (!strcasecmp(keyword, "rawhdlc")) {
621                                 sig[x] = sigtype_to_str(DAHDI_SIG_HDLCRAW);
622                                 if (master) {
623                                         cc[x].sigtype = DAHDI_SIG_SLAVE;
624                                         cc[x].master = master;
625                                 } else {
626                                         cc[x].sigtype = DAHDI_SIG_HDLCRAW;
627                                         master = x;
628                                 }
629                                 is_digital = 1;
630                         } else if (!strcasecmp(keyword, "nethdlc")) {
631                                 sig[x] = sigtype_to_str(DAHDI_SIG_HDLCNET);
632                                 memset(cc[x].netdev_name, 0, sizeof(cc[x].netdev_name));
633                                 if (master) {
634                                         cc[x].sigtype = DAHDI_SIG_SLAVE;
635                                         cc[x].master = master;
636                                 } else {
637                                         cc[x].sigtype = DAHDI_SIG_HDLCNET;
638                                         if (idle) {
639                                             dahdi_copy_string(cc[x].netdev_name, idle, sizeof(cc[x].netdev_name));
640                                         }
641                                         master = x;
642                                 }
643                                 is_digital = 1;
644                         } else if (!strcasecmp(keyword, "fcshdlc")) {
645                                 sig[x] = sigtype_to_str(DAHDI_SIG_HDLCFCS);
646                                 if (master) {
647                                         cc[x].sigtype = DAHDI_SIG_SLAVE;
648                                         cc[x].master = master;
649                                 } else {
650                                         cc[x].sigtype = DAHDI_SIG_HDLCFCS;
651                                         master = x;
652                                 }
653                                 is_digital = 1;
654                         } else if (!strcasecmp(keyword, "dchan")) {
655                                 sig[x] = "D-channel";
656                                 cc[x].sigtype = DAHDI_SIG_HDLCFCS;
657                                 is_digital = 1;
658                         } else if (!strcasecmp(keyword, "hardhdlc")) {
659                                 sig[x] = "Hardware assisted D-channel";
660                                 cc[x].sigtype = DAHDI_SIG_HARDHDLC;
661                                 is_digital = 1;
662                         } else if (!strcasecmp(keyword, "mtp2")) {
663                                 sig[x] = "MTP2";
664                                 cc[x].sigtype = DAHDI_SIG_MTP2;
665                                 is_digital = 1;
666                         } else {
667                                 fprintf(stderr, "Huh? (%s)\n", keyword);
668                         }
669                         if (is_digital)
670                                 chan2span[x] = current_span;
671                         else
672                                 current_span = 0;
673                 }
674         }
675         return 0;
676 }
677
678 static int setlaw(char *keyword, char *args)
679 {
680         int res;
681         int law;
682         int x;
683         int chans[DAHDI_MAX_CHANNELS];
684
685         bzero(chans, sizeof(chans));
686         res = apply_channels(chans, args);
687         if (res <= 0)
688                 return -1;
689         if (!strcasecmp(keyword, "alaw")) {
690                 law = DAHDI_LAW_ALAW;
691         } else if (!strcasecmp(keyword, "mulaw")) {
692                 law = DAHDI_LAW_MULAW;
693         } else if (!strcasecmp(keyword, "deflaw")) {
694                 law = DAHDI_LAW_DEFAULT;
695         } else {
696                 fprintf(stderr, "Huh??? Don't know about '%s' law\n", keyword);
697                 return -1;
698         }
699         for (x=0;x<DAHDI_MAX_CHANNELS;x++) {
700                 if (chans[x])
701                         cc[x].deflaw = law;
702         }
703         return 0;
704 }
705
706 static int setfiftysixkhdlc(char *keyword, char *args)
707 {
708         int res;
709
710         res = apply_channels(fiftysixkhdlc, args);
711         if (res <= 0)
712                 return -1;
713
714         return 0;
715 }
716
717 static void apply_fiftysix(void)
718 {
719         int x;
720         int rate;
721         int chanfd;
722
723         for (x = 1; x < DAHDI_MAX_CHANNELS; x++) {
724                 if (skip_channel(x))
725                         continue;
726                 chanfd = open("/dev/dahdi/channel", O_RDWR);
727                 if (chanfd == -1) {
728                         fprintf(stderr, 
729                             "Couldn't open /dev/dahdi/channel: %s\n", 
730                             strerror(errno));
731                         exit(-1);
732                 }
733
734                 if (ioctl(chanfd, DAHDI_SPECIFY, &x)) {
735                         close(chanfd);
736                         continue;
737                 }
738
739                 if (fiftysixkhdlc[x]) {
740                         printf("Setting channel %d to 56K mode (only valid on HDLC channels)\n", x);
741                         rate = 56;
742                 } else {
743                         rate = 64;
744                 }
745
746                 if (ioctl(chanfd, DAHDI_HDLC_RATE, &rate)) {
747                         fprintf(stderr, "Error setting HDLC rate\n");
748                         exit(-1);
749                 }
750                 close(chanfd);
751         }
752 }
753
754 static int setechocan(char *keyword, char *args)
755 {
756         int res;
757         int chans[DAHDI_MAX_CHANNELS] = { 0, };
758         char *echocan, *chanlist;
759         unsigned int x;
760
761         echocan = strtok(args, ",");
762
763         while ((chanlist = strtok(NULL, ","))) {
764                 res = apply_channels(chans, chanlist);
765                 if (res <= 0) {
766                         return -1;
767                 }
768         }
769
770         for (x = 0; x < DAHDI_MAX_CHANNELS; x++) {
771                 if (chans[x]) {
772                         dahdi_copy_string(ae[x].echocan, echocan, sizeof(ae[x].echocan));
773                 }
774         }
775
776         return 0;
777 }
778
779 static int registerzone(char *keyword, char *args)
780 {
781         if (numzones >= DAHDI_TONE_ZONE_MAX) {
782                 error("Too many tone zones specified\n");
783                 return 0;
784         }
785         dahdi_copy_string(zonestoload[numzones++], args, sizeof(zonestoload[0]));
786         return 0;
787 }
788
789 static int defaultzone(char *keyword, char *args)
790 {
791         struct tone_zone *z;
792         if (!(z = tone_zone_find(args))) {
793                 error("No such tone zone known: %s\n", args);
794                 return 0;
795         }
796         deftonezone = z->zone;
797         return 0;
798 }
799
800 #if 0
801 static int unimplemented(char *keyword, char *args)
802 {
803         fprintf(stderr, "Warning: '%s' is not yet implemented\n", keyword);
804         return 0;
805 }
806 #endif
807
808
809 /* Radio functions */
810
811 int ctcss(char *keyword, char *args)
812 {
813         static char *realargs[10];
814         int res;
815         int rxtone;
816         int rxtag;
817         int txtone;
818         int isdcs = 0;
819         res = parseargs(args, realargs, 3, ',');
820         if (res != 3) {
821                 error("Incorrect number of arguments to 'ctcss' (should be <rxtone>,<rxtag>,<txtone>)\n");
822                 return -1;
823         }
824         res = sscanf(realargs[0], "%d", &rxtone);
825         if ((res == 1) && (rxtone < 1))
826                 res = -1;
827         if (res != 1) {
828                 error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]);
829                 return -1;
830         }
831         res = sscanf(realargs[1], "%d", &rxtag);
832         if ((res == 1) && (rxtag < 0))
833                 res = -1;
834         if (res != 1) {
835                 error("Invalid rxtag '%s', should be a number > 0.\n", realargs[1]);
836                 return -1;
837         }
838         if ((*realargs[2] == 'D') || (*realargs[2] == 'd'))
839         {
840                 realargs[2]++;
841                 isdcs = 0x8000;
842         }
843         res = sscanf(realargs[2], "%d", &txtone);
844         if ((res == 1) && (rxtag < 0))
845                 res = -1;
846         if (res != 1) {
847                 error("Invalid txtone '%s', should be a number > 0.\n", realargs[2]);
848                 return -1;
849         }
850
851         if (toneindex >= NUM_TONES)
852         {
853                 error("Cannot specify more then %d CTCSS tones\n",NUM_TONES);
854                 return -1;
855         }
856         rxtones[toneindex] = rxtone;
857         rxtags[toneindex] = rxtag;
858         txtones[toneindex] = txtone | isdcs;
859         toneindex++;
860         return 0;
861 }
862
863 int dcsrx(char *keyword, char *args)
864 {
865         static char *realargs[10];
866         int res;
867         int rxtone;
868         res = parseargs(args, realargs, 1, ',');
869         if (res != 1) {
870                 error("Incorrect number of arguments to 'dcsrx' (should be <rxtone>)\n");
871                 return -1;
872         }
873         res = sscanf(realargs[0], "%d", &rxtone);
874         if ((res == 1) && (rxtone < 1))
875                 res = -1;
876         if (res != 1) {
877                 error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]);
878                 return -1;
879         }
880
881         rxtones[0] = rxtone;
882         return 0;
883 }
884
885 int tx(char *keyword, char *args)
886 {
887         static char *realargs[10];
888         int res;
889         int txtone;
890         int isdcs = 0;
891         res = parseargs(args, realargs, 1, ',');
892         if (res != 1) {
893                 error("Incorrect number of arguments to 'tx' (should be <txtone>)\n");
894                 return -1;
895         }
896         if ((*realargs[0] == 'D') || (*realargs[0] == 'd'))
897         {
898                 realargs[0]++;
899                 isdcs = 0x8000;
900         }
901         res = sscanf(realargs[0], "%d", &txtone);
902         if ((res == 1) && (txtone < 1))
903                 res = -1;
904         if (res != 1) {
905                 error("Invalid tx (tone) '%s', should be a number > 0.\n", realargs[0]);
906                 return -1;
907         }
908
909         txtones[0] = txtone | isdcs;
910         return 0;
911 }
912
913 int debounce_time(char *keyword, char *args)
914 {
915         static char *realargs[10];
916         int res;
917         int val;
918         res = parseargs(args, realargs, 1, ',');
919         if (res != 1) {
920                 error("Incorrect number of arguments to 'debouncetime' (should be <value>)\n");
921                 return -1;
922         }
923         res = sscanf(realargs[0], "%d", &val);
924         if ((res == 1) && (val < 1))
925                 res = -1;
926         if (res != 1) {
927                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
928                 return -1;
929         }
930
931         debouncetime = val;
932         return 0;
933 }
934
935 int burst_time(char *keyword, char *args)
936 {
937         static char *realargs[10];
938         int res;
939         int val;
940         res = parseargs(args, realargs, 1, ',');
941         if (res != 1) {
942                 error("Incorrect number of arguments to 'bursttime' (should be <value>)\n");
943                 return -1;
944         }
945         res = sscanf(realargs[0], "%d", &val);
946         if ((res == 1) && (val < 1))
947                 res = -1;
948         if (res != 1) {
949                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
950                 return -1;
951         }
952
953         bursttime = val;
954         return 0;
955 }
956
957 int tx_gain(char *keyword, char *args)
958 {
959         static char *realargs[10];
960         int res;
961         int val;
962         res = parseargs(args, realargs, 1, ',');
963         if (res != 1) {
964                 error("Incorrect number of arguments to 'txgain' (should be <value>)\n");
965                 return -1;
966         }
967         res = sscanf(realargs[0], "%d", &val);
968         if (res != 1) {
969                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
970                 return -1;
971         }
972
973         txgain = val;
974         return 0;
975 }
976
977 int rx_gain(char *keyword, char *args)
978 {
979         static char *realargs[10];
980         int res;
981         int val;
982         res = parseargs(args, realargs, 1, ',');
983         if (res != 1) {
984                 error("Incorrect number of arguments to 'rxgain' (should be <value>)\n");
985                 return -1;
986         }
987         res = sscanf(realargs[0], "%d", &val);
988         if (res != 1) {
989                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
990                 return -1;
991         }
992
993         rxgain = val;
994         return 0;
995 }
996
997 int de_emp(char *keyword, char *args)
998 {
999         static char *realargs[10];
1000         int res;
1001         int val;
1002         res = parseargs(args, realargs, 1, ',');
1003         if (res != 1) {
1004                 error("Incorrect number of arguments to 'de-emp' (should be <value>)\n");
1005                 return -1;
1006         }
1007         res = sscanf(realargs[0], "%d", &val);
1008         if ((res == 1) && (val < 1))
1009                 res = -1;
1010         if (res != 1) {
1011                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1012                 return -1;
1013         }
1014
1015         deemp = val;
1016         return 0;
1017 }
1018
1019 int pre_emp(char *keyword, char *args)
1020 {
1021         static char *realargs[10];
1022         int res;
1023         int val;
1024         res = parseargs(args, realargs, 1, ',');
1025         if (res != 1) {
1026                 error("Incorrect number of arguments to 'pre_emp' (should be <value>)\n");
1027                 return -1;
1028         }
1029         res = sscanf(realargs[0], "%d", &val);
1030         if ((res == 1) && (val < 1))
1031                 res = -1;
1032         if (res != 1) {
1033                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1034                 return -1;
1035         }
1036
1037         preemp = val;
1038         return 0;
1039 }
1040
1041 int invert_cor(char *keyword, char *args)
1042 {
1043         static char *realargs[10];
1044         int res;
1045         int val;
1046         res = parseargs(args, realargs, 1, ',');
1047         if (res != 1) {
1048                 error("Incorrect number of arguments to 'invertcor' (should be <value>)\n");
1049                 return -1;
1050         }
1051         if ((*realargs[0] == 'y') || (*realargs[0] == 'Y')) val = 1;
1052         else if ((*realargs[0] == 'n') || (*realargs[0] == 'N')) val = 0;
1053         else
1054         {
1055                 res = sscanf(realargs[0], "%d", &val);
1056                 if ((res == 1) && (val < 0))
1057                         res = -1;
1058                 if (res != 1) {
1059                         error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1060                         return -1;
1061                 }
1062         }
1063         invertcor = (val > 0);
1064         return 0;
1065 }
1066
1067 int ext_tone(char *keyword, char *args)
1068 {
1069         static char *realargs[10];
1070         int res;
1071         int val;
1072         res = parseargs(args, realargs, 1, ',');
1073         if (res != 1) {
1074                 error("Incorrect number of arguments to 'exttone' (should be <value>)\n");
1075                 return -1;
1076         }
1077         if ((*realargs[0] == 'y') || (*realargs[0] == 'Y')) val = 1;
1078         else if ((*realargs[0] == 'n') || (*realargs[0] == 'N')) val = 0;
1079         else if ((*realargs[0] == 'i') || (*realargs[0] == 'I')) val = 2;
1080         else
1081         {
1082                 res = sscanf(realargs[0], "%d", &val);
1083                 if ((res == 1) && (val < 0))
1084                         res = -1;
1085                 if (val > 2) res = -1;
1086                 if (res != 1) {
1087                         error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1088                         return -1;
1089                 }
1090         }
1091         exttone = val;
1092         return 0;
1093 }
1094
1095 int cor_thresh(char *keyword, char *args)
1096 {
1097         static char *realargs[10];
1098         int res;
1099         int val;
1100         int x = 0;
1101         res = parseargs(args, realargs, 1, ',');
1102         if (res != 1) {
1103                 error("Incorrect number of arguments to 'corthresh' (should be <value>)\n");
1104                 return -1;
1105         }
1106         res = sscanf(realargs[0], "%d", &val);
1107         if ((res == 1) && (val < 1))
1108                 res = -1;
1109         for(x = 0; corthreshes[x]; x++)
1110         {
1111                 if (corthreshes[x] == val) break;
1112         }
1113         if (!corthreshes[x]) res = -1;
1114         if (res != 1) {
1115                 error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
1116                 return -1;
1117         }
1118         corthresh = x + 1;
1119         return 0;
1120 }
1121
1122 static int rad_chanconfig(char *keyword, char *args)
1123 {
1124         int chans[DAHDI_MAX_CHANNELS];
1125         int res = 0;
1126         int x,i,n;
1127         struct dahdi_radio_param p;
1128         int chanfd;
1129
1130         toneindex = 1;
1131         bzero(chans, sizeof(chans));
1132         res = apply_channels(chans, args);
1133         if (res <= 0)
1134                 return -1;
1135         for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
1136                 if (chans[x]) {
1137                         const char *CHANNEL_FILENAME = "/dev/dahdi/channel";
1138                         chanfd = open(CHANNEL_FILENAME, O_RDWR);
1139                         if (-1 == chanfd) {
1140                                 error("Failed to open '%s'.\n", CHANNEL_FILENAME);
1141                                 exit(-1);
1142                         }
1143
1144                         res = ioctl(chanfd, DAHDI_SPECIFY, &x);
1145                         if (res) {
1146                                 error("Failed to open channel %d.\n", x);
1147                                 close(chanfd);
1148                                 continue;
1149                         }
1150                         p.radpar = DAHDI_RADPAR_NUMTONES;
1151                         if (ioctl(chanfd,DAHDI_RADIO_GETPARAM,&p) == -1)
1152                                 n = 0;
1153                         else
1154                                 n = p.data;
1155
1156                         if (n)
1157                         {
1158                                 p.radpar = DAHDI_RADPAR_INITTONE;
1159                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1) {
1160                                         error("Cannot init tones for channel %d\n",x);
1161                                 }
1162                                 if (!rxtones[0]) for(i = 1; i <= n; i++)
1163                                 {
1164                                         if (rxtones[i])
1165                                         {
1166                                                 p.radpar = DAHDI_RADPAR_RXTONE;
1167                                                 p.index = i;
1168                                                 p.data = rxtones[i];
1169                                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1170                                                         error("Cannot set rxtone on channel %d\n",x);
1171                                         }
1172                                         if (rxtags[i])
1173                                         {
1174                                                 p.radpar = DAHDI_RADPAR_RXTONECLASS;
1175                                                 p.index = i;
1176                                                 p.data = rxtags[i];
1177                                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1178                                                         error("Cannot set rxtag on channel %d\n",x);
1179                                         }
1180                                         if (txtones[i])
1181                                         {
1182                                                 p.radpar = DAHDI_RADPAR_TXTONE;
1183                                                 p.index = i;
1184                                                 p.data = txtones[i];
1185                                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1186                                                         error("Cannot set txtone on channel %d\n",x);
1187                                         }
1188                                 } else { /* if we may have DCS receive */
1189                                         if (rxtones[0])
1190                                         {
1191                                                 p.radpar = DAHDI_RADPAR_RXTONE;
1192                                                 p.index = 0;
1193                                                 p.data = rxtones[0];
1194                                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1195                                                         error("Cannot set DCS rxtone on channel %d\n",x);
1196                                         }
1197                                 }
1198                                 if (txtones[0])
1199                                 {
1200                                         p.radpar = DAHDI_RADPAR_TXTONE;
1201                                         p.index = 0;
1202                                         p.data = txtones[0];
1203                                         if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1204                                                 error("Cannot set default txtone on channel %d\n",x);
1205                                 }
1206                         }
1207                         if (debouncetime)
1208                         {
1209                                 p.radpar = DAHDI_RADPAR_DEBOUNCETIME;
1210                                 p.data = debouncetime;
1211                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1212                                         error("Cannot set debouncetime on channel %d\n",x);
1213                         }
1214                         if (bursttime)
1215                         {
1216                                 p.radpar = DAHDI_RADPAR_BURSTTIME;
1217                                 p.data = bursttime;
1218                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1219                                         error("Cannot set bursttime on channel %d\n",x);
1220                         }
1221                         p.radpar = DAHDI_RADPAR_DEEMP;
1222                         p.data = deemp;
1223                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1224                         p.radpar = DAHDI_RADPAR_PREEMP;
1225                         p.data = preemp;
1226                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1227                         p.radpar = DAHDI_RADPAR_TXGAIN;
1228                         p.data = txgain;
1229                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1230                         p.radpar = DAHDI_RADPAR_RXGAIN;
1231                         p.data = rxgain;
1232                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1233                         p.radpar = DAHDI_RADPAR_INVERTCOR;
1234                         p.data = invertcor;
1235                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1236                         p.radpar = DAHDI_RADPAR_EXTRXTONE;
1237                         p.data = exttone;
1238                         ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p);
1239                         if (corthresh)
1240                         {
1241                                 p.radpar = DAHDI_RADPAR_CORTHRESH;
1242                                 p.data = corthresh - 1;
1243                                 if (ioctl(chanfd,DAHDI_RADIO_SETPARAM,&p) == -1)
1244                                         error("Cannot set corthresh on channel %d\n",x);
1245                         }
1246
1247                         close(chanfd);
1248                 }
1249         }
1250         clear_fields();
1251         return 0;
1252 }
1253
1254 /* End Radio functions */
1255
1256 static void printconfig(int fd)
1257 {
1258         int x,y;
1259         int ps;
1260         int configs=0;
1261         struct dahdi_versioninfo vi;
1262
1263         strcpy(vi.version, "Unknown");
1264         strcpy(vi.echo_canceller, "Unknown");
1265
1266         if (ioctl(fd, DAHDI_GETVERSION, &vi))
1267                 error("Unable to read DAHDI version information.\n");
1268
1269         printf("\nDAHDI Version: %s\n"
1270                "Echo Canceller(s): %s\n"
1271                "Configuration\n"
1272                "======================\n\n", vi.version, vi.echo_canceller);
1273         for (x = 0; x < spans; x++) {
1274                 if (only_span && only_span != lc[x].span)
1275                         continue;
1276                 printf("SPAN %d: %3s/%4s Build-out: %s\n",
1277                        lc[x].span,
1278                        (lc[x].lineconfig & DAHDI_CONFIG_D4 ? "D4" :
1279                         lc[x].lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
1280                         lc[x].lineconfig & DAHDI_CONFIG_CCS ? "CCS" : "CAS"),
1281                        (lc[x].lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
1282                         lc[x].lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
1283                         lc[x].lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" : "???"),
1284                        lbostr[lc[x].lbo]);
1285         }
1286         for (x=0;x<numdynamic;x++) {
1287                 printf("Dynamic span %d: driver %s, addr %s, channels %d, timing %d\n",
1288                        x +1, zds[x].driver, zds[x].addr, zds[x].numchans, zds[x].timing);
1289         }
1290         if (verbose > 1) {
1291                 printf("\nChannel map:\n\n");
1292                 for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
1293                         if (skip_channel(x))
1294                                 continue;
1295                         if ((cc[x].sigtype != DAHDI_SIG_SLAVE) && (cc[x].sigtype)) {
1296                                 configs++;
1297                                 ps = 0;
1298                                 if ((cc[x].sigtype & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS)
1299                                         printf("Channel %02d %s to %02d", x, sig[x], cc[x].idlebits);
1300                                 else {
1301                                         printf("Channel %02d: %s (%s)", x, sig[x], laws[cc[x].deflaw]);
1302                                         printf(" (Echo Canceler: %s)", ae[x].echocan[0] ? ae[x].echocan : "none");
1303                                         for (y=1;y<DAHDI_MAX_CHANNELS;y++) {
1304                                                 if (cc[y].master == x)  {
1305                                                         printf("%s%02d", ps++ ? " " : " (Slaves: ", y);
1306                                                 }
1307                                         }
1308                                 }
1309                                 if (ps)
1310                                         printf(")\n");
1311                                 else
1312                                         printf("\n");
1313                         } else
1314                                 if (cc[x].sigtype) configs++;
1315                 }
1316         } else {
1317                 for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
1318                         if (skip_channel(x))
1319                                 continue;
1320                         if (cc[x].sigtype)
1321                                 configs++;
1322                 }
1323         }
1324         printf("\n%d channels to configure.\n\n", configs);
1325 }
1326
1327 static struct handler {
1328         char *keyword;
1329         int (*func)(char *keyword, char *args);
1330 } handlers[] = {
1331         { "span", spanconfig },
1332         { "dynamic", dspanconfig },
1333         { "loadzone", registerzone },
1334         { "defaultzone", defaultzone },
1335         { "e&m", chanconfig },
1336         { "e&me1", chanconfig },
1337         { "fxsls", chanconfig },
1338         { "fxsgs", chanconfig },
1339         { "fxsks", chanconfig },
1340         { "fxols", chanconfig },
1341         { "fxogs", chanconfig },
1342         { "fxoks", chanconfig },
1343         { "rawhdlc", chanconfig },
1344         { "nethdlc", chanconfig },
1345         { "fcshdlc", chanconfig },
1346         { "hardhdlc", chanconfig },
1347         { "mtp2", chanconfig },
1348         { "dchan", chanconfig },
1349         { "bchan", chanconfig },
1350         { "indclear", chanconfig },
1351         { "clear", chanconfig },
1352         { "unused", chanconfig },
1353         { "cas", chanconfig },
1354         { "dacs", chanconfig },
1355         { "dacsrbs", chanconfig },
1356         { "user", chanconfig },
1357         { "alaw", setlaw },
1358         { "mulaw", setlaw },
1359         { "deflaw", setlaw },
1360         { "ctcss", ctcss },
1361         { "dcsrx", dcsrx },
1362         { "rxdcs", dcsrx },
1363         { "tx", tx },
1364         { "debouncetime", debounce_time },
1365         { "bursttime", burst_time },
1366         { "exttone", ext_tone },
1367         { "invertcor", invert_cor },
1368         { "corthresh", cor_thresh },
1369         { "rxgain", rx_gain },
1370         { "txgain", tx_gain },
1371         { "deemp", de_emp },
1372         { "preemp", pre_emp },
1373         { "channel", rad_chanconfig },
1374         { "channels", rad_chanconfig },
1375         { "echocanceller", setechocan },
1376         { "56k", setfiftysixkhdlc },
1377 };
1378
1379 static char *readline()
1380 {
1381         static char buf[256];
1382         char *c;
1383         do {
1384                 if (!fgets(buf, sizeof(buf), cf)) 
1385                         return NULL;
1386                 /* Strip comments */
1387                 c = strchr(buf, '#');
1388                 if (c)
1389                         *c = '\0';
1390                 trim(buf);
1391                 lineno++;
1392         } while (!strlen(buf));
1393         return buf;
1394 }
1395
1396 static void usage(char *argv0, int exitcode)
1397 {
1398         char *c;
1399         c = strrchr(argv0, '/');
1400         if (!c)
1401                 c = argv0;
1402         else
1403                 c++;
1404         fprintf(stderr, "%s\n", dahdi_tools_version);
1405         fprintf(stderr, 
1406                 "Usage: %s [options]\n"
1407                 "    Valid options are:\n"
1408                 "  -c <filename>     -- Use <filename> instead of " CONFIG_FILENAME "\n"
1409                 "  -d [level]        -- Generate debugging output. (Default level is 1.)\n"
1410                 "  -f                -- Always reconfigure every channel\n"
1411                 "  -h                -- Generate this help statement\n"
1412                 "  -s                -- Shutdown spans only\n"
1413                 "  -t                -- Test mode only, do not apply\n"
1414                 "  -C <chan_list>    -- Only configure specified channels\n"
1415                 "  -S <spanno>       -- Only configure specified span\n"
1416                 "  -v                -- Verbose (more -v's means more verbose)\n"
1417         ,c);
1418         exit(exitcode);
1419 }
1420
1421 static int chan_restrict(char *str)
1422 {
1423         if (apply_channels(selected_channels, str) < 0)
1424                 return 0;
1425         restrict_channels = 1;
1426         return 1;
1427 }
1428
1429 static int span_restrict(char *str)
1430 {
1431         long    spanno;
1432         char    *endptr;
1433
1434         spanno = strtol(str, &endptr, 10);
1435         if (endptr == str) {
1436                 fprintf(stderr, "Missing valid span number after '-S'\n");
1437                 return 0;
1438         }
1439         if (*endptr != '\0') {
1440                 fprintf(stderr, "Extra garbage after span number in '-S'\n");
1441                 return 0;
1442         }
1443         only_span = spanno;
1444         return 1;
1445 }
1446
1447 int main(int argc, char *argv[])
1448 {
1449         int c;
1450         char *buf;
1451         char *key, *value;
1452         int x,found;
1453
1454         while((c = getopt(argc, argv, "fthc:vsd::C:S:")) != -1) {
1455                 switch(c) {
1456                 case 'c':
1457                         filename=optarg;
1458                         break;
1459                 case 'h':
1460                         usage(argv[0], 0);
1461                         break;
1462                 case '?':
1463                         usage(argv[0], 1);
1464                         break;
1465                 case 'v':
1466                         verbose++;
1467                         break;
1468                 case 'f':
1469                         force++;
1470                         break;
1471                 case 't':
1472                         fo_real = 0;
1473                         break;
1474                 case 's':
1475                         stopmode = 1;
1476                         break;
1477                 case 'C':
1478                         if (!chan_restrict(optarg))
1479                                 usage(argv[0], 1);
1480                         break;
1481                 case 'S':
1482                         if (!span_restrict(optarg))
1483                                 usage(argv[0], 1);
1484                         break;
1485                 case 'd':
1486                         if (optarg)
1487                                 debug = atoi(optarg);
1488                         else
1489                                 debug = 1;      
1490                         break;
1491                 }
1492         }
1493         
1494         if (verbose) {
1495                 fprintf(stderr, "%s\n", dahdi_tools_version);
1496         }
1497
1498         if (fd == -1) fd = open(MASTER_DEVICE, O_RDWR);
1499         if (fd < 0) {
1500                 error("Unable to open master device '%s'\n", MASTER_DEVICE);
1501                 goto finish;
1502         }
1503         cf = fopen(filename, "r");
1504         if (cf) {
1505                 while((buf = readline())) {
1506                         if (*buf == 10) /* skip new line */
1507                                 continue;
1508
1509                         if (debug & DEBUG_READER) 
1510                                 fprintf(stderr, "Line %d: %s\n", lineno, buf);
1511
1512                         if ((value = strchr(buf, '='))) {
1513                                 *value++ = '\0';
1514                                 value = trim(value);
1515                                 key = trim(buf);
1516                         }
1517
1518                         if (!value || !*value || !*key) {
1519                                 error("Syntax error. Should be <keyword>=<value>\n");
1520                                 continue;
1521                         }
1522
1523                         if (debug & DEBUG_PARSER)
1524                                 fprintf(stderr, "Keyword: [%s], Value: [%s]\n", key, value);
1525
1526                         found = 0;
1527                         for (x = 0; x < sizeof(handlers) / sizeof(handlers[0]); x++) {
1528                                 if (!strcasecmp(key, handlers[x].keyword)) {
1529                                         found++;
1530                                         handlers[x].func(key, value);
1531                                         break;
1532                                 }
1533                         }
1534
1535                         if (!found) 
1536                                 error("Unknown keyword '%s'\n", key);
1537                 }
1538                 if (debug & DEBUG_READER)
1539                         fprintf(stderr, "<End of File>\n");
1540                 /* fclose(cf); // causes seg fault (double free) */
1541         } else {
1542                 error("Unable to open configuration file '%s'\n", filename);
1543         }
1544
1545 finish:
1546         if (errcnt) {
1547                 fprintf(stderr, "\n%d error(s) detected\n\n", errcnt);
1548                 exit(1);
1549         }
1550         if (verbose) {
1551                 printconfig(fd);
1552         }
1553         if (!fo_real) 
1554                 exit(0);
1555
1556         
1557         if (debug & DEBUG_APPLY) {
1558                 printf("About to open Master device\n");
1559                 fflush(stdout);
1560         }
1561         for (x=0;x<numdynamic;x++) {
1562                 /* destroy them all */
1563                 ioctl(fd, DAHDI_DYNAMIC_DESTROY, &zds[x]);
1564         }
1565         if (stopmode) {
1566                 for (x=0;x<spans;x++) {
1567                         if (only_span && lc[x].span != only_span)
1568                                 continue;
1569                         if (ioctl(fd, DAHDI_SHUTDOWN, &lc[x].span)) {
1570                                 fprintf(stderr, "DAHDI shutdown failed: %s\n", strerror(errno));
1571                                 close(fd);
1572                                 exit(1);
1573                         }
1574                 }
1575                 exit(1);
1576         }
1577         for (x=0;x<spans;x++) {
1578                 if (only_span && lc[x].span != only_span)
1579                         continue;
1580                 if (ioctl(fd, DAHDI_SPANCONFIG, lc + x)) {
1581                         fprintf(stderr, "DAHDI_SPANCONFIG failed on span %d: %s (%d)\n", lc[x].span, strerror(errno), errno);
1582                         close(fd);
1583                         exit(1);
1584                 }
1585         }
1586         for (x=0;x<numdynamic;x++) {
1587                 if (ioctl(fd, DAHDI_DYNAMIC_CREATE, &zds[x])) {
1588                         fprintf(stderr, "DAHDI dynamic span creation failed: %s\n", strerror(errno));
1589                         close(fd);
1590                         exit(1);
1591                 }
1592         }
1593         for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
1594                 struct dahdi_params current_state;
1595                 int master;
1596                 int needupdate = force;
1597
1598                 if (skip_channel(x)) {
1599                         if (debug & DEBUG_APPLY) {
1600                                 printf("Skip device %d\n", x);
1601                                 fflush(stdout);
1602                         }
1603                         continue;
1604                 }
1605                 if (debug & DEBUG_APPLY) {
1606                         printf("Configuring device %d\n", x);
1607                         fflush(stdout);
1608                 }
1609                 if (!cc[x].sigtype)
1610                         continue;
1611                 
1612                 if (!needupdate) {
1613                         memset(&current_state, 0, sizeof(current_state));
1614                         current_state.channo = cc[x].chan | DAHDI_GET_PARAMS_RETURN_MASTER;
1615                         if (ioctl(fd, DAHDI_GET_PARAMS, &current_state))
1616                                 needupdate = 1;
1617                 }
1618                 
1619                 if (!needupdate) {
1620                         master = current_state.channo >> 16;
1621                         
1622                         if (cc[x].sigtype != current_state.sigtype) {
1623                                 needupdate++;
1624                                 if (verbose > 1)
1625                                         printf("Changing signalling on channel %d from %s to %s\n",
1626                                                cc[x].chan, sigtype_to_str(current_state.sigtype),
1627                                                sigtype_to_str(cc[x].sigtype));
1628                         }
1629                         
1630                         if ((cc[x].deflaw != DAHDI_LAW_DEFAULT) && (cc[x].deflaw != current_state.curlaw)) {
1631                                 needupdate++;
1632                                 if (verbose > 1)
1633                                         printf("Changing law on channel %d from %s to %s\n",
1634                                                cc[x].chan, laws[current_state.curlaw],
1635                                                laws[cc[x].deflaw]);
1636                         }
1637                         
1638                         if (cc[x].master != master) {
1639                                 needupdate++;
1640                                 if (verbose > 1)
1641                                         printf("Changing master of channel %d from %d to %d\n",
1642                                                cc[x].chan, master,
1643                                                cc[x].master);
1644                         }
1645                         
1646                         if (cc[x].idlebits != current_state.idlebits) {
1647                                 needupdate++;
1648                                 if (verbose > 1)
1649                                         printf("Changing idle bits of channel %d from %d to %d\n",
1650                                                cc[x].chan, current_state.idlebits,
1651                                                cc[x].idlebits);
1652                         }
1653                 }
1654                 
1655                 if (needupdate && ioctl(fd, DAHDI_CHANCONFIG, &cc[x])) {
1656                         fprintf(stderr, "DAHDI_CHANCONFIG failed on channel %d: %s (%d)\n", x, strerror(errno), errno);
1657                         if (errno == EINVAL) {
1658                                 /* give helpful suggestions on signaling errors */
1659                                 fprintf(stderr, "Selected signaling not "
1660                                                 "supported\n");
1661                                 fprintf(stderr, "Possible causes:\n");
1662                                 switch(cc[x].sigtype) {
1663                                 case DAHDI_SIG_FXOKS:
1664                                 case DAHDI_SIG_FXOLS:
1665                                 case DAHDI_SIG_FXOGS:
1666                                         fprintf(stderr, "\tFXO signaling is "
1667                                                 "being used on a FXO interface"
1668                                                 " (use a FXS signaling variant"
1669                                                 ")\n");
1670                                         fprintf(stderr, "\tRBS signaling is "
1671                                                 "being used on a E1 CCS span"
1672                                                 "\n");
1673                                         break;
1674                                 case DAHDI_SIG_FXSKS:
1675                                 case DAHDI_SIG_FXSLS:
1676                                 case DAHDI_SIG_FXSGS:
1677                                         fprintf(stderr, "\tFXS signaling is "
1678                                                 "being used on a FXS interface"
1679                                                 " (use a FXO signaling variant"
1680                                                 ")\n");
1681                                         fprintf(stderr, "\tRBS signaling is "
1682                                                 "being used on a E1 CCS span"
1683                                                 "\n");
1684                                         break;
1685                                 case DAHDI_SIG_EM:
1686                                         fprintf(stderr, "\te&m signaling is "
1687                                                 "being used on a E1 line (use"
1688                                                 " e&me1)\n");
1689                                         break;
1690                                 case DAHDI_SIG_EM_E1:
1691                                         fprintf(stderr, "\te&me1 signaling is "
1692                                                 "being used on a T1 line (use "
1693                                                 "e&m)\n");
1694                                         fprintf(stderr, "\tRBS signaling is "
1695                                                 "being used on a E1 CCS span"
1696                                                 "\n");
1697                                         break;
1698                                 case DAHDI_SIG_HARDHDLC:
1699                                         fprintf(stderr, "\thardhdlc is being "
1700                                                 "used on a TE12x (use dchan)\n"
1701                                                 );
1702                                         break;
1703                                 case DAHDI_SIG_HDLCFCS:
1704                                         fprintf(stderr, "\tdchan is being used"
1705                                                 " on a BRI span (use hardhdlc)"
1706                                                 "\n");
1707                                         break;
1708                                 default:
1709                                         break;
1710                                 }
1711                                 fprintf(stderr, "\tSignaling is being assigned"
1712                                         " to channel 16 of an E1 CAS span\n");
1713                         }
1714                         close(fd);
1715                         exit(1);
1716                 }
1717
1718                 ae[x].chan = x;
1719                 if (verbose) {
1720                         printf("Setting echocan for channel %d to %s\n", ae[x].chan, ae[x].echocan[0] ? ae[x].echocan : "none");
1721                 }
1722
1723                 if (ioctl(fd, DAHDI_ATTACH_ECHOCAN, &ae[x])) {
1724                         fprintf(stderr, "DAHDI_ATTACH_ECHOCAN failed on channel %d: %s (%d)\n", x, strerror(errno), errno);
1725                         close(fd);
1726                         exit(1);
1727                 }
1728         }
1729         if (0 == numzones) {
1730                 /* Default to the us zone if one wasn't specified. */
1731                 dahdi_copy_string(zonestoload[numzones++], "us", sizeof(zonestoload[0]));
1732                 deftonezone = 0;
1733         }
1734
1735         for (x=0;x<numzones;x++) {
1736                 if (debug & DEBUG_APPLY) {
1737                         printf("Loading tone zone for %s\n", zonestoload[x]);
1738                         fflush(stdout);
1739                 }
1740                 if (tone_zone_register(fd, zonestoload[x])) {
1741                         if (errno != EBUSY)
1742                                 error("Unable to register tone zone '%s'\n", zonestoload[x]);
1743                 }
1744         }
1745         if (debug & DEBUG_APPLY) {
1746                 printf("Doing startup\n");
1747                 fflush(stdout);
1748         }
1749         if (deftonezone > -1) {
1750                 if (ioctl(fd, DAHDI_DEFAULTZONE, &deftonezone)) {
1751                         fprintf(stderr, "DAHDI_DEFAULTZONE failed: %s (%d)\n", strerror(errno), errno);
1752                         close(fd);
1753                         exit(1);
1754                 }
1755         }
1756         for (x=0;x<spans;x++) {
1757                 if (only_span && lc[x].span != only_span)
1758                         continue;
1759                 if (ioctl(fd, DAHDI_STARTUP, &lc[x].span)) {
1760                         fprintf(stderr, "DAHDI startup failed: %s\n", strerror(errno));
1761                         close(fd);
1762                         exit(1);
1763                 }
1764         }
1765         apply_fiftysix();
1766         exit(0);
1767 }