ne3200.386

Warning: This file has been marked up for HTML

page ,130
;***********************************************************************
; $name: ne3200.386
; $version: 6
; $date_modified: 121898
; $description: NE3200 LAN Driver
; $owner: ODI LAN Driver Manager
; Copyright (c) 1991 - 1998 Novell, Inc. All Rights Reserved.
;
; THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
; USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
; ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS THIS WORK.
; PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
; ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
; PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
; DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
; PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
; CUSTOMERS WITH RESPECT TO THIS CODE.
;***********************************************************************
;
; BEGIN_MANUAL_ENTRY( History, NE3200/HISTORY )
;
;   Novell NE3200 Driver Code for NetWare 386.
;
;   This driver must be loaded after MSM.NLM and ETHERNET.NLM.
;
;   Written by:   DFS
;   Date:      January, 1991
;
;***********************************************************************
;
; History Log:
;
; 06-10-91 dfs   Modified driver to new MSM spec and enabled interrupts.
;
; 09-03-91 dfs   Converted to NLM.(Version 3.20)
;
; 12-16-92 dfs   - Rejected bad ECB pointers from Type 4 NLMs.
;      - Rejected Packets who's fragment counts exceed 1514.
;      - Added 2 second Transmit Timeout.(Version 3.21)
;
; 01-05-93 dfs   Added support for DriverEnableInterrupt/DriverDisableInterrupt.
;
; 01-20-93 dfs   Limited firmware to 16 fragments instead of 15.
;
; 02-03-93 dfs   Removed MSMRescheduleLast from DriverReset.
;
; 02-08-93 dfs   Increased RCB's allocated to 16 and table sizes to 32. 
;
; 03-30-93 dfs   Fixed DriverSend to convert ECB to Physical Address.
;      (Version 3.22)
;
; 05-12-93 dfs   - Set default back to polling(POLL=0 disables polling).
;      - Defaulted board numbers to -1 for clients.
;      - Used EtherTSMRcvCompleteStatus instead of EtherTSMRcvComplete.
;      - Allowed 2K packets to be received by receive monitor.
;      - Fixed receive error status bit bugs.
;      - Allowed 14 byte packets to be received.
;      (Version 3.23)
;
; 10-05-93 dfs   - Added support for DriverSupportsPhysFrags.
;      - Stopped checking for Product ID 2(01) at init.
;      (Version 3.24)
;
; 02-11-94 akw  - Changed the shared interrupt check from the DriverISR routine
;                 to the DriverDisableInterrupt routine.  This will enable the
;                 the MSM to call other adapters if the interrupt is NOT ours.
;      - Changed the # of TX BUFFERS from 10 to 4 in ADAPTER.386.
;               - Added support to flag TxTooBig packets and increment counter.
;                 - Added HSM_SPEC_VERSION string.
;      (Version 3.25)
;
; 03-24-94 stc  - Changed driver send and send complete code in both the host and
;        firmware code to handle fast back-to-back send of more than two
;        packets.  Changed use of TCB valid mailbox to indicate current
;        tx queue index.
;      (Version 3.25)
;
; 04-13-94 akw  - Changed adapter receive code to not only simply stuff the 
;                 WORD sized board number into the RxECB, but to clear the 
;                 upper WORD as well.
;
; 04-21-94 akw  - Added code to SAVE the RProtocolWorkspace field of the
;                 Rx ECB before handing it to the adapter.  Then when the
;                 adapter is through with it, I restore the field.
;
; 06-28-94 akw  - Bumped TOTAL_EISA_SLOTS from 8 to 15 to allow new machines
;                 with additional slots to run this adapter.
;                 (Version 3.27)
;
;
; 4 May 1995 15:36   DGM
;
;   Added code to DriverDisableInterrupt and DriverEnableInterrupt to
;   remove spurious interrupt problem (clearing a pending interrupt
;   when enabling adapter).  Corrected DriverDisableInterrupt to
;   disable the adapter's interrupt even when it's not the adapter's
;   as per spec.
;
;   Also added code to reject interrupts as ours if we have already 
;   been disabled. Added code in DriverDisableInterrupt and
;   DriverEnableInterrupt to set and clear added InDriverDisable flag.
;
;   Altered input parameters to DriverDisableInterrupt to allow for
;   0/1 inputs, also changed initial code in DriverDisableInterrupt 
;   to first test if we are disabled.
;
;   Bumped version number in makefile from 3,2X.
;
; 5 May 1995 8:30   DGM
;   Done repair on Adapter firmware, as seeing problems with version 3.50.
;   Pulled back orig. code 06-28-94 and re-implemented changes and fixes.
;
;   Added code in DriverInit to utilize MSMGetPollSupportLevel which 
;   returns poll support level.  This implies that in SMP OS's the
;   NE3200 will operate in Interrupt Only mode.  This reduces the 
;   number of mutexs obtained due to polling routines being continually
;   called.
;
;   Bumped version number in makefile 3,53
;
; 27 July 1995 4:40    TNL
;       Fixed bug in \ introduced in 4-21-94 change.
;
;   Changed InDriverInit flag usage and changed name to InDriverReset
;   so that DriverShutdown and DriverMulticastChange behave correctly
;   when called with DriverReset.
;
; 14 September 1995  11:00 MPK
;       Made changes to make code compatable with 3.3 specification.
;       Includes changes to DriverConfigTemplate (versions and Scatter
;       gap count,  Also added changes to initialization, to determine
;       BUS by use of NBI calls.
;
; 23 February 1996  11:00 TNL
;   Modified DriverInit to call MSMScheduleIntTimeCallback and 
;   MSMSetHardwareInterrupt in the correct order as described in the
;   spec.
;
; 26 February 1996  11:00 TNL
;   Modified DriverInit to use NBI calls to get EISA config info.
;   See 'if UseNBICalls' code sections.
;
; 05 March 1996     12:00 LON
;   Single sourced the NE3200 and the NE3200P. Used existing NE3200
;   base and added the Promiscuous code.
;
; 29 March 1996     12:00 TNL
;   Modified DriverInit to call MSMReturnDriverResources only when
;   appopriate. SPD #121142.
;
; 29 March 1996      1:30 LON
;   Removed unneeded Ne3200Promisc. code due to compiler warning. The
;   code (offset RBDWrappedCount) was there only for maintaining code.
;
; 26 April 1996      3:30 LON
;   Added comments for clarification.
;
; 29 April 1996      6:00 LON
;   The SMP driver load/unload test was failing due to a timing window
;   where interrupts were still enabled during permanent driver shutdown.
;   This allowed the DriverISR routine to allocate RCBs before the
;   driver was unloaded (SPD 124131).
;
; 12 June 1996       2:00 LON
;   During multiple DriverReset calls, the adapter would appear to not
;   reset in fast PCI/EISA boxes. In reality the adapter needed more
;   time to initialize after being reset in DriverShutdown. When
;   DriverReset detects the adapter failed to reset, the code will now
;   call DriverShutdown up to 3 times, giving the adapter another
;   chance to reset (SPD 128318).
;
; 11-25-96 PM   Modified DriverParameterBlock structure to add the following
;      fields immediately after DriverDisableInterrupt field in
;       accordance with 3.31 specs. SPD #141183:
;         - DriverISR2Ptr - Null entry
;         - DriverReserved2 - Null entry
;         - HSMSpecVerString - pointer to spec version string
;         - DriverPriorityQueuePtr - Null entry
;         - DriverDisableInterrupt2Ptr - Null entry
;
; 11-25-96 PM   Modified Config Table template to change the following in
;      accordance with 3.31 specs. SPD #141183:
;         - changed MLIDCFG_MinorVersion from 13 to 14
;         - splited up MLIDReserved field that follows
;         -  MLIDCFG_SGCount into the following fields:
;            - MLIDReserved1
;            - MLIDPrioritySup
;            - MLIDReserved2
;         - changed MLIDIOCfgMajorVersion from 00 to 01
;
; 11-25-96 PM   Modified DriverReset and DriverShutdown routines to add
;      operation scope parameter. SPD #141329
;
; 01-08-97 PM   Modified DriverInit routine to point EAX to a valid error 
;      message before calling MSMPrintSting in case the load fails
;      due to some condition.
;
; 07-22-97 JCJ  DriverReset and DriverShutdown are modified to update adapter 
;      about the Shutdown status. SPD #160930
;
; 09-18-97 JCJ  If adapter provides 100% filtering of group addresses and
;               the TSM does not need to perform any checking, then bits 10&9
;               of MLIDFlags should be set. SPD# 165219, 165221.
;
; 12-22-97 LON The AdapterOptionDefinitionStructure had undefined fields (?),
;              which can cause abends. All fields are now defined, SPD 174679.
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
;
   name   NE3200
   title   NE3200 LAN Driver (HSM Version)
   subttl   -- Structures and Equate Values --
   page
DEBUG         equ   0
CheckTCBs      equ   0
CatchIncomplete      equ   0

include         driver.inc

BusMaster      equ   -1
UseFastCalls      equ   -1
AddPolling      equ   -1
TxQueue         equ   -1
SupportJabber      equ   -1
UseNBICalls      equ   -1

;***********************************************************************\
;                                                                       *
; NE3200 Equates.                     *
;                                                                       *
;***********************************************************************/
;
DEFAULT_TIMEOUT_VALUE   equ   2      ; Default Poll timeout.

;***************************************************************\
;                                                               *
; Commands to Pass to the NIC's mailbox's.         *
;                                                               *
;***************************************************************/
;
ADD_MULTICAST_COMMAND   equ   1      ; Update Multcast list.
IDLE_COMMAND      equ   4      ; Idle the NIC firmware.

;***************************************************************\
;                                                               *
; Loop counter equates.                  *
;                                                               *
;***************************************************************/
;
RESET_BASE_COUNT   equ   200      ; Speed from slow 386.

;***************************************************************\
;                                                               *
; EISA slot equates.                  *
;                                                               *
;***************************************************************/
;
TOTAL_EISA_SLOTS   equ   15
MANUFACTURE_CHAR_CODE_1   equ   3Ah      ; Computed from the
MANUFACTURE_CHAR_CODE_2   equ   0CCh      ;  code "NVL 07 01".
PRODUCT_NUMBER_1   equ   07
PRODUCT_NUMBER_2   equ   01
PRODUCT_NUMBER_2b   equ   02


;***************************************************************\
;                                                               *
; BMIC port structure.                  *
;                                                               *
;***************************************************************/
;
BMICIOStructure   struc
   ID               db   4 dup (?)
   Reserved0            db   4 dup (?)
   GlobalConfigurationRegister      db   ?
   SystemInterruptMaskControlRegister   db   ?
   Semaphores            db   2 dup (?)
   LocalDoorbellMaskRegister      db   ?
   LocalDoorbellInterruptStatusRegister   db   ?
   SystemDoorbellMaskRegister      db   ?
   SystemDoorbellInterruptStatusRegister   db   ?
   MailboxRegisters         db   16 dup (?)
   Reserved1            db   16 dup (?)
BMICIOStructure   ends

;***************************************************************\
;                                                               *
; Equates and structures used in performing BIOS calls.      *
;                                                               *
;***************************************************************/
;
ISOLATE_INT_MASK   equ   00001111b
EISA_INT_FUNCTION_BIT   equ   00000100b

;***************************************************************\
;                                                               *
; Miscellaneous driver equates.               *
;                                                               *
;***************************************************************/
;
TOTAL_RCBS      equ   10h
TABLE_SIZE      equ   20h
TABLE_MASK      equ   TABLE_SIZE-1

TCB_TABLE_SIZE      equ   256
TOTAL_TCBS      equ   128

;***************************************************************\
;                                                               *
; ASCII String equates.                  *
;                                                               *
;***************************************************************/
;
BEEP         equ   07h         ; Bell.
LF         equ   0Ah         ; Line Feed.
CR         equ   0Dh         ; Carriage Return.

;***********************************************************************\
;                                                                       *
; NE3200 Structures.                     *
;                                                                       *
;***********************************************************************/


;***************************************************************\
;                                                               *
; Start of the Adapter Data Space structure for NE3200.      *
;                                                               *
;***************************************************************/
;
                        ;JCP
GenericVariableBegin    equ     offset TotalTxPacketCount       ;941130 *Begin*
GenericVariableEnd      equ     offset CustomVariableCount
CustomVariableBegin     equ     offset TxRetryFailure
CustomVariableEnd       equ     offset VectorToTheStrings       ;941130 *End*

DriverAdapterDataSpace   struc
;
;***************************************************************\
;                                                               *
; I/O port register variables.               *
;                                                               *
;***************************************************************/
;
ResetRegister         dd   0   ; Reset Port.
EisaSystemDoorbellEnable   dd   0   ; BMIC Doorbell Enable.
EisaSystemDoorbellStatus   dd   0   ; BMIC Doorbell Status.
IdleMailbox         dd   0   ; Idle adapter Mailbox(1 byte).
UpdateParmMailbox      dd   0   ; Update parm mail(1 byte)
UpdateStatMailbox      dd   0   ; Update stat mail(1 byte)
TCBValidMailbox         dd   0   ; TCB Valid Mail(1 byte port).
;PollingMailbox                 dd      0 dup (0) ; JCP, 941130.
TCBMailbox         dd   0   ; TCB  Mailbox(4 byte port).
ParametersMailbox      dd   0   ; Parm Mailbox(4 byte port).
;
;--------------------------------------------------------------\
;                                                               *
; Adapter Parameter Block. Do not change the order of the   *
; following 12 fields.                  *
;                                                               *
;---------------------------------------------------------------/
;
LogicalToPhysicalOffset      dd   0
NodeAddressPointer      dd   0
BoardNumber8023         dw   -1
BoardNumberEII         dw   -1
BoardNumber8022         dw   -1
BoardNumberSNAP         dw   -1
MaxReceivePacketSize      dd   0
GenericStatisticsPointer   dd   0
CustomStatisticsCount      dw   0
RCBListPointer         dd   0
MulticastCount         dw   0
MulticastTablePointer      dd   0
HostNodeAddress         db   6 dup (0)
PromiscuousMode         db   0
PollTimeout         dw   DEFAULT_TIMEOUT_VALUE   ;#
GlobalConfigValue      db   00001110b
            dw   ?   ; DWORD align
;;IF DEBUG
;;DiagnosticBufferPointer      dd   0   ;Diagnostic dump
;;ENDIF

;
; Must be DWORD aligned.
;
;---------------------------------------------------------------\
;                                                               *
; Command Parameter storage location.            *
;                                                               *
;---------------------------------------------------------------/
;
ParameterCommand   dd   0      ; Command to NIC.
Parameter1      dd   0      ; Parameter 1.
Parameter2      dd   0      ; Possible Parameter 2.
;
;---------------------------------------------------------------\
;                                                               *
; Receive and Transmit Pointers.            *
;                                                               *
;---------------------------------------------------------------/
;
ReceiveQueueHead   dd   0      ; Point to first RCB.
ReceiveQueueTail   dd   0      ; Point to last RCB.
NeedRCBCount      dd   TOTAL_RCBS   ; RCB's currently needed.
;
; !!! Important - This list must be dword aligned !!!
; The BMIC locked exchange only works on dword boundaries.
;
; NOTE: AdapterRCBList and HostRCBList are circular queues of pointers which
; point to the exact same ECBs(RCBs). Except AdapterRCBList has the physical
; address of the ECB and HostRCBList has the logical address. When the
; firmware (i.e. Adapter.asm) has received an incoming frame, the firmware
; overwrites the ECB physical address (in AdapterRCBList) with a value of
; Zero. This serves to notify the HSM (Ne3200.386) that the ECB is complete
; and needs to be processed. When the ECB is processed, Ne3200.386
; uses the logical address of the ECB from the HostRCBList.
;

AdapterRCBList      dd   TABLE_SIZE dup (-1)   ; Phys. adr of ECB.
AdapterTCBList      dd   TCB_TABLE_SIZE dup (-1)   ; if TxQueue
;
; HostPWSList1-2 is used for saving/restoring the ECB's RProtocolWorkspace.
HostPWSList1      dd   TABLE_SIZE dup (0)
HostPWSList2      dd   TABLE_SIZE dup (0)

HostRCBList      dd   TABLE_SIZE dup (0)   ; Logical adr of ECB
HostTCBList      dd   TCB_TABLE_SIZE dup (0)   ; if TxQueue
TxStartList      dd   TCB_TABLE_SIZE dup (0)   ; if TxQueue

TCBQueueHead      dd   0      ; if TxQueue
TCBQueueTail      dd   0      ; if TxQueue

TCBInProcess      dd   0      ; Transmit Sending to NIC.
TxStartTime      dd   0      ; Send Time out flag.
UpdateStatCount         dd      0               ; Update StatTable every 4 sec.

;
;---------------------------------------------------------------\
;                                                               *
; In Driver Procedure flags.               *
;                                                               *
;---------------------------------------------------------------/
;
InDriverPoll      dd   0      ; In Driver Poll flag.
;;TNL InDriverInit   dd   0      ; In Driver Init flag.
InDriverReset      dd   0      ; In Driver Reset flag.
InDriverDisable      dd   0      ; In Driver Disable Flag.
DriverShutdownType   dd   0      ; 1=PartialShutdown, 0=Permanent.

;---------------------------------------------------------------\
;                                                               *
; Diagnostic structures and variables              *
;                                                               *
;---------------------------------------------------------------/
;

;;IF DEBUG
;;   ALink         dd   ?
;;   AWakeUpDelayAmount   dd   10      ;Not changed
;;   AWakeUpTime      dd   ?
;;   AProcessToCall   dd   WriteDiagnosticFile    ;Not changed
;;   ARTag         dd   ?      ;Not changed
;;   AOldLink      dd   ?

;;   DirEntryPtr   dd   ?
;;   DirNumber   dd   ?
;;   FileHandle   dd   ?
;;   BufferAddress   dd   0
;;   ErrorInstance   dd   0
;;   FilePathStr   db   6,'SYSTEM',12
;;   FileName   db   'NE32DMPx.xxx'
;;ENDIF
;
;---------------------------------------------------------------\
;                                                               *
; Statistics table (This matches the struc in ASTRUC.INC).   *
;                                                               *
;---------------------------------------------------------------/
;
StatisticsVersion       db   03, 00
GenericVariableCount   dw   (GenericVariableEnd - GenericVariableBegin) / 4
;;;dgm   NotSupportedMask0   dd   11110010110010000000000000000011b
NotSupportedMask0   dd   11101010000010000000000000100010b

;GenericVariableBegin           db      0 dup (?)       ; JCP, 941130.
   TotalTxPacketCount      dd   0      ; 1 - (Used by MSM)
   TotalRxPacketCount      dd   0      ; 1 - (Used by MSM)
   NoECBAvailableCount     dd   0      ; 1 - (Used by MSM)
   PacketTxTooBigCount   dd   0      ; 0 - Used by driver
   PacketTxTooSmallCount   dd   0      ; 1 - not used
   PacketRxOverflowCount   dd   0      ; 0 - Used by driver
   PacketRxTooBigCount   dd   0      ; 1 - not used
   PacketRxTooSmallCount   dd   0      ; 0 - not used
   PacketTxMiscErrorCount   dd   0      ; 0 - used by driver
   PacketRxMiscErrorCount   dd   0      ; 0 - used by driver
   RetryTxCount      dd   0      ; 0 - Used by driver
   ChecksumErrorCount   dd   0      ; 0 - Used by driver
   HardwareRxMismatchCount   dd   0      ; 1 - (Used by MSM)
   TotalTxOKByteCountLow   dd   0      ; 0 - Used by MSM
   TotalTxOKByteCountHigh   dd   0      ; 0 - Used by MSM
   TotalRxOKByteCountLow   dd   0      ; 0 - Used by MSM
   TotalRxOKByteCountHigh   dd   0      ; 0 - Used by MSM
   TotalGroupAddrTxCount   dd   0      ; 0 - Used by MSM
   TotalGroupAddrRxCount   dd   0      ; 0 - Used by MSM
   AdapterResetCount   dd   0      ; 0 - Used by HSM driver
   AdapterOprTimeStamp   dd   0      ; 0 - Used by MSM
   QDepth         dd   0      ; 0 - Used by MSM

   TxOKSingleCollision   dd   0      ; 0 - Used by driver
   TxOKMultipleCollisions   dd   0      ; 0 - Used by driver
   TxOKButDeferred      dd   0      ; 1 - not used
   TxAbortLateCollision   dd   0      ; 0 - Used by driver
   TxAbortExcessCollisions   dd   0      ; 0 - Used by driver
   TxAbortCarrierSense   dd   0      ; 0 - Used by driver
   TxAbortExDeferral   dd   0      ; 1 - not used
   RxAbortFrameAlignment   dd   0      ; 0 - Used by driver
;GenericVariableEnd             db      0 dup (?)       ; JCP, 941130.

CustomVariableCount      dw   (CustomVariableEnd - CustomVariableBegin) / 4

;CustomVariableBegin            db      0 dup (?)   ; JCP, 941130.
   TxRetryFailure      dd   0   ; Tx Retry failure.
   ClearToSend      dd   0   ; Tx Clear To Send.
   UnderRun      dd   0   ; Tx DMA Underrun.
   RxDMAOverrun      dd   0   ; Rx DMA Overrun.
   PacketSlideCount   dd   0   ; Rcv frames not matching our
                  ;  MC table or node IA adr.
   ; IFDEF NE3200P
   ; Wrapping of rcv frame data buffer caused an extra BMIC xfer (3 total).
   ;
   ; RBDWrappedCount      offset PacketSlideCount

   DummyRCBCount      dd   0   ; Rx Dummy RCB used.
   AdapterReset1      dd   0   ; Adapter Reset
   BadFragLengthCount   dd   0   ; Mondo Frag length.
   PollingTimeout      dd   0   ; Poll Timeout.
   AdapterDied      dd   0   ; Dead hardware.
   NumberOfIntsFired   dd   0   ; if AddPolling
;CustomVariableEnd              db      0 dup (?)       ; JCP, 941130.

VectorToTheStrings   dd   offset DiagnosticsStrings

AlignDEndVA      db   (4 - offset (AlignDEndVA and 3)) and 3 dup (?)   ; Align 4 for MOVSD

DriverAdapterDataSpace   ends

;***************************************************************\
;***************************************************************/


PollingMailbox          equ     offset TCBMailbox ; JCP, 941130.


   subttl   -- OSDATA Data Segment --
   page
   assume   cs: OSCODE, ds: OSDATA, es: OSDATA, ss: OSDATA
;
;***********************************************************************\
;                                                                       *
; The following variables are common to the entire driver.      *
;                                                                       *
;***********************************************************************/
;
OSDATA   segment rw public 'DATA'

HSMSPEC                 db      'HSM_SPEC_VERSION: 3.31',0
;
;***************************************************************\
;                                                               *
; Statistic Diagnostic Strings.               *
;                                                               *
;***************************************************************/
;
DiagnosticsStrings   dw   (EndOfStrings-DiagnosticsStrings)

   db   'Transmit Retry Failure:', 0
   db   'Tx Clear To Sends Errors:', 0
   db   'Tx DMA Underrun Errors:',0
   db   'Rx DMA Overrun Errors:', 0

IFNDEF  NE3200P
   db      'Rx Packet Slide Errors:', 0
ELSE
   db      '3 BMIC receive transfers:', 0
ENDIF
   db   'Rx Dummy RCB Used Errors:', 0
   db   'Internal Adapter Reset:', 0
   db   'Mondo Fragment Length Errors:', 0
;;if CatchIncomplete
;;   db   'Adapter Incomplete Errors:', 0
;;   db   'Host Incomplete Error:', 0
;;endif
   db   'Polling Timeout:', 0            ;#
   db   'Reset Because Hardware Died Errors:', 0
if AddPolling
   db   'Number Of Interrupts Fired:', 0
endif
   db   0,0

EndOfStrings   equ   $


;***************************************************************\
;                                                               *
; Driver Parameter Block to pass to MSM.         *
;                                                               *
;***************************************************************/
;
   public   DriverFirmwareSize
   align   4
DriverParameterBlock      label   dword
DriverParameterSize      dd   DriverParameterBlockSize
DriverStackPointer      dd   0
DriverModuleHandle      dd   0
DriverBoardPointer      dd   0
DriverAdapterPointer      dd   0
DriverConfigTemplatePtr      dd   DriverConfigTemplate
DriverFirmwareSize      dd   -1
DriverFirmwareBuffer      dd   0
DriverNumKeywords      dd   1
DriverKeywordText      dd   NE3200KeywordText
DriverKeywordTextLen      dd   NE3200TextLen
DriverProcessKeywordTab      dd   NE3200ProcessKeywordTab
DriverAdapterDataSpaceSize   dd   SIZE DriverAdapterDataSpace
DriverAdapterTemplate      dd   DriverAdapterDataSpaceTemplate
DriverStatisticsTable      dd   StatisticsVersion
DriverEndOfChainFlag      dd   0
DriverSendWantsECBs      dd   -1         ; want ECBs
DriverMaxMulticast      dd   20
DriverNeedsBelow16Meg      dd   0
DriverAESPtr         dd   0
DriverCallBackPtr      dd   offset DriverCallBack
DriverISRPtr         dd   offset DriverISR
DriverMulticastChangePtr   dd   offset DriverMulticastChange
if AddPolling
DriverPollPtr         dd   offset DriverPoll
else
DriverPollPtr         dd   0
endif
DriverResetPtr         dd   offset DriverReset
DriverSendPtr         dd   offset DriverSend
DriverShutdownPtr      dd   offset DriverShutdown
DriverTxTimeoutPtr      dd   0
DriverPromiscuousChangePtr   dd   offset DriverPromiscuousChange
DriverStatisticsChangePtr   dd   offset DriverStatisticsChange ; JCP, 941130.
DriverRxLookAheadChangePtr   dd   0
DriverManagementPtr      dd   0
DriverEnableInterruptPtr   dd   offset DriverEnableInterrupt
DriverDisableInterruptPtr   dd   offset DriverDisableInterrupt

DriverISR2Ptr         dd   0
DriverReserved2         dd   0
HSMSpecVerString      dd   offset HSMSPEC
DriverPriorityQueuePtr      dd   0
DriverDisableInterrupt2Ptr   dd   0

DriverParameterBlockSize   equ   $ - DriverParameterBlock
;
;***************************************************************\
;                                                               *
; Copy of Virtual Adapter Data area to be copied at      *
; initialization.                  *
;                                                               *
;***************************************************************/
;
DriverAdapterDataSpaceTemplate   DriverAdapterDataSpace   <>

;DriverConfigTemplate    db      0 dup (?)      ; JCP, 941130.
DriverConfigTemplate     label   byte           ; JCP, 941130.
   db   'HardwareDriverMLID        '   ; [ebx].MLIDCFG_Signature
   db   01            ; [ebx].MLIDCFG_MajorVersion
   db   14            ; [ebx].MLIDCFG_MinorVersion
   db   6 dup (0ffh)         ; [ebx].MLIDNodeAddress
if BusMaster
   dw   0011000001001001b      ; [ebx].MLIDModeFlags
else
   dw   0010000001001011b      ; [ebx].MLIDModeFlags
endif
   dw   0000            ; [ebx].MLIDBoardNumber
   dw   0000            ; [ebx].MLIDBoardInstance
   dd   00000000         ; [ebx].MLIDMaximumSize
   dd   00000000         ; [ebx].MLIDMaxRecvSize
   dd   00000000         ; [ebx].MLIDRecvSize
   dd   00000000         ; [ebx].MLIDCardName
   dd   DriverNICShortName      ; [ebx].MLIDshortName
   dd   00000000         ; [ebx].MLIDFrameType
   dw   0000            ; [ebx].MLIDReserved0
   dw   0000            ; [ebx].MLIDFrameID
   dw   0001            ; [ebx].MLIDTransportTime
   dd   000000000         ; [ebx].MLIDRouteHandler
   dw   10            ; [ebx].MLIDLineSpeed
   dw   0000            ; [ebx].MLIDLookAheadSize
        db      17                              ; [ebx].MLIDCFG_SGCount
   db      00                           ; [ebx].MLIDReserved1
   dw   0000            ; [ebx].MLIDPrioritySup
        dd   00000000         ; [ebx].MLIDReserved2
   db   00            ; [ebx].MLIDMajorVersion
   db   00            ; [ebx].MLIDMinorVersion
;JCJ: 18-Sep-97 SPD# 165219, 165221
;If adapter provides 100% filtering of group addresses and the TSM does
;not need to perform any checking bits 10&9 of MLIDFlags should be set.
        dw      0000011000000000b               ; [ebx].MLIDFlags
   dw   0005            ; [ebx].MLIDSendRetries
   dd   00000000         ; [ebx].MLIDLink
   dw   IOShareInterrupt0Bit      ; [ebx].MLIDSharingFlags
   dw   0000            ; [ebx].MLIDSlot
   dw   0300h, 30h, 0, 0      ; [ebx].MLIDIOPortsAndLengths
   dd   00000000         ; [ebx].MLIDMemoryDecode0
   dw   0000            ; [ebx].MLIDLength0
   dd   00000000         ; [ebx].MLIDMemoryDecode1
   dw   0000            ; [ebx].MLIDLength1
   db   0FFh, 0FFh         ; [ebx].MLIDInterrupt
   db   0FFh, 0FFh         ; [ebx].MLIDDMAUsage
   dd   00000000         ; [ebx].MLIDResourceTag
   dd   00000000         ; [ebx].MLIDConfiguration
   dd   00000000         ; [ebx].MLIDCommandString
   db   18 dup (0)         ; [ebx].MLIDLogicalName
   dd   00000000         ; [ebx].MLIDLinearMemory0
   dd   00000000         ; [ebx].MLIDLinearMemory1
   dw   0000            ; [ebx].MLIDChannelNumber
        dd      00000000                        ; [ebx].MLIDBusTag
        db      01                              ; [ebx].MLIDIOCfgMajorVersion
        db      00                              ; [ebx].MLIDIOCfgMinorVersion

IFNDEF NE3200P
Message      DriverNICShortName,   'NE3200'
ELSE
Message      DriverNICShortName,   'NE3200P'
ENDIF

if UseNBICalls

;
;***********************************************************************\
;                                                                       *
; Parameters required by NBI Calls                              *
;                                                                       *
;***********************************************************************/
;

CFG_BUFFER_SIZE      equ   320      ; Size of EISA cfg block

ProductID   db   MANUFACTURE_CHAR_CODE_1, MANUFACTURE_CHAR_CODE_2
      db   PRODUCT_NUMBER_1, PRODUCT_NUMBER_2   
ConfigBuffer   db   CFG_BUFFER_SIZE dup (0)

endif


;***************************************************************\
;                                                               *
; Parameters required by ParseDriverParameters.         *
;                                                               *
;***************************************************************/
;
SlotsWithMyBoardCount   dd   0
SlotsWithMyBoard   dd   TOTAL_EISA_SLOTS dup (0)

AdapterOptions   AdapterOptionDefinitionStructure  < SlotsWithMyBoardCount,0,0,0,0,0,0,0,0,0,0,0,0,0 >

CountForLoop      dd   600000         ; Force to minimum.

CountForReset      dd   RESET_BASE_COUNT * 5   ; Force to minimum.

CommonMaximumSize   dd   0         ; Max Packet size.

EISAInterruptField   db   0
;
;***************************************************************\
;                                                               *
; Top Of Physical Memory variables.            *
;                                                               *
;***************************************************************/
;
SystemMemoryMap      dd   (2 * 8) dup (0)
if CheckTCBs
TopOfPhysicalMemory   dd   0
endif
;
;***************************************************************\
;                                                               *
; Custom Keyword information.               *
;                                                               *
;***************************************************************/
;
; Poll = <TIMEOUT> or 0 to disable polling.
;
PollText      db   'POLL'      ; POLL = keyword.
PollTextLen      equ   $-PollText OR T_HEX_NUMBER
         dd   0      ; Minimum.
         dd   0ffffh      ; Maximum.
NE3200KeywordText   dd   PollText   ; First Keyword.
NE3200TextLen      dd   PollTextLen   ; First Keywords length.

NE3200ProcessKeywordTab   dd   PollTimeoutRoutine
PollingTimeoutValue   dd   0
;
;***************************************************************\
;                                                               *
; Hardware Initialization Error Messages.         *
;                                                               *
;***************************************************************/
;
NoBoardsFound      db   050, 00, 'The board cannot be found.', CR, LF, 0
EisaBiosReadErrorMsg   db   234, 00, 'The board cannot read the configuration.', CR, LF, 0
NoIntMsg      db   235, 00, 'No interrupt was selected. The board must be reconfigured.', CR, LF, 0
NoFirstRCBMsg      db   236, 00, "No RCBs are available for the board to initialize.", CR, LF, 0
FirmwareInitErrorMsg   db   237, 00, 'The firmware cannot be initialized.', CR, LF, 0
StaticMemoryErrorMsg   db   051, 00, "Board RAM failed the memory test.", CR, LF, 0
RomErrorMsg      db   241, 00, "The board's ROM has checksum errors.", CR, LF, 0
FirmwareLoadErrorMsg   db   238, 00, 'The firmware cannot be started.', CR, LF, 0
ParameterPassErrorMsg   db   070, 00, 'The board has failed.', CR, LF, 0
if BusMaster
LevelErrorMsg      db   150, 00, 'EtherTSM.NLM Assembly HSM Interface Level is %d.', CR, LF
         db       'This HSM needs Level 200.', CR, LF, 0
endif
if AddPolling
InterruptOnlyMsg   db   'Interrupt Only Mode.', CR, LF, 0
PollingMsg      db   'Polling With Interrupt Backup and %dns Poll Timeout Mode.', CR, LF, 0
endif
IF DEBUG
DiagAllocMemErrorMsg   db   052, 00, "Unable to allocate 64k diagnostic buffer.", CR, LF, 0
ENDIF
InstanceMappingErrorMsg db      230, 00, "Failed to retrieve information associated with the specified Instance Number.", CR
CardConfigErrorMsg  db  200, 00, "Can not read the configuration parameters for the given adapter.", CR, LF, 0
InterruptSetMsg     db  150, 00, "The Hardware Interrupt can not be set.", CR, LF, 0
EnablePollingErrorMsg   db  100, 00, "The polling process can not be enabled.", CR, LF, 0
ParameteridentifyErrorMsg db    250, 00, "Can not read bus specific information represented by the given identifier.", CR, LF, 0
ScheduleIntErrorMsg     db      230, 00, "Can not schedule an interrupt time callback with the OS.", CR, LF, 0
;
;***************************************************************\
;                                                               *
; Run-time Alert Error Messages.            *
;                                                               *
;***************************************************************/
;
BadECBMessage   db   "An NLM sent an ECB pointer(%x) that was out of range to a DMA adapter.", CR, LF, 0

OSDATA   ends
   subttl   -- DriverChangeMulticast --
   page
OSCODE   segment er public 'CODE'
;
;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverMulticastChange, NE3200/API/MULTI )
;
; Name:      DriverMulticastChange
;
; Description:   This routine will modify the NIC's multicast registers to
;      enable it to receive the multicast addresses listed in
;      the multicast table. Each entry in the multicast table is as
;      follows:
;
;      bytes 0-5 = Multicast Address.
;      bytes 6-7 = Entry used(Non zero if used).
;
; On Entry:   EAX   N/A
;      EBX   N/A
;      ECX   # of Entries in Table( 0 if empty )
;      EDX   N/A
;      EBP   @ Adapter Data Space
;      ESI   @ Multicast Table
;      EDI   N/A
;
;       Note:   Interrupts are in any state.
;
; On Return:   EAX   Destroyed
;      EBX   Preserved
;      ECX   Destroyed
;      EDX   Destroyed
;      EBP   Preserved
;      ESI   Preserved
;      EDI   Preserved
;
;       Flags:
;
;       Note:   Interrupts preserved.
;
; Remarks:   This routine is called by the ethernet media module.
;      (e.g. EtherTSMUpdateMulticast which our DriverReset calls).
;      It can be called at process or interrupt time.
;
; See Also:   ETHERTSM\EtherTSMAddMulticastAddress
;      ETHERTSM\EtherTSMDeleteMulticastAddress
;      ETHERTSM\EtherTSMUpdateMulticast
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
;
   align   16
