home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / driver6s / ni5010.asm < prev    next >
Assembly Source File  |  1990-03-15  |  20KB  |  778 lines

  1. version    equ    0
  2.  
  3.     include    defs.asm
  4.  
  5. ;Ported from Bill Doster's il.c, a C-language driver for the Interlan NI5010
  6. ;by Russell Nelson.  Any bugs are due to Russell Nelson.
  7. ;Updated to version 1.08 Feb. 17, 1989 by Russell Nelson.
  8.  
  9. ;   Copyright, 1988, 1989, Russell Nelson
  10.  
  11. ;   This program is free software; you can redistribute it and/or modify
  12. ;   it under the terms of the GNU General Public License as published by
  13. ;   the Free Software Foundation, version 1.
  14. ;
  15. ;   This program is distributed in the hope that it will be useful,
  16. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. ;   GNU General Public License for more details.
  19. ;
  20. ;   You should have received a copy of the GNU General Public License
  21. ;   along with this program; if not, write to the Free Software
  22. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  
  24. code    segment    byte public
  25.     assume    cs:code, ds:code
  26.  
  27. ; The various IE command registers
  28. EDLC_XSTAT    equ    0        ; EDLC transmit csr
  29. EDLC_XCLR    equ    0        ; EDLC transmit "Clear IRQ"
  30. EDLC_XMASK    equ    1        ; EDLC transmit "IRQ Masks"
  31. EDLC_RSTAT    equ    2        ; EDLC receive csr
  32. EDLC_RCLR    equ    2        ; EDLC receive "Clear IRQ"
  33. EDLC_RMASK    equ    3        ; EDLC receive "IRQ Masks"
  34. EDLC_XMODE    equ    4        ; EDLC transmit Mode
  35. EDLC_RMODE    equ    5        ; EDLC receive Mode
  36. EDLC_RESET    equ    6        ; EDLC RESET register
  37. EDLC_TDR1    equ    7        ; "Time Domain Reflectometry" reg1
  38. EDLC_ADDR    equ    8        ; EDLC station address, 6 bytes
  39.                     ; 0Eh doesn't exist for r/w
  40. EDLC_TDR2    equ    0fh        ; "Time Domain Reflectometry" reg2
  41. IE_GP        equ    10h        ; GP pointer (word register)
  42.                     ; 11h is 2nd byte of GP Pointer
  43. IE_RCNT        equ    10h        ; Count of bytes in rcv'd packet
  44.                     ; 11h is 2nd byte of "Byte Count"
  45. IE_MMODE    equ    12h        ; Memory Mode register
  46. IE_DMA_RST    equ    13h        ; IE DMA Reset.  write only
  47. IE_ISTAT    equ    13h        ; IE Interrupt Status.  read only
  48. IE_RBUF        equ    14h        ; IE Receive Buffer port
  49. IE_XBUF        equ    15h        ; IE Transmit Buffer port
  50. IE_SAPROM    equ    16h        ; window on station addr prom
  51. IE_RESET    equ    17h        ; any write causes Board Reset
  52.  
  53. ; bits in EDLC_XSTAT, interrupt clear on write, status when read
  54. XS_TPOK        equ    80h        ; transmit packet successful
  55. XS_CS        equ    40h        ; carrier sense
  56. XS_RCVD        equ    20h        ; transmitted packet received
  57. XS_SHORT    equ    10h        ; transmission media is shorted
  58. XS_UFLW        equ    08h        ; underflow.  iff failed board
  59. XS_COLL        equ    04h        ; collision occurred
  60. XS_16COLL    equ    02h        ; 16th collision occurred
  61. XS_PERR        equ    01h        ; parity error
  62.  
  63. XS_CLR_UFLW    equ    08h        ; clear underflow
  64. XS_CLR_COLL    equ    04h        ; clear collision
  65. XS_CLR_16COLL    equ    02h        ; clear 16th collision
  66. XS_CLR_PERR    equ    01h        ; clear parity error
  67.  
  68. ; bits in EDLC_XMASK, mask/enable transmit interrupts.  register is r/w
  69. XM_TPOK        equ    80h        ; =1 to enable Xmt Pkt OK interrupts
  70. XM_RCVD        equ    20h        ; =1 to enable Xmt Pkt Rcvd ints
  71. XM_UFLW        equ    08h        ; =1 to enable Xmt Underflow ints
  72. XM_COLL        equ    04h        ; =1 to enable Xmt Collision ints
  73. XM_COLL16    equ    02h        ; =1 to enable Xmt 16th Coll ints
  74. XM_PERR        equ    01h        ; =1 to enable Xmt Parity Error ints
  75.                     ; note: always clear this bit
  76.  
  77. ; bits in EDLC_RSTAT, interrupt clear on write, status when read
  78. RS_PKT_OK    equ    80h        ; received good packet
  79. RS_RST_PKT    equ    10h        ; RESET packet received
  80. RS_RUNT        equ    08h        ; Runt Pkt rcvd.  Len < 64 Bytes
  81. RS_ALIGN    equ    04h        ; Alignment error. not 8 bit aligned
  82. RS_CRC_ERR    equ    02h        ; Bad CRC on rcvd pkt
  83. RS_OFLW        equ    01h        ; overflow for rcv FIFO
  84. RS_VALID_BITS    equ    RS_PKT_OK or RS_RST_PKT or RS_RUNT or RS_ALIGN or RS_CRC_ERR or RS_OFLW
  85.                     ; all valid RSTAT bits
  86.  
  87. RS_CLR_PKT_OK    equ    80h        ; clear rcvd packet interrupt
  88. RS_CLR_RST_PKT    equ    10h        ; clear RESET packet received
  89. RS_CLR_RUNT    equ    08h        ; clear Runt Pckt received
  90. RS_CLR_ALIGN    equ    04h        ; clear Alignment error
  91. RS_CLR_CRC_ERR    equ    02h        ; clear CRC error
  92. RS_CLR_OFLW    equ    01h        ; clear rcv FIFO Overflow
  93.  
  94. ; bits in EDLC_RMASK, mask/enable receive interrupts.  register is r/w
  95. RM_PKT_OK    equ    80h        ; =1 to enable rcvd good packet ints
  96. RM_RST_PKT    equ    10h        ; =1 to enable RESET packet ints
  97. RM_RUNT        equ    08h        ; =1 to enable Runt Pkt rcvd ints
  98. RM_ALIGN    equ    04h        ; =1 to enable Alignment error ints
  99. RM_CRC_ERR    equ    02h        ; =1 to enable Bad CRC error ints
  100. RM_OFLW        equ    01h        ; =1 to enable overflow error ints
  101.  
  102. ; bits in EDLC_RMODE, set Receive Packet mode.  register is r/w
  103. RMD_TEST    equ    80h        ; =1 for Chip testing.  normally 0
  104. RMD_ADD_SIZ    equ    10h        ; =1 5-byte addr match.  normally 0
  105. RMD_EN_RUNT    equ    08h        ; =1 enable runt rcv.  normally 0
  106. RMD_EN_RST    equ    04h        ; =1 to rcv RESET pkt.  normally 0
  107.  
  108. RMD_PROMISC    equ    03h        ; receive *all* packets.  unusual
  109. RMD_MULTICAST    equ    02h        ; receive multicasts too.  unusual
  110. RMD_BROADCAST    equ    01h        ; receive broadcasts & normal. usual
  111. RMD_NO_PACKETS    equ    00h        ; don't receive any packets. unusual
  112.  
  113. ; bits in EDLC_XMODE, set Transmit Packet mode.  register is r/w
  114. XMD_COLL_CNT    equ    0f0h        ; coll's since success.  read-only
  115. XMD_IG_PAR    equ    008h        ; =1 to ignore parity.  ALWAYS set
  116. XMD_T_MODE    equ    004h        ; =1 to power xcvr. ALWAYS set this
  117. XMD_LBC        equ    002h        ; =1 for loopbakc.  normally set
  118. XMD_DIS_C    equ    001h        ; =1 disables contention. normally 0
  119.  
  120. ; bits in EDLC_RESET, write only
  121. RS_RESET    equ    80h        ; =1 to hold EDLC in reset state
  122.  
  123. ; bits in IE_MMODE, write only
  124. MM_EN_DMA    equ    80h        ; =1 begin DMA xfer, Cplt clrs it
  125. MM_EN_RCV    equ    40h        ; =1 allows Pkt rcv.  clr'd by rcv
  126. MM_EN_XMT    equ    20h        ; =1 begin Xmt pkt.  Cplt clrs it
  127. MM_BUS_PAGE    equ    18h        ; =00 ALWAYS.  Used when MUX=1
  128. MM_NET_PAGE    equ    06h        ; =00 ALWAYS.  Used when MUX=0
  129. MM_MUX        equ    01h        ; =1 means Rcv Buff on system bus
  130.                     ; =0 means Xmt Buff on system bus
  131.  
  132. ; bits in IE_ISTAT, read only
  133. IS_TDIAG    equ    80h        ; =1 if Diagnostic problem
  134. IS_EN_RCV    equ    20h        ; =1 until frame is rcv'd cplt
  135. IS_EN_XMT    equ    10h        ; =1 until frame is xmt'd cplt
  136. IS_EN_DMA    equ    08h        ; =1 until DMA is cplt or aborted
  137. IS_DMA_INT    equ    04h        ; =0 iff DMA done interrupt. 
  138. IS_R_INT    equ    02h        ; =0 iff unmasked Rcv interrupt
  139. IS_X_INT    equ    01h        ; =0 iff unmasked Xmt interrupt
  140.  
  141. BFRSIZ        equ    2048    ;number of bytes in a buffer
  142.  
  143.     public    int_no
  144. int_no        db    3,0,0,0        ; interrupt number.
  145. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  146. ipkt_size    dw    ?
  147. opkt_size    dw    ?
  148.  
  149.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  150. driver_class    db    1        ;from the packet spec
  151. driver_type    db    3        ;from the packet spec
  152. driver_name    db    'NI5010',0    ;name of the driver.
  153. driver_function    db    2
  154. parameter_list    label    byte
  155.     db    1    ;major rev of packet driver
  156.     db    9    ;minor rev of packet driver
  157.     db    14    ;length of parameter list
  158.     db    EADDR_LEN    ;length of MAC-layer address
  159.     dw    GIANT    ;MTU, including MAC headers
  160.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  161.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  162.     dw    0    ;(# of successive xmits) - 1
  163.     dw    0    ;Interrupt # to hook for post-EOI
  164.             ;processing, 0 == none,
  165.  
  166.     public    rcv_modes
  167. rcv_modes    dw    4        ;number of receive modes in our table.
  168.         dw    0,0,0,rcv_mode_3
  169.  
  170. is_186        db    0        ;=0 if 808[68], =1 if 80[123]86.
  171. our_type    dw    ?
  172. intstat        db    ?
  173.  
  174.     public    send_pkt
  175. send_pkt:
  176. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  177. ;  (only if the high-performance bit is set in driver_function)
  178. ;enter with ds:si -> packet, cx = packet length.
  179. ;exit with nc if ok, or else cy if error, dh set to error number.
  180.     assume    ds:nothing
  181.     cmp    cx,RUNT        ; minimum length for Ether
  182.     jae    oklen
  183.     mov    cx,RUNT        ; make sure size at least RUNT
  184. oklen:
  185.     inc    cx            ;round size up to next even number.
  186.     and    cx,not 1
  187.  
  188. ;Wait for transmitter ready, if necessary. IE_XMTBSY is valid
  189. ;only in the transmit mode, hence the initial check.
  190.  
  191.     loadport
  192.     setport    IE_ISTAT
  193.     in    al,dx
  194.     and    al,IS_EN_XMT        ;on-going xmit
  195.     je    send_pkt_2
  196.  
  197.     mov    bx,20000        ;try this many times.
  198. send_pkt_3:
  199.     in    al,dx            ;if not busy, exit.
  200.     and    al,IS_EN_XMT
  201.     je    send_pkt_2
  202.     dec    bx
  203.     jne    send_pkt_3
  204.     mov    dh,CANT_SEND        ;timed out, can't send.
  205.     stc
  206.     ret
  207. send_pkt_2:
  208.  
  209.     pushf            ; No distractions from the receiver
  210.     cli
  211.  
  212. ; Disable the Receiver
  213.     mov    al, 0        ; Mask all Receive Interrupts
  214.     loadport
  215.     setport    EDLC_RMASK
  216.     out    dx,al
  217.  
  218.     mov    al, 0        ; Put Xmt Buffer on System Bus
  219.     setport    IE_MMODE
  220.     out    dx,al
  221.  
  222.     mov    al, 0FFh    ; Clear out any pending Rcv Ints
  223.     setport    EDLC_RCLR
  224.     out    dx,al
  225.  
  226.     mov    ax, BFRSIZ    ; Point GP at beginning of packet
  227.     sub    ax,cx
  228.     setport    IE_GP
  229.     out    dx,ax
  230.  
  231.     setport    IE_XBUF
  232.  
  233.     mov    opkt_size,cx    ; opkt_size = cx;
  234.     cmp    is_186,0    ; Can we use rep outsb?
  235.     je    out86        ; no - have to do it slowly.
  236.     db    0f3h, 06eh    ;masm 4.0 doesn't grok "rep outsb"
  237.     jmp    short ocnteven
  238. out86:
  239.     test    si,1        ; (buf & 1) ?
  240.     jz    obufeven    ; no
  241.     lodsb            ; al = *si++;
  242.     out    dx,al        ; out(dx,al);
  243.     dec    cx        ; cx--;
  244. obufeven:
  245.     mov    di,cx        ; save for later test
  246.     shr    cx,1        ; cx = cnt >> 1; (convert to word count)
  247. ; Do the bulk of the buffer, a word at a time
  248.     jcxz    onobuf        ; if(cx != 0){
  249. xb:    lodsw            ; do { ax = *si++; (si is word pointer)
  250.     out    dx,al        ; out(dx,lowbyte(ax));
  251.     mov    al,ah
  252.     out    dx,al        ; out(dx,hibyte(ax));
  253.     loop    xb        ; } while(--cx != 0); }
  254. ; now check for odd trailing byte
  255. onobuf:    shr    di,1        ; if (di & 1)
  256.     jnc    ocnteven
  257.     lodsb            ;   out(dx,*si++);
  258.     out    dx,al
  259. ocnteven:
  260.  
  261. ; Rewrite where packet starts
  262.     mov    ax,BFRSIZ
  263.     sub    ax,opkt_size
  264.     loadport
  265.     setport    IE_GP
  266.     out    dx,ax
  267.  
  268. ; Flip Xmt Buffer to EDLC Bus so it can be transmitted
  269.     mov    al, MM_MUX
  270.     setport    IE_MMODE
  271.     out    dx,al
  272.  
  273. ; Begin transmission.
  274.     mov    al, MM_EN_XMT or MM_MUX
  275.     setport    IE_MMODE
  276.     out    dx,al
  277.  
  278. ; Cause interrupt after completion (or if something fails)
  279.     mov    al, XM_TPOK or XM_RCVD or XM_UFLW or XM_COLL or XM_COLL16
  280.     setport    EDLC_XMASK
  281.     out    dx,al
  282.  
  283.     popf
  284.     clc
  285.     ret
  286.  
  287.  
  288.     public    get_address
  289. get_address:
  290. ;get the address of the interface.
  291. ;enter with es:di -> place to get the address, cx = size of address buffer.
  292. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  293.     assume    ds:code
  294.     cmp    cx,EADDR_LEN            ;make sure that we have enough room.
  295.     jb    get_address_2
  296.     cmp    cx,9            ;do we have room for all of it?
  297.     jb    get_address_3        ;no.
  298.     mov    cx,9            ;yes - get the whole thing.
  299.     xor    bx,bx
  300.     jmp    short get_address_1
  301. get_address_3:
  302.     mov    cx,EADDR_LEN
  303.     xor    bx,bx
  304. get_address_1:
  305.     mov    ax,bx
  306.     loadport
  307.     setport    IE_GP
  308.     out    dx,ax
  309.  
  310.     setport    IE_SAPROM
  311.     in    al,dx
  312.     stosb
  313.     inc    bx
  314.     loop    get_address_1
  315.  
  316.     mov    cx,EADDR_LEN
  317.     clc
  318.     ret
  319. get_address_2:
  320.     stc
  321.     ret
  322.  
  323.  
  324. ;Set Ethernet address on controller
  325.     public    set_address
  326. set_address:
  327.     assume    ds:nothing
  328. ;enter with ds:si -> Ethernet address, CX = length of address.
  329. ;exit with nc if okay, or cy, dh=error if any errors.
  330. ;
  331.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  332.     je    set_address_4
  333.     mov    dh,BAD_ADDRESS
  334.     stc
  335.     jmp    short set_address_done
  336. set_address_4:
  337.  
  338.     loadport
  339.     setport    EDLC_ADDR
  340. set_address_1:
  341.     lodsb
  342.     out    dx,al
  343.     inc    dx
  344.     loop    set_address_1
  345. set_address_okay:
  346.     mov    cx,EADDR_LEN        ;return their address length.
  347.     clc
  348. set_address_done:
  349.     push    cs
  350.     pop    ds
  351.     assume    ds:code
  352.     ret
  353.  
  354.  
  355. rcv_mode_3:
  356. ;receive mode 3 is the only one we support, so we don't have to do anything.
  357.     ret
  358.  
  359.  
  360.     public    set_multicast_list
  361. set_multicast_list:
  362. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  363. ;return nc if we set all of them, or cy,dh=error if we didn't.
  364.     mov    dh,NO_MULTICAST
  365.     stc
  366.     ret
  367.  
  368.  
  369.     public    terminate
  370. terminate:
  371.     ; put card in held-RESET state
  372.     mov    al,0
  373.     loadport
  374.     setport    IE_MMODE
  375.     out    dx,al
  376.     mov    al,RS_RESET
  377.     loadport
  378.     setport    EDLC_RESET
  379.     out    dx,al
  380.  
  381.     ret
  382.  
  383.  
  384.     public    reset_interface
  385. reset_interface:
  386. ;reset the interface.
  387. ;we don't do anything.
  388.     ret
  389.  
  390.  
  391. ;called when we want to determine what to do with a received packet.
  392. ;enter with cx = packet length, es:di -> packet type.
  393.     extrn    recv_find: near
  394.  
  395. ;called after we have copied the packet into the buffer.
  396. ;enter with ds:si ->the packet, cx = length of the packet.
  397.     extrn    recv_copy: near
  398.  
  399.     extrn    count_in_err: near
  400.     extrn    count_out_err: near
  401.  
  402.     public    recv
  403. recv:
  404. ;called from the recv isr.  All registers have been saved, and ds=cs.
  405. ;Upon exit, the interrupt will be acknowledged.
  406.     assume    ds:code
  407.  
  408.     loadport
  409.     setport    IE_ISTAT
  410.     in    al,dx
  411.     mov    intstat,al
  412.  
  413. ; DMA Complete Interrupt.  We don't use DMA, but just in case ...
  414.     test    al,IS_DMA_INT
  415.     jne    recv_isr_3
  416.  
  417.     mov    al, 0         ; Reset DMA Interrupt
  418.     setport    IE_DMA_RST
  419.     out    dx,al
  420.  
  421. recv_isr_3:
  422.  
  423. ; Transmit Complete/Fail Interrupt
  424.     test    intstat,IS_X_INT
  425.     jne    recv_isr_1
  426.  
  427.     loadport
  428.     setport    EDLC_XSTAT
  429.     in    al,dx
  430.     mov    ah,al
  431.  
  432.     mov    al, 0            ; Disable Xmt IRQ's
  433.     setport    EDLC_XMASK
  434.     out    dx,al
  435.  
  436.     mov    al, 0FFh        ; clr all Xmt IRQ's
  437.     setport    EDLC_XCLR
  438.     out    dx,al
  439.  
  440.     test    ah,XS_COLL
  441.     je    recv_isr_1
  442.     ;Crank counter back to beginning and restart xmt
  443.  
  444.     mov    ax,BFRSIZ        ; Point GP at beginning of packet
  445.     sub    ax,opkt_size
  446.     setport    IE_GP
  447.     out    dx,ax
  448.  
  449.     mov    al, 0        ; De-assert MM_EN_RCV bit Just In Case
  450.     setport    IE_MMODE
  451.     out    dx,al
  452.  
  453.                 ; Flip Xmt Buffer to EDLC Bus and restart xmt
  454.     mov    al, MM_EN_XMT or MM_MUX
  455.     setport    IE_MMODE
  456.     out    dx,al
  457.  
  458.             ; Interrupt for all Transmit errors along with TPOK
  459.     mov    al, XM_TPOK or XM_RCVD or XM_UFLW or XM_COLL or XM_COLL16
  460.     setport    EDLC_XMASK
  461.     out    dx,al
  462.  
  463.     ret            ; Wait for it to complete again
  464.  
  465. recv_isr_1:
  466.     ; Is this a Receive Packet Interrupt?
  467.     test    intstat,IS_R_INT
  468.     jne    recv_isr_9_j_1        ;no.
  469.  
  470.     loadport
  471.     setport    EDLC_RSTAT        ;get the status of this packet
  472.     in    al,dx
  473.     and    al,RS_VALID_BITS
  474.     cmp    al,RS_PKT_OK        ;is it ok?
  475.     jne    recv_isr_7        ;yes.
  476.  
  477.     ; Clear the interrupt
  478.     mov    al, 0FFh
  479.     loadport
  480.     setport    EDLC_RCLR
  481.     out    dx,al
  482.  
  483.     ; Flip Rcv Buffer onto the system bus
  484.     mov    al, MM_MUX
  485.     setport    IE_MMODE
  486.     out    dx,al
  487.  
  488.     ; Get the size of the packet.
  489.     setport    IE_RCNT
  490.     in    ax,dx
  491.     mov    ipkt_size,ax
  492.  
  493.     cmp    ax,GIANT        ;greater than GIANT?
  494.     jbe    recv_isr_8        ;no.
  495. recv_isr_7:
  496.     call    count_in_err
  497. recv_isr_9_j_1:
  498.     jmp    recv_isr_9
  499. recv_isr_8:
  500. ;Put it on the receive queue
  501.  
  502.     mov    ax,EADDR_LEN+EADDR_LEN            ;seek to the type word.
  503.     setport    IE_GP
  504.     out    dx,ax
  505.  
  506.     setport    IE_RBUF
  507.     in    al,dx            ;read the type word out of the board.
  508.     mov    ah,al
  509.     in    al,dx
  510.     xchg    al,ah            ;should be in network byte order.
  511.     mov    our_type,ax
  512.  
  513.     mov    ax,ds            ;look up our type.
  514.     mov    es,ax
  515.     mov    di,offset our_type
  516.     mov    cx,ipkt_size
  517.     call    recv_find
  518.  
  519.     mov    ax,es            ;is this pointer null?
  520.     or    ax,di
  521.     je    recv_isr_9        ;yes - just free the frame.
  522.  
  523.     push    es            ;remember where the buffer pointer is.
  524.     push    di
  525.  
  526.     xor    ax,ax            ;seek to the beginning again.
  527.     loadport
  528.     setport    IE_GP
  529.     out    dx,ax
  530.  
  531.     mov    cx,ipkt_size
  532.     setport    IE_RBUF
  533.  
  534.     cmp    is_186,0    ; Can we use rep insb?
  535.     je    in86        ; no - have to do it slowly.
  536.     db    0f3h, 06ch    ;masm 4.0 doesn't grok "rep insb"
  537.     jmp    short icnteven
  538. in86:
  539. ; If buffer doesn't begin on a word boundary, get the first byte
  540.     test    di,1    ; if(buf & 1){
  541.     jz    ibufeven ;
  542.     in    al,dx    ; al = in(dx);
  543.     stosb        ; *di++ = al
  544.     dec    cx    ; cx--;
  545. ibufeven:
  546.     mov    si,cx    ; size = cx;
  547.     shr    cx,1    ; cx = cnt >> 1; (convert to word count)
  548. ; Do the bulk of the buffer, a word at a time
  549.     jcxz    inobuf    ; if(cx != 0){
  550. rb:    in    al,dx    ; do { al = in(dx);
  551.     mov    ah,al
  552.     in    al,dx    ; ah = in(dx);
  553.     xchg    al,ah
  554.     stosw        ; *si++ = ax; (di is word pointer)
  555.     loop    rb    ; } while(--cx != 0);
  556. ; now check for odd trailing byte
  557. inobuf:    shr    si,1
  558.     jnc    icnteven
  559.     in    al,dx
  560.     stosb        ; *di++ = al
  561. icnteven:
  562.  
  563.     pop    si
  564.     pop    ds
  565.     assume    ds:nothing
  566.     mov    cx,ipkt_size
  567.     call    recv_copy        ;tell them that we copied it.
  568.  
  569.     mov    ax,cs            ;restore our ds.
  570.     mov    ds,ax
  571.     assume    ds:code
  572.  
  573. recv_isr_9:
  574.  
  575. ; Prime Interlan card for another Receive
  576. il_rcv_reset:
  577.  
  578.     ; Rcv packet at start of Boards buffer
  579.     mov    ax,0
  580.     loadport
  581.     setport    IE_GP
  582.     out    dx,ax
  583.  
  584.     ; Clear any remaining Interrupt conditions
  585.     mov    al,0FFh
  586.     setport    EDLC_RCLR
  587.     out    dx,al
  588.  
  589.     ; Set MUX to allow EDLC to access Rcv Buffer
  590.     mov    al,0
  591.     setport    IE_MMODE
  592.     out    dx,al
  593.  
  594.     ; Enable Receive of Normal and Broadcast Packets only.
  595.     mov    al,RMD_BROADCAST
  596.     setport    EDLC_RMODE
  597.     out    dx,al
  598.  
  599.     ; Enable Receive Interrupts
  600.     mov    al,MM_EN_RCV
  601.     setport    IE_MMODE
  602.     out    dx,al
  603.  
  604.     ; Unmask *all* Receive related interrupts
  605.     mov    al,0FFh
  606.     setport    EDLC_RMASK
  607.     out    dx,al
  608.  
  609.     ret
  610.  
  611.  
  612.     public    recv_exiting
  613. recv_exiting:
  614. ;called from the recv isr after interrupts have been acknowledged.
  615. ;Only ds and ax have been saved.
  616.     assume    ds:nothing
  617.     ret
  618.  
  619.  
  620. end_resident    label    byte
  621.  
  622.     public    usage_msg
  623. usage_msg    db    "usage: NI5010 <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
  624.  
  625.     public    copyright_msg
  626. copyright_msg    db    "Packet driver for the Interlan NI5010, version ",'0'+majver,".",'0'+version,CR,LF
  627.         db    "Portions Copyright 1988 Bill Doster",CR,LF,'$'
  628.  
  629.  
  630. using_186_msg    db    "Using 80[123]86 I/O instructions.",CR,LF,'$'
  631. no_ni5010_msg    db    "No NI5010 found at that address.",CR,LF,'$'
  632. ether_bdcst    db    EADDR_LEN dup(-1)    ;ethernet broadcast address.
  633. our_address    db    EADDR_LEN+3 dup(?)    ;temporarily hold our address
  634.  
  635. int_no_name    db    "Interrupt number ",'$'
  636. io_addr_name    db    "I/O port ",'$'
  637.  
  638.     extrn    set_recv_isr: near
  639.  
  640. ;enter with si -> argument string, di -> word to store.
  641. ;if there is no number, don't change the number.
  642.     extrn    get_number: near
  643.  
  644. ;enter with dx -> name of word, di -> dword to print.
  645.     extrn    print_number: near
  646.  
  647.     public    parse_args
  648. parse_args:
  649. ;exit with nc if all went well, cy otherwise.
  650.     mov    di,offset int_no
  651.     call    get_number
  652.     mov    di,offset io_addr
  653.     call    get_number
  654.     clc
  655.     ret
  656.  
  657.  
  658. no_ni5010_error:
  659.     mov    dx,offset no_ni5010_msg
  660.     mov    ah,9
  661.     int    21h
  662.     stc
  663.     ret
  664.  
  665.  
  666.     public    etopen
  667. etopen:
  668. ;  Initialize the Ethernet board, set receive type.
  669. ;
  670. ;  check for correct EPROM location
  671. ;
  672.     pushf        ; No distractions from the receiver
  673.     cli
  674.  
  675.     ; Hold up EDLC RESET while the board is configured
  676.     mov    al,RS_RESET
  677.     loadport
  678.     setport    EDLC_RESET
  679.     out    dx,al
  680.  
  681.     ; Hardware reset of Interlan Board
  682.     mov    al,0
  683.     loadport
  684.     setport    IE_RESET
  685.     out    dx,al
  686.  
  687.     call    set_recv_isr
  688.  
  689.     popf        ; Shouldn't be any interrupts from here on out
  690.  
  691.     mov    al,XMD_LBC
  692.     loadport
  693.     setport    EDLC_XMODE
  694.     out    dx,al
  695.  
  696. ;Determine the processor type.  The 8088 and 8086 will actually shift ax
  697. ;over by 33 bits, while the 80[123]86 use a shift count mod 32.
  698.     mov    cl,33
  699.     mov    ax,0ffffh
  700.     shl    ax,cl
  701.     jz    not_186
  702.     mov    is_186,1
  703.     mov    dx,offset using_186_msg
  704.     mov    ah,9
  705.     int    21h
  706. not_186:
  707.  
  708.     push    ds
  709.     pop    es
  710.     mov    di,offset our_address
  711.     mov    cx,EADDR_LEN+3        ;get three extra signature bytes.
  712.     call    get_address
  713.     mov    si,offset our_address
  714.     mov    cx,EADDR_LEN
  715.     call    set_address
  716.  
  717. ;See if there really is a ni5010 there.
  718.     cmp    our_address+EADDR_LEN+0,0
  719.     jne    no_ni5010
  720.     cmp    our_address+EADDR_LEN+1,055h
  721.     jne    no_ni5010
  722.     cmp    our_address+EADDR_LEN+2,0aah
  723.     jne    no_ni5010
  724.  
  725.     mov    cx,EADDR_LEN
  726.     mov    di,offset ether_bdcst
  727.     repe    cmpsb
  728.     jne    have_ni5010        ;not broadcast address -- must be real.
  729. no_ni5010:
  730.     jmp    no_ni5010_error        ;not there -- no ni5010.
  731. have_ni5010:
  732.  
  733.     ; Only enable Transmit-type interrupts while Transmitting
  734.     mov    al,0
  735.     loadport
  736.     setport    EDLC_XMASK
  737.     out    dx,al
  738.  
  739.     ; Establish generic Transmit mode
  740.     mov    al,XMD_IG_PAR or XMD_T_MODE or XMD_LBC
  741.     setport    EDLC_XMODE
  742.     out    dx,al
  743.  
  744.     ; Clear any startup related Transmit interrupts
  745.     mov    al,0FFh
  746.     setport    EDLC_XCLR
  747.     out    dx,al
  748.  
  749.     ; Establish generic Receive mode
  750.     mov    al,RMD_BROADCAST
  751.     setport    EDLC_RMODE
  752.     out    dx,al
  753.  
  754.     ; Reset Rcv State to allow receives
  755.     call    il_rcv_reset
  756.  
  757.     ; Finally un-reset the EDLC
  758.     mov    al,0
  759.     loadport
  760.     setport    EDLC_RESET
  761.     out    dx,al
  762.  
  763.     mov    di,offset int_no
  764.     mov    dx,offset int_no_name
  765.     call    print_number
  766.     mov    di,offset io_addr
  767.     mov    dx,offset io_addr_name
  768.     call    print_number
  769.  
  770.     mov    dx,offset end_resident
  771.     clc
  772.     ret
  773.  
  774.  
  775. code    ends
  776.  
  777.     end
  778.