DOC

Vjeba 9 Linux Device Drivers

By Connie Armstrong,2014-08-11 02:09
10 views 0
Vjeba 9 Linux Device Drivers

    Fakultet elektrotehnike i računarstva Sveučilišta u Zagrebu

    Zavod za elektroničke sustave i obradbu informacija

    Laboratorij za sustave i signale

    Programska podrška mjernih i procesnih sustava

    vjeţba br. 9: I/O SYSTEM

UVOD

    Pisanje device drivera je u uskoj vezi sa samom jezgrom operacijskog sustava. Zato je potrebno dobro poznavanje jezgre za uspješno implementiranje device drivera. Ovdje ćemo se zadrţati samo na najosnovnijim konceptima kako bi se dobio osjećaj što je device driver i koja

    je njegova funkcija.

    Ukratko driver je dio jezgre koji je zaduţen za komuniciranje sa ureĎajem koji je spojen na računalo. Većina ureĎaja je korisniku predstavljena preko datoteke i čitanjem odnosno pisanjem u datoteku pristupa ureĎaju.

Postoji nekoliko vrsti ureĎaja:

    ; Chracter devices

     Primjer su serijski i paralelni port. Nad njima se najčešće obavljaju funkcije poput read(), write(), open(), close(). Obiljeţja su da se komunikacija sa njima vodi

    na obično slanje nekoliko byte-ova. Moţe se usporediti sa stream-om.

    ; Block devices

     Tipičan predstavnik je hard disk. Za njih je specifično da mogu na sebi sadrţavati cijeli datotečni sustav. To omogućava izvršenje naredbe mount nad njima. TakoĎer moguće se je

    micati po block device-u te zapisivati podatke gdje hoćemo.

    ; Network interface

     Svi prijenosi preko mreţe se obavljaju preko mreţnog sučelja. Tu se vodi računa o primanju i slanju paketa i sl. Primjer toga je mreţna kartica. Takav device se ne vidi kao datoteka.

    Kada korisnik u svom programu počne čitati i pisati po datoteci koja zapravo predstavlja ureĎaj tada jezgra OS-a taj zahtijev proslijedi driver-u koji zna kako razgovarati sa ureĎajem.

U ovoj vjeţbi mi ćemo se primarno baviti char. ureĎajima jer su oni jednostavniji za koristiti.

Ovu vjeţbu je moguće napraviti u potpunosti samo na računalima tipa siemens/nixdorf.

    Na njima je na samom početku potrebno bootati noviju inačicu kernela 2.4.x a ne defaultnu 2.2.x. Prekid defaultnog boota se postiţe pritiskom tipke shift kad se na ekranu ukaţe LILO. Tipkom tab se vidi koje se mogućnosti mogu odabrati. Treba odabrati Linux jer je LinuxOLD defaultni odabir.

    Naziv datoteke: 70147336.doc Zagreb, 11.8.2010. List 1 od 5

    Ovaj dokument predstavlja intelektualno vlasništvo FER, ZESOI, LSS.

ZADACI ZA VJEŢBU

1. KORISNO JE ZNATI (10%)

KONFIGURIRANJE KERNELA

Konfiguriranje se moţe postići tako da pokrenemo naredbu:

    cd /usr/src/linux/

    make menuconfig

    Time smo editirali /usr/src/Linux/.config datoteku gdje je definirano koje sve ureĎaje, procesore, datotečne sustave jezgra podrţava. Neki driver-i se mogu direktno uključiti u kod

    samog kernela dok se drugi mogu uključiti kao moduli tj. njihovo uključivanje i isključivanje se

    moţe dinamički obaviti nakon sto je jezgra već formirana. Nakon što se pokrene make

    menuconfig, odreĎenu podršku moţemo tipkom y uključiti u jezgru odnosno tipkom m

    uključiti kao modul, ako je ta opcija omogućena.

    Probajte mijenjati neke postavke da vidite što sve jezgra moţe podrţati ali postavke nemojte sačuvati.

    Kada smo podesili postavke moţemo samu jezgru i prevesti u izvršni kod. MeĎutim to se ne preporuča da se radi na ovoj vjeţbi jer prevoĎenje traje preko 1 sat na starim računalima.

