Differences

This shows you the differences between two versions of the page.

Link to this comparison view

so2:laboratoare:lab12:exercitii [2017/05/15 17:32]
octavian.purdila [3. [2p] Atribute device drivere]
so2:laboratoare:lab12:exercitii [2019/05/20 14:32] (current)
razvan.deaconescu [1. [2p] Implementare bus]
Line 1: Line 1:
 ====== Laborator 12: Exerciții ====== ====== Laborator 12: Exerciții ======
  
-Pentru desfășurarea ​laboratorului ​pornim de la [[http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab12-tasks.zip|arhiva de sarcini a laboratorului]]. Descărcăm și decomprimăm arhiva în directorul ''​so2/''​ din directorul home al utilizatorului ''​student''​ de pe sistemul de bază (stația ''​mjolnir''​):<​code bash> +===== Pregătirea laboratorului ​=====
-student@mjolnir:​~$ cd so2/ +
-student@mjolnir:​~/​so2$ wget http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab12-tasks.zip +
-student@mjolnir:​~/​so2$ unzip lab12-tasks.zip +
-student@mjolnir:​~/​so2$ tree lab12-tasks +
-</​code>​ +
-În cadrul directorului ''​lab12-tasks/''​ se găsesc resursele necesare pentru dezvoltarea exercițiilor de mai jos: fișiere schelet de cod sursă, fișiere Makefile și Kbuild, scripturi și programe de test.+
  
-Vom dezvolta exercițiile pe sistemul de bază (stația ''​mjolnir''​) și apoi le vom testa pe [[:​so2:​resurse:​masini-virtuale|mașina virtuală QEMU]]. După editarea ​și compilarea unui modul de kernel îl vom copia în directorul dedicat pentru ​mașina virtuală ​QEMU folosind o comandă de forma<​code bash> +Pentru rezolvarea laboratorului, ​vom lucra în același director din care pornim ​mașina virtuală ​(''​~/so2/linux/tools/labs''​).
-student@mjolnir:​~/so2$ cp /path/to/module.ko ~/​so2/​qemu-so2/​fsimg/​root/​modules/​ +
-</​code>​ unde ''​/​path/​to/​module.ko''​ este calea către fișierul obiect aferent modulului de kernel. Apoi vom porni, din directorul ''​~/​so2/​qemu-so2/''​ mașina virtuală QEMU folosind comanda<​code bash> +
-student@mjolnir:​~/​so2/​qemu-so2$ make +
-</​code>​+
  
-După pornirea mașinii virtuale ​QEMU vom putea folosi comenzi în fereastra QEMU pentru a încărca ​și descărca modulul de kernel:<​code>​ +Pașii de rezolvare sunt următorii: 
-# insmod modules/​module-name.ko +  * pregătirea scheletului de laborator 
-# rmmod module/​module-name +  * compilarea modulelor de Kernel 
-</​code>​ unde ''​module-name''​ este numele modulului de kernel.+  * copierea modulelor pe mașina virtuală 
 +  * pornirea mașinii virtuale și testarea modulelor
  
