home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / lan / drivrs30 / 3c501.asm next >
Assembly Source File  |  1989-06-08  |  13KB  |  584 lines

  1. version    equ    0
  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
  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.  
  87. ipkt_size    dw    ?
  88. opkt_size    dw    ?
  89.  
  90. is_186        db    0        ;=0 if 808[68], =1 if 80[123]86.
  91. our_type    dw    ?
  92.  
  93.     public    send_pkt
  94. send_pkt:
  95. ;enter with ds:si -> packet, cx = packet length.
  96. ;exit with nc if ok, or else cy if error, dh set to error number.
  97.     assume    ds:nothing
  98.     cmp    cx,RUNT        ; minimum length for Ether
  99.     jae    oklen
  100.     mov    cx,RUNT        ; make sure size at least RUNT
  101. oklen:
  102.     inc    cx            ;round size up to next even number.
  103.     and    cx,not 1
  104.  
  105. ;Wait for transmitter ready, if necessary. IE_XMTBSY is valid
  106. ;only in the transmit mode, hence the initial check.
  107.  
  108.     loadport
  109.     setport    IE_CSR
  110.     in    al,dx
  111.     and    al,IE_BUFCTL
  112.     cmp    al,IE_XMTEDLC
  113.     jne    send_pkt_2
  114.  
  115.     mov    bx,20000        ;try this many times.
  116. send_pkt_3:
  117.     in    al,dx            ;if not busy, exit.
  118.     and    al,IE_XMTBSY
  119.     je    send_pkt_2
  120.     dec    bx
  121.     jne    send_pkt_3
  122.     mov    dh,CANT_SEND        ;timed out, can't send.
  123.     stc
  124.     ret
  125. send_pkt_2:
  126.  
  127. ;Get control of the board buffer and disable receiver
  128.     mov    al,IE_RIDE or IE_SYSBFR
  129.     setport    IE_CSR
  130.     out    dx,al
  131.  
  132. ;Point GP at beginning of packet
  133.     mov    ax,BFRSIZ
  134.     sub    ax,cx
  135.     setport    IE_GP
  136.     out    dx,ax
  137.  
  138.     setport    IE_BFR
  139.  
  140.     mov    opkt_size,cx    ; opkt_size = cx;
  141.     cmp    is_186,0    ; Can we use rep outsb?
  142.     je    out86        ; no - have to do it slowly.
  143.     rep    outsb
  144.     jmp    short ocnteven
  145. out86:
  146.     test    si,1        ; (buf & 1) ?
  147.     jz    obufeven    ; no
  148.     lodsb            ; al = *si++;
  149.     out    dx,al        ; out(dx,al);
  150.     dec    cx        ; cx--;
  151. obufeven:
  152.     mov    di,cx        ; save for later test
  153.     shr    cx,1        ; cx = cnt >> 1; (convert to word count)
  154. ; Do the bulk of the buffer, a word at a time
  155.     jcxz    onobuf        ; if(cx != 0){
  156. xb:    lodsw            ; do { ax = *si++; (si is word pointer)
  157.     out    dx,al        ; out(dx,lowbyte(ax));
  158.     mov    al,ah
  159.     out    dx,al        ; out(dx,hibyte(ax));
  160.     loop    xb        ; } while(--cx != 0); }
  161. ; now check for odd trailing byte
  162. onobuf:    shr    di,1        ; if (di & 1)
  163.     jnc    ocnteven
  164.     lodsb            ;   out(dx,*si++);
  165.     out    dx,al
  166. ocnteven:
  167.  
  168. ;Start transmitter
  169. ;Point GP at beginning of packet
  170.     mov    ax,BFRSIZ
  171.     sub    ax,opkt_size
  172.     setport    IE_GP
  173.     out    dx,ax
  174.  
  175.     mov    al,IE_RIDE or IE_XMTEDLC
  176.     setport    IE_CSR
  177.     out    dx,al
  178.  
  179.     clc
  180.     ret
  181.  
  182.  
  183.     public    get_address
  184. get_address:
  185. ;get the address of the interface.
  186. ;enter with es:di -> place to get the address, cx = size of address buffer.
  187. ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
  188.     assume    ds:code
  189.     cmp    cx,EADDR_LEN        ;make sure that we have enough room.
  190.     jb    get_address_2
  191.     mov    cx,EADDR_LEN
  192.     xor    bx,bx
  193. get_address_1:
  194.     mov    ax,bx
  195.     loadport
  196.     setport    IE_GP
  197.     out    dx,ax
  198.  
  199.     setport    IE_SAPROM
  200.     in    al,dx
  201.     stosb
  202.     inc    bx
  203.     loop    get_address_1
  204.  
  205.     mov    cx,EADDR_LEN
  206.     clc
  207.     ret
  208. get_address_2:
  209.     stc
  210.     ret
  211.  
  212.  
  213. ;Set Ethernet address on controller
  214.     public    set_address
  215. set_address:
  216.     assume    ds:nothing
  217. ;enter with ds:si -> Ethernet address, CX = length of address.
  218. ;exit with nc if okay, or cy, dh=error if any errors.
  219. ;
  220.     cmp    cx,EADDR_LEN        ;ensure that their address is okay.
  221.     je    set_address_4
  222.     mov    dh,BAD_ADDRESS
  223.     stc
  224.     jmp    short set_address_done
  225. set_address_4:
  226.  
  227.     loadport
  228.     setport    EDLC_ADDR
  229. set_address_1:
  230.     lodsb
  231.     out    dx,al
  232.     inc    dx
  233.     loop    set_address_1
  234. set_address_okay:
  235.     clc
  236. set_address_done:
  237.     push    cs
  238.     pop    ds
  239.     assume    ds:code
  240.     ret
  241.  
  242.  
  243. terminate:
  244. ;Pulse IE_RESET
  245.     mov    al,IE_RESET
  246.     loadport
  247.     setport    IE_CSR
  248.     out    dx,al
  249.     mov    al,0
  250.     out    dx,al
  251.  
  252.     ret
  253.  
  254.  
  255.     public    reset_interface
  256. reset_interface:
  257. ;reset the interface.
  258. ;we don't do anything.
  259.     ret
  260.  
  261.  
  262. ;called when we want to determine what to do with a received packet.
  263. ;enter with cx = packet length, es:di -> packet type.
  264.     extrn    recv_find: near
  265.  
  266. ;called after we have copied the packet into the buffer.
  267. ;enter with ds:si ->the packet, cx = length of the packet.
  268.     extrn    recv_copy: near
  269.  
  270.     extrn    count_in_err: near
  271.     extrn    count_out_err: near
  272.  
  273.     public    recv
  274. recv:
  275. ;called from the recv isr.  All registers have been saved, and ds=cs.
  276. ;Upon exit, the interrupt will be acknowledged.
  277.     assume    ds:code
  278.  
  279. ;Check for transmit jam
  280.  
  281.     loadport
  282.     setport    IE_CSR
  283.     in    al,dx
  284.     and    al,IE_XMTBSY
  285.     jne    recv_isr_1
  286.  
  287.     setport    EDLC_XMT
  288.     in    al,dx
  289.     test    al,EDLC_16
  290.     je    recv_isr_2
  291. ;ecp->estats.jam16++;
  292.     call    rcv_fixup
  293.     jmp    short     recv_isr_3
  294. recv_isr_2:
  295.     test    al,EDLC_JAM
  296.     je    recv_isr_3
  297. ;Crank counter back to beginning and restart transmit
  298. ;ecp->estats.jam++;
  299.     mov    al,IE_RIDE or IE_SYSBFR
  300.     setport    IE_CSR
  301.     out    dx,al
  302.  
  303.     mov    ax,BFRSIZ
  304.     sub    ax,opkt_size
  305.     setport    IE_GP
  306.     out    dx,ax
  307.  
  308.     mov    al,IE_RIDE or IE_XMTEDLC
  309.     setport    IE_CSR
  310.     out    dx,al
  311.  
  312. recv_isr_3:
  313.  
  314. recv_isr_1:
  315.     loadport
  316.     setport    EDLC_RCV
  317.     in    al,dx
  318.     test    al,EDLC_STALE
  319.     jne    recv_isr_4_j_1
  320.     test    al,EDLC_OVER
  321.     je    recv_isr_5
  322. ;ecp->estats.over++;
  323.     call    rcv_fixup
  324.     jmp    recv_isr_1
  325. recv_isr_5:
  326.     test    al,EDLC_SHORT or EDLC_FCS or EDLC_DRIBBLE
  327.     je    recv_isr_6
  328. ;ecp->estats.bad++;
  329.     call    rcv_fixup
  330.     jmp    recv_isr_1
  331. recv_isr_4_j_1:
  332.     jmp    recv_isr_4
  333. recv_isr_6:
  334.     test    al,EDLC_ANY
  335.     je    recv_isr_4_j_1
  336. ;Get control of the buffer
  337.     mov    al,IE_RIDE or IE_SYSBFR
  338.     setport    IE_CSR
  339.     out    dx,al
  340.  
  341.     setport    IE_RP
  342.     in    ax,dx            ;get the size.
  343.     mov    ipkt_size,ax
  344.     cmp    ax,RUNT            ;less than RUNT?
  345.     jb    recv_isr_7        ;yes.
  346.     cmp    ax,GIANT        ;greater than GIANT?
  347.     jbe    recv_isr_8        ;no.
  348. recv_isr_7:
  349.     call    count_in_err
  350. ;ecp->estats.bad++;
  351.     jmp    recv_isr_9
  352. recv_isr_8:
  353. ;Put it on the receive queue
  354.  
  355.     mov    ax,EADDR_LEN+EADDR_LEN    ;seek to the type word.
  356.     setport    IE_GP
  357.     out    dx,ax
  358.  
  359.     setport    IE_BFR
  360.     in    al,dx            ;read the type word out of the board.
  361.     mov    ah,al
  362.     in    al,dx
  363.     xchg    al,ah            ;should be in network byte order.
  364.     mov    our_type,ax
  365.  
  366.     mov    ax,ds            ;look up our type.
  367.     mov    es,ax
  368.     mov    di,offset our_type
  369.     mov    cx,ipkt_size
  370.     call    recv_find
  371.  
  372.     mov    ax,es            ;is this pointer null?
  373.     or    ax,di
  374.     je    recv_isr_9        ;yes - just free the frame.
  375.  
  376.     push    es            ;remember where the buffer pointer is.
  377.     push    di
  378.  
  379.     xor    ax,ax            ;seek to the beginning again.
  380.     loadport
  381.     setport    IE_GP
  382.     out    dx,ax
  383.  
  384.     mov    cx,ipkt_size
  385.     setport    IE_BFR
  386.  
  387.     cmp    is_186,0    ; Can we use rep insb?
  388.     je    in86        ; no - have to do it slowly.
  389.     rep    insb
  390.     jmp    short icnteven
  391. in86:
  392. ; If buffer doesn't begin on a word boundary, get the first byte
  393.     test    di,1    ; if(buf & 1){
  394.     jz    ibufeven ;
  395.     in    al,dx    ; al = in(dx);
  396.     stosb        ; *di++ = al
  397.     dec    cx    ; cx--;
  398. ibufeven:
  399.     mov    si,cx    ; size = cx;
  400.     shr    cx,1    ; cx = cnt >> 1; (convert to word count)
  401. ; Do the bulk of the buffer, a word at a time
  402.     jcxz    inobuf    ; if(cx != 0){
  403. rb:    in    al,dx    ; do { al = in(dx);
  404.     mov    ah,al
  405.     in    al,dx    ; ah = in(dx);
  406.     xchg    al,ah
  407.     stosw        ; *si++ = ax; (di is word pointer)
  408.     loop    rb    ; } while(--cx != 0);
  409. ; now check for odd trailing byte
  410. inobuf:    shr    si,1
  411.     jnc    icnteven
  412.     in    al,dx
  413.     stosb        ; *di++ = al
  414. icnteven:
  415.  
  416.     pop    si
  417.     pop    ds
  418.     assume    ds:nothing
  419.     mov    cx,ipkt_size
  420.     call    recv_copy        ;tell them that we copied it.
  421.  
  422.     mov    ax,cs            ;restore our ds.
  423.     mov    ds,ax
  424.     assume    ds:code
  425.  
  426. recv_isr_9:
  427.     mov    al,IE_RIDE or IE_RCVEDLC
  428.     loadport
  429.     setport    IE_CSR
  430.     out    dx,al
  431.     xor    al,al
  432.     setport    IE_RP
  433.     out    dx,al
  434. recv_isr_4:
  435. ;Clear any spurious interrupts
  436.     loadport
  437.     setport    EDLC_RCV
  438.     in    al,dx
  439.  
  440.     setport    EDLC_XMT
  441.     in    al,dx
  442.  
  443.     ret
  444.  
  445.  
  446. rcv_fixup:
  447.     call    count_out_err
  448.  
  449.     mov    al,IE_RIDE or IE_SYSBFR
  450.     loadport
  451.     setport    IE_CSR
  452.     out    dx,al
  453.  
  454.     mov    al,IE_RIDE or IE_RCVEDLC
  455.     setport    IE_CSR
  456.     out    dx,al
  457.  
  458.     mov    al,0
  459.     setport    IE_RP
  460.     out    dx,al
  461.  
  462.     ret
  463.  
  464.  
  465. end_resident    label    byte
  466.  
  467.     public    usage_msg
  468. usage_msg    db    "usage: 3C501 <packet_int_no> <int_no> <io_addr>",CR,LF,'$'
  469.  
  470.     public    copyright_msg
  471. copyright_msg    db    "Packet driver for the 3COM 3C501, version ",'0'+majver,".",'0'+version,CR,LF
  472.         db    "Portions Copyright 1988 Phil Karn",CR,LF,'$'
  473.  
  474. using_186_msg    db    "Using 80[123]86 I/O instructions.",CR,LF,'$'
  475. no_3c501_msg    db    "No 3C501 found at that address.",CR,LF,'$'
  476. ether_bdcst    db    6 dup(-1)    ;ethernet broadcast address.
  477. our_address    db    6 dup(?)    ;temporarily hold our address
  478.  
  479. int_no_name    db    "Interrupt number ",'$'
  480. io_addr_name    db    "I/O port ",'$'
  481.  
  482.     extrn    set_recv_isr: near
  483.  
  484. ;enter with si -> argument string, di -> word to store.
  485. ;if there is no number, don't change the number.
  486.     extrn    get_number: near
  487.  
  488.     public    parse_args
  489. parse_args:
  490.     mov    di,offset int_no
  491.     mov    bx,offset int_no_name
  492.     call    get_number
  493.     mov    di,offset io_addr
  494.     mov    bx,offset io_addr_name
  495.     call    get_number
  496.     ret
  497.  
  498.  
  499. no_3c501_error:
  500.     mov    dx,offset no_3c501_msg
  501.     mov    ah,9
  502.     int    21h
  503.     stc
  504.     ret
  505.  
  506.  
  507.     public    etopen
  508. etopen:
  509. ;  Initialize the Ethernet board, set receive type.
  510. ;
  511. ;  check for correct EPROM location
  512. ;
  513. ;Pulse IE_RESET
  514.     mov    al,IE_RESET
  515.     loadport
  516.     setport    IE_CSR
  517.     out    dx,al
  518.  
  519. ;Determine the processor type.  The 8088 and 8086 will actually shift ax
  520. ;over by 33 bits, while the 80[123]86 use a shift count mod 32.
  521.     mov    cl,33
  522.     mov    ax,0ffffh
  523.     shl    ax,cl
  524.     jz    not_186
  525.     mov    is_186,1
  526.     mov    dx,offset using_186_msg
  527.     mov    ah,9
  528.     int    21h
  529. not_186:
  530.  
  531.     call    set_recv_isr
  532.  
  533.     push    ds
  534.     pop    es
  535.     mov    di,offset our_address
  536.     mov    cx,EADDR_LEN
  537.     call    get_address
  538.     mov    si,offset our_address
  539.     mov    cx,EADDR_LEN
  540.     call    set_address
  541.  
  542. ;See if there really is a 3c501 there.
  543.     mov    cx,EADDR_LEN
  544.     mov    si,offset our_address
  545.     mov    di,offset ether_bdcst
  546.     repe    cmpsb
  547.     jne    have_3c501        ;not broadcast address -- must be real.
  548.     jmp    no_3c501_error        ;not there -- no 3c501.
  549. have_3c501:
  550.  
  551. ;Enable DMA/interrupt request, gain control of buffer
  552.     mov    al,IE_RIDE or IE_SYSBFR
  553.     loadport
  554.     setport    IE_CSR
  555.     out    dx,al
  556.  
  557. ;Enable transmit interrupts
  558.     mov    al,EDLC_16 or EDLC_JAM
  559.     setport    EDLC_XMT
  560.     out    dx,al
  561.  
  562. ;Set up the receiver interrupts and flush status
  563.     mov    al,EDLC_MULTI or EDLC_GOOD or EDLC_ANY or EDLC_SHORT or EDLC_DRIBBLE or EDLC_FCS or EDLC_OVER
  564.     setport    EDLC_RCV
  565.     out    dx,al
  566.     in    al,dx            ;flush status.
  567.  
  568. ;Start receiver
  569.     mov    ax,0            ;Reset read pointer
  570.     setport    IE_RP
  571.     out    dx,ax
  572.     mov    al,IE_RIDE or IE_RCVEDLC
  573.     setport    IE_CSR
  574.     out    dx,al
  575.  
  576.     mov    dx,offset end_resident
  577.     clc
  578.     ret
  579.  
  580.  
  581. code    ends
  582.  
  583.     end
  584.