home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / packetdrivers.tar.gz / pd.tar / src / t7231.asm < prev    next >
Assembly Source File  |  1995-06-25  |  26KB  |  1,046 lines

  1. t7231_version    equ    2
  2.   ifndef DAN
  3. DAN    equ    4            ; 4 seems to work best.
  4.   endif
  5.  
  6. ;
  7. ; Code that is common between T7231 implementations.
  8. ;
  9.  
  10. ; Ported from Tim Krauskopf's micnet.asm, an assembly language
  11. ; driver for the MICOM-Interlan NI5210, by Russell Nelson.  Any bugs
  12. ; are due to Russell Nelson.
  13. ; Updated to version 1.08 Feb. 17, 1989 by Russell Nelson.
  14. ; Updated to support 1500 byte MTU April 27, 1989 By Brad Clements.
  15. ; copied and modified to support t7231 LanPACER controller by AT&T
  16. ; June 1, 1991 by Mark Darby.
  17. ; Updated to correct problems with higher speed CPU systems 
  18. ; by Mark Darby - NCR, October 12, 1993
  19.  
  20. ; Copyright, 1988-90, Russell Nelson
  21.  
  22. ;   This program is free software; you can redistribute it and/or modify
  23. ;   it under the terms of the GNU General Public License as published by
  24. ;   the Free Software Foundation, version 1.
  25. ;
  26. ;   This program is distributed in the hope that it will be useful,
  27. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  29. ;   GNU General Public License for more details.
  30. ;
  31. ;   You should have received a copy of the GNU General Public License
  32. ;   along with this program; if not, write to the Free Software
  33. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  34.  
  35. ;
  36. ;  Structure elements specific to the AT&T T7231 chip
  37. ;
  38.  
  39. ; System Configuration Pointer
  40. scp_struc    struc
  41. scp_bus        db    ?,?,?, ?,?,?    ; bus use flag (0=16 bit, 1=8 bit).
  42. scp_ptr        dd    ?        ; 24pointer to iscp
  43. scp_struc    ends
  44.  
  45. ; Intermediate System Configuration Pointer
  46. iscp_struc    struc
  47. iscp_busy    db    ?,?        ; busy flag (zeroed after init).
  48. iscp_offset    dw    ?        ; 16pointer to iscp
  49. iscp_base    dd    ?        ; base for all 16 pointers, lo, hi
  50. iscp_struc    ends
  51.  
  52. ; System Control Block
  53. scb_struc    struc
  54. scb_stat    dw    ?        ; status
  55. scb_com        dw    ?        ; command
  56. scb_cbl        dw    ?        ; 16pointer to command block list
  57. scb_rfa        dw    ?        ; 16pointer to receive frame list
  58. scb_serrs    dw    4 dup(?)    ; 4 words of error counts
  59. scb_struc    ends
  60.  
  61. ; (Received) Frame Descriptor
  62. fd_struc    struc
  63. fd_status    dw    ?        ; status word for frame
  64. fd_eol        dw    ?        ; end of FD list flag
  65. fd_link        dw    ?        ; 16pointer to next FD
  66. fd_ptr        dw    ?        ; 16pointer to list of RBD's
  67. fd_dest        db    EADDR_LEN dup(?); 48 bits of destination
  68. fd_source    db    EADDR_LEN dup(?); 48 bits of source
  69. fd_cnt        dw    ?        ; length field of frame.
  70. fd_struc    ends
  71.  
  72. ; Receive Buffer Descriptor
  73. rbd_struc    struc
  74. rbd_status    dw    ?        ; status word in RBD
  75. rbd_link    dw    ?        ; 16pointer to next RBD
  76. rbd_ptr        dd    ?        ; 24pointer to actual buffer
  77. rbd_size    dw    ?        ; size of the buffer
  78. rbd_struc    ends
  79.  
  80. ; Transmit Command Block
  81. tcb_struc    struc
  82. tcb_status    dw    ?        ; status word for xmit
  83. tcb_com        dw    ?        ; command to transmit
  84. tcb_link    dw    ?        ; 16pointer to next command
  85. tcb_ptr        dw    ?        ; 16pointer to xmit TBD
  86. tcb_addr    db    EADDR_LEN dup(?); destination address
  87. tcb_len        dw    ?
  88. tcb_struc    ends
  89.  
  90. ; Transmit Buffer Descriptor
  91. tbd_struc    struc
  92. tbd_status    dw    ?        ; bit 15=EOF, 13-0=actual count
  93. tbd_link    dw    ?        ; 16pointer to next TBD
  94. tbd_ptr        dd    ?        ; 24pointer to buffer
  95. tbd_struc    ends
  96.  
  97. ; all commands have at least the following:
  98. cmd_struc    struc
  99. cmd_status    dw    ?        ; status word
  100. cmd_com        dw    ?        ; command word.
  101. cmd_struc    ends
  102.  
  103. ; MC-SETUP Command Block
  104. mcb_struc    struc
  105. mcb_status    dw    ?        ; status word for multicast
  106. mcb_com        dw    ?        ; command to setup multicast
  107. mcb_link    dw    ?        ; 16pointer to next command
  108. mcb_cnt        dw    ?        ; number of multicast addresses.
  109. mcb_struc    ends
  110.  
  111.  
  112. ;Memory allocation.
  113.  
  114. ;SCPTR    EQU    0fff6h            ; hardwired address for SCP
  115. ;ISCPTR    EQU    0ffeeh            ; my address for ISCP, points to SCB
  116. SCPTR    EQU    03ff6h            ; hardwired address for SCP
  117. ISCPTR    EQU    03feeh            ; my address for ISCP, points to SCB
  118. SCB    EQU    ISCPTR - 16        ; system control block base
  119. CCBPTR    EQU    SCB - 18        ; offset of configure command block
  120. TBDPTR    EQU    CCBPTR - 8        ; xmit BD offset
  121. TCBPTR    EQU    TBDPTR - 16        ; xmit CB offset
  122. TBUFPTR    EQU    TCBPTR - GIANT        ; xmit buffer offset
  123. ;the receive buffers appear at lower addresses than TBUFPTR.
  124. RBUFLEN    EQU    200
  125. RBUF_TOTAL    equ    (size fd_struc) + (size rbd_struc) + RBUFLEN
  126. FDBASE        equ    TBUFPTR - RBUF_TOTAL
  127.  
  128. memory_begin    dw    ?
  129.  
  130.     public    rcv_modes
  131. rcv_modes    dw    7        ;number of receive modes in our table.
  132.         dw    0               ;There is no mode zero
  133.         dw    0
  134.         dw    rcv_mode_2
  135.         dw    rcv_mode_3
  136.         dw    rcv_mode_4    ;haven't set up perfect filtering yet.
  137.         dw    0
  138.         dw    rcv_mode_6
  139.  
  140. firstfd        dw    FDBASE        ; start of FD queue
  141. lastfd        dw    0        ; end of the FD chain
  142. lastbd        dw    0        ; end of the BD chain
  143. flag        dw    0
  144.  
  145.  
  146. ;
  147. ; Configuration block for 82586, this comprises one config command
  148. ;  Parameters taken from MICOM driver
  149. ;
  150. CBCONF    DW    0        ; status word
  151.     DW    8002H        ; end of command list + configure command
  152.     DW    0ffffh        ; link to next command (not used)
  153.     DW    080CH        ; fifo=8, byte count=C
  154.     DW    2E00H        ; important! Addr (AL) not inserted on the fly!
  155.     DW    6000H        ; IFS = 60h
  156.     DW    0F200H        ; retry=F, slot time=200h
  157. CBCONF_FLAGS    label    byte
  158.     DW    0        ; flags, set to 1 for promiscuous
  159. CBCONF_MINLEN    label    byte
  160.     DW    40H        ; min frame length=40h
  161.  
  162.  
  163. doca_wait:
  164. ;enter with ax = command to execute, es = base_addr.
  165. ;exit with nc if the command ran to completion.
  166. ;exit with cy if the command timed out.  Eventually we'll also reset the chip.
  167.     mov    es:[SCB].scb_com,ax    ;set the command.
  168.  
  169.     mov    si,es:[SCB].scb_cbl    ;
  170.     mov    es:[si].cmd_status,0    ; status word of specific command
  171.     and    ax,0700h
  172.     cmp    ax,0100h        ; is it an action command?
  173.     jne    doca_wait_a        ; no, any other
  174.  
  175.     call    doca
  176.  
  177. comment \
  178. Quoting from the D-Step Errata Revision 2.0:
  179.  
  180. The value for the deadman timer should be greater than the longest
  181. command execution time.  The command which can take the longest time
  182. to execute is the transmit command, assuming maximum retries.  To
  183. determine the maximum amount of time the transmit command may take,
  184. one must use the following equation: 7143 ST + 14 f, where ST stands
  185. for Slot Time and f = Maximum Frame Size + IFS + Preamble.  For
  186. Ethernet/IEEE 802.3 where ST = 512 bits, f = 12144 bits, Preamble =
  187. 64 bits, IFS  96 bits, and one bit = 0.1 usec, the deadman timeout
  188. should be greater than 0.369 seconds.
  189.  
  190. \
  191.  
  192.     mov    ax,14            ;36.4 ticks / seconds * .369 seconds
  193.     call    set_timeout
  194. doca_wait_1:
  195.     test    es:[si].cmd_status,8000h    ; is command complete?
  196.     jnz    doca_wait_2        ;yes.
  197.     call    do_timeout        ;did we time out yet?
  198.     jne    doca_wait_1        ;not yet.
  199. ;reset the chip here, then Configure, IA-Setup, and MC-Setup.
  200.     stc                ;timeout -- uh-oh.
  201.     ret
  202. doca_wait_2:
  203.     clc
  204.     ret
  205.  
  206. doca_wait_a:
  207.     call    doca
  208. doca_wait_a_0:
  209.     cmp    es:[SCB].scb_com,0    ; has the command been accepted?
  210.     jnz    doca_wait_a_0        ; not yet.
  211.     clc
  212.     ret
  213.  
  214.  
  215.     include    timeout.asm
  216.     include    movemem.asm
  217.  
  218.     public bad_command_intercept
  219. bad_command_intercept:
  220. ;called with ah=command, unknown to the skeleton.
  221. ;exit with nc if okay, cy, dh=error if not.
  222.     mov    dh,BAD_COMMAND
  223.     stc
  224.     ret
  225.  
  226.     public    as_send_pkt
  227. ; The Asynchronous Transmit Packet routine.
  228. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  229. ;   interrupts possibly enabled.
  230. ; Exit with nc if ok, or else cy if error, dh set to error number.
  231. ;   es:di and interrupt enable flag preserved on exit.
  232. as_send_pkt:
  233.     ret
  234.  
  235.     public    drop_pkt
  236. ; Drop a packet from the queue.
  237. ; Enter with es:di -> iocb.
  238. drop_pkt:
  239.     assume    ds:nothing
  240.     ret
  241.  
  242.     public    xmit
  243. ; Process a transmit interrupt with the least possible latency to achieve
  244. ;   back-to-back packet transmissions.
  245. ; May only use ax and dx.
  246. xmit:
  247.     assume    ds:nothing
  248.     ret
  249.  
  250.  
  251.     public    send_pkt
  252. send_pkt:
  253. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  254. ;  (only if the high-performance bit is set in driver_function)
  255. ;enter with ds:si -> packet, cx = packet length.
  256. ;exit with nc if ok, or else cy if error, dh set to error number.
  257.     assume    ds:nothing
  258.     mov    es,base_addr        ; base for board
  259.  
  260.     cmp    cx,GIANT        ; Is this packet too large?
  261.     ja    send_pkt_toobig
  262.  
  263.     mov    dx,cx            ; save a copy, might be less than 60, ok
  264.  
  265.     cmp    dx,RUNT            ; minimum length for Ether
  266.     jnb    oklen
  267.     mov    dx,RUNT            ; make sure size at least RUNT
  268. oklen:
  269.     mov    di,TBUFPTR        ; start of xmit buffer
  270.  
  271. ;
  272. ;  check for previous xmit
  273. ;
  274. xwait:
  275.     mov    bx,es:[SCB].scb_com    ; has previous command been accepted?
  276.     or    bx,bx
  277.     jnz    xwait            ; not there yet, wait for it
  278. wait_for_transmit_to_complete:
  279.     test    word ptr es:[TCBPTR],4000h
  280.     jnz    wait_for_transmit_to_complete
  281. ;
  282. ;  move the data using word moves.
  283. ;
  284.     call    movemem
  285. ;
  286. ;  put the correct size into the TBD
  287. ;
  288.     or    dx,08000h            ; end of frame bit flag
  289.     mov    es:[TBDPTR].tbd_status,dx    ; store it
  290. ;    mov    es:[TCBPTR].tcb_status,0    ; zero status wd
  291.     mov    es:[TCBPTR].tcb_com,8004h    ; xmit command in TCB
  292. ;    mov    es:[SCB].scb_com,0100h        ; execute command
  293.     mov    es:[SCB].scb_cbl,TCBPTR    ; say where xmit command is
  294.  
  295.     mov    ax,100h
  296.     call    doca_wait
  297.  
  298.     clc
  299.     ret
  300. send_pkt_toobig:
  301.     mov    dh,NO_SPACE
  302.     stc
  303.     ret
  304.  
  305.  
  306. rcv_mode_2:
  307.     and    CBCONF_FLAGS,not 3
  308.     or    CBCONF_FLAGS,2        ;disable broadcasts.
  309.     mov    CBCONF_MINLEN,40h
  310.     jmp    short reconfigure
  311. rcv_mode_4:
  312. rcv_mode_3:
  313.     and    CBCONF_FLAGS,not 3    ;clear promiscuous mode.
  314.     mov    CBCONF_MINLEN,40h
  315.     jmp    short reconfigure
  316. rcv_mode_6:
  317.     and    CBCONF_FLAGS,not 3
  318.     or    CBCONF_FLAGS,1        ;set promiscuous mode.
  319.     mov    CBCONF_MINLEN,0        ;allow runts.
  320. reconfigure:
  321.     mov    es,base_addr        ;get the base address for the board.
  322.     mov    si,offset CBCONF    ; configure command
  323.     mov    di,CCBPTR        ; where command will reside
  324.     mov    cx,9
  325.     rep    movsw            ; copy to board
  326. ;
  327. ;  issue the configure command
  328. ;
  329.     mov    es:[SCB].scb_cbl,CCBPTR    ; where conf command is
  330.     mov    es:[SCB].scb_serrs[0],0    ; zero errs field
  331.     mov    es:[SCB].scb_serrs[2],0    ; zero errs field
  332.     mov    es:[SCB].scb_serrs[4],0    ; zero errs field
  333.     mov    es:[SCB].scb_serrs[6],0    ; zero errs field
  334.     mov    ax,100h            ; do-command command
  335.     call    doca_wait
  336.     ret
  337.  
  338.  
  339.     public    set_multicast_list
  340. set_multicast_list:
  341. ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
  342. ;  cx = number of bytes.
  343. ;return nc if we set all of them, or cy,dh=error if we didn't.
  344.     assume    ds:code
  345.     mov    es,base_addr
  346.     mov    es:[SCB].scb_cbl,TBUFPTR    ;use the transmit buffer.
  347.  
  348.     mov    es:[TBUFPTR].mcb_status,0    ;status word
  349.     mov    es:[TBUFPTR].mcb_com,08003h    ;command word for mc-setup + EL
  350.     mov    es:[TBUFPTR].mcb_link,-1    ;no command link.
  351.     mov    di,TBUFPTR + mcb_cnt
  352.     mov    ax,cx            ;store the count.
  353.     stosw
  354.     rep    movsb
  355.  
  356. comment \ avoid deferred execution of a CU command during reception.
  357. If a command is executed with a length of 18 to 20 bytes, and a frame
  358. is received, the 82586 may deadlock with HOLD active.  We avoid this
  359. problem by suspending the receiver. \
  360.  
  361.     mov    ax,30h            ;suspend frame receiving.
  362.     call    doca_wait
  363.  
  364.     mov    ax,100h            ; do-command command
  365.     call    doca_wait
  366.     jnc    set_multicast_2
  367.  
  368.     mov    ax,20h            ;resume frame receiving.
  369.     call    doca_wait
  370.  
  371.     mov    dh,NO_MULTICAST        ;for some reason we can't do multi's.
  372.     stc
  373.     ret
  374. set_multicast_2:
  375.     mov    ax,20h            ;resume frame receiving.
  376.     call    doca_wait
  377.  
  378.     clc
  379.     ret
  380.  
  381.  
  382.     public    terminate
  383. terminate:
  384.     assume    ds:code
  385.     ret
  386.  
  387.     public    reset_interface
  388. reset_interface:
  389. ;reset the interface.
  390. ;we don't do anything.
  391.     assume    ds:nothing
  392. retpoint:
  393.     ret
  394.  
  395.  
  396. ;called when we want to determine what to do with a received packet.
  397. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  398.     extrn    recv_find: near
  399.  
  400. ;called after we have copied the packet into the buffer.
  401. ;enter with ds:si ->the packet, cx = length of the packet.
  402.     extrn    recv_copy: near
  403.  
  404. ;call this routine to schedule a subroutine that gets run after the
  405. ;recv_isr.  This is done by stuffing routine's address in place
  406. ;of the recv_isr iret's address.  This routine should push the flags when it
  407. ;is entered, and should jump to recv_exiting_exit to leave.
  408. ;enter with ax = address of routine to run.
  409.     extrn    schedule_exiting: near
  410.  
  411. ;recv_exiting jumps here to exit, after pushing the flags.
  412.     extrn    recv_exiting_exit: near
  413.  
  414.     extrn    count_in_err: near
  415.     extrn    count_out_err: near
  416.  
  417.     public    recv
  418. recv:
  419.   ifdef IO_INTCLR
  420.     loadport            ;clear the interupt latch.
  421.     setport    IO_INTCLR
  422.     out    dx,al
  423.   endif
  424.  
  425.     mov    flag, 1
  426. ;called from the recv isr.  All registers have been saved, and ds=cs.
  427. ;Upon exit, the interrupt will be acknowledged.
  428. recv1:
  429.     mov    ds,base_addr    ; base for board
  430.     assume    ds:nothing
  431.  
  432.     mov    ax,ds:[SCB].scb_stat    ;get the status.
  433. recv_isr_1:
  434.     cmp    ds:[SCB].scb_com,0    ;has previous command been accepted?
  435.     jne    recv_isr_1        ;no -- keep waiting.
  436.  
  437.     and    ax,0f000h        ;isolate the ACK bits to make a
  438.                     ;  command to ack the interrupt.
  439.   if DAN and 1
  440.     jz    recv_isr_2
  441.   endif
  442.  
  443.     mov    ds:[SCB].scb_com,ax    ;set the command.
  444.     call    doca
  445. recv_isr_2:
  446.     cmp    ds:[SCB].scb_com,0    ; has the command been accepted?
  447.     jnz    recv_isr_2        ; not yet.
  448.  
  449. ;  Get whatever packets are on the board
  450. ;
  451.     mov    bx,firstfd    ; get addr of first FD in list
  452.     mov    ax,[bx].fd_status    ; status word of frame
  453.     test    ax,08000h    ; frame written?
  454.     jnz    okframe
  455.  
  456.     jmp    ru_start    ; no, restore receiver if necessary
  457. frame_bad:
  458.     call    count_in_err
  459. ptrupdate_j_1:
  460.     jmp    ptrupdate
  461.  
  462. ;  we have a frame, read it in
  463. ;
  464. okframe:
  465.     test    ax,02000h        ;check frame OK bit
  466.     jz    frame_bad        ;bad, fix it.
  467.     mov    si,[bx].fd_ptr        ;get pointer to buffer descriptor
  468.     xor    cx,cx            ;start with zero bytes.
  469. countbuf:                ;es:di is already set to receive packet
  470.     mov    dx,si            ;save a copy of current BD ptr
  471.     mov    ax,[si].rbd_status    ;get status and count word for BD
  472.     test    ax,04000h        ;is count field there?
  473.     jz    ptrupdate_j_1        ;no - we give up here.
  474.     add    cl,al            ;add the count into cx.
  475.     adc    ch,0
  476.     mov    si,[si].rbd_link    ;go to next BD in list
  477.     test    ax,8000h        ;is this the last frame?
  478.     je    countbuf        ;no - keep counting.
  479.  
  480.     push    bx
  481.     push    cx
  482.  
  483.     mov    ax,cs            ;we need ds = code.
  484.     mov    ds,ax
  485.     assume    ds:code
  486.  
  487.     mov    es,base_addr        ;get a pointer to their type.
  488.     mov    di,es:[bx].fd_ptr    ;get pointer to buffer descriptor
  489.     mov    di,es:[di].rbd_ptr.offs    ;get offset of data
  490.     add    di,EADDR_LEN+EADDR_LEN    ;skip the ethernet addreses and
  491.                     ;  point to the packet type.
  492.  
  493.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  494.     mov    ax, es:[di]
  495.     xchg    ah, al
  496.     cmp     ax, 1500
  497.     ja    BlueBookPacket
  498.     inc    di            ;set di to 802.2 header
  499.     inc    di
  500.     mov    dl, IEEE8023
  501. BlueBookPacket:
  502.     call    recv_find        ;look up our type.
  503.  
  504.     pop    cx
  505.     pop    bx
  506.     mov    ds,base_addr        ;restore ds to the board.
  507.     assume    ds:nothing
  508.  
  509.     mov    ax,es            ;is this pointer null?
  510.     or    ax,di
  511.     je    ptrupdate        ;yes - just free the frame.
  512.  
  513.     push    cx
  514.     push    es            ;remember where the buffer pointer is.
  515.     push    di
  516.   if DAN and 2
  517.     push    cx
  518.   endif
  519.  
  520.     mov    si,[bx].fd_ptr        ;get pointer to buffer descriptor
  521. copybuf:
  522.     mov    dx,si            ;save a copy of current BD ptr
  523.     xor    ch,ch            ;200 bytes is largest this can be
  524.     mov    cl,byte ptr [si].rbd_status;get count word for BD
  525.     mov    si,[si].rbd_ptr.offs    ;get offset of data
  526.   if DAN and 2
  527.     pop    ax
  528.     sub    ax, cx
  529.     jc    copydone
  530.     push    ax
  531.   ENDIf
  532.     call    movemem
  533.     mov    si,dx            ;get back current BD ptr
  534.     test    [si].rbd_status,8000h    ;check EOF bit
  535.     mov    si,[si].rbd_link    ;go to next BD in list
  536.     jz    copybuf            ;not done, keep copying it.
  537.  
  538.   if DAN and 2
  539.     pop    cx
  540. copydone:
  541.   endif
  542.     pop    si            ;now give the frame to the client.
  543.     pop    ds
  544.     pop    cx
  545.     assume    ds:nothing
  546.  
  547.     call    recv_copy
  548. ;
  549. ;  we are done with the frame, do the list management
  550. ;
  551. ptrupdate:
  552.     movseg    ds,cs
  553.     assume    ds:code
  554.     mov    es,base_addr        ; reload board segment
  555.  
  556.     mov    si,es:[bx].fd_ptr    ; first BD in frame list
  557. nextbd:
  558.     mov    cx,es:[si].rbd_status    ; count word for BD, EOF bit
  559.     test    cx,08000h        ; EOF bit, if set, save si in lastbd
  560.     jnz    dolastbd
  561.     mov    es:[si].rbd_status,0    ; clear status word, EOF bit
  562.     cmp    si,lastbd        ; see if we are wrapping
  563.     jz    dolastbd        ; yes, just undo it
  564.     mov    si,es:[si].rbd_link    ; follow link
  565.     jmp    nextbd
  566. dolastbd:
  567.     mov    di,lastbd        ; where end of BD list is now
  568.     mov    lastbd,si        ; store last known BD
  569.     mov    es:[si].rbd_size,08000h+200; end of list here
  570.     mov    es:[si].rbd_status,0    ; clear status word, EOF bit
  571. ; size field for not end of list
  572.     mov    es:[di].rbd_size,200    ; remove old end-of-list
  573.  
  574. ;
  575. ;  update the FD list flags, new end-of-list
  576. ;
  577.     mov    es:[bx].fd_eol,08000h    ; store new EOL
  578.     mov    es:[bx].fd_status,0    ; clear status word for frame
  579.     mov    di,lastfd        ; get old end-of-list
  580.     mov    es:[di].fd_eol,0    ; zero old one
  581.     mov    lastfd,bx        ; update stored pointer
  582.     mov    si,es:[bx].fd_link    ; where next fd is
  583.     mov    firstfd,si        ; store that info for next time
  584.   if DAN and 4
  585.     jmp    recv1
  586.   endif
  587.  
  588. ru_start:
  589. ; re-start receive unit
  590. ;
  591. ;  check to see if the receiver went off because of no resources
  592. ;  and restart receiver if necessary
  593. ;
  594.     movseg    ds,cs
  595.     mov    es,base_addr
  596.     mov    ax,es:[SCB].scb_stat    ; status word for SCB
  597.     and    ax,070h        ; receiver status
  598.     cmp    al,020h        ; receiver has no resources
  599.     jnz    hasres
  600.   if DAN and 8
  601.     cmp    flag, 1
  602.     jnz    ru_start1
  603.     mov    flag, 0
  604.     jmp    recv1
  605.   endif
  606.  
  607. ru_start1:
  608.     call    count_out_err
  609. ;
  610. ;  setup lists for starting the RU on the chip
  611. ;  we know that there isn't anything in the buffer that we want
  612. ;
  613.  
  614.     mov    bx,firstfd        ; get first FD on free list (assume free)
  615.     mov    es:[SCB].scb_rfa,bx    ; put into SCB
  616.     mov    si,lastbd        ; pointer to a BD, end of chain
  617.     mov    ax,es:[si].rbd_link    ; pointer to next BD
  618.     mov    es:[bx].fd_ptr,ax    ; set to start of BDs
  619. ;
  620. ;
  621. ;  Start the RU, doesn't need CB, only SCB parms.
  622. ;   command, to start receiving again
  623. ;
  624.     mov    ax,10h            ; start RU
  625.     call    doca_wait
  626. hasres:
  627. ;I don't we need to wait here because we haven't done anything to wait for.
  628.     ret
  629.  
  630.  
  631.     public    set_address
  632. set_address:
  633.     assume    ds:nothing
  634. ;enter with ds:si -> Ethernet address, CX = length of address.
  635. ;exit with nc if okay, or cy, dh=error if any errors.
  636.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  637.     je    set_address_4
  638.     mov    dh,BAD_ADDRESS
  639.     stc
  640.     jmp    short set_address_done
  641. set_address_4:
  642.  
  643. ;  Next step, load our address into the board
  644. ;     reuses the space that the configure command used, with different command
  645. ;
  646.     mov    es,base_addr        ; set to base address
  647.     mov    es:[SCB].scb_cbl,CCBPTR    ; say where conf command is
  648.  
  649.     mov    di,CCBPTR        ; start of config command block
  650.     xor    ax,ax
  651.     stosw                ; zero status word for commmand
  652.     mov    ax,8001h        ; IA setup command + EL
  653.     stosw
  654.     xor    ax,ax
  655.     dec    ax
  656.     stosw                ; set link value to -1 (unused)
  657.  
  658.     rep    movsb            ; move their ethernet address in.
  659. ;
  660. ;  start the IA setup command
  661. ;
  662.     mov    ax,100h            ; do-command command
  663.     call    doca_wait
  664.     jnc    set_address_okay
  665.     mov    dh,-1            ; no error in the list applies.
  666.     jmp    short set_address_done
  667. set_address_okay:
  668.     mov    cx,EADDR_LEN        ;return their address length.
  669.     clc
  670. set_address_done:
  671.     movseg    ds,cs
  672.     assume    ds:code
  673.     ret
  674.  
  675.  
  676.     public    timer_isr
  677. timer_isr:
  678. ;if the first instruction is an iret, then the timer is not hooked
  679.     iret
  680.  
  681. ;any code after this will not be kept.  Buffers used by the program, if any,
  682. ;are allocated from the memory between end_resident and end_free_mem.
  683.     public end_resident,end_free_mem
  684. end_resident    label    byte
  685. end_free_mem    label    byte
  686.  
  687. timeout_msg    db    "Timed out while initializing the board.",CR,LF,'$'
  688. addr_bad_msg    db    "Memory address should be less than 65536.",CR,LF,'$'
  689.  
  690. security_msg    label    byte
  691. db "Security is enabled.  Do not attempt to change the ethernet address or",CR,LF
  692. db "set promiscuous mode on this board.  Unexpected results may occur.",CR,LF
  693. db '$'
  694.  
  695. mem8_16        db    2        ; 1 for 16k, 2 for 8k
  696.  
  697.     extrn    set_recv_isr: near
  698.     extrn    maskint: near
  699.  
  700. ;enter with si -> argument string, di -> word to store.
  701. ;if there is no number, don't change the number.
  702.     extrn    get_number: near
  703.  
  704. ;enter with dx -> name of word, di -> dword to print.
  705.     extrn    print_number: near
  706.  
  707. ;enter with ax = number to print.
  708.     extrn    decout: near
  709.  
  710. ;-> the assigned Ethernet address of the card.
  711.     extrn    rom_address: byte
  712.  
  713. timeout_error:
  714.     mov    dx,offset timeout_msg
  715.     jmp    short error
  716. error:
  717.     mov    ah,9
  718.     int    21h
  719.     stc
  720.     ret
  721.  
  722. ;
  723. ;  data for configuring and setting up the board
  724. ;
  725. ;  chip always looks at SCP for config info which points to ISCP for the
  726. ;  pointer to the CONTROL BLOCK which handles everything from there.
  727. ;  Kind of indirect, but it works.
  728. ;
  729. SCP    DB    0            ; bus use flag (0=16 bit, 1=8 bit).
  730.  
  731.     public    etopen
  732. etopen:
  733.     mov    al,int_no
  734.     call    maskint            ;disable these interrupts.
  735.  
  736.     cmp    base_addr.offs,0    ;low word of segment can't be zero.
  737.     je    etopen_1
  738.     cmp    base_addr.segm,0    ;high word of segment must be zero.
  739.     je    etopen_2
  740. etopen_1:
  741.     mov    dx,offset addr_bad_msg
  742.     stc
  743.     ret
  744. etopen_2:
  745.  
  746. ;  Initialize the Ethernet board, set receive type.
  747. ;
  748.     mov        es,base_addr
  749. ;
  750. ;    Check for the ATTLAN signature in shared memory
  751. ;
  752.     mov        di,3ff9h
  753.     cmp        byte ptr es:[di],'A'
  754.     jnz        no_sig
  755.     inc        di
  756.     cmp        byte ptr es:[di],'T'
  757.     jnz        no_sig
  758.     inc        di
  759.     cmp        byte ptr es:[di],'T'
  760.     jnz        no_sig
  761.     inc        di
  762.     cmp        byte ptr es:[di],'L'
  763.     jnz        no_sig
  764.     inc        di
  765.     cmp        byte ptr es:[di],'A'
  766.     jnz        no_sig
  767.     inc        di
  768.     cmp        byte ptr es:[di],'N'
  769.     jnz        no_sig
  770.     mov        di,io_addr
  771.     shr        di,1
  772.     shr        di,1
  773.     shr        di,1
  774.     shr        di,1
  775.     and        di,001fh
  776.     mov        es:[3fffh],di
  777. no_sig:
  778.  
  779. ;
  780. ;  check for correct EPROM location
  781. ;
  782.     call    check_board
  783.     jnc    etopen_3
  784.     ret
  785. etopen_3:
  786.  
  787. ;
  788. ;  Turn off interrupts, I don't want them
  789. ;
  790.   ifdef IOINTOF
  791.     loadport
  792.     setport IOINTOF
  793.     out    dx,al
  794.   endif
  795. ;
  796. ;  Disconnect from network
  797. ;
  798.   ifdef IODIS
  799.     loadport
  800.     setport    IODIS
  801.     out    dx,al
  802.   endif
  803.  
  804. ;
  805. ;  Initialize the Ethernet board.
  806. ;
  807.     mov    di,00000h        ;our initial base address.
  808.     mov    si,ISCPTR-2        ;try the init down a little.
  809.  
  810. ;
  811. ;  Now discern the end of memory by repeatedly re-initializing the board
  812. ;  until the BUSY flag in the ISCP gets reset.
  813. ;
  814. re_discern:
  815.     mov    es,base_addr        ;remember where we think it starts.
  816.     call    init_root        ;did we find our memory size?
  817.     jc    confbad            ;no, keep trying.
  818.     inc    si            ;yes, see if we found the real one.
  819.     inc    si
  820.     call    init_root        ;try initializing it in a different locn.
  821.     jnc    confok            ;it worked!  we've found the root.
  822. confbad:
  823.     sti
  824.     jmp    timeout_error
  825.  
  826. confok:
  827.     mov    memory_begin,di
  828.     call    reconfigure
  829.     jc    confbad
  830. ;  
  831. ;  We have to determine if security is enabled on the board.  This is done by
  832. ;  attempting to set the board into promiscuous mode (rcv_mode_6).  We will
  833. ;  then check to see if the "Command Abort" bit has been set.  If it has, then
  834. ;  security is enabled and we will notify the user.
  835. ;
  836.     call    rcv_mode_6
  837.     jc        confbad
  838.     test    es:[CCBPTR].cmd_status,01000h
  839.     jz        no_security
  840.     mov        dx,offset security_msg
  841.     mov        ah,9
  842.     int        21h
  843.     mov        word ptr rcv_modes+14,0000h
  844. no_security:
  845.     call    rcv_mode_3
  846.     jc        confbad
  847. ;
  848. ;  Ask the board for the Ethernet address, and then use set_address to set it.
  849. ;
  850.     movseg    es,ds
  851.     mov    di,offset rom_address
  852.     mov    cx,EADDR_LEN
  853.     call    get_address
  854.  
  855.     mov    si,offset rom_address
  856.     mov    cx,EADDR_LEN
  857.     call    set_address
  858.     jnc    store_address_2
  859.     sti
  860.     jmp    timeout_error
  861. store_address_2:
  862. ;
  863. ;  IA sent, setup all of the other data structures on the board
  864. ;  start with xmit command descriptors
  865. ;
  866.     mov    di,TCBPTR
  867.     mov    es:[di].tcb_status,0
  868.     mov    es:[di].tcb_com,08004h
  869.     mov    es:[di].tcb_link,-1
  870.     mov    es:[di].tcb_ptr,TBDPTR
  871.  
  872.     add    di,(size tcb_struc)
  873.  
  874.     mov    es:[di].tbd_status,0
  875.     mov    es:[di].tbd_link,0
  876.     mov    es:[di].tbd_ptr.offs,TBUFPTR
  877.     mov    es:[di].tbd_ptr.segm,0
  878.  
  879. ; Note that we allocate fd's, rbd's, and buffers all at the same time.  This
  880. ; doesn't mean that each pair of fd's and rbd's necessarily have anything to
  881. ; do with each other.  We just allocate them together because we want to have
  882. ; the same number of each, and it's easier to compute that way.
  883.  
  884.     mov    di,TBUFPTR        ;get the last buffer.
  885.  
  886.     mov    ax,di            ;compute the amount of free memory.
  887.     sub    ax,memory_begin
  888.     xor    dx,dx
  889.     mov    bx,RBUF_TOTAL        ;each buffer takes this much.
  890.     div    bx
  891.     mov    cx,ax            ;put the number of buffers into cx.
  892.  
  893. init_rbuff_0:
  894.     sub    di,RBUF_TOTAL        ;back the pointer down by a little.
  895.  
  896. ;init the FD.
  897.     mov    es:[di].fd_status,0
  898.     mov    es:[di].fd_eol,0
  899.     mov    es:[di].fd_ptr,-1
  900.     lea    ax,[di]-RBUF_TOTAL    ;get the address of the next buffer.
  901.     mov    es:[di].fd_link,ax
  902.  
  903. ;init the BD.
  904.     lea    bx,[di + (size fd_struc)]
  905.     mov    es:[bx].rbd_status,0
  906.     lea    ax,[bx-RBUF_TOTAL]    ;make a pointer to the next BD
  907.     mov    es:[bx].rbd_link,ax
  908.     lea    ax,[bx+(size rbd_struc)]    ;make a pointer to the buffer.
  909.     mov    es:[bx].rbd_ptr.offs,ax
  910.     mov    es:[bx].rbd_ptr.segm,0
  911.     mov    es:[bx].rbd_size,RBUFLEN    ;length of the buffer.
  912.  
  913.     loop    init_rbuff_0
  914.  
  915. init_rbuff_1:
  916. ;patch the parameters of the last FD and BD so they link around to the head.
  917.     mov    es:[di].fd_eol,8000h
  918.     mov    es:[di].fd_link,FDBASE
  919.     mov    lastfd,di
  920.  
  921.     lea    bx,[di + (size fd_struc)]
  922.     mov    es:[bx].rbd_link,FDBASE + (size fd_struc)
  923.     mov    es:[bx].rbd_size,RBUFLEN + 8000h
  924.     mov    lastbd,bx
  925.  
  926. ;now put the location of the first rbd into the first fd.
  927.     mov    es:[FDBASE].fd_ptr,FDBASE  + (size fd_struc)
  928.  
  929.     call    enable_network
  930.  
  931. ;
  932. ;  Start the RU, doesn't need CB, only SCB parms.
  933. ;   command, to start receiving
  934. ;
  935.     mov    es:[SCB].scb_rfa,FDBASE    ; set to frame descriptors
  936.     mov    ax,10h            ; start RU
  937.     call    doca_wait
  938. ;
  939. ; Now reset CX, FR, CNA, and RNR so that we don't get a spurious interrupt.
  940. ;
  941.     mov    ax,es:[SCB].scb_stat    ;get the status.
  942.     and    ax,0f000h        ;isolate the ACK bits.
  943.     mov    es:[SCB].scb_com,ax    ;make a command to
  944.                     ;acknowledge the interrupt.
  945.     call    doca
  946. ;
  947. ; Now hook in our interrupt
  948. ;
  949.     call    set_recv_isr
  950.  
  951.     sti
  952.  
  953.     mov    al, int_no        ; Get board's interrupt vector
  954.     add    al, 8
  955.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  956.     jb    set_int_num        ; No.
  957.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  958. set_int_num:
  959.     xor    ah, ah            ; Clear high byte
  960.     mov    int_num, ax        ; Set parameter_list int num.
  961.  
  962.     clc
  963.     ret
  964.  
  965.  
  966. init_root:
  967. ;enter with es:di -> beginning of our system memory window,
  968. ;  si -> place to put ISC.
  969. ;exit with nc if it worked, cy if it didn't work.
  970.  
  971.     mov    al,SCP
  972.     mov    es:[SCPTR].scp_bus,al
  973.     mov    es:[SCPTR].scp_ptr.offs,si
  974.     mov    es:[SCPTR].scp_ptr.segm,0
  975.  
  976.     mov    es:[si].iscp_busy,1        ;set busy bit.
  977.     mov    es:[si].iscp_offset,SCB        ;point to the SCB.
  978.     mov    es:[si].iscp_base.offs,0    ;scb base.
  979.     mov    es:[si].iscp_base.segm,0    ;scb base.
  980.  
  981.     call    reset_586        ; reset the 586, hardware-specific.
  982.     push    ax
  983.     in    al, 61h
  984.     in    al, 61h
  985.     in    al, 61h
  986.     pop    ax
  987.  
  988.     mov        al,int_no
  989.     cmp        al,2
  990.     jnz        int_not2
  991.     mov        al,9
  992. int_not2:
  993.     loadport
  994.     setport    IOINTR
  995.     out        dx,al
  996.  
  997.     mov        al,08h
  998.     mov        ah,media_sel
  999.     or         ah,ah
  1000.     jz        only_aui
  1001.     add        al,04h
  1002.     mov        ah,li_enabl
  1003.     or        ah,ah
  1004.     jz        tp_noli
  1005.     add        al,02h
  1006.  
  1007. tp_noli:
  1008. only_aui:
  1009.     loadport
  1010.     setport IOMISC
  1011.     out dx,al
  1012.  
  1013. ;    mov        ax,1
  1014. ;    call    set_timeout
  1015. ;time_delay:
  1016. ;    call    do_timeout
  1017. ;    jne        time_delay
  1018.     push    ax
  1019.     in    al, 61h
  1020.     in    al, 61h
  1021.     in    al, 61h
  1022.     pop    ax
  1023.  
  1024. ;
  1025. ;  Issue a CA to initialize the chip after reset
  1026. ;
  1027.     call    doca
  1028.     push    ax
  1029.     in    al, 61h
  1030.     in    al, 61h
  1031.     in    al, 61h
  1032.     pop    ax
  1033.  
  1034. ;    mov    ax,2            ;don't wait too long.
  1035. ;    call    set_timeout
  1036. ;init_root_2:
  1037.     cmp    es:[si].iscp_busy,0    ;did it clear the busy flag?
  1038.     je    init_root_1        ;yes.
  1039. ;    call    do_timeout
  1040. ;    jne    init_root_2
  1041.     stc
  1042.     ret
  1043. init_root_1:
  1044.     clc
  1045.     ret
  1046.