home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / NETWORK / PCRTE220.ZIP / 3C507.INC < prev    next >
Encoding:
Text File  |  1991-02-19  |  38.7 KB  |  1,126 lines

  1. ;;******************************************************************************
  2. ;;                         3c507.inc      3c507.inc
  3. ;;******************************************************************************
  4. ;;
  5. ;;  Copyright (C) 1991 Vance Morrison
  6. ;;
  7. ;;
  8. ;; Permission to view, compile, and modify for LOCAL (intra-organization) 
  9. ;; USE ONLY is hereby granted, provided that this copyright and permission 
  10. ;; notice appear on all copies.  Any other use by permission only.
  11. ;;
  12. ;; Vance Morrison makes no representations about the suitability 
  13. ;; of this software for any purpose.  It is provided "as is" without expressed 
  14. ;; or implied warranty.  See the copywrite notice file for complete details.
  15. ;;
  16. ;;******************************************************************************
  17. ;; 3c507.inc holds the interface routines for the 3com etherlink 16 card.
  18. ;;
  19. ;; The functions provided by this file are
  20. ;;
  21. ;;   C507_DECLARE name, io_address, seg, len, promiscuous
  22. ;;   C507_DEFINE_out_AX name, fail
  23. ;;   C507_IF_R_ACCESS_out_BX_CX_ES name, no_packet
  24. ;;   C507_IF_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES name, ok
  25. ;;   C507_IF_R_FREE_const_BX_CX_BP_SI_DI_ES name
  26. ;;   C507_IF_W_ACCESS_in_CX_out_DI_ES_const_BX_CX_BP name, no_buffer
  27. ;;   C507_IF_W_WRITE_in_CX_const_BX_BP_ES name
  28. ;;   C507_IF_SET_ADDRESS_in_SI_const_BX_CX_BP_DI_ES name
  29. ;;   C507_IF_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES name
  30. ;;
  31. ;; Variables set by this module
  32. ;;
  33. ;;   c507_&name&_declared                     ;; one if this interface exists
  34. ;;   if_&name&_address                       ;; the hardware address
  35. ;;   if_&name&_mtu                           ;; the maximum trans unit
  36. ;;
  37. ;;******************************************************************************
  38. ;; data storage needed by this module
  39.  
  40. c507_data  STRUC
  41.     c507_base             dw 0  ;; these values are set at init only
  42.     c507_end_buff         dw 0
  43.     c507_start_buff       dw 0
  44.  
  45.     c507_last_rbd         dw 0  ;; set at init, and updated at FREE
  46.     c507_last_rfd         dw 0
  47.  
  48.     c507_last_frame_rbd   dw 0  ;; set at R_ACCESS used at FREE
  49.     c507_cur_frame        dw 0
  50.  
  51.     c507_cur_tcb          dw 0  ;; current transmit command buffer
  52. c507_data ENDS
  53.  
  54.  
  55. ;;******************************************************************************
  56. ;;   C507_DECLARE name, io_address, seg, len, promiscuous
  57. ;; declares that there is a 3c507 ethernet card at 'io_address'.  The
  58. ;; shared memory starts a the SEGMENT 'seg' and has length 'len'.  
  59. ;; if 'promiscuous' is non-blank and non-zero then every packet on
  60. ;; the ethernet is returned.
  61. ;;
  62. c507_first = 0          ;; the first 3c507 card.  
  63.  
  64. C507_DECLARE MACRO name, io_address, seg, len, promiscuous
  65.     .errb <seg>
  66.     .errb <len>
  67.  
  68.     .DATA
  69.     c507_&name&_declared     = 1
  70.     c507_&name&_io           = io_address
  71.     c507_&name&_seg          = seg
  72.     c507_&name&_len          = len
  73.  
  74.     c507_&name&_promiscuous = 0
  75.     ifnb <promiscuous>
  76.         c507_&name&_promiscuous = 0&promiscuous
  77.     endif
  78.  
  79.     if (name le c507_first) or (c507_first eq 0)
  80.         c507_first = name
  81.     endif
  82.  
  83.     if_&name&_mtu = 1514
  84.  
  85.     global c507_&name&_data:c507_data
  86.     global if_&name&_address:word 
  87.  
  88.     .CODE
  89.     global c507_&name&_real_define:near
  90. ENDM
  91.  
  92.  
  93. ;;******************************************************************************
  94. ;;   IF_DEFINE name
  95. ;;      sets asside memory an name object and initializes it.  This
  96. ;;      routine is a no-op if 'name' was not declared
  97. ;;      Note that if multiple 3C507 cards are present, they must be
  98. ;;      the smallest named card must be defined first (since this card
  99. ;;      turns on all the cards).  AX holds a failure code if the initialization
  100. ;;      fails.
  101. ;;
  102. C507_DEFINE_out_AX MACRO name, fail
  103. ifdef c507_&name&_declared
  104.     call c507_&name&_real_define
  105.     or AX, AX
  106.     jnz fail
  107. endif
  108. ENDM
  109.  
  110. C507_REAL_DEFINE MACRO name
  111.     local ret_code, rfd_loop, found_rfd, rbd_loop, found_rbd
  112.     .errb <name>
  113.  
  114. ifdef c507_&name&_declared
  115.     .DATA
  116.     if_&name&_address DW 3 dup (0)
  117.     c507_&name&_data  c507_data <>
  118.  
  119.     .CODE
  120. c507_&name&_real_define:
  121.  
  122.         ;; put all card in run state (only done for first card)
  123.     if name eq c507_first
  124.         xor AX, AX
  125.         WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES C507_ID_PORT, 0
  126.         C507_SEND_ID_const_BX_BP_SI_DI_ES C507_ID_PORT 
  127.         xor AX, AX
  128.         WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES C507_ID_PORT, 0
  129.     endif
  130.  
  131.         ;; get the ethernet address
  132.     mov SI, offset if_&name&_address
  133.     C507_GET_ADDRESS_in_SI_const_BX_BP_DI_ES c507_&name&_io
  134.  
  135.     C507_INIT_SETUP_out_ES c507_&name&_io, c507_&name&_seg, c507_&name&_len, if_&name&_address, c507_&name&_promiscuous, ret_code
  136.     mov c507_&name&_data.c507_base, ES
  137.  
  138.         ;; initialize my state variables
  139.     mov SI, ES:[SCB+scb_rframes]
  140.     mov c507_&name&_data.c507_cur_frame, SI
  141.  
  142.     mov DI, ES:[SI+rfd_rbd]     ;; DI points to the first buffer descriptor, we
  143.                                 ;; assume that this rbd points to the begining
  144.                                 ;; of the large block of memory
  145.     mov DX, ES:[DI+rbd_buff.offs]
  146.     mov c507_&name&_data.c507_start_buff, DX
  147.  
  148.         ;; find the last element of the Buffer list
  149.     rbd_loop:
  150.         test ES:[DI+rbd_len], RBD_LEN_EOL
  151.         jnz found_rbd
  152.         mov DI, ES:[DI+rbd_next]
  153.     jmp rbd_loop
  154.     found_rbd:
  155.     mov c507_&name&_data.c507_last_rbd, DI
  156.  
  157.     mov AX, ES:[DI+rbd_len] ;; DI points to the last buffer descriptor.  we
  158.                             ;; assume that this rbd points to the end of the
  159.                             ;; large block of memory.
  160.     and AX, RBD_LEN_MSK
  161.     mov DX, ES:[DI+rbd_buff.offs]
  162.     add DX, AX
  163.     mov c507_&name&_data.c507_end_buff, DX
  164.  
  165.         ;; find the last element of the Frame list
  166.     mov DI, ES:[SCB+scb_rframes]
  167.     rfd_loop:
  168.         test ES:[DI+rfd_cmd], RFD_CMD_EOL
  169.         jnz found_rfd
  170.         mov DI, ES:[DI+rfd_next]
  171.     jmp rfd_loop
  172.     found_rfd:
  173.     mov c507_&name&_data.c507_last_rfd, DI
  174.  
  175.     mov c507_&name&_data.c507_cur_tcb, CU_TCMD1
  176.  
  177.     xor AX, AX
  178. ret_code:
  179.    ret
  180.  
  181. endif
  182. ENDM
  183.  
  184.  
  185. ;;******************************************************************************
  186. ;;   IF_R_ACCESS_out_BX_ES name, no_packet
  187. ;;       IF_R_ACCESS waits for the next packet to come from the the board
  188. ;;       associated with 'name' and returns a pointer to the begining of 
  189. ;;       an ethernet packet in BX:ES.  CX holds the length of the packet
  190. ;;       R_ACCESS jumps to 'no_packet' if there are no packets waiting to 
  191. ;;       be read in
  192. ;;       
  193. C507_IF_R_ACCESS_out_BX_CX_ES MACRO name, no_packet
  194.     local look_packet, found_packet, len_loop, last_buff
  195.     .errb <no_packet>
  196.  
  197.     mov ES, c507_&name&_data.c507_base
  198.     mov SI, c507_&name&_data.c507_cur_frame
  199.  
  200.  
  201.     look_packet:
  202.         mov AX, ES:[SI+rfd_status]
  203.         test AX, RFD_STAT_DONE
  204.         jz no_packet
  205.  
  206.         test AX, RFD_STAT_OK
  207.         jnz found_packet
  208.         mov SI, ES:[SI+rfd_next]
  209.     jmp look_packet                     
  210.     found_packet:
  211.  
  212.     mov c507_&name&_data.c507_cur_frame, SI
  213.     mov SI, ES:[SI+rfd_rbd]
  214.     mov BX, ES:[SI+rbd_buff.offs]
  215.  
  216.         ;; compute the length of the packet, as well as if it wrapped or not
  217.     xor CX, CX
  218.     len_loop:
  219.         mov AX, ES:[SI+rbd_used_len]
  220.         test AX, RBD_USED_LEN_EOF
  221.         jnz last_buff
  222.         and AX, RBD_USED_LEN_MSK
  223.         add CX, AX
  224.         mov SI, ES:[SI+rbd_next]
  225.     jmp len_loop
  226.     last_buff:
  227.     and AX, RBD_USED_LEN_MSK
  228.     add CX, AX
  229.     mov c507_&name&_data.c507_last_frame_rbd, SI
  230. ENDM
  231.  
  232.  
  233. ;;******************************************************************************
  234. ;;   IF_R_FREE_const_BX_CX_BP_SI_DI_ES  name
  235. ;;       After the client is through processing the packet returned by 
  236. ;;       IF_R_ACCESS, IF_R_FREE must be called to inform 'name' that the 
  237. ;;       memory that the packet was in can be reused for future packets.
  238. ;;
  239. C507_IF_R_FREE_const_BX_CX_BP_SI_DI_ES MACRO name
  240.     local ok_rbd, do_restart, no_restart, look_first_nok, found_first_nok
  241.     .errb <name>
  242.  
  243.     mov DX, SI                                  ;; save SI
  244.     mov AX, ES
  245.     xchg AX, c507_&name&_data.c507_base         ;; load/save ES
  246.     mov ES, AX
  247.  
  248.     mov SI, c507_&name&_data.c507_last_frame_rbd
  249.     or ES:[SI+rbd_len], RBD_LEN_EOL
  250.  
  251.     mov SI, c507_&name&_data.c507_last_rbd
  252.     and ES:[SI+rbd_len], (NOT RBD_LEN_EOL)
  253.  
  254.     mov SI, c507_&name&_data.c507_last_frame_rbd
  255.     mov c507_&name&_data.c507_last_rbd, SI
  256.  
  257.     mov SI, c507_&name&_data.c507_cur_frame
  258.     mov AX, SI
  259.     mov ES:[SI+rfd_status], 0
  260.     or ES:[SI+rfd_cmd], RFD_CMD_EOL
  261.     mov SI, ES:[SI+rfd_next]
  262.     mov c507_&name&_data.c507_cur_frame, SI
  263.  
  264.     mov SI, c507_&name&_data.c507_last_rfd
  265.     mov ES:[SI+rfd_cmd], 0
  266.  
  267.     mov c507_&name&_data.c507_last_rfd, AX
  268.  
  269.     mov AX, ES:[SCB+scb_status]         ;; is the reciever still recieving?
  270.     and AX, SCB_STAT_RUS_MSK
  271.     cmp AX, SCB_STAT_RUS_READY
  272.     jz no_restart
  273.         mov SI, c507_&name&_data.c507_cur_frame
  274.         look_first_nok:
  275.             test ES:[SI+rfd_status], RFD_STAT_OK
  276.             jz found_first_nok
  277.  
  278.             mov SI, ES:[SI+rfd_next]
  279.         jmp look_first_nok
  280.         found_first_nok:
  281.         mov ES:[SCB+scb_rframes], SI
  282.         mov ES:[SI+rfd_status], 0
  283.         cmp word ptr ES:[SI+rfd_rbd], 0FFFFH
  284.         jnz ok_rbd
  285.             mov SI, c507_&name&_data.c507_last_rfd
  286.             mov AX, ES:[SI+rfd_rbd]
  287.             mov SI, ES:[SCB+scb_rframes]
  288.             mov ES:[SI+rfd_rbd], AX
  289.         ok_rbd:
  290.     
  291.         mov ES:[SCB+scb_cmd], SCB_RUC_START
  292.             ;; signal the 82586
  293.         WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES c507_&name&_io, C507_IO_ATTN
  294.     no_restart:
  295.  
  296.     mov SI, DX                                  ;; restore SI
  297.     mov AX, ES
  298.     xchg AX, c507_&name&_data.c507_base         ;; restore ES
  299.     mov ES, AX
  300. ENDM
  301.  
  302.  
  303. ;;******************************************************************************
  304. ;;   C507_IF_R_CONT_in_BX_CX_ES name, ok
  305. ;;       IF_R_CONT determines if the packet returned by R_READ in BX:ES
  306. ;;       of length CX is continuous.  If it is it jumps to 'ok' otherwise
  307. ;;       it just returns
  308. ;;
  309. C507_IF_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES MACRO name, ok
  310.     .errb <ok>
  311.  
  312.     mov AX, BX
  313.     add AX, CX
  314.     cmp AX, c507_&name&_data.c507_end_buff
  315.     jb ok
  316. ENDM
  317.  
  318.  
  319. ;;******************************************************************************
  320. ;;   IF_W_ACCESS_in_CX_out_DI_ES name, no_buffer
  321. ;;       IF_W_ACCESS returns a pointer to an output buffer for a packet.  The 
  322. ;;       pointer is returned in DI:ES.  If the ouptut buffer is busy, this 
  323. ;;       routine will jump to 'no_buffer'.  The output buffer  min(CX, 1536) 
  324. ;;       bytes long
  325. ;;
  326. C507_IF_W_ACCESS_in_CX_out_DI_ES_const_BX_CX_BP MACRO name, no_buffer
  327.     local wait_busy, buffer_free, com_accepted, wait_com_accept, nocarry
  328.     .errb <no_buffer>
  329.  
  330.         ;; we ignore CX and always return a buffer 1536 bytes long
  331.  
  332.     mov ES, c507_&name&_data.c507_base
  333.     mov SI, c507_&name&_data.c507_cur_tcb
  334.  
  335.     cmp ES:[SI+cu_status], 0            ;; has the RU done ANYTHING with stat
  336.     jnz com_accepted
  337.                 ;; it may be 0 if the CU hasn't even accepted the command
  338.                 ;; check for this and wait if necessary
  339.         xor DX, DX                      ;; so we don't loop forever
  340.         wait_com_accept:
  341.             test ES:[SCB+scb_cmd], SCB_CMD_CUC_MSK
  342.             jz com_accepted
  343.             dec DX
  344.         jnz wait_com_accept
  345.     com_accepted:
  346.  
  347.     xor DX, DX                  ;; so we don't loop forever
  348.     wait_busy:
  349.         test ES:[SI+cu_status], CU_STAT_BUSY
  350.         jz buffer_free
  351.         dec DX
  352.     jnz wait_busy
  353.     buffer_free:
  354.  
  355.     mov SI, ES:[SI+cu_params+trans_tbd]
  356.     mov DI, ES:[SI+tbd_buff.offs]
  357. ENDM
  358.  
  359.  
  360. ;;******************************************************************************
  361. ;;   IF_W_WRITE_in_CX name
  362. ;;       IF_W_WRITE actually signals the ethernet board to write a packet to 
  363. ;;       the ethernet.  The packet is assumed to be in the buffer returned by 
  364. ;;       IF_W_ACCESS. CX is the length of the packet to send.  
  365. ;;
  366. C507_IF_W_WRITE_in_CX_const_BX_BP_ES MACRO name
  367.     local not_tcmd1, check_prev_com, no_prev_com, wait_busy, buffer_free
  368.     .errb <name>
  369.  
  370.     mov DX, ES                                  ;; save ES
  371.     mov ES, c507_&name&_data.c507_base
  372.     mov DI, c507_&name&_data.c507_cur_tcb
  373.  
  374.         ;; make any previous command has been recognized before
  375.         ;; sending this next one.
  376.     xor AX, AX
  377.     check_prev_com:
  378.         test ES:[SCB+scb_cmd], SCB_CMD_CUC_MSK
  379.         jz no_prev_com
  380.         dec AX
  381.     jnz check_prev_com
  382.     no_prev_com:
  383.  
  384.     xor AX, AX
  385.     wait_busy:
  386.         test ES:[DI+cu_status], CU_STAT_BUSY
  387.         jz buffer_free
  388.         dec AX
  389.     jnz wait_busy
  390.     buffer_free:
  391.  
  392.     mov ES:[DI+cu_status], 0
  393.     mov ES:[DI+cu_cmd], CU_CMD_EOL+CU_CMD_TRANS ;; probably unnecessary
  394.     mov ES:[DI+cu_params+trans_len], CX         ;; probably unnecessary
  395.     mov SI, ES:[DI+cu_params+trans_tbd]
  396.     add CX, TBD_LEN_EOL
  397.     mov ES:[SI+tbd_len], CX
  398.  
  399.         ;; send our transmit command
  400.     mov SI, offset SCB
  401.     mov ES:[SI+scb_status], 0
  402.     mov ES:[SI+scb_cuc], DI
  403.     mov ES:[SI+scb_cmd], SCB_CUC_START
  404.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES c507_&name&_io, C507_IO_ATTN
  405.  
  406.         ;; update the tcb pointer to the 'other' command block
  407.     mov AX, CU_TCMD1
  408.     cmp AX, DI
  409.     jnz not_tcmd1
  410.         mov AX, CU_TCMD2
  411.     not_tcmd1:
  412.     mov c507_&name&_data.c507_cur_tcb, AX
  413.  
  414.     mov ES, DX                                  ;; restore ES
  415. ENDM
  416.  
  417.  
  418. ;;******************************************************************************
  419. ;;   IF_SET_ADDRESS_in_SI name
  420. ;;       IF_SET_ADDRESS_in_SI sets the hardware address to be the value
  421. ;;       pointed to by SI.  Note this function may be a no-op if the
  422. ;;       hardware address cannot be set (ETHERNET for example)
  423. ;;
  424.  
  425. C507_IF_SET_ADDRESS_in_SI_const_BX_CX_BP_DI_ES MACRO name
  426.     .err    ;; we don't support setting ethernet addresses (yet)
  427.     ENDM
  428.  
  429.  
  430. ;;******************************************************************************
  431. ;;   IF_COPY_in_CX_SI_DI_ES_out_SI_DI name
  432. ;;      IF_COPY_in_CX_SI_DI_ES copys a packet from the input buffer (pointed 
  433. ;;      to by SI and the segement register given in IF_DECLARE) to an output 
  434. ;;      buffer (pointed to by DI and dest_reg) of length CX.   It assumes the
  435. ;;      output buffer is contiguous.  (and the caller shouln't care if the 
  436. ;;      input buffer is contiguous)
  437. ;;
  438. C507_IF_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES MACRO name
  439.     local wrap, done
  440.     .errb <name>
  441.  
  442.     mov DX, DS                                  ;; save DS
  443.     mov AX, c507_&name&_data.c507_end_buff
  444.     sub AX, SI                                  ;; space till end
  445.     cmp AX, CX
  446.     jbe wrap
  447.                 inc CX
  448.                 shr CX, 1
  449.                 mov DS, c507_&name&_data.c507_base
  450.                 rep movsw
  451.                 jmp done
  452.                 
  453.     wrap:
  454.                 xchg AX, CX
  455.                 sub AX, CX
  456.  
  457.                 mov DS, c507_&name&_data.c507_base
  458.                 inc CX
  459.                 shr CX, 1
  460.                 rep movsw
  461.  
  462.                 mov CX, AX
  463.                 mov DS, DX
  464.                         ;; remember this instruction rely on DS
  465.                         mov SI, c507_&name&_data.c507_start_buff
  466.                 mov DS, c507_&name&_data.c507_base
  467.                 inc CX
  468.                 shr CX, 1
  469.                 rep movsw
  470.  
  471.    done:
  472.    mov DS, DX                                   ;; restore DS
  473. ENDM
  474.  
  475.  
  476. ;;******************************************************************************
  477. ;; These macros and definitions are specific to the 3C507
  478.  
  479. C507_ID_PORT = 100H
  480.  
  481. C507_IO_ADDR            = 00H
  482. C507_IO_CTR             = 06H
  483. C507_IO_INT_CLEAR       = 0AH
  484. C507_IO_ATTN            = 0BH
  485. C507_IO_ROM             = 0DH
  486. C507_IO_RAM             = 0EH
  487. C507_IO_INT             = 0FH
  488.  
  489.         ;; values for teh IO_CTR reg
  490. C507_CTR_RUN            = 080H          ;; 1 = run 0 = reset
  491. C507_CTR_CA             = 040H          ;; obsolete way of to a chan attn
  492. C507_CTR_LOOP           = 020H          ;; put in loopback
  493. C507_CTR_LAD            = 010H          ;; LA address decode disable
  494. C507_CTR_INT            = 008H          ;; interupt is pending (read only)
  495. C507_CTR_IEN            = 004H          ;; interupt enable
  496. C507_CTR_PG_MSK         = 003H          ;; controls first 6 locations
  497.  
  498.         ;; values for the CTR_PG field
  499. C507_PG_3COM            = 00H           ;; page that has '*3com*' in it
  500. C507_PG_ETHER           = 01H           ;; page ethernet address in it
  501.  
  502.  
  503. ;;*******************************************************************
  504. ;; This macro sends the ID sequence that the 3Com 3C507 responds to.
  505. ;; to the I/O address 'port'.
  506.  
  507. C507_SEND_ID_const_BX_BP_SI_DI_ES MACRO port
  508.     local id_loop, no_xor
  509.  
  510.     mov CX, 0FFH
  511.     mov AL, 0FFH
  512.     id_loop:
  513.         WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, 0
  514.         shl AL, 1
  515.         jnc no_xor
  516.             xor AL, 0E7H
  517.         no_xor:
  518.     loop id_loop
  519.  
  520. ENDM
  521.  
  522. ;;*****************************************************************
  523. ;; this routine gets the ethernet address from the 3Com I/O registers
  524. ;; and places it in the buffer pointed to by SI
  525. C507_GET_ADDRESS_in_SI_const_BX_BP_DI_ES MACRO port
  526.     local eaddr_loop
  527.  
  528.         ;; get the ethernet address
  529.      mov AL, C507_CTR_RUN+C507_PG_ETHER
  530.      WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
  531.      mov CX, 6
  532.      mov DX, port+C507_IO_ADDR
  533.      eaddr_loop:
  534.         in AL, DX
  535.         mov [SI], AL
  536.         inc DX
  537.         inc SI
  538.      loop eaddr_loop
  539. ENDM
  540.  
  541.  
  542. ;;********************************************************************
  543. ;; These definitions have more to do with the 82586
  544.  
  545. longptr struc           ;; just allows me to get at 8086 long ptrs easily
  546.     offs dw ?
  547.     segm dw ?
  548. longptr ends
  549.  
  550. ;;*********************************************************************
  551.  
  552.         ;; This structure is always at a fixed location, and points to
  553.         ;; the system control pointer
  554. i82586_root struc                       ;; the root pointer
  555.     root_bus    dw 0
  556.     root_zero   db 4 dup (0)
  557.     root_scp    dd ?
  558. i82586_root ends
  559.  
  560. I82586_FIXED_ROOT       = 0FFF6H        ;; this is the fixed position 
  561.  
  562. ;;*********************************************************************
  563.  
  564.         ;; The system control pointer, in turn, points to the
  565.         ;; system control block
  566. i82586_scp struc                        ;; the system control pointer
  567.     scp_busy    dw 0                    ;; 82586 sets to 0 when reset complete
  568.     scp_scb     dw 0                    ;; offset to system control block
  569.     scp_base    dd 0                    ;; base for all 16 bit pointers
  570. i82586_scp ends                         ;; the system control block
  571.  
  572.  
  573. ;;*********************************************************************
  574.  
  575.         ;; The system control block is the heart of the communication
  576.         ;; between the CPU and the 82586.   The 82586 has a control
  577.         ;; unit (CU) which you can issue commands to, and a recieve
  578.         ;; unit (RU) that buffers packets.  Commands to these units
  579.         ;; are given from this structure.
  580. i82586_scb struc                        ;; the system control block
  581.     scb_status    dw 0                  ;; RU and CU status
  582.     scb_cmd       dw 0                  ;; RU and/or CU command
  583.     scb_cuc       dw 0                  ;; CU command (list)
  584.     scb_rframes   dw 0                  ;; buffers for RU
  585.     scb_crc_errs  dw 0                  ;; CRC error count
  586.     scb_aln_errs  dw 0                  ;; Alignment error count
  587.     scb_rcs_errs  dw 0                  ;; Resource error (queue filled)
  588.     scb_ovrn_errs dw 0                  ;; Overruns (memory busy)
  589. i82586_scb ends
  590.  
  591.         ;; masks for the scb_status field
  592. SCB_STAT_CX       = 08000H              ;; command with interupt executed
  593. SCB_STAT_FR       = 04000H              ;; Frame recieved
  594. SCB_STAT_CNR      = 02000H              ;; command unit left active state
  595. SCB_STAT_RNR      = 01000H              ;; receive unit left active state
  596. SCB_STAT_CUS_MSK  = 00700H              ;; command status mask
  597. SCB_STAT_RUS_MSK  = 00070H              ;; reciever status mask
  598.  
  599.         ;; these are the values for teh RUS_MSK field
  600. SCB_STAT_RUS_IDLE  = 00000H             ;; reciever idle
  601. SCB_STAT_RUS_SUSP  = 00010H             ;; reciever suspended
  602. SCB_STAT_RUS_NORES = 00020H             ;; reciever no_resources
  603. SCB_STAT_RUS_READY = 00040H             ;; reciever ready
  604.  
  605.         ;; masks for the scb_cmd (set by CPU cleared by 82586)
  606. SCB_CMD_ACK_CX    = 08000H              ;; acks command executed
  607. SCB_CMD_ACK_FR    = 04000H              ;; acks frame received
  608. SCB_CMD_ACK_CNA   = 02000H              ;; acks CU not ready
  609. SCB_CMD_ACK_RNR   = 01000H              ;; acks RU not ready
  610. SCB_CMD_CUC_MSK   = 00700H              ;; CU command mask 
  611. SCB_CMD_RST       = 00080H              ;; reset the 82586 
  612. SCB_CMD_RUC_MSK   = 00070H              ;; RU command mask
  613.  
  614.         ;; values for the CUC_MSK part of the scb_cmd field
  615. SCB_CUC_START     = 00100H              ;; start a CU command
  616. SCB_CUC_RESUME    = 00200H
  617. SCB_CUC_SUSPEND   = 00300H
  618. SCB_CUC_ABORT     = 00400H
  619.  
  620.         ;; values for the RUC_MSK part of the scb_cmd field
  621. SCB_RUC_START     = 00010H              ;; start RU receiving packets
  622. SCB_RUC_RESUME    = 00020H
  623. SCB_RUC_SUSPEND   = 00030H
  624. SCB_RUC_ABORT     = 00040H
  625.  
  626.  
  627. ;;*********************************************************************
  628.  
  629.         ;; the scb_cuc points to a list of commands for the CU
  630.         ;; to execute.  Each entry in the list has this format
  631. i82586_cu struc
  632.     cu_status    dw 0                   ;; status of this command
  633.     cu_cmd       dw 0                   ;; specifies the op
  634.     cu_next      dw 0                   ;; next cmd in the list
  635.     cu_params    db 58 dup (0)          ;; depends on particular cmd
  636. i82586_cu ends
  637.  
  638.         ;; values for the cu_status field
  639. CU_STAT_COMPLETE        = 08000H        ;; command is completed
  640. CU_STAT_BUSY            = 04000H        ;; command not complete
  641. CU_STAT_OK              = 02000H        ;; finished and OK
  642.  
  643.         ;; values for the cu_cmd field
  644. CU_CMD_CMD_MSK          = 00007H        ;; mask for the command
  645. CU_CMD_EOL              = 08000H        ;; last command list in list
  646. CU_CMD_SUSPEND          = 04000H        ;; suspend after completion
  647. CU_CMD_INT              = 02000H        ;; interupt after completion
  648.  
  649.  
  650.         ;; values for the CMD_MSK parat of the cu_cmd field
  651. CU_CMD_NOOP             = 0             ;; noop command
  652. CU_CMD_ADDRESS_SET      = 1             ;; set ethernet address
  653. CU_CMD_CONFIG           = 2             ;; configure ethernet params
  654. CU_CMD_MULTI_SET        = 3             ;; set multicast addresses
  655. CU_CMD_TRANS            = 4             ;; transmit packet
  656. CU_CMD_TDR              = 5             ;; Time domain reflectometer
  657. CU_CMD_DUMP             = 6             ;; dump internal state 
  658. CU_CMD_DIAGNOSE         = 7             ;; run diagnostics
  659.  
  660. ;;*******************************************************************
  661.  
  662.         ;; these are the parameters of the TRAMSMIT command
  663. i82586_trans struc                      
  664.     trans_tbd      dw 0                 ;; points to buffer descriptor
  665.     trans_dst_addr db 6 dup (0)         ;; address to send it to (not used)
  666.     trans_len      dw 0                 ;; 802.3 length field (not used)
  667. i82586_trans ends
  668.  
  669.         ;; the first parameter of a transmit command points to a list 
  670.         ;; of transmit buffer discriptors that characterize the 
  671.         ;; packet to send
  672. i82586_tbd struc                        
  673.     tbd_len     dw 0                    ;; length and EOL flag
  674.     tbd_next    dw 0                    ;; pointer to next descriptor
  675.     tbd_buff    dd 0                    ;; a long pointer to the buffer
  676. i82586_tbd ends
  677.  
  678.         ;; the bit fields bit in the tbd_len field
  679. TBD_LEN_EOL             = 08000H        ;; Last buff in list
  680. TBD_LEN_LEN_MSK         = 03FFFH        ;; this part is the length
  681.  
  682.  
  683. ;;*******************************************************************
  684.  
  685.         ;; the scb_rfd field points to a list of frame descriptors.
  686.         ;; each of these describe a single packet
  687. i82586_rfd struc                        
  688.     rfd_status          dw 0            ;; recieve status
  689.     rfd_cmd             dw 0            ;; really just specifies EOL
  690.     rfd_next            dw 0            ;; next frame descriptor
  691.     rfd_rbd             dw 0            ;; pointer to buff descriptor
  692.     rfd_dst_addr        db 6 dup (0)    ;; ethernet address of destination
  693.     rfd_src_addr        db 6 dup (0)    ;; ethernet address of source
  694.     rfd_len             dw 0            ;; length of packet
  695. i82586_rfd ends                 
  696.  
  697. RFD_STAT_DONE     = 08000H
  698. RFD_STAT_CONSUMED = 04000H
  699. RFD_STAT_OK       = 02000H      
  700. RFD_STAT_CRC      = 00800H
  701. RFD_STAT_ALN      = 00400H
  702. RFD_STAT_RSC      = 00200H
  703. RFD_STAT_OVRN     = 00100H
  704. RFD_STAT_RUNT     = 00080H
  705.  
  706. RFD_CMD_EOL     = 08000H                ;; End of frame list 
  707.         
  708.         ;; the rdb_buff field points to a buffer descriptor, which is
  709.         ;; a unit of memory allocation.
  710. i82586_rbd struc                        
  711.     rbd_used_len        dw 0            ;; also hold some flag bits
  712.     rbd_next            dw 0            ;; next buffer descriptor
  713.     rbd_buff            dd 0            ;; pointer to actual memory
  714.     rbd_len             dw 0            ;; length of buffer
  715. i82586_rbd ends                 
  716.         
  717.         ;; masks for the rdb_used_len field     
  718. RBD_USED_LEN_EOF        = 08000H        ;; Last buff in a frame list
  719. RBD_USED_LEN_VALID      = 04000H        ;; says the used_len field valid
  720. RBD_USED_LEN_MSK        = 03FFFH        ;; this part is the used length
  721.  
  722. RBD_LEN_MSK     = 03FFFH                ;; this part is the used length
  723. RBD_LEN_EOL     = 08000H                ;; End of buffer list 
  724.  
  725.  
  726.  
  727. ;;***********************************************************************
  728. ;; setup the chain of recieve buffers.  SI points to a block
  729. ;; of memory  'len'*(SIZE i82586_rfd) bytes long.  Note 1 < CX < 16K
  730.  
  731. C507_SETUP_R_FRAMES_in_CX_SI_ES_const_AX_BP_ES MACRO 
  732.     local init_loop
  733.  
  734.         ;; create a circular list of receive buffers
  735.     mov DX, SI                          ;; save original pointer
  736.     mov DI, SI
  737.     add DI, (SIZE i82586_rfd)
  738.     dec CX
  739.     init_loop:
  740.                 ;; set up a frame descriptor
  741.         mov ES:[SI+rfd_status], 0
  742.         mov ES:[SI+rfd_cmd], 0          ;; says NOT end of list
  743.         mov ES:[SI+rfd_next], DI
  744.         mov ES:[SI+rfd_rbd], 0FFFFH
  745.  
  746.         add SI, (SIZE i82586_rfd)
  747.         add DI, (SIZE i82586_rfd)
  748.         dec CX
  749.     jnz init_loop
  750.  
  751.     mov ES:[SI+rfd_cmd], RFD_CMD_EOL    ;; logical end of list
  752.     mov ES:[SI+rfd_next], DX            ;; close the loop
  753.     mov ES:[SI+rfd_rbd], 0FFFFH
  754. ENDM
  755.  
  756.  
  757. ;;***********************************************************************
  758. ;; setup the chain of recieve buffers.  BX points to the begining of
  759. ;; a block of memory 'len'* CX bytes long and SI points to a block
  760. ;; of memory  'len'*(SIZE i82586_rbd) bytes long.  Note 1 < CX < 16K
  761. ;; it returns in SI the start of the list of buffer descriptors.
  762.  
  763. C507_SETUP_R_BUFFS_in_BX_CX_SI_ES_out_SI_const_AX_BP_ES MACRO len
  764.     local init_loop
  765.  
  766.         ;; create a circular list of receive buffers
  767.     mov DX, SI                          ;; save original pointer
  768.     mov DI, SI
  769.     add DI, (SIZE i82586_rbd)
  770.     dec CX
  771.     init_loop:
  772.                 ;; set up a buffer descriptor
  773.         mov ES:[SI+rbd_next], DI
  774.         mov ES:[SI+rbd_buff.offs], BX
  775.         mov ES:[SI+rbd_buff.segm], 0
  776.         mov ES:[SI+rbd_len], len
  777.  
  778.         add SI, (SIZE i82586_rbd)
  779.         add DI, (SIZE i82586_rbd)
  780.         add BX, len
  781.         dec CX
  782.     jnz init_loop
  783.  
  784.     mov ES:[SI+rbd_next], DX            ;; close the loop
  785.     mov ES:[SI+rbd_buff.offs], BX
  786.     mov ES:[SI+rbd_buff.segm], 0
  787.     mov ES:[SI+rbd_len], len+RBD_LEN_EOL          ;; logical end of list
  788.  
  789.     mov SI, DX                          ;; return the first one
  790. ENDM
  791.  
  792.  
  793.  
  794. ;;***********************************************************************
  795. ;; setup the data structure needed for the receiver.  CX, ES:SI is the
  796. ;; len and begining of shared memory in which to set it up.  It returns
  797. ;; in SI the pointer that belongs in the scb_rframes field of the system
  798. ;; control block 'len' is the length of a buffer 
  799.  
  800. C507_SETUP_R_MEM_in_CX_SI_ES_out_SI_const_ES MACRO len
  801.  
  802.     ;; since we allocate two buffers for every frame 
  803. TOTAL_BUFF_LEN = len + (SIZE i82586_rbd) + (SIZE i82586_rfd)
  804.  
  805.    mov AX, CX
  806.    sub AX, (SIZE i82586_rfd)    ;; Want an extra frame desc
  807.    xor DX, DX
  808.    mov BX, TOTAL_BUFF_LEN
  809.    div BX
  810.  
  811.    mov CX, AX                   ;; AX holds the number of buffers
  812.    mov BX, SI                   ;; BX start of buffer space
  813.    mov DX, len
  814.    mul DX
  815.    add SI, AX                   ;; SI start of buff desc
  816.  
  817.    mov BP, SI
  818.    mov AX, CX
  819.    mov DX, (SIZE i82586_rbd)
  820.    mul DX
  821.    add BP, AX                   ;; BP points to the start of frame desc
  822.  
  823.    mov AX, CX                   ;; CX holds the number of buffers
  824.    inc AX                       ;; AX holds the number of frames
  825.  
  826.    C507_SETUP_R_BUFFS_in_BX_CX_SI_ES_out_SI_const_AX_BP_ES len
  827.  
  828.    mov CX, AX
  829.    mov AX, SI                   ;; save pointer to start of buffer list
  830.    mov SI, BP
  831.    C507_SETUP_R_FRAMES_in_CX_SI_ES_const_AX_BP_ES 
  832.  
  833.    mov SI, BP                   ;; return final pointer to frames
  834.    mov ES:[SI+rfd_rbd], AX      ;; link the frames to the buffs
  835. ENDM
  836.  
  837.  
  838. ;;***********************************************************************
  839. ;; setup the data structures needed to communicate with the 82586.
  840. ;; SI:ES points to the shared memory window.  Note that We only use
  841. ;; the memory ABOVE SI in the ES segment, thus if SI=C000 there is
  842. ;; a 4K window.   In addition, some data structures are in 'standard'
  843. ;; positions that can be used directly.
  844. ;; 
  845.  
  846. SCP             = 0FFE0H        ;; place for system control ptr
  847. SCB             = (SCP-16)      ;; place for system control block
  848. CU_GCMD         = (SCB-32)      ;; generic command (32 bytes long)
  849. CU_TCMD1        = (CU_GCMD-32)  ;; first trans command (32 bytes long)
  850. CU_TCMD2        = (CU_TCMD1-32) ;; second trans command (32 bytes long)
  851. CU_TBD1         = (CU_TCMD2-8)  ;; first Transmit buffer descriptor
  852. CU_TBD2         = (CU_TBD1-8)   ;; second Transmit buffer descriptor
  853. CU_TB1          = (CU_TBD2-1536);; first Trans buffer (1536 bytes long)
  854. CU_TB2          = (CU_TB1-1536) ;; second Trans buffer (1536 bytes long)
  855.  
  856. START_RESERVED  = CU_TB2        ;; start of fixed allocated memory
  857. LEN_R_BUFF      = 256           ;; this is a optimization param
  858.  
  859.  
  860. ;;*************************************************************************
  861. ;; SETUP_MEM sets up all the shared memory data structures that the 82586
  862. ;; uses SI:ES points the the begining of the memory.  It is assumed that
  863. ;; the memory ranges is ES:SI to ES:FFFF 
  864. ;;
  865. C507_SETUP_MEM_in_SI_ES_const_ES MACRO
  866.  
  867.     mov DI, SI                  ;; zero out memory, it makes reading
  868.     xor AX, AX                  ;; dumps easier
  869.     mov DX, SI
  870.     shr DX, 1
  871.     mov CX, 8000H
  872.     sub CX, DX
  873.     rep stosw
  874.  
  875.         ;; setup ROOT
  876.     mov BX, offset I82586_FIXED_ROOT
  877.     mov ES:[BX+root_bus], 0
  878.     mov ES:[BX+root_scp.offs], offset SCP
  879.     mov ES:[BX+root_scp.segm], 0
  880.  
  881.         ;; setup SCP
  882.     mov BX, offset SCP
  883.     mov ES:[BX+scp_busy], 1             ;; set the busy bit
  884.     mov ES:[BX+scp_scb], SCB
  885.     mov ES:[BX+scp_base.offs], 0
  886.     mov ES:[BX+scp_base.segm], 0
  887.  
  888.         ;; setup SCB
  889.     mov BX, offset SCB
  890.     mov ES:[BX+scb_cmd], 0
  891.     mov ES:[BX+scb_status], 0
  892.     mov ES:[BX+scb_crc_errs], 0
  893.     mov ES:[BX+scb_aln_errs], 0
  894.     mov ES:[BX+scb_rcs_errs], 0
  895.     mov ES:[BX+scb_ovrn_errs], 0
  896.     mov ES:[BX+scb_cuc], offset CU_GCMD
  897.  
  898.         ;; get the length of the rest of memory
  899.     mov CX, START_RESERVED
  900.     sub CX, SI 
  901.     C507_SETUP_R_MEM_in_CX_SI_ES_out_SI_const_ES LEN_R_BUFF
  902.  
  903.     mov BX, offset SCB
  904.     mov ES:[BX+scb_rframes], SI
  905.  
  906.         ;; setup transmit buffers descriptors
  907.     mov BX, CU_TCMD1
  908.     mov ES:[BX+cu_cmd], CU_CMD_EOL+CU_CMD_TRANS
  909.     mov ES:[BX+cu_params+trans_tbd], CU_TBD1
  910.  
  911.     mov BX, CU_TCMD2
  912.     mov ES:[BX+cu_cmd], CU_CMD_EOL+CU_CMD_TRANS
  913.     mov ES:[BX+cu_params+trans_tbd], CU_TBD2
  914.  
  915.     mov BX, CU_TBD1
  916.     mov ES:[BX+tbd_buff.offs], offset CU_TB1
  917.     mov ES:[BX+tbd_buff.segm], 0
  918.  
  919.     mov BX, CU_TBD2
  920.     mov ES:[BX+tbd_buff.offs], offset CU_TB2
  921.     mov ES:[BX+tbd_buff.segm], 0
  922.  
  923. ENDM
  924.  
  925.  
  926. ;;***********************************************************************
  927. ;; DO_CMD simply executes the command 'command'.  It assumes that all
  928. ;; parameters to the command have been set up in the DO_CMD_PARAMS
  929. ;; structure below.  This command waits for completion and jumps to
  930. ;; 'fail' if unsuccessful.  (note that DO_CMD_PARAMS points to the
  931. ;; command specific part of the command.
  932. ;; Note also that this command should not be used if it is possible
  933. ;; that other commands are in progress
  934.  
  935. DO_CMD_PARAMS = (CU_GCMD+6)             
  936.  
  937. C507_DO_CMD_in_ES_const_BP_SI_DI_ES MACRO command, port, fail
  938.     local waitloop, done
  939.     .errb <fail>
  940.  
  941.     mov BX, offset SCB
  942.     mov ES:[BX+scb_status], 0
  943.     mov ES:[BX+scb_cuc], offset CU_GCMD
  944.     mov ES:[BX+scb_cmd], SCB_CUC_START
  945.  
  946.     mov BX, offset CU_GCMD
  947.     mov ES:[BX+cu_status], 0
  948.     mov ES:[BX+cu_cmd], CU_CMD_EOL+command
  949.         ;; we assume that the rest of the command is set up
  950.  
  951.         ;; signal the 82586
  952.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_ATTN
  953.  
  954.     xor CX, CX                  ;; don't wait forever
  955.     waitloop:
  956.         dec CX
  957.         jz fail
  958.  
  959.         mov AX, ES:[BX+cu_status]
  960.         test AX, CU_STAT_COMPLETE
  961.     jz waitloop                 ;; wait for completion
  962.     test AX, CU_STAT_OK
  963.     jz fail     
  964.  
  965. ENDM
  966.     
  967.  
  968. ;;***********************************************************************
  969. ;; do the intial setup of the 3C507 card
  970.  
  971. C507_RESET_82586_in_ES MACRO port, fail
  972.    local reset_wait, reset_done, reset_loop
  973.  
  974.         ;; reset the 82586
  975.     mov ES:[SCP+scp_busy], 1            ;; set the busy bit
  976.  
  977.     mov AL, 0  
  978.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
  979.     nop         ;; wait 10 clock cycles
  980.     nop
  981.  
  982.         ;; just in case there was an interupt pending, clear it
  983.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_INT_CLEAR
  984.  
  985.     mov AL, C507_CTR_RUN+C507_PG_ETHER 
  986.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
  987.     nop
  988.     nop
  989.  
  990.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_ATTN
  991.  
  992.     mov CX, 256
  993.     reset_loop:
  994.         cmp ES:[SCP+scp_busy], 0
  995.         jz reset_done
  996.     loop reset_loop
  997.     jmp fail
  998.  
  999.     reset_done:
  1000. ENDM
  1001.  
  1002.  
  1003. ;;***********************************************************************
  1004. ;; do the intial setup of the 3C507 card
  1005.  
  1006. C507_INIT_SETUP_out_ES MACRO port, segment, len, addr, promiscuous, fail
  1007.    local eaddr_loop, done, diag_fail, config_fail, setaddr_fail
  1008.    local reset_fail, ru_on_fail, wait_ru_on, done_wait_ru
  1009.    .errb <len>
  1010.  
  1011.         ;; adjust ES so that ES:SI point to begining and ES:FFFF the end
  1012.     mov AX, segment
  1013.     sub AX, (1000H - (len / 16))
  1014.     mov ES, AX
  1015.     mov SI, 10000H - len
  1016.  
  1017.         ;; test the memory just a bit
  1018.     mov ES:[SI], 5F75H
  1019.     mov DX, ES:[SI]
  1020.     mov AX, 0101H               ;; signals a memory check error type 1
  1021.     cmp DX, 5F75H
  1022.     jnz fail
  1023.  
  1024.     mov ES:[0FFFEH], 57A5H
  1025.     mov DX, ES:[0FFFEH]
  1026.     mov AX, 0102H               ;; signals a memory check error type 2
  1027.     cmp DX, 57A5H
  1028.     jnz fail
  1029.  
  1030.     C507_SETUP_MEM_in_SI_ES_const_ES 
  1031.  
  1032.  
  1033.         ;; just to test the board is there, get the first char
  1034.         ;; of the '*3com*' identifier from the I/O ROM.  
  1035.     mov AL, C507_CTR_RUN+C507_PG_3COM  
  1036.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
  1037.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES port, C507_IO_ADDR
  1038.     mov DL, AL
  1039.     mov AX, 0201H               ;; signals 82586 not there
  1040.     cmp DL, '*'                 ;; should be part of *3com*' string
  1041.     jnz fail
  1042.  
  1043.     C507_RESET_82586_in_ES port reset_fail
  1044.  
  1045.         ;; check the setup by doing a diag
  1046.     C507_DO_CMD_in_ES_const_BP_SI_DI_ES CU_CMD_DIAGNOSE, port, diag_fail
  1047.  
  1048.         ;; configure ethernet params
  1049.     mov BX, offset DO_CMD_PARAMS 
  1050.     mov word ptr ES:[BX+0], 0080CH  ; fifo=8  byte count=12
  1051.     mov word ptr ES:[BX+2], 02E00H  ; preamble=4, add_len=6, DONT ins headers
  1052.     mov word ptr ES:[BX+4], 06000H  ; interframe spacing = 60h
  1053.     mov word ptr ES:[BX+6], 0F200H  ; retry = 15, slot time = 200h
  1054.     if promiscuous eq 1
  1055.         mov word ptr ES:[BX+8], 1   ; flags bit 1 means promiscuous
  1056.     else
  1057.         mov word ptr ES:[BX+8], 0   ; flags bit 1 means promiscuous
  1058.     endif
  1059.     mov word ptr ES:[BX+10], 0003CH  ; minimum frame length = 60
  1060.     C507_DO_CMD_in_ES_const_BP_SI_DI_ES CU_CMD_CONFIG, port, config_fail
  1061.  
  1062.         ;; set the ethernet address
  1063.     mov DI, offset DO_CMD_PARAMS 
  1064.     mov SI, offset addr
  1065.     mov CX, 3
  1066.     rep movsw
  1067.     C507_DO_CMD_in_ES_const_BP_SI_DI_ES CU_CMD_ADDRESS_SET, port, setaddr_fail
  1068.  
  1069.     mov BX, offset SCB
  1070.     mov ES:[BX+scb_status], 0
  1071.     mov ES:[BX+scb_cmd], SCB_RUC_START
  1072.  
  1073.         ;; signal the 82586
  1074.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_ATTN
  1075.  
  1076.     xor CX, CX
  1077.     wait_ru_on:
  1078.         dec CX
  1079.         mov AX, ES:[BX+scb_status]
  1080.         and AX, SCB_STAT_RUS_MSK
  1081.         jnz done_wait_ru
  1082.         dec CX
  1083.     jnz wait_ru_on
  1084.     done_wait_ru:
  1085.     cmp AX, SCB_STAT_RUS_READY
  1086.     jz done
  1087.  
  1088. ru_on_fail:
  1089.     mov AX, 0206H               ;; failed to turn RU on
  1090.     jmp fail
  1091.  
  1092. reset_fail:
  1093.     mov AX, 0202H               ;; failed resetting the 82586
  1094.     jmp fail
  1095.  
  1096. diag_fail:
  1097.     mov AX, 0203H               ;; signals 82586 failed noop test
  1098.     jmp fail
  1099.  
  1100. config_fail:
  1101.     mov AX, 0204H               ;; signals 82586 failed config
  1102.     jmp fail
  1103.  
  1104. setaddr_fail:
  1105.     mov AX, 0205H               ;; signals 82586 failed set addr
  1106.     jmp fail
  1107.  
  1108.     done:
  1109. ENDM
  1110.  
  1111.  
  1112. ;;******************************************************************************
  1113. ;; utility functions needed only within this module
  1114.  
  1115. READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES MACRO port, if_io
  1116.     mov DX, if_io+port
  1117.     in  AL, DX                              ;; AL contains data read from port
  1118. ENDM
  1119.  
  1120. ;;******************************************************************************
  1121. WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES MACRO port, if_io
  1122.     mov DX, if_io+port
  1123.     out DX, AL                              ;; AL contains data read from port
  1124. ENDM 
  1125.  
  1126.