home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / driver6s / 3c501.asm next >
Assembly Source File  |  1990-03-15  |  16KB  |  695 lines

  1. version    equ    1
  2.  
  3.     include    defs.asm
  4.  
  5. ;Ported from Phil Karn's ec.c, a C-language driver for the 3COM 3C501
  6. ;by Russell Nelson.  Any bugs are due to Russell Nelson.
  7. ;*  Updated to version 1.08 Feb. 17, 1989.
  8.  
  9. ;  Copyright, 1988, 1989, Russell Nelson
  10.  
  11. ;   This program is free software; you can redistribute it and/or modify
  12. ;   it under the terms of the GNU General Public License as published by
  13. ;   the Free Software Foundation, version 1.
  14. ;
  15. ;   This program is distributed in the hope that it will be useful,
  16. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. ;   GNU General Public License for more details.
  19. ;
  20. ;   You should have received a copy of the GNU General Public License
  21. ;   along with this program; if not, write to the Free Software
  22. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  
  24. code    segment    byte public
  25.     assume    cs:code, ds:code
  26.  
  27. ;The various IE command registers
  28. EDLC_ADDR    equ    00h    ;EDLC station address, 6 bytes
  29. EDLC_RCV    equ    06h    ;EDLC receive csr
  30. EDLC_XMT    equ    07h    ;EDLC transmit csr
  31. IE_GP        equ    08h    ;GP pointer
  32. IE_RP        equ    0ah    ;Receive buffer pointer
  33. IE_SAPROM    equ    0ch    ;window on station addr prom
  34. IE_CSR        equ    0eh    ;IE command/status
  35. IE_BFR        equ    0fh    ;window on packet buffer
  36.  
  37. ;Bits in EDLC_RCV, interrupt enable on write, status when read
  38. EDLC_NONE    equ    000h    ;match mode in bits 5-6, write only
  39. EDLC_ALL    equ    040h    ;promiscuous receive, write only
  40. EDLC_BROAD    equ    080h    ;station address plus broadcast
  41. EDLC_MULTI    equ    0c0h    ;station address plus multicast
  42.  
  43. EDLC_STALE    equ    80h    ;receive CSR status previously read
  44. EDLC_GOOD    equ    20h    ;well formed packets only
  45. EDLC_ANY    equ    10h    ;any packet, even those with errors
  46. EDLC_SHORT    equ    08h    ;short frame
  47. EDLC_DRIBBLE    equ    04h    ;dribble error
  48. EDLC_FCS    equ    02h    ;CRC error
  49. EDLC_OVER    equ    01h    ;data overflow
  50.  
  51. EDLC_RERROR    equ    EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
  52. EDLC_RMASK    equ    EDLC_GOOD or EDLC_ANY or EDLC_RERROR
  53.  
  54. ;bits in EDLC_XMT, interrupt enable on write, status when read
  55. EDLC_IDLE    equ    08h    ;transmit idle
  56. EDLC_16        equ    04h    ;packet experienced 16 collisions
  57. EDLC_JAM    equ    02h    ;packet experienced a collision
  58. EDLC_UNDER    equ    01h    ;data underflow
  59.  
  60. ;bits in IE_CSR
  61. IE_RESET    equ    80h    ;reset the controller (wo)
  62. IE_XMTBSY    equ    80h    ;Transmitter busy (ro)
  63. IE_RIDE        equ    40h    ;request interrupt/DMA enable (rw)
  64. IE_DMA        equ    20h    ;DMA request (rw)
  65. IE_EDMA        equ    10h    ;DMA done (ro)
  66.  
  67. IE_BUFCTL    equ    0ch    ;mask for buffer control field (rw)
  68. IE_LOOP        equ    0ch    ;2 bit field in bits 2,3, loopback
  69. IE_RCVEDLC    equ    08h    ;gives buffer to receiver
  70. IE_XMTEDLC    equ    04h    ;gives buffer to transmit
  71. IE_SYSBFR    equ    00h    ;gives buffer to processor
  72.  
  73. IE_CRC        equ    01h    ;causes CRC error on transmit (wo)
  74. IE_RCVBSY    equ    01h    ;receive in progress (ro)
  75.  
  76. BFRSIZ        equ    2048    ;number of bytes in a buffer
  77.  
  78.     public    int_no
  79. int_no        db    3,0,0,0        ; interrupt number.
  80. io_addr        dw    0300h,0        ; I/O address for card (jumpers)
  81.  
  82.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  83. driver_class    db    1        ;from the packet spec
  84. driver_type    db    1        ;from the packet spec
  85. driver_name    db    '3C501',0    ;name of the driver.
  86. driver_function    db    2
  87. parameter_list    label    byte
  88.     db    1    ;major rev of packet driver
  89.     db    9    ;minor rev of packet driver
  90.     db    14    ;length of parameter list
  91.     db    EADDR_LEN    ;length of MAC-layer address
  92.     dw    GIANT    ;MTU, including MAC headers
  93.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  94.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  95.     dw    0    ;(# of successive xmits) - 1
  96.     dw    0    ;Interrupt # to hook for post-EOI
  97.             ;processing, 0 == none,
  98.  
  99.     public    rcv_modes
  100. rcv_modes    dw    7        ;number of receive modes in our table.
  101.         dw    0               ;There is no mode zero
  102.         dw    rcv_mode_1
  103.         dw    0        ;don't want to bother.
  104.         dw    rcv_mode_3
  105.         dw    0        ;haven't set up perfect filtering yet.
  106.         dw    rcv_mode_5
  107.         dw    rcv_mode_6
  108.  
  109. ipkt_size    dw    ?
  110. opkt_size    dw    ?
  111.  
  112. is_186        db    0        ;=0 if 808[68], =1 if 80[123]86.
  113. our_type    dw    ?
  114.  
  115.     public    send_pkt
  116. send_pkt:
  117. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  118. ;  (only if the high-performance bit is set in driver_function)
  119. ;enter with ds:si -> packet, cx = packet length.
  120. ;exit with nc if ok, or else cy if error, dh set to error number.
  121.     assume    ds:nothing
  122.     cmp    cx,RUNT        ; minimum length for Ether
  123.     jae    oklen
  124.     mov    cx,RUNT        ; make sure size at least RUNT
  125. oklen:
  126.     inc    cx            ;round size up to next even number.
  127.     and    cx,not 1
  128.  
  129. ;Wait for transmitter ready, if necessary. IE_XMTBSY is valid
  130. ;only in the transmit mode, hence the initial check.
  131.  
  132.     loadport
  133.     setport    IE_CSR
  134.     in    al,dx
  135.     and    al,IE_BUFCTL
  136.     cmp    al,IE_XMTEDLC
  137.     jne    send_pkt_2
  138.  
  139.     mov    bx,20000        ;try this many times.
  140. send_pkt_3:
  141.     in    al,dx            ;if not busy, exit.
  142.     and    al,IE_XMTBSY
  143.     je    send_pkt_2
  144.     dec    bx
  145.     jne    send_pkt_3
  146.     mov    dh,CANT_SEND        ;timed out, can't send.
  147.     stc
  148.     ret
  149. send_pkt_2:
  150.  
  151. ;Get control of the board buffer and disable receiver
  152.     mov    al,IE_RIDE or IE_SYSBFR
  153.     setport    IE_CSR
  154.     out    dx,al
  155.  
  156. ;Point GP at beginning of packet
  157.     mov    ax,BFRSIZ
  158.     sub    ax,cx
  159.     setport    IE_GP
  160.     out    dx,ax
  161.  
  162.     setport    IE_BFR
  163.  
  164.     mov    opkt_size,cx    ; opkt_size = cx;
  165.     cmp    is_186,0    ; Can we use rep outsb?
  166.     je    out86        ; no - have to do it slowly.
  167.     db    0f3h, 06eh    ;masm 4.0 doesn't grok "rep outsb"
  168.     jmp    short ocnteven
  169. out86:
  170.     test    si,1        ; (buf & 1) ?
  171.     jz    obufeven    ; no
  172.     lodsb            ; al = *si++;
  173.     out    dx,al        ; out(dx,al);
  174.     dec    cx        ; cx--;
  175. obufeven:
  176.     mov    di,cx        ; save for later test
  177.     shr    cx,1        ; cx = cnt >> 1; (convert to word count)
  178. ; Do the bulk of the buffer, a word at a time
  179.     jcxz    onobuf        ; if(cx != 0){
  180. xb:    lodsw            ; do { ax = *si++; (si is word pointer)
  181.     out    dx,al        ; out(dx,lowbyte(ax));
  182.     mov    al,ah
  183.     out    dx,al        ; out(dx,hibyte(ax));
  184.     loop    xb        ; } while(--cx != 0); }
  185. ; now check for odd trailing byte
  186. onobuf:    shr    di,1        ; if (di & 1)
  187.     jnc    ocnteven
  188.     lodsb            ;   out(dx,*si++);
  189.     out    dx,al
  190. ocnteven:
  191.  
  192. ;Start transmitter
  193. ;Point GP at beginning of packet
  194.     mov    ax,BFRSIZ
  195.     sub    ax,opkt_size
  196.     setport    IE_GP
  197.     out    dx,ax
  198.  
  199.     mov    al,IE_RIDE or IE_XMTEDLC
  200.     setport    IE_CSR
  201.     out    dx,al
  202.  
  203.   if 1
  204.     mov    bx,20000        ;try this many times.
  205. send_pkt_4:
  206.     in    al,dx            ;if not busy, exit.
  207.     and    al,IE_XMTBSY
  208.     je    send_pkt_5
  209.     dec    bx
  210.     jne    send_pkt_4
  211.     mov    dh,CANT_SEND        ;timed out, can't send.
  212.     stc
  213.     ret
  214. send_pkt_5:
  215.  
  216.   endif
  217.  
  218.     clc
  219.     ret
  220.  
  221.  
  222.     public    get_address
  223. get_address:
  224. ;get the address of the interface.
  225. ;enter with es:di -> place to get the address, cx = size of address buffer.
  226. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  227.     assume    ds:code
  228.     cmp    cx,EADDR_LEN        ;make sure that we have enough room.
  229.     jb    get_address_2
  230.     mov    cx,EADDR_LEN
  231.     xor    bx,bx
  232. get_address_1:
  233.     mov    ax,bx
  234.     loadport
  235.     setport    IE_GP
  236.     out    dx,ax
  237.  
  238.     setport    IE_SAPROM
  239.     in    al,dx
  240.     stosb
  241.     inc    bx
  242.     loop    get_address_1
  243.  
  244.     mov    cx,EADDR_LEN
  245.     clc
  246.     ret
  247. get_address_2:
  248.     stc
  249.     ret
  250.  
  251.  
  252. ;Set Ethernet address on controller
  253.     public    set_address
  254. set_address:
  255.     assume    ds:nothing
  256. ;enter with ds:si -> Ethernet address, CX = length of address.
  257. ;exit with nc if okay, or cy, dh=error if any errors.
  258. ;
  259.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  260.     je    set_address_4
  261.     mov    dh,BAD_ADDRESS
  262.     stc
  263.     jmp    short set_address_done
  264. set_address_4:
  265.  
  266.     loadport
  267.     setport    EDLC_ADDR
  268. set_address_1:
  269.     lodsb
  270.     out    dx,al
  271.     inc    dx
  272.     loop    set_address_1
  273. set_address_okay:
  274.     mov    cx,EADDR_LEN        ;return their address length.
  275.     clc
  276. set_address_done:
  277.     push    cs
  278.     pop    ds
  279.     assume    ds:code
  280.     ret
  281.  
  282.  
  283. rcv_mode_1:
  284. ;Set up the receiver interrupts and flush status
  285.     mov    al,EDLC_NONE
  286.     loadport
  287.     setport    EDLC_RCV
  288.     out    dx,al
  289.     in    al,dx            ;flush status.
  290.  
  291.     ret
  292.  
  293.  
  294. rcv_mode_3:
  295. ;Set up the receiver interrupts and flush status
  296.     mov    al,EDLC_BROAD or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
  297.     loadport
  298.     setport    EDLC_RCV
  299.     out    dx,al
  300.     in    al,dx            ;flush status.
  301.  
  302.     ret
  303.  
  304.  
  305. rcv_mode_5:
  306. ;Set up the receiver interrupts and flush status
  307.     mov    al,EDLC_MULTI or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
  308.     loadport
  309.     setport    EDLC_RCV
  310.     out    dx,al
  311.     in    al,dx            ;flush status.
  312.  
  313.     ret
  314.  
  315.  
  316. rcv_mode_6:
  317. ;Set up the receiver interrupts and flush status
  318.     mov    al,EDLC_ALL or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
  319.     loadport
  320.     setport    EDLC_RCV
  321.     out    dx,al
  322.     in    al,dx            ;flush status.
  323.  
  324.     ret
  325.  
  326.  
  327.     public    set_multicast_list
  328. set_multicast_list:
  329. ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
  330. ;return nc if we set all of them, or cy,dh=error if we didn't.
  331.     mov    dh,NO_MULTICAST
  332.     stc
  333.     ret
  334.  
  335.  
  336.     public    terminate
  337. terminate:
  338. ;Pulse IE_RESET
  339.     mov    al,IE_RESET
  340.     loadport
  341.     setport    IE_CSR
  342.     out    dx,al
  343.     mov    al,0
  344.     out    dx,al
  345.  
  346.     ret
  347.  
  348.     public    reset_interface
  349. reset_interface:
  350. ;reset the interface.
  351. ;we don't do anything.
  352.     ret
  353.  
  354.  
  355. ;called when we want to determine what to do with a received packet.
  356. ;enter with cx = packet length, es:di -> packet type.
  357.     extrn    recv_find: near
  358.  
  359. ;called after we have copied the packet into the buffer.
  360. ;enter with ds:si ->the packet, cx = length of the packet.
  361.     extrn    recv_copy: near
  362.  
  363.     extrn    count_in_err: near
  364.     extrn    count_out_err: near
  365.  
  366.     public    recv
  367. recv:
  368. ;called from the recv isr.  All registers have been saved, and ds=cs.
  369. ;Upon exit, the interrupt will be acknowledged.
  370.     assume    ds:code
  371.  
  372. ;Check for transmit jam
  373.  
  374.     loadport
  375.     setport    IE_CSR
  376.     in    al,dx
  377.     and    al,IE_XMTBSY
  378.     jne    recv_isr_1
  379.  
  380.     setport    EDLC_XMT
  381.     in    al,dx
  382.     test    al,EDLC_16
  383.     je    recv_isr_2
  384. ;ecp->estats.jam16++;
  385.     call    rcv_fixup
  386.     jmp    short     recv_isr_3
  387. recv_isr_2:
  388.     test    al,EDLC_JAM
  389.     je    recv_isr_3
  390. ;Crank counter back to beginning and restart transmit
  391. ;ecp->estats.jam++;
  392.     mov    al,IE_RIDE or IE_SYSBFR
  393.     setport    IE_CSR
  394.     out    dx,al
  395.  
  396.     mov    ax,BFRSIZ
  397.     sub    ax,opkt_size
  398.     setport    IE_GP
  399.     out    dx,ax
  400.  
  401.     mov    al,IE_RIDE or IE_XMTEDLC
  402.     setport    IE_CSR
  403.     out    dx,al
  404.  
  405. recv_isr_3:
  406.  
  407. recv_isr_1:
  408.     loadport
  409.     setport    EDLC_RCV
  410.     in    al,dx
  411.     test    al,EDLC_STALE
  412.     jne    recv_isr_4_j_1
  413.     test    al,EDLC_OVER
  414.     je    recv_isr_5
  415. ;ecp->estats.over++;
  416.     call    rcv_fixup
  417.     jmp    recv_isr_1
  418. recv_isr_5:
  419.     test    al,EDLC_SHORT or EDLC_FCS or EDLC_DRIBBLE
  420.     je    recv_isr_6
  421. ;ecp->estats.bad++;
  422.     call    rcv_fixup
  423.     jmp    recv_isr_1
  424. recv_isr_4_j_1:
  425.     jmp    recv_isr_4
  426. recv_isr_6:
  427.     test    al,EDLC_ANY
  428.     je    recv_isr_4_j_1
  429. ;Get control of the buffer
  430.     mov    al,IE_RIDE or IE_SYSBFR
  431.     setport    IE_CSR
  432.     out    dx,al
  433.  
  434.     setport    IE_RP
  435.     in    ax,dx            ;get the size.
  436.     mov    ipkt_size,ax
  437.     cmp    ax,RUNT            ;less than RUNT?
  438.     jb    recv_isr_7        ;yes.
  439.     cmp    ax,GIANT        ;greater than GIANT?
  440.     jbe    recv_isr_8        ;no.
  441. recv_isr_7:
  442.     call    count_in_err
  443. ;ecp->estats.bad++;
  444.     jmp    recv_isr_9
  445. recv_isr_8:
  446. ;Put it on the receive queue
  447.  
  448.     mov    ax,EADDR_LEN+EADDR_LEN    ;seek to the type word.
  449.     setport    IE_GP
  450.     out    dx,ax
  451.  
  452.     setport    IE_BFR
  453.     in    al,dx            ;read the type word out of the board.
  454.     mov    ah,al
  455.     in    al,dx
  456.     xchg    al,ah            ;should be in network byte order.
  457.     mov    our_type,ax
  458.  
  459.     mov    ax,ds            ;look up our type.
  460.     mov    es,ax
  461.     mov    di,offset our_type
  462.     mov    cx,ipkt_size
  463.     call    recv_find
  464.  
  465.     mov    ax,es            ;is this pointer null?
  466.     or    ax,di
  467.     je    recv_isr_9        ;yes - just free the frame.
  468.  
  469.     push    es            ;remember where the buffer pointer is.
  470.     push    di
  471.  
  472.     xor    ax,ax            ;seek to the beginning again.
  473.     loadport
  474.     setport    IE_GP
  475.     out    dx,ax
  476.  
  477.     mov    cx,ipkt_size
  478.     setport    IE_BFR
  479.  
  480.     cmp    is_186,0    ; Can we use rep insb?
  481.     je    in86        ; no - have to do it slowly.
  482.     db    0f3h, 06ch    ;masm 4.0 doesn't grok "rep insb"
  483.     jmp    short icnteven
  484. in86:
  485. ; If buffer doesn't begin on a word boundary, get the first byte
  486.     test    di,1    ; if(buf & 1){
  487.     jz    ibufeven ;
  488.     in    al,dx    ; al = in(dx);
  489.     stosb        ; *di++ = al
  490.     dec    cx    ; cx--;
  491. ibufeven:
  492.     mov    si,cx    ; size = cx;
  493.     shr    cx,1    ; cx = cnt >> 1; (convert to word count)
  494. ; Do the bulk of the buffer, a word at a time
  495.     jcxz    inobuf    ; if(cx != 0){
  496. rb:    in    al,dx    ; do { al = in(dx);
  497.     mov    ah,al
  498.     in    al,dx    ; ah = in(dx);
  499.     xchg    al,ah
  500.     stosw        ; *si++ = ax; (di is word pointer)
  501.     loop    rb    ; } while(--cx != 0);
  502. ; now check for odd trailing byte
  503. inobuf:    shr    si,1
  504.     jnc    icnteven
  505.     in    al,dx
  506.     stosb        ; *di++ = al
  507. icnteven:
  508.  
  509.     pop    si
  510.     pop    ds
  511.     assume    ds:nothing
  512.     mov    cx,ipkt_size
  513.     call    recv_copy        ;tell them that we copied it.
  514.  
  515.     mov    ax,cs            ;restore our ds.
  516.     mov    ds,ax
  517.     assume    ds:code
  518.  
  519. recv_isr_9:
  520.     mov    al,IE_RIDE or IE_RCVEDLC
  521.     loadport
  522.     setport    IE_CSR
  523.     out    dx,al
  524.     xor    al,al
  525.     setport    IE_RP
  526.     out    dx,al
  527. recv_isr_4:
  528. ;Clear any spurious interrupts
  529.     loadport
  530.     setport    EDLC_RCV
  531.     in    al,dx
  532.  
  533.     setport    EDLC_XMT
  534.     in    al,dx
  535.  
  536.     ret
  537.  
  538.  
  539. rcv_fixup:
  540.     call    count_out_err
  541.  
  542.     mov    al,IE_RIDE or IE_SYSBFR
  543.     loadport
  544.     setport    IE_CSR
  545.     out    dx,al
  546.  
  547.     mov    al,IE_RIDE or IE_RCVEDLC
  548.     setport    IE_CSR
  549.     out    dx,al
  550.  
  551.     mov    al,0
  552.     setport    IE_RP
  553.     out    dx,al
  554.  
  555.     ret
  556.  
  557.  
  558.     public    recv_exiting
  559. recv_exiting:
  560. ;called from the recv isr after interrupts have been acknowledged.
  561. ;Only ds and ax have been saved.
  562.     assume    ds:nothing
  563.     ret
  564.  
  565.  
  566. end_resident    label    byte
  567.  
  568.     public    usage_msg
  569. usage_msg    db    "usage: 3C501 <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
  570.  
  571.     public    copyright_msg
  572. copyright_msg    db    "Packet driver for the 3COM 3C501, version ",'0'+majver,".",'0'+version,CR,LF
  573.         db    "Portions Copyright 1988 Phil Karn",CR,LF,'$'
  574.  
  575. using_186_msg    db    "Using 80[123]86 I/O instructions.",CR,LF,'$'
  576. no_3c501_msg    db    "No 3C501 found at that address.",CR,LF,'$'
  577. ether_bdcst    db    6 dup(-1)    ;ethernet broadcast address.
  578. our_address    db    6 dup(?)    ;temporarily hold our address
  579.  
  580. int_no_name    db    "Interrupt number ",'$'
  581. io_addr_name    db    "I/O port ",'$'
  582.  
  583.     extrn    set_recv_isr: near
  584.  
  585. ;enter with si -> argument string, di -> word to store.
  586. ;if there is no number, don't change the number.
  587.     extrn    get_number: near
  588.  
  589. ;enter with dx -> name of word, di -> dword to print.
  590.     extrn    print_number: near
  591.  
  592.     public    parse_args
  593. parse_args:
  594. ;exit with nc if all went well, cy otherwise.
  595.     mov    di,offset int_no
  596.     call    get_number
  597.     mov    di,offset io_addr
  598.     call    get_number
  599.     clc
  600.     ret
  601.  
  602.  
  603. no_3c501_error:
  604.     mov    dx,offset no_3c501_msg
  605.     mov    ah,9
  606.     int    21h
  607.     stc
  608.     ret
  609.  
  610.  
  611.     public    etopen
  612. etopen:
  613. ;  Initialize the Ethernet board, set receive type.
  614. ;
  615. ;  check for correct EPROM location
  616. ;
  617. ;Pulse IE_RESET
  618.     mov    al,IE_RESET
  619.     loadport
  620.     setport    IE_CSR
  621.     out    dx,al
  622.  
  623. ;Determine the processor type.  The 8088 and 8086 will actually shift ax
  624. ;over by 33 bits, while the 80[123]86 use a shift count mod 32.
  625.     mov    cl,33
  626.     mov    ax,0ffffh
  627.     shl    ax,cl
  628.     jz    not_186
  629.     mov    is_186,1
  630.     mov    dx,offset using_186_msg
  631.     mov    ah,9
  632.     int    21h
  633. not_186:
  634.  
  635.     call    set_recv_isr
  636.  
  637.     push    ds
  638.     pop    es
  639.     mov    di,offset our_address
  640.     mov    cx,EADDR_LEN
  641.     call    get_address
  642.     mov    si,offset our_address
  643.     mov    cx,EADDR_LEN
  644.     call    set_address
  645.  
  646. ;See if there really is a 3c501 there.
  647.     mov    cx,EADDR_LEN
  648.     mov    si,offset our_address
  649.     mov    di,offset ether_bdcst
  650.     repe    cmpsb
  651.     jne    have_3c501        ;not broadcast address -- must be real.
  652.     jmp    no_3c501_error        ;not there -- no 3c501.
  653. have_3c501:
  654.  
  655. ;Enable DMA/interrupt request, gain control of buffer
  656.     mov    al,IE_RIDE or IE_SYSBFR
  657.     loadport
  658.     setport    IE_CSR
  659.     out    dx,al
  660.  
  661. ;Enable transmit interrupts
  662.     mov    al,EDLC_16 or EDLC_JAM
  663.     setport    EDLC_XMT
  664.     out    dx,al
  665.  
  666. ;Set up the receiver interrupts and flush status
  667.     mov    al,EDLC_MULTI or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
  668.     setport    EDLC_RCV
  669.     out    dx,al
  670.     in    al,dx            ;flush status.
  671.  
  672. ;Start receiver
  673.     mov    ax,0            ;Reset read pointer
  674.     setport    IE_RP
  675.     out    dx,ax
  676.     mov    al,IE_RIDE or IE_RCVEDLC
  677.     setport    IE_CSR
  678.     out    dx,al
  679.  
  680.     mov    di,offset int_no
  681.     mov    dx,offset int_no_name
  682.     call    print_number
  683.     mov    di,offset io_addr
  684.     mov    dx,offset io_addr_name
  685.     call    print_number
  686.  
  687.     mov    dx,offset end_resident
  688.     clc
  689.     ret
  690.  
  691.  
  692. code    ends
  693.  
  694.     end
  695.