\documentclass[a4paper,12pt,titlepage]{article}

\usepackage[polish]{babel}
\usepackage[latin2]{inputenc}
\usepackage{a4wide}
\usepackage{longtable}
\usepackage[T1]{fontenc}
\usepackage{times}
\usepackage[dvips]{graphicx}

\title{Podprogram obs\l{}ugi urz\k{a}dzenia \\ Sterownik urz\k{a}dzenia znakowego}
\author{Jan Posiada\l{}a \\ nr 181062}
\date{}

\begin{document}
\maketitle
\tableofcontents
\newpage

\section{Wprowadzenie}
Wi"ekszo"s"c system"ow Unixowych rozr"o"rnia trzy rodzaje urz"adze"n zewn"etrznych:
znakowe, blokowe i sieciowe. Ten podzia"l przenosi si"e na zestawy funkcji 
obs"luguj"acych operacje wej"scia/wyj"scia na tych urz"adzeniach - sterowniki.

Sterowniki urz"adze"n stanowi"a znaczn"a cz"e"s"c j"adra Linuxa. Jednak s"a 
najbardziej niezale"rn"a jego cz"e"sci"a. W obliczu integralno"sci j"adra mo"remy je
uwa"ra"c za ,,czarne skrzynki'' stoj"ace w p"o"l drogi pomi"edzy systemem a 
urz"adzeniami zewn"etrznymi.

Urz"adzenia znakowe jako jedyne ze wpomnianej tr"ojki mog"a by"c traktowane, w 
naturalny dla Unixa spos"ob, jako strumie"n bajt"ow. Oznacza to, "re zadaniem 
sterownika jest symulacja zachowania urz"adzenia, tak aby u"rytkownik m"og"l 
wykonywa"c na nim operacje charakterystyczne dla zwyk"lego pliku 
\textit{(open, close, read, write)}. Przyk"ladami abstrakcji urz"adzenia znakowego 
jako pliku s"a konsola trybu tekstowego albo drukarka. Jedyn"a istotn"a r"o"rnic"a 
pomiedzy urz"adzeniem znakowym a zwyk"lym plikiem jest brak mo"rliwo"sci swobodnego
poruszania si"e po danych transferowanych pomi"edzy systemem i urz"adzeniem.   

