Aspetti tecnici 

Il bootstrap 

Il bootstrap è la fase iniziale della sessione di lavoro della macchina. Dapprima sono eseguite le routine di autodiagnostica del BIOS, il quale provvede in seguito a cercare sui dischi del computer il loader del DOS: si tratta di una routine, memorizzata in uno dei primi settori del disco fisso (il boot sector), che carica in memoria ed esegue il primo dei due file nascosti del DOS (solitamente chiamato IO.SYS). 

IO.SYS si compone di una parte residente e di una parte transiente: la prima è destinata a rimanere in memoria fino al successivo spegnimento o reset della macchina, mentre la seconda serve esclusivamente ad effettuare le operazioni di caricamento del sistema. La porzione transiente, infatti, tramite una routine chiamata SYSINIT, individua l'indirizzo del cosiddetto top of memory (il limite superiore della memoria convenzionale) e copia IO.SYS "lassù", al fine di sgombrare la parte inferiore della RAM. A questo punto in memoria vi sono due istanze di IO.SYS: la SYSINIT della seconda carica l'altro file nascosto (MSDOS.SYS) in modo da ricoprire la porzione transiente della prima. SYSINIT attiva poi tutti i device driver residenti (quelli incorporati nel DOS), legge il file CONFIG.SYS per determinare quali sono gli installable device driver da caricare e provvede al loro caricamento ed inizializzazione: il device driver consente, da questo momento in poi, di accedere alla periferica mediante un nome, che per il sistema operativo equivale (dal punto di vista logico) ad un nome di file o di unità disco, come sarà meglio chiarito tra breve. L'ultima operazione effettuata da SYSINIT è l'esecuzione dell'interprete dei comandi (COMMAND.COM o il programma specificato dall'istruzione SHELL= nel file CONFIG.SYS [3]). 

Tipi di device driver 

Esistono due tipi di device driver: character e block device driver (driver per periferiche a carattere o a blocchi). 

I primi sono adatti alla gestione di periferiche come terminali e stampanti, cioè periferiche che effettuano le loro operazioni di I/O un carattere (byte) alla volta. Il nome assegnato dal driver alla periferica può essere usato dal DOS e dalle applicazioni come un nome di file, sul quale scrivere o dal quale leggere i byte. Se il nome è identico a quello già utilizzato da un device driver residente, quest'ultimo è sostituito, nelle sue funzionalità, dall'installable device driver[4]. Il DOS può comunicare con i character device driver in due modalità differenti, a seconda che essi siano definiti come raw o cooked: la modalità raw (grezza) prevede che ogni singolo byte passi dal driver al DOS o viceversa senza alcuna modifica; in modalità cooked (letteralmente... "cucinata", ma con un po' di fantasia si potrebbe tradurre in "interpretata") il DOS memorizza i caratteri in un buffer e gestisce opportunamente i caratteri di controllo (CTRL­C, etc.) prima di passarli (al primo RETURN incontrato) all'applicazione o al device driver[5]. La modalità raw o cooked è selezionabile dalle applicazioni, mediante la subfunzione 01h del servizio 44h dell'int 21h: 

INT 21H, SERV. 44H, SUBF. 01H: MODIFICA GLI ATTRIBUTI DI UN DEVICE DRIVER 
Input AH 44h 
AL 01h 
BX handle[6] 
DH 00h 
DL Nuovi bit di stato: 

Bit 7: 1 

5: 1 = RAW, 0 = COOKED 

Per i bit 0-4 e 6 si rimanda alla descrizione della device attribute word 
Output AX Codice di errore se il CarryFlag è 1

Se il CarryFlag è 0 la chiamata ha avuto successo 
I block device driver gestiscono periferiche che effettuano l'I/O mediante blocchi di byte (esempio classico: i dischi). Contrariamente alle periferiche a carattere, accessibili esclusivamente in modo sequenziale, i block device sono dispositivi ai quali è possibile accedere in modo random (casuale), cioè con spostamenti arbitrari avanti o indietro rispetto alla posizione attuale nel flusso di dati. Il DOS assegna ad ogni periferica gestita dal device driver[7] un nome di disco (una lettera dell'alfabeto seguita dai due punti): un installable block device driver non può, dunque, sostituirsi a un resident device driver, ma solamente affiancarsi ad esso nella gestione di altre periferiche dello stesso tipo. Va sottolineato, infine, che i block device driver operano sempre in modalità raw. 

Struttura e comportamento dei device driver 

In cosa consistono le particolarità della struttura dei device driver? Va detto, innanzitutto, che non si tratta di file eseguibili[8] in senso stretto, ma di file dei quali viene caricata in memoria l'immagine binaria: in altre parole, essi vengono caricati in RAM esattamente come sono memorizzati sul disco, senza la creazione di PSP ed environment[9], né la gestione di una eventuale Relocation Table da parte del sistema operativo. 

Inoltre, i primi 18 byte di ogni device driver sono riservati ad una tabella, detta header, contenente informazioni ad uso del DOS (sulla quale ci sofferemeremo tra poco): proprio qui incontriamo uno dei maggiori ostacoli, poiché, come è facile intuire, si tratta di una caratteristica assolutamente incompatibile con la normale modalità di compilazione dei programmi C[10]

