Äîęóěĺíň âç˙ň čç ęýřŕ ďîčńęîâîé ěŕřčíű. Ŕäđĺń îđčăčíŕëüíîăî äîęóěĺíňŕ : http://www.arcetri.astro.it/science/irlab/doc/driver-dio.ps.gz
Äŕňŕ čçěĺíĺíč˙: Thu Jul 28 18:22:26 2005
Äŕňŕ číäĺęńčđîâŕíč˙: Sat Dec 22 07:35:02 2007
Ęîäčđîâęŕ:
Driver Linux per la scheda di acquisizione NI PCI­DIO32HS
E.Giani 1 , A.Checcucci 1 , C.Baffa 1
1 Osservatorio Astrofisico di Arcetri
Arcetri Technical Report N ffi 7/01
Firenze 2001

Abstract
Il progetto della nuova elettronica di controllo per la strumentazione infrarossa FASTI, prevede l'utilizzo di
una scheda di I/O digitale parallela per acquisizione veloce.
Il sistema FASTI `e basato sul SO Linux, da cui la necessit`a di un driver specifico per la scheda di acquisizione
scelta: la PCI DIO32HS della National Instruments.
La National Instruments non ha rilasciato, per il momento, alcun driver Linux specifico. Per questo motivo
abbiamo deciso di svilupparne uno che includesse esclusivamente il supporto per il funzionamento necessario
al nostro lavoro.

1 Introduzione
Il progetto della nuova elettronica di controllo per la strumentazione infrarossa FASTI, prevede l'utilizzo di una
scheda di I/O digitale parallela per acquisizione veloce.
Le specifiche del progetto prevedono come requisiti una velocita' minima di trasferimento di 3­4 Mbytes/s.
La nostra scelta e' ricaduta sulla scheda PCI­DIO32HS della National Instruments che in modalita' sincrona
dichiara velocita' di trasferimento fino a 70 Mbytes/sec.
La National Instruments non ha rilasciato, per il momento, alcun driver Linux specifico mentre il LinuxLab
Project ne comprende uno (comedi) per il supporto di diverse schede di acquisizione NI, compreso quella da noi
utilizzata. Purtroppo la versione non `e ancora completa.
Per questo motivo abbiamo deciso di sviluppare un driver Linux che includesse esclusivamente il supporto per
il funzionamento necessario al nostro lavoro.
Vogliamo sottolineare come molte delle nostre scelte operative siano state vincolate dalle limitate informazioni
tecniche che abbiamo su questa scheda e come tutto ci`o influisca anche sull' efficienza del driver Linux da noi
sviluppato.
2 Descrizione tecnica
La scheda PCI­DIO­32HS appartiene alla famiglia dei devices DIO 6533 della National Instruments.
I devices 6533 costituiscono delle interfaccie parallele di I/O digitale per PC compatibili, PXI o CompactPCI.
In particolare la scheda PCI­DIO32HS `e un device DAQ per bus PCI.
Ciascun device 6533 contiene il chip DAQ­DIO dell NI, un' interfaccia a 32­bit per I/O digitale. Tale chip
abilita il device ad eseguire una vasta serie di operazioni di input ed output: single­point, acquisizione digitale,
generazione di forme d'onde digitale, trasferimenti di dati ad alta velocit`a.
La scheda PCI­DIO32HS include l'interfaccia PCI MITE sviluppata dalla National Instruments. Il MITE offre
la possibilit`a di operazioni bus­master, trasferimenti burst e controllers DMA ad alta velocit`a .
2.1 Caratteristiche del chip DAQ­DIO
Il chip DAQ­DIO pu`o eseguire operazioni di I/O sia unstrobed sia strobed usando 4 porte parallele di I/O ad 8
bit ciascuna, etichettate con le lettere A,B,C e D.
L'I/O unstrobed comprende operazioni che non coinvolgono l'uso di temporazzazioni hardware o di segnali di
handshaking. Semplicemente si pu`o scrivere e leggere direttamente su ciascuna porta. Ogni linea di I/O pu`o
essere programmata ed indirizzata attraverso il controllo dei singoli pins.
Viceversa, l'I/O strobed comprende trasferimenti di dati in cui l'hardware del chip DAQ­DIO regola la tempo­
rizzazione o esegue le funzioni di handshaking. In particolare, i device 6533 supportano una vasta gamma di
protocolli (vedi x 2.4).
Il chip DAQ­DIO supporta due categorie distinte di I/O strobed: il protocollo a due vie ed il pattern generation o
protocollo ad una via. Nel primo tipo di handshaking le informazioni di controllo passano da e verso la periferica
1 , con uno scambio di segnali di strobe del tipo ACK (acknoledgment) REQ (request) attraverso i quali il device
e la periferica comunicano la disponibilit`a dei dati in entrata o uscita.
Nel secondo caso (pattern generation) i dati vengono letti o scritti ad una frequenza prederminata il cui valore
pu`o essere generato internamente dalla scheda oppure fornito da una sorgente esterna.
Non tutte le funzionalit`a fornite dalla scheda PCI­DIO32HS sono utili al nostro tipo di lavoro, per cui ci limi­
tiamo a descrivere solo le specifiche a noi necessarie.
Trascureremo perci`o tutta la parte di I/O digitale che non coinvolge l'uso di segnali di handshaking (cio`e l'I/O
unstrobed ed il pattern generation).
2.2 Protocollo a due vie
Per le operazioni di handshaking, il DAQ­DIO include le seguenti caratteristiche:
1 con questo termine si intende rifersi ad un device esterno che il DAQ­DIO controlla, monitora o con cui comunica
1

ffl due canali di handshaking, a cui ci si riferisce con il termine di gruppo con logica di temporizzazione e
registri di controllo separati
ffl un insieme di linee di controllo di handshaking ed altre opzioni separate per ciascun gruppo
ffl controllo software del protocollo di handshaking e di altre opzioni per ogni gruppo
ffl 4 FIFO interne, ciascuna associata ad una porta
ffl funneling che consente al software di modificare l'instradamento (routing) delle FIFO verso le porte
ffl contatori per controllare il numero di trasferimenti eseguiti.
2.3 FIFO interne e gruppi di acquisizione
Il DAQ­DIO fornisce una FIFO interna per ogni porta. Ogni FIFO `e costituita da un buffer di memoria
bidirezionale, del tipo first­in first­out, ad 8 bit con una profontit`a di 16 parole (words). In totale vi sono 4
FIFO ciascuna associata ad una porta di I/O.
Nell'I/O strobed le porte e le relative FIFO devono essere allocate ad uno dei gruppi di handshaking.
Un gruppo consiste di un controller per le temporizzazioni e di un set di 4 linee di controllo associate: REQ,
ACK (STARTRIG), STOPTRIG e PCLK. Come gi`a accennato al paragrafo precedente, l'hardware della scheda
PCI­DIO32HS supporta fino a 2 gruppi indipendenti, da cui segue che il chip DAQ­DIO pu`o eseguire fino a due
operazioni simultanee di handshaking.
2.3.1 Accesso alle FIFO
In modalit`a strobed I/O, devono essere usate le FIFOs, piuttosto che i registri delle porte di I/O, per leggere o
scrivere i dati. In particolare si pu`o leggere solo da un gruppo di input e scrivere solo su un gruppo di output.
Le operazioni di lettura/scrittura possono essere ad 8­bit, 16­bit o 32­bit.
2.4 I protocolli
Quando vengono eseguite operazioni completamente gestite dai segnali di handshaking (protocollo a due vie),
possono essere selezionati diversi protocolli offerti dai devices della famiglia 6533.
Il protocollo scelto determina la temporizzazione dei segnali di ACK che il device 6533 manda alla periferica e
dei segnali di REQ attesi dalla periferica stessa. Uno dei protocolli, il burst mode differisce dagli altri in quanto
`e l'unico protocollo sincrono.
I protocolli che la scheda pu`o generare sono i seguenti:
ffl protocollo di emulazione 8255. A causa dei tempi di risposta pi`u veloci ed al buffering offerto dalle FIFO,
questo modo di emulazione 8255 offre velocit`a di trasferimento superiori di quelle fornite dal chip 8255.
ffl level ACK. Dopo ciascun trasferimento, il device afferma il segnale ACK verso la periferca. Il manteni­
mento della linea di ACK fa si' che il device non inizi un nuovo trasferiment fino a che non avviene una
transizione false­true sulla linea di REQ.
ffl leading edge pulse. Dopo ciascun trasferimento, il device 6533 manda alla periferica un impulso sulla linea
di ACK. Il device 6533 prima di iniziare un nuovo trasferimento, aspetta una transizione false­true sulla
linea di REQ e l'inizio di un impulso REQ. Il software consente di specificare un ritardo dell'impulso ACK
ffl long pulse. In questa modalit`a il funzionamento `e analogo al precedente, con la sola differenza che si pu`o
specificare un'ampiezza minima dell'impulso.
ffl trailing­edge pulse. Dopo ciascun trasferimento il device 6533 manda alla periferica un impulso sulla linea
di ACK. Prima di un nuovo trasferimento, il device aspetta una transizione true­false sulla linea di REQ
e la fine dell'impulso REQ.
2

ffl burst mode. Il device 6533 manda o riceve un segnale di clock sulla linea PCLK. Durante ogni ciclo il
device 6533 afferma un segnale ACK se `e pronto per il trasferimento e la periferica, in modo analogo,
afferma un segnale di REQ se `e pronta per il trasferimento.
3 Caratteristiche tecniche per la programmazione della scheda
Per programmare un device DIO 6533 devono essere scritti e letti una serie di registri implementati sul device
stesso. Questi registri, rientrano in due distinte categorie:
ffl i registri di interfaccia al bus
ffl i registri di I/O implementati dal chip DAQ­DIO
3.1 Inizializzazione del bus
Il device PCI­DIO32HS usa il chip MITE come interfaccia al bus PCI. Questo circuito integrato `e stato proget­
tato appositamente dalla National Instuments per l'acquisizione dati e deve essere propriamente configurato.
Quando non viene usato il software specifico NI­DAQ della NI, come nel nostro caso, la configurazione del chip
MITE deve essere eseguita nel seguente modo:
1. con le chiamate delle funzioni PCI deve essere individuata la presenza della scheda facendo ricorso ai
numeri identificativi della casa produttrice e della scheda 2
2. mappatura della memoria di I/O del device. In generale la memoria di I/O di devices connessi al bus PCI
`e mappata ad indirizzi fisici alti, molto al di l`a del temine degli indirizzi fisici della RAM. I drivers del
kernel devono tradurre l'indirizzo fisico della memoria di I/O del device PCI in un indirizzo lineare nello
spazio del kernel 3 . Gli indirizzi base dei chip DAQ­DIO e MITE 4 devono essere rimappati nello spazio
della memoria virtuale del kernel. Questa operazione viene eseguita utilizzando la funzione ioremap.
3. scrittura del valore 0x80 all'offset 0xc0 a partire dall'indirizzo rimappato del MITE.
Eseguita la fase di inizializzazione del bus, l'accesso in lettura/scrittura dei registri mappati in memoria viene
effettuata ricorrendo alle seguenti funzioni:
ffl readb/writeb
ffl readw/writew
ffl readl/writel.
Queste macro sono usate per leggere o scrivere nella memoria di I/O dati a 8­bit, 16­bit e 32­bit.
L'uso di tali macro `e preferibile all'accesso diretto dell'indirizzo di memoria dei registri, in quanto tengono conto
delle diverse architetture. L'indirizzo di ciascun registro `e ottenuto sommando all'indirizzo rimappato del chip
DAQ­DIO o del MITE 5 il relativo offset. In Appendice A possiamo trovare l'elenco completo dei registri del
chip DAQ­DIO ed i loro offset.
Per maggiori informazioni rimandiamo al manuale DAQ­DIO Technical Reference Manual che pu`o essere tovato
nel sito web della National Instruments:
http://www.ni.com
Non `e invece disponibile alcuna informazione ufficiale relativa ai registri del MITE.
2 Nel caso specifico il codice numerico della NI `e 0x1093, quello della scheda PCI­DIO32HS 0x1150
3 Si deve tenere in considerazione che gli indirizzi lineari del kernel partono dall'indirizzo 0xc0000000. Durante la fase di
inizializzazione, il kernel mappa gli indirizzi fisici della RAM disponibile nella regione iniziale del quarto GB dello spazio degli
indirizzi lineari
4 L'indirizzo base 0 corrisponde all'indirizzo base del MITE, mentre l'indirizzo base 1 all'indirizzo base del chip DAQ­DIO. La
dimensione di ciascun spazio di memoria `e di 4 kB.
5 La programmazione dei registri del MITE `e necessaria solo nel caso in cui si voglia ricorrere alle funzionalit`a fornite da questo
chip, come ad es. i trasferimenti DMA.
3

