root/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ftdm_sangoma_isdn_process_phy_events
  2. ftdm_sangoma_isdn_poll_events
  3. ftdm_sangoma_isdn_dchan_set_queue_size
  4. ftdm_sangoma_isdn_wakeup_phy
  5. ftdm_sangoma_isdn_dchan_run
  6. ftdm_sangoma_isdn_run
  7. ftdm_sangoma_isdn_process_event_states
  8. ftdm_sangoma_isdn_process_stack_event
  9. ftdm_sangoma_isdn_process_state_change
  10. FIO_CHANNEL_SEND_MSG_FUNCTION
  11. FIO_CHANNEL_OUTGOING_CALL_FUNCTION
  12. FIO_CHANNEL_GET_SIG_STATUS_FUNCTION
  13. FIO_CHANNEL_SET_SIG_STATUS_FUNCTION
  14. FIO_SPAN_GET_SIG_STATUS_FUNCTION
  15. FIO_SPAN_SET_SIG_STATUS_FUNCTION
  16. ftdm_sangoma_isdn_start
  17. ftdm_sangoma_isdn_stop
  18. FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION
  19. FIO_SIG_LOAD_FUNCTION
  20. FIO_SIG_UNLOAD_FUNCTION
  21. FIO_API_FUNCTION
  22. FIO_IO_LOAD_FUNCTION

   1 /*
   2  * Copyright (c) 2010, Sangoma Technologies 
   3  * David Yat Sin <davidy@sangoma.com>
   4  * Moises Silva <moy@sangoma.com>
   5  * All rights reserved.
   6  *
   7  * Redistribution and use in source and binary forms, with or without
   8  * modification, are permitted provided that the following conditions
   9  * are met:
  10  *
  11  * * Redistributions of source code must retain the above copyright
  12  * notice, this list of conditions and the following disclaimer.
  13  *
  14  * * Redistributions in binary form must reproduce the above copyright
  15  * notice, this list of conditions and the following disclaimer in the
  16  * documentation and/or other materials provided with the distribution.
  17  *
  18  * * Neither the name of the original author; nor the names of any contributors
  19  * may be used to endorse or promote products derived from this software
  20  * without specific prior written permission.
  21  *
  22  *
  23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  26  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
  27  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34  */
  35 
  36 
  37 #include "ftmod_sangoma_isdn.h"
  38 
  39 #ifdef FTDM_DEBUG_CHAN_MEMORY
  40 #include <sys/mman.h>
  41 #endif
  42 
  43 
  44 static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj);
  45 static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span);
  46 static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span);
  47 
  48 ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
  49 static void ftdm_sangoma_isdn_poll_events(ftdm_span_t *span);
  50 static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event);
  51 static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan);
  52 static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event);
  53 static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan);
  54 static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *ftdmchan);
  55 
  56 static ftdm_io_interface_t              g_sngisdn_io_interface;
  57 static sng_isdn_event_interface_t       g_sngisdn_event_interface;
  58 
  59 ftdm_sngisdn_data_t                     g_sngisdn_data;
  60 
  61 ftdm_state_map_t sangoma_isdn_state_map = {
  62         {
  63         {
  64                 ZSD_INBOUND,
  65                 ZSM_UNACCEPTABLE,
  66                 {FTDM_ANY_STATE, FTDM_END},
  67                 {FTDM_CHANNEL_STATE_RESET, FTDM_CHANNEL_STATE_RESTART, FTDM_END}
  68         },
  69         {
  70                 ZSD_INBOUND,
  71                 ZSM_UNACCEPTABLE,
  72                 {FTDM_CHANNEL_STATE_RESET, FTDM_END},
  73                 {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
  74         },
  75         {
  76                 ZSD_INBOUND,
  77                 ZSM_UNACCEPTABLE,
  78                 {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
  79                 {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
  80         },
  81         {
  82                 ZSD_INBOUND,
  83                 ZSM_UNACCEPTABLE,
  84                 {FTDM_CHANNEL_STATE_CANCEL, FTDM_END},
  85                 {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}
  86         },
  87         {
  88                 ZSD_INBOUND,
  89                 ZSM_UNACCEPTABLE,
  90                 {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END},
  91                 {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_DIALING,
  92                  FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP,
  93                  FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}
  94         },
  95         {
  96                 ZSD_INBOUND,
  97                 ZSM_UNACCEPTABLE,
  98                 {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
  99                 {FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_GET_CALLERID, FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
 100         },
 101         {
 102                 ZSD_INBOUND,
 103                 ZSM_UNACCEPTABLE,
 104                 {FTDM_CHANNEL_STATE_GET_CALLERID, FTDM_END},
 105                 {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
 106         },
 107         {
 108                 ZSD_INBOUND,
 109                 ZSM_UNACCEPTABLE,
 110                 {FTDM_CHANNEL_STATE_COLLECT, FTDM_END},
 111                 {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END}
 112         },
 113         {
 114                 ZSD_INBOUND,
 115                 ZSM_UNACCEPTABLE,
 116                 {FTDM_CHANNEL_STATE_IN_LOOP, FTDM_END},
 117                 {FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_DOWN, FTDM_END}
 118         },
 119         {
 120                 ZSD_INBOUND,
 121                 ZSM_UNACCEPTABLE,
 122                 {FTDM_CHANNEL_STATE_RING, FTDM_END},
 123                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_END}
 124         },
 125         {
 126                 ZSD_INBOUND,
 127                 ZSM_UNACCEPTABLE,
 128                 {FTDM_CHANNEL_STATE_PROCEED, FTDM_END},
 129                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
 130                  FTDM_CHANNEL_STATE_UP, FTDM_END}
 131         },
 132         {
 133                 ZSD_INBOUND,
 134                 ZSM_UNACCEPTABLE,
 135                 {FTDM_CHANNEL_STATE_RINGING, FTDM_END},
 136                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
 137         },
 138         {
 139                 ZSD_INBOUND,
 140                 ZSM_UNACCEPTABLE,
 141                 {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
 142                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
 143         },
 144         {
 145                 ZSD_INBOUND,
 146                 ZSM_UNACCEPTABLE,
 147                 {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
 148                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_UP, FTDM_END},
 149         },
 150         {
 151                 ZSD_INBOUND,
 152                 ZSM_UNACCEPTABLE,
 153                 {FTDM_CHANNEL_STATE_UP, FTDM_END},
 154                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 155         },
 156         {
 157                 ZSD_INBOUND,
 158                 ZSM_UNACCEPTABLE,
 159                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 160                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 161         },
 162         {
 163                 ZSD_INBOUND,
 164                 ZSM_UNACCEPTABLE,
 165                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 166                 {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 167         },
 168         {
 169                 ZSD_INBOUND,
 170                 ZSM_UNACCEPTABLE,
 171                 {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 172                 {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
 173         },      
 174         {
 175                 ZSD_OUTBOUND,
 176                 ZSM_UNACCEPTABLE,
 177                 {FTDM_ANY_STATE, FTDM_END},
 178                 {FTDM_CHANNEL_STATE_RESET, FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
 179         },
 180         {
 181                 ZSD_OUTBOUND,
 182                 ZSM_UNACCEPTABLE,
 183                 {FTDM_CHANNEL_STATE_RESET, FTDM_END},
 184                 {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
 185         },
 186         {
 187                 ZSD_OUTBOUND,
 188                 ZSM_UNACCEPTABLE,
 189                 {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
 190                 {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
 191         },
 192         {
 193                 ZSD_OUTBOUND,
 194                 ZSM_UNACCEPTABLE,
 195                 {FTDM_CHANNEL_STATE_CANCEL, FTDM_END},
 196                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
 197         },
 198         {
 199                 ZSD_OUTBOUND,
 200                 ZSM_UNACCEPTABLE,
 201                 {FTDM_CHANNEL_STATE_SUSPENDED, FTDM_END},
 202                 {FTDM_CHANNEL_STATE_DOWN, FTDM_CHANNEL_STATE_COLLECT, FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_DIALING,
 203                  FTDM_CHANNEL_STATE_RESTART, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP,
 204                  FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_CANCEL, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}
 205         },
 206         {
 207                 ZSD_OUTBOUND,
 208                 ZSM_UNACCEPTABLE,
 209                 {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
 210                 {FTDM_CHANNEL_STATE_DIALING, FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END}
 211         },
 212         {
 213                 ZSD_OUTBOUND,
 214                 ZSM_UNACCEPTABLE,
 215                 {FTDM_CHANNEL_STATE_DIALING, FTDM_END},
 216                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP,
 217                  FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP,
 218                  FTDM_CHANNEL_STATE_DOWN, FTDM_END}
 219         },
 220         {
 221                 ZSD_OUTBOUND,
 222                 ZSM_UNACCEPTABLE,
 223                 {FTDM_CHANNEL_STATE_PROCEED, FTDM_END},
 224                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP,
 225                  FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
 226         },
 227         {
 228                 ZSD_OUTBOUND,
 229                 ZSM_UNACCEPTABLE,
 230                 {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
 231                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
 232         },
 233         {
 234                 ZSD_OUTBOUND,
 235                 ZSM_UNACCEPTABLE,
 236                 {FTDM_CHANNEL_STATE_RINGING, FTDM_END},
 237                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
 238         },
 239         {
 240                 ZSD_OUTBOUND,
 241                 ZSM_UNACCEPTABLE,
 242                 {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
 243                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_UP, FTDM_END},
 244         },
 245         {
 246                 ZSD_OUTBOUND,
 247                 ZSM_UNACCEPTABLE,
 248                 {FTDM_CHANNEL_STATE_UP, FTDM_END},
 249                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 250         },
 251         {
 252                 ZSD_OUTBOUND,
 253                 ZSM_UNACCEPTABLE,
 254                 {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 255                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 256         },
 257         {
 258                 ZSD_OUTBOUND,
 259                 ZSM_UNACCEPTABLE,
 260                 {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 261                 {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 262         },
 263         {
 264                 ZSD_OUTBOUND,
 265                 ZSM_UNACCEPTABLE,
 266                 {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 267                 {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
 268         }
 269         }
 270 };
 271 
 272 static void ftdm_sangoma_isdn_process_phy_events(ftdm_span_t *span, ftdm_oob_event_t event)
 273 {
 274         sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
 275         sngisdn_snd_event(signal_data->dchan, event);
 276         
 277         switch (event) {
 278                 /* Check if the span woke up from power-saving mode */
 279                 case FTDM_OOB_ALARM_CLEAR:
 280                         if (FTDM_SPAN_IS_BRI(span)) {
 281                                 ftdm_channel_t *ftdmchan;
 282                                 sngisdn_chan_data_t *sngisdn_info;
 283                                 ftdm_iterator_t *chaniter = NULL;
 284                                 ftdm_iterator_t *curr = NULL;
 285                                                                 
 286                                 chaniter = ftdm_span_get_chan_iterator(span, NULL);
 287                                 for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
 288                                         ftdmchan = (ftdm_channel_t*)ftdm_iterator_current(curr);
 289                                         sngisdn_info = (sngisdn_chan_data_t*)ftdmchan->call_data;
 290 
 291                                         if (ftdm_test_flag(sngisdn_info, FLAG_ACTIVATING)) {
 292                                                 ftdm_clear_flag(sngisdn_info, FLAG_ACTIVATING);
 293 
 294                                                 ftdm_sched_timer(signal_data->sched, "delayed_setup", 1000, sngisdn_delayed_setup, (void*) ftdmchan->call_data, NULL);
 295                                         }
 296                                 }
 297                                 ftdm_iterator_free(chaniter);
 298                         }
 299                         break;
 300                 default:
 301                         /* Ignore other events for now */
 302                         break;
 303         }
 304 }
 305 
 306 static void ftdm_sangoma_isdn_poll_events(ftdm_span_t *span)
 307 {
 308         ftdm_status_t   ret_status;
 309                 
 310         ret_status = ftdm_span_poll_event(span, 0, NULL);
 311         switch(ret_status) {
 312                 case FTDM_SUCCESS:
 313                         {
 314                                 ftdm_event_t *event;
 315                                 while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
 316                                         ftdm_sangoma_isdn_process_phy_events(span, event->enum_id);
 317                                 }
 318                         }
 319                         break;
 320                 case FTDM_TIMEOUT:
 321                         /* No events pending */
 322                         break;
 323                 default:
 324                         ftdm_log(FTDM_LOG_WARNING, "%s:Failed to poll span event\n", span->name);
 325         }
 326 }
 327 
 328 static void ftdm_sangoma_isdn_dchan_set_queue_size(ftdm_channel_t *dchan)
 329 {
 330         ftdm_status_t   ret_status;
 331         uint32_t queue_size;
 332         
 333         queue_size = SNGISDN_DCHAN_QUEUE_LEN;
 334         ret_status = ftdm_channel_command(dchan, FTDM_COMMAND_SET_RX_QUEUE_SIZE, &queue_size);
 335         ftdm_assert(ret_status == FTDM_SUCCESS, "Failed to set Rx Queue size");
 336 
 337         queue_size = SNGISDN_DCHAN_QUEUE_LEN;
 338         ret_status = ftdm_channel_command(dchan, FTDM_COMMAND_SET_TX_QUEUE_SIZE, &queue_size);
 339         ftdm_assert(ret_status == FTDM_SUCCESS, "Failed to set Tx Queue size");
 340 
 341         RETVOID;
 342 }
 343 
 344 static void ftdm_sangoma_isdn_wakeup_phy(ftdm_channel_t *dchan)
 345 {
 346         ftdm_status_t   ret_status;
 347         ftdm_channel_hw_link_status_t status = FTDM_HW_LINK_CONNECTED;
 348         ret_status = ftdm_channel_command(dchan, FTDM_COMMAND_SET_LINK_STATUS, &status);
 349         if (ret_status != FTDM_SUCCESS) {
 350                 ftdm_log_chan_msg(dchan, FTDM_LOG_WARNING, "Failed to wake-up link\n");
 351         }
 352         return;
 353 }
 354 
 355 static void *ftdm_sangoma_isdn_dchan_run(ftdm_thread_t *me, void *obj)
 356 {
 357         uint8_t data[1000];
 358         ftdm_status_t status = FTDM_SUCCESS;
 359         ftdm_wait_flag_t wflags = FTDM_READ;
 360         ftdm_span_t *span = (ftdm_span_t*) obj;
 361         ftdm_channel_t *dchan = ((sngisdn_span_data_t*)span->signal_data)->dchan;
 362         ftdm_size_t len = 0;
 363         
 364         ftdm_channel_set_feature(dchan, FTDM_CHANNEL_FEATURE_IO_STATS);
 365         ftdm_sangoma_isdn_dchan_set_queue_size(dchan);
 366 
 367         ftdm_assert(dchan, "Span does not have a dchannel");
 368         ftdm_channel_open_chan(dchan);
 369         
 370         while (ftdm_running() && !(ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD))) {
 371                 wflags = FTDM_READ;
 372                 status = ftdm_channel_wait(dchan, &wflags, 10000);
 373                 switch(status) {
 374                         case FTDM_FAIL:
 375                                 ftdm_log_chan_msg(dchan, FTDM_LOG_CRIT, "Failed to wait for d-channel\n");
 376                                 break;
 377                         case FTDM_TIMEOUT:
 378                                 break;
 379                         case FTDM_SUCCESS:
 380                                 if ((wflags & FTDM_READ)) {
 381                                         len = 1000;
 382                                         status = ftdm_channel_read(dchan, data, &len);
 383                                         if (status == FTDM_SUCCESS) {
 384                                                 sngisdn_snd_data(dchan, data, len);
 385                                         } else {
 386                                                 ftdm_log_chan_msg(dchan, FTDM_LOG_WARNING, "Failed to read from channel \n");
 387                                         }
 388 #ifndef WIN32 /* It is valid on WIN32 for poll to return without errors, but no flags set */
 389                                 } else {
 390                                         ftdm_log_chan_msg(dchan, FTDM_LOG_CRIT, "Failed to poll for d-channel\n");
 391 #endif
 392                                 }
 393                                 break;
 394                         default:
 395                                 ftdm_log_chan_msg(dchan, FTDM_LOG_CRIT, "Unhandled IO event\n");
 396                 }
 397         }
 398         ftdm_channel_close(&dchan);
 399         return NULL;
 400 }
 401 
 402 static void *ftdm_sangoma_isdn_run(ftdm_thread_t *me, void *obj)
 403 {
 404         ftdm_interrupt_t        *ftdm_sangoma_isdn_int[3];
 405         ftdm_status_t           ret_status;
 406         ftdm_span_t             *span   = (ftdm_span_t *) obj;
 407         ftdm_channel_t  *ftdmchan = NULL;
 408         sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*)span->signal_data;
 409         sngisdn_event_data_t *sngisdn_event = NULL;
 410         int32_t sleep = SNGISDN_EVENT_POLL_RATE;
 411 
 412         ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_isdn monitor thread for span=%u started.\n", span->span_id);
 413 
 414         /* set IN_THREAD flag so that we know this thread is running */
 415         ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);
 416 
 417         /* get an interrupt queue for this span */
 418         if (ftdm_queue_get_interrupt(span->pendingchans, &ftdm_sangoma_isdn_int[0]) != FTDM_SUCCESS) {
 419                 ftdm_log(FTDM_LOG_CRIT, "%s:Failed to get a ftdm_interrupt for span = %s!\n", span->name);
 420                 goto ftdm_sangoma_isdn_run_exit;
 421         }
 422         
 423         if (ftdm_queue_get_interrupt(span->pendingsignals, &ftdm_sangoma_isdn_int[1]) != FTDM_SUCCESS) {
 424                 ftdm_log(FTDM_LOG_CRIT, "%s:Failed to get a signal interrupt for span = %s!\n", span->name);
 425                 goto ftdm_sangoma_isdn_run_exit;
 426         }
 427 
 428         if (ftdm_queue_get_interrupt(signal_data->event_queue, &ftdm_sangoma_isdn_int[2]) != FTDM_SUCCESS) {
 429                 ftdm_log(FTDM_LOG_CRIT, "%s:Failed to get a event interrupt for span = %s!\n", span->name);
 430                 goto ftdm_sangoma_isdn_run_exit;
 431         }
 432 
 433         while (ftdm_running() && !(ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD))) {
 434 
 435                 /* Check if there are any timers to process */
 436                 ftdm_sched_run(signal_data->sched);
 437                 ftdm_span_trigger_signals(span);
 438                 
 439                 if (ftdm_sched_get_time_to_next_timer(signal_data->sched, &sleep) == FTDM_SUCCESS) {
 440                         if (sleep < 0 || sleep > SNGISDN_EVENT_POLL_RATE) {
 441                                 sleep = SNGISDN_EVENT_POLL_RATE;
 442                         }
 443                 }
 444                 ret_status = ftdm_interrupt_multiple_wait(ftdm_sangoma_isdn_int, 3, sleep);
 445                 /* find out why we returned from the interrupt queue */
 446                 switch (ret_status) {
 447                         case FTDM_SUCCESS:  /* there was a state change on the span */
 448                                 /* process all pending state changes */                 
 449                                 while ((ftdmchan = ftdm_queue_dequeue(span->pendingchans))) {
 450                                         /* double check that this channel has a state change pending */
 451                                         ftdm_channel_lock(ftdmchan);
 452                                         ftdm_channel_advance_states(ftdmchan);
 453                                         ftdm_channel_unlock(ftdmchan);
 454                                 }
 455 
 456                                 while ((sngisdn_event = ftdm_queue_dequeue(signal_data->event_queue))) {
 457                                         ftdm_sangoma_isdn_process_stack_event(span, sngisdn_event);
 458                                         ftdm_safe_free(sngisdn_event);
 459                                 }
 460                                 break;
 461                         case FTDM_TIMEOUT:
 462                                 /* twiddle */
 463                                 break;
 464                         case FTDM_FAIL:
 465                                 ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned error!\n", span->name);
 466                                 break;
 467 
 468                         default:
 469                                 ftdm_log(FTDM_LOG_ERROR, "%s: ftdm_interrupt_wait returned with unknown code\n", span->name);
 470                                 break;
 471                 }
 472 
 473                 /* Poll for events, e.g HW DTMF */
 474                 ftdm_sangoma_isdn_poll_events(span);
 475         }
 476         
 477         /* clear the IN_THREAD flag so that we know the thread is done */
 478         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 479 
 480         ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_isdn monitor thread for span %s stopping.\n", span->name);
 481 
 482         return NULL;
 483 
 484 ftdm_sangoma_isdn_run_exit:
 485 
 486         /* clear the IN_THREAD flag so that we know the thread is done */
 487         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 488 
 489         ftdm_log(FTDM_LOG_INFO, "ftmod_sangoma_isdn monitor thread for span %s stopping due to error.\n", span->name);
 490 
 491         return NULL;
 492 }
 493 
 494 
 495 /**
 496  * \brief Checks if span has state changes pending and processes
 497  * \param span Span where event was fired
 498  * \param sngisdn_event Event to handle
 499  * \return The locked FTDM channel associated to the event if any, NULL otherwise
 500  */
 501 
 502 ftdm_channel_t* ftdm_sangoma_isdn_process_event_states(ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event)
 503 {
 504         ftdm_channel_t *ftdmchan = NULL;
 505         switch (sngisdn_event->event_id) {
 506                 /* Events that do not have a channel associated to them */
 507                 case SNGISDN_EVENT_SRV_IND:
 508                 case SNGISDN_EVENT_SRV_CFM:
 509                 case SNGISDN_EVENT_RST_CFM:
 510                 case SNGISDN_EVENT_RST_IND:
 511                         return NULL;
 512                         break;
 513                 case SNGISDN_EVENT_CON_IND:
 514                 case SNGISDN_EVENT_CON_CFM:
 515                 case SNGISDN_EVENT_CNST_IND:
 516                 case SNGISDN_EVENT_DISC_IND:
 517                 case SNGISDN_EVENT_REL_IND:
 518                 case SNGISDN_EVENT_DAT_IND:
 519                 case SNGISDN_EVENT_SSHL_IND:
 520                 case SNGISDN_EVENT_SSHL_CFM:
 521                 case SNGISDN_EVENT_RMRT_IND:
 522                 case SNGISDN_EVENT_RMRT_CFM:
 523                 case SNGISDN_EVENT_FLC_IND:
 524                 case SNGISDN_EVENT_FAC_IND:
 525                 case SNGISDN_EVENT_STA_CFM:
 526                         ftdmchan = sngisdn_event->sngisdn_info->ftdmchan;
 527                         ftdm_assert_return(ftdmchan, NULL,"Event should have a channel associated\n");
 528                         break;
 529         }
 530         ftdm_channel_lock(ftdmchan);
 531         ftdm_channel_advance_states(ftdmchan);
 532         return ftdmchan;
 533 }
 534 
 535 
 536 
 537 static void ftdm_sangoma_isdn_process_stack_event (ftdm_span_t *span, sngisdn_event_data_t *sngisdn_event)
 538 {
 539         ftdm_channel_t *ftdmchan = NULL;
 540         
 541         ftdmchan = ftdm_sangoma_isdn_process_event_states(span, sngisdn_event);
 542         switch(sngisdn_event->event_id) {
 543                 case SNGISDN_EVENT_CON_IND:
 544                         sngisdn_process_con_ind(sngisdn_event);
 545                         break;
 546                 case SNGISDN_EVENT_CON_CFM:
 547                         sngisdn_process_con_cfm(sngisdn_event);
 548                         break;
 549                 case SNGISDN_EVENT_CNST_IND:
 550                         sngisdn_process_cnst_ind(sngisdn_event);
 551                         break;
 552                 case SNGISDN_EVENT_DISC_IND:
 553                         sngisdn_process_disc_ind(sngisdn_event);
 554                         break;
 555                 case SNGISDN_EVENT_REL_IND:
 556                         sngisdn_process_rel_ind(sngisdn_event);
 557                         break;
 558                 case SNGISDN_EVENT_DAT_IND:
 559                         sngisdn_process_dat_ind(sngisdn_event);
 560                         break;
 561                 case SNGISDN_EVENT_SSHL_IND:
 562                         sngisdn_process_sshl_ind(sngisdn_event);
 563                         break;
 564                 case SNGISDN_EVENT_SSHL_CFM:
 565                         sngisdn_process_sshl_cfm(sngisdn_event);
 566                         break;
 567                 case SNGISDN_EVENT_RMRT_IND:
 568                         sngisdn_process_rmrt_ind(sngisdn_event);
 569                         break;
 570                 case SNGISDN_EVENT_RMRT_CFM:
 571                         sngisdn_process_rmrt_cfm(sngisdn_event);
 572                         break;
 573                 case SNGISDN_EVENT_FLC_IND:
 574                         sngisdn_process_flc_ind(sngisdn_event);
 575                         break;
 576                 case SNGISDN_EVENT_FAC_IND:
 577                         sngisdn_process_fac_ind(sngisdn_event);
 578                         break;
 579                 case SNGISDN_EVENT_STA_CFM:
 580                         sngisdn_process_sta_cfm(sngisdn_event);
 581                         break;
 582                 case SNGISDN_EVENT_SRV_IND:
 583                         sngisdn_process_srv_ind(sngisdn_event);
 584                         break;
 585                 case SNGISDN_EVENT_SRV_CFM:
 586                         sngisdn_process_srv_cfm(sngisdn_event);
 587                         break;
 588                 case SNGISDN_EVENT_RST_CFM:
 589                         sngisdn_process_rst_cfm(sngisdn_event);
 590                         break;
 591                 case SNGISDN_EVENT_RST_IND:
 592                         sngisdn_process_rst_ind(sngisdn_event);
 593                         break;
 594         }
 595         if (ftdmchan != NULL) {
 596                 ftdm_channel_advance_states(ftdmchan);
 597                 ftdm_channel_unlock(ftdmchan);
 598         }
 599 }
 600 
 601 /* this function is called with the channel already locked by the core */
 602 static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
 603 {
 604         ftdm_sigmsg_t           sigev;
 605         ftdm_channel_state_t initial_state;
 606         sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data;
 607 
 608         memset(&sigev, 0, sizeof(sigev));
 609 
 610         sigev.chan_id = ftdmchan->chan_id;
 611         sigev.span_id = ftdmchan->span_id;
 612         sigev.channel = ftdmchan;
 613 
 614         /* Acknowledge the state change */
 615         ftdm_channel_complete_state(ftdmchan);
 616 
 617 #ifdef FTDM_DEBUG_CHAN_MEMORY
 618         if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
 619                 ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ) == 0, "Failed to mprotect");
 620         }
 621 #endif
 622         
 623         /* Only needed for debugging */
 624         initial_state = ftdmchan->state;
 625 
 626         ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "processing state change to %s\n", ftdm_channel_state2str(ftdmchan->state));
 627 
 628         switch (ftdmchan->state) {
 629         case FTDM_CHANNEL_STATE_COLLECT:         /* SETUP received but waiting on digits */
 630                 {
 631                         /* TODO: Re-implement this. There is a way to re-evaluate new incoming digits from dialplan as they come */
 632                         sngisdn_snd_setup_ack(ftdmchan);
 633                         /* Just wait in this state until we get enough digits or T302 timeout */
 634                 }
 635                 break;
 636         case FTDM_CHANNEL_STATE_GET_CALLERID:
 637                 {
 638                         if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
 639                                 /* By default, we do not send a progress indicator in the proceed */
 640                                 ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID};
 641                                 
 642                                 sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
 643                                 sngisdn_snd_proceed(ftdmchan, prog_ind);
 644                         }
 645                         /* Wait in this state until we get FACILITY msg */                      
 646                 }
 647                 break;
 648         case FTDM_CHANNEL_STATE_RING: /* incoming call request */
 649                 {                       
 650                         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);
 651 
 652                         /* we have enough information to inform FTDM of the call*/
 653                         sigev.event_id = FTDM_SIGEVENT_START;
 654                         ftdm_span_send_signal(ftdmchan->span, &sigev);
 655                 }
 656                 break;
 657         case FTDM_CHANNEL_STATE_DIALING: /* outgoing call request */
 658                 {                       
 659                         if (FTDM_SPAN_IS_BRI(ftdmchan->span) &&
 660                                 ftdm_test_flag(ftdmchan, FTDM_CHANNEL_IN_ALARM) &&
 661                                 ftdm_test_flag(ftdmchan->span, FTDM_SPAN_PWR_SAVING)) {
 662 
 663                                 sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
 664                                 
 665                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Requesting Line activation\n");
 666                                 sngisdn_set_flag(sngisdn_info, FLAG_ACTIVATING);                                
 667                                 ftdm_sangoma_isdn_wakeup_phy(ftdmchan);
 668                                 ftdm_sched_timer(signal_data->sched, "timer_t3", signal_data->timer_t3*1000, sngisdn_t3_timeout, (void*) sngisdn_info, NULL);
 669                         } else {
 670                                 sngisdn_snd_setup(ftdmchan);
 671                         }
 672                 }
 673                 break;
 674         case FTDM_CHANNEL_STATE_PROCEED:
 675                 {
 676                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 677                                 /*OUTBOUND...so we were told by the line of this so noifiy the user*/
 678                                 sigev.event_id = FTDM_SIGEVENT_PROCEED;
 679                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 680                         } else {
 681                                 if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
 682                                         /* By default, we do not send a progress indicator in the proceed */
 683                                         ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID};
 684                                         
 685                                         sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
 686                                         sngisdn_snd_proceed(ftdmchan, prog_ind);
 687                                 }
 688                         }
 689                 }
 690                 break;
 691         case FTDM_CHANNEL_STATE_RINGING:
 692                 {
 693                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 694                                 /* OUTBOUND...so we were told by the line of this so notify the user */
 695                                 sigev.event_id = FTDM_SIGEVENT_RINGING;
 696                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 697                                 if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) {
 698                                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
 699                                 }
 700                         } else {
 701                                 ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN};
 702                                 sngisdn_snd_alert(ftdmchan, prog_ind);
 703                         }
 704                 }
 705                 break;
 706         case FTDM_CHANNEL_STATE_PROGRESS:
 707                 {
 708                         /*check if the channel is inbound or outbound*/
 709                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 710                                 /*OUTBOUND...so we were told by the line of this so noifiy the user*/
 711                                 sigev.event_id = FTDM_SIGEVENT_PROGRESS;
 712                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 713                         } else {
 714                                 /* Send a progress message, indicating: Call is not end-to-end ISDN, further call progress may be available */
 715                                 ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_NETE_ISDN};
 716                                 sngisdn_snd_progress(ftdmchan, prog_ind);                               
 717                         }
 718                 }
 719                 break;
 720         case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
 721                 {
 722                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 723                                 sigev.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
 724                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 725                         } else {
 726                                 /* Send a progress message, indicating: In-band information/pattern available */
 727                                 ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_IB_AVAIL};
 728                                 sngisdn_snd_progress(ftdmchan, prog_ind);
 729                         }
 730                 }
 731                 break; 
 732         case FTDM_CHANNEL_STATE_UP: /* call is answered */
 733                 {
 734                         /* check if the channel is inbound or outbound */
 735                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 736                                 /* OUTBOUND ... so we were told by the line that the other side answered */
 737                                 sigev.event_id = FTDM_SIGEVENT_UP;
 738                                 ftdm_span_send_signal(ftdmchan->span, &sigev);
 739 
 740                                 if (ftdmchan->span->trunk_type == FTDM_TRUNK_BRI_PTMP &&
 741                                         ((sngisdn_span_data_t*)ftdmchan->span->signal_data)->signalling == SNGISDN_SIGNALING_NET) {
 742                                         /* Assign the call to a specific equipment */
 743                                         sngisdn_snd_con_complete(ftdmchan);
 744                                 }
 745                         } else {
 746                                 /* INBOUND ... so FS told us it just answered ... tell the stack */
 747                                 sngisdn_snd_connect(ftdmchan);
 748                         }
 749                 }
 750                 break;
 751         case FTDM_CHANNEL_STATE_CANCEL:
 752                 {
 753                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Hanging up call before informing user!\n");
 754 
 755                         /* Send a release complete */
 756                         sngisdn_snd_release(ftdmchan, 0);
 757                         /*now go to the HANGUP complete state*/                         
 758                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
 759                 }
 760                 break;
 761         case FTDM_CHANNEL_STATE_TERMINATING: /* call is hung up by the remote end */
 762                 {
 763                         /* this state is set when the line is hanging up */
 764                         sigev.event_id = FTDM_SIGEVENT_STOP;
 765                         ftdm_span_send_signal(ftdmchan->span, &sigev);
 766                 }
 767                 break;
 768         case FTDM_CHANNEL_STATE_HANGUP: /* call is hung up locally */
 769                 {
 770                         if (sngisdn_test_flag(sngisdn_info, FLAG_REMOTE_ABORT)) {
 771                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Acknowledging remote abort\n");
 772                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_REMOTE_REL)) {
 773                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Acknowledging remote hangup\n");
 774                                 sngisdn_snd_release(ftdmchan, 0);
 775                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_LOCAL_ABORT)) {
 776                                 /* We aborted this call before sending anything to the stack, so nothing to do anymore */
 777                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Clearing local states from local abort\n");
 778                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_GLARE)) {
 779                                 /* We are hangup local call because there was a glare, we are waiting for a
 780                                 RELEASE on this call, before we can process the saved call */
 781                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Waiting for RELEASE on hungup glared call\n");
 782                         } else if (sngisdn_test_flag(sngisdn_info, FLAG_SEND_DISC)) {
 783                                 /* Remote side sent a PROGRESS message, but cause indicates disconnect or T310 expired*/
 784                                 sngisdn_snd_disconnect(ftdmchan);
 785                         } else {
 786                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Hanging up call upon local request!\n");
 787 
 788                                  /* set the flag to indicate this hangup is started from the local side */
 789                                 sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_REL);
 790 
 791                                 switch(ftdmchan->last_state) {
 792                                         case FTDM_CHANNEL_STATE_RING:
 793                                                 /* If we never sent PROCEED/ALERT/PROGRESS/CONNECT on an incoming call, we need to send release instead of disconnect */
 794                                                 sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
 795                                                 sngisdn_snd_release(ftdmchan, 0);
 796                                                 break;
 797                                         case FTDM_CHANNEL_STATE_DIALING:
 798                                                 /* If we never received a PROCEED/ALERT/PROGRESS/CONNECT on an outgoing call, we need to send release instead of disconnect */
 799                                                 sngisdn_snd_release(ftdmchan, 0);
 800                                                 break;
 801                                         default:
 802                                                 sngisdn_snd_disconnect(ftdmchan);
 803                                                 break;
 804                                 }
 805                         }
 806                         /* now go to the HANGUP complete state */
 807                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
 808                 }
 809                 break;
 810         case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
 811                 {
 812                         if (sngisdn_test_flag(sngisdn_info, FLAG_REMOTE_ABORT) ||
 813                                 sngisdn_test_flag(sngisdn_info, FLAG_LOCAL_ABORT)) {
 814                                 /* If the remote side aborted, we will not get anymore message for this call */
 815                                 ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 816                         } else {
 817                                 /* waiting on remote confirmation before moving to down */
 818                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Waiting for release from stack\n");
 819                         }
 820                 }
 821                 break;
 822         case FTDM_CHANNEL_STATE_DOWN: /* the call is finished and removed */
 823                 {
 824                         uint8_t glare = sngisdn_test_flag(sngisdn_info, FLAG_GLARE);
 825                         /* clear all of the call specific data store in the channel structure */
 826                         clear_call_data(sngisdn_info);
 827 
 828                         /* Close the channel even if we had a glare, we will re-open it when processing state COLLECT for the
 829                                 "glared call" */
 830                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OPEN)) {
 831                                 ftdm_channel_t *close_chan = ftdmchan;
 832                                 /* close the channel */
 833                                 ftdm_channel_close(&close_chan);
 834                         }
 835                         if (glare) {
 836 
 837                                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Glare detected, processing saved call\n");
 838                                 /* We are calling sngisdn_rcv_con_ind with ftdmchan->mutex being locked,
 839                                         so no other threads will be able to touch this channel. The next time we will
 840                                         process this channel is in this function, and it should be in state COLLECT (set inside
 841                                         sngisdn_rcv_con_ind)*/
 842                                 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);
 843                         }
 844                 }
 845                 break;
 846         case FTDM_CHANNEL_STATE_RESTART:
 847                 {
 848                         /* IMPLEMENT ME */
 849                 }
 850 
 851                 break;
 852         case FTDM_CHANNEL_STATE_SUSPENDED:
 853                 {
 854                         /* IMPLEMENT ME */
 855                 }
 856                 break;
 857         case FTDM_CHANNEL_STATE_RESET:
 858                 {
 859                         sngisdn_snd_restart(ftdmchan);
 860                 }
 861                 break;
 862         default:
 863                 {
 864                         ftdm_log_chan(ftdmchan, FTDM_LOG_CRIT, "unsupported sngisdn_rcvd state %s\n", ftdm_channel_state2str(ftdmchan->state));
 865                 }
 866                 break;
 867         }
 868         
 869         if (ftdmchan->state == initial_state) {
 870                 ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "state change flag is still set, but we did not change state\n");
 871         }
 872 #ifdef FTDM_DEBUG_CHAN_MEMORY
 873         if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALING) {
 874                 ftdm_assert(mprotect(ftdmchan, sizeof(*ftdmchan), PROT_READ|PROT_WRITE) == 0, "Failed to mprotect");
 875         }
 876 #endif
 877         return FTDM_SUCCESS;
 878 }
 879 
 880 static FIO_CHANNEL_SEND_MSG_FUNCTION(ftdm_sangoma_isdn_send_msg)
 881 {
 882         ftdm_status_t status = FTDM_FAIL;
 883 
 884         switch (sigmsg->event_id) {
 885                 case FTDM_SIGEVENT_FACILITY:
 886                         sngisdn_snd_fac_req(ftdmchan);
 887                         status = FTDM_SUCCESS;
 888                         break;
 889                 default:
 890                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Unsupported signalling msg requested\n");
 891                         status = FTDM_BREAK;
 892         }
 893         ftdm_call_clear_data(&ftdmchan->caller_data);
 894         return status;
 895 }
 896 
 897 static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_isdn_outgoing_call)
 898 {
 899         sngisdn_chan_data_t  *sngisdn_info = ftdmchan->call_data;
 900         ftdm_status_t status = FTDM_FAIL;       
 901         
 902         /* lock the channel while we check whether it is availble */
 903         ftdm_channel_lock(ftdmchan);
 904 
 905         switch (ftdmchan->state) {
 906 
 907                 case FTDM_CHANNEL_STATE_DOWN:
 908                         {
 909                                 if (sngisdn_test_flag(sngisdn_info, FLAG_GLARE)) {
 910                                         /* A call came in after we called ftdm_channel_open_chan for this call, but before we got here */
 911                                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Glare detected - aborting outgoing call\n");
 912 
 913                                         sngisdn_set_flag(sngisdn_info, FLAG_LOCAL_ABORT);
 914                                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
 915 
 916                                         status = FTDM_BREAK;
 917                                 } else {
 918                                         ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
 919                                         status = FTDM_SUCCESS;
 920                                 }
 921                         }
 922                         break;
 923                 default:
 924                 {
 925                         /* the channel is already used...this can't be, end the request */
 926                         ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Outgoing call requested channel in already in use\n");
 927                         status = FTDM_BREAK;
 928                 }
 929                 break;            
 930         }
 931 
 932         ftdm_channel_unlock(ftdmchan);
 933         return status;
 934 }
 935 static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_chan_sig_status)
 936 {
 937         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_SIG_UP)) {
 938                 *status = FTDM_SIG_STATE_UP;
 939         } else {
 940                 *status = FTDM_SIG_STATE_DOWN;
 941         }
 942 
 943         return FTDM_SUCCESS;
 944 }
 945 
 946 static FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_chan_sig_status)
 947 {
 948         ftdm_log(FTDM_LOG_ERROR,"Cannot set channel status in this module\n");
 949         return FTDM_NOTIMPL;
 950 }
 951 
 952 static FIO_SPAN_GET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_get_span_sig_status)
 953 {       
 954         if (ftdm_test_flag(span->channels[1], FTDM_CHANNEL_SIG_UP)) {
 955                 *status = FTDM_SIG_STATE_UP;
 956         } else {
 957                 *status = FTDM_SIG_STATE_DOWN;
 958         }
 959 
 960         return FTDM_SUCCESS;
 961 }
 962 
 963 static FIO_SPAN_SET_SIG_STATUS_FUNCTION(ftdm_sangoma_isdn_set_span_sig_status)
 964 {
 965         ftdm_log(FTDM_LOG_ERROR,"Cannot set span status in this module\n");
 966         return FTDM_NOTIMPL;
 967 }
 968 
 969 static ftdm_status_t ftdm_sangoma_isdn_start(ftdm_span_t *span)
 970 {
 971         sngisdn_span_data_t *signal_data = span->signal_data;
 972         ftdm_log(FTDM_LOG_INFO,"Starting span %s:%u.\n",span->name,span->span_id);
 973         if (sngisdn_stack_start(span) != FTDM_SUCCESS) {
 974                 ftdm_log(FTDM_LOG_CRIT, "Failed to start span %s\n", span->name);
 975                 return FTDM_FAIL;
 976         }
 977         /* clear the monitor thread stop flag */
 978         ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
 979         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
 980 
 981         if (signal_data->raw_trace_q921 == SNGISDN_OPT_TRUE) {
 982                 sngisdn_activate_trace(span, SNGISDN_TRACE_Q921);
 983         }
 984         
 985         if (signal_data->raw_trace_q931 == SNGISDN_OPT_TRUE) {
 986                 sngisdn_activate_trace(span, SNGISDN_TRACE_Q931);
 987         }
 988 
 989         /*start the span monitor thread*/
 990         if (ftdm_thread_create_detached(ftdm_sangoma_isdn_run, span) != FTDM_SUCCESS) {
 991                 ftdm_log(FTDM_LOG_CRIT,"Failed to start Sangoma ISDN Span Monitor Thread!\n");
 992                 return FTDM_FAIL;
 993         }
 994 
 995         /*start the dchan monitor thread*/
 996         if (ftdm_thread_create_detached(ftdm_sangoma_isdn_dchan_run, span) != FTDM_SUCCESS) {
 997                 ftdm_log(FTDM_LOG_CRIT,"Failed to start Sangoma ISDN d-channel Monitor Thread!\n");
 998                 return FTDM_FAIL;
 999         }
1000 
1001         ftdm_log(FTDM_LOG_DEBUG,"Finished starting span %s\n", span->name);
1002         return FTDM_SUCCESS;
1003 }
1004 
1005 static ftdm_status_t ftdm_sangoma_isdn_stop(ftdm_span_t *span)
1006 {       
1007         ftdm_iterator_t *chaniter = NULL;
1008         ftdm_iterator_t *curr = NULL;
1009         unsigned i;
1010         sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) span->signal_data;
1011         ftdm_log(FTDM_LOG_INFO, "Stopping span %s\n", span->name);
1012         
1013         /* throw the STOP_THREAD flag to signal monitor thread stop */
1014         ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
1015 
1016         /* wait for the thread to stop */
1017         while (ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
1018                 ftdm_log(FTDM_LOG_DEBUG, "Waiting for monitor thread to end for span %s\n", span->name);
1019                 ftdm_sleep(10);
1020         }
1021 
1022         if (sngisdn_stack_stop(span) != FTDM_SUCCESS) {
1023                 ftdm_log(FTDM_LOG_CRIT, "Failed to stop span %s\n", span->name);
1024         }
1025         
1026         chaniter = ftdm_span_get_chan_iterator(span, NULL);
1027         for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
1028                 ftdm_safe_free(((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data);
1029                 ((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data = NULL;
1030         }
1031         ftdm_iterator_free(chaniter);
1032 
1033         ftdm_sched_destroy(&signal_data->sched);
1034         ftdm_queue_destroy(&signal_data->event_queue);
1035         for (i = 0 ; i < signal_data->num_local_numbers ; i++) {
1036                 if (signal_data->local_numbers[i] != NULL) {
1037                         ftdm_safe_free(signal_data->local_numbers[i]);
1038                 }
1039         }
1040         ftdm_safe_free(span->signal_data);
1041 
1042         ftdm_log(FTDM_LOG_DEBUG, "Finished stopping span %s\n", span->name);
1043 
1044         return FTDM_SUCCESS;
1045 }
1046 
1047 static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
1048 {
1049         ftdm_iterator_t *chaniter = NULL;
1050         ftdm_iterator_t *curr = NULL;
1051 
1052         sngisdn_span_data_t *span_data;
1053         
1054         ftdm_log(FTDM_LOG_INFO, "Configuring ftmod_sangoma_isdn span = %s\n", span->name);      
1055 
1056         span_data = ftdm_calloc(1, sizeof(sngisdn_span_data_t));
1057         span_data->ftdm_span = span;
1058         span->signal_data = span_data;
1059         
1060         chaniter = ftdm_span_get_chan_iterator(span, NULL);
1061         for (curr = chaniter; curr; curr = ftdm_iterator_next(curr)) {
1062                 sngisdn_chan_data_t *chan_data = ftdm_calloc(1, sizeof(sngisdn_chan_data_t));
1063                 chan_data->ftdmchan = ((ftdm_channel_t*)ftdm_iterator_current(curr));
1064                 ((ftdm_channel_t*)ftdm_iterator_current(curr))->call_data = chan_data;
1065                 
1066         }
1067         ftdm_iterator_free(chaniter);
1068 
1069         if (ftmod_isdn_parse_cfg(ftdm_parameters, span) != FTDM_SUCCESS) {
1070                 ftdm_log(FTDM_LOG_ERROR, "Failed to parse configuration\n");
1071                 return FTDM_FAIL;
1072         }
1073 
1074         if (sngisdn_stack_cfg(span) != FTDM_SUCCESS) {
1075                 ftdm_log(FTDM_LOG_CRIT, "Sangoma ISDN Stack configuration failed\n");
1076                 return FTDM_FAIL;
1077         }
1078 
1079 
1080         span->start = ftdm_sangoma_isdn_start;
1081         span->stop = ftdm_sangoma_isdn_stop;
1082         span->signal_type = FTDM_SIGTYPE_ISDN;
1083         span->outgoing_call = ftdm_sangoma_isdn_outgoing_call;
1084         span->send_msg = ftdm_sangoma_isdn_send_msg;
1085         span->channel_request = NULL;
1086         span->signal_cb = sig_cb;
1087         span->get_channel_sig_status = ftdm_sangoma_isdn_get_chan_sig_status;
1088         span->set_channel_sig_status = ftdm_sangoma_isdn_set_chan_sig_status;
1089         span->get_span_sig_status = ftdm_sangoma_isdn_get_span_sig_status;
1090         span->set_span_sig_status = ftdm_sangoma_isdn_set_span_sig_status;
1091         span->state_map = &sangoma_isdn_state_map;
1092         span->state_processor = ftdm_sangoma_isdn_process_state_change;
1093         ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
1094         ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
1095         ftdm_set_flag(span, FTDM_SPAN_USE_PROCEED_STATE);
1096         ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
1097         ftdm_set_flag(span, FTDM_SPAN_NON_STOPPABLE);
1098 
1099         if (span->trunk_type == FTDM_TRUNK_BRI_PTMP ||
1100                 span->trunk_type == FTDM_TRUNK_BRI) {
1101                 
1102                 sngisdn_set_span_avail_rate(span, SNGISDN_AVAIL_PWR_SAVING);
1103         }
1104 
1105         /* Initialize scheduling context */
1106         ftdm_assert(ftdm_sched_create(&((sngisdn_span_data_t*)span->signal_data)->sched, "sngisdn_schedule") == FTDM_SUCCESS, "Failed to create a new schedule!!");
1107 
1108         /* Initialize the event queue */
1109         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!!");
1110 
1111         ftdm_log(FTDM_LOG_INFO, "Finished configuring ftmod_sangoma_isdn span = %s\n", span->name);
1112         return FTDM_SUCCESS;
1113 }
1114 
1115 static FIO_SIG_LOAD_FUNCTION(ftdm_sangoma_isdn_init)
1116 {
1117         unsigned i;
1118         ftdm_log(FTDM_LOG_INFO, "Loading ftmod_sangoma_isdn...\n");
1119 
1120         memset(&g_sngisdn_data, 0, sizeof(g_sngisdn_data));
1121         memset(&g_sngisdn_event_interface, 0, sizeof(g_sngisdn_event_interface));
1122         /* set callbacks */
1123         g_sngisdn_event_interface.cc.sng_con_ind        = sngisdn_rcv_con_ind;
1124         g_sngisdn_event_interface.cc.sng_con_cfm        = sngisdn_rcv_con_cfm;
1125         g_sngisdn_event_interface.cc.sng_cnst_ind       = sngisdn_rcv_cnst_ind;
1126         g_sngisdn_event_interface.cc.sng_disc_ind       = sngisdn_rcv_disc_ind;
1127         g_sngisdn_event_interface.cc.sng_rel_ind        = sngisdn_rcv_rel_ind;
1128         g_sngisdn_event_interface.cc.sng_dat_ind        = sngisdn_rcv_dat_ind;
1129         g_sngisdn_event_interface.cc.sng_sshl_ind       = sngisdn_rcv_sshl_ind;
1130         g_sngisdn_event_interface.cc.sng_sshl_cfm       = sngisdn_rcv_sshl_cfm;
1131         g_sngisdn_event_interface.cc.sng_rmrt_ind       = sngisdn_rcv_rmrt_ind;
1132         g_sngisdn_event_interface.cc.sng_rmrt_cfm       = sngisdn_rcv_rmrt_cfm;
1133         g_sngisdn_event_interface.cc.sng_flc_ind        = sngisdn_rcv_flc_ind;
1134         g_sngisdn_event_interface.cc.sng_fac_ind        = sngisdn_rcv_fac_ind;
1135         g_sngisdn_event_interface.cc.sng_sta_cfm        = sngisdn_rcv_sta_cfm;
1136         g_sngisdn_event_interface.cc.sng_srv_ind        = sngisdn_rcv_srv_ind;
1137         g_sngisdn_event_interface.cc.sng_srv_ind        = sngisdn_rcv_srv_cfm;
1138         g_sngisdn_event_interface.cc.sng_rst_ind        = sngisdn_rcv_rst_cfm;
1139         g_sngisdn_event_interface.cc.sng_rst_ind        = sngisdn_rcv_rst_ind;
1140         g_sngisdn_event_interface.cc.sng_rst_cfm        = sngisdn_rcv_rst_cfm;
1141 
1142         g_sngisdn_event_interface.lg.sng_log            = sngisdn_rcv_sng_log;
1143         g_sngisdn_event_interface.lg.sng_assert         = sngisdn_rcv_sng_assert;
1144         
1145         g_sngisdn_event_interface.sta.sng_phy_sta_ind   = sngisdn_rcv_phy_ind;
1146         g_sngisdn_event_interface.sta.sng_q921_sta_ind  = sngisdn_rcv_q921_ind;
1147         g_sngisdn_event_interface.sta.sng_q921_trc_ind  = sngisdn_rcv_q921_trace;
1148         g_sngisdn_event_interface.sta.sng_q931_sta_ind  = sngisdn_rcv_q931_ind;
1149         g_sngisdn_event_interface.sta.sng_q931_trc_ind  = sngisdn_rcv_q931_trace;
1150         g_sngisdn_event_interface.sta.sng_cc_sta_ind    = sngisdn_rcv_cc_ind;
1151 
1152         g_sngisdn_event_interface.io.sng_l1_data_req    = sngisdn_rcv_l1_data_req;
1153         g_sngisdn_event_interface.io.sng_l1_cmd_req             = sngisdn_rcv_l1_cmd_req;
1154         
1155         for(i=1;i<=MAX_VARIANTS;i++) {          
1156                 ftdm_mutex_create(&g_sngisdn_data.ccs[i].mutex);
1157         }
1158         
1159         /* initalize sng_isdn library */
1160 
1161         ftdm_assert_return(!sng_isdn_init(&g_sngisdn_event_interface), FTDM_FAIL, "Failed to initialize stack\n");
1162         return FTDM_SUCCESS;
1163 }
1164 
1165 static FIO_SIG_UNLOAD_FUNCTION(ftdm_sangoma_isdn_unload)
1166 {
1167         unsigned i;
1168         ftdm_log(FTDM_LOG_INFO, "Starting ftmod_sangoma_isdn unload...\n");
1169 
1170         sng_isdn_free();
1171         
1172         for(i=1;i<=MAX_VARIANTS;i++) {          
1173                 ftdm_mutex_destroy(&g_sngisdn_data.ccs[i].mutex);
1174         }
1175 
1176         ftdm_log(FTDM_LOG_INFO, "Finished ftmod_sangoma_isdn unload!\n");
1177         return FTDM_SUCCESS;
1178 }
1179 
1180 static FIO_API_FUNCTION(ftdm_sangoma_isdn_api)
1181 {
1182         ftdm_status_t status = FTDM_SUCCESS;
1183         char *mycmd = NULL, *argv[10] = { 0 };
1184         int argc = 0;
1185 
1186         if (data) {
1187                 mycmd = ftdm_strdup(data);
1188                 argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
1189         }
1190 
1191         /*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]);*/
1192         if (argc <= 0) {
1193                 ftdm_log(FTDM_LOG_ERROR, "No parameters provided\n");
1194                 goto done;
1195         }
1196 
1197         /* TODO: Move functions to table + function pointers */
1198         if (!strcasecmp(argv[0], "trace")) {
1199                 char *trace_opt;
1200                 
1201                 ftdm_span_t *span;
1202 
1203                 if (argc < 3) {
1204                         ftdm_log(FTDM_LOG_ERROR, "Usage: ftdm sangoma_isdn trace <q921|q931> <span name>\n");
1205                         status = FTDM_FAIL;
1206                         goto done;
1207                 }
1208                 trace_opt = argv[1];
1209                 
1210                 status = ftdm_span_find_by_name(argv[2], &span);
1211                 if (FTDM_SUCCESS != status) {
1212                         stream->write_function(stream, "-ERR failed to find span by name %s\n", argv[2]);
1213                         goto done;
1214                 }
1215                 
1216                 if (!strcasecmp(trace_opt, "q921")) {
1217                         sngisdn_activate_trace(span, SNGISDN_TRACE_Q921);
1218                 } else if (!strcasecmp(trace_opt, "q931")) {
1219                         sngisdn_activate_trace(span, SNGISDN_TRACE_Q931);
1220                 } else if (!strcasecmp(trace_opt, "disable")) {
1221                         sngisdn_activate_trace(span, SNGISDN_TRACE_DISABLE);
1222                 } else {
1223                         stream->write_function(stream, "-ERR invalid trace option <q921|q931> <span name>\n");
1224                 }
1225         }
1226         if (!strcasecmp(argv[0], "l1_stats")) {
1227                 ftdm_span_t *span;
1228                 if (argc < 2) {
1229                         stream->write_function(stream, "Usage: ftdm sangoma_isdn l1_stats <span name>\n");
1230                         status = FTDM_FAIL;
1231                         goto done;
1232                 }
1233                 status = ftdm_span_find_by_name(argv[1], &span);
1234                 if (FTDM_SUCCESS != status) {
1235                         stream->write_function(stream, "-ERR failed to find span with name %s\n", argv[1]);
1236                         /* Return SUCCESS because we do not want to print the general FTDM usage list */
1237                         status = FTDM_SUCCESS; 
1238                         goto done;
1239                 }
1240                 sngisdn_print_phy_stats(stream, span);
1241         }
1242         
1243         if (!strcasecmp(argv[0], "show_spans")) {
1244                 ftdm_span_t *span = NULL;
1245                 if (argc == 2) {
1246                         status = ftdm_span_find_by_name(argv[1], &span);
1247                         if (FTDM_SUCCESS != status) {
1248                                 stream->write_function(stream, "-ERR failed to find span with name %s\n", argv[1]);
1249                                 /* Return SUCCESS because we do not want to print the general FTDM usage list */
1250                                 status = FTDM_SUCCESS;
1251                                 goto done;
1252                         }
1253                         sngisdn_print_span(stream, span);
1254                         status = FTDM_SUCCESS;
1255                         goto done;
1256                 }
1257                 sngisdn_print_spans(stream);
1258         }
1259         if (!strcasecmp(argv[0], "check_ids")) {
1260                 sngisdn_check_free_ids();
1261         }
1262 done:
1263         ftdm_safe_free(mycmd);
1264         return status;
1265 }
1266 
1267 static FIO_IO_LOAD_FUNCTION(ftdm_sangoma_isdn_io_init)
1268 {
1269         memset(&g_sngisdn_io_interface, 0, sizeof(g_sngisdn_io_interface));
1270 
1271         g_sngisdn_io_interface.name = "sangoma_isdn";
1272         g_sngisdn_io_interface.api = ftdm_sangoma_isdn_api;
1273 
1274         *fio = &g_sngisdn_io_interface;
1275 
1276         return FTDM_SUCCESS;
1277 }
1278 
1279 EX_DECLARE_DATA ftdm_module_t ftdm_module =
1280 {
1281         "sangoma_isdn",                /* char name[256]; */
1282         ftdm_sangoma_isdn_io_init,     /* fio_io_load_t */
1283         NULL,                                              /* fio_io_unload_t */
1284         ftdm_sangoma_isdn_init,        /* fio_sig_load_t */
1285         NULL,                          /* fio_sig_configure_t */
1286         ftdm_sangoma_isdn_unload,      /* fio_sig_unload_t */
1287         ftdm_sangoma_isdn_span_config  /* fio_configure_span_signaling_t */
1288 };
1289 
1290 
1291 /* For Emacs:
1292  * Local Variables:
1293  * mode:c
1294  * indent-tabs-mode:t
1295  * tab-width:4
1296  * c-basic-offset:4
1297  * End:
1298  * For VIM:
1299  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
1300  */
1301 
1302 /******************************************************************************/
1303 
1304 

/* [<][>][^][v][top][bottom][index][help] */