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

capifunc.c

/* $Id: capifunc.c,v 1.61.4.7 2005/02/11 19:40:25 armin Exp $
 *
 * ISDN interface module for Eicon active cards DIVA.
 * CAPI Interface common functions
 * 
 * Copyright 2000-2003 by Armin Schindler (mac@melware.de) 
 * Copyright 2000-2003 Cytronics & Melware (info@melware.de)
 * 
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 */

#include "platform.h"
#include "os_capi.h"
#include "di_defs.h"
#include "capi20.h"
#include "divacapi.h"
#include "divasync.h"
#include "capifunc.h"

#define DBG_MINIMUM  (DL_LOG + DL_FTL + DL_ERR)
#define DBG_DEFAULT  (DBG_MINIMUM + DL_XLOG + DL_REG)

DIVA_CAPI_ADAPTER *adapter = (DIVA_CAPI_ADAPTER *) NULL;
APPL *application = (APPL *) NULL;
byte max_appl = MAX_APPL;
byte max_adapter = 0;
static CAPI_MSG *mapped_msg = (CAPI_MSG *) NULL;

byte UnMapController(byte);
char DRIVERRELEASE_CAPI[32];

extern void AutomaticLaw(DIVA_CAPI_ADAPTER *);
extern void callback(ENTITY *);
extern word api_remove_start(void);
extern word CapiRelease(word);
extern word CapiRegister(word);
extern word api_put(APPL *, CAPI_MSG *);

static diva_os_spin_lock_t api_lock;

static LIST_HEAD(cards);

static dword notify_handle;
static void DIRequest(ENTITY * e);
static DESCRIPTOR MAdapter;
static DESCRIPTOR DAdapter;
static byte ControllerMap[MAX_DESCRIPTORS + 1];


static void diva_register_appl(struct capi_ctr *, __u16,
                         capi_register_params *);
static void diva_release_appl(struct capi_ctr *, __u16);
static char *diva_procinfo(struct capi_ctr *);
static u16 diva_send_message(struct capi_ctr *,
                       diva_os_message_buffer_s *);
extern void diva_os_set_controller_struct(struct capi_ctr *);

extern void DIVA_DIDD_Read(DESCRIPTOR *, int);

/*
 * debug
 */
static void no_printf(unsigned char *, ...);
#include "debuglib.c"
static void xlog(char *x, ...)
{
#ifndef DIVA_NO_DEBUGLIB
      va_list ap;
      if (myDriverDebugHandle.dbgMask & DL_XLOG) {
            va_start(ap, x);
            if (myDriverDebugHandle.dbg_irq) {
                  myDriverDebugHandle.dbg_irq(myDriverDebugHandle.id,
                                        DLI_XLOG, x, ap);
            } else if (myDriverDebugHandle.dbg_old) {
                  myDriverDebugHandle.dbg_old(myDriverDebugHandle.id,
                                        x, ap);
            }
            va_end(ap);
      }
#endif
}

/*
 * info for proc
 */
static char *diva_procinfo(struct capi_ctr *ctrl)
{
      return (ctrl->serial);
}

/*
 * stop debugging
 */
static void stop_dbg(void)
{
      DbgDeregister();
      memset(&MAdapter, 0, sizeof(MAdapter));
      dprintf = no_printf;
}

/*
 * dummy debug function
 */
static void no_printf(unsigned char *x, ...)
{
}

/*
 * Controller mapping
 */
byte MapController(byte Controller)
{
      byte i;
      byte MappedController = 0;
      byte ctrl = Controller & 0x7f;      /* mask external controller bit off */

      for (i = 1; i < max_adapter + 1; i++) {
            if (ctrl == ControllerMap[i]) {
                  MappedController = (byte) i;
                  break;
            }
      }
      if (i > max_adapter) {
            ControllerMap[0] = ctrl;
            MappedController = 0;
      }
      return (MappedController | (Controller & 0x80));      /* put back external controller bit */
}

/*
 * Controller unmapping
 */
byte UnMapController(byte MappedController)
{
      byte Controller;
      byte ctrl = MappedController & 0x7f;      /* mask external controller bit off */

      if (ctrl <= max_adapter) {
            Controller = ControllerMap[ctrl];
      } else {
            Controller = 0;
      }

      return (Controller | (MappedController & 0x80));      /* put back external controller bit */
}

/*
 * find a new free id
 */
static int find_free_id(void)
{
      int num = 0;
      DIVA_CAPI_ADAPTER *a;

      while (num < MAX_DESCRIPTORS) {
            a = &adapter[num];
            if (!a->Id)
                  break;
            num++;
      }
      return(num + 1);
}

/*
 * find a card structure by controller number
 */
static diva_card *find_card_by_ctrl(word controller)
{
      struct list_head *tmp;
      diva_card *card;

      list_for_each(tmp, &cards) {
            card = list_entry(tmp, diva_card, list);
            if (ControllerMap[card->Id] == controller) {
                  if (card->remove_in_progress)
                        card = NULL;
                  return(card);
            }
      }
      return (diva_card *) 0;
}

/*
 * Buffer RX/TX 
 */
void *TransmitBufferSet(APPL * appl, dword ref)
{
      appl->xbuffer_used[ref] = true;
      DBG_PRV1(("%d:xbuf_used(%d)", appl->Id, ref + 1))
          return (void *)(long)ref;
}

