home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload
/
ShartewareOverload.cdr
/
windows
/
w3pktdr2.zip
/
HEAD.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-06-28
|
22KB
|
941 lines
include defs.asm
; WARNING !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; Modifications make to enchance use under muti-taskers (windows etc)
;
; Steven Wallace
; Indiana University
; Bloomington, IN
; wallaces@ucs.indiana.edu
; this version of the packet drivers may be buggy!!!
; Copyright, 1988-9, 1990, Russell Nelson
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, version 1.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
code segment byte public
assume cs:code, ds:code
public phd_environ
org 2ch
phd_environ dw ?
public phd_dioa
org 80h
phd_dioa label byte
org 100h
start:
jmp start_1
extrn start_1: near
;we use our dioa for a stack space. Very hard usage has shown that only
; 27 bytes were being used, so 128 should be sufficient.
our_stack label byte
extrn int_no: byte
public packet_int_no, is_at, sys_features
packet_int_no db ?,?,?,? ; interrupt to communicate.
is_at db 0 ; =1 if we're on an AT.
sys_features db 0 ; 2h = MC 40h = 2nd 8259
functions label word
dw f_not_implemented
dw f_driver_info
dw f_access_type
dw f_release_type
dw f_send_pkt
dw f_terminate
dw f_get_address
dw f_reset_interface
dw f_not_implemented
dw f_not_implemented
dw f_get_parameters
dw f_as_send_pkt
dw f_not_implemented
dw f_not_implemented
dw f_not_implemented
dw f_not_implemented
dw f_not_implemented
dw f_not_implemented
dw f_not_implemented
dw f_not_implemented
dw f_set_rcv_mode
dw f_get_rcv_mode
dw f_set_multicast_list
dw f_get_multicast_list
dw f_get_statistics
dw f_set_address
extrn driver_class: byte
extrn driver_type: byte
extrn driver_name: byte
extrn driver_function: byte
extrn parameter_list: byte
extrn send_pkt: near
extrn get_address: near
extrn set_address: near
extrn terminate: near
extrn reset_interface: near
extrn recv: near
extrn recv_exiting: near
extrn rcv_modes: word ;count of modes followed by mode handles.
extrn set_multicast_list: near
linc macro n ; inc a 32 bit integer
local a
inc n ;increment the low word
jne a ;go if not overflow
inc n+2 ;increment the high word
a:
endm
per_handle struc
in_use db 0 ;non-zero if this handle is in use.
packet_type db MAX_P_LEN dup(0);associated packet type.
packet_type_len dw 0 ;associated packet type length.
receiver dd 0 ;receiver handler.
; ssw
sig1 dw 0 ;We'll store the first 4 words
sig2 dw 0 ; of the receiver function
sig3 dw 0 ; and use them as a signature
sig4 dw 0
; ssw
per_handle ends
handles per_handle max_handle dup(<>)
end_handles label byte
cur_handle dw
public multicast_count, multicast_addrs, multicast_broad
multicast_count dw 0 ;count of stored multicast addresses.
multicast_broad db 0ffh,0ffh,0ffh,0ffh,0ffh,0ffh ; entry for broadcast
multicast_addrs db MAX_MULTICAST*EADDR_LEN dup(?)
have_my_address db 0 ;nonzero if our address has been set.
my_address db MAX_ADDR_LEN dup(?)
my_address_len dw ?
rcv_mode_num dw 3
free_handle dw 0 ; temp, a handle not in use
found_handle dw 0 ; temp, handle for our packet
receive_ptr dd 0 ; the pkt receive service routine
statistics_list label dword
packets_in dw ?,?
packets_out dw ?,?
bytes_in dw ?,?
bytes_out dw ?,?
errors_in dw ?,?
errors_out dw ?,?
packets_dropped dw ?,? ;dropped due to no type handler.
savess dw ? ;saved during the stack swap.
savesp dw ?
regs struc ; stack offsets of incoming regs
_ES dw ?
_DS dw ?
_BP dw ?
_DI dw ?
_SI dw ?
_DX dw ?
_CX dw ?
_BX dw ?
_AX dw ?
_IP dw ?
_CS dw ?
_F dw ? ; flags, Carry flag is bit 0
regs ends
CY equ 0001h
EI equ 0200h
bytes struc ; stack offsets of incoming regs
dw ? ; es, ds, bp, di, si are 16 bits
dw ?
dw ?
dw ?
dw ?
_DL db ?
_DH db ?
_CL db ?
_CH db ?
_BL db ?
_BH db ?
_AL db ?
_AH db ?
bytes ends
public our_isr, their_isr
their_isr dd 0 ; original owner of pkt driver int
our_isr:
jmp our_isr_0 ;the required signature.
db 'PKT DRVR',0
our_isr_0:
assume ds:nothing
push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
cld
mov bx,cs ;set up ds.
mov ds,bx
assume ds:code
mov bp,sp ;we use bp to access the original regs.
and _F[bp],not CY ;start by clearing the carry flag.
mov bl,ah ;jump to the correct function.
mov bh,0
cmp bx,25 ;only twenty five functions right now.
mov dh,BAD_COMMAND ;in case we find a bad number.
ja our_isr_error
add bx,bx ;*2
call functions[bx]
jnc our_isr_return
our_isr_error:
mov _DH[bp],dh
or _F[bp],CY ;return their carry flag.
our_isr_return:
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
iret
f_not_implemented:
mov dh,BAD_COMMAND
stc
ret
f_driver_info:
; As of 1.08, the handle is optional, so we no longer verify it.
; call verify_handle
cmp _AL[bp],0ffh ; correct calling convention?
jne f_driver_info_1 ; ne = incorrect, fail
mov _BX[bp],majver ;version
mov al,driver_class
mov _CH[bp],al
mov al,driver_type
cbw
mov _DX[bp],ax
mov _CL[bp],0 ;number zero.
mov _DS[bp],ds ; point to our name in their ds:si
mov _SI[bp],offset driver_name
mov al,driver_function
mov _AL[bp],al
clc
ret
f_driver_info_1:
stc
ret
f_set_rcv_mode:
call verify_handle
mov cx,_CX[bp] ;Tell them how much room they have.
cmp cx,rcv_modes ;do they have this many modes?
jae f_set_rcv_mode_1 ;no - must be a bad mode for us.
mov bx,cx
add bx,bx ;we're accessing words, not bytes.
mov ax,rcv_modes[bx]+2 ;get the handler for this mode.
or ax,ax ;do they have one?
je f_set_rcv_mode_1 ;no - must be a bad mode for us.
mov rcv_mode_num,cx ;yes - remember the number and
call ax ; call it.
clc
ret
f_set_rcv_mode_1:
mov dh,BAD_MODE
stc
ret
f_get_rcv_mode:
call verify_handle
mov ax,rcv_mode_num ;return the current receive mode.
mov _AX[bp],ax
clc
ret
f_set_multicast_list:
; mov cx,_CX[bp] ;Tell them how much room they have.
;verify that they supplied an even number of EADDR's.
mov ax,cx
xor dx,dx
mov bx,EADDR_LEN
div bx
or dx,dx ;zero remainder?
jne f_set_multicast_list_2 ;no, we don't have an even number of
; addresses.
cmp ax,MAX_MULTICAST ;is this too many?
ja f_set_multicast_list_3 ;yes - return NO_SPACE
f_set_multicast_list_1:
mov multicast_count,ax ;remember the number of addresses.
push cs
pop es
mov di,offset multicast_addrs
push ds
mov ds,_ES[bp] ; get ds:si -> new list.
mov si,_DI[bp]
push cx
rep movsb
pop cx
pop ds
mov si,offset multicast_addrs
call set_multicast_list
ret
f_set_multicast_list_2:
mov dh,BAD_ADDRESS
stc
ret
f_set_multicast_list_3:
mov dh,NO_SPACE
stc
ret
f_get_multicast_list:
mov _ES[bp],ds ;return what we have remembered.
mov _DI[bp],offset multicast_addrs
mov ax,EADDR_LEN ;multiply the count by the length.
mul multicast_count
mov _CX[bp],ax ;because they want total bytes.
clc
ret
f_get_statistics:
call verify_handle ;just in case.
mov _DS[bp],ds
mov _SI[bp],offset statistics_list
clc
ret
access_type_class:
mov dh,NO_CLASS
stc
ret
access_type_type:
mov dh,NO_TYPE
stc
ret
access_type_number:
mov dh,NO_NUMBER
stc
ret
access_type_bad:
mov dh,BAD_TYPE
stc
ret
access_type_space:
mov dh,NO_SPACE
stc
ret
;register caller of pkt TYPE
f_access_type:
mov al,driver_class
cmp _AL[bp],al ;our class?
jne access_type_class ;no.
cmp _BX[bp],-1 ;generic type?
je access_type_2 ;yes.
mov al,driver_type
cbw
cmp _BX[bp],ax ;our type?
jne access_type_type ;no.
access_type_2:
cmp _DL[bp],0 ;generic number?
je access_type_3
cmp _DL[bp],1 ;our number?
jne access_type_number
access_type_3:
cmp _CX[bp],MAX_P_LEN ;is the type length too long?
ja access_type_bad ;yes - can't be ours.
; now we do two things--look for an open handle, and check the existing
; handles to see if they're replicating a packet type.
mov free_handle,0 ;remember no free handle yet.
mov bx,offset handles
access_type_4:
cmp [bx].in_use,0 ;is this handle in use?
je access_type_5 ;no - don't check the type.
mov es,_DS[bp] ;get a pointer to their type
mov di,_SI[bp] ; from their ds:si to our es:di
mov cx,_CX[bp] ;get the minimum of their length
; and our length. As currently
; implemented, only one receiver
; gets the packets, so we have to
; ensure that the shortest prefix
; is unique.
cmp cx,[bx].packet_type_len ;Are we less specific than they are?
jb access_type_8 ;no.
mov cx,[bx].packet_type_len ;yes - use their count.
access_type_8:
lea si,[bx].packet_type
or cx,cx ; pass-all TYPE? (zero TYPE length)
jne access_type_7 ; ne = no
mov bx,offset handles+(max_handle -1)*(size per_handle)
jmp short access_type_5 ; put pass-all last
access_type_7:
repe cmpsb
jne short access_type_6 ;go look at the next one.
access_type_inuse:
mov dh,TYPE_INUSE ;a handle has been assigned for TYPE
stc ;and we can't assign another
ret
access_type_5: ;handle is not in use
cmp free_handle,0 ;found a free handle yet?
jne access_type_6 ;yes.
mov free_handle,bx ;remember a free handle
access_type_6:
add bx,(size per_handle) ;go to the next handle.
cmp bx,offset end_handles ;examined all handles?
jb access_type_4 ;no, continue.
mov bx,free_handle ;did we find a free handle?
or bx,bx
je access_type_space ;no - return error.
mov [bx].in_use,1 ;remember that we're using it.
mov ax,_DI[bp] ;remember the receiver type.
mov [bx].receiver.offs,ax
mov ax,_ES[bp]
mov [bx].receiver.segm,ax
push ds
mov ax,ds
mov es,ax
mov ds,_DS[bp] ;remember their type.
mov si,_SI[bp]
mov cx,_CX[bp]
mov es:[bx].packet_type_len,cx ; remember the TYPE length
lea di,[bx].packet_type
rep movsb
pop ds
mov _AX[bp],bx ;return the handle to them.
clc
; ssw
mov ax, [bx].receiver.segm ;copy the first 4 words
mov es, ax ; pointed to by receiver
mov di, [bx].receiver.offs ; to sig1, sig2, sig3, sig4
mov ax, es:[di] ; will be used latter
mov [bx].sig1, ax ; to test if the real receiver
inc di ; is loaded in memory
mov ax, es:[di]
mov [bx].sig2, ax
inc di
mov ax, es:[di]
mov [bx].sig3, ax
inc di
mov ax, es:[di]
mov [bx].sig4, ax
ret
f_release_type:
call verify_handle ;mark this handle as being unused.
mov [bx].in_use,0
clc
ret
f_as_send_pkt:
;ds:si -> buffer, cx = length, es:di -> upcall.
test driver_function,4 ;is this a high-performance driver?
jne f_send_pkt_1 ;yes.
mov dh,BAD_COMMAND ;no - return an error.
stc
ret
f_send_pkt:
;ds:si -> buffer, cx = length
xor di,di
mov es,di
f_send_pkt_1:
;ds:si -> buffer, cx = length, es:di -> upcall (only used if high-pref driver).
linc packets_out
add bytes_out.offs,cx ;add up the received bytes.
adc bytes_out.segm,0
push ds ; set up proper ds for the buffer
mov ds,_DS[bp] ; address of buffer from caller's ds.
;following two instructions not needed because si and cx haven't been changed.
; mov si,_SI[bp]
; mov cx,_CX[bp] ; count of bytes in the packet.
call send_pkt
pop ds
ret
f_terminate:
call verify_handle ; must have a handle
f_terminate_1:
mov [bx].in_use,0 ; mark handle as free
mov bx,offset handles ; check that all handles are free
f_terminate_2:
cmp [bx].in_use,0 ; is this handle free?
jne f_terminate_4 ; ne = no, so can't exit completely
add bx,(size per_handle) ; next handle
cmp bx,offset end_handles ; examined all handles?
jb f_terminate_2 ; b = no, continue examination
call terminate ;terminate the hardware.
;
; Now disable interrupts
;
mov al,int_no
call maskint
;
; Now return the interrupt to their handler.
;
mov ah,25h ;get the old interrupt into es:bx
mov al,int_no
add al,8
cmp al,8+8 ;is it a slave 8259 interrupt?
jb f_terminate_3 ;no.
add al,70h - (8+8) ;map it to the real interrupt.
f_terminate_3:
push ds
lds dx,their_recv_isr
int 21h
pop ds
mov al,packet_int_no ;release our_isr.
mov ah,25h
push ds
lds dx,their_isr
int 21h
pop ds
;
; Now free our memory
;
push cs
pop es
mov ah,49h
int 21h
f_terminate_4:
clc
ret
f_get_address:
call verify_handle
; mov es,_ES[bp] ; get new one
; mov di,_DI[bp] ; get pointer, es:di is ready
mov cx,_CX[bp] ;Tell them how much room they have.
cmp have_my_address,0 ;has our address been set?
jne get_address_set ;yes - go report it.
call get_address ;no, can we get the address?
jc get_address_space ;no - we must not have enough space.
mov _CX[bp],cx ;Tell them how long our address is.
clc
ret
get_address_set:
cmp cx,my_address_len ;is there enough room?
jb get_address_space ;no.
mov cx,my_address_len ;yes - get our address length.
mov _CX[bp],cx ;Tell them how long our address is.
mov si,offset my_address ;copy it into their area.
rep movsb
clc
ret
get_address_space:
mov dh,NO_SPACE
stc
ret
f_set_address:
mov bx,offset handles
mov cl,0 ;number of handles in use.
f_set_address_1:
add cl,[bx].in_use ;is this handle in use?
add bx,(size per_handle) ;go to the next handle.
cmp bx,offset end_handles
jb f_set_address_1
cmp cl,1 ;more than one handle in use?
ja f_set_address_inuse ;yes - we can't set the address
mov ds,_ES[bp] ; set new one
assume ds:nothing
mov si,_DI[bp] ; set pointer, ds:si is ready
; mov cx,_CX[bp] ;Tell them how much address is being set.
call set_address
;set_address restores ds.
jc f_set_address_exit ;Did it work?
mov _CX[bp],cx ;yes - return our address length.
cmp cx,MAX_ADDR_LEN ;is it too long for us to remember?
ja f_set_address_too_long ;yes, return a too-long error.
mov ds,_ES[bp] ; set new one
mov si,_DI[bp] ; set pointer, ds:si is ready
mov ax,cs
mov es,ax
mov my_address_len,cx ;remember how long our address is.
mov di,offset my_address
rep movsb
mov have_my_address,1
mov ds,ax ;restoer ds.
assume ds:code
clc
ret
f_set_address_inuse:
mov dh,CANT_SET
stc
ret
f_set_address_too_long:
mov dh,NO_SPACE
stc
f_set_address_exit:
ret
f_reset_interface:
call verify_handle
call reset_interface
clc
ret
f_get_parameters:
;strictly speaking, this function only works for high-performance drivers.
test driver_function,4 ;is this a high-performance driver?
jne f_get_parameters_1 ;yes.
mov dh,BAD_COMMAND ;no - return an error.
stc
ret
f_get_parameters_1:
mov _ES[bp],cs
mov _DI[bp],offset parameter_list
clc
ret
verify_handle:
;Ensure that their handle is real. If it isn't, we pop off our return
;address, and return to *their* return address with cy set.
mov bx,_BX[bp] ;get the handle they gave us
cmp bx,offset handles
jb verify_handle_bad ;no - must be bad.
cmp bx,offset end_handles
jae verify_handle_bad ;no - must be bad.
cmp [bx].in_use,0 ;if it's not in use, it's bad.
je verify_handle_bad
ret
verify_handle_bad:
mov dh,BAD_HANDLE
add sp,2 ;pop off our return address.
stc
ret
public set_recv_isr
set_recv_isr:
mov ah,35h ;get the old interrupt into es:bx
mov al,int_no ; board's interrupt vector
add al,8
cmp al,8+8 ;is it a slave 8259 interrupt?
jb set_recv_isr_1 ;no.
add al,70h - 8 - 8 ;map it to the real interrupt.
set_recv_isr_1:
int 21h
mov their_recv_isr.offs,bx ;remember the old seg:off.
mov their_recv_isr.segm,es
mov ah,25h ;now set our recv interrupt.
mov dx,offset recv_isr
int 21h
mov al,int_no ; Now enable interrupts
call unmaskint
ret
public count_in_err
count_in_err:
assume ds:nothing
linc errors_in
ret
public count_out_err
count_out_err:
assume ds:nothing
linc errors_out
ret
their_recv_isr dd 0 ; original owner of board int
recv_isr:
push ax
push ds
mov ax,cs ;ds = cs.
mov ds,ax
assume ds:code
mov savesp,sp
mov savess,ss
mov ss,ax
mov sp,offset our_stack
cld
sti
push bx
push cx
push dx
push si
push di
push bp
push es
call recv
cli ;interrupts *must* be off between
;here and the stack restore, because
;if we have one of our interrupts
;pending, we would trash our stack.
;
; The following code is ruthlessly stolen from Phil Karn's NET package.
;
test sys_features,40h ; 2nd 8259 installed?
jz recv_isr_3 ; Only one 8259, so skip this stuff
mov al,0bh ; read in-service register from
out 0a0h,al ; secondary 8259
nop ; settling delay
nop
nop
in al,0a0h ; get it
or al,al ; Any bits set?
jz recv_isr_3 ; nope, not a secondary interrupt
mov al,20h ; Get EOI instruction
out 0a0h,al ; Secondary 8259 (PC/AT only)
recv_isr_3:
mov al,20h ;acknowledge the interrupt.
out 20h,al
pop es
pop bp
pop di
pop si
pop dx
pop cx
pop bx
mov ss,savess
mov sp,savesp
call recv_exiting ;this routine can enable interrupts.
pop ds
pop ax
iret
public maskint
maskint:
or al,al ;are they using a hardware interrupt?
je maskint_1 ;no, don't mask off the timer!
assume ds:code
mov dx,21h ;assume the master 8259.
cmp al,8 ;using the slave 8259 on an AT?
jb mask_not_irq2
mov dx,0a1h ;go disable it on slave 8259
sub al,8
mask_not_irq2:
mov cl,al
in al,dx ;disable them on the correct 8259.
mov ah,1 ;set the bit.
shl ah,cl
or al,ah
out dx,al
maskint_1:
ret
unmaskint:
assume ds:code
mov dx,21h ;assume the master 8259.
cmp al,8 ;using the slave 8259 on an AT?
jb unmask_not_irq2
mov dx,0a1h ;go enable it on slave 8259
sub al,8
unmask_not_irq2:
mov cl,al
in al,dx ;enable interrupts on the correct 8259.
mov ah,1 ;clear the bit.
shl ah,cl
not ah
and al,ah
out dx,al
ret
public recv_find
recv_find:
;called when we want to determine what to do with a received packet.
;enter with cx = packet length, es:di -> packet type.
;exit with es:di = 0 if the packet is not desired, or es:di -> packet buffer
; to be filled by the driver.
assume ds:code, es:nothing
push cx
mov bx,offset handles
recv_find_1:
cmp [bx].in_use,0 ;is this handle in use?
je recv_find_2 ;no - don't check the type.
mov ax,[bx].receiver.offs ;do they have a receiver?
or ax,[bx].receiver.segm
je recv_find_2 ;no - they're not serious about it.
mov cx,[bx].packet_type_len ;compare the packets.
lea si,[bx].packet_type
jcxz recv_find_3 ;if cx is zero, they want them all.
push di
repe cmpsb
pop di
je recv_find_3 ;we've got it!
recv_find_2:
add bx,(size per_handle) ;go to the next handle.
cmp bx,offset end_handles
jb recv_find_1
linc packets_dropped
pop cx ;we didn't find it -- discard it.
xor di,di ;"return" a null pointer.
mov es,di
ret
recv_find_3:
pop cx ; the packet_length
linc packets_in
add bytes_in.offs,cx ;add up the received bytes.
adc bytes_in.segm,0
mov ax,[bx].receiver.offs
mov receive_ptr.offs,ax
mov ax,[bx].receiver.segm
mov receive_ptr.segm,ax
mov found_handle,bx ;remember what our handle was.
mov ax,0 ;allocate request.
stc ;with stc, flags must be an odd number
push ax ; save a number that cant be flags
pushf ;save flags incase iret used.
; ssw
mov ax, [bx].receiver.segm ;does the receiver signature
mov es, ax ; match whats currently in
mov di, [bx].receiver.offs ; memory?
mov ax, es:[di] ; if not, jump to fake return
cmp ax, [bx].sig1
jne not_there
inc di
mov ax, es:[di]
cmp ax, [bx].sig2
jne not_there
inc di
mov ax, es:[di]
cmp ax, [bx].sig3
jne not_there
inc di
mov ax, es:[di]
cmp ax, [bx].sig4
jne not_there
stc
mov ax, 0
call receive_ptr ;ask the client for a buffer.
jmp there
not_there:
; on return, flags should be at top of stack. if an IRET has nbeen used,
; then 0 will be at the top of the stack
; ssw
mov ax, 0 ; receiver was not there
mov es, ax ; fake a return from receiver
mov di, ax ; no buffer space
; ssw
there:
pop bx
cmp bx,0
je recv_find_4 ;0 is at top of stack
add sp,2
recv_find_4:
ret
public recv_copy
recv_copy:
;called after we have copied the packet into the buffer.
;enter with ds:si ->the packet, cx = length of the packet.
;preserve bx.
assume ds:nothing, es:nothing
push bx
mov bx,found_handle
mov ax,1 ;store request.
clc ;with clc, flags must be an even number
push ax ; save a number that cant be flags
pushf ;save flags incase iret used.
call receive_ptr ;ask the client for a buffer.
pop bx
cmp bx,1 ;if this is a 1, IRET was used.
je recv_copy_1
pop bx
recv_copy_1:
pop bx
ret
code ends
end start