root/src/ftmod/ftmod_zt/ftmod_zt.c

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

DEFINITIONS

This source file includes following definitions.
  1. zt_build_gains
  2. zt_open_range
  3. FIO_CONFIGURE_SPAN_FUNCTION
  4. FIO_CONFIGURE_FUNCTION
  5. FIO_OPEN_FUNCTION
  6. FIO_CLOSE_FUNCTION
  7. FIO_COMMAND_FUNCTION
  8. FIO_GET_ALARMS_FUNCTION
  9. FIO_WAIT_FUNCTION
  10. FIO_SPAN_POLL_EVENT_FUNCTION
  11. zt_channel_process_event
  12. FIO_CHANNEL_NEXT_EVENT_FUNCTION
  13. FIO_SPAN_NEXT_EVENT_FUNCTION
  14. FIO_READ_FUNCTION
  15. FIO_WRITE_FUNCTION
  16. FIO_CHANNEL_DESTROY_FUNCTION
  17. FIO_IO_LOAD_FUNCTION
  18. FIO_IO_UNLOAD_FUNCTION

   1 /*
   2  * Copyright (c) 2007, Anthony Minessale II
   3  * All rights reserved.
   4  * 
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 
   9  * * Redistributions of source code must retain the above copyright
  10  * notice, this list of conditions and the following disclaimer.
  11  * 
  12  * * Redistributions in binary form must reproduce the above copyright
  13  * notice, this list of conditions and the following disclaimer in the
  14  * documentation and/or other materials provided with the distribution.
  15  * 
  16  * * Neither the name of the original author; nor the names of any contributors
  17  * may be used to endorse or promote products derived from this software
  18  * without specific prior written permission.
  19  * 
  20  * 
  21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
  25  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  */
  33 
  34 #include "private/ftdm_core.h"
  35 #include "ftmod_zt.h"
  36 
  37 /* used by dahdi to indicate there is no data available, but events to read */
  38 #ifndef ELAST
  39 #define ELAST 500
  40 #endif
  41 
  42 /**
  43  * \brief Zaptel globals
  44  */
  45 static struct {
  46         uint32_t codec_ms;
  47         uint32_t wink_ms;
  48         uint32_t flash_ms;
  49         uint32_t eclevel;
  50         uint32_t etlevel;
  51     float rxgain;
  52     float txgain;
  53 } zt_globals;
  54 
  55 #if defined(__FreeBSD__)
  56 typedef unsigned long ioctlcmd;
  57 #else
  58 typedef int ioctlcmd;
  59 #endif
  60 
  61 /**
  62  * \brief General IOCTL codes
  63  */
  64 struct ioctl_codes {
  65     ioctlcmd GET_BLOCKSIZE;
  66     ioctlcmd SET_BLOCKSIZE;
  67     ioctlcmd FLUSH;
  68     ioctlcmd SYNC;
  69     ioctlcmd GET_PARAMS;
  70     ioctlcmd SET_PARAMS;
  71     ioctlcmd HOOK;
  72     ioctlcmd GETEVENT;
  73     ioctlcmd IOMUX;
  74     ioctlcmd SPANSTAT;
  75     ioctlcmd MAINT;
  76     ioctlcmd GETCONF;
  77     ioctlcmd SETCONF;
  78     ioctlcmd CONFLINK;
  79     ioctlcmd CONFDIAG;
  80     ioctlcmd GETGAINS;
  81     ioctlcmd SETGAINS;
  82     ioctlcmd SPANCONFIG;
  83     ioctlcmd CHANCONFIG;
  84     ioctlcmd SET_BUFINFO;
  85     ioctlcmd GET_BUFINFO;
  86     ioctlcmd AUDIOMODE;
  87     ioctlcmd ECHOCANCEL;
  88     ioctlcmd HDLCRAWMODE;
  89     ioctlcmd HDLCFCSMODE;
  90     ioctlcmd SPECIFY;
  91     ioctlcmd SETLAW;
  92     ioctlcmd SETLINEAR;
  93     ioctlcmd GETCONFMUTE;
  94     ioctlcmd ECHOTRAIN;
  95     ioctlcmd SETTXBITS;
  96     ioctlcmd GETRXBITS;
  97 };
  98 
  99 /**
 100  * \brief Zaptel IOCTL codes
 101  */
 102 static struct ioctl_codes zt_ioctl_codes = {
 103     .GET_BLOCKSIZE = ZT_GET_BLOCKSIZE,
 104     .SET_BLOCKSIZE = ZT_SET_BLOCKSIZE,
 105     .FLUSH = ZT_FLUSH,
 106     .SYNC = ZT_SYNC,
 107     .GET_PARAMS = ZT_GET_PARAMS,
 108     .SET_PARAMS = ZT_SET_PARAMS,
 109     .HOOK = ZT_HOOK,
 110     .GETEVENT = ZT_GETEVENT,
 111     .IOMUX = ZT_IOMUX,
 112     .SPANSTAT = ZT_SPANSTAT,
 113     .MAINT = ZT_MAINT,
 114     .GETCONF = ZT_GETCONF,
 115     .SETCONF = ZT_SETCONF,
 116     .CONFLINK = ZT_CONFLINK,
 117     .CONFDIAG = ZT_CONFDIAG,
 118     .GETGAINS = ZT_GETGAINS,
 119     .SETGAINS = ZT_SETGAINS,
 120     .SPANCONFIG = ZT_SPANCONFIG,
 121     .CHANCONFIG = ZT_CHANCONFIG,
 122     .SET_BUFINFO = ZT_SET_BUFINFO,
 123     .GET_BUFINFO = ZT_GET_BUFINFO,
 124     .AUDIOMODE = ZT_AUDIOMODE,
 125     .ECHOCANCEL = ZT_ECHOCANCEL,
 126     .HDLCRAWMODE = ZT_HDLCRAWMODE,
 127     .HDLCFCSMODE = ZT_HDLCFCSMODE,
 128     .SPECIFY = ZT_SPECIFY,
 129     .SETLAW = ZT_SETLAW,
 130     .SETLINEAR = ZT_SETLINEAR,
 131     .GETCONFMUTE = ZT_GETCONFMUTE,
 132     .ECHOTRAIN = ZT_ECHOTRAIN,
 133     .SETTXBITS = ZT_SETTXBITS,
 134     .GETRXBITS = ZT_GETRXBITS
 135 };
 136 
 137 /**
 138  * \brief Dahdi IOCTL codes
 139  */
 140 static struct ioctl_codes dahdi_ioctl_codes = {
 141     .GET_BLOCKSIZE = DAHDI_GET_BLOCKSIZE,
 142     .SET_BLOCKSIZE = DAHDI_SET_BLOCKSIZE,
 143     .FLUSH = DAHDI_FLUSH,
 144     .SYNC = DAHDI_SYNC,
 145     .GET_PARAMS = DAHDI_GET_PARAMS,
 146     .SET_PARAMS = DAHDI_SET_PARAMS,
 147     .HOOK = DAHDI_HOOK,
 148     .GETEVENT = DAHDI_GETEVENT,
 149     .IOMUX = DAHDI_IOMUX,
 150     .SPANSTAT = DAHDI_SPANSTAT,
 151     .MAINT = DAHDI_MAINT,
 152     .GETCONF = DAHDI_GETCONF,
 153     .SETCONF = DAHDI_SETCONF,
 154     .CONFLINK = DAHDI_CONFLINK,
 155     .CONFDIAG = DAHDI_CONFDIAG,
 156     .GETGAINS = DAHDI_GETGAINS,
 157     .SETGAINS = DAHDI_SETGAINS,
 158     .SPANCONFIG = DAHDI_SPANCONFIG,
 159     .CHANCONFIG = DAHDI_CHANCONFIG,
 160     .SET_BUFINFO = DAHDI_SET_BUFINFO,
 161     .GET_BUFINFO = DAHDI_GET_BUFINFO,
 162     .AUDIOMODE = DAHDI_AUDIOMODE,
 163     .ECHOCANCEL = DAHDI_ECHOCANCEL,
 164     .HDLCRAWMODE = DAHDI_HDLCRAWMODE,
 165     .HDLCFCSMODE = DAHDI_HDLCFCSMODE,
 166     .SPECIFY = DAHDI_SPECIFY,
 167     .SETLAW = DAHDI_SETLAW,
 168     .SETLINEAR = DAHDI_SETLINEAR,
 169     .GETCONFMUTE = DAHDI_GETCONFMUTE,
 170     .ECHOTRAIN = DAHDI_ECHOTRAIN,
 171     .SETTXBITS = DAHDI_SETTXBITS,
 172     .GETRXBITS = DAHDI_GETRXBITS
 173 };
 174 
 175 #define ZT_INVALID_SOCKET -1
 176 static struct ioctl_codes codes;
 177 static const char *ctlpath = NULL;
 178 static const char *chanpath = NULL;
 179 
 180 static const char dahdi_ctlpath[] = "/dev/dahdi/ctl";
 181 static const char dahdi_chanpath[] = "/dev/dahdi/channel";
 182 
 183 static const char zt_ctlpath[] = "/dev/zap/ctl";
 184 static const char zt_chanpath[] = "/dev/zap/channel";
 185 
 186 static ftdm_socket_t CONTROL_FD = ZT_INVALID_SOCKET;
 187 
 188 FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event);
 189 FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event);
 190 FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event);
 191 
 192 /**
 193  * \brief Initialises codec, and rx/tx gains
 194  * \param g Structure for gains to be initialised
 195  * \param rxgain RX gain value
 196  * \param txgain TX gain value
 197  * \param codec Codec
 198  */
 199 static void zt_build_gains(struct zt_gains *g, float rxgain, float txgain, int codec)
 200 {
 201         int j;
 202         int k;
 203         float linear_rxgain = pow(10.0, rxgain / 20.0);
 204     float linear_txgain = pow(10.0, txgain / 20.0);
 205 
 206         switch (codec) {
 207         case FTDM_CODEC_ALAW:
 208                 for (j = 0; j < (sizeof(g->receive_gain) / sizeof(g->receive_gain[0])); j++) {
 209                         if (rxgain) {
 210                                 k = (int) (((float) alaw_to_linear(j)) * linear_rxgain);
 211                                 if (k > 32767) k = 32767;
 212                                 if (k < -32767) k = -32767;
 213                                 g->receive_gain[j] = linear_to_alaw(k);
 214                         } else {
 215                                 g->receive_gain[j] = j;
 216                         }
 217                         if (txgain) {
 218                                 k = (int) (((float) alaw_to_linear(j)) * linear_txgain);
 219                                 if (k > 32767) k = 32767;
 220                                 if (k < -32767) k = -32767;
 221                                 g->transmit_gain[j] = linear_to_alaw(k);
 222                         } else {
 223                                 g->transmit_gain[j] = j;
 224                         }
 225                 }
 226                 break;
 227         case FTDM_CODEC_ULAW:
 228                 for (j = 0; j < (sizeof(g->receive_gain) / sizeof(g->receive_gain[0])); j++) {
 229                         if (rxgain) {
 230                                 k = (int) (((float) ulaw_to_linear(j)) * linear_rxgain);
 231                                 if (k > 32767) k = 32767;
 232                                 if (k < -32767) k = -32767;
 233                                 g->receive_gain[j] = linear_to_ulaw(k);
 234                         } else {
 235                                 g->receive_gain[j] = j;
 236                         }
 237                         if (txgain) {
 238                                 k = (int) (((float) ulaw_to_linear(j)) * linear_txgain);
 239                                 if (k > 32767) k = 32767;
 240                                 if (k < -32767) k = -32767;
 241                                 g->transmit_gain[j] = linear_to_ulaw(k);
 242                         } else {
 243                                 g->transmit_gain[j] = j;
 244                         }
 245                 }
 246                 break;
 247         }
 248 }
 249 
 250 /**
 251  * \brief Initialises a range of ftdmtel channels
 252  * \param span FreeTDM span
 253  * \param start Initial wanpipe channel number
 254  * \param end Final wanpipe channel number
 255  * \param type FreeTDM channel type
 256  * \param name FreeTDM span name
 257  * \param number FreeTDM span number
 258  * \param cas_bits CAS bits
 259  * \return number of spans configured
 260  */
 261 static unsigned zt_open_range(ftdm_span_t *span, unsigned start, unsigned end, ftdm_chan_type_t type, char *name, char *number, unsigned char cas_bits)
 262 {
 263         unsigned configured = 0, x;
 264         zt_params_t ztp;
 265 
 266         memset(&ztp, 0, sizeof(ztp));
 267 
 268         if (type == FTDM_CHAN_TYPE_CAS) {
 269                 ftdm_log(FTDM_LOG_DEBUG, "Configuring CAS channels with abcd == 0x%X\n", cas_bits);
 270         }       
 271         for(x = start; x < end; x++) {
 272                 ftdm_channel_t *ftdmchan;
 273                 ftdm_socket_t sockfd = ZT_INVALID_SOCKET;
 274                 int len;
 275 
 276                 sockfd = open(chanpath, O_RDWR);
 277                 if (sockfd != ZT_INVALID_SOCKET && ftdm_span_add_channel(span, sockfd, type, &ftdmchan) == FTDM_SUCCESS) {
 278 
 279                         if (ioctl(sockfd, codes.SPECIFY, &x)) {
 280                                 ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s chan %d fd %d (%s)\n", chanpath, x, sockfd, strerror(errno));
 281                                 close(sockfd);
 282                                 continue;
 283                         }
 284 
 285                         if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
 286                                 struct zt_bufferinfo binfo;
 287                                 memset(&binfo, 0, sizeof(binfo));
 288                                 binfo.txbufpolicy = 0;
 289                                 binfo.rxbufpolicy = 0;
 290                                 binfo.numbufs = 32;
 291                                 binfo.bufsize = 1024;
 292                                 if (ioctl(sockfd, codes.SET_BUFINFO, &binfo)) {
 293                                         ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
 294                                         close(sockfd);
 295                                         continue;
 296                                 }
 297                         }
 298 
 299                         if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
 300                                 struct zt_chanconfig cc;
 301                                 memset(&cc, 0, sizeof(cc));
 302                                 cc.chan = cc.master = x;
 303                                 
 304                                 switch(type) {
 305                                 case FTDM_CHAN_TYPE_FXS:
 306                                         {
 307                                                 switch(span->start_type) {
 308                                                 case FTDM_ANALOG_START_KEWL:
 309                                                         cc.sigtype = ZT_SIG_FXOKS;
 310                                                         break;
 311                                                 case FTDM_ANALOG_START_LOOP:
 312                                                         cc.sigtype = ZT_SIG_FXOLS;
 313                                                         break;
 314                                                 case FTDM_ANALOG_START_GROUND:
 315                                                         cc.sigtype = ZT_SIG_FXOGS;
 316                                                         break;
 317                                                 default:
 318                                                         break;
 319                                                 }
 320                                         }
 321                                         break;
 322                                 case FTDM_CHAN_TYPE_FXO:
 323                                         {
 324                                                 switch(span->start_type) {
 325                                                 case FTDM_ANALOG_START_KEWL:
 326                                                         cc.sigtype = ZT_SIG_FXSKS;
 327                                                         break;
 328                                                 case FTDM_ANALOG_START_LOOP:
 329                                                         cc.sigtype = ZT_SIG_FXSLS;
 330                                                         break;
 331                                                 case FTDM_ANALOG_START_GROUND:
 332                                                         cc.sigtype = ZT_SIG_FXSGS;
 333                                                         break;
 334                                                 default:
 335                                                         break;
 336                                                 }
 337                                         }
 338                                         break;
 339                                 default:
 340                                         break;
 341                                 }
 342                                 
 343                                 if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
 344                                         ftdm_log(FTDM_LOG_WARNING, "this ioctl fails on older ftdmtel but is harmless if you used ztcfg\n[device %s chan %d fd %d (%s)]\n", chanpath, x, CONTROL_FD, strerror(errno));
 345                                 }
 346                         }
 347 
 348                         if (type == FTDM_CHAN_TYPE_CAS) {
 349                                 struct zt_chanconfig cc;
 350                                 memset(&cc, 0, sizeof(cc));
 351                                 cc.chan = cc.master = x;
 352                                 cc.sigtype = ZT_SIG_CAS;
 353                                 cc.idlebits = cas_bits;
 354                                 if (ioctl(CONTROL_FD, codes.CHANCONFIG, &cc)) {
 355                                         ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d err:%s", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd, strerror(errno));
 356                                         close(sockfd);
 357                                         continue;
 358                                 }
 359                         }
 360 
 361                         if (ftdmchan->type != FTDM_CHAN_TYPE_DQ921 && ftdmchan->type != FTDM_CHAN_TYPE_DQ931) {
 362                                 len = zt_globals.codec_ms * 8;
 363                                 if (ioctl(ftdmchan->sockfd, codes.SET_BLOCKSIZE, &len)) {
 364                                         ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d err:%s\n", 
 365                                                         chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd, strerror(errno));
 366                                         close(sockfd);
 367                                         continue;
 368                                 }
 369 
 370                                 ftdmchan->packet_len = len;
 371                                 ftdmchan->effective_interval = ftdmchan->native_interval = ftdmchan->packet_len / 8;
 372                         
 373                                 if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
 374                                         ftdmchan->packet_len *= 2;
 375                                 }
 376                         }
 377                         
 378                         if (ioctl(sockfd, codes.GET_PARAMS, &ztp) < 0) {
 379                                 ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
 380                                 close(sockfd);
 381                                 continue;
 382                         }
 383 
 384                         if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
 385                                 if (
 386                                         (ztp.sig_type != ZT_SIG_HDLCRAW) &&
 387                                         (ztp.sig_type != ZT_SIG_HDLCFCS) &&
 388                                         (ztp.sig_type != ZT_SIG_HARDHDLC)
 389                                         ) {
 390                                         ftdm_log(FTDM_LOG_ERROR, "Failure configuring device %s as FreeTDM device %d:%d fd:%d, hardware signaling is not HDLC, fix your Zap/DAHDI configuration!\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
 391                                         close(sockfd);
 392                                         continue;
 393                                 }
 394                         }
 395 
 396                         ftdm_log(FTDM_LOG_INFO, "configuring device %s channel %d as FreeTDM device %d:%d fd:%d\n", chanpath, x, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
 397                         
 398                         ftdmchan->rate = 8000;
 399                         ftdmchan->physical_span_id = ztp.span_no;
 400                         ftdmchan->physical_chan_id = ztp.chan_no;
 401                         
 402                         if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO || type == FTDM_CHAN_TYPE_EM || type == FTDM_CHAN_TYPE_B) {
 403                                 if (ztp.g711_type == ZT_G711_ALAW) {
 404                                         ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_ALAW;
 405                                 } else if (ztp.g711_type == ZT_G711_MULAW) {
 406                                         ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_ULAW;
 407                                 } else {
 408                                         int type;
 409 
 410                                         if (ftdmchan->span->trunk_type == FTDM_TRUNK_E1) {
 411                                                 type = FTDM_CODEC_ALAW;
 412                                         } else {
 413                                                 type = FTDM_CODEC_ULAW;
 414                                         }
 415 
 416                                         ftdmchan->native_codec = ftdmchan->effective_codec = type;
 417 
 418                                 }
 419                         }
 420 
 421                         ztp.wink_time = zt_globals.wink_ms;
 422                         ztp.flash_time = zt_globals.flash_ms;
 423 
 424                         if (ioctl(sockfd, codes.SET_PARAMS, &ztp) < 0) {
 425                                 ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, sockfd);
 426                                 close(sockfd);
 427                                 continue;
 428                         }
 429 
 430                         if (!ftdm_strlen_zero(name)) {
 431                                 ftdm_copy_string(ftdmchan->chan_name, name, sizeof(ftdmchan->chan_name));
 432                         }
 433                         if (!ftdm_strlen_zero(number)) {
 434                                 ftdm_copy_string(ftdmchan->chan_number, number, sizeof(ftdmchan->chan_number));
 435                         }
 436                         configured++;
 437                 } else {
 438                         ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s\n", chanpath);
 439                 }
 440         }
 441         
 442 
 443 
 444         return configured;
 445 }
 446 
 447 /**
 448  * \brief Initialises an freetdm ftdmtel span from a configuration string
 449  * \param span FreeTDM span
 450  * \param str Configuration string
 451  * \param type FreeTDM span type
 452  * \param name FreeTDM span name
 453  * \param number FreeTDM span number
 454  * \return Success or failure
 455  */
 456 static FIO_CONFIGURE_SPAN_FUNCTION(zt_configure_span)
 457 {
 458 
 459         int items, i;
 460         char *mydata, *item_list[10];
 461         char *ch, *mx;
 462         unsigned char cas_bits = 0;
 463         int channo;
 464         int top = 0;
 465         unsigned configured = 0;
 466 
 467         assert(str != NULL);
 468         
 469 
 470         mydata = ftdm_strdup(str);
 471         assert(mydata != NULL);
 472 
 473 
 474         items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
 475 
 476         for(i = 0; i < items; i++) {
 477                 ch = item_list[i];
 478 
 479                 if (!(ch)) {
 480                         ftdm_log(FTDM_LOG_ERROR, "Invalid input\n");
 481                         continue;
 482                 }
 483 
 484                 channo = atoi(ch);
 485                 
 486                 if (channo < 0) {
 487                         ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
 488                         continue;
 489                 }
 490 
 491                 if ((mx = strchr(ch, '-'))) {
 492                         mx++;
 493                         top = atoi(mx) + 1;
 494                 } else {
 495                         top = channo + 1;
 496                 }
 497                 
 498                 
 499                 if (top < 0) {
 500                         ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
 501                         continue;
 502                 }
 503                 if (FTDM_CHAN_TYPE_CAS == type && ftdm_config_get_cas_bits(ch, &cas_bits)) {
 504                         ftdm_log(FTDM_LOG_ERROR, "Failed to get CAS bits in CAS channel\n");
 505                         continue;
 506                 }
 507                 configured += zt_open_range(span, channo, top, type, name, number, cas_bits);
 508 
 509         }
 510         
 511         ftdm_safe_free(mydata);
 512 
 513         return configured;
 514 
 515 }
 516 
 517 /**
 518  * \brief Process configuration variable for a ftdmtel profile
 519  * \param category Wanpipe profile name
 520  * \param var Variable name
 521  * \param val Variable value
 522  * \param lineno Line number from configuration file
 523  * \return Success
 524  */
 525 static FIO_CONFIGURE_FUNCTION(zt_configure)
 526 {
 527 
 528         int num;
 529     float fnum;
 530 
 531         if (!strcasecmp(category, "defaults")) {
 532                 if (!strcasecmp(var, "codec_ms")) {
 533                         num = atoi(val);
 534                         if (num < 10 || num > 60) {
 535                                 ftdm_log(FTDM_LOG_WARNING, "invalid codec ms at line %d\n", lineno);
 536                         } else {
 537                                 zt_globals.codec_ms = num;
 538                         }
 539                 } else if (!strcasecmp(var, "wink_ms")) {
 540                         num = atoi(val);
 541                         if (num < 50 || num > 3000) {
 542                                 ftdm_log(FTDM_LOG_WARNING, "invalid wink ms at line %d\n", lineno);
 543                         } else {
 544                                 zt_globals.wink_ms = num;
 545                         }
 546                 } else if (!strcasecmp(var, "flash_ms")) {
 547                         num = atoi(val);
 548                         if (num < 50 || num > 3000) {
 549                                 ftdm_log(FTDM_LOG_WARNING, "invalid flash ms at line %d\n", lineno);
 550                         } else {
 551                                 zt_globals.flash_ms = num;
 552                         }
 553                 } else if (!strcasecmp(var, "echo_cancel_level")) {
 554                         num = atoi(val);
 555                         if (num < 0 || num > 256) {
 556                                 ftdm_log(FTDM_LOG_WARNING, "invalid echo can val at line %d\n", lineno);
 557                         } else {
 558                                 zt_globals.eclevel = num;
 559                         }
 560                 } else if (!strcasecmp(var, "echo_train_level")) {
 561                         if (zt_globals.eclevel <  1) {
 562                                 ftdm_log(FTDM_LOG_WARNING, "can't set echo train level without setting echo cancel level first at line %d\n", lineno);
 563                         } else {
 564                                 num = atoi(val);
 565                                 if (num < 0 || num > 256) {
 566                                         ftdm_log(FTDM_LOG_WARNING, "invalid echo train val at line %d\n", lineno);
 567                                 } else {
 568                                         zt_globals.etlevel = num;
 569                                 }
 570                         }
 571                 } else if (!strcasecmp(var, "rxgain")) {
 572                         fnum = (float)atof(val);
 573                         if (fnum < -100.0 || fnum > 100.0) {
 574                                 ftdm_log(FTDM_LOG_WARNING, "invalid rxgain val at line %d\n", lineno);
 575                         } else {
 576                                 zt_globals.rxgain = fnum;
 577                                 ftdm_log(FTDM_LOG_INFO, "Setting rxgain val to %f\n", fnum);
 578                         }
 579                 } else if (!strcasecmp(var, "txgain")) {
 580                         fnum = (float)atof(val);
 581                         if (fnum < -100.0 || fnum > 100.0) {
 582                                 ftdm_log(FTDM_LOG_WARNING, "invalid txgain val at line %d\n", lineno);
 583                         } else {
 584                                 zt_globals.txgain = fnum;
 585                                 ftdm_log(FTDM_LOG_INFO, "Setting txgain val to %f\n", fnum);
 586                         }
 587                 } else {
 588                                 ftdm_log(FTDM_LOG_WARNING, "Ignoring unknown setting '%s'\n", var);
 589                 }
 590         }
 591 
 592         return FTDM_SUCCESS;
 593 }
 594 
 595 /**
 596  * \brief Opens a ftdmtel channel
 597  * \param ftdmchan Channel to open
 598  * \return Success or failure
 599  */
 600 static FIO_OPEN_FUNCTION(zt_open) 
 601 {
 602         ftdm_channel_set_feature(ftdmchan, FTDM_CHANNEL_FEATURE_INTERVAL);
 603 
 604         if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921 || ftdmchan->type == FTDM_CHAN_TYPE_DQ931) {
 605                 ftdmchan->native_codec = ftdmchan->effective_codec = FTDM_CODEC_NONE;
 606         } else {
 607                 int blocksize = zt_globals.codec_ms * (ftdmchan->rate / 1000);
 608                 int err;
 609                 if ((err = ioctl(ftdmchan->sockfd, codes.SET_BLOCKSIZE, &blocksize))) {
 610                         snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
 611                         return FTDM_FAIL;
 612                 } else {
 613                         ftdmchan->effective_interval = ftdmchan->native_interval;
 614                         ftdmchan->packet_len = blocksize;
 615                         ftdmchan->native_codec = ftdmchan->effective_codec;
 616                 }
 617                 
 618                 if (ftdmchan->type == FTDM_CHAN_TYPE_B) {
 619                         int one = 1;
 620                         if (ioctl(ftdmchan->sockfd, codes.AUDIOMODE, &one)) {
 621                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
 622                                 ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
 623                                 return FTDM_FAIL;
 624                         }
 625                 }
 626                 if (zt_globals.rxgain || zt_globals.txgain) {
 627                         struct zt_gains gains;
 628                         memset(&gains, 0, sizeof(gains));
 629 
 630                         gains.chan_no = ftdmchan->physical_chan_id;
 631                         zt_build_gains(&gains, zt_globals.rxgain, zt_globals.txgain, ftdmchan->native_codec);
 632 
 633                         if (zt_globals.rxgain)
 634                                 ftdm_log(FTDM_LOG_INFO, "Setting rxgain to %f on channel %d\n", zt_globals.rxgain, gains.chan_no);
 635 
 636                         if (zt_globals.txgain)
 637                                 ftdm_log(FTDM_LOG_INFO, "Setting txgain to %f on channel %d\n", zt_globals.txgain, gains.chan_no);
 638 
 639                         if (ioctl(ftdmchan->sockfd, codes.SETGAINS, &gains) < 0) {
 640                                 ftdm_log(FTDM_LOG_ERROR, "failure configuring device %s as FreeTDM device %d:%d fd:%d\n", chanpath, ftdmchan->span_id, ftdmchan->chan_id, ftdmchan->sockfd);
 641                         }
 642                 }
 643 
 644                 if (zt_globals.eclevel >= 0) {
 645                         int len = zt_globals.eclevel;
 646                         if (len) {
 647                                 ftdm_log(FTDM_LOG_INFO, "Setting echo cancel to %d taps for %d:%d\n", len, ftdmchan->span_id, ftdmchan->chan_id);
 648                         } else {
 649                                 ftdm_log(FTDM_LOG_INFO, "Disable echo cancel for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
 650                         }
 651                         if (ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &len)) {
 652                                 ftdm_log(FTDM_LOG_WARNING, "Echo cancel not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
 653                         } else if (zt_globals.etlevel > 0) {
 654                                 len = zt_globals.etlevel;
 655                                 if (ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &len)) {
 656                                         ftdm_log(FTDM_LOG_WARNING, "Echo training not available for %d:%d\n", ftdmchan->span_id, ftdmchan->chan_id);
 657                                 }
 658                         }
 659                 }
 660 
 661         }
 662         return FTDM_SUCCESS;
 663 }
 664 
 665 /**
 666  * \brief Closes ftdmtel channel
 667  * \param ftdmchan Channel to close
 668  * \return Success
 669  */
 670 static FIO_CLOSE_FUNCTION(zt_close)
 671 {
 672         if (ftdmchan->type == FTDM_CHAN_TYPE_B) {
 673                 int value = 0;  /* disable audio mode */
 674                 if (ioctl(ftdmchan->sockfd, codes.AUDIOMODE, &value)) {
 675                         snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
 676                         ftdm_log(FTDM_LOG_ERROR, "%s\n", ftdmchan->last_error);
 677                         return FTDM_FAIL;
 678                 }
 679         }
 680         return FTDM_SUCCESS;
 681 }
 682 
 683 /**
 684  * \brief Executes an FreeTDM command on a ftdmtel channel
 685  * \param ftdmchan Channel to execute command on
 686  * \param command FreeTDM command to execute
 687  * \param obj Object (unused)
 688  * \return Success or failure
 689  */
 690 static FIO_COMMAND_FUNCTION(zt_command)
 691 {
 692         zt_params_t ztp;
 693         int err = 0;
 694 
 695         memset(&ztp, 0, sizeof(ztp));
 696 
 697         switch(command) {
 698         case FTDM_COMMAND_ENABLE_ECHOCANCEL:
 699                 {
 700                         int level = FTDM_COMMAND_OBJ_INT;
 701                         err = ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &level);
 702                         FTDM_COMMAND_OBJ_INT = level;
 703                 }
 704         case FTDM_COMMAND_DISABLE_ECHOCANCEL:
 705                 {
 706                         int level = 0;
 707                         err = ioctl(ftdmchan->sockfd, codes.ECHOCANCEL, &level);
 708                         FTDM_COMMAND_OBJ_INT = level;
 709                 }
 710                 break;
 711         case FTDM_COMMAND_ENABLE_ECHOTRAIN:
 712                 {
 713                         int level = FTDM_COMMAND_OBJ_INT;
 714                         err = ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &level);
 715                         FTDM_COMMAND_OBJ_INT = level;
 716                 }
 717         case FTDM_COMMAND_DISABLE_ECHOTRAIN:
 718                 {
 719                         int level = 0;
 720                         err = ioctl(ftdmchan->sockfd, codes.ECHOTRAIN, &level);
 721                         FTDM_COMMAND_OBJ_INT = level;
 722                 }
 723                 break;
 724         case FTDM_COMMAND_OFFHOOK:
 725                 {
 726                         int command = ZT_OFFHOOK;
 727                         if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
 728                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "OFFHOOK Failed");
 729                                 return FTDM_FAIL;
 730                         }
 731                         ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
 732                 }
 733                 break;
 734         case FTDM_COMMAND_ONHOOK:
 735                 {
 736                         int command = ZT_ONHOOK;
 737                         if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
 738                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ONHOOK Failed");
 739                                 return FTDM_FAIL;
 740                         }
 741                         ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
 742                 }
 743                 break;
 744         case FTDM_COMMAND_FLASH:
 745                 {
 746                         int command = ZT_FLASH;
 747                         if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
 748                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "FLASH Failed");
 749                                 return FTDM_FAIL;
 750                         }
 751                 }
 752                 break;
 753         case FTDM_COMMAND_WINK:
 754                 {
 755                         int command = ZT_WINK;
 756                         if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
 757                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "WINK Failed");
 758                                 return FTDM_FAIL;
 759                         }
 760                 }
 761                 break;
 762         case FTDM_COMMAND_GENERATE_RING_ON:
 763                 {
 764                         int command = ZT_RING;
 765                         if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
 766                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring Failed");
 767                                 return FTDM_FAIL;
 768                         }
 769                         ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
 770                 }
 771                 break;
 772         case FTDM_COMMAND_GENERATE_RING_OFF:
 773                 {
 774                         int command = ZT_RINGOFF;
 775                         if (ioctl(ftdmchan->sockfd, codes.HOOK, &command)) {
 776                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Ring-off failed");
 777                                 return FTDM_FAIL;
 778                         }
 779                         ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
 780                 }
 781                 break;
 782         case FTDM_COMMAND_GET_INTERVAL:
 783                 {
 784 
 785                         if (!(err = ioctl(ftdmchan->sockfd, codes.GET_BLOCKSIZE, &ftdmchan->packet_len))) {
 786                                 ftdmchan->native_interval = ftdmchan->packet_len / 8;
 787                                 if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
 788                                         ftdmchan->packet_len *= 2;
 789                                 }
 790                                 FTDM_COMMAND_OBJ_INT = ftdmchan->native_interval;
 791                         }                       
 792                 }
 793                 break;
 794         case FTDM_COMMAND_SET_INTERVAL: 
 795                 {
 796                         int interval = FTDM_COMMAND_OBJ_INT;
 797                         int len = interval * 8;
 798 
 799                         if (!(err = ioctl(ftdmchan->sockfd, codes.SET_BLOCKSIZE, &len))) {
 800                                 ftdmchan->packet_len = len;
 801                                 ftdmchan->effective_interval = ftdmchan->native_interval = ftdmchan->packet_len / 8;
 802 
 803                                 if (ftdmchan->effective_codec == FTDM_CODEC_SLIN) {
 804                                         ftdmchan->packet_len *= 2;
 805                                 }
 806                         }
 807                 }
 808                 break;
 809         case FTDM_COMMAND_SET_CAS_BITS:
 810                 {
 811                         int bits = FTDM_COMMAND_OBJ_INT;
 812                         err = ioctl(ftdmchan->sockfd, codes.SETTXBITS, &bits);
 813                 }
 814                 break;
 815         case FTDM_COMMAND_GET_CAS_BITS:
 816                 {
 817                         err = ioctl(ftdmchan->sockfd, codes.GETRXBITS, &ftdmchan->rx_cas_bits);
 818                         if (!err) {
 819                                 FTDM_COMMAND_OBJ_INT = ftdmchan->rx_cas_bits;
 820                         }
 821                 }
 822                 break;
 823         case FTDM_COMMAND_FLUSH_TX_BUFFERS:
 824                 {
 825                         int flushmode = ZT_FLUSH_WRITE;
 826                         err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode);
 827                 }
 828                 break;
 829         case FTDM_COMMAND_FLUSH_RX_BUFFERS:
 830                 {
 831                         int flushmode = ZT_FLUSH_READ;
 832                         err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode);
 833                 }
 834                 break;
 835         case FTDM_COMMAND_FLUSH_BUFFERS:
 836                 {
 837                         int flushmode = ZT_FLUSH_BOTH;
 838                         err = ioctl(ftdmchan->sockfd, codes.FLUSH, &flushmode);
 839                 }
 840                 break;
 841         default:
 842                 err = FTDM_NOTIMPL;
 843                 break;
 844         };
 845 
 846         if (err && err != FTDM_NOTIMPL) {
 847                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "%s", strerror(errno));
 848                 return FTDM_FAIL;
 849         }
 850 
 851 
 852         return err == 0 ? FTDM_SUCCESS : err;
 853 }
 854 
 855 /**
 856  * \brief Gets alarms from a ftdmtel Channel
 857  * \param ftdmchan Channel to get alarms from
 858  * \return Success or failure
 859  */
 860 static FIO_GET_ALARMS_FUNCTION(zt_get_alarms)
 861 {
 862         struct zt_spaninfo info;
 863 
 864         memset(&info, 0, sizeof(info));
 865         info.span_no = ftdmchan->physical_span_id;
 866 
 867         if (ioctl(CONTROL_FD, codes.SPANSTAT, &info)) {
 868                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "ioctl failed (%s)", strerror(errno));
 869                 snprintf(ftdmchan->span->last_error, sizeof(ftdmchan->span->last_error), "ioctl failed (%s)", strerror(errno));
 870                 return FTDM_FAIL;
 871         }
 872 
 873         ftdmchan->alarm_flags = info.alarms;
 874 
 875         return FTDM_SUCCESS;
 876 }
 877 
 878 /**
 879  * \brief Waits for an event on a ftdmtel channel
 880  * \param ftdmchan Channel to open
 881  * \param flags Type of event to wait for
 882  * \param to Time to wait (in ms)
 883  * \return Success, failure or timeout
 884  */
 885 static FIO_WAIT_FUNCTION(zt_wait)
 886 {
 887         int32_t inflags = 0;
 888         int result;
 889         struct pollfd pfds[1];
 890 
 891         if (*flags & FTDM_READ) {
 892                 inflags |= POLLIN;
 893         }
 894 
 895         if (*flags & FTDM_WRITE) {
 896                 inflags |= POLLOUT;
 897         }
 898 
 899         if (*flags & FTDM_EVENTS) {
 900                 inflags |= POLLPRI;
 901         }
 902 
 903 pollagain:
 904         memset(&pfds[0], 0, sizeof(pfds[0]));
 905         pfds[0].fd = ftdmchan->sockfd;
 906         pfds[0].events = inflags;
 907         result = poll(pfds, 1, to);
 908         *flags = 0;
 909 
 910         if (result < 0 && errno == EINTR) {
 911                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "DAHDI wait got interrupted, trying again\n");
 912                 goto pollagain;
 913         }
 914 
 915         if (pfds[0].revents & POLLERR) {
 916                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "DAHDI device got POLLERR\n");
 917                 result = -1;
 918         }
 919 
 920         if (result > 0) {
 921                 inflags = pfds[0].revents;
 922         }
 923 
 924         *flags = FTDM_NO_FLAGS;
 925 
 926         if (result < 0){
 927                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "Poll failed");
 928                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed to poll DAHDI device: %s\n", strerror(errno));
 929                 return FTDM_FAIL;
 930         }
 931 
 932         if (result == 0) {
 933                 return FTDM_TIMEOUT;
 934         }
 935 
 936         if (inflags & POLLIN) {
 937                 *flags |= FTDM_READ;
 938         }
 939 
 940         if (inflags & POLLOUT) {
 941                 *flags |= FTDM_WRITE;
 942         }
 943 
 944         if (inflags & POLLPRI) {
 945                 *flags |= FTDM_EVENTS;
 946         }
 947 
 948         return FTDM_SUCCESS;
 949 
 950 }
 951 
 952 /**
 953  * \brief Checks for events on a ftdmtel span
 954  * \param span Span to check for events
 955  * \param ms Time to wait for event
 956  * \return Success if event is waiting or failure if not
 957  */
 958 FIO_SPAN_POLL_EVENT_FUNCTION(zt_poll_event)
 959 {
 960         struct pollfd pfds[FTDM_MAX_CHANNELS_SPAN];
 961         uint32_t i, j = 0, k = 0;
 962         int r;
 963         
 964         for(i = 1; i <= span->chan_count; i++) {
 965                 memset(&pfds[j], 0, sizeof(pfds[j]));
 966                 pfds[j].fd = span->channels[i]->sockfd;
 967                 pfds[j].events = POLLPRI;
 968                 j++;
 969         }
 970 
 971     r = poll(pfds, j, ms);
 972 
 973         if (r == 0) {
 974                 return FTDM_TIMEOUT;
 975         } else if (r < 0 || (pfds[i-1].revents & POLLERR)) {
 976                 snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
 977                 return FTDM_FAIL;
 978         }
 979         
 980         for(i = 1; i <= span->chan_count; i++) {
 981                 if (pfds[i-1].revents & POLLPRI) {
 982                         ftdm_set_flag(span->channels[i], FTDM_CHANNEL_EVENT);
 983                         span->channels[i]->last_event_time = ftdm_current_time_in_ms();
 984                         k++;
 985                 }
 986         }
 987 
 988         if (!k) {
 989                 snprintf(span->last_error, sizeof(span->last_error), "no matching descriptor");
 990         }
 991 
 992         return k ? FTDM_SUCCESS : FTDM_FAIL;
 993 }
 994 
 995 /**
 996  * \brief Process an event from a ftdmchan and set the proper OOB event_id. The channel must be locked.
 997  * \param fchan Channel to retrieve event from
 998  * \param event_id Pointer to OOB event id
 999  * \param zt_event_id Zaptel event id
1000  * \return FTDM_SUCCESS or FTDM_FAIL
1001  */
1002 static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, ftdm_oob_event_t *event_id, zt_event_t zt_event_id)
1003 {
1004         switch(zt_event_id) {
1005         case ZT_EVENT_RINGEROFF:
1006                 {
1007                         return FTDM_FAIL;
1008                 }
1009                 break;
1010         case ZT_EVENT_RINGERON:
1011                 {
1012                         return FTDM_FAIL;
1013                 }
1014                 break;
1015         case ZT_EVENT_RINGBEGIN:
1016                 {
1017                         *event_id = FTDM_OOB_RING_START;
1018                 }
1019                 break;
1020         case ZT_EVENT_ONHOOK:
1021                 {
1022                         *event_id = FTDM_OOB_ONHOOK;
1023                 }
1024                 break;
1025         case ZT_EVENT_WINKFLASH:
1026                 {
1027                         if (fchan->state == FTDM_CHANNEL_STATE_DOWN || fchan->state == FTDM_CHANNEL_STATE_DIALING) {
1028                                 *event_id = FTDM_OOB_WINK;
1029                         } else {
1030                                 *event_id = FTDM_OOB_FLASH;
1031                         }
1032                 }
1033                 break;
1034         case ZT_EVENT_RINGOFFHOOK:
1035                 {
1036                         if (fchan->type == FTDM_CHAN_TYPE_FXS || (fchan->type == FTDM_CHAN_TYPE_EM && fchan->state != FTDM_CHANNEL_STATE_UP)) {
1037                                 ftdm_set_flag_locked(fchan, FTDM_CHANNEL_OFFHOOK);
1038                                 *event_id = FTDM_OOB_OFFHOOK;
1039                         } else if (fchan->type == FTDM_CHAN_TYPE_FXO) {
1040                                 *event_id = FTDM_OOB_RING_START;
1041                         } else {
1042                                 *event_id = FTDM_OOB_NOOP;
1043                         }
1044                 }
1045                 break;
1046         case ZT_EVENT_ALARM:
1047                 {
1048                         *event_id = FTDM_OOB_ALARM_TRAP;
1049                 }
1050                 break;
1051         case ZT_EVENT_NOALARM:
1052                 {
1053                         *event_id = FTDM_OOB_ALARM_CLEAR;
1054                 }
1055                 break;
1056         case ZT_EVENT_BITSCHANGED:
1057                 {
1058                         *event_id = FTDM_OOB_CAS_BITS_CHANGE;
1059                         int bits = 0;
1060                         int err = ioctl(fchan->sockfd, codes.GETRXBITS, &bits);
1061                         if (err) {
1062                                 return FTDM_FAIL;
1063                         }
1064                         fchan->rx_cas_bits = bits;
1065                 }
1066                 break;
1067         case ZT_EVENT_NONE:
1068                 {
1069                         ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "No event\n");
1070                         *event_id = FTDM_OOB_NOOP;
1071                 }
1072                 break;
1073         default:
1074                 {
1075                         ftdm_log_chan(fchan, FTDM_LOG_WARNING, "Unhandled event %d\n", zt_event_id);
1076                         *event_id = FTDM_OOB_INVALID;
1077                 }
1078                 break;
1079         }
1080         return FTDM_SUCCESS;
1081 }
1082 
1083 /**
1084  * \brief Retrieves an event from a ftdm channel
1085  * \param ftdmchan Channel to retrieve event from
1086  * \param event FreeTDM event to return
1087  * \return Success or failure
1088  */
1089 FIO_CHANNEL_NEXT_EVENT_FUNCTION(zt_channel_next_event)
1090 {
1091         uint32_t event_id = FTDM_OOB_INVALID;
1092         zt_event_t zt_event_id = 0;
1093         ftdm_span_t *span = ftdmchan->span;
1094 
1095         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_EVENT)) {
1096                 ftdm_clear_flag(ftdmchan, FTDM_CHANNEL_EVENT);
1097         }
1098 
1099         if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
1100                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event from channel: %s\n",
1101                                 strerror(errno));
1102                 return FTDM_FAIL;
1103         }
1104 
1105         /* the core already locked the channel for us, so it's safe to call zt_channel_process_event() here */
1106         if ((zt_channel_process_event(ftdmchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
1107                 ftdm_log_chan_msg(ftdmchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
1108                 return FTDM_FAIL;
1109         }
1110 
1111         ftdmchan->last_event_time = 0;
1112         span->event_header.e_type = FTDM_EVENT_OOB;
1113         span->event_header.enum_id = event_id;
1114         span->event_header.channel = ftdmchan;
1115         *event = &span->event_header;
1116         return FTDM_SUCCESS;
1117 }
1118 
1119 /**
1120  * \brief Retrieves an event from a ftdmtel span
1121  * \param span Span to retrieve event from
1122  * \param event FreeTDM event to return
1123  * \return Success or failure
1124  */
1125 FIO_SPAN_NEXT_EVENT_FUNCTION(zt_next_event)
1126 {
1127         uint32_t i, event_id = FTDM_OOB_INVALID;
1128         zt_event_t zt_event_id = 0;
1129 
1130         for(i = 1; i <= span->chan_count; i++) {
1131                 ftdm_channel_t *fchan = span->channels[i];
1132                 if (ftdm_test_flag(fchan, FTDM_CHANNEL_EVENT)) {
1133                         ftdm_clear_flag(fchan, FTDM_CHANNEL_EVENT);
1134                         if (ioctl(fchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
1135                                 snprintf(span->last_error, sizeof(span->last_error), "%s", strerror(errno));
1136                                 return FTDM_FAIL;
1137                         }
1138 
1139                         ftdm_channel_lock(fchan);
1140                         if ((zt_channel_process_event(fchan, &event_id, zt_event_id)) != FTDM_SUCCESS) {
1141                                 ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Failed to process event from channel\n");
1142                                 ftdm_channel_unlock(fchan);
1143                                 return FTDM_FAIL;
1144                         }
1145                         ftdm_channel_unlock(fchan);
1146 
1147                         fchan->last_event_time = 0;
1148                         span->event_header.e_type = FTDM_EVENT_OOB;
1149                         span->event_header.enum_id = event_id;
1150                         span->event_header.channel = fchan;
1151                         *event = &span->event_header;
1152                         return FTDM_SUCCESS;
1153                 }
1154         }
1155 
1156         return FTDM_FAIL;
1157 }
1158 
1159 /**
1160  * \brief Reads data from a ftdmtel channel
1161  * \param ftdmchan Channel to read from
1162  * \param data Data buffer
1163  * \param datalen Size of data buffer
1164  * \return Success, failure or timeout
1165  */
1166 static FIO_READ_FUNCTION(zt_read)
1167 {
1168         ftdm_ssize_t r = 0;
1169         int errs = 0;
1170 
1171         while (errs++ < 30) {
1172                 if ((r = read(ftdmchan->sockfd, data, *datalen)) > 0) {
1173                         break;
1174                 }
1175                 else if (r == 0) {
1176                         ftdm_sleep(10);
1177                         if (errs) errs--;
1178                 }
1179                 else {
1180                         if (errno == EAGAIN || errno == EINTR)
1181                                 continue;
1182                         if (errno == ELAST)
1183                                 break;
1184 
1185                         ftdm_log(FTDM_LOG_ERROR, "read failed: %s\n", strerror(errno));
1186                 }
1187         }
1188         if (r > 0) {
1189                 *datalen = r;
1190                 if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
1191                         *datalen -= 2;
1192                 }
1193                 return FTDM_SUCCESS;
1194         }
1195         else if (errno == ELAST) {
1196                 return FTDM_SUCCESS;
1197         }
1198         return r == 0 ? FTDM_TIMEOUT : FTDM_FAIL;
1199 }
1200 
1201 /**
1202  * \brief Writes data to a ftdmtel channel
1203  * \param ftdmchan Channel to write to
1204  * \param data Data buffer
1205  * \param datalen Size of data buffer
1206  * \return Success or failure
1207  */
1208 static FIO_WRITE_FUNCTION(zt_write)
1209 {
1210         ftdm_ssize_t w = 0;
1211         ftdm_size_t bytes = *datalen;
1212 
1213         if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
1214                 memset(data+bytes, 0, 2);
1215                 bytes += 2;
1216         }
1217 
1218 tryagain:
1219         w = write(ftdmchan->sockfd, data, bytes);
1220         
1221         if (w >= 0) {
1222                 *datalen = w;
1223                 return FTDM_SUCCESS;
1224         }
1225 
1226         if (errno == ELAST) {
1227                 zt_event_t zt_event_id = 0;
1228                 if (ioctl(ftdmchan->sockfd, codes.GETEVENT, &zt_event_id) == -1) {
1229                         ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Failed retrieving event after ELAST on write: %s\n", strerror(errno));
1230                         return FTDM_FAIL;
1231                 }
1232                 /* we should enqueue this event somewhere so it can be retrieved by the user, for now, dropping it to see what it is! */
1233                 ftdm_log_chan(ftdmchan, FTDM_LOG_ERROR, "Dropping event %d to be able to write data\n", zt_event_id);
1234                 goto tryagain;
1235         }
1236 
1237         return FTDM_FAIL;
1238 }
1239 
1240 /**
1241  * \brief Destroys a ftdmtel Channel
1242  * \param ftdmchan Channel to destroy
1243  * \return Success
1244  */
1245 static FIO_CHANNEL_DESTROY_FUNCTION(zt_channel_destroy)
1246 {
1247         close(ftdmchan->sockfd);
1248         ftdmchan->sockfd = ZT_INVALID_SOCKET;
1249 
1250         return FTDM_SUCCESS;
1251 }
1252 
1253 /**
1254  * \brief Global FreeTDM IO interface for ftdmtel
1255  */
1256 static ftdm_io_interface_t zt_interface;
1257 
1258 /**
1259  * \brief Loads ftdmtel IO module
1260  * \param fio FreeTDM IO interface
1261  * \return Success or failure
1262  */
1263 static FIO_IO_LOAD_FUNCTION(zt_init)
1264 {
1265         assert(fio != NULL);
1266     struct stat statbuf;
1267         memset(&zt_interface, 0, sizeof(zt_interface));
1268         memset(&zt_globals, 0, sizeof(zt_globals));
1269 
1270     if (!stat(zt_ctlpath, &statbuf)) {
1271         ftdm_log(FTDM_LOG_NOTICE, "Using Zaptel control device\n");
1272         ctlpath = zt_ctlpath;
1273         chanpath = zt_chanpath;
1274         memcpy(&codes, &zt_ioctl_codes, sizeof(codes));
1275     } else if (!stat(dahdi_ctlpath, &statbuf)) {
1276         ftdm_log(FTDM_LOG_NOTICE, "Using DAHDI control device\n");
1277         ctlpath = dahdi_ctlpath;
1278         chanpath = dahdi_chanpath;
1279         memcpy(&codes, &dahdi_ioctl_codes, sizeof(codes));
1280     } else {
1281                 ftdm_log(FTDM_LOG_ERROR, "No DAHDI or Zap control device found in /dev/\n");
1282                 return FTDM_FAIL;
1283     }
1284         if ((CONTROL_FD = open(ctlpath, O_RDWR)) < 0) {
1285                 ftdm_log(FTDM_LOG_ERROR, "Cannot open control device %s: %s\n", ctlpath, strerror(errno));
1286                 return FTDM_FAIL;
1287         }
1288 
1289         zt_globals.codec_ms = 20;
1290         zt_globals.wink_ms = 150;
1291         zt_globals.flash_ms = 750;
1292         zt_globals.eclevel = 0;
1293         zt_globals.etlevel = 0;
1294         
1295         zt_interface.name = "zt";
1296         zt_interface.configure = zt_configure;
1297         zt_interface.configure_span = zt_configure_span;
1298         zt_interface.open = zt_open;
1299         zt_interface.close = zt_close;
1300         zt_interface.command = zt_command;
1301         zt_interface.wait = zt_wait;
1302         zt_interface.read = zt_read;
1303         zt_interface.write = zt_write;
1304         zt_interface.poll_event = zt_poll_event;
1305         zt_interface.next_event = zt_next_event;
1306         zt_interface.channel_destroy = zt_channel_destroy;
1307         zt_interface.get_alarms = zt_get_alarms;
1308         *fio = &zt_interface;
1309 
1310         return FTDM_SUCCESS;
1311 }
1312 
1313 /**
1314  * \brief Unloads ftdmtel IO module
1315  * \return Success
1316  */
1317 static FIO_IO_UNLOAD_FUNCTION(zt_destroy)
1318 {
1319         close(CONTROL_FD);
1320         memset(&zt_interface, 0, sizeof(zt_interface));
1321         return FTDM_SUCCESS;
1322 }
1323 
1324 /**
1325  * \brief FreeTDM ftdmtel IO module definition
1326  */
1327 ftdm_module_t ftdm_module = { 
1328         "zt",
1329         zt_init,
1330         zt_destroy,
1331 };
1332 
1333 /* For Emacs:
1334  * Local Variables:
1335  * mode:c
1336  * indent-tabs-mode:t
1337  * tab-width:4
1338  * c-basic-offset:4
1339  * End:
1340  * For VIM:
1341  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
1342  */

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