void *TransmitBufferGet(APPL * appl, void *p)
{
      if (appl->xbuffer_internal[(dword)(long)p])
            return appl->xbuffer_internal[(dword)(long)p];

      return appl->xbuffer_ptr[(dword)(long)p];
}

void TransmitBufferFree(APPL * appl, void *p)
{
      appl->xbuffer_used[(dword)(long)p] = false;
      DBG_PRV1(("%d:xbuf_free(%d)", appl->Id, ((dword)(long)p) + 1))
}

void *ReceiveBufferGet(APPL * appl, int Num)
{
      return &appl->ReceiveBuffer[Num * appl->MaxDataLength];
}

/*
 * api_remove_start/complete for cleanup
 */
void api_remove_complete(void)
{
      DBG_PRV1(("api_remove_complete"))
}

/*
 * main function called by message.c
 */
void sendf(APPL * appl, word command, dword Id, word Number, byte * format, ...)
{
      word i, j;
      word length = 12, dlength = 0;
      byte *write;
      CAPI_MSG msg;
      byte *string = NULL;
      va_list ap;
      diva_os_message_buffer_s *dmb;
      diva_card *card = NULL;
      dword tmp;

      if (!appl)
            return;

      DBG_PRV1(("sendf(a=%d,cmd=%x,format=%s)",
              appl->Id, command, (byte *) format))

      PUT_WORD(&msg.header.appl_id, appl->Id);
      PUT_WORD(&msg.header.command, command);
      if ((byte) (command >> 8) == 0x82)
            Number = appl->Number++;
      PUT_WORD(&msg.header.number, Number);

      PUT_DWORD(&msg.header.controller, Id);
      write = (byte *) & msg;
      write += 12;

      va_start(ap, format);
      for (i = 0; format[i]; i++) {
            switch (format[i]) {
            case 'b':
                  tmp = va_arg(ap, dword);
                  *(byte *) write = (byte) (tmp & 0xff);
                  write += 1;
                  length += 1;
                  break;
            case 'w':
                  tmp = va_arg(ap, dword);
                  PUT_WORD(write, (tmp & 0xffff));
                  write += 2;
                  length += 2;
                  break;
            case 'd':
                  tmp = va_arg(ap, dword);
                  PUT_DWORD(write, tmp);
                  write += 4;
                  length += 4;
                  break;
            case 's':
            case 'S':
                  string = va_arg(ap, byte *);
                  length += string[0] + 1;
                  for (j = 0; j <= string[0]; j++)
                        *write++ = string[j];
                  break;
            }
      }
      va_end(ap);

      PUT_WORD(&msg.header.length, length);
      msg.header.controller = UnMapController(msg.header.controller);

      if (command == _DATA_B3_I)
            dlength = GET_WORD(
                        ((byte *) & msg.info.data_b3_ind.Data_Length));

      if (!(dmb = diva_os_alloc_message_buffer(length + dlength,
                                (void **) &write))) {
            DBG_ERR(("sendf: alloc_message_buffer failed, incoming msg dropped."))
            return;
      }

      /* copy msg header to sk_buff */
      memcpy(write, (byte *) & msg, length);

      /* if DATA_B3_IND, copy data too */
      if (command == _DATA_B3_I) {
            dword data = GET_DWORD(&msg.info.data_b3_ind.Data);
            memcpy(write + length, (void *)(long)data, dlength);
      }

#ifndef DIVA_NO_DEBUGLIB
      if (myDriverDebugHandle.dbgMask & DL_XLOG) {
            switch (command) {
            default:
                  xlog("\x00\x02", &msg, 0x81, length);
                  break;
            case _DATA_B3_R | CONFIRM:
                  if (myDriverDebugHandle.dbgMask & DL_BLK)
                        xlog("\x00\x02", &msg, 0x81, length);
                  break;
            case _DATA_B3_I:
                  if (myDriverDebugHandle.dbgMask & DL_BLK) {
                        xlog("\x00\x02", &msg, 0x81, length);
                        for (i = 0; i < dlength; i += 256) {
                          DBG_BLK((((char *)(long)GET_DWORD(&msg.info.data_b3_ind.Data)) + i,
                              ((dlength - i) < 256) ? (dlength - i) : 256))
                          if (!(myDriverDebugHandle.dbgMask & DL_PRV0))
                                break; /* not more if not explicitly requested */
                        }
                  }
                  break;
            }
      }
#endif

      /* find the card structure for this controller */
      if (!(card = find_card_by_ctrl(write[8] & 0x7f))) {
            DBG_ERR(("sendf - controller %d not found, incoming msg dropped",
                   write[8] & 0x7f))
            diva_os_free_message_buffer(dmb);
            return;
      }
      /* send capi msg to capi layer */
      capi_ctr_handle_message(&card->capi_ctrl, appl->Id, dmb);
}

/*
 * cleanup adapter
 */