DriverMulticastChange   proc

if BusMaster
   mov   [ebp].MulticastCount, cx      ; Save cnt in Parm blk.
   mov   eax, esi            ; EAX -> MulticastTbl.
   call   MSMGetPhysical            ; Convert to phys.
   mov   [ebp].MulticastTablePointer, eax   ; Store phys addr.
else
   add   esi, LogicalToPhysical         ; Convert to phys.
   mov   [ebp].MulticastTablePointer, esi   ; Save in adapter
   mov   [ebp].MulticastCount, cx      ;  parameter block.
endif
;;TNL   cmp   [ebp].InDriverInit, 0         ;   In Driver Init?
   cmp   [ebp].InDriverReset, 0         ; In Driver Reset?
   jnz   short DriverMulticastExit      ; Exit if so.

   mov   edx, [ebp].UpdateParmMailbox      ; EDX = Parm Update.

   mov   ecx, CountForLoop         ; Set Loop counter.
WaitForMailBoxToClear:
   in   al, dx               ; AL = Parm Update.
   or   al, al               ; Cleared by adapter?
   jz   short ParameterMailboxClear      ; Jump if so.
   dec   ecx               ; Loop.
   jnz   WaitForMailBoxToClear

ParameterMailboxClear:
   inc   al               ; Set AL = 1.
   out   dx, al               ; Set Update port.

