page 60,132 comment * PARINT.COM - (C) 1984 by David G Hunter. This program may be freely copied but may not be sold for profit. (Necessary modifications for the early model (1981) IBM PC made by Lawrence B. Afrin, 12/30/84. These modifications are documented at the appropriate point in this program. Modifications are Copyright (c) 1984 by Lawrence B. Afrin. Along with Mr. Hunter's code, these modifications may be freely copied but may not be sold for profit.) PARINT.COM detects parity errors, logs them on the printer if possible, beeps, and returns to program execution. The system does not halt when this program is resident. Parity error checking is terminated after first error is detected. The error message includes the time of the event. If the printer is not available, errors are logged to the screen. * ;***************** Addresses of Interrupt handlers ******************* Book segment at 0h ;this is where the interrupt address books is org 2h*4 ; Int_2 label dword ;address of NMI handler Book ends ;***************** Beginning of PARINT Instructions ******************* cseg segment assume cs:cseg org 100h Start: jmp newvec ;install new NMI handler in RAM ;************************** NMI handler ******************************** newint proc near ;new interrupt handler assume ds:cseg, es:cseg sti ;this flag was cleared when interrupt was issued jmp go ;jump over more data go: push cx push ds pushf push dx push bx push ax pushf mov al, 00h out 0A0h, al ;turn off parity checking for now xor cx, cx ;cx=error flag: cx=1 if parity OK in al,62h ;get data in port C ; - - find origin of NMI - - - - - - test al, 40h jz mother mov dx, offset par2 ;if bit 6 set, error is on expansion board jmp out ; print message and exit mother: test al, 80h jz other mov dx, offset par1 ;if bit 7 set, error is on main board jmp out ;print message and exit other: or cx, 1h ;If neither bit set, no parity error occurred, mov al, 80h ;so set parity OK flag out 0A0h, al ;turn parity checking back on jmp noprt ;Don't print message if not parity error ; - - print error message and exit. Type of exit depends on type of error -- out: mov ax,cs ;establish proper data segment to mov ds,ax ; allow access to messages call whatime ;get time of error mov bx, device1 cmp bx,0004 ;if output is to printer, make sure it's ready jne f1 call testprt f1: call print mov dx, offset time ;"time of error" message call print mov dx, offset paroff call print noprt: popf pop ax pop bx pop dx popf pop ds test cx, 1h ;special exit if parity OK jnz oth pop cx iret ;message printed; let execution continue ; If no parity error, turn control over to pre-existing NMI handler. ; This is done by restoring DS and jumping to the instruction that ; specifies the address of the old interrupt routine. This unusual exit ; is necessary because otherwise, once DS was restored, the address of the ; old interrupt routine would not be accessible. oth: cli pop cx jmp GetOut newint endp ;**************************** SUBROUTINES ****************************** Testprt proc near push dx push ax xor dx,dx ;print # 0 mov ah,2 int 17h ;read printer status test ah,00101001b ;error bits jz aok mov bx, device2 ;if not ok, try other device aok: pop ax pop dx ret testprt endp Print proc near ;output to file named in bx; if error try another file push cx mov cx,34 ;34 characters to print mov ah,40h ;DOS function call int 21h pop cx ret print endp Whatime proc near ;what time is it? put result in hour/min push cx push dx mov ah,2Ch ;DOS time int 21h mov al,ch ;hours (0-23) call convt ;put tens in ah, ones in al mov hour,"00" add hour,ax mov al,cl call convt ;do same for minutes (0-59) mov min,"00" add min,ax pop dx pop cx ret Whatime endp Convt proc near ;convert number (<100) to ASCII. Number is in ;al. result: tens in ah, ones in al. xor ah,ah ;input is less than 100 anyway, so clear it push cx mov cl,10 div cl ;divide ax by 10 pop cx little: ret Convt endp ;------------------------------- DATA ---------------------------------- GetOut: nop Instruc db 0EAh ;this is the jump-immediate instruction! ;it jumps to the address stored in oldint Oldint dd ? ;address of old interrupt 2 routine - Device1 dw 0004 ;printer Device2 dw 0001 ;standard output device par1 db 0Dh,0Ah,"Parity Error: Main Board ",07h,0Dh,0Ah par2 db 0Dh,0Ah,"Parity Error: Expansion Board",07h,0Dh,0Ah time db " TIME: " hour dw "00" db ":" min dw "00" db " ",0Dh,0Ah paroff db "PARITY CHECKING NOW DISABLED ",0Dh,0Ah,0Ah ;---------------------------- MAIN PROGRAM ----------------------------- ;************************* INSTALL NMI HANDLER ************************** Newvec proc near jmp past loaded db 0Dh,0Ah,"PARITY ERROR INTERCEPTOR v2.00 by David Hunter IS NOW" db " INSTALLED",0Dh,0Ah,"$" past: mov dx, offset loaded mov ah,9 int 21h assume ds:Book ;interrupt address book area push ds ;save old ds for future use mov ax,Book mov ds,ax ; NOTE: The following modifications and their associated documentation ; are Copyright (c) 1984 by Lawrence B. Afrin. Further copyright ; information is included in this program's header comment block. ; ; The following two instructions have been removed from David ; Hunter's version by Lawrence B. Afrin because Mr. Afrin found that ; on the original model of the IBM PC (and possibly later models, too), ; these instructions cause the machine to go into the Twilight Zone ; later on when NMI interrupts are re-enabled. For some reason in the ; early IBM PC models, when NMI interrupts are re-enabled after having ; been disabled, the reenabling operation causes the system to signal ; an NMI interrupt. At the point in this program at which that occurs, ; the program is not ready to handle that interrupt and consequently ; dies. Therefore, by preventing the initial disabling of NMI ; interrupts, the problem is take care of. -- LBA, 12/30/84 ; mov al, 00h ; out 0A0h, al ;turn off parity checking mov ax,int_2 ;get the address mov oldint,ax ;save it for some future use mov ax,int_2[2] ;second part of double word mov oldint[2],ax mov int_2, offset newint ;now load the new address mov int_2[2],cs ;cs is ds in com program mov al, 80h ; ; NOTE: It is at the following instruction that the early model PC would ; ordinarily enter the Twilight Zone if the NMI-disabling instructions ; noted above were to be left in the program. Because those instructions ; were removed, the following instruction, which re-enables an already ; enabled NMI mask, has no effect on the machine and does not cause a ; spurious NMI interrupt. ; out 0A0h, al ;turn parity checking back on mov dx, offset newvec ;leave new interrupt routine resident int 27h ;don't need "newvec" or beyond newvec endp cseg ends end start