This source file includes following definitions.
- tdmv_api_wait_socket
- tdmv_api_open_span_chan
- __tdmv_api_open_span_chan
- wanpipe_swap_bits
- wp_open_range
- FIO_CONFIGURE_FUNCTION
- FIO_CONFIGURE_SPAN_FUNCTION
- FIO_OPEN_FUNCTION
- FIO_CLOSE_FUNCTION
- FIO_COMMAND_FUNCTION
- FIO_READ_FUNCTION
- FIO_WRITE_FUNCTION
- FIO_WAIT_FUNCTION
- FIO_SPAN_POLL_EVENT_FUNCTION
- FIO_GET_ALARMS_FUNCTION
- FIO_SPAN_NEXT_EVENT_FUNCTION
- FIO_CHANNEL_DESTROY_FUNCTION
- FIO_IO_LOAD_FUNCTION
- FIO_IO_UNLOAD_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 #ifdef __sun
42 #include <unistd.h>
43 #include <stropts.h>
44 #endif
45 #include "private/ftdm_core.h"
46 #ifndef __WINDOWS__
47 #include <poll.h>
48 #include <sys/socket.h>
49 #endif
50 #include "libsangoma.h"
51
52 #if defined(__WINDOWS__)
53
54 #define sangoma_open_tdmapi_span_chan sangoma_open_api_span_chan
55 #define sangoma_open_tdmapi_span sangoma_open_api_span
56 #define sangoma_open_tdmapi_ctrl sangoma_open_api_ctrl
57 #define sangoma_tdm_get_fe_status sangoma_get_fe_status
58 #define sangoma_socket_close sangoma_close
59 #define sangoma_tdm_get_hw_coding sangoma_get_hw_coding
60 #define sangoma_tdm_set_fe_status sangoma_set_fe_status
61 #define sangoma_tdm_get_link_status sangoma_get_link_status
62 #define sangoma_tdm_flush_bufs sangoma_flush_bufs
63 #define sangoma_tdm_cmd_exec sangoma_cmd_exec
64 #define sangoma_tdm_read_event sangoma_read_event
65 #define sangoma_readmsg_tdm sangoma_readmsg
66 #define sangoma_readmsg_socket sangoma_readmsg
67 #define sangoma_sendmsg_socket sangoma_writemsg
68 #define sangoma_writemsg_tdm sangoma_writemsg
69 #define sangoma_create_socket_intr sangoma_open_api_span_chan
70 #endif
71
72
73
74
75 #ifdef LIBSANGOMA_VERSION
76 #if LIBSANGOMA_VERSION_CODE < LIBSANGOMA_VERSION(3,0,0)
77 #undef LIBSANGOMA_VERSION
78 #endif
79 #endif
80
81
82
83
84 typedef enum {
85 WP_RINGING = (1 << 0)
86 } wp_flag_t;
87
88
89
90
91 static struct {
92 uint32_t codec_ms;
93 uint32_t wink_ms;
94 uint32_t flash_ms;
95 uint32_t ring_on_ms;
96 uint32_t ring_off_ms;
97 } wp_globals;
98
99
100
101 FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event);
102 FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event);
103
104
105
106
107
108
109
110
111
112
113
114
115 static __inline__ int tdmv_api_wait_socket(ftdm_channel_t *ftdmchan, int timeout, int *flags)
116 {
117
118 #ifdef LIBSANGOMA_VERSION
119 int err;
120 uint32_t inflags = *flags;
121 uint32_t outflags = 0;
122 sangoma_wait_obj_t *sangoma_wait_obj = ftdmchan->mod_data;
123
124 err = sangoma_waitfor(sangoma_wait_obj, inflags, &outflags, timeout);
125 *flags = 0;
126 if (err == SANG_STATUS_SUCCESS) {
127 *flags = outflags;
128 err = 1;
129 }
130 if (err == SANG_STATUS_APIPOLL_TIMEOUT) {
131 err = 0;
132 }
133 return err;
134 #else
135 struct pollfd pfds[1];
136 int res;
137
138 memset(&pfds[0], 0, sizeof(pfds[0]));
139 pfds[0].fd = ftdmchan->sockfd;
140 pfds[0].events = *flags;
141 res = poll(pfds, 1, timeout);
142 *flags = 0;
143
144 if (pfds[0].revents & POLLERR) {
145 res = -1;
146 }
147
148 if (res > 0) {
149 *flags = pfds[0].revents;
150 }
151
152 return res;
153 #endif
154
155 }
156
157
158
159
160
161
162
163 static __inline__ sng_fd_t tdmv_api_open_span_chan(int span, int chan)
164 {
165 return sangoma_open_tdmapi_span_chan(span, chan);
166 }
167
168 #ifdef LIBSANGOMA_VERSION
169 static __inline__ sng_fd_t __tdmv_api_open_span_chan(int span, int chan)
170 {
171 return __sangoma_open_tdmapi_span_chan(span, chan);
172 }
173 #endif
174
175 static ftdm_io_interface_t wanpipe_interface;
176
177
178
179
180
181
182 static unsigned char wanpipe_swap_bits(unsigned char cas_bits)
183 {
184 unsigned char swapped_bits = 0x0;
185 if (cas_bits & 0x8) {
186 swapped_bits |= 0x1;
187 }
188 if (cas_bits & 0x4) {
189 swapped_bits |= 0x2;
190 }
191 if (cas_bits & 0x2) {
192 swapped_bits |= 0x4;
193 }
194 if (cas_bits & 0x1) {
195 swapped_bits |= 0x8;
196 }
197 return swapped_bits;
198 }
199
200
201
202
203
204
205
206
207
208
209
210
211
212 static unsigned wp_open_range(ftdm_span_t *span, unsigned spanno, unsigned start, unsigned end, ftdm_chan_type_t type, char *name, char *number, unsigned char cas_bits)
213 {
214 unsigned configured = 0, x;
215 #ifdef LIBSANGOMA_VERSION
216 sangoma_status_t sangstatus;
217 sangoma_wait_obj_t *sangoma_wait_obj;
218 #endif
219
220 if (type == FTDM_CHAN_TYPE_CAS) {
221 ftdm_log(FTDM_LOG_DEBUG, "Configuring Wanpipe CAS channels with abcd == 0x%X\n", cas_bits);
222 }
223 for(x = start; x < end; x++) {
224 ftdm_channel_t *chan;
225 ftdm_socket_t sockfd = FTDM_INVALID_SOCKET;
226 const char *dtmf = "none";
227 if (!strncasecmp(span->name, "smg_prid_nfas", 8) && span->trunk_type == FTDM_TRUNK_T1 && x == 24) {
228 #ifdef LIBSANGOMA_VERSION
229 sockfd = __tdmv_api_open_span_chan(spanno, x);
230 #else
231 ftdm_log(FTDM_LOG_ERROR, "span %d channel %d cannot be configured as smg_prid_nfas, you need to compile freetdm with newer libsangoma\n", spanno, x);
232 #endif
233 } else {
234 sockfd = tdmv_api_open_span_chan(spanno, x);
235 }
236
237 if (sockfd == FTDM_INVALID_SOCKET) {
238 ftdm_log(FTDM_LOG_ERROR, "Failed to open wanpipe device span %d channel %d\n", spanno, x);
239 continue;
240 }
241
242 if (ftdm_span_add_channel(span, sockfd, type, &chan) == FTDM_SUCCESS) {
243 wanpipe_tdm_api_t tdm_api;
244 memset(&tdm_api, 0, sizeof(tdm_api));
245 #ifdef LIBSANGOMA_VERSION
246
247
248
249
250 sangstatus = sangoma_wait_obj_create(&sangoma_wait_obj, sockfd, SANGOMA_DEVICE_WAIT_OBJ_SIG);
251 if (sangstatus != SANG_STATUS_SUCCESS) {
252 ftdm_log(FTDM_LOG_ERROR, "failure create waitable object for s%dc%d\n", spanno, x);
253 continue;
254 }
255 chan->mod_data = sangoma_wait_obj;
256 #endif
257
258 chan->physical_span_id = spanno;
259 chan->physical_chan_id = x;
260 chan->rate = 8000;
261
262 if (type == FTDM_CHAN_TYPE_FXS
263 || type == FTDM_CHAN_TYPE_FXO
264 || type == FTDM_CHAN_TYPE_CAS
265 || type == FTDM_CHAN_TYPE_B) {
266 int err;
267
268 dtmf = "software";
269
270 err = sangoma_tdm_get_hw_coding(chan->sockfd, &tdm_api);
271
272 if (tdm_api.wp_tdm_cmd.hw_tdm_coding) {
273 chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
274 } else {
275 chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
276 }
277
278 err = sangoma_tdm_get_hw_dtmf(chan->sockfd, &tdm_api);
279 if (err > 0) {
280 ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_DTMF_DETECT);
281 dtmf = "hardware";
282 }
283
284 err = sangoma_tdm_get_hw_ec(chan->sockfd, &tdm_api);
285 if (err > 0) {
286 ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_HWEC);
287 }
288
289 #ifdef WP_API_FEATURE_HWEC_PERSIST
290 err = sangoma_tdm_get_hwec_persist_status(chan->sockfd, &tdm_api);
291 if (err == 0) {
292 ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_HWEC_DISABLED_ON_IDLE);
293 }
294 #else
295 if (span->trunk_type == FTDM_TRUNK_BRI || span->trunk_type == FTDM_TRUNK_BRI_PTMP) {
296 ftdm_log(FTDM_LOG_WARNING, "WP_API_FEATURE_HWEC_PERSIST feature is not supported \
297 with your version of libsangoma, you should update your Wanpipe drivers\n");
298
299 }
300 #endif
301
302 }
303
304 #ifdef LIBSANGOMA_VERSION
305 if (type == FTDM_CHAN_TYPE_FXS) {
306 if (sangoma_tdm_disable_ring_trip_detect_events(chan->sockfd, &tdm_api)) {
307
308
309 ftdm_log(FTDM_LOG_WARNING, "Failed to disable ring trip events in channel s%dc%d\n", spanno, x);
310 }
311 }
312 #endif
313 #if 0
314 if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
315
316 int err=sangoma_set_rm_rxflashtime(chan->sockfd, &tdm_api, wp_globals.flash_ms);
317 if (err == 0) {
318 ftdm_log(FTDM_LOG_ERROR, "flash enabled s%dc%d\n", spanno, x);
319 } else {
320 ftdm_log(FTDM_LOG_ERROR, "flash disabled s%dc%d\n", spanno, x);
321 }
322 }
323 #endif
324
325 if (type == FTDM_CHAN_TYPE_CAS || type == FTDM_CHAN_TYPE_EM) {
326 #ifdef LIBSANGOMA_VERSION
327 sangoma_tdm_write_rbs(chan->sockfd,&tdm_api,chan->physical_chan_id, wanpipe_swap_bits(cas_bits));
328
329
330
331
332 if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
333 ftdm_log(FTDM_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
334 continue;
335 }
336
337 sangoma_flush_bufs(chan->sockfd, &tdm_api);
338 #else
339
340
341
342
343
344
345 if (sangoma_tdm_enable_rbs_events(chan->sockfd, &tdm_api, 100)) {
346 ftdm_log(FTDM_LOG_ERROR, "Failed to enable RBS/CAS events in device %d:%d fd:%d\n", chan->span_id, chan->chan_id, sockfd);
347 }
348
349 sangoma_tdm_flush_bufs(chan->sockfd, &tdm_api);
350 sangoma_tdm_write_rbs(chan->sockfd,&tdm_api, wanpipe_swap_bits(cas_bits));
351 #endif
352 }
353
354 if (!ftdm_strlen_zero(name)) {
355 ftdm_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
356 }
357
358 if (!ftdm_strlen_zero(number)) {
359 ftdm_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
360 }
361 configured++;
362 ftdm_log_chan(chan, FTDM_LOG_INFO, "configured wanpipe device s%dc%d as FreeTDM channel %d:%d fd:%d DTMF: %s\n",
363 spanno, x, chan->span_id, chan->chan_id, sockfd, dtmf);
364
365 } else {
366 ftdm_log(FTDM_LOG_ERROR, "ftdm_span_add_channel failed for wanpipe span %d channel %d\n", spanno, x);
367 }
368 }
369
370 return configured;
371 }
372
373
374
375
376
377
378
379
380
381 static FIO_CONFIGURE_FUNCTION(wanpipe_configure)
382 {
383 int num;
384
385 if (!strcasecmp(category, "defaults")) {
386 if (!strcasecmp(var, "codec_ms")) {
387 num = atoi(val);
388 if (num < 10 || num > 60) {
389 ftdm_log(FTDM_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
390 } else {
391 wp_globals.codec_ms = num;
392 }
393 } else if (!strcasecmp(var, "wink_ms")) {
394 num = atoi(val);
395 if (num < 50 || num > 3000) {
396 ftdm_log(FTDM_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
397 } else {
398 wp_globals.wink_ms = num;
399 }
400 } else if (!strcasecmp(var, "flash_ms")) {
401 num = atoi(val);
402 if (num < 50 || num > 3000) {
403 ftdm_log(FTDM_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
404 } else {
405 wp_globals.flash_ms = num;
406 }
407 } else if (!strcasecmp(var, "ring_on_ms")) {
408 num = atoi(val);
409 if (num < 500 || num > 5000) {
410 ftdm_log(FTDM_LOG_WARNING, "invalid ring_on_ms at line %d (valid range 500 to 5000)\n", lineno);
411 } else {
412 wp_globals.ring_on_ms = num;
413 }
414 } else if (!strcasecmp(var, "ring_off_ms")) {
415 num = atoi(val);
416 if (num < 500 || num > 5000) {
417 ftdm_log(FTDM_LOG_WARNING, "invalid ring_off_ms at line %d (valid range 500 to 5000)\n", lineno);
418 } else {
419 wp_globals.ring_off_ms = num;
420 }
421 }
422 }
423
424 return FTDM_SUCCESS;
425 }
426
427
428
429
430
431
432
433
434
435
436 static FIO_CONFIGURE_SPAN_FUNCTION(wanpipe_configure_span)
437 {
438 int items, i;
439 char *mydata, *item_list[10];
440 char *sp, *ch, *mx;
441 unsigned char cas_bits = 0;
442 int channo;
443 int spanno;
444 int top = 0;
445 unsigned configured = 0;
446
447 assert(str != NULL);
448
449
450 mydata = ftdm_strdup(str);
451 assert(mydata != NULL);
452
453
454 items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
455
456 for(i = 0; i < items; i++) {
457 sp = item_list[i];
458 if ((ch = strchr(sp, ':'))) {
459 *ch++ = '\0';
460 }
461
462 if (!(sp && ch)) {
463 ftdm_log(FTDM_LOG_ERROR, "No valid wanpipe span and channel was specified\n");
464 continue;
465 }
466
467 channo = atoi(ch);
468 spanno = atoi(sp);
469
470 if (channo < 0) {
471 ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
472 continue;
473 }
474
475 if (spanno < 0) {
476 ftdm_log(FTDM_LOG_ERROR, "Invalid span number %d\n", channo);
477 continue;
478 }
479
480 if ((mx = strchr(ch, '-'))) {
481 mx++;
482 top = atoi(mx) + 1;
483 } else {
484 top = channo + 1;
485 }
486
487
488 if (top < 0) {
489 ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
490 continue;
491 }
492 if (FTDM_CHAN_TYPE_CAS == type && ftdm_config_get_cas_bits(ch, &cas_bits)) {
493 ftdm_log(FTDM_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
494 continue;
495 }
496 configured += wp_open_range(span, spanno, channo, top, type, name, number, cas_bits);
497
498 }
499
500 ftdm_safe_free(mydata);
501
502 return configured;
503 }
504
505
506
507
508
509
510 static FIO_OPEN_FUNCTION(wanpipe_open)
511 {
512
513 wanpipe_tdm_api_t tdm_api;
514
515 memset(&tdm_api,0,sizeof(tdm_api));
516 sangoma_tdm_flush_bufs(ftdmchan->sockfd, &tdm_api);
517 #ifdef LIBSANGOMA_VERSION
518 sangoma_flush_event_bufs(ftdmchan->sockfd, &tdm_api);
519 #endif
520
521 if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) {
522 ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE;
523 } else {
524 ftdmchan->effective_codec = ftdmchan->native_codec;
525
526 sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, wp_globals.codec_ms);
527
528 ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL);
529 ftdmchan->effective_interval = ftdmchan->native_interval = wp_globals.codec_ms;
530 ftdmchan->packet_len = ftdmchan->native_interval * 8;
531 }
532
533 return FTDM_SUCCESS;
534 }
535
536
537
538
539
540
541 static FIO_CLOSE_FUNCTION(wanpipe_close)
542 {
543 #ifdef LIBSANGOMA_VERSION
544 sangoma_wait_obj_t *waitobj = ftdmchan->mod_data;
545
546 sangoma_wait_obj_signal(waitobj);
547 #endif
548 return FTDM_SUCCESS;
549 }
550
551
552
553
554
555
556
557
558 static FIO_COMMAND_FUNCTION(wanpipe_command)
559 {
560 wanpipe_tdm_api_t tdm_api;
561 int err = 0;
562
563 memset(&tdm_api, 0, sizeof(tdm_api));
564
565 switch(command) {
566 case FTDM_COMMAND_OFFHOOK:
567 {
568 err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
569 if (err) {
570 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed");
571 return FTDM_FAIL;
572 }
573 ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
574 }
575 break;
576 case FTDM_COMMAND_ONHOOK:
577 {
578 err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
579 if (err) {
580 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
581 return FTDM_FAIL;
582 }
583 ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
584 }
585 break;
586 case FTDM_COMMAND_GENERATE_RING_ON:
587 {
588 err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
589 if (err) {
590 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
591 return FTDM_FAIL;
592 }
593 ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
594 ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
595 ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
596 }
597 break;
598 case FTDM_COMMAND_GENERATE_RING_OFF:
599 {
600 err=sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
601 if (err) {
602 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
603 return FTDM_FAIL;
604 }
605 ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
606 ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
607 }
608 break;
609 case FTDM_COMMAND_GET_INTERVAL:
610 {
611 err=sangoma_tdm_get_usr_period(ftdmchan->sockfd, &tdm_api);
612 if (err > 0 ) {
613 FTDM_COMMAND_OBJ_INT = err;
614 err=0;
615 }
616 }
617 break;
618 case FTDM_COMMAND_ENABLE_ECHOCANCEL:
619 {
620 #ifdef WP_API_FEATURE_EC_CHAN_STAT
621 err=sangoma_tdm_get_hwec_chan_status(ftdmchan->sockfd, &tdm_api);
622 if (err > 0) {
623
624 err = 0;
625 break;
626 }
627 #endif
628 err=sangoma_tdm_enable_hwec(ftdmchan->sockfd, &tdm_api);
629 if (err) {
630 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Enable Failed");
631 return FTDM_FAIL;
632 }
633 }
634 break;
635 case FTDM_COMMAND_DISABLE_ECHOCANCEL:
636 {
637 #ifdef WP_API_FEATURE_EC_CHAN_STAT
638 err=sangoma_tdm_get_hwec_chan_status(ftdmchan->sockfd, &tdm_api);
639 if (!err) {
640
641 break;
642 }
643 #endif
644 err=sangoma_tdm_disable_hwec(ftdmchan->sockfd, &tdm_api);
645 if (err) {
646 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HWEC Disable Failed");
647 return FTDM_FAIL;
648 }
649 }
650 break;
651 case FTDM_COMMAND_ENABLE_DTMF_DETECT:
652 {
653 #ifdef WP_API_FEATURE_DTMF_EVENTS
654 err = sangoma_tdm_enable_dtmf_events(ftdmchan->sockfd, &tdm_api);
655 if (err) {
656 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Enabling of Sangoma HW DTMF failed\n");
657 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Enable Failed");
658 return FTDM_FAIL;
659 }
660 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Enabled DTMF events\n");
661 #else
662 return FTDM_NOTIMPL;
663 #endif
664 }
665 break;
666 case FTDM_COMMAND_DISABLE_DTMF_DETECT:
667 {
668 #ifdef WP_API_FEATURE_DTMF_EVENTS
669 err = sangoma_tdm_disable_dtmf_events(ftdmchan->sockfd, &tdm_api);
670 if (err) {
671 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Disabling of Sangoma HW DTMF failed\n");
672 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "HW DTMF Disable Failed");
673 return FTDM_FAIL;
674 }
675 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Disabled DTMF events\n");
676 #else
677 return FTDM_NOTIMPL;
678 #endif
679 }
680 break;
681 case FTDM_COMMAND_ENABLE_LOOP:
682 {
683 #ifdef WP_API_FEATURE_LOOP
684 err=sangoma_tdm_enable_loop(ftdmchan->sockfd, &tdm_api);
685 if (err) {
686 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Enable Failed");
687 return FTDM_FAIL;
688 }
689 #endif
690 }
691 break;
692 case FTDM_COMMAND_DISABLE_LOOP:
693 {
694 #ifdef WP_API_FEATURE_LOOP
695 err=sangoma_tdm_disable_loop(ftdmchan->sockfd, &tdm_api);
696 if (err) {
697 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Loop Disable Failed");
698 return FTDM_FAIL;
699 }
700 #endif
701 }
702 break;
703 case FTDM_COMMAND_SET_INTERVAL:
704 {
705 err=sangoma_tdm_set_usr_period(ftdmchan->sockfd, &tdm_api, FTDM_COMMAND_OBJ_INT);
706 ftdmchan->packet_len = ftdmchan->native_interval * (ftdmchan->effective_codec == FTDM_CODEC_SLIN ? 16 : 8);
707 }
708 break;
709 case FTDM_COMMAND_SET_CAS_BITS:
710 {
711 #ifdef LIBSANGOMA_VERSION
712 err = sangoma_tdm_write_rbs(ftdmchan->sockfd,&tdm_api, ftdmchan->physical_chan_id, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
713 #else
714 err = sangoma_tdm_write_rbs(ftdmchan->sockfd, &tdm_api, wanpipe_swap_bits(FTDM_COMMAND_OBJ_INT));
715 #endif
716 }
717 break;
718 case FTDM_COMMAND_GET_CAS_BITS:
719 {
720 #ifdef LIBSANGOMA_VERSION
721 unsigned char rbsbits;
722 err = sangoma_tdm_read_rbs(ftdmchan->sockfd, &tdm_api, ftdmchan->physical_chan_id, &rbsbits);
723 if (!err) {
724 FTDM_COMMAND_OBJ_INT = wanpipe_swap_bits(rbsbits);
725 }
726 #else
727
728 FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits;
729 #endif
730 }
731 break;
732 case FTDM_COMMAND_SET_LINK_STATUS:
733 {
734 ftdm_channel_hw_link_status_t status = FTDM_COMMAND_OBJ_INT;
735 char sangoma_status = status == FTDM_HW_LINK_CONNECTED ? FE_CONNECTED : FE_DISCONNECTED;
736 err = sangoma_tdm_set_fe_status(ftdmchan->sockfd, &tdm_api, sangoma_status);
737 }
738 break;
739 case FTDM_COMMAND_GET_LINK_STATUS:
740 {
741 unsigned char sangoma_status = 0;
742 err = sangoma_tdm_get_fe_status(ftdmchan->sockfd, &tdm_api, &sangoma_status);
743 if (!err) {
744 FTDM_COMMAND_OBJ_INT = sangoma_status == FE_CONNECTED ? FTDM_HW_LINK_CONNECTED : FTDM_HW_LINK_DISCONNECTED;
745 }
746 }
747 break;
748 default:
749 break;
750 };
751
752 if (err) {
753 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
754 return FTDM_FAIL;
755 }
756
757
758 return FTDM_SUCCESS;
759 }
760
761
762
763
764
765
766
767
768 static FIO_READ_FUNCTION(wanpipe_read)
769 {
770 int rx_len = 0;
771 int myerrno = 0;
772 wp_tdm_api_rx_hdr_t hdrframe;
773
774 memset(&hdrframe, 0, sizeof(hdrframe));
775
776 rx_len = sangoma_readmsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (int)*datalen, 0);
777 *datalen = rx_len;
778
779 if (rx_len == 0) {
780 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Read 0 bytes\n");
781 return FTDM_TIMEOUT;
782 }
783
784 if (rx_len < 0) {
785 myerrno = errno;
786 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
787 ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Failed to read from sangoma device: %s (%d)\n", strerror(errno), rx_len);
788 return FTDM_FAIL;
789 }
790
791
792 return FTDM_SUCCESS;
793 }
794
795
796
797
798
799
800
801
802 static FIO_WRITE_FUNCTION(wanpipe_write)
803 {
804 int bsent;
805 wp_tdm_api_tx_hdr_t hdrframe;
806
807
808 memset(&hdrframe, 0, sizeof(hdrframe));
809 if (*datalen == 0) {
810 return FTDM_SUCCESS;
811 }
812 bsent = sangoma_writemsg_tdm(ftdmchan->sockfd, &hdrframe, (int)sizeof(hdrframe), data, (unsigned short)(*datalen),0);
813
814
815 if (bsent > 0) {
816 *datalen = bsent;
817 return FTDM_SUCCESS;
818 }
819
820 return FTDM_FAIL;
821 }
822
823
824
825
826
827
828
829
830
831 static FIO_WAIT_FUNCTION(wanpipe_wait)
832 {
833 int32_t inflags = 0;
834 int result;
835
836 if (*flags & FTDM_READ) {
837 inflags |= POLLIN;
838 }
839
840 if (*flags & FTDM_WRITE) {
841 inflags |= POLLOUT;
842 }
843
844 if (*flags & FTDM_EVENTS) {
845 inflags |= POLLPRI;
846 }
847
848 result = tdmv_api_wait_socket(ftdmchan, to, &inflags);
849
850 *flags = FTDM_NO_FLAGS;
851
852 if (result < 0){
853 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Poll failed");
854 return FTDM_FAIL;
855 }
856
857 if (result == 0) {
858 return FTDM_TIMEOUT;
859 }
860
861 if (inflags & POLLIN) {
862 *flags |= FTDM_READ;
863 }
864
865 if (inflags & POLLOUT) {
866 *flags |= FTDM_WRITE;
867 }
868
869 if (inflags & POLLPRI) {
870 *flags |= FTDM_EVENTS;
871 }
872
873 return FTDM_SUCCESS;
874 }
875
876
877
878
879
880
881
882 FIO_SPAN_POLL_EVENT_FUNCTION(wanpipe_poll_event)
883 {
884 #ifdef LIBSANGOMA_VERSION
885 sangoma_status_t sangstatus;
886 sangoma_wait_obj_t *pfds[FTDM_MAX_CHANNELS_SPAN] = { 0 };
887 uint32_t inflags[FTDM_MAX_CHANNELS_SPAN];
888 uint32_t outflags[FTDM_MAX_CHANNELS_SPAN];
889 #else
890 struct pollfd pfds[FTDM_MAX_CHANNELS_SPAN];
891 #endif
892 uint32_t i, j = 0, k = 0, l = 0;
893 int r;
894
895 for(i = 1; i <= span->chan_count; i++) {
896 ftdm_channel_t *ftdmchan = span->channels[i];
897 #ifdef LIBSANGOMA_VERSION
898 if (!ftdmchan->mod_data) {
899 continue;
900 }
901 pfds[j] = ftdmchan->mod_data;
902 inflags[j] = POLLPRI;
903 #else
904 memset(&pfds[j], 0, sizeof(pfds[j]));
905 pfds[j].fd = span->channels[i]->sockfd;
906 pfds[j].events = POLLPRI;
907 #endif
908
909
910 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK) || ftdm_test_flag(ftdmchan, FTDM_CHANNEL_FLASH)) {
911 l = 5;
912 }
913
914 j++;
915
916 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING)) {
917 l = 5;
918 }
919
920 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_RINGING) && ftdm_current_time_in_ms() >= ftdmchan->ring_time) {
921 wanpipe_tdm_api_t tdm_api;
922 int err;
923 memset(&tdm_api, 0, sizeof(tdm_api));
924 if (ftdm_test_pflag(ftdmchan, WP_RINGING)) {
925 err = sangoma_tdm_txsig_offhook(ftdmchan->sockfd,&tdm_api);
926 if (err) {
927 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off Failed");
928 ftdm_log(FTDM_LOG_ERROR, "sangoma_tdm_txsig_offhook failed\n");
929 return FTDM_FAIL;
930 }
931 ftdm_clear_pflag_locked(ftdmchan, WP_RINGING);
932 ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_off_ms;
933 } else {
934 err=sangoma_tdm_txsig_start(ftdmchan->sockfd,&tdm_api);
935 if (err) {
936 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
937 ftdm_log(FTDM_LOG_ERROR, "sangoma_tdm_txsig_start failed\n");
938 return FTDM_FAIL;
939 }
940 ftdm_set_pflag_locked(ftdmchan, WP_RINGING);
941 ftdmchan->ring_time = ftdm_current_time_in_ms() + wp_globals.ring_on_ms;
942 }
943 }
944 }
945
946 if (l) {
947 ms = l;
948 }
949 #ifdef LIBSANGOMA_VERSION
950 sangstatus = sangoma_waitfor_many(pfds, inflags, outflags, j, ms);
951 if (SANG_STATUS_APIPOLL_TIMEOUT == sangstatus) {
952 r = 0;
953 } else if (SANG_STATUS_SUCCESS == sangstatus) {
954 r = 1;
955 } else {
956 ftdm_log(FTDM_LOG_ERROR, "sangoma_waitfor_many failed: %d, %s\n", sangstatus, strerror(errno));
957 r = -1;
958 }
959 #else
960 r = poll(pfds, j, ms);
961 #endif
962
963 if (r == 0) {
964 return l ? FTDM_SUCCESS : FTDM_TIMEOUT;
965 } else if (r < 0) {
966 snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
967 return FTDM_FAIL;
968 }
969
970 for(i = 1; i <= span->chan_count; i++) {
971 ftdm_channel_t *ftdmchan = span->channels[i];
972
973 #ifdef LIBSANGOMA_VERSION
974 if (outflags[i-1] & POLLPRI) {
975 #else
976 if (pfds[i-1].revents & POLLPRI) {
977 #endif
978 ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
979 ftdmchan->last_event_time = ftdm_current_time_in_ms();
980 k++;
981 }
982 }
983
984 return FTDM_SUCCESS;
985 }
986
987
988
989
990
991
992 static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
993 {
994 wanpipe_tdm_api_t tdm_api;
995 unsigned int alarms = 0;
996 int err;
997
998 memset(&tdm_api,0,sizeof(tdm_api));
999
1000 #ifdef LIBSANGOMA_VERSION
1001 if ((err = sangoma_tdm_get_fe_alarms(ftdmchan->sockfd, &tdm_api, &alarms))) {
1002 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
1003 snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
1004 return FTDM_FAIL;
1005 }
1006 #else
1007 if ((err = sangoma_tdm_get_fe_alarms(ftdmchan->sockfd, &tdm_api)) < 0){
1008 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
1009 snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
1010 return FTDM_FAIL;
1011 }
1012 alarms = tdm_api.wp_tdm_cmd.fe_alarms;
1013 #endif
1014 ftdmchan->alarm_flags = FTDM_ALARM_NONE;
1015
1016 if (alarms & WAN_TE_BIT_ALARM_RED) {
1017 ftdmchan->alarm_flags |= FTDM_ALARM_RED;
1018 alarms &= ~WAN_TE_BIT_ALARM_RED;
1019 }
1020
1021 if (alarms & WAN_TE_BIT_ALARM_AIS) {
1022 ftdmchan->alarm_flags |= FTDM_ALARM_BLUE;
1023 alarms &= ~WAN_TE_BIT_ALARM_AIS;
1024 }
1025
1026 if (alarms & WAN_TE_BIT_ALARM_RAI) {
1027 ftdmchan->alarm_flags |= FTDM_ALARM_YELLOW;
1028 alarms &= ~WAN_TE_BIT_ALARM_RAI;
1029 }
1030
1031 if (alarms) {
1032
1033 ftdm_log(FTDM_LOG_DEBUG, "Unmapped wanpipe alarms: %d\n", alarms);
1034 }
1035
1036 return FTDM_SUCCESS;
1037 }
1038
1039
1040
1041
1042
1043
1044
1045 FIO_SPAN_NEXT_EVENT_FUNCTION(wanpipe_next_event)
1046 {
1047 uint32_t i,err;
1048 ftdm_oob_event_t event_id;
1049 for(i = 1; i <= span->chan_count; i++) {
1050 if (span->channels[i]->last_event_time && !ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
1051 uint32_t diff = (uint32_t)(ftdm_current_time_in_ms() - span->channels[i]->last_event_time);
1052
1053 if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
1054 if (diff > wp_globals.wink_ms) {
1055 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1056 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1057 ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
1058 event_id = FTDM_OOB_OFFHOOK;
1059 goto event;
1060 }
1061 }
1062
1063 if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
1064 if (diff > wp_globals.flash_ms) {
1065 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1066 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1067 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
1068 event_id = FTDM_OOB_ONHOOK;
1069
1070 if (span->channels[i]->type == FTDM_CHAN_TYPE_FXO) {
1071 ftdm_channel_t *ftdmchan = span->channels[i];
1072 wanpipe_tdm_api_t tdm_api;
1073 memset(&tdm_api, 0, sizeof(tdm_api));
1074
1075 sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
1076 }
1077 goto event;
1078 }
1079 }
1080 }
1081 if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
1082 wanpipe_tdm_api_t tdm_api;
1083 ftdm_channel_t *ftdmchan = span->channels[i];
1084 memset(&tdm_api, 0, sizeof(tdm_api));
1085 ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
1086
1087 err = sangoma_tdm_read_event(ftdmchan->sockfd, &tdm_api);
1088 if (err != FTDM_SUCCESS) {
1089 snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
1090 return FTDM_FAIL;
1091 }
1092
1093 ftdm_log_chan(span->channels[i], FTDM_LOG_DEBUG, "read wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
1094 switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type) {
1095
1096 case WP_TDMAPI_EVENT_LINK_STATUS:
1097 {
1098 switch(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
1099 case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
1100 event_id = FTDM_OOB_ALARM_CLEAR;
1101 break;
1102 default:
1103 event_id = FTDM_OOB_ALARM_TRAP;
1104 break;
1105 };
1106 }
1107 break;
1108
1109 case WP_TDMAPI_EVENT_RXHOOK:
1110 {
1111 if (span->channels[i]->type == FTDM_CHAN_TYPE_FXS) {
1112 event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_OFFHOOK : FTDM_OOB_ONHOOK;
1113 if (event_id == FTDM_OOB_OFFHOOK) {
1114 if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_FLASH)) {
1115 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1116 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1117 event_id = FTDM_OOB_FLASH;
1118 goto event;
1119 } else {
1120 ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1121 }
1122 } else {
1123 if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_WINK)) {
1124 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_WINK);
1125 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1126 event_id = FTDM_OOB_WINK;
1127 goto event;
1128 } else {
1129 ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_FLASH);
1130 }
1131 }
1132 continue;
1133 } else {
1134 int err;
1135 ftdm_channel_t *ftdmchan = span->channels[i];
1136 err=sangoma_tdm_txsig_onhook(ftdmchan->sockfd,&tdm_api);
1137 if (err) {
1138 snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "ONHOOK Failed");
1139 return FTDM_FAIL;
1140 }
1141 event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_hook_state & WP_TDMAPI_EVENT_RXHOOK_OFF ? FTDM_OOB_ONHOOK : FTDM_OOB_NOOP;
1142 }
1143 }
1144 break;
1145 case WP_TDMAPI_EVENT_RING_DETECT:
1146 {
1147 event_id = tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_ring_state == WP_TDMAPI_EVENT_RING_PRESENT ? FTDM_OOB_RING_START : FTDM_OOB_RING_STOP;
1148 }
1149 break;
1150
1151
1152
1153
1154
1155
1156
1157
1158 case WP_TDMAPI_EVENT_RBS:
1159 {
1160 event_id = FTDM_OOB_CAS_BITS_CHANGE;
1161 span->channels[i]->rx_cas_bits = wanpipe_swap_bits(tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_rbs_bits);
1162 }
1163 break;
1164 case WP_TDMAPI_EVENT_DTMF:
1165 {
1166 char tmp_dtmf[2] = { tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_digit, 0 };
1167 event_id = FTDM_OOB_NOOP;
1168
1169 if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_PRESENT) {
1170 ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
1171 }
1172
1173 if (tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_dtmf_type == WAN_EC_TONE_STOP) {
1174 ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_MUTE);
1175 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INUSE)) {
1176 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Queuing wanpipe DTMF: %c\n", tmp_dtmf[0]);
1177 ftdm_channel_queue_dtmf(ftdmchan, tmp_dtmf);
1178 }
1179 }
1180 }
1181 break;
1182 case WP_TDMAPI_EVENT_ALARM:
1183 {
1184 ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Got wanpipe alarms %d\n", tdm_api.wp_tdm_cmd.event.wp_api_event_alarm);
1185 event_id = FTDM_OOB_ALARM_TRAP;
1186 }
1187 break;
1188 default:
1189 {
1190 ftdm_log_chan(ftdmchan, FTDM_LOG_WARNING, "Unhandled wanpipe event %d\n", tdm_api.wp_tdm_cmd.event.wp_tdm_api_event_type);
1191 event_id = FTDM_OOB_INVALID;
1192 }
1193 break;
1194 }
1195
1196 event:
1197
1198 span->channels[i]->last_event_time = 0;
1199 span->event_header.e_type = FTDM_EVENT_OOB;
1200 span->event_header.enum_id = event_id;
1201 span->event_header.channel = span->channels[i];
1202 *event = &span->event_header;
1203 return FTDM_SUCCESS;
1204 }
1205 }
1206
1207 return FTDM_FAIL;
1208
1209 }
1210
1211
1212
1213
1214
1215
1216 static FIO_CHANNEL_DESTROY_FUNCTION(wanpipe_channel_destroy)
1217 {
1218 #ifdef LIBSANGOMA_VERSION
1219 if (ftdmchan->mod_data) {
1220 sangoma_wait_obj_t *sangoma_wait_obj;
1221 sangoma_wait_obj = ftdmchan->mod_data;
1222 ftdmchan->mod_data = NULL;
1223 sangoma_wait_obj_delete(&sangoma_wait_obj);
1224 }
1225 #endif
1226
1227 if (ftdmchan->sockfd != FTDM_INVALID_SOCKET) {
1228
1229
1230
1231
1232 if (ftdm_channel_test_feature(ftdmchan, FTDM_CHANNEL_FEATURE_DTMF_DETECT)) {
1233 wanpipe_tdm_api_t tdm_api;
1234 int err;
1235 memset(&tdm_api, 0, sizeof(tdm_api));
1236 err = sangoma_tdm_enable_dtmf_events(ftdmchan->sockfd, &tdm_api);
1237 if (err) {
1238 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Failed enabling Sangoma HW DTMF failed on channel destroy\n");
1239 }
1240 }
1241 sangoma_close(&ftdmchan->sockfd);
1242 }
1243
1244 return FTDM_SUCCESS;
1245 }
1246
1247
1248
1249
1250
1251
1252 static FIO_IO_LOAD_FUNCTION(wanpipe_init)
1253 {
1254 assert(fio != NULL);
1255 memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
1256
1257 wp_globals.codec_ms = 20;
1258 wp_globals.wink_ms = 150;
1259 wp_globals.flash_ms = 750;
1260 wp_globals.ring_on_ms = 2000;
1261 wp_globals.ring_off_ms = 4000;
1262 wanpipe_interface.name = "wanpipe";
1263 wanpipe_interface.configure_span = wanpipe_configure_span;
1264 wanpipe_interface.configure = wanpipe_configure;
1265 wanpipe_interface.open = wanpipe_open;
1266 wanpipe_interface.close = wanpipe_close;
1267 wanpipe_interface.command = wanpipe_command;
1268 wanpipe_interface.wait = wanpipe_wait;
1269 wanpipe_interface.read = wanpipe_read;
1270 wanpipe_interface.write = wanpipe_write;
1271 wanpipe_interface.poll_event = wanpipe_poll_event;
1272 wanpipe_interface.next_event = wanpipe_next_event;
1273 wanpipe_interface.channel_destroy = wanpipe_channel_destroy;
1274 wanpipe_interface.get_alarms = wanpipe_get_alarms;
1275 *fio = &wanpipe_interface;
1276
1277 return FTDM_SUCCESS;
1278 }
1279
1280
1281
1282
1283
1284 static FIO_IO_UNLOAD_FUNCTION(wanpipe_destroy)
1285 {
1286 memset(&wanpipe_interface, 0, sizeof(wanpipe_interface));
1287 return FTDM_SUCCESS;
1288 }
1289
1290
1291
1292
1293 EX_DECLARE_DATA ftdm_module_t ftdm_module = {
1294 "wanpipe",
1295 wanpipe_init,
1296 wanpipe_destroy,
1297 };
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308