2010-06-30 16:42:11 +00:00
/*
* Copyright ( c ) 2010 , Sangoma Technologies
* David Yat Sin < davidy @ sangoma . com >
* Moises Silva < moy @ sangoma . com >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
*
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* * Neither the name of the original author ; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission .
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL ,
* EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR
* PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2010-08-31 17:29:31 +00:00
2010-06-30 16:42:11 +00:00
# include "ftmod_sangoma_isdn.h"
2010-08-31 17:29:31 +00:00
# ifdef FTDM_DEBUG_CHAN_MEMORY
# include <sys/mman.h>
# endif
2010-06-30 16:42:11 +00:00
2010-11-30 18:17:48 +00:00
static void * ftdm_sangoma_isdn_run ( ftdm_thread_t * me , void * obj ) ;
2010-06-30 16:42:11 +00:00
static ftdm_status_t ftdm_sangoma_isdn_stop ( ftdm_span_t * span ) ;
static ftdm_status_t ftdm_sangoma_isdn_start ( ftdm_span_t * span ) ;
2011-05-26 15:38:24 +00:00
static ftdm_status_t ftdm_sangoma_isdn_dtmf ( ftdm_channel_t * ftdmchan , const char * dtmf ) ;
2010-06-30 16:42:11 +00:00
2010-08-31 17:29:31 +00:00
ftdm_channel_t * ftdm_sangoma_isdn_process_event_states ( ftdm_span_t * span , sngisdn_event_data_t * sngisdn_event ) ;
2010-11-11 00:03:15 +00:00
static void ftdm_sangoma_isdn_process_phy_events ( ftdm_span_t * span , ftdm_oob_event_t event ) ;
2010-12-31 14:42:15 +00:00
static ftdm_status_t ftdm_sangoma_isdn_process_state_change ( ftdm_channel_t * ftdmchan ) ;
2010-08-31 17:29:31 +00:00
static void ftdm_sangoma_isdn_process_stack_event ( ftdm_span_t * span , sngisdn_event_data_t * sngisdn_event ) ;
2010-11-16 00:16:09 +00:00
static void ftdm_sangoma_isdn_wakeup_phy ( ftdm_channel_t * dchan ) ;
static void ftdm_sangoma_isdn_dchan_set_queue_size ( ftdm_channel_t * ftdmchan ) ;
2010-08-31 17:29:31 +00:00
2011-05-26 15:38:24 +00:00
static ftdm_io_interface_t g_sngisdn_io_interface ;
2010-11-11 23:43:53 +00:00
static sng_isdn_event_interface_t g_sngisdn_event_interface ;
2010-06-30 16:42:11 +00:00
2011-05-26 15:38:24 +00:00
ftdm_sngisdn_data_t g_sngisdn_data ;
2011-06-13 20:22:10 +00:00
SNGISDN_ENUM_NAMES ( SNGISDN_TRANSFER_TYPE_NAMES , SNGISDN_TRANSFER_TYPE_STRINGS )
SNGISDN_STR2ENUM ( ftdm_str2sngisdn_transfer_type , sngisdn_transfer_type2str , sngisdn_transfer_type_t , SNGISDN_TRANSFER_TYPE_NAMES , SNGISDN_TRANSFER_INVALID )
2010-06-30 16:42:11 +00:00
ftdm_state_map_t sangoma_isdn_state_map = {
{
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_ANY_STATE , FTDM_END } ,
2010-12-14 16:23:47 +00:00
{ FTDM_CHANNEL_STATE_RESET , FTDM_CHANNEL_STATE_RESTART , FTDM_END }
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_RESET , FTDM_END } ,
{ FTDM_CHANNEL_STATE_DOWN , FTDM_END }
2010-06-30 16:42:11 +00:00
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_RESTART , FTDM_END } ,
{ FTDM_CHANNEL_STATE_DOWN , FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP , FTDM_END }
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_CANCEL , FTDM_END } ,
2010-08-31 17:29:31 +00:00
{ FTDM_CHANNEL_STATE_HANGUP_COMPLETE , FTDM_END }
2010-06-30 16:42:11 +00:00
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_SUSPENDED , FTDM_END } ,
{ FTDM_CHANNEL_STATE_DOWN , FTDM_CHANNEL_STATE_COLLECT , FTDM_CHANNEL_STATE_RING , FTDM_CHANNEL_STATE_DIALING ,
FTDM_CHANNEL_STATE_RESTART , FTDM_CHANNEL_STATE_PROGRESS , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_CHANNEL_STATE_UP ,
FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_CANCEL , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_HANGUP_COMPLETE , FTDM_END }
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_DOWN , FTDM_END } ,
2010-08-31 17:29:31 +00:00
{ FTDM_CHANNEL_STATE_COLLECT , FTDM_CHANNEL_STATE_RING , FTDM_CHANNEL_STATE_GET_CALLERID , FTDM_CHANNEL_STATE_IN_LOOP , FTDM_END }
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_GET_CALLERID , FTDM_END } ,
{ FTDM_CHANNEL_STATE_RING , FTDM_CHANNEL_STATE_CANCEL , FTDM_CHANNEL_STATE_IN_LOOP , FTDM_END }
2010-06-30 16:42:11 +00:00
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_COLLECT , FTDM_END } ,
{ FTDM_CHANNEL_STATE_RING , FTDM_CHANNEL_STATE_CANCEL , FTDM_CHANNEL_STATE_IN_LOOP , FTDM_END }
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_IN_LOOP , FTDM_END } ,
{ FTDM_CHANNEL_STATE_COLLECT , FTDM_CHANNEL_STATE_DOWN , FTDM_END }
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_RING , FTDM_END } ,
2011-01-14 15:48:09 +00:00
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_PROCEED , FTDM_CHANNEL_STATE_RINGING , FTDM_CHANNEL_STATE_PROGRESS , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_END }
2010-11-25 01:04:43 +00:00
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_PROCEED , FTDM_END } ,
2011-05-26 15:38:24 +00:00
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_RINGING , FTDM_CHANNEL_STATE_PROGRESS , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_CHANNEL_STATE_UP , FTDM_CHANNEL_STATE_TRANSFER , FTDM_END }
2010-11-25 01:04:43 +00:00
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_RINGING , FTDM_END } ,
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_PROGRESS , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_CHANNEL_STATE_UP , FTDM_END } ,
2010-06-30 16:42:11 +00:00
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_PROGRESS , FTDM_END } ,
2010-12-01 20:11:51 +00:00
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_CHANNEL_STATE_UP , FTDM_END } ,
2010-06-30 16:42:11 +00:00
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_END } ,
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_UP , FTDM_END } ,
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_UP , FTDM_END } ,
2011-05-26 15:38:24 +00:00
{ FTDM_CHANNEL_STATE_TRANSFER , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_TERMINATING , FTDM_END } ,
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_TRANSFER , FTDM_END } ,
{ FTDM_CHANNEL_STATE_PROCEED , FTDM_CHANNEL_STATE_PROGRESS , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_CHANNEL_STATE_UP , FTDM_CHANNEL_STATE_TERMINATING , FTDM_END } ,
2010-06-30 16:42:11 +00:00
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_END } ,
{ FTDM_CHANNEL_STATE_HANGUP , FTDM_END } ,
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_HANGUP , FTDM_END } ,
{ FTDM_CHANNEL_STATE_HANGUP_COMPLETE , FTDM_END } ,
} ,
{
ZSD_INBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_HANGUP_COMPLETE , FTDM_END } ,
{ FTDM_CHANNEL_STATE_DOWN , FTDM_END } ,
2010-08-31 17:29:31 +00:00
} ,
2010-06-30 16:42:11 +00:00
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_ANY_STATE , FTDM_END } ,
2010-12-14 16:23:47 +00:00
{ FTDM_CHANNEL_STATE_RESET , FTDM_CHANNEL_STATE_RESTART , FTDM_CHANNEL_STATE_TERMINATING , FTDM_END }
} ,
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_RESET , FTDM_END } ,
{ FTDM_CHANNEL_STATE_DOWN , FTDM_END }
2010-06-30 16:42:11 +00:00
} ,
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_RESTART , FTDM_END } ,
{ FTDM_CHANNEL_STATE_DOWN , FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP , FTDM_END }
} ,
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_CANCEL , FTDM_END } ,
{ FTDM_CHANNEL_STATE_HANGUP , FTDM_END }
} ,
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_SUSPENDED , FTDM_END } ,
{ FTDM_CHANNEL_STATE_DOWN , FTDM_CHANNEL_STATE_COLLECT , FTDM_CHANNEL_STATE_RING , FTDM_CHANNEL_STATE_DIALING ,
FTDM_CHANNEL_STATE_RESTART , FTDM_CHANNEL_STATE_PROGRESS , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_CHANNEL_STATE_UP ,
FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_CANCEL , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_HANGUP_COMPLETE , FTDM_END }
} ,
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_DOWN , FTDM_END } ,
2010-08-31 17:29:31 +00:00
{ FTDM_CHANNEL_STATE_DIALING , FTDM_CHANNEL_STATE_HANGUP_COMPLETE , FTDM_END }
2010-06-30 16:42:11 +00:00
} ,
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_DIALING , FTDM_END } ,
2010-11-25 01:04:43 +00:00
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP ,
2010-12-15 16:45:50 +00:00
FTDM_CHANNEL_STATE_PROCEED , FTDM_CHANNEL_STATE_RINGING , FTDM_CHANNEL_STATE_PROGRESS , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_CHANNEL_STATE_UP ,
2010-11-25 01:04:43 +00:00
FTDM_CHANNEL_STATE_DOWN , FTDM_END }
2010-06-30 16:42:11 +00:00
} ,
2010-11-25 01:04:43 +00:00
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_PROCEED , FTDM_END } ,
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP ,
2010-12-15 16:45:50 +00:00
FTDM_CHANNEL_STATE_RINGING , FTDM_CHANNEL_STATE_PROGRESS , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_CHANNEL_STATE_UP , FTDM_END } ,
} ,
2010-06-30 16:42:11 +00:00
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_PROGRESS , FTDM_END } ,
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_CHANNEL_STATE_UP , FTDM_END } ,
} ,
2010-12-15 16:45:50 +00:00
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_RINGING , FTDM_END } ,
2011-01-05 21:25:06 +00:00
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_PROGRESS , FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_CHANNEL_STATE_UP , FTDM_END } ,
2010-12-15 16:45:50 +00:00
} ,
2010-06-30 16:42:11 +00:00
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_PROGRESS_MEDIA , FTDM_END } ,
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_UP , FTDM_END } ,
} ,
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_UP , FTDM_END } ,
{ FTDM_CHANNEL_STATE_HANGUP , FTDM_CHANNEL_STATE_TERMINATING , FTDM_END } ,
} ,
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_TERMINATING , FTDM_END } ,
{ FTDM_CHANNEL_STATE_HANGUP , FTDM_END } ,
} ,
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_HANGUP , FTDM_END } ,
{ FTDM_CHANNEL_STATE_HANGUP_COMPLETE , FTDM_END } ,
} ,
{
ZSD_OUTBOUND ,
ZSM_UNACCEPTABLE ,
{ FTDM_CHANNEL_STATE_HANGUP_COMPLETE , FTDM_END } ,
{ FTDM_CHANNEL_STATE_DOWN , FTDM_END } ,
}
}
} ;
2010-11-11 00:03:15 +00:00
static void ftdm_sangoma_isdn_process_phy_events ( ftdm_span_t * span , ftdm_oob_event_t event )
{
2010-11-16 00:16:09 +00:00
sngisdn_span_data_t * signal_data = ( sngisdn_span_data_t * ) span - > signal_data ;
2012-06-07 00:41:48 +00:00
sngisdn_snd_event ( signal_data , event ) ;
2010-11-11 00:03:15 +00:00
switch ( event ) {
/* Check if the span woke up from power-saving mode */
case FTDM_OOB_ALARM_CLEAR :
if ( FTDM_SPAN_IS_BRI ( span ) ) {
ftdm_channel_t * ftdmchan ;
2010-11-11 23:43:53 +00:00
sngisdn_chan_data_t * sngisdn_info ;
2010-11-11 00:03:15 +00:00
ftdm_iterator_t * chaniter = NULL ;
ftdm_iterator_t * curr = NULL ;
2010-11-16 00:16:09 +00:00
2010-11-11 00:03:15 +00:00
chaniter = ftdm_span_get_chan_iterator ( span , NULL ) ;
for ( curr = chaniter ; curr ; curr = ftdm_iterator_next ( curr ) ) {
ftdmchan = ( ftdm_channel_t * ) ftdm_iterator_current ( curr ) ;
2010-11-11 23:43:53 +00:00
sngisdn_info = ( sngisdn_chan_data_t * ) ftdmchan - > call_data ;
2010-11-11 00:03:15 +00:00
if ( ftdm_test_flag ( sngisdn_info , FLAG_ACTIVATING ) ) {
ftdm_clear_flag ( sngisdn_info , FLAG_ACTIVATING ) ;
2010-11-16 00:16:09 +00:00
ftdm_sched_timer ( signal_data - > sched , " delayed_setup " , 1000 , sngisdn_delayed_setup , ( void * ) ftdmchan - > call_data , NULL ) ;
2010-11-11 00:03:15 +00:00
}
}
ftdm_iterator_free ( chaniter ) ;
}
break ;
default :
/* Ignore other events for now */
break ;
}
}
2010-11-16 00:16:09 +00:00
static void ftdm_sangoma_isdn_dchan_set_queue_size ( ftdm_channel_t * dchan )
{
ftdm_status_t ret_status ;
uint32_t queue_size ;
queue_size = SNGISDN_DCHAN_QUEUE_LEN ;
ret_status = ftdm_channel_command ( dchan , FTDM_COMMAND_SET_RX_QUEUE_SIZE , & queue_size ) ;
ftdm_assert ( ret_status = = FTDM_SUCCESS , " Failed to set Rx Queue size " ) ;
queue_size = SNGISDN_DCHAN_QUEUE_LEN ;
ret_status = ftdm_channel_command ( dchan , FTDM_COMMAND_SET_TX_QUEUE_SIZE , & queue_size ) ;
ftdm_assert ( ret_status = = FTDM_SUCCESS , " Failed to set Tx Queue size " ) ;
RETVOID ;
}
static void ftdm_sangoma_isdn_wakeup_phy ( ftdm_channel_t * dchan )
{
ftdm_status_t ret_status ;
ftdm_channel_hw_link_status_t status = FTDM_HW_LINK_CONNECTED ;
ret_status = ftdm_channel_command ( dchan , FTDM_COMMAND_SET_LINK_STATUS , & status ) ;
if ( ret_status ! = FTDM_SUCCESS ) {
ftdm_log_chan_msg ( dchan , FTDM_LOG_WARNING , " Failed to wake-up link \n " ) ;
}
return ;
}
2011-05-26 15:38:24 +00:00
static void * ftdm_sangoma_isdn_io_run ( ftdm_thread_t * me , void * obj )
2010-11-11 00:03:15 +00:00
{
uint8_t data [ 1000 ] ;
2011-06-10 16:55:22 +00:00
unsigned i = 0 ;
2010-11-11 00:03:15 +00:00
ftdm_status_t status = FTDM_SUCCESS ;
ftdm_span_t * span = ( ftdm_span_t * ) obj ;
ftdm_size_t len = 0 ;
2011-05-26 15:38:24 +00:00
ftdm_channel_t * ftdmchan = NULL ;
unsigned waitms = 10000 ;
ftdm_iterator_t * chaniter = NULL ;
ftdm_iterator_t * citer = NULL ;
2011-06-09 20:49:55 +00:00
ftdm_event_t * event ;
2011-05-26 15:38:24 +00:00
short * poll_events = ftdm_malloc ( sizeof ( short ) * span - > chan_count ) ;
/* Initialize the d-channel */
chaniter = ftdm_span_get_chan_iterator ( span , NULL ) ;
if ( ! chaniter ) {
ftdm_log ( FTDM_LOG_CRIT , " Failed to allocate channel iterator for span %s! \n " , span - > name ) ;
goto done ;
}
2010-11-16 00:16:09 +00:00
2010-11-11 00:03:15 +00:00
while ( ftdm_running ( ) & & ! ( ftdm_test_flag ( span , FTDM_SPAN_STOP_THREAD ) ) ) {
2011-05-26 15:38:24 +00:00
len = 1000 ;
waitms = 1000 ;
memset ( poll_events , 0 , sizeof ( short ) * span - > chan_count ) ;
for ( i = 0 , citer = ftdm_span_get_chan_iterator ( span , chaniter ) ; citer ; citer = ftdm_iterator_next ( citer ) , i + + ) {
ftdmchan = ftdm_iterator_current ( citer ) ;
2011-07-29 18:01:49 +00:00
poll_events [ i ] | = FTDM_EVENTS ;
2011-05-26 15:38:24 +00:00
if ( FTDM_IS_VOICE_CHANNEL ( ftdmchan ) ) {
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_RX_DISABLED ) ) {
poll_events [ i ] | = FTDM_READ ;
waitms = 20 ;
}
} else {
/* We always read the d-channel */
poll_events [ i ] | = FTDM_READ ;
}
}
status = ftdm_span_poll_event ( span , waitms , poll_events ) ;
switch ( status ) {
2010-11-11 00:03:15 +00:00
case FTDM_FAIL :
2011-05-26 15:38:24 +00:00
ftdm_log ( FTDM_LOG_CRIT , " Failed to poll span for IO \n " ) ;
2010-11-11 00:03:15 +00:00
break ;
case FTDM_TIMEOUT :
break ;
case FTDM_SUCCESS :
2011-06-09 20:49:55 +00:00
/* Check if there are any channels that have data available */
2011-05-26 15:38:24 +00:00
for ( citer = ftdm_span_get_chan_iterator ( span , chaniter ) ; citer ; citer = ftdm_iterator_next ( citer ) ) {
2012-01-23 02:54:35 +00:00
len = sizeof ( data ) ;
2011-05-26 15:38:24 +00:00
ftdmchan = ftdm_iterator_current ( citer ) ;
if ( FTDM_IS_VOICE_CHANNEL ( ftdmchan ) ) {
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_RX_DISABLED ) ) {
if ( ftdm_test_io_flag ( ftdmchan , FTDM_CHANNEL_IO_READ ) ) {
status = ftdm_raw_read ( ftdmchan , data , & len ) ;
if ( status ! = FTDM_SUCCESS ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " raw I/O read failed \n " ) ;
continue ;
}
status = ftdm_channel_process_media ( ftdmchan , data , & len ) ;
if ( status ! = FTDM_SUCCESS ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " Failed to process media \n " ) ;
continue ;
}
}
}
2010-11-11 00:03:15 +00:00
} else {
2011-05-26 15:38:24 +00:00
if ( ftdm_test_io_flag ( ftdmchan , FTDM_CHANNEL_IO_READ ) ) {
status = ftdm_channel_read ( ftdmchan , data , & len ) ;
if ( status = = FTDM_SUCCESS ) {
sngisdn_snd_data ( ftdmchan , data , len ) ;
}
}
2010-11-11 00:03:15 +00:00
}
}
2011-06-09 20:49:55 +00:00
/* Check if there are any channels that have events available */
while ( ftdm_span_next_event ( span , & event ) = = FTDM_SUCCESS ) {
ftdm_sangoma_isdn_process_phy_events ( span , event - > enum_id ) ;
}
2010-11-11 00:03:15 +00:00
break ;
default :
2011-05-26 15:38:24 +00:00
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_CRIT , " Unhandled IO event \n " ) ;
2010-11-11 00:03:15 +00:00
}
2011-05-26 15:38:24 +00:00
}
done :
ftdm_iterator_free ( chaniter ) ;
ftdm_safe_free ( poll_events ) ;
2010-11-11 00:03:15 +00:00
return NULL ;
}
2010-06-30 16:42:11 +00:00
static void * ftdm_sangoma_isdn_run ( ftdm_thread_t * me , void * obj )
{
2010-11-23 22:41:40 +00:00
ftdm_interrupt_t * ftdm_sangoma_isdn_int [ 3 ] ;
2010-08-31 17:29:31 +00:00
ftdm_status_t ret_status ;
2010-06-30 16:42:11 +00:00
ftdm_span_t * span = ( ftdm_span_t * ) obj ;
ftdm_channel_t * ftdmchan = NULL ;
2010-08-31 17:29:31 +00:00
sngisdn_span_data_t * signal_data = ( sngisdn_span_data_t * ) span - > signal_data ;
sngisdn_event_data_t * sngisdn_event = NULL ;
int32_t sleep = SNGISDN_EVENT_POLL_RATE ;
2010-06-30 16:42:11 +00:00
ftdm_log ( FTDM_LOG_INFO , " ftmod_sangoma_isdn monitor thread for span=%u started. \n " , span - > span_id ) ;
/* set IN_THREAD flag so that we know this thread is running */
ftdm_set_flag ( span , FTDM_SPAN_IN_THREAD ) ;
/* get an interrupt queue for this span */
2010-08-31 17:29:31 +00:00
if ( ftdm_queue_get_interrupt ( span - > pendingchans , & ftdm_sangoma_isdn_int [ 0 ] ) ! = FTDM_SUCCESS ) {
2012-07-12 01:01:20 +00:00
ftdm_log ( FTDM_LOG_CRIT , " Failed to get a ftdm_interrupt for span = %s! \n " , span - > name ) ;
2010-06-30 16:42:11 +00:00
goto ftdm_sangoma_isdn_run_exit ;
}
2010-11-23 22:41:40 +00:00
if ( ftdm_queue_get_interrupt ( span - > pendingsignals , & ftdm_sangoma_isdn_int [ 1 ] ) ! = FTDM_SUCCESS ) {
2012-07-12 01:01:20 +00:00
ftdm_log ( FTDM_LOG_CRIT , " Failed to get a signal interrupt for span = %s! \n " , span - > name ) ;
2010-11-23 22:41:40 +00:00
goto ftdm_sangoma_isdn_run_exit ;
}
2010-06-30 16:42:11 +00:00
2010-11-23 22:41:40 +00:00
if ( ftdm_queue_get_interrupt ( signal_data - > event_queue , & ftdm_sangoma_isdn_int [ 2 ] ) ! = FTDM_SUCCESS ) {
2012-07-12 01:01:20 +00:00
ftdm_log ( FTDM_LOG_CRIT , " Failed to get a event interrupt for span = %s! \n " , span - > name ) ;
2010-08-31 17:29:31 +00:00
goto ftdm_sangoma_isdn_run_exit ;
}
2010-06-30 16:42:11 +00:00
2010-08-31 17:29:31 +00:00
while ( ftdm_running ( ) & & ! ( ftdm_test_flag ( span , FTDM_SPAN_STOP_THREAD ) ) ) {
/* Check if there are any timers to process */
ftdm_sched_run ( signal_data - > sched ) ;
2010-11-23 22:41:40 +00:00
ftdm_span_trigger_signals ( span ) ;
2010-10-14 18:52:17 +00:00
2010-11-23 22:41:40 +00:00
if ( ftdm_sched_get_time_to_next_timer ( signal_data - > sched , & sleep ) = = FTDM_SUCCESS ) {
if ( sleep < 0 | | sleep > SNGISDN_EVENT_POLL_RATE ) {
sleep = SNGISDN_EVENT_POLL_RATE ;
}
}
ret_status = ftdm_interrupt_multiple_wait ( ftdm_sangoma_isdn_int , 3 , sleep ) ;
2010-10-14 18:52:17 +00:00
/* find out why we returned from the interrupt queue */
2010-08-31 17:29:31 +00:00
switch ( ret_status ) {
case FTDM_SUCCESS : /* there was a state change on the span */
/* process all pending state changes */
while ( ( ftdmchan = ftdm_queue_dequeue ( span - > pendingchans ) ) ) {
/* double check that this channel has a state change pending */
ftdm_channel_lock ( ftdmchan ) ;
2010-12-31 14:42:15 +00:00
ftdm_channel_advance_states ( ftdmchan ) ;
2010-08-31 17:29:31 +00:00
ftdm_channel_unlock ( ftdmchan ) ;
2010-06-30 16:42:11 +00:00
}
2010-08-31 17:29:31 +00:00
while ( ( sngisdn_event = ftdm_queue_dequeue ( signal_data - > event_queue ) ) ) {
ftdm_sangoma_isdn_process_stack_event ( span , sngisdn_event ) ;
ftdm_safe_free ( sngisdn_event ) ;
2010-09-03 21:09:21 +00:00
}
2010-08-31 17:29:31 +00:00
break ;
case FTDM_TIMEOUT :
/* twiddle */
break ;
case FTDM_FAIL :
2010-12-31 14:42:15 +00:00
ftdm_log ( FTDM_LOG_ERROR , " %s: ftdm_interrupt_wait returned error! \n " , span - > name ) ;
2010-08-31 17:29:31 +00:00
break ;
2010-06-30 16:42:11 +00:00
2010-08-31 17:29:31 +00:00
default :
2010-12-31 14:42:15 +00:00
ftdm_log ( FTDM_LOG_ERROR , " %s: ftdm_interrupt_wait returned with unknown code \n " , span - > name ) ;
2010-10-14 18:52:17 +00:00
break ;
}
2010-06-30 16:42:11 +00:00
}
2010-08-31 17:29:31 +00:00
2010-06-30 16:42:11 +00:00
/* clear the IN_THREAD flag so that we know the thread is done */
ftdm_clear_flag ( span , FTDM_SPAN_IN_THREAD ) ;
ftdm_log ( FTDM_LOG_INFO , " ftmod_sangoma_isdn monitor thread for span %s stopping. \n " , span - > name ) ;
return NULL ;
ftdm_sangoma_isdn_run_exit :
/* clear the IN_THREAD flag so that we know the thread is done */
ftdm_clear_flag ( span , FTDM_SPAN_IN_THREAD ) ;
ftdm_log ( FTDM_LOG_INFO , " ftmod_sangoma_isdn monitor thread for span %s stopping due to error. \n " , span - > name ) ;
return NULL ;
}
2010-08-31 17:29:31 +00:00
/**
* \ brief Checks if span has state changes pending and processes
* \ param span Span where event was fired
* \ param sngisdn_event Event to handle
* \ return The locked FTDM channel associated to the event if any , NULL otherwise
*/
ftdm_channel_t * ftdm_sangoma_isdn_process_event_states ( ftdm_span_t * span , sngisdn_event_data_t * sngisdn_event )
{
ftdm_channel_t * ftdmchan = NULL ;
switch ( sngisdn_event - > event_id ) {
/* Events that do not have a channel associated to them */
case SNGISDN_EVENT_SRV_IND :
case SNGISDN_EVENT_SRV_CFM :
case SNGISDN_EVENT_RST_CFM :
case SNGISDN_EVENT_RST_IND :
return NULL ;
break ;
case SNGISDN_EVENT_CON_IND :
case SNGISDN_EVENT_CON_CFM :
case SNGISDN_EVENT_CNST_IND :
case SNGISDN_EVENT_DISC_IND :
case SNGISDN_EVENT_REL_IND :
case SNGISDN_EVENT_DAT_IND :
case SNGISDN_EVENT_SSHL_IND :
case SNGISDN_EVENT_SSHL_CFM :
case SNGISDN_EVENT_RMRT_IND :
case SNGISDN_EVENT_RMRT_CFM :
case SNGISDN_EVENT_FLC_IND :
case SNGISDN_EVENT_FAC_IND :
case SNGISDN_EVENT_STA_CFM :
ftdmchan = sngisdn_event - > sngisdn_info - > ftdmchan ;
ftdm_assert_return ( ftdmchan , NULL , " Event should have a channel associated \n " ) ;
break ;
}
ftdm_channel_lock ( ftdmchan ) ;
2010-12-31 14:42:15 +00:00
ftdm_channel_advance_states ( ftdmchan ) ;
2010-08-31 17:29:31 +00:00
return ftdmchan ;
}
static void ftdm_sangoma_isdn_process_stack_event ( ftdm_span_t * span , sngisdn_event_data_t * sngisdn_event )
{
ftdm_channel_t * ftdmchan = NULL ;
ftdmchan = ftdm_sangoma_isdn_process_event_states ( span , sngisdn_event ) ;
switch ( sngisdn_event - > event_id ) {
case SNGISDN_EVENT_CON_IND :
sngisdn_process_con_ind ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_CON_CFM :
sngisdn_process_con_cfm ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_CNST_IND :
sngisdn_process_cnst_ind ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_DISC_IND :
sngisdn_process_disc_ind ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_REL_IND :
sngisdn_process_rel_ind ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_DAT_IND :
sngisdn_process_dat_ind ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_SSHL_IND :
sngisdn_process_sshl_ind ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_SSHL_CFM :
sngisdn_process_sshl_cfm ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_RMRT_IND :
sngisdn_process_rmrt_ind ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_RMRT_CFM :
sngisdn_process_rmrt_cfm ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_FLC_IND :
sngisdn_process_flc_ind ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_FAC_IND :
sngisdn_process_fac_ind ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_STA_CFM :
sngisdn_process_sta_cfm ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_SRV_IND :
sngisdn_process_srv_ind ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_SRV_CFM :
sngisdn_process_srv_cfm ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_RST_CFM :
sngisdn_process_rst_cfm ( sngisdn_event ) ;
break ;
case SNGISDN_EVENT_RST_IND :
sngisdn_process_rst_ind ( sngisdn_event ) ;
break ;
}
2010-12-31 14:42:15 +00:00
if ( ftdmchan ! = NULL ) {
ftdm_channel_advance_states ( ftdmchan ) ;
2010-08-31 17:29:31 +00:00
ftdm_channel_unlock ( ftdmchan ) ;
}
}
2010-12-31 14:42:15 +00:00
/* this function is called with the channel already locked by the core */
static ftdm_status_t ftdm_sangoma_isdn_process_state_change ( ftdm_channel_t * ftdmchan )
2010-06-30 16:42:11 +00:00
{
2011-05-26 15:38:24 +00:00
ftdm_sigmsg_t sigev ;
ftdm_channel_state_t initial_state ;
sngisdn_chan_data_t * sngisdn_info = ftdmchan - > call_data ;
uint8_t state_change = 0 ;
2010-06-30 16:42:11 +00:00
memset ( & sigev , 0 , sizeof ( sigev ) ) ;
sigev . chan_id = ftdmchan - > chan_id ;
sigev . span_id = ftdmchan - > span_id ;
sigev . channel = ftdmchan ;
2010-08-31 17:29:31 +00:00
# ifdef FTDM_DEBUG_CHAN_MEMORY
if ( ftdmchan - > state = = FTDM_CHANNEL_STATE_DIALING ) {
2010-12-31 14:42:15 +00:00
ftdm_assert ( mprotect ( ftdmchan , sizeof ( * ftdmchan ) , PROT_READ ) = = 0 , " Failed to mprotect " ) ;
2010-08-31 17:29:31 +00:00
}
# endif
/* Only needed for debugging */
initial_state = ftdmchan - > state ;
2010-06-30 16:42:11 +00:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " processing state change to %s \n " , ftdm_channel_state2str ( ftdmchan - > state ) ) ;
switch ( ftdmchan - > state ) {
2010-08-31 17:29:31 +00:00
case FTDM_CHANNEL_STATE_COLLECT : /* SETUP received but waiting on digits */
2010-06-30 16:42:11 +00:00
{
2010-08-31 17:29:31 +00:00
/* TODO: Re-implement this. There is a way to re-evaluate new incoming digits from dialplan as they come */
sngisdn_snd_setup_ack ( ftdmchan ) ;
/* Just wait in this state until we get enough digits or T302 timeout */
}
break ;
case FTDM_CHANNEL_STATE_GET_CALLERID :
{
2011-05-26 15:38:24 +00:00
/* By default, we do not send a progress indicator in the proceed */
ftdm_sngisdn_progind_t prog_ind = { SNGISDN_PROGIND_LOC_USER , SNGISDN_PROGIND_DESCR_INVALID } ;
sngisdn_snd_proceed ( ftdmchan , prog_ind ) ;
/* Wait in this state until we get FACILITY msg */
2010-06-30 16:42:11 +00:00
}
break ;
case FTDM_CHANNEL_STATE_RING : /* incoming call request */
2011-05-26 15:38:24 +00:00
{
2010-06-30 16:42:11 +00:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_DEBUG , " Sending incoming call from %s to %s to FTDM core \n " , ftdmchan - > caller_data . ani . digits , ftdmchan - > caller_data . dnis . digits ) ;
2010-09-08 23:41:34 +00:00
2010-06-30 16:42:11 +00:00
/* we have enough information to inform FTDM of the call*/
2011-02-18 18:01:57 +00:00
sngisdn_send_signal ( sngisdn_info , FTDM_SIGEVENT_START ) ;
2010-06-30 16:42:11 +00:00
}
break ;
case FTDM_CHANNEL_STATE_DIALING : /* outgoing call request */
2010-11-11 00:03:15 +00:00
{
2012-04-03 20:48:14 +00:00
if ( FTDM_SPAN_IS_BRI ( ftdmchan - > span ) & & ftdm_test_flag ( ftdmchan - > span , FTDM_SPAN_PWR_SAVING ) ) {
ftdm_signaling_status_t sigstatus ;
ftdm_span_get_sig_status ( ftdmchan - > span , & sigstatus ) ;
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_IN_ALARM ) ) {
sngisdn_span_data_t * signal_data = ( sngisdn_span_data_t * ) ftdmchan - > span - > signal_data ;
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Requesting Physical Line activation \n " ) ;
sngisdn_set_flag ( sngisdn_info , FLAG_ACTIVATING ) ;
ftdm_sangoma_isdn_wakeup_phy ( ftdmchan ) ;
ftdm_sched_timer ( signal_data - > sched , " timer_t3 " , signal_data - > timer_t3 * 1000 , sngisdn_t3_timeout , ( void * ) sngisdn_info , NULL ) ;
} else if ( sigstatus = = FTDM_SIG_STATE_DOWN ) {
sngisdn_span_data_t * signal_data = ( sngisdn_span_data_t * ) ftdmchan - > span - > signal_data ;
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Requesting Q.921 Line activation \n " ) ;
sngisdn_set_flag ( sngisdn_info , FLAG_ACTIVATING ) ;
sngisdn_snd_info_req ( ftdmchan ) ;
ftdm_sched_timer ( signal_data - > sched , " timer_t3 " , signal_data - > timer_t3 * 1000 , sngisdn_t3_timeout , ( void * ) sngisdn_info , NULL ) ;
} else {
sngisdn_snd_setup ( ftdmchan ) ;
}
2010-11-11 00:03:15 +00:00
} else {
sngisdn_snd_setup ( ftdmchan ) ;
}
2010-06-30 16:42:11 +00:00
}
break ;
2010-11-25 01:04:43 +00:00
case FTDM_CHANNEL_STATE_PROCEED :
{
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OUTBOUND ) ) {
/*OUTBOUND...so we were told by the line of this so noifiy the user*/
2011-02-18 18:01:57 +00:00
sngisdn_send_signal ( sngisdn_info , FTDM_SIGEVENT_PROCEED ) ;
2011-01-20 15:42:28 +00:00
if ( sngisdn_test_flag ( sngisdn_info , FLAG_MEDIA_READY ) ) {
2011-03-02 15:59:43 +00:00
state_change + + ;
2011-01-20 15:42:28 +00:00
ftdm_set_state ( ftdmchan , FTDM_CHANNEL_STATE_PROGRESS_MEDIA ) ;
}
2010-11-25 01:04:43 +00:00
} else {
2011-05-26 15:38:24 +00:00
ftdm_sngisdn_progind_t prog_ind = { SNGISDN_PROGIND_LOC_USER , SNGISDN_PROGIND_DESCR_INVALID } ;
sngisdn_snd_proceed ( ftdmchan , prog_ind ) ;
2010-11-25 01:04:43 +00:00
}
}
break ;
case FTDM_CHANNEL_STATE_RINGING :
{
2010-12-15 16:45:50 +00:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OUTBOUND ) ) {
/* OUTBOUND...so we were told by the line of this so notify the user */
2011-02-18 18:01:57 +00:00
sngisdn_send_signal ( sngisdn_info , FTDM_SIGEVENT_RINGING ) ;
2010-12-15 16:45:50 +00:00
if ( sngisdn_test_flag ( sngisdn_info , FLAG_MEDIA_READY ) ) {
2011-03-02 15:59:43 +00:00
state_change + + ;
2010-12-15 16:45:50 +00:00
ftdm_set_state ( ftdmchan , FTDM_CHANNEL_STATE_PROGRESS_MEDIA ) ;
}
} else {
ftdm_sngisdn_progind_t prog_ind = { SNGISDN_PROGIND_LOC_USER , SNGISDN_PROGIND_DESCR_NETE_ISDN } ;
sngisdn_snd_alert ( ftdmchan , prog_ind ) ;
}
2010-11-25 01:04:43 +00:00
}
break ;
2010-06-30 16:42:11 +00:00
case FTDM_CHANNEL_STATE_PROGRESS :
{
/*check if the channel is inbound or outbound*/
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OUTBOUND ) ) {
/*OUTBOUND...so we were told by the line of this so noifiy the user*/
2011-02-18 18:01:57 +00:00
sngisdn_send_signal ( sngisdn_info , FTDM_SIGEVENT_PROGRESS ) ;
2010-11-25 01:04:43 +00:00
} else {
2010-12-14 21:04:25 +00:00
/* Send a progress message, indicating: Call is not end-to-end ISDN, further call progress may be available */
ftdm_sngisdn_progind_t prog_ind = { SNGISDN_PROGIND_LOC_USER , SNGISDN_PROGIND_DESCR_NETE_ISDN } ;
sngisdn_snd_progress ( ftdmchan , prog_ind ) ;
2010-06-30 16:42:11 +00:00
}
}
break ;
case FTDM_CHANNEL_STATE_PROGRESS_MEDIA :
{
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OUTBOUND ) ) {
2011-02-18 18:01:57 +00:00
sngisdn_send_signal ( sngisdn_info , FTDM_SIGEVENT_PROGRESS_MEDIA ) ;
2010-06-30 16:42:11 +00:00
} else {
2010-11-25 01:04:43 +00:00
/* Send a progress message, indicating: In-band information/pattern available */
2010-11-30 18:17:48 +00:00
ftdm_sngisdn_progind_t prog_ind = { SNGISDN_PROGIND_LOC_USER , SNGISDN_PROGIND_DESCR_IB_AVAIL } ;
sngisdn_snd_progress ( ftdmchan , prog_ind ) ;
2010-06-30 16:42:11 +00:00
}
}
break ;
case FTDM_CHANNEL_STATE_UP : /* call is answered */
{
2010-08-31 17:29:31 +00:00
/* check if the channel is inbound or outbound */
2010-06-30 16:42:11 +00:00
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OUTBOUND ) ) {
2010-08-31 17:29:31 +00:00
/* OUTBOUND ... so we were told by the line that the other side answered */
2011-02-18 18:01:57 +00:00
sngisdn_send_signal ( sngisdn_info , FTDM_SIGEVENT_UP ) ;
2010-08-31 17:29:31 +00:00
2010-06-30 16:42:11 +00:00
if ( ftdmchan - > span - > trunk_type = = FTDM_TRUNK_BRI_PTMP & &
( ( sngisdn_span_data_t * ) ftdmchan - > span - > signal_data ) - > signalling = = SNGISDN_SIGNALING_NET ) {
/* Assign the call to a specific equipment */
sngisdn_snd_con_complete ( ftdmchan ) ;
}
} else {
/* INBOUND ... so FS told us it just answered ... tell the stack */
sngisdn_snd_connect ( ftdmchan ) ;
}
}
break ;
case FTDM_CHANNEL_STATE_CANCEL :
{
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Hanging up call before informing user! \n " ) ;
/* Send a release complete */
2010-08-31 17:29:31 +00:00
sngisdn_snd_release ( ftdmchan , 0 ) ;
2010-06-30 16:42:11 +00:00
/*now go to the HANGUP complete state*/
2011-03-02 15:59:43 +00:00
state_change + + ;
2010-08-31 17:29:31 +00:00
ftdm_set_state ( ftdmchan , FTDM_CHANNEL_STATE_HANGUP_COMPLETE ) ;
2010-06-30 16:42:11 +00:00
}
break ;
case FTDM_CHANNEL_STATE_TERMINATING : /* call is hung up by the remote end */
{
/* this state is set when the line is hanging up */
2011-02-18 18:01:57 +00:00
sngisdn_send_signal ( sngisdn_info , FTDM_SIGEVENT_STOP ) ;
2010-06-30 16:42:11 +00:00
}
break ;
case FTDM_CHANNEL_STATE_HANGUP : /* call is hung up locally */
{
2010-08-31 17:29:31 +00:00
if ( sngisdn_test_flag ( sngisdn_info , FLAG_REMOTE_ABORT ) ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Acknowledging remote abort \n " ) ;
} else if ( sngisdn_test_flag ( sngisdn_info , FLAG_REMOTE_REL ) ) {
2010-06-30 16:42:11 +00:00
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Acknowledging remote hangup \n " ) ;
2010-08-31 17:29:31 +00:00
sngisdn_snd_release ( ftdmchan , 0 ) ;
} else if ( sngisdn_test_flag ( sngisdn_info , FLAG_LOCAL_ABORT ) ) {
/* We aborted this call before sending anything to the stack, so nothing to do anymore */
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Clearing local states from local abort \n " ) ;
} else if ( sngisdn_test_flag ( sngisdn_info , FLAG_GLARE ) ) {
/* We are hangup local call because there was a glare, we are waiting for a
RELEASE on this call , before we can process the saved call */
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Waiting for RELEASE on hungup glared call \n " ) ;
2010-09-07 17:28:30 +00:00
} else if ( sngisdn_test_flag ( sngisdn_info , FLAG_SEND_DISC ) ) {
/* Remote side sent a PROGRESS message, but cause indicates disconnect or T310 expired*/
sngisdn_snd_disconnect ( ftdmchan ) ;
2010-06-30 16:42:11 +00:00
} else {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Hanging up call upon local request! \n " ) ;
/* set the flag to indicate this hangup is started from the local side */
2010-08-31 17:29:31 +00:00
sngisdn_set_flag ( sngisdn_info , FLAG_LOCAL_REL ) ;
2010-06-30 16:42:11 +00:00
2011-01-07 20:39:25 +00:00
switch ( ftdmchan - > last_state ) {
case FTDM_CHANNEL_STATE_RING :
/* If we never sent PROCEED/ALERT/PROGRESS/CONNECT on an incoming call, we need to send release instead of disconnect */
sngisdn_set_flag ( sngisdn_info , FLAG_LOCAL_ABORT ) ;
sngisdn_snd_release ( ftdmchan , 0 ) ;
break ;
case FTDM_CHANNEL_STATE_DIALING :
/* If we never received a PROCEED/ALERT/PROGRESS/CONNECT on an outgoing call, we need to send release instead of disconnect */
sngisdn_snd_release ( ftdmchan , 0 ) ;
break ;
2011-02-01 20:41:23 +00:00
case FTDM_CHANNEL_STATE_PROCEED :
2011-02-04 23:22:53 +00:00
if ( ! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OUTBOUND ) ) {
if ( ( ( sngisdn_span_data_t * ) ( ftdmchan - > span - > signal_data ) ) - > switchtype = = SNGISDN_SWITCH_4ESS | |
( ( sngisdn_span_data_t * ) ( ftdmchan - > span - > signal_data ) ) - > switchtype = = SNGISDN_SWITCH_5ESS ) {
2011-02-01 20:41:23 +00:00
2011-02-04 23:22:53 +00:00
/* When using 5ESS, if the user wants to clear an inbound call, the correct procedure is to send a PROGRESS with in-band info available, and play tones. Then send a DISCONNECT. If we reached this point, it means user did not try to play-tones, so send a RELEASE because remote side does not expect DISCONNECT in state 3 */
sngisdn_snd_release ( ftdmchan , 0 ) ;
break ;
}
2011-02-01 20:41:23 +00:00
}
/* fall-through */
2011-01-07 20:39:25 +00:00
default :
sngisdn_snd_disconnect ( ftdmchan ) ;
break ;
2010-06-30 16:42:11 +00:00
}
}
/* now go to the HANGUP complete state */
2011-03-02 15:59:43 +00:00
state_change + + ;
2010-08-31 17:29:31 +00:00
ftdm_set_state ( ftdmchan , FTDM_CHANNEL_STATE_HANGUP_COMPLETE ) ;
2010-06-30 16:42:11 +00:00
}
break ;
case FTDM_CHANNEL_STATE_HANGUP_COMPLETE :
{
2010-08-31 17:29:31 +00:00
if ( sngisdn_test_flag ( sngisdn_info , FLAG_REMOTE_ABORT ) | |
sngisdn_test_flag ( sngisdn_info , FLAG_LOCAL_ABORT ) ) {
2010-06-30 16:42:11 +00:00
/* If the remote side aborted, we will not get anymore message for this call */
2011-03-02 15:59:43 +00:00
state_change + + ;
2010-08-31 17:29:31 +00:00
ftdm_set_state ( ftdmchan , FTDM_CHANNEL_STATE_DOWN ) ;
2010-06-30 16:42:11 +00:00
} else {
2010-08-31 17:29:31 +00:00
/* waiting on remote confirmation before moving to down */
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Waiting for release from stack \n " ) ;
2010-06-30 16:42:11 +00:00
}
}
break ;
case FTDM_CHANNEL_STATE_DOWN : /* the call is finished and removed */
{
2010-11-30 21:45:05 +00:00
uint8_t glare = sngisdn_test_flag ( sngisdn_info , FLAG_GLARE ) ;
2010-08-31 17:29:31 +00:00
/* clear all of the call specific data store in the channel structure */
clear_call_data ( sngisdn_info ) ;
2010-06-30 16:42:11 +00:00
2010-08-31 17:29:31 +00:00
/* Close the channel even if we had a glare, we will re-open it when processing state COLLECT for the
" glared call " */
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_OPEN ) ) {
ftdm_channel_t * close_chan = ftdmchan ;
2010-06-30 16:42:11 +00:00
/* close the channel */
2010-08-31 17:29:31 +00:00
ftdm_channel_close ( & close_chan ) ;
}
if ( glare ) {
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_DEBUG , " Glare detected, processing saved call \n " ) ;
/* We are calling sngisdn_rcv_con_ind with ftdmchan->mutex being locked,
so no other threads will be able to touch this channel . The next time we will
process this channel is in this function , and it should be in state COLLECT ( set inside
sngisdn_rcv_con_ind ) */
sngisdn_rcv_con_ind ( sngisdn_info - > glare . suId , sngisdn_info - > glare . suInstId , sngisdn_info - > glare . spInstId , & sngisdn_info - > glare . setup , sngisdn_info - > glare . dChan , sngisdn_info - > glare . ces ) ;
2010-06-30 16:42:11 +00:00
}
}
break ;
2011-05-26 15:38:24 +00:00
case FTDM_CHANNEL_STATE_TRANSFER :
{
/* sngisdn_transfer function will always result in a state change */
sngisdn_transfer ( ftdmchan ) ;
state_change + + ;
}
break ;
2010-06-30 16:42:11 +00:00
case FTDM_CHANNEL_STATE_RESTART :
{
2010-08-31 17:29:31 +00:00
/* IMPLEMENT ME */
2010-06-30 16:42:11 +00:00
}
break ;
case FTDM_CHANNEL_STATE_SUSPENDED :
{
2010-08-31 17:29:31 +00:00
/* IMPLEMENT ME */
2010-06-30 16:42:11 +00:00
}
break ;
2010-12-14 16:23:47 +00:00
case FTDM_CHANNEL_STATE_RESET :
{
sngisdn_snd_restart ( ftdmchan ) ;
}
break ;
2010-06-30 16:42:11 +00:00
default :
{
2010-08-31 17:29:31 +00:00
ftdm_log_chan ( ftdmchan , FTDM_LOG_CRIT , " unsupported sngisdn_rcvd state %s \n " , ftdm_channel_state2str ( ftdmchan - > state ) ) ;
2010-06-30 16:42:11 +00:00
}
break ;
}
2011-02-18 18:01:57 +00:00
2011-03-02 15:59:43 +00:00
if ( ! state_change ) {
/* Acknowledge the state change */
ftdm_channel_complete_state ( ftdmchan ) ;
}
2011-02-25 14:58:15 +00:00
2011-02-18 18:01:57 +00:00
/* If sngisdn_info->variables is not NULL, it means did not send any
2011-02-25 14:58:15 +00:00
* sigevent to the user , therefore we have to free that hashtable */
2011-02-18 18:01:57 +00:00
if ( sngisdn_info - > variables ) {
hashtable_destroy ( sngisdn_info - > variables ) ;
sngisdn_info - > variables = NULL ;
}
/* If sngisdn_info->raw_data is not NULL, it means did not send any
2011-02-25 14:58:15 +00:00
* sigevent to the user , therefore we have to free that raw data */
2011-02-18 18:01:57 +00:00
if ( sngisdn_info - > raw_data ) {
ftdm_safe_free ( sngisdn_info - > raw_data ) ;
sngisdn_info - > raw_data = NULL ;
sngisdn_info - > raw_data_len = 0 ;
}
2010-08-31 17:29:31 +00:00
if ( ftdmchan - > state = = initial_state ) {
ftdm_assert ( ! ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_STATE_CHANGE ) , " state change flag is still set, but we did not change state \n " ) ;
}
# ifdef FTDM_DEBUG_CHAN_MEMORY
if ( ftdmchan - > state = = FTDM_CHANNEL_STATE_DIALING ) {
2010-12-31 14:42:15 +00:00
ftdm_assert ( mprotect ( ftdmchan , sizeof ( * ftdmchan ) , PROT_READ | PROT_WRITE ) = = 0 , " Failed to mprotect " ) ;
2010-08-31 17:29:31 +00:00
}
# endif
2010-12-31 14:42:15 +00:00
return FTDM_SUCCESS ;
2010-06-30 16:42:11 +00:00
}
2011-02-25 14:58:15 +00:00
static FIO_CHANNEL_INDICATE_FUNCTION ( ftdm_sangoma_isdn_indicate )
2010-12-09 18:20:05 +00:00
{
ftdm_status_t status = FTDM_FAIL ;
2011-02-25 14:58:15 +00:00
switch ( indication ) {
case FTDM_CHANNEL_INDICATE_FACILITY :
2010-12-09 18:20:05 +00:00
sngisdn_snd_fac_req ( ftdmchan ) ;
2010-12-23 17:41:12 +00:00
status = FTDM_SUCCESS ;
2010-12-09 18:20:05 +00:00
break ;
default :
2011-02-25 14:58:15 +00:00
status = FTDM_NOTIMPL ;
2011-02-18 18:01:57 +00:00
}
2010-12-09 18:20:05 +00:00
return status ;
}
2010-06-30 16:42:11 +00:00
static FIO_CHANNEL_OUTGOING_CALL_FUNCTION ( ftdm_sangoma_isdn_outgoing_call )
{
2010-08-31 17:29:31 +00:00
sngisdn_chan_data_t * sngisdn_info = ftdmchan - > call_data ;
ftdm_status_t status = FTDM_FAIL ;
2010-06-30 16:42:11 +00:00
2011-02-18 18:01:57 +00:00
if ( ftdmchan - > state = = FTDM_CHANNEL_STATE_DOWN ) {
if ( sngisdn_test_flag ( sngisdn_info , FLAG_GLARE ) ) {
/* A call came in after we called ftdm_channel_open_chan for this call, but before we got here */
ftdm_log_chan_msg ( ftdmchan , FTDM_LOG_WARNING , " Glare detected - aborting outgoing call \n " ) ;
2010-06-30 16:42:11 +00:00
2011-02-18 18:01:57 +00:00
sngisdn_set_flag ( sngisdn_info , FLAG_LOCAL_ABORT ) ;
ftdm_set_state ( ftdmchan , FTDM_CHANNEL_STATE_HANGUP_COMPLETE ) ;
2010-06-30 16:42:11 +00:00
2010-08-31 17:29:31 +00:00
status = FTDM_BREAK ;
2011-02-18 18:01:57 +00:00
} else {
status = FTDM_SUCCESS ;
2010-06-30 16:42:11 +00:00
}
2011-02-18 18:01:57 +00:00
} else {
/* the channel is already used...this can't be, end the request */
ftdm_log_chan ( ftdmchan , FTDM_LOG_WARNING , " Outgoing call requested channel in already in use (%s) \n " , ftdm_channel_state2str ( ftdmchan - > state ) ) ;
status = FTDM_BREAK ;
2010-06-30 16:42:11 +00:00
}
2011-02-18 18:01:57 +00:00
2010-08-31 17:29:31 +00:00
return status ;
2010-06-30 16:42:11 +00:00
}
2010-09-08 23:41:34 +00:00
static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION ( ftdm_sangoma_isdn_get_chan_sig_status )
2010-06-30 16:42:11 +00:00
{
if ( ftdm_test_flag ( ftdmchan , FTDM_CHANNEL_SIG_UP ) ) {
* status = FTDM_SIG_STATE_UP ;
} else {
* status = FTDM_SIG_STATE_DOWN ;
}
return FTDM_SUCCESS ;
}
2010-09-08 23:41:34 +00:00
static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION ( ftdm_sangoma_isdn_set_chan_sig_status )
2010-06-30 16:42:11 +00:00
{
ftdm_log ( FTDM_LOG_ERROR , " Cannot set channel status in this module \n " ) ;
return FTDM_NOTIMPL ;
}
2010-09-08 23:41:34 +00:00
static FIO_SPAN_GET_SIG_STATUS_FUNCTION ( ftdm_sangoma_isdn_get_span_sig_status )
{
if ( ftdm_test_flag ( span - > channels [ 1 ] , FTDM_CHANNEL_SIG_UP ) ) {
* status = FTDM_SIG_STATE_UP ;
} else {
* status = FTDM_SIG_STATE_DOWN ;
}
return FTDM_SUCCESS ;
}
static FIO_SPAN_SET_SIG_STATUS_FUNCTION ( ftdm_sangoma_isdn_set_span_sig_status )
{
ftdm_log ( FTDM_LOG_ERROR , " Cannot set span status in this module \n " ) ;
return FTDM_NOTIMPL ;
}
2011-05-26 15:38:24 +00:00
static ftdm_status_t ftdm_sangoma_isdn_dtmf ( ftdm_channel_t * ftdmchan , const char * dtmf )
{
sngisdn_chan_data_t * sngisdn_info = ftdmchan - > call_data ;
switch ( sngisdn_info - > transfer_data . type ) {
case SNGISDN_TRANSFER_ATT_COURTESY_VRU :
case SNGISDN_TRANSFER_ATT_COURTESY_VRU_DATA :
return sngisdn_att_transfer_process_dtmf ( ftdmchan , dtmf ) ;
default :
/* We do not care about DTMF events, do nothing */
break ;
}
return FTDM_SUCCESS ;
}
2012-06-07 00:41:48 +00:00
static ftdm_status_t ftdm_sangoma_isdn_perform_start ( ftdm_span_t * span )
2010-12-15 21:29:03 +00:00
{
sngisdn_span_data_t * signal_data = span - > signal_data ;
2011-07-15 18:48:24 +00:00
2012-06-07 00:41:48 +00:00
ftdm_log ( FTDM_LOG_DEBUG , " Actually starting span:%s \n " , span - > name ) ;
2010-06-30 16:42:11 +00:00
/* clear the monitor thread stop flag */
ftdm_clear_flag ( span , FTDM_SPAN_STOP_THREAD ) ;
ftdm_clear_flag ( span , FTDM_SPAN_IN_THREAD ) ;
2011-04-20 18:44:47 +00:00
if ( signal_data - > trace_q921 = = SNGISDN_OPT_TRUE | |
signal_data - > raw_trace_q921 = = SNGISDN_OPT_TRUE ) {
2010-12-15 21:29:03 +00:00
sngisdn_activate_trace ( span , SNGISDN_TRACE_Q921 ) ;
}
2011-04-20 18:44:47 +00:00
if ( signal_data - > trace_q931 = = SNGISDN_OPT_TRUE | |
signal_data - > raw_trace_q931 = = SNGISDN_OPT_TRUE ) {
2010-12-15 21:29:03 +00:00
sngisdn_activate_trace ( span , SNGISDN_TRACE_Q931 ) ;
}
2010-06-30 16:42:11 +00:00
/*start the span monitor thread*/
if ( ftdm_thread_create_detached ( ftdm_sangoma_isdn_run , span ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_CRIT , " Failed to start Sangoma ISDN Span Monitor Thread! \n " ) ;
return FTDM_FAIL ;
}
2010-11-11 00:03:15 +00:00
/*start the dchan monitor thread*/
2011-05-26 15:38:24 +00:00
if ( ftdm_thread_create_detached ( ftdm_sangoma_isdn_io_run , span ) ! = FTDM_SUCCESS ) {
2010-11-11 00:03:15 +00:00
ftdm_log ( FTDM_LOG_CRIT , " Failed to start Sangoma ISDN d-channel Monitor Thread! \n " ) ;
return FTDM_FAIL ;
}
2011-07-15 21:56:41 +00:00
if ( signal_data - > restart_timeout ) {
ftdm_log ( FTDM_LOG_DEBUG , " %s:Scheduling Restart timeout \n " , signal_data - > ftdm_span - > name ) ;
ftdm_sched_timer ( signal_data - > sched , " restart_timeout " , signal_data - > restart_timeout ,
2012-06-07 00:41:48 +00:00
sngisdn_restart_timeout , ( void * ) signal_data , & signal_data - > timers [ SNGISDN_SPAN_TIMER_RESTART ] ) ;
2011-07-15 21:56:41 +00:00
}
2012-06-07 00:41:48 +00:00
2010-06-30 16:42:11 +00:00
ftdm_log ( FTDM_LOG_DEBUG , " Finished starting span %s \n " , span - > name ) ;
return FTDM_SUCCESS ;
}
2012-06-07 00:41:48 +00:00
static ftdm_status_t ftdm_sangoma_isdn_start ( ftdm_span_t * span )
{
sngisdn_span_data_t * signal_data = span - > signal_data ;
ftdm_log ( FTDM_LOG_INFO , " Starting span %s:%u. \n " , span - > name , span - > span_id ) ;
if ( signal_data - > dchan ) {
ftdm_channel_set_feature ( signal_data - > dchan , FTDM_CHANNEL_FEATURE_IO_STATS ) ;
ftdm_channel_open_chan ( signal_data - > dchan ) ;
ftdm_sangoma_isdn_dchan_set_queue_size ( signal_data - > dchan ) ;
}
if ( signal_data - > nfas . trunk ) {
if ( signal_data - > nfas . trunk - > num_spans = = signal_data - > nfas . trunk - > num_spans_configured ) {
int i ;
ftdm_log ( FTDM_LOG_DEBUG , " Starting span for all spans within trunkgroup:%s \n " , signal_data - > nfas . trunk - > name ) ;
sngisdn_stack_start ( signal_data - > nfas . trunk - > dchan - > ftdm_span ) ;
ftdm_sangoma_isdn_perform_start ( signal_data - > nfas . trunk - > dchan - > ftdm_span ) ;
if ( signal_data - > nfas . trunk - > backup ) {
sngisdn_stack_start ( signal_data - > nfas . trunk - > backup - > ftdm_span ) ;
ftdm_sangoma_isdn_perform_start ( signal_data - > nfas . trunk - > backup - > ftdm_span ) ;
}
for ( i = 0 ; i < signal_data - > nfas . trunk - > num_spans ; i + + ) {
if ( signal_data - > nfas . trunk - > spans [ i ] & &
signal_data - > nfas . trunk - > spans [ i ] - > nfas . sigchan = = SNGISDN_NFAS_DCHAN_NONE ) {
sngisdn_stack_start ( signal_data - > nfas . trunk - > spans [ i ] - > ftdm_span ) ;
ftdm_sangoma_isdn_perform_start ( signal_data - > nfas . trunk - > spans [ i ] - > ftdm_span ) ;
}
}
return FTDM_SUCCESS ;
} else {
ftdm_log ( FTDM_LOG_DEBUG , " Delaying span start until all spans within trunkgroup are started: %s \n " , signal_data - > nfas . trunk - > name ) ;
return FTDM_SUCCESS ;
}
}
if ( sngisdn_stack_start ( span ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_CRIT , " Failed to start span %s \n " , span - > name ) ;
return FTDM_FAIL ;
}
ftdm_sangoma_isdn_perform_start ( span ) ;
return FTDM_SUCCESS ;
}
2010-06-30 16:42:11 +00:00
static ftdm_status_t ftdm_sangoma_isdn_stop ( ftdm_span_t * span )
2010-09-30 15:41:47 +00:00
{
2010-09-08 23:41:34 +00:00
ftdm_iterator_t * chaniter = NULL ;
ftdm_iterator_t * curr = NULL ;
2010-09-30 15:41:47 +00:00
unsigned i ;
sngisdn_span_data_t * signal_data = ( sngisdn_span_data_t * ) span - > signal_data ;
2010-06-30 16:42:11 +00:00
ftdm_log ( FTDM_LOG_INFO , " Stopping span %s \n " , span - > name ) ;
/* throw the STOP_THREAD flag to signal monitor thread stop */
ftdm_set_flag ( span , FTDM_SPAN_STOP_THREAD ) ;
/* wait for the thread to stop */
while ( ftdm_test_flag ( span , FTDM_SPAN_IN_THREAD ) ) {
ftdm_log ( FTDM_LOG_DEBUG , " Waiting for monitor thread to end for span %s \n " , span - > name ) ;
ftdm_sleep ( 10 ) ;
}
2010-11-11 00:03:15 +00:00
if ( sngisdn_stack_stop ( span ) ! = FTDM_SUCCESS ) {
2010-09-08 23:41:34 +00:00
ftdm_log ( FTDM_LOG_CRIT , " Failed to stop span %s \n " , span - > name ) ;
}
chaniter = ftdm_span_get_chan_iterator ( span , NULL ) ;
for ( curr = chaniter ; curr ; curr = ftdm_iterator_next ( curr ) ) {
ftdm_safe_free ( ( ( ftdm_channel_t * ) ftdm_iterator_current ( curr ) ) - > call_data ) ;
( ( ftdm_channel_t * ) ftdm_iterator_current ( curr ) ) - > call_data = NULL ;
2010-06-30 16:42:11 +00:00
}
2010-09-08 23:41:34 +00:00
ftdm_iterator_free ( chaniter ) ;
2010-09-30 15:41:47 +00:00
ftdm_sched_destroy ( & signal_data - > sched ) ;
ftdm_queue_destroy ( & signal_data - > event_queue ) ;
for ( i = 0 ; i < signal_data - > num_local_numbers ; i + + ) {
if ( signal_data - > local_numbers [ i ] ! = NULL ) {
ftdm_safe_free ( signal_data - > local_numbers [ i ] ) ;
}
}
2010-06-30 16:42:11 +00:00
ftdm_safe_free ( span - > signal_data ) ;
ftdm_log ( FTDM_LOG_DEBUG , " Finished stopping span %s \n " , span - > name ) ;
return FTDM_SUCCESS ;
}
static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION ( ftdm_sangoma_isdn_span_config )
{
2010-09-08 23:41:34 +00:00
ftdm_iterator_t * chaniter = NULL ;
ftdm_iterator_t * curr = NULL ;
2012-06-07 00:41:48 +00:00
sngisdn_span_data_t * signal_data ;
2010-06-30 16:42:11 +00:00
ftdm_log ( FTDM_LOG_INFO , " Configuring ftmod_sangoma_isdn span = %s \n " , span - > name ) ;
2012-06-07 00:41:48 +00:00
signal_data = ftdm_calloc ( 1 , sizeof ( sngisdn_span_data_t ) ) ;
signal_data - > ftdm_span = span ;
span - > signal_data = signal_data ;
2010-09-08 23:41:34 +00:00
chaniter = ftdm_span_get_chan_iterator ( span , NULL ) ;
for ( curr = chaniter ; curr ; curr = ftdm_iterator_next ( curr ) ) {
2010-06-30 16:42:11 +00:00
sngisdn_chan_data_t * chan_data = ftdm_calloc ( 1 , sizeof ( sngisdn_chan_data_t ) ) ;
2010-09-08 23:41:34 +00:00
chan_data - > ftdmchan = ( ( ftdm_channel_t * ) ftdm_iterator_current ( curr ) ) ;
( ( ftdm_channel_t * ) ftdm_iterator_current ( curr ) ) - > call_data = chan_data ;
2010-06-30 16:42:11 +00:00
}
2010-09-08 23:41:34 +00:00
ftdm_iterator_free ( chaniter ) ;
2010-06-30 16:42:11 +00:00
if ( ftmod_isdn_parse_cfg ( ftdm_parameters , span ) ! = FTDM_SUCCESS ) {
ftdm_log ( FTDM_LOG_ERROR , " Failed to parse configuration \n " ) ;
return FTDM_FAIL ;
}
2012-06-07 00:41:48 +00:00
if ( signal_data - > nfas . trunk ) {
if ( signal_data - > nfas . trunk - > num_spans = = + + signal_data - > nfas . trunk - > num_spans_configured ) {
int i ;
ftdm_log ( FTDM_LOG_DEBUG , " Starting stack configuration for all spans within trunkgroup:%s \n " , signal_data - > nfas . trunk - > name ) ;
sngisdn_stack_cfg ( signal_data - > nfas . trunk - > dchan - > ftdm_span ) ;
if ( signal_data - > nfas . trunk - > backup ) {
sngisdn_stack_cfg ( signal_data - > nfas . trunk - > backup - > ftdm_span ) ;
}
for ( i = 0 ; i < signal_data - > nfas . trunk - > num_spans ; i + + ) {
if ( signal_data - > nfas . trunk - > spans [ i ] & &
signal_data - > nfas . trunk - > spans [ i ] - > nfas . sigchan = = SNGISDN_NFAS_DCHAN_NONE ) {
sngisdn_stack_cfg ( signal_data - > nfas . trunk - > spans [ i ] - > ftdm_span ) ;
}
}
} else {
ftdm_log ( FTDM_LOG_DEBUG , " Delaying span stack configuration until all spans within trunkgroup are started:%s \n " , signal_data - > nfas . trunk - > name ) ;
}
} else if ( sngisdn_stack_cfg ( span ) ! = FTDM_SUCCESS ) {
2010-06-30 16:42:11 +00:00
ftdm_log ( FTDM_LOG_CRIT , " Sangoma ISDN Stack configuration failed \n " ) ;
return FTDM_FAIL ;
}
2012-06-07 00:41:48 +00:00
if ( signal_data - > cid_name_method = = SNGISDN_CID_NAME_AUTO ) {
switch ( signal_data - > switchtype ) {
2011-11-03 23:23:00 +00:00
case SNGISDN_SWITCH_EUROISDN :
if ( FTDM_SPAN_IS_BRI ( span ) ) {
2012-06-07 00:41:48 +00:00
signal_data - > cid_name_method = SNGISDN_CID_NAME_USR_USR_IE ;
2011-11-03 23:23:00 +00:00
} else {
2012-06-07 00:41:48 +00:00
signal_data - > cid_name_method = SNGISDN_CID_NAME_DISPLAY_IE ;
2011-11-03 23:23:00 +00:00
}
break ;
case SNGISDN_SWITCH_DMS100 :
2012-06-07 00:41:48 +00:00
signal_data - > cid_name_method = SNGISDN_CID_NAME_DISPLAY_IE ;
2011-11-03 23:23:00 +00:00
break ;
case SNGISDN_SWITCH_NI2 :
case SNGISDN_SWITCH_5ESS :
case SNGISDN_SWITCH_4ESS :
2012-06-07 00:41:48 +00:00
signal_data - > cid_name_method = SNGISDN_CID_NAME_FACILITY_IE ;
2011-11-03 23:23:00 +00:00
break ;
default :
break ;
}
}
2012-06-07 00:41:48 +00:00
if ( signal_data - > send_cid_name = = SNGISDN_OPT_DEFAULT ) {
switch ( signal_data - > switchtype ) {
2011-11-03 23:23:00 +00:00
case SNGISDN_SWITCH_EUROISDN :
# ifdef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY
case SNGISDN_SWITCH_NI2 :
case SNGISDN_SWITCH_5ESS :
case SNGISDN_SWITCH_4ESS :
# endif
2012-06-07 00:41:48 +00:00
if ( signal_data - > signalling = = SNGISDN_SIGNALING_NET ) {
signal_data - > send_cid_name = SNGISDN_OPT_TRUE ;
2011-11-03 23:23:00 +00:00
} else {
2012-06-07 00:41:48 +00:00
signal_data - > send_cid_name = SNGISDN_OPT_FALSE ;
2011-11-03 23:23:00 +00:00
}
break ;
case SNGISDN_SWITCH_DMS100 :
2012-06-07 00:41:48 +00:00
signal_data - > send_cid_name = SNGISDN_OPT_TRUE ;
2011-11-03 23:23:00 +00:00
break ;
# ifndef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY
case SNGISDN_SWITCH_NI2 :
case SNGISDN_SWITCH_5ESS :
case SNGISDN_SWITCH_4ESS :
2012-06-07 00:41:48 +00:00
signal_data - > send_cid_name = SNGISDN_OPT_FALSE ;
2011-11-03 23:23:00 +00:00
break ;
# endif
default :
2012-06-07 00:41:48 +00:00
signal_data - > send_cid_name = SNGISDN_OPT_FALSE ;
2011-11-03 23:23:00 +00:00
break ;
}
2012-06-07 00:41:48 +00:00
} else if ( signal_data - > send_cid_name = = SNGISDN_OPT_TRUE ) {
switch ( signal_data - > switchtype ) {
2011-11-03 23:23:00 +00:00
case SNGISDN_SWITCH_NI2 :
case SNGISDN_SWITCH_5ESS :
case SNGISDN_SWITCH_4ESS :
# ifndef SNGISDN_SUPPORT_CALLING_NAME_IN_FACILITY
ftdm_log ( FTDM_LOG_WARNING , " Sending Calling Name in Facility IE not supported, please update your libsng_isdn library \n " ) ;
2012-06-07 00:41:48 +00:00
signal_data - > send_cid_name = SNGISDN_OPT_FALSE ;
2011-11-03 23:23:00 +00:00
# endif
break ;
case SNGISDN_SWITCH_INSNET : /* Don't know how to transmit caller ID name on INSNET */
case SNGISDN_SWITCH_QSIG : /* It seems like QSIG does not support Caller ID */
2012-06-07 00:41:48 +00:00
signal_data - > send_cid_name = SNGISDN_OPT_FALSE ;
2011-11-03 23:23:00 +00:00
break ;
case SNGISDN_SWITCH_EUROISDN :
break ;
default :
2012-06-07 00:41:48 +00:00
signal_data - > send_cid_name = SNGISDN_OPT_FALSE ;
2011-11-03 23:23:00 +00:00
break ;
}
}
2010-06-30 16:42:11 +00:00
span - > start = ftdm_sangoma_isdn_start ;
span - > stop = ftdm_sangoma_isdn_stop ;
span - > signal_type = FTDM_SIGTYPE_ISDN ;
span - > outgoing_call = ftdm_sangoma_isdn_outgoing_call ;
2011-02-25 14:58:15 +00:00
span - > indicate = ftdm_sangoma_isdn_indicate ;
2010-06-30 16:42:11 +00:00
span - > channel_request = NULL ;
span - > signal_cb = sig_cb ;
2011-05-26 15:38:24 +00:00
span - > sig_dtmf = ftdm_sangoma_isdn_dtmf ;
2010-09-08 23:41:34 +00:00
span - > get_channel_sig_status = ftdm_sangoma_isdn_get_chan_sig_status ;
span - > set_channel_sig_status = ftdm_sangoma_isdn_set_chan_sig_status ;
span - > get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status ;
span - > set_span_sig_status = ftdm_sangoma_isdn_set_span_sig_status ;
2010-06-30 16:42:11 +00:00
span - > state_map = & sangoma_isdn_state_map ;
2010-12-31 14:42:15 +00:00
span - > state_processor = ftdm_sangoma_isdn_process_state_change ;
2010-06-30 16:42:11 +00:00
ftdm_set_flag ( span , FTDM_SPAN_USE_CHAN_QUEUE ) ;
2010-08-31 23:05:37 +00:00
ftdm_set_flag ( span , FTDM_SPAN_USE_SIGNALS_QUEUE ) ;
2010-11-25 01:04:43 +00:00
ftdm_set_flag ( span , FTDM_SPAN_USE_PROCEED_STATE ) ;
2010-12-09 23:01:31 +00:00
ftdm_set_flag ( span , FTDM_SPAN_USE_SKIP_STATES ) ;
2011-01-10 22:46:18 +00:00
ftdm_set_flag ( span , FTDM_SPAN_NON_STOPPABLE ) ;
2011-05-26 15:38:24 +00:00
ftdm_set_flag ( span , FTDM_SPAN_USE_TRANSFER ) ;
2010-06-30 16:42:11 +00:00
2011-05-26 15:38:24 +00:00
if ( FTDM_SPAN_IS_BRI ( span ) ) {
2010-12-14 16:23:47 +00:00
sngisdn_set_span_avail_rate ( span , SNGISDN_AVAIL_PWR_SAVING ) ;
2010-08-31 17:29:31 +00:00
}
/* Initialize scheduling context */
ftdm_assert ( ftdm_sched_create ( & ( ( sngisdn_span_data_t * ) span - > signal_data ) - > sched , " sngisdn_schedule " ) = = FTDM_SUCCESS , " Failed to create a new schedule!! " ) ;
/* Initialize the event queue */
ftdm_assert ( ftdm_queue_create ( & ( ( sngisdn_span_data_t * ) span - > signal_data ) - > event_queue , SNGISDN_EVENT_QUEUE_SIZE ) = = FTDM_SUCCESS , " Failed to create a new queue!! " ) ;
2010-06-30 16:42:11 +00:00
ftdm_log ( FTDM_LOG_INFO , " Finished configuring ftmod_sangoma_isdn span = %s \n " , span - > name ) ;
return FTDM_SUCCESS ;
}
static FIO_SIG_LOAD_FUNCTION ( ftdm_sangoma_isdn_init )
{
unsigned i ;
ftdm_log ( FTDM_LOG_INFO , " Loading ftmod_sangoma_isdn... \n " ) ;
memset ( & g_sngisdn_data , 0 , sizeof ( g_sngisdn_data ) ) ;
2010-11-11 23:43:53 +00:00
memset ( & g_sngisdn_event_interface , 0 , sizeof ( g_sngisdn_event_interface ) ) ;
2010-06-30 16:42:11 +00:00
/* set callbacks */
g_sngisdn_event_interface . cc . sng_con_ind = sngisdn_rcv_con_ind ;
g_sngisdn_event_interface . cc . sng_con_cfm = sngisdn_rcv_con_cfm ;
g_sngisdn_event_interface . cc . sng_cnst_ind = sngisdn_rcv_cnst_ind ;
g_sngisdn_event_interface . cc . sng_disc_ind = sngisdn_rcv_disc_ind ;
g_sngisdn_event_interface . cc . sng_rel_ind = sngisdn_rcv_rel_ind ;
g_sngisdn_event_interface . cc . sng_dat_ind = sngisdn_rcv_dat_ind ;
g_sngisdn_event_interface . cc . sng_sshl_ind = sngisdn_rcv_sshl_ind ;
g_sngisdn_event_interface . cc . sng_sshl_cfm = sngisdn_rcv_sshl_cfm ;
g_sngisdn_event_interface . cc . sng_rmrt_ind = sngisdn_rcv_rmrt_ind ;
g_sngisdn_event_interface . cc . sng_rmrt_cfm = sngisdn_rcv_rmrt_cfm ;
g_sngisdn_event_interface . cc . sng_flc_ind = sngisdn_rcv_flc_ind ;
g_sngisdn_event_interface . cc . sng_fac_ind = sngisdn_rcv_fac_ind ;
g_sngisdn_event_interface . cc . sng_sta_cfm = sngisdn_rcv_sta_cfm ;
g_sngisdn_event_interface . cc . sng_srv_ind = sngisdn_rcv_srv_ind ;
2011-05-11 21:33:45 +00:00
g_sngisdn_event_interface . cc . sng_srv_cfm = sngisdn_rcv_srv_cfm ;
2010-06-30 16:42:11 +00:00
g_sngisdn_event_interface . cc . sng_rst_ind = sngisdn_rcv_rst_ind ;
2011-05-11 21:33:45 +00:00
g_sngisdn_event_interface . cc . sng_rst_cfm = sngisdn_rcv_rst_cfm ;
2010-06-30 16:42:11 +00:00
2010-08-31 17:29:31 +00:00
g_sngisdn_event_interface . lg . sng_log = sngisdn_rcv_sng_log ;
g_sngisdn_event_interface . lg . sng_assert = sngisdn_rcv_sng_assert ;
2010-06-30 16:42:11 +00:00
g_sngisdn_event_interface . sta . sng_phy_sta_ind = sngisdn_rcv_phy_ind ;
g_sngisdn_event_interface . sta . sng_q921_sta_ind = sngisdn_rcv_q921_ind ;
g_sngisdn_event_interface . sta . sng_q921_trc_ind = sngisdn_rcv_q921_trace ;
g_sngisdn_event_interface . sta . sng_q931_sta_ind = sngisdn_rcv_q931_ind ;
g_sngisdn_event_interface . sta . sng_q931_trc_ind = sngisdn_rcv_q931_trace ;
2010-11-11 00:03:15 +00:00
g_sngisdn_event_interface . sta . sng_cc_sta_ind = sngisdn_rcv_cc_ind ;
2010-11-15 19:13:01 +00:00
g_sngisdn_event_interface . io . sng_l1_data_req = sngisdn_rcv_l1_data_req ;
g_sngisdn_event_interface . io . sng_l1_cmd_req = sngisdn_rcv_l1_cmd_req ;
2010-11-11 23:43:53 +00:00
2010-06-30 16:42:11 +00:00
for ( i = 1 ; i < = MAX_VARIANTS ; i + + ) {
2010-08-31 17:29:31 +00:00
ftdm_mutex_create ( & g_sngisdn_data . ccs [ i ] . mutex ) ;
2010-06-30 16:42:11 +00:00
}
2010-09-08 23:41:34 +00:00
2010-06-30 16:42:11 +00:00
/* initalize sng_isdn library */
2010-11-01 14:24:11 +00:00
2010-11-11 00:03:15 +00:00
ftdm_assert_return ( ! sng_isdn_init ( & g_sngisdn_event_interface ) , FTDM_FAIL , " Failed to initialize stack \n " ) ;
2010-06-30 16:42:11 +00:00
return FTDM_SUCCESS ;
}
static FIO_SIG_UNLOAD_FUNCTION ( ftdm_sangoma_isdn_unload )
{
unsigned i ;
ftdm_log ( FTDM_LOG_INFO , " Starting ftmod_sangoma_isdn unload... \n " ) ;
sng_isdn_free ( ) ;
for ( i = 1 ; i < = MAX_VARIANTS ; i + + ) {
2010-08-31 17:29:31 +00:00
ftdm_mutex_destroy ( & g_sngisdn_data . ccs [ i ] . mutex ) ;
2010-06-30 16:42:11 +00:00
}
ftdm_log ( FTDM_LOG_INFO , " Finished ftmod_sangoma_isdn unload! \n " ) ;
return FTDM_SUCCESS ;
}
2011-05-02 19:37:19 +00:00
# define SANGOMA_ISDN_API_USAGE_TRACE "ftdm sangoma_isdn trace <q921|q931> <span name>\n"
# define SANGOMA_ISDN_API_USAGE_SHOW_L1_STATS "ftdm sangoma_isdn l1_stats <span name>\n"
# define SANGOMA_ISDN_API_USAGE_SHOW_SPANS "ftdm sangoma_isdn show_spans [<span name>]\n"
# define SANGOMA_ISDN_API_USAGE "\t"SANGOMA_ISDN_API_USAGE_TRACE \
" \t " SANGOMA_ISDN_API_USAGE_SHOW_L1_STATS \
" \t " SANGOMA_ISDN_API_USAGE_SHOW_SPANS
2010-06-30 16:42:11 +00:00
static FIO_API_FUNCTION ( ftdm_sangoma_isdn_api )
{
2011-05-02 19:37:19 +00:00
ftdm_status_t status = FTDM_EINVAL ;
2010-06-30 16:42:11 +00:00
char * mycmd = NULL , * argv [ 10 ] = { 0 } ;
int argc = 0 ;
if ( data ) {
mycmd = ftdm_strdup ( data ) ;
argc = ftdm_separate_string ( mycmd , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ;
}
/*ftdm_log(FTDM_LOG_DEBUG, "Sangoma argc:%d argv[0]:%s argv[1]:%s argv[2]:%s \n", argc, argv[0], argv[1], argv[2]);*/
if ( argc < = 0 ) {
ftdm_log ( FTDM_LOG_ERROR , " No parameters provided \n " ) ;
goto done ;
}
2010-12-14 16:23:47 +00:00
/* TODO: Move functions to table + function pointers */
2010-06-30 16:42:11 +00:00
if ( ! strcasecmp ( argv [ 0 ] , " trace " ) ) {
char * trace_opt ;
ftdm_span_t * span ;
if ( argc < 3 ) {
2011-05-02 19:37:19 +00:00
ftdm_log ( FTDM_LOG_ERROR , " Usage: %s \n " , SANGOMA_ISDN_API_USAGE_TRACE ) ;
2010-06-30 16:42:11 +00:00
status = FTDM_FAIL ;
goto done ;
}
trace_opt = argv [ 1 ] ;
status = ftdm_span_find_by_name ( argv [ 2 ] , & span ) ;
if ( FTDM_SUCCESS ! = status ) {
stream - > write_function ( stream , " -ERR failed to find span by name %s \n " , argv [ 2 ] ) ;
2011-05-02 19:37:19 +00:00
status = FTDM_FAIL ;
2010-06-30 16:42:11 +00:00
goto done ;
}
2010-12-15 21:29:03 +00:00
2010-06-30 16:42:11 +00:00
if ( ! strcasecmp ( trace_opt , " q921 " ) ) {
2011-05-02 19:37:19 +00:00
status = sngisdn_activate_trace ( span , SNGISDN_TRACE_Q921 ) ;
2010-06-30 16:42:11 +00:00
} else if ( ! strcasecmp ( trace_opt , " q931 " ) ) {
2011-05-02 19:37:19 +00:00
status = sngisdn_activate_trace ( span , SNGISDN_TRACE_Q931 ) ;
2010-06-30 16:42:11 +00:00
} else if ( ! strcasecmp ( trace_opt , " disable " ) ) {
2011-05-02 19:37:19 +00:00
status = sngisdn_activate_trace ( span , SNGISDN_TRACE_DISABLE ) ;
2010-06-30 16:42:11 +00:00
} else {
stream - > write_function ( stream , " -ERR invalid trace option <q921|q931> <span name> \n " ) ;
2011-05-02 19:37:19 +00:00
status = FTDM_FAIL ;
2010-12-15 21:29:03 +00:00
}
2011-05-02 19:37:19 +00:00
goto done ;
2010-06-30 16:42:11 +00:00
}
2011-05-02 19:37:19 +00:00
2010-08-31 17:29:31 +00:00
if ( ! strcasecmp ( argv [ 0 ] , " l1_stats " ) ) {
ftdm_span_t * span ;
if ( argc < 2 ) {
2011-05-02 19:37:19 +00:00
stream - > write_function ( stream , " Usage: %s \n " , SANGOMA_ISDN_API_USAGE_SHOW_L1_STATS ) ;
2010-08-31 17:29:31 +00:00
status = FTDM_FAIL ;
goto done ;
}
status = ftdm_span_find_by_name ( argv [ 1 ] , & span ) ;
if ( FTDM_SUCCESS ! = status ) {
2010-09-08 23:41:34 +00:00
stream - > write_function ( stream , " -ERR failed to find span with name %s \n " , argv [ 1 ] ) ;
2011-05-02 19:37:19 +00:00
status = FTDM_FAIL ;
2010-09-08 23:41:34 +00:00
goto done ;
}
2011-05-02 19:37:19 +00:00
status = sngisdn_show_l1_stats ( stream , span ) ;
goto done ;
2010-09-08 23:41:34 +00:00
}
2010-12-14 16:23:47 +00:00
2010-09-08 23:41:34 +00:00
if ( ! strcasecmp ( argv [ 0 ] , " show_spans " ) ) {
ftdm_span_t * span = NULL ;
if ( argc = = 2 ) {
status = ftdm_span_find_by_name ( argv [ 1 ] , & span ) ;
if ( FTDM_SUCCESS ! = status ) {
stream - > write_function ( stream , " -ERR failed to find span with name %s \n " , argv [ 1 ] ) ;
2011-05-02 19:37:19 +00:00
stream - > write_function ( stream , " Usage: %s \n " , SANGOMA_ISDN_API_USAGE_SHOW_SPANS ) ;
status = FTDM_FAIL ;
2010-09-08 23:41:34 +00:00
goto done ;
}
2011-05-02 19:37:19 +00:00
status = sngisdn_show_span ( stream , span ) ;
2010-08-31 17:29:31 +00:00
goto done ;
}
2011-05-02 19:37:19 +00:00
status = sngisdn_show_spans ( stream ) ;
goto done ;
2010-08-31 17:29:31 +00:00
}
2011-05-02 19:37:19 +00:00
2010-08-31 17:29:31 +00:00
if ( ! strcasecmp ( argv [ 0 ] , " check_ids " ) ) {
2011-05-02 19:37:19 +00:00
status = sngisdn_check_free_ids ( ) ;
goto done ;
2010-08-31 17:29:31 +00:00
}
2011-05-30 21:07:59 +00:00
if ( ! strcasecmp ( argv [ 0 ] , " check_mem " ) ) {
sngisdn_get_memory_info ( ) ;
2010-08-31 17:29:31 +00:00
}
2010-06-30 16:42:11 +00:00
done :
2011-05-02 19:37:19 +00:00
switch ( status ) {
case FTDM_SUCCESS :
stream - > write_function ( stream , " Command executed OK \n " ) ;
break ;
case FTDM_EINVAL :
stream - > write_function ( stream , " Invalid arguments [%s] \n " , mycmd ) ;
stream - > write_function ( stream , " Usage: \n %s \n " , SANGOMA_ISDN_API_USAGE ) ;
break ;
default :
/* FTDM_FAIL - Do nothing since we already printed the cause of the error */
break ;
}
/* Return SUCCESS because we do not want to print the general FTDM usage list */
status = FTDM_SUCCESS ;
2010-06-30 16:42:11 +00:00
ftdm_safe_free ( mycmd ) ;
return status ;
}
2011-05-26 15:38:24 +00:00
2010-06-30 16:42:11 +00:00
static FIO_IO_LOAD_FUNCTION ( ftdm_sangoma_isdn_io_init )
{
memset ( & g_sngisdn_io_interface , 0 , sizeof ( g_sngisdn_io_interface ) ) ;
g_sngisdn_io_interface . name = " sangoma_isdn " ;
g_sngisdn_io_interface . api = ftdm_sangoma_isdn_api ;
* fio = & g_sngisdn_io_interface ;
return FTDM_SUCCESS ;
}
2010-10-18 17:37:28 +00:00
EX_DECLARE_DATA ftdm_module_t ftdm_module =
2010-06-30 16:42:11 +00:00
{
" sangoma_isdn " , /* char name[256]; */
ftdm_sangoma_isdn_io_init , /* fio_io_load_t */
NULL , /* fio_io_unload_t */
ftdm_sangoma_isdn_init , /* fio_sig_load_t */
NULL , /* fio_sig_configure_t */
ftdm_sangoma_isdn_unload , /* fio_sig_unload_t */
ftdm_sangoma_isdn_span_config /* fio_configure_span_signaling_t */
} ;
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : t
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 :
*/
/******************************************************************************/