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

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