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

  1. version    equ    0
  2. ;History:562,1
  3.  
  4. ;  Copyright, 1988-1992, Russell Nelson, Crynwr Software
  5.  
  6. ;   This program is free software; you can redistribute it and/or modify
  7. ;   it under the terms of the GNU General Public License as published by
  8. ;   the Free Software Foundation, version 1.
  9. ;
  10. ;   This program is distributed in the hope that it will be useful,
  11. ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ;   GNU General Public License for more details.
  14. ;
  15. ;   You should have received a copy of the GNU General Public License
  16. ;   along with this program; if not, write to the Free Software
  17. ;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     include    defs.asm
  20.  
  21. code    segment    word public
  22.     assume    cs:code, ds:code
  23.  
  24. comment \
  25.  
  26. The following says how to transfer a sequence of bytes.  The bytes
  27. are structured as [ count-low, count-high, bytes, bytes, bytes, checksum ].
  28.  
  29. Send        Recv
  30. 8->
  31. [ repeat the following
  32.         <-1
  33. 10h+low_nib->
  34.         <-0
  35. high_nib->
  36. until all bytes have been transferred ]
  37.         <-0
  38. \
  39.  
  40. DATA        equ    0
  41. REQUEST_IRQ    equ    08h
  42. STATUS        equ    1
  43. CONTROL        equ    2
  44.  
  45.     public    int_no
  46. int_no    db    7,0,0,0            ;must be four bytes long for get_number.
  47. io_addr    dw    0378h,0            ; I/O address for card (jumpers)
  48.  
  49.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  50. driver_class    db    1,0        ;null terminated list of classes.
  51. driver_type    db    90        ;from the packet spec
  52. driver_name    db    'parallel',0    ;name of the driver.
  53. driver_function    db    2
  54. parameter_list    label    byte
  55.     db    1    ;major rev of packet driver
  56.     db    9    ;minor rev of packet driver
  57.     db    14    ;length of parameter list
  58.     db    EADDR_LEN    ;length of MAC-layer address
  59.     dw    GIANT    ;MTU, including MAC headers
  60.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  61.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  62.     dw    0    ;(# of successive xmits) - 1
  63. int_num    dw    0    ;Interrupt # to hook for post-EOI
  64.             ;processing, 0 == none,
  65.  
  66. recv_buffer    dw    ?        ;-> buffer.
  67. recv_count    dw    ?
  68.  
  69. send_nib_count    db    ?
  70. recv_byte_count    db    ?
  71.  
  72.     public    rcv_modes
  73. rcv_modes    dw    7        ;number of receive modes in our table.
  74.         dw    0,0,0,rcv_mode_3
  75.         dw    0,0,rcv_mode_6
  76.  
  77.     include    timeout.asm
  78.  
  79. hexout_ptr    dw    0
  80. hexout_color    db    70h
  81.  
  82. hexout_more:
  83.     ret
  84.     push    di
  85.     mov    di,cs:hexout_ptr
  86.     call    hexout
  87.     add    di,4
  88.     cmp    di,25*80*2
  89.     jb    hexout_more_1
  90.     xor    di,di
  91. hexout_more_1:
  92.     mov    cs:hexout_ptr,di
  93.     pop    di
  94.     ret
  95.  
  96. hexout:
  97. ;enter with al = number, di->place on screen to store chars.
  98.     push    ax
  99.     push    es
  100.  
  101.     push    di
  102.     mov    di,0b800h
  103.     mov    es,di
  104.     pop    di
  105.  
  106.     push    ax
  107.     shr    al,1
  108.     shr    al,1
  109.     shr    al,1
  110.     shr    al,1
  111.     call    nibble2hex
  112.     mov    byte ptr es:[di+0],al
  113.     mov    al,cs:hexout_color
  114.     mov    byte ptr es:[di+1],al
  115.     pop    ax
  116.     call    nibble2hex
  117.     mov    byte ptr es:[di+2],al
  118.     mov    al,cs:hexout_color
  119.     mov    byte ptr es:[di+3],al
  120.  
  121.     pop    es
  122.     pop    ax
  123.     ret
  124.  
  125.  
  126. nibble2hex:
  127.     and    al,0fh
  128.     add    al,90h            ;binary digit to ascii hex digit.
  129.     daa
  130.     adc    al,40h
  131.     daa
  132.     ret
  133.  
  134.  
  135.     public bad_command_intercept
  136. bad_command_intercept:
  137. ;called with ah=command, unknown to the skeleton.
  138. ;exit with nc if okay, cy, dh=error if not.
  139.     mov    dh,BAD_COMMAND
  140.     stc
  141.     ret
  142.  
  143.     public    as_send_pkt
  144. ; The Asynchronous Transmit Packet routine.
  145. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  146. ;   interrupts possibly enabled.
  147. ; Exit with nc if ok, or else cy if error, dh set to error number.
  148. ;   es:di and interrupt enable flag preserved on exit.
  149. as_send_pkt:
  150.     ret
  151.  
  152.     public    drop_pkt
  153. ; Drop a packet from the queue.
  154. ; Enter with es:di -> iocb.
  155. drop_pkt:
  156.     assume    ds:nothing
  157.     ret
  158.  
  159.     public    xmit
  160. ; Process a transmit interrupt with the least possible latency to achieve
  161. ;   back-to-back packet transmissions.
  162. ; May only use ax and dx.
  163. xmit:
  164.     assume    ds:nothing
  165.     ret
  166.  
  167.  
  168.     public    send_pkt
  169. send_pkt:
  170. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  171. ;  (only if the high-performance bit is set in driver_function)
  172. ;enter with ds:si -> packet, cx = packet length.
  173. ;if we're a high-performance driver, es:di -> upcall.
  174. ;exit with nc if ok, or else cy if error, dh set to error number.
  175.     assume    ds:nothing
  176.  
  177.     cmp    cx,GIANT        ; Is this packet too large?
  178.     ja    send_pkt_toobig
  179.  
  180. ;cause an interrupt on the other end.
  181.     loadport
  182.     setport    DATA
  183.     mov    al,REQUEST_IRQ
  184.     out    dx,al
  185.  
  186. ;wait for the other end to ack the interrupt.
  187.     mov    ax,18
  188.     call    set_timeout
  189.     setport    STATUS
  190. send_pkt_1:
  191.     in    al,dx
  192.     test    al,1 shl 3        ;wait for them to output 1.
  193.     jne    send_pkt_2
  194.     call    do_timeout
  195.     jne    send_pkt_1
  196.     jmp    short send_pkt_4    ;if it times out, they're not listening.
  197. send_pkt_2:
  198.  
  199.     mov    send_nib_count,0
  200.     setport    DATA
  201.     mov    al,cl            ;send the count.
  202.     call    send_byte
  203.     jc    send_pkt_4        ;it timed out.
  204.     mov    al,ch
  205.     call    send_byte
  206.     jc    send_pkt_4        ;it timed out.
  207.     xor    bl,bl
  208. send_pkt_3:
  209.     lodsb                ;send the data bytes.
  210.     add    bl,al
  211.     call    send_byte
  212.     jc    send_pkt_4        ;it timed out.
  213.     loop    send_pkt_3
  214.  
  215.     mov    al,bl            ;send the checksum.
  216.     mov    hexout_color,30h    ;aqua
  217.     call    hexout_more
  218.     call    send_byte
  219.     jc    send_pkt_4        ;it timed out.
  220.  
  221.     mov    al,0            ;go back to quiescent state.
  222.     out    dx,al
  223.     clc
  224.     ret
  225.  
  226. send_pkt_toobig:
  227.     mov    dh,NO_SPACE
  228.     stc
  229.     ret
  230.  
  231. send_pkt_4:
  232.     loadport
  233.     setport    DATA
  234.     mov    al,send_nib_count
  235.     mov    hexout_color,20h    ;green
  236.     call    hexout_more
  237.     xor    al,al            ;clear the data.
  238.     out    dx,al
  239.     mov    dh,CANT_SEND
  240.     stc
  241.     ret
  242. ;
  243. ; It's important to ensure that the most recent setport is a setport DATA.
  244. ;
  245. send_byte:
  246. ;enter with al = byte to send.
  247. ;exit with cy if it timed out.
  248.     push    ax
  249.     or    al,10h            ;set the clock bit.
  250.     call    send_nibble
  251.     pop    ax
  252.     jc    send_nibble_2
  253.     shr    al,1
  254.     shr    al,1
  255.     shr    al,1
  256.     shr    al,1            ;clock bit is cleared by shr.
  257. send_nibble:
  258. ;enter with setport DATA, al[3-0] = nibble to output.
  259. ;exit with dx set to DATA.
  260.     out    dx,al
  261.     and    al,10h            ;get the bit we're waiting for to come back.
  262.     shl    al,1            ;put it in the right position.
  263.     shl    al,1
  264.     shl    al,1
  265.     mov    ah,al
  266.     mov    hexout_color,60h    ;orange
  267.     call    hexout_more
  268.  
  269.     setport    STATUS
  270.     push    cx
  271.     xor    cx,cx
  272. send_nibble_1:
  273.     in    al,dx            ;keep getting the status until
  274.     xor    al,87h
  275.     and    al,80h
  276.     cmp    al,ah            ;  we get the status we're looking for.
  277.     loopne    send_nibble_1
  278.     pop    cx
  279.     jne    send_nibble_2
  280.  
  281.     mov    hexout_color,50h    ;purple
  282.     call    hexout_more
  283.  
  284.     inc    send_nib_count
  285.     setport    DATA            ;leave with setport DATA.
  286.     clc
  287.     ret
  288. send_nibble_2:
  289.     stc
  290.     ret
  291.  
  292.  
  293.     public    set_address
  294. set_address:
  295. ;enter with ds:si -> Ethernet address, CX = length of address.
  296. ;exit with nc if okay, or cy, dh=error if any errors.
  297.     assume    ds:nothing
  298.     mov    dh,CANT_SET
  299.     stc
  300.     ret
  301.  
  302.  
  303. rcv_mode_3:
  304. rcv_mode_6:
  305. ;receive mode 3 is the only one we support, so we don't have to do anything.
  306.     ret
  307.  
  308.  
  309.     public    set_multicast_list
  310. set_multicast_list:
  311. ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
  312. ;  cx = number of bytes.
  313. ;return nc if we set all of them, or cy,dh=error if we didn't.
  314.     mov    dh,NO_MULTICAST
  315.     stc
  316.     ret
  317.  
  318.  
  319.     public    terminate
  320. terminate:
  321.     ret
  322.  
  323.  
  324.     public    reset_interface
  325. reset_interface:
  326. ;reset the interface.
  327.     assume    ds:code
  328.     ret
  329.  
  330.  
  331. ;called when we want to determine what to do with a received packet.
  332. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  333.     extrn    recv_find: near
  334.  
  335. ;called after we have copied the packet into the buffer.
  336. ;enter with ds:si ->the packet, cx = length of the packet.
  337.     extrn    recv_copy: near
  338.  
  339. ;call this routine to schedule a subroutine that gets run after the
  340. ;recv_isr.  This is done by stuffing routine's address in place
  341. ;of the recv_isr iret's address.  This routine should push the flags when it
  342. ;is entered, and should jump to recv_exiting_exit to leave.
  343. ;enter with ax = address of routine to run.
  344.     extrn    schedule_exiting: near
  345.  
  346. ;recv_exiting jumps here to exit, after pushing the flags.
  347.     extrn    recv_exiting_exit: near
  348.  
  349. ;enter with dx = amount of memory desired.
  350. ;exit with nc, dx -> that memory, or cy if there isn't enough memory.
  351.     extrn    malloc: near
  352.  
  353.     extrn    count_in_err: near
  354.     extrn    count_out_err: near
  355.  
  356. recv_char    db    '0'
  357.  
  358.     public    recv
  359. recv:
  360. ;called from the recv isr.  All registers have been saved, and ds=cs.
  361. ;Upon exit, the interrupt will be acknowledged.
  362.     assume    ds:code
  363.  
  364.     loadport            ;see if we've gotten a real interrupt.
  365.     setport    STATUS
  366.     in    al,dx
  367.     cmp    al,0c7h            ;it must be 0c7h, otherwise spurious.
  368.     je    recv_real
  369.     jmp    recv_err
  370. recv_real:
  371.  
  372.     mov    al,recv_char
  373.     inc    recv_char
  374.     and    recv_char,'7'
  375.     to_scrn    24,79,al
  376.  
  377.     movseg    es,ds
  378.     mov    di,recv_buffer
  379.  
  380.     loadport
  381.     setport    DATA
  382.     mov    al,1            ;say that we're ready.
  383.     out    dx,al
  384.  
  385.     mov    recv_byte_count,0
  386.  
  387.     setport    STATUS
  388.     call    recv_byte        ;get the count.
  389.     jc    recv_err            ;it timed out.
  390.     mov    cl,al
  391.     call    recv_byte
  392.     jc    recv_err            ;it timed out.
  393.     mov    ch,al
  394.     xor    bl,bl
  395.     mov    recv_count,cx
  396. recv_1:
  397.     call    recv_byte        ;get a data byte.
  398.     jc    recv_err            ;it timed out.
  399.     add    bl,al
  400.     stosb
  401.     loop    recv_1
  402.  
  403.     call    recv_byte        ;get the checksum.
  404.     jc    recv_err            ;it timed out.
  405.     cmp    al,bl            ;checksum okay?
  406.     jne    recv_err        ;no.
  407.  
  408.     movseg    es,cs
  409.     mov    di,recv_buffer
  410.     push    es
  411.     push    di
  412.  
  413.     mov    cx,recv_count
  414.     add    di,EADDR_LEN+EADDR_LEN    ;skip the ethernet addreses and
  415.                     ;  point to the packet type.
  416.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  417.     mov    ax, es:[di]
  418.     xchg    ah, al
  419.     cmp     ax, 1500
  420.     ja    BlueBookPacket
  421.     inc    di            ;set di to 802.2 header
  422.     inc    di
  423.     mov    dl, IEEE8023
  424. BlueBookPacket:
  425.     push    cx
  426.     call    recv_find
  427.     pop    cx
  428.  
  429.     pop    si
  430.     pop    ds
  431.     assume    ds:nothing
  432.  
  433.     mov    ax,es            ;is this pointer null?
  434.     or    ax,di
  435.     je    recv_free        ;yes - just free the frame.
  436.  
  437.     push    es
  438.     push    di
  439.     push    cx
  440.     rep    movsb
  441.     pop    cx
  442.     pop    si
  443.     pop    ds
  444.     assume    ds:nothing
  445.  
  446.     call    recv_copy
  447.  
  448.     jmp    short recv_free
  449.  
  450. recv_err:
  451.     call    count_in_err
  452. recv_free:
  453.     movseg    ds,cs
  454.     assume    ds:code
  455.  
  456. ;wait for the other end to reset to zero.
  457.     mov    ax,10            ;1/9th of a second.
  458.     call    set_timeout
  459.     loadport
  460.     setport    STATUS
  461. recv_pkt_1:
  462.     in    al,dx
  463.     cmp    al,87h            ;wait for them to output 0.
  464.     je    recv_4
  465.  
  466.     mov    hexout_color,20h    ;green
  467.     call    hexout_more
  468.  
  469.     call    do_timeout
  470.     jne    recv_pkt_1
  471.  
  472.     mov    al,recv_byte_count
  473.     mov    hexout_color,20h    ;green
  474.     call    hexout_more
  475. recv_4:
  476.     loadport
  477.     setport    DATA
  478.     xor    al,al
  479.     out    dx,al
  480.     ret
  481.  
  482.     setport    STATUS            ;this code doesn't get executed,
  483.                     ;but it sets up for call to recv_byte.
  484.  
  485. recv_byte:
  486. ;called with setport STATUS.
  487. ;exit with nc, al = byte, or cy if it timed out.
  488.  
  489.     push    cx
  490.     mov    cx,65535
  491. recv_low_nibble:
  492.     in    al,61h
  493.     in    al,61h
  494.     in    al,61h
  495.     in    al,61h
  496.     in    al,61h
  497.     in    al,61h
  498.     in    al,61h
  499.     in    al,61h
  500.  
  501.     in    al,dx            ;get the next data value.
  502.     test    al,80h            ;wait for handshake low (transmitted hi).
  503.     loopne    recv_low_nibble
  504.     pop    cx
  505.     jne    recv_byte_1
  506.  
  507.     shr    al,1            ;put our bits into position.
  508.     shr    al,1
  509.     shr    al,1
  510.     mov    ah,al
  511.     and    ah,0fh
  512.  
  513.     mov    al,10h            ;send our handshake back.
  514.     setport    DATA
  515.     out    dx,al
  516.     setport    STATUS
  517.  
  518.     push    cx
  519.     mov    cx,65535
  520. recv_high_nibble:
  521.     in    al,61h
  522.     in    al,61h
  523.     in    al,61h
  524.     in    al,61h
  525.     in    al,61h
  526.     in    al,61h
  527.     in    al,61h
  528.     in    al,61h
  529.  
  530.     in    al,dx            ;get the next data value.
  531.     test    al,80h            ;check for handshake high (transmitted low).
  532.     loope    recv_high_nibble
  533.     pop    cx
  534.     je    recv_byte_1
  535.  
  536.     shl    al,1            ;put our bits into position.
  537.     and    al,0f0h
  538.     or    ah,al
  539.  
  540.     mov    al,0            ;send our handshake back.
  541.     setport    DATA
  542.     out    dx,al
  543.     setport    STATUS
  544.  
  545.     inc    recv_byte_count
  546.  
  547.     mov    al,ah
  548.     mov    hexout_color,40h    ;red
  549.     call    hexout_more
  550.     clc
  551.     ret
  552. recv_byte_1:
  553.     stc
  554.     ret
  555.  
  556.  
  557.     public    timer_isr
  558. timer_isr:
  559. ;if the first instruction is an iret, then the timer is not hooked
  560.     iret
  561.  
  562. ;any code after this will not be kept after initialization. Buffers
  563. ;used by the program, if any, are allocated from the memory between
  564. ;end_resident and end_free_mem.
  565.     public end_resident,end_free_mem
  566. end_resident    label    byte
  567.     db    GIANT dup(?)
  568. end_free_mem    label    byte
  569.  
  570.  
  571.     public    usage_msg
  572. usage_msg    db    "usage: parallel [options] <packet_int_no> [-t] <hardware_irq> <io_addr> [<Ethernet_address>]",CR,LF,'$'
  573.  
  574.     public    copyright_msg
  575. copyright_msg    db    "Packet driver for parallel port interfaces, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  576.         db    "Portions Copyright 1992, Russell Nelson",CR,LF,'$'
  577. no_memory_msg    db    "Unable to allocate enough memory, look at end_resident in PARALLEL.ASM",CR,LF,'$'
  578.  
  579. int_no_name    db    "Interrupt number ",'$'
  580. io_addr_name    db    "I/O port ",'$'
  581.  
  582. test_switch    db    0
  583. test_bit    db    1
  584.  
  585.     extrn    set_recv_isr: near
  586.  
  587.     extrn    chrout: near
  588.     extrn    skip_blanks: near
  589.  
  590. ;enter with si -> argument string, di -> dword to store.
  591. ;if there is no number, don't change the number.
  592.     extrn    get_number: near
  593.  
  594. ;enter with dx -> argument string, di -> dword to print.
  595.     extrn    print_number: near
  596.  
  597. ;-> the assigned Ethernet address of the card.
  598.     extrn    rom_address: byte
  599.  
  600.     public    parse_args
  601. parse_args:
  602. ;exit with nc if all went well, cy otherwise.
  603.     call    skip_blanks
  604.     cmp    al,'-'            ;did they specify a switch?
  605.     jne    not_switch
  606.     cmp    byte ptr [si+1],'t'    ;did they specify '-t'?
  607.     je    got_test_switch
  608.     stc                ;no, must be an error.
  609.     ret
  610. got_test_switch:
  611.     mov    test_switch,1
  612.     add    si,2            ;skip past the switch's characters.
  613.     jmp    parse_args        ;go parse more arguments.
  614. not_switch:
  615.  
  616.     mov    di,offset int_no
  617.     call    get_number
  618.     mov    di,offset io_addr
  619.     call    get_number
  620.  
  621.     mov    rom_address[0],2    ;locally administered.
  622.  
  623.     mov    ax,40h
  624.     mov    es,ax
  625.     mov    ax,es:[6ch]
  626.     mov    word ptr rom_address[2],ax
  627.     mov    ax,es:[6eh]
  628.     mov    word ptr rom_address[4],ax
  629.  
  630.     movseg    es,ds
  631.     mov    di,offset rom_address
  632.     call    get_eaddr
  633.     clc
  634.     ret
  635.  
  636.  
  637.     public    etopen
  638. etopen:
  639.     mov    dx,37ah            ;enable interrupts on the board.
  640.     mov    al,10h
  641.     out    dx,al
  642.  
  643.     cmp    test_switch,0
  644.     je    etopen_1
  645.  
  646.     mov    ax,5
  647.     call    set_timeout
  648. etopen_2:
  649. ;print the status of the incoming lines.
  650.     loadport
  651.     setport    STATUS
  652.     in    al,dx
  653.     xor    al,87h
  654.     mov    ah,al
  655.     mov    cx,5            ;print five bits.
  656. etopen_3:
  657.     push    ax            ;time to toggle the outgoing bits?
  658.     call    do_timeout
  659.     jne    etopen_4        ;no.
  660.     setport    DATA            ;yes, shuffle the bit around.
  661.     mov    al,test_bit
  662.     shr    al,1
  663.     jnc    etopen_5
  664.     mov    al,10h
  665. etopen_5:
  666.     mov    test_bit,al
  667.     out    dx,al
  668.     setport    STATUS
  669.     mov    ax,5
  670.     call    set_timeout
  671. etopen_4:
  672.     pop    ax
  673.     shl    ah,1
  674.     mov    al,'0'
  675.     adc    al,0
  676.     call    chrout
  677.     loop    etopen_3
  678.     mov    al,CR
  679.     call    chrout
  680.  
  681.     mov    ah,1            ;did they hit a key?
  682.     int    16h
  683.     jz    etopen_2        ;no.
  684.  
  685.     mov    ah,0            ;yes, suck the key out.
  686.     int    16h
  687.  
  688.     setport    DATA            ;reset the data port.
  689.     xor    al,al
  690.     out    dx,al
  691.  
  692. etopen_1:
  693.  
  694.     mov    dx,GIANT        ;allocate memory for the receive buffer.
  695.     call    malloc
  696.     jc    no_memory
  697.     mov    recv_buffer,dx
  698.  
  699.     call    set_recv_isr
  700.  
  701.     mov    al, int_no        ; Get board's interrupt vector
  702.     add    al, 8
  703.     cmp    al, 8+8            ; Is it a slave 8259 interrupt?
  704.     jb    set_int_num        ; No.
  705.     add    al, 70h - 8 - 8        ; Map it to the real interrupt.
  706. set_int_num:
  707.     xor    ah, ah            ; Clear high byte
  708.     mov    int_num, ax        ; Set parameter_list int num.
  709.  
  710.     clc
  711.     ret
  712. no_memory:
  713.     mov    dx,offset no_memory_msg
  714.     stc
  715.     ret
  716.  
  717.     public    print_parameters
  718. print_parameters:
  719. ;echo our command-line parameters
  720.     mov    di,offset int_no
  721.     mov    dx,offset int_no_name
  722.     call    print_number
  723.     mov    di,offset io_addr
  724.     mov    dx,offset io_addr_name
  725.     call    print_number
  726.     ret
  727.  
  728.     extrn    get_hex: near
  729.     include    getea.asm
  730.  
  731. code    ends
  732.  
  733.     end
  734.