"Fossies" - the Fresh Open Source Software Archive

Member "bayonne-1.2.16/drivers/aculab/driver.cpp" (2 Apr 2003, 17468 Bytes) of package /linux/misc/old/bayonne-1.2.16.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "driver.cpp" see the Fossies "Dox" file reference documentation.

    1 // Copyright (C) 2000 Open Source Telecom Corporation.
    2 //  
    3 // This program is free software; you can redistribute it and/or modify
    4 // it under the terms of the GNU General Public License as published by
    5 // the Free Software Foundation; either version 2 of the License, or
    6 // (at your option) any later version.
    7 // 
    8 // This program is distributed in the hope that it will be useful,
    9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
   10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11 // GNU General Public License for more details.
   12 // 
   13 // You should have received a copy of the GNU General Public License
   14 // along with this program; if not, write to the Free Software 
   15 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
   16 //
   17 // As a special exception to the GNU General Public License, permission is
   18 // granted for additional uses of the text contained in its release
   19 // of Bayonne as noted here.
   20 //
   21 // This exception is that permission is hereby granted to link Bayonne 
   22 // with the Aculab telephony libraries to produce a executable image
   23 // without requiring Aculab's sources to be supplied in a free software
   24 // license long as each source file so linked contains this exclusion
   25 // and the unalrtered Aculab source files are also provided.
   26 //
   27 // This exception does not however invalidate any other reasons why
   28 // the resulting executable file might be covered by the GNU General
   29 // public license or invalidate the licensing requirements of any
   30 // other component or library.
   31 //
   32 // This exception applies only to the code released by OST under the
   33 // name Bayonne.  If you copy code from other releases into a copy of
   34 // Bayonne, as the General Public License permits, the exception does not
   35 // apply to the code that you add in this way.  To avoid misleading
   36 // anyone as to the status of such modified files, you must delete
   37 // this exception notice from them.
   38 //
   39 // If you write modifications of your own to Bayonne, it is your choice
   40 // whether to permit this exception to apply to your modifications.
   41 // If you do not wish that, delete this exception notice, at which
   42 // point the terms of your modification would be covered under the GPL
   43 // as explicitly stated in "COPYING".
   44 
   45 //
   46 // General Aculab driver overview
   47 // ------------------------------
   48 //
   49 // At this time, I only have Prosody PCI/T1/PRI cards to work with
   50 // so some assumptions may be incorrect for other hardware produced
   51 // by Aculab and supported by their drivers.
   52 //
   53 // Each 'port' on an Aculab card is a T1 interface.  Each T1/E1
   54 // interface can support 24 (T1) or 30 (E1) simultaneous phone
   55 // calls (channels).  Currently the highest density PCI Aculab card
   56 // is the Prosody with a PM4 module which gives 4 ports, for a total
   57 // capacity of 96 T1 or 120 E1 channels per board.  There can be multiple
   58 // Prosody cards in one chassis.  I don't know what the limit is at
   59 // this time, but I suspect it is limited by available PCI slots
   60 // more than anything else.  My development system has 2 4-port
   61 // cards installed, with room for 2 more.
   62 //
   63 // Because of the very high density involved with these cards,
   64 // doing a simple thread-per-trunk(channel) mapping here in the
   65 // driver rapidly gets out of hand as you add more cards.  Take
   66 // a 16-port machine for example.  That would give 384(T1) or
   67 // 480(E1) threads!  The machine will rapidly be running out of
   68 // resources at that point.  Also, in the case of Compact-PCI systems,
   69 // it's possible to cram the machine full of ports, which could
   70 // easily double this number.
   71 //
   72 // To economize on resources, the main driver thread is responsible
   73 // for receiving events from the Aculab driver and dispatching
   74 // them to worker threads through a small queue class.  The optimal
   75 // number of worker threads has yet to be determined, but I imagine
   76 // one per port should suffice.
   77 //
   78 // There are 3 additional threads used by this driver:
   79 //
   80 // o An audio processing thread.  There is one of these per driver
   81 //   and is responsible for feeding audio to/from the hardware
   82 // o A dsp event monitor thread.  This pretty much only listens for
   83 //   DTMF events at the moment.  There is one of these per driver.
   84 // o A timer event thread.  Any time a timer is set, this thread
   85 //   sits and waits for it to expire, posting an event when it does.
   86 //
   87 // See thread.c and atimer.c for more details.
   88 //
   89 // NOTE: The Aculab driver can operate in either state-driven
   90 //       mode or event-driven.  For simplicity of the code, the
   91 //       event driven model is being used.  At some point it may
   92 //       be worth re-examining the issue to see if state-driven
   93 //       provides any advantages.
   94 
   95 #include "driver.h"
   96 
   97 #ifdef    CCXX_NAMESPACES
   98 using namespace std;
   99 namespace ost {
  100 #endif
  101 
  102 AculabConfig::AculabConfig() :
  103 Keydata("/bayonne/aculab")
  104 {
  105     static Keydata::Define defkeys[] = {
  106     {"prifirmware", "ni2_usr.p4r"},
  107     {"brifirmware", "ets_bnet.ram"},
  108     {"prosody", "/home/aculab/dtk111/speech/download/speech/sp30a.smf"},
  109     {"briconfig", ""},
  110     {"priconfig", ""},
  111     {"netformat", "alaw"},
  112     {"buffersize","256"},
  113     {NULL, NULL}};
  114 
  115     if(isFHS())
  116         load("/drivers/aculab");
  117 
  118     load(defkeys);
  119 }
  120 
  121 unsigned AculabConfig::getMaxPorts(void)
  122 {
  123     const char *val = getLast("maxports");
  124     int v;
  125     if(!val)
  126         return MAXPORT;
  127 
  128     v = atoi(val);
  129     if(v > MAXPORT)
  130         return MAXPORT;
  131 
  132     return v;
  133 }
  134 
  135 AculabDriver::AculabDriver() :
  136 Driver(), AculabConfig(), Thread(keythreads.priService())
  137 {
  138     static Script::Define keywords[] = {
  139         {"join", (Method)&AculabTrunk::scrJoin, &ScriptCommand::chkHasArgs},
  140         {"wait", (Method)&AculabTrunk::scrWait, &ScriptCommand::chkHasArgs},
  141         {"sync", (Method)&AculabTrunk::scrMaxTime, &ScriptCommand::chkIgnore},
  142         {NULL, NULL, NULL}};
  143 
  144     running = false;
  145     port_count = 0;
  146     unsigned long mask;
  147     unsigned port, ts;
  148 //  AculabTrunk *trunk;
  149 
  150 #if 0
  151     int rc, x;
  152     char *mykey[128];
  153     rc=keytones.getIndex(mykey,127);
  154 
  155     /* Setup custom-defined tones */
  156     for (x=0; x < rc; x++) {
  157         if (!stricmp(mykey[x],"tones")) {
  158             continue;
  159         }
  160         slog(Slog::levelDebug)<<"GETTING tone for KEY="<<mykey[x]<<endl;
  161         /*
  162          * TODO TODO - convert phTone into an Aculab custom tone
  163          * parameter and let DSP do tone generation...
  164          */
  165     }
  166 #endif
  167 
  168     status = AculabTrunk::status;
  169     memset(status, ' ', sizeof(AculabTrunk::status));
  170 
  171     if(InitNetworks()) {
  172         if(InitProsody()) {
  173             port_count = call_nports();
  174         }
  175     }
  176 
  177     if(port_count < 0)
  178         port_count = 0;
  179 
  180     if(!port_count) {
  181         slog(Slog::levelCritical) << "Aculab driver failure; no ports" << endl; 
  182         trunks = NULL;
  183         groups = NULL;
  184         imaps = NULL;
  185         omaps = NULL;
  186         qthreads = NULL;
  187         throw((Driver *)this);
  188     }
  189 
  190     qthreads = NULL;
  191     audiothread = NULL;
  192 
  193     imaps = new AculabTrunk *[port_count * MAXCHANNELS];
  194     omaps = new AculabTrunk *[port_count * MAXCHANNELS];
  195     ixmaps = new AculabTrunk *[MAX_CH_IDX];
  196     tsmap = new char[port_count * MAXTIMESLOTS];
  197     groups = new TrunkGroup *[port_count * MAXTIMESLOTS];
  198     trunks = new AculabTrunk *[port_count * MAXTIMESLOTS];
  199 
  200     memset(imaps, 0, sizeof(AculabTrunk *) * port_count * MAXCHANNELS);
  201     memset(omaps, 0, sizeof(AculabTrunk *) * port_count * MAXCHANNELS);
  202     memset(ixmaps, 0, sizeof(AculabTrunk *) * MAX_CH_IDX);
  203     memset(tsmap, 0, sizeof(char) * port_count * MAXTIMESLOTS);
  204     memset(groups, 0, sizeof(TrunkGroup *) * port_count * MAXTIMESLOTS);
  205     memset(trunks, 0, sizeof(AculabTrunk *) * port_count * MAXTIMESLOTS);
  206     memset(MVIP,0,sizeof(MVIP));
  207 
  208     mvipMutex=new Mutex();
  209 
  210     queue = new AculabFifo();
  211 
  212     call_signal_info(&siginfo[0]);
  213 
  214     /*
  215      * Determine what timeslots are available
  216      */
  217     for(port = 0; port < port_count; ++port) {
  218         slog(Slog::levelInfo) << "aculab("<<port<<",) signalling system: "
  219                 << siginfo[port].sigsys <<endl;
  220         mask = 1L;
  221         for(ts = 0; ts < MAXTIMESLOTS; ++ts) {
  222             if(mask & siginfo[port].validvector) {
  223                 tsmap[port * MAXTIMESLOTS + ts] = 1;
  224             }
  225             mask <<=1L;
  226         }
  227     }           
  228 
  229     ScriptCommand::load(keywords);
  230 
  231     slog(Slog::levelInfo) << "Aculab driver loaded; capacity="
  232             << port_count * MAXCHANNELS << " channels" <<  endl;
  233 }
  234 
  235 AculabDriver::~AculabDriver()
  236 {
  237     if(running)
  238         terminate();
  239 
  240     if(tsmap)
  241         delete[] tsmap;
  242 
  243     if(trunks)
  244         delete[] trunks;
  245 
  246     if(groups)
  247         delete[] groups;
  248 
  249     if(imaps)
  250         delete[] imaps;
  251 
  252     if(omaps)
  253         delete[] omaps;
  254 
  255 }
  256 
  257 interface_t AculabDriver::getInterface(unsigned port)
  258 {
  259     if(port >= port_count)
  260         return INVALID_PORT;
  261 
  262     return interfaces[port];
  263 }
  264 
  265 void AculabDriver::setChannel(AculabTrunk *trunk)
  266 {
  267     if(trunk->channel >= MAXCHANNELS)
  268         return;
  269 
  270     if (call_handle_2_io(trunk->handle) == 0) { /* Incoming call */
  271         imaps[trunk->port * MAXCHANNELS + trunk->channel] = trunk;
  272     }
  273     else {
  274         omaps[trunk->port * MAXCHANNELS + trunk->channel] = trunk;
  275     }
  276     if (trunk->dspChannel != -1) {
  277         ixmaps[sm_get_channel_ix(trunk->dspChannel)] = trunk;
  278     }
  279 }
  280 
  281 void AculabDriver::clrChannel(AculabTrunk *trunk)
  282 {
  283     if(trunk->channel >= MAXCHANNELS)
  284         return;
  285 
  286     if (call_handle_2_io(trunk->handle) == 0) { /* Incoming call */
  287         imaps[trunk->port * MAXCHANNELS + trunk->channel] = NULL;
  288     }
  289     else {
  290         omaps[trunk->port * MAXCHANNELS + trunk->channel] = NULL;
  291     }
  292 }
  293 
  294 bool AculabDriver::getMVIPslot(int *stream, int *slot)
  295 {
  296     int mvip_stream=0;
  297     int mvip_slot=0;
  298 
  299     mvipMutex->enterMutex();
  300     while(MVIP[(mvip_stream * MVIP_FD_STREAMS) + mvip_slot]) {
  301         if(mvip_slot==(MVIP_TIMESLOTS-1)) {
  302             mvip_slot=0;
  303             if(mvip_stream==(MVIP_FD_STREAMS-1)) {
  304                 return false;
  305             }
  306             else {
  307                 mvip_stream++;
  308             }
  309         }
  310         else {
  311             mvip_slot++;
  312         }
  313     }
  314     MVIP[(mvip_stream * MVIP_FD_STREAMS) + mvip_slot]=1;
  315     mvipMutex->leaveMutex();
  316 
  317     *stream=mvip_stream;
  318     *slot=mvip_slot;
  319 
  320     return true;
  321 }
  322 
  323 
  324 void AculabDriver::freeMVIPslot(int stream, int slot)
  325 {
  326     mvipMutex->enterMutex();
  327     MVIP[(stream * MVIP_FD_STREAMS) + slot]=0;
  328     mvipMutex->leaveMutex();
  329 }
  330 
  331 bool AculabDriver::InitProsody(void)
  332 {
  333     struct sm_download_parms sm_download_parms;
  334     int rc;
  335     int this_module;
  336     int total_modules = sm_get_modules();
  337 
  338     slog(Slog::levelInfo) << "Aculab loading " << total_modules
  339             << " prosody modules" << endl;
  340 
  341     for(this_module = 0; this_module < total_modules; ++this_module) {
  342         if(sm_reset_module(this_module)) {
  343             slog(Slog::levelError) << "Aculab module " << this_module
  344                     << " failed, exiting..." << endl;
  345             return false;
  346         }
  347         sm_download_parms.module = this_module;
  348         sm_download_parms.id = 0;
  349         sm_download_parms.filename = (char *)getProsody();
  350         slog(Slog::levelInfo) << "Aculab module " << this_module
  351                 << " downloading '"<<sm_download_parms.filename
  352                 << "'..." << endl;
  353         rc=sm_download_fmw(&sm_download_parms);
  354         if (rc != 0) {
  355             slog(Slog::levelError) << "Aculab module download failed: "<<rc<<", exiting..." << endl;
  356             return false;
  357         }
  358     }
  359     return true;
  360 }
  361 
  362 bool AculabDriver::InitNetworks(void)
  363 {
  364     int total_switches;
  365     unsigned this_port, total_ports;
  366 
  367 //  struct sysinfo_xparms sysinfo;
  368     struct restart_xparms restart_xparms;
  369 
  370     int rc;
  371 
  372     pri_count = bri_count = 0;
  373     total_switches = sw_get_drvrs();
  374     if(total_switches < 1) {
  375         slog(Slog::levelError) << "Aculab Failure: no switch drivers" << endl;
  376         return false;
  377     }
  378 
  379     total_ports = call_nports();
  380 
  381     slog(Slog::levelInfo) << "Aculab: " << total_ports
  382             << " network ports available" << endl;
  383 
  384     for(this_port = 0; this_port < getMaxPorts(); ++this_port) {
  385         interfaces[this_port] = INVALID_PORT;
  386     }
  387 
  388     for(this_port = 0; this_port < total_ports; ++this_port) {
  389         
  390         if(call_line(this_port) == L_BASIC_RATE) {
  391             interfaces[this_port] = BRI_PORT;
  392             ++bri_count;
  393             restart_xparms.filenamep = (char *)getBriFirmware();
  394             restart_xparms.config_stringp = (char *)getBriConfig();
  395         }
  396         else {
  397             interfaces[this_port] = PRI_PORT;
  398             ++pri_count;
  399 
  400             char *firmware=(char *)getPriFirmware(this_port);
  401             if (firmware == NULL) {
  402                 restart_xparms.filenamep = (char *)getPriFirmware();
  403             }
  404             else {
  405                 restart_xparms.filenamep = firmware;
  406             }
  407             restart_xparms.config_stringp = (char *)getPriConfig();
  408             if (restart_xparms.config_stringp == NULL) {
  409                 restart_xparms.config_stringp="";
  410             }
  411         }
  412 
  413         if(call_is_download(this_port)) {
  414             slog(Slog::levelInfo) << "Aculab(" << this_port
  415                 << "): loading '" << restart_xparms.filenamep
  416                 << "'/'"<<restart_xparms.config_stringp
  417                 << "' to port  " << this_port << endl;
  418 
  419             restart_xparms.net = this_port;
  420             rc = call_restart_fmw(&restart_xparms);
  421             if(rc) {
  422                 slog(Slog::levelError) << "Aculab(" << this_port
  423                     << "): firmware load failure: " << rc << endl;
  424                 interfaces[this_port] = FAILED_PORT;
  425                 return false;
  426             }
  427         }
  428     }
  429 
  430     if(system_init()) {
  431         slog(Slog::levelError) << "Aculab: system init failure" << endl;
  432         return false;
  433     }
  434     return true;
  435 }
  436 
  437 int AculabDriver::start(void)
  438 {
  439     int count = 0;
  440     unsigned port, ts, id;
  441     int n;
  442 
  443     if(active) {
  444         slog(Slog::levelError) << "driver already started" << endl;
  445         return 0;
  446     }
  447 
  448     slog(Slog::levelDebug) << "starting " << WORKER_THREADS << " worker threads..." << endl;
  449 
  450     queue->enable();
  451 
  452     qthreads = new AculabQueueThread *[WORKER_THREADS];
  453 
  454     for(port = 0; port < port_count; ++port) {
  455         for(ts = 0; ts < MAXTIMESLOTS; ++ts) {
  456             id = port * MAXTIMESLOTS + ts;
  457             if(!tsmap[port * MAXTIMESLOTS + ts])
  458                 continue;
  459 
  460             trunks[id] = new AculabTrunk(port, ts);
  461             ++count;
  462         }
  463     }
  464 
  465     /*
  466      * start the consumer threads - just one per port for now.
  467      */
  468     for (n=0; n < WORKER_THREADS; n++) {
  469         qthreads[n]=new AculabQueueThread(queue);
  470         qthreads[n]->start();
  471     }
  472 
  473     /*
  474      * Start the dsp event thread (must be done after all
  475      * trunks are initialized).
  476      */
  477     dspthread=new AculabDSPEventThread(queue, ixmaps);
  478     dspthread->start();
  479 
  480     /*
  481      * start the audio processing thread
  482      */
  483     audiothread=new AculabAudioThread(queue, ixmaps);
  484     audiothread->start();
  485 
  486     /*
  487      * start the layer-1 monitoring thread
  488      */
  489     l1thread=new AculabMonitorThread();
  490     l1thread->start();
  491 
  492     timer=new AculabTimer();
  493     timer->start();
  494 
  495     if (!running) {
  496         Thread::start();
  497     }
  498     active=true;
  499 
  500     slog(Slog::levelInfo) << "driver started..." << endl;
  501     return count;
  502 }
  503 
  504 void AculabDriver::stop(void)
  505 {
  506     if(!active)
  507         return;
  508 
  509     if(trunks)
  510         memset(trunks, 0, sizeof(AculabTrunk *) * port_count * MAXTIMESLOTS);
  511 
  512     active = false;
  513     slog(Slog::levelInfo) << "driver stopping..." << endl;
  514 
  515     queue->disable();
  516 
  517     delete[] qthreads;
  518     qthreads = NULL;
  519 
  520     delete timer;
  521     timer=NULL;
  522 
  523     delete dspthread;
  524     dspthread=NULL;
  525 
  526     delete l1thread;
  527     l1thread=NULL;
  528 }
  529 
  530 Trunk *AculabDriver::getTrunkPort(int id)
  531 {
  532     if(id < 0 || id >= (int)port_count * MAXTIMESLOTS)
  533         return NULL;
  534 
  535     if(!trunks)
  536         return NULL;
  537 
  538     return (Trunk *)trunks[id];
  539 }
  540 
  541 // this should dispatch events thru putEvent!
  542 void AculabDriver::run(void)
  543 {
  544     struct state_xparms event_xparms;
  545 //  struct detail_xparms detail_xparms;
  546 //  struct cause_xparms cause;
  547     unsigned port, channel;
  548     int rc;
  549     AculabTrunk *trunk;
  550 
  551     while(active) {
  552         event_xparms.handle = 0;
  553         event_xparms.timeout = 500L;
  554 
  555         rc=call_event(&event_xparms);
  556         if(rc != 0) {
  557             slog(Slog::levelError) << "Aculab event failure, rc="<<rc<< endl;
  558             Thread::sleep(100);
  559             continue;
  560         }
  561 
  562         if(!event_xparms.handle)
  563             continue;
  564 
  565         port = call_handle_2_port(event_xparms.handle);
  566         channel = call_handle_2_chan(event_xparms.handle);
  567 
  568         if(port >= MAXPORT)
  569             continue;
  570 
  571         if(channel >= MAXCHANNELS)
  572             continue;
  573 
  574         slog(Slog::levelDebug)<<"got aculab event "<<event_xparms.state<<
  575                 " on port "<<port<<",chan "<<channel<<endl;
  576 
  577         if (call_handle_2_io(event_xparms.handle) == 0) {
  578             trunk = imaps[port * MAXCHANNELS + channel];
  579         }
  580         else {
  581             trunk = omaps[port * MAXCHANNELS + channel];
  582         }
  583         if(!trunk) {
  584             slog(Slog::levelWarning)<<": NO TRUNK FOR CHANNEL!"<<endl;
  585             continue;
  586         }
  587 
  588         switch(event_xparms.state) {
  589         case EV_WAIT_FOR_INCOMING:
  590         case EV_WAIT_FOR_OUTGOING:
  591         case EV_OUTGOING_PROCEEDING:
  592             break;
  593         case EV_DETAILS:
  594             postEvent(trunk,TRUNK_CALL_INFO);
  595             break;
  596         case EV_INCOMING_CALL_DET:
  597             postEvent(trunk,TRUNK_CALL_DETECT);
  598             break;
  599         case EV_CALL_CONNECTED:
  600             postEvent(trunk,TRUNK_CALL_CONNECT);
  601             break;
  602         case EV_PROGRESS:
  603         case EV_OUTGOING_RINGING:
  604             postEvent(trunk,TRUNK_CPA_RINGBACK);
  605             break;
  606         case EV_HOLD:
  607             postEvent(trunk,TRUNK_CALL_HOLD);
  608             break;
  609         case EV_HOLD_REJECT:
  610             postEvent(trunk,TRUNK_CALL_NOHOLD);
  611             break;
  612         case EV_TRANSFER_REJECT: /* Need better value here? */
  613             postEvent(trunk,TRUNK_CALL_FAILURE);
  614             break;
  615         case EV_IDLE:
  616             postEvent(trunk,TRUNK_CALL_RELEASE);
  617             break;
  618         default:
  619             slog(Slog::levelInfo) << "Aculab("<<port<<","<<trunk->ts<<") "
  620                     << "Unknown event type received: "
  621                     << event_xparms.state << endl;
  622             break;
  623         }
  624     }
  625 }
  626 
  627 /*
  628  * NOTE: This must _NOT_ block for very long!!!!
  629  * (or we will lose hardware events - driver doesn't queue events!)
  630  */
  631 void AculabDriver::postEvent(AculabTrunk *trunk, trunkevent_t id)
  632 {
  633     AculabTrunkEvent *aevent;
  634 
  635     aevent=new AculabTrunkEvent();
  636     aevent->trunk=trunk;
  637     aevent->event.id=id;
  638     queue->push(aevent);
  639 }
  640 
  641 /*
  642  * Dump out relavent information about an incoming call
  643  */
  644 void AculabDriver::dumpCallDetail(struct detail_xparms *details)
  645 {
  646     slog(Slog::levelInfo) << "  " << ((details->calltype == INCOMING) ? "INCOMING" : "OUTGOING")
  647             << " call initiated" <<endl;
  648 
  649     slog(Slog::levelInfo) << "  sending_complete="<<details->sending_complete<<endl;
  650     slog(Slog::levelInfo) << "  destination_addr='"<<details->destination_addr<<"'"<<endl;
  651     slog(Slog::levelInfo) << "  originating_addr='"<<details->originating_addr<<"'"<<endl;
  652     slog(Slog::levelInfo) << "  connected_addr  ='"<<details->connected_addr<<"'"<<endl;
  653     slog(Slog::levelInfo) << "  feature_info    ="<<details->feature_information<<endl;
  654 }
  655 
  656 
  657 AculabDriver aculabivr;
  658 
  659 #ifdef    CCXX_NAMESPACES
  660 };
  661 #endif