3.2 Interrupts
Il DAQ­DIO presenta le seguenti caratteristiche per gli interrupts:
ffl una linea di interrupt per l'interfaccia diretta con il bus controllabile tramite software
ffl un bit principale per l'abilitazione globale della linea di interrupt
ffl un bit di abilitazione per ogni possibile sorgente di interrupt.
La scheda genera un interrupt solo quando entrambi i bit sono configurati.
Le cause che possono generare un interrupt, sono le seguenti:
ffl trasferimento pronto
ffl numero dei trasferimenti terminato
ffl la logica di I/O deve fermarsi ed aspettare per la CPU o il controller DMA.
ffl si `e verificato un DMA terminal counter sul primo gruppo del DMA
ffl si `e verificato un DMA terminal counter sul secondo gruppo del DMA
Entrambi i gruppi di linee di handshaking possono essere programmati per generare i segnali di interrupt nel
caso si verifichi uno (o pi'u) degli eventi elencati sopra.
3.3 Funzionamento del DMA nella scheda PCI DIO32­HS
Per eseguire trasferimenti DMA, il chip DAQ­DIO deve lavorare con un controller DMA. La scheda PCI­
DIO32HS possiede il DMA controller sulla scheda stessa, implementato nel chipset PCI MITE ASIC.
`
E importante sottolineare che per il funzionamento dei trasferimenti DMA, devono essere programmati sia il
chip DAQ­DIO, sia il controller DMA.
Il chip DAQ­DIO include le seguenti caratteristiche per il DMA:
ffl supporta due canali DMA. Questi possono essere allocati entrambi ad un gruppo, oppure uno a ciascun
gruppo.
ffl l'ampiezza del trasferimento DMA (che pu`o essere a 8­bit, 16­bit o 32­bit) `e controllata tramite software.
3.3.1 Caratteristiche del controller MITE DMA
Il MITE contiene i canali DMA che possono essere usati per trasferire i dati tra le porte di I/O e la memoria di
sistema. Il MITE fornisce due canali separati per i due gruppi di I/O 6 . Ciascun canale supporta diversi modi
operativi.
Uno di questi `e il link­chaining 7 che rende possibile il trasferimento di blocchi di dati in aree di memoria non
contigue.
Questo tipo di implementazione bus­master `e una combinazione di hardware e software dove il controller `e
progettato in modo da riprogrammare se stesso senza l'uso di interrupt e l'intervento da parte della CPU.
In modalit`a link­chaining il controller DMA non viene riprogrammato per le nuove locazioni di memoria ma si
autoconfigura leggendo una serie di record di dati concatenati tra loro, immagazzinati in un buffer di memoria.
Ciascun record contiene l'indirizzo di destinazione dei dati, il numero di byte da trasferire e l'indirizzo del
successivo record di dati. Il controller DMA legge ed esegue ciascun nodo contenuto nella lista. Il microprocessore
deve solamente programmare il controller con l' indirizzo del primo nodo della catena, il resto del lavoro viene
6 Deve essere usato il controller DMA 1, la linea DRQ 1 e la linea DACK 1 per il gruppo 1; il controller DMA 2, la linea DRQ 2
e la linea DACQ 2 per il gruppo 2.
7 Questa modalit`a sar`a l'unica presa in considerazione, perch`e `e la sola per la quale siamo in grado di trovare esempi della
programmazione del chipset MITE
4

svolto direttamente dal controller DMA.
La modalit`a link­chaining richiede perci`o la costruzione di una catena di strutture in cui sono immagazzinate
le informazioni relative a ciascun buffer di memoria usato nel trasferimento. Per ogni nodo della catena devono
essere specificati i valori dei seguenti registri del controller DMA:
ffl Transfer Count Register (TCR): contiene il numero di byte da trasferire
ffl Memory Address Register (MAR): contiene l'indirizzo fisico del buffer di memoria
ffl Device Address Register (DAR): non viene usato dal chip DAQ­DIO
ffl Link Address Register (LKAR): contiene l'indirizzo fisico del nodo successivo della catena di strutture.
Prima di iniziare il trasferimento DMA, deve essere caricato il registro LKAR con l'indirizzo fisico del primo
nodo perch`e, come accennato in precedenza, il MITE necessita un punto iniziale di accesso alla catena.
Dopo che il DMA `e stato attivato per il trasferimento, il MITE scorre l'intera catena di strutture e carica gli
indirizzi fisici dei buffer di memoria all'interno del MAR. In seguito il MITE trasferisce i dati dalla scheda al
buffer (input) oppure dal buffer alla scheda (output).
Nel caso di un trasferimento finito di dati, il processo continua finch`e il MITE non raggiunge un nodo vuoto,
cio`e un nodo i cui valori sono posti tutti a zero. Per un trasferimento continuo, invece, l'ultimo nodo della
catena punta nuovamente al primo.
4 Configurazione della scheda per operazioni di acquisizione
In questo capitolo intendiamo fornire le informazioni utili per configurare ed eseguire le operazioni di I/O in mo­
dalit`a handshaking. Indipendentemente dal metodo scelto per acquisire i dati (polling, interrupt o trasferimenti
DMA) le seguenti operazioni dovranno essere comunque eseguite nell'ordine indicato:
ffl configurazione del gruppo (o dei gruppi) di I/O
ffl programmazione del protocollo di handshaking
ffl reset delle flags
ffl esecuzione della modalit`a handshaking
ffl reset delle FIFO
Rimandiamo alle App. A e B per l'elenco dei registri della scheda PCI­DIO32HS e la locazione dei bit.
4.0.2 Configurazione del gruppo di I/O
Per configurare un gruppo di acquisizione, devono essere eseguiti i passi successivi:
1­ assegnare le FIFO e le porte a ciascun gruppo
2­ fissare la direzione di acquisizione del gruppo (input o output)
3­ configurare ogni porta assegnata al gruppo
4­ selezionare l'ampiezza dell'operazione di lettura/ scrittura/ trasferimento DMA (8­bit, 16­bit oppure 32­
bit)
1) Per assegnare una o pi`u FIFO ad un gruppo di I/O devono essere settati i bit relativi nel registro Data—Path.
Non `e possibile assegnare la stessa FIFO ad entrambi i gruppi.
2) Lo stesso registro consente di configurare il funneling 8 e la direzione di acquisizione. I valori da attribuire ai
bit sono i seguenti:
8 Il funneling consente di configurare la dimensione dell' I/O pi`u piccola della dimensione del gruppo, cio`e di usare un numero
minore di porte rispetto al numero di FIFO. Ad es. il funneling del tipo 8:16 consente di eseguire operazioni di I/O ad 8­bit per
un gruppo di 16­bit, assumendo che vengano trasferiti un numero pari di dati.
5

funneling = 0 (no funneling) o 2 (8­bit funneling)
GroupDirection = 0 (input) o 1 (output)
3) La configurazione delle porte consiste nel porre la direzione di acquisizione uguale a quella del gruppo a cui
appartengono. Ad ogni porta `e associato un registro Port—Pin—Directions. I singoli bit del registro vanno
posti a 0 oppure ad 1 a seconda che il gruppo a cui appartiene la porta sia un gruppo di input o di output.
4) L'ampiezza delle operazioni di lettura, scrittura o trasferimento DMA (che di seguito indicheremo con il
termine TransferWidth) viene determinata dai primi due bit del registro Transfer—Size—Control.
TransferWidth pu`o assumere i seguenti valori:
ffl 0,1 : per operazioni effettuate a 32­bit
ffl 2 : per operazioni a 8­bit
ffl 3: per operazioni a 16­bit
Il valore configurato per TransferWidth deve essere uguale o minore alla dimensione in bit del gruppo di
acquisizione. Ad es. ad un gruppo composto da tutte e quattro le FIFO (32­bit) possono essere associate
operazioni di acquisizione a 16­bit o 32­bit.
4.0.3 Programmazione del protocollo di handshaking
La configurazione del protocollo di handshaking comporta la programmazione dei quindici registri
Protocol—Register—1, ... ,Protocol—Register—15
facendo riferimento ai valori riportati in App.C e alla direzione di acquisizione del gruppo.
4.0.4 Reset delle flags
Prima dell'avvio di ogni operazione di I/O `e indispensabile eseguire il reset delle flags associate al gruppo.
Queste sono:
ffl Clear Waited
ffl Clear PrimaryTC
ffl Clear SecondaryTC
ffl DMAReset
ffl FIFOReset
ffl Clear Expired
Ogni flag `e associata ad un bit del registro GROUP—FIRST—CLEAR o GROUP—SECOND—CLEAR: per resettare una flag
deve essere posto ad 1 il corrispondente bit del registro a cui appartiene.
4.0.5 Esecuzione delle operazioni di I/O in modalit`a handshaking
L'avvio del processo di handshaking necessita della:
1­ definizione di acquisizione definita (numbered) o continua
2­ abilitazione dei segnali di handshaking
6

