home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / driver6s / 3c503.asm < prev    next >
Assembly Source File  |  1990-04-10  |  40KB  |  1,140 lines

  1. version    equ    3
  2.  
  3.     include    defs.asm
  4.  
  5. ;/* PC/FTP Packet Driver source, conforming to version 1.05 of the spec,
  6. ;*  for the 3-Com 3C503 interface card.
  7. ;*  Robert C Clements, K1BC, 14 February, 1989
  8. ;*  Portions (C) Copyright 1988, 1989 Robert C Clements
  9. ;*
  10. ;  Copyright, 1988, 1989, Russell Nelson
  11.  
  12. ;   This program is free software; you can redistribute it and/or modify
  13. ;   it under the terms of the GNU General Public License as published by
  14. ;   the Free Software Foundation, version 1.
  15. ;
  16. ;   This program is distributed in the hope that it will be useful,
  17. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19. ;   GNU General Public License for more details.
  20. ;
  21. ;   You should have received a copy of the GNU General Public License
  22. ;   along with this program; if not, write to the Free Software
  23. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  
  25. ;* Change history:
  26. ;*  Updated to driver spec version 1.08 Feb. 17, 1989 by Russell Nelson.
  27. ;*  Changes 27 Jul 89 by Bob Clements (/Rcc)
  28. ;*    Added Thick versus Thin Ethernet switch  27 Jul 89 by Bob Clements (/Rcc)
  29. ;*    Added call to memory_test.
  30. ;*    Added rcv_mode logic.  Started, but didn't finish, multicast logic. 
  31. ;*      Fixed get_address to return current, not PROM, address.
  32. ;*      Minor races fixed.
  33.  
  34. comment /
  35. From: "James A. Harvey" <IJAH400@indyvax.iupui.edu>
  36. Subject: Patches for 6.x packet drivers; lockup problem fixed!
  37.  
  38. Now for the best part, the lockup problem fix.  I think this may be one that
  39. I keep hearing about that for most people the machine locks up for a minute
  40. on startup, but then continues.  For me it was worse because it appears that
  41. the "recovery" time is only short on heavily loaded networks.  The lockup is
  42. caused by the "first page for RX" being set improperly in etopen; I finally
  43. figured it out by looking at code from other drivers that used the DS8390
  44. chip.  One must switch to the page 1 command registers first.
  45. /
  46.  
  47.  
  48. code    segment    byte public
  49.     assume    cs:code, ds:code
  50.  
  51. HT    equ    09h
  52. CR    equ    0dh
  53. LF    equ    0ah
  54.  
  55. ;
  56. ;  Packet Driver Error numbers
  57. BAD_HANDLE    equ    1        ;invalid handle number
  58. NO_CLASS    equ    2        ;no interfaces of specified class found
  59. NO_TYPE        equ    3        ;no interfaces of specified type found
  60. NO_NUMBER    equ    4        ;no interfaces of specified number found
  61. BAD_TYPE    equ    5        ;bad packet type specified
  62. NO_MULTICAST    equ    6        ;this interface does not support
  63. CANT_TERMINATE    equ    7        ;this packet driver cannot terminate
  64. BAD_MODE    equ    8        ;an invalid receiver mode was specified
  65. NO_SPACE    equ    9        ;operation failed because of insufficient
  66. TYPE_INUSE    equ    10        ;the type had previously been accessed,
  67. BAD_COMMAND    equ    11        ;the command was out of range, or not
  68. CANT_SEND    equ    12        ;the packet couldn't be sent (usually
  69.  
  70. ; Stuff specific to the 3-Com 3C503 Ethernet controller board
  71. ; WD version in C by Bob Clements, K1BC, May 1988 for the KA9Q TCP/IP package
  72. ; 3Com version based on WD8003E version in .ASM, also by Bob Clements, dated
  73. ;  19 August 1988.  The WD and 3Com cards both use the National DS8390.
  74.  
  75. ; Symbol prefix "EN" is for Ethernet, National chip
  76. ; Symbol prefix "E33" is for _E_thernet, _3_Com 50_3_
  77. ; Symbol prefix "E33G" is for registers in the Gate array ASIC.
  78.  
  79. ; The E33 registers - For the ASIC on the 3C503 card:
  80. ; Offsets from the board's base address, which can be set by
  81. ; jumpers to be one of the following 8 values (hex):
  82. ;  350, 330, 310, 300, 2E0, 2A0, 280, 250
  83. ; Factory default address is 300H.
  84. ; The card occupies a block of 16 I/O addresses.
  85. ; It also occupies 16 addresses at base+400 through base+40F.
  86. ; These high-addressed registers are in the ASIC.
  87. ; Recall that the normal PC I/O decoding is only 10 bits. The 11'th
  88. ; bit (400H) can be used on the same card for additional registers.
  89. ; This offset requires word, not byte, arithmetic
  90. ; on the DX register for the setport macro. Current SETPORT is OK.
  91.  
  92. ; The card can also be jumpered to have the shared memory disabled
  93. ; or enabled at one of four addresses: C8000, CC000, D8000 or DC000.
  94. ; This version of the driver REQUIRES the shared memory to be 
  95. ; enabled somewhere.
  96. ; The card can be operated using direct I/O instructions or by
  97. ; using the PC's DMA channels instead of the shared memory, but
  98. ; I haven't included the code for those other two methods. 
  99. ; They would be needed in a system where all four possible addresses
  100. ; for the shared memory are in use by other devices.  /Rcc
  101.  
  102. ; Blocks of I/O addresses:
  103.  
  104. E33GA        equ    400h    ; Registers in the gate array.
  105. E33_SAPROM    equ    000h    ; Window on station addr prom (if
  106.                 ; E33G_CNTRL bits 3,2 = 0,1
  107.  
  108. ; The EN registers - the DS8390 chip registers
  109. ; These appear at Base+0 through Base+0F when bits 3,2 of
  110. ; E33G_CNTRL are 0,0.
  111. ; There are two (really 3) pages of registers in the chip. You select
  112. ; which page you want, then address them at offsets 00-0F from base.
  113. ; The chip command register (EN_CCMD) appears in both pages.
  114.  
  115. EN_CCMD        equ    000h    ; Chip's command register
  116.  
  117. ; Page 0
  118.  
  119. EN0_STARTPG    equ    001h    ; Starting page of ring bfr
  120. EN0_STOPPG    equ    002h    ; Ending page +1 of ring bfr
  121. EN0_BOUNDARY    equ    003h    ; Boundary page of ring bfr
  122. EN0_TSR        equ    004h    ; Transmit status reg
  123. EN0_TPSR    equ    004h    ; Transmit starting page
  124. EN0_TCNTLO    equ    005h    ; Low  byte of tx byte count
  125. EN0_TCNTHI    equ    006h    ; High byte of tx byte count
  126. EN0_ISR        equ    007h    ; Interrupt status reg
  127. EN0_RSARLO    equ    008h    ; Remote start address reg 0
  128. EN0_RSARHI    equ    009h    ; Remote start address reg 1
  129. EN0_RCNTLO    equ    00ah    ; Remote byte count reg
  130. EN0_RCNTHI    equ    00bh    ; Remote byte count reg
  131. EN0_RXCR    equ    00ch    ; RX control reg
  132. EN0_TXCR    equ    00dh    ; TX control reg
  133. EN0_COUNTER0    equ    00dh    ; Rcv alignment error counter
  134. EN0_DCFG    equ    00eh    ; Data configuration reg
  135. EN0_COUNTER1    equ    00eh    ; Rcv CRC error counter
  136. EN0_IMR        equ    00fh    ; Interrupt mask reg
  137. EN0_COUNTER2    equ    00fh    ; Rcv missed frame error counter
  138.  
  139. ; Page 1
  140.  
  141. EN1_PHYS    equ    001h    ; This board's physical enet addr
  142. EN1_CURPAG    equ    007h    ; Current memory page
  143. EN1_MULT    equ    008h    ; Multicast filter mask array (8 bytes)
  144.  
  145. ; Chip commands in EN_CCMD
  146. ENC_STOP    equ    001h    ; Stop the chip
  147. ENC_START    equ    002h    ; Start the chip
  148. ENC_TRANS    equ    004h    ; Transmit a frame
  149. ENC_RREAD    equ    008h    ; remote read
  150. ENC_RWRITE    equ    010h    ; remote write
  151. ENC_NODMA    equ    020h    ; No remote DMA used on this card
  152. ENC_PAGE0    equ    000h    ; Select page 0 of chip registers
  153. ENC_PAGE1    equ    040h    ; Select page 1 of chip registers
  154.  
  155. ; Commands for RX control reg
  156. ENRXCR_MON    equ    020h    ; Monitor mode (no packets rcvd)
  157. ENRXCR_PROMP    equ    010h    ; Promiscuous physical addresses 
  158. ENRXCR_MULTI    equ    008h    ; Multicast (if pass filter)
  159. ENRXCR_BCST    equ    004h    ; Accept broadcasts
  160. ENRXCR_BAD    equ    003h    ; Accept runts and bad CRC frames
  161.  
  162. ; Commands for TX control reg
  163. ENTXCR_LOOP    equ    002h    ; Set loopback mode
  164.  
  165. ; Bits in EN0_DCFG - Data config register
  166. ENDCFG_BM8    equ    048h    ; Set burst mode, 8 deep FIFO
  167.  
  168. ; Bits in EN0_ISR - Interrupt status register
  169. ENISR_RX    equ    001h    ; Receiver, no error
  170. ENISR_TX    equ    002h    ; Transmitter, no error
  171. ENISR_RX_ERR    equ    004h    ; Receiver, with error
  172. ENISR_TX_ERR    equ    008h    ; Transmitter, with error
  173. ENISR_OVER    equ    010h    ; Receiver overwrote the ring
  174. ENISR_COUNTERS    equ    020h    ; Counters need emptying
  175. ENISR_RDC    equ    040h    ; remote dma complete
  176. ENISR_RESET    equ    080h    ; Reset completed
  177. ENISR_ALL    equ    03fh    ; Interrupts we will enable
  178.  
  179. ; Bits in received packet status byte and EN0_RSR
  180. ENPS_RXOK    equ    001h    ; Received a good packet
  181.  
  182. ; Bits in TX status reg
  183.  
  184. ENTSR_PTX    equ    001h    ; Packet transmitted without error
  185. ENTSR_COLL    equ    004h    ; Collided at least once
  186. ENTSR_COLL16    equ    008h    ; Collided 16 times and was dropped
  187. ENTSR_FU    equ    020h    ; TX FIFO Underrun
  188.  
  189. ; Registers in the 3-Com custom Gate Array
  190.  
  191. E33G_STARTPG    equ E33GA+00h    ; Start page, must match EN0_STARTPG
  192. E33G_STOPPG    equ E33GA+01h    ; Stop  page, must match EN0_STOPPG
  193. E33G_NBURST    equ E33GA+02h    ; Size of DMA burst before relinquishing bus
  194. E33G_IOBASE    equ E33GA+03h    ; Bit coded: where I/O regs are jumpered.
  195.                 ; (Which you have to know already to read it)
  196. E33G_ROMBASE    equ E33GA+04h    ; Bit coded: Where/whether EEPROM&DPRAM exist
  197. E33G_GACFR    equ E33GA+05h    ; Config/setup bits for the ASIC GA
  198. E33G_CNTRL    equ E33GA+06h    ; Board's main control register
  199. E33G_STATUS    equ E33GA+07h    ; Status on completions.
  200. E33G_IDCFR    equ E33GA+08h    ; Interrupt/DMA config register
  201.                 ; (Which IRQ to assert, DMA chan to use)
  202. E33G_DMAAH    equ E33GA+09h    ; High byte of DMA address reg
  203. E33G_DMAAL    equ E33GA+0ah    ; Low byte of DMA address reg
  204. E33G_VP2    equ E33GA+0bh    ; Vector pointer - for clearing RAM select
  205. E33G_VP1    equ E33GA+0ch    ;  on a system reset, to re-enable EPROM.
  206. E33G_VP0    equ E33GA+0dh    ;  3Com says set this to Ctrl-Alt-Del handler
  207. E33G_FIFOH    equ E33GA+0eh    ; FIFO for programmed I/O data moves ...
  208. E33G_FIFOL    equ E33GA+0fh    ; .. low byte of above.
  209.  
  210. ; Bits in E33G_CNTRL register:
  211.  
  212. ECNTRL_RESET    equ    001h    ; Software reset of the ASIC and 8390
  213. ECNTRL_THIN    equ    002h    ; Onboard thin-net xcvr enable
  214. ECNTRL_SAPROM    equ    004h    ; Map the station address prom
  215. ECNTRL_DBLBFR    equ    020h    ; FIFO configuration bit
  216. ECNTRL_OUTPUT    equ    040h    ; PC-to-3C501 direction if 1
  217. ECNTRL_START    equ    080h    ; Start the DMA logic
  218.  
  219. ; Bits in E33G_STATUS register:
  220.  
  221. ESTAT_DPRDY    equ    080h    ; Data port (of FIFO) ready
  222. ESTAT_UFLW    equ    040h    ; Tried to read FIFO when it was empty
  223. ESTAT_OFLW    equ    020h    ; Tried to write FIFO when it was full
  224. ESTAT_DTC    equ    010h    ; Terminal Count from PC bus DMA logic
  225. ESTAT_DIP    equ    008h    ; DMA In Progress
  226.  
  227. ; Bits in E33G_GACFR register:
  228.  
  229. EGACFR_NORM    equ    049h    ; Enable 8K shared mem, no DMA TC int
  230. EGACFR_IRQOFF    equ    0c9h    ; Above, and disable 8390 IRQ line
  231.  
  232. ; Shared memory management parameters
  233.  
  234. XMIT_MTU    equ    600h    ; Largest packet we have room for.
  235. SM_TSTART_PG    equ    020h    ; First page of TX buffer
  236. SM_RSTART_PG    equ    026h    ; Starting page of RX ring
  237. SM_RSTOP_PG    equ    040h    ; Last page +1 of RX ring
  238.  
  239. ; Description of header of each packet in receive area of shared memory
  240.  
  241. EN_RBUF_STAT    equ    0    ; Received frame status
  242. EN_RBUF_NXT_PG    equ    1    ; Page after this frame
  243. EN_RBUF_SIZE_LO    equ    2    ; Length of this frame
  244. EN_RBUF_SIZE_HI    equ    3    ; Length of this frame
  245. EN_RBUF_NHDR    equ    4    ; Length of above header area
  246.  
  247. ; End of 3C503 parameter definitions
  248.  
  249. ; The following two values may be overridden from the command line.
  250. ; If they are omitted from the command line, these defaults are used.
  251. ; The shared memory base is set by a jumper.  We read it from the
  252. ; card and set up accordingly.
  253.  
  254.     public    int_no, io_addr, thick_or_thin
  255. int_no        db    2,0,0,0        ; Interrupt level
  256. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  257. thick_or_thin    dw    1,0        ; Non-zero means thin net
  258.     public    mem_base
  259. mem_base    dw    00000h,0    ; Shared memory addr (jumpers)
  260. ; (Not changeable by software in 3C503)    ; (0 if disabled by jumpers)
  261. thin_bit    db    ECNTRL_THIN    ; Default to thin cable
  262. rxcr_bits       db      ENRXCR_BCST     ; Default to ours plus multicast
  263.  
  264.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  265. driver_class    db    1        ;from the packet spec
  266. driver_type    db    12        ;from the packet spec
  267. driver_name    db    '3C503',0    ;name of the driver.
  268. driver_function    db    2
  269. parameter_list    label    byte
  270.     db    1    ;major rev of packet driver
  271.     db    9    ;minor rev of packet driver
  272.     db    14    ;length of parameter list
  273.     db    EADDR_LEN    ;length of MAC-layer address
  274.     dw    GIANT    ;MTU, including MAC headers
  275.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  276.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  277.     dw    0    ;(# of successive xmits) - 1
  278.     dw    0    ;Interrupt # to hook for post-EOI
  279.             ;processing, 0 == none,
  280.  
  281.     public    card_hw_addr, curr_hw_addr, mcast_list_bits, mcast_all_flag
  282. card_hw_addr    db    0,0,0,0,0,0    ;Physical ethernet address
  283. curr_hw_addr    db    0,0,0,0,0,0    ;Address set into the 8390
  284. mcast_list_bits db      0,0,0,0,0,0,0,0 ;Bit mask from last set_multicast_list
  285. mcast_all_flag  db      0               ;Non-zero if hware should have all
  286.                     ; ones in mask rather than this list.
  287.  
  288.     public    rcv_modes
  289. rcv_modes    dw    7        ;number of receive modes in our table.
  290.         dw    0               ;There is no mode zero
  291.         dw    rcv_mode_1
  292.         dw    rcv_mode_2
  293.         dw    rcv_mode_3
  294.         dw    rcv_mode_4
  295.         dw    rcv_mode_5
  296.         dw    rcv_mode_6
  297.  
  298. ; send_pkt: - The Transmit Frame routine
  299.  
  300.     public    send_pkt
  301. send_pkt:
  302. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  303. ;  (only if the high-performance bit is set in driver_function)
  304. ;enter with ds:si -> packet, cx = packet length.
  305. ;exit with nc if ok, or else cy if error, dh set to error number.
  306.     assume    ds:nothing
  307.     loadport        ; Point at chip command register
  308.     setport EN_CCMD        ; ..
  309.     mov bx,    8000h        ; Avoid infinite loop
  310. tx_wait:
  311.     in al,    dx        ; Get chip command state
  312.     test al,ENC_TRANS    ; Is transmitter still running?
  313.     jz    tx_idle        ; Go if free
  314.     dec    bx        ; Count the timeout
  315.     jnz    tx_wait        ; Fall thru if TX is stuck
  316.                 ; Should count these error timeouts
  317.                 ; Maybe need to add recovery logic here
  318. tx_idle:
  319.     cmp    cx,XMIT_MTU    ; Is this packet too large?
  320.     ja    send_pkt_toobig
  321.  
  322.     cmp cx,    RUNT        ; Is the frame long enough?
  323.     jnb    tx_oklen    ; Go if OK
  324.     mov cx,    RUNT        ; Stretch frame to minimum allowed
  325. tx_oklen:
  326.     push    cx        ; Hold count for later
  327.     loadport        ; Set up for address of TX buffer in
  328.     setport    E33G_GACFR    ; Make sure gate array is set up and
  329.     mov al,    EGACFR_NORM    ;  the RAM is enabled (not EPROM)
  330.     out dx,    al        ; ..
  331.     mov ax,    cs:mem_base    ; Set up ES at the shared RAM
  332.     mov es,    ax        ; ..
  333.     xor ax,    ax        ; Set up DI at base of tx buffer
  334.     mov ah,    SM_TSTART_PG    ; Where to put tx frame
  335.     mov di,    ax        ; ..
  336.     call    movemem
  337.     pop    cx        ; Get back count to give to board
  338.     setport    EN0_TCNTLO    ; Low byte of TX count
  339.     mov al,    cl        ; Get the count
  340.     out dx,    al        ; Tell card the count
  341.     setport    EN0_TCNTHI    ; High byte of TX count
  342.     mov al,    ch        ; Get the count
  343.     out dx,    al        ; Tell card the count
  344.     setport    EN0_TPSR    ; Transmit Page Start Register
  345.     mov al,    SM_TSTART_PG
  346.     out dx,    al        ; Start the transmitter
  347.     setport    EN_CCMD        ; Chip command reg
  348.     mov al,    ENC_TRANS+ENC_NODMA
  349.     out dx,    al        ; Start the transmitter
  350.     clc            ; Successfully started
  351.     ret            ; End of transmit-start routine
  352. send_pkt_toobig:
  353.     mov    dh,NO_SPACE
  354.     stc
  355.     ret
  356.  
  357.  
  358. movemem:
  359. ;does the same thing as "rep movsb", only 50% faster.
  360. ;moves words instead of bytes, and handles the case of both addresses odd
  361. ;efficiently.  There is no way to handle one address odd efficiently.
  362. ;This routine always aligns the source address in the hopes that the
  363. ;destination address will also get aligned.  This is from Phil Karn's
  364. ;code from ec.c, a part of his NET package.  I bummed a few instructions
  365. ;out.
  366.     jcxz    movemem_cnte        ; If zero, we're done already.
  367.     test    si,1            ; Does source start on odd byte?
  368.     jz    movemem_adre        ; Go if not
  369.     movsb                ; Yes, move the first byte
  370.     dec    cx            ; Count that byte
  371. movemem_adre:
  372.     shr    cx,1            ; convert to word count
  373.     rep    movsw            ; Move the bulk as words
  374.     jnc    movemem_cnte        ; Go if the count was even
  375.     movsb                ; Move leftover last byte
  376. movemem_cnte:
  377.     ret
  378.  
  379.  
  380.     public    get_address
  381. get_address:
  382. ;get the address of the interface.
  383. ;enter with es:di -> place to get the address, cx = size of address buffer.
  384. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  385. ; Give caller the one currently in the 8390, not necessarily the one in PROM.
  386.     assume ds:code
  387.     cmp cx,    EADDR_LEN    ; Caller wants a reasonable length?
  388.     jb    get_addr_x    ; No, fail.
  389.     mov cx,    EADDR_LEN    ; Move one ethernet address from our copy
  390.     mov si, offset curr_hw_addr     ; Copy from most recent setting
  391.     rep     movsb
  392.     mov cx,    EADDR_LEN    ; Tell caller how many bytes we fed him
  393.     clc            ; Carry off says success
  394.     ret
  395. get_addr_x:
  396.     stc            ; Tell caller our addr is too big for him
  397.     ret
  398.  
  399.  
  400.     public    set_address
  401. set_address:
  402.     assume    ds:nothing
  403. ;enter with ds:si -> Ethernet address, CX = length of address.
  404. ;exit with nc if okay, or cy, dh=error if any errors.
  405. ;
  406.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  407.     je    set_address_4
  408.     mov    dh,BAD_ADDRESS
  409.     stc
  410.     jmp    short set_address_done
  411. set_address_4:
  412.     push    cs              ; Copy from them to our RAM copy
  413.     pop     es              ; Destination of move
  414.     mov di, offset curr_hw_addr
  415.     rep     movsb           ; Move their address
  416.     call    set_8390_eaddr  ; Put that address in the chip
  417. set_address_okay:
  418.     mov    cx,EADDR_LEN        ;return their address length.
  419.     clc
  420. set_address_done:
  421.     push    cs
  422.     pop    ds
  423.     assume    ds:code
  424.     ret
  425.  
  426. ; Copy our Ethernet address from curr_hw_addr into the DS8390
  427. set_8390_eaddr:
  428.     push    cs              ; Get it from our local RAM copy
  429.     pop     ds
  430.     mov si, offset curr_hw_addr
  431.     mov cx,    EADDR_LEN    ; Move one ethernet address from our copy
  432.     loadport
  433.     setport    EN_CCMD        ; Chip command register
  434.     cli            ; Protect from irq changing page bits
  435.     mov al,    ENC_NODMA+ENC_PAGE1
  436.     out dx,    al        ; Switch to page one for writing eaddr
  437.     setport    EN1_PHYS    ; Where it goes in 8390
  438. set_8390_1:
  439.     lodsb
  440.     out    dx,al
  441.     inc    dx
  442.     loop    set_8390_1
  443.     loadport
  444.     setport    EN_CCMD        ; Chip command register
  445.     mov al,    ENC_NODMA+ENC_PAGE0
  446.     out dx,    al        ; Restore to page zero
  447.     sti            ; OK for interrupts now
  448.     ret
  449.  
  450. ; Routines to set address filtering modes in the DS8390
  451. rcv_mode_1:     ; Turn off receiver
  452.     mov al,    ENRXCR_MON      ; Set to monitor for counts but accept none
  453.     jmp short rcv_mode_set
  454. rcv_mode_2:     ; Receive only packets to this interface
  455.     mov al, 0               ; Set for only our packets
  456.     jmp short rcv_mode_set
  457. rcv_mode_3:     ; Mode 2 plus broadcast packets (This is the default)
  458.     mov al,    ENRXCR_BCST     ; Set four ours plus broadcasts
  459.     jmp short rcv_mode_set
  460. rcv_mode_4:     ; Mode 3 plus selected multicast packets
  461.     mov al,    ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
  462.     mov     mcast_all_flag,0
  463.     jmp short rcv_mode_set
  464. rcv_mode_5:     ; Mode 3 plus ALL multicast packets
  465.     mov al,    ENRXCR_BCST+ENRXCR_MULTI ; Ours, bcst, and filtered multicasts
  466.     mov     mcast_all_flag,1
  467.     jmp short rcv_mode_set
  468. rcv_mode_6:     ; Receive all packets (Promiscuous physical plus all multi)
  469.     mov al,    ENRXCR_BCST+ENRXCR_MULTI+ENRXCR_PROMP
  470.     mov     mcast_all_flag,1
  471. rcv_mode_set:
  472.     push    ax              ; Hold mode until masks are right
  473.     call    set_8390_multi  ; Set the multicast mask bits in chip
  474.     pop     ax
  475.     loadport
  476.     setport    EN0_RXCR    ; Set receiver to selected mode
  477.     out dx,    al
  478.     mov     rxcr_bits,al    ; Save a copy of what we set it to
  479.     ret
  480.  
  481.  
  482.     public    set_multicast_list
  483. set_multicast_list:
  484. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  485. ;return nc if we set all of them, or cy,dh=error if we didn't.
  486.     mov    dh,NO_MULTICAST
  487.     stc
  488.     ret
  489.  
  490.  
  491. ; Set the multicast filter mask bits in case promiscuous rcv wanted
  492. set_8390_multi:
  493.     loadport
  494.     setport    EN_CCMD        ; Chip command register
  495.     mov cx,    8        ; Eight bytes of multicast filter
  496.     mov si, offset mcast_list_bits  ; Where bits are, if not all ones
  497.     push    cs
  498.     pop     ds
  499.     cli            ; Protect from irq changing page bits
  500.     mov al,    ENC_NODMA+ENC_PAGE1
  501.     out dx,    al        ; Switch to page one for writing eaddr
  502.     setport    EN1_MULT    ; Where it goes in 8390
  503.     mov al, mcast_all_flag  ; Want all ones or just selected bits?
  504.     or al,  al
  505.     je      set_mcast_2     ; Just selected ones
  506.     mov al,    0ffh        ; Ones for filter
  507. set_mcast_all:
  508.     out dx,    al        ; Write a mask byte
  509.     inc    dl        ; Step to next one
  510.     loop    set_mcast_all    ; ..    
  511.     jmp short set_mcast_x
  512.  
  513. set_mcast_2:
  514.     lodsb                   ; Get a byte of mask bits
  515.     out dx,    al        ; Write a mask byte
  516.     inc    dl        ; Step to next I/O register
  517.     loop    set_mcast_2     ; ..    
  518. set_mcast_x:
  519.     loadport
  520.     setport    EN_CCMD        ; Chip command register
  521.     mov al,    ENC_NODMA+ENC_PAGE0
  522.     out dx,    al        ; Restore to page zero
  523.     sti            ; OK for interrupts now
  524.     ret
  525.  
  526.     public    terminate
  527. terminate:
  528.     ret
  529.  
  530.     public    reset_interface
  531. reset_interface:
  532.     assume ds:code
  533.     loadport        ; Base of I/O regs
  534.     setport    EN_CCMD        ; Chip command reg
  535.     mov al,    ENC_STOP+ENC_NODMA
  536.     out dx,    al        ; Stop the DS8390
  537.     setport    EN0_ISR        ; Interrupt status reg
  538.     mov al,    0ffh        ; Clear all pending interrupts
  539.     out dx,    al        ; ..
  540.     setport    EN0_IMR        ; Interrupt mask reg
  541.     xor al,    al        ; Turn off all enables
  542.     out dx,    al        ; ..
  543.     ret
  544.  
  545. ; Linkages to non-device-specific routines
  546. ;called when we want to determine what to do with a received packet.
  547. ;enter with cx = packet length, es:di -> packet type.
  548. ;It returns with es:di = 0 if don't want this type or if no buffer available.
  549.     extrn    recv_find: near
  550.  
  551. ;called after we have copied the packet into the buffer.
  552. ;enter with ds:si ->the packet, cx = length of the packet.
  553.     extrn    recv_copy: near
  554.  
  555.     extrn    count_in_err: near
  556.     extrn    count_out_err: near
  557.  
  558.     public    recv
  559. recv:
  560. ;called from the recv isr.  All registers have been saved, and ds=cs.
  561. ;Actually, not just receive, but all interrupts come here.
  562. ;Upon exit, the interrupt will be acknowledged.
  563.  
  564.     assume    ds:code
  565. check_isr:            ; Was there an interrupt from this card?
  566.     loadport        ; Point at card's I/O port base
  567.     setport    E33G_GACFR    ; Make sure gate array is set up and
  568.     mov al,    EGACFR_NORM    ;  the RAM is enabled (not EPROM)
  569.     out dx,    al        ; ..
  570.     setport    EN0_ISR        ; Point at interrupt status register
  571.     in al,    dx        ; Get pending interrupts
  572.     and al,    ENISR_ALL    ; Any?
  573.     jnz    isr_test_overrun
  574.     jmp    interrupt_done    ; Go if none
  575. ; First, a messy procedure for handling the case where the rcvr
  576. ; over-runs its ring buffer.  This is spec'ed by National for the chip.
  577. ; This is handled differently in sample code from 3Com and from WD.
  578. ; This is close to the WD version.  May need tweaking if it doesn't
  579. ; work for the 3Com card.
  580.  
  581. isr_test_overrun: 
  582.     test al,ENISR_OVER    ; Was there an overrun?
  583.     jnz    recv_overrun    ; Go if so.
  584.     jmp    recv_no_overrun    ; Go if not.
  585. recv_overrun:
  586.     setport    EN_CCMD        ; Stop the chip
  587.     mov al,    ENC_STOP+ENC_NODMA
  588.     out dx,    al        ; Write "stop" to command register
  589.  
  590.     mov al, ENC_NODMA+ENC_PAGE1    ; Could be in previous out, but
  591.     out dx,al        ; was only tested this way
  592.     setport EN1_CURPAG    ; Get current page
  593.     in al,dx
  594.     mov bl,al        ; save it
  595.     setport    EN_CCMD        ;
  596.     mov al, ENC_NODMA+ENC_PAGE0
  597.     out dx,al        ; Back to page 0
  598.  
  599. ; Remove one frame from the ring
  600.     setport    EN0_BOUNDARY    ; Find end of this frame
  601.     in al,    dx        ; Get memory page number
  602.     inc    al        ; Page plus 1
  603.     cmp al,    SM_RSTOP_PG    ; Wrapped around ring?
  604.     jnz    rcv_ovr_nwrap    ; Go if not
  605.     mov al,    SM_RSTART_PG    ; Yes, wrap the page pointer
  606. rcv_ovr_nwrap:
  607.  
  608.     cmp    al,bl        ; Check if buffer emptry
  609.     je    rcv_ovr_empty    ; Yes ? Don't receive anything
  610.  
  611.     xor ah,    ah        ; Convert page to segment
  612.     mov cl,    4
  613.     mov bl,    al        ; Page number as arg to rcv_frm
  614.     shl ax,    cl        ; ..
  615.     add ax,    mem_base    ; Page in this memory
  616.     mov es,    ax        ; Segment pointer to the frame header
  617.     push    es        ; Hold this frame pointer for later
  618.     mov al,    es:[EN_RBUF_STAT]    ; Get the buffer status byte
  619.     test al,ENPS_RXOK    ; Is this frame any good?
  620.     jz    rcv_ovr_ng    ; Skip if not
  621.      call    rcv_frm        ; Yes, go accept it
  622. rcv_ovr_ng:
  623.     pop    es        ; Back to start of this frame
  624.     mov al,    es:[EN_RBUF_NXT_PG]    ; Get pointer to next frame
  625.     dec    al        ; Back up one page
  626.     cmp al,    SM_RSTART_PG    ; Did it wrap?
  627.     jge    rcv_ovr_nwr2
  628.     mov al,    SM_RSTOP_PG-1    ; Yes, back to end of ring
  629. rcv_ovr_nwr2:
  630.     loadport        ; Point at boundary reg
  631.     setport    EN0_BOUNDARY    ; ..
  632.     out dx,    al        ; Set the boundary
  633. rcv_ovr_empty:
  634.     setport    EN0_RCNTLO    ; Point at byte count regs
  635.     xor al,    al        ; Clear them
  636.     out dx,    al        ; ..
  637.     setport    EN0_RCNTHI
  638.     out dx,    al
  639.     setport    EN0_ISR        ; Point at status reg
  640.     mov cx,    8000h        ; Timeout counter
  641. rcv_ovr_rst_loop:
  642.     in al,    dx        ; Is it finished resetting?
  643.     test al,ENISR_RESET    ; ..
  644.     jnz    rcv_ovr_rst    ; Go if so
  645.     dec    cx        ; Loop til reset, or til timeout
  646.     jnz    rcv_ovr_rst_loop
  647. rcv_ovr_rst:
  648.     loadport        ; Point at Transmit control reg
  649.      setport    EN0_TXCR    ; ..
  650.     mov al,    ENTXCR_LOOP    ; Put transmitter in loopback mode
  651.     out dx,    al        ; ..
  652.     setport    EN_CCMD        ; Point at Chip command reg
  653.     mov al,    ENC_START+ENC_NODMA
  654.     out dx,    al        ; Start the chip running again
  655.     setport    EN0_TXCR    ; Back to TX control reg
  656.     xor al,    al        ; Clear the loopback bit
  657.     out dx,    al        ; ..
  658.     setport    EN0_ISR        ; Point at Interrupt status register
  659.     mov al,    ENISR_OVER    ; Clear the overrun interrupt bit
  660.     out dx,    al        ; ..
  661.     call    count_in_err    ; Count the anomaly
  662.      jmp    check_isr    ; Done with the overrun case
  663.  
  664. recv_no_overrun:
  665. ; Handle receive flags, normal and with error (but not overrun).
  666.     test al,ENISR_RX+ENISR_RX_ERR    ; Frame received without overrun?
  667.     jnz    recv_frame    ; Go if so.
  668.     jmp    recv_no_frame    ; Go if not.
  669. recv_frame:
  670.     loadport        ; Point at Chip's Command Reg
  671.      setport    EN_CCMD        ; ..
  672.     mov al,    ENC_NODMA+ENC_PAGE1
  673.     out dx,    al        ; Switch to page 1 registers
  674.     setport    EN1_CURPAG    ;Get current page of rcv ring
  675.     in al,    dx        ; ..
  676.     mov ah,    al        ; Hold current page in AH
  677.      setport    EN_CCMD        ; Back to page zero registers
  678.     mov al,    ENC_NODMA+ENC_PAGE0
  679.     out dx,    al        ; Switch back to page 0 registers
  680.     setport    EN0_BOUNDARY    ;Get boundary page
  681.     in al,    dx        ; ..
  682.     inc    al        ; Step boundary from last used page
  683.     cmp al,    SM_RSTOP_PG    ; Wrap if needed
  684.     jne    rx_nwrap3    ; Go if not
  685.     mov al,    SM_RSTART_PG    ; Wrap to first RX page
  686. rx_nwrap3:
  687.     cmp al,    ah        ; Read all the frames?
  688.     je    recv_frame_break    ; Finished them all
  689.     mov bl,    al        ; Page number as arg to rcv_frm
  690.     xor ah,    ah        ; Make segment pointer to this frame
  691.     mov cl,    4        ; 16 * pages = paragraphs
  692.     shl ax,    cl        ; ..
  693.     add ax,    mem_base    ; That far into shared memory
  694.     mov es,    ax        ; Segment part of pointer
  695.     push    es        ; Hold on to this pointer for later
  696.     mov al,    es:[EN_RBUF_STAT]    ; Get the buffer status byte
  697.     test al,ENPS_RXOK    ; Good frame?
  698.     jz    recv_no_rcv
  699.     call    rcv_frm        ; Yes, go accept it
  700. recv_no_rcv:
  701.     pop    es        ; Back to base of frame
  702.     mov al,    es:[EN_RBUF_NXT_PG]    ; Start of next frame
  703.     dec    al        ; Make previous page for new boundary
  704.     cmp al,    SM_RSTART_PG    ; Wrap around the bottom?
  705.     jge    rcv_nwrap4
  706.     mov al,    SM_RSTOP_PG-1    ; Yes
  707. rcv_nwrap4:
  708.     loadport        ; Point at the Boundary Reg again
  709.      setport    EN0_BOUNDARY    ; ..
  710.     out dx,    al        ; Set new boundary
  711.     jmp    recv_frame    ; See if any more frames
  712.  
  713. recv_frame_break:
  714.     loadport        ; Point at Interrupt Status Reg
  715.      setport    EN0_ISR        ; ..
  716.     mov al,    ENISR_RX+ENISR_RX_ERR+ENISR_OVER
  717.     out dx,    al        ; Clear those requests
  718.     jmp    check_isr    ; See if any other interrupts pending
  719.  
  720. recv_no_frame:                ; Handle transmit flags.
  721.     test al,ENISR_TX+ENISR_TX_ERR    ; Frame transmitted?
  722.     jnz    isr_tx        ; Go if so.
  723.     jmp    isr_no_tx    ; Go if not.
  724. isr_tx:
  725.     mov ah,    al        ; Hold interrupt status bits
  726.     loadport        ; Point at Transmit Status Reg
  727.      setport    EN0_TSR        ; ..
  728.     in al,    dx        ; ..
  729.     test ah,ENISR_TX    ; Non-error TX?
  730.     jz    isr_tx_err    ; No, do TX error completion
  731.     test al,ENTSR_COLL16    ; Jammed for 16 transmit tries?
  732.     jz    isr_tx_njam    ; Go if not
  733.     call    count_out_err    ; Yes, count those
  734. isr_tx_njam:
  735.     setport    EN0_ISR        ; Clear the TX complete flag
  736.     mov al,    ENISR_TX    ; ..
  737.     out dx,    al        ; ..    
  738.     jmp    isr_tx_done
  739. isr_tx_err:
  740.     test al,ENTSR_FU    ; FIFO Underrun?
  741.     jz    isr_txerr_nfu
  742.     call    count_out_err    ; Yes, count those
  743. isr_txerr_nfu:
  744.     loadport        ; Clear the TX error completion flag
  745.     setport    EN0_ISR        ; ..
  746.     mov al,    ENISR_TX_ERR    ; ..
  747.     out dx,    al        ; ..    
  748. isr_tx_done:
  749. ; If TX queue and/or TX shared memory ring buffer were being
  750. ; used, logic to step through them would go here.  However,
  751. ; in this version, we just clear the flags for background to notice.
  752.  
  753.      jmp    check_isr    ; See if any other interrupts on
  754.  
  755. isr_no_tx:
  756. ; Now check to see if any counters are getting full
  757.     test al,ENISR_COUNTERS    ; Interrupt to handle counters?
  758.     jnz    isr_stat    ; Go if so.
  759.     jmp    isr_no_stat    ; Go if not.
  760. isr_stat:
  761. ; We have to read the counters to clear them and to clear the interrupt.
  762. ; Version 1 of the PC/FTP driver spec doesn't give us
  763. ; anything useful to do with the data, though.
  764. ; Fix this up for V2 one of these days.
  765.     loadport        ; Point at first counter
  766.      setport    EN0_COUNTER0    ; ..
  767.     in al,    dx        ; Read the count, ignore it.
  768.     setport    EN0_COUNTER1
  769.     in al,    dx        ; Read the count, ignore it.
  770.     setport    EN0_COUNTER2
  771.     in al,    dx        ; Read the count, ignore it.
  772.     setport    EN0_ISR        ; Clear the statistics completion flag
  773.     mov al,    ENISR_COUNTERS    ; ..
  774.     out dx,    al        ; ..
  775. isr_no_stat:
  776.      jmp    check_isr    ; Anything else to do?
  777.  
  778. interrupt_done:
  779.     ret
  780.  
  781. ; Do the work of copying out a receive frame.
  782. ; Called with bl/ the page number of the frame header in shared memory/
  783. ; Also, es/ the paragraph number of that page.
  784.  
  785. rcv_frm:
  786. ; Old version checked size, memory space, queue length here. Now done
  787. ; in higher level code.
  788. ; Set cx to length of this frame.
  789.     mov ch,    es:[EN_RBUF_SIZE_HI]    ; Extract size of frame
  790.     mov cl,    es:[EN_RBUF_SIZE_LO]    ; Extract size of frame
  791.     sub cx,    EN_RBUF_NHDR        ; Less the header stuff
  792. ; Set es:di to point to Ethernet type field.  es is already at base of
  793. ; page where this frame starts.  Set di after the header and two addresses.
  794.     mov di,    EN_RBUF_NHDR+EADDR_LEN+EADDR_LEN
  795.     push    bx            ; Save page number in bl
  796.     push    cx            ; Save frame size
  797.     push    es
  798.     mov ax,    cs            ; Set ds = code
  799.     mov ds,    ax
  800.     assume    ds:code
  801.     call    recv_find        ; See if type and size are wanted
  802.     pop    ds            ; RX page pointer in ds now
  803.     assume    ds:nothing
  804.     pop    cx
  805.     pop    bx
  806.     cld            ; Copies below are forward, please
  807.     mov ax,    es        ; Did recv_find give us a null pointer?
  808.     or ax,    di        ; ..
  809.     je    rcv_no_copy    ; If null, don't copy the data    
  810.  
  811.     push    cx        ; We will want the count and pointer
  812.     push    es        ;  to hand to client after copying,
  813.     push    di        ;  so save them at this point
  814.  
  815. ;; if ( (((size + 255 + EN_RBUF_NHDR) >> 8) + pg) > SM_RSTOP_PG){
  816.     mov ax,    cx        ; Length of frame
  817.     add ax,    EN_RBUF_NHDR+255 ; Including the overhead bytes, rounded up
  818.     add ah,    bl        ; Compute page with last byte of data in ah
  819.     cmp ah,    SM_RSTOP_PG    ; Over the top of the ring?
  820.     jg    rcopy_wrap    ; Yes, move in two pieces
  821.     mov si,    EN_RBUF_NHDR    ; One piece, starts here in first page (in ds)
  822.     jmp    rcopy_one_piece    ; Go move it
  823.  
  824. rcopy_wrap:
  825. ;; Copy in two pieces due to buffer wraparound. */
  826. ;; n = ((SM_RSTOP_PG - pg) << 8) - EN_RBUF_NHDR;    /* To top of mem */
  827.     mov ah,    SM_RSTOP_PG    ; Compute length of first part
  828.     sub ah,    bl        ;  as all of the pages up to wrap point
  829.     xor al,    al        ; 16-bit count
  830.     sub ax,    EN_RBUF_NHDR    ; Less the four overhead bytes
  831.     sub cx,    ax        ; Move the rest in second part
  832.     push    cx        ; Save count of second part
  833.     mov cx,    ax        ; Count for first move
  834.     mov si,    EN_RBUF_NHDR    ; ds:si points at first byte to move
  835.     shr cx,    1        ; All above are even numbers, do words.
  836.     rep    movsw        ; Move first part of frame
  837.     mov ax,    mem_base    ; Paragraph of base of shared memory
  838.     mov ds,    ax        ; ..
  839.     mov si,    SM_RSTART_PG*256  ; Offset to start of first receive page
  840.     pop    cx        ; Bytes left to move
  841. rcopy_one_piece:
  842.     call    movemem
  843.     pop    si        ; Recover pointer to destination
  844.     pop    ds        ; Tell client it's his source
  845.     pop    cx        ; And it's this long
  846.     assume    ds:nothing
  847.     call    recv_copy    ; Give it to him
  848. rcv_no_copy:
  849.     push    cs        ; Put ds back in code space
  850.     pop    ds        ; ..
  851.     assume    ds:code
  852.     ret            ; That's it for rcv_frm
  853.  
  854.  
  855.     public    recv_exiting
  856. recv_exiting:
  857. ;called from the recv isr after interrupts have been acknowledged.
  858. ;Only ds and ax have been saved.
  859.     assume    ds:nothing
  860.     ret
  861.  
  862.  
  863. ;any code after this will not be kept after initialization.
  864. end_resident    label    byte
  865.  
  866.  
  867.     public    usage_msg
  868. usage_msg    db    "usage: 3C503 <packet_int_no> <int_level(2-5)> <io_addr> <thin_net_flag>",CR,LF,'$'
  869.  
  870.     public    copyright_msg
  871. copyright_msg    db    "Packet driver for 3-Com 3C503, version ",'0'+majver,".",'0'+version,CR,LF
  872.         db    "Portions Copyright 1989, Robert C. Clements, K1BC",CR,LF,'$'
  873.  
  874. cfg_err_msg:
  875.     db    "3C503 Configuration failed. Check parameters.",CR,LF,'$'
  876. no_mem_msg:
  877.     db    "3C503 memory jumper must be set to enable memory.",CR,LF
  878.     db    "Driver cannot run with memory disabled.",'$'
  879. int_no_name:
  880.     db    "Interrupt number ",'$'
  881. io_addr_name:
  882.     db    "I/O port ",'$'
  883. mem_base_name:
  884.     db    "Memory address ",'$'
  885. thick_thin_msg:
  886.     db    "Flag, non-zero if thin Ethernet: ",'$'
  887. mem_busted_msg:
  888.     db    "Shared RAM on 3C503 card is defective or there is an address conflict.",CR,LF,'$'
  889.  
  890.     extrn    set_recv_isr: near
  891.  
  892. ;enter with si -> argument string, di -> word to store.
  893. ;if there is no number, don't change the number.
  894.     extrn    get_number: near
  895.  
  896. ;enter with dx -> name of word, di -> dword to print.
  897.     extrn    print_number: near
  898.  
  899.     public    parse_args
  900. parse_args:
  901. ;exit with nc if all went well, cy otherwise.
  902.     mov di,    offset int_no        ; May override interrupt channel
  903.     call    get_number
  904.     mov di,    offset io_addr        ; May override I/O address
  905.     call    get_number
  906.     mov di,    offset thick_or_thin    ; May override thick/thin cable flag
  907.     call    get_number
  908.     mov ax,    thick_or_thin        ; Now make the right bit
  909.     cmp ax,    0
  910.     je    parse_thin1        ; If zero, leave bit off
  911.     mov al,    ECNTRL_THIN        ; Else the bit for the card
  912. parse_thin1:
  913.     mov    thin_bit,al        ; Save for setting up the card
  914.  
  915. ;    mov di,    offset mem_base        ; Not movable in 3C503
  916. ;    mov bx,    offset mem_base_name    ; Message for it
  917. ;    call    get_number        ; Must get from jumpers.
  918.     clc
  919.     ret
  920.  
  921.  
  922. mem_busted:
  923.     mov dx,    offset mem_busted_msg
  924.     jmp    short error
  925. nomem_error:
  926.     mov    dx,offset no_mem_msg
  927.     jmp    short error
  928. cfg_error:
  929.     mov    dx,offset cfg_err_msg
  930. error:
  931.     mov    ah,9        ; Type the msg
  932.     int    21h
  933.     stc            ; Indicate error
  934.     ret            ; Return to common code
  935.  
  936. ; Called once to initialize the 3C503 card
  937.  
  938.     public    etopen
  939. etopen:                ; Initialize interface
  940. ; First, initialize the Gate Array (ASIC) card logic.  Later do the 8390.
  941.     loadport        ; First, pulse the board reset
  942.     setport    E33G_CNTRL
  943.     mov al,    thin_bit    ; Thick or thin cable bit
  944.     or al,    ECNTRL_RESET
  945.     out dx,    al        ; Turn on board reset bit
  946.     and al,    ECNTRL_THIN
  947.     out dx,    al        ; Turn off board reset bit
  948. ; Now get the board's physical address from on-board PROM into card_hw_addr
  949.     cli                     ; Protect the E33G_CNTRL contents
  950.     setport E33G_CNTRL    ; Switch control bits to enable SA PROM
  951.     mov al,    thin_bit
  952.     or al,    ECNTRL_SAPROM
  953.     out dx,    al        ; ..
  954.     setport    E33_SAPROM    ; Where the address prom is
  955.     cld            ; Make sure string mode is right
  956.     push    cs        ; Point es:di at local copy space
  957.     pop    es
  958.     mov di,    offset card_hw_addr
  959.     mov cx,    EADDR_LEN    ; Set count for loop
  960. ini_addr_loop:
  961.     in al,    dx        ; Get a byte of address
  962.     stosb            ; Feed it to caller
  963.     inc    dx        ; Next byte at next I/O port
  964.     loop    ini_addr_loop    ; Loop over six bytes
  965.     loadport        ; Re-establish I/O base after dx mods
  966.     setport E33G_CNTRL    ; Switch control bits to turn off SA PROM
  967.     mov al,    thin_bit
  968.     out dx,    al        ; Turn off SA PROM windowing
  969.     sti                     ; Ok for E33G_CNTRL to change now
  970. ; Point the "Vector Pointer" registers off into the boonies so we
  971. ; don't get the shared RAM disabled on us while we're using it.
  972. ; Ideally a warm boot should reset this too, to get to ROM on this card,
  973. ; but I don't know a guaranteed way to determine that value.
  974.     setport    E33G_VP2
  975.     mov al,    0ffh        ; Point this at the ROM restart location
  976.     out dx,    al        ;  of ffff0h.
  977.     setport E33G_VP1
  978.     out dx,    al
  979.     xor al,    al
  980.     setport E33G_VP0
  981.     out dx,    al
  982. ;Make sure shared memory is jumpered on. Find its address.
  983.     setport E33G_ROMBASE    ; Point at rom/ram cfg reg
  984.     in al,    dx        ; Read it
  985.     test al,0f0h        ; Any bits on?
  986.     jne    memcfg_1    ; Yes
  987.     jmp    nomem_error    ; No, can't run without it
  988. memcfg_1:
  989.     mov bx,    0c600h        ; Build mem segment here
  990.     test al,0c0h        ; DC00 or D800?
  991.     je    memcfg_2    ; No
  992.     add bx,    01000h        ; Yes, make Dx00
  993. memcfg_2:
  994.     test al,0a0h        ; DC00 or CC00?
  995.     je    memcfg_3
  996.     add bx,    00400h        ; Yes, make xC00
  997. memcfg_3:
  998.     mov mem_base,bx        ; Remember segment addr of memory
  999. ; Set up Gate Array's Config Reg to enable and size the RAM.
  1000.     setport    E33G_GACFR    ; Make sure gate array is set up and
  1001.     mov al,    EGACFR_IRQOFF    ;  the RAM is enabled (not EPROM)
  1002.     out dx,    al        ; ..
  1003. ; Check the card's memory
  1004.     mov ax,    mem_base    ; Set segment of the shared memory
  1005.     add ax,    16*SM_TSTART_PG    ;  which starts 2000h up from "base"
  1006.     mov cx,    2000h        ; Length of RAM to test
  1007.     call    memory_test    ; Check it out
  1008.     jz    mem_works    ; Go if it's OK
  1009.     jmp    mem_busted    ; Go report failure if it's bad
  1010. mem_works:
  1011. ; Set up control of shared memory, buffer ring, etc.
  1012.     loadport
  1013.     setport    E33G_STARTPG    ; Set ASIC copy of rx's first buffer page
  1014.     mov al,    SM_RSTART_PG
  1015.     out dx,    al
  1016.     setport    E33G_STOPPG    ;  and ASIC copy of rx's last buffer page + 1
  1017.     mov al,    SM_RSTOP_PG
  1018.     out dx,    al
  1019. ; Set up interrupt/DMA control register in ASIC.
  1020. ; For now, we won't use the DMA, so B0-B3 are zero.
  1021.     xor ah,    ah        ; Get the interrupt level from arg line
  1022.     mov al,    int_no        ; ..
  1023.     cmp al,    9        ; If converted to 9, make back into 2
  1024.     jne    get_irq1    ; Not 9
  1025.     mov al,    2        ; Card thinks it's IRQ2
  1026. get_irq1:            ; Now should have level in range 2-5
  1027.     sub ax,    2        ; Make 0-3 for tables
  1028.     cmp ax,    5-2        ; In range?
  1029.     jna    get_irq2
  1030.     jmp    cfg_error    ; If not, can't configure.
  1031. get_irq2:
  1032.     xor cx,    cx        ; Make the bit for the ASIC
  1033.     mov cl,    al        ; Shift count
  1034.     mov al,    10h        ; Bit for irq2
  1035.     jcxz    get_irq3    ; Go if it's 2
  1036.     shl al,    cl        ; Shift over for 3-5
  1037. get_irq3:
  1038.     setport    E33G_IDCFR    ; Point at ASIC reg for IRQ level
  1039.     out dx,    al        ; Set the bit
  1040.     setport    E33G_NBURST    ; Set burst size to 8
  1041.     mov al,    8
  1042.     out dx,    al        ; ..
  1043.     setport    E33G_DMAAH    ; Set up transmit bfr in DMA addr
  1044.     mov al,    SM_TSTART_PG
  1045.     out dx,    al
  1046.     xor ax,    ax
  1047.     setport E33G_DMAAL
  1048.     out dx,    al
  1049. ; Now, initialize the DS8390 Ethernet Controller chip
  1050. ini_8390:
  1051.     setport    EN_CCMD        ; DS8390 chip's command register
  1052.     mov al,    ENC_NODMA+ENC_PAGE0+ENC_STOP
  1053.     out dx,    al        ; Switch to page zero
  1054.     setport    EN0_ISR        ; Clear all interrupt flags
  1055.     mov al,    0ffh        ; ..
  1056.     out dx,    al        ; ..
  1057.     setport    EN0_DCFG    ; Configure the fifo organization
  1058.     mov al,    ENDCFG_BM8    ; Fifo threshold = 8 bytes
  1059.     out dx,    al
  1060.     setport    EN0_TXCR    ; Set transmitter mode to normal
  1061.     xor al,    al
  1062.     out dx,    al
  1063.     setport    EN0_RXCR    ; Set receiver to monitor mode
  1064.     mov al,    ENRXCR_MON
  1065.     out dx,    al
  1066. ; Set up control of shared memory, buffer ring, etc.
  1067.     setport    EN0_STARTPG    ; Set receiver's first buffer page
  1068.     mov al,    SM_RSTART_PG
  1069.     out dx,    al
  1070.     setport    EN0_STOPPG    ;  and receiver's last buffer page + 1
  1071.     mov al,    SM_RSTOP_PG
  1072.     out dx,    al
  1073.     setport    EN0_BOUNDARY    ; Set initial "last page we have emptied"
  1074.     mov al,    SM_RSTART_PG    ; (WD doc says set to RSTART_PG)
  1075. ;    dec    al        ; (3Com doc says set to RSTOP_PG-1 ?)
  1076. ;                ; (and 3Com handling of BOUNDARY is
  1077. ;                ;  different throughout.)
  1078.     out dx,    al        ; (Check out why WD and 3Com disagree)
  1079.     push    ds              ; Copy from card's address to current address
  1080.     pop     es
  1081.     mov si, offset card_hw_addr
  1082.     mov di, offset curr_hw_addr
  1083.     mov cx, EADDR_LEN       ; Copy one address length
  1084.     rep     movsb           ; ..
  1085.     call    set_8390_eaddr  ; Now set the address in the 8390 chip
  1086.     call    set_8390_multi  ; Put the right stuff into 8390's multicast masks
  1087.     loadport        ; Base of I/O regs
  1088.     setport EN_CCMD        ;[jah] Switch to page 1 registers
  1089.     mov al,ENC_NODMA+ENC_PAGE1    ;[jah]
  1090.     out dx, al        ;[jah]
  1091.     setport    EN1_CURPAG    ; Set current shared page for RX to work on
  1092.     mov al,    SM_RSTART_PG+1
  1093.     out dx,    al
  1094.     setport    EN_CCMD        ; Chip command register
  1095.     mov al,    ENC_NODMA+ENC_PAGE0
  1096.     out dx,    al        ; Back to page zero
  1097.     setport    EN0_RCNTLO    ; Clear the byte count registers
  1098.     xor al,    al        ; ..
  1099.     out dx,    al
  1100.     setport    EN0_RCNTHI
  1101.     out dx,    al        ; Clear high byte, too
  1102.     setport    EN0_IMR        ; Clear all interrupt enable flags
  1103.     xor al,    al
  1104.     out dx,    al
  1105.     setport    EN0_ISR        ; Clear all interrupt assertion flags
  1106.     mov al,    0ffh        ; again for safety before making the
  1107.     out dx,    al        ; interrupt be enabled
  1108.     call    set_recv_isr    ; Put ourselves in interrupt chain
  1109.     loadport
  1110.     setport    EN_CCMD        ; Now start the DS8390
  1111.     mov al,    ENC_START+ENC_NODMA
  1112.     out dx,    al        ; interrupt be enabled
  1113.     setport    EN0_RXCR    ; Tell it what frames to accept
  1114.     mov al,    rxcr_bits       ; As most recently set by set_mode
  1115.     out dx,    al
  1116.     setport    E33G_GACFR    ; Now let it interrupt us
  1117.     mov al,    EGACFR_NORM    ;  and leave RAM enabled
  1118.     out dx,    al
  1119.     setport    EN0_IMR        ; Tell card it can cause these interrupts
  1120.     mov al,    ENISR_ALL
  1121.     out dx,    al
  1122.     mov di,    offset int_no        ; May override interrupt channel
  1123.     mov dx,    offset int_no_name    ; Message for it
  1124.     call    print_number
  1125.     mov di,    offset io_addr        ; May override I/O address
  1126.     mov dx,    offset io_addr_name    ; Message for it
  1127.     call    print_number
  1128.     mov di,    offset thick_or_thin    ; May override thick/thin cable flag
  1129.     mov dx,    offset thick_thin_msg    ; Message for it
  1130.     call    print_number
  1131.     mov dx,    offset end_resident    ; Report our size
  1132.     clc                ; Say no error
  1133.     ret                ; Back to common code
  1134.  
  1135.     include memtest.asm
  1136.  
  1137. code    ends
  1138.  
  1139.     end
  1140.