Sample Printer Driver Skeleton For PC-DOS
Clayton Cramer
cramer at kontron.UUCP
Tue Jan 20 11:41:34 AEST 1987
Several weeks ago I asked for help relating to building an interrupt
service routine so that I can build a C program that takes the standard
PC-DOS printer driver. A number of people provided very helpful advise.
Consequently, I am posting the following code to provide a skeleton
so that can build your own TSR programs that take over the printer ISR.
It's not copyrighted, but when you get filthy rich writing the next
1-2-3, I sure hope you'll remember where you got your start. :-)
The following files are included:
make Makes the various components of the TSR and the
testing filter.
loadisr.c Loads the ISR and gets it started.
isr.asm The actual ISR that dispatches control to the
C function.
filter.c A C function that is called by isr.asm.
testfilt.c A program that simulates the functions of isr.asm
so that you can debug filter.c without the extraneous
junk involved with the interrupt service routine.
Use Microsoft C V4.0 and MASM V4.0.
It's not beautiful, and it's not perfect, but it does work.
Also, can anyone tell me:
1. how to make a TSR program go away?
2. how to figure out the size of a .EXE file at link time?
--------------make file----------------------------------------
.c.exe:
cl -DLINTARGS /Zi /Od $*.c
.asm.obj:
masm $*.asm,$*.obj,$*.lst;
# The filter written in C.
filter.obj: filter.c
cl /Gs /AL -DLINTARGS -c /Zi /Od $*.c
# The interrupt service routine that invokes the filter written in C.
isr.obj: isr.asm
# The C program that loads the ISR and the filter.
loadisr.obj: loadisr.c
cl /AL -DLINTARGS -c /Zi /Od $*.c
# The link step that links the ISR, the ISR loader, and the filter.
filter.exe: loadisr.obj isr.obj filter.obj
cl /AL /Zi /Od filter.obj loadisr.obj isr.obj
# The C program that tests the filter.
testfilt.obj: testfilt.c
cl /AL -DLINTARGS -c /Zi /Od $*.c
testfilt.exe: testfilt.obj filter.obj
cl /AL /Zi /Od testfilt.obj filter.obj
--------------------loadisr.c----------------------------------------
#include <stdio.h>
#include <dos.h>
#define _ProgramSize_ 25000
extern char far *DRIVERPTR;
extern void far SETINTNBR ();
extern void far SAVE_DS_SS ();
int IntNbrToTakeOver = 0x61;
main (Argc, Argv)
int Argc;
char *Argv[];
{
int ExitCode = 0;
union REGS Regs;
struct SREGS SegRegs;
SAVE_DS_SS ();
switch (Argc)
{
case 1: break;
case 2: if (1 != sscanf (Argv[1], "%d", &IntNbrToTakeOver))
{
fprintf (stderr, "invalid interrupt number: %s\n", Argv[1]);
ExitCode = 3;
}
break;
default: fprintf (stderr, "too many arguments -- only an alternate interrupt number is valid\n");
ExitCode = 2;
break;
}
if (0 == ExitCode)
{
Regs.h.ah = 0x35; /* Get ptr to any existing interrupt vector */
Regs.h.al = (char) IntNbrToTakeOver;
int86x (0x21, &Regs, &Regs, &SegRegs);
if ((0 == SegRegs.es) && (0 == Regs.x.bx))
{
/* Means that the interrupt we intend to cannibalize isn't in use. */
fprintf (stderr, "installing print translator\n");
Regs.h.al = (char) 0x17;
int86x (0x21, &Regs, &Regs, &SegRegs); /* Get ptr to existing printer driver */
SegRegs.ds = SegRegs.es; /* es:bx = addr of existing printer driver */
Regs.x.dx = Regs.x.bx;
Regs.h.ah = 0x25; /* set ptr to interrupt driver */
Regs.h.al = (char) IntNbrToTakeOver; /* interrupt we are taking over */
int86x (0x21, &Regs, &Regs, &SegRegs); /* point printer driver to ouriver */
Regs.h.al = (char) 0x17; /* the original printer driver */
SegRegs.ds = FP_SEG ((char far*) DRIVERPTR); /* get addr of driver we are installing */
Regs.x.dx = FP_OFF ((char far*) DRIVERPTR);
int86x (0x21, &Regs, &Regs, &SegRegs);
SETINTNBR (IntNbrToTakeOver);
printf ("test string for printer\n");
Regs.x.dx = _ProgramSize_; /* size of the program we want to remain resident */
int86x (0x27, &Regs, &Regs, &SegRegs); /* terminate and stay resident */
}
}
}
--------------------isr.asm----------------------------------------
page 50,132
extrn _FILTER:far
CODE_SEG SEGMENT
ASSUME CS:CODE_SEG
public _DRIVERPTR,_SETINTNBR, _SAVE_DS_SS
_DRIVERPTR dd DRIVER
filter_ds dw 0
filter_ss dw 0
isr_ds dw 0
isr_ss dw 0
Printer dw 0
Count dw 0
DRIVER proc far
sti
; Save the ISR DS and SS registers so that I can retrieve later after the
; C function we call for filtering is finished.
push bx
mov bx,ds
mov cs:isr_ds,bx
mov bx,ss
mov cs:isr_ss,bx
pop bx
push bx
push cx
push dx
push di
push si
push es
cmp ah,0
je PRT_CHAR
; This must be some other printer function -- let's just perform the function
call PRT_INT
jmp SAVE_RESULT ; save the output
PRT_CHAR:
mov cs:Printer,dx
cli
mov bx,filter_ds
mov ds,bx
mov bx,filter_ss
mov ss,bx
mov bx,offset Count ; Push ptr to Count on stack
push cs
push bx
push ax ; Push character to print
call _FILTER
add sp,6 ; throw away arguments
mov bx,isr_ds
mov ds,bx
mov bx,isr_ss
mov ss,bx
sti
mov cx,cs:Count ; get count of characters to print
cmp cx,0 ; any characters to print?
je NoCharsToPrint ; no, return to caller
mov es,dx
mov bx,ax ; es:bx = ptr to buffer
mov dx,cs:Printer ; get the Printer number
NextChar:
mov ah,0
mov al,es:[bx] ; get the character to send
call PRT_INT ; print the character
inc bx ; increment the char ptr
dec cx ; decrement the char count
ja NextChar ; get the next character
NoCharsToPrint:
mov ah,010h ; shows that we wrote it
SAVE_RESULT:
pop es
pop si
pop di
pop dx
pop cx
pop bx
iret
DRIVER endp
PRT_INT proc near
NEW_PRT_INT: int 17h ; default prt interrupt nbr
ret
PRT_INT endp
_SAVE_DS_SS proc far
; Stores the DS and SS of the C program into SAVE_DS and SAVE_SS so that
; can correctly invoke the C function from the ISR.
push ax
mov ax,ds
mov cs:filter_ds,ax
mov ax,ss
mov cs:filter_ss,ax
pop ax
ret
_SAVE_DS_SS endp
_SETINTNBR proc far
push bp
mov bp,sp
mov ax,[bp+6]
mov cs:byte ptr NEW_PRT_INT+1,al
mov sp,bp
pop bp
ret
_SETINTNBR endp
CODE_SEG ENDS
END
-------------------filter.c----------------------------------------
#include <stdio.h>
char Hex[] = "0123456789ABCDEF";
char Buffer[1024];
char*
FILTER(Ch, Count)
int Ch, *Count;
{
/* Ch is the character to be translated, and *Count is the number of
output characters put into Buffer. */
Buffer[*Count = 0] = Hex[(Ch >> 4) & 0xf];
Buffer[++(*Count)] = Hex[Ch & 0xf];
++(*Count);
return (Buffer);
}
--------------------testfilt.c----------------------------------------
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
extern char *FILTER ();
main (Argc, Argv)
int Argc;
char *Argv[];
{
int Ch, Count, I;
char *String;
setmode (fileno (stdout), O_BINARY);
freopen (Argv[1], "rb", stdin);
while (EOF != (Ch = getchar ()))
{
String = FILTER (Ch, &Count);
if (Count > 0)
for (I = 0; I < Count; I++)
putchar (String[I]);
}
}
More information about the Comp.lang.c
mailing list