PAGE ,132 TITLE ADI INT DRIVER FOR MPI 150 PRINTER ; THIS PROGRAM IS A MEMORY RESIDENT UTILITY THAT ; PROVIDES AN ADI DRIVER INTERRUPT PROCESSOR FOR ; AUTOCAD VERSION 2.5 OR HIGHER TO ALLOW PLOTTING ; ON AN MPI 150 OR MPI SPRINTER PRINTER. ; ; BY PATRICK SWAYNE, HUG SOFTWARE ENGINEER 09-NOV-87 ; MOD 29-SEP-88 ; REMOVABLE VERSION 28-FEB-90 TRUE EQU 0FFFFH ;DEFINE TRUE FALSE EQU NOT TRUE ;AND FALSE TEST EQU FALSE ;ASSEMBLE TEST VERSION IF TRUE ADIINT EQU 7BH ;ADI INTERRUPT USED PORT EQU 0 ;PRINTER PORT TO USE (LPT1) TIMEOUT EQU 78H ;ADDRESS OF LPT TIMEOUT JMPF MACRO DB 0EAH ;DEFINE FAR JUMP ENDM CODE SEGMENT ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE ; DEFINE SOME MEMORY LOCATIONS ORG 1 PSPSEG LABEL WORD ;PROGRAM SEGMENT PREFIX SEGMENT ADDR. ORG 3 MCBSIZE LABEL WORD ;MEMORY CONTROL BLOCK SIZE ORG 2CH ENVSEG LABEL WORD ;ENVIRONMENT SEGMENT ORG 5DH FCBARG LABEL BYTE ;FCB ARGUMENT ORG 100H START: JMP SETUP ;SET UP PROGRAM EVEN SIG DB 'ADIMPI 1.1' ; DATA AREA ADIVEC DW 0,0 ;OLD ADI INT VECTOR UNFLG DB 0 ;UNLOAD FLAG OTIMOUT DB 0 ;OLD TIMEOUT NEFLG DB 0 ;NOT EMPTY FLAG LINPTR DW 0 ;LINE POINTER ; OUTPUT LINE BUFFER. THE LINE IS 8 TIMES THE LENGTH ; OF ONE LINE ABOVE, BECAUSE OF 8 DOTS PER BYTE. ; (THE ACTUAL BUFFER IS NOT HERE. A COPY OF THIS HEADER ; IS MOVED TO THE ACTUAL BUFFER.) GRCODE DB 1BH,'W' ;PRINT GRAPHICS COMMAND OUTLINE DB '6' ;END OF LINE MARKER IF TEST DB 1152 DUP (0) ;BUFFER IS HERE IF TEST VERSION ENDIF ENDFLG DB 0 ;END OF PLOT FLAG ENDMSG DB 1BH,'\',0CH ;RESET PRINTER MSG ENDMSZ EQU $-ENDMSG ; ADI INTERRUPT PROCESSOR ADIPROC:PUSH DX ;WE'LL USE THIS STI CMP AX,8001H ;START PLOT? JZ STPLOT ;YES CMP CS:ENDFLG,1 ;THIS PLOT ENDED? JNZ DOPLOT ;NO, CAN DO PLOT POP DX XOR AX,AX IRET DOPLOT: CMP AX,8002H ;END PLOT? JB DATALIN ;NO, MUST BE DATA LINE PUSH SI PUSH DI PUSH DS PUSH ES PUSH CS POP ES ;PUT ES HERE PUSH CS POP DS ;PUT DS HERE MOV ENDFLG,1 ;MARK END OF PLOT JMP PRTLIN ;PRINT THE LAST LINE STPLOT: CLD MOV CS:ENDFLG,0 ;CLEAR END FLAG PUSH DI PUSH CX PUSH ES MOV AX,CS MOV ES,AX ;PUT ES HERE MOV DI,OFFSET LINES ;POINT TO DATA MOV CX,(146*6)/2 MOV AX,0 REP STOSW ;CLEAR INPUT BUFFER MOV AX,40H MOV ES,AX ;POINT TO BIOS RAM MOV DI,OFFSET TIMEOUT+PORT ;POINT TO TIMEOUT FOR CURRENT PORT MOV AL,ES:[DI] ;GET OLD TIMEOUT MOV CS:OTIMOUT,AL ;SAVE IT MOV BYTE PTR ES:[DI],0FFH ;SET TIMEOUT TO MAX POP ES POP CX POP DI MOV AH,2 MOV DX,PORT INT 17H ;TEST PRINTER PORT AND AH,90H CMP AH,90H ;IS PRINTER READY? JNZ PRNBAD ;NO PRCH1: MOV AX,1BH ;AH = 0, AL = ESC INT 17H ;SEND ESCAPE TO INIT PRINTER TEST AH,1 JNZ PRNBAD ;PRINTER CONKED OUT PRCH2: MOV AX,5FH INT 17H ;SET 85 DOTS PER INCH TEST AH,1 JNZ PRNBAD MOV BX,0 ;INDICATE MONOCHROME PRNOK: MOV AX,1 ;RETURN INIT OK POP DX IRET PRNBAD: XOR AX,AX ;RETURN INIT NO GOOD POP DX IRET ; A DATA LINE HAS BEEN SENT. STORE IT, AND IF 6 LINES ; HAVE BEEN SENT, PRINT THEM. DATALIN:PUSH SI ;SAVE SOME REGISTERS PUSH DI PUSH DS PUSH ES PUSH CS POP ES ;PUT ES HERE OR AX,AX ;EMPTY LINE? JZ EMLIN ;IF SO, SKIP IT MOV CS:NEFLG,1 ;MARK LINE NOT EMPTY CMP AX,145 ;TEST LINE SIZE JBE DATAL1 ;OK MOV AX,145 ;ELSE, TRUNCATE DATAL1: MOV DS,CX ;DATA SEGMENT TO DS MOV SI,BX ;DATA OFFSET TO SI MOV CX,AX ;COUNT TO CX MOV AX,ES:LINPTR ;GET LINE POINTER MOV BX,146 ;AND SIZE OF LINE MUL BX ;GET LINE OFFSET ADD AX,OFFSET LINES ;AX = DESTINATION ADDRESS MOV DI,AX ;RESULT TO DI CLD MOV AL,CL STOSB ;STORE COUNT REP MOVSB ;MOVE THE DATA EMLIN: PUSH CS POP DS ;PUT DS HERE MOV AX,LINPTR ;GET LINE POINTER INC AL ;ADD 1 MOV LINPTR,AX ;UPDATE POINTER CMP AL,6 ;6 LINES DONE? JZ PRTLIN ;TIME TO PRINT LINE LINDN: POP ES POP DS POP DI POP SI JMP PRNOK ;EXIT, INDICATING OK PRTLIN: MOV LINPTR,0 ;RESET LINE POINTER CMP NEFLG,0 ;IS LINE EMPTY? JZ DOPRT ;IF SO, SKIP CONVERSION ; FIND OUT WHICH LINE IS LONGEST, AND USE LENGTH FOR ; CONVERSION COUNT MOV SI,OFFSET LINES ;POINT TO LINE 1 MOV AL,[SI] ;GET COUNT THERE MOV CX,5 ;SET COUNTER FNDSIZ: ADD SI,146 ;MOVE TO NEXT LINE CMP AL,[SI] ;COMPARE SIZES JAE SIZOK ;CURRENT SIZE IS OK MOV AL,[SI] ;ELSE, GET BIGGER SIZE SIZOK: LOOP FNDSIZ MOV DH,AL ;SIZE TO DH ; DATA CONVERSION SECTION. WHAT WE HAVE TO DO IS CONVERT ; INFORMATION IN SCREEN (SCAN LINE) FORMAT (HORIZONTAL BYTES ; OF PIXELS) INTO PRINT HEAD FORMAT (VERTICAL BYTES OF DOTS). IF TEST MOV DI,OFFSET OUTLINE ;POINT TO OUTPUT LINE ELSE MOV DI,OFFSET BA.OUTLIN ;POINT TO OUTPUT LINE ENDIF MOV SI,OFFSET LINES+1 ;POINT TO LINES SAVED (LESS COUNT) MLOOP: MOV DL,8 ;8 DOTS PER BYTE BLOOP: MOV AL,0 ;CLEAR OUTPUT BYTE MOV CX,6 ;6 LINES TO PROCESS SLOOP: SHL BYTE PTR [SI],1 ;SHIFT BYTE IN A LINE RCL AL,1 ;PUT RESULT IN OUTPUT BYTE ADD SI,146 ;MOVE TO NEXT LINE LOOP SLOOP ;UNTIL 6 LINES DONE OR AL,40H ;MAKE RESULT ASCII STOSB ;STORE IT SUB SI,146*6 ;MOVE BACK TO LINE 1 DEC DL ;COUNT THIS ROW OF DOTS JNZ BLOOP ;LOOP UNTIL INPUT BYTE PROCESSED INC SI ;MOVE TO NEXT BYTE DEC DH ;COUNT THIS BYTE JNZ MLOOP ;UNTIL ALL BYTES PROCESSED ; STORE ASCII "6" AT THE END OF THE LINE, TO SIGNAL ; THE END OF GRAPHICS PRINTING. MOV AL,'6' STOSB ; NOW, PRINT THE CONVERTED LINE, WHICH REPRESENTS 6 LINES OF ; DATA FROM AUTOCAD. DOPRT: MOV NEFLG,0 ;CLEAR NOT EMPTY FLAG IF TEST MOV SI,OFFSET GRCODE ;POINT TO OUTPUT LINE + GRAPHIC CODE ELSE MOV SI,OFFSET BA.GRCODE1 ;POINT TO OUTPUT LINE + GRAPHIC CODE ENDIF MOV DX,PORT ;SET PRINTER PORT PRLOOP: LODSB ;GET A BYTE MOV AH,0 INT 17H ;PRINT IT TEST AH,1 ;TEST PRINTER JNZ PRTBAD ;IT'S BAD CMP AL,'6' ;DONE? JNZ PRLOOP ;IF NOT, LOOP MOV DI,OFFSET LINES ;POINT TO DATA MOV CX,(146*6)/2 MOV AX,0 REP STOSW ;CLEAR EVERYTHING IF TEST MOV DI,OFFSET OUTLINE ;POINT TO OUTPUT LINE ELSE MOV DI,OFFSET BA.OUTLIN ;POINT TO OUTPUT LINE ENDIF MOV CX,1152/2 REP STOSW IF TEST MOV BYTE PTR OUTLINE,'6' ;ALLOW NULL LINE ELSE MOV BYTE PTR BA.OUTLIN,'6' ;ALLOW NULL LINE ENDIF CMP ENDFLG,1 ;END OF PLOT? JNZ LINDNJ ;NO MOV SI,OFFSET ENDMSG ;POINT TO PRINTER RESET MSG MOV DX,PORT ;SET PRINTER PORT MOV CX,ENDMSZ ;NO. OF CHARACTERS TO PRINT PELOOP: LODSB ;GET A BYTE MOV AH,0 INT 17H ;PRINT IT TEST AH,1 ;TEST PRINTER JNZ PRTBAD ;IT'S BAD LOOP PELOOP ;LOOP UNTIL DONE MOV CL,OTIMOUT ;GET OLD TIMEOUT MOV AX,40H MOV DS,AX ;POINT TO BIOS RAM MOV SI,OFFSET TIMEOUT+PORT ;POINT TO CURRENT TIMEOUT MOV [SI],CL ;RESTORE OLD TIMEOUT LINDNJ: JMP LINDN ;LINE DONE, EXIT PRTBAD: POP ES POP DS POP DI POP SI JMP PRNBAD ;EXIT, INDICATING BAD IF NOT TEST ; INT 28H PROCESSOR. USED FOR UN-INSTALLING ADIMPI. INT28: CMP CS:UNFLG,1 ;UN-INSTALL ADIMPI? JZ UNINS ;YES JMPF INT28V DW 0,0 ;ELSE, EXIT UNINS: PUSH CS POP DS ;POINT TO THIS SEGMENT XOR AX,AX MOV ES,AX ;AND TO INT. SEGMENT MOV SI,OFFSET ADIVEC ;POINT TO ADI INT VECTOR MOV DI,ADIINT*4 ;WHERE IT GOES CLD CLI MOVSW ;RESTORE VECTOR MOVSW MOV SI,OFFSET INT28V ;POINT TO INT 28 VECTOR MOV DI,28H*4 ;WHERE IT GOES MOVSW ;RESTORE VECTOR MOVSW PUSH CS POP ES ;PUT ES HERE MOV AH,49H INT 21H ;RELEASE THIS PROGRAM'S MEMORY MOV ES,ENVSEG ;POINT TO ENVIRONMENT SEGMENT MOV AH,49H INT 21H ;RELEASE ENVIRONMENT SEGMENT STI ;ENABLE INTERRUPTS INT 20H ;EXIT ENDIF BA: ;BUFFER AREA ; INPUT LINE BUFFERS. 6 LINES ARE INPUT AT A TIME ; BECAUSE THE MPI PRINTER DRIVES 6 PINS DURING GRAPHIC ; OUTPUT. LINES LABEL BYTE ;STORE LINES HERE IF TEST DB 146*6 DUP (0) ;STORE LINES HERE IF TEST VERSION ENDIF BUFF STRUC IF TEST DB ? ELSE DB 146*6 DUP (?) ;STORE LINES HERE IF NORMAL VERSION GRCODE1 DB 2 DUP (?) ;PRINT GRAPHICS COMMAND OUTLIN DB ? ;'6' DB 1152 DUP (?) ENDIF ENDRES DB ? ;END OF RESIDENT CODE BUFF ENDS ; INSTALL THIS DRIVER IN MEMORY SETUP: MOV DX,OFFSET SIGNON MOV AH,9 INT 21H ;PRINT SIGN-ON CLD MOV AH,52H INT 21H ;GET MEMORY CONTROL BLOCK ADDR. MOV AX,ES:[BX-2] ;GET FIRST MCB SEGMENT MOV DS,AX ;POINT TO IT FNDLP: MOV AX,PSPSEG ;GET PSP SEGMENT MOV DX,CS CMP AX,DX ;IN THIS SEGMENT? JAE CHKFND ;IF SO, CHECK IF ADIMPI FOUND MOV ES,AX ;ELSE, PSP SEGMENT TO ES MOV SI,OFFSET SIG MOV DI,SI PUSH DS ;SAVE MCB SEGMENT PUSH CS POP DS ;PUT DS HERE MOV CX,5 ;5 WORDS IN SIGNATURE REPZ CMPSW ;IS ADIMPI HERE? JZ GOTCC ;WE FOUND ADIMPI MOV LSTSEG,ES ;SAVE PSP SEGMENT FNDNXT: POP DS ;RESTORE MCB SEGMENT MOV AX,MCBSIZE ;GET MCB SIZE INC AX ;CORRECT IT MOV BX,DS ADD AX,BX ;CALCULATE NEXT MCB SEGMENT MOV DS,AX ;POINT TO IT JMP FNDLP ;TRY AGAIN GOTCC: MOV FNDSEG,ES ;SAVE SEGMENT WHERE FOUND MOV BYTE PTR FNDFLG,1 ;MARK PROGRAM FOUND JMP FNDNXT CHKFND: PUSH CS POP DS ;FIX DS CMP BYTE PTR FNDFLG,1 ;WAS ADIMPI FOUND? JNZ NOTFND ;NO MOV ES,FNDSEG ;GET SEGMENT WHERE FOUND CMP FCBARG,'U' ;UNINSTALL? JZ DOUNIN MOV DX,OFFSET ALMSG MOV AH,9 INT 21H ;SAY "ADIMPI ALREADY IN" INT 20H DOUNIN: MOV BX,FNDSEG ;GET SEGMENT WHERE FOUND CMP BX,LSTSEG ;COMPARE WITH LAST PSP FOUND JNC UNLOK ;OK TO UNLOAD MOV DX,OFFSET NOUNMSG MOV AH,9 INT 21H ;ELSE, SAY "CAN'T UNLOAD" INT 20H UNLOK: MOV DX,OFFSET UNMSG MOV AH,9 INT 21H ;PRINT UNLOAD MESSAGE MOV ES:UNFLG,1 ;FLAG UNLOAD DESIRED INT 20H ;AND EXIT NOTFND: CMP FCBARG,'U' ;UNINSTALL? JNZ DOINS ;NO MOV DX,OFFSET NINMSG MOV AH,9 INT 21H ;ELSE, SAY "ALREADY UNLOADED" INT 20H ;AND EXIT DOINS: PUSH CS POP ES ;FIX ES PUSH DS ;SAVE DS XOR AX,AX MOV DS,AX ;DS AT 0 MOV SI,OFFSET ADIINT*4 ;POINT TO ADI INTERRUPT MOV DI,OFFSET ADIVEC ;PUT OLD VECTOR HERE PUSH SI CLI ;TURN OFF INTERRUPTS CLD MOVSW ;MOVE VECTOR MOVSW POP SI MOV WORD PTR [SI],OFFSET ADIPROC ;PUT IN MY VECTOR MOV 2[SI],CS ;AND THIS SEGMENT IF NOT TEST MOV SI,OFFSET 28H*4 ;POINT TO INT 28 VECTOR MOV DI,OFFSET INT28V PUSH SI MOVSW ;COPY INT 28 VECTOR MOVSW POP SI MOV WORD PTR [SI],OFFSET INT28 ;SET NEW ONE MOV 2[SI],CS ENDIF STI POP DS IF NOT TEST MOV DX,OFFSET INMSG MOV AH,9 INT 21H ;SAY "ADIMPI INSTALLED" MOV SI,OFFSET GRCODE MOV DI,OFFSET BA.GRCODE1 MOV CX,OUTLINE-GRCODE+2 REP MOVSB ;FIX OUTPUT LINE MOV DX,OFFSET BA.ENDRES ;POINT TO END OF RES. CODE INT 27H ;EXIT, LEAVE PROGRAM HERE ELSE MOV AX,8001H INT 7BH ;INITIALIZE PRINTER OR AL,AL ;TEST PRINTER JNZ GOON ;GO ON WITH TEST MOV DX,OFFSET SAYBAD MOV AH,9 INT 21H INT 20H GOON: MOV AX,85 ;GET A BYTE COUNT MOV BX,OFFSET GDATA ;POINT TO GRAPHIC DATA TSTLOOP:MOV CX,DS ;USE THIS DS PUSH AX ;SAVE COUNT PUSH BX ;AND POINTER INT 7BH ;CALL DRIVER POP BX POP AX DEC AX ;MAKE NEXT LINE SHORTER JNZ TSTLOOP MOV AX,8002H INT 7BH ;SIGNAL END XOR AX,AX MOV ES,AX ;AND TO INT. SEGMENT MOV SI,OFFSET ADIVEC ;POINT TO ADI INT VECTOR MOV DI,ADIINT*4 ;WHERE IT GOES CLD MOVSW ;RESTORE VECTOR MOVSW INT 20H SAYBAD DB 13,10,'Printer reported bad.$' GDATA DB 85 DUP (0FFH) ENDIF LSTSEG DW 0 ;LAST PSP SEGMENT (SHOULD BE < PSPSEG) FNDSEG DW 0 ;SEGMENT WHERE FOUND FNDFLG DB 0 ;PROGRAM FOUND FLAG SIGNON DB 13,10,'ADI Driver for MPI 150, 99G, and Sprinter printers,' DB ' v 1.1',13,10 DB 'By Patrick Swayne, HUG Software Engineer',13,10 DB "Copyright (C) 1990 by Heath/Zenith Users' Group",13,10,10,'$' INMSG DB 'ADIMPI is now installed.',13,10 DB 'To uninstall, type ADIMPI U.',13,10,'$' ALMSG DB 'ADIMPI is already installed.',13,10,'$' UNMSG DB 'ADIMPI is now uninstalled.',13,10,'$' NOUNMSG DB "ADIMPI is not the last TSR. Can't uninstall.",13,10,'$' NINMSG DB "ADIMPI is already not installed.",13,10,'$' CODE ENDS END START