summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_sandrv.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/if_sandrv.c')
-rw-r--r--sys/dev/pci/if_sandrv.c1584
1 files changed, 1584 insertions, 0 deletions
diff --git a/sys/dev/pci/if_sandrv.c b/sys/dev/pci/if_sandrv.c
new file mode 100644
index 00000000000..b5ad8cd02f4
--- /dev/null
+++ b/sys/dev/pci/if_sandrv.c
@@ -0,0 +1,1584 @@
+/*-
+ * Copyright (c) 2001-2004 Sangoma Technologies (SAN)
+ * All rights reserved. www.sangoma.com
+ *
+ * This code is written by Alex Feldman <al.feldman@sangoma.com> for SAN.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of Sangoma Technologies nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SANGOMA TECHNOLOGIES AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __SDLA_HW_LEVEL
+#define __SDLADRV__
+
+/*
+****************************************************************************
+**** For Debug purpose (only OpenBSD) ****
+****************************************************************************
+*/
+
+/***************************************************************************
+**** I N C L U D E F I L E S ****
+***************************************************************************/
+
+# include <sys/types.h>
+# include <sys/param.h>
+# include <sys/systm.h>
+# include <sys/syslog.h>
+# include <sys/malloc.h>
+# include <sys/kernel.h>
+
+# include <dev/pci/pcireg.h>
+# include <dev/pci/pcivar.h>
+# include <dev/pci/if_san_front_end.h>
+# include <dev/pci/if_sandrv.h>
+
+/***************************************************************************
+**** M A C R O S / D E F I N E S ****
+***************************************************************************/
+
+#define EXEC_DELAY 20 /* shared memory access delay, mks */
+# define EXEC_TIMEOUT (hz*2)
+#define MAX_NLOOPS (EXEC_DELAY*2000)
+ /* timeout used if jiffies are stopped
+ ** EXEC_DELAY=20
+ ** EXEC_TIMEOUT=EXEC_DELAY*2000 = 40000
+ ** 40000 ~= 80 jiffies = EXEC_TIMEOUT */
+
+#define EXEC_HZ_DIVISOR 8/10
+ /* We don't want to wait a full second on sdla_exec
+ ** timeout, thus use HZ * EXEC_HZ_DIVISOR to get
+ ** the number of jiffies we would like to wait */
+
+#define IS_SUPPORTED_ADAPTER(hw) ((hw)->type == SDLA_AFT)
+
+#define SDLA_CTYPE_NAME(type) \
+ ((type) == SDLA_AFT) ? "AFT" : "Unknown"
+
+#define IS_AFT(hw) (hw->type == SDLA_AFT)
+
+/* Definitions for identifying and finding S514 PCI adapters */
+#define V3_VENDOR_ID 0x11B0 /* V3 vendor ID number */
+#define V3_DEVICE_ID 0x0002 /* V3 device ID number */
+#define SANGOMA_SUBSYS_VENDOR 0x4753 /* ID for Sangoma */
+
+/* Definition for identifying and finding XILINX PCI adapters */
+#define SANGOMA_PCI_VENDOR 0x1923 /* Old value -> 0x11B0 */
+#define SANGOMA_PCI_VENDOR_OLD 0x10EE /* Old value -> 0x11B0 */
+#define SANGOMA_PCI_DEVICE 0x0300 /* Old value -> 0x0200 */
+
+#define A101_1TE1_SUBSYS_VENDOR 0xA010 /* A101 with T1/E1 1 line */
+#define A101_2TE1_SUBSYS_VENDOR 0xA011 /* A101 with T1/E1 2 lines */
+#define A105_T3_SUBSYS_VENDOR 0xA020 /* A102 with T3 */
+
+/* Read PCI SUBVENDOR ID */
+#define PCI_SUBVENDOR_MASK 0xFFFF
+#define PCI_SUBVENDOR(pa) (pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG) & PCI_SUBVENDOR_MASK)
+#define PCI_DEVICE_MASK 0xFFFF0000
+#define PCI_DEVICE(id) ((id & PCI_DEVICE_MASK ) >> 16)
+
+/* Status values */
+#define SDLA_MEM_RESERVED 0x0001
+#define SDLA_MEM_MAPPED 0x0002
+#define SDLA_IO_MAPPED 0x0004
+#define SDLA_PCI_ENABLE 0x0008
+
+struct san_softc
+{
+ struct device dev;
+ struct pci_attach_args pa;
+};
+
+typedef struct sdla_hw_probe {
+ int used;
+ unsigned char hw_info[100];
+ LIST_ENTRY(sdla_hw_probe) next;
+} sdla_hw_probe_t;
+
+/*
+ * This structure keeps common parameters per physical card.
+ */
+typedef struct sdlahw_card {
+ int used;
+ unsigned int type; /* S50x/S514/ADSL/XILINX */
+ unsigned int atype; /* SubVendor ID */
+ unsigned char core_id; /* SubSystem ID [0..7] */
+ unsigned char core_rev; /* SubSystem ID [8..15] */
+ unsigned char pci_extra_ver;
+ unsigned int slot_no;
+ unsigned int bus_no;
+ bus_space_tag_t memt;
+ struct pci_attach_args pa; /* PCI config header info */
+ pci_intr_handle_t ih;
+ LIST_ENTRY(sdlahw_card) next;
+} sdlahw_card_t;
+
+/*----------------------------------------------------------------------------
+ * Adapter hardware configuration. Pointer to this structure is passed to all
+ * APIs.
+ */
+typedef struct sdlahw
+{
+ int used;
+ unsigned magic;
+ char devname[20];
+ u_int16_t status;
+ int irq; /* interrupt request level */
+ unsigned int cpu_no; /* PCI CPU Number */
+ char auto_pci_cfg; /* Auto PCI configuration */
+ bus_addr_t mem_base_addr;
+ bus_space_handle_t dpmbase; /* dual-port memory base */
+ unsigned dpmsize; /* dual-port memory size */
+ unsigned long memory; /* memory size */
+
+ unsigned reserved[5];
+ unsigned char hw_info[100];
+
+ u_int16_t configured;
+ void *arg; /* card structure */
+ sdla_hw_probe_t* hwprobe;
+ sdlahw_card_t* hwcard;
+ LIST_ENTRY(sdlahw) next;
+} sdlahw_t;
+
+/****** Function Prototypes *************************************************/
+/* Entry Point for Low-Level function */
+int sdladrv_init(void);
+int sdladrv_exit(void);
+
+static int sdla_pci_probe(int, struct pci_attach_args*);
+
+/* PCI bus interface function */
+static int sdla_pci_write_config_word(void*, int, u_int16_t);
+static int sdla_pci_write_config_dword(void*, int, u_int32_t);
+static int sdla_pci_read_config_byte(void*, int, u_int8_t*);
+static int sdla_pci_read_config_word(void*, int, u_int16_t*);
+static int sdla_pci_read_config_dword(void*, int, u_int32_t*);
+
+static int sdla_detect (sdlahw_t* hw);
+static int sdla_detect_aft(sdlahw_t* hw);
+static int sdla_exec (sdlahw_t* hw, unsigned long offset);
+static void sdla_peek_by_4 (sdlahw_t*, unsigned long, void*, unsigned int);
+static void sdla_poke_by_4 (sdlahw_t*, unsigned long, void*, unsigned int);
+
+static sdlahw_card_t* sdla_card_register(u_int16_t atype, int slot_no, int bus_no);
+#if 0
+static int sdla_card_unregister (unsigned char hw_type, int slot_no, int bus_no, int ioport);
+#endif
+static sdlahw_card_t* sdla_card_search(u_int16_t atype, int slot_no, int bus_no);
+
+static sdlahw_t* sdla_hw_register(sdlahw_card_t* card, int cpu_no, int irq, void*);
+#if 0
+static int sdla_hw_unregister(sdlahw_card_t* card, int cpu_no);
+#endif
+static sdlahw_t* sdla_hw_search(u_int16_t atype, int slot_no, int bus_no, int cpu_no);
+
+static sdlahw_t* sdla_aft_hw_select (sdlahw_card_t* card, int cpu_no, int irq, struct pci_attach_args* pa);
+static void sdla_save_hw_probe (sdlahw_t* hw, int port);
+
+
+/* SDLA PCI device relative entry point */
+int san_match __P((struct device*, void*, void*));
+void san_attach __P((struct device*, struct device*, void*));
+
+/****** Global Data *********************************************************/
+
+struct cfdriver san_cd = {
+ NULL, "san", DV_IFNET
+};
+
+struct cfattach san_ca = {
+ sizeof(struct san_softc), san_match, san_attach
+};
+
+extern int ticks;
+
+/* SDLA ISA/PCI varibles */
+static int Sangoma_cards_no = 0;
+static int Sangoma_devices_no = 0;
+static int Sangoma_PCI_cards_no = 0;
+
+/* private data */
+char *san_drvname = "san";
+
+/* Array of already initialized PCI slots */
+static int pci_slot_ar[MAX_S514_CARDS];
+
+LIST_HEAD(, sdlahw_card) sdlahw_card_head =
+ LIST_HEAD_INITIALIZER(sdlahw_card_head);
+LIST_HEAD(, sdlahw) sdlahw_head =
+ LIST_HEAD_INITIALIZER(sdlahw_head);
+LIST_HEAD(, sdla_hw_probe) sdlahw_probe_head =
+ LIST_HEAD_INITIALIZER(sdlahw_probe_head);
+static sdla_hw_type_cnt_t sdla_adapter_cnt;
+
+
+/***************************************************************************/
+
+/******* PCI Device Driver Entry Points ********************************/
+int san_match(parent, match, aux)
+ struct device* parent;
+ void* match, *aux;
+{
+ struct pci_attach_args* pa = aux;
+ u_int16_t vendor_id = PCI_VENDOR(pa->pa_id);
+ u_int16_t device_id = PCI_DEVICE(pa->pa_id);
+
+ if (!(vendor_id == SANGOMA_PCI_VENDOR && device_id == SANGOMA_PCI_DEVICE) ||
+ (vendor_id == SANGOMA_PCI_VENDOR_OLD && device_id == SANGOMA_PCI_DEVICE)){
+ return 0;
+ }
+ return 1;
+}
+
+#define PCI_CBIO 0x10
+void san_attach(parent, self, aux)
+ struct device *parent, *self;
+ void* aux;
+{
+ struct pci_attach_args* pa = aux;
+ u_int16_t vendor_id = PCI_VENDOR(pa->pa_id);
+ u_int16_t subvendor_id = PCI_SUBVENDOR(pa);
+ int atype = 0x00;
+
+ atype = PCI_PRODUCT(pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG));
+ switch(vendor_id){
+ case SANGOMA_PCI_VENDOR_OLD:
+ case SANGOMA_PCI_VENDOR:
+ switch(subvendor_id){
+ case A101_1TE1_SUBSYS_VENDOR:
+ atype = A101_ADPTR_1TE1;
+ break;
+ case A101_2TE1_SUBSYS_VENDOR:
+ atype = A101_ADPTR_2TE1;
+ break;
+ default:
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+
+ if (sdla_pci_probe(atype, pa)){
+ printf(": PCI probe FAILED!\n");
+ return;
+ }
+
+#if defined(DEBUG)
+ switch(PCI_VENDOR(pa->pa_id)){
+ case V3_VENDOR_ID:
+ switch(atype){
+ case S5141_ADPTR_1_CPU_SERIAL:
+ log(LOG_INFO, "%s: Sangoma S5141/FT1 (Single CPU) adapter\n",
+ self->dv_xname);
+ break;
+ case S5142_ADPTR_2_CPU_SERIAL:
+ log(LOG_INFO, "%s: Sangoma S5142 (Dual CPU) adapter\n",
+ self->dv_xname);
+ break;
+ case S5143_ADPTR_1_CPU_FT1:
+ log(LOG_INFO, "%s: Sangoma S5143 (Single CPU) FT1 adapter\n",
+ self->dv_xname);
+ break;
+ case S5144_ADPTR_1_CPU_T1E1:
+ case S5148_ADPTR_1_CPU_T1E1:
+ log(LOG_INFO, "%s: Sangoma S5144 (Single CPU) T1/E1 adapter\n",
+ self->dv_xname);
+ break;
+ case S5145_ADPTR_1_CPU_56K:
+ log(LOG_INFO, "%s: Sangoma S5145 (Single CPU) 56K adapter\n",
+ self->dv_xname);
+ break;
+ case S5147_ADPTR_2_CPU_T1E1:
+ log(LOG_INFO, "%s: Sangoma S5147 (Dual CPU) T1/E1 adapter\n",
+ self->dv_xname);
+ break;
+ }
+ break;
+
+ case PCI_VENDOR_ID_GSI:
+ log(LOG_INFO, "%s: Sangoma S518 ADSL adapter\n",
+ self->dv_xname);
+ break;
+ case SANGOMA_PCI_VENDOR_OLD:
+ switch(atype){
+ case A101_ADPTR_1TE1:
+ log(LOG_INFO, "%s: Sangoma AFT (1 channel) T1/E1 adapter\n",
+ self->dv_xname);
+ break;
+ case A101_ADPTR_2TE1:
+ log(LOG_INFO, "%s: Sangoma AFT (2 channels) T1/E1 adapter\n",
+ self->dv_xname);
+ break;
+ }
+ break;
+ }
+#endif
+ return;
+}
+
+/*==========================================================================
+ * Module init point.
+ */
+int sdladrv_init(void)
+{
+ int volatile i=0;
+
+ /* Initialize the PCI Card array, which
+ * will store flags, used to mark
+ * card initialization state */
+ for (i=0; i<MAX_S514_CARDS; i++)
+ pci_slot_ar[i] = 0xFF;
+
+ memset(&sdla_adapter_cnt,0,sizeof(sdla_hw_type_cnt_t));
+
+ return 0;
+}
+
+/*============================================================================
+ * Module deinit point.
+ * o release all remaining system resources
+ */
+int sdladrv_exit (void)
+{
+#if 0
+ sdla_hw_probe_t *elm_hw_probe;
+ sdlahw_t *elm_hw;
+ sdlahw_card_t *elm_hw_card;
+
+
+ elm_hw = LIST_FIRST(&sdlahw_head);
+ while(elm_hw){
+ sdlahw_t *tmp = elm_hw;
+ elm_hw = LIST_NEXT(elm_hw, next);
+ if (sdla_hw_unregister(tmp->hwcard, tmp->cpu_no) == -EBUSY){
+ return -EBUSY;
+ }
+ }
+ LIST_INIT(&sdlahw_head);
+
+ elm_hw_card = LIST_FIRST(&sdlahw_card_head);
+ while(elm_hw_card){
+ sdlahw_card_t *tmp = elm_hw_card;
+ elm_hw_card = LIST_NEXT(elm_hw_card, next);
+ if (sdla_card_unregister(tmp->hw_type,
+ tmp->slot_no,
+ tmp->bus_no,
+ tmp->ioport) == -EBUSY){
+ return -EBUSY;
+ }
+ }
+ LIST_INIT(&sdlahw_card_head);
+
+ elm_hw_probe = LIST_FIRST(&sdlahw_probe_head);
+ while(elm_hw_probe){
+ sdla_hw_probe_t *tmp = elm_hw_probe;
+ elm_hw_probe = LIST_NEXT(elm_hw_probe, next);
+ if (tmp->used){
+ log(LOG_INFO, "sdladrv: HW probe info is in used (%s)\n",
+ elm_hw_probe->hw_info);
+ return -EBUSY;
+ }
+ LIST_REMOVE(tmp, next);
+ free(tmp, M_DEVBUF);
+ }
+#endif
+ return 0;
+}
+
+/*
+*****************************************************************************
+*****************************************************************************
+G*** S A N G O M A H A R D W A R E P R O B E *****
+*****************************************************************************
+*****************************************************************************
+*/
+/*
+*****************************************************************************
+** sdla_save_hw_probe
+*****************************************************************************
+*/
+static void
+sdla_save_hw_probe (sdlahw_t* hw, int port)
+{
+ sdla_hw_probe_t *tmp_hw_probe;
+
+ tmp_hw_probe = malloc(sizeof(sdla_hw_probe_t), M_DEVBUF, M_NOWAIT);
+ if (!tmp_hw_probe)
+ return;
+
+ memset(tmp_hw_probe,0,sizeof(sdla_hw_probe_t));
+
+ /*sprintf(tmp_hw_probe->hw_info,*/
+ snprintf(tmp_hw_probe->hw_info, sizeof(tmp_hw_probe->hw_info),
+ "%s : SLOT=%d : BUS=%d : IRQ=%d : CPU=%c : PORT=%s",
+ SDLA_ADPTR_DECODE(hw->hwcard->atype),
+ hw->hwcard->slot_no,
+ hw->hwcard->bus_no,
+ hw->irq,
+ SDLA_GET_CPU(hw->cpu_no),
+ "PRI");
+
+ hw->hwprobe = tmp_hw_probe;
+ tmp_hw_probe->used++;
+ LIST_INSERT_HEAD(&sdlahw_probe_head, tmp_hw_probe, next);
+}
+
+
+/*
+*****************************************************************************
+** sdla_hw_select
+*****************************************************************************
+*/
+static sdlahw_t* sdla_aft_hw_select (sdlahw_card_t* hwcard, int cpu_no, int irq, struct pci_attach_args* pa)
+{
+ sdlahw_t* hw=NULL;
+ int number_of_cards = 0;
+
+ hwcard->type = SDLA_AFT;
+ switch(hwcard->atype){
+ case A101_ADPTR_1TE1:
+ hw = sdla_hw_register(hwcard, cpu_no, irq, pa);
+ sdla_save_hw_probe(hw, 0);
+ number_of_cards += 1;
+#if defined(DEBUG)
+ log(LOG_INFO, "%s: %s T1/E1 card found (%s rev.%d), cpu(s) 1, bus #%d, slot #%d, irq #%d\n",
+ san_drvname,
+ SDLA_ADPTR_DECODE(hwcard->atype),
+ AFT_CORE_ID_DECODE(hwcard->core_id),
+ hwcard->core_rev,
+ hwcard->bus_no, hwcard->slot_no, irq);
+#endif
+ break;
+
+ case A101_ADPTR_2TE1:
+ hw = sdla_hw_register(hwcard, cpu_no, irq, pa);
+ sdla_save_hw_probe(hw, 0);
+ number_of_cards += 1;
+#if defined(DEBUG)
+ log(LOG_INFO, "%s: %s T1/E1 card found (%s rev.%d), cpu(s) 2, bus #%d, slot #%d, irq #%d\n",
+ san_drvname,
+ SDLA_ADPTR_DECODE(hwcard->atype),
+ AFT_CORE_ID_DECODE(hwcard->core_id),
+ hwcard->core_rev,
+ hwcard->bus_no, hwcard->slot_no, irq);
+#endif
+ break;
+
+ case A105_ADPTR_1_CHN_T3E3:
+
+ hw = sdla_hw_register(hwcard, cpu_no, irq, pa);
+ sdla_save_hw_probe(hw, 0);
+ number_of_cards += 1;
+#if defined(DEBUG)
+ log(LOG_INFO, "%s: %s T3/E3 card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n",
+ san_drvname,
+ SDLA_ADPTR_DECODE(hwcard->atype),
+ hwcard->bus_no,
+ hwcard->slot_no,
+ irq);
+#endif
+ break;
+
+
+ default:
+ log(LOG_INFO,
+ "%s: Unknown adapter %04X (bus #%d, slot #%d, irq #%d)!\n",
+ san_drvname, hwcard->atype, hwcard->bus_no, hwcard->slot_no, irq);
+
+ break;
+ }
+
+ return hw;
+}
+
+
+static int sdla_pci_probe(int atype, struct pci_attach_args* pa)
+{
+ sdlahw_card_t* hwcard;
+ sdlahw_t* hw;
+ /*sdladev_t* dev = NULL;*/
+ int dual_cpu = 0;
+ int bus, slot, cpu = SDLA_CPU_A;
+ u_int16_t vendor_id, subvendor_id, device_id;
+ u_int8_t irq;
+ pci_intr_handle_t ih;
+ const char* intrstr = NULL;
+
+ bus = pa->pa_bus;
+ slot = pa->pa_device;
+ vendor_id = PCI_VENDOR(pa->pa_id);
+ subvendor_id = PCI_SUBVENDOR(pa);
+ device_id = PCI_DEVICE(pa->pa_id);
+ irq = (u_int8_t)pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_INTLINE);
+
+ /* Map and establish the interrupt */
+ if (pci_intr_map(pa,&ih)){
+ printf(": couldn't map interrupt\n");
+ return -EINVAL;
+ }
+ intrstr = pci_intr_string(pa->pa_pc, ih);
+ if (intrstr != NULL){
+ printf(" %s\n", intrstr);
+ }
+ Sangoma_cards_no ++;
+reg_new_card:
+ Sangoma_PCI_cards_no ++;
+ hwcard = sdla_card_register(atype, slot, bus);
+ if (hwcard == NULL){
+ return -EINVAL;
+ }
+ hwcard->memt = pa->pa_memt;
+ hwcard->ih = ih;
+ hwcard->pa = *pa;
+ /* Increment number of available Sangoma devices */
+ Sangoma_devices_no ++;
+ switch(atype){
+ case A101_ADPTR_1TE1:
+ case A101_ADPTR_2TE1:
+ hw = sdla_aft_hw_select(hwcard, cpu, irq, pa);
+ sdla_adapter_cnt.AFT_adapters++;
+ if (atype == A101_ADPTR_2TE1) dual_cpu = 1;
+ break;
+
+ }
+
+ if (hw == NULL) return -EINVAL;
+ if (san_dev_attach(hw, hw->devname)){
+ return -EINVAL;
+ }
+ hw->used++;
+
+ if (dual_cpu && cpu == SDLA_CPU_A){
+ cpu = SDLA_CPU_B;
+ goto reg_new_card;
+ }
+
+ return 0;
+}
+
+int sdla_intr_establish(void *phw, int(*intr_func)(void*), void* intr_arg)
+{
+ sdlahw_t *hw = (sdlahw_t*)phw;
+ sdlahw_card_t *hwcard;
+
+ WAN_ASSERT(hw == NULL);
+ hwcard = hw->hwcard;
+ if (pci_intr_establish(
+ hwcard->pa.pa_pc,
+ hwcard->ih,
+ IPL_NET,
+ intr_func,
+ intr_arg,
+ "san") == NULL){
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int sdla_intr_disestablish(void *phw)
+{
+ sdlahw_t *hw = (sdlahw_t*)phw;
+
+ log(LOG_INFO, "%d: Disestablish interrupt is not defined!\n",
+ hw->devname);
+ return -EINVAL;
+}
+
+/*
+*****************************************************************************
+** sdla_get_hw_devices
+*****************************************************************************
+*/
+int sdla_get_hw_devices (void)
+{
+ return Sangoma_devices_no;
+}
+
+/*
+*****************************************************************************
+** sdla_get_hw_adptr_cnt
+*****************************************************************************
+*/
+void *sdla_get_hw_adptr_cnt (void)
+{
+ return &sdla_adapter_cnt;
+}
+
+/*
+*****************************************************************************
+** sdla_card_register
+*****************************************************************************
+*/
+static sdlahw_card_t*
+sdla_card_register(u_int16_t atype, int slot_no, int bus_no)
+{
+ sdlahw_card_t *new_hwcard, *last_hwcard;
+
+ new_hwcard = sdla_card_search(atype, slot_no, bus_no);
+ if (new_hwcard){
+ return new_hwcard;
+ }
+ new_hwcard = malloc(sizeof(sdlahw_card_t), M_DEVBUF, M_NOWAIT);
+ if (!new_hwcard){
+ return NULL;
+ }
+
+ memset(new_hwcard,0,sizeof(sdlahw_card_t));
+
+ new_hwcard->atype = atype;
+ new_hwcard->slot_no = slot_no;
+ new_hwcard->bus_no = bus_no;
+
+ if (LIST_EMPTY(&sdlahw_card_head)){
+ /* Initialize SAN HW parameters */
+ sdladrv_init();
+ }
+ LIST_FOREACH(last_hwcard, &sdlahw_card_head, next){
+ if (!LIST_NEXT(last_hwcard, next)){
+ break;
+ }
+ }
+ if (last_hwcard){
+ LIST_INSERT_AFTER(last_hwcard, new_hwcard, next);
+ }else{
+ LIST_INSERT_HEAD(&sdlahw_card_head, new_hwcard, next);
+ }
+ return new_hwcard;
+}
+
+/*
+*****************************************************************************
+** sdla_card_unregister
+*****************************************************************************
+*/
+#if 0
+static int
+sdla_card_unregister (u_int16_t atype, int slot_no, int bus_no, int ioport)
+{
+ sdlahw_card_t* tmp_card;
+
+ LIST_FOREACH(tmp_card, &sdlahw_card_head, next){
+ if (tmp_card->atype != atype){
+ continue;
+ }
+ if (tmp_card->slot_no == slot_no &&
+ tmp_card->bus_no == bus_no){
+ break;
+ }
+ }
+ if (tmp_card == NULL){
+ log(LOG_INFO, "Error: Card didn't find %04X card (slot=%d, bus=%d)\n",
+ atype, slot_no, bus_no);
+ return -EFAULT;
+ }
+ if (tmp_card->used){
+ log(LOG_INFO, "Error: Card is still in used (slot=%d,bus=%d,used=%d)\n",
+ slot_no, bus_no, tmp_card->used);
+ return -EBUSY;
+ }
+ LIST_REMOVE(tmp_card, next);
+ free(tmp_card, M_DEVBUF);
+ return 0;
+}
+#endif
+/*
+*****************************************************************************
+** sdla_card_search
+*****************************************************************************
+*/
+static sdlahw_card_t*
+sdla_card_search(u_int16_t atype, int slot_no, int bus_no)
+{
+ sdlahw_card_t* tmp_card;
+
+ LIST_FOREACH(tmp_card, &sdlahw_card_head, next){
+ if (tmp_card->atype != atype){
+ continue;
+ }
+ if (tmp_card->slot_no == slot_no &&
+ tmp_card->bus_no == bus_no){
+ return tmp_card;
+ }
+ }
+ return NULL;
+}
+
+/*
+*****************************************************************************
+** sdla_cpu_register
+*****************************************************************************
+*/
+static sdlahw_t*
+sdla_hw_register(sdlahw_card_t* card, int cpu_no, int irq, void* dev)
+{
+ sdlahw_t *new_hw, *last_hw;
+
+ new_hw = sdla_hw_search(card->atype, card->slot_no, card->bus_no, cpu_no);
+ if (new_hw){
+ return new_hw;
+ }
+ new_hw = malloc(sizeof(sdlahw_t), M_DEVBUF, M_NOWAIT);
+ if (!new_hw)
+ return NULL;
+
+ memset(new_hw,0,sizeof(sdlahw_t));
+
+ new_hw->cpu_no = cpu_no;
+ new_hw->irq = irq;
+ new_hw->hwcard = card;
+#if 0
+ new_hw->dev = dev;
+#endif
+ new_hw->magic = SDLAHW_MAGIC;
+ card->used++;
+
+ LIST_FOREACH(last_hw, &sdlahw_head, next){
+ if (!LIST_NEXT(last_hw, next)){
+ break;
+ }
+ }
+ if (last_hw){
+ LIST_INSERT_AFTER(last_hw, new_hw, next);
+ }else{
+ LIST_INSERT_HEAD(&sdlahw_head, new_hw, next);
+ }
+ return new_hw;
+}
+
+/*
+*****************************************************************************
+** sdla_hw_unregister
+*****************************************************************************
+*/
+#if 0
+static int
+sdla_hw_unregister (sdlahw_card_t* hwcard, int cpu_no)
+{
+ sdlahw_t* tmp_hw;
+ int i;
+
+ LIST_FOREACH(tmp_hw, &sdlahw_head, next){
+ if (tmp_hw->hwcard != hwcard){
+ continue;
+ }
+ if (tmp_hw->cpu_no == cpu_no){
+ break;
+ }
+ }
+ if (tmp_hw == NULL){
+ log(LOG_INFO, "Error: Failed to find device (slot=%d,bus=%d,cpu=%c)\n",
+ hwcard->slot_no, hwcard->bus_no, SDLA_GET_CPU(cpu_no));
+ return -EFAULT;
+ }
+ if (tmp_hw->used){
+ log(LOG_INFO, "Error: Device is still in used (slot=%d,bus=%d,cpu=%c,used=%d)\n",
+ hwcard->slot_no, hwcard->bus_no, SDLA_GET_CPU(cpu_no), hwcard->used);
+ return -EBUSY;
+ }
+
+ tmp_hw->hwprobe = NULL;
+ tmp_hw->hwcard = NULL;
+ hwcard->used--; /* Decrement card usage */
+ LIST_REMOVE(tmp_hw, next);
+ free(tmp_hw, M_DEVBUF);
+ return 0;
+}
+#endif
+/*
+*****************************************************************************
+** sdla_cpu_search
+*****************************************************************************
+*/
+static sdlahw_t*
+sdla_hw_search(u_int16_t atype, int slot_no, int bus_no, int cpu_no)
+{
+ sdlahw_t* tmp_hw;
+
+ LIST_FOREACH(tmp_hw, &sdlahw_head, next){
+ if (tmp_hw->hwcard == NULL){
+ log(LOG_INFO, "Critical Error: sdla_cpu_search: line %d\n", __LINE__);
+ LIST_REMOVE(tmp_hw, next);
+ continue;
+ }
+ if (tmp_hw->hwcard->atype != atype){
+ LIST_REMOVE(tmp_hw, next);
+ continue;
+ }
+ if (tmp_hw->hwcard->slot_no == slot_no &&
+ tmp_hw->hwcard->bus_no == bus_no &&
+ tmp_hw->cpu_no == cpu_no){
+ return tmp_hw;
+ }
+ }
+ return NULL;
+}
+
+
+/*
+*****************************************************************************
+*****************************************************************************
+*** S A N G O M A H A R D W A R E R E G I S T E R *****
+*****************************************************************************
+*****************************************************************************
+*/
+
+/******* Kernel APIs ********************************************************/
+
+/*============================================================================
+ * Set up adapter.
+ * o detect adapter type
+ * o set up adapter shared memory
+ * Return: 0 ok.
+ * < 0 error
+ */
+/* ALEX int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)*/
+int sdla_setup (void* phw)
+{
+ sdlahw_card_t* hwcard = NULL;
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ int err=0;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ hwcard = hw->hwcard;
+ switch(hwcard->type){
+ case SDLA_AFT:
+ break;
+
+ default:
+ log(LOG_INFO, "%s: Invalid card type %x\n",
+ hw->devname, hw->hwcard->type);
+ return -EINVAL;
+ }
+
+ hw->dpmsize = SDLA_WINDOWSIZE;
+
+ err = sdla_detect(hw);
+ return err;
+}
+
+
+/*============================================================================
+ * Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
+ */
+int sdla_down (void* phw)
+{
+ sdlahw_card_t* card = NULL;
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ card = hw->hwcard;
+ switch (card->type) {
+ case SDLA_AFT:
+ /* free up the allocated virtual memory */
+ if (hw->status & SDLA_MEM_MAPPED){
+ bus_space_unmap(hw->hwcard->memt,
+ hw->dpmbase,
+ XILINX_PCI_MEM_SIZE);
+ hw->status &= ~SDLA_MEM_MAPPED;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*============================================================================
+ * Read the hardware interrupt status.
+ */
+int sdla_read_int_stat (void* phw, u_int32_t* int_status)
+{
+ sdlahw_card_t* card = NULL;
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ card = hw->hwcard;
+ switch(card->type){
+ case SDLA_AFT:
+ sdla_pci_read_config_dword(hw, PCI_INT_STATUS, int_status);
+ }
+ return 0;
+}
+
+
+/*============================================================================
+ * Generate an interrupt to adapter's CPU.
+ */
+int sdla_cmd (void* phw, unsigned long offset, wan_mbox_t* mbox)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ int len = sizeof(wan_cmd_t);
+ int err = 0;
+ u_int8_t value;
+
+ SDLA_MAGIC(hw);
+ len += mbox->wan_data_len;
+
+ sdla_peek(hw, offset, (void*)&value, 1);
+ if (value != 0x00){
+ log(LOG_INFO, "%s: opp flag set on entry to sdla_exec!\n",
+ hw->devname);
+ return 0;
+ }
+ mbox->wan_opp_flag = 0x00;
+ sdla_poke(hw, offset, (void*)mbox, len);
+
+ err = sdla_exec(hw, offset);
+ if (!err){
+ log(LOG_INFO, "%s: Command 0x%02X failed!\n",
+ hw->devname, mbox->wan_command);
+ return WAN_CMD_TIMEOUT;
+ }
+ sdla_peek(hw, offset, (void*)mbox, sizeof(wan_cmd_t));
+ if (mbox->wan_data_len){
+ sdla_peek(hw, offset+offsetof(wan_mbox_t, wan_data),
+ mbox->wan_data, mbox->wan_data_len);
+ }
+
+ return mbox->wan_return_code;
+}
+
+/*============================================================================
+ * Execute Adapter Command.
+ * o Set exec flag.
+ * o Busy-wait until flag is reset.
+ * o Return number of loops made, or 0 if command timed out.
+ */
+static int sdla_exec (sdlahw_t* hw, unsigned long offset)
+{
+ volatile unsigned long tstop;
+ volatile unsigned long nloops;
+ u_int8_t value;
+
+ value = 0x01;
+ sdla_poke(hw, offset, (void*)&value, 1);
+ tstop = ticks + EXEC_TIMEOUT;
+
+ sdla_peek(hw, offset, (void*)&value, 1);
+ for (nloops = 1; value == 0x01; ++ nloops){
+ DELAY(EXEC_DELAY);
+ if (ticks > tstop || nloops > MAX_NLOOPS){
+ log(LOG_INFO, "%s: Timeout %lu ticks (max=%lu) loops %lu (max=%u)\n",
+ hw->devname,
+ (ticks-tstop+EXEC_TIMEOUT),
+ (unsigned long)EXEC_TIMEOUT,
+ nloops,
+ MAX_NLOOPS);
+ return 0; /* time is up! */
+ }
+ sdla_peek(hw, offset, (void*)&value, 1);
+ }
+
+ return nloops;
+}
+
+
+/*============================================================================
+ * Read absolute adapter memory.
+ * Transfer data from adapter's memory to data buffer.
+ *
+ * Note:
+ * Care should be taken when crossing dual-port memory window boundary.
+ * This function is not atomic, so caller must disable interrupt if
+ * interrupt routines are accessing adapter shared memory.
+ */
+int sdla_peek (void* phw, unsigned long addr, void* buf, unsigned len)
+{
+ sdlahw_card_t* card = NULL;
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ int err = 0;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ card = hw->hwcard;
+ if (addr + len > hw->memory) /* verify arguments */
+ return -EINVAL;
+
+ switch(card->type){
+ case SDLA_AFT:
+ sdla_peek_by_4(hw, addr, buf, len);
+ break;
+
+ default:
+ log(LOG_INFO, "%s: Invalid card type 0x%X\n",
+ __FUNCTION__,card->type);
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+
+/*============================================================================
+ * Read data from adapter's memory to a data buffer in 4-byte chunks.
+ * Note that we ensure that the SDLA memory address is on a 4-byte boundary
+ * before we begin moving the data in 4-byte chunks.
+*/
+static void
+sdla_peek_by_4 (sdlahw_t* hw, unsigned long offset, void* buf, unsigned int len)
+{
+ /* byte copy data until we get to a 4-byte boundary */
+ while (len && (offset & 0x03)){
+ sdla_bus_read_1(hw, offset++, (u_int8_t*)buf);
+ ((u_int8_t *)buf) ++;
+ len --;
+ }
+
+ /* copy data in 4-byte chunks */
+ while (len >= 4){
+ sdla_bus_read_4(hw, offset, (u_int32_t*)buf);
+ (u_int8_t*)buf += 4;
+ offset += 4;
+ len -= 4;
+ }
+
+ /* byte copy any remaining data */
+ while (len){
+ sdla_bus_read_1(hw, offset++, (u_int8_t*)buf);
+ ((u_int8_t *)buf) ++;
+ len --;
+ }
+}
+
+/*============================================================================
+ * Write Absolute Adapter Memory.
+ * Transfer data from data buffer to adapter's memory.
+ *
+ * Note:
+ * Care should be taken when crossing dual-port memory window boundary.
+ * This function is not atomic, so caller must disable interrupt if
+ * interrupt routines are accessing adapter shared memory.
+ */
+int sdla_poke (void* phw, unsigned long addr, void* buf, unsigned len)
+{
+ sdlahw_card_t* card = NULL;
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ int err = 0;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ card = hw->hwcard;
+ if (addr + len > hw->memory){ /* verify arguments */
+ return -EINVAL;
+ }
+
+ switch (card->type){
+ case SDLA_AFT:
+ sdla_poke_by_4(hw, addr, buf, len);
+ break;
+
+ default:
+ log(LOG_INFO, "%s: Invalid card type 0x%X\n",
+ __FUNCTION__,card->type);
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+
+/*============================================================================
+ * Write from a data buffer to adapter's memory in 4-byte chunks.
+ * Note that we ensure that the SDLA memory address is on a 4-byte boundary
+ * before we begin moving the data in 4-byte chunks.
+*/
+static void sdla_poke_by_4 (sdlahw_t* hw, unsigned long offset, void* buf, unsigned int len)
+{
+ /* byte copy data until we get to a 4-byte boundary */
+ while (len && (offset & 0x03)){
+ sdla_bus_write_1(hw, offset++, *(char *)buf);
+ ((char *)buf) ++;
+ len --;
+ }
+
+ /* copy data in 4-byte chunks */
+ while (len >= 4){
+ sdla_bus_write_4(hw, offset, *(unsigned long *)buf);
+ offset += 4;
+ (char*)buf += 4;
+ len -= 4;
+ }
+
+ /* byte copy any remaining data */
+ while (len){
+ sdla_bus_write_1(hw, offset++, *(char *)buf);
+ ((char *)buf) ++;
+ len --;
+ }
+}
+
+int sdla_poke_byte (void* phw, unsigned long offset, u_int8_t value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ SDLA_MAGIC(hw);
+ /* Sangoma ISA card sdla_bus_write_1(hw, offset, value); */
+ sdla_poke(hw, offset, (void*)&value, 1);
+ return 0;
+}
+
+int sdla_set_bit (void* phw, unsigned long offset, u_int8_t value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ u_int8_t tmp;
+
+ SDLA_MAGIC(hw);
+ /* Sangoma ISA card -> sdla_bus_read_1(hw, offset, &tmp); */
+ sdla_peek(hw, offset, (void*)&tmp, 1);
+ tmp |= value;
+ /* Sangoma ISA card -> sdla_bus_write_1(hw, offset, tmp); */
+ sdla_poke(hw, offset, (void*)&tmp, 1);
+ return 0;
+}
+
+
+int sdla_clear_bit (void* phw, unsigned long offset, u_int8_t value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ u_int8_t tmp;
+
+ SDLA_MAGIC(hw);
+ /* Sangoma ISA card -> sdla_bus_read_1(hw, offset, &tmp); */
+ sdla_peek(hw, offset, (void*)&tmp, 1);
+ tmp &= ~value;
+ /* Sangoma ISA card -> sdla_bus_write_1(hw, offset, tmp); */
+ sdla_poke(hw, offset, (void*)&tmp, 1);
+ return 0;
+}
+
+
+/****** Hardware-Specific Functions *****************************************/
+
+/*
+*****************************************************************************
+*****************************************************************************
+*** S A N G O M A H A R D W A R E D E T E C T I O N *****
+*****************************************************************************
+*****************************************************************************
+*/
+
+/*============================================================================
+ * Find the AFT HDLC PCI adapter in the PCI bus.
+ * Return the number of AFT adapters found (0 if no adapter found).
+ */
+static int sdla_detect_aft(sdlahw_t* hw)
+{
+ sdlahw_card_t* card;
+ u_int16_t ut_u16;
+
+ WAN_ASSERT(hw == NULL);
+ WAN_ASSERT(hw->hwcard == NULL);
+ card = hw->hwcard;
+ sdla_pci_read_config_dword(hw,
+ (hw->cpu_no == SDLA_CPU_A) ? PCI_IO_BASE_DWORD :
+ PCI_MEM_BASE0_DWORD, (u_int32_t*)&hw->mem_base_addr);
+ if (!hw->mem_base_addr){
+ if(hw->cpu_no == SDLA_CPU_B){
+ printf("%s: No PCI memory allocated for CPU #B\n",
+ hw->devname);
+ }else{
+ printf("%s: No PCI memory allocated to card\n",
+ hw->devname);
+ }
+ return -EINVAL;
+ }
+#if defined(DEBUG)
+ log(LOG_INFO, "%s: AFT PCI memory at 0x%lX\n",
+ hw->devname, (unsigned long)hw->mem_base_addr);
+#endif
+ sdla_pci_read_config_byte(hw, PCI_INTLINE, (u_int8_t*)&hw->irq);
+ if(hw->irq == PCI_IRQ_NOT_ALLOCATED) {
+ printf("%s: IRQ not allocated to AFT adapter\n",
+ hw->devname);
+ return -EINVAL;
+ }
+
+#if defined(DEBUG)
+ log(LOG_INFO, "%s: IRQ %d allocated to the AFT PCI card\n",
+ hw->devname, hw->irq);
+#endif
+
+ hw->memory=XILINX_PCI_MEM_SIZE;
+
+ /* map the physical PCI memory to virtual memory */
+ bus_space_map(hw->hwcard->memt,
+ hw->mem_base_addr,
+ XILINX_PCI_MEM_SIZE,
+ 0,
+ &hw->dpmbase);
+ if (!hw->dpmbase){
+ printf("%s: couldn't map memory\n",
+ hw->devname);
+ return -EINVAL;
+ }
+ hw->status |= SDLA_MEM_MAPPED;
+
+
+ /* Enable master operation on PCI and enable
+ * bar0 memory */
+ sdla_pci_read_config_word(hw, XILINX_PCI_CMD_REG, &ut_u16);
+ ut_u16 |=0x06;
+ sdla_pci_write_config_word(hw, XILINX_PCI_CMD_REG, ut_u16);
+
+ /* Set PCI Latency of 0xFF*/
+ sdla_pci_write_config_dword(hw, XILINX_PCI_LATENCY_REG, XILINX_PCI_LATENCY);
+
+ return 0;
+}
+
+
+/*
+ * ============================================================================
+ * Detect adapter type.
+ */
+static int sdla_detect (sdlahw_t* hw)
+{
+ sdlahw_card_t* card = NULL;
+ int err = 0;
+
+ WAN_ASSERT(hw == NULL);
+ WAN_ASSERT(hw->hwcard == NULL);
+ card = hw->hwcard;
+ switch (card->type){
+ case SDLA_AFT:
+ err = sdla_detect_aft(hw);
+ break;
+ }
+ if (err){
+ sdla_down(hw);
+ }
+ return err;
+}
+
+
+
+
+/*
+*****************************************************************************
+*****************************************************************************
+*** H A R D W A R E C O N F I G U R A T I O N *****
+*****************************************************************************
+*****************************************************************************
+*/
+
+int sdla_is_te1(void* phw)
+{
+ sdlahw_card_t* hwcard = NULL;
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ hwcard = hw->hwcard;
+ switch(hwcard->atype){
+ case S5144_ADPTR_1_CPU_T1E1:
+ case S5147_ADPTR_2_CPU_T1E1:
+ case S5148_ADPTR_1_CPU_T1E1:
+ case A101_ADPTR_1TE1:
+ case A101_ADPTR_2TE1:
+ return 1;
+ }
+ return 0;
+
+
+}
+
+int sdla_check_mismatch(void* phw, unsigned char media)
+{
+ sdlahw_card_t* hwcard = NULL;
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ hwcard = hw->hwcard;
+ if (media == WANOPT_MEDIA_T1 ||
+ media == WANOPT_MEDIA_E1){
+ if (hwcard->atype != S5144_ADPTR_1_CPU_T1E1 &&
+ hwcard->atype != S5147_ADPTR_2_CPU_T1E1 &&
+ hwcard->atype != S5148_ADPTR_1_CPU_T1E1){
+ log(LOG_INFO, "%s: Error: Card type mismatch: User=T1/E1 Actual=%s\n",
+ hw->devname,
+ SDLA_ADPTR_DECODE(hwcard->atype));
+ return -EIO;
+ }
+ hwcard->atype = S5144_ADPTR_1_CPU_T1E1;
+
+ }else if (media == WANOPT_MEDIA_56K){
+ if (hwcard->atype != S5145_ADPTR_1_CPU_56K){
+ log(LOG_INFO, "%s: Error: Card type mismatch: User=56K Actual=%s\n",
+ hw->devname,
+ SDLA_ADPTR_DECODE(hwcard->atype));
+ return -EIO;
+ }
+ }else{
+ if (hwcard->atype == S5145_ADPTR_1_CPU_56K ||
+ hwcard->atype == S5144_ADPTR_1_CPU_T1E1 ||
+ hwcard->atype == S5147_ADPTR_2_CPU_T1E1 ||
+ hwcard->atype == S5148_ADPTR_1_CPU_T1E1){
+ log(LOG_INFO, "%s: Error: Card type mismatch: User=S514(1/2/3) Actual=%s\n",
+ hw->devname,
+ SDLA_ADPTR_DECODE(hwcard->atype));
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+int sdla_getcfg(void* phw, int type, void* value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ sdlahw_card_t* hwcard;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ hwcard = hw->hwcard;
+ switch(type){
+ case SDLA_CARDTYPE:
+ *(u_int16_t*)value = hwcard->type;
+ break;
+ case SDLA_MEMBASE:
+ *(bus_space_handle_t*)value = hw->dpmbase;
+ break;
+ case SDLA_MEMEND:
+ *(u_int32_t*)value = ((unsigned long)hw->dpmbase + hw->dpmsize - 1);
+ break;
+ case SDLA_MEMSIZE:
+ *(u_int16_t*)value = hw->dpmsize;
+ break;
+ case SDLA_MEMORY:
+ *(u_int32_t*)value = hw->memory;
+ break;
+ case SDLA_IRQ:
+ *(u_int16_t*)value = hw->irq;
+ break;
+ case SDLA_ADAPTERTYPE:
+ *(u_int16_t*)value = hwcard->atype;
+ break;
+ case SDLA_CPU:
+ *(u_int16_t*)value = hw->cpu_no;
+ break;
+ case SDLA_SLOT:
+ *(u_int16_t*)value = hwcard->slot_no;
+ break;
+ case SDLA_BUS:
+ *(u_int16_t*)value = hwcard->bus_no;
+ break;
+ case SDLA_DMATAG:
+ *(bus_dma_tag_t*)value = hwcard->pa.pa_dmat;
+ break;
+ case SDLA_PCIEXTRAVER:
+ *(u_int8_t*)value = hwcard->pci_extra_ver;
+ break;
+ case SDLA_BASEADDR:
+ *(u_int32_t*)value = hw->mem_base_addr;
+ break;
+ }
+ return 0;
+}
+
+
+int sdla_get_hwcard(void* phw, void** phwcard)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+
+ *phwcard = hw->hwcard;
+ return 0;
+}
+
+
+int sdla_get_hwprobe(void* phw, void** str)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+
+ if (hw->hwprobe){
+ *str = hw->hwprobe->hw_info;
+ }
+ return 0;
+}
+
+/*
+*****************************************************************************
+*****************************************************************************
+*** M I S C E L L A N E O U S *****
+*****************************************************************************
+*****************************************************************************
+*/
+
+int sdla_bus_write_1(void* phw, unsigned int offset, u_int8_t value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ if (!(hw->status & SDLA_MEM_MAPPED)) return 0;
+ bus_space_write_1(hw->hwcard->memt, hw->dpmbase, offset, value);
+ return 0;
+}
+
+int sdla_bus_write_2(void* phw, unsigned int offset, u_int16_t value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ if (!(hw->status & SDLA_MEM_MAPPED)) return 0;
+ bus_space_write_2(hw->hwcard->memt, hw->dpmbase, offset, value);
+ return 0;
+}
+
+int sdla_bus_write_4(void* phw, unsigned int offset, u_int32_t value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ if (!(hw->status & SDLA_MEM_MAPPED)) return 0;
+ bus_space_write_4(hw->hwcard->memt, hw->dpmbase, offset, value);
+ return 0;
+}
+
+int sdla_bus_read_1(void* phw, unsigned int offset, u_int8_t* value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT2(hw == NULL, 0);
+ SDLA_MAGIC(hw);
+ if (!(hw->status & SDLA_MEM_MAPPED)) return 0;
+ *value = bus_space_read_1(hw->hwcard->memt, hw->dpmbase, offset);
+ return 0;
+}
+
+int sdla_bus_read_2(void* phw, unsigned int offset, u_int16_t* value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT2(hw == NULL, 0);
+ SDLA_MAGIC(hw);
+ if (!(hw->status & SDLA_MEM_MAPPED)) return 0;
+ *value = bus_space_read_2(hw->hwcard->memt, hw->dpmbase, offset);
+ return 0;
+}
+
+int sdla_bus_read_4(void* phw, unsigned int offset, u_int32_t* value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+
+ WAN_ASSERT2(hw == NULL, 0);
+ WAN_ASSERT2(hw->dpmbase == 0, 0);
+ SDLA_MAGIC(hw);
+ if (!(hw->status & SDLA_MEM_MAPPED)) return 0;
+ *value = bus_space_read_4(hw->hwcard->memt, hw->dpmbase, offset);
+ return 0;
+}
+
+static int sdla_pci_read_config_dword(void* phw, int reg, u_int32_t* value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ sdlahw_card_t* hwcard;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ hwcard = hw->hwcard;
+ *value = pci_conf_read(hwcard->pa.pa_pc, hwcard->pa.pa_tag, reg);
+ return 0;
+}
+
+static int sdla_pci_read_config_word(void* phw, int reg, u_int16_t* value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ sdlahw_card_t* hwcard;
+ u_int32_t tmp = 0x00;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ hwcard = hw->hwcard;
+ tmp = pci_conf_read(hwcard->pa.pa_pc, hwcard->pa.pa_tag, reg);
+ *value = (u_int16_t)((tmp >> 16) & 0xFFFF);
+ return 0;
+}
+
+static int sdla_pci_read_config_byte(void* phw, int reg, u_int8_t* value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ sdlahw_card_t* hwcard;
+ u_int32_t tmp = 0x00;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ hwcard = hw->hwcard;
+ tmp = pci_conf_read(hwcard->pa.pa_pc, hwcard->pa.pa_tag, reg);
+ *value = (u_int8_t)(tmp & 0xFF);
+ return 0;
+}
+
+static int sdla_pci_write_config_dword(void* phw, int reg, u_int32_t value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ sdlahw_card_t* card;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ card = hw->hwcard;
+ pci_conf_write(card->pa.pa_pc, card->pa.pa_tag, reg, value);
+ return 0;
+}
+
+static int sdla_pci_write_config_word(void* phw, int reg, u_int16_t value)
+{
+ sdlahw_t* hw = (sdlahw_t*)phw;
+ sdlahw_card_t* card;
+
+ WAN_ASSERT(hw == NULL);
+ SDLA_MAGIC(hw);
+ WAN_ASSERT(hw->hwcard == NULL);
+ card = hw->hwcard;
+ pci_conf_write(card->pa.pa_pc, card->pa.pa_tag, reg, value);
+ return 0;
+}
+
+