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

  1. version    equ    0
  2. ;History:916,1
  3.  
  4. ; Copyright, 1990-1992, Russell Nelson, Crynwr Software
  5.  
  6. ;   This program is free software; you can redistribute it and/or modify
  7. ;   it under the terms of the GNU General Public License as published by
  8. ;   the Free Software Foundation, version 1.
  9. ;
  10. ;   This program is distributed in the hope that it will be useful,
  11. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ;   GNU General Public License for more details.
  14. ;
  15. ;   You should have received a copy of the GNU General Public License
  16. ;   along with this program; if not, write to the Free Software
  17. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     .286                ;the tcenet requires a 286.
  20.  
  21. comment \
  22.  
  23. We have to lock all the data structures accessed by the board.  We
  24. also have to keep track of which ones have been locked and which have not.
  25.  
  26. \
  27.  
  28.     include    defs.asm
  29.  
  30. pause_    macro
  31. ;    jmp    $+2
  32. ;
  33. ; The reason for the pause_ macro is to establish a minimum time between
  34. ; accesses to the card hardware. The assumption is that the fetch and execution
  35. ; of the jmp $+2 instruction will provide this time. In a fast cache machine
  36. ; this may be a false assumption. In a fast cache machine, there may be 
  37. ; NO REAL TIME DIFFERENCE between the two I/O instruction streams below:
  38. ;
  39. ;    in    al,dx        in    al,dx
  40. ;    jmp    $+2
  41. ;    in    al,dx        in    al,dx
  42. ;
  43. ; To establish a minimum delay, an I/O instruction must be used. A good rule of
  44. ; thumb is that ISA I/O instructions take ~1.0 microseconds and MCA I/O
  45. ; instructions take ~0.5 microseconds. Reading the NMI Status Register (0x61)
  46. ; is a good way to pause on all machines.
  47. ;
  48. ; The National 8390 Chip (NIC) requires 4 bus clocks between successive
  49. ; chip selects (National DP8390 Data Sheet Addendum, June 1990 -- it took them
  50. ; long enough to figure this out and tell everyone) or the NIC behaves badly.
  51. ; Therefor one I/O instruction should be inserted between each successive
  52. ; NIC I/O instruction that could occur 'back - to - back' on a fast cache
  53. ; machine.
  54. ;   - gft - 910529
  55. ;
  56.     push    ax
  57.     in    ax, 61h
  58.     pop    ax
  59. ;
  60. endm
  61.  
  62. DMA_8MASK_REG    equ    0Ah
  63. DMA_8MODE_REG    equ    0Bh
  64. DMA_16MASK_REG    equ    0D4h
  65. DMA_16MODE_REG    equ    0D6h
  66.  
  67. CASCADE_MODE      equ    0C0h
  68. SET_DMA_MASK      equ    4
  69. DMA_CHANNEL_FIELD equ    3
  70.  
  71. ;tcenet registers.
  72. EBASE        equ    0
  73. CONFIG        equ    0eh
  74. PORTPAGE    equ    0fh
  75. SONICREG    equ    10h
  76.  
  77. ;we don't use setport to refer to Sonic registers, because of the crufty
  78. ;port paging.
  79. sncport    macro    new_port_no
  80. ;    if ((new_port_no xor port_no) and (not 0fh)) or (port_no EQ 0)
  81.  
  82.     loadport
  83.         setport    PORTPAGE
  84.         push    ax
  85.         mov    al, (new_port_no shr 1)
  86.         out    dx,al
  87.         in    al,61h        ;see pause_ macro.
  88.         pop    ax
  89.  
  90. ;    endif
  91.  
  92.     setport    <(SONICREG+(new_port_no and 0fh))>
  93.     endm
  94.  
  95.  
  96. RDA_COUNT    equ    8
  97.  
  98. TRANSMIT_BUF_COUNT    equ    1
  99. RECEIVE_BUF_COUNT    equ    2
  100. TRANSMIT_BUF_SIZE    equ    1520
  101. RECEIVE_BUF_SIZE    equ    1522*2
  102.  
  103. EOL        equ    1        ;descriptor EOL flag
  104.  
  105. ;-----------------------------------------------------------------------------
  106. ;
  107. ;    Sonic Register Definitions
  108.  
  109. ;    Sonic command register bits
  110.  
  111. LCAM    equ    0200h            ;Load CAM
  112. RRRA    equ    0100h            ;Read RRA
  113. RST    equ    0080h            ;Software Reset
  114. ST    equ    0020h            ;Start Timer
  115. STP    equ    0010h            ;Stop Timer
  116. RXEN    equ    0008h            ;Receiver Enable
  117. RXDIS    equ    0004h            ;Receiver Disable
  118. TXP    equ    0002h            ;Transmit packets
  119. HTX    equ    0001h            ;Halt transmission
  120.  
  121. ;    Sonic Data Configuration Register Bits
  122.  
  123. EXBUS    equ    8000h            ;Extended Bus mode
  124. LBR    equ    2000h            ;Latched Bus Retry
  125. PO1    equ    1000h            ;Programmable Outputs
  126. PO0    equ    0800h            ;. .
  127. SBUS    equ    0400h            ;Synchronous Bus Mode
  128. USR1    equ    0200h            ;User Definable Pins
  129. USR0    equ    0100h            ;. .
  130. WC1    equ    0080h            ;Wait State Control
  131. WC0    equ    0040h            ;. .
  132. DW32    equ    0020h            ;Data Width Select
  133. BMS    equ    0010h            ;Block Mode Select for DMA
  134. RFT1    equ    0008h            ;Receive FIFO Threshold
  135. RFT0    equ    0004h            ;. .
  136. TFT1    equ    0002h            ;Transmit FIFO Threshold
  137. TFT0    equ    0001h            ;. .
  138.  
  139. ;    Sonic Receive Control Register bits
  140.  
  141. ERR    equ    8000h            ;Accept Packet with Errors
  142. RNT    equ    4000h            ;Accept Runt Packets
  143. BRD    equ    2000h            ;Accept Broadcast Packets
  144. PRO    equ    1000h            ;Accept all Physical Packets (Promiscuous Mode)
  145. AMC    equ    0800h            ;Accept all Multicast Packets
  146. LB1    equ    0400h            ;Loopback Control 1
  147. LB0    equ    0200h            ;Loopback Control 0
  148. MCRx    equ    0100h            ;Multicast Packet Received
  149. BCRx    equ    0080h            ;Broadcast Packet Received
  150. LPKT    equ    0040h            ;Last Packet in RBA
  151. CRS    equ    0020h            ;Carrier Sense Activity
  152. COL    equ    0010h            ;Collision Activity
  153. CRCR    equ    0008h            ;CRC Error
  154. FAER    equ    0004h            ;Frame Alignment Error
  155. LBK    equ    0002h            ;LoopBack Packet Received
  156. PRX    equ    0001h            ;Packet Received OK
  157.  
  158. ;    Transmit Control Register bits
  159.  
  160. PINTR    equ    8000h            ;Programmable Interrupt
  161. POWC    equ    4000h            ;Program 'Out of Window Collision' Timer
  162. CRCI    equ    2000h            ;CRC Inhibit
  163. EXDIS    equ    1000h            ;Disable Excessive Deferral Timer
  164. EXD    equ    0400h            ;Excessive Deferral
  165. DEF    equ    0200h            ;Deferred Transmission
  166. NCRS    equ    0100h            ;No CRS
  167. CRSL    equ    0080h            ;CRS Lost
  168. EXC    equ    0040h            ;Excessive Collisions
  169. OWC    equ    0020h            ;Out of Window Collision
  170. PMB    equ    0008h            ;Packet Monitored Bad
  171. FU    equ    0004h            ;Tx FIFO UnderRun
  172. BCM    equ    0002h            ;Byte Count Mismatch
  173. PTX    equ    0001h            ;Packet Transmitted OK
  174.  
  175. TXDONE    equ    EXD or CRSL or EXC or PTX    ;nonzero when transmit done.
  176.  
  177. ;    Interrupt Mask Register bits
  178.  
  179. BREN    equ    4000h            ;Bus Retry Occurred Enable
  180. HBLEN    equ    2000h            ;HeartBeat Lost Enable
  181. LCDEN    equ    1000h            ;Load CAM Done Interrupt Enable
  182. PINTEN    equ    0800h            ;Programmable Interrupt Enable
  183. PRXEN    equ    0400h            ;Packet Received Enable
  184. PTXEN    equ    0200h            ;Packet Transmitted OK Enable
  185. TXEREN    equ    0100h            ;Transmit Error Enable
  186. TCEN    equ    0080h            ;Timer Complete Enable
  187. RDEEN    equ    0040h            ;Receive Descriptors Exhausted Enable
  188. RBEEN    equ    0020h            ;Receive Buffers Exhausted Enable
  189. RBAEEN    equ    0010h            ;Receive Buffer Area Exceeded Enable
  190. CRCEN    equ    0008h            ;CRC Tally Counter Warning Enable
  191. FAEEN    equ    0004h            ;FAE Tally Counter Warning Enable
  192. MPEN    equ    0002h            ;MP Tally Counter Warning Enable
  193. RFOEN    equ    0001h            ;Receive FIFO Overrun Enable
  194.  
  195. ; these are the interrupts we enable:
  196. enabled_IMR    equ    (PTXEN or TXEREN or PRXEN or RBEEN or BREN)
  197.  
  198. ;    Interrupt Status Register bits
  199.  
  200. BR    equ    4000h            ;Bus Retry Occurred
  201. HBL    equ    2000h            ;HeartBeat Lost
  202. LCD    equ    1000h            ;Load CAM Done
  203. PINT    equ    0800h            ;Programmable Interrupt
  204. PKTRX    equ    0400h            ;Packet Received
  205. TXDN    equ    0200h            ;Transmission Done
  206. TXER    equ    0100h            ;Transmit Error
  207. TC    equ    0080h            ;Timer Complete
  208. RDE    equ    0040h            ;Receive Descriptors Exhausted
  209. RBE    equ    0020h            ;Receive Buffers Exhausted
  210. RBAE    equ    0010h            ;Receive Buffer Area Exceeded
  211. CRC    equ    0008h            ;CRC Tally Counter Rollover
  212. FAE    equ    0004h            ;FAE Tally Counter Rollover
  213. MP    equ    0002h            ;Missed Packet Tally Counter Rollover
  214. RFO    equ    0001h            ;Receive FIFO Overrun
  215.  
  216. ;SONIC registers.  The registers are sixteen-bit registers that are also
  217. ;byte-addressable.  So, the word addresses must be multiplied by two.
  218.  
  219. ;    Command and Status Register Offsets
  220.  
  221. SonicCR        equ    (0 * 2)
  222. SonicDCR    equ    (1 * 2)
  223. SonicRCR    equ    (2 * 2)
  224. SonicTCR    equ    (3 * 2)
  225. SonicIMR    equ    (4 * 2)
  226. SonicISR    equ    (5 * 2)
  227.  
  228. ;    Transmit Registers
  229.  
  230. SonicUTDA    equ    (6 * 2)
  231. SonicCTDA    equ    (7 * 2)
  232.  
  233. ;    Receive Registers
  234.  
  235. SonicURDA    equ    (0dh * 2)
  236. SonicCRDA    equ    (0eh * 2)
  237. SonicEOBC    equ    (13h * 2)
  238. SonicURRA    equ    (14h * 2)
  239. SonicRSA    equ    (15h * 2)
  240. SonicREA    equ    (16h * 2)
  241. SonicRRP    equ    (17h * 2)
  242. SonicRWP    equ    (18h * 2)
  243. SonicRSC    equ    (2bh * 2)
  244.  
  245. ;    CAM Registers
  246.  
  247. SonicCEP    equ    (21h * 2)
  248. SonicCAP2    equ    (22h * 2)
  249. SonicCAP1    equ    (23h * 2)
  250. SonicCAP0    equ    (24h * 2)
  251. SonicCE        equ    (25h * 2)
  252. SonicCDP    equ    (26h * 2)
  253. SonicCDC    equ    (27h * 2)
  254.  
  255. ;    Tally Counters
  256.  
  257. SonicCRCT    equ    (2ch * 2)
  258. SonicFAET    equ    (2dh * 2)
  259. SonicMPT    equ    (2eh * 2)
  260.  
  261. ;    Watchdog Counters
  262.  
  263. SonicWT0    equ    (29h * 2)
  264. SonicWT1    equ    (2ah * 2)
  265.  
  266. ;    Silicon Revision
  267.  
  268. SonicSR        equ    (28h * 2)
  269.  
  270. ;Receiver Resource Area
  271.  
  272. rra_struc    struc
  273. rra_ptr        dd    ?
  274. rra_cnt        dd    ?
  275. rra_struc    ends
  276.  
  277. ;Receiver Descriptor Area
  278.  
  279. rda_struc    struc
  280. rda_status    dw    ?
  281. rda_byte_count    dw    ?
  282. rda_ptr        dd    ?
  283. rda_seq_number    dw    ?
  284. rda_link    dw    ?
  285. rda_in_use    dw    ?
  286. rda_backlink    dw    ?        ;for our own purposes, not SONIC's.
  287. rda_forelink    dw    ?        ;for our own purposes, not SONIC's.
  288. rda_struc    ends
  289.  
  290. ;    Transmit Descriptor structure
  291.  
  292. tda_struc    struc
  293. tda_status    dw    ?
  294. tda_config    dw    ?
  295. tda_size    dw    ?
  296. tda_frag_count    dw    ?
  297. tda_frag_ptr    dd    ?
  298. tda_frag_size    dw    ?
  299. tda_link    dw    ?
  300. tda_struc    ends
  301.  
  302. ; Content-Addressible Memory descriptor.
  303.  
  304. cam_struc    struc
  305. cam_entry_ptr    dw    0
  306. cam_addr0    dw    0
  307. cam_addr1    dw    0
  308. cam_addr2    dw    0
  309. cam_struc    ends
  310.  
  311. dds_struc    struc
  312. dds_size    dd    0        ;region size.
  313. dds_offset    dd    0        ;offset (using 32 bits)
  314. dds_seg        dw    0        ;segment or selector
  315. dds_buffer_id    dw    0
  316. dds_physical    dd    0        ;physical address
  317. dds_struc    ends
  318.  
  319. ;MAX8023LENGTH        equ    1514
  320. MAX8023LENGTH        equ    1520
  321.  
  322. code    segment    para public
  323.     assume    cs:code, ds:code
  324.  
  325.     public    int_no
  326. int_no        db    3,0,0,0        ;must be four bytes long for get_number.
  327. io_addr        dw    -1,-1
  328. port_addr    dw    ?
  329. dma_no        db    ?
  330.  
  331.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  332. driver_class    db    BLUEBOOK, IEEE8023, 0        ;from the packet spec
  333. driver_type    db    89        ;from the packet spec
  334. driver_name    db    'TCENET',0    ;name of the driver.
  335. driver_function    db    2        ;basic, extended
  336. parameter_list    label    byte
  337.     db    1    ;major rev of packet driver
  338.     db    9    ;minor rev of packet driver
  339.     db    14    ;length of parameter list
  340.     db    EADDR_LEN    ;length of MAC-layer address
  341.     dw    GIANT    ;MTU, including MAC headers
  342.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  343.     dw    RECEIVE_BUF_COUNT-1    ;(# of back-to-back MTU rcvs) - 1
  344.     dw    TRANSMIT_BUF_COUNT-1    ;(# of successive xmits) - 1
  345. int_num    dw    0    ;Interrupt # to hook for post-EOI
  346.             ;processing, 0 == none,
  347.  
  348.         align    2
  349.     public    rcv_modes
  350. rcv_modes    dw    7        ;number of receive modes in our table.
  351.         dw    0               ;There is no mode zero
  352.         dw    rcv_mode_1
  353.         dw    rcv_mode_2    ;only ours.
  354.         dw    rcv_mode_3    ;ours plus broadcast
  355.         dw    0        ;some multicasts
  356.         dw    rcv_mode_5    ;all multicasts
  357.         dw    rcv_mode_6    ;all packets
  358.  
  359. my_dds        dds_struc<>
  360. vds_active    db    ?        ;<>0 if memory mapping is on.
  361.  
  362. tdaptr        dw    tda1        ;-> the TDA's we're using.
  363. rraptr        dw    rra1
  364. camptr        dw    cam1        ;-> the CAM we're using.
  365. camcount    dw    1        ;always has our address.
  366. rdaptr        dw    rda1
  367. next_rda    dw    ?
  368.  
  369.     include    timeout.asm
  370.     include    movemem.asm
  371.  
  372.     public bad_command_intercept
  373. bad_command_intercept:
  374. ;called with ah=command, unknown to the skeleton.
  375. ;exit with nc if okay, cy, dh=error if not.
  376.     mov    dh,BAD_COMMAND
  377.     stc
  378.     ret
  379.  
  380.     public    as_send_pkt
  381. ; The Asynchronous Transmit Packet routine.
  382. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  383. ;   interrupts possibly enabled.
  384. ; Exit with nc if ok, or else cy if error, dh set to error number.
  385. ;   es:di and interrupt enable flag preserved on exit.
  386. as_send_pkt:
  387.     ret
  388.  
  389.     public    drop_pkt
  390. ; Drop a packet from the queue.
  391. ; Enter with es:di -> iocb.
  392. drop_pkt:
  393.     assume    ds:nothing
  394.     ret
  395.  
  396.     public    xmit
  397. ; Process a transmit interrupt with the least possible latency to achieve
  398. ;   back-to-back packet transmissions.
  399. ; May only use ax and dx.
  400. xmit:
  401.     assume    ds:nothing
  402.     ret
  403.  
  404.  
  405.     public    send_pkt
  406. send_pkt:
  407. ;enter with ds:si -> packet, cx = packet length.
  408. ;exit with nc if ok, or else cy if error, dh set to error number.
  409.     assume    ds:nothing
  410.  
  411.     mov    bx,tdaptr
  412.  
  413.     mov    ax,18
  414.     call    set_timeout
  415.     loadport
  416.     sncport    SonicCR
  417. send_pkt_1:
  418.     in    ax,dx
  419.     test    ax,TXP
  420.     je    send_pkt_2        ;zero means yes, done transmitting.
  421. ;    test    code:[bx].tda_status,TXDONE    ;Is the SONIC done transmitting it?
  422. ;    jne    send_pkt_2        ;any non-zero means yes.
  423.     call    do_timeout
  424.     jne    send_pkt_1
  425.     mov    dh,CANT_SEND
  426.     stc
  427.     ret
  428. send_pkt_2:
  429.  
  430.     mov    ax,cx            ;store the count.
  431.     cmp    ax,RUNT            ; minimum length for Ether
  432.     ja    oklen
  433.     mov    ax,RUNT            ; make sure size at least RUNT
  434. oklen:
  435.     mov    code:[bx].tda_frag_size,cx
  436.     mov    code:[bx].tda_size,cx
  437.  
  438.     mov    code:[bx].tda_config,0
  439.  
  440.     mov    ax,code:[bx].tda_frag_ptr.offs    ;store the packet.
  441.     mov    dx,code:[bx].tda_frag_ptr.segm
  442.     call    phys_to_segmoffs
  443.     call    movemem
  444.  
  445.     lea    di,code:[bx].tda_status    ;get the address of the TDA.
  446.     movseg    es,cs
  447.     call    segmoffs_to_phys
  448.     loadport            ;point the CTDA to the TDA.
  449.     sncport    SonicCTDA
  450.     out    dx,ax
  451.     sncport    SonicCR            ;command SONIC to transmit.
  452.     mov    ax,TXP
  453.     out    dx,ax
  454.     clc
  455.     ret
  456.  
  457.  
  458.     public    get_address
  459. get_address:
  460. ;get the address of the interface.
  461. ;enter with es:di -> place to get the address, cx = size of address buffer.
  462. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  463.     assume    ds:code
  464.     cmp    cx,EADDR_LEN        ;make sure that we have enough room.
  465.     jb    get_address_2
  466.     mov    cx,EADDR_LEN
  467.     loadport            ; Get our Ethernet address base.
  468.     setport    EBASE
  469.     cld
  470. get_address_1:
  471.     insb                ; get a byte of the eprom address
  472.     inc    dx            ; next register
  473.     loop    get_address_1        ; go back for rest
  474.     mov    cx,EADDR_LEN
  475.     clc
  476.     ret
  477. get_address_2:
  478.     stc
  479.     ret
  480.  
  481.  
  482.     public    set_address
  483. set_address:
  484. ;enter with ds:si -> Ethernet address, CX = length of address.
  485. ;exit with nc if okay, or cy, dh=error if any errors.
  486.     assume    ds:nothing
  487.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  488.     je    set_address_4
  489.     mov    dh,BAD_ADDRESS
  490.     stc
  491.     jmp    short set_address_done
  492. set_address_4:
  493.  
  494.     movseg    es,cs
  495.     mov    di,camptr        ;point di to our Ethernet adddr.
  496.     add    di,2
  497.     rep    movsb
  498.  
  499.     movseg    ds,cs
  500.     assume    ds:code
  501.  
  502.     call    load_cam        ;initialize with our new address.
  503.     mov    dh,CANT_SET        ;just in case.
  504.     jc    set_address_done
  505. set_address_okay:
  506.     mov    cx,EADDR_LEN        ;return their address length.
  507.     clc
  508. set_address_done:
  509.     ret
  510.  
  511. load_cam:
  512.     loadport
  513.     sncport    SonicCR
  514. load_cam_1:
  515.     in    ax,dx            ;wait for transmit done.
  516.     test    ax,TXP
  517.     jne    load_cam_1        ;nonzero means still transmitting.
  518.  
  519.     movseg    es,ds
  520.     mov    di,camptr        ;point the Descriptor Pointer Register
  521.     call    segmoffs_to_phys
  522.     sncport    SonicCDP        ;  to our CAM area.
  523.     out    dx,ax
  524.     pause_
  525.  
  526.     sncport    SonicCDC        ;load the CAM descriptor table length.
  527.     mov    ax,camcount
  528.     out    dx,ax
  529.     pause_
  530.  
  531.     sncport    SonicCR
  532.     mov    ax,LCAM            ;load the CAM.
  533.     out    dx,ax
  534.  
  535.     ret
  536.  
  537.  
  538. rcv_mode_2:
  539.     mov    ax,0            ;accept only mine
  540.     jmp    short rcv_mode_set
  541. rcv_mode_3:
  542.     mov    ax,BRD            ;accept mine + broadcast
  543.     jmp    short rcv_mode_set
  544. rcv_mode_5:
  545.     mov    ax,AMC            ;accept any multicast frames.
  546.     jmp    short rcv_mode_set
  547. rcv_mode_6:
  548.     mov    ax,RNT or PRO or BRD or AMC    ;promiscuous mode (runts also)
  549. rcv_mode_set:
  550.     loadport
  551.     sncport    SonicRCR
  552.     out    dx,ax
  553.     pause_
  554.     mov    ax,RXEN            ;enable reception.
  555.     jmp    short rcv_mode_set_1
  556. rcv_mode_1:
  557.     mov    ax,RXDIS        ;disable the receiver.
  558. rcv_mode_set_1:
  559.     loadport            ;enable or disable reception.
  560.     sncport    SonicCR
  561.     out    dx,ax
  562.     pause_
  563.     ret
  564.  
  565.  
  566.     public    set_multicast_list
  567. set_multicast_list:
  568. ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
  569. ;  cx = address byte count.
  570. ;return nc if we set all of them, or cy,dh=error if we didn't.
  571.  
  572.     mov    cx,ax
  573.     inc    ax            ;one more for our Ethernet address.
  574.     mov    camcount,ax
  575.     mov    ax,1
  576.     mov    di,camptr
  577.     add    di,8            ;skip first entry (our address).
  578. set_multicast_list_1:
  579.     stosw                ;store the CAM entry number.
  580.     movsw                ;move the address over.
  581.     movsw
  582.     movsw
  583.     loop    set_multicast_list_1
  584.  
  585.     mov    cx,camcount        ;compute the enable mask.
  586.     mov    ax,-1            ;shift zeroes in, then turn them
  587.     shl    ax,cl
  588.     not    ax            ;  into ones.
  589.     stosw                ;store the enable mask.
  590.  
  591.     call    load_cam        ;now stick it to the hardware.
  592.  
  593.     mov    dh,NO_MULTICAST        ;for some reason we can't do multi's.
  594.     stc
  595.     ret
  596.  
  597.  
  598.     public    terminate
  599. terminate:
  600.     loadport
  601.     sncport SonicCR
  602.     mov    ax,RST or STP or RXDIS    ;reset the sonic, stop timer, stop rcv.
  603.     out    dx,ax
  604.  
  605. ;This routine will remove the (host) DMA controller from
  606. ;cascade mode of operation.
  607.     mov    al,dma_no
  608.     or    al,SET_DMA_MASK
  609.     cmp    dma_no,4        ;If channel 5 or 6,
  610.     ja    terminate_16        ;  use sixteen bit dma.
  611. terminate_8:
  612.     out    DMA_8MASK_REG,al
  613.     jmp    short terminate_done
  614. terminate_16:
  615.     out    DMA_16MASK_REG,al
  616. terminate_done:
  617.  
  618. ; unlock the dma block.
  619.     mov    di,offset my_dds
  620.     mov    ax,cs
  621.     mov    es,ax
  622.     mov    dx,0
  623.     mov    ax,8104h
  624.     int    4bh
  625.  
  626.     ret
  627.  
  628.     public    reset_interface
  629. reset_interface:
  630. ;reset the interface.
  631.     assume    ds:code
  632.     ret
  633.  
  634.  
  635. ;called when we want to determine what to do with a received packet.
  636. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  637.     extrn    recv_find: near
  638.  
  639. ;called after we have copied the packet into the buffer.
  640. ;enter with ds:si ->the packet, cx = length of the packet.
  641.     extrn    recv_copy: near
  642.  
  643. ;call this routine to schedule a subroutine that gets run after the
  644. ;recv_isr.  This is done by stuffing routine's address in place
  645. ;of the recv_isr iret's address.  This routine should push the flags when it
  646. ;is entered, and should jump to recv_exiting_exit to leave.
  647. ;enter with ax = address of routine to run.
  648.     extrn    schedule_exiting: near
  649.  
  650. ;recv_exiting jumps here to exit, after pushing the flags.
  651.     extrn    recv_exiting_exit: near
  652.  
  653. ;enter with dx = amount of memory desired.
  654. ;exit with nc, dx -> that memory, or cy if there isn't enough memory.
  655.     extrn    malloc: near
  656.  
  657.     extrn    count_in_err: near
  658.     extrn    count_out_err: near
  659.  
  660.     public    recv
  661. recv:
  662. ;called from the recv isr.  All registers have been saved, and ds=cs.
  663. ;Upon exit, the interrupt will be acknowledged.
  664.     assume    ds:code
  665.  
  666.     loadport
  667.     sncport    SonicIMR
  668.     in    ax,dx
  669.     pause_
  670.     mov    cx,ax            ;remember the interrupt mask.
  671.     xor    ax,ax            ;clear interrupt requests.
  672.     out    dx,ax
  673.     pause_
  674.     sncport    SonicISR
  675.     in    ax,dx            ;now match the IMR against the ISR.
  676.     and    cx,ax
  677.     jnz    recv_1            ;if they overlap, then we have a real interrupt.
  678.     ret                ;spurious interrupt.
  679.  
  680. recv_1:
  681. ;check out and get rid of interrupt causes.
  682.  
  683.     test    ax,PKTRX        ;packet received?
  684.     jne    recv_2            ;yes.
  685.     jmp    recv_rbe        ;no, go see if we ran out of buffers.
  686. recv_2:
  687.     and    ax,PKTRX or RBAE    ;clear the PKTRX and RBAE flags.
  688.     out    dx,ax
  689.  
  690. ; handle received packet
  691.  
  692. recv_do_next:
  693.     mov    bx,next_rda        ;point to the rda that the sonic filled.
  694.     cmp    [bx].rda_in_use,0    ;did they really fill it?
  695.     je    recv_do_next_1        ;yes.
  696.     jmp    recv_rbe
  697. recv_do_next_1:
  698.   if 0
  699.     cmp    TossRxFlag,0        ;should we toss this one?
  700.     je    recv_do_next_2        ;no.
  701.     mov    TossRxFlag,0        ;yes, just toss it.
  702.     jmp    recv_err
  703. recv_do_next_2:
  704.   endif
  705.     test    ax,RBAE            ;did we exceed the size of the buffer?
  706.     je    recv_do_next_3        ;no.
  707. ;;;    inc    ReceiveBufferExceeded    ;yes.
  708.     jmp    recv_err
  709. recv_do_next_3:
  710.     mov    ax,[bx].rda_status
  711.     test    ax,CRCR            ;checksum error?
  712.     je    recv_do_next_4        ;no.
  713. ;;;    inc    CRCErrors
  714.     jmp    recv_err
  715. recv_do_next_4:
  716.     test    ax,FAER            ;alignment error?
  717.     je    recv_do_next_5        ;no.
  718. ;;;    inc    FrameAlignmentErrors
  719.     jmp    recv_err
  720.  
  721. recv_do_next_5:
  722.     test    ax,PRX            ;otherwise okay?
  723.     jne    recv_do_next_6        ;yes.
  724.     jmp    recv_err
  725.  
  726. recv_do_next_6:
  727.  
  728. ; get logical address of the buffer.
  729.  
  730.     mov    cx,[bx].rda_byte_count        ; bp := # of bytes received
  731.     sub    cx,4            ;leave the FCS behind.
  732.     mov    ax,[bx].rda_ptr.offs
  733.     mov    dx,[bx].rda_ptr.segm
  734.     call    phys_to_segmoffs    ;make es:di -> packet.
  735.  
  736.     push    bx
  737.     push    es
  738.     push    di
  739.  
  740.     add    di,EADDR_LEN+EADDR_LEN    ;skip the ethernet addreses and
  741.                     ;  point to the packet type.
  742.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  743.     mov    ax, es:[di]
  744.     xchg    ah, al
  745.     cmp     ax, 1500
  746.     ja    BlueBookPacket
  747.     inc    di            ;set di to 802.2 header
  748.     inc    di
  749.     mov    dl, IEEE8023
  750. BlueBookPacket:
  751.     push    cx
  752.     call    recv_find
  753.     pop    cx
  754.  
  755.     pop    si
  756.     pop    ds
  757.     pop    bx
  758.     assume    ds:nothing
  759.  
  760.     mov    ax,es            ;is this pointer null?
  761.     or    ax,di
  762.     je    recv_free        ;yes - just free the frame.
  763.  
  764.     push    es
  765.     push    di
  766.     push    cx
  767.     call    movemem
  768.     pop    cx
  769.     pop    si
  770.     pop    ds
  771.     assume    ds:nothing
  772.  
  773.     call    recv_copy
  774.  
  775.     jmp    short recv_free
  776.  
  777. recv_err:
  778.     call    count_in_err
  779. recv_free:
  780.     movseg    ds,cs
  781.     assume    ds:code
  782.  
  783.     test    [bx].rda_status,LPKT    ;is it the last packet in the RBA?
  784.     je    recv_not_last        ;no, go deal with it.
  785.  
  786.     push    bx            ;we filled up all the RDAs, have
  787.     call    update_rwp        ;  to clean up.
  788.     pop    bx
  789.  
  790. recv_not_last:
  791.     or    [bx].rda_link,EOL    ; this RDA is now new EOL.
  792.     mov    [bx].rda_in_use,0ffffh    ; sonic now has this one.
  793.  
  794.     mov    si,[bx].rda_backlink
  795.     and    [si].rda_link,not EOL    ;clear EOL in previous RDA.
  796.  
  797.     sncport    SonicCR
  798.     mov    ax,RXEN
  799.     out    dx,ax            ; re-enable Receive
  800.  
  801.     mov    bx,[bx].rda_forelink    ; now move to next rda.
  802.     mov    next_rda,bx
  803.  
  804.     sncport    SonicISR        ; setup for next check
  805.     in    ax,dx
  806.     jmp    recv_do_next
  807.  
  808. recv_rbe:
  809. ;we get here with dx = SonicISR
  810.     in    ax,dx            ; get interrupt status
  811.     test    ax,RBE            ; is it a Receive Buf Exhaust?
  812.     jz    recv_txdn
  813.  
  814. ; SONIC thinks its out of receive bufs.  ReRead the RDA
  815.  
  816. ;    inc    RxBufferExhaustedCount
  817.     call    update_rwp
  818.  
  819.     loadport
  820.     sncport    SonicISR
  821.     mov    ax,RBE
  822.     out    dx,ax                ; clr int & reread the RDA
  823.     pause_
  824.  
  825. recv_txdn:
  826. ;we get here with dx = SonicISR
  827.     in    ax,dx
  828.     and    ax, (TXDN or TXER)    ;done sending pkts?
  829.     jz    recv_txdn_1        ;go if not.
  830.     pause_
  831.     out    dx,ax            ;clear this cause.
  832. recv_txdn_1:
  833. ;we get here with dx = SonicISR
  834. ;    cli
  835.     add    dx,-2            ;point dx to SonicIMR
  836.     mov    ax,enabled_IMR        ;re-enable our ints.
  837.     out    dx,ax
  838.  
  839.     ret
  840.  
  841.  
  842. update_rwp:
  843.     loadport
  844.     sncport    SonicRSA
  845.     in    ax,dx
  846.     pause_
  847.     mov    si,ax            ;get the RSA into si.
  848.  
  849.     sncport    SonicREA
  850.     in    ax, dx
  851.     pause_
  852.     mov    di,ax            ;get the REA into di.
  853.  
  854.     sncport    SonicRWP
  855.     in    ax,dx            ; get RWP
  856.  
  857.     add    si,(RECEIVE_BUF_COUNT * (size rra_struc))/2
  858.                     ; assume we'll set @ 1/2
  859.     cmp    ax,di            ; if at end set to 1/2
  860.     je    update_rwp_1
  861.     mov    si,di            ; else its at 1/2 - set to end
  862. update_rwp_1:
  863.     mov    ax,si
  864.     out    dx,ax            ; update RWP
  865.     pause_
  866.  
  867.     ret
  868.  
  869.  
  870. phys_to_segmoffs:
  871. ;enter with dx:ax as the physical address of the buffer,
  872. ;exit with es:di -> buffer.
  873.     cmp    vds_active,0
  874.     jne    phys_to_segmoffs_1
  875.     shl    dx,16-4            ;move the upper four bits into position.
  876.     mov    di,ax            ;now get the low 12 bits of the segment.
  877.     shr    di,4
  878.     or    dx,di            ;combine them.
  879.     mov    es,dx
  880.     mov    di,ax
  881.     and    di,0fh            ;now compute the offset.
  882.     ret
  883. phys_to_segmoffs_1:
  884.     sub    ax,my_dds.dds_physical.offs    ;make into physical addresses.
  885.     add    ax,offset begin_dma
  886.     mov    di,ax            ;make dx:ax be offset into dma region.
  887.     movseg    es,cs
  888.     ret
  889.  
  890.  
  891. segmoffs_to_phys:
  892. ;enter with es:di -> buffer.
  893. ;exit with dx:ax as the physical address of the buffer,
  894.     cmp    vds_active,0
  895.     jne    segmoffs_to_phys_1
  896.     mov    dx,es            ;get the high 4 bits of the segment,
  897.     shr    dx,16-4
  898.     mov    ax,es            ;and the low 12 bits of the segment.
  899.     shl    ax,4
  900.     add    ax,di            ;add in the offset.
  901.     adc    dx,0
  902.     ret
  903. segmoffs_to_phys_1:
  904.     xor    dx,dx            ;make dx:ax be offset into dma region.
  905.     mov    ax,di
  906.     sub    ax,offset begin_dma
  907.     add    ax,my_dds.dds_physical.offs    ;make into physical addresses.
  908.     adc    dx,my_dds.dds_physical.segm
  909.     ret
  910.  
  911.     public    timer_isr
  912. timer_isr:
  913. ;if the first instruction is an iret, then the timer is not hooked
  914.     iret
  915.  
  916. ;beginning of the area of memory that the SONIC knows about (and that we will
  917. ;  have to lock down for DMA).
  918. begin_dma    label    byte
  919.  
  920. ;we have two tda's because one of them might cross a physical 64K boundary.
  921. ;If that happens, then we use the other.
  922.     align    2
  923. tda1    db    (TRANSMIT_BUF_COUNT * size tda_struc) dup(?)
  924.     align    2
  925. tda2    db    (TRANSMIT_BUF_COUNT * size tda_struc) dup(?)
  926.  
  927. ;the rra and cam share a common upper 16 bits of address, therefore they
  928. ;must be on the same 64K physical segment.  There's also alignment
  929. ;considerations.
  930.     align    2
  931. rra1    dw    RECEIVE_BUF_COUNT * 4 dup(?)
  932. cam1    dw    0            ;our address is always zero.
  933.     db    EADDR_LEN dup(?)    ;leave room for our address.
  934.     dw    1            ;for the CAM Enable register.
  935.     db    (EADDR_LEN+2)*15 dup(?)        ;leave room for up to 15 more.
  936. RRA1SIZE    equ    $ - rra1
  937.  
  938.     align    2
  939. rra2    dw    RECEIVE_BUF_COUNT * 4 dup(?)
  940. cam2    dw    0            ;our address is always zero.
  941.     db    EADDR_LEN dup(?)    ;leave room for our address.
  942.     dw    1            ;for the CAM Enable register.
  943.     db    (EADDR_LEN+2)*15 dup(?)        ;leave room for up to 15 more.
  944.  
  945. ;we have two rda's because one of them might cross a physical 64K boundary.
  946. ;If that happens, then we use the other.
  947.     align    2
  948. rda1    db    (RDA_COUNT * size rda_struc) dup(?)
  949.     align    2
  950. rda2    db    (RDA_COUNT * size rda_struc) dup(?)
  951.  
  952. ;any code after this will not be kept.  Buffers used by the program, if any,
  953. ;are allocated from the memory between end_resident and end_free_mem.
  954.     public end_resident,end_free_mem
  955.     align    4            ;just for efficiency's sake.
  956. end_resident    label    byte
  957.     db    (RECEIVE_BUF_COUNT*RECEIVE_BUF_SIZE) + (TRANSMIT_BUF_COUNT*TRANSMIT_BUF_SIZE) dup(?)
  958. end_free_mem    label    byte
  959. ;end of the area of memory that the SONIC knows about (and that we will
  960. ;  have to lock down for DMA).
  961.  
  962.  
  963.     public    usage_msg
  964. usage_msg    db    "usage: tcenet [options] <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
  965. no_board_msg    db    "No tcenet detected.",CR,LF,'$'
  966. io_addr_funny_msg    label    byte
  967.         db    "No tcenet detected, continuing anyway.",CR,LF,'$'
  968. bad_reset_msg    db    "Unable to reset the tcenet.",CR,LF,'$'
  969. bad_init_msg    db    "Unable to initialize the tcenet.",CR,LF,'$'
  970. vds_ver_msg    db    "Using VDS version ",'$'
  971.  
  972.     public    copyright_msg
  973. copyright_msg    db    "Packet driver for a Thomas-Conrad tcenet, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  974.         db    '$'
  975.  
  976. io_addrs    dw    100h,120h,140h,160h,300h,320h,340h,0
  977. io_addrs_end    label    word
  978. int_nos        db    2,3,5,7,10,11,12,15    ;interrupt numbers.
  979. dma_nos        db    1,5,6,7        ;dma channel numbers
  980.  
  981. our_address    db    6 dup(?)    ;temporarily hold our address
  982.  
  983. int_no_name    db    "Interrupt number ",'$'
  984. io_addr_name    db    "I/O port ",'$'
  985.  
  986.     extrn    set_recv_isr: near
  987.     extrn    maskint: near
  988.  
  989. ;enter with si -> argument string, di -> dword to store.
  990. ;if there is no number, don't change the number.
  991.     extrn    get_number: near
  992.  
  993. ;enter with dx -> name of word, di -> dword to print.
  994.     extrn    print_number: near
  995.  
  996.     extrn    decout: near
  997.     extrn    chrout: near
  998.  
  999. ;print a crlf
  1000.     extrn    crlf: near
  1001.  
  1002.     public    parse_args
  1003. parse_args:
  1004. ;exit with nc if all went well, cy otherwise.
  1005.     assume    ds:code
  1006.     mov    di,offset int_no
  1007.     call    get_number
  1008.     mov    di,offset io_addr
  1009.     call    get_number
  1010.     clc
  1011.     ret
  1012.  
  1013.  
  1014.     public    etopen
  1015. etopen:
  1016.     assume    ds:code
  1017.  
  1018.     cmp    io_addr,-1        ;Did they ask for auto-detect?
  1019.     je    find_board
  1020.  
  1021.     call    detect_board        ;no, just verify its existance.
  1022.     je    find_board_found
  1023.  
  1024.     mov    dx,offset io_addr_funny_msg
  1025.     mov    ah,9
  1026.     int    21h
  1027.  
  1028.     jmp    find_board_found
  1029.  
  1030. find_board:
  1031.     mov    bx,offset io_addrs    ;Search for the Ethernet address.
  1032.     mov    io_addr+2,0
  1033. find_board_0:
  1034.     mov    ax,[bx]
  1035.     mov    io_addr,ax
  1036.     call    detect_board
  1037.     je    find_board_found
  1038. find_board_again:
  1039.     add    bx,2            ;not at this port, try another.
  1040.     cmp    bx,offset io_addrs_end    ;last address?
  1041.     jb    find_board_0
  1042.  
  1043.     mov    dx,offset no_board_msg    ;Tell them that we can't find it.
  1044.     mov    ah,9
  1045.     int    21h
  1046.  
  1047.     stc
  1048.     ret
  1049. find_board_found:
  1050.  
  1051.     loadport
  1052.     sncport SonicCR
  1053.     mov    ax,RST or STP or RXDIS    ;reset the sonic, stop timer, stop rcv.
  1054.     out    dx,ax
  1055.     pause_
  1056.  
  1057.     setport    CONFIG            ;get the configuration register and
  1058.     in    ax,dx            ;  determine the interrupt number.
  1059.     and    ax,7
  1060.     mov    bx,ax
  1061.     mov    al,int_nos[bx]
  1062.     mov    int_no,al
  1063.  
  1064. ;This routine will put the (host) DMA controller into
  1065. ;cascade mode of operation.
  1066.  
  1067.     in    ax,dx            ;get the dma channel field.
  1068.     shr    ax,3
  1069.     and    ax,3
  1070.     mov    bx,ax
  1071.     mov    al,dma_nos[bx]
  1072.     mov    dma_no,al
  1073.     mov    ah,al            ;save a copy.
  1074.     and    al,DMA_CHANNEL_FIELD
  1075.     or    al,SET_DMA_MASK
  1076.     cmp    ah,4            ;If channel 5 or 6,
  1077.     ja    dma_16            ;  use sixteen bit dma.
  1078. dma_8:
  1079.     out    DMA_8MASK_REG,al    ;mask the channel off.
  1080.     mov    al,ah
  1081.     or    al,CASCADE_MODE        ;put it into cascade mode.
  1082.     out    DMA_8MODE_REG,al
  1083.     mov    al,ah            ;turn the channel on.
  1084.     out    DMA_8MASK_REG,al
  1085.     jmp    short dma_done
  1086. dma_16:
  1087.     and    ah,DMA_CHANNEL_FIELD    ;turn off the extra bits.
  1088.     out    DMA_16MASK_REG,al    ;mask the channel off.
  1089.     mov    al,ah
  1090.     or    al,CASCADE_MODE        ;put it into cascade mode.
  1091.     out    DMA_16MODE_REG,al
  1092.     mov    al,ah            ;turn the channel on.
  1093.     out    DMA_16MASK_REG,al
  1094. dma_done:
  1095.  
  1096.     mov    al, int_no        ; Get board's interrupt vector
  1097.     add    al, 8
  1098.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  1099.     jb    set_int_num        ; No.
  1100.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  1101. set_int_num:
  1102.     xor    ah, ah            ; Clear high byte
  1103.     mov    int_num, ax        ; Set parameter_list int num.
  1104.  
  1105.     mov    al,int_no
  1106.     call    maskint            ;disable these interrupts.
  1107.  
  1108.     loadport
  1109.     sncport SonicCR
  1110.     xor    ax,ax            ;take sonic out of reset.
  1111.     out    dx,ax
  1112.     pause_
  1113.  
  1114.     sncport    SonicDCR
  1115.     mov    ax,PO1 or USR1 or WC1 or WC0 or BMS or RFT1 or TFT0
  1116.     out    dx,ax
  1117.     pause_
  1118.  
  1119.     sncport    SonicRCR
  1120.     mov    ax,BRD            ; accept broadcast
  1121.     out    dx,ax
  1122.     pause_
  1123.  
  1124.     sncport    SonicTCR
  1125. ;;;voodoo programming -- these bits are read-only.
  1126. ;;;    mov    ax,04eh             ; national's value
  1127.     xor    ax,ax            ;normal Ethernet.
  1128.     out    dx,ax
  1129.     pause_
  1130.  
  1131.     sncport    SonicIMR
  1132.     xor    ax,ax            ; disable all, for now.
  1133.     out    dx,ax
  1134.     pause_
  1135.  
  1136.     sncport    SonicISR
  1137.     mov    ax,-1            ; clear all
  1138.     out    dx,ax
  1139.     pause_
  1140.  
  1141. ;
  1142. ; now we lock down the memory that we'll be using for DMA.  That is,
  1143. ; assuming we're running under some sort of memory mapper.
  1144. ;
  1145.     mov    ax,40h            ;is some program providing VDS?
  1146.     mov    es,ax
  1147.     test    byte ptr es:[7bh],20h
  1148.     jz    memory_locked        ;no.
  1149.  
  1150.     mov    ax,08102h        ;get version information.
  1151.     mov    dx,1010b        ;no auto-remap, copy data into buffer.
  1152.     int    4bh
  1153.     cmp    ax,8102h        ;did it change into version number?
  1154.     je    memory_locked        ;no, must not be there...
  1155.  
  1156.     push    ax
  1157.     mov    dx,offset vds_ver_msg
  1158.     mov    ah,9
  1159.     int    21h
  1160.     pop    ax
  1161.  
  1162.     push    ax
  1163.     mov    al,ah            ;print major version number.
  1164.     xor    ah,ah
  1165.     xor    dx,dx
  1166.     call    decout
  1167.     mov    al,'.'
  1168.     call    chrout
  1169.     pop    ax            ;print minor version number.
  1170.     xor    ah,ah
  1171.     xor    dx,dx
  1172.     call    decout
  1173.     call    crlf
  1174.  
  1175.     mov    vds_active,1
  1176.  
  1177.     movseg    es,cs
  1178.     mov    di,offset my_dds
  1179.     mov    dx,0
  1180.     call    malloc
  1181.     sub    dx,offset begin_dma
  1182.     mov    [di].dds_size.offs,dx
  1183.     mov    [di].dds_size.segm,0
  1184.     mov    [di].dds_offset.offs,offset begin_dma
  1185.     mov    [di].dds_offset.segm,0
  1186.     mov    [di].dds_seg,cs
  1187.     mov    [di].dds_buffer_id,0
  1188.     mov    ax,08103h        ;request that the memory be locked.
  1189.     mov    dx,1010b        ;no auto-remap, copy data into buffer.
  1190.     int    4bh
  1191.  
  1192. memory_locked:
  1193.  
  1194.  
  1195. ;
  1196. ; We need to keep the all the TDAs in the same physical 64K segment.  So, if the
  1197. ; first crosses a segment, the second cannot, so we'll use it.
  1198. ;
  1199.     mov    di,offset tda1
  1200.     movseg    es,cs
  1201.     call    segmoffs_to_phys
  1202.     add    ax,TRANSMIT_BUF_COUNT * (size tda_struc)
  1203.     jnc    no_tda_overflow
  1204.     mov    di,offset tda2
  1205. no_tda_overflow:
  1206.     mov    tdaptr,di        ;remember where the tda's are.
  1207.  
  1208.     mov    cx,TRANSMIT_BUF_COUNT
  1209.     mov    bx,di
  1210. init_tdas:
  1211.     mov    dx,TRANSMIT_BUF_SIZE
  1212.     call    malloc
  1213.     mov    di,dx
  1214.     mov    [bx].tda_size,0
  1215.     mov    [bx].tda_status,0
  1216.     mov    [bx].tda_frag_count,1    ;packet driver spec only allows one.
  1217.     mov    [bx].tda_link,EOL
  1218.  
  1219.     call    segmoffs_to_phys    ;convert es:di into physical address.
  1220.     mov    [bx].tda_frag_ptr.offs,ax    ;store the packet's physical address.
  1221.     mov    [bx].tda_frag_ptr.segm,dx
  1222.     add    bx,(size tda_struc)
  1223.     loop    init_tdas
  1224.  
  1225. ; init transmit regs UTDA
  1226.  
  1227.     mov    di,tdaptr
  1228.     call    segmoffs_to_phys    ; get physical
  1229.     push    dx            ;save the high word.
  1230.     loadport
  1231.     sncport    SonicUTDA
  1232.     pop    ax            ; hi word phys
  1233.     out    dx,ax
  1234.  
  1235. ;
  1236. ; We need to keep the all the RDAs in the same physical 64K segment.  So, if the
  1237. ; first crosses a segment, the second cannot, so we'll use it.
  1238. ;
  1239.     mov    si,offset rda1
  1240.     mov    ax,si
  1241.     call    segmoffs_to_phys
  1242.     add    ax,RDA_COUNT * (size rda_struc)
  1243.     jnc    no_rda_overflow
  1244.     mov    si,offset rda2
  1245. no_rda_overflow:
  1246.     mov    rdaptr,si        ;remember which one we're using
  1247.     mov    next_rda,si
  1248.  
  1249.     mov    di,rdaptr
  1250.     mov    cx,RDA_COUNT
  1251.     xor    si,si
  1252. init_rda_1:
  1253.     push    di
  1254.     add    di,(size rda_struc)
  1255.     call    segmoffs_to_phys    ;get physical offset of next link.
  1256.     pop    di
  1257.  
  1258.     mov    [di].rda_link,ax    ;make a pointer to the next.
  1259.     mov    [di].rda_backlink,si    ;make a pointer to the previous.
  1260.     mov    [di].rda_in_use,0ffffh    ;set ownership to SONIC.
  1261.     lea    ax,[di]+(size rda_struc)
  1262.     mov    [di].rda_forelink,ax    ;make a pointer to the next.
  1263.     mov    si,di            ;remember where we were.
  1264.     add    di,(size rda_struc)    ;point di to next.
  1265.     loop    init_rda_1
  1266.  
  1267.     mov    di,rdaptr
  1268.     mov    [si].rda_forelink,di    ;succ(end) = begin.
  1269.     mov    [di].rda_backlink,si    ;prev(begin) = end.
  1270.     call    segmoffs_to_phys    ;get physical offset of first link.
  1271.  
  1272.     mov    [si].rda_link,ax
  1273.     or    [si].rda_link,EOL    ;mark this one as the last.
  1274.  
  1275. ;set SONIC receive descriptor area pointers.
  1276.  
  1277.     push    dx            ;save upper word.
  1278.     loadport
  1279.     sncport    SonicCRDA        ;set current
  1280.     out    dx,ax
  1281.     pause_
  1282.     sncport    SonicURDA        ;set upper.
  1283.     pop    ax            ;restore upper word (pushed as dx).
  1284.     out    dx,ax
  1285.  
  1286. ; Init the RRA.  The RRA and CAM share the same upper address bits, so they,
  1287. ; like all the TDAs and RDAs, must be in the same physical segment.
  1288.  
  1289.     mov    si,offset rra1
  1290.     mov    ax,si
  1291.     call    segmoffs_to_phys    ;get the physical address
  1292.     add    ax,RRA1SIZE        ;fits in one segment?
  1293.     jnc    no_rra_overflow        ;yes.
  1294.     mov    si, offset rra2        ;no, the second *must*.
  1295. no_rra_overflow:
  1296.     mov    rraptr,si        ;save the pointer to the right rra.
  1297.     add    si,cam1-rra1        ;compute the pointer to the CAM.
  1298.     mov    camptr,si
  1299.  
  1300.     mov    bx,rraptr        ;point di to our rra.
  1301.     mov    cx,RECEIVE_BUF_COUNT
  1302. InitRRALoop:
  1303.     mov    dx,RECEIVE_BUF_SIZE
  1304.     call    malloc
  1305.     mov    di,dx
  1306.     call    segmoffs_to_phys    ; get physical
  1307.  
  1308.     mov    [bx].rra_ptr.offs,ax    ;low word address
  1309.     mov    [bx].rra_ptr.segm,dx    ;high word address
  1310.     mov    [bx].rra_cnt.offs,MAX8023LENGTH    ;count low word
  1311.     mov    [bx].rra_cnt.segm,0    ;count high word.
  1312.     add    bx,(size rra_struc)
  1313.     loop    InitRRALoop
  1314.  
  1315.     loadport
  1316.     sncport    SonicEOBC
  1317.     mov    ax, (MAX8023LENGTH)/2    ;count of words.
  1318.     out    dx,ax
  1319.     pause_
  1320.  
  1321.     mov    di,rraptr        ;init the pointers.
  1322.     call    segmoffs_to_phys
  1323.  
  1324.     push    ax            ;preserve the low word.
  1325.     mov    ax,dx
  1326.     loadport
  1327.     sncport    SonicURRA
  1328.     out    dx,ax            ;high word.
  1329.     pause_
  1330.     pop    ax
  1331.  
  1332.     sncport    SonicRSA        ;output the low word.
  1333.     out    dx,ax
  1334.  
  1335.     sncport    SonicRRP
  1336.     out    dx,ax
  1337.  
  1338.     add    ax,cam1-rra1        ;point to the end of the RRA.
  1339.     sncport    SonicREA
  1340.     out    dx,ax            ;set the end pointer.
  1341.  
  1342.     setport    SonicRWP
  1343.     out    dx,ax            ; write reg gets it
  1344.  
  1345. ; Init SONIC internal counters
  1346.  
  1347.     mov    ax,-1            ;clear registers (inverted on write)
  1348.     sncport    SonicCRCT
  1349.     out    dx,ax            ;CRC Tally
  1350.     sncport    SonicFAET
  1351.     out    dx,ax            ;FAE Tally
  1352.     sncport    SonicMPT
  1353.     out    dx,ax            ;Missed Packet Tally
  1354. ;take SONIC out of reset.
  1355.     sncport    SonicCR
  1356.     xor    ax,ax
  1357.     out    dx,ax
  1358.     pause_
  1359.  
  1360.     mov    ax, RRRA        ;Start the RRA.
  1361.     out    dx,ax
  1362.  
  1363. ; get our address out of ROM, and stuff it into the CAM.
  1364.     movseg    es,ds
  1365.     mov    di,offset our_address
  1366.     mov    cx,EADDR_LEN
  1367.     call    get_address
  1368.     mov    si,offset our_address
  1369.     mov    cx,EADDR_LEN
  1370.     call    set_address
  1371.  
  1372.     loadport
  1373.     sncport    SonicCR
  1374.     mov    ax,RXEN            ;Enable receive.
  1375.     out    dx,ax
  1376.  
  1377.     sncport    SonicIMR        ;Enable interrupts.
  1378.     mov    ax,enabled_IMR
  1379.     out    dx,ax
  1380.  
  1381.     call    set_recv_isr
  1382.  
  1383.     clc
  1384.     ret
  1385.  
  1386.     public    print_parameters
  1387. print_parameters:
  1388. ;echo our command-line parameters
  1389.     mov    di,offset int_no
  1390.     mov    dx,offset int_no_name
  1391.     call    print_number
  1392.     mov    di,offset io_addr
  1393.     mov    dx,offset io_addr_name
  1394.     call    print_number
  1395.     ret
  1396.  
  1397. ;TCC's manufacturer prefix is 13:80:00.  They've also used the token
  1398. ;ring version of the prefix (bit-reversed) , which is 00:01:8c.  Oops.
  1399.  
  1400. detect_board:
  1401. ;test to see if a board is located at io_addr.
  1402. ;return nz if not.
  1403.     loadport
  1404.     setport    EBASE
  1405.     in    ax,dx
  1406.     setport    EBASE+2
  1407.     cmp    ax,00h + 01h*256
  1408.     jne    detect_board_1
  1409.     in    al,dx
  1410.     cmp    al,0c8h
  1411.     ret
  1412. detect_board_1:
  1413.     cmp    ax,13h + 80h*256
  1414.     jne    detect_board_exit
  1415.     in    al,dx
  1416.     cmp    al,0
  1417. detect_board_exit:
  1418.     ret
  1419.  
  1420. code    ends
  1421.  
  1422.     end
  1423.