DriverMulticastExit:
   ret                  ; Exit.

DriverMulticastChange   endp

   subttl   -- DriverPromiscuousChange --
   page
;
;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverPromiscuousChange, NE2000/API/PROMISCU )
;
; Name:      DriverPromiscuousChange
;
; Description:   This routine will enable/disable the Promiscuous Mode.
;
; On Entry:   EAX   N/A
;      EBX   N/A
;      ECX   0 to disable the Promiscuous mode
;         If non zero, bit 3 is set if Remote Multicast Frames are to be received.
;      EDX   N/A
;      EBP   @ Adapter Data Space
;      ESI   @ Multicast Table
;      EDI   N/A
;
;       Note:   Interrupts are in any state.
;
; On Return:   EAX   Destroyed
;      EBX   Preserved
;      ECX   Destroyed
;      EDX   Destroyed
;      EBP   Preserved
;      ESI   Destroyed
;      EDI   Destroyed
;
;       Flags:
;
;       Note:   Interrupts preserved.
;
; Remarks:   This routine is called by the ethernet media module,
;      (e.g. EtherTSMUpdateMulticast which our DriverReset calls).
;      It can be called at process or interrupt time.
;
; See Also:   ETHERTSM\EtherTSMPromiscuousChange
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
;
   align   16
DriverPromiscuousChange   proc

   mov   [ebp].PromiscuousMode, cl   ; Store mode.
;;TNL   cmp   [ebp].InDriverInit, 0      ;; In Driver Init?
   cmp   [ebp].InDriverReset, 0      ; In Driver Reset?
   jnz   short DriverPromiscuousExit   ; Exit if so.

   mov   edx, [ebp].UpdateParmMailbox      ; EDX == Parm Update.
   mov   ecx, CountForLoop         ; Set Loop counter.
PromWaitForMailBoxToClear:
   in   al, dx               ; AL = Parm Update.
   or   al, al               ; Cleared by adapter?
   jz   short ParameterMailboxReady      ; Jump if so.
   dec   ecx               ; Loop.
   jnz   PromWaitForMailBoxToClear
ParameterMailboxReady:
   inc   al               ; Set AL = 1.
   out   dx, al               ; Set Update port.
DriverPromiscuousExit:
   ret

DriverPromiscuousChange   endp

   subttl  -- DriverStatisticsChange --
   page
;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverStatisticsChange, NE3200/API/PROMISCU )
;
; Name:         DriverStatisticsChange
;
; Description:  This routine will update the statistics table.
;
; On Entry:     EAX     N/A
;               EBX     @ Frame Data Space
;               ECX     N/A
;               EDX     N/A
;               EBP     @ Adapter Data Space
;               ESI     N/A
;               EDI     N/A
;
;               Note:   Interrupts are disable.
;
; On Return:    EAX     Destroyed
;               EBX     Preserved
;               ECX     Destroyed
;               EDX     Destroyed
;               EBP     Preserved
;               ESI     Destroyed
;               EDI     Destroyed
;
;               Flags:
;
;               Note:   Interrupts preserved.
;
; Remarks:      This routine is called by the media specific module.
;               It can be called at process or interrupt time.
;               Added by JCP, 941130.
;
; See Also:     MSM\MSMGetMLIDStatistics
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
        align   16

DriverStatisticsChange proc
   mov     edx, [ebp].UpdateStatMailbox    ; EDX -> Stat Update.
   mov     al, 1                           ; Set AL = 1.
   out     dx, al                          ; Write to port(Notify firmware).

   call    MSMGetMicroTimer                ; EAX = current count.
   mov     edx, eax                        ; Save the old count.
   neg     edx                             ; Negate so later add does subt.

WaitForTxOrRxToFinish:         ; Give firmware time to update cntrs.
   call    MSMGetMicroTimer                ; EAX = New current count.
   add     eax, edx                        ; Subtract old time from new.
   cmp     eax, 16000                      ; Have 1.6 millisec passed?
        jb      WaitForTxOrRxToFinish           ; Jump if below 1.6 msec.

        mov     [ebp].UpdateStatCount, 0        ; Reset Counter. JCP, 941205.
        ret

DriverStatisticsChange endp

   subttl   -- DriverSend --
   page
;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverSend, NE3200/API/SEND )
;
; Name:      DriverSend
;
; Description:   This routine passes the ECB to the adapter for transmission.
;      The driver will place the physical address of the TCB into
;      the NE3200's send ECB mailbox and informs the NE3200 that it
;      is there. It will then return until DriverISR finds that the
;      adapter has DMA'd it into its own buffer.
;
; On Entry:   EAX   N/A
;      EBX   @ Frame Data Space
;      ECX   Padded Packet Length
;      EDX   N/A
;      EBP   @ Adapter Data Space
;      ESI   @ Logical address of ECB (i.e TCB)
;      EDI   @ Physical address of ECB (i.e TCB)
;
;       Note:   Interrupts are disabled.
;
; On Return:   EAX   Destroyed
;      EBX   Preserved
;      ECX   Destroyed
;      EDX   Destroyed
;      EBP   Preserved
;      ESI   Destroyed
;      EDI   Destroyed
;
;       Flags:
;
;       Note:   Interrupts disabled.
;
; Remarks:   This routine is called by the MSM media module.
;      It is called at process or interrupt time.
;
; See Also:   ETHERTSM\EtherTSMDriverSend
;      ETHERTSM\MediaSendRaw8023
;      ETHERTSM\MediaSendEthernetII
;      ETHERTSM\MediaSend8022Over8023
;      ETHERTSM\MediaSend8022Snap
;
; END_MANUAL_ENTRY
;
;***********************************************************************/

   public   DriverSend
   align   16
DriverSend   proc

if TxQueue
   mov   ecx, [ebp].TCBQueueTail      ; EAX -> Next spot in list.
;;   STC 3/24/94
;;   mov   edx, [ebp].TCBMailbox      ; DX -> NIC's TCB port.

   mov   [ebp].HostTCBList[ecx*4], esi   ; Save TCB into list.
ife BusMaster
   add   esi, LogicalToPhysical      ; Convert to physical addr.
endif
if CheckTCBs
   cmp   esi, TopOfPhysicalMemory   ; ECB out of range?
   ja   short DriverSendError      ; Jump if so.
   mov   eax, [esi].RFragmentCount
   lea   edi, [esi].RPacketOffset
CheckTCBLoop1:
   test   dword ptr [edi], 80000000h   ; Fragment out of range?
   jne   short DriverSendError      ; Jump if so.
   add   edi, 8
   dec   eax
   jne   CheckTCBLoop1
endif
if BusMaster
   mov   [ebp].AdapterTCBList[ecx*4], edi
else
   mov   [ebp].AdapterTCBList[ecx*4], esi
endif

;;   STC 3/24/94
;;   mov   al, 1            ; Set Tx waiting bit.
;;   dec   edx            ; Place it into Tx State box.
;;   out   dx, al
   mov   edx, [ebp].TCBValidMailbox   ; DX -> NIC's TCB Valid port.
   mov   al, cl            ; Give new queue index to firmware.
   inc   al            ; Note TCB queue size is 256.
   out   dx, al

   MSMGetCurrentTime
   mov   [ebp].TxStartList[ecx*4], eax   ; Save Start time.
   inc   cl            ; Bump index(Index is 0 - 255).
   mov   [ebp].TCBQueueTail, ecx      ; Save new TCB index.

   cmp   [ebp].MSMTxFreeCount, TOTAL_TCBS-1   ; Transmits pending?
   jb   short DriverSendComplete      ; Jump if not.
DriverSendExit:
   ret               ; Exit.

DriverSendComplete:
   mov   eax, [ebp].TCBQueueHead      ; EAX -> Head of TCB list.
   cmp   dword ptr [ebp].AdapterTCBList[eax*4], -1   ; Done?
   jne   DriverSendExit                ; Jump if not.

   mov   esi, [ebp].HostTCBList[eax*4]   ; ESI = RCB.
   inc   al            ; Bump index.
   mov   [ebp].TCBQueueHead, eax      ; Save new index.
   inc   [ebp].MSMTxFreeCount      ; We now can send another ECB.
   jmp   EtherTSMFastSendComplete   ; Return the TCB.
   ;ret

else
   mov   eax, esi         ; EAX -> Logical TCB.
if BusMaster
   add   eax, LogicalToPhysical      ; EAX -> Physical TCB.
endif
if CheckTCBs
   cmp   eax, TopOfPhysicalMemory   ; ECB out of range?
   ja   short DriverSendError      ; Jump if so.
   mov   ecx, [esi].RFragmentCount
   lea   edi, [esi].RPacketOffset
CheckTCBLoop2:
   test   dword ptr [edi], 80000000h   ; Fragment out of range?
   jne   short DriverSendError      ; Jump if so.
   add   edi, 8
   dec   ecx
   jne   CheckTCBLoop2
endif
   mov   edx, [ebp].TCBMailbox      ; DX -> NIC's TCB port.
   out   dx, eax            ; Load it into TCB mailbox.

   mov   al, 1            ; Set Tx waiting bit.
   dec   edx            ; Place it into Tx State box.
   out   dx, al

   mov   [ebp].TCBInProcess, esi      ; Save TCB until BMIC is done.
   MSMGetCurrentTime
   mov   [ebp].TxStartTime, eax      ; Save start time.
   ret
endif

if CheckTCBs
DriverSendError:
   push   esi
   mov   ecx, esi         ; ECX -> ECB.
   lea   esi, BadECBMessage      ; ESI -> Error Message.
   call   MSMAlertFatal
   pop   esi            ; ESI -> ECB.
   inc   [ebp].MSMTxFreeCount      ; We now can send another ECB.
   jmp   EtherTSMFastSendComplete   ; Give ECB back and return.
endif

DriverSend   endp
   subttl   -- DriverISR --
   page
;
;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverISR, NE3200/API/ISR )
;
; Name:      DriverISR
;
; Description:   This routine handles packet reception and transmit complete
;      interrupts.
;
; On Entry:   EAX   N/A
;      EBX   N/A
;      ECX   N/A
;      EDX   N/A
;      EBP   @ Adapter Data Space
;      ESI   N/A
;      EDI   N/A
;
;       Note:   Interrupts are disabled.
;
; On Return:   EAX   Destroyed
;      EBX   Destroyed
;      ECX   Destroyed
;      EDX   Destroyed
;      EBP   Destroyed
;      ESI   Destroyed
;      EDI   Destroyed
;
;       Flags:
;
;       Note:   Interrupts disabled.
;
; Remarks:   This routine is called by the MSM.
;      It is called at interrupt time.
;
; See Also:   MSM\MSMInterruptProcedure
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
;
   public   DriverISR
   align   16
DriverISR   proc

if AddPolling
   inc   [ebp].NumberOfIntsFired      ; Inc stat counter.
   cmp   [ebp].InDriverPoll, 0      ; In DriverPoll?
   jne   DriverISRExit         ; Exit if so.
endif

;---------------------------------------------------------------\
;                                                               *
; Check for Completed RCBs. When the firmware is done receiving   *
; a frame, it overwrites the physical address of the ECB   *
; (in AdapterRCBList) with a value of Zero.         *
;                        *
;---------------------------------------------------------------/

DriverISRCheckRCBLoop:
   mov   eax, [ebp].ReceiveQueueHead   ; EAX -> Head of RCB list.

;;   mov   ecx, [ebp].AdapterRCBList[eax*4]; ECX = Size field.
;;if SupportJabber
;;   cmp   ecx, 2048+14
;;else
;;   cmp   ecx, 1514         ; Filled in by adapter?
;;endif
;;   cmp   ecx, 2048+14

   cmp   [ebp].AdapterRCBList[eax*4], 0   ; Did adapter copy a new rcv
                  ; frame to us for processing?
   ja   DriverISRCheckNeedCount      ; Jump if no.

   mov   [ebp].AdapterRCBList[eax*4], -1   ; Indicate entry is unused.
   mov   esi, [ebp].HostRCBList[eax*4]   ; ESI = RCB.

   mov     edx, eax                        ; Save ReceiveQueueHead

   inc   eax            ; Bump index.
   and   al, TABLE_MASK
   mov   [ebp].ReceiveQueueHead, eax   ; Save new Head of RCB list.
   inc   [ebp].NeedRCBCount      ; Inc Get RCB flag for alloc.

