# Driver

Un driver, dall'inglese "guidatore", in informatica indica l'insieme di procedure software, spesso scritte in assembly, che permette ad un sistema operativo di pilotare un dispositivo hardware (ad es. una periferica).

## Descrizione

Esso permette al sistema operativo di utilizzare l'hardware senza sapere come esso funzioni, ma dialogandoci attraverso un'interfaccia standard, i registri del controllore della periferica, che astrae dall'implementazione dell'hardware e che ne considera solo il funzionamento logico. In questo modo hardware diverso costruito da produttori diversi può essere utilizzato in modo intercambiabile.
Ne consegue che un driver è specifico sia dal punto di vista dell'hardware che pilota, sia dal punto di vista del sistema operativo per cui è scritto. Non è possibile utilizzare driver scritti per un sistema operativo su uno differente, perché l'interfaccia è generalmente diversa.
Il driver è scritto solitamente dal produttore del dispositivo hardware, dato che è necessaria un'approfondita conoscenza dell'hardware per poter scrivere un driver funzionante. A volte, i driver vengono scritti da terze parti sulla base della documentazione tecnica fornita dal produttore, se questa è disponibile.
A volte nel pacchetto d'installazione di uno (o più) driver è compresa un'applicazione, eseguibile a sistema operativo avviato, che funge da strumento di controllo del driver e/o dell'eventuale periferica pilotata da esso: a rigori, questa applicazione è cosa diversa dal driver vero e proprio (spesso non è singolarmente disinstallabile). In alcuni casi non si tratta di un'applicazione ma di funzionalità collegate al driver ma il concetto di elementi aggiuntivi (add on) rispetto al driver vero e proprio non cambia.

### Struttura e funzionamento

Ogni driver deve risolvere il problema della mutua esclusione garantendo ad un solo processo (specie se il sistema è multiprocessore) l'accesso esclusivo alla periferica in ogni istante. A seconda di quanti processi potranno interagire direttamente con la periferica, può essere necessario introdurre un driver virtualizzato. Infatti, se ogni processo può agire sulla periferica in maniera indipendente dagli altri (si pensi ad un masterizzatore in fase di scrittura), fermo restando l'ipotesi di accessi seguenti elementi:
* Procedura di acquisizione
* Procedura/e d'uso
* Procedura di rilascio
Prima di chiamare le procedure d'uso, il processo deve acquisire l'uso esclusivo della periferica, e alla fine deve rilasciare la stessa agli altri processi. Il modello di sincronizzazione delle procedure d'uso è quello dei semafori inizializzati a rosso. Le procedure di acquisizione e rilascio, viceversa, sono le wait e signal di un semaforo virtuale associato alla periferica tale da garantire la mutua esclusione.
Le procedure d'uso, come già accennato, seguono il modello dei semafori sempre rossi. Questo perché, data l'enorme differenza di velocità tra la CPU e la periferica, è necessario che il processo attenda la sincronizzazione delle operazioni con la periferica. Ciò avviene mediante gli interrupt.
Il driver fisico opera sui registri del controllore della periferica, in particolare su tre tipi registri fondamentali:
* Registro di controllo
* Registro di stato
* Registro dati
Il primo è un registro in sola scrittura: il driver inserisce i dati relativi all'operazione richiesta. Solitamente è presente un bit di attivazione, impostato ad 1 alla fine del caricamento dei registri (quando cioè la periferica è pronta a partire), e azzerato dalla periferica al termine delle operazioni. Il registro di stato è un registro in sola lettura: al termine delle operazioni, la prima cosa da fare è verificare che la periferica non abbia restituito condizioni di errore. Il registro dati è un registro che può essere usato sia in lettura che in scrittura dalla CPU, in quanto viene usato per caricare i parametri di ingresso dell'operazione (es. che traccia leggere da disco) e può venire usato per leggere il risultato dell'operazione. Si noti che al posto di un unico registro dati può esistere una batteria di registri dati, il cui uso è documentato nel driver.

### Tipologie

