; DDSEGCOS.ASI - Barninga Z! - 1994 ; ; ASSEMBLER INCLUDE FILE PER DEVICE DRIVER TOOLKIT ; ; dichiarazione dei segmenti di codice ; ; Le righe che seguono dichiarano i segmenti di codice del device driver
e ; stabiliscono l'ordine in cui essi devono essere presenti nel file
binario. Quasi ; tutte le definizioni sono riprese dallo startup module del TINY
MODEL e riportate ; NEL MEDESIMO ORDINE. Alcune di esse non hanno utilita' nel caso dei
device driver ; ma devono essere ugualmente riportate per evitare errori di compilazione
o di ; runtime. ; Segmento del codice eseguibile _TEXT segment byte public 'CODE' ; da startup code _TEXT ends ; Segmento dati inizializzati _DATA segment word public 'DATA' ; da startup code _DATA ends ; Segmento dati costanti _CONST SEGMENT WORD PUBLIC 'CONST' ; da startup code _CONST ENDS ; Segmenti di riferimento _CVTSEG SEGMENT WORD PUBLIC 'DATA' ; da startup code _CVTSEG ENDS _SCNSEG SEGMENT WORD PUBLIC 'DATA' ; da startup code _SCNSEG ENDS ; Segmento dati non inizializzati _BSS segment word public 'BSS' _BSS ends ; Segmento che inizia al termine del segmento _BSS (e' una definizione
dummy che ; consente di identificare con facilita' la fine del segmento _BSS. _BSSEND SEGMENT BYTE PUBLIC 'BSSEND' ; da startup code _BSSEND ENDS ; Segmenti definiti per la gestione delle operazioni di inizializzazione
e ; terminazione del programma. _INIT_ SEGMENT WORD PUBLIC 'INITDATA' ; da startup code _INIT_ ENDS _INITEND_ SEGMENT BYTE PUBLIC 'INITDATA' ; da startup code _INITEND_ ENDS _EXIT_ SEGMENT WORD PUBLIC 'EXITDATA' ; da startup code _EXIT_ ENDS _EXITEND_ SEGMENT BYTE PUBLIC 'EXITDATA' ; da startup code _EXITEND_ ENDS ; Segmento definito appositamente per i device driver. Consente di
conoscere con ; facilita' l'indirizzo di fine codice. _DRVREND segment byte public 'DRVREND' _DRVREND ends ;------------------------------------------------------------------------------ ; I segmenti sono tutti quanti inseriti nel gruppo DGROUP, secono lo
schema del ; tiny model, che prevede un unico segmento di RAM (64 Kb) per tutti
i segmenti ; del sorgente (i loro indirizzi si differenziano nell'offset). La
direttiva ASSUME ; indica all'assemblatore che durante l'esecuzione tutti i registri
di segmento ; verranno inizializzati con l'indirizzo di DGROUP; cio' permette all'assemblatore ; di calcolare correttamente gli offsets di tutti gli indirizzamenti
nel listato. DGROUP group _TEXT, \ _DATA, \ _CVTSEG, \ _SCNSEG, \ _BSS, \ _BSSEND, \ _INIT_, \ _INITEND_, \ _EXIT_, \ _EXITEND_, \ _DRVREND \ assume cs : DGROUP, \ ds : DGROUP, \ ss : DGROUP, \ es : DGROUP \ ;------------------------------------------------------------------------------ ; Seguono le definizioni di alcune costanti manifeste. Importante e'
la STKSIZE, ; che definisce l'ampiezza iniziale dello stack locale del device driver.
Circa ; la gestione dello stack vedere la funzione setStack(). STKSIZE equ 512 ; dimensione in bytes dello stack locale ; 512 bytes e' il MINIMO possibile CMDSIZE equ 128 ; max lunghezza cmd line SYSINIT_KB equ 96 ; Kb riservati da Top of Mem per SYSINIT ; Seguono le definizioni delle costanti manifeste per la gestione della
status ; word del request header. ; Codici di status da restituire al DOS in OR tra loro. Modificano
i bits del ; byte piu' significativo della status word. S_SUCCESS equ 0000h S_ERROR equ 8000h ; usare in caso di errore S_BUSY equ 0200h S_DONE equ 0100h ; Codici di ritorno in OR coi precedenti. Indicano lo stato con cui
si e' chiuso ; il servizio richiesto dal DOS (byte meno significativo della status
word). E_OK equ 0000h E_WR_PROTECT equ 0 E_UNKNOWN_UNIT equ 1 E_NOT_READY equ 2 E_UNKNOWN_CMD equ 3 ; richiesto servizio non implementato E_CRC equ 4 E_LENGTH equ 5 E_SEEK equ 6 E_UNKNOWN_MEDIA equ 7 E_SEC_NOTFOUND equ 8 E_OUT_OF_PAPER equ 9 E_WRITE equ 10 E_READ equ 11 E_GENERAL equ 12 ; Costante manifesta per la gestione dello stack. Ha un fondamentale
ruolo ; nell'implementazione del meccanismo che consente al device driver
di ; modifcare la dimensione dello stack iniziale in fase di inizializzazione. ; Vedere setStack(). ; SE SI INTENDE MODIFICARE LA GESTIONE DELLO STACK TRA L'ISTRUZIONE
CHE IN ; driverInit() COPIA SP IN __savSP1 E QUELLA CHE IN setStack() COPIA
SP IN __savSP2, ; LE COSTANTI MANIFESTE CHE SEGUONO DEVONO ESSERE MODIFICATE DI CONSEGUENZA!! NPA_SP_DIFF equ 8 ; differenza tra SP prima delle PUSH dei parms ; di main() e SP in ingresso a setStack() nel ; caso di main(void) e senza variabili auto.
; DDHEADER.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - STARTUP ; ; ; device driver STARTUP MODULE. Da linkare in testa all'object prodotto
dal ; compilatore e contenente la reale implementazione C del driver. ; DDHEADER.ASM implementa il device driver header, e le strategy e
interrupt ; routines del device driver. Sono inoltre inserite incluse alcune
routines di ; inizializzazione e le dichiarazioni delle variabili globali (alcune
delle quali ; non pubblicate e quindi non visibili in C) per il supporto delle
librerie ; C, in base allo startup module dei normali programmi. Si noti che
i nomi C ; devono ignorare l'underscore (o il primo degli underscore) in testa
ai nomi ; assembler. include DDSEGCOS.ASI ; definizioni dei segmenti!!! org 0 ; no PSP: e' un device driver ; Dichiarazione dei simboli esterni: sono dichiarate le variabili e
le funzioni ; referenziate ma non definite in questo sorgente. Tutte le funzioni
sono near ; dal momento che si lavora con il modello TINY. extrn __stklen : word ; da libreria C: gestione stack. ; Vedere setStack(). ; seguono le dichiarazioni delle funzioni che gestiscono i vari servizi
del device ; driver. La loro implementazione e' libera, ma il nome nel sorgente
C deve essere ; identico a quello qui riportato (salvo l'underscore iniziale). Se
il sorgente C ; non implementa una o piu' delle seguenti funzioni, all'eseguibile
viene linkata ; la corrispondente dummy function inclusa nella libreria. ; Fa eccezione _driverInit() (DDINIT.ASM), che implementa il servizio
INIT standard ; e chiama la init() definita dal programmatore nel sorgente C. extrn _driverInit : near extrn _mediaCheck : near ; servizi del driver, da extrn _buildBPB : near ; implementare in C. Le extrn _inputIOCTL : near ; implementazioni assembler in extrn _input : near ; libreria servono solo come extrn _inputND : near ; placeholders per quelle non extrn _inputStatus : near ; realizzate in C e non fanno che extrn _inputFlush : near ; chiamare errorReturn(), definita extrn _output : near ; in questo stesso sorgente extrn _outputVerify : near extrn _outputStatus : near extrn _outputFlush : near extrn _outputIOCTL : near extrn _deviceOpen : near extrn _deviceClose : near extrn _mediaRemove : near extrn _outputBusy : near extrn _genericIOCTL : near extrn _getLogicalDev : near extrn _setLogicalDev : near extrn _endOfServices : near ;------------------------------------------------------------------------------ _TEXT segment ; inizio del segmento _TEXT (codice) ;------------------------------------------------------------------------------ ; Il codice (segmento _TEXT) - e quindi il file binario - inizia con
il ; device driver header. Notare il primo campo (4 bytes) posto a -1
(FFFFFFFFh). ; La device attribute word (secondo campo) e il logical name (ultimo
campo) ; sono "per default" posti a 0 e, rispettivamente, 8 spazi.
Dovranno essere ; settati dopo il linking, utilizzando la utility DRVSET. ; E' fondamentale che il device driver header sia il primo oggetto
definito ; nel segmento del codice. public _DrvHdr ; header del device driver _DrvHdr dd -1 dw 0 ; DA SETTARE CON DRVSET dw offset _TEXT:_Strategy dw offset _TEXT:_Interrupt db 8 dup(32) ; DA SETTARE CON DRVSET ;----------------------------------------------------------------- ; Tabella dei servizi del device driver. E' utilizzata dalla interrupt
routine ; (listata poco piu' avanti) per individuare la funzione da chiamare
a seconda ; del servizio richiesto dal DOS. Il posizionamento della tabella all'inizio
del ; modulo forza l'assemblatore a referenziare per prime le funzioni
dei servizi ; (solo Strategy() e Interrupt() sono referenziate prima di esse, nello
header): ; in tal modo esse sono ricercate per prime nelle librerie (se non
definite nel ; sorgente) e linkate all'eseguibile prima di tutte le funzioni di
libreria C. ; Cio' permette l'utilizzo di _endOfServices(), come dichiarata al
termine della ; tabella stessa. _FuncTab dw offset _TEXT:_driverInit ; 0 dw offset _TEXT:_mediaCheck ; 1 dw offset _TEXT:_buildBPB ; 2 dw offset _TEXT:_inputIOCTL ; 3 dw offset _TEXT:_input ; 4 dw offset _TEXT:_inputND ; 5 dw offset _TEXT:_inputStatus ; 6 dw offset _TEXT:_inputFlush ; 7 dw offset _TEXT:_output ; 8 dw offset _TEXT:_outputVerify ; 9 dw offset _TEXT:_outputStatus ; 10 A dw offset _TEXT:_outputFlush ; 11 B dw offset _TEXT:_outputIOCTL ; 12 C dw offset _TEXT:_deviceOpen ; 13 D dw offset _TEXT:_deviceClose ; 14 E dw offset _TEXT:_mediaRemove ; 15 F dw offset _TEXT:_outputBusy ; 16 10 dw offset _TEXT:_unSupported ; 17 11 dw offset _TEXT:_unSupported ; 18 12 dw offset _TEXT:_genericIOCTL ; 19 13 dw offset _TEXT:_unSupported ; 20 14 dw offset _TEXT:_unSupported ; 21 15 dw offset _TEXT:_unSupported ; 22 16 dw offset _TEXT:_getLogicalDev ; 23 17 dw offset _TEXT:_setLogicalDev ; 24 18 ; E' dichiarata una label (etichetta) il cui indirizzo (offset) indica
la fine ; della tabella delle funzioni di servizio. public __endOfSrvc __endOfSrvc label word ; off DGROUP:fine f() servizi ; E' dichiarata una funzione dummy inserita in libreria dopo tutte
le funzioni ; di servizio: il suo indirizzo indica, nel file binario, la fine del
codice ; eseguibile delle funzioni di servizio. Vedere anche endOfServices(). dw offset _TEXT:_endOfServices ; dummy func per segnare ; indirizzo fine ultima ; f() di servizio. ;----------------------------------------------------------------- ; L'espressione $-_FuncTab-2 calcola la distanza (in bytes) tra l'inizio
della ; tabella dei servizi e l'indirizzo attuale, meno due bytes. In pratica
si ottiene ; la dimensione della tabella dei puntatori alle funzioni di servizio
e, dal momento ; che ogni puntatore occupa due bytes (tutti puntatori near), __FuncIDX__
puo' ; fungere da indice per individuare la funzione da chiamare a seconda
del servizio ; richiesto dal DOS. __FuncIDX__ dw $ - _FuncTab - 2 ; max indice (word off) in tabella ; il 2 e' per la f() dummy ; Seguono le definizioni di diverse variabili globali. Solo quelle
per le quali e' ; specificata la clausola PUBLIC sono visibili da C. Sono definite
anche alcune ; labels (etichette) che servono per gestire indirizzi senza utilizzare
veri e ; propri puntatori. Tutte le variabili e labels pubblicate al C sono
dichiarate ; nell'include file della libreria toolkit BZDD.H. public _RHptr _RHptr dd 0 ; puntatore far al Request Header _DosStkPtr dd 0 ; ptr far a DOS Stack (SS:SP ingresso) public _DrvStk _DrvStk db STKSIZE dup(0) ; stack locale del driver public _DrvStkEnd _DrvStkEnd label word ; fine dello stack (e' solo una label) ; Alcune delle variabili definite di seguito sono descritte e commentate
in un ; paragrafo dedicato ; Kb mem conv installati (usata nel codice di inizializzazione per
l'int 12h). Si ; tratta di un dato raccolto per comodita' del programmatore. public __systemMem __systemMem dw 0 ; Di seguito sono definite un'etichetta ed una variabile. La prima
rappresenta un ; sinonimo della seconda e possono essere utilizzate da C come se fossero
la stessa ; cosa. La variabile contiene l'indirizzo di segmento al quale e' caricato
il ; driver (CS); il sinonimo _psp e' definito per analogia con la libreria
C, ma ; il driver non ha un PSP. Questa e' la parte segmento dell'indirizzo
al quale ; si trova il device driver header; percio' RHptr vale _psp:0000 o
_baseseg:0000. public __psp __psp label word public __baseseg __baseseg dw 0 ; segmento di base del DevDrv (CS) ; Di seguito sono definite due variabili di comodita' per il programmatore.
I device ; driver non hanno un far heap in cui allocare memoria far: _farMemBase
e ; _farMemTop sono gli indirizzi far dell'inizio e, rispettivamente,
della fine della ; memoria libera oltre il driver. Va tenuto presente che in quell'area
di RAM ci ; sono parti di DOS attive: essa puo' percio' essere usata a discrezione,
ma con ; prudenza. public __farMemBase __farMemBase dd 0 ; puntatore far alla memoria libera ; oltre il driver in init() public __farMemTop __farMemTop dd 0 ; puntatore far alla fine della memoria ; libera oltre il driver in init(). ; _cmdLine e' una copia della command line del driver in CONFIG.SYS,
a partire dal ; carattere che segue "DEVICE=". In pratica e' un array di
char. public __cmdLine __cmdLine db CMDSIZE dup(0) ; copia locale della command line ; _cmdArgsN e _cmdArgs equivalgono a argc e argv. Il massimo numero
di puntatori che ; _cmdArgs puo' contenere e' 64, perche' una command line e' al massimo
di 128 ; caratteri e ogni argomento occupa almeno 2 bytes (1 carattere + 1
spazio). public __cmdArgsN __cmdArgsN dw 0 ; come argc public __cmdArgs __cmdArgs db CMDSIZE dup(0) ; array puntat. ad argom. cmd line ; Definizione di alcuni puntatori per comodita' del puntatore. Gli
indirizzi (near) ; sono calcolati mediante labels definite in coda a questo stesso sorgente. public __endOfCode __endOfCode dw offset DGROUP:_ecode@ ; offset (CS:) della fine codice public __endOfData __endOfData dw offset DGROUP:_edata@ ; offset (CS:) della fine dati public __endOfDrvr __endOfDrvr dw offset DGROUP:_edrvr@ ; offset (CS:) fine spazio driver ; Variabili per la gestione dello stack. Lo stack locale DrvStk e'
rilocabile ; (vedere setStack()): qualora esso, a discrezione
del ; programmatore, venga effettivamente rilocato, lo spazio di STACKDIM
bytes occupato ; inizialmente puo' essere riutilizzato come un normale array di char,
il cui ; indirizzo (near) e' _freArea. La sua effettiva dimensione e' _freAreaDim.
Le altre ; variabili sono utilizzate da setStack() e sono pubblicate al C con
finalita' di ; debugging. public __freArea __freArea dw 0 ; offset ex-stack per riutilizzo public __freAreaDim __freAreaDim dw 0 ; dimensione ex-stack public __savSP1 __savSP1 dw 0 ; SP prima di push parms per init() public __savSP2 __savSP2 dw 0 ; SP all'ingresso di SetStack() public __newTOS __newTOS dw 0 ; offset del nuovo Top Of Stack ; Seguono definizioni di variabili date per analogia con lo startup
code dei normali ; programmi C. public __version __version label word ; versione e revisione DOS public __osversion __osversion label word ; versione e revisione DOS public __osmajor __osmajor db 0 ; versione DOS public __osminor __osminor db 0 ; revisione DOS public __StartTime __StartTime dd 0 ; clock ticks allo startup public _errno _errno dw 0 ; codice di errore public ___MMODEL ___MMODEL dw 0 ; tiny model public _DGROUP@ _DGROUP@ dw 0 ; segmento del gruppo DGROUP ; Le variabili definite di seguito sono necessarie alle funzioni di
libreria C per ; la gestione dello heap (malloc(), etc.). Quelle relative al far heap
non sono ; inizializzate in quanto ai device driver non e' mai possibile effettuare ; allocazioni far mediante farmalloc(). Le allocazioni dello heap sono
effettuate ; all'interno dello stack, secondo lo schema del modello TINY. public ___heapbase ___heapbase dw offset _DrvStk ; inizio near heap public ___brklvl ___brklvl dw offset _DrvStk ; attuale fine near heap public __heapbase __heapbase dd 0 ; inizio far heap ; public __brklvl ; __brklvl dd 0 ; inizio far heap ; public __heaptop ; __heaptop dd 0 ; fine far heap ;----------------------------------------------------------------- ; Inizia qui il codice eseguibile. Siamo sempre nell'ambito del code
segment (il che ; e' normale per le routine, un po' meno per le variabili appena definite). ; Ecco la strategy routine. Essa non fa altro che salvare l'indirizzo
del request ; header, passato dal DOS in ES:BX, nel puntatore far RHptr. Si noti
che Strategy() ; deve essere una funzione far; inoltre essa non e' pubblicata al C,
in quanto si ; tratta di una routine interna al driver, che non deve mai essere
chiamata da C. _Strategy proc far mov word ptr cs:[_RHptr],bx ; salva ptr al Request Header mov word ptr cs:[_RHptr+2],es ; prima offset poi segmento ret _Strategy endp ;----------------------------------------------------------------- ; Ed ecco la interrupt routine: come si vede, ha una struttura semplice.
Essa ; attiva lo stack locale e salva i registri, dopodiche' scandisce la
tabella ; dei servizi: se il servizio e' 0 (inizializzazione) richiama driverInit(), ; definita oltre in questo sorgente, la quale a sua volta chiama la
init() del ; sorgente C. Se il servizio non e' definito chiama errorReturn(),
definita oltre ; in questo sorgente, passandole E_UNSUPPORTED quale codice di errore,
altrimenti ; chiama la funzione dedicata al servizio. Se il sorgente C implementa
una funzione ; con quel nome (vedere la tabella in testa a questo sorgente) e' invocata
proprio ; quella funzione, altrimenti e' chiamata la corrispondente funzione
dummy della ; libreria toolkit. Al termine delle operazioni, Interrupt() ripristina
i registri ; e lo stack DOS e termina restituendo il controllo al sistema. Interrupt(),
come ; Strategy(), deve essere far e non e' pubblicata al C, che non la
puo' invocare. _Interrupt proc far ; E' bene che il driver utilizzi un proprio stack, per evitare di ; sottarre risorse al DOS: quindi bisogna modificare SS:SP in modo ; che puntino allo stack del driver e non piu' a quello DOS. E' ovvio ; che l'indirizzo dello stack DOS (SS:SP) deve essere salvato (NON ; SULLO STACK STESSO!) per poterlo ripristinare in uscita. Allo ; scopo e' usata la variabile DosStkPtr. mov word ptr cs:[_DosStkPtr],sp ; salva SS:SP (ptr a stack DOS) mov word ptr cs:[_DosStkPtr+2],ss ; prima offset poi segmento ; Lo stack locale viene attivato caricando SS:SP con l'indirizzo ; della fine (lo stack e' usato dall'alto in basso!) dell'area ; allo scopo riservata. Percio' in SS e' caricato CS (nel modello ; TINY il segmento di stack e' lo stesso del codice) e in SP e' ; caricato l'offset della label DrvStkEnd, che indica la fine di ; DrvStk, l'array di STKSIZE bytes dedicato allo scopo. mov _DGROUP@,cs ; stack pointers settati allo mov ss,_DGROUP@ ; stack locale (_DGROUP@ e' mov sp,offset _DrvStkEnd ; una variabile di comodo) ; A questo punto si puo' usare lo stack locale per salvare tutti i ; registri e generare una standard stack frame,
cioe' il settaggio ; di SS, SP e BP secondo le convenzioni C in ingresso alle funzioni. push bp ; genera standard stack frame mov bp,sp push ax ; ...e salva tutti i registri push bx ; senza piu' intaccare lo push cx ; stack dos push dx push si push di push ds push es pushf ; Tutti i registri di segmento sono uguagliati a CS (tiny model); SS ; e' gia' stato settato. mov bx,cs mov ds,bx mov es,bx ; Qui viene esaminato il servizio richiesto ed e' lanciata la funzione ; corrispondente: il numero di servizio, letto ad offset 2 nel request ; header, e' moltiplicato per 2 (i puntatori alle funzioni sono near
e ; percio' ciascuno occupa 2 bytes; quindi in tal modo si ottiene ; direttamente l'offset nella tabella FuncTab del puntatore alla ; funzione da lanciare). Se il risultato della moltiplicazione e' ; maggiore di _FuncIDX__ (massimo indice), e' chiamata la funzione ; unSupported() (definita oltre in questo sorgente), altrimenti si ; salta alla label EXECUTE. push ds lds si,DGROUP:_RHptr ; DS:SI punta al Request Header mov al,[si+2] ; AL = servizio (campo a offset 2) pop ds shl al,1 ; per 2 (offsets in _FuncTab sono words) xor ah,ah ; AX = offset in termini di words cmp ax,__FuncIDX__ ; ** MAX VALORE DEL COMMAND BYTE x 2 ** jle EXECUTE call _unSupported jmp EXITDRIVER EXECUTE: ; Il servizio richiesto e' lecito: la coppia DS:SI e' caricata con ; l'indirizzo del puntatore alla funzione opportuna e si procede ; alla chiamata con una tecnica analoga all'indirezione di puntatore ; a funzione. mov si,offset _FuncTab add si,ax ; DS:SI punta al puntat. a funz. in _FuncTab call word ptr [si] ; chiama funzione void f(void) EXITDRIVER: ; Alla fine delle operazioni Interrupt() setta a 1 il bit 8 della ; status word nel request header: si presume che tutte le funzioni ; dedicate ai servizi restituiscano (e percio' il compilatore lo ; carichera' in AX) il valore della status word stessa. or ax,S_DONE ; segnala fine operazioni push ds lds si,DGROUP:_RHptr ; DS:SI punta al Request Header mov [si+3],ax ; valorizza lo STATUS di ritorno pop ds ; Uscita da Interrupt(): tutti i registri sono ripristinati, viene ; eliminata la standard stack frame ed e' ricaricato in SS:SP ; l'indirizzo dello stack DOS prelevandolo da DosStkPtr. La funzione ; termina con una normale RET (far, dato che Interrupt() e' dichiarata ; tale) e NON con una IRET. popf ; ripristina tutti i registri pop es ; estraendone i valori di ingresso pop ds ; dallo stack locale pop di pop si pop dx pop cx pop bx pop ax pop bp ; rispristina BP (standard stack frame) mov sp,word ptr cs:[_DosStkPtr] ; ripristina SS:SP (ora puntano mov ss,word ptr cs:[_DosStkPtr+2] ; nuovamente allo stack DOS) ret ; non e' un interrupt! _Interrupt endp ;----------------------------------------------------------------- ; La funzione errorReturn() e' pubblicata al C e deve essere usata
per segnalare ; che un servizio e' terminato in errore. Accetta come parametro un
intero il cui ; byte meno significativo rappresenta il codice di errore e lo restituisce
dopo ; avere settato a 1 il bit 15. Vedere la status
word e DDSEGCOS.ASI. public _errorReturn ; f() per restituzione errore _errorReturn proc near ; int errorReturn(int errcod); ; procedura per restituzione codice push bp ; di errore secondo costanti manifeste mov bp,sp ; Il parm e' referenziato [BP+4] infatti mov ax,[bp+4] ; [BP+0] = BP e [BP+2] = IP (per la ret) or ax,S_ERROR ; setta bit di errore pop bp ret _errorReturn endp ;----------------------------------------------------------------- ; La funzione unSupported(), pubblicata al C, e' dedicata a restituire
lo stato di ; errore per servizio non supportato. Non fa altro che chiamare errorReturn()
con ; l'appropriato codice di errore. public _unSupported ; f() per servizio non supportato _unSupported proc near ; int unSupported(void); mov ax,E_UNKNOWN_CMD push ax call _errorReturn ; restituisce codice errore add sp,2 ret _unSupported endp ;------------------------------------------------------------------------------ _TEXT ends ; Fine del segmento di codice ;------------------------------------------------------------------------------ ; Labels pubbliche per individuare gli offsets dei segmenti (non possono ; essere dichiarate in DDSEGCOS.ASI) perche' devono essere dichiarate
una ; volta soltanto. ;----------------------------------------------------------- _DATA segment word public 'DATA' public _ecode@ ; fine codice (_TEXT) _ecode@ label byte _DATA ends ;----------------------------------------------------------- _CVTSEG SEGMENT WORD PUBLIC 'DATA' ; da startup code public __RealCvtVector __RealCvtVector label word _CVTSEG ENDS ;----------------------------------------------------------- _SCNSEG SEGMENT WORD PUBLIC 'DATA' ; da startup code public __ScanTodVector __ScanTodVector label word _SCNSEG ENDS ;----------------------------------------------------------- _BSS segment word public 'BSS' ; da startup code public _bdata@ ; inizio BSS _bdata@ label byte _BSS ends ;----------------------------------------------------------- _BSSEND SEGMENT BYTE PUBLIC 'BSSEND' ; da startup code public _edata@ ; fine BSS _edata@ label byte _BSSEND ENDS ;----------------------------------------------------------- _DRVREND segment byte public 'DRVREND' public _edrvr@ ; fine driver _edrvr@ label byte _DRVREND ends ;------------------------------------------------------------------------------ end
; DDINIT.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione driverInit() per l'inizializzazione standard del device
driver include ddsegcos.asi ; dichiarazione di init(). Equivale alla main() dei normali programmi
C, assente ; nei device driver. E' richiamata dalla interrupt routine quando il
DOS ; richiede il servizio 0, cioe' al caricamento del driver. Tutte le
operazioni ; di inizializzazione devono percio' essere gestite nella init(),
che deve essere ; presente in tutti i device driver scritti utilizzando il toolkit. ; Ovviamente non deve esserci main(). extrn _init : near ; user defined! E' la "main()" del ; device driver. ; Dichiarazione della funzione di libreria toolkit setupcmd(),
che ; effettua la scansione della command line e genera argc e argv per
la init(). extrn _setupcmd : near ; Altri simboli esterni dallo startup module extrn __version : word extrn __stklen : word extrn __baseseg : word extrn __systemMem : word extrn __farMemTop : dword extrn __farMemBase : dword extrn __StartTime : dword extrn __cmdArgs : word extrn __cmdArgsN : word extrn __savSP1 : word extrn _DGROUP@ : word extrn _edrvr@ : byte extrn _bdata@ : byte extrn _edata@ : byte ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ ; driverInit() e' il vero e proprio startup code del driver. Dal momento
che il ; suo indirizzo si trova ad offset 0 nella FuncTab (e' il primo puntatore
nella ; tabella) essa e' chiamata da Interrupt() in corrispondenza del servizio
0 e ; procede alla inizializzazione del driver. driverInit() si occupa
delle operazioni ; di inizializzazione standardizzate per tutti i driver: al termine
di queste ; chiama init(), che deve essere definita dal programmatore nel sorgente
C, la ; quale esegue le operazioni peculiari per quel driver. Il programmatore
C deve ; gestire l'inizializzazione dedicata allo specifico driver esclusivamente
con ; init(). public _driverInit _driverInit proc near ; driverInit(): simula parte dello startup code mov ah,30h int 21h ; richiede versione dos mov __version,ax ; e la salva mov __stklen, STKSIZE ; dimensione stack mov word ptr __baseseg,cs ; segmento di caricamento ; L'algoritmo che segue non trova corrispondenza nello startup code ; dei normali programmi. Viene calcolato EMPIRICAMENTE il confine ; superiore della memoria libera oltre il driver: in caso di problemi ; può essere necessario aumentare il valore di SYSINIT_KB, costante ; manifesta definita in DDSEGCOS.ASI, che esprime
il numero di Kb ; riservati alla routine SYSINIT del
DOS. E' poi ; individuato l'offset della fine dello spazio occupato dal driver
e, ; a partire da quello, l'indirizzo far dell'inizio della memoria ; libera oltre il driver. Lo spazio tra gli indirizzi far _farMemBase ; e _farMemTop e' a disposizione del driver per qualsiasi utilizzo, ; purche' limitato alla sola fase di inizializzazione, in quanto ; quella memoria sara' successivamente usata dal DOS (e non e' ; comunque gestibile via farmalloc(), etc.). int 12h ; Kb RAM instal. (AX); <= 640 mov __systemMem,ax ; salva valore restituito sub ax,SYSINIT_KB ; protegge spazio per SYSINIT mov cx,6 shl ax,cl ; Kb * 64 = Seg esa mov word ptr __farMemTop+2,ax ; top della memoria far libera mov ax,offset DGROUP:_edrvr@ ; offset fine spazio driver mov cx,4 shr ax,cl ; off / 16 = normalizzazione inc ax ; annulla arrotondamento add ax,word ptr _DGROUP@ ; segmento normalizzato mov word ptr __farMemBase+2,ax ; base far free mem e' il primo ; seg:0000 oltre il driver ; Seguono nuovamente operazioni derivate dal normale startup code. mov ah,0 int 1ah ; BIOS time ticks mov word ptr __StartTime,dx ; per la funzione C clock() mov word ptr __StartTime+2,cx or al,al ; midnight flag settato? jz NOT_MIDNIGHT push es mov ax,40h ; setta BIOS midnight flag mov es,ax ; all'indirizzo 0040:0070 mov bx,70h mov byte ptr es:[bx],1 pop es NOT_MIDNIGHT: mov di,offset DGROUP:_bdata@ ; da startup code: azzera area mov cx,offset DGROUP:_edata@ ; BSS. (ES = CS = DGROUP) sub cx,di ; CX = dist. _bdata@-_edata@ xor ax,ax cld rep stosb ; A questo punto e' chiamata la funzione di libreria toolkit ; setupcmd(), che effettua la scansione della
command line ; data in CONFIG.SYS e setta _cmdArgsN e _cmdArgs, equivalenti a argc ; e, rispettivamente, argv. call _setupcmd ; scansione command line mov bx,offset __cmdArgs push bx ; analogo ad argv push __cmdArgsN ; analogo ad argc mov __savSP1,sp ; per setStack(): deve essere ; l'ultima prima di call _init ; Infine e' chiamata init(): il controllo
dell'inizializzazione passa ; al sorgente C. call _init ; int init(...) USER DEFINED add sp,4 ; pulizia stack ; Al termine dell'inizializzazione sono (per prudenza) azzerati i ; puntatori all'inizio e alla fine della memoria far disponibile oltre ; il driver, dal momento che, come sottolineato poco fa, dopo la fase ; di bootstrap essa non e' piu' disponibile. mov word ptr __farMemBase,0 ; dopo init() non ha piu' mov word ptr __farMemBase+2,0 ; alcun significato mov word ptr __farMemTop,0 ; dopo init() non ha piu' mov word ptr __farMemTop+2,0 ; alcun significato ret ; torna a Interrupt() _driverInit endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end
; DDMEDCHE.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione mediaCheck() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _mediaCheck _mediaCheck proc near ; int mediaCheck(void); call _unSupported ret _mediaCheck endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDBUIBPB.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione buildBPB() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _buildBPB _buildBPB proc near ; int buildBPB(void); call _unSupported ret _buildBPB endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDINPIOC.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione inputIOCTL() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _inputIOCTL _inputIOCTL proc near ; int inputIOCTL(void); call _unSupported _inputIOCTL endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDINPUT.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione input() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _input _input proc near ; int input(void); call _unSupported ret _input endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDINPND.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione inputND() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _inputND _inputND proc near ; int inputND(void); call _unSupported ret _inputND endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDINPSTA.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione inputStatus() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _inputStatus _inputStatus proc near ; int inputStatus(void); call _unSupported ret _inputStatus endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDINPFLU.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione inputFlush() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _inputFlush _inputFlush proc near ; int inputFlush(void); call _unSupported ret _inputFlush endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDOUTPUT.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione output() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _output _output proc near ; int output(void); call _unSupported ret _output endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDOUTVER.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione outputVerify() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _outputVerify _outputVerify proc near ; int outputVerify(void); call _unSupported ret _outputVerify endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDOUTSTA.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione outputStatus() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _outputStatus _outputStatus proc near ; int outputStatus(void); call _unSupported ret _outputStatus endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDOUTFLU.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione outputFlush() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _outputFlush _outputFlush proc near ; int outputFlush(void); call _unSupported ret _outputFlush endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDOUTIOC.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione outputIOCTL() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _outputIOCTL _outputIOCTL proc near ; int outputIOCTL(void); call _unSupported ret _outputIOCTL endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDDEVOPE.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione deviceOpen() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _deviceOpen _deviceOpen proc near ; int deviceOpen(void); call _unSupported ret _deviceOpen endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDDEVCLO.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione deviceClose() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _deviceClose _deviceClose proc near ; int deviceClose(void); call _unSupported ret _deviceClose endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDMEDREM.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione mediaRemove() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _mediaRemove _mediaRemove proc near ; int MediaRemove(void); call _unSupported ret _mediaRemove endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDOUTBUS.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione outputBusy() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _outputBusy _outputBusy proc near ; int outputBusy(void); call _unSupported ret _outputBusy endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDGENIOC.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione genericIOCTL() dummy usata solo se non implementata in C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _genericIOCTL _genericIOCTL proc near ; int genericIOCTL(void); call _unSupported ret _genericIOCTL endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDGETLOG.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione getLogicalDev() dummy usata solo se non implementata in
C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _getLogicalDev _getLogicalDev proc near ; int getLogicalDev(void); call _unSupported ret _getLogicalDev endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDSETLOG.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione setLogicalDev() dummy usata solo se non implementata in
C include ddsegcos.asi extrn _unSupported : near ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _setLogicalDev _setLogicalDev proc near ; int setLogicalDev(void); call _unSupported ret _setLogicalDev endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end
; DDENDOFS.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; funzione endOfServices() dummy usata solo per calcolare l'indirizzo
al ; quale termina l'ultima delle f() dummy di servizio. non e' mai eseguita include ddsegcos.asi ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _endOfServices _endOfServices proc near ret _endOfServices endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end
; DD_EXPTR.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; procedure dummy che i normali programmi usano per uscire a DOS o ; resettare vettori ed effettuare il flush degli streams: dati ; include DDSEGCOS.ASI extrn _dummy : near ; dummy() e' definita in DDDUMMY.ASM ;------------------------------------------------------------------------------ _DATA segment ;------------------------------------------------------------------------------ ; puntatori a funzioni di cleanup per streams e file ;-------------------------------------------------------------- public __exitbuf __exitbuf dw offset _TEXT:_dummy public __exitfopen __exitfopen dw offset _TEXT:_dummy public __exitopen __exitopen dw offset _TEXT:_dummy ;------------------------------------------------------------------------------ _DATA ends ;------------------------------------------------------------------------------ end ; DD_VECT.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; include DDSEGCOS.ASI ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ _Int0Vector dd 0 ; area locale memorizzazione _Int4Vector dd 0 ; vettori per SaveVectors() e _Int5Vector dd 0 ; _restorezero() _Int6Vector dd 0 ; ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDDUMMY.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; procedure dummy che i normali programmi usano per uscire a DOS o ; resettare vettori ed effettuare il flush degli streams ; include DDSEGCOS.ASI ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ ; labels per nomi funzioni di uscita e cleanup: puntano ; tutte a __dummy__proc, che segue solo una RET ;-------------------------------------------------------------- public dummy ; static dummy dummy label ;-------------------------------------------------------------- public _abort ; abort() _abort label ;-------------------------------------------------------------- public _atexit ; atexit() _atexit label ;-------------------------------------------------------------- public _dummy ; static dummy _dummy label ;-------------------------------------------------------------- public _exit ; exit() _exit label ;-------------------------------------------------------------- public _keep ; keep() _keep label ;-------------------------------------------------------------- public __cexit ; _cexit() __cexit label ;-------------------------------------------------------------- public __checknull ; asm __checknull label ;-------------------------------------------------------------- public __cleanup ; asm __cleanup label ;-------------------------------------------------------------- public __c_exit ; _c_exit() __c_exit label ;-------------------------------------------------------------- public __dos_keep ; _dos_keep() __dos_keep label ;-------------------------------------------------------------- public __exit ; _exit() __exit label ;-------------------------------------------------------------- public __terminate ; asm __terminate label ;-------------------------------------------------------------- public ___EXIT ; pascal ___exit() ___EXIT label ;-------------------------------------------------------------- public ___exit ; pascal ___exit() ___exit label ;------------------------------------------------------------------------------ __dummy__proc PROC near ; funzione dummy: esegue solo RET ret __dummy__proc ENDP ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end ; DDRESVEC.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; procedure per la gestione dei vettori int 0, 4, 5, 6 e del gestore ; dell'int 0 (divide by zero). Nei normali programmi al ritorno a DOS ; e' chiamata _restorezero(), che ripristina detti vettori, salvati
da ; SaveVectors() e modificati da alcune funzioni di libreria C. Il device ; driver deve invocare esplicitamente SaveVectors() e _restorezero() ; se necessario. ; include DDSEGCOS.ASI extrn _Int0Vector : dword ; definiti in DD_VECT.ASM extrn _Int4Vector : dword extrn _Int5Vector : dword extrn _Int6Vector : dword ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public __restorezero __restorezero proc near ; void _restorezero(void) push ds mov ax,2500h lds dx,_Int0Vector int 21h pop ds push ds mov ax,2504h lds dx,_Int4Vector int 21h pop ds push ds mov ax,2505h lds dx,_Int5Vector int 21h pop ds push ds mov ax,2506h lds dx,_Int6Vector int 21h pop ds ret __restorezero endp ;------------------------------------------------------------------------------ _TEXT ENDS ;------------------------------------------------------------------------------ END ; DDSAVVEC.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; procedure per la gestione dei vettori int 0, 4, 5, 6 e del gestore ; dell'int 0 (divide by zero). Nei normali programmi SaveVectors()
e' ; chiamata dallo startup code e installa ZeroDivision. Al ritorno a
DOS ; e' chiamata _restorezero(), che ripristina i vettori. La ErrorDisplay ; scrive su stderr un mesaggio di errore. Il device driver deve invocare ; esplicitamente SaveVectors() e _restorezero() se necessario. ; include DDSEGCOS.ASI extrn _Int0Vector : dword ; definiti in DD_VECT.ASM extrn _Int4Vector : dword extrn _Int5Vector : dword extrn _Int6Vector : dword ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ ZDivMsg db 'Divide error', 13, 10 ; messaggio di errore int 0 ZDivMsgLen equ $ - ZDivMsg ErrorDisplay proc near ; void pascal ErrorDisplay(void) mov ah,040h mov bx,2 int 021h ret ErrorDisplay endp ;-------------------------------------------------------------- ZeroDivision proc far ; void far pascal ZeroDivision(void) mov cx,ZDivMsgLen mov dx,offset DGROUP:ZDivMsg push cs ; modello tiny: DS = CS pop ds call ErrorDisplay mov ax, 3 push ax ret ZeroDivision endp ;-------------------------------------------------------------- public SaveVectors SaveVectors proc near ; void pascal SaveVectors(void) push ds mov ax, 3500h int 021h mov word ptr _Int0Vector,bx mov word ptr _Int0Vector+2,es mov ax,3504h int 021h mov word ptr _Int4Vector,bx mov word ptr _Int4Vector+2,es mov ax,3505h int 021h mov word ptr _Int5Vector,bx mov word ptr _Int5Vector+2,es mov ax,3506h int 021h mov word ptr _Int6Vector,bx mov word ptr _Int6Vector+2,es mov ax,2500h mov dx,cs mov ds,dx mov dx,offset ZeroDivision int 21h pop ds ret SaveVectors endp ;--------------------------------------------------------------------------- _TEXT ENDS ;--------------------------------------------------------------------------- END
; DDSETSTK.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; unsigned setStack(unsigned base,unsigned len); ; ; genera un nuovo stack locale per il device driver ; ; unsigned base; offset del (puntatore near al) nuovo stack ; unsigned len; lunghezza dello stack in bytes ; ; restituisce: la lunghezza effettiva del nuovo stack; puo' essere ; inferiore a quella richiesta se quest'ultima e' ; dispari o se e' dispri l'offset dello stack (viene ; effettuato allineamento alla word); se il valore ; restituito e' 0 uno dei parametri e' errato e lo ; stack non e' stato generato ; ; note: se utilizzata, e' opportuno che sia la prima f() ; chiamata da init(), inoltre non e' disponibile una ; funzione per ritornare allo stack precedente ed ; eliminare quello generato da setStack(); se il ; nuovo stack viene effettivamente attivato, allora ; l'area statica occupata dallo stack originale del ; driver e' riutilizzabile secondo le necessita' ; dell'utente: il suo offset (puntatore near) e la ; sua lunghezza in bytes sono disponibili in _freArea ; e _freAreaDim rispettivamente. ; INCLUDE DDSEGCOS.ASI ; dichiarazione simboli esterni extrn __savSP1 : word extrn __savSP2 : word extrn __newTOS : word extrn _DrvStk : byte extrn _DrvStkEnd : byte extrn ___heapbase : word extrn ___brklvl : word extrn __freArea : word extrn __freAreaDim : word extrn __stklen : word ; da libreria C extrn __setupio : near ; e' una funzione di libreria C ; chiamata dallo startup code dei ; normali programmi: prepara le ; strutture statiche di tipo FILE ; per gli streams ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _setStack _setStack proc near ; unsigned setStack(unsigned base,unsigned len); mov __savSP2,sp ; salva SP in ingresso: deve essere la ; prima istruzione di setStack() push bp ; genera std stack frame per accedere mov bp,sp ; ai parametri passati da init() mov dx,word ptr [bp+4] ; DX = offset di inizio del nuovo stack mov ax,word ptr [bp+6] ; AX = lunghezza pop bp ; elimina stack frame per operaz. copia test dx,1 ; offset base del nuovo stack e' pari? jz W_ALIGNED_BASE ; si; salta inc dx ; allinea base stack e heap a word dec ax ; no: lo spazio e' diminuito di 1 byte! W_ALIGNED_BASE: and ax,0FFFEh ; impone lunghezza stack pari mov cx,offset _DrvStkEnd ; CX = attuale TopOfStack sub cx,__savSP2 ; CX = TOS - SP = bytes da copiare cmp ax,cx ; lungh. (AX) > bytes (CX) ? jbe ERROR ; no: stack insufficiente; salta mov bx,dx ; si: BX = offset base nuovo stack add dx,ax ; DX = off base + lunghezza = nuovo TOS jnc PARMS_OK ; CARRY = 0: TOS <= FFFFh: OK; salta ERROR: xor ax,ax ; segnala errore jmp EXIT_FUNC PARMS_OK: mov __newTOS,dx ; salva nuovo TOS mov ___heapbase,bx ; base heap = base nuovo stack mov ___brklvl,bx ; attuale fine heap = base nuovo stack mov __freArea,offset _DrvStk ; offset ex-stack per riutilizzo mov __freAreaDim,STKSIZE ; dimensione vecchio stack mov bx,__savSP1 ; SP prima di push parametri di init() sub bx,__savSP2 ; differenza tra i due SP cmp bx,NPA_SP_DIFF ; diff se init() non ha parms e var. auto je BP_ADJUST ; se = basta settare BP e copiare stack STACK_ADJUST: ; altrimenti prima di copiare: mov word ptr [bp],dx ; BP = offset da SS della copia di BP ; PUSHed in init(), cioe' SS:[BP] ; = precedente BP (TOS), ora = __newTOS mov bx,offset _DrvStkEnd ; BP e' offset rispetto a SS, ora BX = sub bx,bp ; distanza tra quell'offset e fine stack mov bp,dx ; BP viene trasformato per puntare allo sub bp,bx ; stesso offset rispetto a __newTOS (AX) jmp COPY_STACK ; BP gia' valorizzato BP_ADJUST: mov bp,dx ; BP = __newTOS: init(void) e no var auto COPY_STACK: push es ; salva ES (DS e' sempre = CS = SS), SI push si ; e DI. Non copiati perche' estratti da push di ; stack prima dell'attivazione nuovo stk std ; copia dall'alto al basso mov si,offset _DrvStkEnd ; fine vecchio stack sub si,2 ; DS:SI -> prima word da copiare (BP DOS) push ds pop es ; ES = DS mov di,dx ; DI = __newTOS sub di,2 ; ES:DI -> ultima word del nuovo stack mov bx,cx ; CX contiene ancora numero bytes stack cli rep movsb ; copia il contenuto dello stack sti pop di ; ripristina i registri salvati pop si ; estraendoli ancora dal vecchio stack pop es ; ES era la prima word non copiata mov sp,dx ; SP = __newTOS sub sp,bx ; __newTOS - bytes_in_stack = nuovo SP mov __stklen,ax ; per libreria C push ax ; usa gia' il nuovo stack call __setupio ; ora ha senso: c'e' spazio (da startup) pop ax ; restit. AX = LEN: nuovo stack attivato! EXIT_FUNC: ret _setStack endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end
; DDSETCMD.ASM - Barninga Z! - 1994 ; ; ASSEMBLER SOURCE FILE PER DEVICE DRIVER TOOLKIT - LIBRARY ; ; ; void setupcmd(void); ; ; funzione di parsing della command line ; ; genera una copia locale statica della command line e in questa tronca ; opportunamente le stringhe con NULLs, valorizzando un array statico
di ; puntatori a char (_cmdArgs) e un intero (_cmdArgsN) che contiene
il ; numero degli items presenti sulla cmd line (compreso il nome del
driver) ; include DDSEGCOS.ASI ; dichiarazioni dei simboli esterni extrn _RHptr : dword extrn __cmdLine : word extrn __cmdArgs : word extrn __cmdArgsN : word ;------------------------------------------------------------------------------ _TEXT segment ;------------------------------------------------------------------------------ public _setupcmd _setupcmd proc near ; void setupcmd(void) prepara due parametri ; per init() analoghi a argc e argv push si push di push ds lds si,DGROUP:_RHptr ; DS:SI punta a Request Header lds si,[si+18] ; DS:SI punta a Command Line mov di,offset __cmdLine ; ES:DI punta a _cmdLine (ES = SS = CS) mov cx,CMDSIZE rep movsb ; crea copia locale della command line pop ds mov si,offset __cmdLine ; DS:SI -> _cmdLine (ES = DS = SS = CS) inc si ; punta al secondo byte (emula LODSB) mov di,offset __cmdArgs ; ES:DI -> _cmdArgs (ES = DS = SS = CS) xor dx,dx ; contatore argomenti cld ; operazioni stringa: forward call _setarg ; funz. di servizio: vedere a fine listato NEXTARG: NEXTCHAR: ;;;; scansione di un parametro lodsb cmp al,32 je ENDARG ; blank \ cmp al,9 ; > fine argomento je ENDARG ; tab / cmp al,13 je ENDCMD ; CR \ cmp al,10 ; | je ENDCMD ; LF > fine command line cmp al,26 ; | je ENDCMD ; EOF / cmp al,34 ; je DQUOTES ; DOUBLE QUOTES jmp NEXTCHAR ENDARG: ;;;; fine parametro mov byte ptr [si-1],0 ; termina str. con NULL (SI gia' incr.) ENDARG_1: ;;;; scansione spazio tra due parametri lodsb cmp al,32 je ENDARG_1 ; blank \ cmp al,9 ; > separatori argomenti je ENDARG_1 ; tab / cmp al,13 je ENDCMD_1 ; CR \ cmp al,10 ; | je ENDCMD_1 ; LF > fine command line cmp al,26 ; | je ENDCMD_1 ; EOF / cmp al,34 ; je DQUOTES ; DOUBLE QUOTES: inizio parametro call _setarg jmp NEXTARG DQUOTES: ;;;; virgolette nella command line mov byte ptr [si-1],0 inc si ; le virgolette sono scartate: call _setarg ; in _setarg AX=SI e DEC AX dec si ; ripristina il puntatore DQUOTES_1: lodsb cmp al,13 je ENDCMD ; CR \ cmp al,10 ; | je ENDCMD ; LF > fine command line cmp al,26 ; | je ENDCMD ; EOF / cmp al,34 ; je ENDARG ; DQUOTES: fine parametro jmp DQUOTES_1 ENDCMD: ;;;; fine parametro e command line mov byte ptr [si-1],0 ; termina str. con NULL (SI gia' incr.) ENDCMD_1: ;;;; fine command line xor ax,ax stosw ; _cmdArgs[DX] = NULL mov __cmdArgsN,dx ; _cmdArgsN = numero argomenti pop di pop si ret _setupcmd endp ;----------------------------------------------------------------- _setarg proc near ;;;; inizio di un nuovo parametro ;;;; routine di servizio per setupcmd() mov ax,si dec ax ; SI e' gia' stato incrementato stosw ; _cmdArgs[DX] -> argomento inc dx ; trovato un altro argomento ret _setarg endp ;------------------------------------------------------------------------------ _TEXT ends ;------------------------------------------------------------------------------ end
// BZDD.H - Barninga Z! - 1994 // // include file per libreria device driver // #ifndef __BZDD_H // evita doppia inclusione #define __BZDD_H // necessario includere DOS.H se non ancora incluso #ifndef __DOS_H #include <dos.h> #endif // COSTANTI MANIFESTE // codici di ritorno e di stato #define S_SUCCESS 0x0000 #define S_ERROR 0x8000 // codici di status #define S_BUSY 0x0200 // in OR tra di loro #define S_DONE 0x0100 #define E_OK 0 // codici di ritorno in OR coi precedenti #define E_WR_PROTECT 0 #define E_UNKNOWN_UNIT 1 #define E_NOT_READY 2 #define E_UNKNOWN_CMD 3 #define E_CRC 4 #define E_LENGTH 5 #define E_SEEK 6 #define E_UNKNOWN_MEDIA 7 #define E_SEC_NOTFOUND 8 #define E_OUT_OF_PAPER 9 #define E_WRITE 10 #define E_READ 11 #define E_GENERAL 12 #define E_RESERVED_1 13 #define E_RESERVED_2 14 #define E_INVALID_DSKCHG 15 // servizi del driver #define C_INIT 0 #define C_MEDIACHECK 1 #define C_BUILDBPB 2 #define C_INPUTIOCTL 3 #define C_INPUT 4 #define C_INPUTND 5 #define C_INPUTSTATUS 6 #define C_INPUTFLUSH 7 #define C_OUTPUT 8 #define C_OUTPUTVERIFY 9 #define C_OUTPUTSTATUS 10 #define C_OUTPUTFLUSH 11 #define C_OUTPUTIOCTL 12 #define C_DEVICEOPEN 13 #define C_DEVICECLOSE 14 #define C_MEDIAREMOVE 15 #define C_OUTPUTBUSY 16 #define C_GENERICIOCTL 19 #define C_GETLOGICALDEV 23 #define C_SETLOGICALDEV 24 // altre #define NO_VLABEL "NO NAME" // per dischi senza volume label #define RB_CHG 0xFF // dischetto sostituito #define RB_MAYBE 0 // dischetto sostituito... forse #define RB_NOTCHG 1 // dischetto non sostituito #define NOT_RESIDENT 0 // da passare a setResCodeEnd() se il // driver non deve rimanere residente. // setResCodeEnd() e' una macro definita // in questo sorgente. // FUNZIONI CORRISPONDENTI AI SERVIZI DEI DRIVER // servizi del driver, da implementare in C. Le implementazioni assembler
in // libreria servono solo come placeholders per quelle non realizzate
in C e // non fanno che chiamare unSupported() #ifdef __cplusplus // per poter usare il toolkit con il C++ extern "C" { #endif int mediaCheck(void); int buildBPB(void); int inputIOCTL(void); int input(void); int inputND(void); int inputStatus(void); int inputFlush(void); int output(void); int outputVerify(void); int outputStatus(void); int outputFlush(void); int outputIOCTL(void); int deviceOpen(void); int deviceClose(void); int mediaRemove(void); int outputBusy(void); int genericIOCTL(void); int getLogicalDev(void); int setLogicalDev(void); // ALTRE FUNZIONI void discardDriver(void); // comunica al DOS di non lasciare residente
il driver int errorReturn(int errNum); // restit. al DOS il codice errNum unsigned setStack(unsigned base,unsigned len); // genera un nuovo stack int unSupported(void); // rest. al DOS l'err E_UNKNOWN_CMD // FUNZIONI DA STARTUP CODE void pascal SaveVectors(void); // salva vett. 0 4 5 6 installa handler
int 0 void _restorezero(void); // ripristina vettori 0 4 5 6 // VARIABILI GLOBALI (derivate da startup code o definite liberamente) extern int errno; // codice di errore extern unsigned _version; // versione e revisione DOS extern unsigned _osversion; // versione e revisione DOS extern unsigned char _osmajor; // versione DOS extern unsigned char _osminor; // revisione DOS extern unsigned long _StartTime; // timer clock ticks al caricamento extern unsigned _systemMem; // Kb di memoria convenzionale installati extern unsigned _psp; // segmento di caricamento (CS), non vero PSP extern unsigned _baseseg; // segmento di caricamento (CS) extern void huge *_farMemBase; // ptr huge a mem libera dos (varia
atomatic.) extern void huge *_farMemTop; // ptr huge a fine mem libera dos (varia
aut.) extern void *_endOfSrvc; // offset fine funzioni dummy dei servizi extern void *_endOfCode; // offset fine codice eseguibile extern void *_endOfData; // offset fine spazio dati (= Drvr) extern void *_endOfDrvr; // offset fine spazio driver extern void *_freArea; // offset area statica libera (ex-stack) extern unsigned _freAreaDim; // dimensione dell'area statica libera extern int _cmdArgsN; // num. parametri cmd line (argc) extern char **_cmdArgs; // array ptr param. cmd line (argv) #ifdef __cplusplus } #endif // typedefs per semplificare le dichiarazioni typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long DWORD; // strutture di vario tipo typedef struct { // struct per Bios Parameter
Block WORD secsize; // bytes in un settore BYTE clusecs; // settori in un cluster WORD ressecs; // settori riservati prima della FAT BYTE fatno; // numero di FATs esistenti WORD rootntr; // numero di entries nell root WORD totsecs; // numero di settori nel disco BYTE mediadb; // Media Descriptor Byte WORD fatsecs; // numero di settori in una copia della FAT } BPBLK; // GESTIONE DEL DEVICE DRIVER HEADER // la struct e la union seguenti possono essere utilizzate per la gestione
del campo // nome logico del device driver header:
infatti la union consente di // utilizzare gli 8 bytes a disposizione come una stringa di caratteri
(e' il caso // dei character device driver) oppure come una struttura blkName,
definita come // 1 byte (numero i unita' supportate) e un campo riservato di 7 bytes
(e' il caso // dei block device driver) typedef struct { // struttura Nome Logico per Block Device BYTE nUnits; // unita' supportate char breserved[7]; // riservato } blkName; typedef union { // union Nome Logico per Dev. Driver Header char cname[8]; // nome character device blkName bn; // nome block device } h_logName; // La struct DevDrvHeader ricalca la struttura del device driver header,
consentendo // altresi' l'uso della union h_logName per la gestione del nome logico
del device typedef struct { // struttura per Device Driver Header void far *nextDrv; // ptr al prossimo device driver WORD attrib; // device attribute word WORD stratOff; // offset della Strategy routine WORD intrOff; // offset della Intterupt routine h_logName ln; // gestione nome logico del device } DevDrvHeader; // GESTIONE DEL REQUEST HEADER // E' definita una struct per la parte di request header differenziata
per ogni // specifico servizio ed una union che le comprende tutte. Vi e' poi
una struct // che rappresenta la parte fissa del reqest header piu' la union da
utilizzare // per il servizio. In altre parole, i templates di seguito definiti
consentono // di gestire il request header come una struttura (la stessa per tutti
i servizi) // che rappresenta la parte fissa, alla quale ne e' "accodata"
una seconda a // scelta tra quelle definite appositamente per i vari servizi. // parti variabili per i diversi servizi typedef struct { // servzio 0 (init) BYTE nUnits; void far *endAddr; char far *cmdLine; BYTE firstUnit; } c_init; typedef struct { // 1 (media check) BYTE mdByte; BYTE retByte; char far *vLabel; } c_mediaCheck; typedef struct { // 2 (build BPB) BYTE mdByte; BYTE far *trAddr; BPBLK *bpb; } c_buildBPB; typedef struct { // 3 (input IOCTL) BYTE mdByte; BYTE far *trAddr; WORD itemCnt; WORD startSec; char far *vLabel; } c_inputIOCTL; typedef struct { // 4 (input) BYTE mdByte; BYTE far *trAddr; WORD itemCnt; WORD startSec; char far *vLabel; } c_input; typedef struct { // 5 (non destructive input) BYTE readCh; } c_inputND; typedef struct { // 6 (input status) BYTE dummy; } c_inputStatus; typedef struct { // 7 (flush input buffers) BYTE dummy; } c_inputFlush; typedef struct { // 8 (output) BYTE mdByte; BYTE far *trAddr; WORD itemCnt; WORD startSec; char far *vLabel; } c_output; typedef struct { // 9 (output with verify) BYTE mdByte; BYTE far *trAddr; WORD itemCnt; WORD startSec; char far *vLabel; } c_outputVerify; typedef struct { // 10 0A (output status) BYTE dummy; } c_outputStatus; typedef struct { // 11 0B (flush output buffers) BYTE dummy; } c_outputFlush; typedef struct { // 12 0C (output IOCTL) BYTE mdByte; BYTE far *trAddr; WORD itemCnt; WORD startSec; char far *vLabel; } c_outputIOCTL; typedef struct { // 13 0D (device open) BYTE dummy; } c_deviceOpen; typedef struct { // 14 0E (device close) BYTE dummy; } c_deviceClose; typedef struct { // 15 0F (is media removable) BYTE dummy; } c_mediaRemove; typedef struct { // 16 10 (output until busy) BYTE mdByte; BYTE far *trAddr; WORD itemCnt; WORD startSec; char far *vLabel; } c_outputBusy; typedef struct { // 19 13 (generic IOCTL interface) BYTE category; BYTE function; WORD siReg; WORD diReg; void far *packet; } c_genericIOCTL; typedef struct { // 23 17 (get logical device) BYTE dummy; } c_getLogicalDev; typedef struct { // 24 18 (set logical device) BYTE dummy; } c_setLogicalDev; // union raggruppante le struct che descrivono la parte variabile di
request // header per i vari servizi typedef union { c_init initReq; c_mediaCheck mCReq; c_buildBPB bBReq; c_inputIOCTL iIReq; c_input iReq; c_inputND iNReq; c_inputStatus iSReq; c_inputFlush iFReq; c_output oReq; c_outputVerify oVReq; c_outputStatus oSReq; c_outputFlush oFReq; c_outputIOCTL oIReq; c_deviceOpen dOReq; c_deviceClose dCReq; c_mediaRemove mRReq; c_outputBusy oBReq; c_genericIOCTL gIReq; c_getLogicalDev gLReq; c_setLogicalDev sLReq; } cParms; // struct rappresentante il request header (5 campi per la parte fissa
piu' la // union per la parte variabile). La typedef consente di definire,
per // comodita', tipi di dato corrispondenti al request header stesso, // all'indirizzo near e all'indirizzo far di un request header. typedef struct { BYTE length; BYTE unitCode; BYTE command; WORD status; BYTE reserved[8]; cParms cp; } RequestHeader, *RequestHeaderP, far *RequestHeaderFP; // DICHIARAZIONE DEGLI ITEMS DEFINITI NEL MODULO DI STARTUP (DDHEADER.ASM) extern RequestHeaderFP RHptr; // puntatore al request header extern DevDrvHeader DrvHdr; // header del device driver // MACRO di comodo // La macro che segue puo' essere utilizzata per settare nella parte
variabile del // request header (per il servizio 0) l'indirizzo di fine codice residente
del // device driver. Per scaricare il driver dalla memoria evitandone
l'installazione // e' sufficiente passarle 0. Vedere la costante manifesta NOT_RESIDENT
sopra // definita e la funzione discardDriver(), il
cui utilizzo sostituisce la // chiamata setResCodeEnd(NOT_RESIDENT). La setResCodeEnd() fornisce,
tra l'altro, // un esempio di utilizzo delle strutture e della union definite per
manipolare il // request header. #define setResCodeEnd(off) (RHptr->cp.initReq.endAddr
= MK_FP(_CS,off)); #endif // __BZDD_H
/************************************************************ DRVSET.C - Barninga Z! - 1994 Utility per modificare la device attribute word e il logical name nello
header dei device driver. Funziona con qualsiasi device driver (purché
non .EXE) anche se non realizzato con la libreria toolkit. Lanciare DRVSET con: drvset [opzioni] nome_di_file dove: nome_di_file e' il nome del device driver da modificare opzioni puo' essere: -b o -d o -h e -n Le opzioni -b, -d e -h sono alternative tra loro e devono essere seguite
(senza spazi frapposti) dalla nuova device attribute word in binario, decimale
e, rispettivamente, esadecimale. L'opzione -n deve essere seguita (senza spazi frapposti) dal nome logico
del device driver, che viene troncato o completato con blanks, se necessario,
e convertito in maiuscole. Nel caso di block device driver, in luogo
del nome logico deve essere specificato il numero di unita' supportate, racchiuso
tra barre ('/'). I campi dello header sono aggiornati solo previa conferma da parte
dell'utente. Compilato con Borland C++ 3.1 bcc drvset.c parseopt.obj ************************************************************/ #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #include <ctype.h> #include <parseopt.h> // per la gestione
della command line #define PRG "DRVSET" #define VER "1.0" #define YEAR "1994" #define SWCHAR '-' #define BLANK ' ' #define UFLAG '/' #define ILLMSG "Illegal Option" #define ATTR_MASK 0x17A0 // tutti i bits illeciti nella attrib word #define BIT_15 0x8000 // character device driver #define NAMELEN 8 #define MIN_UNITS 1L #define MAX_UNITS 26L #define MAX_LINE 128 typedef struct { // struttura gestione device driver header long nextDev; unsigned attrib; unsigned strategyOff; unsigned interruptOff; char name[NAMELEN]; } DEVHDR; // la typedef consente di usare DEVHDR per dichiarare variabili // prototipi di gestione delle opzioni di
command line int valid_b(struct OPT *vld,int cnt); int valid_d(struct OPT *vld,int cnt); int valid_h(struct OPT *vld,int cnt); int valid_n(struct OPT *vld,int cnt); int err_handler(struct OPT *vld,int cnt); int name_flag(struct OPT *vld,int cnt); // prototipi delle altre funzioni int main(int argc,char **argv); void checkAttrBits(void); int confirm(char *prompt,char yes,char no); void displayHeader(DEVHDR *hdr,char *title); int setDevDrvHdr(char *fname); DEVHDR DevDrvHdr; // globale per semplicita'; e' la struttura per gestire
lo header const char *helpStr = "\ filename is : the name of the device driver file to be updated\n\ option(s) are:\n\n\ One of the following:\n\ -bBinAttr\n\ -dDecAttr\n\ -hHexAttr\n\ where BinAttr, DecAttr and HexAttr are the Device Driver Attribute
Word\n\ in binary, decimal or hexadecimal notation.\n\ And/or one of the following:\n\ -nDevDrvName (for character devive driver)\n\ -n/LogUnits/ (for block device driver)\n\ Device Driver Logical Name (will be uppercased and truncated if necessary).\n\ If Block Device Driver, /LogUnits/ specifies the number of Supported\n\ Logical Units (slashes must be typed).\n\n\ *** No update done. ***\n\ "; const char *invAttrib = "%s: Invalid Device Driver Attribute Word.\n"; const char *invName = "%s: Invalid Device Driver Logical Name.\n"; const char *invUnits = "%s: Invalid Device Driver Supported Units.\n"; const char *invFile = "%s: Too many filenames specified.\n"; const unsigned char nonFNameChars[] = { // caratteri illeciti in nomi
file 0x22,0x2A,0x2C,0x2E,0x2F,0x3A,0x3B,0x3C,0x3D,0x3E,0x5B,0x5C,0x5D,0x7C,0x81, 0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x91,0x93,0x94, 0x95,0x96,0x97,0x98,0xA0,0xA1,0xA2,0xA3,0xA4,NULL }; unsigned optCnt; // contatore opzioni: massimo una tra -b, -h, -d unsigned nameFlag; // nome file specificato? // FUNZIONI DI CONTROLLO DELLE OPZIONI DELLA COMMAND LINE #pragma warn -par #pragma warn -rvl // La funzione valid_b() effettua i controlli sul parametro specificato
per // l'opzione -b, onde verificare la correttezza dei bits impostati
per la device // attribute word. Il parametro specificato e' un numero BINARIO. Non
vengono // effettuati controlli sulla coerenza reciproca dei bits settati. int valid_b(struct OPT *vld,int cnt) // convalida opzione "b" { extern unsigned optCnt; extern DEVHDR DevDrvHdr; extern const char *invAttrib; char *ptr; register i; if(optCnt++) err_handler(NULL,NULL); for(ptr = vld->arg; *ptr == '0'; ptr++); if(strlen(ptr) > 16) { fprintf(stderr,invAttrib,PRG); err_handler(NULL,NULL); } strrev(ptr); for(i = 0; ptr[i]; i++) switch(ptr[i]) { case '1': DevDrvHdr.attrib += (1 << i); case '0': break; default: fprintf(stderr,invAttrib,PRG); err_handler(NULL,NULL); } checkAttrBits(); } // La funzione valid_d() effettua i controlli sul parametro specificato
per // l'opzione -d, onde verificare la correttezza dei bits impostati
per la device // attribute word. Il parametro specificato e' un numero DECIMALE.
Non vengono // effettuati controlli sulla coerenza reciproca dei bits settati. int valid_d(struct OPT *vld,int cnt) // convalida opzione "d" { extern unsigned optCnt; extern DEVHDR DevDrvHdr; extern const char *invAttrib; register temp; if(optCnt++) err_handler(NULL,NULL); if(atol(vld->arg) > UINT_MAX) { fprintf(stderr,invAttrib,PRG); err_handler(NULL,NULL); } if((temp = atoi(vld->arg)) < 0) { fprintf(stderr,invAttrib,PRG); err_handler(NULL,NULL); } DevDrvHdr.attrib = temp; checkAttrBits(); } // La funzione valid_h() effettua i controlli sul parametro specificato
per // l'opzione -h, onde verificare la correttezza dei bits impostati
per la device // attribute word. Il parametro specificato e' un numero ESADECIMALE.
Non vengono // effettuati controlli sulla coerenza reciproca dei bits settati. int valid_h(struct OPT *vld,int cnt) // convalida opzione "h" { extern unsigned optCnt; extern DEVHDR DevDrvHdr; extern const char *invAttrib; register i; if(optCnt++) err_handler(NULL,NULL); for(i = 0; vld->arg[i] == '0'; i++); if(strlen(vld->arg+i) > 4) { fprintf(stderr,invAttrib,PRG); err_handler(NULL,NULL); } sscanf(vld->arg+i,"%X",&DevDrvHdr.attrib); checkAttrBits(); } // La valid_n() controlla la validita' del nome logico specificato
per il device e // lo copia nel campo apposito del device driver header, trasformando
tutti i // caratteri in maiuscoli, troncandolo se piu' lungo di 8 caratteri
e aggiungendo // spazi a "tappo" se piu' corto. Nel caso sia usata la sintassi
/units/ per // specificare il numero di unita' supportate (block device driver)
controlla la // correttezza sintattica e la validita' del parametro e lo copia nel
primo byte // del campo. Il controllo tra tipo di parametro e tipo di device e'
effettuato // dalla name_flag(), listata poco sotto. int valid_n(struct OPT *vld,int cnt) // convalida opzione "n" { extern const unsigned char nonFNameChars[]; extern DEVHDR DevDrvHdr; extern const char *invName; extern const char *invUnits; static int instance; register i; long units; char *ptr; char line[MAX_LINE]; if(instance++) err_handler(NULL,NULL); // consentito solo un nome if(*vld->arg == UFLAG) { // BLOCK DEVICE DRIVER if(sscanf(vld->arg+1,"%ld%s",&units,line) != 2) { fprintf(stderr,invUnits,PRG); err_handler(NULL,NULL); } if((units > MAX_UNITS) || (units < MIN_UNITS)) { fprintf(stderr,invUnits,PRG); err_handler(NULL,NULL); } if(strcmp(line,"/")) { fprintf(stderr,invUnits,PRG); err_handler(NULL,NULL); } DevDrvHdr.name[0] = (unsigned char)units; } else { // CHARACTER DEVICE DRIVER ptr = vld->arg; if(strpbrk(strupr(ptr),(char *)nonFNameChars)) { fprintf(stderr,invName,PRG); err_handler(NULL,NULL); } strncpy(DevDrvHdr.name,ptr,NAMELEN); for(i = strlen(ptr); i < NAMELEN; i++) DevDrvHdr.name[i] = BLANK; // lunghezza fissa 8 blank padded } } // La err_handler() gestisce il caso di opzione errata int err_handler(struct OPT *vld,int cnt) // gestione opz. errate { extern const char *helpStr; fprintf(stderr,"%s: Syntax is:\n%s option[s] filename\n\n%s",PRG,PRG, helpStr); exit(1); } // la name_flag() e' chiamata dalla parseopt() una volta per ogni parametro // non-option incontrato sulla command line, pertanto e' chiamata una
sola volta // se sulla cmd line e' specificato un solo nome di file. Tramite il
contatore // nameFlag verifica di non essere chiamata piu' di una volta. Inoltre
essa // controlla che vi sia coerenza tra il tipo di device driver indicato
nella // device attribute word (bit 15 settato) e il tipo di parametro per
l'opzione // -n (nome logico o numero di unita'). int name_flag(struct OPT *vld,int cnt) // gestione nome file { extern DEVHDR DevDrvHdr; extern unsigned nameFlag; extern const char *invAttrib; extern const char *invFile; if(nameFlag++) { fprintf(stderr,invFile,PRG); err_handler(NULL,NULL); } if((DevDrvHdr.name[0] < BLANK) && (DevDrvHdr.attrib &
BIT_15)) { fprintf(stderr,invAttrib,PRG); err_handler(NULL,NULL); } } #pragma warn .par #pragma warn .rvl // Struttura per la gestione delle opzioni (associa ogni opzione lecita
alla // funzione corrispondente). struct VOPT valfuncs[] = { {'?',err_handler}, {'b',valid_b}, {'d',valid_d}, {'h',valid_h}, {'n',valid_n}, {ERRCHAR,err_handler}, {NULL,name_flag} }; // stringa di definizione delle opzioni (se seguite dai due punti richiedono
un // parametro) const char *optionS = "?b:d:h:n:"; // FUNZIONI: main(), poi tutte le altre in ordine alfabetico int main(int argc,char **argv) { extern unsigned optCnt; extern unsigned nameFlag; extern const char *optionS; extern struct VOPT valfuncs[]; struct OPT *opt; fprintf(stderr,"%s %s - Set DevDrv Header - Barninga Z! %s. -?
help\n\n", PRG,VER,YEAR); // main() usa parseopt() per analizzare
le opzioni // specificate sulla command line. Sono queste ad effettuare tutti
i controlli // (vedere sopra). if(!(opt = parseopt(argc,argv,(char *)optionS,SWCHAR,ILLMSG,ILLMSG, valfuncs))) { perror(PRG); return(1); } if(!optCnt) { fprintf(stderr,"%s: No option specified.\n",PRG); return(1); } if(!nameFlag) { fprintf(stderr,"%s: No filename specified.\n",PRG); return(1); } return(setDevDrvHdr(opt[opt[0].opt].arg)); } // Controlla che i bits settatti nella attribute word del device driver
header // non siano tra quelli riservati DOS (che devono essere zero) void checkAttrBits(void) { if(DevDrvHdr.attrib & ATTR_MASK) { fprintf(stderr,invAttrib,PRG); err_handler(NULL,NULL); } } // Chiede conferma all'utente. Dal momento che attende lo standard
input, la // conferma puo' essere letta da un file (con la redirezione '<')
contenente // la lettera 'Y' o 'N' seguita da un CR LF. Cio' risulta utile nei
casi in cui // si voglia automatizzare l'operazione di agiornamento, ad esempio
in un // batch file di compilazione del device driver. int confirm(char *prompt,char yes,char no) { int ch; fprintf(stderr,prompt,yes,no); do { ch = toupper(getch()); } while((ch != yes) && (ch != no)); fprintf(stderr," %c\n\n",ch); return((ch == yes) ? 1 : 0); } // Visualizza i campi dello header void displayHeader(DEVHDR *hdr,char *title) { register i = 0; fprintf(stdout,"%s\n",title); fprintf(stdout,"\tNext Device Address: %Fp\n",hdr->nextDev); fprintf(stdout,"\tAttribute Word: %04X\n",hdr->attrib); fprintf(stdout,"\tStrategy Routine Offset: %04X\n",hdr->strategyOff); fprintf(stdout,"\tInterrupt Routine Offset: %04X\n",hdr->interruptOff); fprintf(stdout,"\tLogical Name: \""); if(*hdr->name < BLANK) { i = 1; putch(*hdr->name); } for( ; i < NAMELEN; i++) fputc(hdr->name[i],stdout); fprintf(stdout,"\"\n\n"); } // Legge lo header attuale del driver e chiama displayHeader() una
prima volta per // visualizzarne i campi. Successivamente visualizza, sempre tramite
displayHeader() // i campi come saranno scritti nel driver in base ai parametri passati
sulla // command line e attende conferma via confirm(). int setDevDrvHdr(char *fname) { extern DEVHDR DevDrvHdr; DEVHDR fileHdr; FILE *file; if(!(file = fopen(fname,"r+b"))) { perror(PRG); return(1); } if(fread(&fileHdr,sizeof(DEVHDR),1,file) < 1) { perror(PRG); return(1); } displayHeader(&fileHdr,"Current Header Fields:"); fileHdr.attrib = DevDrvHdr.attrib; strncpy(fileHdr.name,DevDrvHdr.name,NAMELEN); displayHeader(&fileHdr,"New Header Fields:"); if(confirm("Confirm Update (%c/%c)?",'Y','N')) { rewind(file); if(fwrite(&fileHdr,sizeof(DEVHDR),1,file) < 1) { perror(PRG); fprintf(stdout,"%s: %s may have been partially modified.\n",PRG, strupr(fname)); return(1); } fprintf(stdout,"%s: %s updated successfully.\n",PRG,strupr(fname)); } else fprintf(stdout,"%s: %s not updated.\n",PRG,strupr(fname)); return(0); }