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

diva.c

/* $Id: diva.c,v 1.21.4.1 2004/05/08 14:33:43 armin Exp $ */

#define CARDTYPE_H_WANT_DATA            1
#define CARDTYPE_H_WANT_IDI_DATA        0
#define CARDTYPE_H_WANT_RESOURCE_DATA   0
#define CARDTYPE_H_WANT_FILE_DATA       0

#include "platform.h"
#include "debuglib.h"
#include "cardtype.h"
#include "pc.h"
#include "di_defs.h"
#include "di.h"
#include "io.h"
#include "pc_maint.h"
#include "xdi_msg.h"
#include "xdi_adapter.h"
#include "diva_pci.h"
#include "diva.h"

#ifdef CONFIG_ISDN_DIVAS_PRIPCI
#include "os_pri.h"
#endif
#ifdef CONFIG_ISDN_DIVAS_BRIPCI
#include "os_bri.h"
#include "os_4bri.h"
#endif

PISDN_ADAPTER IoAdapters[MAX_ADAPTER];
extern IDI_CALL Requests[MAX_ADAPTER];
extern int create_adapter_proc(diva_os_xdi_adapter_t * a);
extern void remove_adapter_proc(diva_os_xdi_adapter_t * a);

#define DivaIdiReqFunc(N) \
static void DivaIdiRequest##N(ENTITY *e) \
{ if ( IoAdapters[N] ) (* IoAdapters[N]->DIRequest)(IoAdapters[N], e) ; }

/*
**  Create own 32 Adapters
*/
DivaIdiReqFunc(0)
DivaIdiReqFunc(1)
DivaIdiReqFunc(2)
DivaIdiReqFunc(3)
DivaIdiReqFunc(4)
DivaIdiReqFunc(5)
DivaIdiReqFunc(6)
DivaIdiReqFunc(7)
DivaIdiReqFunc(8)
DivaIdiReqFunc(9)
DivaIdiReqFunc(10)
DivaIdiReqFunc(11)
DivaIdiReqFunc(12)
DivaIdiReqFunc(13)
DivaIdiReqFunc(14)
DivaIdiReqFunc(15)
DivaIdiReqFunc(16)
DivaIdiReqFunc(17)
DivaIdiReqFunc(18)
DivaIdiReqFunc(19)
DivaIdiReqFunc(20)
DivaIdiReqFunc(21)
DivaIdiReqFunc(22)
DivaIdiReqFunc(23)
DivaIdiReqFunc(24)
DivaIdiReqFunc(25)
DivaIdiReqFunc(26)
DivaIdiReqFunc(27)
DivaIdiReqFunc(28)
DivaIdiReqFunc(29)
DivaIdiReqFunc(30)
DivaIdiReqFunc(31)

/*
**  LOCALS
*/
static LIST_HEAD(adapter_queue);

typedef struct _diva_get_xlog {
      word command;
      byte req;
      byte rc;
      byte data[sizeof(struct mi_pc_maint)];
} diva_get_xlog_t;

typedef struct _diva_supported_cards_info {
      int CardOrdinal;
      diva_init_card_proc_t init_card;
} diva_supported_cards_info_t;

static diva_supported_cards_info_t divas_supported_cards[] = {
#ifdef CONFIG_ISDN_DIVAS_PRIPCI
      /*
         PRI Cards
       */
      {CARDTYPE_DIVASRV_P_30M_PCI, diva_pri_init_card},
      /*
         PRI Rev.2 Cards
       */
      {CARDTYPE_DIVASRV_P_30M_V2_PCI, diva_pri_init_card},
      /*
         PRI Rev.2 VoIP Cards
       */
      {CARDTYPE_DIVASRV_VOICE_P_30M_V2_PCI, diva_pri_init_card},
#endif
#ifdef CONFIG_ISDN_DIVAS_BRIPCI
      /*
         4BRI Rev 1 Cards
       */
      {CARDTYPE_DIVASRV_Q_8M_PCI, diva_4bri_init_card},
      {CARDTYPE_DIVASRV_VOICE_Q_8M_PCI, diva_4bri_init_card},
      /*
         4BRI Rev 2 Cards
       */
      {CARDTYPE_DIVASRV_Q_8M_V2_PCI, diva_4bri_init_card},
      {CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI, diva_4bri_init_card},
      /*
         4BRI Based BRI Rev 2 Cards
       */
      {CARDTYPE_DIVASRV_B_2M_V2_PCI, diva_4bri_init_card},
      {CARDTYPE_DIVASRV_B_2F_PCI, diva_4bri_init_card},
      {CARDTYPE_DIVASRV_VOICE_B_2M_V2_PCI, diva_4bri_init_card},
      /*
         BRI
       */
      {CARDTYPE_MAESTRA_PCI, diva_bri_init_card},
#endif

      /*
         EOL
       */
      {-1}
};

