====== 12. Dispozitive și drivere ======
===== Subiecte abordate =====
* Dispozitive văzute în user space
* Dispozitive virtuale
* Operații pe dispozitive
===== Resurse utile =====
* [[https://lwn.net/Kernel/LDD3/|Linux Device Drivers, 3rd Edition]] (free)
* [[https://lwn.net/images/pdf/LDD3/ch03.pdf|Linux Device Drivers, 3rd Edition, Chapter 3: Char Drivers]] (free, PDF)
* [[http://ocw.cs.pub.ro/courses/so2/laboratoare/lab04|SO2: Device drivere în Linux]]
* [[http://koala.cs.pub.ro/training/res/linux-kernel-dev/arc/cap-12-tasks.zip|Arhivă de suport]] (ZIP)
===== Arhivă de suport =====
Arhiva de suport pentru exerciții se găsește [[http://koala.cs.pub.ro/training/res/linux-kernel-dev/arc/cap-12-tasks.zip|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" >
unde '''' 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.