Ogni device driver, inoltre, incorpora una routine che deve provvedere a salvare, per utilizzi successivi, l'indirizzo del buffer attraverso il quale il DOS comunica con il driver stesso: è la cosiddetta strategy routine (a dire il vero non si vede che cosa ci sia di strategico in tutto ciò, ma comunque...). 

Il terzo elemento caratteristico dei device driver è, infine, la interrupt routine: anche in questo caso il nome è poco azzeccato, perchè si tratta di una procedura che ha ben poco a che fare con i "classici" gestori di interrupt[11] (vedere, ad esempio, il capitolo dedicato); il suo compito consiste nell'individuare il servizio richiesto dal DOS al driver ed attivare la routine (interna al driver) corrispondente. 

Ne consegue in modo ovvio che, per ogni servizio gestito, il driver deve incorporare una routine dedicata, più una routine generalizzata di gestione dell'errore per i casi in cui il DOS richieda un servizio non previsto: ogni driver deve però necessariamente gestire è il servizio 00h, corrispondente alla propria inizializzazione in fase di bootstrap[12]

Struttura di un Device DriverLa figura 17, riprodotta qui accanto, schematizza la struttura di un device driver, coerentemente con le considerazioni sin qui esposte: si vede facilmente che le analogie con i programmi TSR sono molteplici (vedere, ad esempio, la  figura14). 

