diff options
Diffstat (limited to 'private/ntos/ndis/madge/driver/hwi_at.c')
-rw-r--r-- | private/ntos/ndis/madge/driver/hwi_at.c | 2206 |
1 files changed, 2206 insertions, 0 deletions
diff --git a/private/ntos/ndis/madge/driver/hwi_at.c b/private/ntos/ndis/madge/driver/hwi_at.c new file mode 100644 index 000000000..fa9ed25dc --- /dev/null +++ b/private/ntos/ndis/madge/driver/hwi_at.c @@ -0,0 +1,2206 @@ +/**************************************************************************** +* +* HWI_AT.C : Part of the FASTMAC TOOL-KIT (FTK) +* +* HARDWARE INTERFACE MODULE FOR ATULA 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_AT.C module contains the routines specific to 16/4 PC and 16/4 +* AT 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_ATULA + +/*--------------------------------------------------------------------------- +| +| LOCAL PROCEDURES +| +---------------------------------------------------------------------------*/ + +local void +hwi_atula_read_node_address( + ADAPTER * adapter + ); + +local WBOOLEAN +hwi_atula_valid_io_location( + WORD io_location + ); + +#ifndef FTK_NO_PROBE + +local WORD +hwi_atula_get_irq_channel( + WORD io_location, + UINT adapter_revision + ); + +local WORD +hwi_atula_get_dma_channel( + WORD io_location, + UINT adapter_revsion + ); + +#endif + +local WORD +hwi_atula_valid_transfer_mode( + ADAPTER * adapter + ); + +local WORD +hwi_atula_valid_irq_channel( + ADAPTER * adapter + ); + +local WORD +hwi_atula_valid_dma_channel( + ADAPTER * adapter + ); + +/*--------------------------------------------------------------------------- +| +| LOCAL VARIABLES +| +---------------------------------------------------------------------------*/ + +local BYTE atp_irq_select_table[16] = +{ + 0xff, /* 0 Unused */ + 0xff, /* 1 Unused */ + 0x07, /* 2 */ + 0x06, /* 3 */ + 0xff, /* 4 Unused */ + 0x05, /* 5 */ + 0xff, /* 6 Unused */ + 0x04, /* 7 */ + 0xff, /* 8 Unused */ + 0x07, /* 9 */ + 0x03, /* 10 */ + 0x02, /* 11 */ + 0x01, /* 12 */ + 0xff, /* 13 Unused */ + 0xff, /* 14 Unused */ + 0x00 /* 15 */ +}; + +local BYTE atp_dma_select_table[7] = +{ + 0xff, /* 0 Unused */ + 0xff, /* 1 Unused */ + 0xff, /* 2 Unused */ + 0x08, /* 3 */ + 0xff, /* 4 Unused */ + 0x10, /* 5 */ + 0x18 /* 6 */ +}; + +local WORD adapter_card_at_rmsz_lut[7] = +{ + 128, /* 16/4 AT */ + 128, /* 16/4 AT */ + 256, /* 16/4 AT */ + 256, /* 16/4 Fibre AT */ + 256, /* 16/4 AT Bridgenode */ + 128, /* 16/4 ISA Client */ + 512 /* 16/4 AT Plus */ +}; + +#ifndef FTK_NO_PROBE +/**************************************************************************** +* +* hwi_atula_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 ATULA based 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_atula_probe_card routine is called by hwi_probe_adapter. It +* probes the adapter card for information such as DMA channel, IRQ number +* etc. This information can then be supplied by the user when starting the +* adapter. +* +* +* 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_atula_probe_card) +#endif + +export UINT +hwi_atula_probe_card( + PROBE * resources, + UINT length, + WORD * valid_locations, + UINT number_locations + ) +{ + WBOOLEAN card_found; + WORD control_1; + WORD control_2; + WORD status; + WORD control_6; + WORD control_7; + WORD bia_prom; + WORD bia_prom_id; + WORD bia_prom_adap; + WORD bia_prom_rev; + WORD bia_prom_hwf; + BYTE bia_temp_bd; + BYTE bia_temp_rev; + BYTE bia_temp_hwf; + UINT i; + UINT j; + + /* + * Sanity check the bounds. + */ + + if (length <= 0 || number_locations <= 0) + { + return PROBE_FAILURE; + } + + /* + * Validate the IO locations. + */ + + for (i = 0; i < number_locations; i++) + { + if (!hwi_atula_valid_io_location(valid_locations[i])) + { + return PROBE_FAILURE; + } + } + + /* + * j is the number of adapters found. + */ + + j = 0; + + for (i = 0; i < number_locations; i++) + { + /* + * Make sure that we haven't run out of PROBE structures. + */ + + if (j >= length) + { + return j; + } + + /* + * Set up the ATULA control IO locations. + */ + + control_1 = valid_locations[i] + ATULA_CONTROL_REGISTER_1; + control_2 = valid_locations[i] + ATULA_CONTROL_REGISTER_2; + status = valid_locations[i] + ATULA_STATUS_REGISTER; + control_6 = valid_locations[i] + ATULA_CONTROL_REGISTER_6; + control_7 = valid_locations[i] + ATULA_CONTROL_REGISTER_7; + bia_prom = valid_locations[i] + ATULA_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; + bia_prom_hwf = bia_prom + BIA_PROM_FEATURES_BYTE; + +#ifndef FTK_NO_IO_ENABLE + macro_probe_enable_io(valid_locations[i], ATULA_IO_RANGE); +#endif + + /* + * Reset adapter (ATULA_CTRL1_NRESET = 0). + */ + + sys_probe_outsb(control_1, 0); + + /* + * Page in first page of BIA PROM. + * set ATULA_CTRL7_PAGE = 0 and ATULA_CTRL7_SIFSEL = 0. + */ + + sys_probe_outsb(control_7, 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. + */ + + /* + * At the moment there are four major board types that are acceptable + * AT, PC, MAXY, and ATP. + */ + + card_found = FALSE; + + if (sys_probe_insb(bia_prom_id) == 'M') + { + bia_temp_bd = sys_probe_insb(bia_prom_adap); + bia_temp_rev = sys_probe_insb(bia_prom_rev); + bia_temp_hwf = sys_probe_insb(bia_prom_hwf); + + if (bia_temp_bd == BIA_PROM_TYPE_16_4_PC) + { + resources[j].adapter_card_revision = ADAPTER_CARD_16_4_PC; + resources[j].adapter_ram_size = 128; + card_found = TRUE; + } + else if (bia_temp_bd == BIA_PROM_TYPE_16_4_MAXY) + { + resources[j].adapter_card_revision = ADAPTER_CARD_16_4_MAXY; + resources[j].adapter_ram_size = 256; + card_found = TRUE; + } + else if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT) + { + if (bia_temp_rev <= MAX_ADAPTER_CARD_AT_REV) + { + resources[j].adapter_ram_size = adapter_card_at_rmsz_lut[bia_temp_rev]; + } + else + { + resources[j].adapter_ram_size = 128; + } + + if (bia_temp_rev < ADAPTER_CARD_16_4_AT) + { + resources[j].adapter_card_revision = ADAPTER_CARD_16_4_AT; + } + else + { + resources[j].adapter_card_revision = bia_temp_rev; + } + card_found = TRUE; + } + else if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT_P) + { + resources[j].adapter_ram_size = 512; + + switch(bia_temp_rev) + { + case ADAPTER_CARD_16_4_FIBRE: + resources[j].adapter_card_revision = ADAPTER_CARD_16_4_FIBRE_P; + break; + case ADAPTER_CARD_16_4_ISA_C: + resources[j].adapter_card_revision = ADAPTER_CARD_16_4_ISA_C_P; + resources[j].adapter_ram_size = 128; + break; + case ADAPTER_CARD_16_4_AT_P_REV: + resources[j].adapter_card_revision = ADAPTER_CARD_16_4_AT_P; + break; + default: + resources[j].adapter_card_revision = ADAPTER_CARD_UNKNOWN; + break; + } + + card_found = TRUE; + } + } + + /* + * Check for the features byte - if it is non-zero, it may override our + * RAM size calculations. + */ + + if (bia_temp_hwf) + { + UINT dram = (bia_temp_hwf & BIA_PROM_FEATURE_DRAM_MASK) * DRAM_MULT; + + if (dram) + { + resources[j].adapter_ram_size = dram; + } + } + + /* + * If we've found an adapter then we need to make a note of + * the IO location and attempt to determine the interrupt + * number and DMA channel. + */ + + if (card_found) + { + resources[j].io_location = valid_locations[i]; + resources[j].adapter_card_bus_type = ADAPTER_CARD_ATULA_BUS_TYPE; + resources[j].adapter_card_type = ADAPTER_CARD_TYPE_16_4_AT; + + resources[j].dma_channel = hwi_atula_get_dma_channel( + valid_locations[i], + resources[j].adapter_card_revision + ); + + /* + * If we get a DMA channel of 0 back then we can't use DMA so + * default the transfer mode to PIO. Otherwise we'll set the + * transfer mode to DMA. + */ + + if (resources[j].dma_channel == 0) + { + resources[j].transfer_mode = PIO_DATA_TRANSFER_MODE; + } + else + { + resources[j].transfer_mode = DMA_DATA_TRANSFER_MODE; + } + + resources[j].interrupt_number = hwi_atula_get_irq_channel( + valid_locations[i], + resources[j].adapter_card_revision + ); + + /* + * And note that we've found an adapter. + */ + + j++; + } + +#ifndef FTK_NO_IO_ENABLE + macro_probe_disable_io(valid_locations[i], ATULA_IO_RANGE); +#endif + } + + return j; +} +#endif /* FTK_NO_PROBE */ + +#ifndef FTK_NO_DETECT +/****************************************************************************/ +/* */ +/* hwi_atula_read_rate_error */ +/* ========================= */ +/* */ +/* */ +/* PARAMETERS : */ +/* ============ */ +/* */ +/* adapter : The ubiqitous adapter structure. */ +/* */ +/* BODY : */ +/* ====== */ +/* */ +/* The hwi_atula_read_rate_error reads the NRATE_ERR signal from the */ +/* adapter DIO space. This is read from chapter 0 address 0. */ +/* */ +/* RETURNS : */ +/* ========= */ +/* */ +/* The routine returns RATE_ERROR if there is a rate error, 0 if there is no*/ +/* error, and NOT_SUPP if the card doesn't support this. */ +/* */ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_atula_read_rate_error) +#endif + +export WORD hwi_atula_read_rate_error( ADAPTER * adapter + ) +{ + WBOOLEAN ret_code; + WORD error_word; + +#ifndef FTK_NO_IO_ENABLE + macro_enable_io( adapter ); +#endif + + if (adapter->speed_detect == TRUE) + { + hwi_atula_set_dio_address( adapter, 0x00000000L); + + sys_outsw( adapter->adapter_handle, adapter->sif_adr, 0x0); + + + error_word = sys_insw( adapter->adapter_handle, adapter->sif_dat) & 0x0080; + + hwi_atula_set_dio_address( adapter, DIO_LOCATION_EAGLE_DATA_PAGE); + + if (error_word & 0x0080) + { + ret_code = 0; + } + else + { + ret_code = RATE_ERROR; + } + } + else + { + ret_code = NOT_SUPP; + } + +#ifndef FTK_NO_IO_ENABLE + macro_disable_io( adapter ); +#endif + + return ret_code; +} +#endif /* FTK_NO_DETECT */ + +/**************************************************************************** +* +* hwi_atula_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_atula_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. +* Similarly, operating system calls are used to enable DMA if required. If +* DMA is not used then the adapter is set up for PIO. +* +* 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_atula_install_card) +#endif + +export WBOOLEAN +hwi_atula_install_card( + ADAPTER * adapter, + DOWNLOAD_IMAGE * download_image + ) +{ + WBOOLEAN is_soft_prog = FALSE; + ADAPTER_HANDLE handle = adapter->adapter_handle; + WORD control_1 = adapter->io_location + ATULA_CONTROL_REGISTER_1; + WORD control_2 = adapter->io_location + ATULA_CONTROL_REGISTER_2; + WORD status = adapter->io_location + ATULA_STATUS_REGISTER; + WORD control_6 = adapter->io_location + ATULA_CONTROL_REGISTER_6; + WORD control_7 = adapter->io_location + ATULA_CONTROL_REGISTER_7; + WORD bia_prom = adapter->io_location + ATULA_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; + WORD bia_prom_hwf = bia_prom + BIA_PROM_FEATURES_BYTE; + WORD bia_prom_hwf2 = bia_prom + BIA_PROM_HWF2; + WORD bia_prom_hwf3 = bia_prom + BIA_PROM_HWF3; + BYTE control_6_out; + BYTE dummy_sifdat; + BYTE bia_temp_bd = 0; + BYTE bia_temp_rev = 0; + BYTE bia_temp_hwf = 0; + BYTE bia_temp_hwf2 = 0; + BYTE bia_temp_hwf3 = 0; + WBOOLEAN card_found; + WORD sif_base; + + /* + * Check that the IO location is valid. + */ + + if (!hwi_atula_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; + } + + /* + * Record the locations of the SIF registers. + */ + + sif_base = adapter->io_location + ATULA_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 + ATULA_EAGLE_SIFACL; + adapter->sif_adr2 = sif_base + ATULA_EAGLE_SIFADR_2; + adapter->sif_adx = sif_base + ATULA_EAGLE_SIFADX; + adapter->sif_dmalen = sif_base + ATULA_EAGLE_DMALEN; + + adapter->io_range = ATULA_IO_RANGE; + +#ifndef FTK_NO_IO_ENABLE + macro_enable_io(adapter); +#endif + + /* + * Enable adapter card interrupts. + */ + + sys_outsb(handle, control_2, ATULA_CTRL2_INTEN); + + /* + * Reset adapter (ATULA_CTRL1_NRESET = 0). + */ + + sys_outsb(handle, control_1, 0); + + /* + * Page in first page of BIA PROM. + * Set ATULA_CTRL7_PAGE = 0 and ATULA_CTRL7_SIFSEL = 0. + */ + + sys_outsb(handle, control_7, 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. + */ + + /* + * At the moment there are four major board types that are acceptable + * AT, PC, MAXY, and ATP. + */ + + card_found = FALSE; + + if (sys_insb(handle, bia_prom_id) == 'M') + { + bia_temp_bd = sys_insb(handle, bia_prom_adap); + bia_temp_rev = sys_insb(handle, bia_prom_rev); + bia_temp_hwf = sys_insb(handle, bia_prom_hwf); + bia_temp_hwf2 = sys_insb(handle, bia_prom_hwf2); + bia_temp_hwf3 = sys_insb(handle, bia_prom_hwf3); + + if (bia_temp_bd == BIA_PROM_TYPE_16_4_PC) + { + adapter->adapter_card_revision = ADAPTER_CARD_16_4_PC; + adapter->adapter_ram_size = 128; + card_found = TRUE; + } + else if (bia_temp_bd == BIA_PROM_TYPE_16_4_MAXY) + { + adapter->adapter_card_revision = ADAPTER_CARD_16_4_MAXY; + adapter->adapter_ram_size = 256; + card_found = TRUE; + } + else if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT) + { + if (bia_temp_rev <= MAX_ADAPTER_CARD_AT_REV) + { + adapter->adapter_ram_size = adapter_card_at_rmsz_lut[bia_temp_rev]; + } + else + { + adapter->adapter_ram_size = 128; + } + + if (bia_temp_rev < ADAPTER_CARD_16_4_AT) + { + adapter->adapter_card_revision = ADAPTER_CARD_16_4_AT; + } + else + { + adapter->adapter_card_revision = bia_temp_rev; + } + + card_found = TRUE; + } + else if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT_P) + { + adapter->adapter_ram_size = 512; + + switch(bia_temp_rev) + { + case ADAPTER_CARD_16_4_FIBRE: + adapter->adapter_card_revision = ADAPTER_CARD_16_4_FIBRE_P; + break; + case ADAPTER_CARD_16_4_ISA_C: + adapter->adapter_card_revision = ADAPTER_CARD_16_4_ISA_C_P; + adapter->adapter_ram_size = 128; + adapter->mc32_config = MC_AND_ISACP_USE_PIO; + break; + case ADAPTER_CARD_16_4_AT_P_REV: + adapter->adapter_card_revision = ADAPTER_CARD_16_4_AT_P; + break; + default: + adapter->adapter_card_revision = ADAPTER_CARD_UNKNOWN; + break; + } + + card_found = TRUE; + } + } + + /* + * If no ATULA 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; + } + + /* + * Sanity check the interrupt number and DMA channel. The checking + * routines fill in the error record in the adapter structure. + */ + + if (!hwi_atula_valid_irq_channel(adapter) || + !hwi_atula_valid_transfer_mode(adapter) || + !hwi_atula_valid_dma_channel(adapter)) + { +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif + return FALSE; + } + + /* + * Note the major card type. + */ + + adapter->adapter_card_type = ADAPTER_CARD_TYPE_16_4_AT; + + /* + * If this card has a C30 on board and the ring speed bit is set then + * we support ring speed detect. + */ + + if (((bia_temp_hwf2 & 0x3) == C30 ) && (bia_temp_hwf3 & RSPEED_DETECT)) + { + adapter->speed_detect = TRUE; + } + + /* + * Now we need to check for AT/P cards - these need special processing. + */ + + if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT_P || + bia_temp_rev == ADAPTER_CARD_16_4_AT_P_REV) + { + WORD atp_eisa_rev2 = adapter->io_location + AT_P_EISA_REV2_CTRL_REG; + BYTE eisa_rev2_byte = 0; + + if (bia_temp_bd == BIA_PROM_TYPE_16_4_AT_P) + { + eisa_rev2_byte |= ATP_RSCTRL; + } + + if ((bia_temp_hwf & BIA_PROM_FEATURE_CLKDIV_MASK) || + (bia_temp_rev == ADAPTER_CARD_16_4_ISA_C)) + { + eisa_rev2_byte |= ATP_CLKDIV; + } + + sys_outsb(handle, atp_eisa_rev2, eisa_rev2_byte); + + is_soft_prog = TRUE; + } + + /* + * Check for the features byte - if it is non-zero, it may override our + * RAM size calculations. + */ + + if (bia_temp_hwf) + { + UINT dram = (bia_temp_hwf & BIA_PROM_FEATURE_DRAM_MASK) * DRAM_MULT; + + if (dram) + { + adapter->adapter_ram_size = dram; + } + } + + /* + * The user might have asked to override the card configuration with + * the values supplied - this only works for ATPs and ISA/C/Ps. + */ + + if (is_soft_prog) + { + WORD atp_sw_config = adapter->io_location + AT_P_SW_CONFIG_REG; + BYTE config_byte; + UINT int_num = adapter->interrupt_number; + UINT dma_chan = adapter->dma_channel; + + if (adapter->set_irq || adapter->set_dma || adapter->set_ring_speed) + { + config_byte = sys_insb(handle, atp_sw_config); + + /* + * Override the interrupt number. + */ + + if (adapter->set_irq && + int_num < sizeof(atp_irq_select_table) && + atp_irq_select_table[int_num] != 0xff) + { + config_byte = (config_byte & ~ATP_INTSEL) | + atp_irq_select_table[int_num]; + } + + /* + * Override the DMA channel. + */ + + if (adapter->set_dma && + dma_chan < sizeof(atp_dma_select_table) && + atp_dma_select_table[dma_chan] != 0xff) + { + config_byte = (config_byte & ~ATP_DMA) | + atp_dma_select_table[dma_chan]; + } + + /* + * Set the ring speed. + */ + + if (adapter->set_ring_speed == 16) + { + config_byte = (config_byte & ~ATP_S4N16); + } + else if (adapter->set_ring_speed == 4) + { + config_byte = (config_byte | ATP_S4N16); + } + + sys_outsb(handle, atp_sw_config, config_byte); + } + } + + /* + * May have changed from software running in bus master to PIO. + * Hence get spurious data at ?a28 cos of DLATCH bug in ATULA hardware + * so get next read data as if doing PIO data transfer. + * Hence do extra read from ?a28 to fix bug. + */ + + dummy_sifdat = sys_insb(handle, adapter->sif_dat); + + /* + * Check here to see if we have to force card to 16 Mb/s for a none + * soft programmable card. + */ + + if (!is_soft_prog && adapter->set_ring_speed == 16) + { + macro_setb_bit(handle, control_1, ATULA_CTRL1_4_16_SEL); + } + + /* + * Interrupts for ATULA cards are always edge triggered. + */ + + adapter->edge_triggered_ints = TRUE; + + /* + * Machine reset does not affect speed or media setting of ATULA cards. + */ + + /* + * Find the adapter card node address. + */ + + hwi_atula_read_node_address(adapter); + + /* + * If have REV3 adapter type then must set up special bus timings + * must do this before any SIF register access + * on 16/4 PC doing this is not necessary but has no effect + */ + + if ((sys_insb(handle, control_7) & ATULA_CTRL7_REV_4) == 0) + { + /* + * Note that a sys_outsb here will clear the INTEN bit that was set + * earlier on. This does not matter, however, because we have found + * the interrupt vector by this stage. If this does become a problem, + * use macro_setb_bit(). + */ + + sys_outsb(handle, control_2, ATULA_CTRL2_CS16DLY); + } + + /* + * Set control register 6 for normal or synchronous bus operation. + * Use status register to get bus operation mode. On 16/4 PC will always + * in fact have normal bus operation. + */ + + control_6_out = 0; + + if ((sys_insb(handle, status) & ATULA_STATUS_ASYN_BUS) != 0) + { + control_6_out |= ATULA_CTRL6_CLKSEL_ON_BOARD; + } + else + { + control_6_out |= ATULA_CTRL6_CLKSEL_HOST; + } + + /* + * If want to use DMA, need a 16 bit slot. + * Note that 16/4 PC will always be in an 8 bit slot. + */ + + if ((adapter->transfer_mode == DMA_DATA_TRANSFER_MODE) && + ((sys_insb(handle, status) & ATULA_STATUS_BUS8) != 0)) + { + adapter->error_record.type = ERROR_TYPE_HWI; + adapter->error_record.value = HWI_E_06_CANNOT_USE_DMA; + +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif + return FALSE; + } + + /* + * Set up transfer mode now that we know we are in a valid slot. + */ + + if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE) + { + control_6_out |= ATULA_CTRL6_MODE_BUS_MASTER; + } + else + { + control_6_out |= ATULA_CTRL6_MODE_PIO; + } + + /* + * Now output to control register 6 the required value we have set up. + */ + + sys_outsb(handle, control_6, control_6_out); + + /* + * Wait at least 10 milliseconds and bring adapter out of reset state. + * 10ms is the minimum time must hold ATULA_CTRL1_NRESET low after + * changing ATULA_CTRL6_CLKSEL bits. 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(10); + +#ifndef FTK_NO_IO_ENABLE + macro_enable_io(adapter); +#endif + + macro_setb_bit( handle, control_1, ATULA_CTRL1_NSRESET); + + /* + * Get extended SIF registers, halt EAGLE, then get normal SIF regs. + */ + + macro_setb_bit(handle, control_7, ATULA_CTRL7_SIFSEL); + macro_setb_bit(handle, control_1, ATULA_CTRL1_SRSX); + + hwi_halt_eagle(adapter); + + macro_clearb_bit(handle, control_1, ATULA_CTRL1_SRSX); + + /* + * Download code to adapter. View download image as a sequence of + * download records. Pass address of routine to set up DIO addresses + * on ATULA cards. If routine fails return failure (error record + * already filled in). + */ + + if (!hwi_download_code( + adapter, + (DOWNLOAD_RECORD *) download_image, + hwi_atula_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, ATULA_CTRL1_SRSX); + + hwi_start_eagle(adapter); + + macro_clearb_bit(handle, control_1, ATULA_CTRL1_SRSX); + + /* + * Wait for a valid bring up code, may wait 3 seconds. + * if routine fails return failure (error record already filled in). + */ + + if (!hwi_get_bring_up_code(adapter)) + { +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif + return FALSE; + } + + /* + * Set DIO address to point to EAGLE DATA page 0x10000L. + */ + + hwi_atula_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); + 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 fail enable irq channel then fill in error record and return. + */ + + 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, ATULA_CTRL1_SINTREN); + macro_setb_bit( handle, control_2, ATULA_CTRL2_INTEN); + + /* + * Set up PIO or DMA as required. + */ + + if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE) + { + /* + * Bus master DMA. This is not possible for 16/4 PC adapters. + * Enable DMA at adapter and then call system service routine. + * Must enable DMA at adapter before enable DMA channel + * otherwise machine will 'crash'. Also important that DMA + * channel is correct for same reason. dma_on field is used + * when disabling DMA for adapter. + */ + + macro_setb_bit(handle, control_6, ATULA_CTRL6_DMAEN); + + adapter->dma_on = sys_enable_dma_channel(handle, adapter->dma_channel); + + /* + * If we fail to enable dma channel then fill in error record + * and return also disable DMA at adapter because of failure. + */ + + if (!adapter->dma_on) + { + macro_clearb_bit(handle, control_6, ATULA_CTRL6_DMAEN); + + adapter->error_record.type = ERROR_TYPE_HWI; + adapter->error_record.value = HWI_E_0C_FAIL_DMA_ENABLE; + +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif + return FALSE; + } + } + else + { + /* + * PIO mode. This is only data transfer mode possible for + * 16/4 PC adapters. Enable PIO interrupt. + */ + + macro_setb_bit(handle, control_2, ATULA_CTRL2_SHRQEN); + } + +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif + + /* + * Return successfully. + */ + + return TRUE; +} + + +/**************************************************************************** +* +* hwi_atula_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_atula_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 or by the +* ATULA in order to do a PIO data transfer. 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). +* +* On PIO interrupts, the length, direction and physical address of the +* transfer is determined. A system provided routine is called to do the +* data transfer itself. Note the EAGLE thinks it is doing a DMA transfer +* - it is the ATULA which allows us to do it via in/out instructions. Also +* note that the IO location for the PIO is mapped onto the location of the +* EAGLE SIFDAT register - the PIO does not actually use the SIFDAT +* register so it's value is not effected by this routine. +* +* RETURNS : +* ========= +* +* The routine always successfully completes. +* +****************************************************************************/ + +#ifdef FTK_IRQ_FUNCTION +#pragma FTK_IRQ_FUNCTION(hwi_atula_interrupt_handler) +#endif + +export void +hwi_atula_interrupt_handler( + ADAPTER * adapter + ) +{ + ADAPTER_HANDLE handle = adapter->adapter_handle; + WORD control_1 = adapter->io_location + ATULA_CONTROL_REGISTER_1; + WORD control_2 = adapter->io_location + ATULA_CONTROL_REGISTER_2; + WORD status = adapter->io_location + ATULA_STATUS_REGISTER; + WORD control_7 = adapter->io_location + ATULA_CONTROL_REGISTER_7; + WORD sifadr = adapter->sif_adr; + WORD sifdat = adapter->sif_dat; + WORD sifint = adapter->sif_int; + WORD sifint_value; + WORD sifint_tmp; + BYTE FAR * pio_virtaddr; + WORD pio_len_bytes; + WBOOLEAN pio_from_adapter; + WORD saved_sifadr; + UINT dummy; + DWORD dma_high_word; + WORD dma_low_word; + + /* + * Inform system about the IO ports we are going to access. + */ + +#ifndef FTK_NO_IO_ENABLE + macro_enable_io(adapter); +#endif + + /* + * Check for SIF interrupt or PIO interrupt. + */ + + if ((sys_insb(handle, control_7) & ATULA_CTRL7_SINTR) != 0) + { + /* + * SIF interrupt has occurred. SRB free, adapter check + * or received frame interrupt. + */ + + /* + * Toggle SIF interrupt enable to acknowledge interrupt at ATULA. + */ + + macro_clearb_bit(handle, control_1, ATULA_CTRL1_SINTREN); + macro_setb_bit(handle, control_1, ATULA_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, sifint, 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, sifint); + do + { + sifint_tmp = sifint_value; + sifint_value = sys_insw(handle, sifint); + } + 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 + + /* + * Toggle interrupt enable bit to regenerate any lost interrupts. + * Need do this because using edge triggered interrupts. + */ + + macro_clearb_bit(handle, control_2, ATULA_CTRL2_INTEN); + macro_setb_bit(handle, control_2, ATULA_CTRL2_INTEN); + + /* + * Call driver with details of SIF interrupt. + */ + driver_interrupt_entry(handle, adapter, sifint_value); + } + else if ((sys_insb(handle, control_2) & ATULA_CTRL2_SHRQ) != 0) + { + /* + * PIO interrupt has occurred. Data transfer to/from adapter + * interrupt. + */ + + /* + * Toggle PIO interrupt enable to acknowledge interrupt at ATULA. + */ + + macro_clearb_bit(handle, control_2, ATULA_CTRL2_SHRQEN); + macro_setb_bit(handle, control_2, ATULA_CTRL2_SHRQEN); + + /* + * We must preserve the value of SIF address in case we have + * interrupted someone who relies on it not chaning. + */ + + saved_sifadr = sys_insw(handle, adapter->sif_adr); + + /* + * Read the virtual address for the PIO through DIO space from the + * SIF registers. Because the SIF thinks that it is doing real DMA, + * the SDMAADR/SDMAADX registers cannot be paged in, so they must + * be read from their memory mapped locations in Eagle memory. + */ + + sys_outsw(handle, sifadr, DIO_LOCATION_EXT_DMA_ADDR); + dma_high_word = (DWORD) sys_insw(handle, sifdat); + + sys_outsw(handle, sifadr, DIO_LOCATION_DMA_ADDR); + dma_low_word = sys_insw(handle, sifdat); + + pio_virtaddr = (BYTE FAR *) ((dma_high_word << 16) | ((DWORD) dma_low_word)); + + /* + * Read the DMA length from the extended SIF register. + */ + + macro_setb_bit(handle, control_1, ATULA_CTRL1_SRSX); + pio_len_bytes = sys_insw(handle, adapter->sif_dmalen); + macro_clearb_bit( handle, control_1, ATULA_CTRL1_SRSX); + + /* + * If we are talking to the ISA Client/P, we need to use software + * handshaking across the PIO. Start by writing zero to a magic + * location on the adapter. + */ + + if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P) + { + sys_outsw(handle, sifadr, DIO_LOCATION_DMA_CONTROL); + sys_outsw(handle, sifdat, 0); + } + + /* + * Start what the SIF thinks is a DMA but is PIO instead. + */ + + macro_setb_bit(handle, control_2, ATULA_CTRL2_SHLDA); + + /* + * Determine what direction the data transfer is to take place in. + */ + + pio_from_adapter = sys_insb(handle, status) & ATULA_STATUS_SDDIR; + + /* + * Do the actual data transfer. Note that Fastmac only copies whole + * WORDs to DWORD boundaries. FastmacPlus, however, can transfer + * any length to any address. + */ + + if (pio_from_adapter) + { + /* + * Transfer into host memory from adapter. + */ + + /* + * First, check if host address is on an odd byte boundary. + */ + + if ((card_t) pio_virtaddr % 2) + { + pio_len_bytes--; + *(pio_virtaddr++) = + sys_insb(handle, (WORD) (sifdat + ATULA_PIO_IO_LOC + 1)); + } + + /* + * Now transfer the bulk of the data. + */ + + sys_rep_insw( + handle, + (WORD) (sifdat + ATULA_PIO_IO_LOC), + pio_virtaddr, + (WORD) (pio_len_bytes >> 1) + ); + + /* + * Finally transfer any trailing byte. + */ + + if (pio_len_bytes % 2) + { + *(pio_virtaddr + pio_len_bytes - 1) = + sys_insb(handle, (WORD) (sifdat + ATULA_PIO_IO_LOC)); + } + } + else + { + /* + * Transfer into adapter memory from the host. + */ + + /* + * If we are talking to an ISA Client/P card, we need to assert + * the -CLKDIV signal to prevent dips in one of the signals to + * the ATULA. This is only needed for ISA/C/P transmits. + */ + + if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P && + pio_len_bytes > 13) + { + /* + * Need to write ATP_RSCTRL to ATP_EISA_REV2_CTRL reg. + */ + + sys_outsb( + handle, + (WORD) (adapter->io_location + AT_P_EISA_REV2_CTRL_REG), + ATP_RSCTRL + ); + } + + /* + * First, check if host address is on an odd byte boundary. + */ + + if ((card_t) pio_virtaddr % 2) + { + pio_len_bytes--; + sys_outsb( + handle, + (WORD) (sifdat + ATULA_PIO_IO_LOC + 1), + *(pio_virtaddr++) + ); + } + + /* + * Now transfer the bulk of the data. + */ + + sys_rep_outsw( + handle, + (WORD) (sifdat + ATULA_PIO_IO_LOC), + pio_virtaddr, + (WORD) (pio_len_bytes >> 1) + ); + + /* + * Finally transfer any trailing byte. + */ + + if (pio_len_bytes % 2) + { + sys_outsb( + handle, + (WORD) (sifdat + ATULA_PIO_IO_LOC), + *(pio_virtaddr + pio_len_bytes - 1) + ); + } + + /* + * If we are talking to an ISA Client/P card, we need to remove + * the -CLKDIV signal that we asserted above. + */ + + if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P && + pio_len_bytes > 13) + { + /* + * Deassert the -CLKDIV signal that we asserted up above. + */ + + sys_outsb( + handle, + (WORD) (adapter->io_location + AT_P_EISA_REV2_CTRL_REG), + ATP_RSCTRL | ATP_CLKDIV + ); + } + } + + /* + * If we are talking to an ISA Client/P card, we now finish off the + * software handshake process that we started at the beginning. + */ + + if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P) + { + /* + * Do a read first - otherwise the write might fail. + */ + + sys_outsw(handle, sifadr, DIO_LOCATION_DMA_CONTROL); + dummy = sys_insw(handle, sifdat); + + sys_outsw(handle, sifadr, DIO_LOCATION_DMA_CONTROL); + sys_outsw(handle, sifdat, 0xFFFF); + } + + /* + * Restore the SIF address. + */ + + sys_outsw(handle, adapter->sif_adr, saved_sifadr); + + /* + * Acknowledge/clear interrupt at interrupt controller. + */ + +#ifndef FTK_NO_CLEAR_IRQ + sys_clear_controller_interrupt(handle, adapter->interrupt_number); +#endif + + /* + * Toggle interrupt enable bit to regenerate any lost interrupts. + */ + + macro_clearb_bit(handle, control_2, ATULA_CTRL2_INTEN); + macro_setb_bit(handle, control_2, ATULA_CTRL2_INTEN); + } + + /* + * Let system know we have finished accessing the IO ports. + */ + +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif +} + + +/**************************************************************************** +* +* hwi_atula_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_atula_remove_card routine is called by hwi_remove_adapter. It +* disables DMA and interrupts if they are being used. It also resets the +* adapter. +* +* RETURNS : +* ========= +* +* The routine always successfully completes. +* +****************************************************************************/ + +#ifdef FTK_RES_FUNCTION +#pragma FTK_RES_FUNCTION(hwi_atula_remove_card) +#endif + +export void +hwi_atula_remove_card( + ADAPTER * adapter + ) +{ + ADAPTER_HANDLE handle = adapter->adapter_handle; + WORD control_1 = adapter->io_location + ATULA_CONTROL_REGISTER_1; + WORD control_2 = adapter->io_location + ATULA_CONTROL_REGISTER_2; + WORD control_6 = adapter->io_location + ATULA_CONTROL_REGISTER_6; + + /* + * Disable DMA if successfully enabled. DMA will only be on if not + * in PIO mode. DMA channel must be disabled before disabling DMA + * at adapter otherwise machine will 'crash'. + */ + +#ifndef FTK_NO_IO_ENABLE + macro_enable_io(adapter); +#endif + + if (adapter->dma_on) + { + sys_disable_dma_channel(handle, adapter->dma_channel); + + macro_clearb_bit(handle, control_6, ATULA_CTRL6_DMAEN); + + adapter->dma_on = FALSE; + } + + /* + * Disable interrupts being generated. 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_2, ATULA_CTRL2_INTEN); + + if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE) + { + sys_disable_irq_channel(handle, adapter->interrupt_number); + } + + adapter->interrupts_on = FALSE; + } + + /* + * Perform adapter reset, set ATULA_CTRL1_NSRESET low. + */ + + sys_outsb(handle, control_1, 0); + +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif +} + + +/**************************************************************************** +* +* hwi_atula_set_dio_address +* ========================= +* PARAMETERS : +* ============ +* +* ADAPTER * adapter +* +* This structure is used to identify and record specific information about +* the required adapter. +* +* DWORD dio_address +* +* The 32 bit DIO address to select. +* +* BODY : +* ====== +* +* The hwi_atula_set_dio_address routine is used, with ATULA 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_atula_set_dio_address) +#endif + +export void +hwi_atula_set_dio_address( + ADAPTER * adapter, + DWORD dio_address + ) +{ + ADAPTER_HANDLE handle = adapter->adapter_handle; + WORD control_1 = adapter->io_location + ATULA_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, ATULA_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, ATULA_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_atula_valid_io_location +| =========================== +| +| The hwi_atula_valid_io_location routine checks to see if the user has +| supplied a valid IO location for an ATULA based adapter card. +| +---------------------------------------------------------------------------*/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_atula_valid_io_location) +#endif + +local WBOOLEAN +hwi_atula_valid_io_location( + WORD io_location + ) +{ + WBOOLEAN io_valid; + + switch (io_location) + { + case 0x0A20 : + case 0x1A20 : + case 0x2A20 : + case 0x3A20 : + + /* + * These are the valid user supplied io locations. + */ + + io_valid = TRUE; + break; + + + default : + + /* + * Anything else is invalid. + */ + + io_valid = FALSE; + break; + } + + return io_valid; +} + + +/*--------------------------------------------------------------------------- +| +| hwi_atula_read_node_address +| =========================== +| +| The hwi_atula_read_node_address routine reads in the node address that +| is stored in the second page of the BIA PROM on ATULA cards. +| +---------------------------------------------------------------------------*/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_atula_read_node_address) +#endif + +local void +hwi_atula_read_node_address( + ADAPTER * adapter + ) +{ + ADAPTER_HANDLE handle = adapter->adapter_handle; + WORD control_7 = adapter->io_location + ATULA_CONTROL_REGISTER_7; + WORD bia_prom = adapter->io_location + ATULA_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_7, ATULA_CTRL7_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_7, ATULA_CTRL7_PAGE); +} + + +#ifndef FTK_NO_PROBE +/*--------------------------------------------------------------------------- +| +| hwi_atula_get_irq_channel +| ========================= +| +| The hwi_atula_get_irq_channel routine attempts to determine the +| interrupt number that an ATULA card is using. It does this by calling +| system provided routine. It does not always succeed in finding the +| interrupt number being used. +| +---------------------------------------------------------------------------*/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_atula_get_irq_channel) +#endif + +local WORD +hwi_atula_get_irq_channel( + WORD io_location, + UINT adapter_revision + ) +{ + WORD control_2 = io_location + ATULA_CONTROL_REGISTER_2; + WORD control_7 = io_location + ATULA_CONTROL_REGISTER_7; + BYTE original_ctrl7; + BYTE irq_off; + BYTE irq_on; + WORD irq; + + /* + * Enable interrupts at adapter card temporarily. + */ + + macro_probe_setb_bit(control_2, ATULA_CTRL2_INTEN); + + /* + * Save contents of ATULA control register 7. + */ + + original_ctrl7 = sys_probe_insb(control_7); + + /* + * Current contents of control register 7 does not generate interrupt. + */ + + irq_off = original_ctrl7; + + /* + * If set user interrupt bit then will generate interrupt. + */ + + irq_on = irq_off | ATULA_CTRL7_UINT; + + /* + * Call system provided routine to attempt to dicover interrupt number. + * Routine returns FTK_NOT_DETERMINED if not get interrupt number. + */ + + irq = sys_atula_find_irq_channel(control_7, irq_on, irq_off); + + /* + * Restore original contents of ATULA control register 7. + */ + + sys_probe_outsb(control_7, original_ctrl7); + + /* + * Disable interrupts at adapter card. + */ + + macro_probe_clearb_bit( control_2, ATULA_CTRL2_INTEN); + + /* + * Return discovered interrupt number (could be FTK_NOT_DETERMINED). + */ + + return irq; +} +#endif + +#ifndef FTK_NO_PROBE +/*--------------------------------------------------------------------------- +| +| hwi_atula_get_dma_channel +| ========================= +| +| The hwi_atula_get_dma_channel routine attempts to determine the DMA +| channel that an ATULA card is using. It does this by calling a system +| provided routine. +| +| It may be that the system routine does not always succeed in finding the +| DMA channel being used. However, if the provided system routine is used, +| then PIO mode is chosen if the DMA channel can not be determined. Hence, +| in this case, the value FTK_NOT_DETERMINED will never be returned by the +| hwi_atula_get_dma_channel routine. +| +---------------------------------------------------------------------------*/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_atula_get_dma_channel) +#endif + +local WORD +hwi_atula_get_dma_channel( + WORD io_location , + UINT adapter_revision + ) +{ + WORD control_6 = io_location + ATULA_CONTROL_REGISTER_6; + WORD bia_prom = io_location + ATULA_BIA_PROM; + WORD bia_prom_adap = bia_prom + BIA_PROM_ADAPTER_BYTE; + BYTE original_ctrl6; + BYTE dma_off; + BYTE dma_on; + WORD dma; + + /* + * Check to see if an adapter that doesn't support DMA is being used. + */ + + if (adapter_revision == ADAPTER_CARD_16_4_PC || + adapter_revision == ADAPTER_CARD_16_4_ISA_C || + adapter_revision == ADAPTER_CARD_16_4_ISA_C_P) + { + dma = 0; + } + else + { + /* + * For the 16/4 AT card, save the contents of control register 6. + */ + + original_ctrl6 = sys_probe_insb(control_6); + + /* + * Need to enable DMA for bus master. + */ + + dma_off = original_ctrl6 | + ATULA_CTRL6_MODE_BUS_MASTER | + ATULA_CTRL6_DMAEN; + + /* + * Set user generate DMA request bit for turning DMA signal on. + */ + + dma_on = dma_off | ATULA_CTRL6_UDRQ; + + /* + * Call system provided routine to attempt to dicover DMA channel. + * Provided routine returns PIO_DATA_TRANSFER_MODE if not find. + */ + + dma = sys_atula_find_dma_channel(control_6, dma_on, dma_off); + + /* + * Restore original contents of ATULA control register 6. + */ + + sys_probe_outsb(control_6, original_ctrl6); + } + + /* + * Return discovered DMA channel details. + */ + + return dma; +} +#endif + + +/*--------------------------------------------------------------------------- +| +| hwi_atula_valid_transfer_mode +| ============================= +| +| The hwi_atula_valid_transfer mode routine checks to see if the user has +| supplied a valid transfer mode for an ATULA based adapter card. +| +---------------------------------------------------------------------------*/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_atula_valid_transfer_mode) +#endif + +local WBOOLEAN +hwi_atula_valid_transfer_mode( + ADAPTER * adapter + ) +{ + WBOOLEAN mode_valid; + + /* + * Assume that transfer mode is valid. + */ + + mode_valid = TRUE; + + /* + * MMIO is always invalid. + */ + + if (adapter->transfer_mode == MMIO_DATA_TRANSFER_MODE) + { + mode_valid = FALSE; + } + + /* + * PIO is always valid but DMA may not be. + */ + + else if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE) + { + if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_PC || + adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C || + adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P) + { + mode_valid = FALSE; + } + } + + if (!mode_valid) + { + adapter->error_record.type = ERROR_TYPE_HWI; + adapter->error_record.value = HWI_E_17_BAD_TRANSFER_MODE; + } + + return mode_valid; +} + +/*--------------------------------------------------------------------------- +| +| hwi_atula_valid_irq_channel +| =========================== +| +| The hwi_atula_valid_irq_channel routine checks to see if the user has +| supplied a valid interrupt number for an ATULA based adapter card. +| +---------------------------------------------------------------------------*/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_atula_valid_irq_channel) +#endif + +local WBOOLEAN +hwi_atula_valid_irq_channel( + ADAPTER * adapter + ) +{ + WBOOLEAN int_valid; + + /* + * Assume that interrupt number is valid. + */ + + int_valid = TRUE; + + /* + * No need to do any check on interrupt number if in polling mode. + */ + + if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE) + { + /* + * Check the interrupt number based on adapter type. + */ + + if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_PC) + { + switch (adapter->interrupt_number) + { + case 2 : + case 3 : + case 5 : + case 7 : + case 9 : + break; + + default : + int_valid = FALSE; + break; + + } + } + else + { + switch (adapter->interrupt_number) + { + case 2 : + case 3 : + case 5 : + case 7 : + case 9 : + case 10 : + case 11 : + case 12 : + case 15 : + break; + + default : + int_valid = FALSE; + break; + } + } + } + + if (!int_valid) + { + adapter->error_record.type = ERROR_TYPE_HWI; + adapter->error_record.value = HWI_E_03_BAD_INTERRUPT_NUMBER; + } + + return int_valid; +} + +/*--------------------------------------------------------------------------- +| +| hwi_atula_valid_dma_channel +| =========================== +| +| The hwi_atula_valid_dma_channel routine checks to see if the user has +| supplied a valid DMA channel for an ATULA based adapter card. +| +---------------------------------------------------------------------------*/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_atula_valid_dma_channel) +#endif + +local WBOOLEAN +hwi_atula_valid_dma_channel( + ADAPTER * adapter + ) +{ + WBOOLEAN dma_valid; + + /* + * Assume that DMA channel is valid. + */ + + dma_valid = TRUE; + + /* + * Only need to check on DMA channel in DMA mode. + */ + + if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE) + { + /* + * Some adapters do not support DMA. + */ + + if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_PC || + adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C || + adapter->adapter_card_revision == ADAPTER_CARD_16_4_ISA_C_P) + { + dma_valid = FALSE; + } + else if (adapter->adapter_card_revision == ADAPTER_CARD_16_4_AT_P || + adapter->adapter_card_revision == ADAPTER_CARD_16_4_FIBRE_P) + { + switch (adapter->dma_channel) + { + case 3 : + case 5 : + case 6 : + break; + + default : + dma_valid = FALSE; + break; + } + } + else + { + switch (adapter->dma_channel) + { + case 1 : + case 3 : + case 5 : + case 6 : + break; + + default : + dma_valid = FALSE; + break; + } + } + } + + if (!dma_valid) + { + adapter->error_record.type = ERROR_TYPE_HWI; + adapter->error_record.value = HWI_E_04_BAD_DMA_CHANNEL; + } + + return dma_valid; +} + + +#endif + +/**** End of HWI_AT.C file *************************************************/ |