home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / driver6s / ne1000.asm < prev    next >
Assembly Source File  |  1990-03-15  |  25KB  |  1,007 lines

  1. ; Packet driver for Novell's NE1000 
  2. ; Written by:
  3. ;    Eric Henderson
  4. ;    Brigham Young University
  5. ;    
  6. ; Based on the "generic" packet driver by Russell Nelson with help
  7. ; from the western digital pd by Russell Nelson.
  8. ; 80[123]86 processor support lifted from 3com driver by permission
  9. ;    from Russell Nelson
  10. ;
  11. ;   Portions (C) Copyright 1989 BYU
  12.  
  13. version    equ    2
  14.  
  15.     include    defs.asm
  16.  
  17. code    segment    byte public
  18.     assume    cs:code, ds:code
  19.  
  20. ;*****************************************************************************
  21. ;
  22. ;    NE1000 controller board offsets
  23. ;    IO port definition (BASE in io_addr)
  24. ;*****************************************************************************
  25. ADDROM  EQU    10h            ; LAN Address ROM
  26. RACK    EQU    10h            ; NE1000 Port Window (?)
  27. NERESET EQU    1fh            ; Issue a read for reset
  28. ; 8390 LAN Controller (page0) register offset for read and write 
  29. CMDR    EQU    00h            ; command register for read & write
  30. CLDA0    EQU    01h            ; current local dma addr 0 for read
  31. PSTART    EQU    01h            ; page start register for write
  32. CLDA1    EQU    02h            ; current local dma addr 1 for read
  33. PSTOP    EQU    02h            ; page stop register for write
  34. BNRY    EQU    03h            ; boundary reg for rd and wr
  35. TSR    EQU    04h            ; tx status reg for rd
  36. TPSR    EQU    04h            ; tx start page start reg for wr    
  37. NCR    EQU    05h            ; number of collision reg for rd
  38. TBCR0    EQU    05h            ; tx byte count 0 reg for wr
  39. FIFO    EQU    06h            ; FIFO for rd
  40. TBCR1    EQU    06h            ; tx byte count 1 reg for wr
  41. ISR    EQU    07h            ; interrupt status reg for rd and wr
  42. CRDA0    EQU    08h            ; current remote dma address 0 for rd
  43. RSAR0    EQU    08h            ; remote start address reg 0  for wr
  44. CRDA1    EQU    09h            ; current remote dma address 1 for rd
  45. RSAR1    EQU    09h            ; remote start address reg 1 for wr
  46. RBCR0    EQU    0Ah            ; remote byte count reg 0 for wr
  47. RBCR1    EQU    0Bh            ; remote byte count reg 1 for wr
  48. RSR    EQU    0Ch            ; rx status reg for rd
  49. RCRWD    EQU    0Ch            ; rx configuration reg for wr
  50. CNTR0    EQU    0Dh            ; tally cnt 0 for frm alg err for rd
  51. TCR    EQU    0Dh            ; tx configuration reg for wr
  52. CNTR1    EQU    0Eh            ; tally cnt 1 for crc err for rd
  53. DCR    EQU    0Eh            ; data configuration reg for wr
  54. CNTR2    EQU    0Fh            ; tally cnt 2 for missed pkt for rd
  55. IMR    EQU    0Fh            ; interrupt mask reg for wr
  56. ; 8390 LAN Controller (page1) register offset for read and write 
  57. PAR0    EQU    01h             ; physical addr reg 0 for rd and wr
  58. PAR1    EQU    02h             ; physical addr reg 1 for rd and wr
  59. PAR2    EQU    03h             ; physical addr reg 2 for rd and wr
  60. PAR3    EQU    04h             ; physical addr reg 3 for rd and wr
  61. PAR4    EQU    05h             ; physical addr reg 4 for rd and wr
  62. PAR5    EQU    06h             ; physical addr reg 5 for rd and wr
  63. CURR    EQU    07h            ; current page reg for rd and wr
  64. MAR0    EQU    08h            ; multicast addr reg 0 fro rd and WR
  65. MAR1    EQU    09h            ; multicast addr reg 1 fro rd and WR
  66. MAR2    EQU    0Ah            ; multicast addr reg 2 fro rd and WR
  67. MAR3    EQU    0Bh            ; multicast addr reg 3 fro rd and WR
  68. MAR4    EQU    0Ch            ; multicast addr reg 4 fro rd and WR
  69. MAR5    EQU    0Dh            ; multicast addr reg 5 fro rd and WR
  70. MAR6    EQU    0Eh            ; multicast addr reg 6 fro rd and WR
  71. MAR7    EQU    0Fh            ; multicast addr reg 7 fro rd and WR
  72.  
  73. ;***********************************************************************
  74. ;
  75. ;    8003 control register operations
  76. ;***********************************************************************
  77.  
  78. MSK_RESET    EQU    80h            ; reset LAN controller
  79. MSK_ENASH    EQU    40h        ; enable PC access to shared mem
  80. MSK_DECOD    EQU    3Fh         ; ???? memory decode bits, corresponding
  81.                     ; to SA 18-13. SA 19 assumed to be 1
  82. ;***********************************************************************
  83. ;
  84. ;    8390 CMDR MASK
  85. ;***********************************************************************
  86.  
  87. MSK_STP        EQU    01h        ; software reset, take 8390 off line
  88. MSK_STA        EQU    02h        ; activate the 8390 NIC
  89. MSK_TXP        EQU    26h        ; initial txing of a frm  (With DMA)
  90. MSK_RD2        EQU    20h        ; abort remote DMA
  91. MSK_PG0        EQU    00h        ; select register page 0
  92. MSK_PG1        EQU    40h        ; select register page 1
  93. MSK_PG2        EQU    80h        ; select register page 2
  94. MSK_DMA_RD    EQU    0ah        ; start DMA read
  95. MSK_DMA_WR    EQU    12h        ; start DMA write
  96.  
  97. ;***********************************************************************
  98. ;
  99. ;    8390 ISR & IMR MASK
  100. ;***********************************************************************
  101.  
  102. MSK_PRX  EQU    01h        ; rx with no error
  103. MSK_PTX  EQU    02h        ; tx with no error
  104. MSK_RXE  EQU    04h        ; rx with error
  105. MSK_TXE  EQU    08h        ; tx with error
  106. MSK_OVW  EQU    10h        ; overwrite warning
  107. MSK_CNT  EQU    20h        ; MSB of one of the tally counters is set
  108. MSK_RDC  EQU    40h        ; remote dma completed
  109. MSK_RST     EQU    80h        ; reset state indicator
  110. UnmaskByte        equ    1fh
  111. InterruptMask        equ    0fh
  112.  
  113. ;***********************************************************************
  114. ;
  115. ;    8390 DCR MASK
  116. ;***********************************************************************
  117.  
  118. MSK_WTS EQU    01h        ; word transfer mode selection
  119. MSK_BOS    EQU    02h        ; byte order selection
  120. MSK_LAS    EQU    04h        ; long addr selection
  121. MSK_BMS    EQU    08h        ; burst mode selection
  122. MSK_ARM    EQU    10h        ; atuoinitialize remote
  123. MSK_FT00 EQU    00h        ; burst lrngth selection
  124. MSK_FT01 EQU    20h        ; burst lrngth selection
  125. MSK_FT10 EQU    40h        ; burst lrngth selection
  126. MSK_FT11 EQU    60h        ; burst lrngth selection
  127.  
  128. ;***********************************************************************
  129. ;
  130. ;    8390 RCR MASK
  131. ;***********************************************************************
  132.  
  133. MSK_SEP EQU    01h        ; save error pkts
  134. MSK_AR     EQU    02h        ; accept runt pkt
  135. MSK_AB     EQU    04h        ; accept broadcast 
  136. MSK_AM     EQU    08h        ; accept multicast 
  137. MSK_PRO    EQU    10h        ; promiscuous physical
  138.                 ; accept all pkt with physical adr
  139. MSK_MON EQU    20h        ; monitor mode
  140.  
  141. ;***********************************************************************
  142. ;
  143. ;    8390 TCR MASK
  144. ;***********************************************************************
  145.  
  146. MSK_CRC EQU    01h        ; inhibit CRC, do not append crc
  147. MSK_LB01 EQU    06h        ; encoded loopback control
  148. MSK_ATD    EQU    08h        ; auto tx disable
  149. MSK_OFST EQU    10h        ; collision offset enable 
  150.  
  151. ;***********************************************************************
  152. ;
  153. ;    8390 RSR MASK
  154. ;***********************************************************************
  155.  
  156. SMK_PRX  EQU    01h        ; rx without error
  157. SMK_CRC  EQU    02h        ; CRC error
  158. SMK_FAE  EQU    04h        ; frame alignment error
  159. SMK_FO   EQU    08h        ; FIFO overrun
  160. SMK_MPA  EQU    10h        ; missed pkt
  161. SMK_PHY  EQU    20h        ; physical/multicase address
  162. SMK_DIS  EQU    40h        ; receiver disable. set in monitor mode
  163. SMK_DEF     EQU    80h        ; deferring
  164.  
  165. ;***********************************************************************
  166. ;
  167. ;    8390 TSR MASK
  168. ;***********************************************************************
  169.  
  170. SMK_PTX  EQU    01h        ; tx without error
  171. SMK_DFR  EQU    02h        ; non deferred tx
  172. SMK_COL  EQU    04h        ; tx collided
  173. SMK_ABT  EQU    08h        ; tx aboort because of excessive collisions
  174. SMK_CRS  EQU    10h        ; carrier sense lost
  175. SMK_FU   EQU    20h        ; FIFO underrun
  176. SMK_CDH  EQU    40h        ; collision detect heartbeat
  177. SMK_OWC     EQU    80h        ; out of window collision
  178.  
  179. ;***********************************************************************
  180. ;
  181. ;    on board memory constant definition
  182. ;***********************************************************************
  183. ; for rcv buff ring of onboard mem
  184. START_PG EQU    26h                  ; start at page 26
  185. STOP_PG  EQU    40h            ; end at page 40 
  186. ; for tx buff of shr mem
  187. TB_SIZE EQU    1            ; number of tb buff in shr mem
  188. TB_PGNO EQU    6            ; number of pages in one tb buff
  189.  
  190.  
  191.     public    int_no, io_addr
  192. int_no        db    3,0,0,0        ;must be four bytes long for get_number.
  193. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  194. my_eaddr      db    6 dup(?)    ; 6 byte LAN address
  195. m_channel     dw     0        ; micro channel flag    
  196. is_186        db    0        ;=0 if 808[68], =1 if 80[123]86.
  197.  
  198. rd_NE    MACRO    port
  199.     mov    DX, CS:io_addr
  200.     add    DX, port        ; DX contains address of port
  201.     in    AL, DX            ; AL contains data read from port
  202.     ENDM
  203.  
  204. wr_NE    MACRO    port
  205.     mov    DX, CS:io_addr
  206.     add    DX, port        ; DX contains address of port
  207.     out    DX, AL            ; AL contains data to be written to port
  208.     ENDM
  209.  
  210. ReceiveHeaderStructure    struc
  211.    RReceiveStatus    db    ?
  212.    RNextBuffer        db    ?
  213.    RByteCount        dw    ?
  214.  
  215.    RDestinationAddress    db    6 dup(?)
  216.    RSourceAddress    db    6 dup(?)
  217.    RPacketLength    dw    ?
  218.    RChecksum        dw    ?
  219.    RRPacketLength    dw    ?
  220.    RTranControl        db    ?
  221.    RHPacketType        db    ?
  222.    RDestinationNet    db    4 dup(?)
  223.    RDestinationNode    db    6 dup(?)
  224.    RDestinationSocket    dw    ?
  225. ReceiveHeaderStructure    ends
  226.  
  227. ReceiveHeader    ReceiveHeaderStructure    <>
  228.  
  229. BLUEBOOK    equ    1
  230. IEEE8023    equ    11h
  231.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  232. driver_class    db    BLUEBOOK, 0    ;from the packet spec
  233. driver_type    dw    53        ;Wild card matches any type
  234. driver_name    db    'NE1000',0    ;name of the driver.
  235. driver_function    db    2
  236. parameter_list    label    byte
  237.     db    1    ;major rev of packet driver
  238.     db    9    ;minor rev of packet driver
  239.     db    14    ;length of parameter list
  240.     db    EADDR_LEN    ;length of MAC-layer address
  241.     dw    GIANT    ;MTU, including MAC headers
  242.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  243.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  244.     dw    0    ;(# of successive xmits) - 1
  245.     dw    0    ;Interrupt # to hook for post-EOI
  246.             ;processing, 0 == none,
  247.  
  248.     public    rcv_modes
  249. rcv_modes    dw    4        ;number of receive modes in our table.
  250.         dw    0,0,0,rcv_mode_3
  251.  
  252.     public    send_pkt
  253. send_pkt:
  254. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  255. ;  (only if the high-performance bit is set in driver_function)
  256. ;enter with ds:si -> packet, cx = packet length.
  257. ;exit with nc if ok, or else cy if error, dh set to error number.
  258.     assume    ds:nothing
  259. ; get txblk length                          
  260.     inc    cx
  261.     and    cl, 0feh
  262.     cmp    CX, RUNT
  263.     jnb    length_ok
  264.     mov    cx, RUNT
  265. length_ok:
  266.     cmp    cx, GIANT
  267.     jbe    length1_ok
  268.     mov    dh, NO_SPACE
  269.     stc    
  270.     jmp    count_out_err
  271. length1_ok:
  272. ;new stuff
  273.     mov    AX, CX
  274.     wr_NE    TBCR0            ; Transmit byte count
  275.     mov    al, ah
  276.     wr_NE    TBCR1
  277.     mov    al, 0
  278.     wr_NE    RSAR0
  279.     mov    al, 20h
  280.     wr_NE    RSAR1
  281.     mov    ax, cx
  282.     wr_NE    RBCR0            ; Remote byte count
  283.     mov    al, ah
  284.     wr_NE    RBCR1
  285.  
  286.  
  287. ; Clear out DMA complete interrupt
  288.     mov    al, MSK_PG0        
  289.     wr_NE    CMDR
  290.     mov    al, 40h
  291.     wr_NE    ISR
  292.  
  293.     mov    al, MSK_DMA_WR
  294.     wr_NE    CMDR
  295.  
  296.     mov    DX, CS:io_addr
  297.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  298.  
  299.     cmp    is_186,0    ; Can we use rep outsb?
  300.     je    out86        ; no - have to do it slowly.
  301.     db    0f3h, 06eh    ;masm 4.0 doesn't grok "rep outsb"
  302.     jmp    short ocnteven
  303. out86:
  304.     test    si,1        ; (buf & 1) ?
  305.     jz    obufeven    ; no
  306.     lodsb            ; al = *si++;
  307.     out    dx,al        ; out(dx,al);
  308.     dec    cx        ; cx--;
  309. obufeven:
  310.     mov    di,cx        ; save for later test
  311.     shr    cx,1        ; cx = cnt >> 1; (convert to word count)
  312. ; Do the bulk of the buffer, a word at a time
  313.     jcxz    onobuf        ; if(cx != 0){
  314. xb:    lodsw            ; do { ax = *si++; (si is word pointer)
  315.     out    dx,al        ; out(dx,lowbyte(ax));
  316.     mov    al,ah
  317.     out    dx,al        ; out(dx,hibyte(ax));
  318.     loop    xb        ; } while(--cx != 0); }
  319. ; now check for odd trailing byte
  320. onobuf:    shr    di,1        ; if (di & 1)
  321.     jnc    ocnteven
  322.     lodsb            ;   out(dx,*si++);
  323.     out    dx,al
  324. ocnteven:
  325.     mov    cx, 1000h        ; Prevent infinite loop
  326. WaitForDMAComplete:
  327.     rd_NE    ISR
  328.     test    al, 40h
  329.     jnz    DMAComplete
  330.     loop    WaitForDMAComplete
  331.  
  332. DMAComplete:
  333.     mov    al, MSK_TXP
  334.     wr_NE    CMDR
  335.     clc
  336. exit_now:
  337.     ret
  338.  
  339.  
  340.     public    get_address
  341. get_address:
  342. ;get the address of the interface.
  343. ;enter with es:di -> place to get the address, cx = size of address buffer.
  344. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  345.     assume    ds:code
  346.     cmp cx,    EADDR_LEN    ; Caller wants a reasonable length?
  347.     jb    get_addr_x    ; No, fail.
  348.     mov cx,    EADDR_LEN    ; Yes. Set count for loop
  349.     mov    si, offset cs:my_eaddr
  350.     cld            ; Make sure string mode is right
  351.     rep    movsb
  352.     mov cx,    EADDR_LEN    ; Tell caller how many bytes we fed him
  353.     clc            ; Carry off says success
  354.     ret
  355. get_addr_x:
  356.     stc            ; Tell caller our addr is too big for him
  357.     ret
  358.  
  359.  
  360.     public    set_address
  361. set_address:
  362. ;enter with ds:si -> Ethernet address, CX = length of address.
  363. ;exit with nc if okay, or cy, dh=error if any errors.
  364. ;This proc will set the first CX bytes of the ethernet address, leaving
  365. ; the rest unchanged.
  366.     assume    ds:nothing
  367.  
  368.     cmp    cx, 6
  369.     jbe    set1
  370.     mov    dh, BAD_ADDRESS
  371.     stc
  372.     ret
  373. set1:
  374.     push    es
  375.     push    di
  376.     mov    di, offset my_eaddr
  377.     mov    ax, cs
  378.     mov    es, ax
  379.  
  380.     mov    al, 61h
  381.     wr_NE    CMDR
  382.     mov    DX, CS:io_addr
  383.     add    DX, PAR0        ; DX has address 8390 Phys Address Reg
  384. AddressToChip1:
  385.     lodsb
  386.     out    dx, al
  387.     mov    es:[di], al
  388.     inc    di
  389.     inc    dx
  390.     nop
  391.     nop
  392.     nop    
  393.     nop
  394.     loop    AddressToChip1
  395.     pop    di
  396.     pop    es
  397.  
  398.     mov     al, 21h
  399.     wr_NE     CMDR
  400.     clc
  401.     ret
  402.  
  403.  
  404. rcv_mode_3:
  405. ;receive mode 3 is the only one we support, so we don't have to do anything.
  406.     ret
  407.  
  408.  
  409.     public    set_multicast_list
  410. set_multicast_list:
  411. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  412. ;return nc if we set all of them, or cy,dh=error if we didn't.
  413.     mov    dh,NO_MULTICAST
  414.     stc
  415.     ret
  416.  
  417.  
  418.     public    terminate
  419. terminate:
  420.     ret
  421.  
  422.     public    reset_interface
  423. reset_interface:
  424. ;reset the interface.
  425.     assume    ds:code
  426.     mov    al, MSK_STP + MSK_RD2    
  427.     wr_NE    CMDR
  428.     mov al,    0ffh        ; Clear all pending interrupts
  429.     wr_NE    ISR
  430.     xor al,    al        ; Turn off all enables
  431.     wr_NE    IMR
  432.     rd_NE   NERESET        ; Hard reset NE1000
  433.     wr_NE   NERESET
  434.     ret
  435.  
  436.  
  437. ;called when we want to determine what to do with a received packet.
  438. ;enter with cx = packet length, es:di -> packet type.
  439. ;It returns with es:di = 0 if don't want this type or if no buffer available.    
  440.     extrn    recv_find: near
  441.  
  442. ;called after we have copied the packet into the buffer.
  443. ;enter with ds:si ->the packet, cx = length of the packet.
  444.     extrn    recv_copy: near
  445.  
  446.     extrn    count_in_err: near
  447.     extrn    count_out_err: near
  448.  
  449.  
  450.     public    recv
  451. recv:
  452. ;called from the recv isr.  All registers have been saved, and ds=cs.
  453. ;Actually, not just receive, but all interrupts come here.
  454. ;Upon exit, the interrupt will be acknowledged.
  455.     assume    ds:code
  456.  
  457. ; read irq status register
  458.  
  459. rd_isr:
  460.     rd_NE    ISR            ; read isr into AL
  461.     and    AL, 3Fh            ; check bit0-bit5, if all 1's no irq
  462.     cmp    AL, 0            ; if any irq
  463.     jne    tst_ovw            ; some irq
  464.     ret                ; no more irq, exit
  465.  
  466. ; process OVW    (OVW = 1)       
  467. ;    may report error here
  468. tst_ovw:
  469.     test    AL, MSK_OVW        ; if OVW irq
  470.     jnz    prcs_ov            ; OVW (OVW = 1) 
  471.     jmp    test_rx            ; no OVW (OVW = 0) 
  472.  
  473. ; **************************************************************
  474. ; follow the DP8390 datasheet addendum to handle the buff ring overflow
  475. prcs_ov:
  476. ; 1. issue a STOP mode command
  477.     mov    AL, MSK_STP + MSK_RD2
  478.     wr_NE    CMDR
  479.     jmp    $+2
  480. ; 6. remove one packet from the ring
  481.     rd_NE    BNRY            ; BNRY in AL
  482.     add    AL, 1            ; start page of frm in AL
  483.     cmp    AL, STOP_PG        ; check boundary
  484.         jne    get1
  485.     mov    AL, START_PG        
  486. ; ring not empty
  487. get1:
  488.     mov    BH, AL            ; BX has the rx_frm pointer
  489.  
  490.     mov    al, SIZE ReceiveHeader
  491.     wr_NE    RBCR0
  492.     xor    al, al
  493.     jmp    $+2
  494.     wr_NE    RBCR1
  495.     jmp    $+2
  496.     wr_NE    RSAR0
  497.     mov    al, bh
  498.     wr_NE    RSAR1
  499.     mov    al, MSK_DMA_RD
  500.     wr_NE    CMDR
  501.  
  502.     mov    DX, CS:io_addr
  503.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  504.     mov    di, OFFSET ReceiveHeader
  505.     mov    ax, cs
  506.     mov    es, ax
  507.     mov    cx, SIZE ReceiveHeader
  508.     
  509. Receive1:
  510.     in    al, dx
  511.     stosb
  512.     loop    Receive1
  513.  
  514. SkipReceive1:
  515.     mov    bx, offset ReceiveHeader
  516.     mov    AL, CS:[BX]        ; AL has the status byte
  517.     test    AL, SMK_PRX        ; if rx good
  518.     jz    fd_bnr            ; rx error, drop frm by forward bnry
  519.  
  520. ; good frm, call _rcv_frm
  521.     call     _rcv_frm           
  522.  
  523. fd_bnr:                    ;drop frm by forward BNRY
  524.     mov    al, cs:ReceiveHeader.RNextBuffer    ; al = next pointer 
  525.     sub    AL, 1            ; new BNRY in AL
  526.     cmp    AL, START_PG        ; check boundary
  527.     jae    wrbnr            ; unsigned arithmetic
  528.     mov    AL, STOP_PG        ;
  529.     dec    AL            ;
  530. wrbnr:
  531.     wr_NE    BNRY
  532.     jmp    $+2            ;
  533. ; 2. clear the remote byte count registers (RBCR0,RBCR1)
  534.     xor    AL, AL
  535.     wr_NE    RBCR0
  536.     jmp    $+2            ;
  537.     wr_NE    RBCR1
  538.     jmp    $+2            ;
  539. ; 3. poll the ISR for the RST bit
  540. plisr:
  541.     rd_NE    ISR
  542.     jmp    $+2            ;
  543.     test    AL, MSK_RST
  544.     jz    plisr        ; keep polling until the RST bit set
  545. ; 4. place the NIC in loopback mode (mode 1 or 2) by writing 02 or 04 to TCR
  546.     mov    AL, 02h        ; put it in mode 2 (internal loopback)
  547.     wr_NE    TCR
  548.     jmp    $+2            ;
  549. ; 5. issue start mode command
  550.     mov    AL, MSK_STA + MSK_RD2
  551.     wr_NE    CMDR
  552.     jmp    $+2            ;
  553. ; 7. out from loopback mode by writing 00 to TCR
  554.     xor    AL, AL
  555.     wr_NE    TCR        ; normal operation configuration
  556.     jmp    $+2            ;
  557. ; clear OVW in ISR              
  558.     mov    AL, MSK_OVW 
  559.     wr_NE    ISR            ; clear OVW
  560.     call    count_in_err        ; increment overflow counter
  561.     jmp    rd_isr            ; back to the top
  562.  
  563.  
  564. ; end of the modification 
  565. ; *****************************************************
  566. ;    
  567. ;process PRX and RXE
  568. ;
  569. test_rx:        
  570.     test      AL, MSK_PRX    
  571.     jnz    prcs_rx                 ; PRX = 1
  572.     test     AL, MSK_RXE        
  573.     jnz    prcs_rxe        ; RXE = 1
  574.     jmp    test_tx
  575.  
  576. prcs_rxe:
  577.     call    count_in_err
  578. prcs_rx:
  579.     mov    AL, MSK_PG1 + MSK_RD2    ; read CURR reg
  580.     wr_NE    CMDR
  581.     jmp    $+2
  582.     rd_NE    CURR
  583.     jmp    $+2
  584.     mov    BL, AL            ; CURR in BL 
  585.     mov    AL, MSK_PG0 + MSK_RD2    ; read BNRY reg
  586.     wr_NE  CMDR
  587.     jmp    $+2
  588.     rd_NE    BNRY            ; BNRY in AL
  589.     add    AL, 1            ; start page of frm in AL
  590.     cmp    AL, STOP_PG         ; check boundary
  591.     jne    go_cmp
  592.     mov    AL, START_PG         ;         
  593. go_cmp:
  594.     cmp    AL, BL            
  595.     je    end_rx            ; buff ring empty
  596.  
  597. ; Ring Not Empty
  598.     wr_NE    RSAR1
  599.     jmp    $+2
  600.     xor    al, al
  601.     jmp    $+2
  602.     wr_NE    RBCR1
  603.     jmp    $+2
  604.     wr_NE    RSAR0
  605.     mov    al, SIZE ReceiveHeader
  606.     wr_NE    RBCR0
  607.     mov    al, MSK_DMA_RD
  608.     wr_NE    CMDR
  609.  
  610.     mov    DX, CS:io_addr
  611.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  612.     mov    di, OFFSET ReceiveHeader
  613.     mov    ax, cs
  614.     mov    es, ax
  615.     mov    cx, SIZE ReceiveHeader
  616.  
  617. Receive2:
  618.     in    al, dx
  619.     stosb
  620.     loop    Receive2
  621.  
  622. SkipReceive2:
  623.     mov    bx, offset ReceiveHeader
  624.     mov    AL, CS:[BX]        ; AL has the status byte
  625.     test    AL, SMK_PRX        ; if rx good
  626.     jz    fd_bnry            ; rx error, drop frm by forward bnry
  627.  
  628. ; good frm, call _rcv_frm
  629.        call     _rcv_frm           
  630.  
  631. fd_bnry:                ; drop frm by forward BNRY
  632.     mov    al, CS:ReceiveHeader.RNextBuffer    ; al = next pointer 
  633.     sub    AL, 1            ; new BNRY in AL
  634.     cmp    AL, START_PG        ; check boundary
  635.     jae    wrbnry            ; unsigned arithmetic
  636.     mov    AL, STOP_PG        ;
  637.     dec    AL            ;
  638. wrbnry:
  639.     wr_NE    BNRY
  640.     jmp    prcs_rx     
  641.        
  642. ; clear PRX, RXE, OVW in ISR              
  643. end_rx:
  644.     mov    AL, MSK_OVW + MSK_RXE + MSK_PRX
  645.     wr_NE    ISR            ; clear OVW, RXE, PRX
  646.     jmp    rd_isr            ; back to the top
  647.  
  648. ;process PTX and TXE
  649. test_tx:
  650.     test      AL, MSK_PTX    
  651.     jnz    prc_ptx                 ; PTX = 1
  652.     test     AL, MSK_TXE        
  653.     jnz    prc_txe            ; TXE = 1
  654.     jmp    test_cnt
  655.       
  656.  
  657. ; process tx good, update txok, lostcrs, collsn
  658. prc_ptx:                ; tx good 
  659.     rd_NE    TSR
  660.     test    AL, SMK_CRS        ; is crs set in TSR
  661.     jz    nocrs            ; no               
  662. nocrs:    
  663.     rd_NE    NCR            ; read number of collision in AL
  664.     mov    AL, MSK_PTX
  665.     wr_NE    ISR            ; clear PTX
  666.     jmp    rd_isr
  667.  
  668. ; process tx error, update .txbad .underrun
  669. prc_txe:                ; tx bad
  670.     call    count_out_err    
  671.     rd_NE    TSR
  672.     test    AL, SMK_FU        ; it fu set in TSR
  673.     jz    nofu            ; no               
  674. nofu:                                  
  675.         mov    AL, MSK_TXE
  676.     wr_NE    ISR            ; clear PTX
  677.     jmp    rd_isr
  678.  
  679. ; process counter overflow, update .algerr .crcerr .???(missed pkt)
  680. test_cnt:
  681.     test      AL, MSK_CNT    
  682.     jnz    prc_cnt            ; yes, process cnt
  683.     jmp    rd_isr                 ; no CNT irq, back to the top
  684. ; process CNT            
  685. prc_cnt:
  686.     mov    AL, MSK_CNT
  687.     wr_NE    ISR            ; clear CNT
  688.     jmp    rd_isr            ; back to the top
  689.  
  690. ; End of RECV
  691.  
  692. _rcv_frm:
  693.     
  694. ; read byte count 
  695.     mov     cx, cs:ReceiveHeader.RByteCount    ; Extract size of frame
  696.     cmp    CX, 5dch
  697.     jna    rxlen_ok
  698.     jmp    rcv_ret
  699. rxlen_ok:
  700.     sub    CX, 4            ; 4 control bytes
  701.     mov    AX, cs
  702.     mov    ES, AX
  703.     mov     di, offset cs:ReceiveHeader.RPacketLength
  704.  
  705.     push    cx            ; Save frame size
  706.     push    es
  707.  
  708.     mov ax,    cs            ; Set ds = code
  709.     mov ds,    ax
  710.     assume    ds:code
  711.     call    recv_find        ; See if type and size are wanted
  712.                     ;     CX = packet length
  713.                     ;    ES:DI = packet type
  714.  
  715.     pop    ds            ; RX page pointer in ds now
  716.     assume    ds:nothing
  717.     pop    cx
  718.  
  719.     cld                ; Copies below are forward
  720.     mov ax,    es            ; Did recv_find give us a null pointer?
  721.     or  ax,    di            ; ..
  722.     je    no_buff            ; If null, don't copy the data    
  723. has_buf:  
  724.  
  725. ;Tell DMA to copy the whole packet for us
  726.     mov    ax, 4
  727.     wr_NE    RSAR0        ; Don't copy  4 8390 control bytes
  728.     mov    ax, cx        ; CX has byte count
  729.     wr_NE    RBCR0        ; LSB first
  730.     mov    al, ah
  731.     wr_NE    RBCR1        ; Now MSB
  732.  
  733.     mov    al, MSK_DMA_RD  ; Issue DMA read command
  734.     wr_NE    CMDR
  735.  
  736. ; copy from NE1000 on board memory using the window RACK
  737. ; use IN and stosb to do the copy, IN -> AX -> ES:DI (CX has byte count)                        
  738.  
  739. copynow:
  740.     push    cx        ; We will want the count and pointer
  741.     push    es        ;  to hand to client after copying,
  742.     push    di        ;  so save them at this point
  743.  
  744.     mov    DX, CS:io_addr
  745.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  746.  
  747.     cmp    is_186,0    ; Can we use rep insb?
  748.     je    in86        ; no - have to do it slowly.
  749.     db    0f3h, 06ch    ;masm 4.0 doesn't grok "rep insb"
  750.     jmp    short icnteven
  751. in86:
  752. ; If buffer doesn't begin on a word boundary, get the first byte
  753.     test    di,1    ; if(buf & 1){
  754.     jz    ibufeven ;
  755.     in    al,dx    ; al = in(dx);
  756.     stosb        ; *di++ = al
  757.     dec    cx    ; cx--;
  758. ibufeven:
  759.     mov    si,cx    ; size = cx;
  760.     shr    cx,1    ; cx = cnt >> 1; (convert to word count)
  761. ; Do the bulk of the buffer, a word at a time
  762.     jcxz    inobuf    ; if(cx != 0){
  763. rb:    in    al,dx    ; do { al = in(dx);
  764.     mov    ah,al
  765.     in    al,dx    ; ah = in(dx);
  766.     xchg    al,ah
  767.     stosw        ; *si++ = ax; (di is word pointer)
  768.     loop    rb    ; } while(--cx != 0);
  769. ; now check for odd trailing byte
  770. inobuf:    shr    si,1
  771.     jnc    icnteven
  772.     in    al,dx
  773.     stosb        ; *di++ = al
  774. icnteven:
  775.  
  776. call_rc:
  777.     pop    si            ; Recover pointer to destination
  778.     pop    ds            ; Tell client it's his source
  779.     pop    cx            ; And it's this long
  780.     assume    ds:nothing
  781.     call    recv_copy        ; Give it to him
  782.     jmp    short rcv_ret
  783.  
  784. ; no system buff availble to hold rx frm
  785. no_buff:
  786. rcv_ret:
  787.     push    cs        ; Put ds back in code space
  788.     pop    ds        ; ..
  789.     assume    ds:code
  790.     ret
  791.  
  792.  
  793.  
  794.     public    recv_exiting
  795. recv_exiting:
  796. ;called from the recv isr after interrupts have been acknowledged.
  797. ;Only ds and ax have been saved.
  798.     assume    ds:nothing
  799.     ret
  800.  
  801.  
  802. ;any code after this will not be kept after initialization.
  803. end_resident    label    byte
  804.  
  805.  
  806.     public    usage_msg
  807. usage_msg    db    "usage: NE1000 <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
  808.  
  809.     public    copyright_msg
  810. copyright_msg    db    "Packet driver for NE1000, version "
  811.         db    '0'+majver,".",'0'+version,CR,LF
  812.         db    "Portions Copyright 1989, Eric Henderson, BYU",CR,LF,'$'
  813. int_no_name    db    "Interrupt number ",'$'
  814. io_addr_name    db    "I/O port ",'$'
  815. no_board_msg:
  816.     db    "NE1000 apparently not present at this IO address.",CR,LF,'$'
  817. HardwareFailure:
  818.     db    "The NE1000 is not responding.",CR,LF,'$'
  819. using_186_msg    db    "Using 80[123]86 I/O instructions.",CR,LF,'$'
  820.  
  821.     extrn    set_recv_isr: near
  822.  
  823. ;enter with si -> argument string, di -> word to store.
  824. ;if there is no number, don't change the number.
  825.     extrn    get_number: near
  826.  
  827. ;enter with dx -> name of word, di -> dword to print.
  828.     extrn    print_number: near
  829.  
  830.     public    parse_args
  831. parse_args:
  832. ;exit with nc if all went well, cy otherwise.
  833.     mov    di,offset int_no
  834.     call    get_number
  835.     mov    di,offset io_addr
  836.     call    get_number
  837.     clc
  838.     ret
  839.  
  840.     extrn    etopen_diagn: byte
  841.  
  842. BoardNotResponding:
  843.     mov    dx, offset HardwareFailure
  844.     mov    etopen_diagn, 35
  845.     jmp    short error_wrt
  846. bad_cksum:
  847. no_memory:
  848.     mov    dx,offset no_board_msg
  849.     mov    etopen_diagn,37
  850. error_wrt:
  851.     mov    ah,9
  852.     int    21h
  853.     stc
  854.     ret
  855.  
  856.     public    etopen
  857. etopen:
  858. ;if all is okay,
  859.  
  860.     ; reset NE1000 board 
  861.     rd_NE    NERESET
  862.     wr_NE    NERESET
  863.     mov    al, 21h
  864.     wr_NE    CMDR
  865.  
  866.     ; Test to see if we're OK
  867.     rd_NE    CMDR
  868.     cmp    al, 21h
  869.     je    WeBeOK
  870.     jmp    BoardNotResponding
  871.  
  872. WeBeOK:
  873.     mov    al, 0
  874.     wr_NE    DCR        
  875.     mov    al, 60h
  876.     wr_NE    TPSR        
  877.     mov    al, 0
  878.     wr_NE    TCR        
  879.     mov    al, 20h
  880.     wr_NE    RCRWD        
  881.     mov    al, 4
  882.     wr_NE    PSTART        
  883.     mov    al, 4
  884.     wr_NE    BNRY        
  885.     mov    al, 0ffh
  886.     wr_NE    PSTOP        
  887.     mov    al, 3ch
  888.     wr_NE    TBCR0        
  889.     mov    al, 0
  890.     wr_NE    TBCR1        
  891.     mov    al, 0ffh
  892.     wr_NE    ISR        
  893.     mov    al, 61h
  894.     wr_NE    CMDR        
  895.     mov    al, 4
  896.     wr_NE    CURR        
  897.     mov    al, 22h
  898.     wr_NE    CMDR        
  899.  
  900.     ; Test to see if we're still OK
  901.     rd_NE    CMDR
  902.     cmp    al, 22h
  903.     je    WeBeStillOK
  904.     jmp    BoardNotResponding
  905.  
  906. WeBeStillOK:
  907.  
  908.     ; set up my_eaddr from addr ROM 
  909.     mov    al, 21h
  910.     wr_NE    CMDR
  911.     mov    al, 6
  912.     wr_NE    RBCR0
  913.     mov    al, 0
  914.     wr_NE    RBCR1
  915.     wr_NE    RSAR0
  916.     wr_NE    RSAR1
  917.     mov    al, MSK_DMA_RD
  918.     wr_NE    CMDR
  919.  
  920.     mov    DX, CS:io_addr
  921.     add    DX, RACK        ; DX has address NE1000 Port window (?)
  922.     mov    di, OFFSET my_eaddr
  923.     mov    ax, cs
  924.     mov    es, ax
  925.     mov    cx, 6
  926. GetEnetAddress:
  927.     in    al, dx
  928.     stosb
  929.     loop    GetEnetAddress
  930.  
  931.     mov    ax, cs
  932.     mov    ds, ax
  933.     mov    si, OFFSET my_eaddr
  934.     mov    cx, 6
  935.     call    set_address
  936.  
  937.     mov     al, 21h
  938.     wr_NE     CMDR
  939.  
  940.     mov    al, START_PG
  941.     jmp    $+2
  942.     wr_NE    PSTART
  943.     jmp    $+2
  944.     wr_NE    BNRY
  945.     mov    al, STOP_PG
  946.     jmp    $+2
  947.     wr_NE    PSTOP
  948.  
  949.     mov    al, 61h
  950.     jmp    $+2
  951.     wr_NE    CMDR
  952.     mov    al, START_PG + 1
  953.     jmp    $+2
  954.     wr_NE    CURR
  955.     mov    al, 21h
  956.     jmp    $+2
  957.     wr_NE    CMDR
  958.  
  959.     mov     al, 48h
  960.     jmp    $+2
  961.     wr_NE    DCR
  962.     mov    al, 0
  963.     jmp    $+2
  964.     wr_NE    TCR
  965.     mov    al, MSK_RXE
  966.     jmp    $+2
  967.     wr_NE    RCRWD
  968.     mov    al, 0ffh
  969.     jmp    $+2
  970.     wr_NE    ISR
  971.     mov    al, UnmaskByte
  972.     jmp    $+2
  973.     wr_NE    InterruptMask
  974.  
  975. ;Determine the processor type.  The 8088 and 8086 will actually shift ax
  976. ;over by 33 bits, while the 80[123]86 use a shift count mod 32.
  977.     mov    cl,33
  978.     mov    ax,0ffffh
  979.     shl    ax,cl
  980.     jz    not_186
  981.     mov    is_186,1
  982.     mov    dx,offset using_186_msg
  983.     mov    ah,9
  984.     int    21h
  985. not_186:
  986.  
  987.     call    set_recv_isr    ; Put ourselves in interrupt chain
  988.     
  989.     mov    al, 22h
  990.     jmp    $+2
  991.     wr_NE    CMDR    
  992.  
  993.     mov    di,offset int_no
  994.     mov    dx,offset int_no_name
  995.     call    print_number
  996.     mov    di,offset io_addr
  997.     mov    dx,offset io_addr_name
  998.     call    print_number
  999.  
  1000.     mov    dx,offset end_resident
  1001.     clc
  1002.     ret
  1003.  
  1004. code    ends
  1005.  
  1006.     end
  1007.