2. HELLO WORLD PRIMJER ZA DRIVER (10%)

Kao prvi primjer drivera ćemo napisati sljedeći kod

     #define MODULE

     #include <linux/module.h>

     int init_module(void) {

    printk("<1>Pozdrav svima, koliko vas ima\n");

    return 0;

    }

     void cleanup_module(void) {

    printk("<1>Dovidenja") // <1> daje visoki prioritet

    }

    MODULE_LICENSE("GPL");

printk() funkcija je ekvivalentna printf() funkciji samo je printk() definirana unutar

    kernela. Postoji bitna razlika izmeĎu programa koji izvršavaju funkciju driver-a i programa

    (aplikacije) koji je napisao korisnik i izvršava se u normalnom načinu rada (user space). Dva

    su prostora u kojima se izvršava proces. Moţe biti user space ili kernel space. Aplikacija se

    izvršava u user space-u i ona koristi biblioteke koje su joj tamo namijenjene (npr. libc). U kernel space-u se izvršavaju funkcije driver-a i koristi se biblioteka od kernela. TakoĎer jedina zaglavlja koja se koriste su definirana u /usr/include/linux i /usr/include/asm.

    Naziv datoteke: 70147336.doc Zagreb, 11.8.2010. List 2 od 5

    Ovaj dokument predstavlja intelektualno vlasništvo FER, ZESOI, LSS.

Zato je glavni posao drivera da podatke prebacuje iz kernel space-a u user space i obratno

    odakle je startana aplikacija koja je traţila podatke sa ureĎaja.

Gornji primjer drivera je zamišljen da bude implementiran kao modul. On se uključuje u jezgru

    naredbom insmod. Dakle potrebno je učiniti sljedeće:

# gcc -c hello.c

Ovdje opcija -c znači da se samo kompajlira bez linkanja tako da je rezultat hello.o

# insmod hello.o

Da vidimo da je modul doista učitan mozemo se posluţiti lsmod naredbom.

    Kad ga hocemo maknuti potrebno je otipkati:

# rmmod hello

U trenutku učitavanja driver-a starta se funkcija init_module() koja obično sluţi za

    inicijalizaciju drivera. TakoĎer kod rmmod izvrši se funkcija cleanup_module().

    Zanimljivo je primjetiti da driver nema main() funkciju. Aplikacija obično izvrši zadatak i onda umre. Za razliku od nje driver se sastoji od skupa funkcija za rukovanje ureĎajima i te funkcije

    se zovu onda kada se trebaju. Ovaj gornji primjer driver-a ne implementira niti jednu upotrebljivu funkciju nego je samo dan primjer onog što svaki driver mora imati.

4. KORIŠTENJE IOCTL() FUNKCIJE (30%)

Za podešavanje nekih kontrolnih parametara ureĎaja posebno je pogodna ioctl() funkcija.

    Neke kontrolne operacije se ne mogu dobiti slanjem i čitanjem podataka sa ureĎaja. Za takve

    stvari koristi se ioctl() funkcija. Npr. ne moţemo čitanjem i pisanjem serijskog porta promijeniti baud rate nego to moramo učiniti sa ioctl() funkcijom.

    Njenu primjenu ćemo isprobati na primjeru ledica na tastaturi. Zadatak se sastoji u tome da

    treba na tastaturi naizmjenično paliti i gasiti ledicu za num_lock, scroll_lock i caps_lock.

    Datoteka u /dev direktoriju koja predstavlja tastaturu je /dev/tty0.

Otvaranje tog device-a postiţemo sa npr.

    fd=open("/dev/tty0",O_RDONLY)