\section{Rejestracja urz"adzenia}

Dost"ep do urz"adzenia znakowego nast"epuje poprzez plik znajduj"acy si"e zazwyczaj
w katalogu \textit{/dev}. Jednym z atrybut"ow takiego pliku specjalnego 
(dla pliku zwi"azanego z urz"adzeniem znakowym ,,c'' w najbardziej znacz"acym bicie
ci"agu praw) jest para liczb z zakresu od 0 do 255: numer g"l"owny \texttt{major}
i numer podrz"edny \texttt{minor} urz"adzenia. 

Numer g"l"owny wi"a"re urz"adzenie z odpowiadaj"acym mu sterownikiem. Wiele plikow
mo"re mie"c ten sam numer g"l"owny. Oznacza to "re odpowiadaj"ace im urz"adzenia 
s"a tego samego typu i b"ed"a obs"lugiwane przez ten sam sterownik.

Numer podrz"edny jest przekazywany do sterownika zidentyfikowanego za pomoc"a
numeru g"l"ownego. Oznacza instancj"e urz"adzenia typu \texttt{major} i mo"re
r"o"rnicowa"c zachowanie sterownika wobec urz"adzenia.

Dodanie nowego urz"adzenia polega na wywolaniu funkcji      
\begin{verbatim}
int register_chrdev ( 
    unsigned int major,  
    const char *name,  
    struct file_operations *fops ); 
\end{verbatim}

zdefiniowanej w \texttt{<linux/fs.h>}.

W wyniku wywo"lania tej funkcji zostanie utworzone urz"adzenie o nazwie 
\texttt{name} i numerze \texttt{major} (je"sli ten numer by"l wolny),
\texttt{fops} jest wska"znikiem do tablicy wska"znik"ow do funkcji, kt"orych
wywo"lania standardowych funkcji systemowych ma u"ry"c do obs"lugi operacji
na pliku specjalnym.

Urz"adzenie usuwamy wywo"luj"ac funkcj"e
\begin{verbatim}
int unregister_chrdev ( 
    unsigned int major,  
    const char *name); 
\end{verbatim}

Wywo"lania te najcz"e"sciej znajduj"a si"e w funkcjach za"ladowuj"acych i 
usuwaj"acych modu"l sterownika urz"adzenia z systemu. 

Plik specjalny zwi"azany z urz"adzeniem znakowym tworzymy:

\texttt{mknod /dev/nazwa\_pliku c \$(major) \$(minor)}  

\subsection{Numery g"l"owny i podrz"edny w strukturze w"ez"la}

Numery urz"adzenia znajduj"a si"e w polu \texttt{i\_rdev} struktury \texttt{inode}.
Poniewa"r niekt"ore funkcje pobieraj"a wska"znik do struktury w"ez"la mo"rna
pobra"c numery urz"adzenia.

\section{Operacje na plikach} 

\subsection{Struktura \texttt{struct file}}
W"la"sciwo"sci otwartego urz"adzenia, jak ka"rdego  pliku, s"a okre"slone 
przez struktur"e \texttt{struct file (<linux/fs.h>)}. Struktura ta jest 
tworzona przez systemowy \texttt{open} i przekazywana do wszystkich funkcji 
operuj"acych na pliku. Wska"znik do tej struktury w nag"l"owkach funkcji wyst"epuje
pod nazw"a \texttt{filp} (,,file pointer'').


\subsection{Struktura \texttt{file\_operations}}
 Struktura \texttt{struct file} zawiera pole 
\texttt{f\_op} b"ed"ace wska"znikiem do tablicy wska"znik"ow na funkcje 
dzia"laj"acych na tym pliku (lub na NULL). Tablica ta jest struktur"a typu 
\texttt{file\_operations}. W"la"snie wska"znik na tak"a struktur"e jest 
argumentem funkcji rejestruj"acej urz"adzenie. Zadaniem sterownika jest 
implementacja potrzebnego podzbioru tych funkcji.

\includegraphics[scale = 0.7]{obrazek1.ps}

\subsection{Funkcje \texttt{open} i \texttt{release}}

Zadaniem funkcji open jest:
\begin{enumerate}
\item Zwi"ekszy"c licznik u"rycia
\item Zainicjalizowa"c urz"adzenie je"sli otwierane pierwszy raz
\item Przechwyci"c b"ledy zwi"azane z urz"adzeniem fizycznym    
\item Pobra"c numer podrz"edny i poprawi"c wska"znik \texttt{f\_op} 
\item Zaalokowa"c i zapisa"c dane przechowywane w \texttt{flip->private\_data} 
\end{enumerate} 

Oto funkcja \texttt{open} dla d"rojstika z j"adra 2.4.7
W tek"scie funkcji zaznaczono, kt"ore linie realizuj"a odpowiednie
zadanie funkcji \texttt{open} (licznik u"rycia utrzymuje j"adro):   

\begin{tabbing}
123\=456\=789\=\kill

\texttt{static int joydev\_open(struct inode *inode, struct file *file)} \\ 
\{ \\
\>	\texttt{struct joydev\_list *list;}\\ 
\>	\texttt{int i = MINOR(inode->i\_rdev) - JOYDEV\_MINOR\_BASE;} /* punkt 4 */\\
 \\
\>	\texttt{if (i >= JOYDEV\_MINORS || !joydev\_table[i])} \\
\>\>		\texttt{return -ENODEV;} \\ 
 \\
\>	\texttt{if (!(list = kmalloc(sizeof(struct joydev\_list), GFP\_KERNEL)))} \\
\>\>		\texttt{return -ENOMEM;} \\
\>	\texttt{memset(list, 0, sizeof(struct joydev\_list));} \\
        /* punkt 5 */ \\
\>	\texttt{list->joydev = joydev\_table[i];} \\
\>	\texttt{list->next = joydev\_table[i]->list;} \\
\>	\texttt{joydev\_table[i]->list = list;}	\\ 
 \\
\>	\texttt{file->private\_data = list;} \\
 \\ 
\>	\texttt{if (!list->joydev->open++)} /* punkt 2 */ \\ 
\>\>		\texttt{if (list->joydev->exist)} \\
\>\>\>			\texttt{input\_open\_device(\&list->joydev->handle);} \\
\\ 
\>	\texttt{return 0;}\\
\texttt{\}}
\end{tabbing}

Zadaniem funkcji \texttt{release} jest:

\begin{enumerate}
\item Zwolni"c ca"l"a pami"e"c zaalokowan"a przez \texttt{open}
\item Zamkn"a"c urz"adzenie po ostatnim \texttt{close}
\item Zmiejszy"c licznik u"rycia
\end{enumerate}

\subsection{Przestrze"n adresowa j"adra i u"rytkownika}

Oto nag"l"owki funkcji \texttt{read} i \texttt{write}:

\begin{verbatim}
ssize_t read( 
  struct file *flip, 
  char *buff, 
  size_t count, 
  loft_t *offp 
);

ssize_t write( 
  struct file *flip,
  const char *buff, 
  size_t count, 
  loft_t *offp 
);
\end{verbatim}

Systemowe \texttt{read} i \texttt{write} przekazuje do funkcji sterownika
wska"znik do bufora w przestrzeni adresowej u"rytkownika (drugi argument).
Oznacza to, "re te funkcje sterownika b"ed"a kopiowa"c dane pomi"edzy 
przestrzeni"a adresow"a j"adra i przestrzeni"a adresow"a u"rytkownika. Bezpo"srednie
odwo"lanie si"e do przestrzeni adresowej u"rytkownika (np. przez \texttt{memcpy})
mo"re spowodowa"c b"l"ad braku strony w pami"eci (page fault).
 
Do kopiowania danych pomiedzy przestrzeni"a adresow"a j"adra i przestrzeni"a 
adresow"a u"rytkownika s"lu"r"a dwie funcj"e (z \texttt{<asm/uacces.h>})
b"ed"ace podstawowym narz"edziem w implementacji funkcji read i write.

\texttt{ \\
unsigned long copy\_to\_user(\\
  void *to, \\
  const void *from, \\ 
  unsigned long count \\
);}

\texttt{ \\
unsigned long copy\_from\_user(\\
  void *to, \\
  const void *from, \\ 
  unsigned long count \\
);}

Obie funkcj"e sprawdzaj"a poprawno"s"c wska"znika w przestrzeni adresowej 
u"rytkownika. W przypadku niepoprawno"sci wska"znika   
lub napotkania niepoprawnego adresu podczas kopiownania funkcje zwracaj"a ilo"s"c
bajt"ow, kt"ore zosta"ly jeszcze do skopiowania. 

\includegraphics[scale = 0.7]{obrazek2.ps}

\subsection{Funkcje read i write}
   
W dodatkach A i B  s"a kody operacji \texttt{read} i \texttt{write} z 
dw"och sterownik"ow (oba "zr"od"lo Linux 2.4.2): \\ 
\begin{itemize}
\item funkcji pisz"acej do generatora liczb losowych \\ 
\item funkcji czytaj"acej z urz"adzenia b"ed"acego zwyk"l"a pami"eci"a \\ 
\end{itemize}

Warto zauwa"ry"c "re, oba korzystaj"a z funkcji copy\_to|from\_user.
Program u"rytkownika ma prawo w nast"epuj"acy spos"ob interpretowa"c
warto"s"c zwracan"a przez funkcje \texttt{read} i \texttt{write}:
\begin{enumerate}
\item Warto"s"c r"owna \texttt{count} - przeczytano/zapisano
"r"adan"a ilo"s"c bajt"ow.
\item Dodatnia warto"s"c \texttt{ret} mniejsza od \texttt{count} - 
przeczytano/zapisano \texttt{ret} bajt"ow. Informacja o niepowodzeniu nie 
jest ustawiana na \texttt{errno}. 
\item Warto"s"c 0 - wczytano znak ko"nca pliku, nie ma miejsca na na zapis 
w urz"adzeniu lub w buforze urz"adzenia. 
\item Warto"s"c -1 - wyst"api"l b"l"ad, mo"rliwe warto"s"ci \texttt{errno}:
\texttt{ \textsc{-eintr} } - przerwane wywo"lanie systemowe, \texttt{ \textsc{-efault}} 
- odwo"lanie do niepoprawnego adresu. 
\end{enumerate}

\subsection{Funkcja \texttt{ioctl}}

Funkcja \texttt{ioctl} dostrcza mo"rliwo"s"c manipulowania urz"adzeniem.
Wywo"lanie systemowe funkcji \texttt{ioctl} wygl"ada tak:

\texttt{int ioctl( int fd, int cmd, char *argp);}

Taki jest nag"l"owek funcji sterownika:
 
\texttt{int ioctl( \\
struct inode *inode, \\
struct file *flip, \\
unsigned int cmd, \\
unsigned long arg);}

Argumenty \texttt{flip} i \texttt{inode} s"a warto"sciami odpowiadaj"acymi
deskryptorowi pliku \texttt{fd} przekazanymi przez wywo"lanie sytemowe.
\texttt{cmd} jest przekazane niezmienione, natomiast \texttt{arg} jest 
\texttt{unsigned long} niezale"rnie od tego czy \texttt{argp} zosta"l 
podany jako liczba ca"lkowita czy wska"znik. \texttt{cmd} jest warto"sci"a
przechwytywan"a w \texttt{ioctl} sterownika przez instrukcj"e \texttt{switch}
(to ona zazwyczaj jest szkieletem \texttt{ioctl}),
\texttt{arg} jest traktowany jako argument \texttt{cmd}.   

\subsubsection{Pobieranie \texttt{arg}}

Je"reli pod \texttt{arg} zapisana jest liczba ca"lkowita mo"remy z niej korzysta"c
bezpo"srednio. Je"reli jest to wska"znik ponownie mamy problem z dost"epem do  danych
zapisanych w przestrzeni adresowej u"rytkownika. Aby ustrzec si"e przed 
bezpo"srednim odwo"laniem do strony nie znajduj"acej si"e w pami"eci nale"ry u"ry"c
funkcji sprawdzaj"acej (z \texttt{<asm/uacces.h>}):


\texttt{access\_ok(int type, const void *addr, unsigned long size);}

Pierwszy argument okre"sla akcje jak"a chcemy przeprowadzi"c na przestrzeni adresowej
u"rytkownika \texttt{( VERIFY\_READ | VERIFY\_WRITE)}, \texttt{addr} jest adresem
w pami"eci u"rytkownika, kt"ory sprawdzamy, \texttt{size} ilo"s"c bajt"ow.


Do czytania i pisania, odpowiednio, w przestrzeni adresowej u"rytkownika pojedy"nczych
jednostek pami"eci s"lu"ry zestaw funkcji:\\
\texttt{put\_user(datum,ptr)} - zawiera \texttt{access\_ok} \\
\texttt{\_\_put\_user(datum,ptr)} \\
\noindent 
\texttt{get\_user(local,ptr)} - zawiera \texttt{access\_ok} \\
\texttt{\_\_get\_user(local,ptr)} \\

Funkcje te mog"a kopiowa"c bajt, s"lowo, podw"ojne s"lowo. Odpowiedni"a ilo"s"c
transferowanych danych zapewnia specjalna funkcja \textit{gcc}. 



\newpage
\paragraph{Dodatek A} 
 
Funkcja pisz"aca do generatora liczb losowych \\ 
\begin{tabbing}
123\=456\=789\=\kill
\texttt{ \noindent
static ssize\_t read\_mem(struct file * file, char * buf,} \\
\>\>\> \texttt{size\_t count, loff\_t *ppos) } \\
\texttt{ \{ } \\
\end{tabbing}
\begin{verbatim}
  unsigned long 	p = *ppos;
  unsigned long 	end_mem;
  ssize_t 	read;
\end{verbatim}
\begin{tabbing} 
123\=456\=789\=101112\=\kill 
\>  \texttt{end\_mem =\_\_pa(high\_memory);} \\
\>  \texttt{if (p >= end\_mem)} \\
\>\>    \texttt{return 0;} \\
\>  \texttt{if (count > end\_mem - p)} \\
\>\>    \texttt{count = end\_mem - p;} \\
\>  \texttt{read = 0;} \\
\texttt{\#if defined(\_\_sparc\_\_) || defined(\_\_mc68000\_\_)} \\
\>  /* we don't have page 0 mapped on sparc and m68k.. */ \\
\>  \texttt{if (p < PAGE\_SIZE) \{} \\
\>\>    \texttt{unsigned long sz = PAGE\_SIZE-p;} \\
\>\>    \texttt{if (sz > count)}\\ 
\>\>\>      \texttt{sz = count;} \\
\>\>    \texttt{if (sz > 0) \{ } \\ 
\>\>\>        \texttt{if(clear\_user(buf, sz))} \\  
\>\>\>\>        \texttt{return -EFAULT;} \\
\>\>\>		\texttt{buf += sz;} \\
\>\>\>		\texttt{p += sz;} \\
\>\>\>		\texttt{count -= sz;}\\ 
\>\>\>		\texttt{read += sz;} \\
\>\>		\texttt{ \} } \\
\>	\texttt{ \} }\\
\texttt{\#endif}\\
\>	\texttt{if (\textsf{copy\_to\_user}(buf, \_\_va(p), count))}\\
\>\>		\texttt{return -EFAULT;}\\
\>	\texttt{read += count;}\\
\>	\texttt{*ppos += read;}\\
\>	\texttt{return read;}\\
\texttt{ \} } \\
 
\end{tabbing}

\newpage
\paragraph{Dodatek B} 

Funkcja czytaj"aca z urz"adzenia b"ed"acego zwyk"l"a pami"eci"a  
\begin{tabbing}
123\=456\=789\=\kill

\texttt{static ssize\_t random\_write(struct file * file, } \\ 
\>\>\> \texttt{const char * buffer, size\_t count, loff\_t *ppos) } \\ 
\texttt{\{} \\ 
\end{tabbing}
\begin{verbatim}
  int              ret = 0;
  size_t           bytes; 
  __u32            buf[16]; 
  const char       *p = buffer;  
  size_t           c = count;  
\end{verbatim}	
\begin{tabbing}
123\=456\=789\=101112=\kill 
\>	\texttt{while (c > 0) \{} \\ 
\>\>		\texttt{bytes = MIN(c, sizeof(buf));} \\
		\\ 
\>\>		\texttt{bytes -= \textsf{copy\_from\_user}(\&buf, p, bytes);}\\
\>\>		\texttt{if (!bytes) \{ }\\
\>\>\>			\texttt{ret = -EFAULT;}\\
\>\>\>			\texttt{break;}\\ 
\>\>		\texttt{\}} \\ 
\>\>		\texttt{c -= bytes;}\\
\>\>		\texttt{p += bytes;}\\
 \\
\>\>		/* Convert bytes to words */ \\
\>\>		\texttt{bytes = (bytes + 3) / sizeof(\_\_u32);}\\
\>\>		\texttt{add\_entropy\_words(random\_state, buf, bytes);}\\ 
\>	\texttt{\}} \\ 
\>	\texttt{if (p == buffer) \{ }\\
\>\>		\texttt{return (ssize\_t)ret;} \\ 
\>	\texttt{\} else \{} \\ 
\>\>		\texttt{file->f\_dentry->d\_inode->i\_mtime = CURRENT\_TIME;}\\
\>\>		\texttt{mark\_inode\_dirty(file->f\_dentry->d\_inode);}\\
\>\>		\texttt{return (ssize\_t)(p - buffer);} \\
\>	\texttt{\}}\\ 
\texttt{\}}\\
\end{tabbing}


\end{document} 