/****************************************************************************
*
* HWI_MC.C : Part of the FASTMAC TOOL-KIT (FTK)
*
* THE HARDWARE INTERFACE MODULE FOR MICROCHANNEL CARDS
*
* Copyright (c) Madge Networks Ltd. 1990-1994
*
* COMPANY CONFIDENTIAL
*
*****************************************************************************
*
* The purpose of the Hardware Interface (HWI) is to supply an adapter card
* independent interface to any driver. It performs nearly all of the
* functions that involve affecting SIF registers on the adapter cards.
* This includes downloading code to, initializing, and removing adapters.
*
* The HWI_MC.C module contains the routines specific to 16/4 MC and 16/4
* MC 32 cards which are necessary to install an adapter, to initialize an
* adapter, to remove an adapter and to handle interrupts on an adapter.
*
****************************************************************************/
/*---------------------------------------------------------------------------
|
| DEFINITIONS
|
---------------------------------------------------------------------------*/
#include "ftk_defs.h"
/*---------------------------------------------------------------------------
|
| MODULE ENTRY POINTS
|
---------------------------------------------------------------------------*/
#include "ftk_intr.h" /* routines internal to FTK */
#include "ftk_extr.h" /* routines provided or used by external FTK user */
#ifndef FTK_NO_MC
/*---------------------------------------------------------------------------
|
| LOCAL PROCEDURES
|
---------------------------------------------------------------------------*/
local void
hwi_mc_read_node_address(
ADAPTER * adapter
);
local WBOOLEAN
hwi_mc_valid_io_location(
WORD io_location
);
#ifndef FTK_NO_PROBE
local WORD
hwi_mc_get_irq_channel(
WORD io_location
);
local WORD
hwi_mc_get_dma_channel(
WORD io_location
);
#endif
local WBOOLEAN
hwi_mc_valid_irq_channel(
WORD irq_channel
);
local WBOOLEAN
hwi_mc_valid_dma_channel(
WORD dma_channel
);
local WBOOLEAN
hwi_mc_valid_transfer_mode(
UINT transfer_mode
);
#ifndef FTK_NO_PROBE
/****************************************************************************
*
* hwi_mc_probe_card
* =================
*
*
* PARAMETERS (passed by hwi_probe_adapter) :
* ==========================================
*
* PROBE * resources
*
* resources is an array structures used to identify and record specific
* information about adapters found.
*
* UINT length
*
* length is the number of structures pointed to by reources.
*
* WORD * valid_locations
*
* valid_locations is an array of IO locations to examine for the presence
* of an adapter. For microchannel adapters with should be a subset of
* {0x0a20, 0x1a20, 0x2a20, 0x3a20}.
*
* UINT number_locations
*
* This is the number of IO locations in the above list.
*
* BODY :
* ======
*
* The hwi_mc_probe_card routine is called by hwi_probe_adapter. It
* reads the id registers to find the type of card and also reads the IRQ.
*
*
* RETURNS :
* =========
*
* The routine returns the number of adapters found, or PROBE_FAILURE if
* there's a problem.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_mc_probe_card)
#endif
export UINT
hwi_mc_probe_card(
PROBE * resources,
UINT length,
WORD * valid_locations,
UINT number_locations
)
{
WORD pos_0;
WORD pos_1;
WORD pos_2;
WORD control_0;
WORD control_1;
WORD control_7;
WORD bia_prom;
WORD bia_prom_id;
WORD bia_prom_adap;
WORD bia_prom_rev;
WBOOLEAN card_found;
UINT i;
UINT j;
/*
* Check the bounds.
*/
if(length <= 0 || number_locations <= 0)
{
return PROBE_FAILURE;
}
/*
* Check we've been passed a valid set of IO locations.
*/
for(i = 0; i < number_locations; i++)
{
if(!hwi_mc_valid_io_location(valid_locations[i]))
{
return PROBE_FAILURE;
}
}
/*
* j is the number of adapters found, so zero it.
*/
j = 0;
for(i = 0; i < number_locations; i++)
{
/*
* If we've run out of PROBE structures, return.
*/
if(j >= length)
{
return j;
}
/*
* Set up the MC control registers.
*/
pos_0 = valid_locations[i] + MC_POS_REGISTER_0;
pos_1 = valid_locations[i] + MC_POS_REGISTER_1;
pos_2 = valid_locations[i] + MC_POS_REGISTER_2;
control_0 = valid_locations[i] + MC_CONTROL_REGISTER_0;
control_1 = valid_locations[i] + MC_CONTROL_REGISTER_1;
control_7 = valid_locations[i] + MC_CONTROL_REGISTER_7;
bia_prom = valid_locations[i] + MC_BIA_PROM;
bia_prom_id = bia_prom + BIA_PROM_ID_BYTE;
bia_prom_adap = bia_prom + BIA_PROM_ADAPTER_BYTE;
bia_prom_rev = bia_prom + BIA_PROM_REVISION_BYTE;
#ifndef FTK_NO_IO_ENABLE
macro_probe_enable_io(valid_locations[i], MC_IO_RANGE);
#endif
card_found = FALSE;
/*
* Reset the card.
*/
sys_probe_outsb( control_1, 0);
sys_probe_outsb( control_0, 0);
if (sys_probe_insb(bia_prom_id) == 'M')
{
if (sys_probe_insb(bia_prom_adap) ==
BIA_PROM_TYPE_16_4_MC)
{
resources[j].adapter_card_type =
ADAPTER_CARD_TYPE_16_4_MC;
if(sys_probe_insb(bia_prom_rev) < 2)
{
resources[j].adapter_ram_size = 128;
}
else
{
resources[j].adapter_ram_size = 256;
}
card_found = TRUE;
}
else if (sys_probe_insb(bia_prom_adap) ==
BIA_PROM_TYPE_16_4_MC_32)
{
resources[j].adapter_card_type =
ADAPTER_CARD_TYPE_16_4_MC_32;
resources[j].adapter_ram_size = 256;
card_found = TRUE;
}
}
if(card_found)
{
resources[j].io_location = valid_locations[i];
resources[j].adapter_card_bus_type = ADAPTER_CARD_MC_BUS_TYPE;
resources[j].interrupt_number = hwi_mc_get_irq_channel(
valid_locations[i]);
resources[j].dma_channel = hwi_mc_get_dma_channel(
valid_locations[i]);
resources[j].transfer_mode = DMA_DATA_TRANSFER_MODE;
/*
* Increment j to point at the next PROBE structure.
*/
j++;
}
#ifndef FTK_NO_IO_ENABLE
macro_probe_disable_io(resources->io_location, MC_IO_RANGE);
#endif
}
return j;
}
#endif
/****************************************************************************
*
* hwi_mc_install_card
* ===================
*
*
* PARAMETERS (passed by hwi_install_adapter) :
* ============================================
*
* ADAPTER * adapter
*
* This structure is used to identify and record specific information about
* the required adapter.
*
* DOWNLOAD_IMAGE * download_image
*
* This is the code to be downloaded to the adapter. The image must be of
* the correct type i.e. must be downloadable into the adapter. If the
* pointer is 0 downloading is not done.
*
*
* BODY :
* ======
*
* The hwi_mc_install_card routine is called by hwi_install_adapter. It
* sets up the adapter card and downloads the required code to it. Firstly,
* it checks there is a valid adapter at the required IO address. If so it
* reads the node address from the BIA PROM and sets up and checks numerous
* on-board registers for correct operation.
*
* Then, it halts the EAGLE, downloads the code, restarts the EAGLE and
* waits up to 3 seconds for a valid bring-up code. If interrupts are
* required, these are enabled by operating system specific calls. There is
* no need to explicitly enable DMA. Note PIO can not be used.
*
*
* RETURNS :
* =========
*
* The routine returns TRUE if it succeeds. If this routine fails (returns
* FALSE) then a subsequent call to driver_explain_error, with the adapter
* handle corresponding to the adapter parameter used here, will give an
* explanation.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_mc_install_card)
#endif
export WBOOLEAN
hwi_mc_install_card(
ADAPTER * adapter,
DOWNLOAD_IMAGE * download_image
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
WORD pos_0 = adapter->io_location +
MC_POS_REGISTER_0;
WORD pos_1 = adapter->io_location +
MC_POS_REGISTER_1;
WORD pos_2 = adapter->io_location +
MC_POS_REGISTER_2;
WORD control_0 = adapter->io_location +
MC_CONTROL_REGISTER_0;
WORD control_1 = adapter->io_location +
MC_CONTROL_REGISTER_1;
WORD control_7 = adapter->io_location +
MC_CONTROL_REGISTER_7;
WORD bia_prom = adapter->io_location +
MC_BIA_PROM;
WORD bia_prom_id = bia_prom +
BIA_PROM_ID_BYTE;
WORD bia_prom_adap = bia_prom +
BIA_PROM_ADAPTER_BYTE;
WORD bia_prom_rev = bia_prom +
BIA_PROM_REVISION_BYTE;
BYTE streaming;
BYTE fairness;
BYTE arbitration;
WBOOLEAN card_found;
WORD sif_base;
/*
* Check the IO location is valid.
*/
if(!hwi_mc_valid_io_location(adapter->io_location))
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_02_BAD_IO_LOCATION;
return FALSE;
}
/*
* Check the transfer mode is valid.
*/
if(!hwi_mc_valid_transfer_mode(adapter->transfer_mode))
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_02_BAD_IO_LOCATION;
return FALSE;
}
/*
* Check the DMA channel is valid.
*/
if(!hwi_mc_valid_dma_channel(adapter->dma_channel))
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_04_BAD_DMA_CHANNEL;
return FALSE;
}
/*
* Check the IRQ is valid.
*/
if(!hwi_mc_valid_irq_channel(adapter->interrupt_number))
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_03_BAD_INTERRUPT_NUMBER;
return FALSE;
}
/*
* Save IO locations of SIF registers.
*/
sif_base = adapter->io_location + MC_FIRST_SIF_REGISTER;
adapter->sif_dat = sif_base + EAGLE_SIFDAT;
adapter->sif_datinc = sif_base + EAGLE_SIFDAT_INC;
adapter->sif_adr = sif_base + EAGLE_SIFADR;
adapter->sif_int = sif_base + EAGLE_SIFINT;
adapter->sif_acl = sif_base + MC_EAGLE_SIFACL;
adapter->sif_adr2 = sif_base + MC_EAGLE_SIFADR_2;
adapter->sif_adx = sif_base + MC_EAGLE_SIFADX;
adapter->sif_dmalen = sif_base + MC_EAGLE_DMALEN;
adapter->io_range = MC_IO_RANGE;
#ifndef FTK_NO_IO_ENABLE
macro_enable_io(adapter);
#endif
/*
* Reset adapter (MC_CTRL1_NSRESET = 0).
*/
sys_outsb(handle, control_1, 0);
/*
* Page in the first page of BIA PROM and set MC_CTRL0_PAGE = 0
* and MC_CTRL0_SIFSEL = 0.
*/
sys_outsb(handle, control_0, 0);
/*
* Check we have a functioning adapter at the given IO location by
* checking the BIA PROM for an 'M' id byte and also by checking that
* the BIA adapter card byte is for a supported card type
* While we are doing this, we might as well record the card revision
* type, and use it to work out how much memory is on the card.
*/
card_found = FALSE;
if (sys_insb( handle, bia_prom_id) == 'M')
{
if (sys_insb( handle, bia_prom_adap) ==
BIA_PROM_TYPE_16_4_MC)
{
adapter->adapter_card_type =
ADAPTER_CARD_TYPE_16_4_MC;
adapter->adapter_card_revision =
sys_insb(handle, bia_prom_rev);
if (adapter->adapter_card_revision < 2)
{
adapter->adapter_ram_size = 128;
}
else
{
adapter->adapter_ram_size = 256;
}
card_found = TRUE;
}
else if (sys_insb(handle, bia_prom_adap) ==
BIA_PROM_TYPE_16_4_MC_32)
{
adapter->adapter_card_type =
ADAPTER_CARD_TYPE_16_4_MC_32;
adapter->adapter_card_revision =
sys_insb(handle, bia_prom_rev);
adapter->adapter_ram_size = 256;
card_found = TRUE;
}
}
/*
* If no MC card found then fill in error record and return.
*/
if (!card_found)
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
#ifndef FTK_NO_IO_ENABLE
macro_disable_io(adapter);
#endif
return FALSE;
}
/*
* Check that the adapter card is enabled. If not then fill in error
* record and return.
*/
if ((sys_insb(handle, pos_0) & MC_POS0_CDEN) == 0)
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_0D_CARD_NOT_ENABLED;
#ifndef FTK_NO_IO_ENABLE
macro_disable_io(adapter);
#endif
return FALSE;
}
/*
* Check that a speed has been selected for the card.
*/
if ((sys_insb(handle, pos_1) & MC_POS1_NOSPD) != 0)
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_0E_NO_SPEED_SELECTED;
#ifndef FTK_NO_IO_ENABLE
macro_disable_io(adapter);
#endif
return(FALSE);
}
/*
* Interrupts for MC cards are always level triggered.
*/
adapter->edge_triggered_ints = FALSE;
/*
* Card speed has been set to 4Mb/s by machine reset. Set card to 16Mb/s
* if necessary.
*/
if ((sys_insb(handle, pos_2) & MC_POS2_16N4) != 0)
{
macro_setb_bit(handle, control_1, MC_CTRL1_16N4);
}
/*
* Find the adapter card node address.
*/
hwi_mc_read_node_address(adapter);
/*
* There are no other special control registers to set up for MC cards.
*/
/*
* Wait at least 14 microseconds and bring adapter out of reset state.
* 14us is the minimum time must hold MC_CTRL1_NSRESET low.
* There are no CLKSEL issues as with ATULA cards for MC cards.
* Disable and re-enable accessing IO locations around the wait
* so the OS can reschedule this task and not effect others running.
*/
#ifndef FTK_NO_IO_ENABLE
macro_disable_io(adapter);
#endif
sys_wait_at_least_microseconds(14);
#ifndef FTK_NO_IO_ENABLE
macro_enable_io(adapter);
#endif
macro_setb_bit(handle, control_1, MC_CTRL1_NSRESET);
/*
* Media type set to STP (type 6) by machine reset on 16 4 MC
* and set to UTP (type 3) by MC_CTRL1_NSRESET on 16 4 MC 32.
* Change media type if necessary now that MC_CTRL1_NSRESET != 0.
* POS media type bit is in different place for 16/4 MC and 16/4 MC 32.
*/
if (adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_MC)
{
if ((sys_insb(handle, pos_1) & MC_POS1_STYPE6) == 0)
{
macro_setb_bit(handle, control_7, MC_CTRL7_STYPE3);
}
}
else
{
if ((sys_insb(handle, pos_1) & MC32_POS1_STYPE6) != 0)
{
macro_clearb_bit(handle, control_7, MC_CTRL7_STYPE3);
}
}
/*
* Get extended SIF registers, halt EAGLE, then get normal SIF regs.
*/
macro_setb_bit(handle, control_0, MC_CTRL0_SIFSEL);
macro_setb_bit(handle, control_1, MC_CTRL1_SRSX);
hwi_halt_eagle(adapter);
macro_clearb_bit(handle, control_1, MC_CTRL1_SRSX);
/*
* Download code to the adapter. View download image as a sequence of
* download records. Pass address of routine to set up DIO addresses
* on MC cards.
*/
if (!hwi_download_code(
adapter,
(DOWNLOAD_RECORD *) download_image,
hwi_mc_set_dio_address))
{
#ifndef FTK_NO_IO_ENABLE
macro_disable_io(adapter);
#endif
return FALSE;
}
/*
* Get extended SIF registers, start EAGLE, then get normal SIF regs.
*/
macro_setb_bit(handle, control_1, MC_CTRL1_SRSX);
hwi_start_eagle(adapter);
macro_clearb_bit(handle, control_1, MC_CTRL1_SRSX);
/*
* Wait for a valid bring up code, may wait 3 seconds.
*/
if (!hwi_get_bring_up_code(adapter))
{
return FALSE;
}
/*
* Set DIO address to point to EAGLE DATA page 0x10000L.
*/
hwi_mc_set_dio_address(
adapter,
DIO_LOCATION_EAGLE_DATA_PAGE);
/*
* Set maximum frame size from the ring speed.
*/
adapter->max_frame_size = hwi_get_max_frame_size(adapter);
/*
* Set the ring speed.
*/
adapter->ring_speed = hwi_get_ring_speed(adapter);
/* if not in polling mode then set up interrupts */
/* interrupts_on field is used when disabling interrupts for adapter */
if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
{
adapter->interrupts_on =
sys_enable_irq_channel(handle, adapter->interrupt_number);
if (!adapter->interrupts_on)
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_0B_FAIL_IRQ_ENABLE;
#ifndef FTK_NO_IO_ENABLE
macro_disable_io(adapter);
#endif
return FALSE;
}
}
else
{
adapter->interrupts_on = TRUE;
}
/*
* Enable interrupts at adapter (do this even in polling mode).
* Hence when polling still 'using' interrupt channel
* so do not use card interrupt switch setting shared by other devices.
*/
macro_setb_bit(handle, control_1, MC_CTRL1_SINTREN);
/*
* No need to explicitly set up DMA channel for MC card.
*/
/*
* Set up 16/4 MC 32 configuation information.
* This information is later placed in the TI initialization block.
* It includes streaming, fairness and aribtration level details.
*/
if (adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_MC_32)
{
/*
* Get streaming info, adjust bit position for mc32_config byte.
*/
streaming = sys_insb(handle, pos_2) & MC_POS2_STREAMING;
streaming = (BYTE)(streaming >> MC32_CONFIG_STREAMING_SHIFT);
/*
* Get fairness info, adjust bit position for mc32_config byte.
*/
fairness = sys_insb(handle, pos_2) & MC_POS2_FAIRNESS;
fairness = (BYTE)(fairness >> MC32_CONFIG_FAIRNESS_SHIFT);
/*
* Get arbitration info, adjust bit position for mc32_config byte.
*/
arbitration = sys_insb(handle, pos_0) & MC_POS0_DMAS;
arbitration = (BYTE)(arbitration >> MC32_CONFIG_DMA_SHIFT);
/*
* Record mc32_config byte.
*/
adapter->mc32_config = streaming | fairness | arbitration;
}
/*
* Return successfully.
*/
#ifndef FTK_NO_IO_ENABLE
macro_disable_io(adapter);
#endif
return(TRUE);
}
/****************************************************************************
*
* hwi_mc_interrupt_handler
* ========================
*
*
* PARAMETERS (passed by hwi_interrupt_entry) :
* ============================================
*
* ADAPTER * adapter
*
* This structure is used to identify and record specific information about
* the required adapter.
*
*
* BODY :
* ======
*
* The hwi_mc_interrupt_handler routine is called, when an interrupt
* occurs, by hwi_interrupt_entry. It checks to see if a particular card
* has interrupted. The interrupt could be generated by the SIF only.
* There are no PIO interupts on MC cards. Note it could in fact be the
* case that no interrupt has occured on the particular adapter being
* checked.
*
* On SIF interrupts, the interrupt is acknowledged and cleared. The value
* in the SIF interrupt register is recorded in order to pass it to the
* driver_interrupt_entry routine (along with the adapter details).
*
*
* RETURNS :
* =========
*
* The routine always successfully completes.
*
****************************************************************************/
#ifdef FTK_IRQ_FUNCTION
#pragma FTK_IRQ_FUNCTION(hwi_mc_interrupt_handler)
#endif
export void
hwi_mc_interrupt_handler(
ADAPTER * adapter
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
WORD control_0 = adapter->io_location +
MC_CONTROL_REGISTER_0;
WORD control_1 = adapter->io_location +
MC_CONTROL_REGISTER_1;
WORD sifint_value;
WORD sifint_tmp;
#ifndef FTK_NO_IO_ENABLE
macro_enable_io( adapter);
#endif
/*
* Check for SIF interrupt (do not get PIO interrupts on MC cards).
*/
if ((sys_insb( handle, control_0) & MC_CTRL0_SINTR) != 0)
{
/*
* SIF interrupt has occurred. This could be an SRB free, an adapter
* check or a received frame interrupt.
*/
/*
* Toggle SIF interrupt enable to acknowledge interrupt at MC card.
*/
macro_clearb_bit(handle, control_1, MC_CTRL1_SINTREN);
macro_setb_bit(handle, control_1, MC_CTRL1_SINTREN);
/*
* Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF.
*/
/*
* WARNING: Do NOT reorder the clearing of the SIFINT register with
* the reading of it. If SIFINT is cleared after reading it, any
* interrupts raised after reading it will be lost. Admittedly
* this is a small time frame, but it is important.
*/
sys_outsw(handle, adapter->sif_int, 0);
/*
* Record the EAGLE SIF interrupt register value.
*/
/*
* WARNING: Continue to read the SIFINT register until it is stable
* because of a potential problem involving the host reading the
* register after the adapter has written the low byte of it, but
* before it has written the high byte. Failure to wait for the
* SIFINT register to settle can cause spurious interrupts.
*/
sifint_value = sys_insw(handle, adapter->sif_int);
do
{
sifint_tmp = sifint_value;
sifint_value = sys_insw(
handle,
adapter->sif_int );
} while (sifint_tmp != sifint_value);
/*
* Acknowledge/clear interrupt at interrupt controller.
*/
#ifndef FTK_NO_CLEAR_IRQ
sys_clear_controller_interrupt(handle, adapter->interrupt_number);
#endif
/*
* No need regenerate any interrupts because using level sensitive.
*/
/*
* Call driver with details of SIF interrupt.
*/
driver_interrupt_entry(handle, adapter, sifint_value);
}
/*
* Let system know we have finished accessing the IO ports.
*/
#ifndef FTK_NO_IO_ENABLE
macro_disable_io( adapter);
#endif
return;
}
/****************************************************************************
*
* hwi_mc_remove_card
* ==================
*
*
* PARAMETERS (passed by hwi_remove_adapter) :
* ===========================================
*
* ADAPTER * adapter
*
* This structure is used to identify and record specific information about
* the required adapter.
*
*
* BODY :
* ======
*
* The hwi_mc_remove_card routine is called by hwi_remove_adapter. It
* disables interrupts if they are being used. It also resets the adapter.
* Note there is no need to explicitly disable DMA channels.
*
*
* RETURNS :
* =========
*
* The routine always successfully completes.
*
****************************************************************************/
#ifdef FTK_RES_FUNCTION
#pragma FTK_RES_FUNCTION(hwi_mc_remove_card)
#endif
export void
hwi_mc_remove_card(
ADAPTER * adapter
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
WORD control_1 = adapter->io_location + MC_CONTROL_REGISTER_1;
#ifndef FTK_NO_IO_ENABLE
macro_enable_io(adapter);
#endif
/*
* Disable interrupts. Only need to do this if interrupts successfully
* enabled. Interrupt must be disabled at adapter before unpatching
* interrupt. Even in polling mode we must turn off interrupts at
* adapter.
*/
if (adapter->interrupts_on)
{
macro_clearb_bit(handle, control_1, MC_CTRL1_SINTREN);
if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
{
sys_disable_irq_channel(handle, adapter->interrupt_number);
}
adapter->interrupts_on = FALSE;
}
/*
* Perform adapter reset, set MC_CTRL1_NSRESET low.
*/
sys_outsb(handle, control_1, 0);
#ifndef FTK_NO_IO_ENABLE
macro_disable_io(adapter);
#endif
}
/****************************************************************************
*
* hwi_mc_set_dio_address
* ======================
*
* The hwi_mc_set_dio_address routine is used, with MC cards, for putting a
* 32 bit DIO address into the SIF DIO address and extended DIO address
* registers. Note that the extended address register should be loaded
* first.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_mc_set_dio_address)
#endif
export void
hwi_mc_set_dio_address(
ADAPTER * adapter,
DWORD dio_address
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
WORD control_1 = adapter->io_location +
MC_CONTROL_REGISTER_1;
WORD sif_dio_adr = adapter->sif_adr;
WORD sif_dio_adrx = adapter->sif_adx;
/*
* Page in extended SIF registers.
*/
macro_setb_bit(handle, control_1, MC_CTRL1_SRSX);
/*
* Load extended DIO address register with top 16 bits of address.
* Always load extended address register first.
*/
sys_outsw(handle, sif_dio_adrx, (WORD)(dio_address >> 16));
/*
* Return to having normal SIF registers paged in.
*/
macro_clearb_bit(handle, control_1, MC_CTRL1_SRSX);
/*
* Load DIO address register with low 16 bits of address.
*/
sys_outsw(handle, sif_dio_adr, (WORD)(dio_address & 0x0000FFFF));
}
/*---------------------------------------------------------------------------
|
| LOCAL PROCEDURES
|
---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
|
| hwi_mc_read_node_address
| ========================
|
| The hwi_mc_read_node_address routine reads in the node address that is
| stored in the second page of the BIA PROM on MC cards.
|
---------------------------------------------------------------------------*/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_mc_read_node_address)
#endif
local void
hwi_mc_read_node_address(
ADAPTER * adapter
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
WORD control_0 = adapter->io_location +
MC_CONTROL_REGISTER_0;
WORD bia_prom = adapter->io_location +
MC_BIA_PROM;
WORD bia_prom_address = bia_prom + BIA_PROM_NODE_ADDRESS;
WORD index;
/*
* Page in second page of BIA PROM containing node address.
*/
macro_setb_bit(handle, control_0, MC_CTRL0_PAGE);
/*
* Read node address from BIA PROM.
*/
for (index = 0; index < 6; index++)
{
adapter->permanent_address.byte[index] =
sys_insb(handle, (WORD) (bia_prom_address + index));
}
/*
* Restore first page of BIA PROM.
*/
macro_clearb_bit(handle, control_0, MC_CTRL0_PAGE);
}
/*---------------------------------------------------------------------------
|
| hwi_mc_valid_io_location
| ========================
|
| The hwi_mc_valid_io_location routine checks to see if the user has
| supplied a valid IO location for an MC adapter card.
|
---------------------------------------------------------------------------*/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_mc_valid_io_location)
#endif
local WBOOLEAN
hwi_mc_valid_io_location(
WORD io_location
)
{
WBOOLEAN io_valid;
switch (io_location)
{
case 0x0A20 :
case 0x1A20 :
case 0x2A20 :
case 0x3A20 :
case 0x0E20 :
case 0x1E20 :
case 0x2E20 :
case 0x3E20 :
/*
* These are the valid user supplied io locations.
*/
io_valid = TRUE;
break;
default :
/*
* Anything else is invalid.
*/
io_valid = FALSE;
break;
}
return(io_valid);
}
#ifndef FTK_NO_PROBE
/*---------------------------------------------------------------------------
|
| hwi_mc_get_irq_channel
| ======================
|
| The hwi_mc_get_irq_channel routine determines the interrupt number that
| an MC card is using. It does this by looking at one of the POS
| registers. It always succeeds in finding the interrupt number being
| used.
|
---------------------------------------------------------------------------*/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_mc_get_irq_channel)
#endif
local WORD
hwi_mc_get_irq_channel(
WORD io_location
)
{
WORD pos_0 = io_location + MC_POS_REGISTER_0;
WORD irq = 0;
WORD irq_coded;
/*
* The interrupt number is encoded in two bits (7,6) in POS register 0.
*/
irq_coded = sys_probe_insb(pos_0) & MC_POS0_IRQSEL;
/*
* There are only 3 possible interrupt numbers that can be configured.
* One of these 3 cases will always be true.
*/
switch (irq_coded)
{
case MC_POS0_IRSEL_IRQ3 :
irq = 3;
break;
case MC_POS0_IRSEL_IRQ9 :
irq = 9;
break;
case MC_POS0_IRSEL_IRQ10 :
irq = 10;
break;
default :
break;
}
/*
* Return the discovered interrupt number.
*/
return(irq);
}
#endif
#ifndef FTK_NO_PROBE
/*---------------------------------------------------------------------------
|
| hwi_mc_get_dma_channel
| ======================
|
| The hwi_mc_get_dma_channel routine determines the DMA channel
| (arbitration level) that an MC card is using. It does this by looking at
| one of the POS registers. It always succeeds in finding the DMA channel
| being used.
|
---------------------------------------------------------------------------*/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_mc_get_dma_channel)
#endif
local WORD
hwi_mc_get_dma_channel(
WORD io_location
)
{
WORD pos_0 = io_location + MC_POS_REGISTER_0;
WORD dma_coded;
WORD dma;
/*
* The DMA channel is encoded in 4 bits (4,3,2,1) in POS register 0.
*/
dma_coded = sys_probe_insb(pos_0) & MC_POS0_DMAS;
/*
* In order to get the actual DMA channel, shift right by one bit.
*/
dma = dma_coded >> 1;
/*
* Return the discovered DMA channel.
*/
return(dma);
}
#endif
/*---------------------------------------------------------------------------
|
| hwi_mc_valid_irq_channel
| ========================
|
| The hwi_mc_valid_irq_channel routine checks to see if the user has
| supplied a sensible IRQ for an MC adapter card.
|
---------------------------------------------------------------------------*/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_mc_valid_irq_channel)
#endif
export WBOOLEAN
hwi_mc_valid_irq_channel(
WORD irq_channel
)
{
return (irq_channel == POLLING_INTERRUPTS_MODE ||
irq_channel == 3 ||
irq_channel == 9 ||
irq_channel == 10);
}
/*---------------------------------------------------------------------------
|
| hwi_mc_valid_dma_channel
| ========================
|
| The hwi_mc_valid_dma_channel routine checks to see if the user has
| supplied a sensible dma channel for an MC adapter card.
|
---------------------------------------------------------------------------*/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_mc_valid_dma_channel)
#endif
export WBOOLEAN
hwi_mc_valid_dma_channel(
WORD dma_channel
)
{
return (dma_channel <= 14);
}
/*---------------------------------------------------------------------------
|
| hwi_mc_valid_transfer_mode
| ============================
|
| The hwi_mc_valid_transfer_mode routine checks to see if the user has
| supplied a sensible transfer mode for an MC adapter card. That means DMA
| at the moment.
|
---------------------------------------------------------------------------*/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_mc_valid_transfer_mode)
#endif
export WBOOLEAN
hwi_mc_valid_transfer_mode(
UINT transfer_mode
)
{
return (transfer_mode == DMA_DATA_TRANSFER_MODE);
}
#endif
/******** End of HWI_MC.C **************************************************/