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