home *** CD-ROM | disk | FTP | other *** search
- version equ 1
-
- include defs.asm ;SEE ENCLOSED COPYRIGHT MESSAGE
-
- ; PARnet PC/FTP Packet Driver Source, conforming to version 1.08 of spec.
- ; Ported by S.A.Pechler (S.A.Pechler@bdk.tue.nl) from the Amiga's PARnet
- ; device.
- ; Original Amiga code is Copyright (c) 1989 by Matthew Dillon.
- ;
- ; Date: July 10, 1993
-
- ; Permission is granted to any individual or institution to use,copy,
- ; modify or redistribute this software provided this notice is retained.
- ; The authors make no guarantee to the suitability of the software for
- ; any purpose. Any damage caused by using this program is the responsibility
- ; of the user and not the authors.
-
- code segment word public
- assume cs:code, ds:code
-
- ; PARnet definitions
-
- BUFSIZE EQU 4096
- PARPORT EQU 4 ; This is 1024 in 2 byte network order (0400h)
- TX_HDRSIZE EQU 8
- ARP_TYPE EQU 0608h ; ARP packet type identifier in host order
-
- ; Private Data
- ; ------------
- ; Driver definitions
-
- ether_arp_frame db 0,0,0,0,0
- arp_srcaddr db ? ; target ethernet address (myself)
- db 0,0,0,0,0,0 ; source ethernet address (fake)
- ether_arp_type db 8,6 ; type field (0806h)
- db 0,1 ; hardware type (1 = ethernet)
- db 8,0 ; protocol type ( 0800h = IP addresses)
- db 6 ; hardware address length (6 for ethernet)
- db 4 ; address length for high level (4 for IP addr)
- db 0,2 ; operation: response
- arp_sendhard db 0,0,0,0,0,? ; sender hardware address
- arp_sendIP db 0,0,0,0 ; sender IP address
- arp_targhard db 0,0,0,0,0,? ; target hardware address (myself)
- arp_targIP db 0,0,0,0 ; target IP address (myself)
-
- ether_arp_end label byte
-
- ARP_LENGTH EQU ether_arp_end-ether_arp_frame
-
- ; Receiver buffer (contains PARnet packet header)
- rx_buffer db BUFSIZE dup(?) ; receiver buffer (max 64 kb).
- rx_header EQU rx_buffer
- rx_port EQU rx_buffer ; ! port number is in network order.
- rx_dlen EQU rx_buffer+6 ; ! last 2 bytes of length (is in network
- ; ! order!).
- rx_data EQU rx_buffer+8
-
- ; pointer to receiver buffer (given to upper level process).
- ;rx_offset dw rx_data ; buffer data offset
-
- ; transmitter packet header
- tx_header dw PARport ; portnumber is fixed to 1024 (in network order)
- dw 0 ; checksum
- dw 0 ; length of datafield; it should be a DD
- tx_dlen EQU this word
- tx_dlenh db 0 ; but on PC's a PARnet packet can't be
- tx_dlenl db 0 ; larger than 64 kb.
-
- ; pointer to transmitter buffer
- tx_data EQU this dword
- tx_offset dw ? ; offset of host transmit buffer
- tx_segment dw ? ; segment of host transmit buffer
- tx_length dw ? ; packet length
-
- tx_dest db ? ; physical destination address
-
- output_active db 0 ; flag, packet being written.
-
- ; Public Data
- ; -----------
-
- public int_no,io_addr,mem_base
-
- int_no db 2,0,0,0 ;must be four bytes long for get_number.
- io_addr dw 0378h,0 ;io addr for parallel card (default)
- mem_base dw 0,0 ;share memory addr (not used)
-
- public driver_class, driver_type, driver_name, driver_function, parameter_list
-
- driver_class db 1,0,0,0 ;no class specified for PARnet,
- ;using class for serial line (the
- ;trailing zero's are for the
- ;print_number function
- driver_type db 0,0,0,0 ;no specific type.
- driver_name db 'PARnet',0 ;name of the driver.
- driver_function db 2 ;basic and extended functions present.
- parameter_list label byte
- db 1 ;major rev of packet driver
- db 9 ;minor rev of packet driver
- db 14 ;length of parameter list
- db EADDR_LEN ;length of MAC-layer address
- dw GIANT ;MTU, including MAC headers
- dw MAX_MULTICAST * EADDR_LEN ;buffer size of multicast addrs
- dw 0 ;(# of back-to-back MTU rcvs) - 1
- dw 0 ;(# of successive xmits) - 1
- int_num dw 0 ;Interrupt # to hook for post-EOI
- ;processing, 0 == none,
-
- public rcv_modes
- rcv_modes dw 7 ;number of receive modes in our table.
- dw 0,0,rcv_mode_2,0,0,0,rcv_mode_6
-
- ; Private routines
- ; ----------------
-
- ; See PARKERN.ASM
-
- include parsubr.asm
-
- ; Public routines
- ; ---------------
-
- public as_send_pkt
- ; The Asynchronous Transmit Packet routine.
- ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
- ; interrupts possibly enabled.
- ; Exit with nc if ok, or else cy if error, dh set to error number.
- ; es:di and interrupt enable flag preserved on exit.
- as_send_pkt:
- ret
-
- public drop_pkt
- ; Drop a packet from the queue.
- ; Enter with es:di -> iocb.
- drop_pkt:
- assume ds:nothing
- ret
-
- public xmit
- ; Process a transmit interrupt with the least possible latency to achieve
- ; back-to-back packet transmissions.
- ; May only use ax and dx.
- xmit:
- assume ds:nothing
- ret
-
-
- public send_pkt
- send_pkt:
- ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
- ; (only if the high-performance bit is set in driver_function)
- ;enter with ds:si -> packet, cx = packet length.
- ;exit with nc if ok, or else cy if error, dh set to error number.
- assume ds:nothing
-
- ;a PARnet network can't handle broadcasts, but ARP-requests will be
- ;'answerred' by making an ARP-response with as hardware address the
- ;LSB of the destination IP-address.
-
- mov al,[si+EADDR_LEN-1] ; get LSB of destination hard.address
- cmp al,-1 ; is it 0xff?
- jne send_pkt_nobrd ; no, just send the packet
- mov ax,[si+EADDR_LEN+EADDR_LEN] ; get packet type
- cmp ax,ARP_TYPE ; is it an ARP-packet?
- jne send_pkt_err ; no, can't handle this packet
-
- ; no need to save es:di here ?
-
- ; swap sender & targer address fields:
-
- ; 1. put sender addresses into target address fields
- add si,22 ; let SI point to sender's hardware address
- mov cx,EADDR_LEN+4 ; copy both the hardware & IP addresses
- mov ax,cs
- mov es,ax ; mov es,cs ; is this needed?
- mov di,OFFSET arp_targhard
- rep movsb
-
- ; 2. put target IP address into sender IP address field
- add si,EADDR_LEN ; skip target hardware address
- mov cx,4 ; IP address length
- mov di,OFFSET arp_sendIP
- rep movsb
-
- ; now calculate the target hardware address from the last octet of
- ; the IP address.
- mov al,[si-1]
- mov arp_sendhard+5,al
-
- ; prepare arp response for the receiver
-
- mov ax,cs ; ds=cs align
- mov ds,ax
- assume ds:code
- mov es,ax ; for es:di pointer
- mov di,offset ether_arp_type ; pointer to type field
- mov si,offset ether_arp_frame ; pointer to start of frame
- mov cx,ARP_LENGTH ; packet length
- jmp recv_reply_arp ; Pass the arp response to the receiver
-
- send_pkt_nobrd:
- assume ds:nothing
-
- mov tx_segment,ds ; tx->data
-
- mov bx,cs ; cs = ds align
- mov ds,bx
-
- assume ds:code
-
- mov tx_dest,al ; hardware destination address.
- mov tx_offset,si ; tx_offset ->segment offset
- mov tx_length,cx ; packet data length (host order)
-
-
- ;Create a PARnet packet header
- ;(At the moment it's simple: just fill in the data-length, the rest
- ; is default)
- mov tx_dlenh,ch ; put it in network order
- mov tx_dlenl,cl
-
- ;Send the packet
- mov output_active,1 ; set flag, to undo recv-interrupt
- call ParWrite ; see parsubr.asm
- mov output_active,0 ; recv-intrps are now accepted again
- or ax,ax ; check return value (# bytes written)
- jz send_pkt_err ; = 0, can't..
- js send_pkt_err ; < 0, error.
- cmp tx_length,ax ; check if all bytes were written
- jne send_pkt_err ; not, then error.
- clc
- jmp short send_pkt_end
- send_pkt_err:
- mov dh,CANT_SEND ; errornum
- stc
- send_pkt_end:
- ret
-
-
- public get_address
-
-
- get_address:
- ;get the address of the interface.
- ;enter with es:di -> place to get the address, cx = size of address buffer.
- ;exit with nc, cx = actual size of address, or cy if buffer not big enough.
- assume ds:code
-
- cmp cx, EADDR_LEN ; does caller want reasonable length?
- jb get_addr_fail ; no , fails
-
- cld ; make sure of string operation
- mov si,offset Par_EthAddr ; load source of address
- mov cx,EADDR_LEN ; return length of address
- rep movsb ; copy address
- mov cx,EADDR_LEN ; return length of address
- clc
- ret
- get_addr_fail:
- stc
- ret
-
- public set_address
-
- set_address:
- ;enter with ds:si -> Ethernet address, CX = length of address.
- ;exit with nc if okay, or cy, dh=error if any errors.
- assume ds:nothing
-
- cmp cx,EADDR_LEN ; check if address ok
- je set_addr_1
- mov dh,BAD_ADDRESS ; don't like length
- stc
- ret
- set_addr_1:
- ; is ES always pointing to CS at this moment?
- mov di,offset Par_EthAddr ;di->destination offset
- rep movsb ;return address
- mov cx,EADDR_LEN ;return their address length.
- clc
- ret
-
- rcv_mode_2:
- ; Turn off receiver
- ret
-
- rcv_mode_6:
- ; Receive all packets (Promiscuous physical plus all multi)
- ret
-
-
- public set_multicast_list
- set_multicast_list:
- ;enter with ds:si ->list of multicast addresses, cx = number of addresses.
- ;return nc if we set all of them, or cy,dh=error if we didn't.
- mov dh,NO_MULTICAST
- stc
- ret
-
-
- public terminate
- terminate:
- ret
-
- public reset_interface
- reset_interface:
- ;reset the interface.
- assume ds:code
-
- call stable
- ret
-
- ;called when we want to determine what to do with a received packet.
- ;enter with cx = packet length, es:di -> packet type, dl = packet class.
- extrn recv_find: near
-
- ;called after we have copied the packet into the buffer.
- ;enter with ds:si ->the packet, cx = length of the packet.
- extrn recv_copy: near
-
- extrn count_in_err: near
- extrn count_out_err: near
-
- public recv
- recv:
- ;called from the recv isr. All registers have been saved, and ds=cs.
- ; all interrupts come here
- ;Upon exit, the interrupt will be acknowledged.
- assume ds:code
- ;sti
- cld
-
-
- ; an IRQ 7 occures only when an incoming packet is pending.
- ; so check with ParDataReady if the packet is addressed to me.
- ; otherwise quit.
- ; (is buffering needed?)
-
- recv1:
- cmp output_active,1
- je Not_for_me ; 1 = interrupt during write
- call pardataready
- or al,al
- jz Line_idle ; AL = 0, nothing on the line anymore
- js Not_for_me ; AL = -1, packet not addressed to me
-
- call parread
- or ax,ax
- jz Read_error ; AL = 0, no bytes read
- js Read_error ; AL = -1, read timeout
- cmp ax,BUFSIZE
- jg Read_overflow ; packet did not fit in buffer.
-
- ; push packet to upper layer.
-
- mov ch,rx_dlen ; convert packet length
- mov cl,rx_dlen+1 ; to byte order.
-
- mov ax,cs
- mov es,ax ; for es:di pointer in recv_find call
- mov di,offset rx_data ; reset di to beginning
- mov si,di ; si will be used later
- add di,EADDR_LEN+EADDR_LEN ; point to type field
- ; of buffer
-
- recv_reply_arp:
- mov dl, BLUEBOOK ;packet class: assume bluebook Ethernet
-
- push cx ; save packet_length
- push si ; save packet start
- call recv_find ; loop up our type (first call).
- pop si
- pop cx
-
- mov ax,es ; ax->es
- or ax,di ; is this pointer null? (es=di=0)
- je rcv_no_copy
-
- push cx ; save packet length
- push es ; remember client's buffer
- push di
-
- rep movsb ; copy from SI (packet start) to
- ; DI (upper level buffer)
- pop si ; make client's buffer a new source
- pop ds ; for the recv_copy call.
- pop cx
-
- call recv_copy ; second call
- rcv_no_copy:
- Line_Idle:
- Not_for_me:
- Read_error:
- Read_overflow:
- mov ax,cs ; set DS back to CS, otherwise the
- mov ds,ax ; remaining ISR routine will crash.
- assume ds:code
- ret
-
-
- public recv_exiting
- recv_exiting:
- ;called from the recv isr after interrupts have been acknowledged.
- ;Only ds and ax have been saved.
- assume ds:nothing
- ret
-
- ;any code after this will not be kept after initialization.
- end_resident label byte
-
- public usage_msg
- usage_msg db "usage: PARNET [-n] [-d] [-w] <packet_int_no> <int_level> <io_addr> <netaddr>",CR,LF,'$'
- public copyright_msg
- copyright_msg db "Packet Driver for PARnet, version "
- db '0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
- db "Ported by S.A.Pechler@bdk.tue.nl. "
- db "Portions Copyright 1989, Matthew Dillon.",CR,LF,'$'
- int_no_name db "Interrupt number ",'$'
- io_addr_name db "I/O port ",'$'
- PARaddress_name db "PARnet address ",'$'
- bad_addr_msg db "Bad PARnet address given.",CR,LF,'$'
-
- extrn set_recv_isr: near
-
- ;enter with si -> argument string, di -> word to store.
- ;if there is no number, don't change the number.
- extrn get_number: near
-
- ;enter with dx -> name of word, di -> dword to print.
- extrn print_number: near
-
- extrn error: near
-
- public parse_args
- parse_args:
- ;exit with nc if all went well, cy otherwise.
- mov di,offset int_no
- call get_number
- jc param_error
-
-
- mov di,offset io_addr
- call get_number
- jc param_error
-
- mov di,offset parnetaddr
- call get_number
- jc param_error
-
- ; call print_parameters
-
- mov al,parnetaddr
- or al,al ; address 0 is reserved
- je parnet_err
- cmp al,-1 ; address 255 is reserved
- je parnet_err
- mov arp_srcaddr,al ; initialize the arp response packet
- clc
- ret
-
- param_error:
- mov dx,offset usage_msg
- jmp error
-
- parnet_err:
- mov dx,offset bad_addr_msg
- jmp error
-
- public etopen
- etopen:
- call paraddress
-
- call set_recv_isr ;install the interrupt handler
- mov dx,offset end_resident
- clc
- ret
-
- public print_parameters
- print_parameters:
- mov di,offset int_no
- mov dx,offset int_no_name
- call print_number
- mov di,offset io_addr
- mov dx,offset io_addr_name
- call print_number
- mov di,offset parnetaddr
- mov dx,offset PARaddress_name
- call print_number
- ret
-
- code ends
- end
-