-<​note>​ +==== Pregătirea scheletului ​de laborator ====
-Pentru dezvoltarea laboratorului,​ este recomandat să folosim trei terminale sau, mai bine, trei tab-uri ​de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''​Ctrl+Alt+t''​. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: +
-  - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtaulă QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. +
-  - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/​descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''​~/​so2/​qemu-so2/''​. +
-  - În al treilea tab de terminal pornim [[:​so2:​laboratoare:​lab02#​minicom|minicom]] sau un server UDP care să primească [[:​so2:​laboratoare:​lab02#​netconsole|mesajele de netconsole]]. Nu contează în ce director ne aflăm. Folosim comanda<​code bash> +
-student@mjolnir:​~$ netcat -lup 6666 +
-</​code>​ +
-</​note>​+
  
-===== [0.5p] Intro =====+Scheletul de laborator este generat din sursele din directorul ''​tools/​labs/​templates''​Putem genera scheletele pentru toate laboratoarele folosind următoarea comanda:
  
-<note warning+<code bash
-Bonus - 1 punct: Vă invităm să evaluați activitatea echipei de SO2 și să precizați punctele tari și punctele slabe și sugestiile voastre de îmbunătățire a materiei. Feedback-ul vostru este foarte important pentru noi să creștem calitatea materiei în anii următori și să îmbunătățim materiile pe care le veți face în continuare. +tools/labs $ make skels 
-Găsiți formularul de feedback în partea dreaptă a paginii principale de SO2 de pe cs.curs.pub.ro într-un frame numit “FEEDBACK” +</code>
-</note>+
  
-Vă mulțumim! +Pentru a genera scheletul pentru un singur laboratorvom folosi ​variabila ​de mediu ''​LABS''​:
-Găsiți definițiile următoarelor simboluri în nucleul Linux: +
-  * funcțiile ''​dev_name''​''​dev_set_name''​. +
-  * funcțiile ''​pnp_device_probe'',​ ''​pnp_bus_match'',​ ''​pnp_register_driver''​ și variabila ''​pnp_bus_type''​.+
  
-===== [1p] BONUS: Completare formular de feedback =====+<code bash> 
 +tools/labs $ make clean 
 +tools/labs $ LABS=<lab name> make skels 
 +</​code>​
  
-Apreciem opinia voastră legată de activitățile cursului de SO2Ne ajută să îmbunătățim cursul și să facem materia cât mai accesibilă și interesantă. Pentru această vă rugăm să completați [[http://​cs.curs.pub.ro/​2016/​blocks/​feedbackacs/​view.php?​courseid=150&​blockid=3269|formularul de feedback de pe cs.curs.pub.ro]] (trebuie să fiți autentificați și înrolați în cadrul cursului). Vă mulțumim! +<note important>​ 
-===== [6.5p] Linux Device Model =====+Numele laboratorului curent este ''​device_model''​. 
 +</note>
  
-În prima parte ne propunem să ne familiarizăm cu modelul ''​Linux Device Model'' ​și reflectarea acestuia în userspace prin intermediul sistemului virtual de fișiere ''​sysfs''​. Vom analiza implementarea magistralelor și modul în care device driverele se conectează la o magistrală. Pentru început, vom lucra cu o magistrală virtualădefinită în modulul ​''​mybus.ko''​ din subdirectorul ''​virtual_bus/​mybus/'' ​la care vom atașa driverul ​''​mydriver.ko''​ din subdirectorul ''​virtual_bus/​mydriver''​.+Similar, putem genera ​și scheletul pentru un singur exercițiuatribuind valoarea ​''​<​lab_name>​/<​task_name>​'' ​variabilei ​''​LABS''​.
  
-<​note ​tip+<​note>​ 
-În rezolvarea acestui exerciţiu vă veţi întâlni cu:  +Scheletul este generat în directorul ​''​tools/​labs/​skels''​.
-  * ''​my_bus_type''​(mybus.c):​ variabilă globală pentru tipul de magistrală +
-  * ''​my_bus_device''​(mybus.c):​ variabilă globală pentru dispozitivul magistralei +
-  * ''​my_device''​(virtual_bus.h):​ structură folosită pentru dispozitivele ce se conectează la magistrală +
-  * ''​my_driver''​(virtual_bus.h):​ structură folosită pentru driverul care lucrează cu dispozitivele ce se conectează la magistrală +
-  * ''​dev_data''​(mydriver.c): variabilă globală ce menţine datele necesare driverului+
 </​note>​ </​note>​
-==== 1. [1p] Implementare magistrală ==== 
  
-Intrați în directorul ''​virtual_bus/​mybus'',​ unde găsiți implementarea unei magistrale ''​mybus'',​ așa cum este descrisă în laborator. Analizați conținutul fișierelor ''​mybus/​mybus.c''​ și ''​include/​virtual_bus.h''​. +==== Compilarea modulelor ====
-Observaţi că la încărcarea modulului se înregistrează atât o structură [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L109|bus_type]],​ reprezentând tipul de magistrală,​ cât și o structură [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L782|device]],​ reprezentând dispozitivul efectiv al magistralei. ​+
  
-Compilați și inserați modulul. +Comanda ''​make build''​ compilează toate modulele ​din directorul ''​skels''​.
-Verificaţi că tipul de magistrală apare în /sys/bus, iar dispozitivul în /​sys/​devices. +
-Scoateți modulul şi observaţi că intrările ​din sysfs sunt înlăturate.+
  
-Modificați sursa astfel încât intrările pentru magistrală și dispozitivul asociat să fie ''​virtualbus'',​ respectiv ''​virtualbus0''​. +<code bash
- +student@eg106:~/so2/linux/tools/labs$ make build 
-<note tip+echo "autogenerated,​ do not edit " > skels/Kbuild 
-Recitiți secțiunile [[:so2:​laboratoare:​lab12#​magistrale|Magistrale]] și [[:​so2:​laboratoare:​lab12#​dispozitive|Dispozitive]] din laborator. +echo "​ccflags-y += -Wno-unused-function -Wno-unused-label -Wno-unused-variable " >> skels/Kbuild 
-</note> +for i in ./device_model;​ do echo "obj-m += $i/" >> skels/Kbuild; done 
- +...
-Pentru verificare trebuie să se fi creat pe mașina virtuală în ''​/sys''​ intrările aferente magistralei (''​virtualbus''​) și dispozitivului părinte (''​virtualbus0''​):<​code>​ +
-ls /sys/​bus/​virtualbus+
-# ls /sys/devices/​virtualbus0/+
 </​code>​ </​code>​
  
-==== 2. [2p] Conectare driver la magistrală ====+==== Copierea modulelor pe mașina virtuală ====
  
-Intrați în directorul ​''​virtual_bus/​mydriver'', ​unde găsiți implementarea unui device driver de tip caracter.+Putem copia modulele generate pe mașina virtuală folosind target-ul ​''​copy'' ​al comenzii makeatunci când mașina virtuală este oprită.
  
-Modificați sursa astfel încât să respecte modelul ''​Linux Device Model''​. Dispozitivul ''​echo''​ se va conecta la magistrala virtualbus de la exercițiul anterior, având un driver asociat ''​echo''​. Numele driverului și al dispozitivului trebuie să fie identice.+<code bash> 
 +student@eg106:​~/​so2/​linux/​tools/​labs$ make copy 
 +student@eg106:​~/​so2/​linux/​tools/​labs$ make boot 
 +</​code>​
  
-Urmăriți comentariile ​''​TODO 2'' ​din cod și exemplele de înregistrare dispozitiv/​driver din laborator: ​[[:so2:​laboratoare:​lab12#dispozitive|înregistrare dispozitiv]],​ [[:​so2:​laboratoare:​lab12#​drivere|înregistrare driver]].+Alternativ, putem copia fișierele prin ''​scp''​, pentru e evita repornirea mașinii virtuale. Pentru detalii despre folosirea interacțiunea prin rețea cu mașina virtuală citiți [[https://​ocw.cs.pub.ro/​courses/​so2/​resurse/​masini-virtuale#interactiunea_cu_masina_virtuala|Interacțiunea cu mașina virtuală]].
  
-Pentru a vă conecta la magistrala ''​virtualbus'',​ va trebui să folosiți funcțiile și tipurile de driver/​device exportate de aceasta.+==== Testarea modulelor ====
  
-În structura ''​struct my_device_data''​ adăugați un câmp de tipul ''​struct my_device''​ (tip de date definit ​în ''​include/virtual_bus.h''​). Câmpurile structurii ''​my_device''​ vor fi inițializate în funcția ''​my_init''​.+Modulele generate sunt copiate pe mașina virtuală în directorul ​''/​home/​root/​skels/<​lab_name>​''​.
  
-Definiți o variabilă de tipul ''​struct my_driver''​ şi inițializați pentru aceasta modulul şi numele driver-uluiÎnregistraţi driverul în funcţia ''​my_init''​.+<code bash> 
 +root@qemux86:​~/​skels/​device_model#​ ls 
 +bex.ko       ​bex_misc.ko 
 +</​code>​
  
-<note tip+După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU (sau în ''​minicom''​) pentru a încărca și descărca modulul de kernel:<code
-Parcurgeți secțiunea [[:so2:​laboratoare:​lab12#drivere|Drivere]] din laboratorUrmăriți exemplele de cod+root@qemux86:~insmod skels/<​lab_name>/<​task_name>/<​module_name>​.ko 
-</note>+root@qemux86:​~#​ rmmod skels/<​lab_name>/<​task_name>/<​module_name>​.ko 
 +</code>
  
-<​note ​tip+<​note>​ 
-Trebuie ​să înregistrați / deînregistrați variabilele ​de tipul ''​struct my_device''​ și ''​struct my_driver'' ​în funcția ​de init / exit modululuiPentru aceasta folosițfuncțiile ''​my_register_driver'' ​''​my_unregister_driver''​respectiv ''​my_register_device''​ / ''​my_unregister_device''​, definite în fișierul ''​mybus.c''​. +Pentru dezvoltarea laboratorului,​ este recomandat ​să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''​Ctrl+Shift+t''​. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: 
-</note>+  - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtuală QEMU. Lucrăm ​în directorul aferent rezultat în urma decomprimării arhivei ​de sarcini ​laboratorului. 
 +  - În al doilea tab de terminal pornim mașina virtuală QEMU șapoi testăm modulul de kernel: încărcare/descărcare modulrulare teste. Lucrăm în directorul aferent mașinii virtuale: ​''​~/so2/​linux/​tools/​labs''​
 +  - În al treilea tab de terminal accesăm directorul ​''​~/​so2/​linux/​'' ​cu sursele nucleului unde putem folosi [[:​so2:​laboratoare:​lab01#​cscope|Vim și cscope]] pentru parcurgerea codului sursă.<​code>​ 
 +student@eg106-pc:​~$ netcat -lup 6666 
 +</code>
  
-<note tip> 
-Pentru a transmite primul argument (magistrala) funcției ''​bus_find_device''​ folosiți o expresie de forma ''​mydriver.driver.bus''​. 
 </​note>​ </​note>​
  
-În cadrul funcţiei ''​my_init'',​ iniţializaţi dispozitivul şi înregistraţi-l. Vor trebui completate cel puțin câmpurile ''​name''​ și ''​driver''​.+===== Exerciții =====
  
-De asemeneaputeți stoca un back pointer către ''​struct my_device_data''​ în câmpul ​''​%%dev->p->​driver_data%%''​. Acest câmp e util pentru a putea accesa datele private (''​my_device_data''​) ale dispozitivului și din locurile în care aveți acces doar la structura generică [[http://​elixir.free-electrons.com/linux/​v4.9/​source/​include/​linux/​device.h#​L782|struct device]]. Fiind un câmp din [[http://​elixir.free-electrons.com/​linux/​v3.13/​source/​drivers/​base/​base.h#​L73|datele private]] ale dispozitivului, pentru a accesa ''​%%dev->​p->​driver_data%%''​ e recomandat să folosiți funcțiile (interfața) [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L920|dev_set_drvdata]],​ [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L915|dev_get_drvdata]]. +<note important>​ 
- +Înainte de începerea rezolvării laboratoruluirulați comanda ​''​%%git pull --rebase%%'' ​in directorul ​''​~/so2/linux''​, pentru a obține ultima versiune ​scheletului de laborator.
-<note tip> +
-Parcurgeți secțiunea [[:​so2:​laboratoare:​lab12#​dispozitive|Dispozitive]] din laborator. Urmăriți exemplele de cod.+
 </​note>​ </​note>​
  
-Compilaţi modulul şi copiaţi-l pe maşina virtuală, împreună cu modulul de la exerciţiul anterior.+===== [0.5p] Intro =====
  
 <note warning> <note warning>
-Pentru a elimina warning-urile legate de nedefinirea funcțiilor de înregistrare/​deînregistrare ​de dispozitiv, compilați ambele module din directorul părinteAveți în vedere să inserați modulul ​de la pasul anterior (''​mybus.ko''​) înaintea inserării modulului curent.+Bonus 1 punct: Vă invităm să evaluați activitatea echipei ​de SO2 și să precizați punctele tari și punctele slabe și sugestiile voastre de îmbunătățire a materieiFeedback-ul vostru este foarte important pentru noi să creștem calitatea materiei în anii următori și să îmbunătățim materiile pe care le veți face în continuare. 
 +Găsiți formularul ​de feedback în partea dreaptă a paginii principale de SO2 de pe cs.curs.pub.ro într-un frame numit “FEEDBACK”
 </​note>​ </​note>​
  
-Pentru testare urmăriți intrările de dispozitiv (''​echo''​) și de driver (''​echo''​) în ''​/sys'' ​pe mașina virtuală:​ +Vă mulțumim! 
-<​code>​ +Găsiți definițiile următoarelor simboluri în nucleul Linux: 
-# ls /​sys/​bus/​virtualbus/​devices/​ +  * funcțiile ​''​dev_name''​''​dev_set_name''​
-# ls /​sys/​bus/​virtualbus/​drivers/​ +  * funcțiile ​''​pnp_device_probe'',​ ''​pnp_bus_match'',​ ''​pnp_register_driver''​ și variabila ''​pnp_bus_type''​.
-# ls /​sys/​devices/​virtualbus0/​ +
-</​code>​+
  
-==== 2.1. [1.5p] Informații device-uri ​de pe magistrală ​====+===== Completare formular ​de feedback =====
  
-La sfârșitul inițilizării modulului ''​mydriver''​ (TODO 2.1), verificați dacă device-ul a fost atașat la magistrală. Pornind ​de la magistrala asociată, parcurgeți device-urile atașate și căutați-l pe cel cu numele ''​echo''​Afișați numele device-ului,​ dacă acesta a fost găsit.+Apreciem opinia voastră legată de activitățile cursului ​de SO2. Ne ajută să îmbunătățim cursul ​și să facem materia cât mai accesibilă ​și interesantă. Pentru această vă rugăm să completați [[https://​acs.curs.pub.ro/​2018/​course/​view.php?​id=295|formularul de feedback de pe cs.curs.pub.ro]] (trebuie să fiți autentificați ​și înrolați în cadrul cursului)Vă mulțumim!
  
-<note tip> +==== 1. [2p] Implementare ​bus ====
-Pentru căutarea unui dispozitiv folosiți funcția ​[[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​drivers/​base/​bus.c#​L371|bus_find_device_by_name]]. Transmiteți ''​NULL''​ ca al doilea argument al funcției.+
  
-Obțineți structura ​de tip magistrală ​(''​struct bus_type''​) printr-o construcție de forma ''​my_driver.driver.bus''​.+Analizați conținutul fișierului ''​bex.c'',​ care conține implementarea unui driver ​de magistrală. Urmăriți comentariile marcate cu ''​TODO 1'' ​pentru a implementa părțile ce lipsesc: înregistrați driverul ​de magistrală și adăugați un nou device, numit ''​root'',​ cu tipul ''​none''​ și versiunea ''​1''​.
  
-Numele device-ului întors de funcția [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​drivers/​base/​bus.c#​L371|bus_find_device_by_name]] se poate obține cu funcția [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L868|dev_name]].+<note tip> 
 +Aruncați o privire pe implementarea ​funcției ''​bex_add_dev()''​.
 </​note>​ </​note>​
  
-Pentru verificare la inserarea modulului se va afișa mesaj cu numele dispozitivului.+<note tip> 
 +Înregistrarea ​și deînregistrarea o faceți folosind respectiv funcțiile ''​bus_register()''​ și ''​bus_unregister()''​. 
 +</​note>​
  
-==== 3[2p] Atribute device drivere ====+Compilați, copiați modulul pe mașina virtuală, încărcați-l în kernel și verificați faptul că dispozitivul de tip magistrală este vizibil în ''/​sys/​bus''​. De asemenea, verificați că dispozitivul este vizibil în ''/​sys/​bus/​bex/​devices.''​.
  
-Extindeți driverul echo de la exercițiul anterior prin adăugarea unui atribut ''​myattr''​ pentru dispozitivul creat, ce va conține majorul și minorul dispozitivului (''​major:​minor''​). Acest atribut va fi expus prin interfaţa ​''​sysfs'' ​din directorul device-ului ''​echo''​.+Eliminați modulul și observați că intrările din ''​sysfs'' ​sunt eliminate.
  
-Urmăriți comentariile ''​TODO ​3'' ​din cod.+==== 2. [2p] Adăugare atribute pentru tip și versiune ==== 
 + 
 +Adăugați două atribute read-only: ''​type''​ și ''​version''​. ​Urmăriți comentariile ​marcate cu ''​TODO ​2''​.
  
 <note tip> <note tip>
-Va trebui să declarați și să înregistrați o structură [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L549| device_attribute]]. Puteți folosi macro-ul [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L575|DEVICE_ATTR]] ce va crea o structură cu numele ​''​dev_attr_##​_name''​, unde ''​##_name'' ​este numele atributului. +Va trebui să adăugați cele două atribute ​''​type'' ​și ''​version''​ în structura ​''​bex_dev_attrs'' ​pe modelul: 
-Pentru folosirea macro-ului va trebui să specificaţi, ​în această ordine: +<​code>​ 
-  * numele atributului +&​dev_attr_<​insert-attribute-type-here>​.attr, 
-  * permisiunile la acces la intrarea din sysfs aferentă atributului;​ folosiţi valoarea ​''​0444''​. +</code> 
-  * o funcție [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L551|show]] ce afișează valoarea atributului pornind de la informațiile din [[http://​elixir.free-electrons.com/linux/​v4.9/​source/​include/​linux/​device.h#​L782|struct device]]. +</note>
-  * o funcţie [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L553|store]],​ care în cazul vostru poate fi ''​NULL''​.+
  
-În funcţia [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L303|show]],​ puteți folosi macrodefinițiile [[http://elixir.free-electrons.com/linux/v4.9/source/​include/​linux/​kdev_t.h#​L9|MAJOR]] și [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​kdev_t.h#​L9|MINOR]] pentru aflarea majorului și minorului. Aceste funcții primesc ca argument câmpul ''​dev''​ al structurii ''​struct cdev''​. ​Câmpul de tipul ''​struct cdev''​ îl găsiți în structura de tipul ''​struct my_device_data''​. Pentru a obține structura de tipul ''​struct my_device_data'',​ atunci când știți adresa unei variabile de tipul ''​struct device'',​ puteți folosi funcția [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L915|dev_get_drvdata]].+Observați că cele două atribute noi sunt vizibile în ''​/sys/bus/bex/devices/root''​. ​Verificați conținutul acestor atribute.
  
-Țineți cont să adăugați/​eliminați atributul la inițializarea/​dezactivarea modulului cu ajutorul ​funcțiilor [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​drivers/​base/​core.c#​L587|device_create_file]],​ [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​drivers/​base/​core.c#​L611|device_remove_file]].+O implementare pentru ​funcția de afișare de type este
  
-Parcurgeți secțiunile [[:​so2:​laboratoare:​lab12#​magistrale|Magistrale]] și [[:​so2:​laboratoare:​lab12#​dispozitive|Dispozitive]] din laborator. +<code c> 
-</note>+static ssize_t 
 +type_show(struct device *dev, struct device_attribute *attr, char *buf) 
 +
 + struct bex_device *bex_dev = to_bex_device(dev);​
  
-Pentru testare rulați comanda: + return sprintf(buf,​ "​%s\n",​ bex_dev->type); 
-<code+} 
-# cat /​sys/​devices/​virtualbus0/​echo/​myattr+DEVICE_ATTR_RO(type);​
 </​code>​ </​code>​
-Această comanda va conduce la rularea funcției ''​my_show''​. +==== 3. [2p] Adăugare atribute del și add ====
- +
-===== [4p] Plug and Play ===== +
- +
-==== 4. [2p] Conectarea la magistrala PNP ====+
  
-Intrați în directorul ​''​parallel''​, unde găsiți implementarea unui driver simplu pentru portul paralel. +Adăugați două atribute write-only, numite ​''​del''​ ș''​add''​. ''​del'' ​așteaptă un nume de device pentru a îl elimina, iar ''​add'' ​așteaptă numele, tipul și versiunea pentru a crea un device nouUrmăriți comentariile marcate cu ''​TODO 3''​.
-Analizați conținutul fișierului ​''​parallel.c''​. ​Modificați sursa astfel încât să respecte modelul ​''​Linux Device Model''​ ș''​plug and play''​. ​Dispozitivul se va conecta la magistrala ​''​PNP''​.+
  
 <note tip> <note tip>
-Înregistrați/​deînregistrați structura ​[[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​pnp.h#​L380|pnp_driver]] la încărcarea/​descărcarea modulului cu ajutorul funcțiilor [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​drivers/​pnp/​driver.c#​L266|pnp_register_driver]]respectiv [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​drivers/​pnp/​driver.c#​L274|pnp_unregister_driver]].+Va trebui să adăugați atributele ''​del''​ ș''​add''​ în structura ​''​bex_bus_attr''​ pe modelul: 
 +<​code>​ 
 +&​bus_attr_<​insert-attribute-name-here>​.attr, 
 +</code>
  
-Pentru a fi un driver ''​plug and play'',​ inițializarea dispozitivelor trebuie făcută în momentul în care acestea apar în sistem (la execuția funcției ''​parallel_pnp_probe''​),​ iar deînregistrarea în momentul în care dispar din sistem (la execuția funcției ''​parallel_pnp_remove''​). 
- 
-Recitiți secțiunile [[:​so2:​laboratoare:​lab12#​magistrala_pnp|Magistrala PNP]] și [[:​so2:​laboratoare:​lab12#​operatii_pnp|Operații plug and play]] din laborator. 
 </​note>​ </​note>​
  
 <note tip> <note tip>
-Pentru înregistrarea și deînregistrarea unui dispozitiv folosiți funcțiile ​''​register_parallel_dev'' ​respectiv ​''​unregister_parallel_dev'' ​definite în cadrul scheletului de cod de laborator.+Folosiți ''​sscanf'' ​pentru a parsa inputul de la ''​sysfs'' ​și ''​bex_del_dev()''​ and ''​bex_add_dev()''​ pentru a șterge și crea un device nou.
 </​note>​ </​note>​
  
-Pentru verificare, urmăriți conținutul din directorul aferent din sysfs: +Un exemplu de funcție de tipul ''​store''​ este:
-<​code>​ +
-# ls /​sys/​bus/​pnp/​drivers/​parallel +
-</​code>​+
  
-==== 5. [2pClase ====+<code c> 
 +static ssize_t 
 +add_store(struct bus_type *bt, const char *buf, size_t count) 
 +
 + char type[32], name[32]; 
 + int version; 
 + int ret;
  
-Pornind de la modulul anterioradăugați informațiile pentru o nouă clasă ''​parclass''​de care aparține modulul ''​paralel''​.+ ret = sscanf(buf"%31s %31s %d"name, type, &​version);​ 
 + if (ret != 3) 
 + return -EINVAL;
  
-<note tip> + return bex_add_dev(name,​ type, version) ? : count; 
-Definiți o structură [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L388|class]] și o structură [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L782|device]].+
 +BUS_ATTR(add,​ S_IWUSR, NULL, add_store);​ 
 +</code>
  
-Structura [[http://elixir.free-electrons.com/linux/v4.9/​source/​include/​linux/​device.h#​L388|class]] trebuie inițializată odată cu resursele driver-ului (la execuția funcției ''​parallel_init''​) șeliminată la ieșirea driverului (''​parallel_exit''​). Va trebui să folosiţi funcţiile [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L424|class_register]] şi [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​drivers/​base/​class.c#​L212|class_unregister]].+Creați un device nou și verificați dacă este vizibil în ''​/sys/bus/bex/devices''​Eliminați-l și verificați că a dispărut din ''​sysfs''​.
  
-În plus, pentru fiecare dispozitiv trebuie inițializată o structură [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L782|device]] șînregistrată cu [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​drivers/​base/​core.c#​L1798|device_create]] (la execuția funcției ​''​parallel_pnp_probe''​). La apelul funcţiei [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​drivers/​base/​core.c#​L1798|device_create]],​ folosiți ​pentru ​al patrulea parametru construcția ''​%%&​dev->​dev%%''​. Este câmpul de tipul [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​device.h#​L782|struct device]] al structurii [[http://​elixir.free-electrons.com/​linux/​v4.9/​source/​include/​linux/​pnp.h#​L244|struct pnp_dev]].+<note tip> 
 +Folosiți ''​echo''​ pentru ​a scrie în atributele magistralei:
  
-La înlăturarea dispozitivului (în funcţia ''​parallel_pnp_remove''​) folosiți funcția [[http://elixir.free-electrons.com/linux/v4.9/source/drivers/base/core.c#​L1870|device_destroy]].+<​code>​ 
 +$ echo "name type 1" > /sys/bus/bex/add 
 +$ echo "​name"​ > /sys/bus/bex/del 
 +</​code>​ 
 +</​note>​
  
-Recitiți secțiunea ​[[:​so2:​laboratoare:​lab12#​clase|Clase]] din laborator.+==== 4. [2pÎnregistrarea driver-ului bex misc ====
  
 +Modificați fișierul ''​bex-misc.c''​ pentru a înregistra driver-ul la magistrala ''​bex''​. ​
 +Inserați modulul bex_misc.ko și creați un nou device de tip ''​bex''​ din ''​sysfs'',​ cu numele //Test//, tipul //misc// și versiunea //2//. Urmăriți comentariile marcate cu ''​TODO 4''​.
  
 +Verificați dacă noul driver este vizibil în ''/​sys/​bus/​bex/​drivers''​.
 +De ce nu este apelată funcția ''​probe''?​
 +
 +<note tip>
 +Observați faptul că funcția de ''​match''​ pentru magistrală nu este implementată în ''​bex.c''​.
 </​note>​ </​note>​
  
-Pentru verificare, urmăriți ​conținutul directorului aferent ​din sysfs:<​code>​ +Implementați funcția pentru match în fișierul ''​bex.c''​. Urmăriți ​comentariile marcate cu ''​TODO 5''​. 
-# ls /​sys/​class/​parclass/​ +Încercațdin nou adăugarea unui dispozitiv de tip ''​bex''​ și observați că de data aceasta funcția de ''​probe''​ este apelată.
-</​code>​ +
-===== Extra ===== +
-== (+3 karma) USB Hotplug ==+
  
-În subdirectorul ''​usb_extra''​ găsiți o implementare minimală a unui driver USBAnalizați sursa ''​usb.c''​ și observați implementarea mecanismului de ''​Hotplug''​ si conectarea la magistrala ''​USB''​. Observați asemănările cu interfața dintre magistralei ''​PNP''​ studiată ​în laborator și driverele asociate: ''​struct usb_driver''​ / ''​struct pnp_driver'',​ implementarea ​funcției ''​probe''​ (''​skel_probe''​),​ tabela ''​skel_table''​ cu care se inițializează câmpul ''​id_table''​ pentru a identifica device-urile compatibile,​ etc.+==== 5[1.5p] Înregistrarea unui device bex misc în funcția probe ====
  
-Conectați un device USB pe mașina fizicăApelaț''​dmesg'' ​sau ''​lsusb'' ​pentru a identifica vendorId-ul șproductId-ul ​device-ul ​atașat+Modificați ''​bex_misc.c''​ astfel încât operația ''​probe'' ​să eșueze dacă ''​version > 1''​. Înregistrați device-ul ​misc în funcția ''​bex_misc_probe()'' ​și deînregistrați-l în ''​bex_misc_remove''​. Urmăriți comentariile marcate cu ''​TODO 6''​.
  
-<code bash+<note tip
-usb 3-2: New USB device found, idVendor=1e3d,​ idProduct=6025 +Folosiți ''​misc_register()''​ and ''​misc_deregister()''​. 
-</code>+</note>
  
-Modificați codul din ''​usb.c''​ pentru a crea un driver compatibil cu device-ul vostru. Compilațmodulul ​și inserați-l pe mașina fizică (sau pe o mașină virtuală cu udev și acces la USB-ul gazdei)Reconectați device-ul USB. Ce observați la rularea comenzii dmesg?+Creați un device ​nou cu numele //test//, tipul //misc// șversiunea //2// și verificați că operația ''​probe''​ eșuează. 
 +Creați un nou device ​cu numele //test//, tipul //misc// și versiunea //1// și verificați că operația se termină cu succes.
  
-Cel mai probabil device-ul va fi preluat de alt driver usb din sistem (e.x. usb_storage). În acest caz, puteți descărca temporar modulul concurent (rmmod usb_storage). Dacă device-ul ​se conectează la driverului ​''​usb.ko'', ​puteți observa mesajul "USB Skeleton ​device ​now attached to USBSkel-0"​mesaj afișat de funcția ​''​skel_probe''​. ​  ​+Verificați conținutul ​fișierului ''/​sys/​bus/​bex/​devices/​test''​ și observați că există o nouă intrare. Identificați majorul și minorul pentru ​device-ul ''​misc'', ​creați un device ​node de tip caracter pentru acest dispozitiv (''​Hint'':​ mknod) și încercați operații de citire și scriere pe fișierul creatpentru a accesa buffer-ul dispozitivului. 
 + 
 +<note tip> 
 +Indicatorii ''​major'' ​și ''​minor''​ sunt vizibili în atributul ''​dev''​ al dispozitivului ​de tip ''​misc''​. 
 +</​note>​
  
-Descărcați modulul. Creați o regulă ​''​udev'',​ care la identificarea dispozitivului (după ''​ATTRS{idVendor}''​ și ''​ATTRS{idProduct}''​), să încarce driverul ​''​usb.ko''​. Recitiți secțiunea [[:​so2:​laboratoare:​lab12#​hotplug | Hotplug]] din laborator. Cu modulul descărcat, reconectați device-ul USB. Ce observați la rularea comenzilor ''​dmesg'' ​și ''​lsmod''?​+==== 6. [1p] Monitorizarea notificărilor uevent ==== 
 +Folosiți comanda ​''​udevadm''​ și observați ce se întâmplă când: 
 +  * modulele ​''​bex.ko'' ​and ''​bex_misc.ko'' ​sunt inserate 
 +  * un nou device cu tipul //test// este creat 
 +  * un nou device cu tipul //misc// șversiunea //2// este creat 
 +  * un nou device ​cu tipul //​misc// ​și versiunea //1// este creat 
 +  * toate de mai sus sunt eliminate
  
-===== Soluții ===== 
  
-  * [[http://​elf.cs.pub.ro/​so2/​res/​laboratoare/​lab12-sol.zip|Soluții exerciții laborator 12]] 
so2/laboratoare/lab12/exercitii.1494858747.txt.gz · Last modified: 2017/05/15 17:32 by octavian.purdila
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0