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