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