Version 0.1.1 from FTP
[asterisk/asterisk.git] / channels / chan_modem.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * A/Open ITU-56/2 Voice Modem Driver (Rockwell, IS-101, and others)
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdio.h>
15 #include <pthread.h>
16 #include <string.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/channel_pvt.h>
19 #include <asterisk/config.h>
20 #include <asterisk/logger.h>
21 #include <asterisk/module.h>
22 #include <asterisk/pbx.h>
23 #include <asterisk/options.h>
24 #include <asterisk/vmodem.h>
25 #include <sys/socket.h>
26 #include <sys/time.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <arpa/inet.h>
31 #include <fcntl.h>
32 #include <sys/ioctl.h>
33 #include <sys/termios.h>
34 #include <sys/signal.h>
35 #include <ctype.h>
36
37 /* Up to 10 seconds for an echo to arrive */
38 #define ECHO_TIMEOUT 10
39
40 static char *desc = "Generic Voice Modem Driver";
41 static char *tdesc = "Generic Voice Modem Channel Driver";
42 static char *type = "Modem";
43 static char *config = "modem.conf";
44 static char dialtype = 'T';
45 static int gmode = MODEM_MODE_IMMEDIATE;
46
47 /* Default modem type */
48 static char mtype[80] = "autodetect";
49 /* Default context for incoming calls */
50 static char context[AST_MAX_EXTENSION]= "default";
51
52 /* Initialization String */
53 static char initstr[AST_MAX_INIT_STR] = "ATE1Q0";
54
55 static int usecnt =0;
56
57 static int baudrate = 115200;
58
59 static int stripmsd = 0;
60
61 static pthread_mutex_t usecnt_lock = PTHREAD_MUTEX_INITIALIZER;
62
63 /* Protect the interface list (of ast_modem_pvt's) */
64 static pthread_mutex_t iflock = PTHREAD_MUTEX_INITIALIZER;
65
66 /* Protect the monitoring thread, so only one process can kill or start it, and not
67    when it's doing something critical. */
68 static pthread_mutex_t monlock = PTHREAD_MUTEX_INITIALIZER;
69
70 /* This is the thread for the monitor which checks for input on the channels
71    which are not currently in use.  */
72 static pthread_t monitor_thread = -1;
73
74 static int restart_monitor(void);
75
76 /* The private structures of the Phone Jack channels are linked for
77    selecting outgoing channels */
78    
79 static struct ast_modem_pvt  *iflist = NULL;
80
81 static int modem_digit(struct ast_channel *ast, char digit)
82 {
83         struct ast_modem_pvt *p;
84         p = ast->pvt->pvt;
85         if (p->mc->dialdigit)
86                 return p->mc->dialdigit(p, digit);
87         else ast_log(LOG_DEBUG, "Channel %s lacks digit dialing\n");
88         return 0;
89 }
90
91 static struct ast_modem_driver *drivers = NULL;
92
93 static struct ast_frame *modem_read(struct ast_channel *);
94
95 static struct ast_modem_driver *find_capability(char *ident)
96 {
97         struct ast_modem_driver *mc;
98         int x;
99         mc = drivers;
100         while(mc) {
101                 for (x=0;mc->idents[x];x++) {
102                         if (!strcmp(ident, mc->idents[x])) 
103                                 break;
104                 }
105                 if (mc->idents[x])
106                         break;
107                 mc = mc->next;
108         }
109         if (mc) {
110                 if (mc->incusecnt)
111                         mc->incusecnt();
112         }
113         return mc;
114 }
115
116 static struct ast_modem_driver *find_driver(char *drv)
117 {
118         struct ast_modem_driver *mc;
119         mc = drivers;
120         while(mc) {
121                 if (!strcasecmp(mc->name, drv)) 
122                         break;
123                 mc = mc->next;
124         }
125         if (mc) {
126                 if (mc->incusecnt)
127                         mc->incusecnt();
128         }
129         return mc;
130 }
131
132 int ast_register_modem_driver(struct ast_modem_driver *mc)
133 {
134         mc->next = drivers;
135         drivers = mc;
136         return 0;
137 }
138
139 int ast_unregister_modem_driver(struct ast_modem_driver *mc)
140 {
141         struct ast_modem_driver *last = NULL, *cur;
142         cur = drivers;
143         while(cur) {
144                 if (cur == mc) {
145                         if (last)
146                                 last->next = mc->next;
147                         else
148                                 drivers = mc->next;
149                         return 0;
150                 }
151                 cur = cur->next;
152         }
153         return -1;
154 }
155
156 static int modem_call(struct ast_channel *ast, char *idest, int timeout)
157 {
158         struct ast_modem_pvt *p;
159         int ms = timeout;
160         char rdest[80], *where;
161         strncpy(rdest, idest, sizeof(rdest));
162         strtok(rdest, ":");
163         where = strtok(NULL, ":");
164         if (!where) {
165                 ast_log(LOG_WARNING, "Destination %s requres a real destination (device:destination)\n", idest);
166                 return -1;
167         }
168         p = ast->pvt->pvt;
169         if ((ast->state != AST_STATE_DOWN) && (ast->state != AST_STATE_RESERVED)) {
170                 ast_log(LOG_WARNING, "modem_call called on %s, neither down nor reserved\n", ast->name);
171                 return -1;
172         }
173         if (!strcasecmp(where, "handset")) {
174                 if (p->mc->setdev)
175                         if (p->mc->setdev(p, MODEM_DEV_HANDSET))
176                                 return -1;
177                 /* Should be immediately up */
178                 ast->state = AST_STATE_UP;
179         } else {
180                 if (p->mc->setdev)
181                         if (p->mc->setdev(p, MODEM_DEV_TELCO_SPK))
182                                 return -1;
183                 if (p->mc->dial)
184                         p->mc->dial(p, where + p->stripmsd);
185                 ast->state = AST_STATE_DIALING;
186                 while((ast->state != AST_STATE_UP) && (ms > 0)) {
187                         ms = ast_waitfor(ast, ms);
188                         /* Just read packets and watch what happens */
189                         if (ms > 0) {
190                                 if (!modem_read(ast))
191                                         return -1;
192                         }
193                 }
194                 if (ms < 0)     
195                         return -1;
196         }
197         return 0;
198 }
199
200 int ast_modem_send(struct ast_modem_pvt *p, char *cmd, int len)
201 {
202         int res;
203         if (!len) {
204                 fprintf(p->f, "%s\r\n", cmd);
205                 res = ast_modem_expect(p, cmd, ECHO_TIMEOUT);
206                 if (res) {
207                         ast_log(LOG_WARNING, "Unexpected reply %s\n", p->response);
208                         return -1;
209                 }
210                 return 0;
211         } else {
212                 if (fwrite(cmd, 1, len, p->f) < len)
213                         return -1;
214                 return 0;
215         }
216 }
217
218 int ast_modem_read_response(struct ast_modem_pvt *p, int timeout)
219 {
220         int res = -1;
221         timeout *= 1000;
222         strncpy(p->response, "(No Response)", sizeof(p->response));
223         do {
224                 res = ast_waitfor_n_fd(&p->fd, 1, &timeout);
225                 if (res < 0) {
226                         return -1;
227                 }
228                 /* Read a response */
229                 fgets(p->response, sizeof(p->response), p->f);
230                 return 0;
231         } while(timeout > 0);
232         return -1;
233 }
234
235 int ast_modem_expect(struct ast_modem_pvt *p, char *result, int timeout)
236 {
237         int res = -1;
238         timeout *= 1000;
239         strncpy(p->response, "(No Response)", sizeof(p->response));
240         do {
241                 res = ast_waitfor_n_fd(&p->fd, 1, &timeout);
242                 if (res < 0) {
243                         return -1;
244                 }
245                 /* Read a response */
246                 fgets(p->response, sizeof(p->response), p->f);
247 #if 0
248                 fprintf(stderr, "Modem said: %s", p->response);
249 #endif
250                 if (!strncasecmp(p->response, result, strlen(result))) 
251                         return 0;
252         } while(timeout > 0);
253         return -1;
254 }
255
256 void ast_modem_trim(char *s)
257 {
258         int x;
259         x = strlen(s) - 1;
260         while(x >= 0) {
261                 if ((s[x] != '\r') && (s[x] != '\n') && (s[x] != ' '))
262                         break;
263                 s[x] = '\0';
264                 x--;
265         }
266 }
267
268 static int modem_setup(struct ast_modem_pvt *p, int baudrate)
269 {
270         /* Make sure there's a modem there and that it's in a reasonable 
271            mode.  Set the baud rate, etc.  */
272         char identity[256];
273         char *ident = NULL;
274         if (option_debug)
275                 ast_log(LOG_DEBUG, "Setting up modem %s\n", p->dev);
276         if (ast_modem_send(p, "\r\n", 2)) {
277                 ast_log(LOG_WARNING, "Failed to send enter?\n");
278                 return -1;
279         }
280         /* Read any outstanding stuff */
281         while(!ast_modem_read_response(p, 0));
282         if (ast_modem_send(p, "ATZ", 0)) {
283                 ast_log(LOG_WARNING, "Modem not responding on %s\n", p->dev);
284                 return -1;
285         }
286         if (ast_modem_expect(p, "OK", ECHO_TIMEOUT)) {
287                 ast_log(LOG_WARNING, "Modem reset failed: %s\n", p->response);
288                 return -1;
289         }
290         if (ast_modem_send(p, p->initstr, 0)) {
291                 ast_log(LOG_WARNING, "Modem not responding on %s\n", p->dev);
292                 return -1;
293         }
294         if (ast_modem_expect(p, "OK", ECHO_TIMEOUT)) {
295                 ast_log(LOG_WARNING, "Modem initialization failed: %s\n", p->response);
296                 return -1;
297         }
298         if (ast_modem_send(p, "ATI3", 0)) {
299                 ast_log(LOG_WARNING, "Modem not responding on %s\n", p->dev);
300                 return -1;
301         }
302         if (ast_modem_read_response(p, ECHO_TIMEOUT)) {
303                 ast_log(LOG_WARNING, "Modem did not provide identification\n");
304                 return -1;
305         }
306         strncpy(identity, p->response, sizeof(identity));
307         ast_modem_trim(identity);
308         if (ast_modem_expect(p, "OK", ECHO_TIMEOUT)) {
309                 ast_log(LOG_WARNING, "Modem did not provide identification\n");
310                 return -1;
311         }
312         if (!strcasecmp(mtype, "autodetect")) {
313                 p->mc = find_capability(identity);
314                 if (!p->mc) {
315                         ast_log(LOG_WARNING, "Unable to autodetect modem.  You'll need to specify a driver in modem.conf.  Please report modem identification (%s) and which driver works to markster@linux-support.net.\n", identity); 
316                         return -1;
317                 }
318         } else {
319                 p->mc = find_driver(mtype);
320                 if (!p->mc) {
321                         ast_log(LOG_WARNING, "No driver for modem type '%s'\n", mtype);
322                         return -1;
323                 }
324         }
325         if (p->mc->init) {
326                 if (p->mc->init(p)) {
327                         ast_log(LOG_WARNING, "Modem Initialization Failed on '%s', driver %s.\n", p->dev, p->mc->name);
328                         p->mc->decusecnt();
329                         return -1;
330                 }
331         }                       
332         if (option_verbose > 2) {
333                 ast_verbose(VERBOSE_PREFIX_3 "Configured modem %s with driver %s (%s)\n", p->dev, p->mc->name, p->mc->identify ? (ident = p->mc->identify(p)) : "No identification");
334         }
335         if (ident)
336                 free(ident);
337         return 0;
338 }
339
340 static int modem_hangup(struct ast_channel *ast)
341 {
342         struct ast_modem_pvt *p;
343         ast_log(LOG_DEBUG, "modem_hangup(%s)\n", ast->name);
344         p = ast->pvt->pvt;
345         /* Hang up */
346         if (p->mc->hangup)
347                 p->mc->hangup(p);
348         /* Re-initialize */
349         if (p->mc->init)
350                 p->mc->init(p);
351         ast->state = AST_STATE_DOWN;
352         memset(p->cid, 0, sizeof(p->cid));
353         ((struct ast_modem_pvt *)(ast->pvt->pvt))->owner = NULL;
354         pthread_mutex_lock(&usecnt_lock);
355         usecnt--;
356         if (usecnt < 0) 
357                 ast_log(LOG_WARNING, "Usecnt < 0???\n");
358         pthread_mutex_unlock(&usecnt_lock);
359         ast_update_use_count();
360         if (option_verbose > 2) 
361                 ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name);
362         ast->pvt->pvt = NULL;
363         ast->state = AST_STATE_DOWN;
364         restart_monitor();
365         return 0;
366 }
367
368 static int modem_answer(struct ast_channel *ast)
369 {
370         struct ast_modem_pvt *p;
371         int res=0;
372         ast_log(LOG_DEBUG, "modem_hangup(%s)\n", ast->name);
373         p = ast->pvt->pvt;
374         if (p->mc->answer) {
375                 res = p->mc->answer(p);
376         }
377         if (!res) {
378                 ast->rings = 0;
379                 ast->state = AST_STATE_UP;
380         }
381         return res;
382 }
383
384 static char modem_2digit(char c)
385 {
386         if (c == 12)
387                 return '#';
388         else if (c == 11)
389                 return '*';
390         else if ((c < 10) && (c >= 0))
391                 return '0' + c - 1;
392         else
393                 return '?';
394 }
395
396 static struct ast_frame *modem_read(struct ast_channel *ast)
397 {
398         struct ast_modem_pvt *p = ast->pvt->pvt;
399         struct ast_frame *fr=NULL;
400         if (p->mc->read)
401                 fr = p->mc->read(p);
402         return fr;
403 }
404
405 static int modem_write(struct ast_channel *ast, struct ast_frame *frame)
406 {
407         int res=0;
408         struct ast_modem_pvt *p = ast->pvt->pvt;
409         if (p->mc->write)
410                 res = p->mc->write(p, frame);
411         return 0;
412 }
413
414 struct ast_channel *ast_modem_new(struct ast_modem_pvt *i, int state)
415 {
416         struct ast_channel *tmp;
417         tmp = ast_channel_alloc();
418         if (tmp) {
419                 snprintf(tmp->name, sizeof(tmp->name), "Modem[%s]/%s", i->mc->name, i->dev + 5);
420                 tmp->type = type;
421                 tmp->fd = i->fd;
422                 /* XXX Switching formats silently causes kernel panics XXX */
423                 tmp->format = i->mc->formats;
424                 tmp->state = state;
425                 if (state == AST_STATE_RING)
426                         tmp->rings = 1;
427                 tmp->pvt->pvt = i;
428                 tmp->pvt->send_digit = modem_digit;
429                 tmp->pvt->call = modem_call;
430                 tmp->pvt->hangup = modem_hangup;
431                 tmp->pvt->answer = modem_answer;
432                 tmp->pvt->read = modem_read;
433                 tmp->pvt->write = modem_write;
434                 strncpy(tmp->context, i->context, sizeof(tmp->context));
435                 if (strlen(i->cid))
436                         strncpy(tmp->callerid, i->cid, sizeof(tmp->callerid));
437                 i->owner = tmp;
438                 pthread_mutex_lock(&usecnt_lock);
439                 usecnt++;
440                 pthread_mutex_unlock(&usecnt_lock);
441                 ast_update_use_count();
442                 if (state != AST_STATE_DOWN) {
443                         if (ast_pbx_start(tmp)) {
444                                 ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
445                                 ast_hangup(tmp);
446                         }
447                 }
448         } else
449                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
450         return tmp;
451 }
452
453 static void modem_mini_packet(struct ast_modem_pvt *i)
454 {
455         struct ast_frame *fr;
456         fr = i->mc->read(i);
457 }
458
459 static void *do_monitor(void *data)
460 {
461         fd_set rfds, efds;
462         int n, res;
463         struct ast_modem_pvt *i;
464         /* This thread monitors all the frame relay interfaces which are not yet in use
465            (and thus do not have a separate thread) indefinitely */
466         /* From here on out, we die whenever asked */
467 #if 0
468         if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
469                 ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
470                 return NULL;
471         }
472 #endif
473         for(;;) {
474                 /* Don't let anybody kill us right away.  Nobody should lock the interface list
475                    and wait for the monitor list, but the other way around is okay. */
476                 if (pthread_mutex_lock(&monlock)) {
477                         ast_log(LOG_ERROR, "Unable to grab monitor lock\n");
478                         return NULL;
479                 }
480                 /* Lock the interface list */
481                 if (pthread_mutex_lock(&iflock)) {
482                         ast_log(LOG_ERROR, "Unable to grab interface lock\n");
483                         pthread_mutex_unlock(&monlock);
484                         return NULL;
485                 }
486                 /* Build the stuff we're going to select on, that is the socket of every
487                    ast_modem_pvt that does not have an associated owner channel */
488                 n = -1;
489                 FD_ZERO(&rfds);
490                 FD_ZERO(&efds);
491                 i = iflist;
492                 while(i) {
493                         if (FD_ISSET(i->fd, &rfds)) 
494                                 ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev);
495                         if (!i->owner) {
496                                 /* This needs to be watched, as it lacks an owner */
497                                 FD_SET(i->fd, &rfds);
498                                 FD_SET(i->fd, &efds);
499                                 if (i->fd > n)
500                                         n = i->fd;
501                         }
502                         
503                         i = i->next;
504                 }
505                 /* Okay, now that we know what to do, release the interface lock */
506                 pthread_mutex_unlock(&iflock);
507                 
508                 /* And from now on, we're okay to be killed, so release the monitor lock as well */
509                 pthread_mutex_unlock(&monlock);
510 #if 0
511                 ast_log(LOG_DEBUG, "In monitor, n=%d, pid=%d\n", n, getpid());
512 #endif
513                 /* Wait indefinitely for something to happen */
514                 pthread_testcancel();
515                 res = select(n + 1, &rfds, NULL, &efds, NULL);
516                 pthread_testcancel();
517                 /* Okay, select has finished.  Let's see what happened.  */
518                 if (res < 1) {
519                         ast_log(LOG_WARNING, "select return %d: %s\n", res, strerror(errno));
520                         continue;
521                 }
522                 /* Alright, lock the interface list again, and let's look and see what has
523                    happened */
524                 if (pthread_mutex_lock(&iflock)) {
525                         ast_log(LOG_WARNING, "Unable to lock the interface list\n");
526                         continue;
527                 }
528                 i = iflist;
529                 while(i) {
530                         if (FD_ISSET(i->fd, &rfds) || FD_ISSET(i->fd, &efds)) {
531                                 if (i->owner) {
532                                         ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d, %s)...\n", i->fd, i->dev);
533                                         i = i->next;
534                                         continue;
535                                 }
536                                 modem_mini_packet(i);
537                         }
538                         i=i->next;
539                 }
540                 pthread_mutex_unlock(&iflock);
541         }
542         /* Never reached */
543         return NULL;
544         
545 }
546
547 static int restart_monitor()
548 {
549         /* If we're supposed to be stopped -- stay stopped */
550         if (monitor_thread == -2)
551                 return 0;
552         if (pthread_mutex_lock(&monlock)) {
553                 ast_log(LOG_WARNING, "Unable to lock monitor\n");
554                 return -1;
555         }
556         if (monitor_thread == pthread_self()) {
557                 pthread_mutex_unlock(&monlock);
558                 ast_log(LOG_WARNING, "Cannot kill myself\n");
559                 return -1;
560         }
561         if (monitor_thread != -1) {
562                 pthread_cancel(monitor_thread);
563                 /* Nudge it a little, as it's probably stuck in select */
564                 pthread_kill(monitor_thread, SIGURG);
565                 pthread_join(monitor_thread, NULL);
566         }
567         /* Start a new monitor */
568         if (pthread_create(&monitor_thread, NULL, do_monitor, NULL) < 0) {
569                 pthread_mutex_unlock(&monlock);
570                 ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
571                 return -1;
572         }
573         pthread_mutex_unlock(&monlock);
574         return 0;
575 }
576
577 static struct ast_modem_pvt *mkif(char *iface)
578 {
579         /* Make a ast_modem_pvt structure for this interface */
580         struct ast_modem_pvt *tmp;
581 #if 0
582         int flags;      
583 #endif
584         
585         tmp = malloc(sizeof(struct ast_modem_pvt));
586         if (tmp) {
587                 tmp->fd = open(iface, O_RDWR | O_NONBLOCK);
588                 if (tmp->fd < 0) {
589                         ast_log(LOG_WARNING, "Unable to open '%s'\n", iface);
590                         free(tmp);
591                         return NULL;
592                 }
593                 tmp->f = fdopen(tmp->fd, "w+");
594                 /* Disable buffering */
595                 setvbuf(tmp->f, NULL, _IONBF,0);
596                 if (tmp->f < 0) {
597                         ast_log(LOG_WARNING, "Unable to fdopen '%s'\n", iface);
598                         free(tmp);
599                         return NULL;
600                 }
601 #if 0
602                 flags = fcntl(tmp->fd, F_GETFL);
603                 fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK);
604 #endif
605                 tmp->owner = NULL;
606                 tmp->ministate = 0;
607                 tmp->stripmsd = stripmsd;
608                 tmp->dialtype = dialtype;
609                 tmp->mode = gmode;
610                 memset(tmp->cid, 0, sizeof(tmp->cid));
611                 strncpy(tmp->dev, iface, sizeof(tmp->dev));
612                 strncpy(tmp->context, context, sizeof(tmp->context));
613                 strncpy(tmp->initstr, initstr, sizeof(tmp->initstr));
614                 tmp->next = NULL;
615                 tmp->obuflen = 0;
616                 
617                 if (modem_setup(tmp, baudrate) < 0) {
618                         ast_log(LOG_WARNING, "Unable to configure modem '%s'\n", iface);
619                         free(tmp);
620                         return NULL;
621                 }
622         }
623         return tmp;
624 }
625
626 static struct ast_channel *modem_request(char *type, int format, void *data)
627 {
628         int oldformat;
629         struct ast_modem_pvt *p;
630         struct ast_channel *tmp = NULL;
631         char dev[80];
632         strncpy(dev, (char *)data, sizeof(dev));
633         strtok(dev, ":");
634         oldformat = format;
635         /* Search for an unowned channel */
636         if (pthread_mutex_lock(&iflock)) {
637                 ast_log(LOG_ERROR, "Unable to lock interface list???\n");
638                 return NULL;
639         }
640         p = iflist;
641         while(p) {
642                 if (!strcmp(dev, p->dev + 5)) {
643                         if (p->mc->formats & format) {
644                                 if (!p->owner) {
645                                         tmp = ast_modem_new(p, AST_STATE_DOWN);
646                                         restart_monitor();
647                                         break;
648                                 } else
649                                         ast_log(LOG_WARNING, "Device '%s' is busy\n", p->dev);
650                         } else 
651                                 ast_log(LOG_WARNING, "Asked for a format %d line on %s\n", format, p->dev);
652                         break;
653                 }
654                 p = p->next;
655         }
656         if (!p) 
657                 ast_log(LOG_WARNING, "Requested device '%s' does not exist\n", p->dev);
658         
659         pthread_mutex_unlock(&iflock);
660         return tmp;
661 }
662
663 int load_module()
664 {
665         struct ast_config *cfg;
666         struct ast_variable *v;
667         struct ast_modem_pvt *tmp;
668         char driver[80];
669         cfg = ast_load(config);
670
671         /* We *must* have a config file otherwise stop immediately */
672         if (!cfg) {
673                 ast_log(LOG_ERROR, "Unable to load config %s\n", config);
674                 return -1;
675         }
676         if (pthread_mutex_lock(&iflock)) {
677                 /* It's a little silly to lock it, but we mind as well just to be sure */
678                 ast_log(LOG_ERROR, "Unable to lock interface list???\n");
679                 return -1;
680         }
681         v = ast_variable_browse(cfg, "interfaces");
682         while(v) {
683                 /* Create the interface list */
684                 if (!strcasecmp(v->name, "device")) {
685                                 tmp = mkif(v->value);
686                                 if (tmp) {
687                                         tmp->next = iflist;
688                                         iflist = tmp;
689                                         
690                                 } else {
691                                         ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value);
692                                         ast_destroy(cfg);
693                                         pthread_mutex_unlock(&iflock);
694                                         unload_module();
695                                         pthread_mutex_unlock(&iflock);
696                                         return -1;
697                                 }
698                 } else if (!strcasecmp(v->name, "driver")) {
699                         snprintf(driver, sizeof(driver), "chan_modem_%s.so", v->value);
700                         if (option_verbose > 1) 
701                                 ast_verbose(VERBOSE_PREFIX_2 "Loading modem driver %s", driver);
702                                 
703                         if (ast_load_resource(driver)) {
704                                 ast_log(LOG_ERROR, "Failed to laod driver %s\n", driver);
705                                 ast_destroy(cfg);
706                                 unload_module();
707                                 pthread_mutex_unlock(&iflock);
708                                 return -1;
709                         }
710                 } else if (!strcasecmp(v->name, "mode")) {
711                         if (!strncasecmp(v->value, "ri", 2)) 
712                                 gmode = MODEM_MODE_WAIT_RING;
713                         else if (!strncasecmp(v->value, "im", 2))
714                                 gmode = MODEM_MODE_IMMEDIATE;
715                         else if (!strncasecmp(v->value, "an", 2))
716                                 gmode = MODEM_MODE_WAIT_ANSWER;
717                         else
718                                 ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value);
719                 } else if (!strcasecmp(v->name, "stripmsd")) {
720                         stripmsd = atoi(v->value);
721                 } else if (!strcasecmp(v->name, "type")) {
722                         strncpy(mtype, v->value, sizeof(mtype));
723                 } else if (!strcasecmp(v->name, "initstr")) {
724                         strncpy(initstr, v->value, sizeof(initstr));
725                 } else if (!strcasecmp(v->name, "dialtype")) {
726                         dialtype = toupper(v->value[0]);
727                 } else if (!strcasecmp(v->name, "context")) {
728                         strncpy(context, v->value, sizeof(context));
729                 }
730                 v = v->next;
731         }
732         pthread_mutex_unlock(&iflock);
733         if (ast_channel_register(type, tdesc, /* XXX Don't know our types -- maybe we should register more than one XXX */ AST_FORMAT_SLINEAR, modem_request)) {
734                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
735                 ast_destroy(cfg);
736                 unload_module();
737                 return -1;
738         }
739         ast_destroy(cfg);
740         /* And start the monitor for the first time */
741         restart_monitor();
742         return 0;
743 }
744
745
746
747 int unload_module()
748 {
749         struct ast_modem_pvt *p, *pl;
750         /* First, take us out of the channel loop */
751         ast_channel_unregister(type);
752         if (!pthread_mutex_lock(&iflock)) {
753                 /* Hangup all interfaces if they have an owner */
754                 p = iflist;
755                 while(p) {
756                         if (p->owner)
757                                 ast_softhangup(p->owner);
758                         p = p->next;
759                 }
760                 iflist = NULL;
761                 pthread_mutex_unlock(&iflock);
762         } else {
763                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
764                 return -1;
765         }
766         if (!pthread_mutex_lock(&monlock)) {
767                 if (monitor_thread > -1) {
768                         pthread_cancel(monitor_thread);
769                         pthread_join(monitor_thread, NULL);
770                 }
771                 monitor_thread = -2;
772                 pthread_mutex_unlock(&monlock);
773         } else {
774                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
775                 return -1;
776         }
777
778         if (!pthread_mutex_lock(&iflock)) {
779                 /* Destroy all the interfaces and free their memory */
780                 p = iflist;
781                 while(p) {
782                         /* Close the socket, assuming it's real */
783                         if (p->fd > -1)
784                                 close(p->fd);
785                         pl = p;
786                         p = p->next;
787                         /* Free associated memory */
788                         free(pl);
789                 }
790                 iflist = NULL;
791                 pthread_mutex_unlock(&iflock);
792         } else {
793                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
794                 return -1;
795         }
796                 
797         return 0;
798 }
799
800 int usecount(void)
801 {
802         int res;
803         pthread_mutex_lock(&usecnt_lock);
804         res = usecnt;
805         pthread_mutex_unlock(&usecnt_lock);
806         return res;
807 }
808
809 char *description()
810 {
811         return desc;
812 }
813