home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / drivrs30 / ni5210.asm < prev    next >
Assembly Source File  |  1989-06-08  |  22KB  |  831 lines

  1. version    equ    1
  2.  
  3.     include    defs.asm
  4.  
  5. ;Ported from Tim Krauskopf's micnet.asm, an assembly language
  6. ;driver for the MICOM-Interlan NI5210, by Russell Nelson.  Any bugs
  7. ;are due to Russell Nelson.
  8. ;Updated to version 1.08 Feb. 17, 1989 by Russell Nelson.
  9. ;Updated to support 1500 byte MTU April 27, 1989 By Brad Clements.
  10.  
  11. ;  Copyright, 1988, 1989, Russell Nelson
  12.  
  13. ;   This program is free software; you can redistribute it and/or modify
  14. ;   it under the terms of the GNU General Public License as published by
  15. ;   the Free Software Foundation, version 1.
  16. ;
  17. ;   This program is distributed in the hope that it will be useful,
  18. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20. ;   GNU General Public License for more details.
  21. ;
  22. ;   You should have received a copy of the GNU General Public License
  23. ;   along with this program; if not, write to the Free Software
  24. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  25.  
  26. code    segment    byte public
  27.     assume    cs:code, ds:code
  28.  
  29. ;
  30. ;  Equates for controlling the MICOM board
  31. ;
  32. ;  I/O addresses, writing anything in AL trips these gates
  33. ;
  34. ;  First six addresses are the EPROM board Ether address (read)
  35. ;
  36. IORESET    EQU    0            ; reset the board
  37. IOCA    EQU    1            ; execute command which is in SCB
  38. IODIS    EQU    2            ; disable network connect
  39. IOENA    EQU    3            ; enable network
  40. IOINTON    EQU    4            ; enable interrupts
  41. IOINTOF    EQU    5            ; disable interrupts, '586 thinks it still ints
  42. ;
  43. ;  Structure elements specific to the Intel 82586 chip
  44. ;
  45. BUF_COUNT EQU    28            ; number of buffers
  46. XMIT_MTU EQU    1500+14            ; size of xmit buffer (1500 MTU +
  47.                     ;   14 bytes for Ethernet headers
  48.  
  49. B    EQU    0            ; base offset for the board.
  50. SCB    EQU    B + 10            ; system control block base
  51. CCBPTR    EQU    B + 26            ; offset of configure command block
  52. TCBPTR    EQU    B + 44            ; xmit CB offset
  53. TBDPTR    EQU    B + 60            ; xmit BD offset
  54. TBUFPTR    EQU    B + 68            ; xmit buffer offset
  55. FDBASE    EQU    TBUFPTR+XMIT_MTU    ; base addr for 30 frame descriptors
  56. FDSIZE  EQU     BUF_COUNT * 22
  57. BDBASE    EQU    FDBASE+FDSIZE        ; base address for 30 buffer descriptors
  58. BDASIZE    EQU     BUF_COUNT * 10
  59. BUFBASE    EQU    BDBASE+BDASIZE        ; base address for 30 200 byte buffers
  60. BUFFTOP EQU     BUFBASE+BUF_COUNT*200
  61. ISCPTR    EQU    B + 03feeh        ; my address for ISCP, points to SCB
  62. SCPTR    EQU    B + 03ff6h        ; hardwired address for SCP
  63.  
  64. if2
  65.         %out Buffer top is BUFFTOP
  66. if BUFFTOP > ISCPTR
  67.         %out Warning, buffers extend beyond ISCPTR, reduce BUF_COUNT.
  68. endif
  69. endif
  70. BDSTAT    EQU    0            ; status word in BD
  71. BDLINK    EQU    2            ; 16pointer to next BD
  72. BDPTR    EQU    4            ; 24pointer to actual buffer
  73. BDSIZE    EQU    8            ; size of the buffer
  74. ;
  75. SSTAT    EQU    0            ; status word for SCB
  76. SCOM    EQU    2            ; command word in SCB
  77. SCBL    EQU    4            ; 16pointer to command block list
  78. SRFA    EQU    6            ; 16pointer to receive frame list
  79. SERRS    EQU    8            ; 4 words of error counts
  80. ;
  81. FDSTAT    EQU    0            ; status word for frame
  82. FDEOL    EQU    2            ; end of FD list flag
  83. FDLINK    EQU    4            ; 16pointer to next FD
  84. FDPTR    EQU    6            ; 16pointer to list of BD's
  85. ;
  86. TSTAT    EQU    0            ; status word for xmit
  87. TCOM    EQU    2            ; command to transmit
  88. TLINK    EQU    4            ; 16pointer to next command (always ffff)
  89. TPTR    EQU    6            ; 16pointer to xmit TBD
  90. TTRIES    EQU    8            ; number of transmit retries
  91. ;
  92. ;  Data segment
  93. ;
  94.  
  95.     public    int_no
  96. int_no        db    2,0,0,0        ; interrupt number. 
  97. io_addr        dw    0360h,0        ; I/O address for card (jumpers)
  98. base_addr    dw      0d000h,0    ; base segment for board (jumper set)
  99.  
  100.     public    driver_class, driver_type, driver_name
  101. driver_class    db    1        ;from the packet spec
  102. driver_type    db    11        ;from the packet spec
  103. driver_name    db    "NI5210",0    ;name of the driver.
  104.  
  105. firstfd        dw    FDBASE        ; start of FD queue
  106. lastfd        dw    0        ; end of the FD chain
  107. lastbd        dw    0        ; end of the BD chain
  108.  
  109.  
  110.     public    send_pkt
  111. send_pkt:
  112. ;enter with ds:si -> packet, cx = packet length.
  113. ;exit with nc if ok, or else cy if error, dh set to error number.
  114.     assume    ds:nothing
  115.     mov    ax,base_addr
  116.     mov    es,ax            ; base for board
  117.  
  118.     mov    word ptr es:[SCB+SCBL],TCBPTR; say where xmit command is
  119.  
  120.     cmp    cx,XMIT_MTU        ; Is this packet too large?
  121.     ja    send_pkt_toobig
  122.  
  123.     mov    dx,cx            ; save a copy, might be less than 60, ok
  124.  
  125.     cmp    dx,RUNT            ; minimum length for Ether
  126.     jnb    oklen
  127.     mov    dx,RUNT            ; make sure size at least RUNT
  128. oklen:
  129.     mov    di,TBUFPTR        ; start of xmit buffer
  130.  
  131. ;
  132. ;  check for previous xmit
  133. ;
  134. xwait:
  135.     mov    bx,word ptr es:[SCB+SCOM]    ; is command zeroed yet?
  136.     or    bx,bx
  137.     jnz    xwait                ; not there yet, wait for it
  138. ;
  139. ;  move the data using word moves.
  140. ;
  141.     call    movemem
  142. ;
  143. ;  put the correct size into the TDB
  144. ;
  145.     or    dx,08000h            ; end of frame bit flag
  146.     mov    word ptr es:[TBDPTR],dx        ; store it
  147.     mov    word ptr es:[TCBPTR],0        ; zero status wd
  148.     mov    word ptr es:[TCBPTR+TCOM],08004h; xmit command in TCB
  149.     mov    word ptr es:[SCB+SCOM],0100h    ; execute command
  150.  
  151.     call    doca
  152.  
  153.     clc
  154.     ret
  155. send_pkt_toobig:
  156.     mov    dh,NO_SPACE
  157.     stc
  158.     ret
  159.  
  160.  
  161. movemem:
  162. ;does the same thing as "rep movsb", only 50% faster.
  163. ;moves words instead of bytes, and handles the case of both addresses odd
  164. ;efficiently.  There is no way to handle one address odd efficiently.
  165. ;This routine always aligns the source address in the hopes that the
  166. ;destination address will also get aligned.  This is from Phil Karn's
  167. ;code from ec.c, a part of his NET package.  I bummed a few instructions
  168. ;out.
  169.     jcxz    movemem_cnte        ; If zero, we're done already.
  170.     test    si,1            ; Does source start on odd byte?
  171.     jz    movemem_adre        ; Go if not
  172.     movsb                ; Yes, move the first byte
  173.     dec    cx            ; Count that byte
  174. movemem_adre:
  175.     shr    cx,1            ; convert to word count
  176.     rep    movsw            ; Move the bulk as words
  177.     jnc    movemem_cnte        ; Go if the count was even
  178.     movsb                ; Move leftover last byte
  179. movemem_cnte:
  180.     ret
  181.  
  182.  
  183.     public    get_address
  184. get_address:
  185. ;get the address of the interface.
  186. ;enter with es:di -> place to get the address, cx = size of address buffer.
  187. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  188.     assume    ds:code
  189.     cmp    cx,EADDR_LEN        ;make sure that we have enough room.
  190.     jb    get_address_2
  191.     mov    cx,EADDR_LEN
  192.     mov    dx,io_addr        ; Get our IO base address.
  193.     cld
  194. get_address_1:
  195.     in    al,dx            ; get a byte of the eprom address
  196.     stosb                ; put it away
  197.     inc    dx            ; next register
  198.     loop    get_address_1        ; go back for rest
  199.     mov    cx,EADDR_LEN
  200.     clc
  201.     ret
  202. get_address_2:
  203.     stc
  204.     ret
  205.  
  206.  
  207.     public    reset_interface
  208. reset_interface:
  209. ;reset the interface.
  210. ;we don't do anything.
  211.     ret
  212.  
  213.  
  214. ;called when we want to determine what to do with a received packet.
  215. ;enter with cx = packet length, es:di -> packet type.
  216.     extrn    recv_find: near
  217.  
  218. ;called after we have copied the packet into the buffer.
  219. ;enter with ds:si ->the packet, cx = length of the packet.
  220.     extrn    recv_copy: near
  221.  
  222.     extrn    count_in_err: near
  223.     extrn    count_out_err: near
  224.  
  225.     public    recv
  226. recv:
  227. ;called from the recv isr.  All registers have been saved, and ds=cs.
  228. ;Upon exit, the interrupt will be acknowledged.
  229.     mov    ds,base_addr    ; base for board
  230.     assume    ds:nothing
  231.  
  232.     mov    ax,ds:[SCB+SSTAT]    ;get the status.
  233. recv_isr_1:
  234.     cmp    word ptr ds:[SCB+SCOM],0 ;are we done yet?
  235.     jne    recv_isr_1        ;no -- keep waiting.
  236.  
  237.     and    ax,0f000h        ;isolate the ACK bits.
  238.     mov    ds:[SCB+SCOM],ax    ;make a command to
  239.                     ;acknowledge the interrupt.
  240.     call    doca
  241. recv_isr_2:
  242.     cmp    word ptr ds:[SCB+SCOM],0 ;are we done yet?
  243.     jne    recv_isr_2        ;no -- keep waiting.
  244.  
  245. ;  Get whatever packets are on the board
  246. ;
  247.     mov    bx,firstfd    ; get addr of first FD in list
  248. ;
  249. ;
  250. ckframe:
  251.     mov    ax,[bx+FDSTAT]    ; status word of frame
  252.     test    ax,08000h    ; frame written?
  253.     jnz    okframe
  254.  
  255.     jmp    ru_start    ; no, restore receiver if necessary
  256. ptrupdate_j_1:
  257.     jmp    ptrupdate
  258. frame_bad_j_1:
  259.     call    count_in_err
  260.     jmp    frame_bad
  261.  
  262. ;  we have a frame, read it in
  263. ;
  264. okframe:
  265.  
  266.     test    ax,02000h        ;check frame OK bit
  267.     jz    frame_bad_j_1        ;bad, fix it.
  268.     mov    si,[bx+FDPTR]        ;get pointer to buffer descriptor
  269.     xor    cx,cx            ;start with zero bytes.
  270. countbuf:                ;es:di is already set to receive packet
  271.     mov    dx,si            ;save a copy of current BD ptr
  272.     mov    ax,[si+BDSTAT]        ;get status and count word for BD
  273.     test    ax,04000h        ;is count field there?
  274.     jz    ptrupdate_j_1        ;no - we give up here.
  275.     add    cl,al            ;add the count into cx.
  276.     adc    ch,0
  277.     mov    si,[si+BDLINK]        ;go to next BD in list
  278.     test    ax,8000h        ;is this the last frame?
  279.     je    countbuf        ;no - keep counting.
  280.  
  281.     push    bx
  282.     push    cx
  283.  
  284.     mov    ax,cs            ;we need ds = code.
  285.     mov    ds,ax
  286.     assume    ds:code
  287.  
  288.     mov    es,base_addr        ;get a pointer to their type.
  289.     mov    di,es:[bx+FDPTR]    ;get pointer to buffer descriptor
  290.     mov    di,es:[di+BDPTR]    ;get offset of data
  291.     add    di,EADDR_LEN+EADDR_LEN    ;skip the ethernet addreses and
  292.                     ;  point to the packet type.
  293.  
  294.     call    recv_find        ;look up our type.
  295.  
  296.     pop    cx
  297.     pop    bx
  298.     mov    ds,base_addr        ;restore ds to the board.
  299.     assume    ds:nothing
  300.  
  301.     mov    ax,es            ;is this pointer null?
  302.     or    ax,di
  303.     je    ptrupdate        ;yes - just free the frame.
  304.  
  305.     push    cx
  306.     push    es            ;remember where the buffer pointer is.
  307.     push    di
  308.  
  309.     mov    si,[bx+FDPTR]        ;get pointer to buffer descriptor
  310. copybuf:
  311.     mov    dx,si            ;save a copy of current BD ptr
  312.     xor    ch,ch            ;200 bytes is largest this can be
  313.     mov    cl,[si+BDSTAT]        ;get count word for BD
  314.     mov    si,[si+BDPTR]        ;get offset of data
  315.     call    movemem
  316.     mov    si,dx            ;get back current BD ptr
  317.     test    [si+BDSTAT],8000h    ;check EOF bit
  318.     mov    si,[si+BDLINK]        ;go to next BD in list
  319.     jz    copybuf            ;not done, keep copying it.
  320.  
  321.     pop    si            ;now give the frame to the client.
  322.     pop    ds
  323.     pop    cx
  324.     assume    ds:nothing
  325.  
  326.     call    recv_copy
  327.  
  328.     jmp    short ptrupdate
  329.  
  330. frame_bad:
  331. ;
  332. ;  we are done with the frame, do the list management
  333. ;
  334. ptrupdate:
  335.     push    cs
  336.     pop    ds
  337.     assume    ds:code
  338.     mov    es,base_addr        ; reload board segment
  339.  
  340.     mov    si,es:[bx+FDPTR]    ; first BD in frame list
  341. nextbd:
  342.     mov    cx,es:[si+BDSTAT]    ; count word for BD, EOF bit
  343.     test    cx,08000h        ; EOF bit, if set, save si in lastbd
  344.     jnz    dolastbd
  345.     mov    word ptr es:[si+BDSTAT],0 ; clear status word, EOF bit
  346.     cmp    si,lastbd        ; see if we are wrapping
  347.     jz    dolastbd        ; yes, just undo it
  348.     mov    si,es:[si+BDLINK]    ; follow link
  349.     jmp    nextbd
  350. dolastbd:
  351.     mov    di,lastbd        ; where end of BD list is now
  352.     mov    lastbd,si        ; store last known BD
  353.     mov    word ptr es:[si+BDSIZE],08000h+200    ; end of list here
  354.     mov    word ptr es:[si+BDSTAT],0 ; clear status word, EOF bit
  355. ; size field for not end of list
  356.     mov    word ptr es:[di+BDSIZE],200    ; remove old end-of-list
  357.  
  358. ;
  359. ;  update the FD list flags, new end-of-list
  360. ;
  361.     mov    word ptr es:[bx+FDEOL],08000h    ; store new EOL
  362.     mov    word ptr es:[bx+FDSTAT],0    ; clear status word for frame
  363.     mov    di,lastfd        ; get old end-of-list
  364.     mov    word ptr es:[di+FDEOL],0 ; zero old one
  365.     mov    lastfd,bx        ; update stored pointer
  366.     mov    si,es:[bx+FDLINK]    ; where next fd is
  367.     mov    firstfd,si        ; store that info for next time
  368.  
  369. ru_start:
  370. ; re-start receive unit
  371. ;
  372. ;  check to see if the receiver went off because of no resources
  373. ;  and restart receiver if necessary
  374. ;
  375.     push    cs
  376.     pop    ds
  377.     mov    es,base_addr
  378.     mov    ax,es:[SCB+SSTAT]    ; status word for SCB
  379.     and    ax,070h        ; receiver status
  380.     cmp    al,020h        ; receiver has no resources
  381.     jnz    hasres
  382.  
  383.     call    count_out_err
  384. ;
  385. ;  setup lists for starting the RU on the chip
  386. ;  we know that there isn't anything in the buffer that we want
  387. ;
  388.  
  389.     mov    bx,firstfd    ; get first FD on free list (assume free)
  390.     mov    word ptr es:[SCB+SRFA],bx    ; put into SCB
  391.     mov    si,lastbd    ; pointer to a BD, end of chain
  392.     mov    ax,word ptr es:[si+BDLINK]    ; pointer to next BD
  393.     mov    word ptr es:[bx+FDPTR],ax    ; set to start of BDs
  394. ;
  395. ;
  396. ;  Start the RU, doesn't need CB, only SCB parms.
  397. ;   command, to start receiving again
  398. ;
  399.     mov    word ptr es:[SCB+SSTAT],0    ; clear status word
  400.     mov    word ptr es:[SCB+SCOM],010h    ; start RU
  401.     call    doca
  402. hasres:
  403. recv_isr_end:
  404.     cmp    word ptr es:[SCB+SCOM],0 ;are we done yet?
  405.     jne    recv_isr_end        ;no -- keep waiting.
  406.     ret
  407.  
  408.  
  409.     public    set_address
  410. set_address:
  411.     assume    ds:nothing
  412. ;enter with ds:si -> Ethernet address, CX = length of address.
  413. ;exit with nc if okay, or cy, dh=error if any errors.
  414.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  415.     je    set_address_4
  416.     mov    dh,BAD_ADDRESS
  417.     stc
  418.     jmp    short set_address_done
  419. set_address_4:
  420.  
  421. ;  Next step, load our address into the board
  422. ;     reuses the space that the configure command used, with different command
  423. ;
  424.     mov    es,base_addr        ; set to base address
  425.     mov    word ptr es:[SCB+SCBL],CCBPTR    ; say where conf command is
  426.  
  427.     mov    di,CCBPTR        ; start of config command block
  428.     xor    ax,ax
  429.     stosw                ; zero status word for commmand
  430.     mov    ax,8001h        ; IA setup command + EL
  431.     stosw
  432.     xor    ax,ax
  433.     dec    ax
  434.     stosw                ; set link value to -1 (unused)
  435.  
  436.     rep    movsb            ; move their ethernet address in.
  437. ;
  438. ;  start the IA setup command
  439. ;
  440.     mov    word ptr es:[SCB+SCOM],0100h    ; do-command command
  441.     call    doca
  442.     xor    cx,cx            ; timeout
  443. set_address_1:
  444.     mov    ax,word ptr es:[CCBPTR]    ; get status word
  445.     test    ax,08000h        ; is command complete?
  446.     loopz    set_address_1
  447.     jnz    set_address_okay
  448.     stc
  449.     mov    dh,-1            ; no error in the list applies.
  450.     jmp    short set_address_done
  451. set_address_okay:
  452.     clc
  453. set_address_done:
  454.     push    cs
  455.     pop    ds
  456.     assume    ds:code
  457.     ret
  458.  
  459.  
  460. lbca:
  461. doca:
  462. ;we may be called from places in which ds is unknown.
  463.     assume    ds:nothing
  464.     loadport
  465.     setport    IOCA
  466.     out    dx,al            ; send it
  467.     ret
  468.     assume    ds:code
  469. ;yet, we really should assume ds==code for the rest of this stuff.
  470.  
  471.  
  472. end_resident    label    byte
  473.  
  474.     public    usage_msg
  475. usage_msg    db    "usage: ni5210 <packet_int_no> <int_no> <io_addr> <base_addr>",CR,LF,'$'
  476.  
  477.     public    copyright_msg
  478. copyright_msg    db    "Packet driver for the MICOM-Interlan NI5210, version ",'0'+majver,".",'0'+version,CR,LF
  479.         db    "Portions Copyright 1988 The Board of Trustees of the University of Illinois",CR,LF,'$'
  480.  
  481. no_5210_msg    db    "No 5210 found at that address.",CR,LF,'$'
  482. timeout_msg    db    "Timed out while initializing 5210.",CR,LF,'$'
  483. int_no_name    db    "Interrupt number ",'$'
  484. io_addr_name    db    "I/O port ",'$'
  485. base_addr_name    db    "Memory address ",'$'
  486. our_address    db    6 dup(?)    ;temporarily hold our address
  487.  
  488. tdr_ok_msg    db    "TDR Ok",CR,LF,'$'
  489. tdr_none_msg    db    "Your Ethernet card doesn't seem to be plugged in.",CR,LF,'$'
  490. tdr_open_msg    db    " clocks away is an OPEN",CR,LF,'$'
  491. tdr_short_msg    db    " clocks away is a SHORT",CR,LF,'$'
  492.  
  493.     extrn    set_recv_isr: near
  494.  
  495.  
  496. ;enter with si -> argument string, di -> word to store.
  497. ;if there is no number, don't change the number.
  498.     extrn    get_number: near
  499.  
  500. ;enter with dx:ax = number to print.
  501.     extrn    hexout: near, decout: near
  502.  
  503.     public    parse_args
  504. parse_args:
  505.     mov    di,offset int_no
  506.     mov    bx,offset int_no_name
  507.     call    get_number
  508.     mov    di,offset io_addr
  509.     mov    bx,offset io_addr_name
  510.     call    get_number
  511.     mov    di,offset base_addr
  512.     mov    bx,offset base_addr_name
  513.     call    get_number
  514.     ret
  515.  
  516.  
  517. timeout_error:
  518.     mov    dx,offset timeout_msg
  519.     jmp    short error
  520. no_5210_error:
  521.     mov    dx,offset no_5210_msg
  522. error:
  523.     mov    ah,9
  524.     int    21h
  525.     stc
  526.     ret
  527.  
  528. ;
  529. ;  data for configuring and setting up the board
  530. ;
  531. ;  chip always looks at SCP for config info which points to ISCP for the
  532. ;  pointer to the CONTROL BLOCK which handles everything from there.
  533. ;  Kind of indirect, but it works.
  534. ;
  535. SCP    DB    1        ; bus use flag
  536.     DB    5 DUP(0)    ; unused
  537.     DW    ISCPTR        ; 24pointer to ISCP offset
  538.     DW    0        ; high part
  539. ;
  540. ; Intermediate SCP
  541. ;
  542. ISCP    DW    1        ; busy flag
  543.     DW    SCB        ; 16pointer to SCB
  544.     DW    0,0        ; base for all 16 pointers, lo, hi
  545.                 ; board is hardwired to 0 for these values
  546. ;
  547. ; Configuration block for 82586, this comprises one config command
  548. ;  Parameters taken from MICOM driver
  549. ;
  550. CBCONF    DW    0        ; status word
  551.     DW    8002H        ; end of command list + configure command
  552.     DW    0ffffh        ; link to next command (not used)
  553.     DW    080CH        ; fifo=8, byte count=C
  554.     DW    2E00H        ; important! Addr (AL) not inserted on the fly!
  555.     DW    6000H        ; IFS = 60h
  556.     DW    0F200H        ; retry=F, slot time=200h
  557.     DW    0        ; flags, set to 1 for promiscuous
  558.     DW    40H        ; min frame length=40h
  559. ;
  560. ; CB for xmit, followed by BD for xmit, copied together
  561. ;
  562. TCB    DW    0        ; status word
  563.     DW    08004H        ; command word for xmit + EL
  564.     DW    0ffffh        ; no command link
  565.     DW    TBDPTR        ; 16pointer to xmit BD
  566.     DW    0,0,0,0        ; no addressing used here
  567. ;
  568. ; BD template for xmit
  569. TBD    DW    0
  570.     DW    0        ; next BD pointer, unused
  571.     DW    TBUFPTR        ; 24pointer to xmit buffer
  572.     DW    0        ; high part of pointer
  573.  
  574.     public    etopen
  575. etopen:
  576. ;  Initialize the Ethernet board, set receive type.
  577. ;
  578. ;  check for correct EPROM location
  579. ;
  580.     mov    dx,io_addr    ; i/o address
  581.     add    dx,EADDR_LEN    ; look past the ethernet address.
  582.     in    al,dx
  583.     mov    bl,al        ; assemble pattern to check
  584.     inc    dx
  585.     in    al,dx
  586.     mov    bh,al
  587.     cmp    bx,05500h        ; pattern known to be there in ROM
  588.     jz    have_5210
  589.     jmp    no_5210_error        ;not there -- no 5210.
  590. have_5210:
  591. ;  Initialize the Ethernet board, set receive type.
  592. ;
  593. ;  Install 8K SCP, we only use 8K bytes no matter what
  594. ;
  595.     mov    es,base_addr    ; set to base address
  596.     mov    di,SCPTR
  597.     mov    si,offset SCP    ; get pre-set values
  598.     mov    cx,5        ; 5 words
  599.     rep    movsw        ; install SCP
  600. ;
  601. ;  Install 16K SCP, just in case they have that much.
  602. ;
  603.     mov    si,offset SCP    ; get pre-set values
  604.     mov    di,SCPTR+2000h    ; offset for 16K board
  605.     mov    cx,5        ; 5 words
  606.     rep    movsw        ; install SCP
  607. ;
  608. ;  Intermediate SCP
  609. ;
  610.     mov    si,offset ISCP    ; addr of pre-set values
  611.     mov    di,ISCPTR
  612.     mov    cx,4        ; 4 words
  613.     rep    movsw        ; install ISCP
  614. ;
  615. ;  Turn off interrupts, I don't want them
  616. ;
  617.     loadport
  618.     setport    IORESET
  619.     out    dx,al        ; reset the chip
  620. ;
  621. ;  Issue a CA to initialize the chip after reset
  622. ;
  623.     call    lbca
  624. ;
  625. ;  Disconnect from network
  626.     loadport
  627.     setport    IODIS
  628.     out    dx,al
  629. ;
  630. ;  configure 82586
  631. ;
  632.     mov    si,offset CBCONF    ; configure command
  633.     mov    di,CCBPTR        ; where command will reside
  634.     mov    cx,9
  635.     rep    movsw            ; copy to board
  636. ;
  637. ;  issue the configure command
  638. ;
  639.     mov    word ptr es:[SCB+SCOM],0100h    ; do-command command
  640.     mov    word ptr es:[SCB+SCBL],CCBPTR    ; where conf command is
  641.     mov    word ptr es:[SCB+SERRS],0    ; zero errs field
  642.     mov    word ptr es:[SCB+SERRS+2],0    ; zero errs field
  643.     mov    word ptr es:[SCB+SERRS+4],0    ; zero errs field
  644.     mov    word ptr es:[SCB+SERRS+6],0    ; zero errs field
  645.     call    lbca
  646.     xor    cx,cx            ; timeout
  647. waitconf:
  648.     mov    ax,word ptr es:[CCBPTR]    ; get status word
  649.     test    ax,08000h        ; is command complete?
  650.     loopz    waitconf
  651.     jnz    confok
  652.     jmp    timeout_error
  653. confok:
  654. ;
  655. ;  Ask the board for the Ethernet address, and then use set_address to set it.
  656. ;
  657.     mov    dx,io_addr        ; Get our IO base address
  658.     mov    si,offset our_address
  659.     mov    cx,EADDR_LEN
  660. store_address_1:
  661.     in    al,dx            ; get a byte of the eprom address
  662.     mov    [si],al            ; put it away
  663.     inc    si
  664.     inc    dx            ; next register
  665.     loop    store_address_1        ; go back for rest
  666.  
  667.     mov    si,offset our_address
  668.     mov    cx,EADDR_LEN
  669.     call    set_address
  670.     jnc    store_address_2
  671.     jmp    timeout_error
  672. store_address_2:
  673. ;
  674. ;  IA sent, setup all of the other data structures on the board
  675. ;  start with xmit command descriptors
  676. ;
  677.     mov    si,offset TCB        ; template for xmit
  678.     mov    di,TCBPTR        ; where it goes on board
  679.     mov    cx,12            ; copies CB and BD for xmit
  680.     rep    movsw
  681. ;
  682. ;  Set up frame and buffer descriptors, 30 each
  683. ;
  684.     mov    cx,BUF_COUNT        ; # of FDs
  685.     mov    di,FDBASE        ; base addr for FDs
  686. fdloop:
  687.     xor    ax,ax
  688.     mov    bx,di            ; save pointer
  689.     stosw                ; clear status wd
  690.     stosw                ; clear EL field
  691.     add    bx,22            ; points to next one
  692.     mov    es:[di],bx        ; put in link ptr
  693.     inc    di
  694.     inc    di
  695.     dec    ax
  696.     stosw                ; clear BD ptr to -1
  697.     add    di,14
  698.     loop    fdloop
  699.  
  700.     sub    di,20            ; point back to last EL field
  701.     mov    ax,08000h        ; end of list
  702.     stosw                ; put into last FD
  703.     sub    di,4            ; back to beginning of last FD
  704.     mov    lastfd,di        ; save the pointer
  705.     mov    word ptr es:[di+FDLINK],FDBASE    ; make list circular,
  706.                         ; from last to first
  707.  
  708.     mov    ax,BDBASE        ; first BD
  709.     mov    word ptr es:[FDBASE+FDPTR],ax    ; put it in the first FD frame
  710. ;
  711. ;  now BDs
  712.     mov    cx,BUF_COUNT
  713.     mov    di,BDBASE        ; start of BD area
  714.     mov    dx,BUFBASE        ; start of buffer area
  715. bdloop:
  716.     xor    ax,ax
  717.     mov    bx,di            ; save pointer
  718.     stosw                ; zero status field
  719.     add    bx,10            ; point to next record
  720.     mov    es:[di],bx        ; put in link ptr
  721.     inc    di
  722.     inc    di
  723.     mov    es:[di],dx        ; address of buffer, lo part
  724.     inc    di
  725.     inc    di
  726.     stosw                ; zero out high part
  727.     mov    ax,200
  728.     stosw                ; store length field
  729.     add    dx,ax            ; add in length of buffer, updates ptr
  730.     loop    bdloop
  731.  
  732.     sub    di,2            ; back to last BD size field
  733.     mov    ax,08000h+200        ; end of list + 200
  734.     stosw                ; mark end of list
  735.     sub    di,8            ; back to last BDLINK field
  736.     mov    ax,BDBASE
  737.     stosw                ; put link to beginning of list here
  738.     sub    di,4            ; back to beginning of last BD
  739.     mov    lastbd,di        ; save pointer to end of list
  740. ;
  741. ;  configure to connect to network
  742. ;
  743.     loadport
  744.     setport    IOENA            ; enable network
  745.     out    dx,al            ; any al value
  746. ;
  747. ; Test to see if the network is okay.
  748. ;
  749.     mov    di,CCBPTR        ; start of config command block
  750.     xor    ax,ax            ; zero status word for commmand
  751.     stosw
  752.     mov    ax,8005h        ; TDR command + EL
  753.     stosw
  754.     xor    ax,ax
  755.     dec    ax
  756.     stosw                ; set link value to -1 (unused)
  757.     inc    ax
  758.     stosw                ; zero time result.
  759.  
  760.     mov    word ptr es:[SCB+SCOM],0100h    ; do-command command
  761.  
  762.     call    lbca
  763.  
  764.     xor    cx,cx            ; timeout
  765. do_tdr_1:
  766.     mov    ax,word ptr es:[CCBPTR]    ; get status word
  767.     test    ax,08000h        ; is command complete?
  768.     loopz    do_tdr_1
  769.     mov    ax,word ptr es:[CCBPTR+6]
  770.     jnz    do_tdr_2
  771.     mov    ax,2000h        ; treat a timeout as an open
  772. do_tdr_2:
  773.     test    ax,8000h
  774.     mov    dx,offset tdr_ok_msg
  775.     jne    do_tdr_3
  776.     mov    dx,offset tdr_short_msg
  777.     test    ax,2000h
  778.     je    do_tdr_4
  779.     mov    dx,offset tdr_none_msg
  780.     cmp    ax,2000h
  781.     je    do_tdr_3
  782.     mov    dx,offset tdr_open_msg
  783. do_tdr_4:
  784.     push    dx
  785.     and    ax,2048-1
  786.     xor    dx,dx
  787.     call    decout
  788.     pop    dx
  789. do_tdr_3:
  790.     mov    ah,9
  791.     int    21h
  792.  
  793. ;
  794. ;  minor detail, but important
  795. ;  Change SCB command block pointer to setup for xmit commands
  796. ;      = only commands needed when operational
  797. ;
  798.     mov    word ptr es:[SCB+SCBL],TCBPTR    ; where xmit command is
  799. ;
  800. ;  Start the RU, doesn't need CB, only SCB parms.
  801. ;   command, to start receiving
  802. ;
  803.     mov    word ptr es:[SCB],0        ; clear status word
  804.     mov    word ptr es:[SCB+SRFA],FDBASE    ; set to frame descriptors
  805.     mov    word ptr es:[SCB+SCOM],010h    ; start RU
  806.     call    lbca
  807. ;
  808. ; Now reset CX, FR, CNA, and RNR so that we don't get a spurious interrupt.
  809. ;
  810. store_ack_1:
  811.     cmp    word ptr es:[SCB+SCOM],0 ;are we done yet?
  812.     jne    store_ack_1        ;no -- keep waiting.
  813.  
  814.     mov    ax,es:[SCB+SSTAT]    ;get the status.
  815.     and    ax,0f000h        ;isolate the ACK bits.
  816.     mov    es:[SCB+SCOM],ax    ;make a command to
  817.                     ;acknowledge the interrupt.
  818.     call    lbca
  819. ;
  820. ; Now hook in our interrupt
  821. ;
  822.     call    set_recv_isr
  823.  
  824.     mov    dx,offset end_resident
  825.     clc
  826.     ret
  827.  
  828. code    ends
  829.  
  830.     end
  831.