1) Il quarto bit (Numbered) del registro Protocol—Register—1 consente di specificare se si tratta di un' ac­
quisizione definita, cio`e con una quantit`a determinata di dati da trasferire, oppure no. Nel primo caso il bit
Numbered deve essere posto uguale ad 1, nell'altro caso a 0.
Per operazioni di I/O finite deve essere programmato anche il numero di conteggi. Tale valore deve essere scritto
nel registro Transfer—Count relativo al gruppo di I/O.
2) I primi tre bit (RunMode) del registro Protocol—Register—1 consentono invece di fermare o attivare la
generazione dei segnali di handshaking. In particolare:
RunMode=0x00 : la generazione dei segnali di handshaking viene fermata. `
E importante sottolineare che la
flag RunMode deve essere posta uguale a zero prima di eseguire la configurazione di un gruppo di
I/O.
RunMode=0x03 : la generazione dei segnali di handshaking viene abilitata.
Una volta programmata la scheda fissando i gruppi di I/O, il protocollo, etc. come descritto nei paragrafi
precedenti, le operazioni di handshaking iniziano quando la flag RunMode viene posta uguale a 0x03. Questa
deve essere l'ultima operazione eseguita prima che abbia inizio il trasferimento dei dati da o verso la periferica.
4.0.6 Reset delle FIFO
Il reset delle FIFO risulta necessario quando vengono eseguiti trasferimenti continui in lettura.
In modalit`a di acquisizione definita `e noto a priori il numero di dati da leggere, per cui non dovrebbero rimanere
dati nelle FIFO alla fine del trasferimento. In modalit`a continua, invece, questa eventualit`a si pu`o presentare
in seguito all' improvvisa interruzione dell'acquisizione.
La presenza di dati in una FIFO `e controllata dal bit DataLeft del registro GROUP—STATUS. Tale flag `e uguale
ad 1 finche' una (o pi`u) FIFO contiene dati.
Per svuotare una FIFO `e necessario leggere il registro GROUP—FIFO fino a quando il bit DataLeft non risulta
uguale a 0.
4.1 Programmazione aggiuntiva per operazioni di I/O con IRQ
Il DAQ­DIO pu`o accrescere l'efficienza del bus usando il canale di interrupt. Si pu`o usare un canale di interrupt
per la notifica di un evento senza dover ricorrere alla tecniche di polling.
Entrambi i gruppi di I/O possono essere programmati per generare un segnale di interrupt quando le condizioni
elencate al x 3.2 sono soddisfatte.
Per abilitare gli interrupts devono essere eseguiti i seguenti passi:
1­ configurare i gruppi e le porte prima di abilitare qualunque interrupt
2­ selezionare le sorgenti di interrupt
3­ abilitare la linea di interrupt
Per il passo 1) rimandiamo al x4.0.2.
2) La selezione delle sorgenti di interrupt viene effettuata configurando, nel registro Interrupt—Control del
gruppo di I/O, i bit corrispondenti.
3) L'abilitazione globale degli interrupt `e realizzata dai primi due bit (InteruptLine) del registro
Master—DMA—and—Interrupt—Control. Questi bit determinao l'uso della linea di interrupt. In particolare:
­ 0 : pone la linea di interrupt in tristate (stato al momento dell'accensione)
­ 1 : guida la linea dell'interrupt nello stato basso (disabilita gli interrupts)
­ 3 : abilita gli interrupt per le normali operazioni
7

4.2 Programmazione aggiuntiva per operazioni di I/O con DMA
Descriviamo ora la programmazione con accesso diretto alla memoria (DMA) del DAQ­DIO e del contoller
DMA 9 .
Il DMA abilita il DAQ­DIO a muovere i dati direttamente da e verso la memoria senza l'uso della CPU. Il DMA
pu`o ridurre drasticamente il carico della CPU crescendo contemporaneamente la velocit`a di trasferimento dei
dati.
Nel caso in cui si voglia implementare questa caratteristica all'interno del software di gestione del device, `e
necessario eseguire una serie ulteriore di operazioni rispetto a quelle descritte nei x4.0.2­x4.0.6.
Per configurare ed eseguire i trasferimenti DMA, devono essere compiute le seguenti operazioni:
1­ configurazione del gruppo e delle porte associate al gruppo
2­ programmazione del protocollo
3­ configurazione del canale DMA usato nel trasferimento
4­ scrittura di una routine che gestisca la fine del singolo trasferimento.
5­ programmazione del controller DMA
6­ inizio del trasferimento DMA, in modalit`a continua o definita (numbered)
I passi 1) e 2) sono gi`a stati descritti al x4.0.2.
3) La selezione del canale usato da un gruppo di I/O viene eseguita ponendo uguake ad 1 i primi quattro bit
(DMAChannel) del registro DMA—Line—Control.
Per usare un solo canale deve essere programmato lo stesso valore per entrambi i canali DMA, altrimenti il
gruppo di I/O utilizza in modo alterno i due canali.
Oltre alla configurazione dei bit
ReadyLevel del registro FIFO—Control e TransferWidth del registro Transfer—Size—Control
(vedi x4.0.2) che sono necessari per le normali operazioni di handshaking, devono essere configurati anche i bit
TransferLength e RequireRLevel nel registro Transfer—Size—Control.
I bit TransferLength determinano la massima durata del segnale DRQ. Il DAQ­DIO fornisce un meccanismo
di time­out che `e richiesto da alcuni controller DMA per prevenire il monopolio del bus da parte del processo
DMA. I valori selezionabili sono:
­ 0: Nessun limite. Questo valore `e raccomandato per il MITE (PCI) DMA
­ 1: massimo di 4 trasferimenti
­ 2: massimo di 8 trasferimenti
­ 3: massimo di 16 trasferimenti
Il bit RequireLevel determina quanto a lungo il segnale DMAReq rimane affermato. Questo bit deve essere
attivato per trasferimenti DMA in output, per trasferimenti non di input e trasferimenti non DMA.
4) Questo passo risulta necessario solo nel caso siano abilitati gli interrupt per segnalare la fine di un singolo
trasferimento DMA.
Purtroppo non abbiamo informazioni sufficienti sulla programmazione del chipset MITE DMA per poter utiliz­
zare questa funzionalit`a.
5) Anche per quanto riguarda questa parte, la documentazione `e completamente assente, per cui non possono
essere forniti dettagli. Possiamo solo rimandare al sorgente scritto da Tomaz Motylewski che ha trasportato in
ambiente Linux un file originariamente scritto dalla National Instruments Corporation per il funzionamento del
MITE DMA in modalit`a link­chaining.
La programmazione del controller DMA in modalit`a link chaining consiste nella programmazione dei seguenti
9 Per la scheda PCI­DIO32HS deve essere programmato il chip MITE ASIC che implementa il controller DMA
8

registri:
­ DMA—CHOR, DMA—CHRC, DMA—MCR, DMA—DCR, DMA—LKCR che configurano la modalit`a di funzionamento link­chaining
­ DMA—LKAR che contiene l'indirizzo fisico del primo nodo della catena (vedi x3.3.1).
6) Il trasferimento DMA viene avviato dopo che `e stato abilitato il bit DMA—CHOR—START nel registro DMA—CHOR
del MITE, configurato il trasferimento come continuo o finito ed abilitati i segnali di handshaking (vedi x4.0.5).
Come detto in precedenza, per trasferimenti finiti deve essere programmato anche il valore del registro Transfer—Count.
5 Descrizione del driver Linux per la scheda PCI­DIO32HS
In questo capitolo non intendiamo fornire una descrizione dettagliata su come scrivere un device driver per
Linux, in quanto esistono pubblicazioni e libri che svolgono egregiamente questo compito ([1]).
Diciamo solamente che la scrittura di un driver Linux comporta in generale la implementazione delle seguenti
operazioni:
1­ registrazione del driver e delle sue funzionalit`a
2­ inizializzazione hardware del device fisico
3­ definizione delle operazioni eseguibili sul device
4­ rimozione del driver
5.1 Registrazione del driver pcidio32
La registrazione del driver viene effettuata dalla funzione init module() che viene chiamata quando il modulo
viene inserito attraverso i comandi insmod o modprobe.
La prima funzione chiamata (register chrdev) ci permette di assegnare al driver, identificato dal nome pcidio32,
il numero maggiore e di registrare in corrispondenza di esso una serie di operazioni dette metodi. Questi vengono
invocati dal kernel tutte le volte che un'applicazione utente esegue un'operazione su un device file con numero
maggiore uguale a quello associato al driver.
I metodi del driver sono definiti nella struttura dio32—fops il cui indirizzo viene passato come argomento alla
funzione register chrdev.
Il numero maggiore del device file associato al driver, non viene assegnato dinamicamente ma viene prefissato
al valore 60. Questo valore appartiene ad uno degli intervalli di numeri maggiori allocati per uso sperimentale.
Dopo la registrazione del driver, la funzione init module() invoca la funzione find NI cards() che rileva il numero
di schede del tipo PCI­DIO32HS installate nel PC.
Questa funzione inizializza per ogni scheda individuata una struttura del tipo mite—struct (vedi x 6.5) e
restituisce il numero delle schede individuate.
Come ultimo passo, la routine init module() alloca la memoria necessaria per contenere le strutture dati del
tipo ni—device (vedi x 6.1).
Se si verifica una condizione di errore durante l'esecuzione della funzione, il driver viene rimosso e viene rilasciata
l'eventuale memoria allocata.
5.2 Inizializzazione hardware del device
L'inizializzazione hardware del device fisico viene generalmente eseguita all' interno dalla funzione init module().
Nel caso specifico abbiamo deciso di procedere in modo diverso, facendo eseguire la funzione di inizializzazione
da un apposito comando ioctl chiamato dal processo utente (vedi x5.3.4). In questo modo, nel caso siano presenti
pi`u schede, l'applicazione utente pu`o non solo specificare quale scheda inizializzare ma anche il numero massimo
di gruppi di I/O che intende programmare per ciascun device.
Per maggiori dettagli rimandiamo al x5.3.4.
9

5.3 Metodi associati al driver
Il driver sviluppato per la scheda PCI­DIO32HS della National Instruments non supporta tutte le funzionalit`a
offerte da questo device, ma solo quelle che abbiamo ritenuto indispensabili al funzionamento del nostro sistema
di acquisizione.
In particolare noi lavoreremo esclusivamente con acquisizioni definite di solo lettura e controllate da
segnali di handshaking.
L'elenco dei metodi associati al driver include le seguenti funzioni:
­ dio32—open() e dio32—close() per l'apertura e la chiusura del device file
­ dio32—read() per la lettura dei dati di acquisizione
­ dio32—ioctl() per la configurazione del device
­ dio32—mmap() per la mappatura del buffer di acquisizione DMA nello spazio degli indirizzi dell'applica­
zione utente.
5.3.1 dio32 open()
Il metodo dio32 open() viene eseguito quando l'applicazione utente apre il device file per le operazioni di I/O.
Come spiegato al x 9 ad ogni device fisico sono associati tre device file distinti: due sono associati ai relativi
gruppi di I/O, il terzo consente di eseguire le operazioni di controllo e programmazione del device.
La funzione dio32 open() ricava dalla struttura inode informazioni sul numero minore del file specificato dalla
chiamata di sistema open(). Il numero minore (vedi x9) `e costruito in modo da fornire informazioni sia sulla
scheda, sia sul numero del gruppo di I/O. In questo modo la funzione dio32 open() `e in grado di associare al
device ed al gruppo di I/O la corretta struttura dati.
La funzione dio32 open() si limita successivamente ad incrementare il contatore del driver con una chiamata a
MODULE—INC—USE—COUNT ed il contatore privato use—count (vedi x 6.2 e x 6.1).
5.3.2 dio32 close()
Quando il programma utente rilascia il file handle che ha usato per interagire con il device, viene chiamata la
funzione dio32 close().
Nel caso in cui il device file sia quello di controllo, la funzione si limita a decrementare sia il contatore del driver
(MODULE—DEC—USE—COUNT) sia quello privato.
Nel caso invece si tratti di uno dei device file associato ad uno dei due gruppi di I/O, viene invocata anche la
funzione do group register() che esegue il reset dei registri del gruppo e della struttura dati ad esso associato.
5.3.3 dio32 read()
La funzione dio32 read() viene chiamata tutte le volte che il programma utente esegue una operazione di lettura
su uno dei device file associati ai gruppi di I/O.
Nessun metodo di lettura `e associato al device file di controllo.
Questa funzione implementa l'acquisizione dei dati in polling mode senza l'utilizzo di interrupt o del DMA.
Quando i dati sono presenti nelle FIFO associate al gruppo di I/O su cui viene eseguita l'operazione di lettura, il
bit TransferReady del registro GROUP—FLAGS relativo al gruppo di I/O ha valore 1. Controllando periodicamente
lo stato di tale bit, `e possile determinare quando i dati sono disponibili.
Per l'operazione di lettura viene usato un buffer interno di dimensione fissa (4096 byte) che, quando completo,
viene copiato nello spazio di indirizzamento del processo utente.
La funzione implementa inoltre un timeout in modo che il driver non congeli il sistema in caso di errato
funzionamento.
10

5.3.4 dio32 ioctl()
Una funzionalit`a complementare alla necessit`a di leggere e scrivere il device `e il controllo dell'hardware ed il
modo pi`u comune di eseguire questa operazione attraverso il device driver, consiste nell'implementare il metodo
ioctl. La chiamata di sistema ioctl offre un metodo per eseguire comandi specifici del device e consente alla
applicazione utente di accedere a caratteristiche uniche dell' hardware che deve essere pilotato dal device driver.
Gli argomenti della chiamata di sistema sono passati al metodo ioctl del driver in accordo alla dichiarazione
del metodo stesso:
int (*ioctl)(struct inode *inode,struct file *filp,
unsigned int cmd,unsinged long arg);
I puntatori inode e flip sono valori che corrispondono al descrittore di file fd passato dall'applicazione.
L'argomento cmd `e passato invariato e l'argomento opzionale arg `e passato sotto forma unsigned long indipen­
dentemente dal fatto che sia stato fornito dalla chiamata di sistema come intero o puntatore. Se il programma
utente non passa il terzo argomento, il valore arg ricevuto dal driver `e privo di significato.
La maggior parte delle implementazioni ioctl consiste in un comando switch che seleziona il corretto compor­
tamento secondo l'argomento cmd. I differenti comandi sono identificati da valori numerici che devono essere
unici. Per semplicit`a, ad ogni comando numerico viene associato un nome simbolico, assegnato attraverso una
direttiva di preprocessore.
Di seguito forniamo l'elenco dei comandi e la loro descrizione.
Vogliamo sottolineare che i comandi ioctl elencati di seguito, vengono eseguiti sul device file di controllo
/dev/nipciNctl (dove N vale 0 per la prima scheda, 1 per la seconda etc.).
ffl DIO32 IOC BOARD CONFIG: la chiamata di sistema ioctl() deve specificare anche il numero della scheda
che deve essere configurata (0 per la prima, 1 per la seconda etc.) ed il numero di gruppi di I/O da
configurare (1 o 2).
A livello di driver, il metodo ioctl esegue la funzione do board config() che eseguito un check sui parametri
passati dall' applicazione utente, chiama successivamente la funzione nidio device attach().
Questa funzione effettua l' inizializzazione hardware del device, eseguendo le seguenti operazioni:
­ chiama la funzione nidio find device(). Questa funzione ricava dal numero di scheda la struttura del
tipo mite—struct ad essa associata che, come descritto al x6.5, contiene le informazioni sulle risorse
hardware del device ;
­ chiama la funzione setup mite() che esegue l'inzializzazione dell'hardware come descritto al paragrafo
x3.1;
­ installa il gestore di interrupt in corrispondenza dell'IRQ del device;
­ alloca la memoria per le strutture del tipo dio32—device;
­ configura la flag attached ad 1, indicando la corretta inizializzazione della scheda;
­ installa le routine ni dio mode0, ni dio mode1,..,ni dio mode4 per la programmazione dei protocolli;
­ salva nei campi relativi della struttura ni—device gli indirizzi rimappati del chip DAQ­DIO e MITE.
ffl DIO32 IOC CONFIG GROUP1
DIO32 IOC CONFIG GROUP2: la chiamata di sistema ioctl relativa a questi comandi deve specificare
anche un parametro aggiuntivo che rappresenta il puntatore ad una struttura del tipo dio32—config.
Questa (vedi x7.5) ingloba tutte le informazioni per la configurazione del gruppo di I/O.
Dal punto di vista del driver, questo comando ioctl attiva la funzione do config ioctl() che svolge i seguenti
compiti:
­ copia la struttura dio32—config passata dall'utente, nello spazio di indirizzamento del kernel. I dati
in essa contenuta configurano i parametri del gruppo di I/O;
11