ife BusMaster
   mov   eax, PhysicalToLogical
   add   [esi].RPacketOffset, eax
endif

if CatchIncomplete
   cmp   dword ptr [esi].RImmediateAddress, 0
   je   short IPXLengthOK
   cmp   dword ptr [esi].RProtocolID+0, 0   ; IPX PID?
   jne   short IPXLengthOK         ; Jump if not.
   mov   eax, dword ptr [esi].RProtocolID+2   ; EAX = PID.
   or   eax, eax            ; IPX 802.3?
   je   short CheckIPXLength         ; Jump if so.
   cmp   eax, 37810000h            ; IPX EII or SNAP?
   je   short CheckIPXLength         ; Jump if so.
   cmp   eax, 0e0000000h            ; IPX 802.2?
   jne   short IPXLengthOK         ; Jump if not.
CheckIPXLength:
   mov   edi, [esi].RPacketOffset
   movzx   eax, word ptr [edi+2]
   xchg   al, ah               ; EAX = IPX length.
   cmp   eax, [esi].RPacketLength      ; Greater than ECB?
   jbe   short IPXLengthOK         ; Jump if not.
   inc   [ebp].HostIncompleteCount      ; Inc statistic.
   mov   ebx, [ebp].MSMDefaultVirtualBoard

   mov   eax, [ebp].HostPWSList1[edx*4]   ; Restore first dword
   mov   [esi].RProtocolWorkspace+0, eax   ; Put it back here.
   mov   eax, [ebp].HostPWSList2[edx*4]   ; Restore second dword
   mov   [esi].RProtocolWorkspace+4, eax   ; Put it back here.

   MSMReturnRCB
        mov   eax, OP_SCOPE_ADAPTER
   call   DriverReset            ; Reset Adapter.
   jmp   DriverISRExit            ; Go exit.
IPXLengthOK:
endif

;---------------------------------------------------------------\
;                                                               *
; NOTE: EtherTSMFastRcvCompleteStatus requires:         *
;   ECX = packet size (including header),         *
;   EAX = error status (if any).            *
;                        *
;---------------------------------------------------------------/

   mov   eax, dword ptr [esi].RProtocolWorkspace     ; EAX = Error Status.
   mov   ecx, dword ptr [esi].RProtocolWorkspace+4 ; ECX = Packet Size.

   mov   ebx, [ebp].HostPWSList1[edx*4]             ; Restore first dword
   mov   dword ptr [esi].RProtocolWorkspace+0, ebx ; Put it back here.
   mov   ebx, [ebp].HostPWSList2[edx*4]             ; Restore second dword
   mov   dword ptr [esi].RProtocolWorkspace+4, ebx ; Put it back here.

if UseFastCalls
   push   ebp
   call   EtherTSMFastRcvCompleteStatus   ; Give RCB to protocol stack.
   pop   ebp
   jmp   DriverISRCheckRCBLoop
else
   push   offset DriverISRCheckRCBLoop   ; Jump back to loop.
   jmp   EtherTSMRcvCompleteStatus   ; Give RCB to LSL.
endif

;-------------------------------------------------------------------\
;                                                                   *
; Allocate more RCB's. At initialization NeedRCBCount starts at 16h.*
;                                                                   *
;-------------------------------------------------------------------/
;
DriverISRCheckNeedCount:
   mov   ecx, [ebp].NeedRCBCount      ; ECX = RCB's needed.
   or   ecx, ecx         ; Any RCB's needed?
   jz   short DriverISRCheckTCB      ; Jump if not.

DriverISRGetRCBLoop:
   mov   esi, CommonMaximumSize      ; ESI = Max packet Size.
   call   MSMAllocateRCB         ; Attempt to get an RCB.
   jnz   short DriverISRCheckTCB      ; Jump if unsuccessful.

;---------------------------------------------------------------\
;                        *
; MSMAllocateRCB zeroed out the RProtocolWorkspace field.   *
;   ESI = Logical address of ECB.            *
;   EDI = Physical address of ECB. (for BusMaster systems)   *
;                        *
;---------------------------------------------------------------/

   dec   [ebp].NeedRCBCount      ; Dec need counter.
   mov   eax, [ebp].ReceiveQueueTail   ; EAX -> Next spot in list.

   mov     edx, dword ptr [esi].RProtocolWorkspace+0 ; Get first dword
   mov   dword ptr [ebp].HostPWSList1[eax*4], edx  ; Save first dword
   mov     edx, dword ptr [esi].RProtocolWorkspace+4 ; Get 2nd dword
   mov   dword ptr [ebp].HostPWSList2[eax*4], edx  ; Save 2nd dword

   mov   [ebp].HostRCBList[eax*4], esi   ; Save RCB into list.
if BusMaster
   mov   [ebp].AdapterRCBList[eax*4], edi
else
   add   esi, LogicalToPhysical      ; Convert to physical addr.
   mov   [ebp].AdapterRCBList[eax*4], esi
endif
   inc   eax            ; Bump index.
   and   al, TABLE_MASK         ; Perform Modulo operation.
   mov   [ebp].ReceiveQueueTail, eax   ; Save new index.

   dec   ecx            ; More RCB's needed?
   jnz   DriverISRGetRCBLoop      ; Jump if so and loop.

DriverISRCheckTCB:
;
;---------------------------------------------------------------\
;                                                               *
; Check if Transmit is finished.            *
;                                                               *
;---------------------------------------------------------------/
;
if TxQueue
   cmp   [ebp].MSMTxFreeCount, TOTAL_TCBS   ; Transmits pending?
   je   short DriverISRGetNextSend      ; Jump if not.
   mov   eax, [ebp].TCBQueueHead      ; EAX -> Head of TCB list.
   cmp   dword ptr [ebp].AdapterTCBList[eax*4], -1   ; Done?
   jne   short DriverISRGetNextSend         ; Jump if not.

   mov   esi, [ebp].HostTCBList[eax*4]   ; ESI = RCB.
   inc   al            ; Bump index.
   mov   [ebp].TCBQueueHead, eax      ; Save new index.
   inc   [ebp].MSMTxFreeCount      ; We now can send another ECB.
if UseFastCalls
   push   ebp
   call   EtherTSMFastSendComplete   ; Return the TCB.
   pop   ebp
else
   call   EtherTSMSendComplete
endif
   jmp   DriverISRCheckTCB


DriverISRGetNextSend:
   test   [ebp].MSMStatusFlags, TXQUEUED
   je   short DriverISRExit
;---------------------------------------------------------------\
;                                                               *
; Call TSM for any more ECBs to send.            *
;   EDI = ESI = ECB address.            *
;                                                               *
;---------------------------------------------------------------/

   call   EtherTSMGetNextSend      ; Another send waiting?
   jnz   short DriverISRExit      ; Jump if not.

   mov   ecx, [ebp].TCBQueueTail      ; ECX -> Next spot in list.

   mov   [ebp].HostTCBList[ecx*4], esi   ; Save TCB into list.
ife BusMaster
   add   esi, LogicalToPhysical      ; Convert to physical addr.
endif
if CheckTCBs
   cmp   esi, TopOfPhysicalMemory   ; ECB out of range?
   ja   short DriverISRBadTCB      ; Jump if so.
   mov   eax, [esi].RFragmentCount
   lea   edi, [esi].RPacketOffset
CheckTCBLoop3:
   test   dword ptr [edi], 80000000h   ; Fragment out of range?
   jne   short DriverISRBadTCB
   add   edi, 8
   dec   eax
   jne   CheckTCBLoop3
endif
if BusMaster
   mov   [ebp].AdapterTCBList[ecx*4], edi
else
   mov   [ebp].AdapterTCBList[ecx*4], esi
endif

;;   STC 3/24/94
;;   mov   edx, [ebp].TCBMailbox      ; DX -> NIC's TCB port.
;;   mov   al, 1            ; Set Tx waiting bit.
;;   dec   edx            ; Place it into Tx State box.
;;   out   dx, al
   mov   edx, [ebp].TCBValidMailbox   ; DX -> NIC's TCB Valid port.
   mov   al, cl            ; Give new queue index to firmware.
   inc   al
   out   dx, al

   MSMGetCurrentTime
   mov   [ebp].TxStartList[ecx*4], eax   ; Save Start time.
   inc   cl            ; Bump index.
   mov   [ebp].TCBQueueTail, ecx      ; Save new index.
   jmp   DriverISRGetNextSend

else
   cmp   [ebp].TCBInProcess, 0      ; TCB In Process?
   je   short DriverISRExit      ; Jump if not.

   mov   edx, [ebp].TCBValidMailbox   ; EDX = NIC's TCB status port.
   in   al, dx            ; AL = Status.
   or   al, al            ; Is it finished?
   jnz   short DriverISRExit      ; Jump if not.

   mov   esi, [ebp].TCBInProcess      ; ESI -> TCB to return.
   mov   [ebp].TCBInProcess, 0      ; NIC is done with TCB.
   inc   [ebp].MSMTxFreeCount      ; We now can send another ECB.
if UseFastCalls
   push   ebp
   call   EtherTSMFastSendComplete   ; Return TCB.
   pop   ebp
else
   call   EtherTSMSendComplete      ; Return TCB.
endif

DriverISRGetNextSend:
   test   [ebp].MSMStatusFlags, TXQUEUED
   je   short DriverISRExit
   call   EtherTSMGetNextSend      ; Another send waiting?
   jnz   short DriverISRExit      ; Jump if not.

   mov   edx, [ebp].TCBMailbox      ; DX -> NIC's TCB port.
   mov   eax, esi         ; EAX -> Logical TCB.
if BusMaster
   add   eax, LogicalToPhysical      ; EAX -> Physical TCB.
endif
if CheckTCBs
   cmp   eax, TopOfPhysicalMemory   ; ECB out of range?
   ja   short DriverISRBadTCB      ; Jump if so.
   mov   eax, [esi].RFragmentCount
   lea   edi, [esi].RPacketOffset
CheckTCBLoop4:
   cmp   dword ptr [edi], 80000000h   ; Fragment out of range?
   jne   short DriverISRBadTCB
   add   edi, 8
   dec   eax
   jne   CheckTCBLoop4
endif
   out   dx, eax            ; Load it into TCB mailbox.

   mov   al, 1            ; Set Tx waiting bit.
   dec   edx            ; Place it into Tx State box.
   out   dx, al

   mov   [ebp].TCBInProcess, esi      ; Save TCB until BMIC is done.
   MSMGetCurrentTime
   mov   [ebp].TxStartTime, eax      ; Save start time.
endif
;
;---------------------------------------------------------------\
;                                                               *
; Exit the ISR.                     *
;                                                               *
;---------------------------------------------------------------/
;
DriverISRExit:

if not UseFastCalls
   MSMServiceEvents
endif
   xor   eax, eax         ; Interrupt Serviced return.
   ret

if CheckTCBs
DriverISRBadTCB:
   push   esi
   mov   ecx, esi         ; ECX -> ECB.
   lea   esi, BadECBMessage      ; ESI -> Error Message.
   call   MSMAlertFatal
   pop   esi            ; ESI -> ECB.
   call   EtherTSMFastSendComplete   ; Give ECB back and return.
   inc   [ebp].MSMTxFreeCount      ; We now can send another ECB.
   jmp   DriverISRGetNextSend      ; Check for another ECB.
endif

DriverISR   endp


If AddPolling
;
;***********************************************************************\
;                                                                       *
; DriverPoll Procedure                     *
;                                                                       *
;***********************************************************************/
;
   public   DriverPoll
   align   16
DriverPoll   proc

   mov   [ebp].InDriverPoll, 1      ; Set flag.
   mov   edx, [ebp].PollingMailbox   ;#
   xor   al, al            ;#
   out   dx, al            ; Zero out the I/O port.

;---------------------------------------------------------------\
;                                                               *
; Polling - Check for finished RCBs.            *
;    The adapter indicates a new rcv frame is ready by zeroing   *
;    out the corresponding ptr in the AdapterRCBList.      *
;                                                               *
;---------------------------------------------------------------/

DriverPollCheckRCBLoop:
   mov   eax, [ebp].ReceiveQueueHead   ; EAX -> Head of RCB list.

;;   mov   ecx, [ebp].AdapterRCBList[eax*4]; ECX = Size field.
;;if SupportJabber
;;   cmp   ecx, 2048+14
;;else
;;   cmp   ecx, 1514         ; Filled in by adapter?
;;endif

   cmp   [ebp].AdapterRCBList[eax*4], 0   ; Did adapter copy a new rcv
                  ; frame to us for processing?

   ja   short DriverPollCheckNeedCount   ; Jump if no.

   mov   [ebp].AdapterRCBList[eax*4], -1   ; Indicate entry's available.
   mov   esi, [ebp].HostRCBList[eax*4]   ; ESI = RCB.

   mov     edx, eax                        ; Save ReceiveQueueHead
   inc   eax            ; Bump index.
   and   al, TABLE_MASK
   mov   [ebp].ReceiveQueueHead, eax   ; Save new Head of RCB list.
   inc   [ebp].NeedRCBCount      ; Inc Get RCB flag for alloc.

ife BusMaster
   mov   eax, PhysicalToLogical
   add   [esi].RPacketOffset, eax
endif

if CatchIncomplete
   cmp   dword ptr [esi].RImmediateAddress, 0
   je   short PollIPXLengthOK
   cmp   dword ptr [esi].RProtocolID+0, 0   ; IPX PID?
   jne   short PollIPXLengthOK         ; Jump if not.
   mov   eax, dword ptr [esi].RProtocolID+2   ; EAX = PID.
   or   eax, eax            ; IPX 802.3?
   je   short PollCheckIPXLength      ; Jump if so.
   cmp   eax, 37810000h            ; IPX EII or SNAP?
   je   short PollCheckIPXLength      ; Jump if so.
   cmp   eax, 0e0000000h            ; IPX 802.2?
   jne   short PollIPXLengthOK         ; Jump if not.
PollCheckIPXLength:
   mov   edi, [esi].RPacketOffset
   movzx   eax, word ptr [edi+2]
   xchg   al, ah               ; EAX = IPX length.
   cmp   eax, [esi].RPacketLength      ; Greater than ECB?
   jbe   short PollIPXLengthOK         ; Jump if not.
;;   inc   [ebp].HostIncompleteCount      ; Inc stat.
;;   mov   ebx, [ebp].MSMDefaultVirtualBoard
;;   MSMReturnRCB
;;      mov     eax, OP_SCOPE_ADAPTER
;;   call   DriverReset            ; Reset Adapter.
;;   jmp   DriverPollExit            ; Get out.
PollIPXLengthOK:
endif

   mov   eax, dword ptr [esi].RProtocolWorkspace     ; EAX = Error Status.
   mov   ecx, dword ptr [esi].RProtocolWorkspace+4 ; ECX = Packet Size.

   mov   ebx, [ebp].HostPWSList1[edx*4]             ; Restore first dword
   mov   dword ptr [esi].RProtocolWorkspace+0, ebx ; Put it back here.
   mov   ebx, [ebp].HostPWSList2[edx*4]             ; Restore second dword
   mov   dword ptr [esi].RProtocolWorkspace+4, ebx ; Put it back here.

if UseFastCalls
   push   ebp
   call   EtherTSMFastRcvCompleteStatus   ; Give RCB to protocol stack.
   pop   ebp
   jmp   DriverPollCheckRCBLoop
else
   push   offset DriverPollCheckRCBLoop   ; Jump back to loop.
   jmp   EtherTSMRcvCompleteStatus   ; Give RCB to LSL.
endif

;---------------------------------------------------------------\
;                                                               *
; Polling - Allocate more RCB's.            *
;                                                               *
;---------------------------------------------------------------/

   align   16
DriverPollCheckNeedCount:
   mov   ecx, [ebp].NeedRCBCount      ; ECX = RCB's needed.
   or   ecx, ecx         ; Any RCB' needed?
   jz   short DriverPollCheckTCB   ; Jump if not.

DriverPollGetRCBLoop:
   mov   esi, CommonMaximumSize      ; ESI = Max packet Size.
   call   MSMAllocateRCB         ; Attempt to get an RCB.
   jnz   short DriverPollCheckTCB   ; Jump if unsuccessful.

;---------------------------------------------------------------\
;                        *
; MSMAllocateRCB zeroed out the RProtocolWorkspace field.   *
;   ESI = Logical address of ECB.            *
;   EDI = Physical address of ECB. (for BusMaster systems)   *
;                        *
;---------------------------------------------------------------/

   mov   eax, [ebp].ReceiveQueueTail   ; EAX -> Next spot in list.
   dec   [ebp].NeedRCBCount      ; Dec need counter.

   mov     edx, dword ptr [esi].RProtocolWorkspace+0 ; Get first dword
   mov   dword ptr [ebp].HostPWSList1[eax*4], edx  ; Save first dword
   mov     edx, dword ptr [esi].RProtocolWorkspace+4 ; Get 2nd dword
   mov   dword ptr [ebp].HostPWSList2[eax*4], edx  ; Save 2nd dword

   mov   [ebp].HostRCBList[eax*4], esi
