mirror of https://github.com/lianthony/NT4.0
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.
2490 lines
68 KiB
2490 lines
68 KiB
/****************************************************************************
|
|
*
|
|
* THE HARDWARE INTERFACE MODULE (SMART PNP RINGNODES)
|
|
* ===================================================
|
|
*
|
|
* HWI_PNP.C : Part of the FASTMAC TOOL-KIT (FTK)
|
|
*
|
|
* Copyright (c) Madge Networks Ltd. 1990-1994
|
|
* Developed by AC
|
|
* From code by MF
|
|
* 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_PNP.C module contains the routines specific to the PnP card
|
|
* 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_PNP
|
|
|
|
/*---------------------------------------------------------------------------
|
|
|
|
|
| LOCAL PROCEDURES
|
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
local WBOOLEAN
|
|
hwi_pnp_valid_io_location(
|
|
WORD io_location
|
|
);
|
|
|
|
local WBOOLEAN
|
|
hwi_pnp_read_node_address(
|
|
ADAPTER * adapter
|
|
);
|
|
|
|
local WBOOLEAN
|
|
hwi_pnp_valid_irq_channel(
|
|
ADAPTER * adapter
|
|
);
|
|
|
|
local WBOOLEAN
|
|
hwi_pnp_test_for_id(
|
|
ADAPTER * adapter
|
|
);
|
|
|
|
local WORD
|
|
pnp_read_a_word(
|
|
ADAPTER * adapter,
|
|
WORD index
|
|
);
|
|
|
|
#ifndef FTK_NO_PROBE
|
|
|
|
local WBOOLEAN
|
|
hwi_pnp_probe_find_card(
|
|
WORD io_location
|
|
);
|
|
|
|
local WORD
|
|
hwi_pnp_probe_get_irq(
|
|
WORD io_location
|
|
);
|
|
|
|
local WORD
|
|
pnp_probe_read_a_word(
|
|
WORD io_location,
|
|
WORD index
|
|
);
|
|
|
|
#endif
|
|
|
|
#ifndef FTK_NO_PROBE
|
|
/****************************************************************************
|
|
*
|
|
* hwi_pnp_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 PNP based adapters this should be a subset of
|
|
* {0x3a20, 0x920, 0x940, 0x960, 0x980, 0xa20, 0xa40, 0xa60, 0xa80, 0xb20,
|
|
* 0xb40, 0xb60, 0xb80}.
|
|
*
|
|
* UINT number_locations
|
|
*
|
|
* This is the number of IO locations in the above list.
|
|
*
|
|
* BODY :
|
|
* ======
|
|
*
|
|
* The hwi_pnp_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_pnp_probe_card)
|
|
#endif
|
|
|
|
export UINT
|
|
hwi_pnp_probe_card(
|
|
PROBE * resources,
|
|
UINT length,
|
|
WORD * valid_locations,
|
|
UINT number_locations
|
|
)
|
|
{
|
|
WORD temp_word;
|
|
UINT adapters_found;
|
|
UINT i;
|
|
|
|
/*
|
|
* 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_pnp_valid_io_location(valid_locations[i]))
|
|
{
|
|
return PROBE_FAILURE;
|
|
}
|
|
}
|
|
|
|
adapters_found = 0;
|
|
|
|
for (i = 0; i < number_locations; i++)
|
|
{
|
|
/*
|
|
* Make sure that we haven't run out of PROBE structures.
|
|
*/
|
|
if (adapters_found >= length)
|
|
{
|
|
return adapters_found;
|
|
}
|
|
|
|
if (hwi_pnp_probe_find_card(valid_locations[i]))
|
|
{
|
|
|
|
/*
|
|
* Found a card! Now fill out the probe structure.
|
|
*/
|
|
|
|
resources[adapters_found].io_location = valid_locations[i];
|
|
resources[adapters_found].adapter_card_bus_type = ADAPTER_CARD_PNP_BUS_TYPE;
|
|
resources[adapters_found].adapter_card_type = ADAPTER_CARD_TYPE_16_4_PNP;
|
|
resources[adapters_found].adapter_card_revision = ADAPTER_CARD_PNP;
|
|
resources[adapters_found].transfer_mode = PIO_DATA_TRANSFER_MODE;
|
|
|
|
/*
|
|
* Now find out how much RAM we have.
|
|
*/
|
|
|
|
temp_word = pnp_probe_read_a_word(
|
|
valid_locations[i],
|
|
PNP_HWARE_FEATURES1);
|
|
|
|
temp_word &= PNP_DRAM_SIZE_MASK;
|
|
|
|
/*
|
|
* Convert the DRAM size to multiples of bytes.
|
|
*/
|
|
|
|
resources[adapters_found].adapter_ram_size = temp_word * 64;
|
|
|
|
/*
|
|
* Now find out what IRQ we are using.
|
|
*/
|
|
|
|
resources[adapters_found].interrupt_number = hwi_pnp_probe_get_irq( valid_locations[i]);
|
|
|
|
adapters_found++;
|
|
}
|
|
}
|
|
|
|
return adapters_found;
|
|
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
*
|
|
* hwi_pnp_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_pnp_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_pnp_install_card)
|
|
#endif
|
|
|
|
export WBOOLEAN
|
|
hwi_pnp_install_card(
|
|
ADAPTER * adapter,
|
|
DOWNLOAD_IMAGE * download_image
|
|
)
|
|
{
|
|
ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
|
|
WORD control_1 = adapter->io_location +
|
|
PNP_CONTROL_REGISTER_1;
|
|
WORD config_addr = adapter->io_location +
|
|
PNP_CONFIG_ADDRESS_REGISTER;
|
|
WORD config_data = adapter->io_location +
|
|
PNP_CONFIG_DATA_REGISTER;
|
|
WORD chip_type;
|
|
WORD ram_size;
|
|
BYTE byte;
|
|
WORD sif_base;
|
|
|
|
|
|
/*
|
|
* Firstly do some validation on the user supplied adapter details
|
|
* check that the IO location is valid
|
|
* if routine fails return failure (error record already filled in)
|
|
* In theory we shouldnt have to do this - but Chicago has been known
|
|
* to pass out junk !!
|
|
*/
|
|
|
|
if (!hwi_pnp_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;
|
|
}
|
|
|
|
/*
|
|
* save IO locations of the SIF registers
|
|
*/
|
|
|
|
sif_base = adapter->io_location + PNP_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 + EAGLE_SIFACL;
|
|
adapter->sif_adr2 = sif_base + EAGLE_SIFADR;
|
|
adapter->sif_adx = sif_base + EAGLE_SIFADX;
|
|
adapter->sif_dmalen = sif_base + EAGLE_DMALEN;
|
|
adapter->sif_sdmadat = sif_base + EAGLE_SDMADAT;
|
|
adapter->sif_sdmaadr = sif_base + EAGLE_SDMAADR;
|
|
adapter->sif_sdmaadx = sif_base + EAGLE_SDMAADX;
|
|
|
|
adapter->io_range = PNP_IO_RANGE;
|
|
|
|
/*
|
|
* Make sure this is a real PNP card by reading the ID register
|
|
*/
|
|
|
|
if(!hwi_pnp_test_for_id(adapter))
|
|
{
|
|
adapter->error_record.type = ERROR_TYPE_HWI;
|
|
adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* You might want to check that we have not already checked for a card
|
|
* at this address (or its rev3/4 equivalent).
|
|
* Read the node address for the specified IO location.
|
|
*/
|
|
|
|
if (!hwi_pnp_read_node_address(adapter))
|
|
{
|
|
adapter->error_record.type = ERROR_TYPE_HWI;
|
|
adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND;
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Check the transfer mode - this is very easy as we only do PIO
|
|
* (albeit EAGLE PseudoDMA).
|
|
*/
|
|
|
|
if (adapter->transfer_mode != PIO_DATA_TRANSFER_MODE)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Check the IRQ channel supplied.
|
|
* In theory we shouldnt have to do this - but Chicago has been known
|
|
* to pass out junk !!
|
|
*/
|
|
|
|
if (!hwi_pnp_valid_irq_channel(adapter))
|
|
{
|
|
/*
|
|
* Fill in error record and return
|
|
*/
|
|
adapter->error_record.type = ERROR_TYPE_HWI;
|
|
adapter->error_record.value = HWI_E_03_BAD_INTERRUPT_NUMBER;
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* These things can all be assumed for the pnp.
|
|
*/
|
|
|
|
adapter->adapter_card_type = ADAPTER_CARD_TYPE_16_4_PNP;
|
|
adapter->adapter_card_revision = ADAPTER_CARD_PNP;
|
|
|
|
/*
|
|
* Now find out how much RAM we have.
|
|
*/
|
|
|
|
ram_size = pnp_read_a_word(adapter,
|
|
PNP_HWARE_FEATURES1);
|
|
|
|
ram_size &= PNP_DRAM_SIZE_MASK;
|
|
|
|
/*
|
|
* Convert the DRAM size to multiples of bytes.
|
|
*/
|
|
|
|
adapter->adapter_ram_size = ram_size * 64;
|
|
adapter->edge_triggered_ints = TRUE;
|
|
adapter->EaglePsDMA = TRUE;
|
|
|
|
/*
|
|
* Set the ring speed if required.
|
|
*/
|
|
|
|
/*
|
|
* RCS 2/11/94 Added code to set the adapter->nselout bits so that
|
|
* the ring speed is fully adopted by the adapter when "hwi_halt_eagle()"
|
|
* is called.
|
|
*
|
|
* Also set the "ringspeed configured" bit if the "set_ring_speed"
|
|
* feature is specified so that we will use the value.
|
|
*
|
|
* Also return an error if the ringspeed hasnt been configured and
|
|
* the user hasnt specified "set_ring_speed".
|
|
*/
|
|
|
|
/*
|
|
* Is this a C30 based card???
|
|
* If it is then we can't drive the lowest bit of the vendor config
|
|
* register as this gives an indication of ring_speed error (Potentially).
|
|
*
|
|
*/
|
|
|
|
chip_type = pnp_read_a_word(
|
|
adapter,
|
|
PNP_HWARE_FEATURES3);
|
|
chip_type &= PNP_C30_MASK;
|
|
|
|
/*
|
|
* First read the current settings
|
|
*/
|
|
|
|
sys_outsb(
|
|
adapter_handle,
|
|
config_addr,
|
|
PNP_VENDOR_CONFIG_BYTE);
|
|
|
|
byte = sys_insb(
|
|
adapter_handle,
|
|
config_data);
|
|
|
|
if (adapter->set_ring_speed != 0)
|
|
{
|
|
if (adapter->set_ring_speed == 4)
|
|
{
|
|
if ( chip_type != PNP_C30 )
|
|
{
|
|
/*
|
|
* Set bits to select 4mbits as the ring speed
|
|
*/
|
|
byte |= (PNP_VENDOR_CONFIG_4MBITS + PNP_VENDOR_CONFIG_PXTAL);
|
|
}
|
|
else
|
|
{
|
|
byte |= PNP_VENDOR_CONFIG_4MBITS;
|
|
}
|
|
}
|
|
else if (adapter->set_ring_speed == 16)
|
|
{
|
|
if ( chip_type != PNP_C30 )
|
|
{
|
|
/*
|
|
* Clear bits to select 16mbits as the ring speed
|
|
*/
|
|
|
|
byte &= ~(PNP_VENDOR_CONFIG_4MBITS +
|
|
PNP_VENDOR_CONFIG_PXTAL);
|
|
}
|
|
else
|
|
{
|
|
byte &= ~(PNP_VENDOR_CONFIG_4MBITS);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Show ring speed as having been configured
|
|
*/
|
|
|
|
byte |= PNP_VENDOR_CONFIG_RSVALID;
|
|
|
|
/*
|
|
* and write it back to the card
|
|
*/
|
|
|
|
sys_outsb(
|
|
adapter_handle,
|
|
config_data,
|
|
byte);
|
|
}
|
|
|
|
/*
|
|
* Use the value in "byte" to set the NSELOUT bits or it will still
|
|
* only run at 16 !!
|
|
*/
|
|
|
|
if (byte & PNP_VENDOR_CONFIG_RSVALID)
|
|
{
|
|
if (byte & PNP_VENDOR_CONFIG_4MBITS)
|
|
{
|
|
adapter->nselout_bits = PNP_RING_SPEED_4;
|
|
}
|
|
else
|
|
{
|
|
adapter->nselout_bits = PNP_RING_SPEED_16;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* The user MUST configure the RING SPEED before we will let him use
|
|
* the card.
|
|
* He can either run the CONFIG util or use the FORCE4/FORCE16
|
|
* mechanism.
|
|
* Fill in error record and return
|
|
*/
|
|
|
|
adapter->error_record.type = ERROR_TYPE_HWI;
|
|
adapter->error_record.value = HWI_E_0E_NO_SPEED_SELECTED;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Bring adapter out of reset state (ensure that SCS is zero before
|
|
* doing this). If active float channel ready is set in the Plug and
|
|
* Play hardware flags then set the PNP_CHRDY_ACTIVE bit.
|
|
*/
|
|
|
|
byte = PNP_CTRL1_NSRESET;
|
|
|
|
if ((pnp_read_a_word(
|
|
adapter,
|
|
PNP_HWARE_PNP_FLAGS) & PNP_ACTIVE_FLOAT_CHRDY) != 0)
|
|
{
|
|
byte |= PNP_CTRL1_CHRDY_ACTIVE;
|
|
}
|
|
|
|
sys_outsb(
|
|
adapter_handle,
|
|
control_1,
|
|
byte);
|
|
|
|
/*
|
|
* Halt the Eagle prior to downloading the MAC code - this will also
|
|
* write the ringspeed bits into the SIFACL register.
|
|
*/
|
|
|
|
hwi_halt_eagle(adapter);
|
|
|
|
/*
|
|
* 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_pnp_set_dio_address))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* Restart the Eagle to initiate bring up diagnostics.
|
|
*/
|
|
|
|
hwi_start_eagle(adapter);
|
|
|
|
/*
|
|
* 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))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
/*
|
|
* set DIO address to point to EAGLE DATA page 0x10000L
|
|
*/
|
|
|
|
hwi_pnp_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);
|
|
|
|
/*
|
|
* Get the ring speed.
|
|
*/
|
|
|
|
adapter->ring_speed = hwi_get_ring_speed(adapter);
|
|
|
|
/*
|
|
* if not in polling mode then set up interrupts
|
|
* interrupts_on field is used when disabling interrupts for adapter
|
|
*/
|
|
|
|
if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
|
|
{
|
|
adapter->interrupts_on =
|
|
sys_enable_irq_channel(adapter_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;
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
adapter->interrupts_on = TRUE;
|
|
}
|
|
|
|
/*
|
|
* return successfully
|
|
*/
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* hwi_pnp_interrupt_handler
|
|
* ==========================
|
|
*
|
|
*
|
|
* PARAMETERS (passed by hwi_interrupt_entry) :
|
|
* ============================================
|
|
*
|
|
* ADAPTER_HANDLE adapter_handle
|
|
*
|
|
* The adapter handle for the adapter so it can later be passed to the user
|
|
* supplied user_receive_frame or user_completed_srb routine.
|
|
*
|
|
* ADAPTER * adapter
|
|
*
|
|
* This structure is used to identify and record specific information about
|
|
* the required adapter.
|
|
*
|
|
*
|
|
* BODY :
|
|
* ======
|
|
*
|
|
* The hwi_pnp_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_pnp_interrupt_handler)
|
|
#endif
|
|
|
|
export void
|
|
hwi_pnp_interrupt_handler(
|
|
ADAPTER * adapter
|
|
)
|
|
{
|
|
WORD sifacl;
|
|
WORD sifint_value;
|
|
WORD sifint_tmp;
|
|
WBOOLEAN sifint_occurred = FALSE;
|
|
WBOOLEAN pioint_occurred = FALSE;
|
|
BYTE FAR * pio_virtaddr;
|
|
WORD lo_word;
|
|
DWORD hi_word;
|
|
WORD pio_len_bytes;
|
|
WBOOLEAN pio_from_adapter;
|
|
ADAPTER_HANDLE adapter_handle;
|
|
|
|
adapter_handle = adapter->adapter_handle;
|
|
|
|
/*
|
|
* inform system about the IO ports we are going to access
|
|
* eanble maximum number of IO locations used by any adapter card
|
|
* do this so at driver level can disable IO not knowing adapter type
|
|
*/
|
|
|
|
#ifndef FTK_NO_IO_ENABLE
|
|
macro_enable_io(adapter);
|
|
#endif
|
|
|
|
/*
|
|
* check for SIF interrupt or PIO interrupt
|
|
*/
|
|
|
|
/*
|
|
* Mask off any further interrupts while we read SIFINT (note that this
|
|
* does not mask off Pseudo DMA interrupts)
|
|
*/
|
|
|
|
macro_clearw_bit(
|
|
adapter_handle,
|
|
adapter->sif_acl,
|
|
EAGLE_SIFACL_SINTEN
|
|
);
|
|
|
|
sifint_value = sys_insw(adapter_handle, adapter->sif_int);
|
|
do
|
|
{
|
|
sifint_tmp = sifint_value;
|
|
sifint_value = sys_insw(adapter_handle, adapter->sif_int);
|
|
}
|
|
while (sifint_tmp != sifint_value);
|
|
|
|
if ((sifint_value & EAGLE_SIFINT_SYSTEM) != 0)
|
|
{
|
|
/*
|
|
* SIF interrupt has occurred
|
|
* SRB free, adapter check or received frame interrupt
|
|
*/
|
|
|
|
sifint_occurred = TRUE;
|
|
|
|
/*
|
|
* clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF
|
|
*/
|
|
|
|
sys_outsw(adapter_handle, adapter->sif_int, 0);
|
|
}
|
|
|
|
sifacl = sys_insw(adapter_handle, adapter->sif_acl);
|
|
|
|
if ((sifacl & EAGLE_SIFACL_SWHRQ) != 0)
|
|
{
|
|
/*
|
|
* PIO interrupt has occurred
|
|
* data transfer to/from adapter interrupt
|
|
*/
|
|
|
|
pioint_occurred = TRUE;
|
|
|
|
macro_setw_bit(
|
|
adapter_handle,
|
|
adapter->sif_acl,
|
|
EAGLE_SIFACL_SWHLDA
|
|
);
|
|
|
|
/*
|
|
* determine what direction the data transfer is to take place in
|
|
*/
|
|
|
|
pio_from_adapter = sys_insw(
|
|
adapter_handle,
|
|
adapter->sif_acl
|
|
) & EAGLE_SIFACL_SWDDIR;
|
|
|
|
pio_len_bytes = sys_insw(
|
|
adapter_handle,
|
|
adapter->sif_dmalen
|
|
);
|
|
|
|
lo_word = sys_insw(
|
|
adapter_handle,
|
|
adapter->sif_sdmaadr
|
|
);
|
|
|
|
hi_word = (DWORD) sys_insw(
|
|
adapter_handle,
|
|
adapter->sif_sdmaadx
|
|
);
|
|
|
|
pio_virtaddr = (BYTE FAR *) ((hi_word << 16) | ((DWORD) lo_word));
|
|
|
|
/*
|
|
* 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
|
|
*/
|
|
|
|
/*
|
|
* transfer whole WORDs to Fastmac receive buffer
|
|
* NOT FORGETTING the possibility of a trailing byte.
|
|
*/
|
|
|
|
sys_rep_insw(
|
|
adapter_handle,
|
|
adapter->sif_sdmadat,
|
|
pio_virtaddr,
|
|
(WORD) (pio_len_bytes >> 1)
|
|
);
|
|
|
|
if (pio_len_bytes % 2)
|
|
{
|
|
/*
|
|
* Finally transfer any trailing byte.
|
|
*/
|
|
|
|
*(pio_virtaddr + pio_len_bytes - 1) =
|
|
sys_insb(adapter_handle, adapter->sif_sdmadat);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* transfer into adapter memory from the host
|
|
*/
|
|
|
|
sys_rep_outsw(
|
|
adapter_handle,
|
|
adapter->sif_sdmadat,
|
|
pio_virtaddr,
|
|
(WORD) (pio_len_bytes >> 1)
|
|
);
|
|
|
|
if (pio_len_bytes % 2)
|
|
{
|
|
sys_outsb(
|
|
adapter_handle,
|
|
adapter->sif_sdmadat,
|
|
*(pio_virtaddr+pio_len_bytes-1)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef FTK_NO_CLEAR_IRQ
|
|
|
|
if (sifint_occurred || pioint_occurred)
|
|
{
|
|
/*
|
|
* acknowledge/clear interrupt at interrupt controller
|
|
*/
|
|
|
|
sys_clear_controller_interrupt(
|
|
adapter_handle,
|
|
adapter->interrupt_number);
|
|
}
|
|
|
|
#endif
|
|
|
|
if (sifint_occurred)
|
|
{
|
|
/*
|
|
* call driver with details of SIF interrupt
|
|
*/
|
|
|
|
driver_interrupt_entry(adapter_handle, adapter, sifint_value);
|
|
}
|
|
|
|
/*
|
|
* Read SIFACL until the SWHLDA bit has cleared.
|
|
*/
|
|
|
|
do
|
|
{
|
|
sifacl = sys_insw(adapter_handle, adapter->sif_acl);
|
|
}
|
|
while ((sifacl & EAGLE_SIFACL_SWHLDA) != 0);
|
|
|
|
/*
|
|
* Now set SINTEN in SIFACL to regenerate interrupts.
|
|
*/
|
|
|
|
sys_outsw(
|
|
adapter_handle,
|
|
adapter->sif_acl,
|
|
(WORD) (sifacl | EAGLE_SIFACL_SINTEN)
|
|
);
|
|
|
|
/*
|
|
* let system know we have finished accessing the IO ports
|
|
*/
|
|
|
|
#ifndef FTK_NO_IO_ENABLE
|
|
macro_disable_io( adapter );
|
|
#endif
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* hwi_pnp_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_pnp_remove_card routine is called by hwi_remove_adapter. It
|
|
* disables 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_pnp_remove_card)
|
|
#endif
|
|
|
|
export void
|
|
hwi_pnp_remove_card(
|
|
ADAPTER * adapter
|
|
)
|
|
{
|
|
ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
|
|
WORD control_1 = adapter->io_location +
|
|
PNP_CONTROL_REGISTER_1;
|
|
WORD sifacl;
|
|
|
|
/*
|
|
* interrupt must be disabled at adapter before unpatching interrupt
|
|
* even in polling mode we must turn off interrupts at adapter
|
|
*/
|
|
|
|
sifacl = sys_insw(adapter_handle, adapter->sif_acl);
|
|
sifacl = (sifacl & ~(EAGLE_SIFACL_PSDMAEN | EAGLE_SIFACL_SINTEN));
|
|
|
|
sys_outsw(adapter_handle,
|
|
adapter->sif_acl,
|
|
sifacl);
|
|
|
|
if (adapter->interrupts_on)
|
|
{
|
|
if (adapter->interrupt_number != POLLING_INTERRUPTS_MODE)
|
|
{
|
|
sys_disable_irq_channel(
|
|
adapter_handle,
|
|
adapter->interrupt_number);
|
|
}
|
|
|
|
adapter->interrupts_on = FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
* perform adapter reset, set PNP_CTRL1_NSRESET low
|
|
*/
|
|
|
|
sys_outsb(adapter_handle, control_1, !PNP_CTRL1_NSRESET);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* hwi_atula_set_dio_address
|
|
* =========================
|
|
*
|
|
* 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_pnp_set_dio_address)
|
|
#endif
|
|
|
|
export void
|
|
hwi_pnp_set_dio_address(
|
|
ADAPTER * adapter,
|
|
DWORD dio_address
|
|
)
|
|
{
|
|
ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
|
|
WORD sif_dio_adr = adapter->sif_adr;
|
|
WORD sif_dio_adrx = adapter->sif_adx;
|
|
|
|
/*
|
|
* load extended DIO address register with top 16 bits of address
|
|
* always load extended address register first
|
|
*/
|
|
|
|
sys_outsw(adapter_handle, sif_dio_adrx, (WORD)(dio_address >> 16));
|
|
|
|
/*
|
|
* load DIO address register with low 16 bits of address
|
|
*/
|
|
|
|
sys_outsw(adapter_handle, sif_dio_adr, (WORD)(dio_address & 0x0000FFFF));
|
|
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
|
|
|
| LOCAL PROCEDURES
|
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
/*---------------------------------------------------------------------------
|
|
|
|
|
| hwi_pnp_read_node_address
|
|
| ==========================
|
|
|
|
|
| The hwi_pnp_read_node_address routine reads in the node address from
|
|
| the BIA, and checks that it is a valid Madge node address.
|
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(hwi_pnp_read_node_address)
|
|
#endif
|
|
|
|
local WBOOLEAN
|
|
hwi_pnp_read_node_address(
|
|
ADAPTER * adapter
|
|
)
|
|
{
|
|
WORD ioport = adapter->io_location;
|
|
|
|
adapter->permanent_address.byte[0] = 0;
|
|
adapter->permanent_address.byte[1] = 0;
|
|
adapter->permanent_address.byte[2] = (BYTE) pnp_read_a_word(adapter, 15);
|
|
adapter->permanent_address.byte[3] = (BYTE) pnp_read_a_word(adapter, 14);
|
|
adapter->permanent_address.byte[4] = (BYTE) pnp_read_a_word(adapter, 13);
|
|
adapter->permanent_address.byte[5] = (BYTE) pnp_read_a_word(adapter, 12);
|
|
|
|
return (adapter->permanent_address.byte[2] == MADGE_NODE_BYTE_2);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
|
|
|
| hwi_pnp_valid_io_location
|
|
| ==========================
|
|
|
|
|
| The hwi_pnp_valid_io_location routine checks to see if the user has
|
|
| supplied a valid IO location for a PNP adapter card.
|
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(hwi_pnp_valid_io_location)
|
|
#endif
|
|
|
|
local WBOOLEAN
|
|
hwi_pnp_valid_io_location(
|
|
WORD io_location
|
|
)
|
|
{
|
|
WBOOLEAN io_valid;
|
|
|
|
switch (io_location)
|
|
{
|
|
|
|
case 0x1A20 :
|
|
case 0x2A20 :
|
|
case 0x3A20 :
|
|
|
|
/*
|
|
* The following are needed coz Chicago won't configure our
|
|
* PNP card at xA20 (a problem with Chicago !??)
|
|
*/
|
|
|
|
case 0x0140 : /* In case CHICAGO cant find a free one */
|
|
|
|
/*
|
|
* It (Chicago) also wont allow cards to be at a 10 bit alias
|
|
* of each other ! (despite the fact we set the bit that says
|
|
* we fully decode all sixteen bits of the address !!)
|
|
*/
|
|
|
|
case 0x0920 :
|
|
case 0x0940 :
|
|
case 0x0960 :
|
|
case 0x0980 :
|
|
|
|
case 0x0A20 :
|
|
case 0x0A40 :
|
|
case 0x0A60 :
|
|
case 0x0A80 :
|
|
case 0x0AA0 :
|
|
|
|
case 0x0B20 :
|
|
case 0x0B40 :
|
|
case 0x0B60 :
|
|
case 0x0B80 :
|
|
|
|
/*
|
|
* 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_pnp_valid_irq_channel
|
|
| ==========================
|
|
|
|
|
| The hwi_pnp_valid_irq_channel routine checks to see if the user has
|
|
| supplied a valid interrupt number for a PNP
|
|
|
|
|
| If the user has stated that polling mode is to be used, then this is
|
|
| always okay. If not, then a check is made that the user given interrupt
|
|
| number is a valid number for the card type.
|
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(hwi_pnp_valid_irq_channel)
|
|
#endif
|
|
|
|
local WBOOLEAN
|
|
hwi_pnp_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)
|
|
{
|
|
/*
|
|
* Can only check that the interrupt number given is valid
|
|
*/
|
|
|
|
switch (adapter->interrupt_number)
|
|
{
|
|
case 2 :
|
|
case 3 :
|
|
case 7 :
|
|
case 9 :
|
|
case 10 :
|
|
case 11 :
|
|
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;
|
|
}
|
|
|
|
|
|
#ifndef FTK_NO_PROBE
|
|
/*---------------------------------------------------------------------------
|
|
|
|
|
| hwi_pnp_probe_find_card
|
|
| =======================
|
|
|
|
|
| The hwi_pnp_find_card checks if a PNP card is at a particular location.
|
|
| This is called by the probe routines.
|
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(hwi_pnp_probe_find_card)
|
|
#endif
|
|
|
|
local WBOOLEAN
|
|
hwi_pnp_probe_find_card(
|
|
WORD io_location
|
|
)
|
|
{
|
|
WORD id_reg = io_location + PNP_ID_REGISTER;
|
|
WORD i;
|
|
|
|
/*
|
|
* Search for leading 'm'
|
|
*/
|
|
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (sys_insb(0 , id_reg) == 'm')
|
|
{
|
|
/*
|
|
* Next byte must be 'd'.
|
|
*/
|
|
|
|
if (sys_insb(0 , id_reg) == 'd')
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* PNP ID not seen, or incorrect!
|
|
*/
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
|
|
|
| hwi_pnp_probe_get_irq
|
|
| =====================
|
|
|
|
|
| The hwi_pnp_gwt_irq gets the Interrupt used by a plug and play card.
|
|
| This is called by the probe routines.
|
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(hwi_pnp_probe_get_irq)
|
|
#endif
|
|
|
|
local WORD
|
|
hwi_pnp_probe_get_irq(
|
|
WORD io_location
|
|
)
|
|
{
|
|
WORD interrupt;
|
|
|
|
sys_probe_outsb(
|
|
(io_location + PNP_CONFIG_ADDRESS_REGISTER),
|
|
PNP_VENDOR_CONFIG_IRQ);
|
|
|
|
interrupt = (WORD)sys_probe_insb(
|
|
(io_location+PNP_CONFIG_DATA_REGISTER));
|
|
|
|
return interrupt;
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------
|
|
|
|
|
| hwi_pnp_test_for_id
|
|
| ===================
|
|
|
|
|
| The hwi_pnp_test_for_id routine confirms that a real PNP card exists
|
|
| at the supplied addreess by checking the contents of the ID register.
|
|
|
|
|
---------------------------------------------------------------------------*/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(hwi_pnp_test_for_id)
|
|
#endif
|
|
|
|
local WBOOLEAN
|
|
hwi_pnp_test_for_id(
|
|
ADAPTER * adapter
|
|
)
|
|
{
|
|
ADAPTER_HANDLE adapter_handle = adapter->adapter_handle;
|
|
WORD id_reg = adapter->io_location + PNP_ID_REGISTER;
|
|
WORD i;
|
|
|
|
/*
|
|
* Search for leading 'm'
|
|
*/
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if (sys_insb(adapter_handle, id_reg) == 'm')
|
|
{
|
|
/*
|
|
* Next byte must be 'd'
|
|
*/
|
|
if (sys_insb(adapter_handle, id_reg) == 'd')
|
|
{
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* PNP ID not seen, or incorrect.
|
|
*/
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
#ifndef FTK_NO_PROBE
|
|
|
|
/************************************************************************
|
|
*
|
|
* Support routines for the serial device fitted to the Plug aNd Play
|
|
* cards. To be used by the probe functions.
|
|
*
|
|
************************************************************************/
|
|
|
|
local void pnp_probe_delay( WORD io_location );
|
|
local void pnp_probe_set_clk( WORD io_location );
|
|
local void pnp_probe_clr_clk( WORD io_location );
|
|
local void pnp_probe_twitch_clk( WORD io_location );
|
|
local void pnp_probe_start_bit( WORD io_location );
|
|
local void pnp_probe_stop_bit( WORD io_location );
|
|
local WBOOLEAN pnp_probe_wait_ack( WORD io_location );
|
|
local WBOOLEAN pnp_probe_dummy_wait_ack(WORD io_location );
|
|
|
|
|
|
/************************************************************************
|
|
* Read a byte from the control register for the specified adapter.
|
|
*
|
|
* Inputs : Adapter structure.
|
|
*
|
|
* Outputs : Value read from control register.
|
|
***********************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_read_ctrl)
|
|
#endif
|
|
|
|
local WORD pnp_probe_read_ctrl( WORD io_location )
|
|
{
|
|
return sys_probe_insb( io_location + PNP_CON_REG_OFFSET );
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Write a byte to the control register for the specified adapter.
|
|
*
|
|
* Inputs : Adapter structure.
|
|
* The data to be written.
|
|
*
|
|
* Outputs : None.
|
|
***********************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_write_ctrl)
|
|
#endif
|
|
|
|
local void pnp_probe_write_ctrl( WORD io_location, WORD data)
|
|
{
|
|
sys_probe_outsb( io_location + PNP_CON_REG_OFFSET, (BYTE)data );
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Delay to allow for serial device timing issues
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_delay)
|
|
#endif
|
|
|
|
local void pnp_probe_delay( WORD io_location )
|
|
{
|
|
UINT i;
|
|
|
|
for (i = 0; i < PNP_DELAY_CNT; i++)
|
|
{
|
|
sys_probe_insb( io_location );
|
|
}
|
|
}
|
|
|
|
/************************************************************************
|
|
* Set the serial device clock bit
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_set_clk)
|
|
#endif
|
|
|
|
local void pnp_probe_set_clk( WORD io_location )
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_probe_read_ctrl( io_location );
|
|
temp |= PNP_SSK;
|
|
|
|
pnp_probe_write_ctrl( io_location, temp);
|
|
|
|
pnp_probe_delay( io_location );
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Clears the serial device clock bit
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_clr_clk)
|
|
#endif
|
|
|
|
local void pnp_probe_clr_clk( WORD io_location )
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_probe_read_ctrl( io_location );
|
|
temp &= ~PNP_SSK;
|
|
|
|
pnp_probe_write_ctrl( io_location, temp);
|
|
|
|
pnp_probe_delay( io_location );
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Puts the serial device data port into OUTPUT mode
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_set_eeden)
|
|
#endif
|
|
|
|
local void pnp_probe_set_eeden( WORD io_location )
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_probe_read_ctrl( io_location );
|
|
temp |= PNP_EEDEN;
|
|
|
|
pnp_probe_write_ctrl( io_location , temp);
|
|
|
|
pnp_probe_delay( io_location );
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Puts the serial device data port into INPUT mode
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_clr_eeden)
|
|
#endif
|
|
|
|
local void pnp_probe_clr_eeden( WORD io_location )
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_probe_read_ctrl( io_location );
|
|
temp &= ~PNP_EEDEN;
|
|
|
|
pnp_probe_write_ctrl( io_location, temp);
|
|
|
|
pnp_probe_delay( io_location );
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Sets the clears the serial device clock bit to strobe data into device
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_twitch_clk)
|
|
#endif
|
|
|
|
local void pnp_probe_twitch_clk( WORD io_location )
|
|
{
|
|
pnp_probe_set_clk( io_location );
|
|
pnp_probe_clr_clk( io_location );
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Sends a start bit to the serial device.
|
|
*
|
|
* This is done by a 1 to 0 transition of the data bit while the clock
|
|
* bit it 1.
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_start_bit)
|
|
#endif
|
|
|
|
local void pnp_probe_start_bit( WORD io_location )
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_probe_read_ctrl( io_location );
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
temp |= (PNP_EEDO + PNP_EEDEN);
|
|
|
|
pnp_probe_write_ctrl( io_location, temp);
|
|
|
|
pnp_probe_delay( io_location );
|
|
|
|
temp |= PNP_SSK;
|
|
|
|
pnp_probe_write_ctrl( io_location, temp);
|
|
|
|
pnp_probe_delay( io_location );
|
|
|
|
temp &= ~PNP_EEDO;
|
|
|
|
pnp_probe_write_ctrl( io_location , temp);
|
|
|
|
pnp_probe_delay( io_location );
|
|
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
|
|
pnp_probe_write_ctrl( io_location , temp);
|
|
|
|
pnp_probe_delay( io_location );
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Sends a stop bit to the serial device.
|
|
*
|
|
* This is done by a 0 to 1 transition of the data bit while the clock
|
|
* bit it 1.
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_stop_bit)
|
|
#endif
|
|
|
|
local void pnp_probe_stop_bit( WORD io_location )
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_probe_read_ctrl( io_location );
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
temp |= (PNP_EEDEN);
|
|
|
|
pnp_probe_write_ctrl( io_location, temp);
|
|
|
|
pnp_probe_delay( io_location );
|
|
|
|
temp |= PNP_SSK;
|
|
|
|
pnp_probe_write_ctrl(io_location, temp);
|
|
|
|
pnp_probe_delay(io_location);
|
|
|
|
temp |= PNP_EEDO;
|
|
|
|
pnp_probe_write_ctrl(io_location, temp);
|
|
|
|
pnp_probe_delay(io_location);
|
|
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
|
|
pnp_probe_write_ctrl(io_location, temp);
|
|
|
|
pnp_probe_delay(io_location);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Waits for the serial device to say its accepted the last cmd/data
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : TRUE if OK, FALSE if it timed out
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_wait_ack)
|
|
#endif
|
|
|
|
local WBOOLEAN pnp_probe_wait_ack(WORD io_location)
|
|
{
|
|
WORD temp;
|
|
WORD i;
|
|
|
|
temp = pnp_probe_read_ctrl(io_location);
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
|
|
pnp_probe_write_ctrl(io_location, temp);
|
|
|
|
pnp_probe_delay(io_location);
|
|
|
|
for (i = 0; i < PNP_WAIT_CNT; i++)
|
|
{
|
|
pnp_probe_set_clk(io_location);
|
|
|
|
temp = pnp_probe_read_ctrl(io_location);
|
|
|
|
pnp_probe_clr_clk(io_location);
|
|
|
|
if (!(temp & PNP_EEDO))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Waits for the serial device to say its passed the last of the data to
|
|
* be read.
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : TRUE if OK, FALSE if it timed out
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_dummy_wait_ack)
|
|
#endif
|
|
|
|
local WBOOLEAN pnp_probe_dummy_wait_ack(WORD io_location)
|
|
{
|
|
WORD temp;
|
|
WORD i;
|
|
|
|
temp = pnp_probe_read_ctrl(io_location);
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
|
|
pnp_probe_write_ctrl(io_location, temp);
|
|
|
|
pnp_probe_delay(io_location);
|
|
|
|
for (i = 0; i < PNP_WAIT_CNT ; i++)
|
|
{
|
|
pnp_probe_set_clk(io_location);
|
|
|
|
temp = pnp_probe_read_ctrl(io_location);
|
|
|
|
pnp_probe_clr_clk(io_location);
|
|
|
|
if (temp & PNP_EEDO)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Writes a bit to the serial device
|
|
* be read.
|
|
*
|
|
* Inputs : Adapter structure
|
|
* The data bit to be written
|
|
*
|
|
* Outputs : TRUE if OK, FALSE if it timed out
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_write_data)
|
|
#endif
|
|
|
|
local void pnp_probe_write_data(WORD io_location, WORD data)
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_probe_read_ctrl(io_location);
|
|
temp &= ~(PNP_EEDO);
|
|
temp |= (data & 0x0080) >> 6;
|
|
|
|
pnp_probe_write_ctrl(io_location, temp);
|
|
|
|
pnp_probe_delay(io_location);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
*
|
|
* Routine to read a byte from the serial device fitted to the Plug aNd Play
|
|
* cards.
|
|
*
|
|
* Inputs : Adapter structure.
|
|
* Offset (address) in the serial device to read
|
|
*
|
|
* Outputs : A word with the interstng byte in the LSB
|
|
*
|
|
* RCS 22/07/94
|
|
*
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_probe_read_a_word)
|
|
#endif
|
|
|
|
local WORD pnp_probe_read_a_word(WORD io_location, WORD index)
|
|
{
|
|
WORD temp;
|
|
WORD data_byte = 0;
|
|
WORD i;
|
|
|
|
/*
|
|
* Wake up the device
|
|
*/
|
|
pnp_probe_start_bit(io_location);
|
|
|
|
/*
|
|
* Set data 'OUTPUT' mode
|
|
*/
|
|
pnp_probe_set_eeden(io_location);
|
|
|
|
/*
|
|
* Send WRITE CMD - a dummy really to allow us to set the READ address!
|
|
*/
|
|
temp = PNP_WRITE_CMD;
|
|
|
|
/*
|
|
* MSB first !
|
|
*/
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
pnp_probe_write_data(io_location, temp);
|
|
pnp_probe_twitch_clk(io_location);
|
|
temp = temp << 1;
|
|
}
|
|
|
|
if (!pnp_probe_wait_ack(io_location))
|
|
{
|
|
/*
|
|
* Return sommat invalid if it timed out !
|
|
*/
|
|
return 0xffff;
|
|
}
|
|
|
|
/*
|
|
* Set data 'OUTPUT' mode
|
|
*/
|
|
pnp_probe_set_eeden(io_location);
|
|
|
|
/*
|
|
* Send Address in ROM
|
|
*/
|
|
temp = index;
|
|
|
|
/*
|
|
* MSB first !
|
|
*/
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
pnp_probe_write_data(io_location, temp);
|
|
pnp_probe_twitch_clk(io_location);
|
|
temp = temp << 1;
|
|
}
|
|
|
|
if (!pnp_probe_wait_ack(io_location))
|
|
{
|
|
/*
|
|
* Return sommat invalid if it timed out !
|
|
*/
|
|
return 0xffff;
|
|
}
|
|
|
|
pnp_probe_start_bit(io_location);
|
|
|
|
/*
|
|
* Set data 'OUTPUT' mode
|
|
*/
|
|
pnp_probe_set_eeden(io_location);
|
|
|
|
/*
|
|
* Send READ CMD
|
|
*/
|
|
temp = PNP_READ_CMD;
|
|
|
|
/*
|
|
* MSB first !
|
|
*/
|
|
for (i = 0; i < 8 ;i++)
|
|
{
|
|
pnp_probe_write_data(io_location, temp);
|
|
pnp_probe_twitch_clk(io_location);
|
|
temp = temp << 1;
|
|
}
|
|
|
|
if (!pnp_probe_wait_ack(io_location))
|
|
{
|
|
/*
|
|
* Return sommat invalid if it timed out !
|
|
*/
|
|
return 0xffff;
|
|
}
|
|
|
|
/*
|
|
* Set data 'INPUT' mode
|
|
*/
|
|
pnp_probe_clr_eeden(io_location);
|
|
|
|
/*
|
|
* Now read the serial data - MSB first !
|
|
*/
|
|
for (i = 0; i < 8 ;i++)
|
|
{
|
|
pnp_probe_set_clk(io_location);
|
|
|
|
temp = pnp_probe_read_ctrl(io_location);
|
|
|
|
pnp_probe_clr_clk(io_location);
|
|
|
|
temp &= PNP_EEDO;
|
|
temp = temp >> 1;
|
|
data_byte = data_byte << 1;
|
|
data_byte &= 0xfffe;
|
|
data_byte |= temp;
|
|
}
|
|
|
|
if (!pnp_probe_dummy_wait_ack(io_location))
|
|
{
|
|
/*
|
|
* Return sommat invalid if it timed out !
|
|
*/
|
|
|
|
return 0xffff;
|
|
}
|
|
|
|
pnp_probe_stop_bit(io_location);
|
|
|
|
return data_byte;
|
|
}
|
|
|
|
#endif
|
|
|
|
/************************************************************************
|
|
*
|
|
* Support routines for the serial device fitted to the Plug aNd Play
|
|
* cards.
|
|
*
|
|
* RCS 22/07/94
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
local void pnp_delay(ADAPTER *);
|
|
local void pnp_set_clk(ADAPTER *);
|
|
local void pnp_clr_clk(ADAPTER *);
|
|
local void pnp_twitch_clk(ADAPTER *);
|
|
local void pnp_start_bit(ADAPTER *);
|
|
local void pnp_stop_bit(ADAPTER *);
|
|
local WBOOLEAN pnp_wait_ack(ADAPTER *);
|
|
local WBOOLEAN pnp_dummy_wait_ack(ADAPTER *);
|
|
local void pnp_write_data(ADAPTER *, WORD);
|
|
|
|
|
|
/************************************************************************
|
|
* Read a byte from the control register for the specified adapter.
|
|
*
|
|
* Inputs : Adapter structure.
|
|
*
|
|
* Outputs : Value read from control register.
|
|
***********************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_read_ctrl)
|
|
#endif
|
|
|
|
local WORD pnp_read_ctrl(ADAPTER * adapter)
|
|
{
|
|
return sys_insb(
|
|
adapter->adapter_handle,
|
|
(WORD) (adapter->io_location + PNP_CON_REG_OFFSET)
|
|
);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Write a byte to the control register for the specified adapter.
|
|
*
|
|
* Inputs : Adapter structure.
|
|
* The data to be written.
|
|
*
|
|
* Outputs : None.
|
|
***********************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_write_ctrl)
|
|
#endif
|
|
|
|
local void pnp_write_ctrl(ADAPTER * adapter, WORD data)
|
|
{
|
|
sys_outsb(
|
|
adapter->adapter_handle,
|
|
(WORD) (adapter->io_location + PNP_CON_REG_OFFSET),
|
|
(BYTE) data
|
|
);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Delay to allow for serial device timing issues
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_delay)
|
|
#endif
|
|
|
|
local void pnp_delay(ADAPTER * adapter)
|
|
{
|
|
WORD i;
|
|
|
|
for (i = 0; i < PNP_DELAY_CNT; i++)
|
|
{
|
|
sys_insb(adapter->adapter_handle, adapter->io_location);
|
|
}
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Set the serial device clock bit
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_set_clk)
|
|
#endif
|
|
|
|
local void pnp_set_clk(ADAPTER * adapter)
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
temp |= PNP_SSK;
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Clears the serial device clock bit
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_clr_clk)
|
|
#endif
|
|
|
|
local void pnp_clr_clk(ADAPTER * adapter)
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
temp &= ~PNP_SSK;
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Puts the serial device data port into OUTPUT mode
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_set_eeden)
|
|
#endif
|
|
|
|
local void pnp_set_eeden(ADAPTER * adapter)
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
temp |= PNP_EEDEN;
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Puts the serial device data port into INPUT mode
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_clr_eeden)
|
|
#endif
|
|
|
|
local void pnp_clr_eeden(ADAPTER * adapter)
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
temp &= ~PNP_EEDEN;
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Sets the clears the serial device clock bit to strobe data into device
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_twitch_clk)
|
|
#endif
|
|
|
|
local void pnp_twitch_clk(ADAPTER * adapter)
|
|
{
|
|
pnp_set_clk(adapter);
|
|
pnp_clr_clk(adapter);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Sends a start bit to the serial device.
|
|
*
|
|
* This is done by a 1 to 0 transition of the data bit while the clock
|
|
* bit it 1.
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_start_bit)
|
|
#endif
|
|
|
|
local void pnp_start_bit(ADAPTER * adapter)
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
temp |= (PNP_EEDO + PNP_EEDEN);
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
|
|
temp |= PNP_SSK;
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
|
|
temp &= ~PNP_EEDO;
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Sends a stop bit to the serial device.
|
|
*
|
|
* This is done by a 0 to 1 transition of the data bit while the clock
|
|
* bit it 1.
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : None
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_stop_bit)
|
|
#endif
|
|
|
|
local void pnp_stop_bit(ADAPTER * adapter)
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
temp |= (PNP_EEDEN);
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
|
|
temp |= PNP_SSK;
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
|
|
temp |= PNP_EEDO;
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Waits for the serial device to say its accepted the last cmd/data
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : TRUE if OK, FALSE if it timed out
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_wait_ack)
|
|
#endif
|
|
|
|
local WBOOLEAN pnp_wait_ack(ADAPTER * adapter)
|
|
{
|
|
WORD temp;
|
|
WORD i;
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
|
|
for (i = 0; i < PNP_WAIT_CNT; i++)
|
|
{
|
|
pnp_set_clk(adapter);
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
|
|
pnp_clr_clk(adapter);
|
|
|
|
if (!(temp & PNP_EEDO))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Waits for the serial device to say its passed the last of the data to
|
|
* be read.
|
|
*
|
|
* Inputs : Adapter structure
|
|
*
|
|
* Outputs : TRUE if OK, FALSE if it timed out
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_dummy_wait_ack)
|
|
#endif
|
|
|
|
local WBOOLEAN pnp_dummy_wait_ack(ADAPTER * adapter)
|
|
{
|
|
WORD temp;
|
|
WORD i;
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
temp &= ~(PNP_EEDO + PNP_EEDEN + PNP_SSK);
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
|
|
for (i = 0; i < PNP_WAIT_CNT ; i++)
|
|
{
|
|
pnp_set_clk(adapter);
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
|
|
pnp_clr_clk(adapter);
|
|
|
|
if (temp & PNP_EEDO)
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* Writes a bit to the serial device
|
|
* be read.
|
|
*
|
|
* Inputs : Adapter structure
|
|
* The data bit to be written
|
|
*
|
|
* Outputs : TRUE if OK, FALSE if it timed out
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_write_data)
|
|
#endif
|
|
|
|
local void pnp_write_data(ADAPTER * adapter, WORD data)
|
|
{
|
|
WORD temp;
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
temp &= ~(PNP_EEDO);
|
|
temp |= (data & 0x0080) >> 6;
|
|
|
|
pnp_write_ctrl(adapter, temp);
|
|
|
|
pnp_delay(adapter);
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
*
|
|
* Routine to read a byte from the serial device fitted to the Plug aNd Play
|
|
* cards.
|
|
*
|
|
* Inputs : Adapter structure.
|
|
* Offset (address) in the serial device to read
|
|
*
|
|
* Outputs : A word with the interstng byte in the LSB
|
|
*
|
|
* RCS 22/07/94
|
|
*
|
|
************************************************************************/
|
|
|
|
#ifdef FTK_INIT_FUNCTION
|
|
#pragma FTK_INIT_FUNCTION(pnp_read_a_word)
|
|
#endif
|
|
|
|
local WORD pnp_read_a_word(ADAPTER * adapter, WORD index)
|
|
{
|
|
WORD temp;
|
|
WORD data_byte = 0;
|
|
WORD i;
|
|
|
|
/*
|
|
* Wake up the device
|
|
*/
|
|
pnp_start_bit(adapter);
|
|
|
|
/*
|
|
* Set data 'OUTPUT' mode
|
|
*/
|
|
pnp_set_eeden(adapter);
|
|
|
|
/*
|
|
* Send WRITE CMD - a dummy really to allow us to set the READ address!
|
|
*/
|
|
temp = PNP_WRITE_CMD;
|
|
|
|
/*
|
|
* MSB first !
|
|
*/
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
pnp_write_data(adapter, temp);
|
|
pnp_twitch_clk(adapter);
|
|
temp = temp << 1;
|
|
}
|
|
|
|
if (!pnp_wait_ack(adapter))
|
|
{
|
|
/*
|
|
* Return sommat invalid if it timed out !
|
|
*/
|
|
return 0xffff;
|
|
}
|
|
|
|
/*
|
|
* Set data 'OUTPUT' mode
|
|
*/
|
|
pnp_set_eeden(adapter);
|
|
|
|
/*
|
|
* Send Address in ROM
|
|
*/
|
|
temp = index;
|
|
|
|
/*
|
|
* MSB first !
|
|
*/
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
pnp_write_data(adapter, temp);
|
|
pnp_twitch_clk(adapter);
|
|
temp = temp << 1;
|
|
}
|
|
|
|
if (!pnp_wait_ack(adapter))
|
|
{
|
|
/*
|
|
* Return sommat invalid if it timed out !
|
|
*/
|
|
return 0xffff;
|
|
}
|
|
|
|
pnp_start_bit(adapter);
|
|
|
|
/*
|
|
* Set data 'OUTPUT' mode
|
|
*/
|
|
pnp_set_eeden(adapter);
|
|
|
|
/*
|
|
* Send READ CMD
|
|
*/
|
|
temp = PNP_READ_CMD;
|
|
|
|
/*
|
|
* MSB first !
|
|
*/
|
|
for (i = 0; i < 8 ;i++)
|
|
{
|
|
pnp_write_data(adapter, temp);
|
|
pnp_twitch_clk(adapter);
|
|
temp = temp << 1;
|
|
}
|
|
|
|
if (!pnp_wait_ack(adapter))
|
|
{
|
|
/*
|
|
* Return sommat invalid if it timed out !
|
|
*/
|
|
return 0xffff;
|
|
}
|
|
|
|
/*
|
|
* Set data 'INPUT' mode
|
|
*/
|
|
pnp_clr_eeden(adapter);
|
|
|
|
/*
|
|
* Now read the serial data - MSB first !
|
|
*/
|
|
for (i = 0; i < 8 ;i++)
|
|
{
|
|
pnp_set_clk(adapter);
|
|
|
|
temp = pnp_read_ctrl(adapter);
|
|
|
|
pnp_clr_clk(adapter);
|
|
|
|
temp &= PNP_EEDO;
|
|
temp = temp >> 1;
|
|
data_byte = data_byte << 1;
|
|
data_byte &= 0xfffe;
|
|
data_byte |= temp;
|
|
}
|
|
|
|
if (!pnp_dummy_wait_ack(adapter))
|
|
{
|
|
/*
|
|
* Return sommat invalid if it timed out !
|
|
*/
|
|
return 0xffff;
|
|
}
|
|
|
|
pnp_stop_bit(adapter);
|
|
|
|
return data_byte;
|
|
}
|
|
|
|
#endif
|
|
|
|
/******** End of HWI_PNP.C *************************************************/
|