­ chiama la funzione check user value() che esegue un controllo dei parametri passati dall'utente, in
modo da stabilirne la validit`a 10 ;
­ chiama la funzione handshaking config() che esegue le operazioni descritte al x4.0.2.
ffl DIO32 IOC RESET GROUP1
DIO32 IOC RESET GROUP2: questo comando esegue un reset della configurazione dei gruppi.
Questa operazione risulta indispensabile quando il programma utente deve modificare l'assegnazione delle
porte (e quindi della FIFO) ai gruppi. Dalla parte del driver, il comando ioctl esegue la funzione
do group reset() che effettua le seguenti operazioni:
­ seleziona la struttura dio32—device relativa al gruppo da resettare;
­ interrompe i segnali di handshaking chiamando la funzione stop handshaking();
­ chiama le funzioni reset registers() e turn off fifo(). Queste due routines resettano i registri del
gruppo: ad es. i registri delle FIFO assegnate,i registri del protocollo, del DMA etc.;
­ dealloca l'eventuale buffer di memoria virtuale chiamando la funzione mbuff dealloc();
­ azzera la struttura dio32—device relativa al gruppo salvando solo il valore del campo use—count.
ffl DIO32 IOC MITE CONFIG GROUP1
DIO32 IOC MITE CONFIG GROUP2: questo comando consente al processo utente di configurare i re­
gistri del controller MITE DMA relativi al gruppo di I/O selezionato.
A livello del kernel il comando seleziona la routine do mite config() che:
­ chiama la funzione DMA Program Minimite() che esegue la programmazione del controller DMA per
il gruppo specificato;
­ chiama la funzione DMA Arm Minimite() che inizia i trasferimenti DMA tutte le volte che vi sono
dati nella FIFO del gruppo;
­ setta il bit SF MITE della flag iobits del gruppo (vedi x7.1), per segnalare che il controller DMA `e
stato programmato.
ffl DIO32 IOC MITE RELEASE GROUP1
DIO32 IOC MITE RELEASE GROUP2: questo comando consente al processo utente di fermare i trasfe­
rimenti DMA per il gruppo di I/O. Il comando ioctl attiva la funzione do mite release() che:
­ chiama la funzione DMA Disarm Minimite() per fermare i trasferimenti DMA;
­ resetta il bit SF MITE della flag iobits del gruppo per segnalare che il controller DMA non `e pi`u
programmato.
ffl DIO32 IOC START GROUP1
DIO32 IOC START GROUP2: il comando avvia la procedura di acquisizione per il corrispondente gruppo
di I/O mandando in esecuzione la funzione start acquisition().
La funzione start acquisition() esegue i seguenti passi:
­ se la flag USE—DMA `e configurata (vedi x 7.4), verifica che il controller DMA sia stato programmato (bit
SF MITE abilitato) e che il buffer virtuale sia stato allocato e mappato nello spazio di indirizzamento
dell'applicazione utente (bit SF MMAP abilitato);
­ chiama la routine run handshaking() che esegue le operazioni descritte al x4.0.5.
ffl DIO32 IOC STOP GROUP1
DIO32 IOC STOP GROUP2: il comando ferma la procedura di acquisizione per il gruppo di I/O. La
funzione corrispondente a questo comando ioctl `e stop acquisition(), che compie le seguenti operazioni:
10 Questo passaggio potrebbe essere evitato se il controllo sui parametri da passare al driver venisse eseguito dalla applicazione
utente. Riteniamo opportuno che tale verifica venga comunque eseguita.
12

