/*
* Copyright (C) Eicon Technology Corporation, 2000.
*
* Eicon File Revision : 1.8
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
*/
#include "eicon.h"
#include "sys.h"
#include "idi.h"
#include "divas.h"
#include "pc.h"
#include "pr_pc.h"
#include "dsp_defs.h"
#include "adapter.h"
#include "uxio.h"
#define PCI_BADDR0 0x10
#define PCI_BADDR1 0x14
#define PCI_BADDR2 0x18
#define DIVAS_SIGNATURE 0x4447
/* offset to start of MAINT area (used by xlog) */
#define DIVAS_MAINT_OFFSET 0xff00 /* value for BRI card */
#define PROTCAP_TELINDUS 0x1
#define PROTCAP_V90D 0x8
word GetProtFeatureValue(char *sw_id);
byte io_in(ADAPTER *a, void *adr);
word io_inw(ADAPTER *a, void *adr);
void io_in_buffer(ADAPTER *a, void *adr, void *P, word length);
void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e);
void io_out(ADAPTER *a, void *adr, byte data);
void io_outw(ADAPTER *a, void *adr, word data);
void io_out_buffer(ADAPTER *a, void *adr, void *P, word length);
void io_inc(ADAPTER *a, void *adr);
static int diva_server_bri_test_int(card_t *card);
static int bri_ISR (card_t* card);
#define PLX_IOBASE 0
#define DIVAS_IOBASE 1
#define REG_DATA 0x00
#define REG_ADDRLO 0x04
#define REG_ADDRHI 0x0C
#define REG_IOCTRL 0x10
#define M_PCI_RESET 0x10
byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset);
word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset);
void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte);
void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word);
int DivasBRIInitPCI(card_t *card, dia_card_t *cfg);
static
int diva_server_bri_reset(card_t *card)
{
byte *DivasIOBase;
word i;
dword dwWait;
UxCardLog(0);
DPRINTF(("divas: resetting BRI adapter"));
DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0);
for (i=0; i < 50000; i++)
;
UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0);
UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x0000);
for (i=0; i<0x8000; i++)
{
UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0);
}
for (dwWait=0; dwWait < 0x00FFFFFF; dwWait++)
;
UxCardMemDetach(card->hw, DivasIOBase);
return 0;
}
static
void diva_server_bri_reset_int(card_t *card)
{
byte *DivasIOBase = NULL;
DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08);
UxCardMemDetach(card->hw, DivasIOBase);
return;
}
static
int diva_server_bri_start(card_t *card, byte *channels)
{
byte *DivasIOBase, *PLXIOBase;
word wSig = 0;
word i;
dword dwSerialNum;
byte bPLX9060 = FALSE;
DPRINTF(("divas: starting Diva Server BRI card"));
card->is_live = FALSE;
DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA , 0);
UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08);
/* wait for signature to indicate card has started */
for (i = 0; i < 300; i++)
{
UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E);
wSig = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA);
if (wSig == DIVAS_SIGNATURE)
{
DPRINTF(("divas: card started after %d ms", i * 10));
break;
}
UxPause(10);
}
if (wSig != DIVAS_SIGNATURE)
{
DPRINTF(("divas: card failed to start (Sig=0x%x)", wSig));
UxCardMemDetach(card->hw, DivasIOBase);
return -1;
}
card->is_live = TRUE;
UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x3F6);
*channels = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA);
UxCardMemDetach(card->hw, DivasIOBase);
PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE);
bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) | UxCardPortIoInW(card->hw, PLXIOBase, 0x6E);
if (bPLX9060)
{
dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x1E) << 16) |
(UxCardPortIoInW(card->hw, PLXIOBase, 0x22));
DPRINTF(("divas: PLX9060 in use. Serial number 0x%04X", dwSerialNum));
}
else
{
dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x22) << 16) |
(UxCardPortIoInW(card->hw, PLXIOBase, 0x26));
DPRINTF(("divas: PLX9050 in use. Serial number 0x%04X", dwSerialNum));
}
UxCardMemDetach(card->hw, PLXIOBase);
card->serial_no = dwSerialNum;
diva_server_bri_test_int(card);
return 0;
}
static
int diva_server_bri_load(card_t *card, dia_load_t *load)
{
byte *DivasIOBase;
dword r3000_base;
dword dwAddr, dwLength, i;
word wTest, aWord;
DPRINTF(("divas: loading Diva Server BRI card"));
switch (load->code_type)
{
case DIA_CPU_CODE:
DPRINTF(("divas: loading RISC %s", &load->code[0x80]));
card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]);
DPRINTF(("divas: features 0x%x", card->hw->features));
if (card->hw->features == 0xFFFF)
{
DPRINTF(("divas: invalid feature string failed load\n"));
return -1;
}
r3000_base = 0;
break;
case DIA_DSP_CODE:
DPRINTF(("divas: DSP code \"%s\"", load->code));
if ((card->hw->features) && (!(card->hw->features & PROTCAP_TELINDUS)))
{
DPRINTF(("divas: only Telindus style binaries supported"));
return -1;
}
if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
{
DPRINTF(("divas: V.90 DSP binary"));
r3000_base = (0xBF790000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC));
}
else
{
DPRINTF(("divas: non-V.90 DSP binary"));
r3000_base = (0xBF7A0000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC));
}
DPRINTF(("divas: loading at 0x%x", r3000_base));
break;
case DIA_TABLE_CODE:
DPRINTF(("divas: TABLE code"));
if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
{
r3000_base = 0xBF790000 + sizeof(dword);
}
else
{
r3000_base = 0xBF7A0000 + sizeof(dword);
}
break;
case DIA_DLOAD_CNT:
DPRINTF(("divas: COUNT code"));
if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
{
r3000_base = 0xBF790000;
}
else
{
r3000_base = 0xBF7A0000;
}
break;
default:
DPRINTF(("divas: unknown code type %d", load->code_type));
return -1;
break;
}
DPRINTF(("divas: Writing %d bytes to adapter, address 0x%x", load->length, r3000_base));
DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
DPRINTF(("divas: Attached to 0x%04X", DivasIOBase));
dwLength = load->length;
for (i=0; i < dwLength; i++)
{
dwAddr = r3000_base + i;
UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, load->code[i]);
}
DPRINTF(("divas: Verifying"));
for (i=0; i<dwLength; i++)
{
dwAddr = r3000_base + i;
UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr);
wTest = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA);
aWord = load->code[i];
if (wTest != aWord)
{
DPRINTF(("divas: load verify failed on byte %d", i));
DPRINTF(("divas: RAM 0x%x File 0x%x",wTest,aWord));
UxCardMemDetach(card->hw, DivasIOBase);
return -1;
}
}
DPRINTF(("divas: Loaded and verified. Detaching from adapter"));
UxCardMemDetach(card->hw, DivasIOBase);
UxCardLog(0);
return 0;
}
static
int diva_server_bri_config(card_t *card, dia_config_t *config)
{
byte *DivasIOBase, i;
DPRINTF(("divas: configuring Diva Server BRI card"));
DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 8);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->tei);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 9);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->sig_flags);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 12);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->permanent);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 13);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 14);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->stable_l2);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 15);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->no_order_check);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 16);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 17);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 18);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->low_channel);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 19);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->prot_version);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 20);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->crc4);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 21);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
{
DPRINTF(("divas: Signifying V.90"));
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 4);
}
else
{
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
}
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 23);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, card->serial_no & 0xFF);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 24);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 8) & 0xFF);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 25);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 16) & 0xFF);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 26);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 21);
for (i=0; i<32; i++)
{
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 32+i);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].oad[i]);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 64+i);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].osa[i]);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 96+i);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].spid[i]);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 128+i);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].oad[i]);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 160+i);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].osa[i]);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 192+i);
UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].spid[i]);
}
UxCardMemDetach(card->hw, DivasIOBase);
return 0;
}
void DivasBriPatch(card_t *card)
{
dword PLXIOBase = 0;
dword DivasIOBase = 0;
PLXIOBase = card->cfg.reset_base;
DivasIOBase = card->cfg.io_base;
if(card->hw == NULL)
{
DPRINTF(("Divas: BRI PATCH (PLX chip) card->hw is null"));
return;
}
if (PLXIOBase == 0)
{
DPRINTF(("Divas: BRI (PLX chip) cannot be patched. The BRI adapter may"));
DPRINTF(("Divas: not function properly. If you do encounter problems,"));
DPRINTF(("Divas: ensure that your machine is using the latest BIOS."));
return;
}
DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase));
DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase));
if (PLXIOBase & 0x80)
{
dword dwSize, dwSerialNum, dwCmd;
boolean_t bPLX9060;
word wSerHi, wSerLo;
DPRINTF(("Divas: Patch required"));
dwCmd = 0;
UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd);
PLXIOBase &= ~0x80;
UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &PLXIOBase);
dwSize = 0xFFFFFFFF;
UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &dwSize);
UxPciConfigRead(card->hw, 4, PCI_BADDR1, &dwSize);
dwSize = (~ (dwSize & ~7)) + 1;
DivasIOBase = PLXIOBase + dwSize;
card->cfg.reset_base = PLXIOBase;
card->cfg.io_base = DivasIOBase;
UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &card->cfg.reset_base);
UxPciConfigWrite(card->hw, 4, PCI_BADDR2, &card->cfg.io_base);
dwCmd = 5;
UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd);
bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) |
UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E);
if (bPLX9060)
{
wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E);
wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
dwSerialNum = (wSerHi << 16) | wSerLo;
UxCardLog(0);
}
else
{
wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26);
dwSerialNum = (wSerHi << 16) | wSerLo;
UxCardLog(0);
}
}
else
{
word wSerHi, wSerLo;
boolean_t bPLX9060;
dword dwSerialNum;
DPRINTF(("divas: No patch required"));
bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) |
UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E);
if (bPLX9060)
{
wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E);
wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
dwSerialNum = (wSerHi << 16) | wSerLo;
}
else
{
wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26);
dwSerialNum = (wSerHi << 16) | wSerLo;
}
}
DPRINTF(("Divas: After patching:"));
DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase));
DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase));
}
#define TEST_INT_DIVAS_BRI 0x12
static
int diva_server_bri_test_int(card_t *card)
{
boolean_t bPLX9060 = FALSE;
byte *PLXIOBase = NULL, *DivasIOBase = NULL;
DPRINTF(("divas: test interrupt for Diva Server BRI card"));
PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE);
bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) || UxCardPortIoInW(card->hw, PLXIOBase, 0x6E);
if (bPLX9060)
{ /* PLX9060 */
UxCardPortIoOut(card->hw, PLXIOBase, 0x69, 0x09);
}
else
{ /* PLX9050 */
UxCardPortIoOut(card->hw, PLXIOBase, 0x4C, 0x41);
}
card->test_int_pend = TEST_INT_DIVAS_BRI;
UxCardMemDetach(card->hw, PLXIOBase);
DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x89);
UxCardMemDetach(card->hw, DivasIOBase);
return 0;
}
static
int diva_server_bri_mem_get(card_t *card, mem_block_t *mem_block)
{
dword user_addr = mem_block->addr;
word length = 0;
dword addr;
word i;
byte *DivasIOBase;
DPRINTF(("divas: Retrieving memory from 0x%x", user_addr));
DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
addr = user_addr;
for (i=0; i < (16 * 8); i++)
{
addr = user_addr + i;
UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, addr >> 16);
UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, (word) addr);
mem_block->data[i] = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA);
length++;
}
UxCardMemDetach(card->hw, DivasIOBase);
return length;
}
int DivasBriInit(card_t *card, dia_card_t *cfg)
{
DPRINTF(("divas: initialise Diva Server BRI card"));
if (DivasBRIInitPCI(card, cfg) == -1)
{
return -1;
}
card->card_reset = diva_server_bri_reset;
card->card_start = diva_server_bri_start;
card->card_load = diva_server_bri_load;
card->card_config = diva_server_bri_config;
card->reset_int = diva_server_bri_reset_int;
card->card_mem_get = diva_server_bri_mem_get;
card->xlog_offset = DIVAS_MAINT_OFFSET;
card->out = DivasOut;
card->test_int = DivasTestInt;
card->dpc = DivasDpc;
card->clear_int = DivasClearInt;
card->card_isr = bri_ISR;
card->a.ram_out = io_out;
card->a.ram_outw = io_outw;
card->a.ram_out_buffer = io_out_buffer;
card->a.ram_inc = io_inc;
card->a.ram_in = io_in;
card->a.ram_inw = io_inw;
card->a.ram_in_buffer = io_in_buffer;
card->a.ram_look_ahead = io_look_ahead;
return 0;
}
word GetProtFeatureValue(char *sw_id)
{
word features = 0;
while ((*sw_id) && (sw_id[0] != '['))
sw_id++;
if (sw_id == NULL)
{
DPRINTF(("divas: no feature string present"));
features = -1;
}
else
{
byte i, shifter;
sw_id += 3;
for (i=0, shifter=12; i<4; i++, shifter-=4)
{
if ((sw_id[i] >= '0') && (sw_id[i] <= '9'))
{
features |= (sw_id[i] - '0') << shifter;
}
else if ((sw_id[i] >= 'a') && (sw_id[i] <= 'f'))
{
features |= (sw_id[i] - 'a' + 10) << shifter;
}
else if ((sw_id[i] >= 'A') && (sw_id[i] <= 'F'))
{
features |= (sw_id[i] - 'A' + 10) << shifter;
}
else
{
DPRINTF(("divas: invalid feature string"));
return -1;
}
}
}
return features;
}
int bri_ISR (card_t* card)
{
int served = 0;
byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01)
{
served = 1;
card->int_pend += 1;
DivasDpcSchedule(); /* ISR DPC */
UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08);
}
UxCardMemDetach(card->hw, DivasIOBase);
return (served != 0);
}