🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.os.msdos.programmer
Article #5631

Device Drivers in C

#5631
From: Frank Whaley
Date: Thu, 04 Apr 1991 16:07
581 lines
13277 bytes
The attached shar file comprises a demonstration of building MS-DOS
Installable Device Drivers with C (currently Turbo C and Microsoft C).

I once had a much larger package designed for the days of crude
compilers.  Things have improved so I have constructed a new package
that does more in less space.

Frank Whaley
Software Engineer
Gupta Technologies
few@gupta.com

Water separates the people of the world;
Wine unites them.
-----
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	mono.c
#	idd.h
#	iddstart.asm
#	tc.bat
#	msc.bat
# This archive created: Thu Apr  4 07:55:21 1991
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'mono.c'
then
	echo shar: "will not over-write existing file 'mono.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mono.c'
X/*
X *	mono.c - monochrome screen device driver
X *
X *	This code provides a device driver for a device named "MON"
X *	which can be opened and written to like any character device.
X *	Output is directed to the monochrome display.  This device
X *	was once handy for debugging a graphics program.  Now it is
X *	just an example of how to build Installable Device Drivers
X *	with C.  For practice, try expanding MON into CON, and provide
X *	a replacement for ANSI.SYS.
X *
X *	Note that drivers that provide interrupt handlers must be built
X *	with Turbo C in the 'tiny' (-mt) model.  The -mt switch causes
X *	interrupt functions to use the code segment variable DGROUP@
X *	for finding the local data segment, instead of making a reference
X *	to the group DGROUP which requires a fixup.
X */
X
X#include "idd.h"
X
X#define VidSeg	(word far *)0xB0000000	/*  addr of monochrome video RAM  */
X#define Attr	0x0700			/*  video attribute mask  */
X#define Blank	(Attr + ' ')		/*  a blank  */
X
Xint row;		/*  current row number  */
Xint col;		/*  current column number  */
X
Xword far *VidAddr;	/*  -> current display character  */
X
X	/*  forward declarations  */
Xvoid cls(void);
Xvoid output(Request far *req);
Xvoid putone(char c);
Xvoid scrollUp(void);
Xvoid wordCopy(word far *from, word far *to, int len);
Xvoid wordSet(word far *ptr, int len, word value);
X
X/*
X *	IDDmain - Installable Device Driver entry point
X */
Xvoid
XIDDmain(req, end)
XRequest far *req;	/*  -> request header  */
Xdword end;		/*  -> end of driver memory  */
X{
X	/*  switch on command code  */
X	switch ( req->commandCode )
X	{
X	case INIT:
X		cls();
X		((InitParms far *)req)->endAddr = end;
X		req->status = Done;
X		break;
X
X	case OUTPUT:
X	case OUTVERIFY:
X		output(req);
X		/*FALLTHRU*/
X	case OUTSTATUS:
X	case OUTFLUSH:
X		req->status = Done;
X		break;
X
X	default:	/*  oops  */
X		req->status = (Error + Done + UnknownCommand);
X		break;
X	}
X}
X
X/*
X *	output - handle output request
X */
Xvoid
Xoutput(Request far *req)
X{
X	InOutParms far *iop = (InOutParms far *)req;
X	byte far *ta;	/*  -> transfer addr  */
X	int ctr;	/*  byte count  */
X	char c;
X
X	ta = (byte far *)iop->transfer;
X	ctr = iop->count;
X
X	while ( ctr-- )
X		switch ( c = *ta++ )
X		{
X		case '\r' :
X			VidAddr -= col;
X			col = 0;
X			break;
X
X		case '\n' :
X			VidAddr += 80;
X			if ( ++row > 24 )
X				scrollUp();
X			break;
X
X		case '\b' :
X			if ( col )
X			{
X				col--;
X				VidAddr--;
X			}
X			break;
X
X		case '\t' :
X			do
X				putone(' ');
X			while ( col & 7 );
X			break;
X
X		case 0x1A :
X			cls();
X			break;
X
X		default :
X			putone(c);
X			break;
X		}
X}
X
X/*
X *	cls - clear the screen
X */
Xvoid
Xcls()
X{
X	/*  fill the screen with blanks  */
X	wordSet(VidSeg, 2000, Blank);
X
X	row = col = 0;
X	VidAddr = VidSeg;
X}
X
X/*
X *	scrollUp - scroll screen up one line
X */
Xvoid
XscrollUp()
X{
X	/*  move up  */
X	wordCopy(VidSeg + 80, VidSeg, 1920);
X	/*  clear last line  */
X	wordSet(VidSeg + 1920, 80, Blank);
X
X	VidAddr -= 80;
X	row = 24;
X}
X
X/*
X *	putone - display one character, scrolling at line-wrap
X */
Xvoid
Xputone(char c)
X{
X	*VidAddr++ = Attr + c;
X
X	if ( ++col > 79 )
X	{
X		VidAddr += (80 - col);
X		col = 0;
X		if ( ++row > 24 )
X			scrollUp();
X	}
X}
X
X/*
X *	wordCopy - copy a range of words
X */
Xvoid
XwordCopy(word far *from, word far *to, int len)
X{
X	while ( len-- )
X		*to++ = *from++;
X}
X
X/*
X *	wordSet - set a range of words
X */
Xvoid
XwordSet(word far *ptr, int len, word value)
X{
X	while ( len-- )
X		*ptr++ = value;
X}
X
X/*  END of mono.c  */
SHAR_EOF
fi
if test -f 'idd.h'
then
	echo shar: "will not over-write existing file 'idd.h'"
