home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / drivrs30 / 3c503.asm < prev    next >
Assembly Source File  |  1989-06-08  |  33KB  |  947 lines

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