Penso che la soluzione più semplice sarebbe creare un dispositivo a caratteri nel driver del kernel, con le proprie operazioni sui file per un file virtuale. Quindi lo spazio utente può aprire questo dispositivo O_RDWR
. Devi implementare due operazioni principali sui file:
-
read
- questo è il modo in cui il kernel ritrasmette i dati allo spazio utente. Questa funzione viene eseguita nel contesto del thread dello spazio utente che chiamaread()
chiamata di sistema, e nel tuo caso dovrebbe bloccarsi fino a quando il kernel non ha un altro valore seme di cui ha bisogno di conoscere l'output. -
write
-- questo è il modo in cui lo spazio utente passa i dati nel kernel. Nel tuo caso, il kernel prenderebbe semplicemente la risposta alla lettura precedente e la passerebbe all'hardware.
Quindi ti ritroverai con un semplice ciclo nello spazio utente:
while (1) {
read(fd, buf, sizeof buf);
calculate_output(buf, output);
write(fd, output, sizeof output);
}
e nessun loop nel kernel:tutto viene eseguito nel contesto del processo dello spazio utente che sta guidando le cose e il driver del kernel è solo responsabile dello spostamento dei dati da/verso l'hardware.
A seconda di cosa sia il tuo "fare cose casuali qui" sul lato del kernel, potrebbe non essere possibile farlo in modo così semplice. Se hai davvero bisogno del loop del kernel, allora devi creare un thread del kernel per eseguire quel loop, e poi avere alcune variabili sulla falsariga di input_data
, input_ready
, output_data
e output_ready
, insieme a un paio di waitqueue e qualsiasi blocco di cui hai bisogno.
Quando il thread del kernel legge i dati, inserisci i dati in input_ready
e imposta il input_ready
contrassegna e segnala l'input waitqueue, quindi esegui wait_event(<output_ready is set>)
. Il read
l'operazione sul file farebbe un wait_event(<input_ready is set>)
e restituire i dati allo spazio utente quando diventa pronto. Allo stesso modo il write
l'operazione file metterebbe i dati che ottiene dallo spazio utente in output_data
e imposta output_ready
e segnala l'output waitqueue.
Un altro modo (più brutto, meno portabile) è usare qualcosa come ioperm
, iopl
o /dev/port
per fare tutto completamente nello spazio utente, incluso l'accesso hardware di basso livello.