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