@ -276,12 +276,9 @@ AST_MUTEX_DEFINE_STATIC(monlock);
/*! \brief This is the thread for the monitor which checks for input on the channels
which are not currently in use . */
static pthread_t monitor_thread = AST_PTHREADT_NULL ;
static ast_cond_t mwi_thread_complete ;
static ast_cond_t ss_thread_complete ;
AST_MUTEX_DEFINE_STATIC ( mwi_thread_lock ) ;
AST_MUTEX_DEFINE_STATIC ( ss_thread_lock ) ;
AST_MUTEX_DEFINE_STATIC ( restart_lock ) ;
static int mwi_thread_count = 0 ;
static int ss_thread_count = 0 ;
static int num_restart_pending = 0 ;
@ -503,6 +500,24 @@ struct dahdi_subchannel {
# define MAX_SLAVES 4
/* States for sending MWI message
* First three states are required for send Ring Pulse Alert Signal
*/
typedef enum {
MWI_SEND_NULL = 0 ,
MWI_SEND_SA ,
MWI_SEND_SA_WAIT ,
MWI_SEND_PAUSE ,
MWI_SEND_SPILL ,
MWI_SEND_CLEANUP ,
MWI_SEND_DONE ,
} mwisend_states ;
struct mwisend_info {
struct timeval pause ;
mwisend_states mwisend_current ;
} ;
static struct dahdi_pvt {
ast_mutex_t lock ;
struct ast_channel * owner ; /*!< Our current active owner (if applicable) */
@ -595,6 +610,7 @@ static struct dahdi_pvt {
unsigned int setup_ack : 1 ;
# endif
unsigned int use_smdi : 1 ; /* Whether to use SMDI on this channel */
struct mwisend_info mwisend_data ;
struct ast_smdi_interface * smdi_iface ; /* The serial port to listen for SMDI data on */
struct dahdi_distRings drings ;
@ -7480,135 +7496,80 @@ quit_no_clean:
return NULL ;
}
/* States for sending MWI message
* First three states are required for send Ring Pulse Alert Signal
*/
enum mwisend_states {
MWI_SEND_SA ,
MWI_SEND_SA_WAIT ,
MWI_SEND_PAUSE ,
MWI_SEND_SPILL ,
MWI_SEND_CLEANUP ,
MWI_SEND_DONE
} ;
static void * mwi_send_thread ( void * data )
/*
* The following three functions ( mwi_send_init , mwi_send_process_buffer ,
* mwi_send_process_event ) work with the do_monitor thread to generate mwi spills
* that are sent out via FXA port on voicemail state change . The execution of
* the mwi send is state driven and can either generate a ring pulse prior to
* sending the fsk spill or simply send an fsk spill .
*/
static int mwi_send_init ( struct dahdi_pvt * pvt )
{
struct mwi_thread_data * mtd = data ;
struct timeval timeout_basis , suspend , now ;
int x , i , res ;
int num_read ;
enum mwisend_states mwi_send_state = MWI_SEND_SPILL ; /*Assume FSK only */
ast_mutex_lock ( & mwi_thread_lock ) ;
mwi_thread_count + + ;
ast_mutex_unlock ( & mwi_thread_lock ) ;
int x , res ;
pvt - > mwisendactive = 1 ;
pvt - > mwisend_data . mwisend_current = MWI_SEND_SPILL ; /*Assume FSK only */
/* Determine how this spill is to be sent */
if ( mwisend_rpas ) {
mwi_send_state = MWI_SEND_SA ;
pvt - > mwisend_data . mwisend_current = MWI_SEND_SA ;
}
gettimeofday ( & timeout_basis , NULL ) ;
mtd - > pvt - > cidspill = ast_calloc ( 1 , MAX_CALLERID_SIZE ) ;
if ( ! mtd - > pvt - > cidspill ) {
mtd - > pvt - > mwisendactive = 0 ;
ast_free ( mtd ) ;
return NULL ;
pvt - > cidspill = ast_calloc ( 1 , MAX_CALLERID_SIZE ) ;
if ( ! pvt - > cidspill ) {
pvt - > mwisendactive = 0 ;
return - 1 ;
}
x = DAHDI_FLUSH_BOTH ;
res = ioctl ( mtd- > pvt- > subs [ SUB_REAL ] . dfd , DAHDI_FLUSH , & x ) ;
res = ioctl ( pvt - > subs [ SUB_REAL ] . dfd , DAHDI_FLUSH , & x ) ;
x = 3000 ;
ioctl ( mtd - > pvt - > subs [ SUB_REAL ] . dfd , DAHDI_ONHOOKTRANSFER , & x ) ;
mtd - > pvt - > cidlen = vmwi_generate ( mtd - > pvt - > cidspill , has_voicemail ( mtd - > pvt ) , CID_MWI_TYPE_MDMF_FULL ,
AST_LAW ( mtd - > pvt ) , mtd - > pvt - > cid_name , mtd - > pvt - > cid_num , 0 ) ;
mtd - > pvt - > cidpos = 0 ;
while ( MWI_SEND_DONE ! = mwi_send_state ) {
num_read = 0 ;
gettimeofday ( & now , NULL ) ;
if ( 10 < ( now . tv_sec - timeout_basis . tv_sec ) ) {
ast_log ( LOG_WARNING , " MWI Send TIMEOUT in state %d \n " , mwi_send_state ) ;
goto quit ;
}
ioctl ( pvt - > subs [ SUB_REAL ] . dfd , DAHDI_ONHOOKTRANSFER , & x ) ;
pvt - > cidlen = vmwi_generate ( pvt - > cidspill , has_voicemail ( pvt ) , CID_MWI_TYPE_MDMF_FULL ,
AST_LAW ( pvt ) , pvt - > cid_name , pvt - > cid_num , 0 ) ;
pvt - > cidpos = 0 ;
return 0 ;
}
i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT ;
if ( ( res = ioctl ( mtd - > pvt - > subs [ SUB_REAL ] . dfd , DAHDI_IOMUX , & i ) ) ) {
ast_log ( LOG_WARNING , " I/O MUX failed: %s \n " , strerror ( errno ) ) ;
goto quit ;
}
static int mwi_send_process_buffer ( struct dahdi_pvt * pvt , int num_read )
{
struct timeval now ;
int res ;
if ( i & DAHDI_IOMUX_SIGEVENT ) {
/* If we get an event, screen out events that we do not act on.
* Otherwise , let handle_init_event determine what is needed
*/
res = dahdi_get_event ( mtd - > pvt - > subs [ SUB_REAL ] . dfd ) ;
switch ( res ) {
case DAHDI_EVENT_RINGEROFF :
if ( mwi_send_state = = MWI_SEND_SA_WAIT ) {
if ( dahdi_set_hook ( mtd - > pvt - > subs [ SUB_REAL ] . dfd , DAHDI_RINGOFF ) ) {
ast_log ( LOG_WARNING , " Unable to finsh RP-AS: %s \n " , strerror ( errno ) ) ;
goto quit ;
}
mwi_send_state = MWI_SEND_PAUSE ;
gettimeofday ( & suspend , NULL ) ;
}
break ;
case DAHDI_EVENT_RINGERON :
case DAHDI_EVENT_HOOKCOMPLETE :
break ;
default :
/* Got to the default init event handler */
if ( 0 < handle_init_event ( mtd - > pvt , res ) ) {
/* I've spawned a thread, get out */
goto quit ;
}
break ;
}
} else if ( i & DAHDI_IOMUX_READ ) {
if ( ( num_read = read ( mtd - > pvt - > subs [ SUB_REAL ] . dfd , mtd - > buf , sizeof ( mtd - > buf ) ) ) < 0 ) {
if ( errno ! = ELAST ) {
ast_log ( LOG_WARNING , " read returned error: %s \n " , strerror ( errno ) ) ;
goto quit ;
}
break ;
}
}
/* Perform mwi send action */
switch ( mwi_send_state ) {
/* sanity check to catch if this had been interrupted previously
* i . e . state says there is more to do but there is no spill allocated
*/
if ( MWI_SEND_DONE ! = pvt - > mwisend_data . mwisend_current & & ! pvt - > cidspill ) {
pvt - > mwisend_data . mwisend_current = MWI_SEND_DONE ;
} else if ( MWI_SEND_DONE ! = pvt - > mwisend_data . mwisend_current ) {
/* Normal processing -- Perform mwi send action */
switch ( pvt - > mwisend_data . mwisend_current ) {
case MWI_SEND_SA :
/* Send the Ring Pulse Signal Alert */
res = ioctl ( mtd- > pvt- > subs [ SUB_REAL ] . dfd , DAHDI_SETCADENCE , & AS_RP_cadence ) ;
res = ioctl ( pvt - > subs [ SUB_REAL ] . dfd , DAHDI_SETCADENCE , & AS_RP_cadence ) ;
if ( res ) {
ast_log ( LOG_WARNING , " Unable to set RP-AS ring cadence: %s \n " , strerror ( errno ) ) ;
goto quit ;
}
dahdi_set_hook ( mtd - > pvt - > subs [ SUB_REAL ] . dfd , DAHDI_RING ) ;
mwi_send_state = MWI_SEND_SA_WAIT ;
res = dahdi_set_hook ( pvt - > subs [ SUB_REAL ] . dfd , DAHDI_RING ) ;
pvt - > mwisend_data . mwisend_current = MWI_SEND_SA_WAIT ;
break ;
case MWI_SEND_SA_WAIT : /* do nothing until I get RINGEROFF event */
break ;
case MWI_SEND_PAUSE : /* Wait between alert and spill - min of 500 mS*/
gettimeofday ( & now , NULL ) ;
if ( ( int ) ( now . tv_sec - pvt - > mwisend_data . pause . tv_sec ) * 1000000 + ( int ) now . tv_usec - ( int ) pvt - > mwisend_data . pause . tv_usec > 500000 ) {
pvt - > mwisend_data . mwisend_current = MWI_SEND_SPILL ;
}
break ;
case MWI_SEND_SA_WAIT : /* do nothing until I get RINGEROFF event */
break ;
case MWI_SEND_PAUSE : /* Wait between alert and spill - min of 500 mS*/
gettimeofday ( & now , NULL ) ;
if ( ( int ) ( now . tv_sec - suspend . tv_sec ) * 1000000 + ( int ) now . tv_usec - ( int ) suspend . tv_usec > 500000 ) {
mwi_send_state = MWI_SEND_SPILL ;
}
break ;
case MWI_SEND_SPILL :
/* We read some number of bytes. Write an equal amount of data */
if ( 0 < num_read ) {
if ( num_read > mtd- > pvt- > cidlen - mtd - > pvt - > cidpos )
num_read = mtd- > pvt- > cidlen - mtd - > pvt - > cidpos ;
res = write ( mtd- > pvt- > subs [ SUB_REAL ] . dfd , mtd- > pvt- > cidspill + mtd - > pvt - > cidpos , num_read ) ;
if ( num_read > pvt - > cidlen - pvt - > cidpos )
num_read = pvt - > cidlen - pvt - > cidpos ;
res = write ( pvt - > subs [ SUB_REAL ] . dfd , pvt - > cidspill + pvt - > cidpos , num_read ) ;
if ( res > 0 ) {
mtd - > pvt - > cidpos + = res ;
if ( mtd - > pvt - > cidpos > = mtd - > pvt - > cidlen ) {
ast_free ( mtd - > pvt - > cidspill ) ;
mtd - > pvt - > cidspill = NULL ;
mtd - > pvt - > cidpos = 0 ;
mtd - > pvt - > cidlen = 0 ;
mwi_send_state = MWI_SEND_CLEANUP ;
pvt - > cidpos + = res ;
if ( pvt - > cidpos > = pvt - > cidlen ) {
pvt - > mwisend_data . mwisend_current = MWI_SEND_CLEANUP ;
}
} else {
ast_log ( LOG_WARNING , " MWI Send Write failed: %s \n " , strerror ( errno ) ) ;
@ -7618,7 +7579,7 @@ static void *mwi_send_thread(void *data)
break ;
case MWI_SEND_CLEANUP :
/* For now, do nothing */
mwi_send_state = MWI_SEND_DONE ;
pvt- > mwisend_data . mwisend_current = MWI_SEND_DONE ;
break ;
default :
/* Should not get here, punt*/
@ -7627,22 +7588,54 @@ static void *mwi_send_thread(void *data)
}
}
quit :
if ( mtd - > pvt - > cidspill ) {
ast_free ( mtd - > pvt - > cidspill ) ;
mtd - > pvt - > cidspill = NULL ;
if ( MWI_SEND_DONE = = pvt - > mwisend_data . mwisend_current ) {
if ( pvt - > cidspill ) {
ast_free ( pvt - > cidspill ) ;
pvt - > cidspill = NULL ;
pvt - > cidpos = 0 ;
pvt - > cidlen = 0 ;
}
pvt - > mwisendactive = 0 ;
}
mtd - > pvt - > mwisendactive = 0 ;
ast_free ( mtd ) ;
return 0 ;
quit :
return - 1 ;
}
ast_mutex_lock ( & mwi_thread_lock ) ;
mwi_thread_count - - ;
ast_cond_signal ( & mwi_thread_complete ) ;
ast_mutex_unlock ( & mwi_thread_lock ) ;
static int mwi_send_process_event ( struct dahdi_pvt * pvt , int event )
{
int handled = 0 ;
return NULL ;
}
if ( MWI_SEND_DONE ! = pvt - > mwisend_data . mwisend_current ) {
switch ( event ) {
case DAHDI_EVENT_RINGEROFF :
if ( pvt - > mwisend_data . mwisend_current = = MWI_SEND_SA_WAIT ) {
handled = 1 ;
if ( dahdi_set_hook ( pvt - > subs [ SUB_REAL ] . dfd , DAHDI_RINGOFF ) ) {
ast_log ( LOG_WARNING , " Unable to finsh RP-AS: %s mwi send aborted \n " , strerror ( errno ) ) ;
if ( pvt - > cidspill ) {
ast_free ( pvt - > cidspill ) ;
pvt - > cidspill = NULL ;
}
pvt - > mwisend_data . mwisend_current = MWI_SEND_DONE ;
pvt - > mwisendactive = 0 ;
} else {
pvt - > mwisend_data . mwisend_current = MWI_SEND_PAUSE ;
gettimeofday ( & pvt - > mwisend_data . pause , NULL ) ;
}
}
break ;
case DAHDI_EVENT_RINGERON :
case DAHDI_EVENT_HOOKCOMPLETE :
break ;
default :
break ;
}
}
return handled ;
}
/* destroy a DAHDI channel, identified by its number */
static int dahdi_destroy_channel_bynum ( int channel )
@ -7941,14 +7934,14 @@ static void *do_monitor(void *data)
i = iflist ;
while ( i ) {
if ( ( i - > subs [ SUB_REAL ] . dfd > - 1 ) & & i - > sig & & ( ! i - > radio ) ) {
if ( ! i - > owner & & ! i - > subs [ SUB_REAL ] . owner & & ! i - > mwimonitoractive & & ! i - > mwisendactive ) {
if ( ! i - > owner & & ! i - > subs [ SUB_REAL ] . owner & & ! i - > mwimonitoractive ) {
/* This needs to be watched, as it lacks an owner */
pfds [ count ] . fd = i - > subs [ SUB_REAL ] . dfd ;
pfds [ count ] . events = POLLPRI ;
pfds [ count ] . revents = 0 ;
/* If we are monitoring for VMWI or sending CID, we need to
read from the channel as well */
if ( i - > cidspill | | i - > mwi monitor_fsk)
if ( i - > cidspill | | i - > mwi sendactive | | i - > mwi monitor_fsk)
pfds [ count ] . events | = POLLIN ;
count + + ;
}
@ -7987,29 +7980,18 @@ static void *do_monitor(void *data)
if ( ! last - > mwisendactive & & last - > sig & __DAHDI_SIG_FXO ) {
res = has_voicemail ( last ) ;
if ( last - > msgstate ! = res ) {
/* This channel has a new voicemail state,
* initiate a thread to send an MWI message
*/
pthread_attr_t attr ;
pthread_t threadid ;
struct mwi_thread_data * mtd ;
/* Set driver resources for signalling VMWI */
res2 = ioctl ( last - > subs [ SUB_REAL ] . dfd , DAHDI_VMWI , res ) ;
if ( res2 ) {
ast_log ( LOG_DEBUG , " Unable to control message waiting led on channel %d: %s \n " , last - > channel , strerror ( errno ) ) ;
}
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
if ( ( mtd = ast_calloc ( 1 , sizeof ( * mtd ) ) ) ) {
last - > msgstate = res ;
mtd - > pvt = last ;
last - > mwisendactive = 1 ;
if ( ast_pthread_create_background ( & threadid , & attr , mwi_send_thread , mtd ) ) {
ast_log ( LOG_WARNING , " Unable to start mwi send thread on channel %d \n " , last - > channel ) ;
ast_free ( mtd ) ;
last - > mwisendactive = 0 ;
}
/* This channel has a new voicemail state,
* initiate a mechanism to send an MWI message
*/
if ( mwi_send_init ( last ) ) {
ast_log ( LOG_WARNING , " Unable to initiate mwi send sequence on channel %d \n " , last - > channel ) ;
}
last - > msgstate = res ;
found + + ;
}
}
@ -8042,8 +8024,8 @@ static void *do_monitor(void *data)
i = i - > next ;
continue ;
}
if ( ! i - > cidspill & & ! i - > mwimonitor_fsk ) {
ast_log ( LOG_WARNING , " Whoa.... I'm reading but have no cidspill (%d)...\n " , i - > subs [ SUB_REAL ] . dfd ) ;
if ( ! i - > mwimonitor_fsk & & ! i - > mwisendactive ) {
ast_log ( LOG_WARNING , " Whoa.... I'm not looking for MWI or sending MWI but am reading (%d)...\n " , i - > subs [ SUB_REAL ] . dfd ) ;
i = i - > next ;
continue ;
}
@ -8071,6 +8053,9 @@ static void *do_monitor(void *data)
}
}
}
if ( i - > mwisendactive ) {
mwi_send_process_buffer ( i , res ) ;
}
} else {
ast_log ( LOG_WARNING , " Read failed with %d: %s \n " , res , strerror ( errno ) ) ;
}
@ -8088,8 +8073,10 @@ static void *do_monitor(void *data)
ast_debug ( 1 , " Monitor doohicky got event %s on channel %d \n " , event2str ( res ) , i - > channel ) ;
/* Don't hold iflock while handling init events */
ast_mutex_unlock ( & iflock ) ;
handle_init_event ( i , res ) ;
ast_mutex_lock ( & iflock ) ;
if ( 0 = = i - > mwisendactive | | 0 ! = mwi_send_process_event ( i , res ) ) {
handle_init_event ( i , res ) ;
}
ast_mutex_lock ( & iflock ) ;
}
}
i = i - > next ;
@ -12053,12 +12040,6 @@ static int dahdi_restart(void)
}
monitor_thread = AST_PTHREADT_NULL ; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
ast_mutex_lock ( & mwi_thread_lock ) ;
while ( mwi_thread_count > 0 ) {
ast_debug ( 3 , " Waiting on %d mwi_send_thread(s) to finish \n " , mwi_thread_count ) ;
ast_cond_wait ( & mwi_thread_complete , & mwi_thread_lock ) ;
}
ast_mutex_unlock ( & mwi_thread_lock ) ;
ast_mutex_lock ( & ss_thread_lock ) ;
while ( ss_thread_count > 0 ) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
int x = DAHDI_FLASH ;
@ -13564,7 +13545,6 @@ static int __unload_module(void)
}
# endif
ast_cond_destroy ( & mwi_thread_complete ) ;
ast_cond_destroy ( & ss_thread_complete ) ;
return 0 ;
}
@ -14822,7 +14802,6 @@ static int load_module(void)
ast_manager_register ( " DAHDIShowChannels " , 0 , action_dahdishowchannels , " Show status DAHDI channels " ) ;
ast_manager_register ( " DAHDIRestart " , 0 , action_dahdirestart , " Fully Restart DAHDI channels (terminates calls) " ) ;
ast_cond_init ( & mwi_thread_complete , NULL ) ;
ast_cond_init ( & ss_thread_complete , NULL ) ;
return res ;