­ chiama la routine stop handshaking() per fermare i segnali di handshaking;
­ chiama la funzione empty fifo() che svuota le FIFO (vedi x 4.0.6);
­ chiama clear flags() che esegue il reset delle flag (vedi x4.0.4).
ffl DIO32 IOC WAIT INTERRUPT GROUP1
DIO32 IOC WAIT INTERRUPT GROUP2: questo comando esegue a livello del driver la funzione
wait for interrupt() il cui comportamento `e analogo a quello della chiamata select. Diversi processi pos­
sono essere sospesi mentre aspettano un interrupt su canali diversi.
Gli argomenti di questa funzione sono il canale di interrupt ed il tempo di timeout specificato in millise­
condi.
Se un interrupt `e gi`a avvenuto sul canale di interesse, allora la funzione decrementa il contatore dell'in­
terrupt e restituisce 1. Se invece il processo deve aspettare il verificarsi dell'interrupt, il processo `e posto
a ''dormire'' sotto il controllo di un timeout. La funzione in questo caso ritorna il valore 0.
ffl DIO32 IOC WAIT END TRANSFER GROUP1
DIO32 IOC WAIT END TRANSFER GROUP2: questo comando manda in esecuzione la funzione che
pone il processo in attesa della fine del trasferimento dati per acquisizioni controllate dal DMA
(wait end for transfer()).
La chiamata di sistema ioctl deve specificare come argomento un intervallo di timeout espresso in millise­
condi.
Per determinare la fine del trasferimento, la routine controlla il numero di byte che rimangono da tra­
sferire all' interno di un singolo nodo. Il numero di byte da trasferire si ricava chiamando la funzione
DMA Remaining Transfers() che legge il valore del registro TCR del controller MITE DMA.
Quando il numero di byte rimasti `e 0, il singolo trasferimento DMA `e terminato e il parametro che tiene
conto del numero di trasferimenti eseguiti viene incrementato. Quando questo valore raggiunge il numero
dei nodi costituenti la catena (mmap—buf—num vedi x6.3) il trasferimento complessivo `e concluso.
Se il trasferimento DMA non `e terminato entro l'intervallo di tempo prestabilito dall'utente, la condizione
di timeout viene segnalata all'applicazione.
Dobbiamo sottolineare come questo metodo risulti valido, ovviamente, solo per acquisizioni definite.
ffl DIO32 IOC CHECK TIMEOUT GROUP1
DIO32 IOC CHECK TIMEOUT GROUP2: in corrispondenza di questo comando ioctl viene chiamata
la funzione check timeout status(). Questo comando pu`o essere eseguito quando un processo viene sospeso
in attesa di un interrupt. L'applicazione utente passa come argomenti di input della funzione il canale di
interrupt relativo all'evento che deve verificarsi. La funzione ioctl() in questo caso restituisce all'applica­
zione utente il valore del contatore relativo al canale di interrupt. Se tale valore risulta positivo, allora si
`e verificato un timeout prima della ricezione dell'interrupt.
ffl DIO32 IOC RECONF GROUP1
DIO32 IOC RECONF GROUP2: questo comando consente all'applicazione utente di modificare solo quei
parametri di configurazione di un gruppo di I/O che non riguardano l'assegnazione delle porte (e delle
FIFO) al gruppo. Ad esempio: modifica del protocollo di handshaking, della modalit`a di acquisizione,
della direzione delle porte (input o output) oppure della sorgente di interrupt.
Se l'applicazione utente deve eseguire una riprogrammazione del gruppo che prevede anche una nuova
assegnazione delle porte di I/O (e quindi della ampiezza di trasferimento), deve essere prima eseguita
un'operazione di reset delle FIFO.
ffl DIO32 IOC EXTRA LINES: questo comando consente all'applicazione utente di gestire la linea PCLK2
per comunicare con l'elettronica esterna.
Questo comando esegue la funzione extra lines()che:
­ chiama la funzione extra lines config() che configura la linea PCLK2 come linea aggiuntiva di output;
­ chiama la funzione extra lines data transfer() che scrive un dato sulla linea PCLK2 ed aspetta per 5
msec.;
13

­ chiama la funzione extra lines unconfig() che ristabilisce la precedente configurazione della linea
PCLK2.
Una nota a parte meritano i due seguenti comandi ioctl perch`e in questo caso il device file specificato dalla
chiamata di sistema ioctl() deve essere quello relativo al gruppo: /dev/nipciN0 oppure /dev/nipciN1, dove N
indica il numero della scheda (0,1, etc.).
ffl DIO32 IOC MEM ALLOC: questo comando consente di allocare un buffer di memoria virtuale in corri­
spondenza del gruppo di I/O associato al device file. La chiamata di sistema ioctl() deve specificare la
dimensione in byte del buffer di memoria.
Il buffer di memoria virtuale viene utilizzato per acquisizioni che ricorrono all'uso del controller DMA.
Questo comando ioctl attiva a livello del kernel la funzione do allocate() che riceve in input il numero
minore del device file associato al gruppo di I/O e la dimensione della memoria da allocare.
La funzione do allocate() invoca la routine mbuff alloc(). Questa funzione procede ad allocare la memoria
per la struttura del tipo mbuff (che racchiude le informazioni relative al buffer DMA) e successivamente
esegue la funzione rvmalloc() che:
­ chiama la funzione vmalloc() la quale alloca una regione di memoria contigua nello spazio degli
indirizzi virtuali della dimensione specificata;
­ riserva le pagine di tale regione in modo che non siano sottoposte al processo di swap.
Sebbene le pagine che costituiscono il buffer non siamo necessariamente consecutive nella memoria fisica,
il kernel le vede come un insieme di indirizzi adiacenti.
Una delle caratteristiche dei trasferimenti DMA `e legata per`o al fatto che quando il buffer DMA `e pi`u
grande della dimensione di una pagina fisica, deve occupare pagine contigue nella memoria fisica. Se il
buffer ha dimensioni grandi (in Linux esiste un limite superiore di 128 KB) la sua allocazione diventa
difficile per un sistema operativo che usa memoria virtuale.
Un buffer virtuale, cio`e allocato con la funzione vmalloc(), permette di allocare ampie regioni di memoria,
ma non risulta adatto ad essere un buffer DMA in quanto non `e rappresentato da un intervallo di indirizzi
contigui in memoria fisica.
La modalit`a di funzionamento link­chaining del controller DMA ci viene incontro per superare questo
problema in quanto, come visto al x3.3.1 consente di trasferire dati in regioni di memoria non contigue.
L' uso combinato della memoria virtuale e della modalit`a di funzionamento link­chaining ci permette di
trasferire un buffer di memoria delle dimensioni adatte a contenere tutti i dati dell'acquisizione.
Un metodo alternativo consiste nel riservare una porzione della memoria fisica durante il boot del sistema.
Sebbene quest'ultimo metodo consenta di ottene un blocco di memoria fisica utilizzabile per trasfermenti
DMA, la conseguente riduzione della memoria non risulta una soluzione ''amichevole'' per i SO basati
sulla memoria virtuale.
Inoltre questa soluzione risulta poco flessibile, non permettendo il ridimensionamento della memoria
durante il processo di acquisizione. Per questi motivi non abbiamo preso in considerazione tale soluzione
ffl DIO32 IOC MEM DEALLOC: questo comando rilascia il buffer di memoria virtuale allocato per l'acqui­
sizione con il DMA per il gruppo di I/O specificato dal device file usato nella chiamata ioctl().
A livello di driver, viene chiamata la routine do deallocate() che chiama la funzione mbuff dealloc(). Que­
sta routine rilascia la memoria associata al buffer DMA, preoccupandosi di sbloccare le pagine in modo
da renderle nuovamente disponibili per il processo di swap.
5.3.5 dio32 mmap()
Il metodo mmap consente di mappare una regione di memoria del device nello spazio di indirizzamento dell'ap­
plicazione utente. In questo modo le operazioni di lettura e scrittura eseguite sul device file corrispondono ad
operazioni analoghe compiute sulla regione di memoria mappata.
La scelta di implementare questo metodo `e una conseguenza delle limitate informazioni che possediamo sul­
la programmazione del controller MITE DMA. Sebbene dalla documentazione risulti possibile programmare
14

il controller DMA in modo che questo generi un interrupt alla fine del trasferimento di ogni singolo blocco,
non abbiamo trovato informazioni sufficienti per implementare questa funzionalit`a. L'unico metodo per sapere
quando il trasferimento DMA di un singolo blocco di dati `e terminato, consiste nel leggere il registro TCR del
controller MITE (vedi x 5.3.4).
Sebbene sia sempre possibile implementare il DMA con il polling, una gestione efficiente del DMA si basa ge­
neralmente sulla notifica di un interrupt.
Per questo motivo abbiamo ritenuto utile procedere nel modo seguente per acquisizioni che si appoggiano al
controller DMA. Qualora l'utente intenda eseguire un trasferimento DMA, deve allocare un buffer di memoria
eseguendo il comando ioctl DIO32—IOC—MEM—ALLOC (vedi x 5.3.4). Questo buffer di memoria viene rimappato
nello spazio degli indirizzi dell'applicazione utente quando il programma invoca la chiamata di sistema mmap()
per il device file associato al gruppo di I/O.
In corrispondenza della chiamata di sistema mmap() viene attivata a livello di kernel il metodo mmap. Il metodo
mmap `e dichiarato come segue:
int (*mmap) (struct file *filp, struct vm area struct *vma);
L'argomento filp `e un puntatore al file mentre vma contiene le informazioni sull' intervallo di indirizzi
virtuali usati per accedere al device. Per implementare il metodo mmap il driver deve:
­ costruire le page table per il range di indirizzi;
­ ridefinire eventualmente i metodi open e close associati alla regioni di memoria virtuale vma con un nuovo
set di funzioni.
Una limitazione del metodo mmap `e che l'operazione di mapping ha una granularit`a pari a PAGE—SIZE 11 . Il kernel
pu`o disporre di indirizzi virtuali solo a livello di page table perci`o la regione mappata deve essere un multiplo di
PAGE—SIZE e deve risiedere nella memoria fisica ad un indirizzo che sia multiplo di PAGE—SIZE, cio`e deve essere
paged aligned.
La funzione dio32 mmap() invocata dal metodo mmap esegue le operazioni descritte nel seguente modo:
­ chiama la routine rvmmap(). Questa funzione esegue le verifiche necessarie sulla dimensione e l'in­
dirizzo della regione di memoria da mappare. Inoltre costruisce le page table chiamando la funzione
remap page range() per ogni pagina costituente il buffer di memoria virtuale.
­ installa il nuovo set di metodi mb open() e mb close() che tengono traccia del contatore d'uso del driver.
Questi due metodi incrementato il contatore del modulo tutte le volte che una VMA `e aperta, e lo
decrementano quando viene chiusa 12 .
Nei kernel pi`u recenti questo lavoro non `e necessario perch`e il kernel non chiama il metodo release se
un'area VMA rimane aperta. Il kernel 2.0, comunque, non tiene traccia di ci`o, cos ` i per avere un codice
portabile `e conveniente tenere traccia del contarore del modulo.
­ incrementa il contatore d'uso del driver (MOD INC USE COUNT). Questo `e necessario perch`e in questo
caso la VMA `e creata dalla chiamata di sistema mmap(), per cui `e invocato il metodo mmap e non il metodo
open della VMA.
­ viene attivato il bit SF MMAP della flag iobits per segnalare che il buffer di memoria `e stato mappato;
La chiamata di sistema mmap() restituisce, se portata a termine correttamente, l'indirizzo nello spazio dell'
applicazione utente a cui `e stata mappata la regione di memoria.
I dati trasferiti con DMA, sono accessibili andando a leggere direattamente tale regione di memoria. In questo
caso non `e necessario implementare nel driver il metodo di lettura.
11 Per un PC IBM compatibile, PAGE SIZE equivale a 4KB
12 Il metodo close viene invocato quando l'intera area viene rilasciata
15

5.4 Rimozione del driver
Il driver viene rimosso dal kernel con il comando rmmod che invoca la funzione cleanup module(). Il compito
svolto da questa funzione `e quello di rilasciare tutte le risorse allocate dal driver prima di liberare il numero
maggiore del device file di controllo attraverso la chiamata della funzione unregister chrdev().
La funzione cleanup module() chiama in successione le funzioni dio32 free() e mite cleanup(). La prima rilascia
la memoria e le risorse hardware associate a ciascun device chiamando la funzione nidio device detach(). La
seconda libera invece la memoria allocata in fase di inizializzazione per la catena di strutture mite—struct.
6 Descrizione delle strutture dati interne
Prendiamo in esame le varie strutture del driver che definiscono i parametri per descrivere in modo completo il
funzionamento della scheda.
Alcune di queste strutture sono interne, cio`e accessibili solo dal kernel, altre invece sono utilizzate anche dall'
applicazione utente per consentire la configurazione del device.
6.1 Struttura ni device
La struttura ni—device riassume le informazioni che caratterizzano il singolo device.
typedef struct ni—device—struct ni—device;
struct ni—device—struct--
int use—count;
unsigned char attached;
unsigned char tgroup;
unsigned char used—fifo;
unsigned char used—group;
int iobase;
int mite—addr;
int irq;
dio32—device *dio32dev;
struct mite—struct *mite;
void(*trig[5])(ni—device*,dio32—device *);
ť;
Prendiamo in esame i campi della struttura:
use count : `e il contatore che tiene traccia manualmente dell' uso del modulo. Il sistema necessita questa
informazione perch`e il device file /dev/nipci0ctl viene aperto in modalit`a singola, cio`e vi pu`o accedere un
solo processo utente.
attached : questa flag vale 0 od 1 a seconda che la scheda sia stata inizializzata oppure no. L' inizializzazione
della scheda comporta la configurazione del bus come descritto al x3.1.
tgroup : questo parametro descrive il numero dei gruppi di I/O usati. Pu`o assumere valore 1 o 2. Se vale 1,
viene usato un solo gruppo di I/O, se vale 2 vengono usati entrambi.
used fifo : questa flag tiene conto delle FIFO configurate. `
E utile sopratutto quando vengono programmati
entrambi i gruppi perch`e ci permette di determinare quale FIFO sono gi`a state associate ad un gruppo in
modo da evitare attribuzioni errate.
used group : questo parametro tiene conto di quale gruppo `e stato configurato. `
E ovvio che le operazioni di
acquisizione possono essere effettuate solo su gruppi di I/O configurati, cio`e per i quali sono state compiute
le operazioni descritte al x4.0.2;
16

iobase : questo parametro contiene l'indirizzo base del chipset DAQ­DIO rimappato nello spazio del kernel;
mite addr : questo campo rappresenta l'indirizzo del chip MITE rimappato nello spazio del kernel;
irq : numero di interrupt;
*dio32dev : puntatore alla struttura del tipo dio32—device che descrive il singolo gruppo di I/O (vedi x6.2);
*mite : puntatore alla struttura del tipo mite—struct (vedi x6.5);
*trig[5] : puntatori alle funzioni di generazione di protocollo.
6.2 Struttura dio32 device
La struttura dio32—device riassume le informazioni che caratterizzano il singolo gruppo di I/O.
struct dio32—device—struct --
unsigned char ngroup;
unsigned char group—fifo;
unsigned char iobits;
int use—count;
short dmaChannel;
short drqnum;
unsigned char Data—Path—Copy;
unsigned char Interrupt—Control—Copy;
unsigned char DMA—and—Int—Control—Copy;
unsigned char OpMode—Copy;
unsigned char DAQ—Options—Copy;
unsigned char Transfer—Size—Control—Copy;
int interrupt—ctr[INTERRUPT—CHANNELS];
int sleeping—process[INTERRUPT—CHANNELS];
struct wait—queue *pcidaq—wait[INTERRUPT—CHANNELS];
struct mbuff *mbuff;
dio32—group cur—group;
dio32—mode cur—mode;
dio32—trig cur—trig;
dio32—interrupt cur—int;
ť;
ngroup : questo parametro rappresenta il numero del gruppo di I/O (1 o 2);
group fifo : il parametro tiene conto delle FIFO assegnate al gruppo;
iobits : questa flag tiene traccia delle configurazioni eseguite sul gruppo. In particolare: configurazione del
controller MITE (bit SF MITE selezionato), mappatura del buffer virtuale (bit SF MMAP selezionato);
use count : ad ogni gruppo di I/O `e associato un device file. L' accesso a tali device file `e monitorato da tale
parametro;
dmaChannel : canale DMA del gruppo di I/O;
drqnum : canale DRQ;
Data Path Copy,...,Transfer Size Control Copy : questi parametri contengono la copia del contenuto dei
registri corrispondenti;
17

