Cyprian Gracz <c.gracz@students.mimuw.edu.pl>
Obsluga plikow specjalnych i tablic rozdzielczych w systemie Linux
1. Wstep
W systemie operacyjnym Linux dostep do urzadzen zewnetrznych uzyskuje sie poprzez system plikow specjalnych. Pozwala to na dostep do urzadzen fizycznych za pomoca tych samych funkcji, co do zwyklych plikow. Jesli zostaje wywolana funkcja systemu plikow, to jadro sprawdza, czy zostala ona wywolana w stosunku do zwyklego pliku, czy do pliku specjalnego. Jesli jest to zwykly plik, wykonywane sa zwykle czynnosci systemu plikow. Jesli natomiast jest to plik specjalny, obsluga jego jest realizowana przez podprogram obslugi urzadzenia, z ktorym zwiazany jest plik specjalny.
Urzadzenia ze wzgledu na dostep do nich podzielone sa na urzadzenia znakowe (character devices) oraz urzadzenia blokowe (block devices). Do urzadzen znakowych mamy dostep sekwencyjny, bajt po bajcie (np. karty dzwiekowe). Natomiast do urzadzen blokowych mamy dostep swobodny, w blokach dowolnej wielkosci (np. dyski twarde).
2. Obsluga plikow specjalnych
Jak juz wczesniej wspomnialem urzadzenia w Linuxie obslugiwane sa przez system plikow specjalnych. Sa one przewaznie zamontowane w katalogu /dev, lecz kazde urzadzenie mozna montowac w dowolnym miejscu drzewa katalogow. Poniewaz urzadzenia widziane sa jako pliki, mozna nadawac uzytkownikom do nich prawa dostepu tak samo, jak ma to miejsce w przypadku zwyklych plikow.
Urzadzenia (pliki specjalne) tworzymy w systemie za pomoca
funkcji mknod (zob. man mknod). Jej argumentami sa: nazwa nowego
urzadzenia, jego typ (blokowe czy znakowe), numer glowny (MAJOR) oraz numer
podrzedny (MINOR). Jako typ urzadzenia podajemy 'c' dla urzadzen znakowych lub
'b' dla urzadzen blokowych. Numer glowny okresla przynaleznosc urzadzenia do
pewnej grupy. Urzadzenia z tej samej grupy obslugiwane sa przez ten sam
podprogram obslugi. Numer podrzedny przekazywany jest jako argument podprogramowi
obslugi. Identyfikuje on urzadzenie w obrebie grupy (musi byc unikatowy).
Zatem stworzenie urzadzenia znakowego o nazwie 'tmpdev', o numerze glownym 123 i
numerze podrzednym 12, wyglada nastepujaco:
mknod tmpdev c 123 12
Numer glowny (MAJOR) i podrzedny sa liczbami z zakresu od
0 do 255, i tworza razem 16-bitowa liczba jednoznacznie identyfikujaca urzadzenie
w systemie (8 starszych bitow to MAJOR, 8 mlodszych to MINOR). Zadne urzadzenie
nie moze miec numeru glownego rownego 0, ani 255 (zarezerwowane na pozniejsze
rozszerzenia systemu).
MAJOR identyfikuje grupe urzadzen. Sa one obslugiwane przez ten sam podprogram
obslugi. Wszystkie podprogramy obslugi mozna znalezc w jednej z dwu tablic
systemowych: blkdevs[] lub chrdevs[]. blkdevs
odpowiada za obsluge urzadzen blokowych, a chrdevs za obsluge urzadzen
znakowych. Maja one identyczna strukture:
struct device_struct chrdevs[MAX_CHRDEV]
lub
struct device_struct blkdevs[MAX_BLKDEV]
Struktura device_struct jest nastepujacej postaci:
struct device_struct {
const char * name; //nazwa urzadzenia
struct file_operations * fops; //wskaznik
do struktury operacji, jakie mozna wykonac na pliku
};
Skoro mamy juz urzadzenie i jego podprogram obslugi, trzeba go zarejestrowac.
Robi sie to za pomoca funkcjiregister_chrdev/register_blkdev.
Opisze pokrotce dzialanie funkcji register_chrdev.
int register_chrdev(unsigned int major, const char * name, struct file_operations *fops){
/* funkcja przyjmuje jako argumenty: swoj numer glowny, nazwe urzadzenia,
ktore podprogram obsluguje, wskaznik do struktury operacji dozwolonych na pliku
*/
Jesli major==0, to major=ostatni wolny numer i
Jesli major>=MAX_CHRDEV, to zwracamy -EINVAL
Jesli ten numer major jest juz zajety i fops!=chrdevs[major].fops (jest to
urzadzenie z innymi operacjami na nim dozwolonymi), to zwracamy -EBUSY
Jesli major jest dozwolonej wielkosci i chrdevs[major]==NULL, to
wstawiamy w to miejsce name i fops
Dla urzadzen blokowych dziala to identycznie, z ta roznica, ze zamiast
chrdevs[] jest uzywana blkdevs[].
Wyrejestrowanie urzadzenia jest proste.
int unregister_chrdev(unsigned int major, const char * name)
Po sprawdzeniu, czy major jest z odpowiedniego zakresu i czy nazwa urzadzenia
zajestrowanego jest taka sama jak name, pola struktury w chrdevs[major]
sa ustawiane na NULL.
Poniewaz urzadzenia sa reprezentowane w systemie jako pliki, jest do nich
zapewniony dostep tak samo, jak do systemu plikow (np. open, close, read, write,
itd...). Jednak ze wzgledu na to, ze kazde urzadzenie powinno inaczej "rozumiec"
poszczegolne funkcje, funkcje systemowe sa podmieniane przez funkcje z
podprogramow obslugi urzadzen. Omowie dzialanie niektorych funkcji systemowych
na plikach specjalnych.
open()