static void diva_init_request_array(void);
static void *divas_create_pci_card(int handle, void *pci_dev_handle);

static diva_os_spin_lock_t adapter_lock;

static int diva_find_free_adapters(int base, int nr)
{
      int i;

      for (i = 0; i < nr; i++) {
            if (IoAdapters[base + i]) {
                  return (-1);
            }
      }

      return (0);
}

static diva_os_xdi_adapter_t *diva_q_get_next(struct list_head * what)
{
      diva_os_xdi_adapter_t *a = NULL;

      if (what && (what->next != &adapter_queue))
            a = list_entry(what->next, diva_os_xdi_adapter_t, link);

      return(a);
}

/* --------------------------------------------------------------------------
    Add card to the card list
   -------------------------------------------------------------------------- */
void *diva_driver_add_card(void *pdev, unsigned long CardOrdinal)
{
      diva_os_spin_lock_magic_t old_irql;
      diva_os_xdi_adapter_t *pdiva, *pa;
      int i, j, max, nr;

      for (i = 0; divas_supported_cards[i].CardOrdinal != -1; i++) {
            if (divas_supported_cards[i].CardOrdinal == CardOrdinal) {
                  if (!(pdiva = divas_create_pci_card(i, pdev))) {
                        return NULL;
                  }
                  switch (CardOrdinal) {
                  case CARDTYPE_DIVASRV_Q_8M_PCI:
                  case CARDTYPE_DIVASRV_VOICE_Q_8M_PCI:
                  case CARDTYPE_DIVASRV_Q_8M_V2_PCI:
                  case CARDTYPE_DIVASRV_VOICE_Q_8M_V2_PCI:
                        max = MAX_ADAPTER - 4;
                        nr = 4;
                        break;

                  default:
                        max = MAX_ADAPTER;
                        nr = 1;
                  }

                  diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");

                  for (i = 0; i < max; i++) {
                        if (!diva_find_free_adapters(i, nr)) {
                              pdiva->controller = i + 1;
                              pdiva->xdi_adapter.ANum = pdiva->controller;
                              IoAdapters[i] = &pdiva->xdi_adapter;
                              diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
                              create_adapter_proc(pdiva);   /* add adapter to proc file system */

                              DBG_LOG(("add %s:%d",
                                     CardProperties
                                     [CardOrdinal].Name,
                                     pdiva->controller))

                              diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
                              pa = pdiva;
                              for (j = 1; j < nr; j++) {    /* slave adapters, if any */
                                    pa = diva_q_get_next(&pa->link);
                                    if (pa && !pa->interface.cleanup_adapter_proc) {
                                          pa->controller = i + 1 + j;
                                          pa->xdi_adapter.ANum = pa->controller;
                                          IoAdapters[i + j] = &pa->xdi_adapter;
                                          diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
                                          DBG_LOG(("add slave adapter (%d)",
                                                 pa->controller))
                                          create_adapter_proc(pa);      /* add adapter to proc file system */
                                          diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add card");
                                    } else {
                                          DBG_ERR(("slave adapter problem"))
                                          break;
                                    }
                              }

                              diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add card");
                              return (pdiva);
                        }
                  }

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

                  /*
                     Not able to add adapter - remove it and return error
                   */
                  DBG_ERR(("can not alloc request array"))
                  diva_driver_remove_card(pdiva);

                  return NULL;
            }
      }

      return NULL;
}

/* --------------------------------------------------------------------------
    Called on driver load, MAIN, main, DriverEntry
   -------------------------------------------------------------------------- */
int divasa_xdi_driver_entry(void)
{
      diva_os_initialize_spin_lock(&adapter_lock, "adapter");
      memset(&IoAdapters[0], 0x00, sizeof(IoAdapters));
      diva_init_request_array();

      return (0);
}

/* --------------------------------------------------------------------------
    Remove adapter from list
   -------------------------------------------------------------------------- */
static diva_os_xdi_adapter_t *get_and_remove_from_queue(void)
{
      diva_os_spin_lock_magic_t old_irql;
      diva_os_xdi_adapter_t *a = NULL;

      diva_os_enter_spin_lock(&adapter_lock, &old_irql, "driver_unload");

      if (!list_empty(&adapter_queue)) {
            a = list_entry(adapter_queue.next, diva_os_xdi_adapter_t, link);
            list_del(adapter_queue.next);
      }

      diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");
      return (a);
}