static void clean_adapter(int id, struct list_head *free_mem_q)
{
      DIVA_CAPI_ADAPTER *a;
      int i, k;

      a = &adapter[id];
      k = li_total_channels - a->li_channels;
      if (k == 0) {
            if (li_config_table) {
                  list_add((struct list_head *)li_config_table, free_mem_q);
                  li_config_table = NULL;
            }
      } else {
            if (a->li_base < k) {
                  memmove(&li_config_table[a->li_base],
                        &li_config_table[a->li_base + a->li_channels],
                        (k - a->li_base) * sizeof(LI_CONFIG));
                  for (i = 0; i < k; i++) {
                        memmove(&li_config_table[i].flag_table[a->li_base],
                              &li_config_table[i].flag_table[a->li_base + a->li_channels],
                              k - a->li_base);
                        memmove(&li_config_table[i].
                              coef_table[a->li_base],
                              &li_config_table[i].coef_table[a->li_base + a->li_channels],
                              k - a->li_base);
                  }
            }
      }
      li_total_channels = k;
      for (i = id; i < max_adapter; i++) {
            if (adapter[i].request)
                  adapter[i].li_base -= a->li_channels;
      }
      if (a->plci)
            list_add((struct list_head *)a->plci, free_mem_q);

      memset(a, 0x00, sizeof(DIVA_CAPI_ADAPTER));
      while ((max_adapter != 0) && !adapter[max_adapter - 1].request)
            max_adapter--;
}

/*
 * remove a card, but ensures consistent state of LI tables
 * in the time adapter is removed
 */
static void divacapi_remove_card(DESCRIPTOR * d)
{
      diva_card *card = NULL;
      diva_os_spin_lock_magic_t old_irql;
      LIST_HEAD(free_mem_q);
      struct list_head *link;
      struct list_head *tmp;

      /*
       * Set "remove in progress flag".
       * Ensures that there is no call from sendf to CAPI in
       * the time CAPI controller is about to be removed.
       */
      diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card");
      list_for_each(tmp, &cards) {
            card = list_entry(tmp, diva_card, list);
            if (card->d.request == d->request) {
                  card->remove_in_progress = 1;
                  list_del(tmp);
                  break;
            }
      }
      diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card");

      if (card) {
            /*
             * Detach CAPI. Sendf cannot call to CAPI any more.
             * After detach no call to send_message() is done too.
             */
            detach_capi_ctr(&card->capi_ctrl);

            /*
             * Now get API lock (to ensure stable state of LI tables)
             * and update the adapter map/LI table.
             */
            diva_os_enter_spin_lock(&api_lock, &old_irql, "remove card");

            clean_adapter(card->Id - 1, &free_mem_q);
            DBG_TRC(("DelAdapterMap (%d) -> (%d)",
                        ControllerMap[card->Id], card->Id))
                        ControllerMap[card->Id] = 0;
            DBG_TRC(("adapter remove, max_adapter=%d",
                        max_adapter));
            diva_os_leave_spin_lock(&api_lock, &old_irql, "remove card");
            
            /* After releasing the lock, we can free the memory */
            diva_os_free (0, card);
      }

      /* free queued memory areas */
      list_for_each_safe(link, tmp, &free_mem_q) {
            list_del(link);
            diva_os_free(0, link);
      }
}

/*
 * remove cards
 */
static void divacapi_remove_cards(void)
{
      DESCRIPTOR d;
      struct list_head *tmp;
      diva_card *card;
      diva_os_spin_lock_magic_t old_irql;

rescan:
      diva_os_enter_spin_lock(&api_lock, &old_irql, "remove cards");
      list_for_each(tmp, &cards) {
            card = list_entry(tmp, diva_card, list);
            diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards");
            d.request = card->d.request;
            divacapi_remove_card(&d);
            goto rescan;
      }
      diva_os_leave_spin_lock(&api_lock, &old_irql, "remove cards");
}

/*
 * sync_callback
 */
static void sync_callback(ENTITY * e)
{
      diva_os_spin_lock_magic_t old_irql;

      DBG_TRC(("cb:Id=%x,Rc=%x,Ind=%x", e->Id, e->Rc, e->Ind))

      diva_os_enter_spin_lock(&api_lock, &old_irql, "sync_callback");
      callback(e);
      diva_os_leave_spin_lock(&api_lock, &old_irql, "sync_callback");
}

/*
 * add a new card
 */