else
sed 's/^X//' << \SHAR_EOF > 'idd.h'
X/*
X *	idd.h - Installable Device Driver header
X */
X
X	/*  magic Intel types  */
Xtypedef unsigned char	byte;
Xtypedef unsigned int	word;
Xtypedef void far *	dword;
X
X	/*  status word bits  */
X#define	Error	0x8000
X#define	Busy	0x0100
X#define	Done	0x0080
X
X	/*  media descriptor byte bits  */
X#define	TwoSided	1
X#define	EightSector	2
X#define	Removable	4
X
X	/*  error return codes  */
X#define	WriteProtect	0
X#define	UnknownUnit	1
X#define	DeviceNotReady	2
X#define	UnknownCommand	3
X#define	CRCError	4
X#define	BadLength	5
X#define	SeekError	6
X#define	UnknownMedia	7
X#define	SectorNotFound	8
X#define	NoPaper		9
X#define	WriteFault	10
X#define	ReadFault	11
X#define	GeneralFailure	12
X
X	/*  function numbers  */
X#define INIT		0
X#define MEDIACHECK	1
X#define BUILDBPB	2
X#define IOCTLIN		3
X#define INPUT		4
X#define NDINPUT		5
X#define INPUTSTATUS	6
X#define INPUTFLUSH	7
X#define OUTPUT		8
X#define OUTVERIFY	9
X#define OUTSTATUS	10
X#define OUTFLUSH	11
X#define IOCTLOUT	12
X#define DEVOPEN		13
X#define DEVCLOSE	14
X#define REMMEDIA	15
X
X	/*  structures  */
X
Xtypedef struct
X{
X	byte length;
X	byte unitCode;
X	byte commandCode;
X	word status;
X	byte reserved[8];
X} Request;
X
Xtypedef struct
X{
X	Request reqHdr;		/*  Request Header  */
X	byte nUnits;		/*  number of units  */
X	dword endAddr;		/*  Ending Address  */
X	dword bpbArray;		/*  ptr to BPB array  */
X} InitParms;
X
Xtypedef struct
X{
X	Request reqHdr;		/*  Request Header  */
X	byte mediaDesc;		/*  Media Descriptor  */
X	byte returnCode;	/*  Return Code  */
X} MediaParms;
X
Xtypedef struct
X{
X	Request reqHdr;		/*  Request Header  */
X	byte mediaDesc;		/*  Media Descriptor  */
X	dword transfer;		/*  Transfer Address  */
X	dword bpbTable;		/*  ptr to BPB table  */
X} BPBParms;
X
Xtypedef struct
X{
X	Request reqHdr;		/*  Request Header  */
X	byte mediaDesc;		/*  Media Descriptor  */
X	dword transfer;		/*  Transfer Address  */
X	word count;		/*  Byte/Sector Count  */
X	word start;		/*  Starting Sector Number  */
X} InOutParms;
X
Xtypedef struct
X{
X	Request reqHdr;		/*  Request Header  */
X	byte Byte;		/*  Byte Read From Device  */
X} ndInputParms;
X
Xtypedef struct
X{
X	Request reqHdr;
X} StatusParms;
X
Xtypedef struct
X{
X	Request reqHdr;
X} FlushParms;
X
Xtypedef struct
X{
X	word BytesPerSector;
X	byte SecsPerAllocUnit;
X	word ReservedSectors;
X	byte FATCount;
X	word RootDirEntries;
X	word SectorsPerLogical;
X	byte MediaDesc;
X	word SecsPerFAT;
X} BPB;
X
Xtypedef struct
X{
X	byte BootJump[3];
X	byte Name[8];
X	BPB BootBPB;
X	word SecsPerTrack;
X	word HeadCount;
X	word HiddenCount;
X} BootSector;
X
X/*  END of idd.h  */
SHAR_EOF
fi
if test -f 'iddstart.asm'
then
	echo shar: "will not over-write existing file 'iddstart.asm'"
