Contributor: D.J. MURDOCK 
{
I've written a simple device driver in TP, and it works. From some things I've
heard, it won't work in all versions of DOS (it's an .EXE format device driver,
not a .BIN format one). There are tons of restrictions on what you can do in
it - DOS isn't reentrant, and the TP system library isn't designed to do things
while DOS is active, so I don't even let it get initialized, etc., etc.
It's still a bit of a mess, but here it is, for your enjoyment and edification:
 a character device driver that keeps a buffer of 255 characters, called
TPDEVICE.
To try it out, compile it (you'll need OPro or TPro; sorry, but stack swapping
is essential, and I wouldn't want to try to write code to do it myself), put it
into your CONFIG.SYS (on a floppy disk, please!) as
 device=tpdev.exe
and then reboot. Hopefully you won't crash, but if you do, you'll have to
reboot from a different disk and remove it from CONFIG.SYS.
Then you can try
 COPY TPDEVICE CON
to see the initialization message, and
 ECHO This is a line for the buffer>TPDEVICE
to replace it with a new one.
}
{ DOS character device driver written entirely in TP 6 }
{ Written by D.J. Murdoch for the public domain, May 1991 }
{$S-,F-} { Stack checking wouldn't work here, and we assume near calls }
{$M 1000,0,0ドル} { We can't use the heap and don't use the stack. This
 setting doesn't really matter though, since you normally
 won't run TPDEV }
program tpdev;
uses
 opint; { OPro interrupt services, needed for stack switching }
procedure strategy_routine(bp:word); interrupt; forward;
procedure interrupt_routine(bp:word); interrupt; forward;
procedure header; assembler;
{ Here's the trick: an assembler routine in the main program, guaranteed to
 be linked first in the .EXE file!!}
asm
 dd $FFFFFFFF { next driver }
 dw 8000ドル { attributes of simple character device }
 dw offset strategy_routine
 dw offset interrupt_routine
 db 'TPDEVICE'
end;
const
 stDone = 100ドル;
 stBusy = 200ドル;
 cmInit = 0;
 cmInput = 4;
 cmInput_no_wait = 5;
 cmInput_status = 6;
 cmInput_flush = 7;
 cmOutput = 8;
 cmOutput_Verify = 9;
 cmOutput_status = 10;
 cmOutput_flush = 11;
type
 request_header = record
 request_length : byte;
 subunit : byte;
 command_code : byte;
 status : word;
 reserved : array[1..8] of byte;
 case byte of
 cmInit : (num_units : byte;
 first_free : pointer;
 args : ^char;
 drive_num : byte;);
 cmInput : { also used for output }
 (media_descriptor : byte;
 buffer : pointer;
 byte_count : word);
 cmInput_no_wait : (next_char : char);
 end;
var
 local_stack : array[1..4000] of byte;
 end_of_stack : byte;
 request : ^request_header;
 line : string;
procedure handler(var regs : intregisters);
{ This routine is called by the strategy routine, and handles all requests.
 The data segment is okay, and we're running on the local_stack so we've got
 plenty of space, but remember:
 ****** The initialization code for SYSTEM and all other units hasn't
 ever been called!! ******** }
begin
 with request^ do
 begin
 case command_code of
 cmInit :
 begin
 { Last thing in the data segment in TP6 - No heap!!}
 first_free := ptr(dseg, ofs(saveint75) + 4);
 status := stDone;
 line := 'TPDRIVER successfully initialized.';
 end;
 cmInput :
 begin
 if byte_count> length(line) then
 byte_count := length(line);
 move(line[1], buffer^, byte_count);
 line := copy(line, byte_count + 1, 255);
 status := stDone;
 end;
 cmInput_no_wait :
 begin
 if length(line)> 0 then
 begin
 next_char := line[1];
 status := stDone;
 end
 else
 status := stBusy;
 end;
 cmInput_Status,
 cmOutput_Status,
 cmInput_Flush,
 cmOutput_Flush : status := stDone;
 cmOutput,
 cmOutput_Verify :
 begin
 if byte_count + length(line)> 255 then
 byte_count := 255 - length(line);
 move(buffer^, line[length(line) + 1], byte_count);
 line[0] := char(byte(byte_count + length(line)));
 status := stDone;
 end;
 end;
 end;
end;
procedure RetFar; assembler;
{ Replacement for the IRET code that ends the interrupt routines below }
asm
 mov sp,bp
 pop bp
 pop es
 pop ds
 pop di
 pop si
 pop dx
 pop cx
 pop bx
 pop ax
 retf
end;
procedure strategy_routine(bp : word);
var
 regs : intregisters absolute bp;
begin
 with regs do
 request := ptr(es, bx);
 RetFar;
end;
procedure interrupt_routine(bp : word);
var
 regs : intregisters absolute bp;
begin
 SwapStackandCallNear(Ofs(handler), @end_of_stack, regs);
 RetFar;
end;
begin
 writeln('TPDEVICE - DOS device driver written *entirely* in Turbo Pascal.');
 writeln('Install using DEVICE=TPDEV.EXE in CONFIG.SYS.');
 request := @header; { Need a reference to pull in the header. }
end.
 

AltStyle によって変換されたページ (->オリジナル) /