interrupt ctr[INTERRUPT CHANNELS] : contatore degli interrupt che possono verificarsi sui diversi
canali;
sleeping process[INTERRUPT CHANNELS] : parametro che controlla il numero dei processi in sospeso
su un canale di interrupt;
*pcidaq wait[INTERRUPT CHANNELS] : coda di attesa per il processo sospeso in attesa di interrupt;
*mbuff : puntatore alla struttura del tipo mbuff (vedi x6.3)
cur group : struttura del tipo dio32 group (vedi x7.1);
cur mode : struttura del tipo dio32 mode (vedi x7.2);
cur trig : struttura del tipo dio32 trig (vedi x7.3);
cur int : struttura del tipo dio32 interrupt (vedi x7.4);
6.3 Struttura mbuff
La struttura mbuff descrive il buffer di memoria che viene allocato quando vengono programmati trasferimenti
DMA.
struct mbuff--
unsigned char *vbuf;
unsigned short mmap—buf—num;
unsigned long size;
struct vm—area—struct *vm—area;
BufferinfoNode *BufferNodePtr;
BufferinfoNode *BufferHeadNodePtr;
ť;
*vbuf : puntatore al buffer di memoria virtuale in cui vengono trasferiti i dati dal DMA;
mmap buf num : numero di nodi nella catena DMA. Tale valore rappresenta anche in numero di trasferimenti
DMA che devono essere effettuati;
size : dimensione in byte del buffer di memoria;
*vm area : puntatore alla struttura vm—area—struct contenente le informazioni della regione di memoria
virtuale (VMA) del processo generata dal mmapping del device;
*BufferNodePtr,*BufferHeadNodePtr : puntatori alla struttura del tipo BufferinfoNode (vedi x6.4);
6.4 Struttura BufferinfoNode e MITELinkStruct
Queste due strutture, definite nel file include pcidio32­dma.h, vengono usate nella programmazione del control­
ler MITE DMA in modalit`a link­chaining. La struttura BufferinfoNode consente di registrare le informazioni
relative ad ogni singolo blocco di dati che deve essere trasferito in memoria dal DMA.
typedef struct BufferinfoNode --
struct BufferinfoNode *NextNode;
unsigned long BufferPhysicalAddress;
unsigned long NumberOfBytesTransfer;
ť BufferinfoNode;
*NextNode : puntatore al nodo successivo;
18

BufferPhysicalAddress : indirizzo fisico del buffer di memoria in cui vengono immagazzinati i dati del
trasferimento DMA;
NumberOfBytesTransfer : numero di byte che costituiscono il blocco da trasferire in memoria;
La struttura MITELinkStruct raccoglie le informazioni di ogni record di dati usati durante l'autoconfigurazione
del controller DMA.
typedef struct --
unsigned long TCRlink;
unsigned long MARlink;
unsigned long DARlink;
unsigned long LKARlink;
ť MITELinkStruct;
TCRlink : `e il valore che deve essere scritto nel registro TCR. Rappresenta il numero di byte di ogni blocco
da trasferire;
MARlink : contiene l'indirizzo fisico del buffer di memoria in cui vengono trasferiti i dati mentre `e in funzione
il DMA;
DARlink : questo parametro viene posto uguale a 0x1c.
LKARLink : `e l'indirizzo fisico del nodo successivo della catena usato dal chip MITE per riprogrammarsi.
6.5 Struttura mite struct
La struttura mite—struct raccoglie le risorse hardware del device.
struct mite—struct--
struct mite—struct *next;
int used;
unsigned char board;
struct pci—dev *pcidev;
unsigned long mite—phys—addr;
unsigned long daq—phys—addr;
unsigned long mite—io—addr;
unsigned long daq—io—addr;
ť;
I campi della struttura hanno il seguente significato:
*next : puntatore ad una struttura dello stesso tipo. In questo modo viene costruita una lista concatenata di
strutture, ciascuna relativa ad un diverso device;
used : la variabile assume valore 1 o 0 a seconda che la struttura a cui appartiene corrisponda ad un device
gi`a in uso oppure no;
board : numero della scheda a cui `e associata la struttura. Assume valore 0 per la prima scheda individuata,
1 per la seconda etc.;
*pcidev : puntatore alla struttura del tipo pci—dev. Questa struttura rappresenta un device PCI ed `e usata
in ogni operazione che coinvolge device PCI ;
mite phys addr : indirizzo fisico del chipset MITE;
daq phys addr : indirizzo fisico del chipset DAQ­DIO;
mite io addr : indirizzo del chipset MITE rimappato nello spazio di indirizzamento del kernel;
daq io addr : indirizzo fisico del chipset DAQ­DIO rimappato nello spazio di indirizzamento del kernel;
19

7 Descrizione delle strutture dati esterne
In questo capitolo diamo una descrizione delle strutture di dati accessibili dal processo utente. I valori dei
campi delle varie strutture vengono definiti dall' applicazione e sono passati nello spazio del kernel attraverso i
comandi ioctl.
7.1 Struttura dio32 group
La struttura dio32—group specifica le caratteristiche di ciascun gruppo ed `e definita come segue:
struct dio32—group—struct--
unsigned char groupSize;
unsigned char dir;
unsigned char port;
unsigned char funneling;
unsigned char pin—mask;
unsigned char transfer—width;
ť;
Di seguito descriviamo il significato di ciascun elemento.
groupSize : specifica la dimensione del gruppo. In particolare questa variabile pu`o assumere solo 3 valori:
1,2 o 4. A seconda del valore assegnato a groupSize, ad ogni gruppo di acquisizone vengono assegnate
rispettivamente 1, 2 o 4 porte di I/O.
dir : specifica la direzione di acquisizione delle porte assegnate al gruppo. Il valore 0 implica che le porte sono
configurate per l'input, il valore 1 per l'output.
port : specifica le porte di I/O assegnate al gruppo. L'assegnazione dipende dalla dimensione del gruppo. In
particolare se groupSize vale 1, la porta pu`o assumere i valori 0,1,2,3 (corrispondenti alle porte A,B,C,D).
Se groupSize vale 2, port pu`o assumere il valore 0 (porte A e B) e 2 (porte C e D). Infine se groupSize
vale 4, allora port pu`o assumere solo valore 0 (porte A,B,C e D).
Tutto ci`o pu`o essere schematizzato nel seguente modo:
groupSize port
1 0,1,2,3
2 0,2
4 0
`
E importante sottolineare che per la famiglia DIO 6533, si possono raggruppare le porte 0 ed 1 insieme e
le porte 2 e 3 insieme, ma non la 1 e la 3 oppure la 0 e la 2.
funneling : questa flag pu`o assumere valore 0 o 2. Nel primo caso il funneling `e disattivato, nel secondo caso
no.
pin mask : rappresenta la maschera dei pin di ciascuna porta. Per operazioni di input questa maschera `e
significativa solo per il change detection una variazione del pattern generation.
transfer width : configura l'ampiezza che il gruppo supporta nelle operazione di lettura, scrittura o acces­
so DMA. Questo valore deve essere minore od uguale all'ampiezza complessiva del gruppo specificata
da groupSize. Ad esempio, per usare un trasferimento DMA a 16­bit deve essere scelto un valore di
transfer—width corrispondente a 16­bit anche se si stanno eseguendo operazioni a 32­bit usando tutte e
quattro le FIFO e tutte e quattro le porte. Questa variabile pu`o assumere solo i valori 0,2 ,3. Il significato
`e il seguente:
20

ffl 0: trasferimenti a 32­bit (DMA o FIFO)
ffl 2: trasferimenti a 8­bit (DMA o FIFO). I trasferimenti hanno comunque luogo tra questi pins e
ciascuna FIFO del gruppo in successione.
ffl 3: trasferimenti a 16­bit (DMA o FIFO). I trasferimenti hanno luogo da o verso le FIFO dei gruppi,
due alla volta, in successione. Un gruppo che esegue un trasferiemnto DMA a 16­bit deve contenere
due o quattro FIFO.
Si pu`o usare la seguente tabella per determinare le combinazioni valide di porte e gruppi che si possono usare
con l'ampiezza dei dati che si vogliono trasferire.
Ampiezza Valore di Possibile Gruppi che possono
Trasferimento groupSize combinazione porte essere usati
8 bits 1 Port 0 Group 1
Port 2 Group 2
16 bits 2 Port 0,Port 1 Group 1
Port 2,Port 3 Group 2
32 bits 4 Port 0,Port 1,Port 2,Port 3 Group 1
7.2 Struttura dio32 mode
La struttura dio32—mode raggruppa i parametri che consentono di specificare le caratteristiche di un protocollo
di handshaking. La struttura contiene i seguenti elementi:
struct dio32—mode—struct--
unsigned char nprot;
unsigned char edge;
unsigned char reqPol;
unsigned char ackPol;
unsigned char delayTime;
ť;
nprot : specifica il numero che identifica il protocollo di handshaking. I valori che tale variabile pu`o assumere
ed i corrispondenti protocolli sono:
ffl 0: level­ACK
ffl 1: pulsed ACK
ffl 2: long pulse ACK
ffl 3: burst mode (modalit`a sincrona)
ffl 4: emulazione 8255
edge : pu`o assumere valore 0 o 1 e specifica se il gruppo `e configurato per il leading­edge o trailing­edge e pu`o
assumere solo i seguenti valori:
ffl 0: leading­edge
ffl 1: trailing­edge
Questo parametro ha significato solo per i protocolli 1 e 2.
reqPol : questo parametro indica se il segnale REQ di richiesta del gruppo deve essere attivo alto o attivo
basso. Questo parametro pu`o assumere i seguenti valori:
ffl 0: REQ attivo alto
21

ffl 1: REQ attivo basso
Se il protocollo specificato `e il 4 (emulazione 8255), questo valore viene ignorato in quanto in tal caso
viene utilizzato un segnale REQ attivo basso.
ackPol : indica se il segnale ACQ del gruppo deve essere attivo alto o attivo basso. Questo parametro pu`o
assumere i seguenti valori:
ffl 0: ACQ attivo alto
ffl 1: ACQ attivo basso
Se il protocollo specificato `e il 4, questo valore viene ignorato in quanto in emulazione 8255 viene utilizzato
un segnale ACQ attivo basso.
delayTime : per tutti i protocolli, eccetto il burst, specifica il ritardo inserito nel protocollo di handshaking,
in multipli di 100 ns fino ad un massimo di 700 ns. Tale parametro pu`o perci`o assumere valori compresi
tra 0 e 7.
L'effetto introdotto da questo parametro varia da protocollo a protocollo. Per il protocollo burst il ritardo
seleziona la frequenza del segnale di clock quando `e generato da una sorgente esterna.
7.3 Struttura dio32 trig
Gli elementi della struttura dio32—trig consentono di definire alcuni dei parametri necessari per il processo
acquisizione.
struct dio32—trig—struct--
unsigned char numbered;
unsigned char sizeInByte;
int transferCount;
ť;
numbered : tale parametro specifica la modalit`a di trasferimento. In particolare il DAQ­DIO supporta due
distinti modi di trasferimento: numerato, in cui cui viene eseguito un trasferimento prederminato e finito
di dati e non numerato (per il momento non supportato dal driver) in cui il trasferimento continua in
modo indefinito fino a che non viene interrotto resettando al valore 0 la flag RunMode (vedi x4.0.5)
transferCount : il numero di dati da trasferire nel caso in cui sia stato selezionata la modalit`a numbered.
sizeInByte : dimensione in byte dei campioni da acquisire.
7.4 Struttura dio32 interrupt
Gli elementi di questa struttura configurano la modalit`a di acquisizione (polling,DMA,interrupt) e le linee di
interrupt da attivare in modo che in corrispondenza dell'evento, il device sia in grado di generare un interrupt.
struct dio32—interrupt—struct --
unsigned char iomode;
unsigned char TR—interrupt;
unsigned char CE—interrupt;
unsigned char Waited—interrupt;
unsigned char P—TC—interrupt;
unsigned char S—TC—interrupt;
ť;
iomode : questa flag consente di scegliere all'utente la modalit`a di acquisizione. Per acquisizioni DMA, il suo
valore consente di programmare il registro DMA MCR in modo da supportare trasferimenti da e verso la
memoria a 8, 16 e 32 bit. I valori che tale variabile pu`o assumere sono:
22

ffl USE—DMA, USE—DMA—16, USE—DMA—32: il trasferimento dei dati viene eseguito utilizzando il controller
DMA integrato sul chip MITE ed il registro DMA MCR viene programmato per trasferimenti da e
verso la memoria rispettivamente a 8,16 e 32 bit. Nel caso in cui sia stato selezionato un trasferimento
finito di dati (variabile numbered della struttura dio32—trig settata ad 1), la fine del processo di
trasferiemnto viene determinata andando a leggere il registro TCR del MITE. Questo registro contiene
il numero di dati che devono ancora essere trasferiti. Quando il valore di tale registro diventa 0, il
trasferimento `e concluso.
ffl USE—DMA + USE—IRQ: anche in questo caso il trasferimento viene eseguito appoggiandosi alle facilit`a
del DMA, ma il controllo sulla fine del trasferimento viene effettuato attraverso la generazione di un
interrupt. Questa modalit`a per il momento non funziona date le scarse informazioni che abbiamo
sulla programmazione del controller DMA del MITE.
ffl USE—IRQ: il trasferimento dei dati viene realizzato appoggiandosi agli interrupt che il device `e in grado
di generare.
Per il momento questa opzione non `e attiva.
ffl USE—READ:il trasferimento dei dei dati viene effettuato in polling mode. Per stabilire se nella FIFO
del gruppo di acquisizione sono presenti i dati,viene letto il valore del registro GROUP—FLAGS relativo
al gruppo. Questa `e la modalit`a di default nel caso in cui la flag iomode sia nulla.
TR interrupt---,CE interrupt,.. : queste flags possono assumere solo il valore 0 o 1.
Quando viene configurata ad 1, il rispettivo bit del registro di interrupt della scheda viene abilitato ed un
interrupt pu`o essere generato in corrispondenza del relativo evento 13 .
7.5 Struttura dio32 config
La struttura dio32—config consente di raggruppare tutte le informazioni realative alla configurazione di un
gruppo di I/O. In particolare la struttura dio32—config `e definita come segue:
struct dio32—config—struct --
unsigned char ngroup;
dio32—group cur—group;
dio32—mode cur—mode;
dio32—trig cur—trig;
dio32—interrupt cur—int;
ť;
Il primo elemento della struttura rappresenta il numero del gruppo di I/O (1 o 2) che l'applicazione utente
configura per l'operazione di acquisizione. I quattro elementi successivi sono costituiti dalle strutture che
abbiamo descritto in precedenza.
8 Organizzazione dei sorgenti del driver
I sorgenti che servono per la costruzione del modulo del driver, sono contenuti in due directory distinte: la
directory include e la directory src. La prima comprende gli includes files, la seconda i sorgenti C ed il Makefile
per la costruzione del modulo.
I sorgenti del driver e le relative versioni di sviluppo, sono controllati dal sistema CVS (version control system).
8.1 Directory src
I files sorgenti sono stati organizzati in modo da rispecchiare l'organizzazione del driver. In particolare:
13 In realt`a questo non `e sufficiente. La generazione di un interrupt da parte del device deve essere abilitata in modo globale. A
tale scopo devono essere posti ad 1 i primi due bits del registro MASTER DMA AND INTERRUPT CONTROL
23