if BusMaster
   mov   [ebp].AdapterRCBList[eax*4], edi; Save RCB into list.
else
   add   esi, LogicalToPhysical      ; Convert to physical addr.
   mov   [ebp].AdapterRCBList[eax*4], esi; Save RCB into list.
endif
   inc   eax            ; Bump index.
   and   al, TABLE_MASK
   mov   [ebp].ReceiveQueueTail, eax   ; Save new index.

   dec   ecx            ; More RCB's needed?
   jnz   DriverPollGetRCBLoop      ; Jump if so.

DriverPollCheckTCB:

;---------------------------------------------------------------\
;                        *
;                                                               *
; Polling - Check if Transmit is finished.         *
;                                                               *
; When polling we want to make sure that the polling loop length*
; is the same whether or not we have an outstanding transmit.   *
; Otherwise, the server utilization number will be messed up.   *
;                        *
;---------------------------------------------------------------/

if TxQueue

   mov   eax, [ebp].TCBQueueHead      ; EAX -> Head of TCB list.
   mov   ecx, [ebp].MSMTxFreeCount
   sub   ecx, TOTAL_TCBS - 1      ; ECX=1 if no xmits, <= 0 if
                  ;  has outstanding transmits.
   add   ecx, [ebp].AdapterTCBList[eax*4]; Test for -1.
   jge   short DriverPollGetNextSend   ; If -1 and ECX not 1 then continue.

   mov   esi, [ebp].HostTCBList[eax*4]   ; ESI = RCB.
   inc   al            ; Bump index.
   mov   [ebp].TCBQueueHead, eax      ; Save new index.
   inc   [ebp].MSMTxFreeCount      ; We now can send another ECB.
if UseFastCalls
   push   ebp
   call   EtherTSMFastSendComplete   ; Return the TCB.
   pop   ebp
else
   call   EtherTSMSendComplete
endif
   jmp   DriverPollCheckTCB      ; Loop.


DriverPollGetNextSend:
   test   [ebp].MSMStatusFlags, TXQUEUED
   je   short DriverPollExit

;---------------------------------------------------------------\
;                                                               *
; Call TSM for any more ECBs to send.            *
;   EDI = ESI = ECB address.            *
;                                                               *
;---------------------------------------------------------------/

   call   EtherTSMGetNextSend      ; Another send waiting?
   jnz   short DriverPollExit      ; Jump if not.

   mov   ecx, [ebp].TCBQueueTail      ; ECX -> Next spot in list.

   mov   [ebp].HostTCBList[ecx*4], esi   ; Save TCB into list.
ife BusMaster
   add   esi, LogicalToPhysical      ; Convert to physical addr.
endif
if CheckTCBs
   cmp   esi, TopOfPhysicalMemory   ; ECB out of range?
   ja   short DriverPollBadTCB      ; Jump if so.
   mov   eax, [esi].RFragmentCount
   lea   edi, [esi].RPacketOffset
CheckTCBLoop5:
   test   dword ptr [edi], 80000000h   ; Fragment out of range?
   ja   short DriverPollBadTCB
   add   edi, 8
   dec   eax
   jne   CheckTCBLoop5
endif
if BusMaster
   mov   [ebp].AdapterTCBList[ecx*4], edi
else
   mov   [ebp].AdapterTCBList[ecx*4], esi
endif

;;   STC 3/24/94
;;   mov   edx, [ebp].TCBMailbox      ; DX -> NIC's TCB port.
;;   mov   al, 1            ; Set Tx waiting bit.
;;   dec   edx            ; Place it into Tx State box.
;;   out   dx, al
   mov   edx, [ebp].TCBValidMailbox   ; DX -> NIC's TCB Valid port.
   mov   al, cl            ; Give new queue index to firmware.
   inc   al
   out   dx, al

   MSMGetCurrentTime
   mov   [ebp].TxStartList[ecx*4], eax   ; Save Start time.
   inc   cl            ; Bump index.
   mov   [ebp].TCBQueueTail, ecx      ; Save new index.
   jmp   DriverPollGetNextSend

else
   cmp   [ebp].TCBInProcess, 0      ; TCB In Process?
   je   short DriverPollExit      ; Jump if not.

   mov   edx, [ebp].TCBValidMailbox   ; EDX = NIC's TCB status port.
   in   al, dx            ; AL = Status.
   or   al, al            ; Is it finished?
   jnz   short DriverPollExit      ; Jump if not.

   mov   esi, [ebp].TCBInProcess      ; ESI -> TCB to return.
   mov   [ebp].TCBInProcess, 0      ; NIC is done with TCB.
   inc   [ebp].MSMTxFreeCount      ; We now can send another ECB.
if UseFastCalls
   push   ebp
   call   EtherTSMFastSendComplete   ; Return TCB.
   pop   ebp
else
   call   EtherTSMSendComplete      ; Return TCB.
endif
DriverPollGetNextSend:
   test   [ebp].MSMStatusFlags, TXQUEUED
   je   short DriverPollExit
   call   EtherTSMGetNextSend      ; Another send waiting?
   jnz   short DriverPollExit      ; Jump if not.

   mov   edx, [ebp].TCBMailbox      ; DX -> NIC's TCB port.
   mov   eax, esi         ; EAX -> Logical TCB.
ife BusMaster
   add   eax, LogicalToPhysical      ; EAX -> Physical TCB.
endif
if CheckTCBs
   cmp   eax, TopOfPhysicalMemory   ; ECB out of range?
   ja   short DriverPollBadTCB      ; Jump if so.
   mov   eax, [esi].RFragmentCount
   lea   edi, [esi].RPacketOffset
CheckTCBLoop6:
   test   dword ptr [edi], 80000000h   ; Fragment out of range?
   jne   short DriverPollBadTCB
   add   edi, 8
   dec   eax
   jne   CheckTCBLoop6
endif
   out   dx, eax            ; Load it into TCB mailbox.

   mov   al, 1            ; Set Tx waiting bit.
   dec   edx            ; Place it into Tx State box.
   out   dx, al

   mov   [ebp].TCBInProcess, esi      ; Save TCB until BMIC is done.
   MSMGetCurrentTime
   mov   [ebp].TxStartTime, eax      ; Save start time.
endif

;---------------------------------------------------------------\
;                                                               *
; Exit DriverPoll.                  *
;                                                               *
;---------------------------------------------------------------/

DriverPollExit:

if not UseFastCalls
   MSMServiceEvents
endif
   mov   [ebp].InDriverPoll, 0
   ret               ; Exit.

if CheckTCBs
DriverPollBadTCB:
   push   esi
   mov   ecx, esi         ; ECX -> ECB.
   lea   esi, BadECBMessage      ; ESI -> Error Message.
   call   MSMAlertFatal
   pop   esi            ; ESI -> ECB.
   call   EtherTSMFastSendComplete   ; Give ECB back and return.
   inc   [ebp].MSMTxFreeCount      ; We now can send another ECB.
   jmp   DriverPollGetNextSend
endif

DriverPoll   endp

endif

   subttl  -- DriverDisableInterrupt --
   page
;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverDisableInterrupt, NE3200/API/DISINT )
;
; Name:         DriverDisableInterrupt
;
; Description:  This routine will disable the adapters ability to
;               interrupt the host.
;
; On Entry:     EAX     1   If we want to know if it's our Interrupt
;         0   just disable the adapter.
;
;               EBX     N/A
;               ECX     N/A
;               EDX     N/A
;               EBP     @ Adapter Data Space
;               ESI     N/A
;               EDI     N/A
;
;               Note:   Interrupts are disabled.
;
; On Return:    EAX     Destroyed
;               EBX     Preserved
;               ECX     Preserved
;               EDX     Destroyed
;               EBP     Preserved
;               ESI     Preserved
;               EDI     Preserved
;
;               Flags:
;
;               Note:   Interrupts disabled.
;
; Remarks:      This routine is called by the MSM.
;
; See Also:     DriverEnableInterrupt
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
   align   16
   public   DriverDisableInterrupt

DriverDisableInterrupt   proc
   cmp   [ebp].InDriverDisable, 0   ; Already disabled interrupts?
   jnz   short DriverDisableNotOurs   ; Jump if yes.

   or   eax, eax         ; Is EAX a Zero?
   jz   short DriverDisableNicOnly   ; Jmp if so (Disable NIC only).
                  ; o/p don't care.
   mov     edx, [ebp].EisaSystemDoorbellStatus ; Check for interrupt.
   in      al, dx
   test    al, 1                           ; Our interrupt?
   jz   short DriverDisableNicOnly   ; Jump if not.

;---------------------------------------------------------------\
;                                                               *
; Disable NE3200's interrupt mechanism.            *
;                                                               *
;---------------------------------------------------------------/

   mov     edx, [ebp].EisaSystemDoorbellEnable
   xor     al, al                          ; Disable doorbell.
   out     dx, al

   mov   [ebp].InDriverDisable, 01   ; Set flag we're disabled.

   mov   eax, 1
   mov     edx, [ebp].EisaSystemDoorbellStatus
   out   dx, al            ; Reset our Status port.

   xor     eax, eax         ; Indicate our interrupt.
   ret               ; Exit.


;---------------------------------------------------------------\
;                                                               *
; Disable NE3200's interrupt mechanism only.         *
;                                                               *
;---------------------------------------------------------------/

DriverDisableNicOnly:

   mov   [ebp].InDriverDisable, 01   ; Set flag we're disabled.
   xor     eax, eax
   mov     edx, [ebp].EisaSystemDoorbellEnable
   out     dx, al            ; Disable doorbell.

DriverDisableNotOurs:
   or      eax, 1                          ; Int not ours flag.
   ret               ; Exit.

DriverDisableInterrupt  endp


   subttl  -- DriverEnableInterrupt --
   page
;***************************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverEnableInterrupt, NE3200/API/ENINT )
;
; Name:         DriverEnableInterrupt
;
; Description:  This routine will enable the adapters ability to
;               interrupt the host.
;
; On Entry:     EAX     N/A
;               EBX     N/A
;               ECX     N/A
;               EDX     N/A
;               EBP     @ Adapter Data Space
;               ESI     N/A
;               EDI     N/A
;
;               Note:   Interrupts are disabled.
;
; On Return:    EAX     Destroyed
;               EBX     Preserved
;               ECX     Preserved
;               EDX     Destroyed
;               EBP     Preserved
;               ESI     Preserved
;               EDI     Preserved
;
;               Flags:
;
;               Note:   Interrupts disabled.
;
; Remarks:      This routine is called by the MSM.
;
; See Also:     DriverDisableInterrupt
;
; END_MANUAL_ENTRY
;
;***************************************************************************/
   align   16
   public   DriverEnableInterrupt

DriverEnableInterrupt   proc

;---------------------------------------------------------------------------\
;                                                                  *
; If we have an interrupt pending, this output to EisaSystemDoorbellStatus  *
; will clear it, which will cause a spurious interrupt.                     *
;                                                                           *
; It's best to just re-enable the adapters interrupts and if one is pending *
; then we will re-enter our interrupt routine to deal with it and not miss  *
; it and hence no spurious interrupts.                                      *
;                                                                  *
;---------------------------------------------------------------------------/

   mov   [ebp].InDriverDisable, 0   ; Clear disable flag.

   mov     edx, [ebp].EisaSystemDoorbellEnable
   mov     eax, 1
   out     dx, al                          ; Enable doorbell.
   ret               ; Exit.

DriverEnableInterrupt   endp


   subttl   -- DriverCallBack --
   page
;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverCallBack, NE3200/API/CALLBACK )
;
; Name:      DriverCallBack
;
; Description:   This routine may be used to schedule events at time intervals
;      specified by the driver. Common uses are for transmit dead-
;      man timers on ethernet or reading statistics from the adapter
;      on token ring. This driver is using it to inform the adapter
;      to upload its statistics every 4 seconds. It is recommended
;      that this call be used over DriverAES and DriverPoll.
;
; On Entry:   EAX   N/A
;      EBX   @ Frame Data Space
;      ECX   N/A
;      EDX   N/A
;      EBP   @ Adapter Data Space
;      ESI   N/A
;      EDI   N/A
;
;       Note:   Interrupts are disabled.
;
; On Return:   EAX   Destroyed
;      EBX   Preserved
;      ECX   Preserved
;      EDX   Destroyed
;      EBP   Preserved
;      ESI   Preserved
;      EDI   Preserved
;
;       Flags:
;
;       Note:   Interrupts preserved.
;
; Remarks:   This routine is called by the MSM.
;      After this call returns, the MSM will schedule another
;      call back.
;      It is called at interrupt time.
;
; See Also:   MSM\MSMCallBackProcedure
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
   align   16

DriverCallBack   proc

;;dgm   mov   edx, [ebp].UpdateStatMailbox      ; EDX -> Stat update
;;dgm   mov   al, 1               ; Set it.
;;dgm   out   dx, al

if TxQueue
   cmp   [ebp].MSMTxFreeCount, TOTAL_TCBS   ; Transmit outstanding?
else
   cmp   [ebp].MSMTxFreeCount, 1         ; Transmit outstanding?
endif
   je   short DriverCallBackExit      ; Jump if not.

   MSMGetCurrentTime            ; EAX = Current Time.
if TxQueue
   mov   ecx, [ebp].TCBQueueHead         ; ECX -> Head of TCB list.
   cmp   [ebp].AdapterTCBList[ecx*4], -1
   je   short DriverCallBackExit

   sub   eax, [ebp].TxStartList[ecx*4]      ; EAX = Send Time.
else
   sub   eax, [ebp].TxStartTime         ; EAX = Send Time.
endif

;       cmp     eax, 18 * 4                             ; Timeout?
   cmp     eax, 18 * 9                             ; Half second.
   jae   short DriverCallBackReset      ; Jump if so.

DriverCallBackExit:               ;;dgm - JCP modified
   cmp     [ebp].UpdateStatCount, 8                ; 4 seconds yet ?
   jae     DriverCallBackFinalExit         ; Jump if yes.

   mov     [ebp].UpdateStatCount, 0           ;Reset Counter.
   mov     edx, [ebp].UpdateStatMailbox       ;EDX -> Stat update
   mov     al, 1                              ;Set it.
   out     dx, al

DriverCallBackFinalExit:
   ret                  ; Done.


DriverCallBackReset:
   inc   [ebp].AdapterDied         ; Bump statistic.
   mov   ebx, [ebp].MSMDefaultVirtualBoard
        mov   eax, OP_SCOPE_ADAPTER
   jmp   DriverReset            ; Reset.

DriverCallBack   endp


   subttl   -- DriverInit --
   page
;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverInit, NE3200/API/INIT )
;
; Name:      DriverInit
;
; Description:   This routine will call EtherTSMRegisterHSM,
;      MSMParseDriverParameters, MSMRegisterHardwareOptions,
;      MSMSetHardwareInterrupt, MSMRegisterMLID, initialize
;      variables in the Adapter Data Space and reset/initialize
;      the card by calling DriverReset.
;
; On Entry:   EAX   N/A
;      EBX   N/A
;      ECX   N/A
;      EDX   N/A
;      EBP   N/A
;      ESI   N/A
;      EDI   N/A
;
;       Note:   Interrupts are enabled.
;
; On Return:   EAX   0 if successful(otherwise it points to error message)
;      EBX   Preserved
;      ECX   Destroyed
;      EDX   Destroyed
;      EBP   Preserved
;      ESI   Preserved
;      EDI   Preserved
;
;       Flags:
;
;       Note:   Interrupts preserved.
;
; Remarks:   This routine is called by the OS at load time.
;      It is called at process time.
;
; See Also:   MSM\MSMParseDriverParameters
;      MSM\MSMRegisterHardwareOptions
;      MSM\MSMSetHardwareInterrupts
;      MSM\MSMRegisterMLID
;      MSM\MSMScheduleIntTimeCallBack
;      MSM\MSMScheduleAESCallBack
;      MSM\MSMEnablePolling
;      DriverReset
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
;
   align   16
   public   DriverInit
DriverInit   proc

   CPush
   mov   PollingTimeoutValue, DEFAULT_TIMEOUT_VALUE   ;#