else
sed 's/^X//' << \SHAR_EOF > 'iddstart.asm'
X	PAGE	60, 132
XTITLE	IDDStart - Installable Device Driver Header
X
X;-----------------------------------------------------------------------|
X;	Sample Installable Device Driver Header				|
X;-----------------------------------------------------------------------|
X
X;  Segment declarations
XIGROUP	Group	_TEXT, TAIL
XDGROUP	Group	_DATA, CONST, c_common, _BSS, DTAIL
X
X_TEXT	Segment Para Public 'CODE'
X	Assume	CS:_TEXT
X_TEXT	EndS
XTAIL	Segment 'CODE'
XTAIL	EndS
X_DATA	Segment Para Public 'DATA'
X	Assume	DS:_DATA
X_DATA	EndS
XCONST	Segment Byte Public 'CONST'
XCONST	EndS
Xc_common Segment Byte Public 'BSS'
Xc_common EndS
X
X_TEXT	Segment
X
X;-----------------------------------------------------------------------|
X;	External declarations of driver functions			|
X;-----------------------------------------------------------------------|
X
X	Extrn	_IDDmain:Near
X
X	;  where do we begin...
X	ORG	0
X
XIDDStart	Proc	Far
X
X;-----------------------------------------------------------------------|
X;	Device Header							|
X;-----------------------------------------------------------------------|
X
X	DD	-1			;  -> next device (init to -1)
X; CONFIGURE: the following value must be set specifically for your driver
X	DW	8000H			;  character only
X	DW	Strategy		;  -> device strategy
X	DW	Interrupt		;  -> device interrupt
X; CONFIGURE: the following value must be set specifically for your driver
X	DB	"MON     "		;  driver name
X
X;-----------------------------------------------------------------------|
X;	Code Segment Variables						|
X;-----------------------------------------------------------------------|
X	Public	DGROUP@
XDGROUP@	DW	0			;  our data segment
Xrequest	DD	(?)			;  copy of request hdr ptr
XssEntry	DW	(?)			;  entry SS
XspEntry	DW	(?)			;  entry SP
X
X	PAGE
X;-----------------------------------------------------------------------|
X;	Device Strategy							|
X;									|
X;	ENTRY :	ES:BX -> Request Header					|
X;									|
X;	EXIT :	all registers preserved					|
X;									|
X;-----------------------------------------------------------------------|
X
XStrategy:
X	;  save request hdr ptr
X	MOV	Word Ptr CS:request,BX
X	MOV	Word Ptr CS:request + 2,ES
X	RET
X
X	PAGE
X;-----------------------------------------------------------------------|
X;	Device Interrupt						|
X;									|
X;	ENTRY :	anything						|
X;									|
X;	EXIT :	all registers preserved					|
X;									|
X;-----------------------------------------------------------------------|
X
XInterrupt:
X	;  save the world
X	PUSH	DS			;  (+1)
X	PUSH	ES			;  (+2)
X	PUSH	AX			;  (+3)
X	PUSH	BX			;  (+4)
X	PUSH	CX			;  (+5)
X	PUSH	DX			;  (+6)
X	PUSH	SI			;  (+7)
X	PUSH	DI			;  (+8)
X	PUSH	BP			;  (+9)
X
X	MOV	CS:ssEntry,SS		;  save entry SS
X	MOV	CS:spEntry,SP		;  and SP
X
X	;  one-time compute of DS
X	MOV	AX,CS:DGROUP@
X	TEST	AX,AX
X	JNE	haveDS
X
X	MOV	AX,Offset IGROUP:TAIL	;  compute our DS
X
X	MOV	CL,4
X	SHR	AX,CL
X	MOV	CX,CS
X	ADD	AX,CX
X	MOV	CS:DGROUP@,AX
X
XhaveDS:
X	MOV	BX,Offset DGROUP:locStk	;  set our DS, SS, BP, and SP
X	MOV	DS,AX
X	;CLI				;  very old chips need this
X	MOV	SS,AX
X	MOV	SP,BX
X	;STI
X	MOV	BP,BX
X
X	;  call IDDmain(Request far *req, void far *end)
X	PUSH	DS
X	MOV	AX,Offset DGROUP:DTAIL
X	PUSH	AX
X	PUSH	Word Ptr CS:request + 2
X	PUSH	Word Ptr CS:request
X	CALL	_IDDmain
X
X	SUB	SP,8
X
X	;  restore entry registers
X	MOV	SS,CS:ssEntry
X	MOV	SP,CS:spEntry
X	POP	BP			;  (+8)
X	POP	DI			;  (+7)
X	POP	SI			;  (+6)
X	POP	DX			;  (+5)
X	POP	CX			;  (+4)
X	POP	BX			;  (+3)
X	POP	AX			;  (+2)
X	POP	ES			;  (+1)
X	POP	DS			;  (+0)
X	RET
X
XIDDStart	EndP
X
X_TEXT	EndS
X
X	PAGE
X;-----------------------------------------------------------------------|
X;	Data Segment							|
X;-----------------------------------------------------------------------|
X
X_DATA	Segment
X
X	Public	__acrtused
X__acrtused	EQU	9876H
X
X_DATA	EndS
X
X_BSS	Segment Word Public 'BSS'
X	DB	2048 Dup (?)		;  our stack
XlocStk	Label	Word
X_BSS	EndS
X
XDTAIL	Segment Word 'BSS'
XDTAIL	EndS
X
X	END	IDDStart		;  of IDDStart.asm
SHAR_EOF
fi
if test -f 'tc.bat'
then
	echo shar: "will not over-write existing file 'tc.bat'"