pcidio32­inits.c : include le funzioni init module e cleanup module() per la registrazione e le rimozione del
driver come pure la routine dio32 free() che esegue il rilascio della memoria allocata per le strutture del
device. Nello stesso sorgente sono definite le due funzioni get device by minor() e get subdevice by minor()
che permettono di selezionare le strutture del device e del gruppo di acquisizione dal numero minore del
device file (vedi x 9).
pcidio32­fops.c : comprende la definizione delle operazioni eseguibili sul device file elencate al x 5.3.
Nello stesso sorgente sono definite anche le funzioni mb open() e mb close() che costituiscono i metodi
associati alle aree di memoria virtuale create dall'operazione di mappatura della memoria.
pcidio32­defs.c : contiene le funzioni che vengono chiamate dai vari comandi ioctl.
pcidio32­ints.c : include la routine associata al gestore di interrupt.
pcidio32­daq.c : include le funzioni di pi`u basso livello che configurano e leggono i registri del chip DAQ­DIO.
pcidio32­util.c : definisce le funzioni che eseguono il controllo sui parametri di configurazione della scheda.
mite.c : definisce le funzioni per il rilevamento ed inizializzazione delle schede PCI­DIO32HS della NI.
dma.c : contiene le funzioni necessarie per programmare in modalit`a link­chaining il controller MITE DMA,
ed alcune funzioni correlate al suo corretto funzionamento.
kvmem.c comprende le funzioni per l' allocazione, il mapping ed il rilascio della memoria virtuale. Queste
routine sono un parziale riadattamento di quelle scritte per i driver bttv e mbuff 14 . I sorgenti di quest'ul­
timo sono prelevabili dal sito internet
http://crds.chemie.unibas.ch/PCI­MIO­E/ .
8.2 Directory include
La directory include contiene i seguenti files:
pcidio32­kernel.h : comprende la definzione delle strutture dati ni—device e dio32—device associate al
device driver e le dichiarazioni delle funzioni.
pcidio32­ioctl.h include la definzioni dei comandi ioctl e le strutture dati del gruppo di I/O. Queste sono
state poste in un file separato, perche`e devono essere accessibili alle applicazioni utenti. `
E preferibile una
netta separazione tra le strutture accessibili esclusivamente dal kernel (definite appunto all'interne del file
pcidio32­kernel.h) e quelle accessibili anche a livello di processo utente.
pcidio32­dma.h : comprende l'elenco dei registri del chipset MITE DMA e la definizione delle strutture dati
utilizzate per la sua configurazione.
mite.h : definisce la struttura dati mite—struct e la dichiarazione delle funzioni di rilevamento ed inizializza­
zione dell'hardware.
daqdio.h : contiene l'elenco degli offset dei registri del chip DAQ­DIO.
mitereg.h : comprende l' elenco dei bitfield dei registri del chipset MITE. Questo file `e fornito dalla National
Instrument.
bitfields.h : include la definizione di alcune macro che consentono di accedere in modo semplice ai singoli bit
dei registri del chip DAQ­DIO.
kvmem.h : comprende la definizione delle funzioni che gestiscono la memoria virtuale.
sysdep.h : questo file raggruppa le incompatibilit`a tra le versioni 2.0, 2.2 e 2.4 del kernel Linux.
14 Il driver Linux mbuff `e stato sviluppato da Tomasz Motylewski
24

pci­compat.h : questo header file deve essere incluso per il supporto corrente del PCI quando il driver `e
compilato per la versione 2.0 del kernel.
Questi due ultimi file sono stati scritti da A.Rubini e J.Corbet e sono prelevabili, insieme ai sorgenti degli esempi
riportati in [1], dal sito internet:
http://examples.oreilly.com/linuxdrive2 .
9 Costruzione ed uso del driver
La compilazione del driver `e eseguita automaticamente dal Makefile contenuto nella directory dei sorgenti. L'
operazione di compilazione produce il file oggetto dio32.o.
Il driver Linux per la scheda PCI­DIO32HS della National Instruments `e stato compilato per le versioni 2.2.19
e 2.4.17 del kernel Linux.
Per usare il device driver il modulo dio32 deve essere caricato nel kernel specificando il comando:
insmod dio32
Prima di eseguire l'applicazione utente, si devono creare nella directory /dev i seguenti device files nipci00,
nipci01, nipci0ctl per la prima scheda, nipci10, nipci11,nipci1ctl per la seconda scheda e cos ` i via.
Come si nota ad ogni scheda sono associati tre distinti device files: i primi due ci consentono di trattare i due
gruppi di I/O (1 e 2) come device separati, il terzo lo abbiamo introdotto per consentire tutte le operazioni di
controllo e configurazione del device fisico.
Questi devices files vengono creati con il comando mknod specificando il tipo di device (caratteri) ed il numero
maggiore e minore. Il numero maggiore, come detto in precedenza `e posto uguale a 60. I numeri minori dei
device files sono stati costruiti in modo da fornire informazioni sulla scheda ed il gruppo di I/O.
In particolare, il numero minore viene generato nel seguente modo:
minor number = card number * MINOR RANGE+ [0­2]
dove:
ffl card—number vale 0 per la prima scheda, 1 per la seconda etc.
ffl MINOR—RANGE vale 3 perch`e tre sono i device file associati al driver
Ne segue che per la prima scheda i device files avranno numeri minori uguali a 0, 1, 2, per la seconda scheda 3,
4, 5 etc.
Dal numero minore si possono perci`o ricavare le seguenti informazioni:
­ card number = minor number / MINOR RANGE
­ group number = (minor number % MINOR RANGE) +1.
10 Test di funzionamento del driver
Il driver per la scheda PCI­DIO32HS della National Instruments `e stato provato utilizzando un'apparecchiatura
costruita in laboratorio che ci ha consentito di generare sia i dati sia i segnali di handshaking. In particolare
abbiamo scelto di lavorare con il protocollo di emulazione 8255.
Per eseguire il test del driver abbiamo scritto alcune applicazioni utenti che si differenziano solo sulla modalit`a
con cui vengono acquisiti i dati: polling oppure DMA.
La modalit`a che si appoggia all'uso degli interrupt al momento non funziona.
I test di funzionamento sono stati eseguiti programmando un solo gruppo di I/O ed associando ad esso le quattro
FIFO e le quattro porte di I/O ed effettuando operazioni di sola lettura con un numero definito di dati.
In modalit`a DMA abbiamo ottenuto velocit`a di trasferimento di circa 5.8 MB/s, mentre in polling mode abbiamo
raggiunto la velocit`a di 3­3.5 MB/s. Entrambi i valori concordano con quelli dichiarati dal protocollo in uso.
25

11 Conclusioni
Anche se il presente driver ha ancora dei limiti, come la mancanza della gestione del DMA (dovuta alla volont`a
della National di non fornire informazioni), lo stato corrente `e pi`u che rispondente alle specifiche del progetto
Fasti per cui `e stato originariamente sviluppato.
Le prospettive future di questo lavoro sono:
ffl integrazione del codice nel software di Fasti.
ffl Rilascio del driver e della documentazione faticosamente raccolta da uno di noi (E.G.) sotto una licenza
GNU, che permetta una larga fruibilit`a di quanto ottenuto.
ffl Registrazione e pubblicazione del nostro lavoro su di un sito pubblico dedicato allo Open Software (ad
esempio sourceforge).
ffl verifica funzionale ed adattamento del codice del driver alla situazione di piu' schede.
12 References
[1] A.Rubini,J.Corbet ''Linux device drivers'',O'Reilly
26

13 Appendice A
13.1 Registri del chip DAQ­DIO
La seguente tabella mostra la mappa dei registri del chip DAQ­DIO elencati in ordine alfabetico
Register Name Offset (decimal) Type
Chip ID 24­27 Read
Data Path 64 (Group 1) Write
96 (Group 2)
DMA Line Control 76 (Group 1) Write
108 (Group 2)
FIFO A 16 Read/Write
FIFO B 17 Read/Write
FIFO C 18 Read/Write
FIFO D 19 Read/Write
Group 1 FIFO 8­11 Read/Write
Group 1 First Clear 6 Write
Group 1 Flags 6 Read
Group 1 Second Clear 46 Write
Group 2 FIFO 12­15 Read/Write
Group 2 First Clear 7 Write
Group 2 Flags 7 Read
Group 2 Second Clear 47 Write
Group Status 5 Read
Inteerupt and Window Status 4 Read
Interrupt Control 75 (Group 1) Write
107 (Group 2)
Master Clock Routing 45 Write
Master DMA and Interrupt Control 5 Write
Pattern Detection 81 (Group 1) Write
113 (Group 2)
Port A Input 28 Read
Port A Output 28 Write
Port A Pattern 48 Write
Port A Pin Directions 32 Write
Port A Pin Mask 36 Write
Port A Polarities 40 Write
27

Port B Input 29 Read
Port B Output 29 Write
Port B Pattern 49 Write
Port B Pin Directions 33 Write
Port B Pin Mask 37 Write
Port B Polarities 41 Write
Port C Input 30 Read
Port C Output 30 Write
Port C Pattern 50 Write
Port C Pin Directions 34 Write
Port C Pin Mask 38 Write
Port C Polarities 42 Write
Port D Input 31 Read
Port D Output 31 Write
Port D Pattern 51 Write
Port D Pin Directions 35 Write
Port D Pin Mask 39 Write
Port D Polarities 43 Write
Protocol Register 1 65 (Group 1) Write
97 (Group 2)
Protocol Register 2 66 (Group 1) Write
98 (Group 2)
Protocol Register 3 67 (Group 1) Write
99 (Group 2)
28

Protocol Register 4 70 (Group 1) Write
102 (Group 2)
Protocol Register 5 71 (Group 1) Write
103 (Group 2)
Protocol Register 6 73 (Group 1) Write
105 (Group 2)
Protocol Register 7 74 (Group 1) Write
106 (Group 2)
Protocol Register 8 88­91 (Group 1) Write
120­123 (Group 2)
Protocol Register 9 82 (Group 1) Write
114 (Group 2)
Protocol Register 10 83 (Group 1) Write
115 (Group 2)
Protocol Register 11 84 (Group 1) Write
116 (Group 2)
Protocol Register 12 85 (Group 1) Write
117 (Group 2)
Protocol Register 13 86 (Group 1) Write
118 (Group 2)
Protocol Register 14 68­69 (Group 1) Write
100­101 (Group 2)
Protocol Register 15 79 (Group 1) Write
111 (Group 2)
Reserved for board­level circuitry 124­127 Write
(RSTI switch)
Subspace 1 56­63 Read/Write
Transfer Count 20­23 (Group 1) Write
24­27 (Group 2)
Transfer Size Control 77 (Group 1) Write
109 (Group 2)
Window Address 4 Write
Window Data 0­3 Read/Write
29

