PAGE	56,132
;
;	ASYNC PORT DRIVER FOR KISS OR NETROM LINKS
;
;	USES WIN32 COMn DRIVER
;
;
;	Feb 2007 Fix ACKMODE processing

.386
;
;  SEGMENT definitions and order
;


;*	32 Bit code
_TEXT		SEGMENT DWORD USE32 PUBLIC 'CODE'
_TEXT		ENDS


;*	Contains 32 Bit data
_BPQDATA		SEGMENT DWORD PUBLIC 'DATA'
_BPQDATA		ENDS



	ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT

OFFSET32 EQU <OFFSET FLAT:>

_BPQDATA	SEGMENT

TICKS	EQU	10				; TICKS PER SECOND

SETARVEC MACRO	A			; MACRO TO CHANGE THE  RX INT VECTOR
	MOV	IORXCA[EBX],OFFSET32 A
	ENDM
SETATVEC MACRO	A			; MACRO TO CHANGE THE  TX INT VECTOR
	MOV	IOTXCA[EBX],OFFSET32 A
	ENDM
;
;DELAY	MACRO
;	JMP	$+2
;	JMP	$+2
;	JMP	$+2
;	JMP	$+2
;	ENDM

FEND	EQU	0C0H	; KISS CONTROL CODES 
FESC	EQU	0DBH
TFEND	EQU	0DCH
TFESC	EQU	0DDH

STX	EQU	2			; NETROM CONTROL CODES
ETX	EQU	3
DLE	EQU	10H

CTSBIT	EQU	10H			; BIT IN MSR

	INCLUDE	STRUCS.INC

KISSDATA	STRUC
		DB	HARDWAREDATA DUP (0)	; REMAP HARDWARE INFO

LINKSTS		DB	0		; CURRENT STATE
CURALP		DD	0		; CURRENT BUFFER
NEXTCHR		DD	0		
ASYNCMSG_Q	DD	0		; RECEIVED MESSAGES
KISSTX_Q	DD	0		; MESSAGES TO SEND
FRAMELEN	DW	0		; LENGTH OF CURRENT MSG
TXCHAR		DD	0		; POINTER TO NEXT BYTE TO SEND
TXTADDR		DD	0		; BASE ADDR OF FRAME BEING SENT
TXCOUNT		DW	0		; SEND FRAME LENGTH

IORXCA		DD	0
IORXEA		DD	0
IOTXCA		DD	0

ESCFLAG		DB	0		; SET IF LAST RX CHAR WAS DLE
ESCTXCHAR	DB	0		; CHAR TO SEND FOLLOWING DLE IF NZ

FIRSTPORT	DD	0		; FIRST PORT DEFINED FOR THIS IO ADDR
SUBCHAIN	DD	0		; NEXT SUBCHANNEL FOR SAME PHYSICAL PORT

OURCTRL		DB	0		; CONTROL BYTE FOR THIS PORT

TXCTRL		DB	0		; CONTROL BYTE TO SEND
REALKISSFLAGS	DB	0		; KISS FLAGS FOR ACTIVE SUBPORT

TXCCC		DB	0		; NETROM/BPQKISS CHECKSUMS
RXCCC		DB	0

TXACTIVE	DW	0		; TIMER TO DETECT 'HUNG' SENDS

POLLFLAG	DB	0		; POLL OUTSTANDING FOR MULTIKISS

POLLPOINTER	DD	0		; LAST GROUP POLLED
POLLED		DB	0		; SET WHEN POLL RECEIVED

WIN32INFO	DB	16 DUP (0);	FOR WINDOWS DRIVER

KISSDATA	ENDS

	IF	TYPE KISSDATA GT TYPE PORTCONTROL
	.ERR2	TOO MUCH PORT DATA
	ENDIF

	public	ENCBUFF

ENCBUFF		DB	600 DUP (0);
KISSPARAMS	DB	24 DUP (0);


