Table of Contents

12. Dispozitive și drivere

Subiecte abordate

Resurse utile

Arhivă de suport

Arhiva de suport pentru exerciții se găsește aici. Descărcați arhiva și apoi decomprimați-o folosind comanda

unzip cap-12-tasks.zip

Demo-uri/Discuții

Parcurgere sysfs

Linux Device Model / Linux Device Tree

Major și minor, /dev, /proc/devices

Operații pe dispozitive: structura cdev, structura file_operations

Subsisteme de I/O: video4linux, mem drivers (zero, null, full, random, urandom, mem, kmem, port)

Exerciții

ioctl în dispozitiv de tip caracter

Comunicarea și interacțiunea dintre user space și kernel space se poate face prind dispozitive (devices). Acestea sunt vizibile utilizatorului ca intrări în sistemul de fișier (de obicei în /dev) pe care acesta le poate opera.

În directorul ioctl-print/ avem un modul de kernel care expunde dispozitivul /dev/print și care, la operații de tip ioctl (Input/Output Control) afișează un mesaj. Este un modul didactic, vrem să urmărim comportamentul ioctl.

Pentru a putea observa apelul ioctl() folosim și un modul de test rulabil din user space, care este compilat static în executabilul print_test.

Modulul de kernel se găsește în subdirectorul kernel/ în vreme ce testul de user space se găsește în subdirectorul user/.

Atât fișierul de test cât și fișierul modul se copiază pe mașina virtuală pentru a putea testa funcționalitatea respectivă: afișarea unui mesaj la apelul ioctl().

După ce modulul este inserat, trebuie creat dispozitivul /dev/print cu ajutorul comenzii

mknod /dev/print c 42 0

Apoi se poate rula executabilul de test cu opțiunea aferentă pentru a invoca funcționalitatea de tip ioctl:

./print_test p

Alocare și dezalocare la ioctl

Actualizați modulul anterior și adăugați două noi operații la ioctl, astfel încât la una dintre ele să aloce o zonă de memorie de 10KB și să rețină pointer-ul rezultat într-o variabilă globală, iar la cealaltă să-l elibereze.

Nu va aloca dacă a fost deja alocată zona de memorie, nu o va elibera dacă a fost deja eliberată.

Pentru a defini cele două noi operații, actualizați fișierul header include/util.h.

Implementarea noilor operații o veți face în cadrul blocului switch din funcția print_ioctl().

Citire din dispozitiv

Operațiile de tipul ioctl sunt operații de comandă/control. Pentru transfer de informație cel mai adesea follosim operații de tipul read și write. Pentru început să folosim operația read.

În directorul read-string/ din arhiva de suport a capitolului se găsește o implementare de modul care întoarce un șir predefinit (anaaremere) la orice operație de citire. Practic, oricând folosim comanda cat pe dispozitivul afernet (/dev/string) ne va afișa șirul predefinit.

Compilați modululul și apoi copiați-l pe mașina virtuală QEMU și testați această funcționalitate.

După ce modulul este inserat în kernel, va trebui să creați dispozitivul aferent. Pentru aceasta rulați, în mașina virtuală QEMU, comanda

mknod /dev/string c 43 0

Apoi, pentru a testa, folosiți comanda cat pe dispozitiv, pentru a citi șirul:

cat /dev/string

În modul vor fi, pentru fiecare apel al funcției string_read(), afișate niște mesaje legat de numărul de octeți care s-au dorit citiți și numărul de octeți care s-a citit. De câte ori a fost apelată funcția string_read()? Cum explicați mesajele afișate (în fapt ne interesează valorile de retur ale funcției)?

Generator de caractere de 1

Creați un modul de kernel care expune un dispozitiv /dev/one care la citire generează o infinnitate de caractere de 1. Se oprește doar când cere spațiul utilizator să se oprească. Este similar cu /dev/zero.

Reply device

Adăugați funcționalitatea de write modulului din directorul read-string/ astfel încât sa și permită scrierea de mesaje în dispozitiv. După ce un mesaj este scris, același mesaj este citit de operațiile de citire.

Pentru a scrie un mesaj într-un fișier, folosiți comanda:

echo "mesaj" > <fisier>

unde <fisier> este numele intrării în care vreți să scrieți, de exemplu /dev/string.

Length device

Actualizați modulul de mai sus astfel încât la citire să nu mai întoarcă șirul scris, ci un șir de cifre care să însemne lungimea șirului scris anterior.