Article View: comp.os.msdos.programmer
Article #5631Device Drivers in C
From: Frank Whaley
Date: Thu, 04 Apr 1991 16:07
Date: Thu, 04 Apr 1991 16:07
581 lines
13277 bytes
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!fewShow 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