;V5.7 (Revised 10/17/80) ; ; ;REMOTE CONSOLE PROGRAM FOR CP/M ;BASED ON AN ORIGINAL PROGRAM WRITTEN ;BY DAVE JAFFE, JANUARY 1979 ; ;Rewritten for PMMI modem ;by Ward Christensen, February 1979 ; ;Lobotomized for D C Hayes 80-103 ;by Bruce Ratoff, May 1980 ; ; ;I'd also like to give credit to Bill Precht ; for the "label + offset" idea allowing ; this program to relocate itself ; without using DDT to initially set it up ; ; ;10/17/80 Add "ani 7f" to console output so lower-to-upper case ; conversion doesn't get fooled. (BRR) ; ;10/09/80 Correct 2.X incompatibility in FCB setup for welcome file. ; Also fixed bug that caused loss of welcome file when /A used. ; (BRR) ; ;09/12/80 Reset user 0/drive A in move-up logic so BYE /A works ; from other drives/users. ; by Bruce Ratoff ; ;06/11/80 Ignore modem characters received with framing or overrun ; errors. This should help eliminate some of the noise ; sensitivities. ; by Bruce Ratoff ; ;06/08/80 Added (optional) lower-to-upper case conversion on output ; by asking extra question at signon. ; by Bruce Ratoff ; ;06/04/80 Added keyboard input timeout to eliminate the "asleep ; at the switch" phenomenon and telco noises that sound ; like a carrier. ; by Bruce Ratoff ; ;05/26/80 Put in "warm boot command" logic to force user into ; a chosen CCP command and disable warm boot on entry. ; The JMP at location 0 is replaced by a CALL, which ; is used to tell BYE to disconnect instead of doing ; warm boot. Program may re-enable warm boot by storing ; JMP opcode back into location 0. Also, whenever ; warm boot is disabled, control-c is converted to null. ; by Bruce Ratoff ; ;05/20/80 Put test at CARCK to force valid user/drive, as ; suggested by Keith Petersen. ; by Bruce Ratoff ; ;05/12/80 Changed modem I/O equates, ports and flags for the ; D C Hayes 80-103A. ; By Bruce Ratoff ; ;01/24/80 Added routines to preserve registers when calling ; the user's CBIOS. Added conditional assembly for ; callback feature. Increased stack space to 60. ; By Keith Petersen. ; ;09/24/79 Added routines to allow automatic multiple baud ; rate selection, exit to CP/M from local console, ; echo nr. of nulls selected. By Keith Petersen, ; with thanks to Bob Mathias for suggestions. ; ;05/06/79 Added routine to allow "callback" operation so modem ; does not answer normal voice calls. By Robbin Hough ; and Keith Petersen, W8SDZ. ; ;------------------------------------------------ ;CHANGE THE FOLLOWING EQUATE TO AN AREA IN YOUR ;HI MEMORY WHERE THIS PROGRAM MAY PATCH ITSELF IN. ;APPROX MEMORY REQUIREMENTS: 900 BYTES. ; DEST EQU 0F800H ;RUNNING LOCATION OF CODE ; ;CHANGE THE FOLLOWING TO YOUR LOCAL CONSOLE KEYBOARD ;DATA PORT NUMBER. ; CONDATA EQU 05H ;LOCAL CONSOLE INPUT DATA PORT ; ;CHANGE THE FOLLOWING IF YOUR HAYES IS NOT AT 090H ;(THE OTHER PORT EQUATES ARE BASED ON THIS VALUE) ; DPORT EQU 090H ;UART DATA PORT ; ;YOU WILL LIKELY ALSO WANT TO CHANGE THE PASSWORD, ;LOCATED BELOW AT LABEL "PASSWD", AND THE MESSAGES ;PRINTED AT LABEL "WELCOME" AND JUST ABOVE LABEL ;"HANGUP" ; ;------------------------------------------------ ; ;THIS PROGRAM RUNS UP IN HIGH RAM. IT GETS THERE ;BY BEING MOVED THERE WHEN 'BYE' IS TYPED. ; ;THE PROGRAM IN HI RAM DOES THE FOLLOWING: ; ; 1. HANGS UP THE PHONE ; 2. AWAITS RING DETECT, ALLOWS EXIT ; TO CP/M IF LOCAL KBD TYPES CTL-C ; 3. OUTPUTS CARRIER ; 4. AWAITS INCOMING CARRIER ; GOING TO STEP 1 IF NONE ; FOUND IN 15 SECONDS ; 5. ASKS NUMBER OF NULLS (0-9) ; 6. TYPES THE FILE "WELCOME" FROM ; DISK, ALLOWING CTL-C TO SKIP IT ; 7. ASKS FOR A PASSWORD, ALLOWING ; 5 TRIES TO GET IT RIGHT. ; 8. WHEN PASSWORD ENTERED, DROPS ; INTO CP/M. ; 9. CALLER CAN LEAVE BY HANGING UP, ; (ANY TIME CARRIER IS LOST, IT ; WAITS 15 SECONDS, THEN GOES ; BACK TO STEP 1), OR THE CALLER ; MAY TYPE THE PROGRAM NAME (BYE) ; ; SYSTEM EQUATES: FALSE EQU 0 TRUE EQU NOT FALSE BDOS EQU 5 CR EQU 0DH LF EQU 0AH ; MAX$DRIVE EQU 2 ;HIGHEST SUPPORTED DRIVE (0=A, 1=B, etc) MAX$USER EQU 3 ;HIGHEST SUPPORTED USER PRINTER EQU FALSE ;WANT TO RETAIN LIST DEVICE? DUAL$IO EQU TRUE ;WANT CONSOLE & MODEM? CALLBAK EQU TRUE ;WANT CALLBACK FEATURE? PSWDREQ EQU FALSE ;PASSWORD REQUIRED? FASTCLK EQU TRUE ;TRUE IF 4MHZ SYSTEM CLOCK CPM2 EQU TRUE ;TRUE FOR CP/M VERSION 2.x WBCMND EQU TRUE ;TRUE TO USE WARM BOOT COMMAND WBUSER EQU 3 ;USER # FOR WARM BOOT COMMAND (MUST BE 0 IN 1.4 CP/M) WBDRV EQU 0 ;DRIVE # FOR WARM BOOT COMMAND (0=A, 1=B, ETC.) ; (COMMAND STRING GOES AT LABEL 'WBCSTR' NEAR ; END OF PROGRAM) TIMEOUT EQU TRUE ;TRUE IF TIMING OUT ON CONSOLE INPUT TOVALUE EQU 20*5*60 ;TIMEOUT TIME IN 20THS OF A SECOND ; ; HAYES MODEM PORT ASSIGNMENTS: ; ;HAYES MODEM PORT EQUATES (DPORT PREVIOUSLY DONE) ; TPORT EQU DPORT+1 ;CONTROL/STATUS PORT RPORT EQU DPORT+1 ;RATE GEN/MODEM STATUS CPORT EQU DPORT+2 ;MODEM CONTROL ; ;MODEM CONTROL COMMAND WORDS ; P3CLEAR EQU 00H ;IDLE MODE ; ; ; ;SWITCH HOOK AND MODEM COMMANDS, ; OUTPUT TO TPORT (PORT 0) ; P0BYE EQU 0 ;ON HOOK, OR DIALING BREAK P0ORIG EQU 84H ;OFF HOOK, ORIG. P0ANSW EQU 82H ;ANSWER PHONE P08BIT EQU 06H ;8 DATA BITS P0NOPY EQU 10H ;NO PARITY P0EPS EQU 01H ;EVEN PARITY SELECT P0TSB EQU 08H ;2 STOP BITS P0EI EQU 20H ;ENABLE INTERRUPTS P0NORM EQU P08BIT+P0NOPY ;I USE 8 BITS, NO PARITY P0110 EQU P08BIT+P0NOPY+P0TSB ;SAME W/2 STOP BITS ; ;MODEM STATUS, INPUT ON TPORT (PORT 1) ; P2RDET EQU 80H ;RING DETECT P2CTS EQU 40H ;CTS (CARRIER DETECT) ; ;HAYES MODEM STATUS MASKS ; P0TBMT EQU 2 ;XMIT BUFF EMPTY P0DAV EQU 1 ;DATA AVAILABLE P0RPE EQU 4 ;REC'D PARITY ERR P0ORUN EQU 10H ;OVERRUN P0FERR EQU 08H ;FRAMING ERROR ; ;BAUD RATE DIVISORS ; B110 EQU 0 ;110 BAUD B300 EQU 1 ;300 BAUD ; ORG 100H ; ;MOVE THE MODEM INTERFACE PROGRAM UP TO HI RAM ;AND JUMP TO IT. ; MOVEUP lxi sp,80h ;set a temporary stack LXI B,PEND-START+1 ;NUMBER OF BYTES TO MOVE LXI H,DEST+PEND-START+1 ;END OF MOVED CODE LXI D,SOURCE+PEND-START ;END OF SOURCE CODE MVLP LDAX D ;GET BYTE DCX H ;BUMP POINTERS MOV M,A ;NEW HOME DCX D DCX B ;BUMP BYTE COUNT MOV A,B ;CHECK IF ZERO ORA C JNZ MVLP ;IF NOT, DO SOME MORE push h ;save jump address sub a ;force user 0, disk A sta 4 ;at next sign-in IF CPM2 mvi e,0 ;need to set user 0 in bdos mvi c,32 ;so that open succeeds on welcome file call bdos ENDIF mvi e,0 mvi c,14 ;also need drive A default call bdos mvi a,0C3H ;reset boot trap/control-c trap sta 0 ret ;JUMP TO "START" (was PUSHed above) ; SOURCE EQU $ ;BOUNDARY MEMORY MARKER ; OFFSET EQU DEST-SOURCE ;RELOC AMOUNT ;-----------------------------------------------; ; THE FOLLOWING CODE GETS MOVED ; ; TO HI RAM LOCATED AT "DEST", ; ; WHERE IT IS EXECUTED. ; ;-----------------------------------------------; ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;XX C A U T I O N : IF MODIFYING ANYTHING XX ;XX IN THIS PROGRAM FROM HERE ON: XX ;XX A-L-L LABELS MUST BE OF THE FORM: XX ;XX label EQU $+OFFSET XX ;XX IN ORDER THAT THE RELOCATION TO HI RAM XX ;XX WORK SUCCESSFULLY. FORGETTING TO XX ;XX SPECIFY '$+OFFSET' WILL CAUSE THE PRO- XX ;XX GRAM TO JMP INTO WHATEVER IS CURRENTLY XX ;XX IN LOW MEMORY, WITH UNPREDICTABLE XX ;XX RESULTS. BE CAREFUL.... XX ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ; ; IF CARRIER LOST, HANG UP, AWAIT RING. ; OTHERWISE, SAY GOODBYE, AND HANG UP ; START EQU $+OFFSET LXI SP,STACK XRA A ;GET 0 STA LOSTFLG ;SHOW NO CARR. LOST ;CHECK FOR /A OPTION ON COMMAND - REQUEST TO ;GO IMMEDIATELY INTO ANSWER MODE LXI H,FCB+1 ;TO OPTION MOV A,M CPI '/' ;OPTION? JNZ NOSLASH ;GOT AN OPTION - VALIDATE IT INX H ;TO OPTION BYTE MOV A,M ;GET IT CPI 'A' ;ANSWER? JZ ANSWER ;NO OPTION, OR INVALID ONE NOSLASH EQU $+OFFSET CALL CARCK ;SIGNED OFF W/THIS PROG? JC HANGUP ;NOBODY THERE CALL ILPRT ;PRINT THIS MSG: DB CR,LF,'GOOD BYE, CALL AGAIN' DB CR,LF,CR,LF,0 CALL UNPATCH ;UNDO BIOS PATCHES ; ; ; NOBODY THERE, OR WE ARE DONE, SO HANG UP ; HANGUP EQU $+OFFSET LXI SP,STACK ;SET UP LOCAL STACK sub a ;force user 0, disk A sta 4 ;at next sign-in IF CPM2 mvi e,0 ;need to set user 0 in bdos mvi c,32 ;so that open succeeds on welcome file call bdos ENDIF mvi e,0 mvi c,14 ;also need drive A default call bdos mvi a,0C3H ;reset boot trap/control-c trap sta 0 ; ;CLEAR DTR CAUSING PHONE TO HANG UP MVI A,P3CLEAR ;CLEAR.. OUT CPORT ;..DTR ; ; AWAIT RINGING ; RINGWT EQU $+OFFSET ;CHECK LOCAL KEYBOARD FOR CTL-C EXIT REQUEST. ;NOTE: MUST DO DIRECT INPUT BECAUSE CBIOS PATCHES ;ARE NOT DONE UNTIL CALL COMES IN. IN CONDATA ;CHECK LOCAL KBD ANI 7FH ;STRIP PARITY BIT CPI 'C'-40H ;CONTROL C? JZ 0 ;YES, --EXIT-- TO CP/M ; RINGW2 EQU $+OFFSET IN RPORT ;GET THE STATUS ANI P2RDET ;RINGING? JNZ RINGWT ;NO, WAIT ; ;THE PHONE IS RINGING, NOW WAIT UNTIL RING IS FINISHED ENDRING EQU $+OFFSET CALL DELAY ;.1 SEC DELAY FOR DEBOUNCE IN RPORT ;GET STATUS ANI P2RDET ;STILL RINGING? JZ ENDRING ;WAIT UNTIL RING FINISHED ; IF CALLBAK ;NEXT ROUTINES IMPLEMENT CALLBACK ; ; THIS ROUTINE MINIMIZES THE COMPUTER'S INTERFERENCE ; WITH NORMAL HOUSEHOLD PHONE USE BY HAVING COMPUTER ; FOLK DIAL, LET THE PHONE RING ONCE, HANG UP AND ; THEN DIAL AGAIN. WHEN THE PHONE RINGS ONLY ONCE IT ; ALERTS THE COMPUTER WHICH THEN WAITS FOR AND ANSWERS ; ANY RING WHICH OCCURS WITHIN THE NEXT 40 SECONDS. ; MVI L,45 ;DELAY 4.5 SECONDS FOR NEXT RING WAITNX EQU $+OFFSET CALL DELAY ;WAIT .1 SECONDS DCR L ;MORE TO GO? JNZ WAITNX ;YES?...LOOP IN RPORT ;GET THE STATUS ANI P2RDET ;RINGING AGAIN? JNZ EXPECT ;NO?...ITS FOR ME! ;CALL NOT FOR COMPUTER - WAIT UNTIL RINGING DONE, THEN RESET WAITNR EQU $+OFFSET MVI L,100 ;WAIT FOR 10 SECS NO RINGING WAITNRL EQU $+OFFSET CALL DELAY ;DELAY .1 SECONDS IN RPORT ;GET THE STATUS ANI P2RDET ;STILL RINGING? JZ WAITNR ;YES, WAIT 10 MORE SECONDS DCR L ;NO RING, MAYBE WE'RE DONE JNZ WAITNRL ;NO, LOOP SOME MORE JMP HANGUP ; EXPECT EQU $+OFFSET LXI H,400 ;40 SECONDS TO REDIAL RELOOK EQU $+OFFSET IN RPORT ANI P2RDET ;RINGING AGAIN? JZ ANSWER CALL DELAY DCX H MOV A,H ORA L JNZ RELOOK JMP HANGUP ; ENDIF ;END OF CALLBACK ROUTINES ; ;SETUP MODEM ANSWER EQU $+OFFSET MVI A,P0ANSW ;TURN ON OUT CPORT ;..DTR MVI E,20 ANSWR1 EQU $+OFFSET CALL DELAY ;GIVE TIME TO TURN ON DCR E JNZ ANSWR1 MVI A,P0110 OUT TPORT ;ANSWER PHONE CALL DELAY ;GIVE TIME FOR ANSWER IN CONDATA ;CLEAR LOCAL KBD PORT IN DPORT ;CLEAR MODEM PORT IN DPORT ;MAKE SURE ITS CLEAR ;OUTPUT VALUE ALLOWING MODEM TO HANG UP ON ;LOSS OF CARRIER CALL CARCK ;LOOK FOR CARRIER JC HANGUP ;AWAIT ANOTHER CALLER ;NOW TEST INPUT FOR BAUD RATE CALL PATCH ;PATCH JMP TABLE CALL TSTBAUD ;SEE IF BAUD = 110 JZ WELCOME ;YES, EXIT MVI A,P0NORM ;SET FOR 1 STOP BIT, ETC. OUT TPORT MVI A,B300+P0ANSW ;SET DIVISOR OUT CPORT ;.. TO 300 RATE CALL TSTBAUD ;SEE IF BAUD = 300 JZ WELCOME ;YES, EXIT CALL UNPATCH ;RESTORE ORIG BIOS JMP TBL JMP ANSWER ;TEST MORE - INVALID BAUD RATE ; ;WELCOME TO THE SYSTEM ; WELCOME EQU $+OFFSET ; GETNULL EQU $+OFFSET CALL ILPRT ;PRINT THIS MSG: DB CR,LF DB 'HOW MANY NULLS DO YOU NEED? ',0 CALL MINPUT ;GET VALUE MOV C,A CALL MOUTPUT ;ECHO CHAR MOV A,C CPI '0' JC GETNULL ;BAD, RETRY CPI '9'+1 JNC GETNULL ;BAD SUI '0' ;MAKE BINARY STA NULLS ;SAVE COUNT GETULC EQU $+OFFSET CALL ILPRT DB CR,LF,'CAN YOUR TERMINAL DISPLAY LOWER CASE? ',0 MVI A,20H STA ULCSW ;FORCE CASE CONVERSION FOR NOW CALL MINPUT ;GET Y OR N MOV C,A CALL MOUTPUT ;ECHO CPI 'N' JZ DONEOPT ;WE'RE ALREADY SET UP FOR NO LOWER CASE CPI 'Y' JNZ GETULC ;WASN'T Y OR N...RE-ASK SUB A STA ULCSW ;SET FLAG FOR NO CONVERSION DONEOPT EQU $+OFFSET CALL ILPRT DB CR,LF,0 ;PRINT THE WELCOME FILE LXI H,WELFILN ;SOURCE LXI D,FCB ;DESTINATION MVI B,16 ;LENGTH CALL MOVE ;MOVE THE NAME ;SET DMA ADDR TO 80H LXI D,80H MVI C,STDMA CALL BDOS ;OPEN THE WELCOME FILE LXI D,FCB MVI C,OPEN CALL BDOS ;DID IT EXIST? INR A ;A=> 0 MEANS "NO" JZ PASSINT ;NO WELCOME FILE ;GOT A FILE, TYPE IT XRA A ;GET 0 STA FCBRNO ;ZERO RECORD # LXI H,100H ;GET INITIAL BUFF POINTER ;TYPE THE WELCOME FILE WELTYLP EQU $+OFFSET CALL RDBYTE ;GET A BYTE CPI 1AH ;EOF? JZ PASSINT ;YES, DONE MOV C,A ;SETUP FOR TYPE CALL MOUTPUT ;TYPE THE CHAR CALL MSTAT ;CHECK FOR.. ORA A ;CHAR TYPED? JZ WELTYLP ;..NO, LOOP CALL MINPUT ;..YES, GET CHAR CPI 'C'-40H ;CTL-C? JNZ WELTYLP ;..NO, LOOP UNTIL EOF ; ;GET THE PASSWORD ; PASSINT EQU $+OFFSET IF PSWDREQ MVI D,5 ;5 TRIES AT PASSWORD PASSINP EQU $+OFFSET CALL ILPRT DB CR,LF,'ENTER PASSWORD: ',0 LXI H,PASSWD ;POINT TO PASSWORD MVI E,0 ;NO MISSED LETTERS IN DPORT ;CLEAR OUT GARBAGE PWMLP EQU $+OFFSET CALL MINPUT ;GET A CHAR CPI 'U'-40H ;CTL-U? JZ PASSINP ;YES, RE-GET IT CPI 60H ;LOWER CASE? JC NOTLC ;NO, ANI 5FH ;MAKE UPPER CASE ALPHA NOTLC EQU $+OFFSET CMP M ;MATCH PASSWORD? JZ PWMAT ;..YES MVI E,1 ;..NO, SHOW MISS CPI CR ;C/R? JNZ PWMLP ;..NO, WAIT FOR C/R ;PASSWORD DIDN'T MATCH PWNMAT EQU $+OFFSET CALL ILPRT DB '++INCORRECT++',CR,LF,0 DCR D ;MORE TRIES? JNZ PASSINP ;YES JMP BADPASS ;NO, GO HANG UP ;CHARACTER MATCHED IN PASSWORD PWMAT EQU $+OFFSET INX H ;TO NEXT CHAR CPI CR ;END? JNZ PWMLP ;..NO, LOOP ;END OF PASSWORD. ANY MISSED CHARS? MOV A,E ;GET FLAG ORA A JNZ PWNMAT ;NOT RIGHT ENDIF ;PASSWORD CORRECT CALL ILPRT DB CR,LF,'BOOTING SYSTEM...',0 IF WBCMND MVI A,0FFH ;SET WARM BOOT FLAG (TESTED AT MOUTPUT) STA WBFLAG ENDIF JMP VWARMBT ;GO LOAD CP/M ; ;TSTBAUD ATTEMPTS TO READ A LF OR CR, RETURNS WITH ;ZERO FLAG IF THE CHARACTER READ IS ONE OF THESE TWO. ; TSTBAUD EQU $+OFFSET CALL MINPUT ;GET CHARACTER FROM MODEM CPI CR ;IF A CARRIAGE RETURN... RZ ;.. RETURN CPI LF ;IF A LINEFEED... RET ;RET ZERO FLAG, ELSE NOT ZERO ; ; LOSS OF CONNECTION TEST ; ;THIS ROUTINE AUTOMATICALLY HANGS UP THE ;PHONE AFTER LOSS OF CARRIER ; ;THIS ROUTINE CHECKS IF CARRIER IS STILL ;PRESENT, AND IF SO, RETURNS WITH CARRY CLEAR. ;IF NOT, IT WAITS FOR CARRIER FOR 15 SECS. ;IF THIS TIME RUNS OUT, IT RETURNS WITH CARRY SET. ; ; CARCK EQU $+OFFSET PUSH D MVI E,150 CARCK1 EQU $+OFFSET IN RPORT ;LOOK AT STATUS ANI P2CTS ;GET CARRIER DETECT BIT JNZ CARCK2 ;IF CARRIER ON, continue with checks ;LOOP UNTIL EITHER TIME EXHAUSTED, OR ;CARRIER RETURNS CALL DELAY ;KILL .1 SEC DCR E ;COUNT DOWN TIME JNZ CARCK1 STC pop d ret CARCK2 EQU $+OFFSET lda 4 ;check disc/user # ani 0fh ;isolate drive cpi max$drive+1 ;valid drive? jc carck3 ;yes, skip this junk lda 4 ;restore whole login byte ani 0f0h ;retain user # sta 4 ;force drive to A jmp 0 ;force warm boot (punishment?) carck3 equ $+offset if cpm2 ;skip this junk if cp/m 1.x lda 4 ;re-fetch login byte ani 0f0h ;isolate user # cpi max$user*16+1 ;valid user ? jc carck4 ;yes, don't change lda 4 ;refresh login byte again ani 0fh ;keep drive, zero user sta 4 jmp 0 ;force warm boot endif ;end of cp/m 2.x dependant stuff CARCK4 EQU $+OFFSET ora a ;clear carry POP D RET ; ; .1 SEC DELAY ROUTINE ; DELAY EQU $+OFFSET PUSH B IF FASTCLK LXI B,16667 ;.1 SEC COUNT FOR 4MHZ SYS CLOCK ENDIF IF NOT FASTCLK LXI B,8334 ;.1 SEC COUNT FOR 2MHZ SYS CLOCK ENDIF DELAY1 EQU $+OFFSET DCX B ;COUNT DOWN DELAY TIME MOV A,B ORA C JNZ DELAY1 ;CONTINUE COUNTING TILL DONE POP B RET ; ; KDELAY EQU $+OFFSET PUSH B IF FASTCLK LXI B,8334 ;.05 SEC COUNT FOR 4MHZ ENDIF IF NOT FASTCLK LXI B,4167 ;.05 SEC COUNT FOR 2MHZ ENDIF JMP DELAY1 ; ; ;PATCH IN THE NEW JMP TABLE (SAVING THE OLD) ; PATCH EQU $+OFFSET CALL TBLADDR ;CALC HL= CP/M JMP TABLE LXI D,VCOLDBT ;POINT TO SAVE LOCATION CALL MOVE ;MOVE IT ;NOW MOVE NEW JMP TABLE TO CP/M CALL TBLADDR ;CALC HL=CP/M'S JMP TABLE XCHG ;MOVE TO DE LXI H,NEWJTBL ;POINT TO NEW CALL MOVE ;MOVE IT RET ; UNPATCH EQU $+OFFSET CALL TBLADDR ;HL=CP/M'S JMP TABLE XCHG ;MOVE TO DE LXI H,VCOLDBT ;GET SAVED TABLE CALL MOVE ;MOVE ORIG BACK RET ; ;CALCULATE HL=CP/M'S JUMP TABLE, B=LENGTH ; TBLADDR EQU $+OFFSET LHLD 1 ;GET BIOS POINTER DCX H ;..SKIP DCX H ;..TO DCX H ;..COLD BOOT ; IF NOT PRINTER MVI B,18 ;BYTES TO MOVE ENDIF ; IF PRINTER ;RETAIN LIST DEVICE? MVI B,15 ;DON'T MOVE LISTER JUMP ENDIF ; RET ; ;MOVE (HL) TO (DE), LENGTH IN (B) ; MOVE EQU $+OFFSET MOV A,M ;GET A BYTE STAX D ;PUT AT NEW HOME INX D ;BUMP POINTERS INX H DCR B ;DEC BYTE COUNT JNZ MOVE ;IF MORE, DO IT RET ;IF NOT,RETURN ; ;COMMON ROUTINE TO CHECK FOR CARRIER LOST, ;CALLED FROM CONSOLE STATUS, AND CONSOLE OUT ; CHECK EQU $+OFFSET CALL CARCK ;SEE IF CARRIER STILL ON RNC ;ALL OK ;CARRIER IS LOST. TYPE MESSAGE SO LOCAL CONSOLE ; SHOWS THE REASON BADPASS EQU $+OFFSET ;COME HERE ON BAD PASSWORD MVI A,1 ;SHOW CARRIER LOST SO STA LOSTFLG ;..WE WON'T CK AGAIN LXI SP,STACK ;ENSURE VALID STACK CALL ILPRT DB CR,LF DB '++CARRIER LOST++' DB CR,LF,' ',0 CALL UNPATCH ;RESTORE ORIG BIOS JMP TBL XRA A ;CLEAR OUT CARRIER.. STA LOSTFLG ;..LOST FLAG JMP HANGUP ; ;READBYTE ROUTINE - USED TO READ THE ; WELCOME FILE ; RDBYTE EQU $+OFFSET MOV A,H ;TIME TO READ? ORA A ;..IF AT 100H JZ NORD ;NO READ REQ'D ;HAVE TO READ A SECTOR LXI D,FCB MVI C,READ CALL BDOS ORA A ;OK? MVI A,1AH ;FAKE UP EOF RNZ ;RET EOF IF BAD LXI H,80H NORD EQU $+OFFSET MOV A,M ;GET CHAR INX H ;TO NEXT RET ; ;KEYBOARD/MODEM STATUS TEST ROUTINE ; MSTAT EQU $+OFFSET ; IF DUAL$IO ;WANT LOCAL CONSOLE? CALL CONSTAT ;GET LOCAL STATUS ORA A RNZ ;RET IF LOCAL CHAR ENDIF ; IN TPORT ;GET STATUS ANI P0DAV ;DATA AVAILABLE? RZ ;RETURN IF NOT READY IN TPORT ;GET STATUS AGAIN ANI 18H ;CHECK FRAMING AND OVERRUN BITS JZ MSTAT1 ;NO ERRORS...LEGIT CHARACTER IN DPORT ;SWALLOW CHARACTER (CLEARS P0DAV) SUB A ;RETURN FALSE (0) RET MSTAT1 EQU $+OFFSET MVI A,0FFH ;SHOW READY ORA A RET ; ;MODEM INPUT FUNCTION, CHECKS LOCAL CONSOLE FIRST ; MINPUT EQU $+OFFSET IF TIMEOUT PUSH H ;INITIALIZE TIMEOUT COUNTER LXI H,TOVALUE SHLD TOCNT POP H ENDIF MINPUT1 EQU $+OFFSET LDA LOSTFLG ;KNOWN LOSS.. ORA A ;..OF CARRIER? CZ CHECK ;CARRIER STILL ON? ; CALL MSTAT ;ANYTHING? ORA A ; IF NOT TIMEOUT JZ MINPUT ;LOOP TILL CHAR RCD ENDIF ; IF TIMEOUT JNZ MINPUT2 CALL KDELAY ;KILL .05 SEC PUSH H LHLD TOCNT ;KNOCK DOWN TIMEOUT COUNTER DCX H SHLD TOCNT MOV A,H ORA L POP H JNZ MINPUT1 ;STILL MORE TIME...KEEP TRYING CALL ILPRT DB '+++INPUT TIMED OUT',7,7,0 JMP NOSLASH ENDIF ; ;GOT CHAR - SEE WHICH PORT ; MINPUT2 EQU $+OFFSET IF DUAL$IO ;BOTH LOCAL AND REMOTE? CALL CONSTAT ;CHECK LOCAL CONSOLE ORA A ;CHAR? JNZ CONIN ;..YES, READ IT, RET. ENDIF ; ;LOCAL CONSOLE WASN'T READY, SO READ MODEM IN DPORT ;GET DATA BYTE ANI 7FH ;DELETE PARITY JZ MINPUT ;IGNORE NULLS IF WBCMND CPI 3 ;CONTROL-C? RNZ ;NO, PASS IT THRU LDA 0 ;SEE IF WARM BOOT DISABLED CPI 0C3H ;JMP MEANS WARM BOOT OK MVI A,3 ;SO RETURN CONTROL-C AS TYPED RZ SUB A ;ELSE CONVERT IT TO A NULL ENDIF RET ; ;MODEM OUTPUT ROUTINE. OUTPUTS TO MODEM, ;THEN TO LOCAL CONSOLE ; MOUTPUT EQU $+OFFSET ;IF WE ALREADY KNOW CARRIER IS LOST, ;DON'T CHECK FOR IT AGAIN LDA LOSTFLG ;KNOWN LOSS OF CARRIER? ORA A CZ CHECK ;CARRIER STILL ON? IF WBCMND LDA WBFLAG ;IS THIS FIRST WARM BOOT SINCE SIGNON? ORA A ;IF NOT, SKIP THIS STUFF JZ MOUTP1 SUB A ;TURN OFF FLAG FOR NEXT TIME STA WBFLAG MVI A,0CDH ;DISABLE WARM BOOT STA 0 LDA 7 ;GET BDOS ADDRESS SUI 8 ;CCP IS 2K DOWN FROM BDOS MOV H,A MVI L,0 ;HL NOW CONTAINS CCP ENTRY ADDRESS PUSH H ;SAVE FOR LATER MVI L,7 ;POINT TO BYTE COUNT IN CCP COMMAND BUFFER XCHG ;MAKE IT DEST POINTER (DE) LXI H,WBCSTR ;POINT TO COMMAND STRING TO DROP IN MOV B,M ;GET BYTE COUNT INR B ;UP BY 2 TO INCLUDE COUNT AND TRAILING NULL INR B CALL MOVE ;DROP IT IN TO CCP MVI A,WBUSER*16+WBDRV ;SET LOCATION 4 (USER/DRIVE) STA 4 MOV C,A ;ALSO PASS IT TO CCP POP H ;GET BACK CCP ENTRY ADDRESS PCHL ;GO THERE MOUTP1 EQU $+OFFSET ENDIF IN TPORT ;READ MODEM STATUS ANI P0TBMT ;XMIT BUFF EMPTY? JZ MOUTPUT ;LOOP IF NOT READY MOV A,C ;GET CHAR ANI 7FH ;STRIP HIGH BIT CPI 60H ;CHECK FOR LOWER CASE JC MOUTP2 ;SKIP IF NOT LC CPI 7FH ;CHECK FOR RUBOUT JZ MOUTP2 PUSH H LXI H,ULCSW ;SUBTRACT EITHER 20H OR 0 SUB M POP H MOV C,A ;FORCE ON LOCAL AS WELL AS REMOTE MOUTP2 EQU $+OFFSET OUT DPORT ;OUTPUT TO MODEM ; IF DUAL$IO ;TO LOCAL ALSO? CALL CONOUT ;SEND TO REGULAR BIOS ENDIF ; ;CHECK FOR NULLS ; CPI LF ;TIME FOR NULLS? RNZ ;NO, RETURN ;SEND NULLS IF REQUIRED LDA NULLS ;GET COUNT ORA A ;ANY? RZ ;..NO PUSH B MOV B,A ;SAVE COUNT MVI C,0 ;0 IS A NULL NULLP EQU $+OFFSET CALL MOUTPUT ;TYPE A NULL DCR B ;MORE? JNZ NULLP ;..YES, LOOP POP B RET ; ;BOOT TRAP - BECOMES DISCONNECT IF JMP AT 0 HAS BEEN ALTERED ; MBOOT EQU $+OFFSET LDA 0 ;LOOK AT OPCODE CPI 0C3H ;IS IT STILL JMP? JZ VWARMBT ;YES, ALLOW IT JMP NOSLASH ;NO, DISCONNECT ; ; INLINE PRINT ROUTINE ; CALL ILPRT ; DB 'MSG',0 ; ILPRT EQU $+OFFSET XTHL ;SAVE HL, GET MSG PUSH B ;SAVE ILPLP EQU $+OFFSET MOV C,M ;GET CHAR CALL MOUTPUT ;OUTPUT IT INX H ;POINT TO NEXT MOV A,M ;TEST ORA A ;..FOR END JNZ ILPLP POP B ;RESTORE XTHL ;RESTORE HL, RET ADDR RET ;RET PAST MSG ; ;ACCESS PASSWORD (ENDS IN C/R) ; PASSWD EQU $+OFFSET DB '******' ;THE PASSWORD ITSELF DB CR ;END OF PASSWORD ;ALLOW ROOM FOR BIGGER PASSWORD TO BE ; PATCHED IN DB 0,0,0,0,0,0,0,0,0,0,0,0,0 ; ;WARM BOOT COMMAND STRING ; IF WBCMND WBCSTR EQU $+OFFSET DB WBCEND-WBCSTR-2 DB 'RIBBS' DB 0 WBCEND EQU $+OFFSET ENDIF ; ;THIS AREA IS USED FOR VECTORING CALLS TO THE ;USER'S CBIOS, BUT SAVING THE REGISTERS FIRST ;IN CASE THEY ARE DESTROYED. ; CONSTAT EQU $+OFFSET PUSH B PUSH D PUSH H CALL VCONSTAT POP H POP D POP B RET ; CONIN EQU $+OFFSET PUSH B PUSH D PUSH H CALL VCONIN POP H POP D POP B RET ; CONOUT EQU $+OFFSET PUSH B PUSH D PUSH H CALL VCONOUT POP H POP D POP B RET ; ; THIS IS THE JMP TABLE WHICH IS COPIED ; ON TOP OF THE ONE POINTED TO BY ; LOCATION 1 IN CP/M ; NEWJTBL EQU $+OFFSET JMP MBOOT ;BOOT TRAP JMP MBOOT ;BOOT TRAP JMP MSTAT ;MODEM STATUS TEST JMP MINPUT ;MODEM INPUT ROUTINE JMP MOUTPUT ;MODEM OUTPUT ROUTINE RET ;DUMMY LIST DEVICE NOP NOP ; WELFILN EQU $+OFFSET DB 0,'WELCOME ',0,0,0,0 ;WELCOME FILE NAME ^^^^^^^^^^^ ; NULLS EQU $+OFFSET DB 5 WBFLAG EQU $+OFFSET DB 0 TOCNT EQU $+OFFSET DW 0 ULCSW EQU $+OFFSET DB 0 ; PEND EQU $+OFFSET ;END OF RELOCATED CODE ; ;KEEP TRACK OF LOST CARRIER WHEN TYPING ;"++CARRIER LOST++" SO WE DON'T LOOP ; LOSTFLG EQU $+OFFSET DS 1 ; ;SAVE THE CP/M JUMP TABLE HERE ; VCOLDBT EQU $+OFFSET DS 3 VWARMBT EQU $+OFFSET DS 3 VCONSTAT EQU $+OFFSET DS 3 VCONIN EQU $+OFFSET DS 3 VCONOUT EQU $+OFFSET DS 3 VLISTOUT EQU $+OFFSET DS 3 ; DS 60 STACK EQU $+OFFSET ;LOCAL STACK ; WRCON EQU 2 OPEN EQU 15 READ EQU 20 STDMA EQU 26 FCB EQU 5CH FCBRNO EQU FCB+32 ; END