PAGE 62,132 ; CODE SEGMENT PUBLIC 'CODE' INCLUDE ENVIRON.ASM ASSUME CS:CODE,DS:CODE,ES:CODE ; ; ODI INTERFACE ROUTINE FOR G8BPQ PACKET SWITCH ; ; INTERFACE TO SWITCH IS VIA SOFTWARE INTERRUPT ; ; ; COMMANDS SUPPORTED ARE: ; ; AH = 0 INIT Driver ; ; AH = 1 Poll for data. Returns CX = 0 if none available, ; otherwise CX= length, DS:SI=Data ; ; AH = 2 Send frame. DS:DI = Buffer header. ; ; AH = 3 Status - Return AX=0 If OK to send a frame. ; CX=0 If no frame available to receive ; CR EQU 0DH LF EQU 0AH ECBSTRUC STRUC NEXTLINK DD ? PREVLINK DD ? STATUS DW ? ESRADDR DD ? ECBSTACKID DW ? ECBPID DB 6 DUP (?) ECBBOARDNO DW ? IMMEDADDR DB 6 DUP (?) DRVRWORKSPACE DB 4 DUP (?) PROTOWORKSPACE DB 8 DUP (?) DATALEN DW ? FRAGCOUNT DW ? FRAG0ADDR DD ? FRAG0LEN DW ? ECBSTRUC ENDS TXECB DB TYPE ECBSTRUC DUP (0) BUFFER DB 350 DUP (0) BUFFSTRUC STRUC BUFFCHAIN DW 0 BUFFLEN DW 0 BUFFPTR DW 0 BUFFDATA DW 594 DUP (0) BUFFSTRUC ENDS RXBUFFS EQU 20 RXBUFLEN EQU 350+TYPE ECBSTRUC EVEN RXPOOL DB RXBUFLEN*RXBUFFS DUP (0) STARTOFPROG: LSLENTRYPOINT DD 0 LSLGENSERVICES DD 0 MUXVEC DB 0 EVEN PSPSEG DW 0 BOARDNUM DW 0 BPQBOARD DW 0 ; BOARD NUMBER FOR IP/ARP BPQSTACKID DW 0 MLIDCONTROL DD 0 BPQPID DB 0,0,0,0,0,0 BPQ DB 3,'BPQ',0 MULTICAST DB 01,'BPQ',0,0 FREE_Q DW 0 RX_Q DW 0 TEMP_Q DW 0 ; FRAMES WAITING TO BE RELEASED SWITCHINT: ; ; RELEASE ANY SAVED FRAMES ; CMP CS:TEMP_Q,0 JE NOTEMP PUSH AX PUSH DS PUSH SI PUSH DI PUSH CS POP DS MOV SI,OFFSET TEMP_Q CALL Q_REM MOV SI,OFFSET FREE_Q CALL Q_ADDF POP DI POP SI POP DS POP AX NOTEMP: CMP AH,3 JE CHKSTATUS CMP AH,2 JE PUTFRAME CMP AH,1 JE POLL IRET CHKSTATUS: MOV AX,0 CMP CS:TXINUSE,0 ; TX BUSY? JE STAT00 ; NO ; MOV AX,1 STAT00: CMP CS:RX_Q,0 ; RX READY? JE POLLRET ; NO MOV CX,1 IRET POLL: CMP CS:RX_Q,0 JE POLLRET ; PUSH CS POP DS ; MOV SI,OFFSET RX_Q CALL Q_REM PUSH DI ; SAVE MOV SI,OFFSET TEMP_Q ; SAVE TILL NEXT ENTRY BEFORE RELEASE CALL Q_ADDF POP SI ADD SI,6+TYPE ECBSTRUC ; TO DATA SUB SI,3 ; EXTRA HEADER MOV CX,3[SI] ; LENGTH CMP CX,340 JBE LENOK MOV CX,0 ; TOO BIG - JUST IGNORE IT LENOK: IRET POLLRET: MOV CX,0 IRET PUTFRAME: PUSH SI PUSH DI PUSH CX PUSH DS PUSH ES MOV CX,3[DI] MOV AX,CX ; MOV SI,DI ADD SI,3 MOV DI,OFFSET BUFFER ; PUSH CS POP ES ; REP MOVSB ; COPY FRAME MOV SI,OFFSET TXECB MOV WORD PTR ES:FRAG0LEN[SI],AX ; LENGTH MOV WORD PTR ES:DATALEN[SI],AX ; LENGTH MOV CS:TXINUSE,1 MOV BX,000CH CALL CS:LSLENTRYPOINT POP ES POP DS POP CX POP DI POP SI IRET TXINUSE DB 0 ; IN CODE SEG TXROUTINE: ; ; TX COMPLETE HANDLER ; MOV CS:TXINUSE,0 CMP ES:STATUS[SI],0 JE TXAXOK MOV AX,ES:STATUS[SI] PUSH AX MOV AL,AH CALL HEXOUT POP AX CALL HEXOUT TXAXOK: RETF HEXOUT: PUSH AX PUSH AX sar al,1 sar al,1 sar al,1 sar al,1 call hexout1 pop ax call hexout1 POP AX ret hexout1: and al,0fh cmp al,10 jl hexout5 add al,7 hexout5: add al,30h call printit ; ret ; printit: PUSH AX PUSH BX mov AH,14 int 10h POP BX POP AX ret ; Q_ADDF: MOV AX,[SI] ; OLD QUEUE HEADER MOV [DI],AX ; CHAIN TO NEW BUFFER ; MOV [SI],DI ; CHAIN NEW BUFFER TO QUEUE HEADER RET ; Q_ADD: MOV WORD PTR [DI],0 ; CLEAR CHAIN POINTER IN NEW BUFFER Q_ADD1: MOV AX,[SI] OR AX,AX JZ Q_ADD5 ; END ; MOV SI,AX JMP Q_ADD1 ; LOOP TILL END FOUND ; Q_ADD5: MOV [SI],DI ; CHAIN NEW BLOCK RET ; Q_FIRST: MOV DI,[SI] CMP DI,0 Q_RET: RET ; Q_REM: CALL Q_FIRST ; SET FIRST ENTRY JZ Q_RET ; QUEUE EMPTY ; MOV AX,[DI] MOV [SI],AX ; SI = HEADER ; RET CONTROLHANDLER: ; ; MAY BE CALLED BY LSL AND OTHER MODULES ; RETF ECBINUSE DB 0 PACKETRECEIVE: ; ; CALLED WHEN A PACKET ARRIVES ; PUSH DS MOV AX,CODE MOV ES,AX ; ; GET A BUFFER ; CMP ES:FREE_Q,0 JE LLCNOBUFFER MOV DI,ES:FREE_Q MOV AX,ES:[DI] ; NEXT BUFFER MOV ES:FREE_Q,AX ; ; ES:DI CONTAINS HEADER - ECB IS ON FRONT OF DATA ; MOV SI,DI ; SAVE BUFFER ADDR ADD SI,6 ; TO ECB ; ADD DI,6+TYPE ECBSTRUC ; OVER ECB HEADER MOV WORD PTR ES:PROTOWORKSPACE[SI],0; BYTES IN HEADER MOV WORD PTR ES:FRAG0ADDR[SI],DI ; BUFFER MOV WORD PTR ES:FRAG0LEN[SI],340 MOV AX,0 OR AX,AX pop ds RETF LLCNOBUFFER: MOV AX,8001H OR AX,AX POP DS RETF RXROUTINE: PUSH DS ; ; ATTACH TO RX QUEUE ; MOV AX,CODE MOV DS,AX ; MOV DI,SI SUB DI,6 ; TO HEADER MOV SI,OFFSET RX_Q CALL Q_ADD POP DS RETF ENDOFCODE LABEL BYTE ; ; REST DISCARDED AFTER LOAD ; EVEN BPQSTACKINFO DD BPQ DD PACKETRECEIVE DD CONTROLHANDLER NOTFOUND DB CR,LF,'LSL not found $' SIGNATURE DB 'LINKSUP$' LSLINIT DD 0 ; INIT ENTRY POINT MSG DB 'ODI Interface for G8BPQ switch version ' db VERSIONSTRING,' ',DATESTRING db 0dh,0ah,'$' ERRORMSG DB 0AH,'Parameter error:',0dh,0ah,0ah db 'Format is ODIDRV interrupt' db 0dh,0ah,'Program NOT installed' DB 0dh,0ah,0AH,'$' ETHMSG DB CR,LF,'Target Ethernet Address = $' PIDMSG DB ', Protocol ID = $' VECTOR DB 0 GO: MOV AX,CODE MOV ES,AX PUSH DS PUSH CS POP DS MOV DX,OFFSET MSG MOV AH,9 INT 21H ; POP DS MOV SI,82H ; PARAM STRING CALL GETVALUE ; NUMBER OF PORTS PUSH CS POP DS JC BADPORTVAL MOV AL,BYTE PTR NEWVALUE OR AL,AL JZ BADPORTVAL ; MOV VECTOR,AL CALL ODIINIT ; ; HOOK OUR SOFTWARE VECTOR ; MOV AL,VECTOR MOV DX,OFFSET SWITCHINT MOV AH,25H INT 21H ; SET VECTOR ; MOV DX,OFFSET ENDOFCODE+256 INT 27H BADPORTVAL: MOV AH,9 MOV DX,OFFSET ERRORMSG JMP ERREXIT NEWVALUE DW 0 D16 DW 16 D10 DW 10 GETVALUE: ; ; EXTRACT NUMBER (HEX OR DECIMAL) FROM INPUT STRING ; MOV CS:NEWVALUE,0 LODSB CMP AL,'$' ; HEX? JE DECODEHEX DEC SI VALLOOP: LODSB CMP AL,' ' JE ENDVALUE CMP AL,0DH JE ENDVALUE CMP AL,',' JE ENDVALUE ; ; ANOTHER DIGIT - MULTIPLY BY 10 ; MOV AX,CS:NEWVALUE MUL CS:D10 MOV CS:NEWVALUE,AX MOV AL,-1[SI] SUB al,'0' JC DUFFVALUE CMP AL,10 JNC DUFFVALUE MOV AH,0 ADD CS:NEWVALUE,AX JC DUFFVALUE JMP VALLOOP DECODEHEX: MOV NEWVALUE,0 HEXLOOP: LODSB CMP AL,' ' JE ENDVALUE CMP AL,':' JE ENDVALUE ; ; ANOTHER DIGIT - MULTIPLY BY 16 ; MOV AX,CS:NEWVALUE MUL CS:D16 MOV CS:NEWVALUE,AX MOV AL,-1[SI] SUB al,'0' JC DUFFVALUE CMP AL,10 JC HEXOK SUB AL,7 CMP AL,10 JC DUFFVALUE CMP AL,16 JNC DUFFVALUE HEXOK: MOV AH,0 ADD CS:NEWVALUE,AX JMP HEXLOOP ENDVALUE: CLC RET DUFFVALUE: STC RET ODIINIT: ; ; BUILD BUFFER POOL ; MOV CX,RXBUFFS MOV DI,OFFSET RXPOOL BUFFERLOOP: ; ; EACH BUFFER HAS AN ECB ON THE FRONT ; LEA SI,6[DI] ; TO ECB BIT MOV WORD PTR ESRADDR[SI],OFFSET RXROUTINE MOV WORD PTR ESRADDR+2[SI],CS MOV FRAGCOUNT[SI],1 MOV WORD PTR FRAG0ADDR+2[SI],DS MOV FRAG0LEN[SI],340 MOV SI,OFFSET FREE_Q MOV AX,[SI] ; OLD QUEUE HEADER MOV [DI],AX ; CHAIN TO NEW BUFFER ; MOV [SI],DI ; CHAIN NEW BUFFER TO QUEUE HEADER ADD DI,RXBUFLEN LOOP BUFFERLOOP ; ; FIND LSL ; MOV MUXVEC,0C0H FINDLOOP: MOV AH,CS:MUXVEC MOV AL,0 INT 2FH CMP AL,0FFH JE SLOTINUSE ; CAN USE THIS ONE TRYNEXT: ; ; TRY NEXT SLOT ; INC CS:MUXVEC CMP CS:MUXVEC,0C8H JB FINDLOOP ; ; NO SLOTS ; MOV DX,OFFSET NOTFOUND JMP ERREXIT SLOTINUSE: ; ; SEE IF US - ES:SI WILL POINT TO LINKSUP$ ; MOV DI,SI MOV SI,OFFSET SIGNATURE MOV CX,8 REP CMPSB JNE TRYNEXT ; ; WE'VE FOUND IT ; MOV WORD PTR LSLINIT,BX MOV WORD PTR LSLINIT+2,DX ; INIT ENTRY POINT PUSH DS POP ES MOV SI,OFFSET LSLENTRYPOINT MOV BX,2 ; GET ENTRY POINTS CALL LSLINIT ; ; GET NET.CFG ADDR (JUST TESTING FOR NOW) ; MOV BX,7 CALL LSLGENSERVICES ; ; DS:DX = FILE NAME ; CALL READCFG ; LOOK FOR AN ETH ADDR PARAM PUSH CS POP DS MOV BX,19H ; GET LSL CONFIG CALL LSLENTRYPOINT ; ; ES:SI = CONFIG TABLE ; PUSH DS POP ES ; ; REGISTER STACK ; MOV BX,6 MOV SI,OFFSET BPQSTACKINFO CALL LSLENTRYPOINT ; OR AX,AX JZ REGOK ; ; FAILED ; MOV DX,OFFSET REGFAILED JMP DISPANDEXIT REGOK: PUSH CS POP ES ; RETURNS STACK ID ; MOV BPQSTACKID,BX ; ; GET BOARD AND PID (LOADED BY MLID FROM NET.CFG) ; MOV BPQBOARD,0 GETLOOP: ; ; MAKE SURE WE HAVE A BOARD AND PID ; MOV AX,BPQSTACKID MOV BX,11H ; GET_PID_FROM_STACKID_BOARD MOV CX,BPQBOARD ; MOV SI,OFFSET BPQPID ; CALL LSLENTRYPOINT ; CMP AX,0 JE GOTBOARDNO JMP NEXTBOARD GOTBOARDNO: ; ; HAVE GOT THE BOARD ID ; PUSH CS POP ES ; ; GET MLID ADDRESS ; MOV AX,BPQBOARD MOV BX,12H CALL LSLENTRYPOINT MOV WORD PTR MLIDCONTROL,SI MOV WORD PTR MLIDCONTROL+2,ES PUSH DS POP ES ; ; SET UP MULTICAST - UNLESS SPECIFIC OR BROADCAST ADDR ; TEST MULTICAST,1 JZ NOTMULTI ; NOT A MULTICAST ADDR CMP WORD PTR MULTICAST,0FFFFH JNE NOTBROAD CMP WORD PTR MULTICAST+2,0FFFFH JNE NOTBROAD CMP WORD PTR MULTICAST+4,0FFFFH JE NOTMULTI ; DONT ADD BROADCAST ADDR AS A MULTICAST NOTBROAD: MOV AX,BPQBOARD MOV BX,2 MOV SI,OFFSET MULTICAST CALL MLIDCONTROL NOTMULTI: PUSH CS POP ES ; ; BIND THE STACK - WE WILL THEN START GETTING MESSAGES ; MOV AX,BPQSTACKID MOV BX,15H ; BINDSTACK MOV CX,BPQBOARD CALL LSLENTRYPOINT PUSH CS POP ES OR AX,AX JZ BINDOK ; ; FAILED ; MOV DX,OFFSET BINDFAILED JMP DISPANDEXIT BINDOK: ; ; SET UP TX ECB ; MOV BX,OFFSET TXECB MOV WORD PTR ESRADDR[BX],OFFSET TXROUTINE MOV WORD PTR ESRADDR+2[BX],CS MOV AX,BPQSTACKID MOV ECBSTACKID[BX],AX MOV AX,BPQBOARD MOV ECBBOARDNO[BX],AX MOV FRAGCOUNT[BX],1 MOV WORD PTR FRAG0ADDR[BX],OFFSET BUFFER MOV WORD PTR FRAG0ADDR+2[BX],DS ; LEA SI,BPQPID LEA DI,ECBPID[BX] MOV CX,6 REP MOVSB LEA SI,MULTICAST LEA DI,IMMEDADDR[BX] MOV CX,6 REP MOVSB MOV DX,OFFSET ETHMSG MOV AH,9 INT 21H LEA SI,MULTICAST MOV CX,6 DADDRLOOP: LODSB CALL HEXOUT CMP CX,1 JE NOCOLON MOV AL,':' CALL PRINTIT NOCOLON: LOOP DADDRLOOP MOV DX,OFFSET PIDMSG MOV AH,9 INT 21H MOV AL,BPQPID+4 CALL HEXOUT MOV AL,BPQPID+5 CALL HEXOUT MOV AL,CR CALL PRINTIT MOV AL,LF CALL PRINTIT RET NEXTBOARD: CMP AX,8002H JE NOBOARD ; CANT FIND A BOARD/PID INC BPQBOARD JMP GETLOOP NOBOARD: MOV DX,OFFSET NOBOARDMSG JMP ERREXIT ERREXIT: MOV AH,9 INT 21H EXIT: MOV AX,4C01H INT 21H DISPANDEXIT: PUSH AX MOV AH,9 INT 21H POP AX PUSH AX MOV AL,AH CALL HEXOUT POP AX CALL HEXOUT JMP EXIT REGFAILED DB 'FAILED TO REGISTER PROTOCOL STACK $' ADDFAILED DB 'FAILED TO ADD PROTOCOL ID $' NOBOARDMSG DB 'NO BOARD AVAILABLE FOR PROTOCOL BPQ$' BINDFAILED DB 'FAILED TO BIND PROTOCOL STACK $' ; ; STUFF TO PROCESS NET.CFG ; KBBUFF DB 80 DUP (0),0FFH READBLOCK DB 128 DUP (0) READCOUNT DW 128 READPOINTER DW OFFSET READBLOCK ; OPENERROR DB CR,'ODI configuration file NET.CFG not found$',0 HANDLE DW 0 BPQPARAMS DB 'BPQPARAMS' ETH_ADDR DB 'ETH_ADDR ' READCFG: ; ; FILE NAME IS IN DS:DX ; MOV AH,3DH MOV AL,0 ; READ ONLY INT 21H PUSH CS POP DS JNC FILEOPENOK MOV DX,OFFSET OPENERROR MOV AH,9 INT 21H RET ; USE DEFAULT FILEOPENOK: MOV HANDLE,AX ; INITLOOP: CALL GETRECORD CMP AL,1AH JNE NOTINITEND INITEND: MOV BX,HANDLE MOV AH,3EH INT 21H ; CLOSE FILE RET NOTINITEND: MOV SI,OFFSET KBBUFF ; ; SEE IF BPQ PROTOCOL HEADER ; MOV DI,OFFSET BPQPARAMS MOV CX,9 REP CMPSB JNE INITLOOP ; NOT PROTO LINE ; ; FOUND BPQPARAMS IN COL 1 - NOW LOOK FOR ETH_ADDR LINE ; BPQLOOP: CALL GETRECORD CMP AL,1AH JE INITEND MOV SI,OFFSET KBBUFF ; CMP BYTE PTR [SI],20H JNE INITEND ; ANOTHER SECTION HEADER - EXIT CALL SKIPSPACE JZ BPQLOOP ; MOV DI,OFFSET ETH_ADDR MOV CX,9 REP CMPSB JNE BPQLOOP ; NOT ETHADDR LINE CALL SKIPSPACE ; ; EXTRACT TARGET ETHERNET ADDR FROM RECORD MOV CX,6 MOV DI,OFFSET MULTICAST ETHCLOOP: CALL DECODEHEX MOV AL,BYTE PTR NEWVALUE STOSB LOOP ETHCLOOP JMP INITEND SKIPSPACE: ; ; RETURNS NZ IF NONSAPCE CHAR FOUND, ZERO IF RUN OFF END CMP BYTE PTR[SI],20H JNE SPACERET INC SI CMP SI,OFFSET KBBUFF+80 JNE SKIPSPACE SPACERET: RET ; ; GET RECORD FROM INPUT STREAM ; GETRECORD: MOV DI,OFFSET KBBUFF MOV CX,40 MOV AX,2020H REP STOSW MOV DI,OFFSET KBBUFF MOV CX,0 GETRECORDLOOP: CMP DI,OFFSET KBBUFF+80 JA GETRET PUSH CX CALL GETDISK POP CX CMP AL,0DH JE GETRET CMP AL,1AH JNE GET000 GETRET: RET GET000: CMP AL,0AH JE GETRECORDLOOP ; CMP AL,09H ; TAB JNE TABEND ; CONVERTTAB: ; REPLACE TAB WITH SPACES MOV AL,CL AND AL,07H ; MASK TO MULTIPLE OF 8 MOV AH,8 SUB AH,AL MOV AL,20H DEC AH JZ TABEND ; ONLY ONE TABLOOP: STOSB INC CX DEC AH JNZ TABLOOP ; TABEND: ; ; STRIP LEADING SPACES ; CMP AL,'a' JB CASEOK CMP AL,'z' JA CASEOK SUB AL,20H ; CONVERT TO UPPER CASE CASEOK: STOSB INC CX JMP GETRECORDLOOP ; ; GETDISK: ; GET A BYTE FROM DISK BUFFER CMP READCOUNT,128 JE READIT ; GET NEW BLOCK ; MOV SI,READPOINTER ; GET NEXT CHAR POINTER READNEXT: LODSB MOV READPOINTER,SI INC READCOUNT ; CHARS USED (AND SETS NONZERO FLAG) ; RET ; WITH ZERO FLAG NOT SET ; READIT: ; MOV DX,OFFSET READBLOCK MOV AH,3FH ; READ MOV BX,HANDLE MOV CX,128 INT 21H ; CMP AX,0 ; PART RECORD READ JNE READOK ; ENDOFINPUT: ; ; END OF FILE ; MOV READBLOCK,1AH ; READOK: SUB READCOUNT,AX MOV SI,OFFSET READBLOCK JMP READNEXT ; CODE ENDS ; STACK SEGMENT STACK 'STACK' DW 126 DUP (0) STACK ENDS END GO