Ovdje smo otvorili sa zastavicom O_RDONLY ali to nije bitno jer mi nećemo ni čitati ni pisati.

Opći oblik ioctl naredbe koja se koristi u aplikaciji (user space) je slijedeći:

    int ioctl(int fd, int cmd, ...);

fd je file descriptor i on se dobije funkcijom open.

    cmd odreĎuje naredbu koju ţelimo izvesti.

    Povratna vrijednost je 0 za uspješnu operaciju.

Naziv datoteke: 70147336.doc Zagreb, 11.8.2010. List 3 od 5

    Ovaj dokument predstavlja intelektualno vlasništvo FER, ZESOI, LSS.

Pozivanjem te funkcije se poziva ioctl() funkcija koju implementira driver. Ona ima malo

    drugačije argumente. Mi ćemo se ovdje baviti isključivo korištenjem iz aplikacije i koristit ćemo već napisane driver-e kao npr. driver za tastaturu /dev/tty0

Tako za upravljanje LED-om se koriste dve naredbe.

    ioctl(fd,KDGETLED,&led);

    led je char varijabla gdje su zadnja 3 bita, stanja 3 led-ova (num, caps, scroll lock). Gornjom naredbom se u varijablu led sprema sadrţaj stanja ledica.

    ioctl(fd,KDSETLED,led);

Zadatak:

    Napisati program gdje se ledice pale jedna za drugom krečući sa lijeva ka desno pa onda desno ka lijevo. Program nije zamišljen kao modul nego kao samostojeća aplikacija ali način rukovanja sa ioctl funkcijom je jednak i kod driver-a.

Kostur programa je dan u datoteci ledice.c

    wget http://ppmps.zesoi.fer.hr/vjezbe/dodaci/vj9/ledice.c

5. SIMULACIJA UPRAVLJANJA UREĐAJA (50%)

    U ovom dijelu vjeţbe će se koristiti memorija kao ureĎaj. Koristit ćemo driver koji će puniti i prazniti memorijski prostor. Taj memorijski prostor će biti globalni i perzistentan. Globalan znači da će svi koji koriste taj driver koristiti isti memorijski prostor a perzistentan znači da se

    memorija ne oslobaĎa pozivom close(). Takvim driver-om je moguće zauzeti svu

    raspoloţivu memoriju računala. MeĎutim to se ne preporuča jer računalo postaje vrlo slabo interaktivno. Dakle pisanjem i čitanjem datoteke mi punimo i praznimo memoriju. Primjer

    takvog drivera je uzet iz knjige Rubini: ''Linux Device Drivers'', O'Reilly, 1998.

Kod je dan u datotekama scull.h i main.c. Datoteke moţete dobiti sa:

wget http://ppmps.zesoi.fer.hr/vjezbe/dodaci/vj9/vj9-linlab.tar.gz

Makefile je zaduţen za kompajliranje (naredba make) a modul se učitava i briše sa insmod

    i rmmod naredbama. Svi kodovi su ostali nepromijenjeni kako bi se dobio uvid u tipičan izgled jednog dobro napravljenog drivera.

Bitno je uočiti 4 funkcije. scull_open, scull_read, scull_write, scull_close

    koje se pozivaju kad se pokrenu funkcije open, read, write i close nad datotekom

    /dev/scull. Koje funkcije se pozivaju pri pozivu generičkih funkcija zapisano je u strukturi struct file_operations. Mi u tu strukturu navedemo puna imena funkcija kao u

    gornjem slučaju scull_open i sl. PronaĎite tu strukturu u kodu main.c.

    Valja primjetiti sponu koja povezuje funkcije drivera sa datotekom koja predstavlja ureĎaj. Naime svaka datoteka u /dev direktoriju ima umjesto veličine dva broja. Zovu se major i minor.

    Primjer:

    crw-rw-rw- root root 61, 1 Sep 11 2001 scull