14 Appendice B
14.1 Locazione dei bit dei registri del chip DAQ­DIO
Data Path
Group1 Offset: 64
Group2 Offset: 96
Type:Write Only
DMA Line Control
Group1 Offset: 76
Group2 Offset: 108
Type:Write Only
0 FIFOEnables(A)
1 FIFOEnables(B)
2 FIFOEnables(C)
3 FIFOEnables(D)
4 funneling
5 funneling
6
7 GroupDirection
0 DMAChannel
1 DMAChannel
2 DMAChannel
3 DMAChannel
4
5
6
7
FIFO Control
Group1 Offset: 72
Group2 Offset: 104
Type:Write Only
Group FIFOs
Group1 Offset: 8­11
Group2 Offset: 12­15
Type: Read/Write
0 ReadyLevel
1 ReadyLevel
2 ReadyLevel
3 ReadyLevel
4
5
6
7
0 FIFOdata
1 FIFOdata
2 FIFOdata
3 FIFOdata
4 FIFOdata
5 FIFOdata
6 FIFOdata
7 FIFOdata
30

Group First Clear
Group1 Offset: 6
Group2 Offset: 7
Type:Write Only
Group Flags
Group1 Offset: 6
Group2 Offset: 7
Type:Read Only
0
1
2
3 ClearWaited
4 Clear PrimaryTC
5 Clear SecondaryTC
6 DMAReset
7 FIFOReset
0 TransferReady
1 CountExpired
2
3
4
5 Waited(overflow/underflow)
6 PrimaryTC
7 SecondaryTC
Group Second Clear
Group1 Offset: 46
Group2 Offset: 47
Type:Write Only
Group Status
Offset: 5
Type: Read Only
0 ClearExpired
1
2 Reserved
3 Reserverd
4 Reserved
5 Reserved
6 Reserved
7 Reserved
0 DataLeft(1)
1 Reserved
2 Req(1)
3 StopTrig(1)
4 DataLeft(2)
5 Reserved
6 Req(2)
7 StopTrig(2)
31

Interrupt and Window Status Interrupt Control
Offset: 4
Type:Read Only
Group1 Offset: 75
Group2 Offset: 107
Type:Write Only
0 IntStatus(1)
1 IntStatus(2)
2 WindowAddressStatus
3 WindowAddressStatus
4 WindowAddressStatus
5 WindowAddressStatus
6 WindowAddressStatus
7 Reserved
0 IntEnables(0) (Transfer Ready)
1 IntEnables(1) (Count Expired)
2
3
4
5 IntEnables(5) (Waited)
6 IntEnables(6) (PrimaryTC)
7 IntEnables(7) (SecondaryTC)
Master DMA and Interrupt Control Master Clock Routing
Offset: 5
Type:Write Only
Offset: 45
Type: Read Only
0 InterruptLine
1 InterruptLine
2 OpenInt
3
4 Reserved
5 Reserved
6 Reserved
7 Reserved
0 Reserved
1 Reserved
2 Reserved
3 Reserved
4 RTSIClocking
5 RTSIClocking
6 Reserved
7 Reserved
32

Port Pin Directions
Port A Offset: 32
Port B Offset: 33
Port C Offset: 34
Port D Offset: 35
Type:Write Only
Port Pin Mask
Port A Offset: 36
Port B Offset: 37
Port C Offset: 38
Port D Offset: 39
Type:Read Only
0 PinDirections
1 PinDirections
2 PinDirections
3 PinDirections
4 PinDirections
5 PinDirections
6 PinDirections
7 PinDirections
0 PinMask
1 PinMask
2 PinMask
3 PinMask
4 PinMask
5 PinMask
6 PinMask
7 PinMask
Protocol Register 1
Group1 Offset: 65
Group2 Offset: 97
Type:Write Only
Protocol Register 2
Group1 Offset: 66
Group2 Offset: 98
Type:Write Only
0 RunMode
1 RunMode
2 RunMode
3 Numbered
4 Protocol(1)
5 Protocol(1)
6 Protocol(1)
7
0 Protocol(2)
1 Protocol(2)
2 Protocol(2)
3 Protocol(2)
4 Protocol(2)
5 Protocol(2)
6 Protocol(2)
7 InverStopTrig
33

Protocol Register 3
Group1 Offset: 67
Group2 Offset: 99
Type:Write Only
Protocol Register 4
Group1 Offset: 70
Group2 Offset: 102
Type:Write Only
0 Protocol(3)
1 Protocol(3)
2 Protocol(3)
3 Protocol(3)
4 Protocol(3)
5 Protocol(3)
6 Protocol(3)
7 Protocol(3)
0 Protocol(4)
1 Protocol(4)
2 Protocol(4)
3 Protocol(4)
4 Protocol(4)
5 Protocol(4)
6 Protocol(4)
7 Protocol(4)
Protocol Register 5
Group1 Offset: 71
Group2 Offset: 103
Type:Write Only
Protocol Register 6
Group1 Offset: 73
Group2 Offset: 105
Type:Write Only
0 Protocol(5)
1 Protocol(5)
2 Protocol(5)
3 Protocol(5)
4 Protocol(5)
5 Protocol(5)
6 Protocol(5)
7 Protocol(5)
0 InvertAck
1 InvertReq
2 InvertClock
3 InvertSerial
4 OpenAck
5 OpenClock
6 Reserved
7 Reserved
34

Protocol Register 7
Group1 Offset: 74
Group2 Offset: 106
Type:Write Only
Protocol Register 8
Group1 Offset: 88­91
Group2 Offset: 120­123
Type:Write Only
0 Protocol(7)
1 Protocol(7)
2 Protocol(7)
3 Protocol(7)
4 Protocol(7)
5 Protocol(7)
6 Protocol(7)
7 Protocol(7)
0 Protocol(8)
1 Protocol(8)
2 Protocol(8)
3 Protocol(8)
4 Protocol(8)
5 Protocol(8)
6 Protocol(8)
7 Protocol(8)
Protocol Register 9
Group1 Offset: 82
Group2 Offset: 114
Type:Write Only
Protocol Register 10
Group1 Offset: 83
Group2 Offset: 115
Type:Write Only
0 Protocol(9)
1 Protocol(9)
2 Protocol(9)
3 Protocol(9)
4 Protocol(9)
5 Protocol(9)
6 Protocol(9)
7 Protocol(9)
0 Protocol(10)
1 Protocol(10)
2 Protocol(10)
3 Protocol(10)
4 Protocol(10)
5 Protocol(10)
6 Protocol(10)
7 Protocol(10)
35

Protocol Register 11
Group1 Offset: 84
Group2 Offset: 116
Type:Write Only
Protocol Register 12
Group1 Offset: 85
Group2 Offset: 117
Type:Write Only
0 Protocol(11)
1 Protocol(11)
2 Protocol(11)
3 Protocol(11)
4 Protocol(11)
5 Protocol(11)
6 Protocol(11)
7 Protocol(11)
0 Protocol(12)
1 Protocol(12)
2 Protocol(12)
3 Protocol(12)
4 Protocol(12)
5 Protocol(12)
6 Protocol(12)
7 Protocol(12)
Protocol Register 13
Group1 Offset: 86
Group2 Offset: 118
Type:Write Only
Protocol Register 14 (16 bits)
Group1 Offset: 68­69
Group2 Offset: 100­101
Type:Write Only
0 Protocol(13)
1 Protocol(13)
2 Protocol(13)
3 Protocol(13)
4 Protocol(13)
5 Protocol(13)
6 Protocol(13)
7 Protocol(13)
0 Protocol(14)
1 Protocol(14)
2 Protocol(14)
3 Protocol(14)
4 Protocol(14)
5 Protocol(14)
6 Protocol(14)
7 Protocol(14)
36

Protocol Register 15
Group1 Offset: 79
Group2 Offset: 111
Type:Write Only
Transfer Count (32 bits)
Group1 Offset: 20
Group2 Offset: 24
Type:Write Only
0 StartSource
1 StartSource
2 InvertStart
3 StopSource
4 StopSource
5 Reserved
6 ReqSource
7 PreStart
0 TransferCount
1 TransferCount
2 TransferCount
3 TransferCount
4 TransferCount
5 TransferCount
6 TransferCount
7 TransferCount
Transfer Size Control
Group1 Offset: 77
Group2 Offset: 109
Type:Write Only
0 TransferWidth
1 TransferWidth
2 Reserved
3 TransferLength
4 TransferLength
5 RequireRLevel
6 Reserved
7 Reserved
37

15 Appendice C
15.1 Registri per la programmazione del protocollo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Protocol/
OpMode
ClockReg
Sequence
ReqReg
BlockMode
LinePolarities
AckSer
StartDelay
ReqDelay
ReqNotDelay
AckDelay
AckNotDelay
DataDelay
ClockSpeed
DAQ
Options
Protocol
Reg.
8255
Input
96
5
38
0
0
1
3
96
pd
x
2
2
1
2
1
1
0
0
Emulation
+1
8255
Output
0
0
38
0
0
1
3
96
pd
x
2
2
1
2
1
1
0
0
Emulation
+1
Level
Mode
0
non
1
7
0
0
1
1
inv
ACK
3
96
pd
x
2
3
pd
x
2
pd
x2
2
1
0
0
Input
64
latch
2
inv
REQ
3
+1
+1
+1
3
both
inv
3
Level
Mode
0
non
0
7
0
0
1
1
inv
ACK
3
96
pd
x
2
3
pd
x
2
pd
x2
2
1
0
0
Output
96
latch
2
inv
REQ
3
+1
+1
+1
3
both
inv
3
Leading
Edge
0
non
0
11
0
0
1
1
inv
ACK
3
96
pd
x
2
3
pd
x
2
pd
x2
3
1
0
0
Pulse
Mode
96
latch
2
inv
REQ
3
+1
+1
+1
Input
3
both
inv
3
Leading
Edge
0
non
1
7
0
0
1
1
inv
ACK
3
96
pd
x
2
3
pd
x
2
2
3
1
0
0
Pulse
Mode
64
latch
2
inv
REQ
3
+1
+2
Output
3
both
inv
3
Long
Pulse
0
non
1
7
0
0
1
1
inv
ACK
3
96
pd
x
2
3
pd
x
2
2
3
1
0
0
Mode
Input
64
latch
2
inv
REQ
3
+1
+2
3
both
inv
3
Long
Pulse
0
non
0
7
0
0
1
1
inv
ACK
3
96
pd
x
2
3
pd
x
2
2
3
1
0
0
Mode
Output
64
latch
2
inv
REQ
3
+1
+2
3
both
inv
3
Trailing
0
non
1
2
0
0
1
1
inv
ACK
3
96
pd
x
2
pd
x
2
3
2
pd
x
2
1
0
0
Edge
96
db
buf
2
inv
REQ
3
+1
+7
4
+7
4
Mode
Input
latch
3
both
inv
3
Trailing
0
non
0
2
0
0
1
1
inv
ACK
3
96
pd
x
2
pd
x
2
3
2
pd
x
2
1
0
0
Edge
96
db
2
inv
REQ
3
+1
+7
4
+7
4
Mode
Output
buf
2
3
both
inv
3
Burst
Mode
0
96
0
8
4
5
1
inv
ACK
3
96
1
1
1
1
1
1
pd
0
Input
2
inv
REQ
3
(drive
PCLK)
3
both
inv
3
Burst
Mode
0
16
0
32
4
5
1
inv
ACK
3
96
1
1
1
1
1
1
0
0
Output
2
inv
REQ
3
(receive
PCLK)
3
both
inv
3
1 Set to 0; if performing funneling, set to 24
2 Use the former value if you wish to disable REQ­edge latching (default mode for output). Usee the latter value if you wish to
enable REQ­edge latching (default mode for input).
3 Set to 0 for active­high ACK and REQ, 1 for active­low ACK, 2 for active­low REQ, or 3 for active­low ACK e REQ.
4 pd= programmable delay, from 0 to 7, in hundreds of ns.
5 Set to 4; if performing 8:16 funneling, set to 0.
38