home *** CD-ROM | disk | FTP | other *** search
/ Serving the Web / ServingTheWeb1995.disc1of1.iso / connect / tcpip / crynwr / pktd11c / lan595.asm < prev    next >
Assembly Source File  |  1993-12-13  |  33KB  |  1,129 lines

  1.  
  2.     include    defs.asm
  3.     include    82595.inc
  4.  
  5. version equ 0
  6.  
  7. code    SEGMENT    word public
  8.     assume    cs:code, ds:code
  9.     include    lan595io.asm
  10.  
  11.     even
  12.  
  13. extrn    sys_features : byte
  14. extrn    decout    : near
  15.  
  16. rx_buff_ptr    dw    ?        ; Start of receive buffer.
  17. next_rx_ptr    dw    ?        ; Points to the end of the receiver buffer
  18.                         ;  i.e. the start of the next receive buffer
  19. inw_routine        dw    ?    ; Address of subroutine to read in a word
  20. outw_routine    dw    ?    ; Address of subroutine to write out a word
  21. repins            dw    ?    ; Address of subroutine to do multiple word reads
  22. repouts            dw    ?    ; Address of subroutine to do multiple word writes
  23.  
  24. tx_buff_no        dw    ?    ; The next Tx buffer to use
  25. buff_ptrs        dw    TX_BUF_CNT dup (?)
  26.  
  27. ; a temp buffer for the received header
  28. ; needs to be 8 header bytes + 2 ethernet address bytes + 2 type bytes
  29. ;    plus some room for IEEE802.3  bytes
  30. ;RCV_HDR_SIZE    equ    30        ; header @8 + 2 ids @6 + type @2+8,
  31. RCV_HDR_SIZE    equ    30        ; header @8 + 2 ids @6 + type @2+6,
  32. rcv_hdr            db    RCV_HDR_SIZE dup(0)
  33.  
  34. lan_595_int    db    ?    ; Int number on the LAN 595 board (0 - 4)
  35.     public    int_no
  36. int_no        db    3,0,0,0        ;must be four bytes long for get_number.
  37. io_addr        dw    0,0            ; I/O address specified on the command line
  38. base_addr    dw     0000h        ; I/O address as located via the I/O scan
  39.  
  40.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  41. driver_class    db    BLUEBOOK,IEEE8023,0    ;null terminated list of classes.
  42.  
  43.     driver_type    db    0        ;from the packet spec
  44.     driver_name    db    10h dup(?)    ;name of the driver.
  45.  
  46. driver_function    db    2
  47.  
  48. parameter_list    label    byte
  49.     db    1    ;major rev of packet driver
  50.     db    9    ;minor rev of packet driver
  51.     db    14    ;length of parameter list
  52.     db    EADDR_LEN    ;length of MAC-layer address
  53.     dw    GIANT    ;MTU, including MAC headers
  54.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  55.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  56.     dw    0    ;(# of successive xmits) - 1
  57. int_num    dw    0    ;Interrupt # to hook for post-EOI
  58.             ;processing, 0 == none,
  59.  
  60. ;-> current address
  61.     extrn    my_address: byte
  62.  
  63. received_ours    db    0
  64.     public    rcv_modes
  65. rcv_modes    dw    7        ;number of receive modes in our table.
  66.         dw    0               ;There is no mode zero
  67.         dw    0
  68.         dw    rcv_mode_2
  69.         dw    rcv_mode_3
  70.         dw    0
  71.         dw    0 ;        dw    rcv_mode_5        ; Multi-cast mode not available
  72.         dw    rcv_mode_6
  73.  
  74.     public bad_command_intercept
  75. bad_command_intercept:
  76. ;called with ah=command, unknown to the skeleton.
  77. ;exit with nc if okay, cy, dh=error if not.
  78.     mov    dh,BAD_COMMAND
  79.     stc
  80.     ret
  81.  
  82.     public    as_send_pkt
  83. ; The Asynchronous Transmit Packet routine.
  84. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  85. ;   interrupts possibly enabled.
  86. ; Exit with nc if ok, or else cy if error, dh set to error number.
  87. ;   es:di and interrupt enable flag preserved on exit.
  88. as_send_pkt:
  89.     ret
  90.  
  91.     public    drop_pkt
  92. ; Drop a packet from the queue.
  93. ; Enter with es:di -> iocb.
  94. drop_pkt:
  95.     assume    ds:nothing
  96.     ret
  97.  
  98.     public    xmit
  99. ; Process a transmit interrupt with the least possible latency to achieve
  100. ;   back-to-back packet transmissions.
  101. ; May only use ax and dx.
  102. xmit:
  103.     assume    ds:nothing
  104.     ret
  105.  
  106.  
  107. send_pkt_toobig:
  108.     mov    dh,NO_SPACE
  109.     stc
  110.     ret
  111.     public    send_pkt
  112. send_pkt:
  113. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  114. ;  (only if the high-performance bit is set in driver_function)
  115. ;enter with ds:si -> packet, cx = packet length.
  116. ;if we're a high-performance driver, es:di -> upcall.
  117. ;exit with nc if ok, or else cy if error, dh set to error number.
  118.     assume    ds:nothing
  119.     cmp        cx,GIANT            ; Is this packet too large?
  120.     ja        send_pkt_toobig
  121.  
  122.     cmp        cx, RUNT            ; Minimum length for Ether
  123.     jae        oklen
  124.     mov        cx, RUNT            ; Make sure size at least RUNT
  125. oklen:
  126. ; Get the next XT buffer address from the buff_ptr array
  127.     mov        ax, tx_buff_no        ; Get the next buffer # to use
  128.     mov        bx, ax                ; Make a copy
  129.     inc        ax                    ; Advance the buffer #
  130.     cmp        ax, TX_BUF_CNT        ; Advanced too far ?
  131.     jl        count_ok            ; No - the next count is ok
  132.     xor        ax, ax                ; Next count will be zero
  133. count_ok:
  134.     mov        tx_buff_no, ax        ; Store the updated buffer #
  135.     sal        bx, 1                ; Make bx a word count
  136.     mov        ax, buff_ptrs[bx]    ; Get the buffer address
  137.     push    ax                    ; Store for later
  138. ; Setup the TX frame at the appropriate point in the TX area
  139.     LOAD_BANK_PORT    BANK0, HOST_ADDRESS
  140.     outw
  141.     SET_BANK_PORT    BANK0, LOCAL_MEM_PORT
  142.     mov        ax, XMT_CMD            ; The command to be obeyed
  143.     outw
  144.     xor        ax, ax
  145.     outw                        ; Clear the status field
  146.     outw                        ; No chaining of frames
  147.     mov        ax, cx                ; Get the packet length
  148.     outw                        ; Write the length into the packet frame
  149.  
  150. ; Write the contents of the packet.
  151.     call    repouts                ; Packet length is in CX
  152.  
  153. ; Now check to see if the EXEC unit is ready for another XMIT command
  154.     SET_BANK_PORT    BANK0, STATUS_REG
  155.     mov        ax, 1
  156.     call    set_timeout
  157. wait_send:
  158.     in        al, dx                ; Get the exec unit status
  159.     test    al, EXEC_STATUS        ; Is the exec unit idle
  160.     je        wait_send_done        ; Yes - then we can proceed
  161.     call    do_timeout
  162.     jnz    wait_send
  163. send_problem:
  164.     pop        ax                    ; Clear from the stack the buffer start address
  165.     mov        dh, CANT_SEND        ; Indicate an error.
  166.     stc
  167.     ret
  168.  
  169. ; Need to load the transmit register and issue a new transmit command.
  170. ; Load Transmit Pointer Register.
  171. wait_send_done:
  172.     SET_BANK_PORT    BANK0, XMT_ADDR_REG
  173.     pop        ax                    ; Get back the buffer start address
  174.     outw
  175.  
  176. ;initiate the transmission.
  177.     SET_BANK_PORT    BANK0, COMMAND_REG
  178.     mov        ax, XMT_CMD
  179.     outw                            ; Send out the command
  180.     clc
  181.     ret
  182.  
  183.     public    set_address
  184. set_address:
  185. ;enter with ds:si -> Ethernet address, CX = length of address.
  186. ;exit with nc if okay, or cy, dh=error if any errors.
  187.     assume      ds:nothing
  188.     call    set_ether    
  189.     xor        dh, dh                    ; Clear error conditions
  190.     clc
  191.     ret
  192.  
  193.  
  194. rcv_mode_2:
  195.     mov        al, MATCH_ID
  196.     jmp    short set_rcv_mode
  197. rcv_mode_3:
  198.     mov        al, MATCH_BRDCAST
  199.     jmp    short set_rcv_mode
  200. rcv_mode_5:
  201.     mov        al, MATCH_MULTICAST
  202.     jmp    short set_rcv_mode
  203. rcv_mode_6:
  204.     mov        al, MATCH_ALL
  205. set_rcv_mode:
  206. ; Need to protect against interrupts but they are currently off
  207.     LOAD_BANK_PORT    BANK2, RECV_MODES_REG
  208.     out        dx, al
  209.     ; Need to write to RE3 for the REV_MODES_REG command to take affect
  210.     SET_BANK_PORT    BANK2, REG3
  211.     in        al, dx
  212.     out        dx, al
  213.     SET_BANK_PORT    BANK0, COMMAND_REG
  214. ; Interrupts could be reenabled here if they were disabled above
  215.     ret
  216.  
  217.     public    set_multicast_list
  218. set_multicast_list:
  219. ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
  220. ;  cx = number of bytes.
  221. ;return nc if we set all of them, or cy,dh=error if we didn't.
  222.     mov    dh,NO_MULTICAST
  223.     stc
  224.     ret
  225.  
  226.     public    terminate
  227. terminate:
  228.     call    reset_chip
  229.     ret
  230.  
  231. set_ether    PROC NEAR
  232. ; Set the Individual address registers with the Ethernet address
  233. ; pointed to by si
  234.     LOAD_BANK_PORT    BANK2, I_ADD_REG0
  235.     mov        cx, EADDR_LEN/2
  236. next_ind_add:
  237.     lodsw
  238.     outw
  239.     inc        dx                        ; Advance to the next address word
  240.     inc        dx
  241.     loop    next_ind_add
  242.     ret
  243. set_ether    ENDP
  244.  
  245.  
  246.     public    reset_chip
  247. reset_chip    PROC    NEAR
  248.     LOAD_BANK_PORT    BANK0, COMMAND_REG
  249.     mov        al, RESET_CMD
  250.     out        dx, al
  251.     call    wait_27ms             ; need to wait at least 200 micro seconds
  252.     ret
  253. reset_chip    ENDP
  254.  
  255.     public    wait_27ms
  256. wait_27ms:
  257.     mov    ax,1            ;only have to wait 4us.
  258. wait:
  259.     call    set_timeout
  260. wait_27ms_1:
  261.     call    do_timeout
  262.     jne    wait_27ms_1
  263.     ret
  264.  
  265.  
  266.     public    reset_interface
  267. reset_interface:
  268. ;reset the interface.
  269.     assume    ds:code
  270.     ret
  271.  
  272. ;called when we want to determine what to do with a received packet.
  273. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  274.     extrn    recv_find: near
  275.  
  276. ;called after we have copied the packet into the buffer.
  277. ;enter with ds:si ->the packet, cx = length of the packet.
  278.     extrn    recv_copy: near
  279.  
  280. ;call this routine to schedule a subroutine that gets run after the
  281. ;recv_isr.  This is done by stuffing routine's address in place
  282. ;of the recv_isr iret's address.  This routine should push the flags when it
  283. ;is entered, and should jump to recv_exiting_exit to leave.
  284. ;enter with ax = address of routine to run.
  285.     extrn    schedule_exiting: near
  286.  
  287. ;recv_exiting jumps here to exit, after pushing the flags.
  288.     extrn    recv_exiting_exit: near
  289.  
  290.     extrn    count_in_err: near
  291.     extrn    count_out_err: near
  292.     extrn    count_handles : near
  293.  
  294. ;this macro writes the given character to the given row and column on
  295. ;  an CGA.
  296. to_scrn    macro    r, c, ch
  297.     local    black,done
  298.   if 0
  299.     push    bx
  300.     push    es
  301.     mov    bx,0b800h
  302.     mov    es,bx
  303.     mov    bx,es:[r*160+c*2]
  304.     test    bh,1
  305.     jne    black
  306.     mov    bh,07h
  307.     jmp    short done
  308. black:
  309.     mov    bh,70h
  310. done:
  311.     mov    bl,ch
  312.     mov    es:[r*160+c*2],bx
  313.     pop    es
  314.     pop    bx
  315.   endif
  316.     endm
  317.  
  318.     public    recv
  319. recv:
  320. ;called from the recv isr.  All registers have been saved, and ds=cs.
  321. ;Upon exit, the interrupt will be acknowledged.
  322.     assume    ds:code
  323.     to_scrn    23,74,'R'
  324.  
  325.     LOAD_BANK_PORT    BANK0, INT_MASK_REG
  326.     mov        al, ALL_MASK    ; Turn off the RC interrupt
  327.     out        dx, al
  328.     SET_BANK_PORT    BANK0, STATUS_REG
  329.     in        al, dx            ; Get status of what interrupted
  330.     test    al, RX_INT        ; Did we get a packet?
  331.     jne        recv_1            ; Yes
  332.     jmp        recv_exit
  333. recv_1:
  334.     mov        al, RX_INT                ; Acknowledge (and hence clear) the
  335.     out        dx, al                    ; RX interrupt
  336.     SET_BANK_PORT    BANK0, HOST_ADDRESS
  337.     mov        ax, rx_buff_ptr
  338.     outw
  339.     SET_BANK_PORT    BANK0, LOCAL_MEM_PORT
  340.  
  341. next_packet:
  342.     mov        cx, RCV_HDR_SIZE        ;read the header in.
  343.     mov        ax, cs
  344.     mov        es, ax
  345.     mov        di, offset rcv_hdr
  346.     call    repins
  347.     cmp        WORD PTR rcv_hdr[RBUF_CMD], RCV_DONE    ; End of chain ?
  348.     je        not_chain_end                ; No - deal with it
  349. found_zero:
  350.     jmp        recv_exit                    ; Yes - jne is too far
  351.  
  352. not_chain_end:
  353.     mov        ax,  WORD PTR rcv_hdr[RBUF_NEXT_LOW]
  354.     mov        next_rx_ptr, ax            ; Remember where the next one is.
  355.  
  356. ; Did we receive our own broadcast?
  357.     mov        di, offset rcv_hdr+RBUF_HEAD_LEN+EADDR_LEN
  358.     mov        si, offset my_address
  359.     mov        cx, EADDR_LEN/2
  360.     repe    cmpsw
  361.     jne        not_our_own        ; Jump if not
  362.     to_scrn    23,79,'O'
  363.     inc        received_ours        ;remember that we received it.
  364.     jmp        recv_update
  365.  
  366. not_our_own:
  367.     mov        ax,  WORD PTR rcv_hdr[RBUF_STAT_LOW]
  368.     and        ax, RX_OK or RX_ERROR    ;  check for errors.
  369.     cmp        ax, RX_OK
  370.     je        recv_noerrs
  371.     call    count_in_err
  372.     to_scrn    23,72,'E'
  373.     jmp        recv_update
  374.  
  375. recv_noerrs:
  376. ; Check against the 82595 truncating a packet with a too small type/size
  377.     mov        cx, WORD PTR rcv_hdr[RBUF_SIZE_LOW]    ; Get the size of the frame
  378.     cmp        cx, RCV_HDR_SIZE-RBUF_HEAD_LEN        ; Should be at least this size
  379.     jl        recv_update                ; Too small - discard with no error
  380. length_ok:
  381.     push    cx
  382.     mov        ax, cs            ; Set ds = code
  383.     mov        ds, ax
  384.     mov        es, ax
  385.     assume    ds:code
  386.     mov        di, offset rcv_hdr+RBUF_HEAD_LEN+EADDR_LEN+EADDR_LEN
  387.     push    dx                    ; Need to save the port address
  388.     mov        dl, BLUEBOOK        ;assume bluebook Ethernet.
  389.     mov        ax, es:[di]            ; Get the packet type
  390.     xchg    ah, al
  391.     cmp     ax, 1500
  392.     ja        BlueBookPacket
  393.     inc        di            ;set di to 802.2 header
  394.     inc        di
  395.     mov        dl, IEEE8023
  396. BlueBookPacket:
  397.     call    recv_find        ; See if type and size are wanted
  398.     pop        dx                ; Get back the port address
  399.     pop        cx
  400.     mov        ax, es            ; Did recv_find give us a null pointer?
  401.     or        ax, di            ; ..
  402.     je        recv_update_discard    ; If null, don't copy the data
  403.  
  404.     push    cx            ; We will want the count and pointer
  405.     push    es            ;  to hand to client after copying,
  406.     push    di            ;  so save them at this point
  407.  
  408.     push    cx            ; move the receive header in.
  409.     mov        si, offset rcv_hdr + RBUF_HEAD_LEN
  410.     mov        cx, (RCV_HDR_SIZE - RBUF_HEAD_LEN)/2
  411.     rep    movsw            ;move rest of packet
  412.     pop    cx
  413.                         ;subtract off what we've already copied.
  414.     sub        cx, RCV_HDR_SIZE - RBUF_HEAD_LEN
  415.     call    repins        ; read the rest of the packet in.
  416.  
  417.     pop        si            ; Recover pointer to destination
  418.     pop        ds            ; Tell client it's his source
  419.     pop        cx            ; And it's this long
  420.     assume    ds:nothing
  421.     call    recv_copy    ; Give it to him
  422.     mov     ax, cs
  423.     mov     ds, ax
  424.     assume  ds: code
  425.     jmp        short recv_update
  426. recv_update_discard:
  427.     to_scrn    23,73,'D'
  428. recv_update:
  429.     mov        ax, next_rx_ptr
  430.     mov        rx_buff_ptr, ax
  431. ; Need to reload the host address register as the host address will not always
  432. ; be pointing to the next frame.  Need a LOAD_PORT as DX could have been
  433. ; modified by the recv_copy routine however the bank is still OK.
  434.     LOAD_PORT    HOST_ADDRESS
  435.     outw
  436. ; Stop register updated to 1 less than the first free location
  437.     or        ax, ax
  438.     jne        no_wrap
  439.     mov        ax, RX_AREA_END + 1
  440. no_wrap:
  441.     dec        ax 
  442.     SET_BANK_PORT    BANK0, RCV_STOP_LOW
  443.     outw
  444.     SET_BANK_PORT    BANK0, LOCAL_MEM_PORT
  445.  
  446.     to_scrn    23,75,'A'
  447.     jmp        next_packet                        ; Go back and get more packets.
  448.  
  449. recv_exit:
  450.     LOAD_BANK_PORT    BANK0, INT_MASK_REG
  451.     mov        al, ALL_MASK AND NOT RX_MASK    ; Reenble the RX interrupt
  452.     out        dx, al
  453.     to_scrn    23,74,' '
  454.     ret
  455.  
  456.     include    timeout.asm
  457.  
  458.     public    timer_isr
  459. timer_isr:
  460. ;if the first instruction is an iret, then the timer is not hooked
  461.     iret
  462.  
  463. ;any code after this will not be kept after initialization. Buffers
  464. ;used by the program, if any, are allocated from the memory between
  465. ;end_resident and end_free_mem.
  466.     public end_resident,end_free_mem
  467. end_resident    label    byte
  468. end_free_mem    label    byte
  469.  
  470.  
  471.     public    usage_msg
  472.     usage_msg    db    "usage: lan595 [options] <packet_int_no> <hardware_irq> <io_addr>",CR,LF,'$'
  473.  
  474.     public    copyright_msg
  475.     copyright_msg    db    "Packet driver for the Intel LAN 595, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  476.  
  477.         db    "Portions written by Morien W. Roberts",CR,LF,'$'
  478.  
  479. this_board_msg    db    "This board is an ",'$'
  480. memory_bad_msg    db    "Ethernet buffer memory bad",CR,LF,'$'
  481. testing_mem_msg    db    CR,LF,"Testing memory .",'$'
  482.  
  483. tp_msg    db "Using twisted pair cable",CR,LF,'$'
  484. bnc_msg    db    "Using coax cable",CR,LF,'$'
  485. byte_msg    db "Performing 8 bit I/O transfers",CR,LF,'$'
  486. word_msg    db "Performing 16 bit I/O transfers",CR,LF,'$'
  487.  
  488. int_bad_msg    db    "That interrupt number is not supported.",CR,LF
  489.         db    "The LAN 595 EEPROM is currently configured to use IRQs "
  490. dummy_msg    db '$'
  491. int_no_name    db    "Interrupt number ",'$'
  492. io_addr_name    db    "I/O port ",'$'
  493. specified_failed     db  "An 82595 Ethernet adapter was not found at specified address.",CR,LF,'$'
  494. scan_failed db  "Scan of I/O space did not find an 82595 Ethernet adapter.",CR,LF,'$'
  495. found_two    db    "Found two 82595 Ethernet controller cards.",CR,LF,'$'
  496. board_name    db      02h, "Intel LAN 595  ",0,48
  497. irq_map        dw    ?    ; Read from the eeprom - holds mapping of the 5 82595 IRQs
  498. no_prom        db    0    ; <> 0 if ethernet address specified on the command line
  499.  
  500.     extrn    set_recv_isr: near
  501.  
  502. ;enter with si -> argument string, di -> wword to store.
  503. ;if there is no number, don't change the number.
  504.     extrn    get_number: near
  505.  
  506. ;enter with dx -> argument string, di -> wword to print.
  507.     extrn    print_number: near
  508.  
  509. ;-> the Ethernet address of the card.
  510.     extrn    rom_address: byte
  511.  
  512. ;print the character in al.
  513.     extrn    chrout: near
  514.  
  515. ;print a crlf
  516.     extrn    crlf: near
  517.  
  518. ;enter with si -> argument string.
  519. ;skip spaces and tabs.  Exit with si -> first non-blank char.
  520.     extrn    skip_blanks: near
  521.  
  522.     public    parse_args
  523. parse_args:
  524. ;exit with nc if all went well, cy otherwise.
  525.     mov    di,offset int_no
  526.     call    get_number
  527.     mov    di,offset io_addr
  528.     call    get_number
  529.     call    skip_blanks
  530.     cmp    al,CR            ;does an Ethernet address follow?
  531.     je    parse_args_1        ;no.
  532.     inc    no_prom            ;we don't have an Ethernet PROM.
  533. ;enter with ds:si -> Ethernet address to parse, es:di -> place to put it.
  534.     movseg    es,ds
  535.     mov    di,offset rom_address
  536.     call    get_eaddr
  537. parse_args_1:
  538.     clc
  539.     ret
  540.  
  541.     public    etopen
  542. etopen:
  543. ;Initialize the driver.
  544. ;Fill in rom_address with the assigned address of the board.
  545.     assume    ds:code
  546.     call    etopen_82595
  547.     jnc        etopen_ok
  548.     ret
  549. ; First check to see if this interrupt is available for the board
  550. etopen_ok:
  551.     mov        cl, int_no
  552.     cmp        cl, 09h                ; Need to change an IRQ9 back to an IRQ2
  553.     jne        not_irq9
  554.     mov        cl, 02h
  555. not_irq9:
  556.     mov        bl, cl                ; Make a copy of the interrupt no
  557.     mov        ax, 0001h    
  558.     shl        ax, cl
  559.     test    irq_map, ax            ; If bit is set then this IRQ is OK
  560.     jne        int_no_ok            ; Yes this interrupt is OK
  561.  
  562. ; This code simply goes through the irq_map an informs which interrupts are
  563. ; available.  The irq_map was obtained form the eeprom and should always have
  564. ; 5 bits set. The interrupt list is generated one by one and separated by
  565. ; commas except the last two interrupts which are separted with an '&'.
  566.     mov     dx, offset int_bad_msg
  567.     mov        ah, 9
  568.     int        21h
  569.     mov        ax, 0001h
  570.     mov        cx, 10h
  571.     xor        dx, dx
  572.     mov        si, dx
  573. check_next:
  574.     test    irq_map, ax
  575.     je        not_available
  576.     inc        si
  577.     push    ax
  578.     push    cx
  579.     mov        ax, 10h
  580.     sub        ax, cx
  581. ;    cmp        al, 02h                    ; Need to display an IRQ2 as an IRQ9
  582. ;    jne        irq_no_ok
  583. ;    test    sys_features,TWO_8259    ; 2nd 8259 ?
  584. ;    je        irq_no_ok                ; No, no mapping needed
  585. ;    add        al, 07h
  586. ;irq_no_ok:
  587.     push    si
  588.     call    decout
  589.     pop        si
  590.     cmp        si, 0004h
  591.     jg        no_output
  592.     je        output_&
  593.     mov        al, ','
  594.     jmp        output_it
  595. output_&:
  596.     mov        al, ' '
  597.     call    chrout
  598.     mov        al, '&'
  599. output_it:
  600.     call    chrout
  601.     mov        al, ' '
  602.     call    chrout
  603. no_output:
  604.     pop        cx
  605.     pop        ax
  606. not_available:
  607.     shl        ax, 1
  608.     loop    check_next
  609.     call    crlf
  610.     mov     dx, offset dummy_msg    ; No more message to print
  611.     stc
  612.     ret
  613.  
  614. int_no_ok:
  615. ; Need to find which LAN 595 interrupt this is
  616.     xor        dl, dl
  617.     mov        cl, bl            ; Get back the copy of the int_no
  618.     jcxz    found_it
  619.     mov        ax, irq_map
  620. next_irq_map_bit:
  621.     sar        ax, 1
  622.     jnc        not_set
  623.     inc        dl
  624. not_set:
  625.     loop    next_irq_map_bit
  626. found_it:
  627.     mov        lan_595_int, dl
  628.  
  629.     mov        si, offset board_name+1        ; skip the board revison number
  630.     mov        dx, offset this_board_msg
  631.     mov        ah, 9
  632.     int        21h
  633.  
  634.     movseg    es,ds            ;copy the driver name to where we need it.
  635.     mov        di, offset driver_name
  636.  
  637. check_board_copy:
  638.     lodsb
  639.     stosb
  640.     or        al, al
  641.     je        check_board_done_print
  642.     call    chrout            ;print the character.
  643.     jmp    check_board_copy
  644. check_board_done_print:
  645.     lodsb                ;copy the driver type number over
  646.     mov        driver_type, al
  647.     mov        dx, offset testing_mem_msg
  648.     mov        ah, 9
  649.     int        21h
  650.  
  651. adapter_verify:
  652.     mov        al, '.'
  653.     call    chrout
  654.     mov        bx, 0aa55h        ;aa55
  655.     xor        si, si
  656.     call    test_memory
  657.     jc        adapter_verify_bad
  658.  
  659.     mov        al, '.'
  660.     call    chrout
  661.     mov        bx, 055aah        ;55aa
  662.     xor        si, si
  663.     call    test_memory
  664.     jc        adapter_verify_bad
  665.  
  666.     mov        al, '.'
  667.     call    chrout
  668.     mov        bx, 0            ;incrementing
  669.     mov        si, 1
  670.     call    test_memory
  671.     jc        adapter_verify_bad
  672.     jmp        short adapter_ok
  673.  
  674. adapter_verify_bad:
  675.     mov        dx, offset memory_bad_msg
  676.     stc
  677.     ret
  678.  
  679. adapter_ok:
  680.     call    crlf
  681.     mov    al, int_no        ; Get board's interrupt vector
  682.     add    al, 8
  683.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  684.     jb    set_int_num        ; No.
  685.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  686. set_int_num:
  687.     xor    ah, ah            ; Clear high byte
  688.     mov    int_num, ax        ; Set parameter_list int num.
  689.  
  690.     movseg    es,ds
  691.     mov    si,offset rom_address
  692.     mov    di,offset my_address
  693.     repmov    EADDR_LEN
  694.  
  695.     call    set_recv_isr
  696.     call    set_RX_TX_areas
  697.     clc
  698.     ret
  699.     
  700.     
  701.     public    set_RX_TX_areas
  702. ; Sets up all the RX and TX buffers variables as well as setting the buffer
  703. ; registers in the 82595 chip.  
  704. ; Enables the 82595 interrupt and masks all but the RX interrupt.
  705. ; Issues a selective rest command and then a receive enable command.
  706. ; Code works on one bank at a time to minimize bank swapping.
  707.  
  708. set_RX_TX_areas    PROC    NEAR
  709. ; Allow interrupts to occur - the 82595 interrupt mask will be cleared later
  710.     LOAD_BANK_PORT    BANK1, INT_NO_REG
  711.     mov        al, lan_595_int
  712.     out        dx, al
  713.  
  714. ; Partion the 82595 RAM into a RX area and TX area with the RX area first.
  715. ; Partition the RAM (RAM_SIZE = 32k) to have a RX_AREA_SIZE receive buffer and a
  716. ; 32k - RX_AREA_SIZE transmit buffer
  717.     SET_BANK_PORT    BANK1, REC_LOW_LIMIT_REG
  718.     mov        al, RX_AREA_BEG
  719.     out        dx, al
  720.     SET_BANK_PORT    BANK1, REC_UPPER_LIMIT_REG
  721.     mov        al, RX_AREA_END / 256
  722.     out        dx, al
  723.     SET_BANK_PORT    BANK1, XMT_LOW_LIMIT_REG
  724.     mov        al, TX_AREA_BEG / 256 
  725.     out        dx, al
  726.     SET_BANK_PORT    BANK1, XMT_UPPER_LIMIT_REG
  727.     mov        al, (RAM_SIZE / 256) -1
  728.     out        dx, al
  729.     SET_BANK_PORT    BANK1, REG1
  730.     in        al, dx
  731.     or        al, INT_ENABLE
  732.     out        dx, al
  733.  
  734. ; Allow only RX events to interrupt
  735.     SET_BANK_PORT    BANK0, INT_MASK_REG
  736.     mov        al, ALL_MASK AND NOT RX_MASK ; Enable only RX interrupts
  737.     out        dx, al
  738.  
  739. ; Perform the RCV initialization
  740.     SET_BANK_PORT    BANK0, BAR_LOW    ; Specify start of the receive area
  741.     mov        ax, RX_AREA_BEG
  742.     outw
  743.     mov        rx_buff_ptr, ax        ; Initialize the receive buffer pointer
  744.     SET_BANK_PORT    BANK0, RCV_STOP_LOW    ; Specify end of receive area
  745.     mov        ax, RX_AREA_END
  746.     outw
  747.  
  748. ; Perform the TX initialization - no chip registers to set, only buffers
  749. ; Set up the various TX buffers, each one will have the maximum size
  750.     mov        ax, cs                ; Need to set es to cs
  751.     mov        es, ax
  752.     mov        di, offset buff_ptrs    ; Start of buffer pointer array
  753.     mov        cx, TX_BUF_CNT        ; Number of buffers
  754.     mov        ax, TX_AREA_BEG        ; Start of the first buffer
  755. buff_set:
  756.     stosw                        ; Store the address of the buffer
  757.     add        ax,    TX_FRAME_SIZE    ; Add the max buffer size
  758.     loop    buff_set
  759.     mov        tx_buff_no, 0        ; The next TX buffer to use
  760.  
  761. ; Issue a selective reset command
  762.     SET_BANK_PORT    BANK0, COMMAND_REG
  763.     mov        al, SEL_RESET
  764.     out        dx, al
  765.     call    wait_27ms
  766.  
  767. ; Issue a RCV_ENABLE command
  768.     SET_BANK_PORT    BANK0, COMMAND_REG
  769.     mov        al, RCV_ENABLE
  770.     out        dx, al 
  771.     ret
  772. set_RX_TX_areas    ENDP
  773.  
  774.     public    print_parameters
  775. print_parameters:
  776. ;echo our command-line parameters
  777.     mov    di,offset int_no
  778.     mov    dx,offset int_no_name
  779.     call    print_number
  780.     mov    di,offset io_addr
  781.     mov    dx,offset io_addr_name
  782.     call    print_number
  783.     ret
  784.  
  785. test_memory:
  786. ; Enter with bx = pattern to write, si = increment for pattern.
  787. ; Set Host address to start of memory
  788.     LOAD_BANK_PORT    BANK0, HOST_ADDRESS
  789.     xor        ax, ax
  790.     outw
  791.     SET_BANK_PORT    BANK0, LOCAL_MEM_PORT
  792.     mov        ax, bx            ;get the pattern word
  793.     mov        cx, RAM_SIZE/2        ;number of words to write
  794. test_memory_write:
  795.     outw                    ;write our pattern.
  796.     add        ax, si            ;increment the pattern.
  797.     loop    test_memory_write
  798.     
  799.     mov        al, '.'
  800.     call    chrout
  801.     
  802.     SET_BANK_PORT    BANK0, HOST_ADDRESS
  803.     xor    ax,ax            ;start at zero again.
  804.     outw
  805.     SET_BANK_PORT    BANK0, LOCAL_MEM_PORT
  806.  
  807.     mov        cx,    RAM_SIZE/2        ;number of words to read
  808. test_memory_read:
  809.     inw
  810.     cmp        ax, bx            ;does it compare correctly?
  811.     jne        test_memory_fail    ;no, quit.
  812.     add        bx, si            ;increment the pattern.
  813.     loop    test_memory_read    ; Otherwise, continue
  814.     clc
  815.     ret
  816.  
  817. test_memory_fail:
  818.     stc
  819.     ret
  820.  
  821. etopen_82595    PROC    NEAR
  822.     call    find_base                ; Go and find the chip
  823.     jc        exit_etopen_82595
  824.     call    reset_chip
  825.     call    get_ethernet_address    ; Fetch ethernet address if necessary
  826.     call    get_IRQ_map                ; Fetch the IRQ map from teh eeprom
  827.     call    config_chip                ; Configure chip
  828.     clc                                ; No errors to report at this point
  829. exit_etopen_82595:
  830.     ret
  831. etopen_82595    ENDP
  832.  
  833. config_chip    PROC    NEAR
  834. ; Set the correct transfer routines
  835.     LOAD_BANK_PORT    BANK1, REG1
  836.     in        al, dx                ; Get current value (8 bits)
  837.     test    al, WORD_WIDTH        ; Is chip configured for word transfers
  838.     je        eight_bit            ; No then do 8 bit transfers
  839.  
  840.                                 ; Setup the 16 bit routines
  841.     mov        dx, offset word_msg    ; Using word transfers message
  842.     mov        inw_routine, offset inw_16
  843.     mov        outw_routine, offset outw_16
  844.  
  845.     cmp        is_186,0            ; Can we use fast routines ?
  846.     je        slow_16_bit            ; No - have to do use the slower routines
  847.     mov        repins, offset quick_rep_ins_16
  848.     mov        repouts, offset quick_rep_outw_16
  849.     jmp        routines_are_set
  850. slow_16_bit:
  851.     mov        repins, offset rep_ins_16
  852.     mov        repouts, offset rep_outw_16
  853.     jmp        routines_are_set
  854.  
  855. eight_bit:                        ; Setup the 8 bit routines
  856.     mov        dx, offset byte_msg    ; Using byte transfers message
  857.     mov        inw_routine, offset inw_2_8
  858.     mov        outw_routine, offset outw_2_8
  859.     cmp        is_186,0            ; Can we use fast routines ?
  860.     je        slow_8_bit            ; No - have to do use the slower routines
  861.     mov        repins, offset quick_rep_ins_2_8
  862.     mov        repouts, offset quick_rep_outw_2_8
  863.     jmp        routines_are_set
  864. slow_8_bit:
  865.     mov        repins, offset rep_ins_2_8
  866.     mov        repouts, offset rep_outw_2_8
  867. routines_are_set:
  868.     mov        ah, 09h                ; Announce which routines we are using
  869.     int        21h
  870. ; DX has been corrupted
  871.     LOAD_BANK_PORT    BANK1, REC_LOW_LIMIT_REG
  872.  
  873. ; Partition the RAM to have a 32k receive buffer and a 32 transmitter buffer
  874. ; As there is actually only 32k of RAM available the receive buffer has it all
  875. ; so that during the memory test there will be undesirable autmated wrap-around
  876. ; of the host address register.
  877.     SET_BANK_PORT    BANK1, REC_LOW_LIMIT_REG
  878.     mov        al, 0
  879.     out        dx,al
  880.     SET_BANK_PORT    BANK1, REC_UPPER_LIMIT_REG
  881.     mov        al, (RAM_SIZE / 256) -1
  882.     out        dx,al
  883.     SET_BANK_PORT    BANK1, XMT_LOW_LIMIT_REG
  884.     mov        al, (RAM_SIZE / 256) 
  885.     out        dx,al
  886.     SET_BANK_PORT    BANK1, XMT_UPPER_LIMIT_REG
  887.     mov        al, 2*(RAM_SIZE / 256) - 1
  888.     out        dx,al
  889.  
  890. ; Set the Individual address registers with the Ethernet address
  891.     mov        si, offset rom_address
  892.     call    set_ether
  893.     LOAD_BANK_PORT    BANK2, RECV_MODES_REG    ; Set default receive modes
  894.     mov        al, MATCH_BRDCAST
  895.     out        dx, al
  896.  
  897. ; Delay for the hardware to work out if the TP cable is present - 150ms
  898.     mov    ax,18            ;wait a half a second.
  899.     call    wait
  900.  
  901.     SET_BANK_PORT    BANK2, REG3
  902.     in        al, dx                    ; Get current value
  903.     and        al, TEST_MODE_MASK         ; Clear the test modes bits
  904.     out        dx, al
  905. ; Determine what connector type has been selected
  906.     mov        dx, offset tp_msg
  907.     test    al, TPE_BIT            ; Using a twisted pair ?
  908.     jne        using_tp
  909.     mov        dx, offset bnc_msg
  910. using_tp:
  911.     mov        ah, 09h
  912.     int        21h
  913.  
  914.     LOAD_BANK_PORT    BANK0, COMMAND_REG         ; Issue a selective reset command
  915.     mov        al, SEL_RESET
  916.     out        dx, al
  917.     call    wait_27ms
  918.     ret
  919. config_chip    ENDP
  920.  
  921.     public    find_base
  922. find_base    PROC    NEAR
  923.     mov        bh, R_ROBIN_BITS    ; The mask bits for the round robin counter
  924.     cmp        io_addr, 0h            ; Has a base address been specified
  925.     jz        full_scan            ; No - start scan from the begining
  926.     mov        dx, io_addr            ; Start scan from specified address
  927.     add        dx, ID_REG
  928.     mov        di, dx                ; DI holds last I/O address to examine
  929.     jmp        f_b_cont
  930. full_scan:
  931.     mov        dx, FIRST_IO        ; First I/O Address to examine
  932.     mov        di, LAST_IO            ; DI holds last I/O address to examine
  933. f_b_cont:
  934.     in        al, dx
  935.     mov        bl, al                ; Keep a copy
  936.     and        al, ID_REG_MASK        ; Mask off bits not required
  937.     cmp        al, ID_REG_SIG      ; Do we have the signature
  938.     jz        check_sig            ; Looks promising go and check it
  939. f_b_cont1:
  940.     add        dx, 10h                ; Advance the I/O address
  941.     cmp        dx, di                ; Have we checked them all ?
  942.     jl        f_b_cont            ; No - then continue
  943.     cmp        base_addr, 0h        ; Did we find a controller ?
  944.     jz        f_b_failed            ; No - then go and complain
  945.     mov        ax, base_addr        ; Yes - then copy it over
  946.     mov        io_addr, ax
  947.     ret
  948. f_b_failed:
  949.     cmp        io_addr, 0h            ; Has a base address been specified
  950.     jz        f_b_failed1            ; No - then the scan failed
  951.     mov        dx, offset specified_failed
  952.     jmp        f_b_failed2
  953. f_b_failed1:
  954.     mov        dx, offset scan_failed    ; Message to announce later
  955. f_b_failed2:
  956.     stc                            ; Set carry and return
  957.     ret
  958.  
  959. check_sig:
  960.     ; Routine to check the round robin counter at the ID register
  961.     ; FIrst task is to sync the counter bits to 0
  962.     and        bl, bh                ; Get only the round_robin counter bits
  963.     rol        bl, 1                ; Bits are required in B1 and B0 of BL
  964.     rol        bl, 1
  965.     mov        cx, 03h                ; Get into cl the number of INs that are
  966.     sub        cl, bl                ;   to sync the round robin counter
  967.     jcxz    sync_ok                ; Jump if already synchronized
  968. cont_sync:
  969.     in        al, dx                ; Read from the ID Register
  970.     loop    cont_sync
  971. ; Now it is synchronized the count can be checked.
  972. ; A loop would be more compact but this code is faster and will not be kept by
  973. ; the TSR.
  974. sync_ok:
  975.     in        al, dx                ; Get the next value of the ID Register
  976.     and        al, bh                ; Leave only the round_robin counter bits in al
  977.     cmp        al, 00h                ; Check if it is the expected count
  978.     jnz     f_b_cont1            ; No - move on to consider the next IO port
  979.     in        al, dx                ; Get the next value of the ID Register
  980.     and        al, bh                ; Leave only the round_robin counter bits in al
  981.     cmp        al, 40h                ; Check if it is the expected count
  982.     jnz     f_b_cont1            ; No - move on to consider the next IO port
  983.     in        al, dx                ; Get the next value of the ID Register
  984.     and        al, bh                ; Leave only the round_robin counter bits in al
  985.     cmp        al, 80h                ; Check if it is the expected count
  986.     jnz     f_b_cont1            ; No -  move on to consider the next IO port
  987.     in        al, dx                ; Get the next value of the ID Register
  988.     and        al, bh                ; Leave only the round_robin counter bits in al
  989.     cmp        al, 0C0h            ; Check if it is the expected count
  990.     jnz     f_b_cont1            ; No -  move on to consider the next IO port
  991. ; Check that another 82595 has not been found
  992.     cmp        base_addr, 0h        ; Value should initially be zero
  993.     jz        first_found            ; Ok to proceed
  994.     mov        dx, offset found_two    ; Message to announce later
  995.     stc                            ; Set carry and return
  996.     ret
  997. first_found:
  998.     sub        dx, ID_REG            ; Get the read base
  999.     mov        base_addr, dx        ; Store the base address
  1000.     add        dx, ID_REG            ; Point back to the ID register
  1001.     jmp     f_b_cont1            ; Continue the scan of IO addresses
  1002. find_base    ENDP
  1003.  
  1004.  
  1005. get_eeprom_data PROC NEAR
  1006.     ; Called with :
  1007.     ; bx = starting offset address in the EEPROM
  1008.     ; cx = number of bytes to read
  1009.     ; di = buffer to place the data
  1010.     ; si is use for temporary storage
  1011.  
  1012.     LOAD_BANK_PORT    BANK2, EEPROM_REG    ; Set the eeprom port
  1013. get_next_eeprom_byte:
  1014.     mov        al, EECS                ; EEPROM chip select
  1015.     out        dx, al                    ; Enable the eeprom
  1016.  
  1017. ;get_next_eeprom_byte:
  1018.     push    cx                    ; Number of bytes left to read
  1019.     push    bx                    ; Address of next byte in eeprom
  1020.  
  1021. ; First select eeprom for reading
  1022. eeprom_ok:
  1023.     mov        al, EEDI OR EECS    ; Set a 1 in the data bit
  1024.     write_eeprom_bit            ; Write a 1
  1025.     write_eeprom_bit            ; Write a 1
  1026.     mov        al, EECS            ; Set a 0 in the data bit
  1027.     write_eeprom_bit            ; Write a 1
  1028.  
  1029.     pop        bx                    ; Next eeprom address bits
  1030.     inc        bx
  1031.     push    bx                    ; Store eeprom address bits
  1032.     dec        bx
  1033.  
  1034.     ror        bl,1                ; Align the address bits so that the MSB
  1035.     ror        bl,1                ; is at the EEDI position
  1036.     ror        bl,1
  1037.     mov        cx, 06h                ; Number of bits in each address is 6
  1038. next_add_bit:
  1039.     mov        bh, bl                ; Save a copy of the address bits
  1040.     and        bl, EEDI            ; Clear all bits except EEDI
  1041.     and        al, NOT EEDI        ; Clear the EDIT bit
  1042.     or        al, bl                ; EDDI bit in al is now set as required
  1043.     write_eeprom_bit            ; Write the address bit
  1044.     jz        eeprom_address_done    ;   no need to do all 6 bits
  1045.     mov        bl, bh                ; Retrive the address bits    
  1046.     rol        bl, 1                ; Rotate the address bits
  1047.     loop    next_add_bit        ; Write out all 6 bits
  1048.  
  1049. eeprom_address_done:            ; Now ready to read the EEPROM data
  1050.     xor        si, si                ; Byte will be assembled in si
  1051.     mov        cx, 10h                ; Number of bits to fetch
  1052. get_next_bit:
  1053.     read_eeprom_bit                ; Value of eeprom bit returned in bl
  1054.     and        bx, EEDO            ; Clear all but the eeprom data output bit
  1055.     or        si, bx                ; Add the bit to the assembled byte
  1056.     rol        si, 1                ; Advance byte ready for next bit
  1057.     loop    get_next_bit        ; Continue until all 16 bits have been read
  1058.  
  1059.     mov        cl, 4h                ; Final rotate for SI gets the word aligned
  1060.     ror        si, cl                ;    correctly
  1061.  
  1062.     mov        [di], si            ; Store the word
  1063.     add        di, 2                ; Advance the buffer pointer
  1064.  
  1065.     pop        bx                    ; Next EEPROM address to read from
  1066.     pop        cx                    ; Remaining bytes to read
  1067.     dec        cx                    ; Two bytes are read each time
  1068.     dec        cx                    ; So cx is decremented by two
  1069.     mov        al, 0                ; Disable the EEPROM
  1070.     out        dx, al                ; Perform the operation
  1071.     jcxz    no_more                ; If zero then we have finished
  1072.     jmp        get_next_eeprom_byte
  1073. no_more:
  1074.     mov        al, 0                ; Disable the EEPROM
  1075.     out        dx, al                ; Perform the operation
  1076.     SET_BANK_PORT    BANK0, COMMAND_REG    ; Setup the default bank
  1077.     ret
  1078. get_eeprom_data ENDP
  1079.  
  1080. get_ethernet_address    PROC    near
  1081.     cmp        no_prom, 0            ; User specified ethernet address
  1082.     jne        no_need                 ; Yes - no need to read the eeprom address
  1083.     mov        bx, 02h                ; Offset into eeprom for start of address
  1084.     mov        cx, EADDR_LEN        ; Number of bytes to read
  1085.     mov        di, offset    rom_address    ; Where to write the ethernet address
  1086.     call    get_eeprom_data        ; Get the ethernet address
  1087.     call    reverse_address        ; Need to reverse the address
  1088. no_need:
  1089.     ret
  1090. get_ethernet_address    ENDP
  1091.  
  1092. reverse_address    PROC    NEAR
  1093. ; Routine that reverses the ethernet address read from the eeprom.
  1094. ; Originally read in LSB to MSB, required in MSB to LSB order for rom_address
  1095.     mov        si, offset    rom_address    ; 
  1096.     mov        di, si                ; Will be written back to the same address
  1097.     mov        ax, ds                ; ES needs to be correct
  1098.     mov        es, ax
  1099.     mov        cx, EADDR_LEN / 2    ; Number of words to be reversed
  1100.     ; 1'st phase of reversing code pushes the words onto the stack
  1101. reverse_1:
  1102.     lodsw
  1103.     xchg    ah, al                ; Need to swap the bytes
  1104.     push    ax
  1105.     loop    reverse_1
  1106.     mov        cx, EADDR_LEN/2        ; Number of words to be reversed
  1107.     ; 2'nd phase of reversing code pops the words back from the stack
  1108. reverse_2:
  1109.     pop        ax
  1110.     stosw
  1111.     loop    reverse_2
  1112.     ret
  1113. reverse_address    ENDP
  1114.  
  1115.  
  1116. get_IRQ_map    PROC    near
  1117.     mov        bx, 07h                ; Offset into eeprom for start of map
  1118.     mov        cx, IRQ_MAP_LEN        ; Number of bytes to read
  1119.     mov        di, offset    irq_map    ; Where to write the ethernet address
  1120.     call    get_eeprom_data        ; Get the ethernet address
  1121.     ret
  1122. get_IRQ_map    ENDP
  1123.  
  1124.     extrn    get_hex: near
  1125.     include    getea.asm
  1126.  
  1127. code    ENDS
  1128.     END
  1129.