Ne sappiamo abbastanza, a questo punto, per capire (a grandi linee) come lavorano i device driver: il "protocollo" di colloquio tra sistema operativo e driver è fisso e si articola in quattro fasi ben definite. 
  1. il DOS invoca la strategy routine passandole in ES:BX l'indirizzo (puntatore far) di un buffer (detto request header[13]) contenente i dati che occorrono per effettuare l'operazione (servizio) prevista (la struttura del buffer varia a seconda del servizio); 
  2. la strategy routine salva l'indirizzo del buffer in una variabile (locazione di memoria) nota ed accessibile alle altre routine del driver e restituisce il controllo al sistema; 
  3. il DOS invoca la interrupt routine[14]
  4. la interrupt routine accede al buffer (mediante l'indirizzo salvato in precedenza dalla strategy routine) per conoscere il numero del servizio richiesto (e relativi dati) e provvede all'esecuzione delle operazioni per esso previste, generalmente chiamando una routine dedicata, la quale, a sua volta, può chiamare altre routine del driver o interrupt di sistema: al termine, la interrupt routine o le routine dedicate scrivono nel solito buffer i risultati dell'elaborazione ed un valore avente significato di codice di errore, ed infine restituiscono il controllo al DOS. 
Flusso delle chiamate ai Device DriverConseguenza immediata di tale algoritmo è il completo isolamento del device driver dalle applicazioni che ne utilizzano i servizi: i driver, è evidente, interagiscono esclusivamente con il sistema operativo, che si pone quale interfaccia tra essi e le applicazioni. Ciò risulta ancora più palese quando si consideri che i driver rendono accessibili le periferiche loro associate attraverso un nome di file o di unità disco: le applicazioni devono ricorrere agli appositi servizi DOS[15]Infatti, le applicazioni effettuano le operazioni di I/O richiedendo l'opportuno servizio al sistema operativo (int 21h): il DOS individua (grazie ad una tabella costruita durante il bootstrap) il device driver interessato, costruisce un request header appropriato e chiama la strategy routine. Il device driver memorizza l'indirizzo del buffer e restituisce il controllo al DOS che, immediatamente, chiama la interrupt routine, secondo lo schema analizzato: ne risulta un flusso come quello rappresentato in figura 18 qui accanto. 

Vale la pena di osservare che la suddivisione delle operazioni di interfacciamento DOS/driver tra due routine (la strategy e la interrupt) è ispirata alle esigenze di sistemi multitasking (come Unix): essa non è di alcuna utilità in sistemi monotasking (quale è il DOS), in quanto questi eseguono sempre e solo un'unica operazione di I/O alla volta. 

Questo è il momento di approfondire l'analisi della struttura dello header, del buffer di comunicazione con il DOS e dei servizi che il device driver può implementare: forse non è divertente, ma è di fondamentale importanza... 

Il Device Driver Header: in profondità 

Il device driver header è la tabella che occupa i primi 18 byte del codice di ogni device driver. Vediamone contenuto e struttura: 

STRUTTURA DEL DEVICE DRIVER HEADER 
OFFSET
DIM.
CONTENUTO
00h 4 Puntatore far al device driver successivo. Deve contenere il valore FFFFFFFFh, in quanto viene inizializzato automaticamente dal DOS al caricamento del driver[16]
04h 2 Device Attribute Word. E' una coppia di byte i cui bit sono utilizzati per descrivere alcune caratteristiche della periferica (vedere di seguito). 
06h 2 Puntatore near alla strategy routine. 
08h 2 Puntatore near alla interrupt routine. 
0Ah 8 Se la periferica che il driver gestisce è di tipo character, il campo contiene il nome logico assegnato alla periferica stessa, utilizzabile dalle applicazioni come un nome di file: se il nome è lungo meno di 8 byte, lo spazio restante deve essere riempito con spazi. 

Se la periferica gestita è di tipo block, il primo byte del campo contiene il numero di unità supportate; l'uso dei restanti 7 byte è riservato al DOS. Il programmatore non ha necessità di inizializzare il primo byte del campo: a ciò provvede il DOS con le informazioni restituite dal driver al termine della fase di Init
Si noti che i puntatori alla strategy e interrupt routine sono near: il DOS effettua però chiamate far, utilizzando quale parte segmento dell'indirizzo il segmento al quale il driver stesso è caricato. Ne segue che i due campi menzionati contengono, in realtà, la parte offset dell'indirizzo delle due funzioni e che queste devono essere dichiarate entrambe far (e terminare quindi con una istruzione RETF). 

La tabella che segue descrive il significato dei bit della Device Attribute Word. 

STRUTTURA DELLA DEVICE ATTRIBUTE WORD 
BIT
SIGNIFICATO
15 1 se si tratta di un character device driver 

0 se è un block device driver 
14 1 se il device driver supporta i servizi IOCTL[17] di lettura e scrittura 
13 1 se la periferica è un block device (disco) formattato in modo non­IBM 
12 0 (riservato)
11 1 se il drivere può gestire un block device (disco) rimuovibile (DOS 3 e succ.) 
7-10 0 (riservati)
6 1 se il device driver supporta i servizi IOCTL Generic e Get/Set Logical Drive 
5 0 (riservato)
4 1 se il device driver supporta la funzione DOS speciale di output veloce per la periferica CON 
3 1 se il device driver è il driver per il device CLOCK 
2 1 se il device driver è il driver per il device NUL 
1 1 se il device driver è il driver per lo standard output 
0 1 se il device driver è il driver per lo standard input
Va sottolineata l'importanza del bit 15, che indica se la periferica gestita lavora a blocchi o a caratteri; qualora esso valga 1 (block device driver), solo i bit 6, 11 e 13­15 sono significativi: tutti gli altri devono essere impostati a 0

E' ancora interessante notare che le informazioni contenute nel device driver header sono utilizzate dal sistema operativo, mentre, di norma, le applicazioni non vi accedono. Vi sono però alcuni servizi IOCTL che consentono di leggere e modificare alcuni dei bit (non tutti) della attribute word[18]

Il Request Header e i servizi: tutti i particolari 

Il request header è il buffer attraverso il quale DOS e device driver si scambiano le informazioni: il sistema operativo ne carica l'indirizzo in ES:BX e chiama la strategy routine perché il device driver possa conoscerlo e memorizzarlo. Il buffer contiene il numero del servizio richiesto, nonché tutti i dati necessari al driver per il suo espletamento, e si divide in due parti: la prima, detta parte fissa, è identica (quanto a numero, ordine e dimensione dei campi) per tutti i servizi, mentre la seconda, detta parte variabile, ha struttura differente a seconda del servizio richiesto (alcuni servizi presentano comunque identica parte variabile del request header, o non la utilizzano del tutto). La parte fissa del request header è strutturata come segue. 

STRUTTURA DEL DEVICE DRIVER REQUEST HEADER 
OFFSET
DIM.
CONTENUTO
00h 1 Lunghezza totale del request header. Il valore, diminuito di 13 (lunghezza della parte fissa) esprime la lunghezza della parte variabile. E' un campo utilizzato assai raramente, dal momento che la lunghezza del request header può essere desunta dal numero del servizio richiesto. 
01h 1 Numero dell'unità (disco). E' un campo significativo solo per i block device driver e indica su quale disco (o altro block device) deve essere eseguito il servizio richiesto. 
02h 1 Command code. E' il numero del servizio richiesto dal DOS al device driver. 
03h 2 Return Code (Status word). E' il valore restituito dal driver al DOS per indicare lo stato del servizio eseguito. 
05h 8 Utilizzo riservato al DOS. 
E' importante approfondire l'analisi del Return Code: si tratta di una word (due byte) nella quale il byte più significativo è interpretato come campo di bit, ed è usato per indicare lo stato del servizio; il byte meno significativo contiene invece un valore che descrive un errore se il bit 15 della word vale 1: se questo è 0, detto valore viene ignorato dal sistema operativo. Il dettaglio dei bit e codici di errore è riportato nella tabella che segue. 

STRUTTURA DELLA DEVICE DRIVER STATUS WORD 
BIT
SIGNIFICATO
15 Error Flag. 1 se si è verificato un errore, 0 altrimenti. 
12-14 Riservati. 
9 Busy Flag. 1 se il driver vuole impedire al DOS di richiedere ulteriori servizi (ad esempio perché l'esecuzione del servizio non è stata ancora portata a termine), 0 altrimenti. 
8 Done Flag. 1 se il servizio è stato completamente eseguito, 0 se l'operazione non è ancora stata completata. 
0-7 Error Code (codice di errore). E' significativo solo se il bit 15 (Error Flag) è 1: 
00h Tentativo di scrittura su unità protetta. 
01h Unità sconosciuta. 
02h Unità non pronta (ad es.: sportello del disk drive aperto). 
03h Servizio non supportato. 
04h Errore di CRC. 
05h Lunghezza del Request Header errata[19]
06h Errore di ricerca dati sull'unità (seek error). 
07h Tipo di unità sconosciuto. 
08h Settore non trovato. 
09h Stampante senza carta. 
0Ah Errore di scrittura. 
0Bh Errore di lettura. 
0Ch Errore generico, non individuato (General failure). 
0Dh Riservato. 
0Eh Riservato. 
0Fh Cambiamento di disco non valido (a partire dal DOS 3.0)[20]
Come si è detto, la parte variabile del request header è strutturata in dipendenza dal servizio richiesto dal DOS al driver, cioè a seconda del valore che il campo Command code assume. Si noti che il driver restituisce valori e informazioni al DOS scrivendoli, a sua volta, nel request header (in campi della parte fissa o variabile). Di seguito è presentato l'elenco completo dei servizi che il DOS può richiedere al driver. 

ELENCO DEI SERVIZI IMPLEMENTABILI DAI DEVICE DRIVER 
CODICE
SERVIZIO
00 Init (inizializzazione del driver). 
01 Media Check (solo per block device driver) 
02 Build BIOS Parameter Block (solo per block device driver) 
03 IOCTL Read
04 Read (input)
05 Nondestructive Read (solo per character device driver) 
06 Input Status (solo per character device driver) 
07 Flush Input Buffers (solo per character device driver) 
08 Write (output)
09 Write With Verify 
10 Output Status (solo per character device driver) 
11 Flush Output Buffers (solo per character device driver) 
12 IOCTL Write
13 Device Open
14 Device Close
15 Removable Media (solo per block device driver) 
16 Output Until Busy (solo per character device driver) 
19 Generic IOCTL Request 
23 Get Logical Device (solo per block device driver) 
24 Set Logical Device (solo per block device driver) 
I servizi 13­16 sono stati introdotti a partire dalla versione 3.0 del DOS, mentre i servizi 19 e 23­24 dalla versione 3.2. Di seguito sono analizzati nel dettaglio tutti i servizi elencati e, per ciascuno di essi, la corrispondente struttura della parte variabile del device driver request header. 

Servizio 00: Init 

Il servizio 0 è la routine di inizializzazione del driver, detta Init. Esso è richiesto dal DOS una volta sola, nella fase di caricamento del driver durante il bootstrap[21]. Il driver ha così la possibilità di effettuare tutte le operazioni necessarie alla predisposizione dell'operatività successiva: controllo dello hardware, installazione di gestori di interrupt e via dicendo. L'utilizzo del request header è il seguente: 

DEVICE DRIVER, SERV. 00: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1
02h 1 Numero del servizio richiesto (0
03h 2 Stato dell'operazione
05h 8
0Dh 1 Numero di unità supportate (solo block device driver). 
0Eh 4 Puntatore far al primo byte di memoria libera oltre il device driver. 
12h 4 Puntatore far alla riga di comando del driver nel file CONFIG.SYS. Punta al primo byte che segue la stringa "DEVICE=".  Usato solo dai block device driver. Puntatore far all'array di puntatori ai BPB (vedere la tabella seguente). E' un array di word, ciascuna delle quali è un puntatore near ad un BPB. L'array contiene un elemento (word) per ogni unità logica supportata dal device driver. 
16h 1 Numero della prima unità disco disponibile[22] (solo block device driver). 
Bisogna tenere presente che quando i device driver vengono caricati dal DOS, quest'ultimo non ha ancora completato la propria installazione[23] e, pertanto, non tutte le funzionalità che esso implementa sono disponibili. In particolare, Microsoft afferma che il servizio 0 dei device driver può utilizzare solo alcune delle funzioni dell'int 21h: da 01h a 0Ch (I/O di caratteri), 25h e 35h (installazione e richiesta di vettori di interrupt), 30h (richiesta della versione DOS). In realtà, esperimenti empirici hanno rivelato che altre funzioni sono attive e disponibili: particolarmente importanti risultano quelle relative all'I/O con i file (durante la fase di init è quindi possibile, ad esempio, leggere un file di configurazione specificato sulla riga di comando del device driver in CONFIG.SYS). 

Il sistema operativo, nel richiedere il servizio 0, consente al driver di conoscere la riga di comando nel file CONFIG.SYS, come specificato circa il campo ad offset 12h nel request header. La stringa, tutta in caratteri maiuscoli, termina al primo LF o CR o EOF (10h o 13h o 1Ah) e non deve essere modificata dal driver, che può però copiarla in una locazione di memoria privata per effettuare tutte le elaborazioni eventualmente necessarie. 

Al termine della Init, il driver deve porre a 1 il bit 8 (Done Flag) della status word (campo ad offset 03h del request header), e deve indicare al DOS quanta memoria deve essere riservata per la parte residente: particolarmente importante allo scopo risulta il campo ad offset 0Eh, in quanto consente al driver di specificare l'indirizzo del primo byte di RAM oltre la porzione residente. Il DOS sa, in tal modo, che a quell'indirizzo inizia la memoria disponibile per le successive operazioni di bootstrap. Detto indirizzo può validamente essere, ad esempio, quello della prima funzione della parte transiente nel sorgente C (se la parte residente non usa funzioni di libreria). Se il driver rileva, durante l'inizializzazione, errori tali da renderne inutile il caricamento (ad esempio: il driver del mouse non ne trova alcuno collegato al personal computer), può scrivere nel campo in questione l'indirizzo del proprio device driver header: essendo questo l'indirizzo al quale il driver stesso è caricato in memoria, il sistema operativo non riserva neppure un byte alla parte residente, risparmiando così preziosa memoria. Per segnalare al DOS la condizione di "aborted installation" occorre anche azzerare il bit 15 della device attribute word nel device driver header e restituire 0 nel campo ad offset 0Dh del request header. 

Il driver (se è un block device driver) può anche conoscere il numero assegnato alla prima delle sue unità grazie all'ultimo campo della parte variabile del request header; esso deve comunicare al DOS il numero di unità supportate (campo ad offset 0Dh), tramite il quale il DOS assegna loro gli identificativi letterali[24], nonché gli indirizzi (campo ad offset 12h) dei BPB che descrivono ogni unità. Il BPB (BIOS Parameter Block) è una tabella che contiene i parametri BIOS per un'unità disco e ha il formato descritto di seguito: 

STRUTTURA DEL BPB 
OFF
DIM
CAMPO
00h 2 Lunghezza del settore in byte 
02h 1 Numero di settori per cluster (unità di allocazione) 
03h 2 Numero di settori riservati (a partire dal settore 0) 
05h 1 Numero di FAT (File Allocation Table) presenti sul disco 
06h 2 Numero massimo di elementi nella directory root 
08h 2 Numero totale di settori 
0Ah 1 Media descriptor byte (o Media ID byte): 

F0h: floppy 3.5" (2 lati, 18 sett./traccia) 

F8h: hard disk 

F9h: floppy 5.25" (2 lati, 15 sett./traccia) 

F9h: floppy 3.5" (2 lati, 9 sett./traccia) 

FCh: floppy 5.25" (1 lato, 9 sett./traccia) 

FDh: floppy 5.25" (2 lati, 9 sett./traccia) 

FEh: floppy 5.25" (1 lati, 8 sett./traccia) 

FFh: floppy 5.25" (2 lati, 8 sett./traccia) 
0Bh 2 Numero di settori in una FAT 
0Dh 2 Numero di settori per traccia (dal DOS 3.0 in poi) 
0Fh 2 Numero di testine (dal DOS 3.0 in poi) 
11h 2 Numero di settori nascosti (dal DOS 3.0 in poi) 
13h 2 Word più significativa del numero di settori nascosti, a partire dal DOS 3.2 (in cui il numero settori nascosti diviene un dato a 32 bit) 
15 4 Se la word ad offset 08h è 0, questo campo contiene il numero totale di settori espresso come dato a 32 bit, onde consentire il superamento del limite di 32Mb alla dimensione delle partizioni dei dischi fissi (dal dos 3.2 in poi). 

Servizio 01: Media Check 

Il servizio 1 è specifico dei block device driver ed è richiesto dal DOS durante operazioni di I/O diverse dalle semplici lettura o scrittura. In pratica, il sistema chiede al driver di verificare se il disco sul quale le operazioni sono in corso è stato sostituito: il driver può rispondere "SI", "NO" oppure "NON SO". Nel primo caso, il DOS non riutilizza il contenuto dei buffer[25] relativi a quella unità, richiede un servizio 2 (descritto di seguito) e rilegge la FAT e la root directory. Se il driver risponde "NO", allora il sistema effettua l'oprazione di I/O richiesta dall'applicazione considerando valido il contenuto dei buffer. Nel caso di risposta dubitativa, il DOS opera in modo differente a seconda dello stato dei buffer: se questi contengono dati in attesa di essere scritti, il sistema li scrive (anche a rischio di danneggiare il contenuto del disco nel caso in cui esso sia stato effettivamente sostituito); in caso contrario procede come per la risposta "SI". 

Il request header è strutturato come segue: 

DEVICE DRIVER, SERV. 01: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1 Numero di unità disco (0 = A:
02h 1 Numero del servizio richiesto (1
03h 2 Stato dell'operazione
05h 8
0Dh 1 Media ID byte 
0Eh 1 Media Change Code: 

­1: Il disco e' stato sostituito 

0: Forse sì, forse no, boh? 

1: Il disco non è stato sostituito 
0Fh 4 A partire dal DOS 3.0: puntatore far ad una stringa ASCIIZ (terminata con un NULL) contenente l'etichetta di volume del disco[26] se il Media Change Code è ­1 e si è verificato un errore 0Fh
Il device driver può utilizzare il campo ad offset 1Fh se il bit 11 della device attribute word vale 1

Servizio 02: Build BPB 

Anche questo servizio è tipico dei block device driver. Il DOS lo richiede dopo un servizio 1 (testè descritto) in due casi: se il device driver di unità restituisce un Media Change Code ­1 (disco sostituito), oppure restituisce 0 (disco forse sostituito) e non vi sono buffer contenenti dati in attesa di essere scritti. La chiamata al servizio 2 consente al DOS di conoscere le caratteristiche del nuovo disco presente nell'unità e "legalizza" la sostituzione avvenuta. Il request header è utilizzato come segue: 

DEVICE DRIVER, SERV. 02: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1 Numero di unità disco (0 = A:
02h 1 Numero del servizio richiesto (2
03h 2 Stato dell'operazione
05h 8
0Dh 1 Media ID byte 
0Eh 1 Puntatore far ad un buffer contenente il primo settore della FAT del disco. 
12h 4 Puntatore far al BPB del disco presente nell'unità. 
Il buffer il cui indirizzo è ricevuto dal driver nel campo ad offset 0Eh non deve essere modificato dal driver stesso se l'unità gestita è formattata secondo lo standard IBM; in caso contrario il buffer può essere utilizzato come area di lavoro. 

Servizio 03: IOCTL Read 

Il servizio 3 deve essere supportato dal driver solo se il bit 14 della device attribute word è 1. Esso è solitamente utilizzato dalle applicazioni per ottenere dal device driver informazioni sullo stato o sulla configurazione della periferica, senza trasferimento di dati, attraverso le apposite subfunzioni dell'int 21h, funzione 44h. La struttura del request header è descritta nella tabella che segue. 

Va infine osservato che le applicazioni possono leggere e scrivere dati da un character device solo dopo averlo "aperto", utilizzando il nome logico come se si trattasse di un vero e proprio file: per un esempio si veda il paragrafo dedicato

Vedere anche il servizio 12.

DEVICE DRIVER, SERV. 03: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1 Numero di unità disco (0 = A:); usato solo dai block device driver 
02h 1 Numero del servizio richiesto (3
03h 2 Stato dell'operazione
05h 8
0Dh 1 Media ID byte; usato solo dai block device driver 
0Eh 4 Puntatore far ad un buffer utilizzato per il trasferimento delle stringhe di controllo. 
12h 2 Numero di byte disponibili nel buffer  Numero di byte utilizzati nel buffer

Servizio 04: Read (Input) 

Il servizio 4 consente il trasferimento di dati dalla periferica ad un buffer in memoria. Il request header è strutturato come dalla tabella che segue. 

Dal momento che (per i block device driver) il DOS gestisce i settori dei dischi come settori logici numerati progressivamente a partire da 0, il device driver, per effettuare l'operazione di lettura deve trasformare (se necessario) il dato ricevuto nel campo ad offset 14h in un numero di settore fisico, esprimibile mediante le coordinate "tridimensionali" BIOS: lato/traccia/settore[27]. A partire dal DOS 3.0, i block device driver possono servirsi dei dati gestiti mediante i servizi 13 e 14 per determinare se il disco sia stato sostituito "imprudentemente". Vedere anche i servizi 8 e 9

DEVICE DRIVER, SERV. 04: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1 Numero di unità disco (0 = A:); usato solo dai block device driver 
02h 1 Numero del servizio richiesto (4
03h 2 Stato dell'operazione
05h 8
0Dh 1 Media ID byte; usato solo dai block device driver 
0Eh 4 Puntatore far ad un buffer utilizzato per il trasferimento dei dati 
12h 2 Numero di byte (character device driver) o settori (block device driver) di cui è richiesto il trasferimento  Numero di byte (character device driver) o settori (block device driver) di cui è effettuato il trasferimento 
14h 2 Numero del settore logico di partenza; usato solo dai block device driver 
16h 4 A partire dal DOS 3.0: puntatore far ad una stringa ASCIIZ (terminata con un NULL) contenente l'etichetta di volume del disco se si è verificato un errore 0Fh
Va infine osservato che le applicazioni possono leggere e scrivere dati da un character device solo dopo averlo "aperto", utilizzando il nome logico come se si trattasse di un vero e proprio file: per un esempio si veda il paragrafo dedicato

Servizio 05: Nondestructive Read 

Il servizio 5 è supportato solo dai character device driver ed è utilizzato dal DOS per ispezionare il prossimo byte presente nel flusso di dati proveniente dalla periferica (nel caso della tastiera, lo scopo specifico è individuare eventuali sequenze CTRL­C). La struttura del request header è descritta nella tabella che segue. 

Se nel flusso dati vi è effettivamente un carattere in attesa di essere letto, il driver deve restituirlo nel campo ad offset 0Dh; esso deve inoltre porre a 0 il Busy Flag Bit nella word di stato dell'operazione. Se non vi è alcun carattere in attesa, il driver deve unicamente porre a 1 detto bit. 

DEVICE DRIVER, SERV. 05: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1
02h 1 Numero del servizio richiesto (5
03h 2 Stato dell'operazione
05h 8
0Dh 1 Prossimo byte nel flusso di dati proveniente dalla periferica 
Le applicazioni possono leggere e scrivere dati da un character device solo dopo averlo "aperto", utilizzando il nome logico come se si trattasse di un vero e proprio file: per un esempio si veda il paragrafo dedicato

Servizio 06: Input Status 

Il servizio 6 è supportato solamente dai character device driver. Esso è utilizzato dal DOS per verificare se vi sono caratteri in attesa di essere letti nel flusso di dati proveniente dalla periferica ed utilizza la sola parte fissa del request header. 

DEVICE DRIVER, SERV. 06: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1
02h 1 Numero del servizio richiesto (6
03h 2 Stato dell'operazione
05h 8
Il driver deve porre a 1 il Busy Flag Bit nella Status Word se non vi è alcun carattere in attesa; in caso contrario deve porre detto bit a 0. Se il device non dispone di un buffer (hardware, o implementato via software dal driver stesso) detto bit deve essere sempre 0. Questo servizio è il supporto di basso livello alla funzione 06h dell'int 21h (Check Input Status). Vedere anche il servizio 10

Servizio 07: Flush Input Buffers 

Il servizio 7 è supportato solo dai character device driver. E' utilizzato dal DOS per richiedere al driver di eliminare tutti i caratteri in attesa di lettura presenti nei buffer associati alla periferica, rendendo questi ultimi disponibili per nuove operazioni di lettura. E' utilizzata solo la parte fissa del request header: 

DEVICE DRIVER, SERV. 07: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1
02h 1 Numero del servizio richiesto (7
03h 2 Stato dell'operazione
05h 8
Vedere anche il servizio 11

Servizio 08: Write (Output) 

Il servizio 8 consente il trasferimento di dati da un buffer in memoria alla periferica. Circa la struttura del request header e le particolarità operative, si veda il servizio 4 (Read), con l'avvertenza che il Command Code è, ovviamente, 8 invece di 4. Vedere anche il servizio 9

Va ancora osservato che le applicazioni possono leggere e scrivere dati da un character device solo dopo averlo "aperto", utilizzando il nome logico come se si trattasse di un vero e proprio file: per un esempio si veda il paragrafo dedicato

Servizio 09: Write With Verify 

Il servizio 9 è analogo al servizio 8, testè descritto, ma dopo l'operazione di scrittura il driver deve effettuare una operazione di lettura dei dati appena scritti per verificarne la correttezza. Il command code è 9. Vedere anche il servizio 4

Servizio 10: Output Status 

Il servizio 10 è supportato solamente dai character device driver. Esso è utilizzato dal DOS per verificare se un'operazione di scrittura da parte del driver sia in corso. Come per il servizio 6, è utilizzata solo la parte fissa del request header (ma il Command Code è 10); il driver deve porre a 1 il Busy Flag Bit nella Status Word se una operazione di scrittura è in corso. In caso contrario (condizione di idle driver) il bit deve essere azzerato. Questo servizio è il supporto di basso livello alla funzione 07h dell'int 21h (Check Output Status). 

Servizio 11: Flush Output Buffers 

Il servizio 11 è supportato solo dai character device driver. E' utilizzato dal DOS per richiedere al driver di completare tutte le operazioni di scrittura in corso, trasferendo fisicamente alla periferica tutti i dati presenti nei buffer ad essa associati e rendendo questi ultimi nuovamente disponibili per nuove operazioni di scrittura. Come per il servizio 7, è utilizzata solo la parte fissa del request header, ma il Command Code è, ovviamente, 11

Servizio 12: IOCTL Write 

Il servizio 12 deve essere supportato dal driver solo se il bit 14 della device attribute word è 1. Esso è solitamente utilizzato dalle applicazioni per inviare al device driver direttive di configurazione della periferica, senza trasferimento di dati, attraverso le apposite subfunzioni dell'int 21h, funzione 44h. La struttura del request header è identica a quella presentata con riferimento al servizio 3, con le sole differenze che il Command Code vale 12 e che il campo ad offset 0Eh del request header passato dal DOS al driver indica il numero di byte utilizzati nel buffer; il medesimo campo restituito dal driver esprime il numero di byte che esso ha effettivamente inviato alla periferica. 

Va infine osservato che le applicazioni possono leggere e scrivere su un character device solo dopo averlo "aperto", utilizzando il nome logico come se si trattasse di un vero e proprio file: per un esempio si veda il paragrafo dedicato

Servizio 13: Device Open 

Il servizio 13 deve essere supportato dai driver che hanno il bit 11 della device attribute word posto a 1 ed è richiesto dal DOS a partire dalla varsione 3.0. E' utilizzata solo la parte fissa del request header: 

DEVICE DRIVER, SERV. 13: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1 Numero dell'unità (solo per i block device driver) 
02h 1 Numero del servizio richiesto (13
03h 2 Stato dell'operazione
05h 8
Il driver non restituisce al DOS alcun risultato: scopo principale del servizio è consentire al driver di gestire un contatore dei file aperti sulla periferica supportata: questo deve essere incrementato dal servizio in esame e decrementato dal servizio 14 (Device Close; commentato di seguito). Il contatore deve inoltre essere forzato a 0 dal driver quando sia intercettata la sostituzione del disco nell'unità (vedere i servizi 1 e 2). 

Il servizio 13 è richiesto dal DOS in corrispondenza di tutte le chiamate da parte di applicazioni alle funzioni dell'int 21h che gestiscono l'apertura o la creazione di file e l'apertura di un character device per input o output. Può essere utilizzato, dai character device driver, per inviare alle periferiche stringhe di inizializzazione, eventualmente ricevute dalle applicazioni (via DOS) attraverso il servizio 12, testè commentato. 

L'apertura di un character device driver viene effettuata come una apertura di file utilizzando il nome logico del device. 

Servizio 14: Device Close 

Il servizio 14 è la controparte del servizio 13, testè descritto; pertanto anch'esso deve essere supportato dai driver che hanno il bit 11 della device attribute word posto a 1. Come per il servizio 13, è utilizzata solo la parte fissa del request header (ma il Command Code è 14) e il driver non restituisce al DOS alcun risultato: scopo principale del servizio è la gestione, in "collaborazione" con il servizio 13, di un contatore dei file aperti sulla periferica. 

Il servizio 14 è richiesto dal DOS in corrispondenza di tutte le chiamate da parte di applicazioni alle funzioni dell'int 21h che gestiscono la chiusura di file e la chiusura di un character device al termine di operazioni di input o output. Può essere utilizzato, dai character device driver, per inviare alle periferiche stringhe di reset o reinizializzazione, eventualmente ricevute dalle applicazioni (via DOS) attraverso il servizio 12.

Servizio 15: Removable Media 

Il servizio 15 è supportato dai block device driver che hanno il bit 11 della device attribute word posto a 1 ed è richiesto dal DOS a partire dalla versione 3.0. Esso costituisce il supporto, a basso livello, della subfunzione 08h della funzione 44h dell'int 21h (CheckIfBlockDeviceIsRemovable). E' utilizzata solo la parte fissa del request header: 

DEVICE DRIVER, SERV. 15: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1 Numero dell'unità 
02h 1 Numero del servizio richiesto (15
03h 2 Stato dell'operazione
05h 8
Il driver deve porre a 1 il Busy Flag Bit (bit 11) della Status Word se il disco non è rimuovibile; in caso contrario detto bit deve essere azzerato. 

Servizio 16: Output Until Busy 

Il servizio 16 è supportato esclusivamente dai character device driver che hanno il bit 13 della device attribute word posto a 1 ed è richiesto dal DOS a partire dalla versione 3.0. Il suo scopo principale è permettere l'implementazione di una routine ottimizzata di output per il pilotaggio in background di periferiche (ad esempio stampanti con spooler). Il request header è strutturato come da tabella: 

DEVICE DRIVER, SERV. 16: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1
02h 1 Numero del servizio richiesto (16
03h 2 Stato dell'operazione
05h 8
0Dh 1
0Eh 4 Puntatore far ad un buffer utilizzato per il trasferimento dei dati 
12h 2 Numero di byte di cui è richiesta la scrittura verso la periferica  Numero di byte effettivamente trasferiti
Il driver trasferisce i dati alla periferica, in modo continuo, sino al loro esaurimento e restituisce al sistema operativo il numero di byte effettivamente trasferiti[28]

Servizio 19: Generic IOCTL Request 

Il servizio 19 è definito a partire dalla versione 3.2 del DOS, che lo richiede solo se il bit 6 della device attribute word è 1. Esso costituisce il supporto di basso livello per la subfunzione 0Ch della funzione 44h dell'int 21h e ha quale principale finalità fornire supporto alla realizzazione di una interfaccia IOCTL con le caratteristiche desiderate dal programmatore[29]. Il request header è utilizzato come segue: 

DEVICE DRIVER, SERV. 19: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1 Numero di unità disco (0 = A:); usato solo dai block device driver 
02h 1 Numero del servizio richiesto (19
03h 2 Stato dell'operazione
05h 8
0Dh 1 Category Code (Major Code) 
0Eh 1 Function Code (Minor Code) 
0Fh 2 Contenuto del registro SI 
11h 2 Contenuto del registro DI 
13h 4 Puntatore far ad un buffer (Generic IOCTL Data Packet) contenente i dati necessari al servizio 
L'interfaccia IOCTL supportata dal servizio 19 è di tipo aperto, disponibile, cioè, per future implementazioni. Tutte le sue caratteristiche e funzionalità, in ogni caso, devono essere definite dal programmatore. Il driver riceve dal DOS Category Code e Function Code, che possono essere utilizzati, rispettivamente, per identificare un tipo di driver e selezionare il sottoservizio desiderato. L'utilizzo dei valori di SI e DI copiati nel request header è libero. Infine, anche la dimensione, il formato ed il contenuto del buffer, il cui indirizzo è memorizzato nell'ultimo campo del request header, sono definiti dal programmatore a seconda della modalità scelta per l'implementazione del servizio. Già a partire dalla versione 3.3 del DOS si sono diffusi alcuni utilizzi standard del servizio, con valori predefiniti per Category Code, Function Code e formato del buffer; ciononstante, nessuno di essi è ufficialmente documentato. 

Analoghe considerazioni valgono per eventuali valori restituiti dal driver al DOS: può essere utilizzato qualsiasi campo del request header (eccetto il campo di status) o lo stesso buffer. 

Per un esempio di utilizzo del servizio 19, si veda il paragrafo dedicato

Servizio 23: Get Logical Device 

Il servizio 23 è supportato dai block device driver nella cui device attribute word il bit 6 è posto a 1 ed è richiesto dal DOS a partire dalla versione 3.2. Esso costituisce il supporto di basso livello per la sottofunzione 0Eh della funzione 44h dell'int 21h (GetLogicalDriveMap), il cui scopo è determinare se alla medesima unità disco sia assegnata più di una lettera. La struttura del request header è la seguente: 

DEVICE DRIVER, SERV. 23: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1 Numero dell'unità  Codice indicativo dell'ultima lettera utilizzata per referenziare l'unità (1=A:, 2=B:, etc.). 
02h 1 Numero del servizio richiesto (23
03h 2 Stato dell'operazione
05h 8
Se il driver supporta una sola unità disco deve restituire 0 nel campo ad offset 01h nel request header. Vedere anche il servizio 24, commentato di seguito. 

Servizio 24: Set Logical Device 

Il servizio 24 è supportato dai block device driver nella cui device attribute word il bit 6 è posto a 1 ed è richiesto dal DOS a partire dalla versione 3.2. Esso costituisce il supporto di basso livello per la sottofunzione 0Fh della funzione 44h dell'int 21h (SetLogicalDriveMap) ed è la controparte del servizio 23, testè descritto. Il suo scopo è far conoscere al driver la successiva lettera con cui è referenziata l'unità disco. La struttura del request header è la seguente: 

DEVICE DRIVER, SERV. 24: USO DEL REQUEST HEADER 
OFF
DIM
Request Header Ricevuto
Request header Restituito
00h 1 Lunghezza del request header 
01h 1 Numero dell'unità 
02h 1 Numero del servizio richiesto (24
03h 2 Stato dell'operazione
05h 8
Il numero di unità passato dal DOS al driver è relativo, con base 0, alla prima unità supportata dal driver stesso[30]



OK, andiamo avanti a leggere il libro... 

Non ci ho capito niente! Ricominciamo...