/* --------------------------------------------------------------------------
    Remove card from the card list
   -------------------------------------------------------------------------- */
void diva_driver_remove_card(void *pdiva)
{
      diva_os_spin_lock_magic_t old_irql;
      diva_os_xdi_adapter_t *a[4];
      diva_os_xdi_adapter_t *pa;
      int i;

      pa = a[0] = (diva_os_xdi_adapter_t *) pdiva;
      a[1] = a[2] = a[3] = NULL;

      diva_os_enter_spin_lock(&adapter_lock, &old_irql, "remode adapter");

      for (i = 1; i < 4; i++) {
            if ((pa = diva_q_get_next(&pa->link))
                && !pa->interface.cleanup_adapter_proc) {
                  a[i] = pa;
            } else {
                  break;
            }
      }

      for (i = 0; ((i < 4) && a[i]); i++) {
            list_del(&a[i]->link);
      }

      diva_os_leave_spin_lock(&adapter_lock, &old_irql, "driver_unload");

      (*(a[0]->interface.cleanup_adapter_proc)) (a[0]);

      for (i = 0; i < 4; i++) {
            if (a[i]) {
                  if (a[i]->controller) {
                        DBG_LOG(("remove adapter (%d)",
                               a[i]->controller)) IoAdapters[a[i]->controller - 1] = NULL;
                        remove_adapter_proc(a[i]);
                  }
                  diva_os_free(0, a[i]);
            }
      }
}

/* --------------------------------------------------------------------------
    Create diva PCI adapter and init internal adapter structures
   -------------------------------------------------------------------------- */
static void *divas_create_pci_card(int handle, void *pci_dev_handle)
{
      diva_supported_cards_info_t *pI = &divas_supported_cards[handle];
      diva_os_spin_lock_magic_t old_irql;
      diva_os_xdi_adapter_t *a;

      DBG_LOG(("found %d-%s", pI->CardOrdinal, CardProperties[pI->CardOrdinal].Name))

      if (!(a = (diva_os_xdi_adapter_t *) diva_os_malloc(0, sizeof(*a)))) {
            DBG_ERR(("A: can't alloc adapter"));
            return NULL;
      }

      memset(a, 0x00, sizeof(*a));

      a->CardIndex = handle;
      a->CardOrdinal = pI->CardOrdinal;
      a->Bus = DIVAS_XDI_ADAPTER_BUS_PCI;
      a->xdi_adapter.cardType = a->CardOrdinal;
      a->resources.pci.bus = diva_os_get_pci_bus(pci_dev_handle);
      a->resources.pci.func = diva_os_get_pci_func(pci_dev_handle);
      a->resources.pci.hdev = pci_dev_handle;

      /*
         Add master adapter first, so slave adapters will receive higher
         numbers as master adapter
       */
      diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
      list_add_tail(&a->link, &adapter_queue);
      diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");

      if ((*(pI->init_card)) (a)) {
            diva_os_enter_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
            list_del(&a->link);
            diva_os_leave_spin_lock(&adapter_lock, &old_irql, "found_pci_card");
            diva_os_free(0, a);
            DBG_ERR(("A: can't get adapter resources"));
            return NULL;
      }

      return (a);
}

/* --------------------------------------------------------------------------
    Called on driver unload FINIT, finit, Unload
   -------------------------------------------------------------------------- */
void divasa_xdi_driver_unload(void)
{
      diva_os_xdi_adapter_t *a;

      while ((a = get_and_remove_from_queue())) {
            if (a->interface.cleanup_adapter_proc) {
                  (*(a->interface.cleanup_adapter_proc)) (a);
            }
            if (a->controller) {
                  IoAdapters[a->controller - 1] = NULL;
                  remove_adapter_proc(a);
            }
            diva_os_free(0, a);
      }
      diva_os_destroy_spin_lock(&adapter_lock, "adapter");
}

