Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2077 lines
73 KiB

/****************************************************************************
*
* HWI_GEN.C : Part of the FASTMAC TOOL-KIT (FTK)
*
* THE GENERAL HARDWARE INTERFACE MODULE
*
* 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_GEN.C module contains the general routines necessary to install
* an adapter, to initialize an adapter, to remove an adapter and to handle
* interrupts on an adapter. It does not contain the routines specific to a
* particular card type involved in any of these processes. These are in
* the relevant HWI_<card_type>.C modules.
*
****************************************************************************/
/*---------------------------------------------------------------------------
|
| 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 */
/*---------------------------------------------------------------------------
|
| GLOBAL VARIABLES
|
---------------------------------------------------------------------------*/
local BYTE scb_test_pattern[] = SCB_TEST_PATTERN_DATA;
local BYTE ssb_test_pattern[] = SSB_TEST_PATTERN_DATA;
/*---------------------------------------------------------------------------
|
| LOCAL PROCEDURES
|
---------------------------------------------------------------------------*/
local void
hwi_copy_to_dio_space(
ADAPTER * adapter,
DWORD dio_location,
BYTE * download_data,
WORD data_length_bytes
);
local WBOOLEAN
hwi_get_init_code(
ADAPTER * adapter
);
#ifndef FTK_NO_PROBE
/****************************************************************************
*
* hwi_deprobe_adapter
* ===================
*
*
* PARAMETERS :
* ============
*
* PROBE * probe_values
*
* This structure identifies cards that have been probed.
*
* UINT length
*
* The length of the above array.
*
* BODY :
* ======
*
* The hwi_deprobe_adapter routine uses the card bus type to call the
* correct hwi_<card_type>_deprobe_card routine.
*
*
* RETURNS :
* =========
*
* The routine returns TRUE if it succeeds.
*
****************************************************************************/
#ifdef FTK_RES_FUNCTION
#pragma FTK_RES_FUNCTION(hwi_deprobe_adapter)
#endif
export WBOOLEAN
hwi_deprobe_adapter(
PROBE * resources,
UINT length
)
{
WBOOLEAN success = TRUE;
UINT i;
for(i = 0; i < length; i++)
{
switch(resources[i].adapter_card_bus_type)
{
/*
* As it stands the only adapter that needs to be deprobed is a
* PCMCIA, since it has to deregister with card services.
*/
#ifndef FTK_NO_PCMCIA
case ADAPTER_CARD_PCMCIA_BUS_TYPE :
success = success && hwi_pcmcia_deprobe_card(resources[i]);
break;
#endif
default :
break;
}
}
return(success);
}
/****************************************************************************
*
* hwi_probe_adapter
* =================
*
*
* PARAMETERS (passed by driver_probe_adapter) :
* =============================================
*
* WORD adapter_card_bus_type
*
* the bus type of the card, so we can switch to the correct hwi module.
*
* 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.
*
* UINT number_locations
*
* This is the number of IO locations in the above list.
*
* BODY :
* ======
*
* The hwi_probe_adapter routine is called by driver_probe_adapter. It
* switches to a hwi_<card type>_probe_card routine which does the work.
*
*
* RETURNS :
* =========
*
* The routine returns the value returned from below.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_probe_adapter)
#endif
export UINT
hwi_probe_adapter(
WORD adapter_card_bus_type,
PROBE * resources,
UINT length,
WORD * valid_locations,
UINT number_locations
)
{
UINT number_found;
UINT i;
/*
* Mark all resource entries as undefined to start off with.
*/
for (i = 0; i < length; i++)
{
resources[i].socket = FTK_UNDEFINED;
resources[i].adapter_card_bus_type = FTK_UNDEFINED;
resources[i].adapter_card_type = FTK_UNDEFINED;
resources[i].adapter_card_revision = FTK_UNDEFINED;
resources[i].adapter_ram_size = FTK_UNDEFINED;
resources[i].io_location = FTK_UNDEFINED;
resources[i].interrupt_number = FTK_UNDEFINED;
resources[i].dma_channel = FTK_UNDEFINED;
resources[i].transfer_mode = FTK_UNDEFINED;
resources[i].mmio_base_address = FTK_UNDEFINED;
}
/*
* And call the appropriate probe routine.
*/
switch(adapter_card_bus_type)
{
#ifndef FTK_NO_ATULA
case ADAPTER_CARD_ATULA_BUS_TYPE :
number_found = hwi_atula_probe_card(resources,
length,
valid_locations,
number_locations);
break;
#endif
#ifndef FTK_NO_PNP
case ADAPTER_CARD_PNP_BUS_TYPE :
number_found = hwi_pnp_probe_card(resources,
length,
valid_locations,
number_locations);
break;
#endif
#ifndef FTK_NO_MC
case ADAPTER_CARD_MC_BUS_TYPE :
number_found = hwi_mc_probe_card(resources,
length,
valid_locations,
number_locations);
break;
#endif
#ifndef FTK_NO_EISA
case ADAPTER_CARD_EISA_BUS_TYPE :
number_found = hwi_eisa_probe_card(resources,
length,
valid_locations,
number_locations);
break;
#endif
#ifndef FTK_NO_SMART16
case ADAPTER_CARD_SMART16_BUS_TYPE :
number_found = hwi_smart16_probe_card(resources,
length,
valid_locations,
number_locations);
break;
#endif
#ifndef FTK_NO_PCI
case ADAPTER_CARD_PCI_BUS_TYPE :
number_found = hwi_pci_probe_card(resources,
length,
valid_locations,
number_locations);
break;
#endif
#ifndef FTK_NO_PCMCIA
case ADAPTER_CARD_PCMCIA_BUS_TYPE :
number_found = hwi_pcmcia_probe_card(resources,
length,
valid_locations,
number_locations);
break;
#endif
#ifndef FTK_NO_PCI_TI
case ADAPTER_CARD_TI_PCI_BUS_TYPE :
number_found = hwi_pcit_probe_card(resources,
length,
valid_locations,
number_locations);
break;
#endif
#ifndef FTK_NO_PCI2
case ADAPTER_CARD_PCI2_BUS_TYPE :
number_found = hwi_pci2_probe_card(resources,
length,
valid_locations,
number_locations);
break;
#endif
default :
/*
* Bad adapter card bus type so fail.
*/
number_found = 0;
break;
}
return number_found;
}
#endif
#ifndef FTK_NO_DETECT
/****************************************************************************
*
* hwi_read_rate_error
* ===================
*
*
* PARAMETERS (passed by driver_probe_adapter) :
* =============================================
*
* ADAPTER * adapter
*
* The adapter structure
*
*
* BODY :
* ======
*
* The hwi_read_rate_error switches to a hwi_<card type>_read_rate_error
* which reads the rate error bit of the C30. Normally this is visible in
* the IO space of the bus interface chip, except for the AT space when we
* read it through DIO.
*
* RETURNS :
* =========
*
* The routine returns TRUE if there was a rate error.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_read_rate_error)
#endif
export WORD
hwi_read_rate_error(
ADAPTER * adapter
)
{
WBOOLEAN wrong_speed = FALSE;
switch (adapter->adapter_card_bus_type)
{
#ifndef FTK_NO_ATULA
case ADAPTER_CARD_ATULA_BUS_TYPE :
wrong_speed = hwi_atula_read_rate_error(
adapter);
break;
#endif
default:
{
wrong_speed = NOT_SUPP;
break;
}
}
return wrong_speed;
}
#endif /* FTK_NO_DETECT */
/****************************************************************************
*
* hwi_install_adapter
* ===================
*
*
* PARAMETERS :
* ============
*
* 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_install_adapter routine uses the card bus type to call the
* correct hwi_<card_type>_install_card routine.
*
*
* 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_install_adapter)
#endif
export WBOOLEAN
hwi_install_adapter(
ADAPTER * adapter,
DOWNLOAD_IMAGE * download_image
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
WBOOLEAN install_success;
/*
* Record fact that adapter does not have interrupts or DMA enabled.
*/
adapter->interrupts_on = FALSE;
adapter->dma_on = FALSE;
/*
* Cards do not support speed detect unless they have a C30.
*/
adapter->speed_detect = FALSE;
/*
* Call correct install routine dependent on adapter card bus type.
*/
switch (adapter->adapter_card_bus_type)
{
#ifndef FTK_NO_ATULA
case ADAPTER_CARD_ATULA_BUS_TYPE :
/*
* Set up pointers to the functions we will need later.
*/
adapter->interrupt_handler = hwi_atula_interrupt_handler;
adapter->remove_card = hwi_atula_remove_card;
adapter->set_dio_address = hwi_atula_set_dio_address;
/*
* Call the install routine.
*/
install_success = hwi_atula_install_card(
adapter,
download_image);
break;
#endif
#ifndef FTK_NO_PNP
case ADAPTER_CARD_PNP_BUS_TYPE :
/*
* Set up pointers to the functions we will need later.
*/
adapter->interrupt_handler = hwi_pnp_interrupt_handler;
adapter->remove_card = hwi_pnp_remove_card;
adapter->set_dio_address = hwi_pnp_set_dio_address;
/*
* Call the install routine.
*/
install_success = hwi_pnp_install_card(
adapter,
download_image);
break;
#endif
#ifndef FTK_NO_MC
case ADAPTER_CARD_MC_BUS_TYPE :
adapter->interrupt_handler = hwi_mc_interrupt_handler;
adapter->remove_card = hwi_mc_remove_card;
adapter->set_dio_address = hwi_mc_set_dio_address;
install_success = hwi_mc_install_card(
adapter,
download_image);
break;
#endif
#ifndef FTK_NO_EISA
case ADAPTER_CARD_EISA_BUS_TYPE :
adapter->interrupt_handler = hwi_eisa_interrupt_handler;
adapter->remove_card = hwi_eisa_remove_card;
adapter->set_dio_address = hwi_eisa_set_dio_address;
install_success = hwi_eisa_install_card(
adapter,
download_image);
break;
#endif
#ifndef FTK_NO_SMART16
case ADAPTER_CARD_SMART16_BUS_TYPE :
adapter->interrupt_handler = hwi_smart16_interrupt_handler;
adapter->remove_card = hwi_smart16_remove_card;
adapter->set_dio_address = hwi_smart16_set_dio_address;
install_success = hwi_smart16_install_card(
adapter,
download_image);
break;
#endif
#ifndef FTK_NO_PCI
case ADAPTER_CARD_PCI_BUS_TYPE :
adapter->interrupt_handler = hwi_pci_interrupt_handler;
adapter->remove_card = hwi_pci_remove_card;
adapter->set_dio_address = hwi_pci_set_dio_address;
install_success = hwi_pci_install_card(
adapter,
download_image);
break;
#endif
#ifndef FTK_NO_PCMCIA
case ADAPTER_CARD_PCMCIA_BUS_TYPE :
adapter->interrupt_handler = hwi_pcmcia_interrupt_handler;
adapter->remove_card = hwi_pcmcia_remove_card;
adapter->set_dio_address = hwi_pcmcia_set_dio_address;
install_success = hwi_pcmcia_install_card(adapter, download_image);
break;
#endif
#ifndef FTK_NO_PCIT
case ADAPTER_CARD_TI_PCI_BUS_TYPE :
adapter->interrupt_handler = hwi_pcit_interrupt_handler;
adapter->remove_card = hwi_pcit_remove_card;
adapter->set_dio_address = hwi_pcit_set_dio_address;
install_success = hwi_pcit_install_card(
adapter,
download_image);
break;
#endif
#ifndef FTK_NO_PCI2
case ADAPTER_CARD_PCI2_BUS_TYPE :
adapter->interrupt_handler = hwi_pci2_interrupt_handler;
adapter->remove_card = hwi_pci2_remove_card;
adapter->set_dio_address = hwi_pci2_set_dio_address;
install_success = hwi_pci2_install_card(
adapter,
download_image);
break;
#endif
default :
/*
* Bad adapter card bus type so fail.
*/
install_success = FALSE;
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_01_BAD_CARD_BUS_TYPE;
break;
}
return install_success;
}
/****************************************************************************
*
* hwi_initialize_adapter
* ======================
*
*
* PARAMETERS :
* ============
*
* ADAPTER * adapter
*
* This structure is used to identify and record specific information about
* the required adapter.
*
* INITIALIZATION_BLOCK * init_block
*
* This is the initialization block that is to be copied into DIO space
* before performing the actual chipset initialization.
*
*
* BODY :
* ======
*
* The hwi_initialize_adapter routine performs the initialization of the
* chipset. It sets up the TI initialization block and the general MAC
* level smart software initialization parameters and copies these into DIO
* space at 0x10A00 on the EAGLE. These are followed in DIO space by the
* Fastmac module specific initialization block details. The
* initialization is started and then the routine waits up to 11 seconds
* for success or failure to be registered by the SIF interrupt register.
* The DMAs that occur during initialization are also checked for success.
* Note these DMAs may actually be done by PIO transfers by the HWI itself
* for ATULA cards.
*
* During downloading BYTE fields in structures need to be swapped and
* DWORDs need to have the UINTs within swapped around. This is because of
* the low-high byte ordering on Intel machines and the high-low ordering
* of the EAGLE and the byte swapping that automatically occurs when
* downloading through the SIF. Note that the automatic byte swapping
* means UINTs do not themselves need any special treatment.
*
*
* 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.
*
* On success we also exit with 0x0001 in the EAGLE_SIDADRX register.
* This should never need to be altered by any user. This means for example
* that the FTK driver need only interest itself in the non-extended SIF
* registers.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_initialize_adapter)
#endif
#if 1
sys_int53( void);
#endif
export WBOOLEAN
hwi_initialize_adapter(
ADAPTER * adapter,
INITIALIZATION_BLOCK * init_block
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
FASTMAC_INIT_PARMS * fastmac_parms = &init_block->fastmac_parms;
WBOOLEAN init_success;
UINT i;
BYTE FAR * dma_test_scb_buff;
BYTE FAR * dma_test_ssb_buff;
DWORD dma_test_scb_phys;
DWORD dma_test_ssb_phys;
#ifdef FMPLUS
WORD fmplus_buffer_size;
DWORD fmplus_max_buffmem;
WORD fmplus_max_buffers;
#endif
/*
* Set up the TI initialization parameters. Those fields not set up here
* must be zero. Set up for burst DMA.
*/
init_block->ti_parms.init_options = TI_INIT_OPTIONS_BURST_DMA;
/*
* Copy in 16/4 MC 32 configuration information. This data is zero for
* non-16/4 MC 32 cards.
*/
init_block->ti_parms.madge_mc32_config = adapter->mc32_config;
/*
* Set up retry counts.
*/
init_block->ti_parms.parity_retry = TI_INIT_RETRY_DEFAULT;
init_block->ti_parms.dma_retry = TI_INIT_RETRY_DEFAULT;
/*
* NB It is not safe to use the Fastmac receive buffer for the DMA test
* because if auto-open is used, a frame could be received before we
* have a chance to test the contents of this memory. So put both SSB
* and SCB in the Tx buffer.
*/
#ifdef FMPLUS
/*
* FMPlus does not have a transmit buffer it can use for the test DMAs,
* so we use a buffer previously allocated in the drv_init module.
*/
dma_test_scb_buff = (BYTE FAR *) adapter->dma_test_buf_virt;
dma_test_scb_phys = adapter->dma_test_buf_phys;
dma_test_ssb_phys = dma_test_scb_phys + SCB_TEST_PATTERN_LENGTH;
dma_test_ssb_buff = dma_test_scb_buff + SCB_TEST_PATTERN_LENGTH;
#else
/*
* For Fastmac, we use the transmit buffer for the test DMAs.
*/
dma_test_scb_buff = (BYTE FAR *) adapter->tx_buffer_virt;
dma_test_scb_phys = adapter->tx_buffer_phys;
dma_test_ssb_phys = dma_test_scb_phys + SCB_TEST_PATTERN_LENGTH;
dma_test_ssb_buff = dma_test_scb_buff + SCB_TEST_PATTERN_LENGTH;
if (adapter->transfer_mode != DMA_DATA_TRANSFER_MODE)
{
fastmac_parms->tx_buf_physaddr = adapter->tx_buffer_virt;
fastmac_parms->rx_buf_physaddr = adapter->rx_buffer_virt;
}
#endif
if (adapter->transfer_mode != DMA_DATA_TRANSFER_MODE)
{
/*
* PIO uses virtual addresses to save having to perform Phys-to-Virt
* conversions in the interrupt service routine.
*/
init_block->ti_parms.scb_addr = (DWORD)dma_test_scb_buff;
init_block->ti_parms.ssb_addr = (DWORD)dma_test_ssb_buff;
}
else
{
/*
* DMA must use physical addresses, however. We already have these
* saved.
*/
init_block->ti_parms.scb_addr = dma_test_scb_phys;
init_block->ti_parms.ssb_addr = dma_test_ssb_phys;
}
macro_word_swap_dword(init_block->ti_parms.scb_addr);
macro_word_swap_dword(init_block->ti_parms.ssb_addr);
#if 0
/*
* TMSDebug support
*/
printf("\nTMSDebug Enabled\n");
init_block->smart_parms.reserved_1 = 3;
sys_int53();
#endif
/*
* Set up the smart software initialization parameters. Those fields
* not set up here must be zero.
* Set up header to identify the smart software initialization parms.
*/
init_block->smart_parms.header.length = sizeof(SMART_INIT_PARMS);
init_block->smart_parms.header.signature = SMART_INIT_HEADER_SIGNATURE;
init_block->smart_parms.header.version = SMART_INIT_HEADER_VERSION;
/*
* Byte swap the permanent node address when setting it up.
*/
init_block->smart_parms.permanent_address = adapter->permanent_address;
util_byte_swap_structure(
(BYTE *) &init_block->smart_parms.permanent_address,
sizeof(NODE_ADDRESS));
#ifdef FMPLUS
/*
* Must set min_buffer_ram field for backwards compatibility with other
* Madge code (see FMPlus programming spec.)
*/
init_block->smart_parms.min_buffer_ram = SMART_INIT_MIN_RAM_DEFAULT;
#endif
/*
* Need to byte swap fields in the Fastmac specific init parms.
* These fields are the opening node address and the buffer addresses.
*/
util_byte_swap_structure(
(BYTE *)&fastmac_parms->open_address,
sizeof(NODE_ADDRESS));
#ifdef FMPLUS
/*
* Now work out the number of transmit and receive buffers.
* The number of buffers allocated depends on the maximum frame size
* anticipated, and on the amount of memory on the card. Unfortunately,
* one cannot know the maximum possible frame size until after the mac
* code has started and worked out what the ring speed is. Thus it is
* necessary to make an assumption about what the largest frame size
* supported will be.
*/
/*
* First, work out how big the buffers are. Unless a different size has
* been specified, use the default buffer size.
*/
fmplus_buffer_size = init_block->smart_parms.rx_tx_buffer_size;
/*
* MC32, EISA and PCIx cards use a smaller default buffer size than other
* cards do (16/4 AT and 16/4 MC cards).
*/
if (adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_EISA ||
adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_MC_32 ||
adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_PCI ||
adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_PCIT ||
adapter->adapter_card_type == ADAPTER_CARD_TYPE_16_4_PCI2)
{
if (fmplus_buffer_size)
{
fmplus_buffer_size =
max(FMPLUS_MIN_TXRX_BUFF_SIZE,
min(FMPLUS_DEFAULT_BUFF_SIZE_SMALL, fmplus_buffer_size)
);
}
else
{
fmplus_buffer_size = FMPLUS_DEFAULT_BUFF_SIZE_SMALL;
}
}
else
{
if (fmplus_buffer_size)
{
fmplus_buffer_size =
max(FMPLUS_MIN_TXRX_BUFF_SIZE, fmplus_buffer_size);
}
else
{
fmplus_buffer_size = FMPLUS_DEFAULT_BUFF_SIZE_LARGE;
}
}
init_block->smart_parms.rx_tx_buffer_size = fmplus_buffer_size;
if (fmplus_buffer_size < FMPLUS_MIN_TXRX_BUFF_SIZE)
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_10_BAD_TX_RX_BUFF_SIZE;
return FALSE;
}
/*
* Next, work out how much memory on the card we can use for buffers.
*/
if (adapter->adapter_ram_size == 128)
{
fmplus_max_buffmem = FMPLUS_MAX_BUFFMEM_IN_128K;
}
else if (adapter->adapter_ram_size == 256)
{
fmplus_max_buffmem = FMPLUS_MAX_BUFFMEM_IN_256K;
}
else if (adapter->adapter_ram_size == 512)
{
fmplus_max_buffmem = FMPLUS_MAX_BUFFMEM_IN_512K;
}
else
{
fmplus_max_buffmem = FMPLUS_MAX_BUFFMEM_IN_128K;
}
/*
* Use the two numbers worked out above to determine the maximum number
* of buffers we can fit on the card.
* The calculation is to round the buffer size up to the nearest 1K,
* and to divide that into the total amount of memory. The rounding up
* has to take account of the eight bytes buffer header that is added
* by FMP i.e. buffer_allocation = (buffer_size + 8 + 1023) 1024
* (there is also a "fudge-factor" of 5 buffers to allow the binary to
* grow a little from its current size!)
*/
fmplus_max_buffers =
(WORD)(fmplus_max_buffmem / ((fmplus_buffer_size + 1031) & ~1023)) -
5;
/*
* Finally, allocate the buffers between transmit and receive. Notice
* that we allow here for frames as big as they are ever going to get
* on token ring. For smaller frames and 4 Mbps rings, this will just
* have the effect of improving back-to-back transmit performance.
*/
fastmac_parms->tx_bufs = 2 *
((fastmac_parms->max_frame_size +
fmplus_buffer_size) /
fmplus_buffer_size);
fastmac_parms->rx_bufs = fmplus_max_buffers -
fastmac_parms->tx_slots -
fastmac_parms->tx_bufs;
/*
* When an error occurs is a little subjective at this point. It is, in
* fact, possible to receive a frame with only about three buffers, but
* for safety's sake, we demand that there be enough to receive a max.
* sized frame.
*/
if (fastmac_parms->rx_bufs < fastmac_parms->tx_bufs)
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_11_TOO_MANY_TX_RX_BUFFS;
return (FALSE);
}
#else
macro_word_swap_dword(fastmac_parms->tx_buf_physaddr);
macro_word_swap_dword(fastmac_parms->rx_buf_physaddr);
#endif
/*
* Inform the system about the IO ports we are going to access.
*/
#ifndef FTK_NO_IO_ENABLE
macro_enable_io(adapter);
#endif
/*
* Download initialization block to required location in DIO space.
* Note routine leaves 0x0001 in EAGLE SIFADRX register.
*/
hwi_copy_to_dio_space(
adapter,
DIO_LOCATION_INIT_BLOCK,
(BYTE *) init_block,
sizeof(INITIALIZATION_BLOCK));
/*
* After downloading byte swap back some Fastmac specific init parms.
* Fields are the opening node address and the Fastmac buffer addresses.
* This is especially important to do for the buffer addresses
* because they are used in transmit/receive routines.
*/
util_byte_swap_structure(
(BYTE *)&fastmac_parms->open_address,
sizeof(NODE_ADDRESS));
#ifndef FMPLUS
macro_word_swap_dword(fastmac_parms->tx_buf_physaddr);
macro_word_swap_dword(fastmac_parms->rx_buf_physaddr);
/*
* The mainline transmit receive code assumes that these values ar
* physical addresses, so we had better convert them back... The al-
* ternative would be to rewrite all the transmit and receive modules
* to note which transfer mode is in use.
*/
if (adapter->transfer_mode != DMA_DATA_TRANSFER_MODE)
{
fastmac_parms->tx_buf_physaddr = adapter->tx_buffer_phys;
fastmac_parms->rx_buf_physaddr = adapter->rx_buffer_phys;
}
#endif
/*
* Start initialization by output 0x9080 to SIF interrupt register.
*/
sys_outsw(handle, adapter->sif_int, EAGLE_INIT_START_CODE);
/*
* Wait for a valid initialization code, may wait 11 seconds.
* During this process test DMAs need to occur, hence in PIO mode needs
* calls to hwi_interrupt_entry, hence need interrupts or polling active.
*/
init_success = hwi_get_init_code(adapter);
/*
* Let the system know we have finished accessing the IO ports.
*/
#ifndef FTK_NO_IO_ENABLE
macro_disable_io( adapter );
#endif
if (!init_success)
{
return FALSE;
}
/*
* Check that test DMAs were successful.
*/
/*
* First check SCB for correct test pattern. Remember used Fastmac
* transmit buffer address for SCB address.
*/
for (i = 0; i < SCB_TEST_PATTERN_LENGTH; i++)
{
if (dma_test_scb_buff[i] != scb_test_pattern[i])
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_07_FAILED_TEST_DMA;
return FALSE;
}
}
/*
* Now check SSB for correct test pattern. Remember used Fastmac
* receive buffer address for SSB address.
*/
for (i = 0; i < SSB_TEST_PATTERN_LENGTH; i++)
{
if (dma_test_ssb_buff[i] != ssb_test_pattern[i])
{
/* fill in error record and fail if pattern doesn't match */
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_07_FAILED_TEST_DMA;
return FALSE;
}
}
/*
* Successful completion of initialization.
*/
return TRUE;
}
/****************************************************************************
*
* hwi_get_node_address_check
* ==========================
*
*
* PARAMETERS :
* ============
*
* ADAPTER * adapter
*
* This structure is used to identify and record specific information about
* the required adapter.
*
*
* BODY :
* ======
*
* The hwi_get_node_address_check routine reads the adapter's permanent
* node address from the Fastmac status block (STB) in DIO space. It then
* checks to see if this node address is a valid Madge address. This
* checks that Fastmac is correctly installed.
*
* For ATULA and MC cards, the adapter node address has actually been read
* once already. There is no harm in getting it again, from Fastmac this
* time; (previously it was read from the BIA PROM). For EISA cards, the
* node address has not been read previously. This is the first time we can
* get it. The node address is not readable from the host with EISA cards.
* Only Fastmac can find it out for us.
*
*
* 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_get_node_address_check)
#endif
export WBOOLEAN
hwi_get_node_address_check(
ADAPTER * adapter
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
#ifndef FTK_NO_IO_ENABLE
macro_enable_io(adapter);
#endif
/*
* Get the permanent node address from the STB in DIO space.
* Record address in adapter structure.
*/
sys_outsw(
handle,
adapter->sif_adr,
(WORD)(card_t)&adapter->stb_dio_addr->permanent_address);
sys_rep_insw(
handle,
adapter->sif_datinc,
(BYTE *)&adapter->permanent_address,
(sizeof(NODE_ADDRESS) / 2));
#ifndef FTK_NO_IO_ENABLE
macro_disable_io( adapter );
#endif
/*
* Byte swap node address after reading from adapter.
*/
util_byte_swap_structure(
(BYTE *) &adapter->permanent_address,
sizeof(NODE_ADDRESS));
return TRUE;
}
/****************************************************************************
*
* hwi_interrupt_entry
* ===================
*
*
* PARAMETERS :
* ============
*
* UINT interrupt_number
*
* This is the interrupt number of the interrupting adapter card. If it is
* zero (POLLING_INTERRUPTS_MODE) then all cards must be checked to see if
* they require servicing.
*
*
* BODY :
* ======
*
* The hwi_interrupt_entry routine is either called by an operating system
* specific interrupt detection routine with an actual interrupt number as
* the parameter or, at intervals, by a routine passing the
* POLLING_INTERRUPTS_MODE parameter. In the former case all adapters using
* the given interrupt number are checked for outstanding interrupts. In
* the latter case, ALL adapters are checked for outstanding interrupts.
*
* It is important that hwi_interrupt_entry is not re-entered with a
* subsequent interrupt on the same adapter. Hence, in the polling case,
* the routine that called hwi_interrupt_entry must not call it again until
* the hwi finishes it's current execution. If real interrupts are being
* used, then care must be taken not to turn interrupts on and allow a
* further interrupt to cause hwi_interrupt_entry to be re-entered.
*
* The details of interrupt handling are dealt with by card specific
* interrupt handlers. In general, for SIF Fastmac interrupts, th
* interrupt is acknowledged at the SIF. Driver_interrupt_entry is then
* called with the interrupt number, details of the relevant adapter and
* the contents of the EAGLE_SIFINT register. If instead a PIO transfer is
* required, then the necessary data transfer is performed between the
* adapter and host memory. PIO can only occur with ATULA adapter cards.
*
*
* Note on increasing speed:
*
* One way of speeding up execution of the interrupt routine would be to
* replace the sys_outsw and sys_insw routines by similar routines supplied
* with your C compiler and have them compiled in-line. This would be
* particularly advantageous when handling PIO data transfer.
*
*
* RETURNS :
* =========
*
* This routine always completes successfully.
*
****************************************************************************/
#ifdef FTK_IRQ_FUNCTION
#pragma FTK_IRQ_FUNCTION(hwi_interrupt_entry)
#endif
export void
hwi_interrupt_entry(
ADAPTER_HANDLE adapter_handle,
WORD interrupt_number
)
{
ADAPTER * adapter;
#ifndef FTK_NO_SHARED_IRQ_POLL
for (adapter_handle = 0;
adapter_handle < MAX_NUMBER_OF_ADAPTERS;
adapter_handle++)
{
#endif
/*
* Get pointer to adapter structure.
*/
adapter = adapter_record[adapter_handle];
/*
* In polling mode check ALL adapters.
* In interrupt mode check all adapters with correct int number.
* Only check actual running, working adapters.
*/
if ((adapter != NULL) &&
(adapter->adapter_status == ADAPTER_RUNNING) &&
((interrupt_number == POLLING_INTERRUPTS_MODE) ||
(adapter->interrupt_number == interrupt_number)))
{
/*
* Interrupts are handled by adapter modules.
*/
(*(adapter->interrupt_handler))(adapter);
}
#ifndef FTK_NO_SHARED_IRQ_POLL
}
#endif
return;
}
/****************************************************************************
*
* hwi_remove_adapter
* ==================
*
*
* PARAMETERS :
* ============
*
* ADAPTER * adapter
*
* This structure is used to identify and record specific information about
* the required adapter.
*
*
* BODY :
* ======
*
* The hwi_remove_adapter routine uses the card bus type to call the
* correct hwi_<card_type>_remove_card routine.
*
*
* RETURNS :
* =========
*
* The routine always successfully completes.
*
****************************************************************************/
#ifdef FTK_RES_FUNCTION
#pragma FTK_RES_FUNCTION(hwi_remove_adapter)
#endif
export void
hwi_remove_adapter(
ADAPTER * adapter
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
/*
* Call correct remove routine.
*/
(*(adapter->remove_card))(adapter);
return;
}
/****************************************************************************
*
* UPCALL PROCEDURES - Used by hwi_<card type>.c modules
*
****************************************************************************/
/****************************************************************************
*
* hwi_halt_eagle
* ==============
*
* The hwi_halt_eagle routine halts the EAGLE. It does this by setting the
* halt EAGLE bit in the SIF adapter control register. It also resets the
* adapter by twiddling the adapter reset bit in the same register.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_halt_eagle)
#endif
export void
hwi_halt_eagle(
ADAPTER * adapter
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
WORD sif_adapter_control_register = adapter->sif_acl;
WORD acontrol_output;
/*
* Set output for SIF register EAGLE_ACONTROL.
* Maintain parity; set halt, reset, enable SIF interrupts.
*/
acontrol_output = (sys_insw(handle, sif_adapter_control_register) &
EAGLE_SIFACL_PARITY) |
EAGLE_SIFACL_ARESET |
EAGLE_SIFACL_CPHALT |
EAGLE_SIFACL_BOOT |
EAGLE_SIFACL_SINTEN |
adapter->nselout_bits;
if (adapter->EaglePsDMA)
{
acontrol_output |= EAGLE_SIFACL_PSDMAEN;
}
/*
* Wait at least 14 microseconds before putting adapter in reset state.
* We may have just taken adapter out of reset state.
* 14us is the minimum time must hold ARESET low between resets.
* Disable and re-enable accessing IO locations around wait so
* 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
/*
* Output to SIF register EAGLE_ACONTROL to halt EAGLE.
*/
sys_outsw(
handle,
sif_adapter_control_register,
acontrol_output);
/*
* Wait at least 14 microseconds before taking adapter out of reset
* state.
* 14us is the minimum time must hold ARESET low between resets.
* Disable and re-enable accessing IO locations around wait so
* 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
/*
* Bring EAGLE out of reset state, maintain halt status.
*/
sys_outsw(
handle,
sif_adapter_control_register,
(WORD) (acontrol_output & ~EAGLE_SIFACL_ARESET));
return;
}
/****************************************************************************
*
* hwi_download_code
* =================
*
* The hwi_download_code routine downloads the given data to the adapter.
* This must be done with the EAGLE halted. Besides details of the adapter
* and a pointer to the first download reocrd of the download image, the
* routine is passed a helper routine for setting DIO addresses for the
* actual downloading.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_download_code)
#endif
export WBOOLEAN
hwi_download_code(
ADAPTER * adapter,
DOWNLOAD_RECORD * download_record,
void (*set_dio_address)(ADAPTER *, DWORD)
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
WORD sif_data_inc_register = adapter->sif_datinc;
UINT i;
/*
* If there is no code to be downloaded then fail.
*/
if (download_record == NULL)
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_0A_NO_DOWNLOAD_IMAGE;
return FALSE;
}
/*
* The first record in the image must be a MODULE type record.
*/
if (download_record->type != DOWNLOAD_RECORD_TYPE_MODULE)
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_09_BAD_DOWNLOAD_IMAGE;
return FALSE;
}
/*
* The code to be downloaded must be Fastmac (Plus).
*/
if ((download_record->body.module.download_features &
DOWNLOAD_FASTMAC_INTERFACE) == 0)
{
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_09_BAD_DOWNLOAD_IMAGE;
return FALSE;
}
/*
* Get the next download record.
*/
macro_get_next_record(download_record);
/*
* Now download the data; a zero length record marks the end.
*/
while (download_record->length != 0)
{
/*
* the action depends on type of record.
*/
if (download_record->type == DOWNLOAD_RECORD_TYPE_DATA_32)
{
/*
* Set DIO address for downloading data to in SIF registers.
*/
(*set_dio_address)(
adapter,
download_record->body.data_32.dio_addr);
/*
* Download data.
*/
for (i = 0; i < download_record->body.data_32.word_count; i++)
{
sys_outsw(
handle,
sif_data_inc_register,
download_record->body.data_32.data[i]);
}
/*
* Check download worked by reading back and comparing.
*/
(*set_dio_address)(
adapter,
download_record->body.data_32.dio_addr);
for (i = 0; i < download_record->body.data_32.word_count; i++)
{
if (sys_insw(handle, sif_data_inc_register) !=
download_record->body.data_32.data[i])
{
/*
* Fill in error record if read back not correct.
*/
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_08_BAD_DOWNLOAD;
return FALSE;
}
}
}
else if (download_record->type == DOWNLOAD_RECORD_TYPE_FILL_32)
{
/*
* Set DIO address for downloading to in SIF registers.
*/
(*set_dio_address)(
adapter,
download_record->body.fill_32.dio_addr);
/*
* Fill EAGLE memory with required pattern.
*/
for (i = 0; i < download_record->body.fill_32.word_count; i++)
{
sys_outsw(
handle,
sif_data_inc_register,
download_record->body.fill_32.pattern);
}
/*
* Check download worked by reading back and comparing.
*/
(*set_dio_address)(
adapter,
download_record->body.fill_32.dio_addr);
for (i = 0; i < download_record->body.fill_32.word_count; i++)
{
WORD x;
if ((x = sys_insw(handle, sif_data_inc_register)) !=
download_record->body.fill_32.pattern)
{
/*
* Fill in error record if read back not correct.
*/
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_08_BAD_DOWNLOAD;
return FALSE;
}
}
}
else
{
/*
* Can only have DATA and FILL records after first MODULE.
*/
adapter->error_record.type = ERROR_TYPE_HWI;
adapter->error_record.value = HWI_E_09_BAD_DOWNLOAD_IMAGE;
return FALSE;
}
/*
* Get the next download record.
*/
macro_get_next_record(download_record);
}
/*
* Successful downloading complete.
*/
return TRUE;
}
/****************************************************************************
*
* hwi_start_eagle
* ===============
*
* The hwi_start_eagle routine takes the EAGLE out of the halt state it is
* in.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_start_eagle)
#endif
export void
hwi_start_eagle(
ADAPTER * adapter
)
{
WORD sif_adapter_control_register = adapter->sif_acl;
/*
* Only change the halt status in the SIF register EAGLE_ACONTROL.
*/
sys_outsw(
adapter->adapter_handle,
sif_adapter_control_register,
(WORD) (sys_insw(
adapter->adapter_handle,
sif_adapter_control_register) & ~EAGLE_SIFACL_CPHALT));
}
/****************************************************************************
*
* hwi_get_bring_up_code
* =====================
*
* The hwi_get_bring_up_code routine waits for at least 15 seconds for a
* valid bring up code to appear in the SIF interrupt register. If bring up
* fails then this routine will retry up to 10 times. If even this fails,
* then an error record is filled in.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_get_bring_up_code)
#endif
export WBOOLEAN
hwi_get_bring_up_code(
ADAPTER * adapter
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
WORD sif_interrupt_register = adapter->sif_int;
UINT index;
BYTE bring_up_code;
BYTE bring_up_error;
UINT retry;
/*
* We'll retry 10 times and if we don't get any other error we'll
* return a timeout.
*/
retry = 10;
bring_up_error = BRING_UP_E_10_TIME_OUT;
do
{
retry--;
for (index = 0; index < 60; index++)
{
/*
* No bring up code available yet. Wait at least a quarter of a
* second before trying again. Disable and re-enable accessing IO
* locations around wait so delay can reschedule this task and not
* effect others running.
*/
#ifndef FTK_NO_IO_ENABLE
macro_disable_io( adapter );
#endif
sys_wait_at_least_milliseconds(250);
#ifndef FTK_NO_IO_ENABLE
macro_enable_io( adapter );
#endif
/*
* Get bring up code from SIFSTS register.
*/
bring_up_code = sys_insb(handle, sif_interrupt_register);
/*
* Check for successful bring up in top nibble of SIFSTS register.
* Success is shown by INITIALIZE bit being set.
*/
if ((bring_up_code & EAGLE_BRING_UP_TOP_NIBBLE) ==
EAGLE_BRING_UP_SUCCESS)
{
return TRUE;
}
/*
* Check for failed bring up in top nibble of SIFSTS register.
* Failure is shown by the TEST and ERROR bits being set.
*/
if ((bring_up_code & EAGLE_BRING_UP_TOP_NIBBLE) ==
EAGLE_BRING_UP_FAILURE)
{
/*
* Get actual bring up error code from bottom nibble of
* SIFSTS.
*/
bring_up_error = bring_up_code & EAGLE_BRING_UP_BOTTOM_NIBBLE;
break;
}
}
/*
* We have failed to do a bring up, if retry hasn't reached
* zero yet then write 0xff00 to SIFINT to reset the Eagle
* and start bring up again.
*/
if (retry > 0)
{
sys_outsw(handle, sif_interrupt_register, (WORD) 0xff00);
}
}
while (retry > 0);
/*
* We have completely failed bring up so return an error.
*/
adapter->error_record.type = ERROR_TYPE_BRING_UP;
adapter->error_record.value = bring_up_error;
return FALSE;
}
/****************************************************************************
*
* hwi_get_max_frame_size
* ======================
*
* The hwi_get_max_frame_size routine uses the ring speed register in DIO
* space to find the ring speed and hence the maximum allowable frame size
* set by the ISO standard.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_get_max_frame_size)
#endif
export WORD
hwi_get_max_frame_size(
ADAPTER * adapter
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
WORD sif_dio_address_register = adapter->sif_adr;
WORD sif_dio_data_register = adapter->sif_dat;
/*
* Set DIO address register to point to ring speed register.
* Note that SIFADRX already equals 0x0001 (for DATA page at 0x10000).
*/
sys_outsw(
handle,
sif_dio_address_register,
DIO_LOCATION_RING_SPEED_REG);
/*
* Use the contents of the ring speed register to determine ring speed.
*/
if (sys_insw(handle, sif_dio_data_register) & RING_SPEED_REG_4_MBITS_MASK)
{
return MAX_FRAME_SIZE_4_MBITS;
}
else
{
return MAX_FRAME_SIZE_16_MBITS;
}
}
/****************************************************************************
*
* hwi_get_ring_speed
* ==================
*
* The hwi_get_ring_speed routine uses the ring speed register in DIO
* space to find the ring speed.
*
****************************************************************************/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_get_ring_speed)
#endif
export UINT
hwi_get_ring_speed(
ADAPTER * adapter
)
{
WORD sif_dio_address_register = adapter->sif_adr;
WORD sif_dio_data_register = adapter->sif_dat;
ADAPTER_HANDLE hnd = adapter->adapter_handle;
/*
* Set DIO address register to point to ring speed register.
* Note that SIFADRX already equals 0x0001 (for DATA page at 0x10000).
*/
sys_outsw(
hnd,
sif_dio_address_register,
DIO_LOCATION_RING_SPEED_REG);
/*
* Use the contents of the ring speed register to determine ring speed.
*/
if (sys_insw(hnd, sif_dio_data_register) & RING_SPEED_REG_4_MBITS_MASK)
{
return 4;
}
else
{
return 16;
}
}
/*---------------------------------------------------------------------------
|
| LOCAL PROCEDURES
|
---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
|
| hwi_copy_to_dio_space
| =====================
|
| The hwi_copy_to_dio_space routine copies the given amount of data into
| DIO space at the specified location. The method of setting up the SIF
| DIO address registers depends on the type of adapter card.
|
---------------------------------------------------------------------------*/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_copy_to_dio_space)
#endif
local void
hwi_copy_to_dio_space(
ADAPTER * adapter,
DWORD dio_location,
BYTE * download_data,
WORD data_length_bytes
)
{
ADAPTER_HANDLE handle = adapter->adapter_handle;
/*
* Set up DIO address in SIF DIO address registers.
* This needs to be done differently depending on adapter card type.
*/
(*(adapter->set_dio_address))(adapter, dio_location);
/*
* Copy data into DIO space.
*/
sys_rep_outsw(
handle,
adapter->sif_datinc,
download_data,
(WORD) (data_length_bytes / 2));
if (data_length_bytes & 1)
{
/*
* Byte out instructions do not work on the Ti PCI card,
* as it is not definate whether we ship this card, the fix
* shall stay here for now. PRR
*/
if (adapter->adapter_card_type != ADAPTER_CARD_TYPE_16_4_PCIT)
{
sys_outsb(
handle,
adapter->sif_datinc,
*(download_data + data_length_bytes - 1));
}
#ifndef FTK_NO_PCIT
else
{
WORD last_byte;
last_byte = *(download_data + data_length_bytes - 1);
last_byte <<= 8;
last_byte &= 0xFF00;
sys_outsw(
handle,
adapter->sif_datinc,
last_byte);
}
#endif
}
return;
}
/*---------------------------------------------------------------------------
|
| hwi_read_sifint
| ===============
|
| Read the SIFINT register. This function is called via
Ý sys_sych_with_interruptto avoid DMA/SIF problems on PciT adapters.
Ý
---------------------------------------------------------------------------*/
local WBOOLEAN
hwi_read_sifint(
void * ptr
);
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_read_sifint)
#endif
local WBOOLEAN
hwi_read_sifint(
void * ptr
)
{
ADAPTER * adapter = (ADAPTER *) ptr;
return sys_insb(adapter->adapter_handle, adapter->sif_int);
}
/*---------------------------------------------------------------------------
|
| hwi_get_init_code
| =================
|
| The hwi_get_init_code routine waits for at least 11 seconds for a valid
| initialization code to appear in the SIF interrupt register. If
| initialization fails then this routine fills in the adapter error
| record.
|
---------------------------------------------------------------------------*/
#ifdef FTK_INIT_FUNCTION
#pragma FTK_INIT_FUNCTION(hwi_get_init_code)
#endif
local WBOOLEAN
hwi_get_init_code(
ADAPTER * adapter
)
{
UINT index;
BYTE init_code;
for (index = 0; index < 100; index++)
{
/*
* Get initialization code from SIFSTS register.
*/
init_code = (BYTE) sys_sync_with_interrupt(
adapter->adapter_handle,
hwi_read_sifint,
(void *) adapter
);
/*
* Check for successful initialization in top nibble of SIFSTS.
* Success is shown by INITIALIZE, TEST and ERROR bits being zero.
*/
if ((init_code & EAGLE_INIT_SUCCESS_MASK) == 0)
{
return TRUE;
}
/*
* Check for failed initialization in top nibble of SIFSTS.
* Failure is shown by the ERROR bit being set.
*/
if ((init_code & EAGLE_INIT_FAILURE_MASK) != 0)
{
/*
* Get actual init error code from bottom nibble of SIFSTS
*/
init_code = init_code & EAGLE_INIT_BOTTOM_NIBBLE;
/*
* Fill in error record with actual initialization error code.
*/
adapter->error_record.type = ERROR_TYPE_INIT;
adapter->error_record.value = init_code;
return FALSE;
}
/*
* No initialization code available yet. Wait at least a quarter of
* a second before trying again. Disable and re-enable accessing IO
* locations around wait so OS can reschedule this task and not
* effect others running.
*/
#ifndef FTK_NO_IO_ENABLE
macro_disable_io( adapter );
#endif
sys_wait_at_least_milliseconds(250);
#ifndef FTK_NO_IO_ENABLE
macro_enable_io( adapter );
#endif
}
/*
* At least 11 seconds have gone so return time out failure.
*/
adapter->error_record.type = ERROR_TYPE_INIT;
adapter->error_record.value = INIT_E_10_TIME_OUT;
return FALSE;
}
/******* End of HWI_GEN.C **************************************************/