;---------------------------------------------------------------\
;                                                               *
; Fill in Driver Parameter Block fields.         *
;                                                               *
;---------------------------------------------------------------/

   mov   DriverStackPointer, esp      ; Fill in stack ->.
   lea   esi, DriverParameterBlock   ; ESI -> Parm block.
   call   EtherTSMRegisterHSM      ; Get EBX ->Frame Data Space
                  ;          (or Config table).
   jnz   DriverInitError         ; Jump if error.

;
;  09/13/95 MPK Spec 3.3 changes
;

   push    ebx                             ; Save EBX we will need it.
   mov     esi,-1                          ; Set Parameter for call.
S33_Bus_Scan:
   call    MSMScanBusInfo                  ; Find out about Bus.
   cmp     eax,ODI_NBI_SUCCESSFUL          ; Are we done?
   jne     S33_Bus_Scan_Done               ; Yes, exit.
   cmp     ecx,ODI_BUSTYPE_EISA            ; Is this EISA? (NE3200 EISA only).
   jne     S33_Bus_Scan                    ; No, then keep looking.
   pop     ebx                             ; Yes, then place tag in param table.
   mov     [ebx].MLIDBusTag,edx            ; Tag in EDX goes into location.
   push    ebx                             ; Keep BX straight.
   jmp     S33_Bus_Scan                    ; Keep cycling (for completeness).
S33_Bus_Scan_Done:
   pop     ebx                             ; Now we can restore EBX for good.
;
;  09/13/95 MPK Spec 3.3 changes End

if BusMaster
   call   EtherTSMGetASMHSMIFLevel
   cmp   eax, 220
   mov   ecx, eax
   lea   eax, LevelErrorMsg
   jb   DriverInitResetError      ; Jump if wrong TSM level.
endif

;---------------------------------------------------------------\
;                                                               *
; Calculate Loop Counter based on Processor Speed.      *
;                                                               *
;---------------------------------------------------------------/

   MSMGetProcessorSpeedRating      ; EAX = Processor Speed.
   cmp   eax, 200         ; Slow machine?
   jb   short InitLoopCountSet      ; Jump if so.

   xor   edx, edx         ; Clear high dword of dividend.
   mov   ecx, 100         ; Divisor = 100.
   idiv   ecx            ; EAX = Speed / 100.
   mov   esi, eax         ; Save quotient.

   mov   ecx, 30000h         ; EAX =
   imul   eax, ecx         ;  (Speed/100) * 30000h.
   mov   CountForLoop, eax      ; Save it.

   mov   eax, esi         ; EAX = Speed / 100.
   mov   ecx, RESET_BASE_COUNT      ; EAX =
   imul   eax, ecx         ;  (Speed/100) * 200.
   mov   CountForReset, eax      ; Save it.
InitLoopCountSet:

;---------------------------------------------------------------\
;                                                               *
; Save Maximum Packet size for Allocating RCB's at run time.   *
;                                                               *
;---------------------------------------------------------------/

   mov   eax, [ebx].MLIDMaximumSize   ; EAX = LSL's Max Packet Size.
   mov   CommonMaximumSize, eax      ; Save it.

;---------------------------------------------------------------\
;                                                               *
; Find all of the Ne3200 NICs in the machine.         *
;                                                               *
;---------------------------------------------------------------/

if UseNBICalls

   mov   esi, -1            ; ESI = ScanSequence
   mov   ebx, offset ProductID      ; EBX -> ProductID   
   mov   byte ptr [ebx+3], PRODUCT_NUMBER_2 ; Set product ID    
   xor   edx, edx         ; Start with zero cards found.

ScanSlotsForID1:
   push   edx            ; Save card count 
   mov   eax, 4            ; EAX = ProductIDLength
   mov   ecx, ODI_BUSTYPE_EISA      ; ECX = BusType
   call   MSMSearchAdapter             ; Let MSM scan for us
   pop   edx            ; Get card count back
   jnz   short ScanNextID      ; Jump if no more cards found
        mov     SlotsWithMyBoard[edx * 4], ecx  ; Save slot # (HIN) into table.
   inc   edx            ; Count it
        jmp     short ScanSlotsForID1           ; Keep looking.

ScanNextID:
   mov   esi, -1            ; ESI = ScanSequence
   mov   ebx, offset ProductID      ; EBX -> ProductID   
   mov   byte ptr [ebx+3], PRODUCT_NUMBER_2b   ; Set next product ID    

ScanSlotsForID2:
   push   edx            ; Save card count 
   mov   eax, 4            ; EAX = ProductIDLength
   mov   ecx, ODI_BUSTYPE_EISA      ; ECX = BusType
   call   MSMSearchAdapter             ; Let MSM scan for us
   pop   edx            ; Get card count back
   jnz   short FinishScanSlots      ; Jump if no more cards found
   mov     SlotsWithMyBoard[edx * 4], ecx  ; Save slot # (HIN) into table.
   inc   edx            ; Count it
        jmp     short ScanSlotsForID2           ; Keep looking.

else

   xor   ecx, ecx         ; Clear slot count.
   xor   esi, esi         ; Clear slot number.
   mov   edx, 0C80h         ; Start with slot zero.
ScanSlots:
   inc   esi            ; Update slot number.
   cmp   esi, TOTAL_EISA_SLOTS      ; Are we done?
   ja   short FinishScanSlots      ; Jump if so.
   and   dx, 0FFF0h         ; Roll back to first id.
   add   dx, 1000h         ; DX = xC80h.

   in   al, dx            ; Get first ID byte.
   cmp   al, MANUFACTURE_CHAR_CODE_1   ; Is this our ID?
   jne   ScanSlots         ; If not goto next slot.
   inc   dx            ; Move to next ID port.
   in   al, dx            ; Get next ID byte.
   cmp   al, MANUFACTURE_CHAR_CODE_2   ; Is this our ID?
   jne   ScanSlots         ; If not goto next slot.
   inc   dx            ; Move to next id port.
   in   al, dx            ; Get next ID byte.
   cmp   al, PRODUCT_NUMBER_1      ; Is this our ID?
   jne   ScanSlots         ; If not goto next slot.

   mov   SlotsWithMyBoard[ecx * 4], esi  ; Save slot number in table.
   inc   ecx            ; Update total slots.
   jmp   ScanSlots         ; Continue search.
endif

FinishScanSlots:
if UseNBICalls
   mov   ecx, edx
endif
   or   ecx, ecx         ; Any cards found?
   lea   eax, NoBoardsFound      ; EAX -> Error message.
   jz   DriverInitResetError      ; Jump if not.
   mov   SlotsWithMyBoardCount, ecx   ; Save number of NE3200's.

;---------------------------------------------------------------\
;                                                               *
; EBX -> Frame Data Space(Config Table).         *
; Let MSM Parse the command line.            *
;                                                               *
;---------------------------------------------------------------/

   mov   eax, NeedsIOSlotBit OR CAN_SET_NODE_ADDRESS
   lea   ecx, AdapterOptions
   call   MSMParseDriverParameters
   jnz   DriverInitError         ; Jump if error.

;---------------------------------------------------------------\
;                                                               *
; Store base I/O port based on physical slot.         *
;                                                               *
;---------------------------------------------------------------/

if UseNBICalls

   push   ebx            ; Save cfg table ptr.
   movzx   edx, [ebx].MLIDSlot      ; EDX = Slot (HIN) to use.
   call   MSMGetInstanceNumberMapping   ; Get UniqueID/BusTag back.
   push    eax
        lea eax, InstanceMappingErrorMsg
        jnz DriverInitErrorPopEBX               ; Jump if error.
        pop eax
                  ; EBX = UniqueID 
                  ; ECX = BusTag
   mov   eax, 1            ; EAX = Parameter count
   mov   edi, offset ConfigBuffer   ; EDI = &Buffer
   call   MSMGetUniqueIdentifierParameters   ; Get Physical slot#
   lea eax, ParameteridentifyErrorMsg 
   jnz   DriverInitErrorPopEBX      ; Jump if error.
   mov   eax, [edi]         ; EAX = Physical slot
   mov   edx, ebx         ; EDX = UniqueID
   pop   ebx            ; EBX = Cfg Table

else

   movzx   eax, [ebx].MLIDSlot      ; EAX = Slot choosen by user.

endif

   shl   eax, 12            ; EAX = Slot index.
   add   eax, 0C80h         ; EAX = index + EISA port.
   mov   [ebx].MLIDIOPortsAndLengths, ax   ; Store in config table.

;---------------------------------------------------------------\
;                                                               *
; Read configuration from EISA BIOS.            *
;                                                               *
;---------------------------------------------------------------/

if UseNBICalls               ; ECX = BusTag

   push   ebx            ; Save Cfg Table ptr
   mov   ebx, edx         ; EBX = UniqueID
   mov   edi, offset ConfigBuffer   ; EDI -> ConfigBuffer
   mov   esi, CFG_BUFFER_SIZE      ; ESI = ConfigBufferSize
   xor   eax, eax         ; EAX = EISA Cfg Block #
ReadConfigBlockLoop:
   push   eax            ; Save Block #
   call   MSMGetCardConfigInfo
   lea   eax, CardConfigErrorMsg
   jnz   DriverInitErrorPopEBX      ; Jump if error
   pop   eax            ; Get Block #
   inc   eax            ; EAX = Next Block #
   test   byte ptr [edi + 22h], EISA_INT_FUNCTION_BIT   ; Valid Int?
   jz   short ReadConfigBlockLoop         ; Jump if not.
   mov   dl, byte ptr [edi + 0b2h]   ; EDX = possible int.
   mov   EISAInterruptField, dl
   and   dl, ISOLATE_INT_MASK      ; Mask off interrupt field.
   jz   short ReadConfigBlockLoop   ; Jump out if not.
   pop   ebx            ; Get Cfg table back

else

   movzx   ecx, [ebx].MLIDSlot      ; Start with Block 0.

ReadConfigBlockLoop:
   call   MSMReadEISAConfig      ; Get config block.
   lea   eax, NoIntMsg         ; EAX -> Error Message.
   jne   DriverInitResetError

   inc   ch            ; CH = Next Block.
   test   byte ptr [esi + 22h], EISA_INT_FUNCTION_BIT   ; Valid Int?
   jz   short ReadConfigBlockLoop         ; Jump if not.

   mov   dl, byte ptr [esi + 0b2h]   ; EDX = possible int.
   mov   EISAInterruptField, dl
   and   dl, ISOLATE_INT_MASK      ; Mask off interrupt field.
   jz   short ReadConfigBlockLoop   ; Jump out if not.

endif

   mov   [ebx].MLIDInterrupt, dl      ; Copy int to config table.

;---------------------------------------------------------------\
;                                                               *
; Let MSM Register the hardware options with the OS.      *
;                                                               *
;---------------------------------------------------------------/

   call   MSMRegisterHardwareOptions
   cmp   eax, 1            ; Error Registering?
   ja   DriverInitError         ; Jump if so.
   je   DriverInitExit         ; Skip if new frame.

;---------------------------------------------------------------\
;                                                               *
; If debugging then allocate a 64K diagnostic buffer      *
;                                                               *
;---------------------------------------------------------------/

IF DEBUG
   extrn   MSMInitAlloc: near

   mov   eax, 1000h         ; Allocate 4K.
   call   MSMInitAlloc
   mov   [ebp].BufferAddress, eax
   or   eax, eax
   lea   eax, DiagAllocMemErrorMsg
   jz   DriverInitResetError

   sub   eax, eax
   mov   edi, [ebp].BufferAddress
   mov   ecx, 1000h/4
   rep   stosd
ENDIF

;---------------------------------------------------------------\
;                                                               *
; EBX -> Frame Data Space(Config Table).         *
; EBP -> Adapter Data Space.               *
;                                                               *
;---------------------------------------------------------------/

   test   EISAInterruptField, 01000000b   ; Shared ints?
   je   short DriverInitSetInterrupt   ; Jump if not.
   and   [ebp].GlobalConfigValue, 11110111b
DriverInitSetInterrupt:

   cmp   [ebx].MLIDInterrupt, 0ffh   ; Interrupt enabled?
   lea   eax, NoIntMsg
   jz   DriverInitResetError

;---------------------------------------------------------------\
;                                                               *
; Set up I/O port variables.               *
;                                                               *
;---------------------------------------------------------------/

DriverInitSetupIOPorts:
   movzx   edx, [ebx].MLIDIOPortsAndLengths
   lea   eax, [edx].SystemDoorbellMaskRegister
   mov   [ebp].EisaSystemDoorbellEnable, eax
   lea   eax, [edx].SystemDoorbellInterruptStatusRegister
   mov   [ebp].EisaSystemDoorbellStatus, eax

   lea   eax, [edx].MailboxRegisters   ; EAX -> Mailbox Base.
   mov   [ebp].IdleMailbox, eax      ; Save Abend port.
   inc   eax
   mov   [ebp].UpdateParmMailbox, eax   ; Save Parm Update port.
   inc   eax
   mov   [ebp].UpdateStatMailbox, eax   ; Save Stat Update port.
   mov     [ebp].UpdateStatCount, 0        ;Reset Counter. JCP, 941205.
   inc   eax
   mov   [ebp].TCBValidMailbox, eax   ; Save TCB Valid Register.
   inc   eax
   mov   [ebp].TCBMailbox, eax      ; Save TCB Register.
   add   eax, 8
   mov   [ebp].ParametersMailbox, eax   ; Save Parm Register.

;;   movzx   eax, [ebx].MLIDSlot      ; EAX = Slot number.
;;   shl   eax, 12            ; EAX = X000 port.
   movzx   eax, [ebx].MLIDIOPortsAndLengths ; EAX = XC80 port.
   sub   eax, 0C80h         ; EAX = X000 port.

   mov   [ebp].ResetRegister, eax   ; Save it for later.

;;TNL   mov   [ebp].InDriverInit, -1      ; Set InDriverInit flag.

if TxQueue
   mov   [ebp].MSMTxFreeCount, TOTAL_TCBS
endif

if AddPolling
   mov   eax, PollingTimeoutValue   ; Save timeout into adapter
   mov   [ebp].PollTimeout, ax      ;  parameter block.

   call   MSMGetPollSupportLevel          ; Check if OS supports polling.
   cmp   eax, 1            ; Is Polling supported?
   ja   short HavePollingSupport   ; Jump if yes.

   mov   [ebp].PollTimeout, 0      ; Force Interrupt only.

HavePollingSupport:

endif

;---------------------------------------------------------------\
;                                                               *
; Reset the adapter.                  *
;                                                               *
;---------------------------------------------------------------/

   mov   eax, OP_SCOPE_ADAPTER
   call   DriverReset         ; Initialize NIC.
;;TNL   mov   [ebp].InDriverInit, 0      ;   Clear InDriverInit flag.
   mov   [ebp].AdapterResetCount, 0   ; DriverReset incremented it.
   jnz   DriverInitResetError      ; Exit if error reseting.

   call   MSMSetHardwareInterrupt
   jnz   DriverInitError       ; Jump if error.

if CheckTCBs

;---------------------------------------------------------------\
;                                                               *
; Calculate Top of memory to protect ourselves from 4.x      *
; Transmit ECBs that may have logical addresses we can't handle.*
;                                                               *
;---------------------------------------------------------------/

   push   8            ; Max Buffer entries.
   push   offset SystemMemoryMap      ; Buffer for OS to fill in.
   call   GetSystemMemoryMap
   add   esp, (2 * 4)
   cmp   eax, 8
   ja   ScheduleCallBack      ; Can't determine it.

   lea   esi, SystemMemoryMap
MemoryMapLoop:
   mov   edi, [esi+0]         ; edi -> Offset.
   add   edi, [esi+4]         ; edi -> Offset + length.
   cmp   edi, TopOfPhysicalMemory   ; Below known Max?
   jb   short MemoryMapNext      ; Jump if so.
   mov   TopOfPhysicalMemory, edi   ; Save current Max.
MemoryMapNext:
   add   esi, 8
   dec   eax
   jne   short MemoryMapLoop
endif

;---------------------------------------------------------------\
;                                                               *
; Let MSM enable Call back and exit DriverInit.         *
;                                                               *
;---------------------------------------------------------------/

if AddPolling
   cmp   [ebp].PollTimeout, 0      ;# Enable Polling?
   je   short DriverRegisterMLID   ;# Jump if not.
   call   MSMEnablePolling
   lea   eax, EnablePollingErrorMsg
   jnz   DriverInitError
DriverRegisterMLID:            ;#
endif
   call   MSMRegisterMLID         ; Register MLID.
   jnz   DriverInitError      ; Jump if error.

ScheduleCallBack:            ; JCP, 941205 *Begin*
;;      mov     eax, (18 * 4)                   ; Schedule call back in 4 secs.
   mov     eax, 18 * 9         ; Schedule callback in 1/2 second.
                  ; JCP, 941205 *End*
   call   MSMScheduleIntTimeCallBack
   lea   eax, ScheduleIntErrorMsg
   jnz   DriverInitError      ; Jump if error.

