Logo Search packages:      
Sourcecode: bayonne version File versions  Download package

driver.cpp

// Copyright (C) 2001 Kai Germaschewski
// Copyright (C) 2002/2003 by Peter Krapfl
// Copyright (C) 2003 Gregor Goldbach
//
// Version 1.2.0.2
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//

// TODO
// switching w/o threads
// common cmsg_put w/mutex
// stop play/tone thread gracefully

#include "driver.h"
#include <capi20.h>
#include <cerrno>
// FIX:
#include <linux/types.h>


#ifdef      CCXX_NAMESPACES
using namespace std;
namespace ost {
#endif

struct capi_profile {
      __u16 ncontroller;      /* number of installed controller */
      __u16 nbchannel;  /* number of B-Channels */
      __u32 goptions;         /* global options */
      __u32 support1;         /* B1 protocols support */
      __u32 support2;         /* B2 protocols support */
      __u32 support3;         /* B3 protocols support */
      __u32 reserved[6];      /* reserved */
      __u32 manu[5];          /* manufacturer specific information */
};

CapiConfig::CapiConfig() :
Keydata("/bayonne/capi20")
{
      static Keydata::Define defkeys[] = {
            {"buffersize", "128"},
            {NULL, NULL}
      };          

        if(isFHS())
                load("/drivers/capi20");



      load(defkeys);
}

CapiDriver::CapiDriver() :
Driver(), CapiConfig(), Thread(keythreads.priService())
{
      static Script::Define keywords[] = {
            {"join", (Method)&CapiTrunk::scrJoin, &ScriptCommand::chkHasArgs},
            {"wait", (Method)&CapiTrunk::scrWait, &ScriptCommand::chkHasArgs},
            {NULL, NULL, NULL}};

      struct capi_profile cprofile,cprofile1;
      int err;
      int count;
            
      status = CapiTrunk::status;
      running = false;
      appl_id = 0;
      msg_id = 1;

      memset(status, ' ', sizeof(CapiTrunk::status));
      err=capi20_isinstalled();
      if (err != CapiNoError) {
            slog(Slog::levelError) << "CAPI20: Capi driver not installed - reason: " 
                         << strerror(err) << endl;
            return;
      }

      capi20_get_profile(0, (CAPI_MESSAGE)&cprofile);
      contr_count = cprofile.ncontroller;
      if (!contr_count) {
            slog(Slog::levelError) << "CAPI20: No controllers found" << endl;
            return;
      }

      slog(Slog::levelDebug) << "CAPI20: Found " << contr_count <<
        " controllers" << endl;

      for (count = 0; count < contr_count; count++) {
          capi20_get_profile(count+1, (CAPI_MESSAGE)&cprofile1);
          b_chan[count]= cprofile1.nbchannel;
          port_count+=b_chan[count];
          slog(Slog::levelDebug) << "CAPI20: Controller: "
                           << count+1 << "B channels: "<< b_chan[count] << endl;
      }    



      err = capi20_register(port_count, 7, getBufferSize(), &appl_id);
      if (err != CapiNoError) {
            slog(Slog::levelError) << "CAPI20: Could not register - " 
                         << strerror(err) << endl;
            return;
      }

      // dsp devices
      ports = new CapiTrunk *[port_count];
      groups = new TrunkGroup *[port_count];
      memset(ports, 0, sizeof(CapiTrunk *) * port_count);
      memset(groups, 0, sizeof(TrunkGroup *) * port_count);

      ScriptCommand::load(keywords);

      pipe(evbuf);
      int opts = fcntl(evbuf[1], F_GETFL);
      fcntl(evbuf[1], F_SETFL, opts | O_NONBLOCK);

      slog(Slog::levelNotice) << "CAPI20: Driver loaded: " << contr_count 
                  << " controllers with "<< port_count << " B channels"
                  << endl;
}

CapiDriver::~CapiDriver()
{
  //  slog(Slog::levelDebug) << "CAPI20: " << __FUNCTION__ << endl;

      stop();

      if(ports)
            delete[] ports;

      if(groups)
            delete[] groups;

      if (appl_id)
            capi20_release(appl_id);

      ::close(evbuf[0]);
      ::close(evbuf[1]);
}

int CapiDriver::start()
{
//    slog(Slog::levelDebug) << "CAPI20: " << __FUNCTION__ << endl;


      int count = 0;
      int totalcount=0;
      int b_chan_offs = 0;
      unsigned err;
      _cmsg cmsg;

      if(active) {
            slog(Slog::levelError) << "CAPI20: Driver already started" << endl;
            return 0;
      }

      slog(Slog::levelNotice) << "CAPI20: Driver starting..." << endl;

      active = true;

      for (unsigned contr = 1; contr <= contr_count; contr++) {
          for (count = 0; count < b_chan[contr-1] ; count++) {
            ports[totalcount] = new CapiTrunk(b_chan_offs+count,contr);
            totalcount++;
            
          } 

      b_chan_offs=totalcount;

      slog(Slog::levelNotice) << "CAPI20: Driver started: " << count 
                        << " B channels total on controller " << contr << endl;

            err = LISTEN_REQ (&cmsg, appl_id, msg_id++,
                          contr,   // Controller
                          0,       // InfoMask
                          0x10011, // CIPMask
                          0,       // CIPMask2
                          (unsigned char *)"",  // CallingPartyNumber
                          (unsigned char *)""); // CallingPartySubaddress
            if (err != CapiNoError) {
                  slog(Slog::levelError) << "CAPI20: LISTEN_REQ err = "
                               << err << endl;
            }
            err = capi20_waitformessage(appl_id, NULL);
            if (err != CapiNoError) {
                  slog(Slog::levelError) << "CAPI20: LISTEN_REQ err = "
                               << err << endl;
            }
            err = capi_get_cmsg(&cmsg, appl_id);
            if (err != CapiNoError) {
                  slog(Slog::levelError) << "CAPI20: LISTEN_CONF err = "
                               << err << endl;
            }
            if (cmsg.Command != CAPI_LISTEN || 
                cmsg.Subcommand !=  CAPI_CONF ||
                cmsg.Info != 0) {
                  slog(Slog::levelError) << "CAPI20: LISTEN_CONF Info = "
                               << cmsg.Info << endl;
            }
      }

//    slog(Slog::levelDebug) << "CAPI20: before thread is started..." << endl;


      if(!running)
            Thread::start();

      return totalcount;
}

void CapiDriver::stop()
{
//    slog(Slog::levelDebug) << "CAPI20: " << __FUNCTION__ << endl;

      unsigned id;

      if (!active)
            return;

      if (running) {
//          slog(Slog::levelDebug) << "terminate()" << endl;
            terminate();
      }
      slog(Slog::levelNotice) << "CAPI20: driver stopping..." << endl;

      for(id = 0; id < port_count; ++id) {
            if(ports[id])
                  delete (ports[id]);
      }
      memset(ports, 0, sizeof(CapiTrunk *) * port_count);
      active = false;

}

unsigned CapiDriver::getTrunkCount()
{
//    slog(SLOG_DEBUG) << "CAPI20: " << __FUNCTION__ << endl;

      return port_count;
}

Trunk *CapiDriver::getTrunkPort(int id)
{
//    slog(SLOG_DEBUG) << "CAPI20: " << __FUNCTION__ << " "
//                 << id << endl;

      if (id < 0 || id >= (int)port_count)
            return NULL;

      if (!ports)
            return NULL;

      return ports[id];
}

void CapiDriver::handleCapiMessage()
{
  //  slog(Slog::levelDebug) << "CAPI: " << __FUNCTION__ << endl;

      unsigned err;
      unsigned contr;
      unsigned controffs=0;
      unsigned controffsmax=0;
      _cmsg cmsg;
      CapiTrunk *trunk;
      TrunkEvent event;

      err = capi_get_cmsg(&cmsg, appl_id);
      //    slog(Slog::levelDebug) << capi20_cmsg2str(&cmsg) << endl;
      
      // return on error
      if (err != CapiNoError) {
            slog(Slog::levelError) << "CAPI20: capi20_get_cmsg err = "
                         << err << endl;
            return;
      }

      // this is the controller
      contr = cmsg.adr.adrController & 0xff;
      if (contr < 1 || contr > contr_count) {
        slog(Slog::levelError) << "CAPI20: Wrong controller number "
                         << contr << ": " << capi20_cmsg2str(&cmsg) << endl;
            return;
      }

      for (int xcount=0; xcount<contr-1; xcount++) {
//      slog(Slog::levelNotice) << "CAPI20: B-Channels:" << b_chan[xcount] << endl;
      controffs+=b_chan[xcount];
      }

      controffsmax=controffs+b_chan[contr-1];
      //    slog(Slog::levelDebug) << "CAPI20: Controlleroffs: " <<
      //controffs << " Max: " << controffsmax << endl;

      if (IS_DATA_B3_IND(&cmsg) || 
          IS_DATA_B3_CONF(&cmsg) ||
          IS_CONNECT_ACTIVE_IND(&cmsg) ||
          IS_DISCONNECT_CONF(&cmsg) || 
          IS_DISCONNECT_IND(&cmsg) || 
          IS_CONNECT_B3_CONF(&cmsg) ||
          IS_CONNECT_B3_IND(&cmsg) ||
          IS_CONNECT_B3_ACTIVE_IND(&cmsg) ||
          IS_DISCONNECT_B3_IND(&cmsg) ||
          IS_FACILITY_CONF(&cmsg) ||
          IS_FACILITY_IND(&cmsg) ||
          IS_ALERT_CONF(&cmsg)) {
//        slog(Slog::levelDebug) << "CAPI20: CMSG received " << endl
//                       << capi20_cmsg2str(&cmsg) << endl;

        // find trunk with that PLCI
        for (unsigned i = controffs; i < controffsmax; i++) {
          CapiTrunk *trunk = ports[i];
          
          if (trunk->plci != (cmsg.adr.adrPLCI & 0xffff))
            continue;

          trunk->recvCapiMsg(&cmsg);
          return;
        }
        slog(Slog::levelError) << "CAPI20: PLCI not found " << endl
                         << capi20_cmsg2str(&cmsg) << endl;
        return;
      }

      if (IS_CONNECT_CONF(&cmsg)) {
        // look for free trunk (plci = 0)
        for (unsigned i = controffs; i < controffsmax; i++) {
          CapiTrunk *trunk = ports[i];
          
          if (trunk->plci == 0) {
            if (trunk->recvCapiMsg(&cmsg)) {
            return;
            }
          }
        }
        // we didn't find a free trunk -- reject?
        slog(Slog::levelNotice) << "CAPI20: No free trunk" << endl;       
        return;
      }

        if (IS_CONNECT_IND(&cmsg)) {
        
        // look for free trunk (plci = 0)
        for (unsigned i = controffs; i < controffsmax; i++) {
          CapiTrunk *trunk = ports[i];
          
          if (trunk->plci == 0) {
            if (trunk->recvCapiMsg(&cmsg))
            return;
          }
        }
        
        // we didn't find a free trunk so we reject the call
        slog(Slog::levelNotice) << "CAPI20: No free trunk, rejecting call " << endl;        
        capi20_cmsg_answer(&cmsg);
        cmsg.Reject = 2;
        err = capi20_put_cmsg(&cmsg);
        if (err != CapiNoError) {
          slog(Slog::levelError) << "CAPI20: capi20_put_cmsg err = "
                           << err << endl;
        }
        return;
        }

      slog(Slog::levelError) << "CAPI20: Message not handled " << endl 
                   << capi20_cmsg2str(&cmsg) << endl;
}

void CapiDriver::run()
{
//    slog(Slog::levelDebug) << "CAPI20 RUN CALLED: " << __FUNCTION__ << endl;

//    int cnt = 0;
      timeout_t timer, expires;
      CapiTrunk *trunk;
      TrunkEvent event;
      struct timeval tv;
      fd_set rfds;
      char dummy;
      int retval;
      int zahl = 0;
      
      if (!appl_id)
            return;

      setCancel(cancelImmediate);
      for (;;) {
//    slog(Slog::levelDebug) << "CAPI20: DRIVER ALIVE" << endl;

            timer = ~0;
            for (unsigned i = 0; i < port_count; i++) {
                  trunk = ports[i];

            retry:
                  expires = trunk->getTimer();
                  if(expires > 0 && expires < timer) timer = expires;

                  if (!expires) {
                        debug->debugService(trunk, "expires");
                        event.id = TRUNK_TIMER_EXPIRED;
                        trunk->postEvent(&event);
// TODO: INFINITE LOOP        goto retry;
                  }

//           slog(Slog::levelError) << "CAPI20: RUN PORT_COUNT: " << zahl++ << endl;


            }
//           slog(Slog::levelError) << "CAPI20: RUN TIMER: " << timer << endl;

            if (timer > 10000) {
                  tv.tv_sec = 10; // FIXME
                  tv.tv_usec = 0;
            } else {
                  tv.tv_sec = timer / 1000;
                  tv.tv_usec = (timer % 1000) * 1000;
            }

            FD_ZERO(&rfds);
            FD_SET(capi20_fileno(appl_id), &rfds);
            FD_SET(evbuf[0], &rfds);
            retval = select(MAX(capi20_fileno(appl_id), evbuf[0])+1, 
                        &rfds, NULL, NULL, &tv);
            if (retval < 0) {
                  slog(Slog::levelError) << "CAPI20: run() - select returned "
                               << strerror(errno) << endl;
                  break;
            }
            if (FD_ISSET(capi20_fileno(appl_id), &rfds))
                  handleCapiMessage();
            if (FD_ISSET(evbuf[0], &rfds))
                  read(evbuf[0], &dummy, 1);
      }
}

CapiDriver capiivr;

#ifdef      CCXX_NAMESPACES
};
#endif

Generated by  Doxygen 1.6.0   Back to index