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