home *** CD-ROM | disk | FTP | other *** search
- ; Copyright, 1988-1992, Russell Nelson, Crynwr Software
-
- ; This program is free software; you can redistribute it and/or modify
- ; it under the terms of the GNU General MakePublic 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 MakePublic License for more details.
- ;
- ; You should have received a copy of the GNU General MakePublic License
- ; along with this program; if not, write to the Free Software
- ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ;
- ;
- ;
- ;
- ; Copyright 1993, University of Minnesota
- ;
- ; Changes at U of M: (slip@booombox.micro.umn.edu)
- ;
- ; Changed many things to make it possible to set serial parameters
- ; on the fly.
- ; Fixed many timing problems.
- ; Added output handshaking.
- ; Cleaned up loop timing code.
- ; Made all opens delayed.
- ; Configuration is done by another program (PHONE.EXE)
- ;
- ; Still need to:
- ; Compute correct timing delays.
- ; Add input handshaking.
- ; Timeout hung handshaking properly.
- ; 38,400 baud loses a few characters.
- ; Doesnt detect missing com port.
- ;
-
-
- majver equ 1 ;version number of the infrastructure.
-
- MAX_ADDR_LEN equ 16 ;maximum number of bytes in our address.
-
- MAX_HANDLE equ 10 ;maximum number of handles.
-
- MAX_P_LEN equ 8 ;maximum type length
-
- MAX_MULTICAST equ 8 ;maximum number of multicast addresses.
-
-
- HT equ 09h
- CR equ 0dh
- LF equ 0ah
-
- ;
- ; Packet Driver Error numbers
- NO_ERROR equ 0 ;no error at all.
- BAD_HANDLE equ 1 ;invalid handle number
- NO_CLASS equ 2 ;no interfaces of specified class found
- NO_TYPE equ 3 ;no interfaces of specified type found
- NO_NUMBER equ 4 ;no interfaces of specified number found
- BAD_TYPE equ 5 ;bad packet type specified
- NO_MULTICAST equ 6 ;this interface does not support
- ;multicast
- CANT_TERMINATE equ 7 ;this packet driver cannot terminate
- BAD_MODE equ 8 ;an invalid receiver mode was specified
- NO_SPACE equ 9 ;operation failed because of
- ;insufficient space
- TYPE_INUSE equ 10 ;the type had previously been accessed,
- ;and not released.
- BAD_COMMAND equ 11 ;the command was out of range, or not
- ;implemented
- CANT_SEND equ 12 ;the packet couldn't be sent (usually
- ;hardware error)
- CANT_SET equ 13 ;hardware address couldn't be changed
- ;(more than 1 handle open)
- BAD_ADDRESS equ 14 ;hardware address has bad length or
- ;format
- CANT_RESET equ 15 ;Couldn't reset interface (more than
- ;1 handle open).
- BAD_IOCB equ 16 ;an invalid iocb was specified
-
- ;a few useful Ethernet definitions.
- RUNT equ 60 ;smallest legal size packet, no fcs
- GIANT equ 1514 ;largest legal size packet, no fcs
- EADDR_LEN equ 6 ;Ethernet address length.
- ARCADDR_LEN equ 1
-
- BLUEBOOK equ 1
- IEEE8023 equ 11
-
-
-
-
- MakePublic macro Sym
- ;;; Public &Sym ; no publics now...
- endm
-
- MakeExternal macro Sym
- ;;; Extrn &Sym ; no externs now...
- endm
-
-
-
-
-
-
-
-
- ;The following two macros are used to manipulate port addresses.
- ;Use loadport to initialize dx. Use setport to set a specific port on
- ;the board. setport remembers what the current port number is, but beware!
- ;setport assumes that code is being executed in the same order as the
- ;code is presented in the source file. Whenever this assumption is violated,
- ;you need to enter another loadport. Some, but not all examples are:
- ;in a loop with multiple setports, or a backward jump over a setport, or
- ;a forward jump over a setport. If you have any doubt, consult the
- ;individual driver sources for examples of usage. If you suspect that
- ;you have too few loadports, define the symbol "no_confidence" to a
- ;one. This will force a loadport before every setport. If you wish to turn
- ;it off for some of your code, redefine it to a zero.
-
- loadport macro
- mov dx,io_addr
- port_no = 0
- endm
-
- ;change the port number from the current value to the new value.
- setport macro new_port_no
- ifdef no_confidence ;define if you suspect that you don't
- if no_confidence
- loadport ; have enough loadports, i.e. dx is
- endif
- endif ; set to the wrong port.
- if new_port_no - port_no EQ 1
- inc dx
- else
- if new_port_no - port_no EQ -1
- dec dx
- else
- if new_port_no - port_no NE 0
- add dx,new_port_no - port_no
- endif
- endif
- endif
- port_no = new_port_no
- endm
-
- Print macro
- call DosPrint
- endm
-
- Delay Macro
- call DelaySub
- endm
-
-
-
- SlowIn macro
- Delay
- in al,dx
- endm
-
-
- SlowOut macro
- Delay
- out dx,al
- endm
-
-
- segmoffs struc ; defines offs as 0, segm as 2
- offs dw ?
- segm dw ?
- segmoffs ends
-
- CY equ 0001h
- EI equ 0200h
-
- iocb struc ; as_send_pkt structure
- buffer dd ? ; Pointer to the buffer
- len dw ? ; Its length
- flags db ? ; Some flags
- ret_code db ? ; Completion code
- upcall dd ? ; I/O completion upcall
- next dd ? ; Private next pointer (queue)
- resv db 4 dup (?) ; Unused private data
- iocb ends
-
- DONE equ 1 ; I/O complete flag
- CALLME equ 2 ; Please upcall me flag
-
-
- send_queueempty macro
- ; Check if send queue is empty.
- ; Enter with interrupts disabled.
- ; Exit with zr (zero) if empty, nz (not zero) if not.
- ; Destroys ax.
- mov ax, word ptr send_head ; Queue empty?
- or ax, word ptr send_head+2
- endm
-
- send_peekqueue macro
- ; Peek into the queue and get the next entry.
- ; Enter with interrupts disabled.
- ; Exit with es:di -> iocb.
- les di, send_head ; Get head segment:offset
- endm
-
- ; Bits in sys_features
- MICROCHANNEL equ 02 ; a micro channel computer
- TWO_8259 equ 40h ; 2nd 8259 exists
-
- ; Bits in flagbyte
- CALLED_ETOPEN equ 1 ; have called etopen
- D_OPTION equ 2 ; delayed initialization
- N_OPTION equ 4 ; Novell protocol conversion
- W_OPTION equ 8 ; Windows upcall checking.
-
- ; Copyright, 1988-1992, Russell Nelson, Crynwr Software
-
- ; This program is free software; you can redistribute it and/or modify
- ; it under the terms of the GNU General MakePublic 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 MakePublic License for more details.
- ;
- ; You should have received a copy of the GNU General MakePublic License
- ; along with this program; if not, write to the Free Software
- ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-
-
- code segment word
- assume cs:code, ds:code
-
- MakePublic phd_environ
- org 2ch
- phd_environ dw ?
-
- MakePublic phd_dioa
- org 80h
- phd_dioa label byte
-
- org 100h
- start:
- jmp start_1
- MakeExternal start_1: near
- even ;put the stack on a word boundary.
-
- ;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
-
-
- MakeExternal int_no: byte
- MakePublic packet_int_no, is_at, sys_features, flagbyte,quiet
-
- packet_int_no db 60h,0,0,0 ; interrupt to communicate.
- is_at db 0 ; =1 if we're on an AT.
- sys_features db 0 ; 2h = MC 40h = 2nd 8259
- flagbyte db 0
- quiet db 0
-
- even
-
- functions label word
- dw f_not_implemented ;0
- dw f_driver_info ;1
- dw f_access_type ;2
- dw f_release_type ;3
- dw f_send_pkt ;4
- dw f_terminate ;5
- dw f_get_address ;6
- dw f_reset_interface ;7
- dw f_stop ;8
- dw f_not_implemented ;9
- dw f_get_parameters ;10
- dw f_not_implemented ;11
- dw f_as_send_pkt ;12
- dw f_drop_pkt ;13
- dw f_ser_func ;14
- dw f_not_implemented ;15
- dw f_not_implemented ;16
- dw f_not_implemented ;17
- dw f_not_implemented ;18
- dw f_not_implemented ;19
- dw f_set_rcv_mode ;20
- dw f_get_rcv_mode ;21
- dw f_set_multicast_list ;22
- dw f_get_multicast_list ;23
- dw f_get_statistics ;24
- dw f_set_address ;25
-
- MakeExternal driver_class: byte
- MakeExternal driver_type: byte
- MakeExternal driver_name: byte
- MakeExternal driver_function: byte
- MakeExternal parameter_list: byte
-
- MakeExternal send_pkt: near
- MakeExternal as_send_pkt: near
- MakeExternal drop_pkt: near
- MakeExternal get_address: near
- MakeExternal set_address: near
- MakeExternal terminate: near
- MakeExternal reset_interface: near
- MakeExternal xmit: near
- MakeExternal recv: near
- MakeExternal recv_exiting: near
- MakeExternal etopen: near
-
- MakeExternal rcv_modes: word ;count of modes followed by mode handles.
-
- MakeExternal 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.
- receiver_sig db 8 dup(?) ;signature at the receiver handler.
- class db ? ;interface class
- per_handle ends
-
- handles per_handle MAX_HANDLE dup(<>)
- end_handles label byte
-
- MakePublic 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
-
- MakePublic send_head, send_tail
- send_head dd 0 ; head of transmit queue
- send_tail dd 0 ; tail of transmit queue
-
- 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
-
- MakePublic 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
-
- MakePublic re_enable_interrupts
- re_enable_interrupts:
- ; Possibly re-enable interrupts. We put this here so that other routines
- ; don't need to know how we put things on the stack.
- test _F[bp], EI ; Were interrupts enabled on pkt driver entry?
- je re_enable_interrupts_1 ; No.
- sti ; Yes, re-enable interrupts now.
- re_enable_interrupts_1:
- ret
-
-
- 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
-
- ;For enhanced PD, if they call
- cmp _BX[bp],offset handles ;with a handle, give them the
- ;class they think it is
- jb default_handle
- cmp _BX[bp],offset end_handles ;otherwise default to first class
- jae default_handle
- mov bx, _BX[bp]
- cmp [bx].in_use,0 ;if it's not in use, it's bad.
- je default_handle
- mov al, [bx].class
- mov _CH[bp], al
- jmp short got_handle
-
- default_handle:
- mov al,driver_class
- mov _CH[bp],al
- got_handle:
-
- mov _BX[bp],majver ;version
- 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
-
- cmp cx,rcv_mode_num ;are we already using that mode?
- je f_set_rcv_mode_4 ;yes, no need to check anything.
-
- mov dx,bx ;remember our handle.
- mov bx,offset handles ; check that all handles are free
- f_set_rcv_mode_2:
- cmp bx,dx ; is this our handle?
- je f_set_rcv_mode_3 ; yes, of course it's not free.
- cmp [bx].in_use,0 ; is this handle free?
- jne f_set_rcv_mode_1 ; ne = no, can't change
- f_set_rcv_mode_3:
- add bx,(size per_handle) ; next handle
- cmp bx,offset end_handles ; examined all handles?
- jb f_set_rcv_mode_2 ; b = no, continue examination
-
- mov cx,_CX[bp] ;get the desired receive mode.
- 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.
- f_set_rcv_mode_4:
- 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
-
- ;register caller of pkt TYPE
- f_access_type:
- mov bx, offset driver_class
- access_type_9:
- mov al, [bx] ;get the next class.
- inc bx
- or al,al ;end of the list?
- je access_type_class ;class failed (story of my life)
- cmp _AL[bp],al ;our class?
- jne access_type_9 ;no, try again
- access_type_1:
- 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 al, _AL[bp] ;is this handle the same class as
- cmp al, [bx].class ; they're want?
- jne short access_type_6
- 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
-
- lds si,es:[bx].receiver ;copy the first 8 bytes
- lea di,[bx].receiver_sig ; to the receiver signature.
- mov cx,8/2
- rep movsw
-
- pop ds
-
- mov al, _AL[bp]
- mov [bx].class, al
-
- mov _AX[bp],bx ;return the handle to them.
-
- clc
- ret
-
-
- access_type_space:
- mov dh,NO_SPACE
- stc
- ret
-
- f_release_type:
- call verify_handle ;mark this handle as being unused.
- mov [bx].in_use,0
- clc
- ret
-
-
- f_send_pkt:
- ;ds:si -> buffer, cx = length
- ; XXX Should re-enable interrupts here, but some drivers are broken.
- ; Possibly re-enable interrupts.
- ; test _F[bp], EI ; Were interrupts enabled on pkt driver entry?
- ; je f_send_pkt_1 ; No.
- ; sti ; Yes, re-enable interrupts now.
- ;f_send_pkt_1:
-
- ;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.
- 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.
- assume ds:nothing, es:nothing
-
- ; If -n option take Ethernet encapsulated Novell IPX packets (from BYU's
- ; PDSHELL) and change them to be IEEE 802.3 encapsulated.
- EPROT_OFF equ EADDR_LEN*2
- test cs:flagbyte,N_OPTION
- jz f_send_pkt_2
- cmp ds:[si].EPROT_OFF,3781h ; if not Novell (prot 8137)
- jne f_send_pkt_2 ; don't tread on it
- push ax ; get scratch reg
- mov ax,[si].EPROT_OFF+4 ; get len
- xchg ah,al
- inc ax ; make even (rounding up)
- and al,0feh
- xchg ah,al
- mov ds:[si].EPROT_OFF,ax ; save in prot field
- pop ax ; restore old contents
- f_send_pkt_2:
- call send_pkt
- pop ds
- assume ds:code
- ret
-
-
- f_as_send_pkt:
- ;es:di -> iocb.
- test driver_function,4 ; is this a high-performance driver?
- je f_as_send_pkt_2 ; no.
- ; Possibly re-enable interrupts.
- test _F[bp], EI ; Were interrupts enabled on pkt driver entry?
- je f_as_send_pkt_1 ; No.
- sti ; Yes, re-enable interrupts now.
- f_as_send_pkt_1:
- push ds ; set up proper ds for the buffer
- lds si,es:[di].buffer ; ds:si -> buffer
- assume ds:nothing
- mov cx,es:[di].len ; cx = length
- linc packets_out
- add bytes_out.offs,cx ; add up the received bytes.
- adc bytes_out.segm,0
-
- ;ds:si -> buffer, cx = length, es:di -> iocb.
- call as_send_pkt
- pop ds
- assume ds:code
- ret
- f_as_send_pkt_2:
- mov dh, BAD_COMMAND ; return an error.
- stc
- ret
-
-
- f_drop_pkt:
- ; es:di -> iocb.
- test driver_function,4 ; is this a high-performance driver?
- je f_as_send_pkt_1 ; no.
- push ds ; Preserve ds
- mov si,offset send_head ; Get head offset
- dp_loop:
- mov ax,ds:[si] ; Get offset
- mov dx,ds:[si+2] ; Get segment
- mov bx,ax
- or bx,dx ; End of list?
- je dp_endlist ; Yes
- cmp ax,di ; Offsets equal?
- jne dp_getnext ; No
- mov bx,es
- cmp dx,bx ; Segments equal?
- jne dp_getnext ; No
- call drop_pkt ; Pass to driver
- les di,es:[di].next ; Get next segment:offset
- mov ds:[si],di ; Set next offset
- mov ds:[si+2],es ; Set next segment
- pop ds ; Restore ds
- clc
- ret
- dp_getnext:
- mov ds,dx ; Get next segment
- mov si,ax ; Get next iocb offset
- lea si,ds:[si].next ; Get next iocb next ptr offset
- jmp dp_loop ; Try again
- dp_endlist:
- pop ds ; Restore ds
- mov dh,BAD_IOCB ; Return error
- stc ; Set carry
- ret
-
- MakeExternal ser_funcs:near
- f_ser_func: ; direct serial functions
- call ser_funcs
- clc
- 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
-
- ;
- ; Now disable interrupts
- ;
- call int_dis
- call terminate ;terminate the hardware.
-
- 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
- clc
- ret
- f_terminate_4:
- mov dh, CANT_TERMINATE
- stc
- ret
-
-
- MakePublic int_dis
- int_dis:
- mov al,int_no
- or al,al ;are they using a hardware interrupt?
- je f_term_no_irq ;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_term_3 ;no.
- add al,70h - (8+8) ;map it to the real interrupt.
- f_term_3:
- push ds
- lds dx,their_recv_isr
- int 21h
- pop ds
-
- f_term_no_irq:
- 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
-
-
- ; Stop the packet driver doing upcalls. Also a following terminate will
- ; always succed (no in use handles any longer).
- f_stop:
- mov bx,offset handles
- f_stop_2:
- mov [bx].in_use,0
- add bx,(size per_handle) ; next handle
- cmp bx,offset end_handles
- jb f_stop_2
- 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
-
-
- MakePublic set_recv_isr
- set_recv_isr:
- mov ah,35h ;get the old interrupt into es:bx
- mov al,int_no ;board's interrupt vector
- or al,al
- je set_isr_no_irq
-
- 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
-
- set_isr_no_irq:
- ret
-
-
-
- MakePublic count_in_err
- count_in_err:
- assume ds:nothing
- linc errors_in
- ret
-
- MakePublic count_out_err
- count_out_err:
- assume ds:nothing
- linc errors_out
- ret
-
- MakePublic DelaySub
-
- DelaySub:
- push cx
- pop cx
- ret
-
- their_recv_isr dd 0 ; original owner of board int
-
- ;
- ; I have had a problem with some hardware which under extreme LAN loading
- ; conditions will re-enter the recv_isr. Since the 8259 interrupts for
- ; the card are masked off, and the card's interrupt mask register is
- ; cleared (in 8390.asm at least) disabling the card from interrupting, this
- ; is clearly a hardware problem. Due to the low frequencey of occurance, and
- ; extreme conditions under which this happens, it is not lilely to be fixed
- ; in hardware any time soon, plus retrofitting of hardware in the field will
- ; not happen. To protect the driver from the adverse effects of this I am
- ; adding a simple re-entrancy trap here. - gft - 910617
- ;
-
- in_recv_isr db 0 ; flag to trap re-entrancy
-
- recv_isr:
- cmp in_recv_isr, 0
- je no_re_enter
- iret
-
- no_re_enter:
- mov in_recv_isr, 1
-
- ; I realize this re-entrancy trap is not perfect, you could be re-entered
- ; anytime before the above instruction. However since the stacks have not
- ; been swapped re-entrancy here will only appear to be a spurious interrupt.
- ; - gft - 910617
-
- ; In order to achieve back-to-back packet transmissions, we handle the
- ; latency-critical portion of transmit interrupts first. The xmit
- ; interrupt routine should only start the next transmission, but do
- ; no other work. It may only touch ax and dx (the only register necessary
- ; for doing "out" instructions) unless it first pushes any other registers
- ; itself.
- push ax
- push dx
- call xmit
-
- ; Now switch stacks, push remaining registers, and do remaining interrupt work.
- 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
-
- push bx
- push cx
- push si
- push di
- push bp
- push es
-
- ; The following comment is wrong in that we now do a specific EOI command,
- ; and because we don't enable interrupts (even though we should).
-
- ; Chips & Technologies 8259 clone chip seems to be very broken. If you
- ; send it a Non Specific EOI command, it clears all In Service Register
- ; bits instead of just the one with the highest priority (as the Intel
- ; chip does and clones should do). This bug causes our interrupt
- ; routine to be reentered if: 1. we reenable processor interrupts;
- ; 2. we reenable device interrupts; 3. a timer or other higher priority
- ; device interrupt now comes in; 4. the new interrupting device uses
- ; a Non Specific EOI; 5. our device interrupts again. Because of
- ; this bug, we now completely mask our interrupts around the call
- ; to "recv", the real device interrupt handler. This allows us
- ; to send an EOI instruction to the 8259 early, before we actually
- ; reenable device interrupts. Since the interrupt is masked, we
- ; are still guaranteed not to get another interrupt from our device
- ; until the interrupt handler returns. This has another benefit:
- ; we now no longer prevent other devices from interrupting while our
- ; interrupt handler is running. This is especially useful if we have
- ; other (multiple) packet drivers trying to do low-latency transmits.
- mov al,int_no ; Disable further device interrupts
- call maskint
-
- ; The following is from Bill Rust, <wjr@ftp.com>
- ; this code dismisses the interrupt at the 8259. if the interrupt number
- ; is > 8 then it requires fondling two PICs instead of just one.
- mov al, int_no ; get hardware int #
- cmp al, 8 ; see if its on secondary PIC
- jg recv_isr_4
- add al, 60h ; make specific EOI dismissal
- out 20h, al
- jmp recv_isr_3 ; all done
-
- recv_isr_4:
- add al,60h - 8 ; make specific EOI (# between 9 & 15).
- out 0a0h,al ; Secondary 8259 (PC/AT only)
- mov al,62h ; Acknowledge on primary 8259.
- out 20h,al
- recv_isr_3:
-
- ; sti ; Interrupts are now completely safe
- 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.
- ;
- ; According to Novell IMSP Technical Memo #2, Lost Interrupts and NetWare,
- ; some LAN controllers can glitch the interrupt line when the interrupt
- ; mask register on the LAN controller is enabled to allow the LAN controller
- ; to interrupt. This can cause spurious/lost interrupt problems, especially
- ; on some 486 processors which latch the int line to the processor. To prevent
- ; glitches from being propogated throug, move the call to recv_exiting (re-
- ; enables interrupts on the LAN card) to before when the 8259 interrupts are
- ; unmasked. - gft - 910617
-
- call recv_exiting
-
- mov al,int_no ; Now reenable device interrupts
- call unmaskint
-
- pop es
- pop bp
- pop di
- pop si
- pop cx
- pop bx
-
- mov ss,savess
- mov sp,savesp
-
- ; move the next call up to above the call unmaskint - gft - 910617
- ; call recv_exiting ;this routine can enable interrupts.
- ; DDP - This is a BIG mistake. This routine SHOULD NOT enable interrupts.
- ; doing so can cause interrupt recursion and blow your stack.
- ; Processor interrupts SHOULD NOT be enabled after enabling device
- ; interrupts until after the "iret". You will lose atleast 12 bytes
- ; on the stack for each recursion.
-
- pop ds
- assume ds:nothing
- pop dx
- pop ax
- mov in_recv_isr, 0 ; clear the re-entrancy flag - gft - 901617
- iret
-
-
- MakePublic 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
-
- SlowIn ;disable them on the correct 8259.
- mov ah,1 ;set the bit.
- shl ah,cl
- or al,ah
- ;
- ; 500ns Stall required here, per INTEL documentation for eisa machines
- ; - gft - 910617
- ;
- Delay
- SlowOut
-
- maskint_1:
- ret
-
-
- MakePublic unmaskint
- unmaskint:
- assume ds:code
- mov dx,21h ;assume the master 8259.
- mov cl,al
- cmp cl,8 ;using the slave 8259 on an AT?
- jb unmask_not_irq2 ;no
-
- SlowIn ;get master mask
- and al,not (1 shl 2) ; and clear slave cascade bit in mask
- SlowOut ;set new master mask (enable slave int)
- ;
- ; 500ns Stall required here, per INTEL documentation for eisa machines
- ; - gft - 910617
- ;
- mov dx,0a1h ;go enable int on slave 8259
- sub cl,8
-
- unmask_not_irq2:
-
- SlowIn ;enable interrupts on the correct 8259.
- mov ah,1 ;clear the bit.
- shl ah,cl
- not ah
- and al,ah
- ;
- ; 500ns Stall required here, per INTEL documentation for eisa machines
- ; - gft - 910617
- ;
- SlowOut
- ret
-
-
- MakePublic 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, dl = packet class.
- ;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
-
- ; If -n option take IEEE 802.3 encapsulated packets that could be Novell IPX
- ; and make them Ethernet encapsulated Novell IPX packets (for PDSHELL).
- test flagbyte,N_OPTION
- jz not_n_op
-
- ; Make IEEE 802.3-like packets that could be Novell IPX into BlueBook class
- ; Novell type 8137 packets.
- cmp dl,IEEE8023 ;Is this an IEEE 802.3 packet?
- jne recv_not_802_3 ;no
- cmp word ptr es:[di],0ffffh ;if this word not ffff
- jne recv_not_8137 ; then not Novell
- sub di,2 ; back it up to the 8137 word.
- mov es:[di],3781h ; fake as Novell protocol (8137)
- mov dl,BLUEBOOK
- jmp short recv_not_8137
- recv_not_802_3:
- ; Convert incoming Ethernet type 8137 IPX packets to type 8138, as with -n in
- ; effect we can't send type 8137, and it will only confuse Netware.
- cmp dl,BLUEBOOK ;Is this a BLUEBOOK packet?
- jne recv_not_8137 ;no, don't change it.
- cmp word ptr es:[di],3781h ;Is it an 8137 packet?
- jne recv_not_8137 ;no, don't change it.
- mov es:[di],word ptr 3881h ;yes, mung it slightly.
- recv_not_8137:
- not_n_op:
-
- 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.
-
- cmp [bx].class, dl ;is this the right class?
- jne recv_find_2 ;no- don't bother
-
- 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.
- recv_find_5:
- 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
-
- les di,[bx].receiver ;remember the receiver upcall.
- mov receive_ptr.offs,di
- mov receive_ptr.segm,es
-
- test flagbyte,W_OPTION ;did they select the Windows option?
- je recv_find_6 ;no, don't check for the upcall.
-
- ; does the receiver signature match whats currently in memory? if not,
- ; jump to fake return
- push si
- push cx
- lea si,[bx].receiver_sig
- mov cx,8/2
- repe cmpsw
- pop cx
- pop si
- jne recv_find_5
- recv_find_6:
-
- 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 in case iret used.
- call receive_ptr ;ask the client for a buffer.
- ; on return, flags should be at top of stack. if an IRET has been used,
- ; then 0 will be at the top of the stack
- pop bx
- cmp bx,0
- je recv_find_4 ;0 is at top of stack
- add sp,2
- recv_find_4:
- ret
-
-
- MakePublic 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 can't 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
-
- MakePublic send_queue
- send_queue:
- ; Queue an iocb.
- ; Enter with es:di -> iocb, interrupts disabled.
- ; Destroys ds:si.
- assume ds:nothing, es:nothing
- mov es:[di].next.offs,0 ; Zero next offset
- mov es:[di].next.segm,0 ; Zero next segment
- mov si,send_head.offs ; Queue empty?
- or si,send_head.segm
- jnz sq_notempty ; No
- mov send_head.offs,di ; Set head offset
- mov send_head.segm,es ; Set head segment
- jmp sq_settail
- sq_notempty: ; Queue is not empty
- lds si,send_tail ; Get tail segment:offset
- mov ds:[si].next.offs,di ; Set next offset
- mov ds:[si].next.segm,es ; Set next segment
- sq_settail:
- mov send_tail.offs,di ; Set tail offset
- mov send_tail.segm,es ; Set tail segment
- ret
-
-
- MakePublic send_dequeue
- send_dequeue:
- ; Dequeue an iocb and possibly call its upcall.
- ; Enter with device or processor interrupts disabled, ah = return code.
- ; Exits with es:di -> iocb; destroys ds:si, ax, bx, cx, dx, bp.
- assume ds:nothing, es:nothing
- les di,send_head ; Get head segment:offset
- lds si,es:[di].next ; Get next segment:offset
- mov send_head.offs, si ; Set head offset
- mov send_head.segm, ds ; Set head segment
- or es:flags[di], DONE ; Mark done
- mov es:ret_code[di], ah ; Set retcode
- test es:[di].flags,CALLME ; Does he want an upcall?
- je send_dequeue_1 ; No.
- push es ; Push iocb segment
- push di ; and offset
- clc ; Clear carry.
- mov ax,1 ; Push a number that cant be flags.
- push ax
- pushf ; Save flags in case iret used.
- call es:[di].upcall ; Call the client.
- pop ax ; Pop first word.
- cmp ax,1 ; If this is a 1, IRET was used.
- je send_dequeue_2 ; Far return used.
- add sp,2 ; Pop flags.
- send_dequeue_2:
- pop di ; Pop iocb segment
- pop es ; and offset
- send_dequeue_1:
- ret
-
-
- code ends
-
- ;;;grg equ 99
-
- base = 50
-
- Alloc macro var,len
- &var equ base*2
- base = base+1+0&len
- endm
-
- Alloc col_chout
- Alloc col_chin
- Alloc col_ovrr,2
- Alloc col_frame,2
- Alloc col_serfull,2
- Alloc col_TCPFull,2
- Alloc col_InIn
- Alloc col_InOut
- Alloc col_inmove
- Alloc col_paks
-
- Show macro Col,Ch
- ifdef grg
- push es
- push ax
- mov ax,0B800h
- mov es,ax
- mov byte ptr es:[&col],&Ch ; twiddle screen if buf full
- pop ax
- pop es
- endif
- endm
-
-
- ShowInc macro Col,Ch
- ifdef grg
- push es
- push ax
- mov ax,0B800h
- mov es,ax
- mov byte ptr es:[&col],&Ch
- inc byte ptr es:[&col+2]
- pop ax
- pop es
- endif
- endm
-
-
- TheVersion equ 1
- majver equ 1 ;version number of the infrastructure.
-
- MAX_ADDR_LEN equ 16 ;maximum number of bytes in our address.
-
- MAX_HANDLE equ 10 ;maximum number of handles.
-
- MAX_P_LEN equ 8 ;maximum type length
-
- MAX_MULTICAST equ 8 ;maximum number of multicast addresses.
-
- ; Copyright, 1988-1992, Russell Nelson, Crynwr Software
-
- ; This program is free software; you can redistribute it and/or modify
- ; it under the terms of the GNU General MakePublic 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 MakePublic License for more details.
- ;
- ; You should have received a copy of the GNU General MakePublic License
- ; along with this program; if not, write to the Free Software
- ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- HT equ 09h
- CR equ 0dh
- LF equ 0ah
-
- ;
- ; Packet Driver Error numbers
- NO_ERROR equ 0 ;no error at all.
- BAD_HANDLE equ 1 ;invalid handle number
- NO_CLASS equ 2 ;no interfaces of specified class found
- NO_TYPE equ 3 ;no interfaces of specified type found
- NO_NUMBER equ 4 ;no interfaces of specified number found
- BAD_TYPE equ 5 ;bad packet type specified
- NO_MULTICAST equ 6 ;this interface does not support
- ;multicast
- CANT_TERMINATE equ 7 ;this packet driver cannot terminate
- BAD_MODE equ 8 ;an invalid receiver mode was specified
- NO_SPACE equ 9 ;operation failed because of
- ;insufficient space
- TYPE_INUSE equ 10 ;the type had previously been accessed,
- ;and not released.
- BAD_COMMAND equ 11 ;the command was out of range, or not
- ;implemented
- CANT_SEND equ 12 ;the packet couldn't be sent (usually
- ;hardware error)
- CANT_SET equ 13 ;hardware address couldn't be changed
- ;(more than 1 handle open)
- BAD_ADDRESS equ 14 ;hardware address has bad length or
- ;format
- CANT_RESET equ 15 ;Couldn't reset interface (more than
- ;1 handle open).
- BAD_IOCB equ 16 ;an invalid iocb was specified
-
- ;a few useful Ethernet definitions.
- RUNT equ 60 ;smallest legal size packet, no fcs
- GIANT equ 1514 ;largest legal size packet, no fcs
- EADDR_LEN equ 6 ;Ethernet address length.
- ARCADDR_LEN equ 1
-
- BLUEBOOK equ 1
- IEEE8023 equ 11
-
- ;The following two macros are used to manipulate port addresses.
- ;Use loadport to initialize dx. Use setport to set a specific port on
- ;the board. setport remembers what the current port number is, but beware!
- ;setport assumes that code is being executed in the same order as the
- ;code is presented in the source file. Whenever this assumption is violated,
- ;you need to enter another loadport. Some, but not all examples are:
- ;in a loop with multiple setports, or a backward jump over a setport, or
- ;a forward jump over a setport. If you have any doubt, consult the
- ;individual driver sources for examples of usage. If you suspect that
- ;you have too few loadports, define the symbol "no_confidence" to a
- ;one. This will force a loadport before every setport. If you wish to turn
- ;it off for some of your code, redefine it to a zero.
-
- loadport macro
- mov dx,io_addr
- port_no = 0
- endm
-
- ;change the port number from the current value to the new value.
- setport macro new_port_no
- ifdef no_confidence ;define if you suspect that you don't
- if no_confidence
- loadport ; have enough loadports, i.e. dx is
- endif
- endif ; set to the wrong port.
- if new_port_no - port_no EQ 1
- inc dx
- else
- if new_port_no - port_no EQ -1
- dec dx
- else
- if new_port_no - port_no NE 0
- add dx,new_port_no - port_no
- endif
- endif
- endif
- port_no = new_port_no
- endm
-
- Print macro
- call DosPrint
- endm
-
- Delay Macro
- call DelaySub
- endm
-
-
-
- SlowIn macro
- Delay
- in al,dx
- endm
-
-
- SlowOut macro
- Delay
- out dx,al
- endm
-
-
- segmoffs struc ; defines offs as 0, segm as 2
- offs dw ?
- segm dw ?
- segmoffs ends
-
- CY equ 0001h
- EI equ 0200h
-
- iocb struc ; as_send_pkt structure
- buffer dd ? ; Pointer to the buffer
- len dw ? ; Its length
- flags db ? ; Some flags
- ret_code db ? ; Completion code
- upcall dd ? ; I/O completion upcall
- next dd ? ; Private next pointer (queue)
- resv db 4 dup (?) ; Unused private data
- iocb ends
-
- DONE equ 1 ; I/O complete flag
- CALLME equ 2 ; Please upcall me flag
-
-
- send_queueempty macro
- ; Check if send queue is empty.
- ; Enter with interrupts disabled.
- ; Exit with zr (zero) if empty, nz (not zero) if not.
- ; Destroys ax.
- mov ax, word ptr send_head ; Queue empty?
- or ax, word ptr send_head+2
- endm
-
- send_peekqueue macro
- ; Peek into the queue and get the next entry.
- ; Enter with interrupts disabled.
- ; Exit with es:di -> iocb.
- les di, send_head ; Get head segment:offset
- endm
-
- ; Bits in sys_features
- MICROCHANNEL equ 02 ; a micro channel computer
- TWO_8259 equ 40h ; 2nd 8259 exists
-
- ; Bits in flagbyte
- CALLED_ETOPEN equ 1 ; have called etopen
- D_OPTION equ 2 ; delayed initialization
- N_OPTION equ 4 ; Novell protocol conversion
- W_OPTION equ 8 ; Windows upcall checking.
-
- ;Ported from Phil Karn's asy.c and slip.c, a C-language driver for the IBM-PC
- ;8250 by Russell Nelson. Any bugs are due to Russell Nelson.
- ;16550 support ruthlessly stolen from Phil Karn's 8250.c.
- ; Bugs by Denis DeLaRoca
- ; Stopped failures from lost transmit interrupts (by eliminating the ints
- ; altogether). Remove unneeded transmitter buffer.
- ; Version 6 by Joe Doupnik, jrd@cc.usu.edu, Utah State University, Dec 1991.
-
- ; Copyright, 1988, 1991, Russell Nelson
-
- ; This program is free software; you can redistribute it and/or modify
- ; it under the terms of the GNU General MakePublic 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 MakePublic License for more details.
- ;
- ; You should have received a copy of the GNU General MakePublic License
- ; along with this program; if not, write to the Free Software
- ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- code segment word
- assume cs:code, ds:code
-
- ;8250 definitions
- ;Control/status register offsets from base address
- THR equ 0 ;Transmitter holding register
- RBR equ 0 ;Receiver buffer register
- DLL equ 0 ;Divisor latch LSB
- DLM equ 1 ;Divisor latch MSB
- IER equ 1 ;Interrupt enable register
- IIR equ 2 ;Interrupt ident register
- FCR equ 2 ;16550 FIFO control register
- LCR equ 3 ;Line control register
- MCR equ 4 ;Modem control register
- LSR equ 5 ;Line status register
- MSR equ 6 ;Modem status register
-
- ;8250 Line Control Register
- LCR_5BITS equ 0 ;5 bit words
- LCR_6BITS equ 1 ;6 bit words
- LCR_7BITS equ 2 ;7 bit words
- LCR_8BITS equ 3 ;8 bit words
- LCR_NSB equ 4 ;Number of stop bits
- LCR_PEN equ 8 ;Parity enable
- LCR_EPS equ 10h ;Even parity select
- LCR_SP equ 20h ;Stick parity
- LCR_SB equ 40h ;Set break
- LCR_DLAB equ 80h ;Divisor Latch Access Bit
-
- ;16550 FIFO control register values
- FIFO_ENABLE equ 001h ;Enable TX and RX fifo
- FIFO_CLR_RX equ 002h ;Clear RX fifo
- FIFO_CLR_TX equ 004h ;Clear TX fifo
- FIFO_START_DMA equ 008h ;Enable TXRDY/RXRDY pin DMA handshake
- FIFO_SIZE_1 equ 000h ;RX fifo trigger levels
- FIFO_SIZE_4 equ 040h
- FIFO_SIZE_8 equ 080h
- FIFO_SIZE_14 equ 0c0h
- FIFO_SIZE_MASK equ 0c0h
-
- FIFO_TRIGGER_LEVEL equ FIFO_SIZE_4
- FIFO_SETUP equ FIFO_ENABLE+FIFO_CLR_RX+FIFO_CLR_TX+FIFO_TRIGGER_LEVEL
- OUTPUT_FIFO_SIZE equ 16
-
- ;8250 Line Status Register
- LSR_DR equ 1 ;Data ready
- LSR_OE equ 2 ;Overrun error
- LSR_PE equ 4 ;Parity error
- LSR_FE equ 8 ;Framing error
- LSR_BI equ 10h ;Break interrupt
- LSR_THRE equ 20h ;Transmitter line holding register empty
- LSR_TSRE equ 40h ;Transmitter shift register empty
-
- ;8250 Interrupt Identification Register
- IIR_IP equ 1 ;0 if interrupt pending
- IIR_ID equ 6 ;Mask for interrupt ID
- IIR_RLS equ 6 ;Receiver Line Status interrupt
- IIR_RDA equ 4 ;Receiver data available interrupt
- IIR_THRE equ 2 ;Transmitter holding register empty int
- IIR_MSTAT equ 0 ;Modem status interrupt
- IIR_FIFO_TIMEOUT equ 008h ;FIFO timeout interrupt pending - 16550 only
- IIR_FIFO_ENABLED equ 080h ;FIFO enabled (FCR0 = 1) - 16550 only
-
- ;8250 interrupt enable register bits
- IER_DAV equ 1 ;Data available interrupt
- IER_TxE equ 2 ;Tx buffer empty interrupt
- IER_RLS equ 4 ;Receive line status interrupt
- IER_MS equ 8 ;Modem status interrupt
-
- ;8250 Modem control register
- MCR_DTR equ 1 ;Data Terminal Ready
- MCR_RTS equ 2 ;Request to Send
- MCR_OUT1 equ 4 ;Out 1 (not used)
- MCR_OUT2 equ 8 ;Master interrupt enable (actually OUT 2)
- MCR_LOOP equ 10h ;Loopback test mode
-
- ;8250 Modem Status Register
- MSR_DCTS equ 1 ;Delta Clear-to-Send
- MSR_DDSR equ 2 ;Delta Data Set Ready
- MSR_TERI equ 4 ;Trailing edge ring indicator
- MSR_DRLSD equ 8 ;Delta Rx Line Signal Detect
- MSR_CTS equ 10h ;Clear to send
- MSR_DSR equ 20h ;Data set ready
- MSR_RI equ 40h ;Ring indicator
- MSR_RLSD equ 80h ;Received line signal detect
-
- pr_ch_al macro alvalue
- ifdef TRACEON
- mov al,alvalue
- call pr_ch
- endif
- endm
-
- ;Slip Definitions
- FR_END equ 0c0h ;Frame End
- FR_ESC equ 0dbh ;Frame Escape
- T_FR_END equ 0dch ;Transposed frame end
- T_FR_ESC equ 0ddh ;Transposed frame escape
-
- ser_buf_size equ 3000 ; (grg)
-
- BRC equ 115200
-
- MakePublic int_no
- TheInfo:
- int_no db 4,0,0,0 ; interrupt number.
- io_addr dw 03f8h,0 ; I/O address for COM1
- baud_rate dw 1234,0 ; support baud higher than 65535
- ser_misc db LCR_8BITS,0,0,0 ; misc control bits
- hardware_switch db 0,0,0,0 ; if zero, don't use hw handshaking
- xmit_time dw 0,0 ; loop timer for ari
-
- baudclk label word
- dd BRC ; 1.8432 Mhz / 16
-
- is_16550 db 0 ; 0=no, 1=yes (try using fifo)
-
- MakePublic driver_class, driver_type, driver_name
- MakePublic driver_function, parameter_list
- driver_class db 6,0,0,0 ;from the packet spec
- driver_type db 0,0,0,0 ;from the packet spec
- driver_name db 'UMSLIP ',0 ;name of the driver.
- driver_function db 2
- 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,
-
- MakePublic recv_buf_size, recv_buf, recv_buf_end, recv_buf_head
- MakePublic recv_buf_tail,end_resident
-
- recv_buf_size dw ser_buf_size,0 ;receive buffer size
- recv_buf dw ? ;->receive buffer
- recv_buf_end dw ? ;->after end of buffer
- recv_buf_head dw ? ;->next character to get
- recv_buf_tail dw ? ;->next character to store
- dummy dw 1234h
-
- IP_TYPE DW 0800H
-
- ifdef debug
- MakePublic Pak_Count, xmit_time
- endif
- Pak_Count dw 0 ; semaphore for packets received
- asyrxint_cnt dw 0 ; loop counter in ari
-
- MakePublic rcv_modes
- rcv_modes dw 4 ;number of receive modes in our table
- dw 0,0,0,rcv_mode_3
-
- MakePublic 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
-
- MakeExternal delaysub:near
-
-
- MakePublic drop_pkt
- ; Drop a packet from the queue.
- ; Enter with es:di -> iocb.
- drop_pkt:
- assume ds:nothing
- ret
-
- MakePublic 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
-
-
- MakePublic send_pkt
- ;
- ; mod 7/25/89 John Grover
- ; - operates with interrupts on. Xmits one byte per interrupt
- ; - only turns transmitter buffer empty interrupt off when
- ; - all bytes of all packets are transmitted.
-
- 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.
- ;called from telnet layer via software interrupt
- ; We just send each byte in turn. No UART interrupts are needed nor wanted.
- ; In fact the overdone receiver material omits to note that xmtr interrupts
- ; can be lost while processing rcvr ones. Small benefits are no stalled
- ; programs, no transmitter buffer, no problems at 19200 b/s. Joe Doupnik
-
- assume ds:nothing, es:nothing
-
- Show col_InOut,'O'
- sti ; enable interrupts
- cld
- mov al,FR_END ; Flush out any line garbage
- call send_char
- jc send_pkt_end ; c = failure to send
-
- ;Copy input to output, escaping special characters
- send_pkt_1:
- lodsb
- cmp al,FR_ESC ; escape FR_ESC with FR_ESC and T_FR_ESC
- jne send_pkt_2
-
- mov al,FR_ESC
- call send_char
- jc send_pkt_end
-
- mov al,T_FR_ESC
- jmp short send_pkt_3
-
- send_pkt_2:
- cmp al,FR_END ; escape FR_END with FR_ESC and T_FR_END
- jne send_pkt_3
-
- mov al,FR_ESC
- call send_char
- jc send_pkt_end
-
- mov al,T_FR_END
-
- send_pkt_3:
- call send_char
- jc send_pkt_end
-
- loop send_pkt_1 ; do cx user characters
-
- mov al,FR_END ; terminate it with a FR_END
- call send_char
- jc send_pkt_end
-
- clc
-
- send_pkt_end:
- Show col_InOut,' '
- ret
-
-
-
- ;----------------------------------------------------------------------------
- ;----------------------------------------------------------------------------
- ;----------------------------------------------------------------------------
-
- ;
- ; our serial driver
- ;
-
- MakePublic ser_funcs
-
-
- ser_DTR:
- mov al,MCR_RTS or MCR_OUT2
- or cx,cx
- jz no_DTR
-
- or al,MCR_DTR
-
- no_DTR: loadport
- setport MCR
- SlowOut
- jmp ser_ret
-
-
- MakeExternal int_dis:near,DOSPrint:near
-
- ser_setall:
- push ds
- push es
- push si
- call int_dis ; return old interrupt
- pop si
- pop ds ; source segment
- push cs
- pop es ; dest segment
- mov di,offset TheInfo ; dest offset
- mov cx,10 ; data length in words
- cld
- rep movsw
- pop ds
- call set_recv_isr
- call etopen ; reinitialize this new chip
- jmp ser_ret
-
-
- ser_info:
- cmp cx,24
- jl nov
-
- cld
- mov di,si
- mov ax,majver
- stosw
- mov ax,TheVersion
- stosw
- mov si,offset TheInfo
- mov cx,10 ; number of words
- rep movsw
-
- nov: jmp ser_ret
-
- ser_lines:
- loadport
- SetPort MSR
- SlowIn
- shr ax,4
- and ax,000Fh
- mov word ptr es:[si],ax
- jmp ser_ret
-
- ser_funcs:
- cmp al,1
- je ser_avail
-
- cmp al,2
- je send_raw
-
- cmp al,3
- je get_raw
-
- cmp al,4
- je ser_DTR
-
- cmp al,5
- je ser_setall
-
- cmp al,6
- je ser_info
-
- cmp al,7
- je ser_lines
-
-
- stc ; unknown function code
- jmp ser_x
-
- ser_ret:
- clc ; ok return code
-
- ser_x: ret
-
-
-
- ser_avail:
- call ser_av
- jmp ser_ret
-
- ser_av:
- call ser_av_reg
- mov es:[si],cx
- ret
-
- ser_av_reg:
- mov cx,recv_buf_tail
- sub cx,recv_buf_head
- jge ser_av_1 ; positive length
-
- add cx,recv_buf_size ; negative, add buf size
- ser_av_1:
- ret
-
-
- assume ds:code
-
-
- get_raw: ; read cx chars to es:di
- push cs
- pop ds ; ds now points to code seg
- mov dx,cx
- call ser_av_reg ; find amount available
- cmp dx,cx
- jle get_lok
-
- mov dx,cx ; trim request to avail
-
- get_lok:
- mov cx,dx ; requested length
- mov ax,cx
- cld
- stosw ; return cx to caller
- or cx,cx
- jle get_ex ; requested <= 0 !!
-
- mov si,recv_buf_head
-
- get_loop:
- lodsb ; get byte from buffer
- stosb ; store in user's buffer
- cmp si,recv_buf_end
- jb get_bot
-
- mov si,recv_buf ; back to top of buffer
-
- get_bot:
- loop get_loop
-
- mov recv_buf_head,si ; update head ptr
-
- get_ex:
- mov cx,dx ; return length read
- jmp ser_ret
-
- assume ds:nothing, es:nothing
-
- ;
- ; send_raw: send a stream of characters (no interpretation)
- ;
- ;
-
- send_raw: ; send cx chars from ds:si
- sti ; enable interrupts
- cld
- push es
- pop ds
- or cx,cx
- jle send_raw_end
-
-
- send_raw_1:
- lodsb
- call send_char
- jc send_raw_end
-
- loop send_raw_1 ; do cx user characters
-
- clc
-
- send_raw_end:
- jmp ser_ret ; done ok
-
-
-
- ;----------------------------------------------------------------------------
- ;----------------------------------------------------------------------------
- ;----------------------------------------------------------------------------
-
- ; mod 7/25/89 John Grover
- ; redone by Joe Doupnik, Dec 1991
- ;
- ;
- assume ds:nothing, es:nothing
- send_char: ; send the character in al
- ifdef grg
- push es
- push ax
- mov ax,0B800h
- mov es,ax
- inc byte ptr es:[col_chout]
- pop ax
- pop es
- endif
- push dx
- push cx
- xchg ah,al ; put data char into ah
- xor cx,cx ; 64K retry counter
- mov bl,hardware_switch ; Get hardware check (CTS) switch
-
- outc1: loadport
- SetPort LSR
- SlowIn
- test al,LSR_THRE ; Transmitter (THRE) ready?
- jnz outc2 ; nz = yes
-
- loop outc1
-
- stc ; carry set for failure
- jmp short outc3 ; timeout
-
- outc2: xor cx,cx ; reset retry counter
- or bl,bl ; Yes -- check CTS ready if needed.
- jz outc25 ; No check -- send the character.
-
- SetPort MSR
- SlowIn
- test al,MSR_CTS ; Is CTS ready?
- jz outc1 ; no, go check again
-
-
- outc25: xchg al,ah ; now send it
- mov dx,io_addr
- Delay
- SlowOut ; send the byte
- clc ; status of success
-
- outc3: pop cx
- pop dx
- ret
-
-
-
- MakePublic 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
- xor cx,cx
- clc
- ret
-
-
- MakePublic set_address
- set_address:
- ;set 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:nothing
- clc
- ret
-
-
- rcv_mode_3:
- ;receive mode 3 is the only one we support, so we don't have to do anything.
- ret
-
-
- MakePublic 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
-
-
- MakePublic get_multicast_list
- get_multicast_list:
- ;return with nc, es:di ->list of multicast addresses, cx = number of bytes.
- ;return cy, NO_ERROR if we don't remember all of the addresses ourselves.
- ;return cy, NO_MULTICAST if we don't implement multicast.
- mov dh,NO_MULTICAST
- stc
- ret
-
-
- MakePublic terminate
- terminate:
- ret
-
- MakePublic reset_interface
- reset_interface:
- ;reset the interface.
- assume ds:code
- 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.
- MakeExternal recv_find: near
-
- ;called after we have copied the packet into the buffer.
- ;enter with ds:si ->the packet, cx = length of the packet.
- MakeExternal recv_copy: near
-
- MakeExternal count_in_err: near
- MakeExternal count_out_err: near
-
- MakePublic recv
-
- ;
- ; mod 7/25/89 John Grover
- ;
- ;called from the recv isr. All registers have been saved, and ds=cs.
- ;Upon exit, the interrupt will be acknowledged.
-
- assume ds:code
-
- recv:
-
- rci_mo: loadport
- setport IIR
- SlowIn ; any interrupts at all?
- test al,IIR_IP
- jne rci_x ; no.
-
- and al,IIR_ID
- cmp al,IIR_RDA ; Receiver interrupt
- je ari
-
- rci_ni: cmp al,IIR_MSTAT
- jne rci_x
-
- setport MSR ; make sure of CTS status
- SlowIn
- ;;;; test al, MSR_CTS ; test removed?????
- jmp rci_mo
-
-
- rci_x: ret
-
-
- ;-------------------------------------------------------------------------
- ;Process 8250 receiver interrupts
- ;
- ; mod 7/25/89 John Grover
- ; - this branches off when bps < 9600. See ari_a.
- ; - Above 9600 bps we go into a loop to process a packet at
- ; - a time. If not data ready for a certain amount of time,
- ; - the process exits and waits for the next byte. This certain
- ; - amount of time to wait depends on the bps and CPU processor speed
- ; - and is determined in the initialization of the driver.
- ; - Upon receiving the FR_END character for the first frame in the
- ; - buffer a semaphore is set which tells rf to run.
-
- ari: mov bx,ds ; get set up for the routine
- mov es,bx
- mov bx,xmit_time ; is zero if no polling desired
-
- ari_a: mov di,recv_buf_tail
- xor bp,bp ; set flag to indicate 1st char processed
- mov si,Pak_Count ; optimization
- mov ah,LSR_DR
-
- ari_again:
- xor cx,cx ; initialize counter
- loadport
- setport LSR
-
- ari_in: SlowIn
- test al,LSR_OE
- jz noovr
-
- ShowInc col_ovrr,'O'
-
- noovr: test al,LSR_FE
- jz nofr
-
- ShowInc col_frame,'F'
-
- nofr: test al,ah
- jnz ari_gd ; yes - break out of loop
-
- inc cx ; no - increase loop counter
- cmp cx,bx ; timeout?
- jae ari_ex ; yes - leave
-
- jmp ari_in ; no - keep looping
-
- ;------ got data ready, read the char
-
- ari_gd: setport RBR
- SlowIn
-
- ; Process incoming data;
- ; If buffer is full, we have no choice but
- ; to drop the character
-
- cmp di,recv_buf_head
- jne ari_ok ; none - continue
-
- ShowInc col_serfull,'S' ; twiddle screen if buf full
-
- or si,si ; maybe - if there are packets
- jnz ari_ex ; yes exit
-
- ari_ok: stosb
- cmp di,recv_buf_end ; did we hit the end of the buffer?
- jne ari_3 ; no.
-
- mov di,recv_buf ; yes - wrap around.
-
- ari_3: cmp al,FR_END ; might this be the end of a frame?
- jne ari_reset ; no - reset flag and loop
-
- inc si ; yes - indicate packet ready
- or bp,bp ; was this the first char?
- jne ari_ex ; no - exit handler
-
- ari_reset:
- inc bp ; set 1st character flag
- jmp ari_again ; get another character
-
- ari_ex: mov recv_buf_tail,di
- mov Pak_Count, si
-
- mov bx,bp
- add bl,'0'
- Show col_serfull,bl ; show char gotten count
- jmp rci_x
-
-
- ; --------------------------------------------------------------
- ;
- ; recv_exiting
- ;
- MakePublic recv_exiting
- recv_exiting:
- cmp Pak_Count,0 ; is a packet ready?
- je recv_isr_exit ; no - skip to end
-
-
- push ax
- push bx
- push cx
- push dx
- push ds
- push es
- push bp
- push di
- push si
- push cs ; point ds properly
- pop ds
- sti ; enable interrupts
-
- call rf
-
- cli
- pop si
- pop di
- pop bp
- pop es
- pop ds
- pop dx
- pop cx
- pop bx
- pop ax
-
- recv_isr_exit:
- ret
-
-
- ; --------------------------------------------------------------
- ;
- ; rf
- ;
- ; mod 7/25/89 John Grover
- ;
- ; - rf now operates with interrupts on. It is triggered
- ; - by the Pak_Count flag and continues until all bytes
- ; - in all packets in the buffer have been transmitted to the upper
- ; - layer.
- ;
- ifdef debug
- MakePublic rf
- endif
-
- rf: cmp Pak_Count, 0 ; should we do this?
- jle rf_end ; no - exit
-
- rf_0: mov si,recv_buf_head ;process characters.
- xor cx,cx ;count up the size here.
- cld ; quite important
-
- rf_1: call recv_char ;get a char.
- je rf_2 ;go if no more chars.
-
- cmp al,FR_ESC ;an escape?
- je rf_1 ;yes - don't count this char.
-
- inc cx ;no - count this one.
- jmp rf_1
-
- rf_2: jcxz rf_3z ;count zero? yes - free the frame
-
- ;we don't need to set the type because none are defined for SLIP.
-
- push si ;save si in case we reject it.
- push bx
- MOV DI,CS
- MOV ES,DI
- mov di,0
- mov dl,cs:driver_class
- call recv_find ;look up our type.
- pop bx
- pop si
-
- mov ax,es ;is this pointer null?
- or ax,di
- je rf_3 ;yes - just free the frame.
-
- push cx
- push es ;remember where the buffer pointer is
- push di
-
- mov si,recv_buf_head ;process characters.
-
- rf_4: call recv_char
- je rf_6 ;yes - we're all done.
-
- cmp al,FR_ESC ;an escape?
- jne rf_5 ;no - just store it.
-
- call recv_char ;get the next character.
- je rf_6
-
- cmp al,T_FR_ESC
- mov al,FR_ESC ;assume T_FR_ESC
- je rf_5 ;yup, that's it - store FR_ESC
-
- mov al,FR_END ;nope, store FR_END
-
- rf_5: stosb ;store the byte.
- jmp rf_4
-
- rf_6: mov recv_buf_head,si ;we're skipped to the end.
- pop si ;now give the frame to the client.
- pop ds
- pop cx
- assume ds:nothing
- call recv_copy ; do the upcall to the tcp driver
- push cs
- pop ds
- assume ds:code
- jmp rf_end
-
- rf_3:
- ShowInc col_TCPFull,'T'
-
- rf_3z: mov recv_buf_head,si ;remember the new starting point.
-
- rf_end: dec Pak_Count
-
- cmp Pak_Count,0 ; are there more packets ready?
- jbe rf_9
-
- jmp rf_0 ; yes - execute again
-
- rf_9: ret
-
-
- ; --------------------------------------------------------------
- ;
- ; recv_char
- ;
- ; mod 7/25/89 John Grover
- ; - Now uses buffer pointers to determine if there are
- ; - characters left.
- ;
-
- recv_char:
- ;enter with si -> receive buffer, bx = receive count. Wrap around if needed.
- ;return with nz, al = next char. Return zr if there are no more chars in
- ; this frame.
- ;
- lodsb
- cmp si,recv_buf_end
- jb recv_char_1
-
- mov si,recv_buf
-
- recv_char_1:
- mov bx, recv_buf_tail
- cmp si, bx
- je recv_char_2
-
- cmp al,FR_END
-
- recv_char_2:
- ret
-
-
-
- set_baud:
- ;compute the divisor given the baud rate.
-
- mov dx,baudclk+2
- mov ax,baudclk
- mov bx,0
-
- sb_1: inc bx
- sub ax,baud_rate
- sbb dx,baud_rate+2
- jnc sb_1
-
- dec bx
- add ax,baud_rate
- adc dx,baud_rate+2
-
- sb_2: call flush_chars
- loadport ;Purge the receive data buffer
- mov ah,LCR_DLAB ;Turn on divisor latch access bit
- setport LCR
- call setbit
-
- mov al,bl ;Load the two bytes of the divisor.
- setport DLL
- SlowOut
- mov al,bh
- setport DLM
- SlowOut
-
- mov ah,LCR_DLAB ;Turn off divisor latch access bit
- setport LCR
- call clrbit
- ret
-
-
-
-
-
- flush_chars:
- loadport ;Purge the receive data buffer
- mov cx,1000 ;flush up to 1K chars
-
- flush_next:
- SlowIn
- test al,LSR_DR
- jz flush_done ; yes - break out of loop
-
- setport RBR
- SlowIn ; read and ignore the char
- loop flush_next
-
- flush_done:
- ret
-
-
-
- ; --------------------------------------------------------------
- ;
- ; etopen
- ;
- ; mod 7/25/89 John Grover
- ; - Contains a loop to determine a pseudo timeout for ari.
- ; - The value is determined by transmitting characters in a
- ; - loop whose clock cycles are nearly the same as the "sister"
- ; - loop in ari. The per character, maximum time used
- ; - basis which is then multiplied by a factor to achieve a timeout
- ; - value for the particular bps and CPU speed of the host.
-
- MakePublic etopen
- etopen:
- pushf
- cli
- ;
- ; mod 3/16/90 Denis DeLaRoca
- ; - determine if 16550 uart is present
- ; - if so initialize fifo buffering
- ;
- loadport
- setport FCR
- mov al,FIFO_ENABLE
- SlowOut ;outportb(base+FCR,(char) FIFO_ENABLE)
- setport IIR
- SlowIn ;inportb(base+IIR)
- and al,IIR_FIFO_ENABLED ; & IIR_FIFO_ENABLED
- cmp al,IIR_FIFO_ENABLED ;both bits must be on NEW, 11/20/90
- jnz not_16550 ;nope, we don't have 16550 chip
-
- mov is_16550,1 ;yes, note fact
- mov al,FIFO_SETUP ;and setup FIFO
- setport FCR
- SlowOut ;outportb(base+FCR,(char) FIFO_SETUP)
-
- not_16550:
- call flush_chars
-
- ;Set line control register: 8 bits, no parity
- loadport
- mov al,ser_misc
-
- setport LCR
- SlowOut
-
- ;Turn on receive interrupt enable in 8250, leave transmit
- ; and modem status interrupts turned off for now
- mov al,IER_DAV
- setport IER
- SlowOut
-
- ; Set modem control register: assert DTR, RTS, turn on 8250
- ; master interrupt enable (connected to OUT2)
-
- mov al,MCR_DTR or MCR_RTS or MCR_OUT2
- setport MCR
- SlowOut
-
- call set_baud
- call set_recv_isr ;Set interrupt vector to SIO handler
-
- ;set up the various pointers.
- mov dx,offset end_resident
-
- mov recv_buf,dx
- mov recv_buf_head,dx
- mov recv_buf_tail,dx
- add dx,recv_buf_size
- mov recv_buf_end,dx
-
- xor si,si
- cmp baud_rate,9600 ; below 19200 we're strictly
- jbe t_a ; interrupt driven
-
-
- ; the following code attempts to determine a pseudo timeout
- ; value to use in the loop that waits for an incoming character
- ; in ari. The value returned in xmit_time is the number of
- ; loops processed between characters - therefore the loop used below
- ; is and should remain similar to the loop used in ari.
-
- mov ah,LSR_THRE
- mov cx,16 ; take the highest of 16 runs
- xor si,si ; will hold highest value
-
- xmit_time_start:
- xor di,di ; initialize counter
- loadport
- setport THR ; xmit a character
- mov al,' ' ; send a space to minimize damage
- SlowOut
- setport LSR ; set up to check for an empty buffer
-
- ; next is the loop actually being timed
-
- mov bx,1 ; wait up to 65K times
-
- xmit_time_top:
- SlowIn
- test al,ah
- jnz xmit_time_done
-
- inc di
- cmp cx,cx ; these next few instructions do nothing
- jmp xmit_time_1 ; except maintain similarity with the
- ; "sister" loop in ari
- xmit_time_1:
- inc bx
- jmp xmit_time_top
-
- xmit_time_done: ; end of timed loop
-
- cmp si,di ; compare highest value with new value
- ja xmit_time_end ; no bigger - just loop
- mov si,di ; bigger - save it
-
- xmit_time_end:
- loop xmit_time_start ; bottom of outer loop
-
- call flush_chars ; throw away any echoed zeroes
-
- shl si,3 ; we'll wait 8 characters worth
-
- t_a: mov xmit_time,si ; retain largest value
- mov al, int_no ; Get board's interrupt vector
- add al, 8
- cmp al, 8+8 ; Is it a slave 8259 interrupt?
- jb set_int_num ; No.
-
- add al, 70h - 8 - 8 ; Map it to the real interrupt.
-
- set_int_num:
- xor ah, ah ; Clear high byte
- mov int_num, ax ; Set parameter_list int num.
-
- popf
- clc ;indicate no errors.
- ret
-
-
- ;Set bit(s) in I/O port
- setbit:
- ;enter with dx = port, ah = bit to set.
- SlowIn
- or al,ah
- SlowOut
- ret
-
-
- ;Clear bit(s) in I/O port
- clrbit:
- ;enter with dx = port, ah = bit to set.
- SlowIn
- not al ;perform an and-not using DeMorgan's.
- or al,ah
- not al
- SlowOut
- ret
-
- is_nochip_msg: db 'Serial Port is not there??',CR,LF,'$'
-
-
- ;**************************************************************************
- ;**************************************************************************
- ;**************************************************************************
- ;any code after this will not be kept after initialization.
-
- end_resident label byte
-
- ;**************************************************************************
- ;**************************************************************************
- ;**************************************************************************
-
- MakePublic usage_msg
- usage_msg db "usage: UMSLIP [?] [-n] [-w] [-s] [packet_int_no]"
- db " [recv_buf_size]",CR,LF,'$'
-
- MakePublic copyright_msg
- copyright_msg db "Packet driver for SLIP, version ",'0'+majver mod 10
- db ".",'0'+TheVersion mod 10,CR,LF
- db "Portions Copyright 1988 Phil Karn,"
- db " 1991 Joe Doupnik,",CR,LF
- db "Portions Copyright 1993 Univ. of Minnesota",cr,lf,'$'
-
-
- MakeExternal set_recv_isr: near
-
- ;enter with si -> argument string, di -> word to store.
- ;if there is no number, don't change the number.
- MakeExternal get_number: near
-
- ;enter with dx -> name of word, di -> dword to print.
- MakeExternal print_number: near
- MakeExternal print_number_dec: near
- MakeExternal print_number_hex: near
- MakeExternal print_crlf: near
-
- ;enter with si -> argument string.
- ;skip spaces and tabs. Exit with si -> first non-blank char.
- MakeExternal skip_blanks: near
-
-
- MakePublic parse_args
-
- parse_args:
- mov di,offset recv_buf_size
- call get_number
- clc
- ret
-
-
- code ends
-
- ; PC/FTP Packet Driver source, conforming to version 1.05 of the spec
- ; Updated to version 1.08 Feb. 17, 1989.
- ; Copyright 1988-1992 Russell Nelson
-
- ; This program is free software; you can redistribute it and/or modify
- ; it under the terms of the GNU General MakePublic 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 MakePublic License for more details.
- ;
- ; You should have received a copy of the GNU General MakePublic License
- ; along with this program; if not, write to the Free Software
- ; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- code segment word
- assume cs:code, ds:code
-
- MakeExternal phd_dioa: byte
- MakeExternal phd_environ: word
- MakeExternal flagbyte: byte,quiet:byte,end_resident:near,recv_buf_size:word
-
- ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
-
- MakePublic print_number_hex
- print_number_hex:
- Print
- mov al,'0'
- call chrout
- mov al,'x'
- call chrout
- mov ax,[di] ;print the number in hex.
- mov dx,[di+2]
- call dwordout
- ret
-
-
-
- MakePublic print_number_dec
-
- print_number_dec:
- or dx,dx
- je NoTxt
-
- Print
-
- NoTxt: mov ax,[di] ;print the number in decimal.
- mov dx,[di+2]
- call decout
- ret
-
- MakePublic print_crlf
- print_crlf:
- mov al,CR
- call chrout
- mov al,LF
- call chrout
- ret
-
-
- MakePublic print_number
- print_number:
- ;enter with dx -> dollar terminated name of number, di ->dword.
- ;exit with the number printed and the cursor advanced to the next line.
-
- call print_number_hex
- mov al,' '
- call chrout
- mov al,'('
- call chrout
- mov dx,0
- call print_number_dec
- mov al,')'
- call chrout
- call print_crlf
- ret
-
-
- ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
-
- MakePublic decout
- decout:
- mov si,ax ;get the number where we want it.
- mov di,dx
- or ax,dx ;is the number zero?
- jne decout_nonzero
- mov al,'0' ;yes - easier to just print it, than
- jmp chrout ; to eliminate all but the last zero.
- decout_nonzero:
-
- xor ax,ax ;start with all zeroes in al,bx,bp
- mov bx,ax
- mov bp,ax
-
- mov cx,32 ;32 bits in two 16 bit registers.
- decout_1:
- shl si,1
- rcl di,1
- xchg bp,ax
- call addbit
- xchg bp,ax
- xchg bx,ax
- call addbit
- xchg bx,ax
- adc al,al
- daa
- loop decout_1
-
- mov cl,'0' ;prepare to eliminate leading zeroes.
- call byteout ;output the first two.
- mov ax,bx ;output the next four
- call wordout ;output the next four
- mov ax,bp
- jmp wordout
-
- addbit: adc al,al
- daa
- xchg al,ah
- adc al,al
- daa
- xchg al,ah
- ret
-
- ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
-
- MakePublic dwordout, wordout, byteout, digout
- dwordout:
- mov cl,'0' ;prepare to eliminate leading zeroes.
- xchg ax,dx ;just output 32 bits in hex.
- call wordout ;output dx.
- xchg ax,dx
- wordout:
- push ax
- mov al,ah
- call byteout
- pop ax
- byteout:
- mov ah,al
- shr al,1
- shr al,1
- shr al,1
- shr al,1
- call digout
- mov al,ah
-
- digout:
- and al,0fh
- add al,90h ;binary digit to ascii hex digit.
- daa
- adc al,40h
- daa
- cmp al,cl ;leading zero?
- je digout_1
- mov cl,-1 ;no more leading zeros.
- jmp chrout
-
- digout_1:
- ret
- ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
-
- MakePublic chrout
- chrout:
- push ax ;print the char in al.
- push dx
- mov dl,al
- test quiet,1
- jnz nochout
-
- mov ah,2
- int 21h
-
- nochout:
- pop dx
- pop ax
- ret
-
-
- ;*************************************************************************
-
- ;usage_msg is of the form "usage: driver [-d -n] <packet_int_no> <args>"
- MakeExternal usage_msg: byte
-
- ;copyright_msg is of the form:
- ;"Packet driver for the foobar",CR,LF
- ;"Portions Copyright 19xx, J. Random Hacker".
- MakeExternal copyright_msg: byte
-
- copyleft_msg label byte
- db "Packet driver skeleton copyright 1988-92, Crynwr Software.",CR,LF
- db "This program is free software; see the file COPYING for details.",CR,LF
- db "NO WARRANTY; see the file COPYING for details."
- crlf_msg db CR,LF,'$'
-
- no_resident_msg label byte
- db CR,LF,"*** Packet driver failed to initialize the board ***",CR,LF,'$'
-
- ;parse_args should parse the arguments.
- ;called with ds:si -> immediately after the packet_int_no.
- MakeExternal parse_args: near
-
- ;print_parameters should print the arguments.
- MakeExternal print_parameters: near
-
- MakeExternal our_isr: near, their_isr: dword
- MakeExternal ser_their_isr: dword
- MakeExternal packet_int_no: byte
- MakeExternal is_at: byte, sys_features: byte
- MakeExternal int_no: byte
- MakeExternal driver_class: byte
-
-
- packet_int_no_name db "Packet interrupt number ",'$'
- eaddr_msg db "My Ethernet address is ",'$'
- aaddr_msg db "My ARCnet address is ",'$'
-
- already_msg db CR,LF,"There is already a packet driver at ",'$'
- int_msg db CR,LF
- db "Error: <int_no> should be between 0 and "
- int_msg_num label word
- db "15 inclusive", '$'
-
- our_address db EADDR_LEN dup(?)
- MakePublic etopen_diagn
- etopen_diagn db 0 ; errorlevel from etopen if set
-
- ;etopen should initialize the device. If it needs to give an error, it
- ;can issue the error message and quit to dos.
- MakeExternal etopen: near
-
- ;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.
- MakeExternal get_address: near
-
- already_error:
- mov quiet,0
- mov dx,offset already_msg
- mov di,offset packet_int_no
- call print_number
- mov ax,4c05h ; give errorlevel 5
- int 21h
-
- usage_error:
- mov dx,offset usage_msg
-
- MakePublic error
- error:
- mov quiet,0
- Print
- mov ax,4c0ah ; give errorlevel 10
- int 21h
-
- MakePublic start_1
- start_1:
- cld
-
- ;
- ; Get the feature byte (if reliable) so we can know if it is a microchannel
- ; computer and how many interrupts there are.
- ;
- mov ah,0c0h
- int 15h ; es:bx <- sys features block
- jc look_in_ROM ; error, must use rom.
- or ah,ah
- jnz look_in_ROM
- mov dx,es:[bx] ; # of feature bytes
- cmp dx,4 ; do we have the feature byte we want?
- jae got_features ;yes.
- look_in_ROM:
- mov dx,0f000h ;ROM segment
- mov es,dx
- cmp byte ptr es:[0fffeh],0fch;is this an AT?
- jne identified ;no.
- or sys_features,TWO_8259 ; ATs have 2nd 8259
- jmp identified ; assume no microchannel
- got_features:
- mov ah,es:[bx+2] ; model byte
- cmp ah,0fch
- je at_ps2
- ja identified ; FD, FE and FF are not ATs
- cmp ah,0f8h
- je at_ps2
- ja identified ; F9, FA and FB are not ATs
- cmp ah,09ah
- jbe identified ; old non-AT Compacs go here
-
- at_ps2: ; 9B - F8 and FC are assumed to
- mov ah,es:[bx+5] ; have reliable feature byte
- mov sys_features,ah
-
- identified:
- mov si,offset phd_dioa+1
- call skip_blanks ;end of line?
- cmp al,CR
- je nopknum ; yes, assume 0x60
-
- chk_options:
- call skip_blanks
- cmp al,'-' ; any options?
- jne no_more_opt
-
- inc si ; skip past option char
- lodsb ; read next char
- or al,20h ; convert to lower case
- cmp al,'n'
- jne not_n_opt
- or flagbyte,N_OPTION
- jmp chk_options
-
- not_n_opt:
- cmp al,'w'
- jne not_w_opt
-
- or flagbyte,W_OPTION
- jmp chk_options
-
- not_w_opt:
- cmp al,'s'
- jne usage_error_j_1
-
- mov quiet,1
- jmp chk_options
-
-
- usage_error_j_1:
- jmp usage_error
-
-
- no_more_opt:
- cmp al,'?'
- je usage_error_j_1
-
- mov di,offset packet_int_no ;parse the packet interrupt number
- mov bx,offset packet_int_no_name
- call get_number ; for them.
-
- call parse_args
- jc usage_error_j_1
-
- call skip_blanks ;end of line?
- cmp al,CR
- jne usage_error_j_1
-
- nopknum:
- call verify_packet_int
- jnc packet_int_ok
- jmp error
-
- packet_int_ok:
- jne packet_int_unused
- jmp already_error ;give an error if there's one there.
- packet_int_unused:
-
- ;
- ; Verify that the interrupt number they gave is valid.
- ;
- cmp int_no,15 ;can't possibly be > 15.
- ja int_bad
- test sys_features,TWO_8259 ; 2nd 8259 ?
- jnz int_ok ;yes, no need to check for <= 7.
- mov int_msg_num,'7'+' '*256 ;correct the error message, just in case.
- cmp int_no,7 ;make sure that the packet interrupt
- jbe int_ok ; number is in range.
- int_bad:
- mov dx,offset int_msg
- jmp error
- int_ok:
-
- ;
- ; Map IRQ 2 to IRQ 9 if needed.
- ;
- test sys_features,TWO_8259 ; 2nd 8259 ?
- je no_mapping_needed ;no, no mapping needed
- cmp int_no,2 ;map IRQ 2 to IRQ 9.
- jne no_mapping_needed
- mov int_no,9
-
- no_mapping_needed:
-
- mov dx,offset copyright_msg
- Print
- mov dx,offset copyleft_msg
- Print
-
- call take_packet_int
-
- mov ah,49h ;free our environment, because
- mov es,phd_environ ; we won't need it.
- int 21h
-
- mov bx,1 ;get the stdout handle.
- mov ah,3eh ;close it in case they redirected it.
- int 21h
-
- mov dx,offset end_resident
- add dx,recv_buf_size
- add dx,0fh ;round up to next highest paragraph.
- mov cl,4
- shr dx,cl
- mov ah,31h ;terminate, stay resident.
- mov al,etopen_diagn ; errorlevel (0 - 9, just diagnostics)
- int 21h
-
-
-
-
- no_resident:
- mov dx,offset no_resident_msg
- Print
-
- mov ax,4c00h + 32 ; give errorlevel 32
- cmp al,etopen_diagn
- ja no_et_diagn ; etopen gave specific reason?
- mov al,etopen_diagn ; yes, use that for error level
- no_et_diagn:
- int 21h
-
- ; Suggested errorlevels:
- ;
- ; _____________________ 0 = normal
- ; 1 = unsuitable memory address given; corrected
- ; In most cases every- 2 = unsuitable IRQ level given; corrected
- ; thing should work as 3 = unsuitable DMA channel given; corrected
- ; expected for lev 1-5 4 = unsuitable IO addr given; corrected (only 1 card)
- ; _____________________ 5 = packet driver for this int # already loaded
- ; External errors, when 20 = general cable failure (but pkt driver is loaded)
- ; corrected normal 21 = network cable is open -"-
- ; operation starts 22 = network cable is shorted -"-
- ; _____________________ 23 =
- ; Packet driver not 30 = usage message
- ; loaded. A new load 31 = arguments out of range
- ; attempt must be done 32 = unspecified device initialization error
- ; 33 =
- ; 34 = suggested memory already occupied
- ; 35 = suggested IRQ already occupied
- ; 36 = suggested DMA channel already occupied
- ; 37 = could not find the network card at this IO address
-
-
- take_packet_int:
- mov ah,35h ;remember their packet interrupt.
- mov al,packet_int_no
- int 21h
- mov their_isr.offs,bx
- mov their_isr.segm,es
-
- mov ah,25h ;install our packet interrupt
- mov dx,offset our_isr
- int 21h
-
- ret
-
-
- MakePublic DOSPrint
-
- DOSPrint:
- test quiet,1
- jnz NoPrint
-
- mov ah,9
- int 21h
-
- NoPrint:
- ret
-
-
- signature db 'PKT DRVR',0
- signature_len equ $-signature
-
- packet_int_msg db CR,LF
- db "Error: <packet_int_no> should be in the range 0x60 to 0x80"
- db '$'
-
- verify_packet_int:
- ;enter with no special registers.
- ;exit with cy,dx-> error message if the packet int was bad,
- ; or nc,zr,es:bx -> current interrupt if there is a packet driver there.
- ; or nc,nz,es:bx -> current interrupt if there is no packet driver there.
- cmp packet_int_no,60h ;make sure that the packet interrupt
- jb verify_packet_int_bad ; number is in range.
- cmp packet_int_no,80h
- jbe verify_packet_int_ok
- verify_packet_int_bad:
- mov dx,offset packet_int_msg
- stc
- ret
- verify_packet_int_ok:
-
- mov ah,35h ;get their packet interrupt.
- mov al,packet_int_no
- int 21h
-
- lea di,3[bx] ;see if there is already a signature
- mov si,offset signature ; there.
- mov cx,signature_len
- repe cmpsb
- clc
- ret
- ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
-
- MakePublic get_number
- get_number:
- mov bp,10 ;we default to 10.
- jmp short get_number_0
-
- MakePublic get_hex
- get_hex:
- mov bp,16
- ;get a hex number, skipping leading blanks.
- ;enter with si->string of digits,
- ; di -> dword to store the number in. [di] is not modified if no
- ; digits are given, so it acts as the default.
- ;return cy if there are no digits at all.
- ;return nc, bx:cx = number, and store bx:cx at [di].
- get_number_0:
- call skip_blanks
- call get_digit ;is there really a number here?
- jc get_number_3
-
- xor ah,ah
- cmp ax,bp ;larger than our base?
- jae get_number_3 ;yes.
-
- or al,al ;Does the number begin with zero?
- jne get_number_4 ;no.
- mov bp,8 ;yes - they want octal.
- get_number_4:
-
- xor cx,cx ;get a hex number.
- xor bx,bx
- get_number_1:
- lodsb
- cmp al,'x' ;did they really want hex?
- je get_number_5 ;yes.
- cmp al,'X' ;did they really want hex?
- je get_number_5 ;yes.
- call get_digit ;convert a character into an int.
- jc get_number_2 ;not a digit (neither hex nor dec).
- xor ah,ah
- cmp ax,bp ;larger than our base?
- jae get_number_2 ;yes.
-
- push ax ;save the new digit.
-
- mov ax,bp ;multiply the low word by ten.
- mul cx
- mov cx,ax ;keep the low word.
- push dx ;save the high word for later.
- mov ax,bp
- mul bx
- mov bx,ax ;we keep only the low word (which is our high word)
- pop dx
- add bx,dx ;add the high result from earlier.
-
- pop ax ;get the new digit back.
- add cx,ax ;add the new digit in.
- adc bx,0
- jmp get_number_1
-
- get_number_5:
- mov bp,16 ;change the base to hex.
- jmp get_number_1
-
- get_number_2:
- dec si
- mov [di],cx ;store the parsed number.
- mov [di+2],bx
- clc
- jmp short get_number_6
-
- get_number_3:
- cmp al,'?' ;did they ask for the default?
- stc
- jne get_number_6 ;no, return cy.
-
- add si,1 ;skip past the question mark.
- clc
-
- get_number_6:
- ret
-
-
- ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
-
- MakePublic get_digit
- get_digit:
- ;enter with al = character
- ;return nc, al=digit, or cy if not a digit.
- cmp al,'0' ;decimal digit?
- jb get_digit_1 ;no.
- cmp al,'9' ;. .?
- ja get_digit_2 ;no.
- sub al,'0'
- clc
- ret
- get_digit_2:
- cmp al,'a' ;hex digit?
- jb get_digit_3
- cmp al,'f' ;hex digit?
- ja get_digit_3
- sub al,'a'-10
- clc
- ret
- get_digit_3:
- cmp al,'A' ;hex digit?
- jb get_digit_1
- cmp al,'F' ;hex digit?
- ja get_digit_1
- sub al,'A'-10
- clc
- ret
- get_digit_1:
- stc
- ret
-
-
- ;put into the MakePublic domain by Russell Nelson, nelson@crynwr.com
-
- MakePublic skip_blanks
- skip_blanks:
- lodsb ;skip blanks.
- cmp al,' '
- je skip_blanks
- cmp al,HT
- je skip_blanks
- dec si
- ret
-
-
-
- MakePublic print_ether_addr
-
-
- print_ether_addr:
- mov cx,EADDR_LEN
-
- print_ether_addr_0:
- push cx
- lodsb
- mov cl,' ' ;Don't eliminate leading zeroes.
- call byteout
- pop cx
- cmp cx,1
- je print_ether_addr_1
-
- mov al,':'
- call chrout
-
- print_ether_addr_1:
- loop print_ether_addr_0
- ret
-
- code ends
-
- end start
-