home *** CD-ROM | disk | FTP | other *** search
- /* DRVFRAME.C - Rahmen für einen Zeichentreiber */
- /* HINWEIS: Benötigt das DOSLIB.OBJ , das zuvor mit TASM /MX DOSLIB
- übersetzt werden muß
- */
- #include <stdio.h>
- #include <dos.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <conio.h> /* <- *nicht* für Ausgaben innerhalb der Funktionen! */
- #include <ctype.h>
- #include "drvlib.inc"
- #include "doslib.h"
-
- /* ------------- Der Treiber selbst ----------------------- */
- typedef struct /* Kopf des Parameterblocks (REQUESTHEADER) */
- { unsigned char DSize; /* Größe des gesamten Blocks */
- unsigned char DUnit; /* Geräte-Kennziffer (relativ) */
- unsigned char DFunc; /* Funktionsnummer (0x00) */
- unsigned DStatus; /* Status als Ergebnis */
- unsigned char DResvd[8];
- } DrvBlock;
-
- DrvBlock far *ParmBlock; /* Adresse des Parameterblocks,
- via "Strategie" gesetzt */
- typedef struct /* Parameterblock für "Init" */
- { unsigned char DSize; /* Größe des gesamten Blocks */
- unsigned char DUnit; /* Geräte-Kennziffer (relativ) */
- unsigned char DFunc; /* Funktionsnummer (0x00) */
- unsigned DStatus; /* Status als Ergebnis */
- unsigned char DResvd[8];
- /* --- Funktionsabhängige Felder --- */
- unsigned char DUnits; /* Anzahl Laufwerke (nur für Block) */
- void far *DEndAddr; /* Endadresse, vom Treiber gesetzt */
- char far *DCmdLine; /* Adresse der "Kommandozeile" */
- unsigned char DFirstDrv; /* Kennziffer erstes Laufwerk (nur Block) */
- unsigned DMsgFlag; /* für Fehlermeldungen des Treibers */
- } DrvInitBlock, far *DrvInitPtr;
-
- #define DriverSize 0x400 /* Annahme: Treiber braucht 0x400 Bytes Platz */
- void DriverInit(void) /* Treiberfunktion 0x00 */
- { char far *Cmd;
- DrvInitPtr p;
-
- cputs("Funktion 0x00 (Init) - Parameter: ");
- p = (DrvInitPtr)ParmBlock; Cmd = p->DCmdLine;
- while (*Cmd != 13)
- { putch(*Cmd++);
- }
- cputs("\r\n");
- /* Annahme: DriverInit ist die erste Routine des Treibers */
- p->DEndAddr = MK_FP(FP_SEG(DriverInit),FP_OFF(DriverInit)+DriverSize+1);
- p->DStatus = 0; /* Error-Bit zurück */
- }
-
- typedef struct /* Parameterblock für "Write" */
- { unsigned char DSize; /* Größe des gesamten Blocks */
- unsigned char DUnit; /* Geräte-Kennziffer (relativ) */
- unsigned char DFunc; /* Funktionsnummer (0x08) */
- unsigned DStatus; /* Status als Ergebnis */
- unsigned char DResvd[8];
- /* --- Funktionsabhängige Felder --- */
- unsigned char DMediaID; /* Media-ID (nur Block) */
- void far *DBuffer; /* Quelladresse im Hauptspeicher */
- unsigned DBytesOrSec; /* Anzahl Datenbytes/Sektoren */
- unsigned DStartSec; /* erster Sektor (nur Block) */
- void far *DVolID; /* wird vom Treiber gesetzt (nur Block) */
- long DStartLong; /* Startsektor mit 32 Bit (nur Block) */
- } DrvWriteBlock, far *DrvWritePtr;
-
- void DriverWrite(void) /* Treiberfunktion 0x08 */
- { unsigned Count;
- char far *p;
- DrvWritePtr Params;
-
- Params = (DrvWritePtr)ParmBlock;
- p = Params->DBuffer; /* Startadresse */
- for (Count = 0; Count < Params->DBytesOrSec; Count++)
- { _AL = p[Count];
- __emit__(0xCD,0x29); /* Ausgabe via Interrupt 0x29 */
- }
-
- /* Params->DBytesorSec = <Anzahl geschriebener Bytes, redundant */
- Params->DStatus = 0; /* "Error" und "Busy"-Bit löschen */
- }
-
- void far DoStrategy(void) /* Strategie-Routine */
- {
- __emit__(0x50,0x53, /* push ax..dx - diese vier Register werden */
- 0x51,0x52); /* von SwapValInCS bzw. MK_FP gebraucht! */
- SwapValInCS(_DS); /* SWAP von DS mit Turbo-DS */
- __emit__(0x8E,0xD8); /* asm mov ds,ax */
- ParmBlock = MK_FP(_ES,_BX);
- SwapValInCS(_DS); /* TURBO-DS speichern, DS wieder setzen */
- __emit__(0x8E,0xD8); /* asm mov ds,ax */
- __emit__(0x5A,0x59,0x5B,0x58); /* pop dx..ax - Register zurück */
- }
-
- void far DoInterrupt(void) /* Interrupt-Routine */
- { /* <- keine lokalen Variablen!! */
- __emit__(0x50,0x53,0x51, /* push ax/bx/cx/dx/si/di/es - ließe */
- 0x52,0x56,0x57,0x06 /* sich eleganter mit PUSHA/PUSH ES machen */
- );
- SwapValInCS(_DS); /* SWAP DS/Turbo-DS */
- __emit__(0x8E,0xD8); /* asm mov ds,ax */
-
- switch(ParmBlock->DFunc)
- { case 0 : DriverInit();
- break;
- case 8 : DriverWrite();
- break;
- default:
- cprintf("Unbekannte Treiberfunktion: %d\n",ParmBlock->DFunc);
- ParmBlock->DStatus = 0x8003; /* "Error"-Bit setzen, Fehlercode */
- break;
- }
-
- ParmBlock->DStatus |= 0x100; /* "Done"-Bit setzen */
- SwapValInCS(_DS); /* DS-Register wieder tauschen */
- __emit__(0x8E,0xD8, /* asm mov ds,ax */
- 0x07,0x5F,0x5E,0x5A, /* pop es/di/si/dx/cx/bx/ax, d.h. POPA/POP ES */
- 0x59,0x5B,0x58
- );
- }
-
- /* -------------------------------------------------------- */
- /* Reserviert einige über das Codesegment adressierbare Bytes
- und liefert die Adresse dieses Bereichs zurück */
- void far *ReserveCS(void)
- { char far *StrPtr;
-
- for (StrPtr = MK_FP(_CS,0); FP_OFF(StrPtr) < 32766 &&
- strcmp(StrPtr, "ReserveCS: Fehler!"); StrPtr++)
- ;
- if (FP_OFF(StrPtr) == 32766)
- { cprintf("ReserveCS: Fehler!\n");
- exit(1);
- }
- return StrPtr;
- }
-
- /* Baut den durch CHARACS spezifizierten Treiber in die Kette ein */
- void LinkDriver(DriverPointer Characs, DrvInitPtr InitParams)
- { DriverPointer NULDev, NULNext;
-
- NULDev = GetFirstHeader(); /* Gerätetreiber NUL ermitteln */
- NULNext = NULDev->DNext; /* Zeiger auf den Nachfolger */
- NULDev->DNext = Characs; /* NUL -> NULNext wird zu */
- Characs->DNext = NULNext; /* NUL -> Characs -> NULNext */
- /* Direkter Aufruf der Strategie- und Interrupt-Routine
- mit dem Initialisierungsblock */
- CallStrategy(Characs, InitParams);
- CallInterrupt(Characs);
- }
-
- /* Baut den Treiber wieder aus der Kette aus */
- void UnlinkDriver(DriverPointer Characs)
- { DriverPointer NULDev = GetFirstHeader();
-
- NULDev->DNext = Characs->DNext; /* NUL -> Characs -> Next */
- } /* wird zu NUL -> Next */
-
- DriverPointer BuildCharDriver(unsigned Attrib, char *DrvName)
- { DriverPointer DrvHead;
- int x;
-
- SwapValInCS(_DS); /* Turbo-Datensegment speichern */
- DrvHead = ReserveCS(); /* Platz im Datensegment */
- DrvHead->DAttr = Attrib; /* Attribute des Treibers */
- DrvHead->DStrat = FP_OFF(DoStrategy);
- DrvHead->DIntr = FP_OFF(DoInterrupt);
- for (x = 0; x < 8; x++) DrvHead->NameOrUnits[x] = ' ';
- for (x = 0; x < strlen(DrvName); x++)
- DrvHead->NameOrUnits[x] = toupper(DrvName[x]);
- DrvHead->DNext = MK_FP(0xFFFF,0xFFFF);
- return DrvHead;
- }
-
- unsigned DrvAttrib = 0x8000; /* zu setzendes Attribut */
- char DrvName[] = "DEMO"; /* zu setzender Name */
- char CmdLine[] = /* "Kommandozeile" aus CONFIG.SYS */
- "Parameter_1 Parameter_2\r\n";
-
- main()
- { DriverPointer OurDriver;
- DrvInitBlock InitParams; /* Parameter zur Initialisierung */
- /* - - - - - - - - - - - - */
- FILE *fp; /* nur zur Demonstration */
-
- OurDriver = BuildCharDriver(DrvAttrib,DrvName);
- memset(&InitParams,0,sizeof(InitParams));
- InitParams.DSize = sizeof(DrvInitBlock);
- InitParams.DFunc = 0x00;
- InitParams.DCmdLine = CmdLine;
- InitParams.DEndAddr = MK_FP(0xA000,0);
-
- LinkDriver(OurDriver,&InitParams);
-
- /* - - - - - - - - - - - - - - - - - - - - - */
- printf("Treiber %s eingebaut und initialisiert.\n",DrvName);
- printf("Treiberkopf: 0x%Fp, Init-Routine 0x%Fp, EndAdresse 0x%Fp\n",
- OurDriver,DriverInit,InitParams.DEndAddr);
- printf("Zurückgelieferter Status: 0x%04X\n",InitParams.DStatus);
-
- printf("Öffnen von %s als Datei für Schreibaktionen: ",DrvName);
- if ((fp = fopen(DrvName,"w")) == NULL)
- printf("DOS-Fehlercode %d\n", errno);
- else
- { printf("OK!\n");
- fprintf(fp,"Ein via Write über das Dateisystem ausgegebener Text.\n");
- fclose(fp);
- }
- /* - - - - - - - - - - - - - - - - - - - - - - - */
- UnlinkDriver(OurDriver);
- printf("Treiber %s wieder ausgebaut.\n",DrvName);
-
- return 0;
- }
-