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