if AddPolling
   movzx   eax, [ebp].PollTimeout      ;# EAX = cycles
   mov   ecx, 400         ;# 400ns per cycle.
   mul   ecx            ;#
   mov   ecx, eax         ;# ECX = timeout in ns.
   lea   esi, InterruptOnlyMsg      ;# ESI -> Interrupt Message.
   or   ecx, ecx         ;# Polling enabled?
   je   short PrintModeMessage      ;# Jump if not.
   lea   esi, PollingMsg         ;# ESI -> Polling Message.
PrintModeMessage:            ;#
   call   MSMPrintString         ;#
endif
DriverInitExit:

;---------------------------------------------------------------\
;                                                               *
; Determine frame type and send Parm Block to adapter.      *
;                                                               *
;---------------------------------------------------------------/

   cmp   [ebx].MLIDFrameID, 5      ; Raw 802.3?
   jnz   short PostCheckEII      ; Jump if not.
   movzx   eax, [ebx].MLIDBoardNumber   ; EAX = Board Number.
   mov   [ebp].BoardNumber8023, ax   ; Save it.
   jmp   short PostUpdateAdapter

PostCheckEII:
   cmp   [ebx].MLIDFrameID, 2      ; Ethernet II?
   jnz   short PostCheck8022      ; Jump if not.
   movzx   eax, [ebx].MLIDBoardNumber   ; EAX = Board Number.
   mov   [ebp].BoardNumberEII, ax   ; Save it.
   jmp   short PostUpdateAdapter

PostCheck8022:
   cmp   [ebx].MLIDFrameID, 3      ; 802.2?
   jnz   short PostMustBeSNAP      ; Jump if not.
   movzx   eax, [ebx].MLIDBoardNumber   ; EAX = Board Number.
   mov   [ebp].BoardNumber8022, ax   ; Save it.
   jmp   short PostUpdateAdapter

PostMustBeSNAP:
   movzx   eax, [ebx].MLIDBoardNumber   ; EAX = Board Number.
   mov   [ebp].BoardNumberSNAP, ax   ; Save it.

PostUpdateAdapter:
   mov   edx, [ebp].UpdateParmMailbox   ; EDX = Parm Update
   mov   ecx, CountForLoop      ; Set Loop counter.

;---------------------------------------------------------------\
;                                                               *
; If any previous command is pending then wait before we   *
; notify the Adapter of a Parameter Update command.      *
;                                                               *
;---------------------------------------------------------------/

WaitForUpdateMailBoxToClear:
   in   al, dx            ; AL = Parm Update.
   or   al, al            ; Cleared by adapter?
   jz   short UpdateParmMailboxClear   ; Jump if so.
   dec   ecx            ; Loop.
   jnz   WaitForUpdateMailBoxToClear

UpdateParmMailboxClear:
   inc   al            ; Set AL = 1.
   out   dx, al            ; Write to Update port.

   xor   eax, eax
   CPop
   ret               ; Exit.

DriverInitErrorPopEBX:
   pop   ebx

DriverInitResetError:
   push   eax            ; Save error message.
   push   ecx
   call   MSMReturnDriverResources   ; Return resources.
   pop   ecx
   pop   eax            ; EAX -> error message.
DriverInitError:
   mov   esi, eax         ; ESI -> error message.
   call   MSMPrintString         ; Display message.
   CPop
   or   eax, 1            ; Do not load error code.
   ret

DriverInit   endp
   subttl   -- DriverReset --
   page

;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverReset, NE3200/API/RESET )
;
; Name:      DriverReset
;
; Description:   This routine will reset and initialize the NIC.
;
; On Entry:     EAX     set to OP_SCOPE_ADAPTER if the adapter specified by EBP
;         is to be reset. Otherwise set to OP_SCOPE_LOGICAL_BOARD
;         which indicates that only the logical board specified
;                       by EBX is to be reset.
;      EBX   @ Frame Data Space
;      ECX   N/A
;      EDX   N/A
;      EBP   @ Adapter Data Space
;      ESI   N/A
;      EDI   N/A
;
;       Note:   Interrupts are disabled.
;
; On Return:   EAX   0 if successful(otherwise points to error message)
;      EBX   Preserved
;      ECX   Destroyed
;      EDX   Destroyed
;      EBP   Preserved
;      ESI   Destroyed
;      EDI   Destroyed
;
;       Flags:
;
;       Note:   Interrupts disabled.
;
; Remarks:   This routine is called by the MSM media module and by
;      DriverInit. It is called at process time.
;
; See Also:   ETHERTSM\EtherTSMReset
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
;
   align   16
   public   DriverReset
DriverReset   proc   near

   mov   [ebp].InDriverReset, 1      ; Set InDriverReset flag.

   cmp   eax, OP_SCOPE_ADAPTER
   je   DriverResetRetry

;------------------------------------------------------------------------
;JCJ 11-July-1997   Now the scope is OP_SCOPE_LOGICAL_BOARD.  
;                   This reset means a previously shutdown logical board to
;                   be activated.  spd #160930
;------------------------------------------------------------------------
        movzx   eax, [ebx].MLIDBoardNumber      ;Board Number in eax
        call   SetDriverDataBoardNumber        ;Set the board number in
                                                ;adapter space
;------------------------------------------------------------------------
;Now inform the firmware that driver parameters have been updated.

        Call    UpdateDriverData
        jz      DoneWithUpdation
        jmp     DriverResetErrorExit
DoneWithUpdation:
        jmp     DontEnableInterrupts            ;Exit reset.

;JCJ END SPD #160930
;End of DriverReset with OP_SCOPE_LOGICAL_BOARD

;Begin DriverReset with OP_SCOPE_ADAPTER
DriverResetRetry:
;---------------------------------------------------------------\
;                                                               *
; Call DriverShutdown to reset NIC (uses the ResetRegister port)*
; and return any TCB's or RCB's that the Driver has acquired.   *
;                                                               *
;---------------------------------------------------------------/
   mov   ecx, 1
   mov   eax, OP_SCOPE_ADAPTER            ; Indicate partial shutdown.
   call   DriverShutdown         ; Reset NIC card.

;---------------------------------------------------------------\
;                                                               *
; Attempt to allocate the first RCB.            *
;                                                               *
;---------------------------------------------------------------/

   inc   [ebp].AdapterResetCount      ; Increment Reset stats.
   xor   eax, eax         ; EAX = index reg(init to 0).
   mov   [ebp].ReceiveQueueHead, eax   ; Init head and queue.
   mov   [ebp].ReceiveQueueTail, eax

   mov   esi, CommonMaximumSize      ; ESI = Max Packet Size.
   call   MSMAllocateRCB         ; Allocate a RCB (ESI= @ECB).
   jnz   short WaitOnFirmware      ; Jump if no RCB.

   dec   [ebp].NeedRCBCount
   xor   eax, eax         ; Start with index of Zero.

;---------------------------------------------------------------\
;                        *
; MSMAllocateRCB zeroed out the RProtocolWorkspace field.   *
;   ESI = Logical address of ECB.            *
;   EDI = Physical address of ECB. (for BusMaster systems)   *
;                        *
;---------------------------------------------------------------/

   mov     edx, dword ptr [esi].RProtocolWorkspace+0 ; Get first dword
   mov   dword ptr [ebp].HostPWSList1[eax*4], edx  ; Save first dword
   mov     edx, dword ptr [esi].RProtocolWorkspace+4 ; Get 2nd dword
   mov   dword ptr [ebp].HostPWSList2[eax*4], edx  ; Save 2nd dword

   mov   [ebp].HostRCBList[eax*4], esi   ; Save log. address of ECB.
if BusMaster
   mov   [ebp].AdapterRCBList[eax*4], edi ; Save phys. adr of ECB.
else
   add   esi, LogicalToPhysical      ; Convert RCB to physical.
   mov   [ebp].AdapterRCBList[eax*4], esi
endif
   inc   eax            ; EAX = 1 (Index).
   mov   [ebp].ReceiveQueueTail, eax
WaitOnFirmware:

;---------------------------------------------------------------\
;                                                               *
; Wait for NIC to report its initial status.         *
;                                                               *
;---------------------------------------------------------------/

   mov   ecx, CountForLoop      ; ECX = Loop counter.
   shl   ecx, 1            ; Allow more time for shutdown.

   mov   edx, [ebp].IdleMailbox      ; EDX -> NIC's Abend port 10h.
WaitForFirmwareStatusLoop:
   in   al, dx            ; Read status.
   or   al, al            ; Non Zero return?
   jnz   short FirmwareStatusComplete   ; Jump if so.
   dec   ecx            ; Loop again?
   jnz   WaitForFirmwareStatusLoop   ; Jump if so.

;---------------------------------------------------------------\
;                                                               *
; The DriverShutdown routine may just need some more time   *
; (especially on a faster machine). We will retry shutdown up   *
; to three more times before concluding the adapter won't reset.*
;                                                               *
;---------------------------------------------------------------/
   inc   [ebp].InDriverReset      ; Inc the inuse/counter.

   cmp   [ebp].InDriverReset, 4      ; Shutdown more than 3 times?
   jbe   DriverResetRetry      ; Jump if no (try again).

   lea   eax, FirmwareInitErrorMsg   ; EAX -> Error Message.
   jmp   DriverResetErrorExit      ; Exit Driver Reset.

FirmwareErrorStatus:
   test   al, 40h            ; Static RAM Error?
   lea   eax, StaticMemoryErrorMsg   ; EAX -> RAM Error message.
   jnz   DriverResetErrorExit      ; Jump if so.
   lea   eax, RomErrorMsg      ; EAX -> ROM Error message.
   jmp   DriverResetErrorExit      ; Exit Driver Reset.

FirmwareStatusComplete:
   test   al, 80h            ; Firmware Init successful?
   jz   FirmwareErrorStatus      ; Jump if not.

;---------------------------------------------------------------\
;                                                               *
; Tell NIC where to read firmware from.            *
;                                                               *
;---------------------------------------------------------------/

   inc   edx            ; DX -> Mailbox+1.
   mov   eax, DriverFirmwareSize      ; EAX = Size of firmware.
   out   dx, al            ; Send LSB of size.
   inc   edx            ; DX -> Mailbox+2.
   mov   al, ah
   out   dx, al            ; Send MSB of size.

   mov   eax, DriverFirmwareBuffer   ; EAX -> Firmware Buffer
if BusMaster
   call   MSMGetPhysical         ; Convert to Physical Addr.
else
   add   eax, LogicalToPhysical      ; Convert to Physical Addr.
endif

   add   edx, 2            ; DX -> Mailbox+4.
   out   dx, eax            ; Send Buffer address.

   add   edx, 4            ; DX -> Mailbox+8.
   xor   eax, eax         ; Dest. = 0.
   out   dx, eax            ; Send Destination addr.

   mov   edx, [ebp].IdleMailbox      ; DX -> Mailbox + 0.
   out   dx, al            ; Send command.

   mov   edx, [ebp].ParametersMailbox   ; DX -> Parm Port.
   mov   ecx, CountForLoop      ; ECX = Loop counter.
   shl     ecx, 1            ;TNL 3/30/95 We need to wait
                  ; a little longer here.
WaitForDownloadLoop:
   in   eax, dx            ; EAX = Download status.
   cmp    eax, 11111111h         ; Code Running?
   jz   short FirmwareOperational   ; Jump if yes.
   dec   ecx            ; Loop again?
   jnz   WaitForDownloadLoop      ; Jump if so.
   lea   eax, FirmwareLoadErrorMsg   ; EAX -> Error Message.
   jmp   DriverResetErrorExit      ; Exit Driver Reset.

;---------------------------------------------------------------\
;                                                               *
; Now fill in adapter parameter block and then give the   block's   *
; address to the adapter, so the firmware can copy it down.   *
;                                                               *
;---------------------------------------------------------------/

FirmwareOperational:
if BusMaster
   lea   eax, [ebx].MLIDNodeAddress      ; Store node address.
   call   MSMGetPhysical
   mov   [ebp].NodeAddressPointer, eax
   mov   eax, [ebx].MLIDMaximumSize      ; Store Max Packet
   mov   [ebp].MaxReceivePacketSize, eax      ;  size.
   lea   eax, [ebp].PacketTxTooBigCount      ; Save ptr to Stat table.
   call   MSMGetPhysical
   mov   [ebp].GenericStatisticsPointer, eax
   movzx   eax, [ebp].CustomVariableCount      ; Store number of
   mov   [ebp].CustomStatisticsCount, ax      ;  custom variables.
   lea   eax, [ebp].AdapterRCBList      ; Save ptr to RCB list.
   call   MSMGetPhysical
   mov   [ebp].RCBListPointer, eax
IF DEBUG
   mov   eax, [ebp].BufferAddress      ;# Set up diagnostic buffer
   call   MSMGetPhysical
   mov   [ebp].DiagnosticBufferPointer, eax
ENDIF
else
   mov   ecx, LogicalToPhysical         ; Store conversion
   mov   [ebp].LogicalToPhysicalOffset, ecx   ; parameter.
   lea   eax, [ebx].MLIDNodeAddress      ; Store node address.
   add   eax, ecx
   mov   [ebp].NodeAddressPointer, eax
   mov   eax, [ebx].MLIDMaximumSize      ; Store Max Packet
   mov   [ebp].MaxReceivePacketSize, eax      ; size.
   lea   eax, [ebp].PacketTxTooBigCount           ; Store pointer to
   add   eax, ecx            ; statistics table.
   mov   [ebp].GenericStatisticsPointer, eax
   movzx   eax, [ebp].CustomVariableCount      ; Store number of
   mov   [ebp].CustomStatisticsCount, ax      ; custom variables.
   lea   eax, [ebp].AdapterRCBList      ; Store pointer to
   add   eax, ecx            ; RCB list.
   mov   [ebp].RCBListPointer, eax
IF DEBUG
   mov   eax, [ebp].BufferAddress      ; Set up diagnostic buffer
   add   eax, ecx
   mov   [ebp].DiagnosticBufferPointer, eax
ENDIF
endif

;-----------------------------------------------------------------\
;                                                                 *
; EtherTSMUpdateMulticast will either call DriverPromiscuousChange*
; if promisc. mode is enabled, or DriverMulticastChange.     *
; Because both procedures normally write to the UpdateParmMailbox *
; I/O port, the flag InDriverReset is used to prevent this.     *
; Otherwise the adapter firmware would become out of sync with us,*
; since it's waiting for a UpdateParmMailbox notification that the*
; address of the adapter parameter block is now available,     *
; (see label WaitForParameterBlock in adapter.386 code).     *
;                                                                 *
;-----------------------------------------------------------------/

   call   EtherTSMUpdateMulticast         ; Store Multicast
                     ;  variables.
SkipMulticastUpdate:
   mov   eax, dword ptr [ebx].MLIDNodeAddress+0   ; Copy Node Address
   mov   dword ptr [ebp].HostNodeAddress+0, eax   ;  to structure.
   mov   ax, word ptr [ebx].MLIDNodeAddress+4
   mov   word ptr [ebp].HostNodeAddress+4, ax
;--------------------------------------------------------------------------
;JCJ 11-July-1997 In an OP_SCOPE_ADAPTER reset we have to reactivate any previous
;                 partial shutdown boards. SPD #160930
;--------------------------------------------------------------------------
        push    ebx                             ;keep pointer to frame data space
        xor     ecx, ecx                        ;for(i=0; i<4; i++)
ReactivateBoard:                             ;i is the board index
        mov     ebx, [ebp].MSMVirtualBoardLink+(ecx*4)
        or      ebx, ebx                        ;Valid frame data space
        jz      CheckNextBoard                  ;no, take next board
        movzx   eax, [ebx].MLIDBoardNumber      ;Board Number in eax
        call    SetDriverDataBoardNumber        ;Set the board number in
                                                ;adapter dataspace
CheckNextBoard:
        inc     ecx                             ;next board
        cmp     ecx, 4                          ;have checked all 4 boards?
        jb      ReactivateBoard                 ;no, go for next board

        pop     ebx

;JCJ END SPD #160930

        lea   eax, [ebp].LogicalToPhysicalOffset   ; EAX -> Parm block.
if BusMaster
   call   MSMGetPhysical
else
   add   eax, LogicalToPhysical      ; Convert to phys.
endif

   mov   edx, [ebp].ParametersMailbox   ; EDX -> parm port.
   out   dx, eax            ; Send address to adapter.

   mov   edx, [ebp].UpdateParmMailbox   ; EDX -> Parm update port.
   mov   al, 1            ; Set it.
   out   dx, al

   mov   ecx, CountForLoop      ; Set loop counter.
   shl   ecx, 1