static int diva_add_card(DESCRIPTOR * d)
{
      int k = 0, i = 0;
      diva_os_spin_lock_magic_t old_irql;
      diva_card *card = NULL;
      struct capi_ctr *ctrl = NULL;
      DIVA_CAPI_ADAPTER *a = NULL;
      IDI_SYNC_REQ sync_req;
      char serial[16];
      void* mem_to_free;
      LI_CONFIG *new_li_config_table;
      int j;

      if (!(card = (diva_card *) diva_os_malloc(0, sizeof(diva_card)))) {
            DBG_ERR(("diva_add_card: failed to allocate card struct."))
                return (0);
      }
      memset((char *) card, 0x00, sizeof(diva_card));
      memcpy(&card->d, d, sizeof(DESCRIPTOR));
      sync_req.GetName.Req = 0;
      sync_req.GetName.Rc = IDI_SYNC_REQ_GET_NAME;
      card->d.request((ENTITY *) & sync_req);
      strlcpy(card->name, sync_req.GetName.name, sizeof(card->name));
      ctrl = &card->capi_ctrl;
      strcpy(ctrl->name, card->name);
      ctrl->register_appl = diva_register_appl;
      ctrl->release_appl = diva_release_appl;
      ctrl->send_message = diva_send_message;
      ctrl->procinfo = diva_procinfo;
      ctrl->driverdata = card;
      diva_os_set_controller_struct(ctrl);

      if (attach_capi_ctr(ctrl)) {
            DBG_ERR(("diva_add_card: failed to attach controller."))
                diva_os_free(0, card);
            return (0);
      }
      
      diva_os_enter_spin_lock(&api_lock, &old_irql, "find id");
      card->Id = find_free_id();
      diva_os_leave_spin_lock(&api_lock, &old_irql, "find id");
      
      strlcpy(ctrl->manu, M_COMPANY, sizeof(ctrl->manu));
      ctrl->version.majorversion = 2;
      ctrl->version.minorversion = 0;
      ctrl->version.majormanuversion = DRRELMAJOR;
      ctrl->version.minormanuversion = DRRELMINOR;
      sync_req.GetSerial.Req = 0;
      sync_req.GetSerial.Rc = IDI_SYNC_REQ_GET_SERIAL;
      sync_req.GetSerial.serial = 0;
      card->d.request((ENTITY *) & sync_req);
      if ((i = ((sync_req.GetSerial.serial & 0xff000000) >> 24))) {
            sprintf(serial, "%ld-%d",
                  sync_req.GetSerial.serial & 0x00ffffff, i + 1);
      } else {
            sprintf(serial, "%ld", sync_req.GetSerial.serial);
      }
      serial[CAPI_SERIAL_LEN - 1] = 0;
      strlcpy(ctrl->serial, serial, sizeof(ctrl->serial));

      a = &adapter[card->Id - 1];
      card->adapter = a;
      a->os_card = card;
      ControllerMap[card->Id] = (byte) (ctrl->cnr);

      DBG_TRC(("AddAdapterMap (%d) -> (%d)", ctrl->cnr, card->Id))

          sync_req.xdi_capi_prms.Req = 0;
      sync_req.xdi_capi_prms.Rc = IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS;
      sync_req.xdi_capi_prms.info.structure_length =
          sizeof(diva_xdi_get_capi_parameters_t);
      card->d.request((ENTITY *) & sync_req);
      a->flag_dynamic_l1_down =
          sync_req.xdi_capi_prms.info.flag_dynamic_l1_down;
      a->group_optimization_enabled =
          sync_req.xdi_capi_prms.info.group_optimization_enabled;
      a->request = DIRequest; /* card->d.request; */
      a->max_plci = card->d.channels + 30;
      a->max_listen = (card->d.channels > 2) ? 8 : 2;
      if (!
          (a->plci =
           (PLCI *) diva_os_malloc(0, sizeof(PLCI) * a->max_plci))) {
            DBG_ERR(("diva_add_card: failed alloc plci struct."))
                memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
            return (0);
      }
      memset(a->plci, 0, sizeof(PLCI) * a->max_plci);

      for (k = 0; k < a->max_plci; k++) {
            a->Id = (byte) card->Id;
            a->plci[k].Sig.callback = sync_callback;
            a->plci[k].Sig.XNum = 1;
            a->plci[k].Sig.X = a->plci[k].XData;
            a->plci[k].Sig.user[0] = (word) (card->Id - 1);
            a->plci[k].Sig.user[1] = (word) k;
            a->plci[k].NL.callback = sync_callback;
            a->plci[k].NL.XNum = 1;
            a->plci[k].NL.X = a->plci[k].XData;
            a->plci[k].NL.user[0] = (word) ((card->Id - 1) | 0x8000);
            a->plci[k].NL.user[1] = (word) k;
            a->plci[k].adapter = a;
      }

      a->profile.Number = card->Id;
      a->profile.Channels = card->d.channels;
      if (card->d.features & DI_FAX3) {
            a->profile.Global_Options = 0x71;
            if (card->d.features & DI_CODEC)
                  a->profile.Global_Options |= 0x6;
#if IMPLEMENT_DTMF
            a->profile.Global_Options |= 0x8;
#endif                        /* IMPLEMENT_DTMF */
            a->profile.Global_Options |= 0x80; /* Line Interconnect */
#if IMPLEMENT_ECHO_CANCELLER
            a->profile.Global_Options |= 0x100;
#endif                        /* IMPLEMENT_ECHO_CANCELLER */
            a->profile.B1_Protocols = 0xdf;
            a->profile.B2_Protocols = 0x1fdb;
            a->profile.B3_Protocols = 0xb7;
            a->manufacturer_features = MANUFACTURER_FEATURE_HARDDTMF;
      } else {
            a->profile.Global_Options = 0x71;
            if (card->d.features & DI_CODEC)
                  a->profile.Global_Options |= 0x2;
            a->profile.B1_Protocols = 0x43;
            a->profile.B2_Protocols = 0x1f0f;
            a->profile.B3_Protocols = 0x07;
            a->manufacturer_features = 0;
      }

      a->li_pri = (a->profile.Channels > 2);
      a->li_channels = a->li_pri ? MIXER_CHANNELS_PRI : MIXER_CHANNELS_BRI;
      a->li_base = 0;
      for (i = 0; &adapter[i] != a; i++) {
            if (adapter[i].request)
                  a->li_base = adapter[i].li_base + adapter[i].li_channels;
      }
      k = li_total_channels + a->li_channels;
      new_li_config_table =
            (LI_CONFIG *) diva_os_malloc(0, ((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * k) * ((k + 3) & ~3));
      if (new_li_config_table == NULL) {
            DBG_ERR(("diva_add_card: failed alloc li_config table."))
            memset(a, 0, sizeof(DIVA_CAPI_ADAPTER));
            return (0);
      }

      /* Prevent access to line interconnect table in process update */
      diva_os_enter_spin_lock(&api_lock, &old_irql, "add card");
      
      j = 0;
      for (i = 0; i < k; i++) {
            if ((i >= a->li_base) && (i < a->li_base + a->li_channels))
                  memset(&new_li_config_table[i], 0, sizeof(LI_CONFIG));
            else
                  memcpy(&new_li_config_table[i], &li_config_table[j], sizeof(LI_CONFIG));
            new_li_config_table[i].flag_table =
                  ((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i) * ((k + 3) & ~3));
            new_li_config_table[i].coef_table =
                  ((byte *) new_li_config_table) + (((k * sizeof(LI_CONFIG) + 3) & ~3) + (2 * i + 1) * ((k + 3) & ~3));
            if ((i >= a->li_base) && (i < a->li_base + a->li_channels)) {
                  new_li_config_table[i].adapter = a;
                  memset(&new_li_config_table[i].flag_table[0], 0, k);
                  memset(&new_li_config_table[i].coef_table[0], 0, k);
            } else {
                  if (a->li_base != 0) {
                        memcpy(&new_li_config_table[i].flag_table[0],
                               &li_config_table[j].flag_table[0],
                               a->li_base);
                        memcpy(&new_li_config_table[i].coef_table[0],
                               &li_config_table[j].coef_table[0],
                               a->li_base);
                  }
                  memset(&new_li_config_table[i].flag_table[a->li_base], 0, a->li_channels);
                  memset(&new_li_config_table[i].coef_table[a->li_base], 0, a->li_channels);
                  if (a->li_base + a->li_channels < k) {
                        memcpy(&new_li_config_table[i].flag_table[a->li_base +
                               a->li_channels],
                               &li_config_table[j].flag_table[a->li_base],
                               k - (a->li_base + a->li_channels));
                        memcpy(&new_li_config_table[i].coef_table[a->li_base +
                               a->li_channels],
                               &li_config_table[j].coef_table[a->li_base],
                               k - (a->li_base + a->li_channels));
                  }
                  j++;
            }
      }
      li_total_channels = k;

      mem_to_free = li_config_table;

      li_config_table = new_li_config_table;
      for (i = card->Id; i < max_adapter; i++) {
            if (adapter[i].request)
                  adapter[i].li_base += a->li_channels;
      }

      if (a == &adapter[max_adapter])
            max_adapter++;

      list_add(&(card->list), &cards);
      AutomaticLaw(a);

      diva_os_leave_spin_lock(&api_lock, &old_irql, "add card");

      if (mem_to_free) {
            diva_os_free (0, mem_to_free);
      }

      i = 0;
      while (i++ < 30) {
            if (a->automatic_law > 3)
                  break;
            diva_os_sleep(10);
      }

      /* profile information */
      PUT_WORD(&ctrl->profile.nbchannel, card->d.channels);
      ctrl->profile.goptions = a->profile.Global_Options;
      ctrl->profile.support1 = a->profile.B1_Protocols;
      ctrl->profile.support2 = a->profile.B2_Protocols;
      ctrl->profile.support3 = a->profile.B3_Protocols;
      /* manufacturer profile information */
      ctrl->profile.manu[0] = a->man_profile.private_options;
      ctrl->profile.manu[1] = a->man_profile.rtp_primary_payloads;
      ctrl->profile.manu[2] = a->man_profile.rtp_additional_payloads;
      ctrl->profile.manu[3] = 0;
      ctrl->profile.manu[4] = 0;

      capi_ctr_ready(ctrl);

      DBG_TRC(("adapter added, max_adapter=%d", max_adapter));
      return (1);
}

/*
 *  register appl
 */
static void diva_register_appl(struct capi_ctr *ctrl, __u16 appl,
                         capi_register_params * rp)
{
      APPL *this;
      word bnum, xnum;
      int i = 0;
      unsigned char *p;
      void *DataNCCI, *DataFlags, *ReceiveBuffer, *xbuffer_used;
      void **xbuffer_ptr, **xbuffer_internal;
      diva_os_spin_lock_magic_t old_irql;
      unsigned int mem_len;
      int nconn = rp->level3cnt;


      if (diva_os_in_irq()) {
            DBG_ERR(("CAPI_REGISTER - in irq context !"))
            return;
      }

      DBG_TRC(("application register Id=%d", appl))

      if (appl > MAX_APPL) {
            DBG_ERR(("CAPI_REGISTER - appl.Id exceeds MAX_APPL"))
            return;
      }

      if (nconn <= 0)
            nconn = ctrl->profile.nbchannel * -nconn;

        if (nconn == 0)
            nconn = ctrl->profile.nbchannel;

      DBG_LOG(("CAPI_REGISTER - Id = %d", appl))
      DBG_LOG(("  MaxLogicalConnections = %d(%d)", nconn, rp->level3cnt))
      DBG_LOG(("  MaxBDataBuffers       = %d", rp->datablkcnt))
      DBG_LOG(("  MaxBDataLength        = %d", rp->datablklen))

      if (nconn < 1 ||
          nconn > 255 ||
          rp->datablklen < 80 ||
          rp->datablklen > 2150 || rp->datablkcnt > 255) {
            DBG_ERR(("CAPI_REGISTER - invalid parameters"))
            return;
      }

      if (application[appl - 1].Id == appl) {
            DBG_LOG(("CAPI_REGISTER - appl already registered"))
            return;     /* appl already registered */
      }

      /* alloc memory */

      bnum = nconn * rp->datablkcnt;
      xnum = nconn * MAX_DATA_B3;

      mem_len  = bnum * sizeof(word);           /* DataNCCI */
      mem_len += bnum * sizeof(word);           /* DataFlags */
      mem_len += bnum * rp->datablklen;   /* ReceiveBuffer */
      mem_len += xnum;              /* xbuffer_used */
      mem_len += xnum * sizeof(void *);   /* xbuffer_ptr */
      mem_len += xnum * sizeof(void *);   /* xbuffer_internal */
      mem_len += xnum * rp->datablklen;   /* xbuffer_ptr[xnum] */

      DBG_LOG(("  Allocated Memory      = %d", mem_len))
      if (!(p = diva_os_malloc(0, mem_len))) {
            DBG_ERR(("CAPI_REGISTER - memory allocation failed"))
            return;
      }
      memset(p, 0, mem_len);

      DataNCCI = (void *)p;
      p += bnum * sizeof(word);
      DataFlags = (void *)p;
      p += bnum * sizeof(word);
      ReceiveBuffer = (void *)p;
      p += bnum * rp->datablklen;
      xbuffer_used = (void *)p;
      p += xnum;
      xbuffer_ptr = (void **)p;
      p += xnum * sizeof(void *);
      xbuffer_internal = (void **)p;
      p += xnum * sizeof(void *);
      for (i = 0; i < xnum; i++) {
            xbuffer_ptr[i] = (void *)p;
            p += rp->datablklen;
      }

      /* initialize application data */
      diva_os_enter_spin_lock(&api_lock, &old_irql, "register_appl");

      this = &application[appl - 1];
      memset(this, 0, sizeof(APPL));

      this->Id = appl;

      for (i = 0; i < max_adapter; i++) {
            adapter[i].CIP_Mask[appl - 1] = 0;
      }

      this->queue_size = 1000;

      this->MaxNCCI = (byte) nconn;
      this->MaxNCCIData = (byte) rp->datablkcnt;
      this->MaxBuffer = bnum;
      this->MaxDataLength = rp->datablklen;

      this->DataNCCI = DataNCCI;
      this->DataFlags = DataFlags;
      this->ReceiveBuffer = ReceiveBuffer;
      this->xbuffer_used = xbuffer_used;
      this->xbuffer_ptr = xbuffer_ptr;
      this->xbuffer_internal = xbuffer_internal;
      for (i = 0; i < xnum; i++) {
            this->xbuffer_ptr[i] = xbuffer_ptr[i];
      }

      CapiRegister(this->Id);
      diva_os_leave_spin_lock(&api_lock, &old_irql, "register_appl");

}

/*
 *  release appl
 */
static void diva_release_appl(struct capi_ctr *ctrl, __u16 appl)
{
      diva_os_spin_lock_magic_t old_irql;
      APPL *this = &application[appl - 1];
      void *mem_to_free = NULL;

      DBG_TRC(("application %d(%d) cleanup", this->Id, appl))

      if (diva_os_in_irq()) {
            DBG_ERR(("CAPI_RELEASE - in irq context !"))
            return;
      }

      diva_os_enter_spin_lock(&api_lock, &old_irql, "release_appl");
      if (this->Id) {
            CapiRelease(this->Id);
            mem_to_free = this->DataNCCI;
            this->DataNCCI = NULL;
            this->Id = 0;
      }
      diva_os_leave_spin_lock(&api_lock, &old_irql, "release_appl");

      if (mem_to_free)
            diva_os_free(0, mem_to_free);

}

/*
 *  send message
 */
static u16 diva_send_message(struct capi_ctr *ctrl,
                       diva_os_message_buffer_s * dmb)
{
      int i = 0;
      word ret = 0;
      diva_os_spin_lock_magic_t old_irql;
      CAPI_MSG *msg = (CAPI_MSG *) DIVA_MESSAGE_BUFFER_DATA(dmb);
      APPL *this = &application[GET_WORD(&msg->header.appl_id) - 1];
      diva_card *card = ctrl->driverdata;
      __u32 length = DIVA_MESSAGE_BUFFER_LEN(dmb);
      word clength = GET_WORD(&msg->header.length);
      word command = GET_WORD(&msg->header.command);
      u16 retval = CAPI_NOERROR;

      if (diva_os_in_irq()) {
            DBG_ERR(("CAPI_SEND_MSG - in irq context !"))
            return CAPI_REGOSRESOURCEERR;
      }
      DBG_PRV1(("Write - appl = %d, cmd = 0x%x", this->Id, command))

      if (card->remove_in_progress) {
            DBG_ERR(("CAPI_SEND_MSG - remove in progress!"))
            return CAPI_REGOSRESOURCEERR;
      }

      diva_os_enter_spin_lock(&api_lock, &old_irql, "send message");

      if (!this->Id) {
            diva_os_leave_spin_lock(&api_lock, &old_irql, "send message");
            return CAPI_ILLAPPNR;
      }

      /* patch controller number */
      msg->header.controller = ControllerMap[card->Id]
          | (msg->header.controller & 0x80);    /* preserve external controller bit */

      switch (command) {
      default:
            xlog("\x00\x02", msg, 0x80, clength);
            break;

      case _DATA_B3_I | RESPONSE:
#ifndef DIVA_NO_DEBUGLIB
            if (myDriverDebugHandle.dbgMask & DL_BLK)
                  xlog("\x00\x02", msg, 0x80, clength);
#endif
            break;

      case _DATA_B3_R:
#ifndef DIVA_NO_DEBUGLIB
            if (myDriverDebugHandle.dbgMask & DL_BLK)
                  xlog("\x00\x02", msg, 0x80, clength);
#endif

            if (clength == 24)
                  clength = 22;     /* workaround for PPcom bug */
            /* header is always 22      */
            if (GET_WORD(&msg->info.data_b3_req.Data_Length) >
                this->MaxDataLength
                || GET_WORD(&msg->info.data_b3_req.Data_Length) >
                (length - clength)) {
                  DBG_ERR(("Write - invalid message size"))
                  retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
                  goto write_end;
            }

            for (i = 0; i < (MAX_DATA_B3 * this->MaxNCCI)
                 && this->xbuffer_used[i]; i++);
            if (i == (MAX_DATA_B3 * this->MaxNCCI)) {
                  DBG_ERR(("Write - too many data pending"))
                  retval = CAPI_SENDQUEUEFULL;
                  goto write_end;
            }
            msg->info.data_b3_req.Data = i;

            this->xbuffer_internal[i] = NULL;
            memcpy(this->xbuffer_ptr[i], &((__u8 *) msg)[clength],
                   GET_WORD(&msg->info.data_b3_req.Data_Length));

#ifndef DIVA_NO_DEBUGLIB
            if ((myDriverDebugHandle.dbgMask & DL_BLK)
                && (myDriverDebugHandle.dbgMask & DL_XLOG)) {
                  int j;
                  for (j = 0; j <
                       GET_WORD(&msg->info.data_b3_req.Data_Length);
                       j += 256) {
                        DBG_BLK((((char *) this->xbuffer_ptr[i]) + j,
                              ((GET_WORD(&msg->info.data_b3_req.Data_Length) - j) <
                                256) ? (GET_WORD(&msg->info.data_b3_req.Data_Length) - j) : 256))
                        if (!(myDriverDebugHandle.dbgMask & DL_PRV0))
                              break;      /* not more if not explicitly requested */
                  }
            }
#endif
            break;
      }

      memcpy(mapped_msg, msg, (__u32) clength);
      mapped_msg->header.controller = MapController(mapped_msg->header.controller);
      mapped_msg->header.length = clength;
      mapped_msg->header.command = command;
      mapped_msg->header.number = GET_WORD(&msg->header.number);

      ret = api_put(this, mapped_msg);
      switch (ret) {
      case 0:
            break;
      case _BAD_MSG:
            DBG_ERR(("Write - bad message"))
            retval = CAPI_ILLCMDORSUBCMDORMSGTOSMALL;
            break;
      case _QUEUE_FULL:
            DBG_ERR(("Write - queue full"))
            retval = CAPI_SENDQUEUEFULL;
            break;
      default:
            DBG_ERR(("Write - api_put returned unknown error"))
            retval = CAPI_UNKNOWNNOTPAR;
            break;
      }

      write_end:
      diva_os_leave_spin_lock(&api_lock, &old_irql, "send message");
      if (retval == CAPI_NOERROR)
            diva_os_free_message_buffer(dmb);
      return retval;
}


/*
 * cards request function
 */
static void DIRequest(ENTITY * e)
{
      DIVA_CAPI_ADAPTER *a = &(adapter[(byte) e->user[0]]);
      diva_card *os_card = (diva_card *) a->os_card;

      if (e->Req && (a->FlowControlIdTable[e->ReqCh] == e->Id)) {
            a->FlowControlSkipTable[e->ReqCh] = 1;
      }

      (*(os_card->d.request)) (e);
}

/*
 * callback function from didd
 */
static void didd_callback(void *context, DESCRIPTOR * adapter, int removal)
{
      if (adapter->type == IDI_DADAPTER) {
            DBG_ERR(("Notification about IDI_DADAPTER change ! Oops."));
            return;
      } else if (adapter->type == IDI_DIMAINT) {
            if (removal) {
                  stop_dbg();
            } else {
                  memcpy(&MAdapter, adapter, sizeof(MAdapter));
                  dprintf = (DIVA_DI_PRINTF) MAdapter.request;
                  DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT);
            }
      } else if ((adapter->type > 0) && (adapter->type < 16)) {   /* IDI Adapter */
            if (removal) {
                  divacapi_remove_card(adapter);
            } else {
                  diva_add_card(adapter);
            }
      }
      return;
}