/*
**  Receive and process command from user mode utility
*/
void *diva_xdi_open_adapter(void *os_handle, const void __user *src,
                      int length,
                      divas_xdi_copy_from_user_fn_t cp_fn)
{
      diva_xdi_um_cfg_cmd_t msg;
      diva_os_xdi_adapter_t *a = NULL;
      diva_os_spin_lock_magic_t old_irql;
      struct list_head *tmp;

      if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
            DBG_ERR(("A: A(?) open, msg too small (%d < %d)",
                   length, sizeof(diva_xdi_um_cfg_cmd_t)))
            return NULL;
      }
      if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) {
            DBG_ERR(("A: A(?) open, write error"))
            return NULL;
      }
      diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter");
      list_for_each(tmp, &adapter_queue) {
            a = list_entry(tmp, diva_os_xdi_adapter_t, link);
            if (a->controller == (int)msg.adapter)
                  break;
            a = NULL;
      }
      diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter");

      if (!a) {
            DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter))
      }

      return (a);
}

/*
**  Easy cleanup mailbox status
*/
void diva_xdi_close_adapter(void *adapter, void *os_handle)
{
      diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;

      a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
      if (a->xdi_mbox.data) {
            diva_os_free(0, a->xdi_mbox.data);
            a->xdi_mbox.data = NULL;
      }
}

int
diva_xdi_write(void *adapter, void *os_handle, const void __user *src,
             int length, divas_xdi_copy_from_user_fn_t cp_fn)
{
      diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
      void *data;

      if (a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY) {
            DBG_ERR(("A: A(%d) write, mbox busy", a->controller))
            return (-1);
      }

      if (length < sizeof(diva_xdi_um_cfg_cmd_t)) {
            DBG_ERR(("A: A(%d) write, message too small (%d < %d)",
                   a->controller, length,
                   sizeof(diva_xdi_um_cfg_cmd_t)))
            return (-3);
      }

      if (!(data = diva_os_malloc(0, length))) {
            DBG_ERR(("A: A(%d) write, ENOMEM", a->controller))
            return (-2);
      }

      length = (*cp_fn) (os_handle, data, src, length);
      if (length > 0) {
            if ((*(a->interface.cmd_proc))
                (a, (diva_xdi_um_cfg_cmd_t *) data, length)) {
                  length = -3;
            }
      } else {
            DBG_ERR(("A: A(%d) write error (%d)", a->controller,
                   length))
      }

      diva_os_free(0, data);

      return (length);
}

/*
**  Write answers to user mode utility, if any
*/
int
diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
            int max_length, divas_xdi_copy_to_user_fn_t cp_fn)
{
      diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter;
      int ret;

      if (!(a->xdi_mbox.status & DIVA_XDI_MBOX_BUSY)) {
            DBG_ERR(("A: A(%d) rx mbox empty", a->controller))
            return (-1);
      }
      if (!a->xdi_mbox.data) {
            a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
            DBG_ERR(("A: A(%d) rx ENOMEM", a->controller))
            return (-2);
      }

      if (max_length < a->xdi_mbox.data_length) {
            DBG_ERR(("A: A(%d) rx buffer too short(%d < %d)",
                   a->controller, max_length,
                   a->xdi_mbox.data_length))
            return (-3);
      }

      ret = (*cp_fn) (os_handle, dst, a->xdi_mbox.data,
                  a->xdi_mbox.data_length);
      if (ret > 0) {
            diva_os_free(0, a->xdi_mbox.data);
            a->xdi_mbox.data = NULL;
            a->xdi_mbox.status &= ~DIVA_XDI_MBOX_BUSY;
      }

      return (ret);
}


irqreturn_t diva_os_irq_wrapper(int irq, void *context)
{
      diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context;
      diva_xdi_clear_interrupts_proc_t clear_int_proc;

      if (!a || !a->xdi_adapter.diva_isr_handler) {
            return IRQ_NONE;
      }

      if ((clear_int_proc = a->clear_interrupts_proc)) {
            (*clear_int_proc) (a);
            a->clear_interrupts_proc = NULL;
            return IRQ_HANDLED;
      }

      (*(a->xdi_adapter.diva_isr_handler)) (&a->xdi_adapter);
      return IRQ_HANDLED;
}

