====== 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.