/*
 * connect to didd
 */
static int divacapi_connect_didd(void)
{
      int x = 0;
      int dadapter = 0;
      IDI_SYNC_REQ req;
      DESCRIPTOR DIDD_Table[MAX_DESCRIPTORS];

      DIVA_DIDD_Read(DIDD_Table, sizeof(DIDD_Table));

      for (x = 0; x < MAX_DESCRIPTORS; x++) {
            if (DIDD_Table[x].type == IDI_DIMAINT) {  /* MAINT found */
                  memcpy(&MAdapter, &DIDD_Table[x], sizeof(DAdapter));
                  dprintf = (DIVA_DI_PRINTF) MAdapter.request;
                  DbgRegister("CAPI20", DRIVERRELEASE_CAPI, DBG_DEFAULT);
                  break;
            }
      }
      for (x = 0; x < MAX_DESCRIPTORS; x++) {
            if (DIDD_Table[x].type == IDI_DADAPTER) { /* DADAPTER found */
                  dadapter = 1;
                  memcpy(&DAdapter, &DIDD_Table[x], sizeof(DAdapter));
                  req.didd_notify.e.Req = 0;
                  req.didd_notify.e.Rc =
                      IDI_SYNC_REQ_DIDD_REGISTER_ADAPTER_NOTIFY;
                  req.didd_notify.info.callback = (void *)didd_callback;
                  req.didd_notify.info.context = NULL;
                  DAdapter.request((ENTITY *) & req);
                  if (req.didd_notify.e.Rc != 0xff) {
                        stop_dbg();
                        return (0);
                  }
                  notify_handle = req.didd_notify.info.handle;
            }
                  else if ((DIDD_Table[x].type > 0) && (DIDD_Table[x].type < 16)) { /* IDI Adapter found */
                  diva_add_card(&DIDD_Table[x]);
            }
      }

      if (!dadapter) {
            stop_dbg();
      }

      return (dadapter);
}