static void diva_init_request_array(void)
{
      Requests[0] = DivaIdiRequest0;
      Requests[1] = DivaIdiRequest1;
      Requests[2] = DivaIdiRequest2;
      Requests[3] = DivaIdiRequest3;
      Requests[4] = DivaIdiRequest4;
      Requests[5] = DivaIdiRequest5;
      Requests[6] = DivaIdiRequest6;
      Requests[7] = DivaIdiRequest7;
      Requests[8] = DivaIdiRequest8;
      Requests[9] = DivaIdiRequest9;
      Requests[10] = DivaIdiRequest10;
      Requests[11] = DivaIdiRequest11;
      Requests[12] = DivaIdiRequest12;
      Requests[13] = DivaIdiRequest13;
      Requests[14] = DivaIdiRequest14;
      Requests[15] = DivaIdiRequest15;
      Requests[16] = DivaIdiRequest16;
      Requests[17] = DivaIdiRequest17;
      Requests[18] = DivaIdiRequest18;
      Requests[19] = DivaIdiRequest19;
      Requests[20] = DivaIdiRequest20;
      Requests[21] = DivaIdiRequest21;
      Requests[22] = DivaIdiRequest22;
      Requests[23] = DivaIdiRequest23;
      Requests[24] = DivaIdiRequest24;
      Requests[25] = DivaIdiRequest25;
      Requests[26] = DivaIdiRequest26;
      Requests[27] = DivaIdiRequest27;
      Requests[28] = DivaIdiRequest28;
      Requests[29] = DivaIdiRequest29;
      Requests[30] = DivaIdiRequest30;
      Requests[31] = DivaIdiRequest31;
}

void diva_xdi_display_adapter_features(int card)
{
      dword features;
      if (!card || ((card - 1) >= MAX_ADAPTER) || !IoAdapters[card - 1]) {
            return;
      }
      card--;
      features = IoAdapters[card]->Properties.Features;

      DBG_LOG(("FEATURES FOR ADAPTER: %d", card + 1))
      DBG_LOG((" DI_FAX3          :  %s",
                 (features & DI_FAX3) ? "Y" : "N"))
      DBG_LOG((" DI_MODEM         :  %s",
                 (features & DI_MODEM) ? "Y" : "N"))
      DBG_LOG((" DI_POST          :  %s",
                 (features & DI_POST) ? "Y" : "N"))
      DBG_LOG((" DI_V110          :  %s",
                 (features & DI_V110) ? "Y" : "N"))
      DBG_LOG((" DI_V120          :  %s",
                 (features & DI_V120) ? "Y" : "N"))
      DBG_LOG((" DI_POTS          :  %s",
                 (features & DI_POTS) ? "Y" : "N"))
      DBG_LOG((" DI_CODEC         :  %s",
                 (features & DI_CODEC) ? "Y" : "N"))
      DBG_LOG((" DI_MANAGE        :  %s",
                 (features & DI_MANAGE) ? "Y" : "N"))
      DBG_LOG((" DI_V_42          :  %s",
                 (features & DI_V_42) ? "Y" : "N"))
      DBG_LOG((" DI_EXTD_FAX      :  %s",
                 (features & DI_EXTD_FAX) ? "Y" : "N"))
      DBG_LOG((" DI_AT_PARSER     :  %s",
                 (features & DI_AT_PARSER) ? "Y" : "N"))
      DBG_LOG((" DI_VOICE_OVER_IP :  %s",
                 (features & DI_VOICE_OVER_IP) ? "Y" : "N"))
}

void diva_add_slave_adapter(diva_os_xdi_adapter_t * a)
{
      diva_os_spin_lock_magic_t old_irql;

      diva_os_enter_spin_lock(&adapter_lock, &old_irql, "add_slave");
      list_add_tail(&a->link, &adapter_queue);
      diva_os_leave_spin_lock(&adapter_lock, &old_irql, "add_slave");
}

int diva_card_read_xlog(diva_os_xdi_adapter_t * a)
{
      diva_get_xlog_t *req;
      byte *data;

      if (!a->xdi_adapter.Initialized || !a->xdi_adapter.DIRequest) {
            return (-1);
      }
      if (!(data = diva_os_malloc(0, sizeof(struct mi_pc_maint)))) {
            return (-1);
      }
      memset(data, 0x00, sizeof(struct mi_pc_maint));

      if (!(req = diva_os_malloc(0, sizeof(*req)))) {
            diva_os_free(0, data);
            return (-1);
      }
      req->command = 0x0400;
      req->req = LOG;
      req->rc = 0x00;

      (*(a->xdi_adapter.DIRequest)) (&a->xdi_adapter, (ENTITY *) req);

      if (!req->rc || req->req) {
            diva_os_free(0, data);
            diva_os_free(0, req);
            return (-1);
      }

      memcpy(data, &req->req, sizeof(struct mi_pc_maint));

      diva_os_free(0, req);

      a->xdi_mbox.data_length = sizeof(struct mi_pc_maint);
      a->xdi_mbox.data = data;
      a->xdi_mbox.status = DIVA_XDI_MBOX_BUSY;

      return (0);
}

void xdiFreeFile(void *handle)
{
}

Generated by  Doxygen 1.6.0   Back to index