home *** CD-ROM | disk | FTP | other *** search
- version equ 5
- DEBUG equ 0
- ;History:31,1
-
- ; Copyright 1991, 1992, 1993 Russell Nelson
-
- ; This program is free software; you can redistribute it and/or modify
- ; it under the terms of the GNU General Public License as published by
- ; the Free Software Foundation, version 1.
- ;
- ; This program is distributed in the hope that it will be useful,
- ; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ; GNU General Public License for more details.
- ;
- ; You should have received a copy of the GNU General Public License
- ; along with this program; if not, write to the Free Software
- ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- include defs.asm
-
- code segment word public
- assume cs:code, ds:code
-
- ;
- ; Waits for SCB command unit to become idle
- ;
- ; MUST NOT TRASH CX OR THE ISSUE_COMMAND PROCEDURE WILL FAIL
- ;cmd_clear exits with cy if the command didn't become idle in one millisecond.
-
- cmd_clear macro
- local exit
-
- lea dx, [bp].@SCB_CMD ;BP -> I/O Base
-
- in ax, dx ;Read SCB command
- or ax, ax ;Wait for command accepted
- jz exit
-
- call cmd_wait
- exit:
- endm
-
- ;
- ; Drives channel attention to the 586. We don't care whats in AX, the write
- ; will cause the ASIC to drive CA to the 586.
- ;
- issue_ca MACRO
- lea dx, [bp].@CA_Ctrl
- out dx, al
- endm
-
-
- ;
- ;
- ; Enable and disable exp16s interrupts.
- ;
- enable_board_ints macro
- lea dx, [bp].@Sel_IRQ
- mov al, encoded_int_no
- or al, 08h
- out dx, al
- endm
-
- disable_board_ints macro
- lea dx, [bp].@Sel_IRQ
- mov al, encoded_int_no
- out dx, al
- endm
-
-
- RxBufferSize equ 1518+14+18 ;Max Rx packet+MAC header+
- ; 18 (alignment)
- TxBufferSize equ 1518+14+20 ;Max Tx packet+MAC header+
- ; 20 (alignment)
-
- include exp16.inc
-
- _64K_not_32K db 0 ;<>0 if we have 64K of memory.
- _16_not_8_bit_slot db 0 ;<>0 if we're in a 16-bit slot.
-
- ;possible values for connection_type:
- CONN_BNC equ 0
- CONN_AUI equ 1
- CONN_TPE equ 2
- CONN_AUTO equ 3
- connection_type db ?
-
- ;Memory Sizes
- mem_size_address equ 00H
- _32K equ 00000h
- _64K equ 00001h
-
- CONNECTION_ADDRESS equ 00H
- CONNECTION_FIELD equ 0001000000000000B
-
- AUTO_CON_ADDRESS EQU 01H
- AUTO_CON_MASK EQU 10000000B
-
- TPE_address equ 05H
- TPE_type_field equ 0000000000000001B
-
- int_num_address equ 00H
- int_num_field equ 1110000000000000B
- int_field_shift equ 13
-
- EE_ETHERNET_ADD_LOW equ 2
- EE_ETHERNET_ADD_MID equ 3
- EE_ETHERNET_ADD_HIGH equ 4
- EE_INT equ 0
- EE_SHIFT equ 13
-
- ; Slot Width
- slot_width_mask equ 04h
- _16_bit_slot equ 0000h
- _8_bit_slot equ 0001h
-
- _16_bit_override_bit equ 08h
-
-
- ;
- ; EXP16 base port structure
- ;
- @EXP16BasePorts struc
- @Data_Reg dw ? ;Data Transfer Register.
- @Write_Ptr dw ? ;Write Address Pointer.
- @Read_Ptr dw ? ;Read Address Pointer.
- @CA_Ctrl db ? ;Channel Attention Control.
- @Sel_IRQ db ? ;IRQ Select.
- @SMB_Ptr dw ? ;Shadow Memory Bank Pointer.
- db ?
- @MEM_Ctrl db ?
- @MEM_Page_Ctrl db ?
- @Config db ?
- @EEPROM_Ctrl db ?
- @ID_Port db ?
- @EXP16BasePorts ends
-
- ECR1 equ 300eh
-
- @ISR_Ports struc
- db 0C008h dup(?)
- @SCB_STAT dw ?
- @SCB_CMD dw ?
- @SCB_CBL dw ?
- @SCB_RFA dw ?
- ; @SCB_CRCERRS dw ?
- ; @SCB_ALNERRS dw ?
- ; @SCB_RSCERRS dw ?
- ; @SCB_OVRNERRS dw ?
- @ISR_Ports ends
-
-
- @memory_page_struc STRUC
- DB 4000H DUP (?)
- @mem_loc_0 DW ?
- @mem_loc_2 DW ?
- @mem_loc_4 DW ?
- @mem_loc_6 DW ?
- @mem_loc_8 DW ?
- @mem_loc_10 DW ?
- @mem_loc_12 DW ?
- @mem_loc_14 DW ?
- DB 4000H - 16 DUP (?)
- @mem_loc_16 DW ?
- @mem_loc_18 DW ?
- @mem_loc_20 DW ?
- @mem_loc_22 DW ?
- @mem_loc_24 DW ?
- @mem_loc_26 DW ?
- @mem_loc_28 DW ?
- @mem_loc_30 DW ?
- @memory_page_struc ENDS
-
- ;
- ;
- ; TData Segment
- ;
- ; This segment template represents the 64-KB segment that the 82586
- ; can address. Shared memory can be either 32K or 64K for the EXP16.
- ; All structures must be quad-word aligned.
- ;
- ; Offset Type of Block Block Size Cnt
- ; ------ ------------- ---------- ---
- ; 0000h ISCP 8 1
- ; 0008h SCB 16 1
- ; 0020h CommandBlock 104 1
- ; 00E0h SendBlock(s) 1568 variable
- ; ????h ReceiveBlock(s) 1568 variable
- ; FFF6h SCP 10 1
- ;
-
- TData_64 segment at 0
-
- ISCP ISysConfigPtr <>
- SCB SystemControlBlock <>
-
- ORG 20H
-
- CB CommandBlock <>
-
- Send_Blocks DB SIZE SendBlock * Number_of_Tx_Buffers dup (?)
- Receive_Blocks LABEL WORD
-
-
- ORG (0FFFFh - SIZE SCPS + 1) AND 0FFE0H
- SCP LABEL BYTE
-
- ORG 0FFFFh - SIZE SCPS + 1
- THeapTop LABEL BYTE ;Top of available memory
-
- end_of_send_blocks = 20h + SIZE CommandBlock + (Number_of_Tx_Buffers * SIZE SendBlock)
- num_rx_buf_32k = (07FFFh - SIZE SCPS + 1 - end_of_send_blocks) / (SIZE ReceiveBlock)
- num_rx_buf_64k = (0FFFFh - SIZE SCPS + 1 - end_of_send_blocks) / (SIZE ReceiveBlock)
-
- TData_64 ENDS
-
-
- public int_no
- int_no db 3,0,0,0 ;must be four bytes long for get_number.
- io_addr dw -1,-1 ; I/O address for card
- encoded_int_no db ? ;encoded for exp16.
-
- public driver_class, driver_type, driver_name, driver_function, parameter_list
- driver_class db BLUEBOOK, IEEE8023, 0 ;from the packet spec
- driver_type db 91 ;from the packet spec
- driver_name db 'EtherExpress16',0 ;name of the driver.
- driver_function db 26
- parameter_list label byte
- db 1 ;major rev of packet driver
- db 9 ;minor rev of packet driver
- db 14 ;length of parameter list
- db EADDR_LEN ;length of MAC-layer address
- dw GIANT ;MTU, including MAC headers
- dw MAX_MULTICAST * EADDR_LEN ;buffer size of multicast addrs
- dw 0 ;(# of back-to-back MTU rcvs) - 1
- dw 0 ;(# of successive xmits) - 1
- int_num dw 0 ;Interrupt # to hook for post-EOI
- ;processing, 0 == none,
- save_err db 0 ;error bits on promiscuous recieve
- pro0 db 0
- pro1 db 0
-
- BART_Board_ID EQU 0BABAH
- BUD_board_ID EQU 0BABBH
- mca_hp_board_ID EQU 0BABCH
-
- board_id dw ?
-
- public rcv_modes
- rcv_modes dw 7 ;number of receive modes in our table.
- dw 0 ;There is no mode zero
- dw 0
- dw rcv_mode_2
- dw rcv_mode_3
- dw rcv_mode_4 ;haven't set up perfect filtering yet.
- dw 0
- dw rcv_mode_6
-
- ;
- ; 82586 Configuration Parameters
- ;
- config_params LABEL WORD
- num_config_params LABEL BYTE ;12 BYTEs
- DB 0CH
-
- fifo_limit LABEL BYTE
- DB 14
-
- srdy LABEL BYTE ;srdy = 1
- save_bad_frame LABEL BYTE ;do not save bad frame
- DB 40H
-
- address_length LABEL BYTE ;6 BYTEs
- auto_insert_address LABEL BYTE ;auto insert off (1)
- preamble_length LABEL BYTE ;2 BYTEs
- internal_loopback LABEL BYTE ;0 = OFF 1 = ON
- external_loopback LABEL BYTE ;0 = OFF 1 = ON
- DB 2EH ;26h in IPXWS
-
- linear_priority LABEL BYTE ;default is 0
- accel_contention_resolution LABEL BYTE ;default is 0
- exp_backoff_method LABEL BYTE ;0 = 802.3 1 = Alternate
- DB 00H
-
- interframe_spacing LABEL BYTE ;default is 60H (96 bits)
- DB 60H
-
- slot_time_low LABEL BYTE ;0
- DB 00H
-
- slot_time_high LABEL BYTE ;2
- retry_num LABEL BYTE ;15
- DB 0F2H
-
- promiscuous_mode LABEL BYTE ;0 = OFF 1 = ON
- broadcast_disable LABEL BYTE ;0 = OFF 1 = ON
- encode_decode LABEL BYTE ;0 = NRZ 1 = MANCHESTER
- transmit_on_no_carrier LABEL BYTE ;0 = STOP 1 = CONTINUE
- no_crc_insertion LABEL BYTE ;0 = OFF 1 = ON
- crc_type LABEL BYTE ;0 = 32 bit autodin II
- ;1 = 16 bit CCITT
- bit_stuffing LABEL BYTE ;0 = 802.3 1 = HDLC
- padding LABEL BYTE ;0 = OFF 1 = ON
- DB 00H
-
- carrier_sense_filter LABEL BYTE ;0 = OFF 1 = 0N
- carrier_sense_source LABEL BYTE ;0 = external 1 = internal
- collision_detect_filter LABEL BYTE ;default = 0
- collision_detect_source LABEL BYTE ;0 = external 1 = internal
- DB 00H
-
- min_frame_length LABEL BYTE ;60 BYTEs
- DB 60
- DB 00H ;undefined
-
-
- RxBufferCount dw ?
- TxBufferCount dw ?
-
- Receive_Head DW ?
- Receive_Tail DW ?
-
- HEADER_LEN equ EADDR_LEN + EADDR_LEN + MAX_P_LEN
- even
- our_type db HEADER_LEN dup(?)
-
- extrn is_186: byte ;=0 if 808[68], =1 if 80[123]86.
- extrn sys_features: byte
-
- include io16.asm
-
- public bad_command_intercept
- bad_command_intercept:
- ;called with ah=command, unknown to the skeleton.
- ;exit with nc if okay, cy, dh=error if not.
- cmp ah,26
- jne bad_command_intercept_1
- jmp do_tdr
- bad_command_intercept_1:
- mov dh,BAD_COMMAND
- stc
- ret
-
- public as_send_pkt
- ; The Asynchronous Transmit Packet routine.
- ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
- ; interrupts possibly enabled.
- ; Exit with nc if ok, or else cy if error, dh set to error number.
- ; es:di and interrupt enable flag preserved on exit.
- as_send_pkt:
- ret
-
- public drop_pkt
- ; Drop a packet from the queue.
- ; Enter with es:di -> iocb.
- drop_pkt:
- assume ds:nothing
- ret
-
- public xmit
- ; Process a transmit interrupt with the least possible latency to achieve
- ; back-to-back packet transmissions.
- ; May only use ax and dx.
- xmit:
- assume ds:nothing
- ret
-
-
- public send_pkt
- send_pkt:
- ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
- ; (only if the high-performance bit is set in driver_function)
- ;enter with ds:si -> packet, cx = packet length.
- ;if we're a high-performance driver, es:di -> upcall.
- ;exit with nc if ok, or else cy if error, dh set to error number.
- assume ds:nothing
- cmp pro1,1
- je no_size_check1
-
- cmp cx,GIANT ; Is this packet too large?
- jna no_size_check1
- jmp send_pkt_toobig
-
- no_size_check1:
-
- push bp
- mov bp,io_addr
-
- disable_board_ints
- cmd_clear ; wait for command processor to clear
-
- cmp pro1,1 ; on pro drive do not ajust size
- je oklen
-
- cmp cx,RUNT ; minimum length for Ether
- jae oklen
- mov cx,RUNT ; make sure size at least RUNT
- oklen:
- ;
- ; Set SMB pointer to the transmit buffer.
- ;
- lea dx,[BP].@SMB_Ptr
- mov ax,offset send_blocks
- out dx,ax
- ;
- ; Write evenized, padded packet length (>= RUNT bytes) to 586 TBD byte
- ; count field. OR on the End of Frame bit.
- ;
- lea dx,[BP].@TBD_ByteCount
- mov ax,cx
- or ah,byte_BIT_EOF
- out dx,ax
- ;
- ; Set the TxCB command field for transmit. Also set the EL bit (End of List).
- ;
- lea dx, [BP].@TxCB_Command
- mov ax, BIT_EL+GA_Transmit
- out dx, ax
- ;
- ; Set write pointer to the data buffer for current send block. Also
- ; set DX to the data register.
- ;
- lea dx, [BP].@Write_Ptr
- mov ax, offset send_blocks
- add ax, offset TB_Data
- out dx, ax
- mov dx, bp ;@Data_Reg
-
- inc cx ;round size up to next even number.
- and cx,not 1
- call repoutsw
-
- send_continue:
- ;
- ; Set the SCBs command block pointer to this send packet.
- ;
- lea dx, [BP].@SCB_CBL
- mov ax, offset send_blocks
- out dx, ax
-
- ;
- ; Set the SCB command to start the command unit.
- ;
- lea dx, [BP].@SCB_CMD
- mov ax, CUC_START
- out dx, ax
- issue_ca
-
- cmd_clear ; wait for frame transmit to start
- lea dx,[BP].@SMB_Ptr
- mov ax,offset send_blocks
- out dx,ax
-
- lea dx,[BP].@TxCB_status
- transmiting:
- in ax,dx
-
- test ax,BIT_C ; check status of transmit
- jz transmiting
-
- test ax,BIT_OK ; how was the x-mit
- jnz tx_ok
-
- enable_board_ints
- pop bp
- mov dh,CANT_SEND
- jmp tx_bad
-
- tx_ok:
- enable_board_ints
-
- pop bp
-
- clc
- ret
-
- send_pkt_toobig:
- mov dh,NO_SPACE
- tx_bad:
- stc
- ret
-
-
- ; ReadTickCounter
- ;
- ; Read the 16 bit timer tick count register (system board timer 0).
- ; The count register decrements by 2 (even numbers) every 838ns.
- ;
- ; Assumes: Interrupts disabled
- ;
- ; Returns: AX with the current count
- ; Interrupts disabled
-
- ReadTickCounter:
-
- push dx
-
- mov dx, 43h ;Command 8254 timer to latch
- xor al, al ; T0's current count
- out dx, al
-
- mov dx, 40h ;read the latched count
- in al, dx ; LSB first
- mov ah, al
- in al, dx ; MSB next
- xchg al, ah ;put count in proper order
-
- pop dx
- ret
-
-
- public set_address
- set_address:
- ;enter with ds:si -> Ethernet address, CX = length of address.
- ;exit with nc if okay, or cy, dh=error if any errors.
- assume ds:code
- push bp
- push si
- ;
- ; Set up individual address command block.
- ;
- mov bp,ds:io_addr
- cmd_clear
- mov bx, BIT_EL+GA_IA_Setup
- call setup_command_block
- pop si
-
- ;
- ; Copy individual address command parameters to individual address
- ; command block.
- ;
- mov cx, EADDR_LEN/2
- move_node_address:
- lodsw
- out dx, ax
- loop move_node_address
-
- ;
- ; Signal 586 to execute individual address command.
- ;
- mov ax, CUC_Start
- mov bx, BIT_CNA
- call issue_command
-
- lea dx, [bp].@SMB_Ptr ;Move IO frame to the command
- mov ax, offset cb ; command block.
- out dx, ax
-
- lea dx,[BP].@CB_Status
- working1:
- in ax,dx
-
- test ax,BIT_C ; check status of set_ia
- jz working1
-
- test ax,BIT_OK
- jnz set_ok
- stc
- jmp set_address_done
-
- set_ok:
- mov cx,5000h ; on 486's if we do not delay this command does not work
- set1:
- mov bx,cx
- mov ax,[bx]
- loop set1 ; just for delay
-
- mov cx,EADDR_LEN ;return their address length.
- clc
- set_address_done:
- pop bp
- ret
-
-
- rcv_mode_2:
- and promiscuous_mode,not 3
- or promiscuous_mode,2 ;disable broadcasts.
- mov min_frame_length,60
- and save_bad_frame,not 80h
- mov pro0,0
- ;;; mov pro1,0 ;not present in NSA version
- jmp short configure_command
- rcv_mode_4:
- rcv_mode_3:
- and promiscuous_mode,not 3 ;clear promiscuous mode.
- mov min_frame_length,60
- and save_bad_frame,not 80h
- mov pro0,0
- ;;; mov pro1,0 ;not present in NSA version
- jmp short configure_command
- rcv_mode_6:
- and promiscuous_mode,not 3
- or promiscuous_mode,1 ;set promiscuous mode.
- mov min_frame_length,60 ;allow runt. but let it come in as a bad frame
- or save_bad_frame,80h ; yes we want bad frames here
- mov pro0,1
- mov pro1,1
- ;
- configure_command:
- mov bp,io_addr
- ;
- ; Set up configure command block.
- ;
- mov bx, bit_el + GA_Configure ;Set command block for a
- call setup_command_block ; configure command. BIT_EL
- ; means last command.
- ;
- ; Copy configure command parameters to configure command block.
- ;
- mov si,offset config_params ;Set DS:SI to parameters and
- mov cx, 6 ; copy them to the command
-
- move_config_params:
-
- lodsw
- out dx, ax
- loop move_config_params
- ;
- ; Signal 586 to execute configure command.
- ;
- mov ax, CUC_Start
- mov bx, BIT_CNA
- call issue_command
- ret
-
-
- ;*****************************************************************
- ; TDR cable tester
- ; enter with es:di pointing to time int
- ;*****************************************************************
-
- public do_tdr
- do_tdr:
- push bp
- push es
- push di
- mov bp,io_addr
- ;
- ; Set up configure command block.
- ;
- mov bx, bit_el + GA_TDR ;Set command block for a
- call setup_command_block ; TDR command. BIT_EL
- ; means last command.
- ; Signal 586 to execute configure command.
- ;
- mov ax, CUC_Start
- mov bx, BIT_CNA
- call issue_command
-
- lea dx, [bp].@SMB_Ptr ;Move IO frame to the command
- mov ax, offset cb ; command block.
- out dx, ax
-
- lea dx,[BP].@CB_Status
- working:
- in ax,dx
-
- test ax,BIT_C ; check status of transmit
- jz working
-
- lea dx,[bp].@CB_Parm0
- in ax,dx
-
- pop di
- pop es
- pop bp
-
- test ax,LNK_OK
- jz tdr_bad_cable
- clc
- ret
-
- tdr_bad_cable:
-
- push ax
- and ax,TDR_TIME
- stosw ; store time
- pop ax
-
- mov cl,12
- shr ax,cl
- and ax,7
- mov dh,al
-
- stc
- ret
-
-
- ;
- ; BX = 586 command word
- ;
- setup_command_block:
-
- ;
- ; Setup command block's command, status, and link fields.
- ;
- lea dx, [bp].@SMB_Ptr ;Move IO frame to the command
- mov ax, offset cb ; command block.
- out dx, ax
-
- lea dx, [bp].@CB_link ;Set command block's link to
- out dx, ax ; itself.
-
- lea dx, [bp].@SCB_CBL ;Point SCB command list
- out dx, ax ; pointer to command block.
-
- lea dx, [bp].@CB_command ;Set command block's command
- mov ax, bx ; word to value passed in
- out dx, ax ; BX.
-
- ;
- ; Return with the write pointer set to the command block parameter
- ; offset.
- ;
- lea dx, [bp].@Write_Ptr ;Set write pointer to command
- lea ax, CB.CB_Param0 ; parameter field.
- out dx, ax
-
- mov dx, bp ;@Data_Reg
- ret
-
-
- ;
- ; Wait for 586 command register to be clear ( 1 millisecond max)
- ; Issue command
- ; Wait for command to complete (500 milliseconds max)
- ; Acknowledge command complete
- ;
- ;
- issue_command:
-
- ;
- ; Make sure 586 command in SCB is clear.
- ;
- mov cx, ax
- cmd_clear
- jc issue_command_error_exit
- mov ax, cx
- ;
- ; Put command code in AX into SCB command register and signal the
- ; 586 to look at it. The cmd_clear macro leaves DX pointing to
- ; the SCB command register.
- ;
- out dx, ax
- issue_ca
-
- wait_for_commad_status_outer_loop:
- ;
- ; Wait here for 586 to complete the command. 586 should never take
- ; more than 500 Milliseconds to complete a command.
- ;
- call readtickcounter
- mov cx, ax
- lea dx, [bp].@SCB_STAT
-
- wait_for_commad_status:
-
- in ax, dx
- cmp ax, bx
- je acknowledge_command_complete
-
- call readtickcounter
- neg ax
- add ax, cx
- cmp ax, ten_mils
- jb wait_for_commad_status
-
- _586_command_error:
- ;
- ; Signal error by pointing AX to error message, and setting
- ; condition codes.
- ;
- mov dx,offset _586_not_responding_msg
- stc
- issue_command_error_exit:
- ret
-
- acknowledge_command_complete:
- ;
- ; Tell the 586 that we know its done by copying the status back to
- ; the command register's acknowledge fields. BX has status.
- ;
- lea dx, [bp].@SCB_CMD
- out dx, ax
- issue_ca
- ;
- ; Signal no error.
- ;
- xor ax, ax
- ret
-
-
- public set_multicast_list
- set_multicast_list:
- ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
- ; cx = number of bytes.
- ;return nc if we set all of them, or cy,dh=error hf we didn't.
- mov dh,NO_MULTICAST
- stc
- ret
-
-
- public terminate
- terminate:
- push bp
- mov bp,io_addr
-
- cmd_clear ; wait until last command is done processing
-
- disable_board_ints ; shut off board ints
-
- lea dx,[bp].@SCB_CMD
- mov ax, RUC_SUSPEND ; suspend recieve unit
- out dx, ax
- issue_ca
-
- pop bp ; now ok to un-hook interrupts and release
- ret ; driver
-
- public reset_interface
- reset_interface:
- ;reset the interface.
- assume ds:code
- ret
-
-
- ;called when we want to determine what to do with a received packet.
- ;enter with cx = packet length, es:di -> packet type, dl = packet class.
- extrn recv_find: near
-
- ;called after we have copied the packet into the buffer.
- ;enter with ds:si ->the packet, cx = length of the packet.
- extrn recv_copy: near
-
- ;call this routine to schedule a subroutine that gets run after the
- ;recv_isr. This is done by stuffing routine's address in place
- ;of the recv_isr iret's address. This routine should push the flags when it
- ;is entered, and should jump to recv_exiting_exit to leave.
- ;enter with ax = address of routine to run.
- extrn schedule_exiting: near
-
- ;recv_exiting jumps here to exit, after pushing the flags.
- extrn recv_exiting_exit: near
-
- extrn count_in_err: near
- extrn count_out_err: near
- ; extrn resource_err_in:word
-
- public recv
- recv:
- ;called from the recv isr. All registers have been saved, and ds=cs.
- ;Upon exit, the interrupt will be acknowledged.
- assume ds:code
- ;
- ; Set BP to the base IO address of exp16. Also disable exp16s ability
- ; to generate interrupts.
- ;
- mov bp,io_addr
- disable_board_ints
- ;
- ; Make sure that command unit is clear before reading the status.
- ;
- cmd_clear
- ;
- ; Get the SCB status to see why exp16 interrupted us. Also need to
- ; copy the status back to the command word to acknowledge the 586
- ; interrupt. Issue channel attention to get the 586 to realize the
- ; interrupt aknowledge.
- ;
- ; lea dx, [bp].@SCB_RSCERRS
- ; in ax,dx
- ; mov word ptr resource_err_in,ax
- ; lea dx, [bp].@SCB_OVRNERRS
- ; in ax,dx
- ; add word ptr resource_err_in,ax
-
- lea dx, [bp].@SCB_STAT
- in ax, dx
- and ax, ACK_INT_MASK
-
- lea dx, [bp].@SCB_CMD
- out dx, ax
- issue_ca ; AX is not changed.
- ;
- ; Check for frame receive status. Jump if no frames received,
- ; otherwise processes the receive.
- ;
- test AX, BIT_FR OR BIT_RNR
- jz ExitDriverISR
- call ProcessRx
- ExitDriverISR:
- ;
- ; Here if there was a bad receive status. Make sure the receive unit
- ; of the 586 is running. Read in the SCB status and jump if we need
- ; to restart the receive unit. We choose to have the jump to restart
- ; the RU since most of the time we will not need to do this. This
- ; saves cycle times when exiting without a restart.
- ;
- lea dx, [bp].@SCB_STAT
- in ax, dx
- test ax, READY
- jz restart_RU
-
- drvisr_continue:
- enable_board_ints
- ret
-
-
- restart_RU:
- ;
- ; Need to restart the receive unit of the 586. Set the SCB pointer to
- ; the receive frame area.
- ;
- lea dx, [bp].@SCB_RFA
- mov ax, Receive_Head
- out dx, ax
- ;
- ; Make sure 586 is in a state to accept a command.
- ;
- cmd_clear
- ;
- ; Put the receive unit start command into the SCB command word and
- ; issue the channel attention.
- ;
- ; NOTE: cmd_clear macro leaves DX pointing to the SCB command word.
- ;
- ; lea dx, [bp].@SCB_CMD
- mov ax, RUC_START
- out dx, ax
- issue_ca
- jmp drvisr_continue
-
-
- ProcessRx:
-
- ;
- ; Prime the pump that services receives by setting AX to the receive
- ; head. There could be over 30 packets received.
- ;
- mov ax,Receive_Head
-
- CheckNextReceiveStatus:
-
- ;
- ; Save receive head pointer in BX. BX should not be altered during
- ; this loop.
- ;
- mov bx, ax
- ;
- ; Set SMB pointer to the top of the receive frame.
- ;
- lea dx, [bp].@SMB_Ptr
- out dx, ax
- ;
- ; Get the status for this receive frame. Check to make sure that
- ; it completed with no errors. If not, then jump to check the
- ; 586 receive unit.
- ;
- lea dx, [bp].@FD_Status
- in ax, dx
-
- mov save_err,1 ; be sure we done accdently report an error
-
- test ax, BIT_C ; command compleat
- jz PRx_no
- test ax,BIT_OK ; good frame
- jnz ProcessRx_1
-
- call count_in_err
- mov save_err,0
- cmp pro0,1
- je PRx_bad ; if not in pro-mode lose bad frames and inc error
- ; call count_in_err
- jmp recv_isr_9
- PRx_no:
- ret
-
- PRx_bad:
- mov dh,0 ;build save_err.
- test ax,BIT_S7
- jz PR_no_frag
- or dh,2
- PR_no_frag:
- test ax,BIT_S11
- jz PR_no_crc
- or dh,4
- PR_no_crc:
- test ax,BIT_S10
- jz PR_no_align
- or dh,8
- PR_no_align:
- test ax,BIT_S8
- jz PR_no_dma
- or dh,16
- PR_no_dma:
- test ax,BIT_S9
- jz PR_no_ru
- or dh,32
- PR_no_ru:
- mov save_err,dh
-
- ProcessRx_1:
- ;
- ; Set the read pointer to access the LengthTypeField.
- ;
- ; NOTE: BX was set to receive head at the beginning of this
- ; procedure.
- ;
- lea dx, [bp].@Read_Ptr
- lea ax, [BX].IPX_DestAddr_HIGH
- out dx, ax
- mov dx, bp ;@Data_Reg
-
- mov ax,cs
- mov es,ax
- mov di,offset our_type
- mov cx,HEADER_LEN
- call repinsw
-
- ;
- ; Get the packet size from the 586 data structure.
- ;
- lea dx, [bp].@RBD_ByteCount
- in ax, dx
- and ah, 3fh
- mov cx, ax
-
- mov di,offset our_type+EADDR_LEN+EADDR_LEN
-
- mov dl, BLUEBOOK ;assume bluebook Ethernet.
- mov ax, es:[di]
- xchg ah, al
- cmp ax, 1518
- ja BlueBookPacket
- inc di ;set di to 802.2 header
- inc di
- mov dl, IEEE8023
- BlueBookPacket:
- push bx
- push cx ; for some reison recv_find trashes cx
- mov dh,save_err
- call recv_find
- mov bp,cs:io_addr ; just in case
- pop cx
- pop bx
-
- mov ax,es ;is this pointer null?
- or ax,di
- je recv_isr_9 ;yes - just free the frame.
- push es ;remember where the buffer pointer is.
- push di
- push cx
- if 0
- ;
- ; Copy the packet's header into their buffer.
- ;
- push cx
- mov si,offset our_type
- mov cx,HEADER_LEN/2
- rep movsw
- pop cx
- sub cx,HEADER_LEN
- endif
- ;
- ; Set the read pointer to access the packet.
- ;
- ; NOTE: BX was set to receive head at the beginning of this
- ; procedure.
- ;
- lea dx, [bp].@Read_Ptr
- if 0
- lea ax, [BX].IPX_DestAddr_HIGH + HEADER_LEN
- else
- lea ax, [BX].IPX_DestAddr_HIGH
- endif
- out dx, ax
- mov dx, bp ;@Data_Reg
- ;
- ; Now read the packet into es:di
- ;
- call repinsw
-
- pop cx
- pop si
- pop ds
- assume ds:nothing
- call recv_copy ;tell them that we copied it.
- mov ax,cs ;restore our ds.
- mov ds,ax
- assume ds:code
-
- recv_isr_9:
- ;
- ; Restore SMB pointer to the top of the receive frame.
- ;
- mov bp,io_addr ; just in case
- mov ax,bx
- lea dx, [bp].@SMB_Ptr
- out dx, ax
-
- ;
- ; Clear the current receive frames status.
- ;
- lea dx, [bp].@FD_Status
- xor ax, ax
- out dx, ax
- ;
- ; Set the end of list bit for the current receive frame.
- ;
- lea dx, [bp].@FD_command
- mov ax, BIT_EL
- out dx, ax
- ;
- ; Read in the pointer to the next receive frame.
- ;
- lea dx, [bp].@FD_Link
- in ax, dx
- ;
- ; Update our local pointer to the receive resources:
- ;
- ; Receive_tail <-- Receive head
- ; Receive_head <-- next receive frame.
- ;
- mov BX, Receive_Head
- mov Receive_Tail, BX
- mov Receive_Head, AX
- mov cx, ax
- ;
- ; Clear previous receive frame descriptors end of list bit to free up
- ; a receive resource. We do this by moving the write pointer to the
- ; the command word in the previous receive frame and then writing a
- ; zero to it.
- ;
- lea dx, [bp].@Write_Ptr
- lea ax, [bx].FD_command
- out dx, ax
-
- mov dx, bp ;@Data_Reg
- xor ax, ax
- out dx, ax
- ;
- ; Check for another receive frame.
- ;
- mov ax, cx
- jmp CheckNextReceiveStatus
-
-
-
- ; This procedure is called from the cmd_clear macro after the macro determines
- ; that we must wait for a command to clear.
- ;
- ; MUST NOT TRASH CX OR THE ISSUE_COMMAND PROCEDURE WILL FAIL.
- ;
- cmd_wait:
- ;enter with dx -> SCB_CMD
- ;exit with nc if it cleared in one millisecond, cy if not.
-
- call readtickcounter ;Reference clock. die after
- mov bx, ax ; 1 ms.
-
- wait_cmd_clear:
-
- in ax, dx ;Read SCB command
- or ax, ax ;Wait for command accepted
- jz exit
-
- call readtickcounter
- neg ax
- add ax, bx
-
- cmp ax, one_mil
- jb wait_cmd_clear
-
- stc
- exit:
- ret
-
-
- public timer_isr
- timer_isr:
- ;if the first instruction is an iret, then the timer is not hooked
- iret
-
- ;any code after this will not be kept after initialization. Buffers
- ;used by the program, if any, are allocated from the memory between
- ;end_resident and end_free_mem.
- public end_resident,end_free_mem
- end_resident label byte
- end_free_mem label byte
-
-
- public usage_msg
- usage_msg db "usage: exp16 [options] <packet_int_no> <io_addr>",CR,LF,'$'
-
- public copyright_msg
- copyright_msg db "Packet driver for the Intel EtherExpress 16, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
- db "Copyright 1991 Intel Corp",CR,LF
- db "Portions Copyright 1993 Crynwr Software",CR,LF,'$'
-
- int_no_name db "Interrupt number ",'$'
- io_addr_name db "I/O port ",'$'
-
- extrn set_recv_isr: near
-
- ;enter with si -> argument string, di -> dword to store.
- ;if there is no number, don't change the number.
- extrn get_number: near
-
- ;enter with dx -> argument string, di -> dword to print.
- extrn print_number: near
-
-
- ;-> the assigned Ethernet address of the card.
- extrn rom_address: byte
-
- chan_sel db 0 ;Channel select for SYS_MCA machines
-
- public etopen
- etopen:
- ;initialize the driver.
- assume ds:code
- ;
- ; Get board information (Node address, etc.). Returns with BP
- ; set to the board IO base address (if not errors).
- ;
- call get_system_info
- jc driver_init_error_exit
-
- disable_board_ints
- ;
- ; If they're in an 8-bit slot, make sure that they aren't using the slave PIC.
- ;
- cmp _16_not_8_bit_slot,0 ;are they using a 16-bit slot?
- jne check_config_exit ;yes -- cool.
-
- mov dx,offset irq_config_error
- cmp int_no, 9 ;no - don't let them use the upper IRQs.
- jb check_config_exit
- driver_init_error_exit:
- stc
- ret
- check_config_exit:
-
- ;
- ; Initialize the 586 and the 586 data structures.
- ;
- call init_586
- jc driver_init_error_exit
-
- ; test iochrdy
- test sys_features,SYS_MCA
- jnz skip_iochrdy_test
- call iochrdy_test
- skip_iochrdy_test:
-
- cmp connection_type,CONN_AUTO
- jne no_auto_con
- call auto_connector
- jnc did_auto_con
- mov dx,offset no_wire_msg
- mov ah,9
- int 21h
- jmp short did_auto_con
- no_auto_con:
- call write_connector_setting_to_hardware
- did_auto_con:
-
- ;
- ; Set up Interrupt line, start the receive unit, and Enable exp16s interrupt.
- ;
- call set_recv_isr
- call ru_start
- enable_board_ints ;;; only one left in broken version.
-
- mov al, int_no ; Get board's interrupt vector
- add al, 8
- cmp al, 8+8 ; Is it a slave 8259 interrupt?
- jb set_int_num ; No.
- add al, 70h - 8 - 8 ; Map it to the real interrupt.
- set_int_num:
- xor ah, ah ; Clear high byte
- mov int_num, ax ; Set parameter_list int num.
-
- clc
- ret
-
- write_connector_setting_to_hardware:
- assume ds:code
- test sys_features,SYS_MCA
- je isa_connector_bart
-
- mov bl,80h
- cmp connection_type,CONN_TPE ;did they ask for TPE?
- je mca_tpe_connector
- mov bl,0
- mca_tpe_connector:
-
- call enable_slot
- mov dx,102h ;stuff the AUI/Other bit in.
- in al,dx
- and al,not 04h
- cmp connection_type,CONN_AUI
- je mca_tpe_connector_1
- or al,04h
- mca_tpe_connector_1:
- out dx,al
-
- mov dx,103h ;stuff the BNC/TPE bit in.
- in al,dx
- and al,not 80h
- cmp connection_type,CONN_BNC
- je mca_tpe_connector_2
- or al,80h ;<>0 means TPE
- mca_tpe_connector_2:
- out dx,al
- call disable_slot
-
- jmp no_connector_bart
- isa_connector_bart:
- cmp board_id,BART_Board_ID ;a real BART?
- je no_connector_bart ;yes, it doesn't *have* an ECR1.
- mov bp,io_addr
- lea dx,ECR1[bp]
- in al,dx
- and al,not 82h ;turn off Other/not_AUI (read as
- ; MCA/ISA), and TPE/not_BNC
- cmp connection_type,CONN_AUI
- je set_connector_bart
- or al,80h ;set Other/not_AUI
- cmp connection_type,CONN_BNC
- je set_connector_bart
- or al,02h ;set TPE/not_BNC
- set_connector_bart:
- out dx,al
- no_connector_bart:
-
- mov cx,10 ;10*10 milliseconds = 100 millis
- cmp connection_type,CONN_AUI
- jne set_connector_delay
- mov cx,50 ;50*10 milliseconds = 500 millis
- set_connector_delay:
- ; Our delay procedure can not accept a value over 27 milliseconds,
- ; so we use a loop to delay the 100 milliseconds.
- set_connector_delay_1:
- push cx
- mov di, ten_mils
- call eeprom_delay
- pop cx
- loop set_connector_delay_1
- ret
-
-
- ; int number to IRQ translate table.
- IRQ_xlat_table LABEL BYTE
- db 12, 2, 3, 4, 5, 10, 11, 15
-
- io_addresses label word
- dw 300h,310h,320h,330h,340h,350h,360h,370h
- dw 200h,210h,220h,230h,240h,250h,260h,270h
- dw 0
-
- enable_slot:
- mov al,chan_sel
- out 96h, al ; select channel
- mov al, 0ffh
- out 94h, al ; protect system board
- ret
-
- disable_slot:
- xor al,al ;disable pos
- out 96h,al
- ret
-
- public parse_args
- parse_args:
- ;exit with nc if all went well, cy otherwise.
- test sys_features,SYS_MCA
- jne parse_args_mc
- jmp parse_args_1
-
- parse_args_mc:
- ;The following code to read the POS registers is courtesy of Racal-Interlan.
-
- ; channel selector resides at io 96h
- ; POS register base is at io 100h
- ; EXP16/MC ID is 0628bh
-
- ; search thro' the slots for a EXP16/MC card
- mov cx, 8 ; for all channels(slots)
-
- ; channel select value for slots 0,1,2.. is 8,9,A etc
- ; start with slot 0, and then 7,6,5,4,3,2,1
- get_05:
- mov ax, cx ; channel number
- or ax, 08h ; reg. select value
- mov chan_sel,al ; save each one, the LAST will right
-
- ; read adapter id
- call enable_slot
- mov dx, 101h
- in al, dx ; adapter id - ms byte
- mov ah, al
- dec dx
- in al, dx ; adapter id - ls byte
-
- ; Check if EXP16/MC
- cmp ax, 0628bh
- je get_10
- loop get_05
-
- call disable_slot
-
- mov dx,offset Board_Not_Installed
- stc
- ret
-
- get_10:
- ; found our Adapter
- call write_pos_to_eeprom
-
- clc
- ret
-
- parse_args_1:
- mov di,offset io_addr
- call get_number
- clc
- ret
-
- include exp16mca.asm
-
- ;-----------------------------------------------------------------------------
- ; It is safe to assume that the command unit is up and running ready
- ; for the first send. And that there are at least two send buffers
- ; available.
- ;
- ; This procedure works by sending a 64 byte packet to itself. We do not turn
- ; on loopback, so we do not expect to see a receive. Instead, we
- ; expect to see that the send completed OK. If the send does not complete OK,
- ; then this routine switches to other connectors and the test is repeated.
- ;-----------------------------------------------------------------------------
- auto_connector:
-
- ; Let's start doing the test send with AUI option first. If we tried BNC
- ; first, and they were using AUI, it would seem like the BNC worked. So
- ; we switch to AUI, which turns off the BNC power supply.
- MOV connection_type, CONN_AUI
- CALL write_connector_setting_to_hardware
-
- ; Test connection to see if it works. Jump if it does.
- call test_send
- clc
- je auto_connector_exit
-
- ; Toggle AUI/Other setting and try to send a packet. Jump if send
- ; works. Now try sending on BNC.
- MOV connection_type, CONN_BNC
- CALL write_connector_setting_to_hardware
- call test_send
- clc
- je auto_connector_exit
-
- ; Here if we just tried a send the BNC. If this is
- ; a three connector card, then we toggle the BNC/TPE setting.
- ; Jump if connection is found.
- MOV connection_type, CONN_TPE
- CALL write_connector_setting_to_hardware
- call test_send
- clc
- je auto_connector_exit
- stc
- auto_connector_exit:
- ret
-
-
- test_packet label byte
- db EADDR_LEN dup(?)
- db EADDR_LEN dup(?)
- db 00h,2eh ;A 46 in network order
- db 0,0 ;DSAP=0 & SSAP=0 fields
- db 0f3h,0 ;Control (Test Req + P bit set)
-
- ; This procedure sends a packet on the wire and wait for the send to
- ; complete. It the checks to see if the send completed OK and returns
- ; the results.
- test_send:
-
- mov si,offset rom_address ;set the destination address.
- movseg es,cs
- mov di,offset test_packet
- repmov EADDR_LEN
- mov si,offset rom_address ;set the source address.
- repmov EADDR_LEN
-
- mov cx,60
- mov si,offset test_packet
- call send_pkt
-
- call ReadTickCounter
- mov cx, ax
-
- mov bp,io_addr
- lea dx, [bp].@TxCB_Status
- send_test_wait:
- in ax,dx
- test ax,8000h ;did it finish?
- jne send_test_done
-
- ; See if we have been here for a millisecond. Jump if not.
- call ReadTickCounter
- neg ax
- add ax, cx
- cmp ax, one_mil
- jb send_test_wait
-
- in ax,dx ;get the transmit status back again.
-
- send_test_done:
-
- mov cx, ax ; Save status in CX.
-
- xor ax, ax ; Clear the transmit command block status.
- out dx, ax
-
- ; Send is complete. Get the status and compare to OK send and return.
- ; Save flags for return.
-
- and cx, 0f000h
- cmp cx, 0a000h
- ret
-
- no_wire_msg db "***Unable to detect a cable on any connector***",CR,LF,'$'
- bnc_connector_msg db "Using the BNC connector",CR,LF,'$'
- aui_connector_msg db "Using the AUI connector",CR,LF,'$'
- tpe_connector_msg db "Using the twisted-pair connector",CR,LF,'$'
-
- _8_bit_slot_msg db "The board is in an 8-bit slot",CR,LF,'$'
- _16_bit_slot_msg db "The board is in a 16-bit slot",CR,LF,'$'
-
- badset_msg db "Set Address Command Failed",CR,LF,'$'
-
-
- public print_parameters
- print_parameters:
- mov di,offset int_no
- mov dx,offset int_no_name
- call print_number
- mov io_addr.segm,0
- mov di,offset io_addr
- mov dx,offset io_addr_name
- call print_number
-
- mov dx,offset bnc_connector_msg ;print the connection type.
- cmp connection_type,CONN_BNC
- je print_parameters_1
- mov dx,offset aui_connector_msg
- cmp connection_type,CONN_AUI
- je print_parameters_1
- mov dx,offset tpe_connector_msg
- print_parameters_1:
- mov ah,9
- int 21h
-
- mov dx,offset _16_bit_slot_msg ;print the slot size.
- cmp _16_not_8_bit_slot,0
- jne print_parameters_2
- mov dx,offset _8_bit_slot_msg
- print_parameters_2:
- mov ah,9
- int 21h
-
- ret
-
-
- init_586:
- ;enter with bp=io_addr, 586 reset.
-
- ;
- ; Set the number of transmit and receive buffers according to the
- ; amount of RAM on the adapter.
- ;
- MOV AX, Number_of_Tx_Buffers
- MOV BX, num_rx_buf_32k
-
- cmp _64K_not_32K,0
- je save_number_of_buffers
-
- MOV BX, num_rx_buf_64k
-
- save_number_of_buffers:
-
- MOV TxBufferCount, AX
- MOV RxBufferCount, BX
- ;
- ; initialize SCP. Move IO frame to top of SCP.
- ;
- LEA DX, [bp].@SMB_Ptr
- MOV AX, OFFSET scp
- OUT DX, AX
- ;
- ; Write initial SCP values:
- ; bus width 0 = 16 bit 1 = 8 bit.
- ; ISCP address always found at address 000000.
- ;
- LEA DX, [BP].@SCP_SystemBus
- MOV AL, bus_width
- OUT DX, AX
-
- LEA DX, [BP].@SCP_ISCP_Ptr_low
- XOR AX, AX
- OUT DX, AX
- LEA DX, [BP].@SCP_ISCP_Ptr_high
- OUT DX, AX
-
- ;
- ; Initialize ISCP. Move IO frame to top of ISCP. NOTE: AX falls
- ; through as zero.
- ;
- LEA DX, [bp].@SMB_Ptr
- OUT DX, AX
- ;
- ; Write initial ISCP values:
- ; ISCP BUSY 1 = Indicates 586 is in initialization
- ; process. 586 sets this byte to 0 when
- ; initialization is complete.
- ;
- ; SCB address Always 000008
- ;
- LEA DX, [BP].@iscp_busy
- MOV AX, initialize_586
- OUT DX, AX
-
- LEA DX, [BP].@ISCP_SCB_Ptr_low
- XOR AX, AX
- OUT DX, AX
- LEA DX, [BP].@ISCP_SCB_Ptr_high
- OUT DX, AX
- LEA DX, [BP].@iscp_scb_offset
- MOV AX, OFFSET scb
- OUT DX, AX
-
- ;
- ; Initialize SCB. Move Write Ptr to top of SCB. NOTE: AX falls
- ; through as offset to SCB.
- ;
- XOR AX, AX
- LEA DX, [BP].@SCB_Status
- OUT DX, AX
- LEA DX, [BP].@SCB_Command
- OUT DX, AX
- LEA DX, [BP].@SCB_CommandList
- OUT DX, AX
- LEA DX, [BP].@SCB_RecBlockList
- OUT DX, AX
- LEA DX, [BP].@SCB_CRC_Errors
- OUT DX, AX
- LEA DX, [BP].@SCB_ALN_Errors
- OUT DX, AX
- LEA DX, [BP].@SCB_RSC_Errors
- OUT DX, AX
- LEA DX, [BP].@SCB_OVR_Errors
- OUT DX, AX
-
- ;
- ; Initialize Receive Block(s). First set head pointer and link from
- ; SCB to first frame descriptor. NOTE: IO frame points to ISCB.
- ; The SCB link field can be addresses becasue the SCB is physically
- ; contiguous to the ISCB.
- ;
- mov ax,offset Receive_Blocks
- lea dx, [bp].@SCB_RecBlockList ;IO address of SCB RF link
- out dx, ax
-
- ;
- ; Initialize the frame descriptor structures. Move the Write ptr
- ; the top of the current frame descriptor. AX falls through with the
- ; offset to the first frame descriptor. DI is used to keep track of
- ; the address of the current frame descriptor. The frame descriptor,
- ; receive buffer descriptor, and receive buffer are all contiguous in
- ; memory, and make up the frame descriptor structure.
- ;
- MOV DI, AX ;DI is current frame descriptor
- MOV RECEIVE_HEAD, DI
- MOV CX, RxBufferCount ;CX is number of frame
- ; descriptors to initialize.
- init_receive_frames:
-
- LEA DX, [bp].@SMB_Ptr
- MOV AX, DI ; descriptor.
- OUT DX, AX
-
- ;
- ; Init Frame Descriptor (FD).
- ;
- XOR AX, AX ;Init frame descriptor status
- LEA DX, [BP+4000H]
- OUT DX, AX ; and command to zero.
- LEA DX, [BP+4002H]
- OUT DX, AX
-
- MOV AX, RECEIVE_HEAD ;Init frame descriptors link
- CMP CX, 1 ; to next frame descriptor.
- JE next_receive_link ; If this is the last receive
- ; block, then set its link to
- LEA AX, [DI+SIZE ReceiveBlock] ; the first receive block.
-
- next_receive_link:
-
- LEA DX, [BP+4004H]
- OUT DX, AX
-
- LEA AX, [DI+OFFSET RBD_ByteCount] ;Init frame descriptors
- LEA DX, [BP+4006H]
- OUT DX, AX ; link to its receive buffer descriptor.
- ;
- ; Init Receive Buffer Descriptor (RBD).
- ;
- LEA DX, [BP+4008H]
- OUT DX, AX ;Init the RBD Actual count to zero.
-
- MOV AX, -1 ;Init the RBD link to next RBD
- LEA DX, [BP+400AH]
- OUT DX, AX ; to minus 1 (unused link).
-
- LEA AX, [DI+RB_Data] ;Init the RDB link to the data
- LEA DX, [BP+400CH]
- OUT DX, AX ; buffer.
- XOR AX, AX
- LEA DX, [BP+400EH]
- OUT DX, AX
-
- MOV AX, RxBufferSize OR BIT_EL ;Init the RBD count and status
- LEA DX, [BP+8000H]
- OUT DX, AX
-
- MOV RECEIVE_TAIL, DI ;Set receive tail pointer.
- ADD DI, SIZE ReceiveBlock ;Point DI to next frame
- LOOP init_receive_frames ; descriptor.
- ;
- ; Initialize the send block structures. Move the Write pointer the
- ; top of the current send block. AX falls through with address of
- ; first send block. DI is used to keep track of the address of the
- ; current send block. The Transmit command block, transmit buffer
- ; descriptor, and transmit buffer are all contiguous in memory, and
- ; make up the send block structure.
- ;
- MOV DI, OFFSET send_blocks
- MOV CX, TxBufferCount
-
- LEA DX, [BP].@SMB_Ptr
- XOR AX, AX
- OUT DX, AX
-
- MOV AX, DI
- LEA DX, [BP].@SCB_CommandList
- OUT DX, AX
-
- init_send_blocks:
-
- LEA DX, [BP].@SMB_Ptr ;Set write pointer to send
- MOV AX, DI ; block.
- OUT DX, AX
- ;
- ; Init Transmit Control Block (TCB).
- ;
- XOR AX, AX ;Init transmit control block
- LEA DX, [BP+4000H]
- OUT DX, AX ; status to zero.
-
- LEA DX, [BP+4002H]
- OUT DX, AX ;Init transmit control block
- ; command to anything. The
- MOV AX, offset send_blocks ; Init transmit control block
- CMP CX, 1 ; link to next send block.
- JE next_send_link ; If this is the last send
- ; block, then point it to
- LEA AX, [DI+SIZE SendBlock] ; the first block.
-
- next_send_link:
-
- LEA DX, [BP+4004H]
- OUT DX, AX
-
- LEA AX, [DI+OFFSET TBD_ByteCount] ;Init transmit control block
- LEA DX, [BP+4006H]
- OUT DX, AX ; link to Transmit Buffer
- ; descriptor.
- ;
- ; Init Transmit Buffer Descriptor (TBD).
- ;
- LEA DX, [BP+4008H]
- OUT DX, AX ;Init Transmit Buffer Descriptor
- ; byte count to anything
- MOV AX, -1 ;Init Transmit Buffer Descriptor
- LEA DX, [BP+400AH]
- OUT DX, AX ; link to next TBD.
-
- LEA AX, [DI+OFFSET TB_Data] ;Init Transmit Buffer Descriptor
- LEA DX, [BP+400CH]
- OUT DX, AX ; link to transmit
- XOR AX, AX ; buffer. Low part of pointer
- LEA DX, [BP+400EH]
- OUT DX, AX ; is done first.
-
- ADD DI, SIZE SendBlock ;Point DI to next send block
- LOOP init_send_blocks ; and loop to initialize it.
-
- ;
- ; Enable loopback to insure nothing acidently hits the cable while
- ; the 586 gets initialized.
- ;
- LEA DX, [BP].@Config
- IN AX, DX
- OR AL, loopback_enable
- OUT DX, AL
- ;
- ; Free the 586 from reset.
- ;
- CALL free_586_reset
- ;
- ; Initialize and configure the 586. Carry flag set means error and
- ; dx will point to error message.
- ;
- CALL init_cmd
- mov dx,offset bad_init_msg
- jc init_exp16_ram_exit
-
- CALL configure_command
- mov dx,offset bad_config_msg
- jc init_exp16_ram_exit
-
- CALL diagnose_command
- jc init_exp16_ram_exit
-
- movseg es,cs
- mov si,offset rom_address
- mov cx,EADDR_LEN
- call set_address
- jnc sa_ok
-
- mov dx,offset badset_msg
- mov ah,9
- int 21h
- sa_ok:
- ;
- ; Disable loopback.
- ;
- LEA DX, [BP].@Config
- IN AX, DX
- AND AL, NOT loopback_enable
- OUT DX, AL
-
- clc
- ret
-
- init_exp16_ram_exit:
- stc
- RET
-
-
- ; This procedure must wait until the ASIC finishes reset. This will take
- ; around 240 uSec. This loop will time out after 500 uSec.
- ;
- five_hundred_micros EQU 1194
- ;
- reset_board:
- ;enter with bp=io_addr
-
- LEA DX, [BP].@EEPROM_Ctrl
- MOV AL, ASIC_Reset
- OUT DX, AL
-
- XOR AL, AL
- OUT DX, AL
-
- ;
- ; Get current tick count. This loop will wait for 500 uSec to pass
- ; before failing.
- ;
- CALL ReadTickCounter
- MOV BX, AX
-
- reset_delay:
-
- PUSH BX
- LEA DX, [BP].@ID_Port ; Set DX to the auto-id port.
- CALL check_for_exp16_hardware
- POP BX
-
- CMP AX, BART_Board_ID
- JE reset_board_exit
-
- CALL ReadTickCounter
- NEG AX
- ADD AX, BX
- CMP AX, five_hundred_micros
- JB reset_delay
-
- mov dx, offset reset_error
- stc
- RET
-
- reset_board_exit:
-
- MOV BX, AX
- clc
- RET
-
-
- reset_586:
- ;enter with bp = io_addr
- lea dx, [bp].@EEPROM_Ctrl
- mov al, _586_Reset
- out dx, al
- ret
-
-
- free_586_reset:
- ;enter with bp = io_addr
- lea dx, [bp].@EEPROM_Ctrl
- xor al, al
- out dx, al
- ret
-
- check_for_exp16_hardware:
- ;enter with dx = ID port (or maybe shadow ID port).
- ;
- ; BX will have board ID when the loop is done. CX is the loop count.
- ;
- XOR BX, BX
- MOV CX, 4
-
- get_board_id_loop:
- ;
- ; Init registers for loop. CX needs to be used in the loop, and AH
- ; could be set from the last loop.
- ;
- PUSH CX
- XOR AH, AH
- ;
- ; Read ID port. See description above.
- ;
- IN AL, DX
- ;
- ; Make nibble ID a shift count in CL.
- ;
- MOV CL, AL
- AND CL, 00000011B
- SHL CL, 1
- SHL CL, 1
- ;
- ; Move ID nibble to low order bits of AX, then shift then into place. Put
- ; the board ID nibble into BX. After four passes, BX will have board ID.
- ;
- SHR AL, 1
- SHR AL, 1
- SHR AL, 1
- SHR AL, 1
- SHL AX, CL
- OR BX, AX
- ;
- ; Recover loop count, and loop.
- ;
- POP CX
- LOOP get_board_id_loop
- ;
- ; Return board ID in AX.
- ;
- MOV AX, BX
- RET
-
-
- ;
- ; Command #1: Initialize
- ;
- init_cmd:
- XOR AX, AX ; Init command
- MOV BX, BIT_CX + BIT_CNA ; status
- CALL issue_command
- RET
-
- diagnose_command:
- ;return nc if no problem, else cy,dx->error message.
- ;
- ; Set up individual address command block.
- ;
- MOV BX, BIT_EL+GA_diagnose
- CALL setup_command_block
- ;
- ; Execute the diagnose command.
- ;
- MOV AX, CUC_Start
- MOV BX, BIT_CNA
- CALL issue_command
- ;
- ; Check diagnostics results.
- ;
- LEA DX, [BP].@SMB_Ptr ;Move IO frame to the command
- MOV AX, OFFSET cb ; command block.
- OUT DX, AX
-
- LEA DX, [BP].@mem_loc_0 ;Read in the diagnose status
- IN AX, DX ; word.
- ;
- ; Assume 586 failed the test. Set AX to an error message and exit
- ; with the zero bit cleared.
- ;
- test ax, 0800H ;Test failure bit. If set,
- jnz diagnose_error ; then error exit.
- clc
- ret
- diagnose_error:
- mov dx,offset _586_diagnostic_failure
- stc
- ret
-
-
- ;
- ; Command #4: RU_START
- ;
- ru_start:
- ;
- ; Set SCBs pointer to receive blocks at head of list.
- ;
- lea dx, [bp].@SCB_RFA ;Set pointer to receive blocks
- mov ax, receive_head ; to the head of the receive
- out dx, ax ; block list.
- ;
- ; Signal 586 to start the receive unit. cmd_clear leaves DX pointing
- ; to SCB command register.
- ;
- cmd_clear
- mov ax, ruc_start
- out dx, ax
- issue_CA
- ret
-
-
- find_a_board:
- mov bx,offset io_addresses
- no_exp16_here:
- mov bp,[bx]
- cmp bp,0
- je no_exp16s
- inc bx
- inc bx
- push bx
- call reset_board
- pop bx
- jc no_exp16_here
-
- clc
- ret
-
- no_exp16s:
- stc
- ret
-
- get_system_info:
- ;exit with zr if okay, or nz, dx -> error message if not okay.
- cmp io_addr,-1
- jne addr_override
- call find_a_board
- jnc board_id_ok
- jmp bad_or_no_board
-
- addr_override:
-
- MOV bp, io_addr
-
- ;
- ; Next, get the exp16 board ID. If the ID is not what we expect, then
- ; exit with error code in AX.
- ;
- call reset_board
- jnc board_id_ok
- ;
- ; Could search for exp16 board, but we error exit instead.
- ;
- bad_or_no_board:
-
- mov dx, offset board_not_installed
- stc
- JMP SHORT get_system_info_exit
-
- board_id_ok:
- mov io_addr,bp
-
- LEA DX, [BP].@ID_Port ; Set DX to the auto-id port.
- or DX,3000h ;use the shadow port
- CALL check_for_exp16_hardware
- mov board_id,ax
-
- ;
- ; Since the software will be reading the EEPROM during the
- ; initialization, the 586 needs to be inactive. This is because the
- ; control lines to the EEPROM are shared between the 586 and this
- ; software. To keep from getting fouled up, the 586 reset line is
- ; asserted here (now that we have a base IO address, and we know that
- ; the hardware is present). The 586 is not released from reset until
- ; after its data structures are intialized.
- ;
- CALL reset_586
- ;
- ; Validate the EEPROM by doing a checksum.
- ;
- mov cx, 40h
- CALL check_eeprom
- JC get_system_info_exit
- ;
- ; Get the amount of memory on the adapter.
- ;
- CALL test_buffer_memory
- JC get_system_info_exit
-
- ;
- ; Get the connection type. If carry clear, then AL has connection
- ; type. Otherwise AX has error code.
- ;
- CALL get_connection_type
- JC get_system_info_exit
- MOV connection_type, AL
- ;
- ; Read the Ethernet address out of the EEPROM.
- ;
- MOV AX, EE_ETHERNET_ADD_HIGH
- CALL read_eeprom
- xchg ah,al
- MOV word ptr rom_address[0], AX
-
- MOV AX, EE_ETHERNET_ADD_MID
- CALL read_eeprom
- xchg ah,al
- MOV word ptr rom_address[2], AX
-
- MOV AX, EE_ETHERNET_ADD_LOW
- CALL read_eeprom
- xchg ah,al
- MOV word ptr rom_address[4], AX
-
- mov ax,EE_INT
- call read_eeprom
- mov cl,EE_SHIFT
- shr ax,cl
- mov encoded_int_no,al
- mov bx,offset irq_xlat_table
- xlat
- mov int_no,al
-
- ;
- ; Get the Slot width. If carry clear, then AL has the slot width.
- ; Otherwise AX has error code.
- ;
- LEA DX, [BP].@Config
- IN AL, DX
- ;
- ; Slot width is found in the adapters configuration register.
- ;
- and al, slot_width_mask
- mov _16_not_8_bit_slot, al
-
- clc
- ret
-
- get_system_info_exit:
- ;we only ever get here with cy set.
- RET
-
- ;
- ;
- ; Return connection type in AL with carry clear.
- ;
- ;
- get_connection_type:
-
- cmp board_id,BART_Board_ID ;a real BART?
- je get_auto_cnt_exit ;yes, it doesn't *have* an ECR1.
-
- MOV AX, AUTO_CON_ADDRESS ;get the auto-connection bit.
- CALL read_eeprom
- TEST AX, AUTO_CON_MASK ;set?
- Je get_auto_cnt_exit ;no, okay.
- mov bl,CONN_AUTO ;yes, we should autosense the connector.
- jmp short get_connection_type_ret
- get_auto_cnt_exit:
-
- ;
- ; Read the connection address from the EEPROM.
- ;
- MOV AX, connection_address
- CALL read_eeprom ;Read_eeprom does not trash DI
-
- ;
- ; Assume AUI type connection. Check connection fields to see if this
- ; is a BNC connection. Jump if it is BNC.
- ;
- MOV BL, CONN_AUI
- TEST AX, CONNECTION_FIELD
- JZ get_connection_type_ret
-
- ;
- ; Here if NOT BNC. Must read another EEPROM word to tell if AUI or
- ; TPE. Assume AUI and then check for TPE.
- ;
- MOV AX, tpe_address
- CALL read_eeprom ;Read_eeprom does not trash DI
-
- ;
- ; Check for AUI connection.
- ;
- mov bl,CONN_BNC
- TEST AX, TPE_type_field
- JZ get_connection_type_ret
-
- ;
- ; Here if TPE type connection.
- ;
- MOV BL, CONN_TPE
-
- get_connection_type_ret:
-
- MOV AL, BL
-
- CLC
- RET
-
-
- ;
- ;
- ; Do a checksum on the EEPROM.
- ;
- ; The checksum is the same as the board ID.
- ;
- check_eeprom:
- ;enter with bp=io_addr, cx = count of bytes to sum starting at 0.
- ;exit with nc if okay, cy, dx -> error message if not.
-
- xor bx, bx
-
- checksum_loop:
-
- mov ax, cx
- dec ax
- call read_eeprom
-
- add bx, ax
- loop checksum_loop
-
- cmp bx, BART_Board_ID
- jne checksum_error
-
- clc
- ret
-
- checksum_error:
- mov dx,offset eeprom_checksum_error
- stc
- ret
-
-
- test_buffer_memory:
- ;enter with bp=io_addr
- ;exit with nc and al=_64k_not_32k if no error, or cy and di -> address in error.
-
- ; Set up SI with the maximum number of words to test. If there is an
- ; error testing the high 32K of memory, then we will restart the
- ; test at 32K. When the tests pass, the memory size is passed back
- ; in AX.
- ;
- mov si, 64 * (1024/2)
- ;
- ; Warm up the buffer memory with 16 word writes.
- ;
- mov cx, 16
- call write_zeros
-
- cmp cs:is_186,0
- jne start_memory_tests
-
- restart_memory_tests:
- ;
- ; Here if error testing memory and SI is set to 64K buffer size.
- ; We restart the tests for 32K buffer only. If an error occurs
- ; with SI set to 32K, then a memory error is reported.
- ;
- mov si, 32 * (1024/2)
-
- start_memory_tests:
- ;
- ; Zero RAM. Set write pointer to the base address and then fill the
- ; bufffer memory with zeros.
- ;
- mov cx, si
- call write_zeros
-
- call word_memory_test_pattern
- jc buffer_mem_error_exit
-
- cmp cs:is_186,0
- je _8088_quick_exit
-
- mov cx, si
- call write_zeros
-
- call byte_memory_test_pattern
- jc buffer_mem_error_exit
-
- _8088_quick_exit:
- ;
- ; Zero RAM. Set write pointer to the base address and then fill the
- ; bufffer memory with zeros.
- ;
- mov cx, si
- call write_zeros
-
- ;
- ; Set _64K_not_32K to the size of the memory that passed diagnostics.
- ;
- cmp si, 32 * (1024/2) ;did we quit at 32K
- je buffer_mem_exit ;yes, we only have 32K.
-
- mov _64K_not_32K,1 ;no, we must have 64K.
-
- buffer_mem_exit:
- clc
- ret
-
- buffer_mem_error_exit:
- ;
- ; If error occured, and SI is not set for 32K, then retry tests with
- ; SI set for 32K. If the error occurs and the size is 32K, then the
- ; Exp16 board memory is bad.
- ;
- CMP SI, 32 * (1024/2)
- JNE restart_memory_tests
-
- MOV DX, OFFSET buffer_memory_error
- STC ;Set carry to indicate error.
- RET
-
-
- write_zeros:
- ;enter with bp=io_addr, cx=number of zero words to write.
- ;
- ; Move write pointer to the beginning of the buffer memory.
- ;
- LEA DX, [BP].@Write_Ptr
- XOR AX, AX
- OUT DX, AX
- ;
- ; Set DX to the data register and write out zeros CX times.
- ;
- mov dx, bp ;@Data_Reg
- warm_up:
- out dx, ax
- loop warm_up
- ret
-
-
- word_memory_test_pattern:
- ;enter with si = number of words to test.
-
- ;
- ; Set CX to number of words to test. Set BX to beginning og pattern.
- ;
- MOV CX, SI
- MOV BX, 1
-
- ;
- ; Set DI to beginning of the buffer.
- ;
- XOR DI, DI
-
- word_inc_pattern:
-
- CALL loop_set_up
- IN AX, DX
- OR AX, AX
- JNE word_memory_test_pattern_error
-
- ;
- ; Write Test Pattern.
- ;
- MOV AX, BX
- OUT DX, AX
-
- ;
- ; Increment BX to next test pattern value.
- ;
- ADD BX, 3
-
- ;
- ; Increment DI to next test memory location.
- ;
- ADD DI, 2
- LOOP word_inc_pattern
-
- ;
- ; Set Read pointer to beginning of buffer.
- ;
- LEA DX, [BP].@read_ptr
- XOR AX, AX
- OUT DX, AX
- MOV DX, BP ;@Data_Reg
-
- ;
- ; Set CX to number of words to test. Set BX to beginning og pattern.
- ;
- MOV CX, SI
- MOV BX, 1
-
- word_check_pattern:
-
- IN AX, DX
- CMP AX, BX
- JNE word_memory_test_pattern_error
-
- ;
- ; Increment BX to next test pattern value.
- ;
- ADD BX, 3
-
- LOOP word_check_pattern
-
- CLC
- RET
-
- word_memory_test_pattern_error:
-
- STC
- RET
-
-
- byte_memory_test_pattern:
- ;enter with si = number of bytes to test.
-
- ;
- ; Set CX to number of bytes to test. Set BX to beginning of pattern.
- ;
- MOV CX, SI
- SHL CX, 1
- MOV BL, 1
-
- ;
- ; Set DI to beginning of the buffer.
- ;
- XOR DI, DI
-
- byte_inc_pattern:
-
- CALL loop_set_up
- IN AL, DX
- OR AL, AL
- JNE byte_memory_test_pattern_error
-
- ;
- ; Write Test Pattern.
- ;
- MOV AL, BL
- OUT DX, AL
-
- ;
- ; Increment BX to next test pattern value.
- ;
- ADD BL, 3
-
- ;
- ; Increment DI to next test memory location.
- ;
- INC DI
-
- LOOP byte_inc_pattern
-
- ;
- ; Set Read pointer to beginning of buffer.
- ;
- LEA DX, [BP].@read_ptr
- XOR AX, AX
- OUT DX, AX
- MOV DX, BP ;@Data_Reg
-
- ;
- ; Set CX to number of bytes to test. Set BX to beginning of pattern.
- ;
- MOV CX, SI
- SHL CX, 1
- MOV BL, 1
-
- byte_check_pattern:
-
- IN AL, DX
- CMP AL, BL
- JNE byte_memory_test_pattern_error
-
- ;
- ; Increment BX to next test pattern value.
- ;
- add bl, 3
-
- loop byte_check_pattern
-
- clc
- ret
-
- byte_memory_test_pattern_error:
-
- stc
- ret
-
- loop_set_up:
- ;enter with bp=io_addr, di=buffer address.
- ;exit with ax=value at di, dx=I/O address to access buffer memory at DI
-
- PUSH DI
-
- MOV AX, DI ;SMB_Ptr must be on 16 byte
- AND AX, 0FFE0H
- AND DI, 0001FH
-
- LEA DX, [BP].@SMB_Ptr ;Set IO page frame to the
- OUT DX, AX
-
-
- TEST DI, 0010H
- JZ loop_set_up_1
-
- ADD DI, @MEM_LOC_0
-
- loop_set_up_1:
- AND DI, 0FFEFH
- LEA DX, [BP+DI].@MEM_LOC_0 ;Set DX for IO from buffer and
-
- POP DI
-
- RET
-
-
- read_eeprom:
- ;enter with bp=io_addr, ax = EEPROM location.
- ;exit with ax = EEPROM contents.
- ;preserves di.
- push di
- push bx
- push cx
-
- ; Point to EEPROM control port.
-
- lea dx, [bp].@eeprom_ctrl
- mov bx, ax
-
- ; Select the EEPROM. Mask off the ASIC and 586 reset bits and set
- ; the ee_cs bit in the EEPROM control register.
-
- in al, dx
- and al, 10110010b
- or al, ee_cs
- out dx, al
-
- ; Write out read opcode and EEPROM location.
-
- mov ax, eeprom_read_opcode ;Set AX to READ opcode and
- mov cx, 3 ;Send it to the EEPROM circuit
- call shift_bits_out
-
- mov ax, bx ;Tell EEPROM which register is
- mov cx, 6 ; to be read. 6 bit address.
- call shift_bits_out
-
- call shift_bits_in ;AX gets EEPROM register
-
- call eeprom_clean_up ;Leave EEPROM in known state.
-
- pop cx
- pop bx
- pop di
- ret
-
-
- ;-----------------------------------------------------------------------------
- ; Writes the specified value to the specified EEPROM register at the
- ; specified base I/O address.
- ;
- ; Entry - BP Base IO.
- ; AX EEPROM location to write.
- ; BX Value to write
- ;
- ; Return - AX = 0 if no error
- ; AX = Pointer to Error message
- ;
- ;-----------------------------------------------------------------------------
- write_eeprom:
- ;enter with bp=io_addr, ax = EEPROM location, bx = new contents.
- ;exit with ax = 0 if no error, ax -> error if error.
- ;preserves di.
-
- push bx
- mov bx, ax
-
- lea dx, [bp].@EEPROM_Ctrl ;Point to EEPROM port.
-
- in al, dx ;Select EEPROM
- and al, 10110000b
- or al, ee_cs
- out dx, al
-
- ; Send Erase/write enable opcode to the EEPROM.
- mov ax, EEPROM_EWEN_opcode ;Send erase/write enable
- mov cx, 5 ; command to the EEPROM.
- call shift_bits_out
-
- mov cx, 4 ;Send 4 don't cares as
- call shift_bits_out ; required by the eeprom
-
- call stand_by
-
- ; Send the erase opcode to the EEPROM and wait for the command to
- ; complete.
- mov ax, EEPROM_erase_opcode ;Send Erase command to the
- mov cx, 3 ; EEPROM.
- call shift_bits_out
-
- mov ax, bx ;Send EEPROM location the the
- mov cx, 6 ; EEPROM. 6 bit address.
- call shift_bits_out
-
- call wait_eeprom_cmd_done ;wait for end-of-operation
- jc write_fault_pop ; go if error
-
- call stand_by
-
- ; Send the write opcode, location to write, and data to write to the
- ; EEPROM. Wait for the write to complete.
- mov ax, EEPROM_write_opcode ;Send write command to the
- mov cx, 3 ; EEPROM.
- call shift_bits_out
-
- mov ax, bx ;Send the EEPROM location to
- mov cx, 6 ; the EEPROM. 5 bit address.
- call shift_bits_out
-
- pop ax ;Send data to write to the
- mov cx, 16 ; EEPROM. 16 bits.
- call shift_bits_out
-
- call wait_eeprom_cmd_done ;Await end-of-command
- jc write_fault ;go if error
-
- call stand_by
-
- ; Send the erase write disable command to the EEPROM.
- mov ax, EEPROM_EWDS_opcode ;Disable the Erase/write
- mov cx, 5 ; command previously sent to
- call shift_bits_out ; EEPROM.
-
- mov cx, 4 ;Send 4 don't cares as
- call shift_bits_out ; required by the eeprom
-
- call eeprom_clean_up
-
- clc
- ret
-
- write_fault_pop:
- add sp, 2 ;Get rid of data on stack
- write_fault:
- ;;; lea ax, eeprom_write_error
- stc
- ret
-
-
- shift_bits_out:
- ;enter with ax=data to be shifted, cx=# of bits to be shifted.
-
- push bx
-
- ; Data bits are right justified in the AX register. Move the data
- ; into BX and left justify it. This will cause addresses to to
- ; be sent to the EEPROM high order bit first.
-
- mov bx, ax
- mov ch, 16
- sub ch, cl
- xchg cl, ch
- shl bx, cl
- xchg cl, ch
- xor ch, ch
-
- ; Get the EEPROM control register into AL. Mask of the ASIC asn 586
- ; reset bits.
-
- in al, dx
- and al, 10111111b
-
- ; Set or clear DI bit in EEPROM control register based on value of
- ; data in BX.
-
- out_shift_loop:
- and al, not ee_di ;Assume data bit will be zero
-
- rcl bx, 1 ;Is the data bit a one?
- jnc out_with_it ;No
- or al, ee_di ;Yes
- out_with_it:
- out dx, al ;Output a 0 or 1 on data pin
-
- ; Set up time for data is .4 Microseconds. So to be safe (incase of
- ; this software is run on a cray), call delay.
- mov di, 1
- call eeprom_delay
-
- call raise_eeprom_clock ; Clock the data into the EEPROM.
- call lower_eeprom_clock
- loop out_shift_loop ;Send next bit
-
- and al, not ee_di ;Force data bit to zero
- out dx, al ;Output a 0 on data pin
-
- pop bx
-
- ret
-
- shift_bits_in:
- ;exit with ax = register contents.
- push bx
- push cx
-
- ; BX will receive the 16 bits read from the EEPROM. Data is valid in
- ; data out bit (DO) when clock is high. There for, this procedure
- ; raises clock and waits a minimum amount of time. DO is read, and
- ; clock is lowered.
-
- in al, dx ;Init AL to eeprom control
- and al, 10111111b ; register.
-
- xor bx, bx ;Init holding register
- mov cx, 16 ;We'll shift in 16 bits
-
- in_shift_loop:
- shl bx, 1 ;Adjust holding register for
- ; next bit
- call raise_eeprom_clock
-
- in al, dx
- and al, 10111111b
-
- test al, ee_do ;Was the data bit a one?
- jz in_eeprom_delay ;No
-
- or bx, 1 ;Yes, reflect data bit state
- ; in holding register.
-
- in_eeprom_delay:
- call lower_eeprom_clock
- loop in_shift_loop ;CONTINUE
-
- mov ax, bx ;AX = data
-
- pop cx
- pop bx
- ret
-
- raise_eeprom_clock:
- or al, ee_sk ;Clock the bit out by raising
- jmp short eeprom_clock_common
- lower_eeprom_clock:
- and al, not ee_sk ;Lower ee_sk
- eeprom_clock_common:
- out dx, al
- mov di, ee_tick
- call eeprom_delay ;Waste time
- ret
-
-
- wait_eeprom_cmd_done:
- ;Wait for ee_do to go high, indicating end-of-write or end-of-erase
- ;operation. Wait at most 20 ms (EEPROM needs at most 10).
- ;exit with nc if no error.
-
- push bx
- push cx
-
- call stand_by
-
- call readtickcounter
- mov di, ax
-
- ee_do_wait_loop:
-
- call readtickcounter
- neg ax
- add ax, di
-
- cmp ax, 28640 ;12 Millisecond wait
- jb ee_do_wait_loop
-
- in al, dx ;Get EEPROM control register
-
- test al, EE_DO ;ee_do high?
- jnz ee_do_found
-
- stc
- jmp short wait_eeprom_cmd_done_exit
-
- ee_do_found:
-
- clc ;"clean" status (no timeout)
-
- wait_eeprom_cmd_done_exit:
-
- pop cx
- pop bx
- ret
-
-
- stand_by:
- ; lower chip select for 1 microsecond.
- in al, dx ;de-select EEPROM
- and al, (10111110b) and (not ee_cs)
- out dx, al
-
- mov di, 2
- call eeprom_delay
-
- or al, ee_cs
- out dx, al
-
- ret
-
- ; Lower EEPROM chip select and DI.
- ; Clock EEPROM twice and leave clock low.
-
- eeprom_clean_up:
-
- push ax
-
- in al, dx
- and al, 10111111b
- and al, not (ee_cs or ee_di)
- out dx, al
-
- call raise_eeprom_clock
- call lower_eeprom_clock
-
- pop ax
- ret
-
- ; DI has number of 838 Nanoseconds clock counts
- eeprom_delay:
-
- push ax
- push bx
- push dx
-
- call readtickcounter
- mov bx, ax
-
- eeprom_delay_loop:
-
- call readtickcounter
- neg ax
- add ax, bx
- cmp ax, di
- jb eeprom_delay_loop
-
- pop dx
- pop bx
- pop ax
- ret
-
- iochrdy_test:
- ; First test to see if the driver is supposed to run this test.
- MOV AX, lock_bit_address
- CALL read_eeprom
-
- TEST AX, lock_bit_mask
- JNZ iochrdy_test_exit
- ; Get the configuration register.
-
- LEA DX, [BP].@config
- IN AL, DX
-
- ; Set the iochrdy test bit with and set iochrdy to late.
- OR AL, iochrdy_test_mask+iochrdy_late
- CLI
- OUT DX, AL
-
- ; Test IOCHRDY with IO.
- LEA DX, [BP].@mem_loc_0
- IN AX, DX
-
- ; Read in the results of the test. Save results in BL.
- LEA DX, [BP].@config
- IN AL, DX
- MOV BL, AL
-
- ; Turn iochrdy test off.
- AND AL, NOT iochrdy_test_mask
- OUT DX, AL
- STI
-
- ; Test results. Exit if IOCHRDY_LATE bit is set correctly.
- TEST BL, iochrdy_test_result
- JZ iochrdy_test_exit
-
- ; Here if test failed. Clear the 16 bit override bit (force 8 bit
- ; transfers) and print a warning message.
- AND AL, NOT _16_bit_override_bit
- OUT DX, AL
-
- mov dx, offset iochrdy_problem
- mov ah,9
- int 21h
-
-
- iochrdy_test_exit:
-
- RET
-
-
-
- iochrdy_problem db "IOCHRDY Problem. EtherExpress forced into 8 Bit Mode.",CR,LF,'$'
- buffer_memory_error db "Memory error on the EtherExpress board",CR,LF,'$'
-
- reset_error db "ASIC reset failure on EtherExpress board",CR,LF,'$'
-
- _586_diagnostic_failure db "82586 diagnostic failure on the "
- db "EtherExpress board",CR,LF,'$'
-
- _586_not_responding_msg db "82586 did not respond to command "
- db "on the EtherExpress board",CR,LF,'$'
-
- command_unit_not_idle db "82586 command unit is not "
- db "responding on the EtherExpress board",CR,LF,'$'
-
- invalid_int_number db "EtherExpress board IRQ/Interrupt number "
- db "not specified correctly",CR,LF,'$'
-
- eeprom_checksum_error db "EEPROM failed checksum",CR,LF,'$'
-
- Board_Not_Installed db "EtherExpress Board not found",CR,LF,'$'
-
- irq_config_error db "IRQ selection is for 16 bit slot only.",CR,LF,'$'
-
- bad_config_msg db "Could not configure the 82586",CR,LF,'$'
-
- bad_init_msg db "Could not initialize the 82586",CR,LF,'$'
-
- code ends
-
- end
-