else
sed 's/^X//' << \SHAR_EOF > 'tc.bat'
X: TC.BAT - build MONO.SYS with Turbo C 2.0
X:  Note that TASM can't seem to build a version of iddstart.obj that
X:  doesn't require fixups.  We may be doing an Evil Thing, but this
X:  is MS-DOS.
Xmasm /mx/t iddstart;
Xtcc -c mono.c
Xtlink iddstart+mono,mono/x/c
Xdel iddstart.obj
Xdel mono.obj
Xexe2bin mono.exe mono.sys
Xdel mono.exe
SHAR_EOF
chmod +x 'tc.bat'
fi
if test -f 'msc.bat'
then
	echo shar: "will not over-write existing file 'msc.bat'"
else
sed 's/^X//' << \SHAR_EOF > 'msc.bat'
X: MSC.BAT - build MONO.SYS with Microsoft C (5.1 or 6.0)
Xmasm /mx/t iddstart;
Xcl -Gs -Zp -c mono.c
Xlink iddstart+mono,mono;
Xdel iddstart.obj
Xdel mono.obj
Xexe2bin mono.exe mono.sys
Xdel mono.exe
SHAR_EOF
chmod +x 'msc.bat'
fi
exit 0
#	End of shell archive
-- 
Frank Whaley
Software Engineer
Gupta Technologies
few@gupta.com
Technical Details
Message-ID: <1991Apr4.160734.6391@gupta.portal.com>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!apple!portal!gupta!few

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!rpi!usc!apple!portal!gupta!few
From: few@gupta.portal.com (Frank Whaley)
Newsgroups: comp.os.msdos.programmer
Subject: Device Drivers in C
Message-ID: <1991Apr4.160734.6391@gupta.portal.com>
Date: 4 Apr 91 16:07:34 GMT
Organization: Gupta Technologies Inc
Lines: 581