home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / packetdrivers.tar.gz / pd.tar / src / znote.asm < prev   
Assembly Source File  |  1995-06-25  |  28KB  |  1,128 lines

  1. version    equ    5
  2. ;History:183,1
  3.  
  4. comment \
  5.  
  6. On a 386/33, run 2.03 as a server.
  7.  
  8. e=137.143.201.3,1500,5 f=1 gives 1 % loss with a colon and MUCH delay.
  9. e=137.143.201.3,1500,6 f=1 gives 17 % loss and hard-crashes the machine.
  10. e=137.143.201.3,1500,7 f=1 gives zero packet loss.
  11.  
  12. \
  13.  
  14.  
  15. ;  Copyright, 1988-1992, Russell Nelson, Crynwr Software
  16.  
  17. ;   This program is free software; you can redistribute it and/or modify
  18. ;   it under the terms of the GNU General Public License as published by
  19. ;   the Free Software Foundation, version 1.
  20. ;
  21. ;   This program is distributed in the hope that it will be useful,
  22. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24. ;   GNU General Public License for more details.
  25. ;
  26. ;   You should have received a copy of the GNU General Public License
  27. ;   along with this program; if not, write to the Free Software
  28. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  29.  
  30.     .286                ;it's a 16-bit adapter.
  31.  
  32.     include    defs.asm
  33.  
  34. pause_    macro
  35. ;    jmp    $+2
  36. ;
  37. ; The reason for the pause_ macro is to establish a minimum time between
  38. ; accesses to the card hardware. The assumption is that the fetch and execution
  39. ; of the jmp $+2 instruction will provide this time. In a fast cache machine
  40. ; this may be a false assumption. In a fast cache machine, there may be 
  41. ; NO REAL TIME DIFFERENCE between the two I/O instruction streams below:
  42. ;
  43. ;    in    al,dx        in    al,dx
  44. ;    jmp    $+2
  45. ;    in    al,dx        in    al,dx
  46. ;
  47. ; To establish a minimum delay, an I/O instruction must be used. A good rule of
  48. ; thumb is that ISA I/O instructions take ~1.0 microseconds and MCA I/O
  49. ; instructions take ~0.5 microseconds. Reading the NMI Status Register (0x61)
  50. ; is a good way to pause on all machines.
  51. ;
  52. ; The National 8390 Chip (NIC) requires 4 bus clocks between successive
  53. ; chip selects (National DP8390 Data Sheet Addendum, June 1990 -- it took them
  54. ; long enough to figure this out and tell everyone) or the NIC behaves badly.
  55. ; Therefor one I/O instruction should be inserted between each successive
  56. ; NIC I/O instruction that could occur 'back - to - back' on a fast cache
  57. ; machine.
  58. ;   - gft - 910529
  59. ;
  60.     push    ax
  61.     in    al, 61h
  62.     pop    ax
  63. ;
  64. endm
  65.  
  66. ; DMA controller registers
  67. DMA_BASE    equ    0c0h        ; DMA controller base
  68. DMA_STAT    equ    0D0h        ; DMA controller status register
  69. DMA_MASK        equ    0D4h        ; DMA controller mask register
  70. DMA_MODE        equ    0D6h        ; DMA controller mode register
  71. DMA_RESETFF    equ    0D8h        ; DMA controller first/last flip flop
  72.  
  73. ; DMA data
  74. DMA_DISABLE     equ    04h        ; Disable channel n
  75. DMA_ENABLE    equ    00h        ; Enable channel n
  76. ; Demand transfers, incr. address, auto init, writes, ch. n
  77. DMA_RX_MODE    equ    14h
  78. ; Demand transfers, incr. address, auto init, reads, ch. n
  79. DMA_TX_MODE     equ    18h
  80.  
  81. ;82593 port 0 bits
  82. CMD0_CHNL_0    equ    0
  83. CMD0_CHNL_1    equ    10h
  84. CMD0_ACK    equ    80h
  85. CMD0_STAT0    equ    0
  86. CMD0_STAT1    equ    20h
  87. CMD0_STAT2    equ    40h
  88. CMD0_STAT3    equ    60h
  89. ;commands (bits 3-0)
  90. CMD0_NOP    equ    0+CMD0_CHNL_0
  91. CMD0_PORT_1    equ    0+CMD0_CHNL_1
  92. CMD0_IA_SETUP    equ    1
  93. CMD0_CONFIGURE    equ    2
  94. CMD0_MC_SETUP    equ    3
  95. CMD0_TRANSMIT    equ    4
  96. CMD0_TDR    equ    5
  97. CMD0_DUMP    equ    6
  98. CMD0_DIAGNOSE    equ    7
  99. CMD0_RCV_ENABLE    equ    8
  100. CMD0_TRANSMIT_NC    equ    9
  101. CMD0_RCV_DIABLE    equ    10
  102. CMD0_STOP_RCV    equ    11
  103. CMD0_RETRANSMIT    equ    12
  104. CMD0_ABORT    equ    13
  105. CMD0_RESET    equ    14
  106. CMD0_RLS_PTR    equ    15+CMD0_CHNL_0
  107. CMD0_FIX_PTR    equ    15+CMD0_CHNL_1
  108.  
  109. ;82593 port 1 commands
  110. CMD1_NOP    equ    0
  111. CMD1_PORT_0    equ    1
  112. CMD1_DISABLE    equ    2
  113. CMD1_ENABLE    equ    3
  114. CMD1_SET_TS    equ    5
  115. CMD1_RST_TS    equ    7
  116. CMD1_POWER_DN    equ    8
  117. CMD1_RST_RING    equ    11
  118. CMD1_RESET    equ    14
  119.  
  120. ;82593 events
  121. IA_SETUP_DONE        equ    1
  122. CONFIGURE_DONE        equ    2
  123. MC_SETUP_DONE        equ    3
  124. TRANSMIT_DONE        equ    4
  125. TDR_DONE        equ    5
  126. DUMP_DONE        equ    6
  127. DIAGNOSE_PASSED        equ    7
  128. END_OF_FRAME        equ    8
  129. TRANSMIT_NC_DONE    equ    9
  130. RECEPTION_ABORTED    equ    10
  131. STOP_REG_HIT        equ    11
  132. RETRANSMIT_DONE        equ    12
  133. EXECUTION_ABORTED    equ    13
  134. DIAGNOSE_FAILED        equ    15
  135.  
  136. ;ID block contained in memory in the 64K block at f000:0
  137. id_block    struc
  138. header        db 8 dup (?)
  139. netid        db 8 dup (?)
  140. nettype     db ?
  141. globalopt    db ?
  142. vendor        db 8 dup (?)
  143. product     db 8 dup (?)
  144. intr1        db ?
  145. intr2        db ?
  146. dma1        db ?
  147. dma2        db ?
  148. membase1    dw 2 dup (?)
  149. memsize1    dw 2 dup (?)
  150. membase2    dw 2 dup (?)
  151. memsize2    dw 2 dup (?)
  152. iobase1     dw ?
  153. iosize1     dw ?
  154. iobase2     dw ?
  155. iosize2     dw ?
  156. driveropt    db ?
  157. reservednib    db ?
  158. id_block    ends
  159.  
  160.  
  161. GOODRECEIVE    equ  2000h
  162. CRCERROR    equ  0800h
  163. ALIGNMENT    equ  0400h
  164. FIFOOVERRUN    equ  0100h
  165. SHORTFRAME    equ  0080h
  166. RXCOLLISION    equ  0001h
  167.  
  168. ;buffer sizes.
  169. TRANSMIT_BUF_SIZE    equ    2+GIANT+2    ;count plus data plus chain cmd.
  170. RECEIVE_BUF_BITS    equ    12
  171. RECEIVE_BUF_SIZE    equ    2 shl RECEIVE_BUF_BITS
  172. RECEIVE_BUF_2K        equ    (1 shl RECEIVE_BUF_BITS) / 2048    ;in words.
  173.  
  174. code    segment    dword public
  175.     assume    cs:code, ds:code
  176.  
  177.     public    int_no
  178. int_no    db    10,0,0,0        ;must be four bytes long for get_number.
  179. io_addr    dw    300h,0            ;must be four bytes long for get_number.
  180.  
  181.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  182. driver_class    db    BLUEBOOK, IEEE8023, 0        ;from the packet spec
  183. driver_type    db    93        ;assigned by FTP Software, <jbvb@ftp.com>
  184. driver_name    db    'Z-Note',0    ;name of the driver.
  185. driver_function    db    2
  186. parameter_list    label    byte
  187.     db    1    ;major rev of packet driver specification
  188.     db    9    ;minor rev of packet driver specification
  189.     db    14    ;length of parameter list
  190.     db    EADDR_LEN    ;length of MAC-layer address
  191.     dw    GIANT    ;MTU, including MAC headers
  192.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  193.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  194.     dw    0    ;(# of successive xmits) - 1
  195. int_num    dw    0    ;Interrupt # to hook for post-EOI
  196.             ;processing, 0 == none,
  197.  
  198.     public    rcv_modes
  199. rcv_modes    dw    7        ;number of receive modes in our table.
  200.         dw    0               ;There is no mode zero
  201.         dw    0
  202.         dw    rcv_mode_2
  203.         dw    rcv_mode_3
  204.         dw    0
  205.         dw    rcv_mode_5
  206.         dw    rcv_mode_6
  207.  
  208. ;b05
  209. rx_channel    db    ?        ;0-3 (really 4-7).
  210. rx_dma_dest    dw    ?
  211. rx_page_addr    dw    ?
  212.  
  213. tx_channel    db    ?        ;0-3 (really 4-7)
  214. tx_dma_dest    dw    ?
  215. tx_page_addr    dw    ?
  216.  
  217. ;b0f = 0efc
  218. transmit_buf    dw    ?        ;points to transmit buffer.
  219. receive_buf    dw    ?        ;points to receive buffer.
  220. receive_buf_end    dw    ?        ;points to first byte after recv buf.
  221. recv_buf_cnt    dw    ?
  222.  
  223. this_rfp_ptr    dw    ?        ;->rfp we started with
  224. last_rfp_ptr    dw    ?        ;->rfp we from last time.
  225.  
  226.     align    4            ;for efficiency's sake.
  227. packet_type    db    MAX_P_LEN dup(?)
  228.  
  229. ; Standard Ethernet values.  Intel makes them configurable in case Ethernet
  230. ; ever changes.
  231. CBCONF    label    byte
  232.     db    0AAh        ; 1:  16-byte input & 80-byte output FIFO
  233.                 ;     threshhold, 96-byte FIFO, 82593 mode.
  234.     db    088h        ; 2:  Continuous w/interrupts, 128-clock DMA.
  235.     db    02Eh        ; 3:  7-byte preamble, NO address insertion,
  236.                 ;     6-byte Ethernet address, loopback off.
  237.     db    000h        ; 4:  Default priorities & backoff methods.
  238.     db    060h        ; 5:  96-bit interframe spacing.
  239.     db    000h        ; 6:  512-bit slot time (low-order).
  240.     db    0F2h        ; 7:  Slot time (high-order), 15 COLL retries.
  241. CBCONF_FLAGS    label    byte
  242.     db    000h        ; 8:  Promisc-off, broadcast-on, default CRC.
  243.     db    000h        ; 9:  Default carrier-sense, collision-detect.
  244. CBCONF_MINLEN    label    byte
  245.     db    040h        ;10:  64-byte minimum frame length.
  246.     db    05Fh        ;11:  Type/length checks OFF, no CRC input,
  247.                 ;     "jabber" termination, etc.
  248.     db    000h        ;12:  Full-duplex disabled.
  249.     db    03Fh        ;13:  Default multicast addresses & backoff.
  250. CBCONF_MC    label    byte
  251.     db    007h        ;14:  Default IFS retriggering.
  252.     db    031h        ;15:  Internal retransmit, drop "runt" packets,
  253.                 ;     synchr. DRQ deassertion, 6 status bytes.
  254.     db    020h+RECEIVE_BUF_2K    ;16:  Receive ring-buffer size (8K),
  255.                     ;     receive-stop register enable.
  256. CBCONF_LEN    equ    $-CBCONF
  257. .erre    (CBCONF_LEN and 1) eq 0        ;must be an even # of words.
  258.  
  259.     include    movemem.asm
  260.     include    timeout.asm
  261.     .286
  262.  
  263.     public bad_command_intercept
  264. bad_command_intercept:
  265. ;called with ah=command, unknown to the skeleton.
  266. ;exit with nc if okay, cy, dh=error if not.
  267.     mov    dh,BAD_COMMAND
  268.     stc
  269.     ret
  270.  
  271.     public    as_send_pkt
  272. ; The Asynchronous Transmit Packet routine.
  273. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  274. ;   interrupts possibly enabled.
  275. ; Exit with nc if ok, or else cy if error, dh set to error number.
  276. ;   es:di and interrupt enable flag preserved on exit.
  277. as_send_pkt:
  278.     ret
  279.  
  280.     public    drop_pkt
  281. ; Drop a packet from the queue.
  282. ; Enter with es:di -> iocb.
  283. drop_pkt:
  284.     assume    ds:nothing
  285.     ret
  286.  
  287.     public    xmit
  288. ; Process a transmit interrupt with the least possible latency to achieve
  289. ;   back-to-back packet transmissions.
  290. ; May only use ax and dx.
  291. xmit:
  292.     assume    ds:nothing
  293.     ret
  294.  
  295.  
  296.     public    send_pkt
  297. send_pkt:
  298. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  299. ;  (only if the high-performance bit is set in driver_function)
  300. ;enter with ds:si -> packet, cx = packet length.
  301. ;if we're a high-performance driver, es:di -> upcall.
  302. ;exit with nc if ok, or else cy if error, dh set to error number.
  303.     assume    ds:nothing
  304.     cmp    cx,GIANT        ; Is this packet too large?
  305.     ja    send_pkt_toobig
  306.  
  307.     mov    dx,io_addr
  308.     mov    al,CMD0_NOP+CMD0_STAT0    ;point to status 0.
  309.     out    dx,al
  310.     in    ax,dx            ;has the device gotten reset?
  311.     cmp    ax,0010h        ;is the status 10 00 00 00?
  312.     jne    send_pkt_ok        ;no.
  313.     in    ax,dx
  314.     cmp    ax,0000h
  315.     jne    send_pkt_ok        ;no.
  316.     in    ax,dx            ;four bytes of status?
  317.     cmp    ax,0010h        ;do we read 10 00 again?
  318.     jne    send_pkt_ok        ;no.
  319.     push    ds
  320.     push    cx
  321.     push    si
  322.     push    cs
  323.     pop    ds
  324.     call    init_82593
  325.     pop    si
  326.     pop    cx
  327.     pop    ds
  328. send_pkt_ok:
  329.     mov    dx,io_addr
  330.     call    wait_for_done
  331.     push    cs
  332.     pop    es
  333.     mov    di,transmit_buf
  334.     add    di,2            ;leave room for count.
  335.     push    cx
  336.     call    movemem
  337.     pop    cx
  338.     cmp    cx,RUNT            ; minimum length for Ether
  339.     ja    oklen
  340.     mov    cx,RUNT            ; make sure size at least RUNT
  341. oklen:
  342.     mov    di,transmit_buf
  343.     mov    bx,cx
  344.     add    bx,2            ;compute the end of the packet.
  345.                     ;store a NOP for chaining.
  346.     mov    word ptr es:[di][bx],CMD0_NOP*256+CMD0_NOP
  347.     mov    al,CMD0_TRANSMIT + CMD0_CHNL_1
  348.     mov    es:[di],cx
  349.     add    cx,2            ; one more word for chain command.
  350.     call    do_write_command
  351.  
  352.     clc
  353.     ret
  354. send_pkt_toobig:
  355.     mov    dh,NO_SPACE
  356.     stc
  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.     assume    ds:code
  365.     push    cs
  366.     pop    es
  367.     mov    di,transmit_buf
  368.     add    di,2            ;leave room for count.
  369.     repmov    EADDR_LEN
  370.     mov    di,transmit_buf
  371.     mov    al,CMD0_IA_SETUP + CMD0_CHNL_1
  372.     call    do_write_command_cx
  373.     call    wait_for_done
  374.     ret
  375.  
  376.  
  377. rcv_mode_6:
  378.     mov    ax,1            ;set promiscuous mode.
  379.     mov    CBCONF_MINLEN,0        ;allow runts.
  380.     jmp    short reconfigure
  381. rcv_mode_2:
  382.     mov    ax,2            ;disable broadcasts.
  383.     jmp    short reconfigure_min
  384. rcv_mode_5:
  385.     mov    ax,8*256+0        ;clear promiscuous mode, set MC-all.
  386.     jmp    short reconfigure_min
  387. rcv_mode_3:
  388.     mov    ax,0            ;clear promiscuous mode.
  389. reconfigure_min:
  390.     mov    CBCONF_MINLEN,40h
  391. reconfigure:
  392.     and    CBCONF_FLAGS,not 3    ;clear existing,
  393.     or    CBCONF_FLAGS,al        ;  or in new
  394.     and    CBCONF_MC,not 8        ;clear existing,
  395.     or    CBCONF_MC,ah        ;  or in new.
  396.  
  397.     mov    si,offset CBCONF    ;copy the cbconf block in.
  398.     push    cs
  399.     pop    es
  400.     mov    di,transmit_buf
  401.     add    di,2            ;leave room for count.
  402.     mov    cx,CBCONF_LEN/2        ;we already check to be sure it's zero.
  403.     rep    movsw
  404.  
  405.     mov    di,transmit_buf        ;configure from the cbconf.
  406.     mov    cx,CBCONF_LEN
  407.     mov    al,CMD0_CONFIGURE + CMD0_CHNL_1
  408.     call    do_write_command_cx
  409.     call    wait_for_done
  410.     ret
  411.  
  412.  
  413.     public    set_multicast_list
  414. set_multicast_list:
  415. ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
  416. ;  cx = number of bytes.
  417. ;return nc if we set all of them, or cy,dh=error if we didn't.
  418.     mov    dh,NO_MULTICAST
  419.     stc
  420.     ret
  421.  
  422.  
  423.     public    terminate
  424. terminate:
  425.     mov    dx,io_addr
  426.     mov    al,CMD0_RESET
  427.     out    dx,al
  428. ;
  429. ; Turn off 82501
  430. ;
  431.     mov    al,10h
  432.     out    0e6h,al
  433.     in    al,0e7h
  434.     and    al,not (10000100b)    ;Turn off both LAN power and reset bit
  435.     out    0e7h,al
  436.  
  437.     ret
  438.  
  439.  
  440.     public    reset_interface
  441. reset_interface:
  442. ;reset the interface.
  443.     assume    ds:code
  444.     ret
  445.  
  446.  
  447. ;called when we want to determine what to do with a received packet.
  448. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  449.     extrn    recv_find: near
  450.  
  451. ;called after we have copied the packet into the buffer.
  452. ;enter with ds:si ->the packet, cx = length of the packet.
  453.     extrn    recv_copy: near
  454.  
  455. ;enter with dx = amount of memory desired.
  456. ;exit with nc, dx -> that memory, or cy if there isn't enough memory.
  457.     extrn    malloc: near
  458.  
  459.     extrn    count_in_err: near
  460.     extrn    count_out_err: near
  461.  
  462.     public    recv
  463. recv:
  464. ;called from the recv isr.  All registers have been saved, ds=cs,
  465. ;our interrupt has been acknowledged, and our interrupts have been
  466. ;masked at the interrupt controller.
  467.     assume    ds:code
  468.     mov    dx,io_addr
  469.     mov    al,CMD0_NOP + CMD0_STAT0    ;reset pointer to 0
  470.     out    dx,al
  471.     in    al,dx            ;get the event.
  472.     test    al,CMD0_ACK        ;an actual interrupt?
  473.     jne    recv_interrupt
  474.     jmp    recv_exit        ;no.
  475. recv_interrupt:
  476.     test    al,40h            ;recv?
  477.     jne    recv_packet
  478. ;we also need to check for a stop register hit, because the 593 might only
  479. ;report that to us, and not report a received frame.
  480.     and    al,0fh
  481.     cmp    al,STOP_REG_HIT        ;did we overflow the buffer?
  482.     je    recv_packet        ;yes, suck all the packets out.
  483.     mov    al,CMD0_ACK or CMD0_NOP    ;ack the interrupt and leave.
  484.     out    dx,al
  485.     jmp    recv_exit
  486. recv_packet:
  487.     mov    al,CMD0_NOP or CMD0_STAT2;get receive frame pointer (RFP).
  488.     out    dx,al
  489.     in    ax,dx            ;RFP is actually a count of words, so
  490.     shl    ax,1            ;  convert it to a byte count.
  491.  
  492.     mov    di,receive_buf        ;make di -> buffer.
  493.     add    di,ax
  494.     mov    recv_buf_cnt,RECEIVE_BUF_SIZE/64
  495.     mov    this_rfp_ptr,di
  496.     xor    si,si            ;no previous.
  497. ;now we traverse the buffer, looking backwards from the current RFP back
  498. ;to the previous RFP.  When we find a packet, we make a forward pointer
  499. ;by storing si.  We also un-wrap the packet trailer by storing it in place.
  500. ;This is cool because we've allocated an extra 8 bytes of memory
  501. ;to the receive buffer.  We're not being particularly paranoid--if
  502. ;something very bad happens, we might loop forever here.
  503. recv_rfp:
  504.     dec    recv_buf_cnt    ; are we lost in the forest?
  505.     jnz    recv_no_loop
  506.  
  507.     to_scrn    23,79,'g'    ; This occurs now and then!!!
  508.  
  509.     jmp    recv_next    ; a life-saver, otherwise we'll get a hang
  510.  
  511. recv_no_loop:
  512.     call    receive_word        ;get the word of high count.
  513.     mov    ch,al
  514.     call    receive_word        ;get the word of low count.
  515.     mov    cl,al
  516.     call    receive_word        ;get the word of high status.
  517.     mov    bh,al
  518.     call    receive_word        ;get the word of low status.
  519.     mov    bl,al
  520.     sub    cx,2            ;remove the status bytes from count.
  521.     mov    [di+2],bx        ;save the whole status
  522.     mov    [di+4],cx        ;save the whole count.
  523.     mov    [di+6],si        ;store the pointer to the end.
  524.     lea    si,[di+8]        ;remember where block started.
  525.  
  526.     inc    cx            ;round up.
  527.     and    cx,not 1
  528.     sub    di,cx
  529.     cmp    di,receive_buf        ;does it wrap around?
  530.     jae    recv_buf_ok        ;no.
  531.     add    di,RECEIVE_BUF_SIZE    ;yes, wrap it around.
  532. recv_buf_ok:
  533.     cmp    di,last_rfp_ptr        ;did we hit the last one we did?
  534.     jne    recv_rfp        ;no, keep going.
  535.  
  536. ;we get here after making a linked list of packets.  Now we loop forwards
  537. ;processing packets and returning their memory to the 593.
  538.  
  539. recv_again:
  540. ;here with di -> beginning of data, si -> after header.
  541.     mov    cx,[si-4]        ;get the count
  542.     mov    bx,[si-6]        ;get the status.
  543.  
  544.     test    bx,GOODRECEIVE        ;received ok?
  545.     je    recv_err        ;no, discard it.
  546.  
  547.     push    ds
  548.     pop    es
  549.  
  550.     push    si
  551.     push    di
  552.  
  553. ;make a pointer to the packet type
  554.     add    di,EADDR_LEN+EADDR_LEN    ;skip the ethernet addreses and
  555.                     ;  point to the packet type.
  556.     cmp    di,receive_buf_end    ;do we need to wrap?
  557.     jb    recv_type_wrap
  558.     sub    di,RECEIVE_BUF_SIZE
  559. recv_type_wrap:
  560.  
  561. ;does our type overlap the end?
  562.     lea    ax,[di+MAX_P_LEN]
  563.     cmp    ax,receive_buf_end
  564.     jb    recv_type_ok        ;no, we're cool.
  565.  
  566.     push    cx
  567.     mov    si,di            ;uh-oh, we've got to make a copy.
  568.     mov    di,offset packet_type
  569.     mov    cx,MAX_P_LEN
  570.     call    receive_move        ;copy in, wrapping as needed.
  571.     pop    cx
  572.  
  573.     mov    di,offset packet_type
  574. recv_type_ok:
  575.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  576.     mov    ax, es:[di]
  577.     xchg    ah, al
  578.     cmp     ax, 1500
  579.     ja    BlueBookPacket
  580.     inc    di            ;set di to 802.2 header
  581.     inc    di
  582.     mov    dl, IEEE8023
  583. BlueBookPacket:
  584.     push    cx
  585.     call    recv_find
  586.     pop    cx
  587.  
  588.     pop    si            ;(pushed as di).
  589.     pop    bp            ;(pushed as si).
  590.  
  591.     mov    ax,es            ;is this pointer null?
  592.     or    ax,di
  593.     je    recv_free        ;yes - just free the frame.
  594.  
  595.     push    es
  596.     push    di
  597.     push    cx
  598.     call    receive_move        ;copy in, wrapping as needed.
  599.     pop    cx
  600.     pop    si
  601.     pop    ds
  602.     assume    ds:nothing
  603.  
  604.     push    bp
  605.     call    recv_copy
  606.     pop    bp            ;pushed as si originally.
  607.  
  608.     jmp    short recv_free
  609.  
  610. recv_err:
  611.     mov    bp,si
  612.     call    count_in_err
  613. recv_free:
  614.     push    cs
  615.     pop    ds
  616.     assume    ds:code
  617.  
  618. ;We update the stop register now.  We're done with the memory we
  619. ;just sucked the packet out of.  Since we will never look at that packet
  620. ;again, we should release it's memory back to the hardware.
  621.  
  622.     mov    di,bp            ;make di ->new data,
  623.     cmp    bp,receive_buf_end    ;did our packet trailer wrap?
  624.     jb    recv_free_nowrap    ;no.
  625.     sub    bp,RECEIVE_BUF_SIZE    ;yes,
  626. recv_free_nowrap:
  627.  
  628.     mov    dx,io_addr
  629.     mov    ax,bp            ;compute the new stop register.
  630.     sub    ax,receive_buf
  631.     call    update_stop_hit
  632.  
  633.     mov    si,[di-2]        ;make si ->new header.
  634.     or    si,si
  635.     je    recv_next
  636.  
  637.     mov    di,bp            ;make di -> beginning of new data.
  638.     jmp    recv_again
  639. recv_next:
  640.     mov    ax,this_rfp_ptr
  641.     mov    last_rfp_ptr,ax        ;remember where the most recent was.
  642.     mov    al,CMD0_ACK or CMD0_NOP or CMD0_STAT0    ;ack the interrupt.
  643.     out    dx,al
  644.     in    al,dx            ;is there another interrupt?
  645.     test    al,CMD0_ACK
  646.     je    recv_exit        ;no.
  647.     jmp    recv_interrupt
  648. recv_exit:
  649.     ret
  650.  
  651. receive_word:
  652. ;enter with di -> after word to fetch
  653.     assume    ds:code
  654.     sub    di,2
  655.     cmp    di,receive_buf        ;time to wrap around?
  656.     jae    receive_buf_1        ;no.
  657.     add    di,RECEIVE_BUF_SIZE    ;yes, wrap round.
  658. receive_buf_1:
  659.     mov    al,[di]            ;fetch the word.
  660.     ret
  661.  
  662. receive_move:
  663. ;enter with ds:si,cx -> packet that might wrap.  Copy it to es:di.
  664.     assume    ds:code
  665.     mov    ax,si            ;does it wrap?
  666.     add    ax,cx
  667.     cmp    ax,receive_buf_end
  668.     jbe    receive_move_1        ;no, just copy it.
  669.     mov    ax,receive_buf_end    ;compute the size of first half.
  670.     sub    ax,si
  671.     sub    cx,ax            ;move the rest in second part.
  672.     push    cx
  673.     mov    cx,ax            ;set the count for the first move.
  674.     call    movemem
  675.     pop    cx
  676.     mov    si,receive_buf        ;and point to the wrapped part.
  677. receive_move_1:
  678.     call    movemem
  679.     ret
  680.  
  681.  
  682. segmoffs_to_phys:
  683. ;enter with es:di -> buffer.
  684. ;exit with dx:ax as the physical address of the buffer,
  685.  
  686.     mov    dx,es            ;get the high 4 bits of the segment,
  687.     shr    dx,16-4
  688.     mov    ax,es            ;and the low 12 bits of the segment.
  689.     shl    ax,4
  690.     add    ax,di            ;add in the offset.
  691.     adc    dx,0
  692.     ret
  693.  
  694.  
  695. do_write_command_cx:
  696. ;enter with al=command, es:di -> buffer, cx = length in bytes (must be even)
  697. ;  of command AND DMA transfer size.
  698.     mov    es:[di],cx        ;set the count to the DMA count.
  699. do_write_command:
  700. ;enter with al=command, es:di -> buffer, cx = DMA length in bytes (must be
  701. ;  even), word ptr es:[di] set to command size.
  702.     assume    ds:nothing
  703.     push    ax            ;save the command
  704.  
  705. ; *just* in case, we wait here for the previous command to finish.
  706.     mov    dx,io_addr
  707.     call    wait_for_done
  708.  
  709.     add    cx,2+1            ;include the command's count in the
  710.                     ;DMA count.
  711.     and    cl,0feh            ;round up.
  712.  
  713.     mov    al,DMA_DISABLE        ; Disable DMA for this channel
  714.     or    al,tx_channel
  715.     out    DMA_MASK,al
  716.     pause_
  717.  
  718.     out    DMA_RESETFF,al        ; Reset byte pointer flipflop
  719.     pause_
  720.  
  721. ; The 16-bit DMA controller ties the low address bit low, and drives
  722. ; a1-16.  The low bit of the page register is discarded.
  723.  
  724.     call    segmoffs_to_phys
  725.     shr    dx,1            ;convert to words.
  726.     rcr    ax,1
  727.  
  728.     mov    dx,tx_dma_dest        ; Output buf start (source) address
  729.     out    dx,al
  730.     pause_
  731.     mov    al,ah
  732.     out    dx,al
  733.     pause_
  734.  
  735.     mov    ax,cx            ;convert the byte count into word count.
  736.     shr    ax,1
  737.     dec    ax            ;DMA controller does one count less.
  738.     add    dx,2            ;point to count registers.
  739.     out    dx,al
  740.     pause_
  741.     mov    al,ah
  742.     out    dx,al
  743.     pause_
  744.  
  745. ; Set DMA mode register to single transfers, incrementing address,
  746. ; no auto init, reads
  747.     mov    al,DMA_TX_MODE
  748.     or    al,tx_channel
  749.     out    DMA_MODE,al
  750.     pause_
  751.  
  752. ; Unmask channel n (enable DMA controller chip)
  753.     mov    al,DMA_ENABLE        ; Enable DMA for this channel
  754.     or    al,tx_channel
  755.     out    DMA_MASK,al
  756.  
  757. ;now issue the command
  758.     pop    ax
  759.     mov    dx,io_addr
  760.     out    dx,al
  761.  
  762.     ret
  763.  
  764. wait_for_done:
  765. ;enter with dx set to io_addr.
  766. ;exit with cy if we timed out.
  767.     assume    ds:nothing
  768. ;first check to see if we're busy at all.
  769.     mov    al,CMD0_NOP + CMD0_STAT3
  770.     out    dx,al
  771.     in    al,dx
  772.     and    al,3            ;get the status of the execution
  773.     je    wait_for_done_3        ;not busy -- just exit.
  774.  
  775.     mov    ax,18            ;wait half a second, max.
  776.     call    set_timeout
  777. wait_for_done_1:
  778.     mov    al,CMD0_NOP + CMD0_STAT3
  779.     out    dx,al
  780.     in    al,dx
  781.     and    al,3            ;get the status of the execution
  782.     je    wait_for_done_2
  783.     call    do_timeout
  784.     jne    wait_for_done_1
  785.     mov    al,CMD0_ABORT        ;abort the current command.
  786.     out    dx,al
  787.     stc
  788.     ret
  789. wait_for_done_2:
  790.     mov    al,CMD0_ACK or CMD0_NOP    ;ack the interrupt we just got.
  791.     out    dx,al
  792. wait_for_done_3:
  793.     ret
  794.  
  795. update_stop_hit:
  796. ;enter with dx set to io_addr, ax=RFP
  797.     assume    ds:code
  798.     push    ax
  799.     mov    al,CMD0_PORT_1        ;switch to port 1.
  800.     out    dx,al
  801.     pop    ax
  802. ;delete all the bits from the pointer but leave seven.  Also, RECEIVE_BUF_BITS
  803. ;is in terms of bytes, so convert it to words by shift it right once more.
  804.     mov    cl,RECEIVE_BUF_BITS - 7    + 1    ;move over to right position.
  805.     shr    ax,cl
  806.     or    al,80h            ;make into CMD1_STOP_REG_UPDATE.
  807.     out    dx,al
  808.     mov    al,CMD1_PORT_0        ;switch back to port 0.
  809.     out    dx,al
  810.     ret
  811.  
  812. init_82593:
  813.     push    ds
  814.     pop    es
  815.     mov    di,transmit_buf
  816.     mov    es:[di+2],word ptr 0    ;we're still in byte mode, so zero
  817.                     ;the second word also.
  818.  
  819.     xor    cx,cx            ;zero length.
  820.     mov    al,CMD0_CONFIGURE + CMD0_CHNL_1
  821.     call    do_write_command_cx
  822.     call    wait_for_done
  823.  
  824.     call    rcv_mode_3        ;configure the 82593.
  825.  
  826.     mov    si,offset rom_address
  827.     mov    cx,EADDR_LEN
  828.     call    set_address
  829.  
  830.     mov    dx,io_addr
  831.     mov    ax,RECEIVE_BUF_SIZE
  832.     call    update_stop_hit
  833.  
  834.     mov    dx,io_addr
  835.     mov    al,CMD0_RCV_ENABLE + CMD0_CHNL_0
  836.     out    dx,al
  837.  
  838.     ret
  839.  
  840.  
  841.     public    timer_isr
  842. timer_isr:
  843. ;if the first instruction is an iret, then the timer is not hooked
  844.     iret
  845.  
  846. ;any code after this will not be kept.  Buffers used by the program, if any,
  847. ;are allocated from the memory between end_resident and end_free_mem.
  848.     public end_resident,end_free_mem
  849.     align    4
  850. end_resident    label    byte
  851.     db    (RECEIVE_BUF_SIZE+8 + 2*TRANSMIT_BUF_SIZE) dup(?)
  852. end_free_mem    label    byte
  853.  
  854.     public    usage_msg
  855. usage_msg    db    "usage: znote [options] <packet_int_no>",CR,LF,'$'
  856.  
  857.     public    copyright_msg
  858. copyright_msg    db    "Packet driver for the ZDS Z-Note, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  859.         db    '$'
  860.  
  861. not_here_msg    label    byte
  862. db "Cannot run the Z-Note packet driver at this segment address.  Try",CR,LF
  863. db "running it at a different point in your AUTOEXEC.BAT",CR,LF,'$'
  864. no_sig_msg    db    "This machine does not have built-in networking (no NETIDBLK found)",CR,LF,'$'
  865. no_memory_msg    db    "Unable to allocate enough memory, look at end_resident in ZNOTE.ASM",CR,LF,'$'
  866. no_power_msg    db    "Networking is disabled.  Use Fn-Setup/Devices Control to enable HSC Port.",CR,LF,'$'
  867.  
  868. netidblk_sig    db    "NETIDBLK"
  869. NETIDBLK_SIG_LEN    equ    $-netidblk_sig    ;we assume this is even.
  870.  
  871. dma_page_addrs    db    0, 8bh, 89h, 8ah
  872.  
  873. ;called when you're ready to receive interrupts.
  874.     extrn    set_recv_isr: near
  875.  
  876. ;enter with si -> argument string, di -> dword to store.
  877. ;if there is no number, don't change the number.
  878.     extrn    get_number: near
  879.  
  880. ;enter with dx -> argument string, di -> dword to print.
  881.     extrn    print_number: near
  882.  
  883. ;-> the unique Ethernet address of the card.  Filled in by the etopen routine.
  884.     extrn    rom_address: byte
  885.  
  886. ;-> current address.  Normally the same as rom_address, unless changed
  887. ;by the set_address() call.
  888.     extrn    my_address: byte
  889.  
  890. ;parse_args is called with si -> first parameter (CR if none).
  891.     public    parse_args
  892. parse_args:
  893. ;exit with nc if all went well, cy otherwise.
  894.     clc
  895.     ret
  896.  
  897.  
  898.     public    etopen
  899. etopen:
  900. ;initialize the driver.  Fill in rom_address with the assigned address of
  901. ;the board.  Exit with nc if all went well, or cy, dx -> $ terminated error msg.
  902. ;if all is okay,
  903.     assume    ds:code
  904.  
  905.     mov    ax,0f000h
  906.     mov    es,ax
  907.     xor    di,di
  908. find_signature:
  909.     mov    si,offset netidblk_sig
  910.     mov    cx,NETIDBLK_SIG_LEN/2    ;we happen to know it's even.
  911.     push    di
  912.     repe    cmpsw
  913.     pop    di
  914.     je    find_signature_1
  915.     inc    di
  916.     cmp    di,-(size id_block)    ;enough room for one more?
  917.     jb    find_signature
  918.     mov    dx,offset no_sig_msg
  919.     stc
  920.     ret
  921. no_memory:
  922.     mov    dx,offset no_memory_msg
  923.     stc
  924.     ret
  925. find_signature_1:
  926.     mov    ax,es:[di].iobase1
  927.     mov    io_addr,ax
  928.     mov    al,es:[di].intr1
  929.     mov    int_no,al
  930.  
  931.     mov    al,es:[di].dma1
  932.     and    al,3
  933.     mov    rx_channel,al
  934.     mov    dx,DMA_BASE
  935.     shl    al,1
  936.     shl    al,1
  937.     add    dl,al
  938.     mov    rx_dma_dest,dx
  939.  
  940.     mov    al,es:[di].dma2
  941.     and    al,3
  942.     mov    tx_channel,al
  943.     mov    dx,DMA_BASE
  944.     shl    al,1
  945.     shl    al,1
  946.     add    dl,al
  947.     mov    tx_dma_dest,dx
  948.  
  949.     mov    bx,offset dma_page_addrs
  950.     mov    al,rx_channel
  951.     xlat
  952.     xor    ah,ah
  953.     mov    rx_page_addr,ax
  954.  
  955.     mov    al,tx_channel
  956.     xlat
  957.     xor    ah,ah
  958.     mov    tx_page_addr,ax
  959.  
  960.     mov    si,offset rom_address
  961.     mov    cx,EADDR_LEN
  962.     push    di
  963.     lea    di,[di].netid
  964. copy_rom_address:
  965.     mov    al,es:[di]
  966.     inc    di
  967.     mov    ds:[si],al
  968.     inc    si
  969.     loop    copy_rom_address
  970.     pop    di
  971.  
  972. ;
  973. ; Turn on 82501
  974. ;
  975.     mov    al,10h            ;LAN control port index
  976.     out    0e6h,al            ;Output index to E6 port
  977.     in    al,0e7h            ;Get data from E7 port
  978.     or       al,10000100b        ;Turn off LAN reset and
  979.                     ;  on bit 2: LAN power bit
  980.     out    0e7h,al
  981.     mov    ax,2            ;delay 50 ms here to wait for LAN clock
  982.     call    delay            ;  to stablize.
  983.  
  984.     mov    dx,io_addr        ;reset the 82593.
  985.     mov    ax,CMD0_RESET
  986.     out    dx,al
  987. ;Strictly speaking, the following code isn't needed, because we *just*
  988. ;turned the thing on!  But it's small and straightforward and unlikely
  989. ;to break anything, so we'll leave it in.
  990.     in    ax,dx
  991.     cmp    ax,0010h
  992.     jne    powered_off
  993.     in    ax,dx
  994.     cmp    ax,0000h
  995.     je    powered_on
  996. powered_off:
  997.     mov    dx,offset no_power_msg
  998.     stc
  999.     ret
  1000. powered_on:
  1001.  
  1002. ;Here we get a transmit buffer.  If it wraps around a segment, we
  1003. ;discard it and get another transmit buffer.  Note that we can't loop
  1004. ;forever because the buffer is smaller than 64K, so if the first time
  1005. ;it wraps, the second it definitely won't.
  1006. transmit_again:
  1007.     mov    dx,TRANSMIT_BUF_SIZE    ;request a transmit buffer.
  1008.     call    malloc
  1009.     jnc    have_tx_mem
  1010. no_memory_1:
  1011.     jmp    no_memory
  1012. have_tx_mem:
  1013.     mov    transmit_buf,dx
  1014.  
  1015.     push    cs
  1016.     pop    es
  1017.     mov    di,transmit_buf
  1018.     call    segmoffs_to_phys
  1019.     add    ax,TRANSMIT_BUF_SIZE
  1020.     jc    transmit_again        ;uh-oh, we'll go try again.
  1021.  
  1022.     mov    al,dl            ; get the page part of the address.
  1023.     mov    dx,tx_page_addr        ; Set up transmit DMA page register
  1024.     out    dx,al
  1025.     pause_
  1026.  
  1027. ;we may need as many as 8 extra bytes following the end of the receive
  1028. ;buffer, because we store a pointer to the next packet there.
  1029.     mov    dx,RECEIVE_BUF_SIZE+8    ;request a receive buffer.
  1030.     call    malloc
  1031.     jc    no_memory_1
  1032.     mov    receive_buf,dx
  1033.     mov    last_rfp_ptr,dx
  1034.     add    dx,RECEIVE_BUF_SIZE
  1035.     mov    receive_buf_end,dx
  1036.  
  1037.     push    cs
  1038.     pop    es
  1039.     mov    di,receive_buf
  1040.     call    segmoffs_to_phys
  1041.     add    ax,RECEIVE_BUF_SIZE
  1042.     jnc    receive_ok
  1043.     mov    dx,offset not_here_msg
  1044.     stc
  1045.     ret
  1046. receive_ok:
  1047.     mov    al,dl            ; get the page part of the address.
  1048.     mov    dx,rx_page_addr        ; Set up receive DMA page register
  1049.     out    dx,al
  1050.     pause_
  1051.  
  1052.     push    cs
  1053.     pop    es
  1054.     mov    di,receive_buf
  1055.     mov    cx,RECEIVE_BUF_SIZE
  1056.  
  1057.     mov    al,DMA_DISABLE        ; Disable DMA for this channel
  1058.     or    al,rx_channel
  1059.     out    DMA_MASK,al
  1060.     pause_
  1061.  
  1062.     out    DMA_RESETFF,al        ; Reset byte pointer flipflop
  1063.     pause_
  1064.  
  1065. ; The 16-bit DMA controller ties the low address bit low, and drives
  1066. ; a1-16.  The low bit of the page register is discarded.
  1067.  
  1068.     call    segmoffs_to_phys
  1069.     shr    dx,1            ;convert to words.
  1070.     rcr    ax,1
  1071.  
  1072.     mov    dx,rx_dma_dest        ; Output buf start (source) address
  1073.     out    dx,al
  1074.     pause_
  1075.     mov    al,ah
  1076.     out    dx,al
  1077.     pause_
  1078.  
  1079.     mov    ax,cx            ;convert the byte count into word count.
  1080.     shr    ax,1
  1081.     dec    ax            ;DMA controller does one count less.
  1082.     add    dx,2            ;point to count registers.
  1083.     out    dx,al
  1084.     pause_
  1085.     mov    al,ah
  1086.     out    dx,al
  1087.     pause_
  1088.  
  1089. ; Set DMA mode register to single transfers, incrementing address,
  1090. ; no auto init, reads
  1091.     mov    al,DMA_RX_MODE
  1092.     or    al,rx_channel
  1093.     out    DMA_MODE,al
  1094.     pause_
  1095.  
  1096. ; Unmask channel n (enable DMA controller chip)
  1097.     mov    al,DMA_ENABLE        ; Enable DMA for this channel
  1098.     or    al,rx_channel
  1099.     out    DMA_MASK,al
  1100.  
  1101.     call    init_82593
  1102.  
  1103.     call    set_recv_isr
  1104.  
  1105.     clc
  1106.     ret
  1107.  
  1108. delay_27_5ms:
  1109. ;delay one timeout period, which is 27.5 ms.
  1110.     mov    ax,1
  1111. delay:
  1112. ;delay AX timeout periods, each of which is 27.5 ms.
  1113.     call    set_timeout
  1114. delay_1:
  1115.     call    do_timeout
  1116.     jnz    delay_1
  1117.     ret
  1118.  
  1119.  
  1120.     public    print_parameters
  1121. print_parameters:
  1122. ;echo our command-line parameters
  1123.     ret
  1124.  
  1125. code    ends
  1126.  
  1127.     end
  1128.