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

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