/***************************************************************************** * libhpsangoma.c: Sangoma High Performance TDM API - Span Based Library * * Author(s): Nenad Corbic * * Copyright: (c) 2008 Nenad Corbic * * 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. * ============================================================================ * */ #include "libhpsangoma.h" #include "libhpsangoma_priv.h" /*--------------------------------------------------------- PRIVATE STRUCTURES ----------------------------------------------------------*/ void (*lib_log)(int level, FILE *fp, char *file, const char *func, int line, char *fmt, ...)=NULL; /*! \brief Channel Method: User tx a chunk into a channel \param chan channel object \param data pointer to user voice chunk \param len size of user voice chunk \return -1 = packet too large, -2 = channel closed, 1 = busy, 0 = tx ok */ static int sangoma_hp_tdm_chan_push(struct sangoma_hptdm_chan *chan, char *data, int len) { hp_tmd_chunk_t *tx_chunk; int free_slots; if (!chan->init) { return -2; } if (len >= SMG_HP_MAX_CHAN_DATA) { /* Data Too Big */ lib_printf(0,NULL,"chan_push c%i tx chunk len %i too big\n", chan->span_no+1,chan->chan_no+1,chan->tx_idx_in,len); return -1; } /* Lock */ if (chan->tx_idx_in >= chan->tx_idx_out) { free_slots=SMG_HP_TDM_CHUNK_IDX_SZ-(chan->tx_idx_in-chan->tx_idx_out); } else { free_slots=chan->tx_idx_out-chan->tx_idx_in; } /* Un Lock */ if (!free_slots) { /* We have just overruned the tx buffer */ lib_printf(0,NULL,"chan_push c%i failed no free slots in %i out %i\n", chan->span_no+1,chan->chan_no+1, chan->tx_idx_in,chan->tx_idx_out); return 1; } tx_chunk = &chan->tx_idx[chan->tx_idx_in]; if (tx_chunk->init) { /* This should NEVER happen the chunk should be free */ lib_printf(15,NULL,"chan_push s%ic%i tx chunk overrun in %i \n", chan->span_no+1,chan->chan_no+1,chan->tx_idx_in); return 1; } memset(tx_chunk,0,sizeof(hp_tmd_chunk_t)); memcpy(&tx_chunk->data,data,len); tx_chunk->len=len; tx_chunk->init=1; lib_printf(15,NULL,"chan_push s%ic%i tx chunk in %i \n", chan->span_no+1,chan->chan_no+1,chan->tx_idx_in); chan->tx_idx_in++; if (chan->tx_idx_in >= SMG_HP_TDM_CHUNK_IDX_SZ) { chan->tx_idx_in=0; } return 0; } /*------------------------------------------------- Internal Span Methods -------------------------------------------------*/ /*! \brief Span Method: Open a channel inside of span \param span span object \param cfg channel registration structure \param chan_no channel number \param chan_ptr pass user the channel pointer reference \return 0 = pass, non zero fail */ static int sangoma_hp_tdm_open_chan(sangoma_hptdm_span_t *span, sangoma_hptdm_chan_reg_t *cfg, unsigned int chan_no, sangoma_hptdm_chan_t **chan_ptr) { sangoma_hptdm_chan_t *chan; if (!span->init) { return -1; } if (chan_no >= SMG_HP_TDM_MAX_CHANS) { lib_printf(0,NULL,"open_chan failed chan_no %i >= max chans %i\n", chan_no, SMG_HP_TDM_MAX_CHANS); return -1; } if (!cfg->rx_data || !cfg->p) { return -1; } if (span->chan_idx[chan_no].chan_no_hw < 0) { lib_printf(0,NULL,"open_chan failed chan_no s%ic%i is not mapped to hardware\n", span->span_no+1,chan_no+1); return -1; } chan = &span->chan_idx[chan_no].chan; if (chan->init) { /* Chan Busy */ lib_printf(0,NULL,"open_chan failed chan_no s%ic%i is busy\n", span->span_no+1,chan_no+1); return 1; } memset(chan,0,sizeof(sangoma_hptdm_chan_t)); chan->chan_no = chan_no; chan->span = span; memcpy(&chan->chan_reg, cfg, sizeof(sangoma_hptdm_chan_reg_t)); chan->push = sangoma_hp_tdm_chan_push; chan->init=1; lib_printf(15,NULL,"open_chan chan_no s%ic%i ok\n", span->span_no+1,chan_no+1); *chan_ptr = chan; return 0; } /*! \brief Span Method: Close channel \param chan channel object \return 0 = pass, non zero fail */ static int sangoma_hp_tdm_close_chan(sangoma_hptdm_chan_t *chan) { chan->init=0; chan->chan_reg.p=NULL; lib_printf(15,NULL,"close_chan chan_no s%ic%i ok\n", chan->span_no+1,chan->chan_no+1); return 0; } /*! \brief Span Method: Test if channel is closed \param chan channel object \return 0 = channel is NOT closed, non zero channel IS closed */ static int sangoma_hp_tdm_is_chan_closed (sangoma_hptdm_chan_t *chan) { return (chan->init == 0) ? 1:0; } /*! \brief Span Method: Close span \param span span object \return 0 = pass, non zero fail */ static int sangoma_hp_tdm_close_span(sangoma_hptdm_span_t *span) { int i; sangoma_hptdm_chan_t *chan=NULL; for (i=0;ichan_idx[i].chan; if (chan->init) { chan->init=0; } } close(span->sock); span->sock=-1; return 0; } /*! \brief Span Method: User passes cmd to the span \param span span object \return 0 = pass, non zero fail */ static int sangoma_hp_tdm_event_ctrl_span(sangoma_hptdm_span_t *span, hp_tdmapi_tx_event_t *event) { int err; if (!span->init || span->sock < 0) { return -1; } err = ioctl(span->sock,SIOC_WANPIPE_API,event); if (err < 0){ lib_printf(0,NULL,"Error: SPAN %i Failed to execute event!\n", span->span_no+1); return -1; } return 0; } /*! \brief Span Method: User requests full span configuration \param span span object \return 0 = pass, non zero fail */ static int sangoma_hp_tdm_event_get_cfg(sangoma_hptdm_span_t *span, wan_if_cfg_t *if_cfg) { memcpy(if_cfg,&span->span_cfg,sizeof(if_cfg)); return 0; } /*! \brief Span Method: handle the span \param span span object \return 0 = pass, non zero fail */ static int sangoma_hp_tdm_run_span(sangoma_hptdm_span_t *span) { int err=0; fd_set sock_read,sock_write,sock_oob; if (!span->init) { lib_printf(0, NULL, "Span %i not initialized %i\n",span->span_no+1); return -1; } lib_printf(15, NULL, "Starting RUN SPAN %i Sock=%i\n",span->span_no+1, span->sock); if (span->sock < 0) { err=sangoma_hptdm_span_open(span); if (err) { usleep(500000); err=-2; goto sangoma_hp_tdm_run_span_exit; } } /* Initialize all select() descriptors */ FD_ZERO(&sock_read); FD_ZERO(&sock_write); FD_ZERO(&sock_oob); FD_SET(span->sock,&sock_oob); FD_SET(span->sock,&sock_read); FD_SET(span->sock,&sock_write); err=select(span->sock + 1,&sock_read, NULL, &sock_oob, NULL); if (err > 0) { if (FD_ISSET(span->sock,&sock_oob)){ err=sangoma_hp_tdm_handle_oob_event(span); if (err) { lib_printf(0, NULL, "RUN SPAN: %i oob err %i\n", span->span_no+1, err); err=-3; goto sangoma_hp_tdm_run_span_exit; } } if (FD_ISSET(span->sock,&sock_read)){ err=sangoma_hp_tdm_handle_read_event(span); if (err) { lib_printf(0, NULL, "RUN SPAN: %i read err %i\n", span->span_no+1, err); err=-4; goto sangoma_hp_tdm_run_span_exit; } err=sangoma_hp_tdm_handle_write_event(span); if (err) { lib_printf(0, NULL, "RUN SPAN: %i write err %i\n", span->span_no+1, err); err=-5; goto sangoma_hp_tdm_run_span_exit; } } } else if (err==0) { /* Timeout continue */ return 0; } else { /* Error */ if (errno == EAGAIN) { goto sangoma_hp_tdm_run_span_exit; } err=-6; } sangoma_hp_tdm_run_span_exit: if (err < 0) { if (span->sock) { close(span->sock); span->sock=-1; } } return err; } /*--------------------------------------------------------- PUBLIC STRUCTURES ----------------------------------------------------------*/ /* \brief Initialize and Configure Span - private functions not to be used directly! \param span_no span number - integer \param cfg span registration struct \param version library version number added by the macro \return NULL: fail, Span Object: pass * * The __sangoma_hptdm_api_span_init() function must NOT be called directly! * One MUST use defined sangoma_hptdm_api_span_init() macro instead */ sangoma_hptdm_span_t * __sangoma_hptdm_api_span_init(int span_no, sangoma_hptdm_span_reg_t *cfg, int version) { int err,i,ch=0; sangoma_hptdm_span_t *span; span = malloc(sizeof(sangoma_hptdm_span_t)); if (!span) { return NULL; } memset(span,0,sizeof(sangoma_hptdm_span_t)); span->span_no=span_no; sprintf(span->if_name,"w%ig1",span_no+1); if (cfg) { memcpy(&span->span_reg,cfg,sizeof(sangoma_hptdm_span_reg_t)); if (!lib_log) { lib_log=cfg->log; } } err=sangoma_hptdm_span_open(span); if (err) { free(span); return NULL; } if (span->span_cfg.media == WAN_MEDIA_E1) { span->span_cfg.active_ch = span->span_cfg.active_ch >> 1; } lib_printf(0,NULL,"Span %i Configuration\n",span->span_no+1); lib_printf(0,NULL,"Used By\t:%i\n",span->span_cfg.usedby); lib_printf(0,NULL,"Media\t:%i\n",span->span_cfg.media); lib_printf(0,NULL,"Active Ch\t:0x%08X\n",span->span_cfg.active_ch); lib_printf(0,NULL,"Chunk Sz\t:%i\n",span->span_cfg.chunk_sz); lib_printf(0,NULL,"HW Coding\t:%i\n",span->span_cfg.hw_coding); lib_printf(0,NULL,"If Number\t:%i\n",span->span_cfg.interface_number); /* Map all channels to the actually configued on hardware */ for (i=0;ichan_idx[i].chan_no_hw=-1; if (span->span_cfg.active_ch & (1<chan_idx[i].chan_no_hw=ch; lib_printf(0,NULL,"Chan %i Mapped to %i",i,ch); ch++; span->max_chans++; } else { lib_printf(0,NULL,"Chan %i Not Mapped",i); } } lib_printf(0,NULL,"Total Chans\t:%i\n",span->max_chans); /* Must be configurable */ span->chunk_sz=span->span_cfg.chunk_sz; span->tx_size=span->max_chans*span->chunk_sz; span->init=1; span->idle=0xFF; span->open_chan = sangoma_hp_tdm_open_chan; span->close_chan = sangoma_hp_tdm_close_chan; span->is_chan_closed = sangoma_hp_tdm_is_chan_closed; span->run_span =sangoma_hp_tdm_run_span; span->close_span = sangoma_hp_tdm_close_span; span->event_ctrl = sangoma_hp_tdm_event_ctrl_span; span->get_cfg = sangoma_hp_tdm_event_get_cfg; lib_printf(5, NULL, "Span %i Initialized\n",span->span_no+1); return span; } /* \brief Free, Un-Initialize Span \param span_no span object \return 0 = pass, non zero fail */ int sangoma_hptdm_api_span_free(sangoma_hptdm_span_t *span) { if (span->sock >= 0) { span->close_span(span); } free(span); span=NULL; return 0; }