diff options
Diffstat (limited to 'private/ntos/ndis/madge/driver/hwi_pcit.c')
-rw-r--r-- | private/ntos/ndis/madge/driver/hwi_pcit.c | 2028 |
1 files changed, 2028 insertions, 0 deletions
diff --git a/private/ntos/ndis/madge/driver/hwi_pcit.c b/private/ntos/ndis/madge/driver/hwi_pcit.c new file mode 100644 index 000000000..fee338a22 --- /dev/null +++ b/private/ntos/ndis/madge/driver/hwi_pcit.c @@ -0,0 +1,2028 @@ +/**************************************************************************** +* +* HWI_PCIT.C : Part of the FASTMAC TOOL-KIT (FTK) +* +* HARDWARE INTERFACE MODULE FOR PCI CARDS +* +* Copyright (c) Madge Networks Ltd. 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_PCIT.C module contains the routines specific to the Smart 16/4 PCI(T) +* based on the TI PCI ASIC, this card supports PSEUDO DMA, and BUs master DMA. +* +* The second spin of the Ti ASIC had a problem where it was not possible to do +* DIO and DMA at the same time. Version 1.36 of FastMac plus had an interlock +* put into it to prevent these happening @ the same time. FastMAC however +* must be used in PIO mode. More details on the interlocking is found +* at the top of hwi_pcit_interrupt +* +***************************************************************************** + +/*--------------------------------------------------------------------------- +| +| DEFINITIONS +| +---------------------------------------------------------------------------*/ + +#define PCI_PCIT_DEVICE_ID 4 + +#include "ftk_defs.h" + +#define COLOUR_BLACK 0x00 +#define COLOUR_BLUE 0x10 +#define COLOUR_GREEN 0x20 +#define COLOUR_CYAN 0x30 +#define COLOUR_RED 0x40 +#define COLOUR_MAGENTA 0x50 +#define COLOUR_YELLOW 0x60 +#define COLOUR_WHITE 0x70 + + +/*--------------------------------------------------------------------------- +| +| MODULE ENTRY POINTS +| +---------------------------------------------------------------------------*/ + +#include "ftk_intr.h" /* routines internal to FTK */ +#include "ftk_extr.h" /* routines provided or used by external FTK user */ + +BYTE bEepromByteStore; +BYTE bLastDataBit; + +#ifndef FTK_NO_PCIT + +/*--------------------------------------------------------------------------- +| +| LOCAL PROCEDURES +| +---------------------------------------------------------------------------*/ + +local WBOOLEAN +hwi_pcit_read_node_address( + ADAPTER * adapter + ); + +local WORD +hwi_at24_read_a_word( + ADAPTER * adapter, + WORD word_address + ); + + +#ifndef FTK_NO_PROBE + +/**************************************************************************** +* +* hwi_pcit_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 normally an array of IO locations to examine for the +* presence of an adapter. However for PCI adapters the io location is read +* from the BIOS, so this array can remain empty. +* +* UINT number_locations +* +* This is the number of IO locations in the above list. +* +* BODY : +* ====== +* +* The hwi_pcit_probe_card routine is called by hwi_probe_adapter. It +* reads the id registers to find the type of card and also reads the IRQ. +* +* +* RETURNS : +* ========= +* +* The routine returns the number of adapters found, or PROBE_FAILURE if +* there's a problem. +* +****************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_pcit_probe_card) +#endif + +export UINT +hwi_pcit_probe_card( + PROBE * Resources, + UINT NumberOfResources, + WORD * IOMask, + UINT NumberIO + ) +{ + WORD i; + WORD Handle; + + if (!sys_pci_valid_machine()) + { + return 0; + } + + for (i=0;i<NumberOfResources;i++) + { + if (!sys_pci_find_card(&Handle, i,PCI_PCIT_DEVICE_ID)) + { + break; + } + + Resources[i].pci_handle = Handle; + Resources[i].adapter_card_bus_type = ADAPTER_CARD_TI_PCI_BUS_TYPE; + + if (!sys_pci_get_io_base(Handle, &(Resources[i].io_location))) + { + return PROBE_FAILURE; + } + + if (!sys_pci_get_irq(Handle, &(Resources[i].interrupt_number))) + { + return PROBE_FAILURE; + } + + /* + * We can't read the memory size from the serial EEPROM until the + * hwi_pcit_install_card function is called. + */ + + Resources[i].adapter_ram_size = 512; + + Resources[i].adapter_card_type = ADAPTER_CARD_TYPE_16_4_PCIT; + +#ifdef FMPLUS + Resources[i].transfer_mode = PIO_DATA_TRANSFER_MODE; +/* Resources[i].transfer_mode = DMA_DATA_TRANSFER_MODE;*/ +#else + Resources[i].transfer_mode = PIO_DATA_TRANSFER_MODE; +#endif + + } + + return i; +} + +#endif + + +/**************************************************************************** +* +* hwi_pcit_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 : +* ====== +* +* hwi_pcit_install_card 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 by reading +* the node address from the BIA PROM. It then sets up and checks various +* 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. +* The adapter is set up for Eagle Pseudo-DMA, since real DMA is not used. +* +* +* RETURNS : +* ========= +* +* The routine returns TRUE if it succeeds. If this routine fails (returns +* FALSE) then a subsequent call to driver_explain_error, with the adapter +* handle corresponding to the adapter parameter used here, will give an +* explanation. +* +****************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_pcit_install_card) +#endif + +export WBOOLEAN +hwi_pcit_install_card( + ADAPTER * adapter, + DOWNLOAD_IMAGE * download_image + ) +{ + ADAPTER_HANDLE adapter_handle = adapter->adapter_handle; + WORD sif_base; + WORD ring_speed; + WORD wControlReg; + WORD wBrokenDMA; + BYTE bCache; +#ifdef FMPLUS + DWORD dwHandShakeAddress; +#endif + + /* + * These things can all be assumed for the Ti PCI Card. + */ + + adapter->adapter_card_type = ADAPTER_CARD_TYPE_16_4_PCIT; + adapter->adapter_card_revision = ADAPTER_CARD_16_4_PCIT; + adapter->edge_triggered_ints = FALSE; + + /* + * Start off by assuming we will use pseudo DMA. + */ + + adapter->EaglePsDMA = TRUE; + + /* + * Save IO locations of SIF registers. + */ + + sif_base = adapter->io_location; + + 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_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 = SIF_IO_RANGE; + + /* + * If we are supposed to use DMA then enable it. + */ + + if (adapter->transfer_mode == DMA_DATA_TRANSFER_MODE) + { + adapter->EaglePsDMA = FALSE; + + /* + * Does this card have a 'broken' DMA ASIC ?? + * Read the HW features 2 to find out. + */ + + wBrokenDMA = hwi_at24_read_a_word(adapter, PCIT_EEPROM_HWF2); + if (wBrokenDMA == PCIT_BROKEN_DMA) + { +#ifdef FMPLUS + adapter->mc32_config = TRN_PCIT_BROKEN_DMA; +#else + adapter->error_record.type = ERROR_TYPE_HWI; + adapter->error_record.value = HWI_E_17_BAD_TRANSFER_MODE; + return FALSE; +#endif + } + else + { + adapter->mc32_config = 0; + } + } + else + { + /* + * If we've using pseudo DMA then we need a software handshake. + */ + adapter->mc32_config = MC_AND_ISACP_USE_PIO; + } + + /* + * The Command word of the PCI config space must be set to 7 i.e. + * we support BUS MASTER DMA. Some BIOS' don't do this. The Ti ASIC + * refuses to let this field be set to 3 which some BIOS's do this is + * turned into 0 by the Ti ASIC. + */ + + sys_pci_write_config_byte( + adapter_handle, + PCI_CONFIG_COMMAND, + PCI_CONFIG_BUS_MASTER_ENABLE | + PCI_CONFIG_IO_ENABLE | + PCI_CONFIG_MEM_ENABLE); + + + /* + * + * Since the BIOS may have failed to set the card up correctly as a result of + * the above problem, it may have got the Latency timer (offset 0Dh) and + * cache line size (offset 0Ch) bytes wrong too. The only observed erroneous + * values (Compaq Deskpro XL 466) are F8h and FFh respectively (all bits set + * that can be set). + * + * The latency timer is not particularly important, and can safely be left at + * F8h. + * + * A cache line size of FFh causes DMA problems and is changed to 20h. + * + */ + + sys_pci_read_config_byte(adapter_handle, CACHE_LINE_SIZE, &bCache); + + if (bCache == 0xFF) + { + sys_pci_write_config_byte( + adapter_handle, + CACHE_LINE_SIZE, + 0x20 + ); + } + + /* + * Set up the Miscellanous Control Register, we only need to modify the + * top word. + */ + + sys_pci_read_config_word( + adapter_handle, + MISC_CONT_REG + 2, + &wControlReg); + +#if 0 + wControlReg &= 0xE4; + wControlReg |= 0x4; +#else + /* + * A fix to the DMA bug, we now clear bit 18 rather than setting it + * (Slight lie this was not really a fix, but J.M. thinks leave it + * in as it does no harm. M.D. & P.R. disagree ) + */ + wControlReg &= 0xE0; +#endif + + sys_pci_write_config_word( + adapter_handle, + MISC_CONT_REG + 2, + wControlReg); + + /* + * Can't RESET the Eagle as this does not work + */ + + if (!hwi_pcit_read_node_address(adapter)) + { + adapter->error_record.type = ERROR_TYPE_HWI; + adapter->error_record.value = HWI_E_05_ADAPTER_NOT_FOUND; + return FALSE; + } + + ring_speed = hwi_at24_read_a_word(adapter, PCIT_EEPROM_RING_SPEED); + + /* + * Get the amount of RAM from the serial EEPROM (in units of 128k). + */ + + adapter->adapter_ram_size = hwi_at24_read_a_word( + adapter, + PCIT_EEPROM_RAM_SIZE) * 128; + + /* + * Set the ring speed. If the user has specified a value then we will + * use that, otherwise we will use the value read from the EEPROM. + */ + + if (adapter->set_ring_speed == 16) + { + adapter->nselout_bits = NSEL_16MBITS; + } + else if (adapter->set_ring_speed == 4) + { + adapter->nselout_bits = NSEL_4MBITS; + } + else if (ring_speed == PCIT_EEPROM_4MBITS) + { + adapter->nselout_bits = NSEL_4MBITS; + } + else + { + adapter->nselout_bits = NSEL_16MBITS; + } + + +#ifndef FTK_NO_IO_ENABLE + macro_enable_io(adapter); +#endif + + /* + * Halt the Eagle prior to downloading the MAC code - this will also + * write the interrupt bits into the SIFACL register, where the MAC can + * find them. + */ + + 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 PCI cards. + * If routine fails return failure (error record already filled in). + */ + + if (!hwi_download_code( + adapter, + (DOWNLOAD_RECORD *) download_image, + hwi_pcit_set_dio_address)) + { +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif + 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 (!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_pcit_set_dio_address(adapter, DIO_LOCATION_EAGLE_DATA_PAGE); + + /* + * Get the ring speed, from the Eagle DIO space. + */ + + adapter->ring_speed = hwi_get_ring_speed(adapter); + + /* + * Set maximum frame size from the ring speed. + */ + + adapter->max_frame_size = hwi_get_max_frame_size(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 (!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; + } + + /* + * Pass the address to be used for the 'broken' DMA handshake to the + * adapter. + */ + +#ifdef FMPLUS + + if (adapter->mc32_config == TRN_PCIT_BROKEN_DMA) + { + sys_outsw( + adapter_handle, + adapter->sif_adr, + DIO_LOCATION_DMA_POINTER); + + dwHandShakeAddress = adapter->dma_test_buf_phys + + SCB_TEST_PATTERN_LENGTH + + SSB_TEST_PATTERN_LENGTH; + + /* + * We have to Output this address LSW first; + */ + + sys_outsw( + adapter_handle, + adapter->sif_datinc, + (WORD) (dwHandShakeAddress & 0xFFFF)); + + sys_outsw( + adapter_handle, + adapter->sif_datinc, + (WORD) ((dwHandShakeAddress & 0xFFFF0000) >> 16)); + + + } + +#endif + + + /* + * Return successfully. + */ + +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif + + return TRUE; +} + + +/**************************************************************************** +* +* hwi_pcit_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_pcit_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 for either +* a PIO data transfer or a normal condition (received frame, SRB complete, +* ARB indication etc). Note it could in fact be the case that no interrupt +* has occured on the particular adapter being checked. +* +* On normal 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 PseudoDMA interrupts, the length, direction and physical address of +* the transfer is determined. A system provided routine is called to do +* the data transfer itself. +* +* The Second spin of the Ti ASIC has some problems such that no access to SIF +* registers can occur safely during a DMA. +* +* If the Broken DMA bit was set in the HW features 2 the we need the following +* mechanism. +* +* - The card wishes to do a DMA +* - The card sets the handshake word to 1111h +* - The card sets the SIF interrupt bit in the SIFINT register +* - The host interrupt routine is entered +* - The host notices it is a SIF interrupt and it is a special SIF +* interrupt since the handshake word is 1111h +* - The host clears the handshake word +* - ... which the card has been waiting for +* - The card performs the DMA transfer +* - The card does an extra, single byte, DMA transfer to a flag in +* the adapter structure on the host, of data 11h +* - ... which the host has been waiting for +* - The host resets the transfer flag to its previous value +* - The host EOIs the interrupt and leaves the interrupt routine +* +* The handshake word off the adapter which tells us the following: +* +* 0000 => Normal SIF interrupt. +* 1111 => Spin whilst DMA completes. +* 2222 => As for 1111 but this hints that a SIF interrupt may follow very soon +* after the DMA, hence poll for this. +* +* RETURNS : +* ========= +* +* The routine always successfully completes. +* +****************************************************************************/ + +local BYTE +hwi_pcit_read_byte( + BYTE FAR * ptr + ); + +#ifdef FTK_IRQ_FUNCTION +#pragma FTK_IRQ_FUNCTION(hwi_pcit_read_byte) +#endif + +local BYTE +hwi_pcit_read_byte( + BYTE FAR * ptr + ) +{ + return *ptr; +} + + +#ifdef FTK_IRQ_FUNCTION +#pragma FTK_IRQ_FUNCTION(hwi_pcit_interrupt_handler) +#endif + +export void +hwi_pcit_interrupt_handler( + ADAPTER * adapter + ) +{ + ADAPTER_HANDLE adapter_handle = adapter->adapter_handle; + WORD sifacl; + WORD sifint_value; + WORD sifint_tmp; + WORD pio_addr_lo; + DWORD pio_addr_hi; + WORD pio_len_bytes; + WORD last_byte; + WBOOLEAN pio_from_adapter; + WBOOLEAN our_interrupt = FALSE; + WBOOLEAN proper_sif_int = FALSE; + BYTE FAR * pio_address; + WORD saved_sifadr; +#ifdef FMPLUS + BYTE FAR * dma_handshake_addr; + WORD dodgy_dma; + WORD timeout; +#endif + +#ifndef FTK_NO_IO_ENABLE + macro_enable_io(adapter); +#endif + + /* + * Check for SIF interrupt or PIO interrupt. + */ + + /* + * Read SIFINT, and then re-read to make sure value is stable. + */ + + 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); + + /* + * Given the SIFINT value, we can check one of the bits in it to see + * if that is what caused the interrupt. + */ + + if ((sifint_value & EAGLE_SIFINT_SYSTEM) != 0) + { + + /* + * It's our interrupt and as far as we can tell it's a real + * SIF interrupt. + */ + + proper_sif_int = TRUE; + our_interrupt = TRUE; + +#ifdef FMPLUS + + if (adapter->mc32_config == TRN_PCIT_BROKEN_DMA) + { + + /* + * Preserve SIFADR. + */ + + saved_sifadr = sys_insw(adapter_handle, adapter->sif_adr); + + /* + * Broken DMA is enabled so check if this was a broken + * DMA interrupt. + */ + + sys_outsw( + adapter_handle, + adapter->sif_adr, + DIO_LOCATION_DMA_CONTROL + ); + + dodgy_dma = sys_insw(adapter_handle, adapter->sif_dat); + + /* + * If there is a DMA pending then do some DMA processing. + */ + + if (dodgy_dma != 0) + { + /* + * This is not a proper SIF interrupt so note the fact. + */ + + proper_sif_int = FALSE; + + /* + * Work out where the handshake byte will be in host + * memory. + */ + + dma_handshake_addr = (BYTE FAR *) + adapter->dma_test_buf_virt + + SCB_TEST_PATTERN_LENGTH + + SSB_TEST_PATTERN_LENGTH; + + /* + * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge + * interrupt at SIF. + */ + + sys_outsw(adapter_handle, adapter->sif_int, 0); + + /* + * Set the host flag to zero. + */ + + *dma_handshake_addr = 0; + + /* + * Clear the flag on the adapter i.e. start DMA. + */ + + sys_outsw(adapter_handle, adapter->sif_dat, 0); + + /* + * Wait until the adapter puts 0x11 in our flag. + */ + + while (hwi_pcit_read_byte(dma_handshake_addr) != 0x11) + NdisStallExecution(10); + } + + /* + * Now did the adapter hint that a SIF interrupt will follow + * presently. + */ + + if (dodgy_dma == 0x2222) + { + /* + * Poll For a SIF interrupt - wait for it to stabalise at the + * same time. + */ + + timeout = 0; + + sifint_value = sys_insw(adapter_handle, adapter->sif_int); + do + { + sifint_tmp = sifint_value; + sifint_value = sys_insw(adapter_handle, adapter->sif_int); + + if (sifint_value == sifint_tmp && + (sifint_value & EAGLE_SIFINT_SYSTEM) != 0); + { + proper_sif_int = TRUE; + } + timeout++; + } + while (!proper_sif_int && timeout < 40); + } + + /* + * Restore SIFADR. + */ + + sys_outsw( + adapter_handle, + adapter->sif_adr, + saved_sifadr); + + } +#endif + } + + /* + * Now read the SIFACL register to check for a PseudoDMA interrupt. + */ + + if (adapter->transfer_mode != DMA_DATA_TRANSFER_MODE) + { + sifacl = sys_insw(adapter_handle, adapter->sif_acl); + + if ((sifacl & EAGLE_SIFACL_SWHRQ) != 0) + { + our_interrupt = TRUE; + + /* + * Using any PCI card, a software handshake must occur so that the MAC + * does not try to initiate another transfer until a point has been reached on + * the host at which the transfer has completed. If not, the following could + * happen: + * + * - The host requests the last word/byte of a receive from the card. + * - The SIF does not has the data ready. + * - Control of the bus is given to a SCSI card. + * - It bursts/does nothing in bus master mode for 16 microseconds. + * - The data becomes ready early on during these 16 microseconds and + * as a result the card software beleives that the transfer has completed. + * - The card software continues and sets up another PsDMA transfer. + * - The SCSI card finishes, but the PdDMA length is now incorrect and + * all is lost. + * + */ + + saved_sifadr = sys_insw(adapter_handle, adapter->sif_adr); + + /* + * Set the PIO_HANDSHAKE word to 0 + */ + + sys_outsw(adapter_handle, adapter->sif_adr, DIO_LOCATION_DMA_CONTROL); + sys_outsw(adapter_handle, adapter->sif_dat, 0 ); + + /* + * NB Words must be byte swapped, this is done in the SIF and + * then Ti kindly byte swap in their ASIC, so we have to do it again. + * Also beacause of a bug in the ASIC byte read/writes don't work + * so if the buffer is odd aligned the rep insw/outsw must + * mis-aligned on the host. Apparently this causes no performance + * loss on the 486 or above. + */ + + /* + * PIO interrupt has occurred. Transfer data to/from adapter. + */ + + /* + * By writing the SWHLDA bit, we "start" the transfer, + * causing the SDMA registers to mapped in. + */ + + 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); + + pio_addr_lo = sys_insw( + adapter_handle, + adapter->sif_sdmaadr); + + pio_addr_hi = (DWORD) sys_insw( + adapter_handle, + adapter->sif_sdmaadx); + + pio_address = (BYTE FAR *) ((pio_addr_hi << 16) | + ((DWORD) pio_addr_lo)); + + + /* + * 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. + */ + + sys_rep_swap_insw( + adapter_handle, + adapter->sif_sdmadat, + pio_address, + (WORD) (pio_len_bytes >> 1)); + + + if (pio_len_bytes % 2) + { + /* + * Odd length transfer, need to get the last byte, this + * is done using an in ax, dx, and the byte is in the top + * byte due to byte swapping issues. + */ + + last_byte = sys_insw( + adapter_handle, + adapter->sif_sdmadat); + + *(pio_address + pio_len_bytes - 1) = (BYTE) + ((last_byte & 0xFF00) >> 8); + + } + } + else + { + /* + * Transfer into adapter memory from the host. + */ + + sys_rep_swap_outsw( + adapter_handle, + adapter->sif_sdmadat, + pio_address, + (WORD) (pio_len_bytes >> 1)); + + if (pio_len_bytes % 2) + { + /* + * Odd length transfer, need to send the last byte, this + * is done using by writing a word, with the byte is in + * the top byte due to byte swapping issues. + */ + + last_byte = (WORD) *(pio_address + pio_len_bytes - 1); + last_byte <<= 8; + + sys_outsw( + adapter_handle, + adapter->sif_sdmadat, + last_byte); + } + } + + /* + * Wait for SWHLDA to go low, it is not safe to access normal + * SIF registers until this is the case. + */ + + do + { + sifacl = sys_insw(adapter_handle, adapter->sif_acl); + } + while (sifacl & EAGLE_SIFACL_SWHLDA); + + /* + * Now output 0xFFFF to the PIO_HANDSHAKE word, to signal + * the DMA is complete. + */ + + sys_outsw(adapter_handle, adapter->sif_dat, 0xFFFF ); + + /* + * Restore the saved SIF address. + */ + + sys_outsw(adapter_handle, adapter->sif_adr, saved_sifadr); + } + } + + /* + * Does a normal sif_int need processing as opposed to a 'dodgy' DMA + * interrupt. + */ + + if (proper_sif_int) + { + /* + * A SIF interrupt has occurred. + * This could be an SRB free, an adapter check or a received + * frame interrupt. + */ + + /* + * Clear EAGLE_SIFINT_HOST_IRQ to acknowledge interrupt at SIF. + */ + + sys_outsw(adapter_handle, adapter->sif_int, 0); + + /* + * Call driver with details of SIF interrupt. + */ + + driver_interrupt_entry(adapter_handle, adapter, sifint_value); + } + + if (our_interrupt) + { + +#ifndef FTK_NO_CLEAR_IRQ + sys_clear_controller_interrupt( + adapter_handle, + adapter->interrupt_number); +#endif + + } + + /* + * Let system know we have finished accessing the IO ports. + */ + +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif +} + + +/**************************************************************************** +* +* hwi_pcit_remove_card +* ==================== +* +* +* PARAMETERS (passed by hwi_remove_card) +* ====================================== +* +* ADAPTER * adapter +* +* This structure is used to identify and record specific information about +* the required adapter. +* +* +* BODY : +* ====== +* +* The hwi_smart16_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_pcit_remove_card) +#endif + +export void +hwi_pcit_remove_card( + ADAPTER * adapter + ) +{ + ADAPTER_HANDLE adapter_handle = adapter->adapter_handle; + WORD wGenConAddr = adapter->io_location + + PCI_GENERAL_CONTROL_REG; + WORD sifacl; + + /* + * Interrupt must be disabled at adapter before unpatching interrupt. + * Even in polling mode we must turn off interrupts at adapter. + */ + +#ifndef FTK_NO_IO_ENABLE + macro_enable_io(adapter); +#endif + + 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; + } + + /* + * Can't reset the Eagle as the reset line does not work, lets try + * hwi_halt_eagle. + */ + + hwi_halt_eagle( adapter ); + +#ifndef FTK_NO_IO_ENABLE + macro_disable_io(adapter); +#endif +} + + +/**************************************************************************** +* +* hwi_pcit_set_dio_address +* ======================= +* +* The hwi_pcit_set_dio_address routine is used, with PCI 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_pcit_set_dio_address) +#endif + +export void +hwi_pcit_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_pcit_read_node_address +| ========================== +| +| The hwi_pcit_read_node_address routine reads in the node address from +| the SEEPROM, and checks that it is a valid Madge node address. +| +---------------------------------------------------------------------------*/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_pcit_read_node_address) +#endif + +local WBOOLEAN +hwi_pcit_read_node_address( + ADAPTER * adapter + ) +{ + WORD temp; + temp = hwi_at24_read_a_word(adapter, PCIT_EEPROM_BIA_WORD0); + adapter->permanent_address.byte[0] = (BYTE) ((temp ) & 0x00ff); + adapter->permanent_address.byte[1] = (BYTE) ((temp >> 8) & 0x00ff); + + temp = hwi_at24_read_a_word(adapter, PCIT_EEPROM_BIA_WORD1); + adapter->permanent_address.byte[2] = (BYTE) ((temp ) & 0x00ff); + adapter->permanent_address.byte[3] = (BYTE) ((temp >> 8) & 0x00ff); + + temp = hwi_at24_read_a_word(adapter, PCIT_EEPROM_BIA_WORD2); + adapter->permanent_address.byte[4] = (BYTE) ((temp ) & 0x00ff); + adapter->permanent_address.byte[5] = (BYTE) ((temp >> 8) & 0x00ff); + + return TRUE; +} + +/*************************************************************************** +* * +* Local routines for accessing the AT93AT24 Serial EEPROM, this is the same* +* EEPROM fitted to the PNP card and the PCI 2 card. The only difference, is* +* that for this card the I/O is done through the PCI config space. * +* * +***************************************************************************/ + +local void hwi_at24_delay( ADAPTER * adapter ); +local void hwi_at24_set_clk( ADAPTER * adapter ); +local void hwi_at24_clr_clk( ADAPTER * adapter ); +local void hwi_at24_twitch_clk( ADAPTER * adapter ); +local void hwi_at24_start_bit( ADAPTER * adapter ); +local void hwi_at24_stop_bit( ADAPTER * adapter ); +local WBOOLEAN hwi_at24_wait_ack( ADAPTER * adapter ); +local WBOOLEAN hwi_at24_dummy_wait_ack( ADAPTER * adapter ); + + +/************************************************************************ +* +* Read the EEPROM bits +* +* The Data Bit does not always match the previously ouptut value. +* +* Inputs : Adapter structure. +* +* Outputs : Value read from control register. +* +***********************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_input) +#endif + +local BYTE hwi_at24_input( ADAPTER * adapter ) +{ + BYTE bInput; + BYTE bStore; + + sys_pci_read_config_byte(adapter->adapter_handle, EEPROM_OFFSET, &bInput); + + /* + * Store the 5 bits which don't interrest us. + */ + + bEepromByteStore = bInput & (BYTE) 0x8F; + + /* + * The bits are arranged as follows + * 0ZXY0000, + * all the above routines are generic and expect + * 00000XYZ + */ + + bStore = bInput; + bInput &= 0x40; + bInput >>= 6; + bStore &= 0x30; + bStore >>= 3; + bInput |= bStore; + + return bInput; +} + + +/************************************************************************ +* +* Write to the three EEPROM bits. +* +* Inputs : Adapter structure. +* The data to be written. +* +* Outputs : None. +* +***********************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_write_bits) +#endif + +local void hwi_at24_write_bits(ADAPTER * adapter, BYTE bValue) +{ + BYTE bTemp; + + bTemp = (BYTE)((bValue & 0x6) << 3); + bTemp |= (BYTE)((bValue & 0x1) << 6); + + /* + * Restore the 5 bits we were not interested in from the previous read. + */ + + bTemp |= bEepromByteStore; + + sys_pci_write_config_byte(adapter->adapter_handle, EEPROM_OFFSET, bTemp); + + + return; +} + + +/************************************************************************ +* +* Write to the three EEPROM bits. +* +* We have to store the DATA bit as we cannot definately read it back. +* +* Inputs : Adapter structure. +* The data to be written. +* +* Outputs : None. +* +***********************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_output) +#endif + +local void hwi_at24_output(ADAPTER * adapter, BYTE bValue) +{ + bLastDataBit = bValue & (BYTE) AT24_IO_DATA; + + hwi_at24_write_bits(adapter, bValue); + + return; +} + + +/************************************************************************ +* +* Write to the three EEPROM bits. +* +* Set the DATA bit to the most recent written bit. +* +* Inputs : Adapter structure. +* The data to be written. +* +* Outputs : None. +* +***********************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_output_preserve_data) +#endif + +local void hwi_at24_output_preserve_data( ADAPTER * adapter, BYTE bValue) +{ + bValue &= ~AT24_IO_DATA; + bValue |= bLastDataBit; + + hwi_at24_write_bits(adapter, bValue); + + return; +} + + +/************************************************************************ +* +* Delay to allow for serial device timing issues +* +* Inputs : Adapter structure +* +* Outputs : None +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_delay) +#endif + +local void hwi_at24_delay(ADAPTER * adapter) +{ + UINT i; + + for (i = 0; i < 100; 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(hwi_at24_set_clk) +#endif + +local void hwi_at24_set_clk(ADAPTER * adapter ) +{ + BYTE temp; + + temp = hwi_at24_input(adapter ); + temp |= AT24_IO_CLOCK; + + hwi_at24_output_preserve_data(adapter, temp); + + return; +} + + +/************************************************************************ +* +* Clears the serial device clock bit +* +* Inputs : Adapter structure +* +* Outputs : None +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_clr_clk) +#endif + +local void hwi_at24_clr_clk(ADAPTER * adapter ) +{ + BYTE temp; + + temp = hwi_at24_input(adapter ); + temp &= ~AT24_IO_CLOCK; + + hwi_at24_output_preserve_data(adapter, temp); + + return; +} + +/************************************************************************ +* +* hwi_at24_read_data +* Read a data bit from the serial EEPROM. It is assumed that the clock is low +* on entry to this routine. The data bit is forced high to allow access to +* the data from the EEPROM, then the clock is toggled, with a read of the +* data in the middle. +* +* Beware! The latched data bit will be set on exit. +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_read_data) +#endif + +local BYTE hwi_at24_read_data(ADAPTER * adapter) +{ + BYTE bData; + + /* + * Set the latched data bit to disconnect us from the data line. + */ + + bData = AT24_IO_ENABLE | AT24_IO_DATA; + + hwi_at24_output(adapter, bData); + + /* + * Set the clk bit to enable the data line. + */ + + hwi_at24_set_clk(adapter); + + /* + * Read the data bit. + */ + + bData = hwi_at24_input(adapter); + + /* + * Get the Data bit into bit 0. + */ + + bData &= AT24_IO_DATA; + bData >>= 1; + + /* + * Clear clock again. + */ + + hwi_at24_clr_clk(adapter); + + return bData; +} + + +/************************************************************************ +* +* hwi_at24_write_data +* +* Write a data bit to the serial EEPROM. No clock toggle is performed. +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_write_data) +#endif + +local void hwi_at24_write_data(ADAPTER * adapter, BYTE bData) +{ + BYTE bTemp; + + /* + * The bit value is in position 0, get it into position 1. + */ + + bData <<= 1; + + /* + * Not strictly neccessary, but I'm paranoid. + */ + + bData &= AT24_IO_DATA; + bTemp = hwi_at24_input(adapter); + bTemp &= ~AT24_IO_DATA; + + bTemp |= bData; + hwi_at24_output(adapter, bTemp); + + return; +} + + +/************************************************************************ +* +* hwi_at24_enable_eeprom +* +* Must be called at the start of eeprom access to ensure we can pull low +* the data and clock pins on the EEPROM. Forces the clock signal low, as part +* of the strategy of routines assuming the clock is low on entry to them. +* +* Inputs : Adapter structure +* +* Outputs : None +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_enable_eeprom) +#endif + +local void hwi_at24_enable_eeprom(ADAPTER * adapter) +{ + BYTE temp; + + temp = hwi_at24_input(adapter); + temp |= AT24_IO_ENABLE; + + hwi_at24_output(adapter, temp); + + return; +} + + +/************************************************************************ +* +* hwi_at24_start_bit +* +* Send a "START bit" to the serial EEPROM. This involves toggling the +* clock bit low to high, with data set on the rising edge and cleared on the +* falling edge. Assumes clock is low and EEPROM enabled on entry. +* +* Inputs : Adapter structure +* +* Outputs : None +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_start_bit) +#endif + +local void hwi_at24_start_bit(ADAPTER * adapter) +{ + BYTE bData; + + bData = AT24_IO_ENABLE | AT24_IO_DATA; + + /* + * Set the Data bit. + */ + + hwi_at24_output(adapter, bData); + + hwi_at24_set_clk(adapter); + + /* + * Clear the Data bit + */ + + bData = AT24_IO_ENABLE | AT24_IO_CLOCK; + hwi_at24_output(adapter, bData); + + hwi_at24_clr_clk(adapter); + + return; + +} + + +/************************************************************************ +* +* hwi_at24_stop_bit +* +* Send a "STOP bit" to the serial EEPROM. This involves toggling the +* clock bit low to high, with data clear on the rising edge and set on the +* falling edge. Assumes clock is low and EEPROM enabled on entry. +* Inputs : Adapter structure +* +* Outputs : None +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_stop_bit) +#endif + +local void hwi_at24_stop_bit(ADAPTER * adapter) +{ + BYTE bData; + + bData = AT24_IO_ENABLE; + + /* + * Clear the Data Bit. + */ + + hwi_at24_output(adapter, bData); + + hwi_at24_set_clk(adapter); + + /* + * Set the Data Bit. + */ + + bData |= (AT24_IO_DATA | AT24_IO_CLOCK); + hwi_at24_output(adapter, bData); + + hwi_at24_clr_clk(adapter); + + return; +} + + +/************************************************************************ +* +* hwi_at24_wait_ack +* +* Wait for an ack from the EEPROM. +* Outputs : TRUE or FALSE +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_wait_ack) +#endif + +local WBOOLEAN hwi_at24_wait_ack(ADAPTER * adapter) +{ + WBOOLEAN Acked = FALSE; + UINT i; + BYTE bData; + + for (i = 0; i < 10; i++) + { + bData = hwi_at24_read_data(adapter); + bData &= 1; + + if (!bData) + { + Acked = TRUE; + break; + } + } + + return Acked; +} + + +/************************************************************************ +* +* hwi_at24_dummy_wait_ack +* +* Wait for a negative ack from the EEPROM. +* +* Outputs : TRUE or FALSE +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_dummy_wait_ack) +#endif + +local WBOOLEAN hwi_at24_dummy_wait_ack(ADAPTER * adapter) +{ + WBOOLEAN Acked = FALSE; + UINT i; + BYTE bData; + + for (i = 0; i < 10; i++) + { + bData = hwi_at24_read_data(adapter); + + if (bData & 1) + { + Acked = TRUE; + break; + } + } + + return Acked; +} + + +/************************************************************************ +* +* hwi_at24_serial_read_bits +* +* Read a Byte from the serial EEPROM. +* +* NB This routine gets 8 bits from the EEPROM, but relies upon commands +* having been sent to the EEPROM 1st. In order to read a byte use +* hwi_at24_receive_data. +* +* Outputs : None +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_serial_read_bits) +#endif + +local BYTE hwi_at24_serial_read_bits(ADAPTER * adapter) +{ + BYTE bData = 0; + BYTE bBit; + UINT i; + + for (i = 0; i < 8; i++) + { + /* + * The EEPROM clocks data out MSB first. + */ + + bBit = hwi_at24_read_data( adapter ); + bData <<= 1; + bData |= bBit; + } + + return bData; +} + + +/************************************************************************ +* +* hwi_at24_serial_write_bits +* +* Send 8 bits to the serial EEPROM. +* +* Outputs : None +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_serial_write_bits) +#endif + +local void hwi_at24_serial_write_bits(ADAPTER * adapter, BYTE bData) +{ + BYTE bBit; + UINT i; + + for ( i = 0; i < 8; i++) + { + bBit = (BYTE)(bData >> (7-i)); + bBit &= 1; + hwi_at24_write_data(adapter, bBit); + + /* + * Toggle the clock line to pass the data to the device. + */ + + hwi_at24_set_clk(adapter); + hwi_at24_clr_clk(adapter); + } + + return; +} + + +/************************************************************************ +* +* hwi_at24_serial_send_cmd +* +* Send a command to the serial EEPROM. +* +* Outputs : TRUE if sent OK +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_serial_send_cmd) +#endif + +local WBOOLEAN hwi_at24_serial_send_cmd( ADAPTER * adapter, BYTE bCommand ) +{ + UINT i = 0; + WBOOLEAN Sent = FALSE; + + while ((i < 40) && (Sent == FALSE)) + { + i++; + + /* + * Wake the device up. + */ + + hwi_at24_start_bit(adapter); + + hwi_at24_serial_write_bits( adapter, bCommand); + + Sent = hwi_at24_wait_ack(adapter); + } + + return Sent; +} + + +/************************************************************************ +* +* hwi_at24_serial_send_cmd_addr +* +* Send a command and address to the serial EEPROM. +* +* Outputs : TRUE if sent OK +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_serial_send_cmd_addr) +#endif + +local WBOOLEAN hwi_at24_serial_send_cmd_addr( + ADAPTER * adapter, + BYTE bCommand, + BYTE bAddr + ) +{ + WBOOLEAN RetCode; + + RetCode = hwi_at24_serial_send_cmd(adapter, bCommand); + + if (RetCode) + { + hwi_at24_serial_write_bits(adapter, bAddr); + + RetCode = hwi_at24_wait_ack(adapter); + } + + return RetCode; +} + + +/************************************************************************ +* +* hwi_at24_serial_receive_data +* +* Having set up the address we want to read from, read the data. +* +* Outputs : Data read back. +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_serial_receive_data) +#endif + +local BYTE hwi_at24_serial_receive_data(ADAPTER * adapter) +{ + BYTE bData; + WBOOLEAN Acked; + + bData = hwi_at24_serial_read_bits(adapter); + + Acked = hwi_at24_dummy_wait_ack(adapter); + + if (!Acked) + { + bData = 0xFF; + } + + return bData; +} + + +/************************************************************************ +* +* hwi_at24_serial_read_byte +* +* Read a byte of data from the specified ROM address +* +* Outputs : Data read back. +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_serial_read_byte) +#endif + +local BYTE hwi_at24_serial_read_byte(ADAPTER * adapter, BYTE bAddr) +{ + BYTE bData; + + hwi_at24_enable_eeprom(adapter); + + /* + * Send the serial device a dummy WRITE command + * that contains the address of the byte we want to + * read ! + */ + + hwi_at24_serial_send_cmd_addr(adapter, AT24_WRITE_CMD, bAddr); + + /* + * Send the read command. + */ + + hwi_at24_serial_send_cmd(adapter, AT24_READ_CMD); + + /* + * Read the data. + */ + + bData = hwi_at24_serial_receive_data(adapter); + + /* + * Deselect the EEPROM. + */ + + hwi_at24_stop_bit( adapter ); + + return bData; +} + + +/************************************************************************ +* +* hwi_at24_read_a_word +* +* Read a word of data from the specified ROM address +* +* Outputs : Data read back. +* +************************************************************************/ + +#ifdef FTK_INIT_FUNCTION +#pragma FTK_INIT_FUNCTION(hwi_at24_read_a_word) +#endif + +local WORD hwi_at24_read_a_word(ADAPTER * adapter, WORD word_address) +{ + WORD wData; + BYTE bLoByte; + BYTE bByteAddress = (BYTE) ((word_address * 2) & 0xFF); + + bLoByte = hwi_at24_serial_read_byte(adapter, bByteAddress); + + wData = (WORD) hwi_at24_serial_read_byte( + adapter, + (BYTE) (bByteAddress + 1)); + + wData <<= 8; + wData |= bLoByte; + + return wData; +} + +#endif + + +/******* End of HWI_PCIT.C **************************************************/ |