/*
 * diconnect from didd
 */
static void divacapi_disconnect_didd(void)
{
      IDI_SYNC_REQ req;

      stop_dbg();

      req.didd_notify.e.Req = 0;
      req.didd_notify.e.Rc = IDI_SYNC_REQ_DIDD_REMOVE_ADAPTER_NOTIFY;
      req.didd_notify.info.handle = notify_handle;
      DAdapter.request((ENTITY *) & req);
}

/*
 * we do not provide date/time here,
 * the application should do this. 
 */
int fax_head_line_time(char *buffer)
{
      return (0);
}

/*
 * init (alloc) main structures
 */
static int DIVA_INIT_FUNCTION init_main_structs(void)
{
      if (!(mapped_msg = (CAPI_MSG *) diva_os_malloc(0, MAX_MSG_SIZE))) {
            DBG_ERR(("init: failed alloc mapped_msg."))
                return 0;
      }

      if (!(adapter = diva_os_malloc(0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS))) {
            DBG_ERR(("init: failed alloc adapter struct."))
            diva_os_free(0, mapped_msg);
            return 0;
      }
      memset(adapter, 0, sizeof(DIVA_CAPI_ADAPTER) * MAX_DESCRIPTORS);

      if (!(application = diva_os_malloc(0, sizeof(APPL) * MAX_APPL))) {
            DBG_ERR(("init: failed alloc application struct."))
            diva_os_free(0, mapped_msg);
            diva_os_free(0, adapter);
            return 0;
      }
      memset(application, 0, sizeof(APPL) * MAX_APPL);

      return (1);
}