Naziv datoteke: 70147336.doc Zagreb, 11.8.2010. List 4 od 5

    Ovaj dokument predstavlja intelektualno vlasništvo FER, ZESOI, LSS.

Takva datoteka se moţe ručno napraviti pomoću naredbe mknod.

     mknod /dev/scull c 61 1

61 je major broj a 1 minor, c označava da se radi o character device-u.

Svaki driver kad se registrira definira za koji major broj je odreĎen (scull modul je po defaultu

    podešen na major broj 61). Tako da kad mi otvorimo datoteku to se zapravo prenese driver-u

    sa tim major brojem. Koji driver je zaduţen za koji major broj piše u datoteci /proc/devices

    kada se modul učita. Pogledati da li major broj modula odgovara broju 61. Bitno je da dve datoteke koje predstavljaju različite ureĎaje ne bi imali iste major brojeve. Zato je poţeljno te

    brojeve dinamički odreĎivati. Driver u kodu registrira major broj sa funkcijom

    register_chrdev(), ondnosno odjavljuje sa unregister_chrdev(). PronaĎite ih u

    kodu.

    Napravite datoteku scull u /dev/ direktoriju tako da predstavlja character device sa major brojem 61 i minor brojem 0. To će nam biti spona izmeĎu aplikacije i driver-a

    Htio bih upozoriti na neke operacije koje su oslonac četiri glavne funkcije (open, close, read, write). Funkcija open sadrţava makro MOD_INC_USE_COUNT. On sluţi da drţi broj otvorenih

    pristupa ureĎaju kako bi znao javiti da je ureĎaj zauzet ako ga netko hoće isključiti sa rmmod

    dok ga netko drugi koristi. TakoĎer funkcija close sadrţava makro naredbu MOD_DEC_USE_COUNT. Svaka funkcija read ima izmeĎu ostalog i zadatak prebacivati sadţaj iz kernel space-a u user space. To se u verziji kernela 2.0.x obavljalo funkcijom memcpy_tofs(). Funkcija write() radi suprotnu stvar tj. prebacuje iz user space-a u kernel space. To obavlja funkcija memcpy_fromfs(). PronaĎite gornje makroe i funkcije u kodu (ili sličnog oblika jer su funkcije promijenile ime u novijim kernelima).

Kad je modul scull uspješno učitan tada se moţe isprobati njegova funkcionalnost.

    Mi moţemo pisati u datoteku /dev/scull koristeći i osnovne naredbe ljuske. Tako ako hoćemo u /dev/scull upisati 10k (10240 byte-a) nula to moţemo obaviti sljedećom naredbom.

# dd if=/dev/zero of=/dev/scull bs=1k count=10

    To će uzrokovati da se 10 blokova od po 1k prebaci iz datoteke /dev/zero u /dev/scull. Čitanjem datoteke /dev/zero se dobijaju same nule.

Naredbom ljuske

# free

    moguće je dobiti ispis trenutno zauzete i prazne memorije. Tako da moţemo puniti memoriju pomoću dd naredbe i gledati kako se ona smanjuje sa free naredbom.

    Driver scull je tako implementiran da svaki put kad se samo piše u datoteku tada to počinje od početka memorijskog prostora. Tako da uzastopnim pisanjem identične dd naredbe neće

    se memorija smanjivati jer će se svaki puta sadrţaj prepisivati preko starog. Zato ako se hoće uzeti vise memorije potrebno je povećati argument count.

Memorija će se osloboditi tek sa micanjem kompletnog modula iz jezgre (izdavanje rmmod

    naredbe).

    Naziv datoteke: 70147336.doc Zagreb, 11.8.2010. List 5 od 5

    Ovaj dokument predstavlja intelektualno vlasništvo FER, ZESOI, LSS.

Report this document

For any questions or suggestions please email
cust-service@docsford.com