Esistono driver di molti tipi, a seconda del tipo di hardware che devono pilotare e soprattutto del sistema operativo su cui devono girare.
* Nei sistemi embedded, in cui tutto il software è un unico programma compilato e caricato in ROM, il driver non è altro che una routine del programma che si interfaccia con l'hardware da pilotare.
* In maniera analoga, nei sistemi operativi con kernel monolitico (come Linux), il driver è un modulo compilato insieme al kernel. Il kernel Linux generalmente supporta decine di migliaia di periferiche in modo nativo, solitamente quindi la maggior parte dell'hardware viene riconosciuto subito, però se una periferica non è supportata da quest'ultimo non è possibile utilizzarla. Il vantaggio di questo approccio è che i driver disponibili sono supervisionati e testati dagli stessi sviluppatori del kernel e quindi forniscono massima efficienza e stabilità. (Nelle nuove versioni del kernel Linux è comunque possibile "aggiungere" nuovi driver al kernel senza necessariamente ricompilarlo da zero.)
* Nei sistemi operativi a kernel ibrido (come Windows), il driver è un file binario che viene caricato dinamicamente dal kernel. In questo caso è possibile aggiungere una nuova periferica e il kernel dovrà semplicemente caricare il file del driver opportuno. Il vantaggio di questo approccio solitamente è la "quasi sicurezza" di riuscire a utilizzare un certo hardware in quanto sono i produttori stessi a fornirlo. Lo svantaggio invece può essere la non totale ottimizzazione o stabilità di un driver, né tanto meno che il produttore hardware continui a fornire driver di vecchie periferiche non più in vendita per le nuove versioni di Windows (come è avvenuto per il sistema operativo Windows Vista).
Come si diceva sopra, alcuni pacchetti driver contengono altri elementi di gestione della periferica nel senso di interfaccia funzionale con l'utente. È il tipico caso dei driver delle stampanti, delle schede video, delle schede audio e altro. In molti casi, il pacchetto è monolitico nel senso che non consente di installare o meno i singoli componenti separatamente.

### Esempio di funzionamento

Supponendo di disporre di una determinata periferica - ad esempio un masterizzatore - e supponiamo di avere più programmi di masterizzazione installati sul nostro PC (e li chiameremo processi masterizzatore). L'operazione di masterizzazione è un'operazione molto delicata, perché deve avvenire in maniera uniforme e alla stessa velocità. Vista l'enorme differenza di velocità tra CPU e masterizzatore, la masterizzazione si effettua grazie ad un buffer che può essere riempito dalla CPU (ovvero dal processo masterizzatore) in ogni momento a grande velocità, e che viene lentamente svuotato dal masterizzatore fisico. Tale buffer non deve essere mai vuoto, pena l'annullamento dell'operazione (a meno che il masterizzatore non supporti tecnologie di prevenzione del buffer underrun).
L'intera operazione di masterizzazione può essere descritta nel seguente modo:
* Il processo masterizzatore chiede al sistema operativo l'uso esclusivo della periferica (procedura di acquisizione)
** Se la periferica è già occupata, il processo riceve una condizione di errore o si mette in attesa della fine dell'operazione
* Il processo masterizzatore invia i primi dati di inizializzazione al masterizzatore e si sospende (procedura d'uso che termina in context switch)
* Il masterizzatore chiede nuovi dati: il processo viene sbloccato (Interrupt Service Routine, o ISR, del driver)
* In attesa che il processo masterizzatore vada in esecuzione, altri processi svolgono le loro funzioni ma il masterizzatore continua a svuotare il buffer
* Il processo masterizzatore va in esecuzione e invia nuovi dati al masterizzatore (una diversa procedura d'uso, con relativo context switch)
* L'operazione si ripete fino a che il programma non termina i dati da scrivere
* Il processo masterizzatore invia al masterizzatore il segnale di operazione completata (una diversa procedura d'uso, e di nuovo context switch)
* Il masterizzatore si sincronizza col processo inviandogli un segnale di stato che conferma che tutto è andato bene (sempre con la ISR)
* Il processo rilascia il masterizzatore agli altri processi eventualmente in attesa (procedura di rilascio)