/*
 * remove (free) main structures
 */
static void remove_main_structs(void)
{
      if (application)
            diva_os_free(0, application);
      if (adapter)
            diva_os_free(0, adapter);
      if (mapped_msg)
            diva_os_free(0, mapped_msg);
}

/*
 * api_remove_start
 */
static void do_api_remove_start(void)
{
      diva_os_spin_lock_magic_t old_irql;
      int ret = 1, count = 100;

      do {
            diva_os_enter_spin_lock(&api_lock, &old_irql, "api remove start");
            ret = api_remove_start();
            diva_os_leave_spin_lock(&api_lock, &old_irql, "api remove start");

            diva_os_sleep(10);
      } while (ret && count--);

      if (ret)
            DBG_ERR(("could not remove signaling ID's"))
}

/*
 * init
 */
int DIVA_INIT_FUNCTION init_capifunc(void)
{
      diva_os_initialize_spin_lock(&api_lock, "capifunc");
      memset(ControllerMap, 0, MAX_DESCRIPTORS + 1);
      max_adapter = 0;


      if (!init_main_structs()) {
            DBG_ERR(("init: failed to init main structs."))
            diva_os_destroy_spin_lock(&api_lock, "capifunc");
            return (0);
      }

      if (!divacapi_connect_didd()) {
            DBG_ERR(("init: failed to connect to DIDD."))
            do_api_remove_start();
            divacapi_remove_cards();
            remove_main_structs();
            diva_os_destroy_spin_lock(&api_lock, "capifunc");
            return (0);
      }

      return (1);
}

/*
 * finit
 */
void DIVA_EXIT_FUNCTION finit_capifunc(void)
{
      do_api_remove_start();
      divacapi_disconnect_didd();
      divacapi_remove_cards();
      remove_main_structs();
      diva_os_destroy_spin_lock(&api_lock, "capifunc");
}

Generated by  Doxygen 1.6.0   Back to index