;---------------------------------------------------------------\
;                                                               *
; Note: A zeroed out UpdateParmMailbox means the adapter has   *
; gotten our command but is probably still processing it.   *
;                                                               *
;---------------------------------------------------------------/

WaitForParametersLoop:
   in   al, dx            ; AL = Parm update value.
   or   al, al            ; Cleared?
   jz   short ParametersUploaded   ; Jump if so.
   dec   ecx
   jnz   WaitForParametersLoop
   lea   eax, ParameterPassErrorMsg   ; EAX -> Error message.
   jmp   short DriverResetErrorExit   ; Exit DriverReset.

ParametersUploaded:

if AddPolling
   mov   edx, [ebp].PollingMailbox   ;# Clear Polling Mailbox.
   xor   al, al            ;#
   out   dx, al            ;#
endif

   mov   edx, [ebp].EisaSystemDoorbellEnable  ; Port 0Eh.
   inc   edx            ; DX = Doorbell + 1.
   mov   al, -1            ; Reset the status port,
   out   dx, al            ;   (EISA_DOORBELL_STATUS).

   dec   edx            ; DX = Doorbell + 0.
   mov   eax, 1            ; Enable it,
   out   dx, al            ;  (EISA_DOORBELL_ENABLE).

   sub   edx, 6            ; DX = Global Config port.
   mov   al, [ebp].GlobalConfigValue
   out   dx, al

   inc   edx            ; DX = System interrupt port.
   mov   al, 1
   out   dx, al            ; Enable it.

DontEnableInterrupts:
;TNL 7/27 Add next line
   mov   [ebp].InDriverReset, 0      ; Clear InDriverReset flag.
   xor     eax, eax
   ret               ; Init successful.

DriverResetErrorExit:
;TNL 7/27 Add next line
   mov   [ebp].InDriverReset, 0      ; Clear InDriverReset flag.
   or   eax, eax         ; Clear the zero flag.
   ret

DriverReset    endp
;-----------------------------------------------------------------------
;JCJ 11-July-1997 This routine is added to set the adapter data space BoardNumber
;                 Variable.   The same has to be done from DriverReset
;                 twice and from DriverShutdown once. SPD #160930
;------------------------------------------------------------------------
        subttl -- SetDriverDataBoardNumber --
;***********************************************************************
; Name:         SetDriverDataBoardNumber
;
; Description:  This is a local procedure which will be called from DriverReset
;               and DriverShutdown.   This procedure sets the adapterdata
;               board field.
;
; On Entry:     EAX     Will have board number or -1(In case of shutdown)
;               EBX     @ Frame Data Space
;               ECX     N/A
;               EDX     N/A
;               EBP     @ Adapter Dataspace
;               ESI     N/A
;               EDI     N/A
;
; On return:    EDX     Destroyed
;
;************************************************************************
        align    16
SetDriverDataBoardNumber proc

        movzx   edx, [ebx].MLIDFrameID          ;edx = MLIDFrameID
        cmp     dx, 2                           ;Config table is for EII?
        jne     check802_2                      ;No check for 802.2
        mov     [ebp].BoardNumberEII, ax        ;Yes, Keep boardnumber
        ret
check802_2:
        cmp     dx, 3                           ;Is it for 802.2?
        jne     check802_3                      ;No, Check 802.3
        mov     [ebp].BoardNumber8022, ax       ;Yes, Keep boardNumber
        ret
check802_3:
        cmp     dx, 5                           ;Is it for 802.3?
        jne     check_SNAP                      ;No, Check SNAP
        mov     [ebp].BoardNumber8023, ax       ;Yes, Keep boardNumber
        ret
check_SNAP:
        cmp     dx, 10                          ;Is it for SNAP?
        jne     SetDriverDataBoardNumberExit
        mov     [ebp].BoardNumberSNAP, ax
SetDriverDataBoardNumberExit:
        ret
SetDriverDataBoardNumber endp

        subttl -- UpdateDriverData --
;***********************************************************************
; Name:         UpdateDriverData
;
; Description:  This is a local procedure which will be called from DriverReset
;               and DriverShutdown.   This is called after setting the driver
;               parameters.  This procedure updates adapter with the board field.
;
; On Entry:     EBP     @ Adapter Dataspace
;
; On return:    EAX     Destroyed
;      ECX     Destroyed
;               EDX     Destroyed
;
;               Flags:  Z  Reset incase of error
;
;************************************************************************
        align    16

UpdateDriverData   proc
        mov     edx, [ebp].UpdateParmMailbox    ; DX -> Parm Port.
   mov   ecx, CountForLoop      ; Set loop counter.
WaitForLoop:
        in      al, dx
        or      al, al                          ;Cleared?
        jz      SetMailBox
        loop    WaitForLoop                     ;else wait till counter elapse.
SetMailBox:                          ;Here I'm not looking for the timeout
        mov     al, 1                           ;Now set the mail box to tell him
        out     dx, al                          ;that driver parameter need to be updated.

        mov     ecx, CountForLoop               ;Wait for the adapter response
        shl     ecx, 1
WaitForAdapterResponse:
        in      al, dx             ;al=param update value
        or      al, al                          ;Cleared
        jz      short ExitUpdateDriverData      ;Yes We're done
        loop    WaitForAdapterResponse          ;No, loop there.
        lea     eax, ParameterPassErrorMsg      ;Counter reaches 0, ErrorExit
        or      eax, eax                        ;Reset zero flag.
ExitUpdateDriverData:
        ret
UpdateDriverData endp

;JCJ END SPD #160930


        subttl   -- DriverShutdown --
   page
;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverShutdown, NE3200/API/SHUTDOWN )
;
; Name:      DriverShutdown
;
; Description:   This routine will set the card into an idle/reset state
;      and return any ECB's that it is holding.
;
; On Entry:     EAX     set to OP_SCOPE_ADAPTER if the adapter specified by EBP
;         is to be shutdown. Otherwise set to OP_SCOPE_LOGICAL_BOARD
;         which indicates that only the logical board specified
;                        by EBX is to be shutdown.
;      EBX   @ Frame Data Space
;      ECX   0 if Permanent Shutdown
;      EDX   N/A
;      EBP   @ Adapter Data Space
;      ESI   N/A
;      EDI   N/A
;
;       Note:   Interrupts are disabled.
;
; On Return:   EAX   0 if successful
;      EBX   Preserved
;      ECX   Destroyed
;      EDX   Destroyed
;      EBP   Preserved
;      ESI   Destroyed
;      EDI   Destroyed
;
;       Flags:
;
;       Note:   Interrupts preserved.
;
; Remarks:   This routine is called by the MSM media module and by
;      DriverReset. It is called at process time.
;
; See Also:   ETHERTSM\EtherTSMShutdown
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
;
   align   16
   public   DriverShutdown
DriverShutdown   proc

   cmp   eax, OP_SCOPE_ADAPTER
   je   ShutdownDriver
;------------------------------------------------------------------------
;JCJ 11-July-1997   Now the scope is OP_SCOPE_LOGICAL_BOARD. This means
;          a logical board needs to be shutdown.  spd #160930
;------------------------------------------------------------------------
        test    [ebx].MLIDSharingFlags, IODetachedBit   ;Shutdown bit is set
        jz      SkipShutDownBoard                       ;No, Do not reset board
;Since DriverShutdown will not be called from DriverReset with OP_SCOPE_LOGICAL_BOARD
;InDriverReset need not be checked.
        mov     eax, -1
        call   SetDriverDataBoardNumber        ;Reset Set the board number in
                                                ;adapter space
;------------------------------------------------------------------------
;Now inform the firmware that driver parameters have been updated.
SkipShutDownBoard:
        Call    UpdateDriverData
        jnz     ShutDownExit                    ;On successfull return Z flag
        xor     eax, eax                        ;will be set.
ShutDownExit:
        ret
;JCJ 11-July-1997 spd #160930
;---------------------------------------------------------------\
;                                                               *
; Set card into idle state and then reset it.         *
;                                                               *
;---------------------------------------------------------------/

ShutdownDriver:
   mov   [ebp].DriverShutdownType, ecx   ; Save for later checking.

;;TNL   cmp   [ebp].InDriverInit, 0      ;   Called by Driver Init?
   cmp   [ebp].InDriverReset, 0      ; Called by Driver Reset?
   jnz   short ShutdownResetNIC      ; Jump if so.

   mov   edx, [ebp].IdleMailbox      ; EDX -> Idle adapter port.
   mov   al, 1            ; Set it.
   out   dx, al

   mov   ecx, CountForLoop      ; ECX = loop counter.
ShutdownWaitForIdle:
   in   al, dx            ; Read idle adapter port.
   or   al, al            ; Cleared by adapter.
   jz   short ShutdownStopInterrupts   ; Jump if so.
   dec   ecx
   jnz   ShutdownWaitForIdle

ShutdownStopInterrupts:
   cmp   [ebp].DriverShutdownType, 0   ; Is this a permanent Shutdown?
   jne   ShutdownResetNIC      ; Jmp if No (Go reset the card).

   mov     edx, [ebp].EisaSystemDoorbellEnable  ; Get I/O reg for Disable
                  ;    interrupts.
   xor     al, al                          ;
   out     dx, al            ; Disable interrupts.
   jmp   short ShutdownClearInterrupt   ; Continue.

ShutdownResetNIC:
    mov   edx, [ebp].ResetRegister   ; EDX -> NIC Reset Port.
   mov   eax, 1            ; Set Reset Bit.
   out   dx, eax            ; Reset the NIC.

   mov   edx, [ebp].IdleMailbox      ; Clear Abend mailboxes.
   xor   eax, eax
   out   dx, al

   mov   ecx, CountForReset      ; Allow reset settling time.
ShutdownHoldReset:
   loop   ShutdownHoldReset      ; Give NIC time to go Idle.

   mov   edx, [ebp].ResetRegister   ; EDX -> NIC Reset Port.
   out   dx, eax            ; Clear NIC's reset state.

;---------------------------------------------------------------\
;                                                               *
; Clear Interrupt Status in case it's level triggered.      *
;                        *
;---------------------------------------------------------------/

ShutdownClearInterrupt:
   mov   eax, 1            ; Select sticky bit to clear.
   mov   edx, [ebp].EisaSystemDoorbellStatus
   in   al, dx
   out   dx, al            ; Reset bits.

;---------------------------------------------------------------\
;                                                               *
; Return any Receive ECB's.               *
;                                                               *
;---------------------------------------------------------------/

   mov   ecx, TOTAL_RCBS
   sub   ecx, [ebp].NeedRCBCount      ; ECX = RCBs in use.
   or   ecx, ecx         ; Any RCBs in use?
   jz   short ShutdownReturnTCB      ; Jump if not.
ShutdownReturnRCBLoop:
   mov   eax, [ebp].ReceiveQueueHead   ; EAX = Head of list Index.
   mov   esi, [ebp].HostRCBList[eax*4]   ; ESI -> RCB.
   inc   eax            ; Bump index.
   and   eax, TABLE_MASK
   mov   [ebp].ReceiveQueueHead, eax   ; Save new head.
   cmp   esi, -1            ; Is the pointer valid?
   je   ShutdownNextRCB         ; Jump if NO.
   MSMReturnRCB            ; Return RCB.
ShutdownNextRCB:
   dec   ecx            ; Get next one.
   jnz   short ShutdownReturnRCBLoop

ShutdownReturnTCB:
if TxQueue
   cmp   [ebp].MSMTxFreeCount, TOTAL_TCBS  ; TCBs given back?
   je   ShutdownInitVariables        ; Jump if so.

   mov   eax, [ebp].TCBQueueHead      ; EAX = Index for Head of TCB list.
   mov   esi, [ebp].HostTCBList[eax*4]   ; ESI = RCB.
   inc   al
   mov   [ebp].TCBQueueHead, eax      ; Save new index.
   inc   [ebp].MSMTxFreeCount
if UseFastCalls
   push   ebp
   push   ebx
   call   EtherTSMFastSendComplete   ; Return the TCB.
   pop   ebx
   pop   ebp
else
   call   EtherTSMSendComplete
endif
   jmp   ShutdownReturnTCB

else
   mov   esi, [ebp].TCBInProcess      ; ESI -> possible TCB.
   or   esi, esi         ; Valid TCB?
   jz   short ShutdownInitVariables   ; Jump if not.
   mov   [ebp].TCBInProcess, 0      ; Clear pointer.
if UseFastCalls
   push   ebp
   push   ebx
   call   EtherTSMFastSendComplete   ; Return TCB.
   pop   ebx
   pop   ebp
else
   call   EtherTSMSendComplete      ; Return TCB.
endif

endif

ShutdownInitVariables:
if   TxQueue
   mov   [ebp].MSMTxFreeCount, TOTAL_TCBS   ; TOTAL_TCBS = 128;
   mov   [ebp].TCBQueueHead, 0
   mov   [ebp].TCBQueueTail, 0
else
   mov   [ebp].MSMTxFreeCount, 1      ; Allow 1 transmit at a time.
endif
   mov   [ebp].NeedRCBCount, TOTAL_RCBS   ; Reset Need RCB count to MAX.

   cmp   [ebp].DriverShutdownType, 0   ; Is this a permanent Shutdown?
   jne   ShutdownSetupLists      ; Jump if No.

;---------------------------------------------------------------\
;                                                               *
; We're in the process of totally shutting down the driver due   *
; to a call to our DriverRemove. We reset NeedRCBCount to zero   *
; so that any pending interrupts that invoke our DriverISR will   *
; not cause this HSM to request more RCBs be allocated due to   *
; the NeedRCBCount being non-zero.            *
;                                                               *
;---------------------------------------------------------------/

   mov   [ebp].NeedRCBCount, 0      ; Reset Need RCB count to Zero.

;---------------------------------------------------------------\
;                                                               *
; Reinitialize the Host and RCB Lists,            *
;    (each entry serves as a pointer to a Receive ECB).      *
;                                                               *
;---------------------------------------------------------------/
ShutdownSetupLists:
   lea   edi, [ebp].AdapterRCBList   ; Setup to initialize RCB List.
   mov   eax, -1
   mov   ecx, TABLE_SIZE + TCB_TABLE_SIZE
   cld
 rep   stosd               ; Reset all entries to -1.

   lea   edi, [ebp].HostRCBList      ;TNL 7/27/95 Added this line.
   xor   eax, eax
   mov   ecx, TABLE_SIZE + TCB_TABLE_SIZE
 rep   stosd               ; Clear all entries to 0.

   xor   eax, eax         ; Successful return.
   ret

DriverShutdown   endp

;***********************************************************************\
; BEGIN_MANUAL_ENTRY( PollTimeoutRoutine)
;
; Name:      PollTimeoutRoutine
;
; Description:   This routine saves the timeout value.
;
; On Entry:   EAX   Timeout Value
;      EBX   N/A
;      ECX   N/A
;      EDX   N/A
;      EBP   N/A
;      ESI   N/A
;      EDI   N/A
;
;       Note:   Interrupts are in any state.
;
; On Return:   EAX   Preserved
;      EBX   Preserved
;      ECX     Preserved
;      EDX   Preserved
;      EBP   Preserved
;      ESI   Preserved
;      EDI   Preserved
;
;       Flags:
;
;       Note:   Interrupts preserved.
;
; END_MANUAL_ENTRY
;
;***********************************************************************/

PollTimeoutRoutine   proc

   mov   PollingTimeoutValue, eax   ; Save timeout value.
   ret               ; Exit.

PollTimeoutRoutine   endp


   subttl   -- DriverRemove --
   page

;***********************************************************************\
;
; BEGIN_MANUAL_ENTRY( DriverRemove, NE3200/API/REMOVE )
;
; Name:      DriverRemove
;
; Description:   This routine calls the MSM to return our resources.
;
; On Entry:   EAX   N/A
;      EBX   N/A
;      ECX   N/A
;      EDX   N/A
;      EBP   N/A
;      ESI   N/A
;      EDI   N/A
;
;       Note:   Interrupts are in any state.
;
; On Return:   EAX   Destroyed
;      EBX   Preserved
;      ECX   Destroyed
;      EDX   Destroyed
;      EBP   Preserved
;      ESI   Preserved
;      EDI   Preserved
;
;       Flags:
;
;       Note:   Interrupts preserved.
;
; Remarks:   This routine is called by the OS at unload.
;      It is called at process time.
;
; See Also:   MSM\MSMDriverRemove
;
; END_MANUAL_ENTRY
;
;***********************************************************************/
;
   align   16
   public   DriverRemove
DriverRemove   proc

   CPush
   mov   eax, DriverModuleHandle
   call   MSMDriverRemove
   CPop
   ret               ; Exit.

DriverRemove   endp

OSCODE   ends

   end