CHECKSUM	EQU	1
POLLINGKISS	EQU	2		; KISSFLAGS BITS
ACKMODE		EQU	4		; CAN USE ACK REQURED FRAMES
POLLEDKISS	EQU	8		; OTHER END IS POLLING US
D700		EQU 16		; D700 Mode (Escape "C" chars
TNCX		EQU 32		; TNC-X Mode (Checksum of ACKMODE frames includes ACK bytes

	EXTRN	PORTTABLE:DWORD,LINKS:DWORD,NUMBEROFPORTS:WORD
;	EXTRN	INTERRUPTS:WORD,CHARS:WORD

	EXTRN	TRACE_Q:DWORD

PUBLIC _CRCTAB

_CRCTAB	DW	0,1189H,2312H,329BH,4624H
	DW	57ADH,6536H,74BFH,8C48H,9DC1H
	DW	0AF5AH,0BED3H,0CA6CH,0DBE5H,0E97EH	
	DW	0F8F7H,1081H,0108H,3393H,221AH
	DW	56A5H,472CH,75B7H,643EH,9CC9H	
	DW	8D40H,0BFDBH,0AE52H,0DAEDH,0CB64H
	DW	0F9FFH,0E876H,2102H,308BH,210H	
	DW	1399H,6726H,76AFH,4434H,55BDH	
	DW	0AD4AH,0BCC3H,8E58H,9FD1H,0EB6EH	
	DW	0FAE7H,0C87CH,0D9F5H,3183H,200AH	
	DW	1291H,318H,77A7H,662EH,54B5H
	DW	453CH,0BDCBH,0AC42H,9ED9H,8F50H
	DW	0FBEFH,0EA66H,0D8FDH,0C974H,4204H	
	DW	538DH,6116H,709FH,420H,15A9H
	DW	2732H,36BBH,0CE4CH,0DFC5H,0ED5EH	
	DW	0FCD7H,8868H
	DW	99E1H,0AB7AH,0BAF3H,5285H,430CH	
	DW	7197H,601EH,14A1H,528H,37B3H
	DW	263AH,0DECDH,0CF44H,0FDDFH,0EC56H	
	DW	98E9H,8960H,0BBFBH,0AA72H,6306H
	DW	728FH,4014H,519DH,2522H,34ABH
	DW	630H,17B9H,0EF4EH,0FEC7H,0CC5CH
	DW	0DDD5H,0A96AH,0B8E3H,8A78H,9BF1H	
	DW	7387H,620EH,5095H,411CH,35A3H	
	DW	242AH,16B1H,738H,0FFCFH,0EE46H	
	DW	0DCDDH,0CD54H,0B9EBH,0A862H,9AF9H	
	DW	8B70H,8408H,9581H,0A71AH,0B693H	
	DW	0C22CH,0D3A5H,0E13EH,0F0B7H,840H	
	DW	19C9H,2B52H,3ADBH,4E64H,5FEDH	
	DW	6D76H,7CFFH,9489H,8500H,0B79BH	
	DW	0A612H,0D2ADH,0C324H,0F1BFH,0E036H	
	DW	18C1H,948H,3BD3H,2A5AH,5EE5H	
	DW	4F6CH,7DF7H,6C7EH,0A50AH,0B483H	
	DW	8618H,9791H,0E32EH,0F2A7H,0C03CH	
	DW	0D1B5H,2942H,38CBH,0A50H,1BD9H	
	DW	6F66H,7EEFH,4C74H,5DFDH,0B58BH	
	DW	0A402H,9699H,8710H,0F3AFH,0E226H	
	DW	0D0BDH,0C134H,39C3H,284AH,1AD1H	
	DW	0B58H,7FE7H,6E6EH,5CF5H,4D7CH
	DW	0C60CH,0D785H,0E51EH,0F497H,8028H	
	DW	91A1H,0A33AH,0B2B3H,4A44H,5BCDH	
	DW	6956H,78DFH,0C60H,1DE9H,2F72H	
	DW	3EFBH,0D68DH,0C704H,0F59FH,0E416H	
	DW	90A9H,8120H,0B3BBH,0A232H,5AC5H	
	DW	4B4CH,79D7H,685EH,1CE1H,0D68H	
	DW	3FF3H,2E7AH,0E70EH,0F687H,0C41CH	
	DW	0D595H,0A12AH,0B0A3H,8238H,93B1H	
	DW	6B46H,7ACFH,4854H,59DDH,2D62H	
	DW	03CEBH,0E70H,1FF9H,0F78FH,0E606H	
	DW	0D49DH,0C514H,0B1ABH,0A022H,92B9H	
	DW	8330H,7BC7H,6A4EH,58D5H,495CH	
	DW	3DE3H,2C6AH,1EF1H,0F78H		


_BPQDATA	ENDS

_TEXT	SEGMENT

;
	EXTRN	NEEDKISS:BYTE
	extrn	_time:near

	EXTRN	_ASYINIT:NEAR,_ASYDISP:NEAR,_ASYSEND:NEAR,_POLLKISS:NEAR

	PUBLIC	KISSINIT
	
KISSINIT:				; INTERRUPT INITIALISATION CODE

	MOV	PORTINTERLOCK[EBX],0	; CANT USE INTERLOCK ON KISS

	MOV	NEEDKISS,1		; NEED TO KEEP KISS CODE

	CALL	CHECKIOADDR		; SEE IF ANOTHER ENTRY FOR THIS ADDR
	MOV	FIRSTPORT[EBX],EBX	; MAY BE CHANGED IN ANOTHER CHANNEL USED
;
	MOV	AL,CHANNELNUM[EBX]
	SUB	AL,'A'
	MOV	CL,4
	SAL	AL,CL			; TO UPPER NIBBLE

	MOV	OURCTRL[EBX],AL		; KISS CONTROL

	CMP	EDI,0			; FIRST ENTRY FOR THIS ADDRESS
	JE SHORT INITCOM			; NO OTHER CHANNEL TO LINK
;
;	THIS IS NOT THE FIRST PORT ON THIS I/O ADDR - WE MUST BE USING
;	AN ADDRESSABLE PROTOCOL - IE KISS AS DEFINED FOR KPC4 ETC
;
 	MOV	FIRSTPORT[EBX],EDI	; QUEUE TX FRAMES ON FIRST
;
;	SET UP SUBCHANNEL CHAIN - ALL PORTS FOR THIS IO ADDR ARE CHAINED
;
SUBLOOP:

	CMP	SUBCHAIN[EDI],0
	JE SHORT ENDOFCHAIN

	MOV	EDI,SUBCHAIN[EDI]		; FOLLOW CHAIN
	JMP SHORT SUBLOOP

ENDOFCHAIN:

	MOV	SUBCHAIN[EDI],EBX		; PUT OURS ON END

	CALL	INITCOMMON	
	
;	Display to Console
	
	PUSH	EBX					; Port Control Record

	CALL	_ASYDISP

	ADD		ESP,4
	RET
	
	RET				; INT ALREADY HOOKED

INITCOM:
;
;	FIRST PORT USING THIS IO ADDRESS
;
	MOV	POLLPOINTER[EBX],EBX	; SET FIRST PORT TO POLL

	CALL	INITCOMMON		; SET UP THE PORT

;	ATTACH WIN32 ASYNC DRIVER
;
	MOVZX	EAX,CHANNELNUM[EBX]
	PUSH	EAX
	
	LEA		EAX,IORXCA[EBX]
	PUSH	EAX						; Char Handler

	PUSH	EBX						; Vector

	MOVZX	EAX,BAUDRATE[EBX]
	PUSH	EAX						; SPEED

	MOVZX	EAX,IOBASE[EBX]
	PUSH	EAX						; Port No

	CALL	_ASYINIT

	ADD		ESP,20
	RET

CHECKIOADDR:
;
;	SEE IF ANOTHER PORT IS ALREADY DEFINED ON THIS CARD
;
	MOV	EDI,PORTTABLE
	MOV	CX,NUMBEROFPORTS
INIT100:
	CMP	EDI,EBX
	JE SHORT INIT110			; NONE BEFORE OURS
	
	CMP	PORTTYPE[EDI],10H		; EXTERNAL?
	JE @F						; YES, SO IGNORE

	MOV	AX,IOBASE[EBX]
	CMP	AX,IOBASE[EDI]
	JE SHORT INIT120			; ANOTHER FOR SAME ADDRESS
@@:
	MOV	EDI,PORTPOINTER[EDI]

	LOOP	INIT100
INIT110:
	MOV	EDI,0			; FLAG NOT FOUND
INIT120:
	RET

INITCOMMON:

	CMP	PROTOCOL[EBX],2		; NETROM?
	JNE SHORT NEEDRTS
;
;	NETROM - CLEAR KISS OPTIONS, JUST IN CASE!
;
	MOV	KISSFLAGS[EBX],0

;	CMP	FULLDUPLEX[EBX],1	; NETROM DROPS RTS TO INHIBIT!	
;	JE SHORT NEEDRTS
;
;	MOV	AL,9			; OUT2 DTR
;
NEEDRTS:

	SETARVEC RXASTX			; INITIAL INTERRUPT ENTRY
	SETATVEC IGNORE

;	IF KISS, SET TIMER TO SEND KISS PARAMS
;
	CMP	PROTOCOL[EBX],2		; NETROM?
	JE SHORT NOPARAMS

	MOV	PARAMTIMER[EBX],TICKS*30	; 30 SECS FOR TESTING

NOPARAMS:

	RET
;

	PUBLIC	KISSTX,KISSRX,KISSTIMER
;
	EXTRN	_Q_ADD:NEAR,Q_REM:NEAR,RELBUFF:NEAR,GETBUFF:NEAR

KISSRX:
;
;	Poll Async Driver
;
	pushad

	MOVZX	EAX,IOBASE[EBX]
	PUSH	EBX						; Port Vector

	CALL	_POLLKISS

	ADD		ESP,4

	popad

	CMP	POLLED[EBX],1		; ZERO = NOT POLLED, 1 = POLL RECOGNISED
	JBE SHORT NOPOLL
;
;	POLL OR POLL RESPONSE HAS BEEN RECEIVED
;
	TEST	KISSFLAGS[EBX],POLLINGKISS
	JZ SHORT POLLRXED
;
;	POLL RESPONSE RECEIVED - CLEAR POLL OUTSTANDING
;
	MOV	POLLED[EBX],0
	MOV	POLLFLAG[EBX],0		; CLEAR POLL OUTSTANDING
	JMP SHORT NOPOLL		; SEE IF ANYTHING ELSE

POLLRXED:
;
;	WE ARE A SLAVE, AND THIS IS A POLL. SEE IF FOR US, AND IF SO, REPLY
;

	MOV	AL,POLLED[EBX]
	MOV	POLLED[EBX],0

	AND	AL,0F0H			; PORT
	
PFINDLOOP:

	CMP	OURCTRL[EBX],AL
	JE SHORT OURPOLL

	MOV	EBX,SUBCHAIN[EBX]
	OR	EBX,EBX
	JZ SHORT NOPOLL		; NOT FOR US

	JMP	PFINDLOOP

OURPOLL:
;
;	SEE IF ANYTHING QUEUED
;
	CMP	KISSTX_Q[EBX],0
	JE SHORT SENDACK
;
	MOV	POLLED[EBX],1		; LET TIMER DO THE SEND
	JMP	NOPOLL

SENDACK:

	MOV	ESI,EBX
	CALL	SENDPOLL		; OTHER END DOESNT CARE ABOUT ADDR

NOPOLL:

	LEA	ESI,ASYNCMSG_Q[EBX]
	CALL	Q_REM
	
	JNZ SHORT GOTAFRAME

	RET				; NOTHING RECEIVED

GOTAFRAME:
;
;	IF NETROM, CAN PASS ON NOW
;
	CMP	PROTOCOL[EBX],2
	JE SHORT FOUNDIT			; NETROM PROTOCOL
;
;	MESSAGE MAY BE DATA OR DATA ACK. IT HAS NOT YET BEEN CHECKSUMMED
;
	MOV	AL,MSGPORT[EDI]
	TEST	AL,0FH
	JZ SHORT CHECK_CHECKSUM		; NORMAL DATA
;
;	SPECIAL FRAME - IS IT AN ACK?
;
	AND	AL,0FH
	CMP	AL,0CH			; ACK
	JE SHORT ACKFRAME

	JMP	NOTFOUND		; DONT RECOGNISE TYPE

ACKFRAME:
;
;	ACK FRAME. WE DONT SUPPORT ACK REQUIRED FRAMES AS A SLAVE - THEY ARE
;	ONLY ACCEPTED BY TNCS
;
	TEST	KISSFLAGS[EBX],POLLEDKISS
	JNZ SHORT ACKREQFRAME		; FRAME REQUIRING AN ACK
;
;	THIS IS AN ACK OF A DATA FRAME
;
	MOVZX	EBX,BYTE PTR 7[EDI]
	MOV	BH,8[EDI]
	ADD	EBX,LINKS

	CMP	L2TIMER[EBX],0
	JE SHORT NOTIMER			; ALREADY EXPIRED

	MOV	AL,L2TIME[EBX]
	XOR	AH,AH
	MOV	L2TIMER[EBX],AX

NOTIMER:

	JMP SHORT NOTFOUND		; RETURN IT


ACKREQFRAME:
;
;	NOT ALLOWED - DISCARD
;
	JMP	DISCARDFRAME

CHECK_CHECKSUM:

	MOVZX	ECX,WORD PTR 5[EDI]		; LENGTH, INCLUDING SUM
	CMP	ECX,13H
	JB SHORT DISCARDFRAME		; TOO SHORT FOR VALID AX25

	TEST	KISSFLAGS[EBX],CHECKSUM
	JZ SHORT KISSRX00
;
;	SUM MESSAGE, AND IF DUFF DISCARD. IF OK DECREMENT COUNT TO REMOVE SUM
;
	DEC	WORD PTR 5[EDI]
;
	MOV	AH,MSGPORT[EDI]		; IS INCLUDED IN SUM

	LEA	ESI,7[EDI]		; TO DATA
	SUB	ECX,7
	jz	@F

SUMLOOP:

	LODSB
	XOR	AH,AL

	LOOP	SUMLOOP

	OR	AH,AH
	JZ SHORT KISSRX00			; SUM OK
@@:
	ADD	RXERRORS[EBX],1

	JMP SHORT DISCARDFRAME

FOUNDIT:

	LEA	ESI,PORTRX_Q[EBX]
	CALL	_Q_ADD			; PUT ON PORT RX QUEUE

	RET


KISSRX00:
;
;	AT THIS STAGE, KISS CONTROL BYTE IS IN PORT FIELD - FIND CORRECT
;	SUBPORT RECORD TO ADD IT TO
;
	MOV	AL,MSGPORT[EDI]
;
;	SHOULD ONLY HAVE NORMAL DATA NOW
;
FINDLOOP:

	CMP	OURCTRL[EBX],AL
	JE SHORT FOUNDIT

	MOV	EBX,SUBCHAIN[EBX]
	OR	EBX,EBX
	JZ SHORT NOTFOUND

	JMP	FINDLOOP

NOTFOUND:
DISCARDFRAME:
;
;	INVALID CONTROL BYTE - DISCARD IT (MAYBE SHOULD COUNT ??)
;
	CALL	RELBUFF
	RET

KISSTX:
;
;	START TRANSMISSION - EDI = ADDR OF MESSAGE
;

	PUSH	EBX
	MOV	EBX,FIRSTPORT[EBX]	; ALL FRAMES GO ON SAME Q

	
	TEST	KISSFLAGS[EBX],POLLEDKISS
	JNZ SHORT QUEUEIT			; MUST QUEUE - CANT SEND TILL POLLED

	CMP	KISSTX_Q[EBX],0
	JNE SHORT QUEUEIT			; ALREADY SOMETHING QUEUED

	CMP	POLLFLAG[EBX],0
	JNE SHORT QUEUEIT			; POLL OUTSTANDING, SO QUEUE FRAME

	CMP	TXTADDR[EBX],0
	JE SHORT OKTOSEND
;
;	ALREADY SENDING - QUEUE FRAME
;
QUEUEIT:

	LEA	ESI,KISSTX_Q[EBX]
	CALL	_Q_ADD
	
	POP	EBX
	RET

OKTOSEND:
;
;	IF NETROM PROTOCOL AND NOT FULL DUPLEX AND BUSY, QUEUE IT
;
	CMP	PROTOCOL[EBX],2		; NETROM?
	JNE SHORT DONTCHECKDCD		; NO

	CMP	FULLDUPLEX[EBX],1
	JE SHORT DONTCHECKDCD		; FULLDUP - NO CHECK
;
;	NETROM USES RTS, CROSS-CONNECTED TO CTS AT OTHER END, TO MEAN
;	NOT BUSY
;
;	MOV	DX,MSR[EBX]
;	IN	AL,DX
;
;	TEST	AL,CTSBIT		; CTS HIGH?
;	JZ SHORT QUEUEIT			; NO, SO QUEUE FRAME
;
;	GOING TO SEND - DROP RTS TO INTERLOCK OTHERS 
;
;	MOV	DX,MCR[EBX]
;	MOV	AL,09H			; DTR OUT2
;
;	OUT	DX,AL
;
;	MAKE SURE CTS IS STILL ACTIVE - IF NOT, WE HAVE A COLLISION,
;	SO RELEASE RTS AND WAIT
;
;	DELAY

;	MOV	DX,MSR[EBX]
;	IN	AL,DX
;	TEST	AL,CTSBIT
;	JNZ SHORT DONTCHECKDCD		; STILL HIGH, SO CAN SEND
;
;	RAISE RTS AGAIN, AND QUEUE FRAME
;
;	DELAY

;	MOV	DX,MCR[EBX]
;	MOV	AL,0BH			; RTS DTR OUT2
;
;	OUT	DX,AL
;
	JMP	QUEUEIT

DONTCHECKDCD:

	MOV	TXTADDR[EBX],1		; ENSURE POLL ISNT SENT
	
	CALL	SENDFRAME
	POP	EBX
	RET

SENDFRAME:
;
;	GET REAL PORT TABLE ENTRY - IF MULTIPORT, FRAME IS QUEUED ON
;	FIRST
;
	CMP	PROTOCOL[EBX],2		; NETROM
	JE NRTX00

	PUSH	EBX
	MOV	AL,4[EDI]		; PORT NUMBER
TXPORTLOOP:
	CMP	PORTNUMBER[EBX],AL
	JE SHORT OURPORT

	MOV	EBX,SUBCHAIN[EBX]
	CMP	EBX,0
	JNE SHORT TXPORTLOOP

	POP	EBX
	MOV	TXTADDR[EBX],0		; ALLOW OTHER ACTIONS

	CALL	RELBUFF
	RET

OURPORT:

	MOV	AL,OURCTRL[EBX]		; CORRECT CONTROL BYTE
	MOV	AH,KISSFLAGS[EBX]	; CORRECT KISSFLAGS

	POP	EBX
	MOV	TXCTRL[EBX],AL		; FOR TX ROUTINE
	MOV	REALKISSFLAGS[EBX],AH
;

	SETATVEC TXKISS			; SEND FRAME DELIMITER FIRST
;
	MOV	ESCTXCHAR[EBX],0
	JMP SHORT TXCOMMON

NRTX00:
	SETATVEC TXTEXT			; SEND FRAME DELIMITER FIRST
	MOV	ESCTXCHAR[EBX],STX	; SEND STX FIRST
	MOV	TXCCC[EBX],0
;
TXCOMMON:

	MOV	TXTADDR[EBX],EDI		; SAVE ADDR OF LAST MESSAGE
;
	MOVZX	ECX,WORD PTR 5[EDI]		; MSG LENGTH
	SUB	ECX,7			; HEADER LENGTH
	ADD	EDI,7
	
	MOV	AX,WORD PTR [EDI]	; KISS CONTROL FRAME?
	AND	AH,0FH			; MASK OUT PORT BITS
	CMP	AX,1C0H			; KISS CONTROL FRAME?
	JNE SHORT TXNORM			; DATA FRAME
;
;	KISS CONTROL FRAME
;
	SETATVEC TXKISSCTRL
TXNORM:
	MOV	TXCHAR[EBX],EDI		; SAVE
	MOV	TXCOUNT[EBX],CX
;
;	encode message, then send to driver
;
	MOV	EDI,OFFSET ENCBUFF
	PUSH	EDI

ENCLOOP:

	CALL	IOTXCA[EBX]		; DO FIRST SEND

	CMP		TXTADDR[EBX],0
	JNE		ENCLOOP
	
	MOV	ECX,EDI
	POP		EDI
	SUB	ECX,EDI

	push	ecx	
	push	edi

	PUSH	EBX						; Port Vector
	
	CALL	_ASYSEND

	add		esp,12

	RET
;
KISSTIMER:
;
;	IF FRAMES QUEUED, AND NOT SENDING, START
;
	CMP	EBX,FIRSTPORT[EBX]		; ALL FRAMES GO ON SAME Q
	JNE	NOTMAINPORT
;
;	SEE IF POLL HAS TIMED OUT
;
	TEST	KISSFLAGS[EBX],POLLINGKISS
	JZ SHORT NOTPOLLED

	CMP	POLLFLAG[EBX],0
	JE SHORT NOTPOLLED

	DEC	POLLFLAG[EBX]
	
	JNZ 	NOTMAINPORT			; TIMING OUT OR RECEIVING
;
;	POLL HAS TIMED OUT - MAY NEED TO DO SOMETHING
;

	PUSH	EBX
	MOV	EBX,POLLPOINTER[EBX]
	ADD	L2URUNC[EBX],1		; PUT IN UNDERRUNS FIELD
	POP	EBX

NOTPOLLED:

	CMP	TXTADDR[EBX],0
	JE SHORT NOTSENDING
;
	JMP	NOTCTSWAIT

;	IFNDEF	KANT
;
;	CMP	TXTADDR[EBX],0FFFFH
;	JNE SHORT NOTCTSWAIT
;
;	WAITING FOR CTS
;
;	MOV	DX,MSR[EBX]
;	IN	AL,DX
;	TEST	AL,CTSBIT
;	JNZ SHORT TIMERSEND		; OK TO SEND NOW
;
;	ENDIF

BUSY_J:
	JMP	BUSY			; WAIT FOR CTS

NOTCTSWAIT:
;
;	SEE IF BEEN SENDING TOO LONG
;
	DEC	TXACTIVE[EBX]
	JNZ SHORT BUSY_J
;
;	SEEM TO HAVE LOST A TX INTERRUPT - TRY CALLING TX ROUTINE
;
	ADD	L1DISCARD[EBX],1		; FOR STATS

	MOV	TXACTIVE[EBX],2

	CALL	IOTXCA[EBX]

	JMP	BUSY

NOTSENDING:
;
;	SEE IF ANYTHING TO SEND
;
	
	CMP	POLLED[EBX],1
	JE SHORT BEENPOLLED		; OK EVEN IF SLAVE MODE

	TEST	KISSFLAGS[EBX],POLLEDKISS
	JNZ 	NOTMAINPORT		; CANT SEND TILL WE GET POLL

BEENPOLLED:


	CMP	KISSTX_Q[EBX],0
	JE SHORT NOTHINGTOSEND
;
;	IF NETROM MODE AND NOT FULL DUP, CHECK DCD
;
	MOV	POLLED[EBX],0

	CMP	PROTOCOL[EBX],2		; NETROM?
	JNE SHORT DONTCHECKDCD_1

	CMP	FULLDUPLEX[EBX],1
	JE SHORT DONTCHECKDCD_1

;	MOV	DX,MSR[EBX]
;	IN	AL,DX
;
;	TEST	AL,CTSBIT		; DCD HIGH?
;	JZ SHORT NOTHINGTOSEND		; NO, SO WAIT
;
;	DROP RTS TO LOCK OUT OTHERS
;
;	MOV	DX,MCR[EBX]
;	MOV	AL,09H			; DTR OUT2
;
;	OUT	DX,AL
;
;
;	MAKE SURE CTS IS STILL ACTIVE - IF NOT, WE HAVE A COLLISION,
;	SO RELEASE RTS AND WAIT
;
;	DELAY

;	MOV	DX,MSR[EBX]
;	IN	AL,DX
;	TEST	AL,CTSBIT
;	JNZ SHORT TIMERSEND		; STILL HIGH, SO CAN SEND
;
;	RAISE RTS AGAIN, AND WAIT A BIT MORE
;
;	DELAY
;
;	MOV	DX,MCR[EBX]
;	MOV	AL,0BH			; RTS DTR OUT2
;
;	OUT	DX,AL

	JMP SHORT NOTHINGTOSEND

DONTCHECKDCD_1:
TIMERSEND:

	PUSH	ESI
	PUSH	EDI
	PUSH	EDX

	LEA	ESI,KISSTX_Q[EBX]
	CALL	Q_REM

	CALL	SENDFRAME

	POP	EDX
	POP	EDI
	POP	ESI

	JMP SHORT NOTMAINPORT

NOTHINGTOSEND:
;
;	IF POLLED MODE, SEND A POLL TO NEXT PORT
;
	TEST	KISSFLAGS[EBX],POLLINGKISS
	JZ SHORT NOTMAINPORT
;
;	FIND WHICH CHANNEL TO POLL NEXT
;
	PUSH	ESI
	MOV	ESI,POLLPOINTER[EBX]
	MOV	ESI,SUBCHAIN[ESI]
	CMP	ESI,0
	JNE SHORT POLLTHISONE

	MOV	ESI,EBX			; BACK TO FIRST

POLLTHISONE:

	MOV	POLLPOINTER[EBX],ESI	; FOR NEXT TIME

	CALL	SENDPOLL
	POP	ESI

BUSY:
	

NOTMAINPORT:


KISSSLOWTIMER:
;
;	SEE IF TIME TO REFRESH KISS PARAMS
;
	TEST	KISSFLAGS[EBX],POLLEDKISS
	JNZ SHORT KTIMERRET		; WE ARE THE SLAVE

	CMP	PROTOCOL[EBX],2		; NETROM?
	JNE SHORT KISSXX

KTIMERRET:

	RET				; NOT ON NETROM

KISSXX:

	DEC	PARAMTIMER[EBX]
	JNZ SHORT KTIMERRET
;
;	QUEUE A 'SET PARAMS' FRAME
;
	PUSH	ESI
	PUSH	EDI

	CMP	PORTDISABLED[EBX],0
	JNE SHORT NOBUFFERS		; PORT DISABLED

	MOV	EDI,OFFSET KISSPARAMS
	PUSH	EDI	

	MOV	AL,FEND
	STOSB
	MOV	AH,OURCTRL[EBX]
	MOV	AL,1
	OR	AL,AH			; PUT IN CHANNEL BITS
	STOSB

	MOV	AL,BYTE PTR PORTTXDELAY[EBX]
	STOSB
	MOV	AL,FEND
	STOSB
	STOSB

	MOV	AL,2
	OR	AL,AH			; PUT IN CHANNEL BITS
	STOSB
	MOV	AL,PORTPERSISTANCE[EBX]
	STOSB
	MOV	AL,FEND
	STOSB
	STOSB

	MOV	AL,3
	OR	AL,AH			; PUT IN CHANNEL BITS
	STOSB
	MOV	AL,PORTSLOTTIME[EBX]
	STOSB
	MOV	AL,FEND
	STOSB
	STOSB

	MOV	AL,4
	OR	AL,AH			; PUT IN CHANNEL BITS
	STOSB
	MOV	AL,PORTTAILTIME[EBX]
	STOSB
	MOV	AL,FEND
	STOSB
	STOSB

	MOV	AL,5
	OR	AL,AH			; PUT IN CHANNEL BITS
	STOSB
	MOV	AL,FULLDUPLEX[EBX]
	STOSB
	MOV	AL,FEND
	STOSB

	MOV	ECX,EDI
	POP	EDI
	SUB	ECX,EDI

	PUSH	EBX
	MOV	EBX,FIRSTPORT[EBX]	; ALL FRAMES GO ON SAME Q
;
;	QUEUE FRAME
;
	push	ecx	
	push	edi

	PUSH	EBX						; Port Vector

	CALL	_ASYSEND

	add		esp,12

	POP	EBX

NOBUFFERS:

	MOV	PARAMTIMER[EBX],TICKS*60*5	; 5 MINS

	POP	EDI
	POP	ESI

	RET

SENDPOLL:
;
;	SEND POLL TO PORT IN ESI
;
	MOV	POLLFLAG[EBX],TICKS / 3	; ALLOW 1/3 SEC 

	MOV	AL,OURCTRL[ESI]		; CORRECT CONTROL BYTE
	OR	AL,0EH				; POLL BITS
	MOV	TXCTRL[EBX],AL		; FOR TX ROUTINE
;
;	encode message, then send to driver
;
	MOV	EDI,OFFSET ENCBUFF

	MOV	AL,FEND
	STOSB

	MOV	AL,TXCTRL[EBX]
	STOSB

	MOV	AL,FEND
	STOSB

	push	3					; LEN
	push	OFFSET ENCBUFF

	PUSH	EBX						; Port Vector

	CALL	_ASYSEND

	add		esp,12

	RET

RXASTX:

	AND	LINKSTS[EBX],0FFH-10H	; CLEAR PARITY ERROR
;
;	ADD	CHARS,1
;	ADC	CHARS+2,0

	CMP	PROTOCOL[EBX],2
	JE SHORT RXNR00			; NETROM PROTOCOL

	CMP	AL,FEND			; FRAME DELIMITER?
	JNE 	RXA010			; NO - IGNORE
;
;	GET BUFFER
;
	CALL	GETBUFF

	JNZ SHORT GETB00

	JMP	RXA010

GETB00:

	MOV	CURALP[EBX],EDI		; SAVE IT
;	MOV	DWORD PTR [EDI],OFFSET32 RXA005

RXA005:

	ADD	EDI,7			; SKIP CHAIN, PORT, LENGTH
	MOV	NEXTCHR[EBX],EDI		; SAVE BUFFER ADDRESS
;
	MOV	FRAMELEN[EBX],7		; INITIAL LENGTH	
	SETARVEC RXACTL

	RET

RXA010:
	RET

RXNR00:

	CMP	ESCFLAG[EBX],1
	JE SHORT RXA011			; DONT ACCEPT DLE/STX

	CMP	AL,STX
	JE SHORT RXA002

	CMP	AL,DLE
	JNE SHORT RXA010			; IGNORE

	MOV	ESCFLAG[EBX],1
	RET


RXA002:
;
;	GET BUFFER
;
	CALL	GETBUFF

	JNZ SHORT GETBNR

	JMP	RXA011			; IGNORE (? WAIT FOR ETX OR TIMEOUT)

GETBNR:

;	MOV	DWORD PTR [EDI],OFFSET32 GETBNR

	MOV	CURALP[EBX],EDI		; SAVE IT

	ADD	EDI,7			; SKIP CHAIN, PORT, LENGTH
	MOV	NEXTCHR[EBX],EDI		; SAVE BUFFER ADDRESS
;
	MOV	FRAMELEN[EBX],7		; INITIAL LENGTH	
	MOV	RXCCC[EBX],0
	SETARVEC RXAMSGNR

RXA011:
	MOV	ESCFLAG[EBX],0
	RET


RXACTL:

;	ADD	CHARS,1
;	ADC	CHARS+2,0

;
;	SHOULD BE PORT NUMBER - IF FEND WE HAVE GOT OUT OF STEP
;
	MOV	EDI,CURALP[EBX]		; GET BUFFER ADDR

	CMP	AL,FEND
	JE 	RXA005			; TRY AGAIN
;
	MOV	MSGPORT[EDI],AL		; PUT CONTROL BYTE IN PORT FIELD
	XOR	RXCCC[EBX],AL		; MAINTAIN CCC
	
	AND	AL,0FH
	CMP	AL,0EH			; POLL OR POLL REPLY?
	JNZ SHORT NOTPOLLREPLY
;
;	POLL OR REPLY TO POLL
;
	MOV	AL,MSGPORT[EDI]
	MOV	POLLED[EBX],AL		; FOR BG TO PROCESS

	RET				; ACCEPT FEND OR CONTROL NEXT

NOTPOLLREPLY:

	SETARVEC RXAMSG
	TEST	KISSFLAGS[EBX],POLLINGKISS
	JZ SHORT NOTPOLL00
;
;	POLLED MODE - EXTEND TIMEOUT FOR DATA FRAME
;
	MOV	POLLFLAG[EBX],5*TICKS	; 5 SECS - SHOULD BE PLENTY

NOTPOLL00:

	RET

RXAMSG:

;	ADD	CHARS,1
;	ADC	CHARS+2,0

	CMP	AL,FEND		
	JE SHORT MSGEND			; END OF FRAME

	CMP	AL,FESC
	JNE SHORT NOTESC
;
;	ESC - SET FLAG 
;
	MOV	ESCFLAG[EBX],1		; SET FESC RECEIVED
	RET

NOTESC:

	CMP	ESCFLAG[EBX],1
	JNE SHORT RXNORM

	CMP	AL,TFESC		; ESC'ED FESC?
	JNE SHORT NOTTFESC

	MOV	AL,FESC			; REAL FESC 
	JMP SHORT RXNORM

NOTTFESC:

	CMP	AL,TFEND		; ESC'ED FEND?
	JNE SHORT RXNORM
 
	MOV	AL,FEND
RXNORM:
	MOV	EDI,NEXTCHR[EBX]		; GET POINTER
	STOSB				; PUT IN BUFFER
	MOV	NEXTCHR[EBX],EDI		; SAVE POINTER

RXA500:

	MOV	ESCFLAG[EBX],0
	INC	FRAMELEN[EBX]
	CMP	FRAMELEN[EBX],MAXDATA
	JB SHORT RXARET			; OK
	DEC	NEXTCHR[EBX]		; PREVENT OVERRUN

	OR	LINKSTS[EBX],10H		; SET ERROR
RXARET:
	RET
;

MSGEND:

	MOV	EDI,NEXTCHR[EBX]		; GET POINTER
	STOSB				; PUT FEND ON END

	MOV	EDI,CURALP[EBX]
	MOV	POLLFLAG[EBX],0		; LINK NOW IDLE

QMSG:

	TEST	LINKSTS[EBX],10H
	JNZ SHORT RXAERROR		; OVERRUN, ETC

	MOV	CX,FRAMELEN[EBX]
	MOV	5[EDI],CX		; LENGTH

	LEA	ESI,ASYNCMSG_Q[EBX]	; PUT ON RX QUEUE - SUBPORT DETAILS ARE
					; SORTED OUT LATER
	CALL	_Q_ADD

	JMP	RXAEXIT

RXAERROR:

	MOV	EDI,CURALP[EBX]

	CALL	RELBUFF

RXAEXIT:

	MOV	IORXCA[EBX],OFFSET32 RXASTX	; FOR NEXT MESSAGE

	RET
;
RXAMSGNR:


;	ADD	CHARS,1
;	ADC	CHARS+2,0

	CMP	AL,DLE
	JNE SHORT NOTDLE
;

;	DLE - SET FLAG UNLESS ALREADY SET
;
	CMP	ESCFLAG[EBX],1
	JE SHORT NOTDLE			; MUST BE DLE/DLE - MEANS REAL 10H!

	MOV	ESCFLAG[EBX],1		; SET DLE RECEIVED
	RET
NOTDLE:
	MOV	EDI,NEXTCHR[EBX]		; GET POINTER
	STOSB				; PUT IN BUFFER
	MOV	NEXTCHR[EBX],EDI		; SAVE POINTER

	CMP	AL,ETX			; END?
	JNE SHORT RXA500NR		; NO
;
	CMP	ESCFLAG[EBX],1
	JE SHORT RXA500NR		; DLE/ETX

	SETARVEC RXACCC
;
	RET
;
RXA500NR:

	ADD	RXCCC[EBX],AL		; UPDATE LRC
	JMP	RXA500			; CHECK FOR BUFFER OVERFLOW, ETC

RXACCC:

;	ADD	CHARS,1
;	ADC	CHARS+2,0

	CMP	AL,RXCCC[EBX]		; ACCUMULATED VALUE
	JE SHORT OK_CRC

	ADD	RXERRORS[EBX],1

	JMP	RXAERROR		; DUFF

OK_CRC:

	MOV	EDI,CURALP[EBX]
	JMP	QMSG			; QUEUE FOR BG TO PROCESS

;
RXAPTY:

	RET
;
TXKISS:

	SETATVEC TXNULL

	MOV	AL,FEND
	JMP	TXA100			; SEND FEND

TXNULL:
;
;	SEND CONTROL BYTE
;
	SETATVEC TXTEXT

	MOV	AL,TXCTRL[EBX]
;
;	SEE IF ACK MODE IN USE
;
	TEST	REALKISSFLAGS[EBX],ACKMODE
	JZ SHORT NOACKMODE
;
;	SEE IF FRAME NEEDS AN ACK
;

	MOV	ESI,TXTADDR[EBX]
	CMP	DWORD PTR BUFFLEN-4[ESI],0
	JE SHORT NOACKMODE

	MOV	EDX,LINKS
	SUB	DWORD PTR BUFFLEN-4[ESI],EDX	; CAN ONLY SEND 2 BYTES TO TNC
	SETATVEC TXHDDR1

	OR	AL,0CH			; RESPONSE MODE

NOACKMODE:

	MOV	TXCCC[EBX],FEND		; INITIALISE CRC - HAVE ALREADY SEND FEND
	XOR	TXCCC[EBX],AL

	JMP	TXA100			; SEND KISS CONTROL

TXHDDR1:
;
;	SEND FIRST ACK BYTE
;

	MOV	ESI,TXTADDR[EBX]
	MOV	AL,BUFFLEN-4[ESI]
	TEST	REALKISSFLAGS[EBX],TNCX
	JZ SHORT @F
	XOR	TXCCC[EBX],AL	; Include ACK byte in Checksum
@@:	
	SETATVEC TXHDDR2

	JMP	TXA100			; SEND IT

TXHDDR2:
;
;	SEND SECOND ACK BYTE
;

	MOV	ESI,TXTADDR[EBX]
	MOV	AL,BUFFLEN-3[ESI]
	TEST	REALKISSFLAGS[EBX],TNCX
	JZ SHORT @F
	XOR	TXCCC[EBX],AL	; Include ACK byte in Checksum
@@:	
	MOV	DWORD PTR BUFFLEN-4[ESI],0; CLEAR INDICATOR	

	SETATVEC TXTEXT

	JMP	TXA100			; SEND IT

TXTEXT:

	MOV	AL,ESCTXCHAR[EBX]
	OR	AL,AL	
	JZ SHORT TXA000			; NORMAL

	MOV	ESCTXCHAR[EBX],0
	JMP	TXA100		; SEND CHAR FOLLOWING ESC

TXA000:
	CMP	TXCOUNT[EBX],0
	JZ SHORT TXETX

	DEC	TXCOUNT[EBX]

	MOV	ESI,TXCHAR[EBX]
	LODSB				; NEXT CHAR
	MOV	TXCHAR[EBX],ESI

	CMP	PROTOCOL[EBX],2
	JE SHORT CHECKDLE		; NETROM MODE

	XOR	TXCCC[EBX],AL

	CMP	AL,FEND
	JNE SHORT NOTTXFEND

	MOV	ESCTXCHAR[EBX],TFEND	; ESC'ED FEND
	MOV	AL,FESC
	JMP SHORT TXA100

NOTTXFEND:

;	If D700 Mode, Escape all C chars to break up TC 0<cr> string

	CMP	AL,'C'
	JNE SHORT NOTTXD700
	
	TEST	KISSFLAGS[EBX],D700
	JZ SHORT NOTTXD700

	MOV	ESCTXCHAR[EBX],'C'	; C Escaped is C
	MOV	AL,FESC
	JMP SHORT TXA100

NOTTXD700:

	CMP	AL,FESC
	JNE SHORT TXA100

	MOV	ESCTXCHAR[EBX],TFESC	; ESC'ED ESC
	JMP SHORT TXA100

CHECKDLE:
;
;	CHECK FOR NETROM CHARS TO PREFIX
;
	ADD	TXCCC[EBX],AL
	CMP	AL,DLE
	JE SHORT TXDLE00
	CMP	AL,STX
	JE SHORT TXDLE00
	CMP	AL,ETX
	JNE SHORT TXA100

TXDLE00:
	MOV	ESCTXCHAR[EBX],AL
	MOV	AL,DLE
	JMP SHORT TXA100


TXETX:

	CMP	PROTOCOL[EBX],2
	JE SHORT TXETXNR

	TEST	KISSFLAGS[EBX],CHECKSUM
	JNZ SHORT TXETXP

	SETATVEC NEXTFRAME
	MOV	AL,FEND			; ETX

TXA100:

	stosb

	RET

TXETXNR:
	SETATVEC ASENDCC
	MOV	AL,03H
	JMP SHORT TXA100

TXETXP:
	SETATVEC ASENDFEND
;
;	SEND CHECKSUM - BEWARE! - IT MAY BE FEND OR FESC
; 
	MOV	AL,TXCCC[EBX]
	XOR	AL,FEND			; HAVNT INCLUDED FEND YET 

	CMP	AL,FEND
	JNE SHORT NOTCHKFEND

	MOV	ESCTXCHAR[EBX],TFEND	; ESC'ED FEND
	MOV	AL,FESC
	JMP SHORT TXA100

NOTCHKFEND:

	CMP	AL,FESC
	JNE SHORT TXA100

	MOV	ESCTXCHAR[EBX],TFESC	; ESC'ED ESC
	JMP SHORT TXA100


ASENDCC:
;
;	NETROM END OF FRAME
;

	MOV	AL,TXCCC[EBX]
	SETATVEC NEXTFRAMENR
	JMP SHORT TXA100


ASENDFEND:
;
;	USED TO SEND FINAL CHAR OF CHECKSUMMED FRAME
;
;	IF THE CHECKSUM WAS FEND OR FESC, WE HAVE TO SEND THE 'ESC'ED VALUE
;	FIRST
;
	MOV	AL,ESCTXCHAR[EBX]
	OR	AL,AL	
	JZ SHORT SENDFEND00		; NORMAL

	MOV	ESCTXCHAR[EBX],0
	JMP SHORT TXA100		; SEND CHAR FOLLOWING ESC

SENDFEND00:

	MOV	AL,FEND
	SETATVEC NEXTFRAME
	JMP SHORT TXA100


NEXTFRAMENR:
;
;	IF NOT FULL DUP, RAISE RTS
;
	CMP	FULLDUPLEX[EBX],1
	JE SHORT NEXTFRAME

;	MOV	DX,MCR[EBX]
;	MOV	AL,0BH			; DTR OUT2
;
;	OUT	DX,AL

NEXTFRAME:

	PUSH	EDI
	
	MOV	EDI,TXTADDR[EBX]

	MOV	ESI,OFFSET32 TRACE_Q
	CALL	_Q_ADD			; FEED TO TRACE CODE

	POP		EDI

	JMP SHORT ENDFRAME
;	TEST	KISSFLAGS[EBX],POLLINGKISS
;	JZ SHORT ENDFRAME
;
;	SEND A POLL AFTER MSG
;

;	MOV	AL, FEND
;	STOSB
	
;	MOV	AL,OURCTRL[EBX]		; CORRECT CONTROL BYTE
;	OR	AL,0EH				; POLL BITS

;	STOSB
	
;	SETATVEC SENDPOLLFEND

;	JMP	TXA100			; SEND IT

;SENDPOLLFEND:

;	MOV	AL,FEND

;POLLRESP:

;	SETATVEC ENDFRAME

;	JMP	TXA100			; SEND IT

ENDFRAME:

	MOV	TXTADDR[EBX],0		; CLEAR SENDING INDICATOR
	MOV	TXACTIVE[EBX],0
;
	SETATVEC IGNORE
	RET

IGNORE:
	RET
;
TXKISSCTRL:
;
;	SEND KISS CONTROL FRAME
;
	CMP	TXCOUNT[EBX],0
	JZ SHORT TXETXC

	DEC	TXCOUNT[EBX]

	MOV	ESI,TXCHAR[EBX]
	LODSB				; NEXT CHAR
	MOV	TXCHAR[EBX],ESI

	JMP SHORT TXA100C

TXETXC:

	MOV	EDI,TXTADDR[EBX]
	CALL	RELBUFF

	SETATVEC ENDFRAME

	MOV	AL,FEND			; ETX
TXA100C:

;	MOV	DX,IOADDR[EBX]
;	OUT	DX,AL			; SEND CHAR
;
;	ADD	CHARS,1
;	ADC	CHARS+2,0

	RET

CALC_CRC:
;
	XOR		DL,AL		; OLD FCS .XOR. CHAR
	MOVZX	EBX,DL		; CALC INDEX INTO TABLE FROM BOTTOM 8 BITS
	ADD		EBX,EBX
	MOV		DL,DH		; SHIFT DOWN 8 BITS
	XOR		DH,DH		; AND CLEAR TOP BITS
	XOR		DX,[EBX+_CRCTAB]	; XOR WITH TABLE ENTRY
	RET
;               
;


_TEXT	ENDS
	END