]> rtime.felk.cvut.cz Git - mf6xx.git/commitdiff
Diploma thesis text.
authorRostislav Lisovy <lisovy@gmail.com>
Sat, 23 Apr 2011 19:52:24 +0000 (21:52 +0200)
committerRostislav Lisovy <lisovy@gmail.com>
Sat, 23 Apr 2011 19:52:24 +0000 (21:52 +0200)
doc/diploma_thesis/text/dip_text.tex

index 7c3107eae20ec6621ce43d3ed3a98d7f82a66eb9..be97182b88fdb58a41ce86ae0e94ea1973995a07 100644 (file)
@@ -1,9 +1,8 @@
-%FIXME
+% ==Typografie==
 % vlna
-% \caption{} bez tečky na konci
 % \item[] a \item s tečkou na konci
-% odsazování zdrojáků
-% parametry funkce. Většinou nejsou, ale u prvních výskytů by se hodily
+% odsazování zdrojaku ve verbatim: __X_|__  nebo jen __
+% Popisy obrázků bez tečky (i s více větami)
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \chapter{Úvod}
@@ -15,7 +14,7 @@ Text popisuje základní aspekty práce s PCI zařízeními v jádře Linux a uv
 
 Jako ukázková zařízení na sběrnici PCI byly zvoleny karty Humusoft MF624 a MF614. Podrobně je popsána jejich funkce, včetně způsobu obsluhy ovladačem. Tyto karty byly zvoleny z důvodu snadno pochopitelného způsobu obsluhy.
   
-Výsledkem práce by měly být, kromě popisu vývoje PCI ovladačů, i ovladače typu UIO a Comedi podporující základní funkce (A/D, D/A převodníky a digitální vstupy a výstupy) karet Humusoft MF614 a MF624, které by mohly posloužit jako jednoduché ukázkové ovladače.
+Výsledkem práce by měly být, kromě popisu vývoje PCI ovladačů, i ovladače typu UIO a Comedi podporující základní funkce (A/D, D/A převodníky a digitální vstupy a výstupy) karet Humusoft MF614 a MF624, které by mohly posloužit jako jednoduché ukázkové ovla\-dače.
 
 Pro maximální možné zhodnocení návodů je cílem práce implementovat některé funkce karty Humusoft MF624 do emulačního programu Qemu tak, aby bylo možné popsané postupy implementace ovladačů vyzkoušet i bez fyzického přístupu ke kartě. (FIXME)
 
@@ -62,7 +61,7 @@ Jak je možné ovládat hardwarové periferie pomocí programu (software) je nej
 \end{description}%
 }
 
-Prvním způsobem, jak změnit stav GPIO pinu (ať už nastavení, zda se má jednat o vstupní/výstupní pin nebo jakou hodnotu má mít v případě, že je výstupní) je provedení operace zápisu na určitou adresu v paměťovém adresním prostoru (ta je pevně daná a liší mezi jednotlivými architekturami mikrokontrolérů), tato adresa odpovídá \textbf{registru}\footnote{Registr může být pro zjednodušení považován za malou paměťovou buňku. Změna její hodnoty přímo ovlivňuje stav hardware. V dokumentaci ke konkrétnímu mikrokontroléru/\-mikroprocesoru/\-programovatelnému integrovanému obvodu je uvedeno, jakou funkci mají jednotlivé bity registru.} GPIO pinu. Vnitřní uspořádání mikrokontroléru, dle adresy na kterou bylo zapisováno, rozpozná, že provedená operace zápisu nebyla určena pro změnu hodnoty vnitřní paměti, ale je určena pro změnu hodnoty registru a z toho plynoucí změny stavu určité části hardwaru. Zapsaná hodnota se tedy projeví změnou stavu GPIO pinu. Tato možnost je nejjednodušší a je možná v případě, že jsou hardwarové periferie mapovány do určité části tzv. \textbf{paměťového prostoru}.\footnote{Také označováno jako MMIO -- \textit{Memory-mapped input/output}}
+Prvním způsobem, jak změnit stav GPIO pinu (ať už nastavení, zda se má jednat o~vstupní/výstupní pin nebo jakou hodnotu má mít v případě, že je výstupní) je provedení operace zápisu na určitou adresu v paměťovém adresním prostoru (ta je pevně daná a liší mezi jednotlivými architekturami mikrokontrolérů), tato adresa odpovídá \textbf{registru}\footnote{Registr může být pro zjednodušení považován za malou paměťovou buňku. Změna její hodnoty přímo ovlivňuje stav hardware. V dokumentaci ke konkrétnímu mikrokontroléru/\-mikroprocesoru/\-programovatelnému integrovanému obvodu je uvedeno, jakou funkci mají jednotlivé bity registru.} GPIO pinu. Vnitřní uspořádání mikrokontroléru, dle adresy na kterou bylo zapisováno, rozpozná, že provedená operace zápisu nebyla určena pro změnu hodnoty vnitřní paměti, ale je určena pro změnu hodnoty registru a z toho plynoucí změny stavu určité části hardwaru. Zapsaná hodnota se tedy projeví změnou stavu GPIO pinu. Tato možnost je nejjednodušší a je možná v případě, že jsou hardwarové periferie mapovány do určité části tzv. \textbf{paměťového prostoru}.\footnote{Také označováno jako MMIO -- \textit{Memory-mapped input/output}}
 
 \begin{figure}[h!]
        \begin{center}
@@ -73,9 +72,9 @@ Prvním způsobem, jak změnit stav GPIO pinu (ať už nastavení, zda se má je
 \end{figure}
 
 
-Jiným způsobem změny stavu registru je použití jiné instrukce než která se používá pro paměťové operace -- tj. místo zápisu na adresu v paměťovém prostoru vyhrazenou pro GPIO registr, se provede zápis do tzv. \textbf{vstupně-výstupního prostoru}\footnote{Také označován zkratkou PIO -- \textit{Programmed input/output} nebo jako I/O adresní prostor} na adresu (v tomto případě označovanou jako \textbf{port}) odpovídající registru GPIO pinů. Adresy paměťového a vstupně-výstupního prostoru spolu nijak nesouvisí. V případě zápisu a čtení do/z portu I/O adresního prostoru je potřeba z dokumentace \textbf{přesně vědět} jak široká (kolikabitová) slova je možné zapisovat/číst. 
+Jiným způsobem změny stavu registru je použití jiné instrukce než která se používá pro paměťové operace -- tj. místo zápisu na adresu v paměťovém prostoru vyhrazenou pro GPIO registr, se provede zápis do tzv. \textbf{vstupně-výstupního prostoru}\footnote{Také označován zkratkou PIO -- \textit{Programmed input/output} nebo jako I/O adresní prostor} na adresu (v tomto případě označovanou jako \textbf{port}) odpovídající registru GPIO pinů. Adresy paměťového a~vstupně-výstupního prostoru spolu nijak nesouvisí. V případě zápisu a čtení do/z portu I/O adresního prostoru je potřeba z dokumentace \textbf{přesně vědět} jak široká (kolikabitová) slova je možné zapisovat/číst. 
 
-\ibox{V případě architektury IA-32 (označované také jako x86) máme k dispozici paměťový a vstupně-výstupní adresní prostor. Vstupně výstupní adresní prostor je pouze 16bitový, zatímco paměťový je (\textit{pro zjednodušení nebereme ohled na PAE -- Physical Address Extension}) 32bitový. Toto rozdělení přetrvává z historických důvodů -- i přesto je již možné některá zařízení mapovat do paměťového prostoru. (Znázorněno na obrázku \ref{mmio}.)}
+\ibox{V případě architektury IA-32 (označované také jako x86) máme k dispozici paměťový a vstupně-výstupní adresní prostor. Vstupně výstupní adresní prostor je pouze 16bitový, zatímco paměťový je (\textit{pro zjednodušení nebereme ohled na PAE -- Physical Address Extension}) 32bitový. Toto rozdělení přetrvává z historických důvodů -- i~přesto je již možné některá zařízení mapovat do paměťového prostoru. (Znázorněno na obrázku \ref{mmio}.)}
 
 Hlavní rozdíly mezi chováním paměťové buňky a registru zařízení jsou:
 \begin{itemize}
@@ -94,12 +93,12 @@ Hlavní rozdíly mezi chováním paměťové buňky a registru zařízení jsou:
 \end{figure}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\clearpage
+%\clearpage
 %\newpage
 \section{PCI sběrnice}\label{pcich}
 %Přesný popis PCI sběrnice je mimo rozsah a zaměření této práce. Pokusím se však zmínit a názorně vysvětlit principy využívané touto sběrnicí, které je nutné alespoň částečně znát při implementaci ovladačů PCI zařízení.
 
-PCI (\textit{Peripheral Component Interconnect}) je standard paralelní sběrnice využívaný v počítačích různých architektur. Šířka paralelně přenášených dat je 32 nebo v modernější, méně často používané verzi, 64 bitů. Sběrnice je orientována na přenos zpráv oproti přímé komunikaci mezi zařízeními\footnote{Příklad: FIXME}
+PCI (\textit{Peripheral Component Interconnect}) je standard paralelní sběrnice využívaný v~počí\-ta\-čích různých architektur. Šířka paralelně přenášených dat je 32 nebo v modernější, méně často používané verzi, 64 bitů. Sběrnice je orientována na přenos zpráv oproti přímé komunikaci mezi zařízeními.\footnote{T.j. místo toho, aby PCI most přistupoval přímo k paměti jednotlivých zařízení, vyšle se na sběrnici zpráva s požadavkem. V případě, že je zařízení schopno požadavek obsloužit, umístí na datovou sběrnici požadovaná data.}
 
 Komunikace mezi zařízeními připojenými na sběrnici a procesorem zajišťuje tzv. \textit{PCI most} (PCI bridge). Propojení více nezávislých sběrnic v jednom počítači jsou zajištěny také PCI mosty.
 
@@ -125,14 +124,14 @@ Pro spojení mezi kartou a sběrnicí je potřeba pouze konektor na straně sbě
 
 
 \subsection{Dynamická konfigurace a konfigurační adresní prostor}\label{pci_conf}
-Mezi hlavní výhody PCI sběrnice (oproti její předchůdkyni -- sběrnici ISA) patří dynamická konfigurace připojených zařízení: Ve většině případů probíhá komunikace mezi hostitelským systémem a připojenou (a nakonfigurovanou) PCI kartou zápisem/čtením do určité paměťové (nebo vstupně-výstupní) oblasti. U starší sběrnice ISA si každá karta pevně určila, kam se její část paměti namapuje -- v takovém případě mohl nastat problém, že více než jedna karta mapovala svoji paměť na stejnou adresu (nebo se jednotlivá mapování překrývala). PCI sběrnice tomuto problému předchází takovým způsobem, že každá z karet nese informaci o tom, kolik jak velkých paměťových nebo I/O regionů potřebuje namapovat -- o samotné mapování se poté postará PCI most.
+Mezi hlavní výhody PCI sběrnice (oproti její předchůdkyni -- sběrnici ISA) patří dynamická konfigurace připojených zařízení: Ve většině případů probíhá komunikace mezi hostitelským systémem a připojenou (a nakonfigurovanou) PCI kartou zápisem/čtením do určité paměťové (nebo vstupně-výstupní) oblasti. U starší sběrnice ISA si každá karta pevně určila, kam se její část paměti namapuje -- v takovém případě mohl nastat problém, že více než jedna karta mapovala svoji paměť na stejnou adresu (nebo se jednotlivá mapování překrývala). PCI sběrnice tomuto problému předchází takovým způsobem, že každá z karet nese informaci o~tom, kolik jak velkých paměťových nebo I/O regionů potřebuje namapovat -- o samotné mapování se poté postará PCI most.
 
-Informaci o tom, kolik (a jaké) paměti karta bude potřebovat má před nakonfigurováním uloženu v tzv. \textbf{Base Address Registrech} -- BAR0--BAR5\footnote{FIXME Ve skutečnosti funguje vyčtení požadované velikosti z registru karty PCI mostem takovým způsobem, že se PCI most snaží do každého BAR registru zapsat 0xFF a poté zapsanou hodnotu přečíst -- do BAR registru je možné zapsat pouze .... bla bla}. Poté co se PCI mostu podaří tuto hodnotu přečíst a požadovanou paměť alokovat, zapíše zpět do daného registru adresu, na které se alokovaná paměť nachází. Tu si poté pro potřeby komunikace vyčte ovladač zařízení, který je součástí operačního systému.
+Informaci o tom, kolik (a jaké) paměti karta bude potřebovat má před nakonfigurováním uloženu v tzv. \textbf{Base Address Registrech} -- BAR0--BAR5\footnote{Informace o velikosti požadované oblasti je v registru uložena takovým způsobem, že je pouze jeho část určena k zápisu a zbytek je pouze pro čtení. PCI most se pokusí do registru zapsat hodnotu 0xFFFFFFFF, poté je hodnota zpět vyčtena -- z bitů náležejících do zapisovatelné části registru, je přečtena $1_2$, zbývající část obsahuje hodnoty $0_2$.}. Poté co se PCI mostu podaří tuto hodnotu přečíst a požadovanou paměť alokovat, zapíše zpět do daného registru adresu, na které se alokovaná paměť nachází. Tu si poté pro potřeby komunikace vyčte ovladač zařízení, který je součástí operačního systému.
 
 
 Kromě výše zmíněných 6 BAR registrů, obsahují PCI zařízení i následující registry:
 \begin{description}
-\item[Vendor ID]~\\Obsahuje unikátní 16bitové číslo identifikující výrobce zařízení. Za poplatek je udělováno PCI-SIG (\textit{PCI Special Interest Group}) organizací.\footnote{V Debianu, po nainstalování balíčku \texttt{hwdata}, se seznam těchto identifikátorů nachází v souboru \texttt{/usr/share/hwdata/pci.ids}}
+\item[Vendor ID]~\\Obsahuje unikátní 16bitové číslo identifikující výrobce zařízení. Za poplatek je udělo\-váno PCI-SIG (\textit{PCI Special Interest Group}) organizací.\footnote{V Debianu, po nainstalování balíčku \texttt{hwdata}, se seznam těchto identifikátorů nachází v souboru \texttt{/usr/share/hwdata/pci.ids}}
 \item[Device ID]~\\Obsahuje 16bitové číslo identifikující model zařízení. Hodnotu tohoto identifikátoru si volí sám výrobce zařízení.
 \item[Class code]~\\Označuje (ve 24 bitech) druh zařízení -- zda se jedná např. o grafickou kartu, zvukovou kartu nebo kartu zpracovávající signál.
 \item[Subsystem Vendor ID] -- Podobá se \texttt{Vendor ID}. V případě, že karta využívá PCI řadič třetí strany, jako \texttt{Vendor ID} se zobrazí ID výrobce tohoto řadiče. Aby bylo možné zařízení odlišit od jiného, které využívá stejný řadič, skutečné ID zařízení bude uloženo v tomto registru.
@@ -150,7 +149,7 @@ Registry \texttt{Vendor ID}, \texttt{Device ID} (příp. ještě \texttt{Subsyst
        \end{center}
 \end{figure}
 
-Výše popsané registry (spolu s ostatními, které zde nebyly popsány) se nacházejí v 256bitovém tzv. \textbf{konfiguračním adresním prostoru} karty\footnote{Po paměťovém a vstupně-výstupním adresním prostoru je zde třetí -- konfigurační -- adresní prostor.}. Přístup do konfiguračního adresního prostoru je na architektuře IA-32 možný pomocí zapsání adresy (\textit{kam chceme v konfiguračním prostoru zapisovat}) a dat (\textit{která chceme do konfiguračního prostoru zapsat}) do dvou speciálních I/O portů, které jsou pro tuto operaci vyhrazeny.
+Výše popsané registry (spolu s ostatními, které zde nebyly popsány) se nacházejí v~256bito\-vém tzv. \textbf{konfiguračním adresním prostoru} karty\footnote{Po paměťovém a vstupně-výstupním adresním prostoru je zde třetí -- konfigurační -- adresní prostor.}. Přístup do konfiguračního adresního prostoru je na architektuře IA-32 možný pomocí zapsání adresy (\textit{kam má být v~konfiguračním prostoru zapisováno}) a dat (\textit{která mají být do konfiguračního prostoru zapsána}) do dvou speciálních I/O portů, které jsou pro tuto operaci vyhrazeny.
 
 
 \subsection{Přerušení}
@@ -159,8 +158,9 @@ Sběrnice PCI obsahuje čtyři linky přerušení a všechny z nich jsou dostupn
 V pozdějších revizích PCI specifikací je přidána podpora pro přerušení signalizované zprávou. V tomto případě zařízení oznamuje svůj požadavek na obsloužení zápisem do paměti PCI mostu -- ten poté tento požadavak směruje dále k procesoru.
 
 \subsection{Budoucnost}
-V posledních letech je na poli osobních počítačů PCI sběrnice nahrazována její nástupkyní -- sběrnicí PCIe (PCI Express). Ta je na rozdíl od PCI sériová a dosahuje rychlostí až 16 GB/s. I přesto je sběrnice PCI stále využívána mnohými zařízeními -- převážně v průmyslu.
+V posledních letech je na poli osobních počítačů PCI sběrnice nahrazována její nástupkyní -- sběrnicí PCIe (PCI Express). Ta je na rozdíl od PCI sériová a dosahuje rychlostí až 16 GB/s. I~přesto je sběrnice PCI stále využívána mnohými zařízeními -- převážně v průmyslu.
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\newpage
 \section{Humusoft MF624}
 \begin{figure}[h!]
        \begin{center}
@@ -241,12 +241,12 @@ Z tabulky \ref{tab_bar} lze vyčíst informaci, že registry ovládající digit
        \hline 0x2E &  & \textbf{DA7} -- D/A 7 data \\ 
        \hline 
        \end{tabular} 
-       \caption{Registry karty obsažené v regionu BAR1}
+       \caption{Registry karty MF624 obsažené v regionu BAR1}
        \label{tab_bar1}
        \end{center}
 \end{table}
 
-Na devátém řádku jsou zmíněny \texttt{DIN} (Digital input) a \texttt{DOUT} (Digital output) registry. Z této tabulky je patrná pozice těchto registrů v paměťovém prostoru (t.j. offset v bytech vůči adrese BAR1).
+Na devátém řádku jsou zmíněny \texttt{DIN} (Digital input) a \texttt{DOUT} (Digital output) registry. Z~této tabulky je patrná pozice těchto registrů v paměťovém prostoru (t.j. offset v bytech vůči adrese BAR1).
 
 Jak jsou data v registrech reprezentována, je možné si přečíst (v oficiálním manuálu) na straně 16, kde jsou tyto dva registry podrobně popsány (zde tabulka \ref{tab_din} a \ref{tab_dout}). 
 První sloupec určuje, kterých bitů se daný řádek týká. V druhém sloupci je informace o funkci. Třetí sloupec udává výchozí hodnotu. Z toho, co je v tabulkách uvedeno, plyne, že pro čtení 8bitového digitálního vstupu stačí přečíst spodních 8 bitů DIN registru, horních 8 bitů je potřeba ignorovat. Stejně tak pro nastavení 8bitového digitálního výstupu se zapíše požadovaná hodnota do spodních 8 bitů registru DOUT, horních 8 bitů je potřeba ignorovat.
@@ -283,7 +283,7 @@ Karta MF624 obsahuje osm 14bitových A/D převodníků s pevně stanoveným rozs
 
 \begin{itemize}
 \item Nejprve se v registru ADCTRL zvolí, které A/D převodníky mají být čteny. 
-Každý z A/D převodníků je reprezentován jedním bitem. Zápisem 1 do daného bitu se nastaví, že bude daný A/D převodník aktivní -- 0 ho deaktivuje. Je možné zvolit více než jeden A/D převodník.
+Každý z~A/D převodníků je reprezentován jedním bitem. Zápisem 1 do daného bitu se nastaví, že bude daný A/D převodník aktivní -- 0 ho deaktivuje. Je možné zvolit více než jeden A/D převodník.
 \item Čtením registru ADSTART se spustí převod na zvolených A/D převod\-nících. Přečtená hodnota se dále nepoužívá.
 \item V případě, že se provedl převod na všech zvolených A/D převodnících, je EOLC bit (17. bit) GPIOC registru nastaven na 0 (jinak je v 1).
 \item Výslednou hodnotu je možné přečíst z registru ADDATA, který je typu FIFO. To znamená, že opětovným čtením jednoho registru jsou vyčítány jednotlivé naměřené hodnoty z měřených A/D převodníků v pořadí od 0 do 7.
@@ -291,7 +291,7 @@ Každý z A/D převodníků je reprezentován jedním bitem. Zápisem 1 do dané
 Jinou možností je místo čtení registru ADDATA číst některý z jeho \textit{zrcadlených registrů} (celkem je jich 7, v manuálu jsou označeny jako \textit{BADR1 + 0x02} až \textit{BADR1 + 0x0E}). Tyto registry se chovají \textbf{zcela stejně} jako registr ADDATA, pouze leží na jiných adresách. Příklad: pokud byly aktivovány první čtyři A/D převodníky, po převodu je možné výslednou hodnotu vyčíst opakovaným čtením registru ADDATA nebo čtením registru ADDATA, ADDATA1, ADDATA2, ADDATA3 přesně v tomto pořadí. Čtení z registrů v jiném pořadí bude stále vracet hodnoty převodníků 0--4.
 \end{itemize}
 
-Hodnota vyčtená z A/D převodníků je ve formátu dvojkového doplňku -- příklad konkrétních hodnot je v tabulce \ref{tab_adval}.
+Hodnota vyčtená z A/D převodníků je ve formátu dvojkového doplňku -- příklad konkrét\-ních hodnot je v tabulce \ref{tab_adval}.
 
 
 \begin{table}[h!]
@@ -363,7 +363,7 @@ Karta disponuje následujícími funkcemi:
 \subsection{Komunikace s kartou}
 Způsob komunikace s kartou MF614 se mírně liší od MF624.
 
-Po nahlédnutí do manuálu (dostupný ze stránek výrobce: \url{http://www2.humusoft.cz/www/datacq/manuals/mf614um.pdf}) je z tabulky 9 (zde tab. \ref{tab_mf614_bars}) patrné, že karta využívá více regionů než MF624, přičemž některé jsou mapovány do paměti, jiné do vstupně-výstupního adresního prostoru. Po prohlédnutí tabulky popisující rozložení registrů (zde tab. \ref{tab_mf614_regs}) je zřejmé, že pro přístup k digitálním vstupům/výstupům a analogovým vstupům/výstupům jsou použity vstupně-výstupní regiony BAR0, BAR2. 
+Po nahlédnutí do manuálu (dostupný ze stránek výrobce: \url{http://www2.humusoft.cz/www/datacq/manuals/mf614um.pdf}) je z tabulky 9 (zde tab. \ref{tab_mf614_bars}) patrné, že karta využívá více regionů než MF624, přičemž některé jsou mapovány do paměti, jiné do vstupně-výstup\-ního adresního prostoru. Po prohlédnutí tabulky popisující rozložení registrů (zde tab. \ref{tab_mf614_regs}) je zřejmé, že pro přístup k digitálním vstupům/výstupům a analogovým vstupům/výstupům jsou použity vstupně-výstupní regiony BAR0, BAR2. 
 
 \begin{table}[h!]
        \begin{center}
@@ -413,10 +413,10 @@ Po nahlédnutí do manuálu (dostupný ze stránek výrobce: \url{http://www2.hu
 
 Jednotlivé registry v těchto regionech jsou 8bitové, proto je potřeba při čtení/zápisu používat pouze 8bitové funkce. 16bitové hodnoty jsou rozděleny do dvou 8bitových registrů -- v takovém případě, obsahuje-li registr ve svém názvu písmena \textbf{LO}, jedná se o spodní bajt, zatímco \textbf{HI} značí horní bajt. Výsledná 16bitová hodnota se získá složením dvou 8bitových:
 \begin{verbatim}
-   u8 regAHI, regALO;
-   u16 regA;
+  u8 regAHI, regALO;
+  u16 regA;
    
-   regA = regALO | (regAHI << 8);
+  regA = regALO | (regAHI << 8);
 \end{verbatim}
 
 \subsection{Digitální vstupy a výstupy}
@@ -512,7 +512,7 @@ Hodnota je zapsána v aditivním kódu (tab. \ref{tab_mf614_dac}).
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \chapter{Implementace ovladačů}
 \section{Operační systém GNU/Linux}
-Jako cílový operační systém, na kterém bude vysvětlena implementace základních ovladačů, byl zvolen GNU/Linux\footnote{Operační systém sestávající z GNU nástrojů a jádra Linux je označován jako GNU/Linux.}. Hlavním důvodem je dostupnost zdrojových kódů, velké množství kvalitní dokumentace, rozšířenost a vysoká kvalita. Distribucí použitou při vývoji je Debian GNU/Linux (verze jádra Linux 2.6.35) -- popsané postupy by však měly fungovat i pro jiné distribuce.
+Jako cílový operační systém, na kterém bude vysvětlena implementace základních ovla\-da\-čů, byl zvolen GNU/Linux\footnote{Operační systém sestávající z GNU nástrojů a jádra Linux je označován jako GNU/Linux.}. Hlavním důvodem je dostupnost zdrojových kódů, velké množství kvalitní dokumentace, rozšířenost a vysoká kvalita. Distribucí použitou při vývoji je Debian GNU/Linux (verze jádra Linux 2.6.35) -- popsané postupy by však měly fungovat i pro jiné distribuce.
 
 \subsection{Práce s PCI zařízeními z uživatelského prostoru}
 Pro výpis všech zařízení v systému připojených pomocí sběrnice PCI slouží program \texttt{lspci}.
@@ -535,8 +535,8 @@ $ lspci -nn -d 186c:0624 -vvv
         Subsystem: Humusoft, s.r.o. MF624 Multifunction I/O Card [186c:0624]
         Control: I/O+ Mem+ BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- 
              Stepping- SERR- FastB2B- DisINTx-
-        Status: Cap- 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- 
-             <MAbort- >SERR- <PERR- INTx-
+        Status: Cap- 66MHz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- 
+             <TAbort- <MAbort- >SERR- <PERR- INTx-
         Interrupt: pin A routed to IRQ 22
         Region 0: Memory at d2dffc00 (32-bit, non-prefetchable) [size=128]
         Region 1: I/O ports at b800 [size=128]
@@ -563,12 +563,12 @@ Informace o PCI zařízeních se nacházejí ve složce \texttt{/sys/bus/pci/dev
 
 Struktura souboru \texttt{resource} může vypadat následovně:
 \begin{verbatim}
-0x00000000d2dffc00 0x00000000d2dffc7f 0x0000000000020200
-0x000000000000b800 0x000000000000b87f 0x0000000000020101
-0x00000000d2dff800 0x00000000d2dff87f 0x0000000000020200
-0x0000000000000000 0x0000000000000000 0x0000000000000000
-0x00000000d2dff400 0x00000000d2dff47f 0x0000000000020200
-0x0000000000000000 0x0000000000000000 0x0000000000000000
+  0x00000000d2dffc00 0x00000000d2dffc7f 0x0000000000020200
+  0x000000000000b800 0x000000000000b87f 0x0000000000020101
+  0x00000000d2dff800 0x00000000d2dff87f 0x0000000000020200
+  0x0000000000000000 0x0000000000000000 0x0000000000000000
+  0x00000000d2dff400 0x00000000d2dff47f 0x0000000000020200
+  0x0000000000000000 0x0000000000000000 0x0000000000000000
 \end{verbatim}
 
 První sloupec označuje adresu začátku regionu, druhý jeho konec. Třetí sloupec obsahuje příznaky daného regionu. Díky nim je možné zjistit, zda se např. jedná o paměťový nebo I/O region. Tyto příznaky jsou popsány v souboru \texttt{include/linux/ioport.h} (ve zdrojových souborech jádra Linux). 
@@ -577,28 +577,28 @@ První sloupec označuje adresu začátku regionu, druhý jeho konec. Třetí sl
 
 
 \subsection{Základní jaderný modul}\label{kern_mod}
-Jádro operačního systému GNU/Linux je monolitické -- to znamená, že po zkompilování a slinkování je tvořeno jedním kusem kódu. Tento druh jádra je léty prověřen a mezi výhody patří jeho snadná implementace. Aby běžící jádro nemuselo obsahovat veškeré dostupné ovladače zařízení (nebo abychom v případě potřeby přidat do jádra ovladač pro nový hardware nemuseli celé jádro znovu kompilovat), existuje mechanismus načítání jaderných modulů za běhu, tzv. LKM -- Loadable Kernel Module. V praxi to vypadá tak, že jsou v běžícím jádře zakompilovány pouze nejnutnější ovladače, všechny ostatní si může systém nebo uživatel za běhu do jádra načíst -- v případě, že již nejsou potřeba, je možné je z jádra uvolnit.
+Jádro operačního systému GNU/Linux je monolitické -- to znamená, že po zkompilování a slinkování je tvořeno jedním kusem kódu. Tento druh jádra je léty prověřen a mezi výhody patří jeho snadná implementace. Aby běžící jádro nemuselo obsahovat veškeré dostupné ovladače zařízení (nebo abychom v případě potřeby přidat do jádra ovladač pro nový hardware nemuseli celé jádro znovu kompilovat), existuje mechanismus načítání jaderných modulů za běhu, tzv. LKM -- Loadable Kernel Module. V praxi to vypadá tak, že jsou v~běžícím jádře zakompilovány pouze nejnutnější ovladače, všechny ostatní si může systém nebo uživatel za běhu do jádra načíst -- v případě, že již nejsou potřeba, je možné je z jádra uvolnit.
 
 Jak se takový jaderný modul může vypadat, je nejlepší si ukázat na příkladu:
 \begin{verbatim}
- 1 |  #include <linux/init.h>
- 2 |  #include <linux/module.h>
- 3 | 
- 4 |  static int hello_init(void)
- 5 |  {
- 6 |      printk("Hello, world!\n");
- 7 |      return 0;
- 8 |  }
- 9 | 
-10 |  static void hello_exit(void)
-11 |  {
-12 |      printk("Goodbye, cruel world!\n");
-13 |  }
-14 | 
-15 |  module_init(hello_init);
-16 |  module_exit(hello_exit);
-17 |  
-18 |  MODULE_LICENSE("Dual BSD/GPL");
 1 |  #include <linux/init.h>
 2 |  #include <linux/module.h>
 3 | 
 4 |  static int hello_init(void)
 5 |  {
 6 |      printk("Hello, world!\n");
 7 |      return 0;
 8 |  }
 9 | 
+ 10 |  static void hello_exit(void)
+ 11 |  {
+ 12 |      printk("Goodbye, cruel world!\n");
+ 13 |  }
+ 14 | 
+ 15 |  module_init(hello_init);
+ 16 |  module_exit(hello_exit);
+ 17 |  
+ 18 |  MODULE_LICENSE("Dual BSD/GPL");
 \end{verbatim}
 
 Z příkladu je patrné, že je modul napsán v programovacím jazyce C. To platí pro většinu všech jaderných modulů (stejně jako zdrojových kódů jádra samotného). Ve skutečnosti se jedná o mírně modifikovaný standard C90.
@@ -612,105 +612,105 @@ Pro jednoduchost je možné s funkcí \texttt{printk()} pracovat jako s, jistě
 \item[řádcích 10--13.] Tato funkce nemá na starost nic jiného než výpis krátkého textu do logu jádra.
 \end{description}
 
-\subsection{Kompilace modulu}
+\subsubsection{Kompilace modulu}
 Dále je potřeba jaderný modul přeložit\footnote{Před samotným překladem jádra je potřeba mít k dispozici zdrojové kódy jádra. Ty je možné stáhnout z \texttt{kernel.org} nebo v distribuci Debian nainstalovat pomocí příkazu \texttt{apt-get install linux-source}}. K tomu poslouží následující \texttt{Makefile}:
 \begin{verbatim}
-1 |  KERNEL_VER=`uname -r`
-2 |  obj-m += hello.o
-3 |
-4 |  all:
-5 |      make -C /lib/modules/$(KERNEL_VER)/build M=$(PWD) modules
-6 |  clean:
-7 |      make -C /lib/modules/$(KERNEL_VER)/build M=$(PWD) clean
+  1 |  KERNEL_VER=`uname -r`
+  2 |  obj-m += hello.o
+  3 |
+  4 |  all:
+  5 |      make -C /lib/modules/$(KERNEL_VER)/build M=$(PWD) modules
+  6 |  clean:
+  7 |      make -C /lib/modules/$(KERNEL_VER)/build M=$(PWD) clean
 \end{verbatim}
-Linux využívá při kompilaci systému \texttt{KBUILD}. Ten je tvořen množstvím Makefile souborů a jeho smyslem je umožnit uživateli snadnou konfiguraci před kompilací -- určující, které čáasti se do jádra zakompilují a které nikoliv. Popis toho systému je mimo rozsah této práce. Stručný popis výše zmíněného Makefile souboru:
+Linux využívá při kompilaci systému \texttt{KBUILD}. Ten je tvořen množstvím Makefile souborů a~jeho smyslem je umožnit uživateli snadnou konfiguraci před kompilací -- určující, které části se do jádra zakompilují a které nikoliv. Výše uvedený (základní) Makefile soubor je tvořen následovně:
 
 \begin{description}
-\item[Na prvním řádku] se do proměnné \texttt{KERNEL\_VER} přiřadí verze aktuálně běžícího jádra (po zavolání příkazu \texttt{uname -r}, který tuto informaci vrací)
-\item[Druhý řádek] říká, že modul bude vytvářen ze zdrojového souboru \texttt{hello.c} (pod tímto názvem jsme uložili náš ukázkový modul)
-\item[Na pátém řádku] (uvozeném tabelátorem) se volá (pomocí přepínače \texttt{-C}) Makefile ze systému \texttt{KBUILD}, který se nachází v adresáři spolu se zdrojovými kódy jádra. Parametrem \texttt{M} říkáme, které moduly si přejeme vytvořit -- v tomto případě jsou to ty, jejichž zdrojové soubory jsou v aktuálním adresáři (tj. \texttt{PWD}).
+\item[Na prvním řádku] se do proměnné \texttt{KERNEL\_VER} přiřadí verze aktuálně běžícího jádra (po zavolání příkazu \texttt{uname -r}, který tuto informaci vrací).
+\item[Druhý řádek] říká, že modul bude vytvářen ze zdrojového souboru \texttt{hello.c} (t.j. modul popisovaný v kapitole \ref{kern_mod}).
+\item[Na pátém řádku] (uvozeném tabelátorem) se volá (pomocí přepínače \texttt{-C}) Makefile ze sys\-tému \texttt{KBUILD}, který se nachází v adresáři spolu se zdrojovými kódy jádra. Parametr \texttt{M} určuje, které moduly mají být vytvořeny -- v tomto případě jsou to ty, které jsou uvedeny v Makefile, nacházejícím se v aktuálním adresáři (tj. \texttt{PWD}).
 \end{description}
 
 V případě, že v adresáři, ve kterém se nachází zdrojový soubor modulu \texttt{hello.c} a výše popsaný soubor \texttt{Makefile}, spustí příkaz \texttt{make}, měl by proběhnout samotný překlad:
 \begin{verbatim}
-$ make
-make -C /lib/modules/`uname -r`/build M=/tmp/kernel_module_example modules
-make[1]: Entering directory `/usr/src/linux-headers-2.6.35-28-generic'
-  CC [M]  /tmp/kernel_module_example/hello.o
-  Building modules, stage 2.
-  MODPOST 1 modules
-  CC      /tmp/hello.mod.o
-  LD [M]  /tmp/hello.ko
-make[1]: Leaving directory `/usr/src/linux-headers-2.6.35-28-generic'
+  $ make
+  make -C /lib/modules/`uname -r`/build M=/tmp/kernel_module_example modules
+  make[1]: Entering directory `/usr/src/linux-headers-2.6.35-28-generic'
+    CC [M]  /tmp/kernel_module_example/hello.o
+    Building modules, stage 2.
+    MODPOST 1 modules
+    CC      /tmp/hello.mod.o
+    LD [M]  /tmp/hello.ko
+  make[1]: Leaving directory `/usr/src/linux-headers-2.6.35-28-generic'
 \end{verbatim}
 V aktuálním adresáři by se měl nacházet kromě různých souborů, které vzniky při překladu, i potřebný \texttt{hello.ko} -- t.j. zkompilovaný jaderný modul připravený na zavedení do jádra.
 
 \begin{verbatim}
-$ ls
-hello.c  hello.ko  hello.mod.c  hello.mod.o  hello.o  
-Makefile  modules.order  Module.symvers
+  $ ls
+  hello.c  hello.ko  hello.mod.c  hello.mod.o  hello.o  
+  Makefile  modules.order  Module.symvers
 \end{verbatim}
 
-\subsection{Zavedení modulu}
+\subsubsection{Zavedení modulu}
 Po úspěšném zkompilování jaderného modulu již pouze zbývá ho zavést do jádra. To se provede programem \texttt{insmod} -- ten musí být spouštěn se superuživatelským oprávněním:
 \begin{verbatim}
-$ sudo insmod ./hello.ko 
+  $ sudo insmod ./hello.ko 
 \end{verbatim}
 
 V případě, že vše proběhlo správně, měl by být v logu jádra text vypisovaný modulem po jeho zavedení. To je možné ověřit:
 \begin{verbatim}
-$ dmesg | tail -1
-[ 9245.757491] Hello, world!
+  $ dmesg | tail -1
+  [ 9245.757491] Hello, world!
 \end{verbatim}
 A skutečně je posledním řádkem v logu text vypsaný úspěšně zavedeným modulem.
 
 Pro plné otestování funkčnosti ukázkového modulu, je potřeba ho ještě z jádra uvolnit. K tomu slouží program \texttt{rmmod} (opět je potřeba spouštět se superuživatelskými privilegii).
 \begin{verbatim}
-$ sudo rmmod hello 
+  $ sudo rmmod hello 
 
-$ dmesg | tail -1
-[ 9612.256929] Goodbye, cruel world!
+  $ dmesg | tail -1
+  [ 9612.256929] Goodbye, cruel world!
 \end{verbatim}
 V logu je opět nachází text vypisovaný modulem při uvolňování z jádra.
 
 
 \ibox{V případě, že má být do jádra zaveden modul, jehož funkčnost a stabilita není jistá, je vhodné si uložit veškerou práci a před zavedením/uvolněním modulu do/z jádra spustit program \texttt{sync}, který uloží obsah diskových bufferů na disky.}
 
-\subsection{Na co si dávat pozor}
-Při psaní základního modulu pro jádro Linux nejsou patrné větší rozdíly oproti psaní programů pro uživatelský prostor. I přesto, že tyto rozdíly nejsou vidět, stále tady jsou. Mezi ty nejdůležitější, kterých si má být programátor vědom, patří:
+\subsubsection{Na co si dávat pozor}
+Při psaní základního modulu pro jádro Linux nejsou patrné větší rozdíly oproti psaní programů pro uživatelský prostor. I~přesto, že tyto rozdíly nejsou vidět, stále tady jsou. Mezi ty nejdůležitější, kterých si má být programátor vědom, patří:
 
 \begin{description}
 \item[Žádná ochrana paměti]~\\Libovolný jaderný modul má přístup k veškeré paměti počítače. V případě, že se chybně pokusí zapsat do paměti, do které by zapisovat neměl, není zde žádný mechanismus, který by mu v tom zabránil nebo ho na to alespoň upozornil.
 \item[Uvolňování paměti]~\\Stejně jako pro programy psané v uživatelském prostoru platí, že nepotřebná dynamicky alokovaná paměť by měla být dealokována. V případě neuvolňování paměti programem v uživatelském prostoru je zde stále operační systém, který po skončení programu veškerou paměť uvolní. Nic takového však v jádře operačního systému nefunguje -- po uvolnění modulu z jádra není nic, co by se postaralo o alokovanou.
-\item[Přímý přístup k hardwaru]~\\Základní jaderný modul psaný například nezkušeným studentem má zcela stejné možnosti přístupu k hardware jako subsystémy jádra, které se starají o správnou funkci jednotlivých ovladačů. V lepším případě může špatný ovladač způsobit pád systému, v horším např. zničení dat na disku nebo dokonce zničení hardware\footnote{Například velmi těžko opravitelné poškození firmware síťových karet Intel e1000e: \\ \url{http://www.abclinuxu.cz/clanky/jaderne-noviny/jaderne-noviny-22.-10.-2008\#pricina-chyby-poskozujici-e1000e}}.
-\item[Globální proměnné]~\\Každý ovladač může být spuštěn ve více instancích, proto by v kódu neměly být globální proměnné. Proměnné, které je potřeba zpřístupnit z více míst ovladače se vloží do jedné struktury, která je poté přístupná skrze ukazatel na \textit{privátní data} ovladače. Struktura reprezentující daný ovladače většinou obsahuje ukazatel s názvem \texttt{private} nebo \texttt{priv}, který slouží k tomuto účelu.
+\item[Přímý přístup k hardwaru]~\\Základní jaderný modul psaný například nezkušeným studentem má zcela stejné možno\-sti přístupu k hardware jako subsystémy jádra, které se starají o správnou funkci jednotlivých ovladačů. V lepším případě může špatný ovladač způsobit pád systému, v~horším např. zničení dat na disku nebo dokonce zničení hardware\footnote{Například velmi těžko opravitelné poškození firmware síťových karet Intel e1000e: \\ \url{http://www.abclinuxu.cz/clanky/jaderne-noviny/jaderne-noviny-22.-10.-2008\#pricina-chyby-poskozujici-e1000e}}.
+\item[Globální proměnné]~\\Každý ovladač může být spuštěn ve více instancích, proto by v kódu neměly být globální proměnné. Proměnné, které je potřeba zpřístupnit z více míst ovladače se vloží do jedné struktury, která je poté přístupná skrze ukazatel na \textit{privátní data} ovladače. Struktura reprezentující daný ovladače většinou obsahuje ukazatel s názvem \texttt{private} nebo \texttt{priv}, který slouží k~tomuto účelu.
 
 V případě ukončení funkce ovladače musí být tato paměť uvolněna.
 \end{description}
 
-\subsection{Příkaz GOTO}
+\subsubsection{Příkaz GOTO}
 Obecně je doporučováno příkaz \texttt{goto} nepoužívat. Najdou se ale případy, kdy jeho použití usnadní práci a i přesto neznepřehlední kód. V jádře Linux se tento příkaz používá při postupném uvolňování zdrojů zařízení.
 
 Příklad pro lepší názornost:
 \begin{verbatim}
- 1 |  int mf614_attach(...)
- 2 |  {
- 3 |      if(pci_enable_device(devpriv->pci_dev))
- 4 |          goto out_exit;
- 5 |  
- 6 |      if(pci_request_regions(devpriv->pci_dev, "mf614"))
- 7 |          goto out_disable;
- 8 |  
- 9 |      if (!pci_iomap(devpriv->pci_dev, 0, 0))
-10 |          goto out_release;
-11 |   
-12 |  out_release:
-13 |      pci_release_regions(devpriv->pci_dev);
-14 |  out_disable:
-15 |      pci_disable_device(devpriv->pci_dev);
-16 |  out_exit:
-17 |      return -ENODEV;
-18 |  }
 1 |  int mf614_attach(...)
 2 |  {
 3 |      if(pci_enable_device(devpriv->pci_dev))
 4 |          goto out_exit;
 5 |  
 6 |      if(pci_request_regions(devpriv->pci_dev, "mf614"))
 7 |          goto out_disable;
 8 |  
 9 |      if (!pci_iomap(devpriv->pci_dev, 0, 0))
+ 10 |          goto out_release;
+ 11 |          
+ 12 |  out_release:
+ 13 |      pci_release_regions(devpriv->pci_dev);
+ 14 |  out_disable:
+ 15 |      pci_disable_device(devpriv->pci_dev);
+ 16 |  out_exit:
+ 17 |      return -ENODEV;
+ 18 |  }
 \end{verbatim}
 
 Na řádcích 3, 6 a 9 jsou volány funkce, které mají za následek alokaci zdrojů zařízení. Po skončení funkce ovladače je potřeba zavolat jiné funkce, které tyto zdroje uvolní.
@@ -724,38 +724,43 @@ Za pomoci volání \texttt{goto} je výše popsaný problém elegantně vyřeše
 V jádře Linux je kromě funkcí specifických pro práci se zařízením určitého typu, také sada obecných funkcí používaných napříč všemi ovladači. Mezi ně patří například funkce pro vypisování ladících zpráv, funkce pro alokaci a uvolňování paměti.
 
 \subsection{Funkce \texttt{printk()} pro vypisování ladících zpráv}
-\ibox{\texttt{printk(FIXME)};}
-V kapitole \ref{kern_mod} již byla zmíněna funkce \texttt{printk()} v základní verzi, přirovnaná k funkci \texttt{printf()} z uživatelského prostoru. Kromě \textit{obyčejného} vypisování textu do logu jádra podporuje tato funkce navíc nastavení úrovně důležitosti zprávy a speciální formátovací řetězce.
+\ibox{\texttt{int printk(const char *s, ...)};}
+V kapitole \ref{kern_mod} již byla zmíněna funkce \texttt{printk()} v základní verzi, přirovnaná k funkci \texttt{printf()} z uživatelského prostoru. Kromě \textit{obyčejného} vypisování textu do logu jádra podporuje tato funkce navíc \textit{nastavení úrovně důležitosti} zprávy a speciální \textit{formátovací řetězce}.
 
 Nastavení úrovně důležitosti zprávy se provede vložením \textit{nastavovacího} makra \textbf{před} samotný řetězec obklopený uvozovkami. Možné druhy zpráv jsou (od nejkritičtější po nejméně důležitou):
 \begin{description}
 \item[\texttt{KERN\_EMERG}]~\\Zpráva nejvyšší úrovně. Většinou předchází neodvratnému pádu jádra.
-\item[\texttt{KERN\_ERR}]~\\Informace o vzniklé chybě. Bývá použito např. při informování o špatné funkci hardware.
+\item[\texttt{KERN\_ERR}]~\\Informace o vzniklé chybě (např. při informování o špatné funkci hardware).
 \item[\texttt{KERN\_WARNING}]~\\Upozornění o nezávažné chybě.
-\item[\texttt{KERN\_INFO}]~\\Informační zpráva. Může být použito např. od ovladače zařízení o úspěšném spuštění.
+\item[\texttt{KERN\_INFO}]~\\Informační zpráva (např. od ovladače zařízení o úspěšném spuštění).
 \item[\texttt{KERN\_DEBUG}]~\\Obyčejná ladící zpráva.
 \end{description}
 
 \vspace{5mm}
 
-Formátovací řetězce fungují podobně jako u funkce \texttt{printf()}. Kromě známých, \texttt{\%s}, \texttt{\%u}, \texttt{\%d} a \texttt{\%x} jsou zde navíc:
+Formátovací řetězce fungují podobně jako u funkce \texttt{printf()}. Kromě známých, \texttt{\%s}, \texttt{\%u}, \texttt{\%d} a \texttt{\%x} je zde navíc \texttt{\%p}, který slouží k výpisu hodnoty ukazatele.
 
+Možné způsoby použití jsou:
 \begin{description}
-\item[\texttt{\%p}] Slouží k výpisu hodnoty ukazatele.
-\item[FIXME]
+\item[\texttt{\%pF}] Pro ukazatel na funkci vypíše název dané funkce.
+\item[\texttt{\%pf}] Pro ukazatel na funkci vypíše název dané funkce včetně offsetu.
+\item[\texttt{\%pR}] Pro ukazatel na strukturu vypíše adresy paměti příslušející dané struktuře, včetně příznaků.
+\item[\texttt{\%pr}] Pro ukazatel na strukturu vypíše adresy paměti příslušející dané struktuře, bez příznaků.
 \end{description}
 
 Příklad nastavení typu zprávy a použití formátovacího řetězce:
 \begin{verbatim}
-    printk(KERN_DEBUG "I'm trashed; giving up on %p\n", ptr);
+  printk(KERN_DEBUG "Hodnota ukazatele ptr je %p\n", ptr);
 \end{verbatim}
 
 
-\subsection{Funkce \texttt{kmalloc()}, \texttt{kzalloc()} pro alokaci paměti}
+\subsection{Funkce \texttt{kzalloc()} pro alokaci paměti}
 Problematika alokace paměti v prostředí jádra Linux je velice rozsáhlá. Pomocí speciálních funkcí je možné alokovat celé paměťové stránky nebo FIXME velkou oblast ve virtuálním paměťovém prostoru.
 
-\ibox{\texttt{void *kmalloc(size\_t size, int flags);}}
-Základní funkce pro alokaci malé paměťové oblasti (např. pro strukturu obsahující privátní data ovladače) je \texttt{kmalloc()}. Prvním parametrem je velikost alokované paměti (maximálně však 128 KB (FIXME)), druhým je příznak určující o jaký druh alokace se jedná. Nejuniverzálnější možností je \texttt{GFP\_KERNEL}.
+\ibox{\texttt{void *kzalloc(size\_t size, gfp\_t flags);}}
+Základní funkce pro alokaci malé paměťové oblasti (např. pro strukturu obsahující privátní data ovladače) je \texttt{kzalloc()}. Prvním parametrem je velikost alokované paměti (maximálně však 128 KB (FIXME)), druhým je příznak určující o jaký druh alokace se jedná. Nejuniverzálnější možností je \texttt{GFP\_KERNEL}.
+
+Nově alokovaná paměť je vždy vynulována.
 
 Příklad alokace a uvolnění paměti (včetně ošetření chybových stavů):
 \begin{verbatim}
@@ -770,7 +775,7 @@ Příklad alokace a uvolnění paměti (včetně ošetření chybových stavů):
 \end{verbatim}
 
 
-\subsection{Funkce \texttt{kfree()}}
+\subsection{Funkce \texttt{kfree()} pro uvolňování alokované paměti}
 \ibox{\texttt{void kfree(void *obj);}}
 
 Když již alokovaná paměť není potřeba, je nutné ji voláním \texttt{kfree()} uvolnit. 
@@ -778,12 +783,12 @@ Když již alokovaná paměť není potřeba, je nutné ji voláním \texttt{kfr
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \section{Ovladače PCI zařízení}\label{pci_driv}
-\ibox{Jako nejlepší reference jednotlivých funkcí slouží zdrojové kódy jádra. Pro jejich prohlížení existuje šikovný online nástroj \textit{The Linux Cross Reference} -- \\
+\ibox{Jako nejlepší reference jednotlivých funkcí slouží zdrojové kódy jádra. Jednou z~možností jejich prohlížení je pomocí online nástroje \textit{The Linux Cross Reference} -- \\
 \url{http://lxr.linux.no/linux/}.}
 
 Ovladače PCI zařízení jsou ve většině případů kompilovány jako jaderné moduly, dynamicky načítané za běhu jádra. Takový modul je možné buď načíst ručně, pomocí příkazu \texttt{insmod} (se zadanou absolutní cestou) nebo, nachází-li se v adresáři \texttt{/lib/modules/\$(uname -r)/} a je součástí seznamu \texttt{modules.dep}\footnote{Tento seznam je aktualizován pomocí příkazu \texttt{depmod}.} (v témže adresáři), je možné ho načíst pomocí příkazu \texttt{modprobe} (kde se jako parametr předá pouze název modulu bez koncovky \texttt{.ko}). Druhá varianta se týká všech ovladačů standardně zkompilovaných s jádrem.
 
-V případě, že se v systému objeví nové PCI zařízení, je jádrem informován subsystém v uživatelském prostoru, který má na starosti správu \textit{hotplug} zařízení (např. \textit{udev}), o tomto zařízení. Hotplug subsystém (v uživatelském prostoru) poté na základě informací od jádra, jako je Vendor ID a Device ID , rozhodne, který ovladač má být pro dané zařízení načten. Seznam, dle kterého se rozhodne, který ovladač bude načten je v souboru \texttt{/lib/modules/\$(uname -r)/modules.pcimap}.
+V případě, že se v systému objeví nové PCI zařízení, je jádrem informován subsystém v~uživatelském prostoru, který má na starosti správu \textit{hotplug} zařízení (např. \textit{udev}), o tomto zařízení. Hotplug subsystém (v uživatelském prostoru) poté na základě informací od jádra, jako je Vendor ID a Device ID , rozhodne, který ovladač má být pro dané zařízení načten. Seznam, dle kterého se rozhodne, který ovladač bude načten je v souboru \texttt{/lib/modules/\$(uname -r)/modules.pcimap}.
 
 Každý ovladač by měl tedy obsahovat informaci o tom, pro které zařízení je určen. To je uvedeno ve struktuře \texttt{struct pci\_device\_id}.
 
@@ -791,25 +796,25 @@ Každý ovladač by měl tedy obsahovat informaci o tom, pro které zařízení
 Struktura \texttt{struct pci\_device\_id} slouží k identifikaci, pro která zařízení je ovladač určen. Mezi hlavní položky struktury patří \texttt{vendor}, \texttt{device}, \texttt{subvendor}, \texttt{subdevice} (typu \texttt{\_\_u32}) -- jejichž hodnota odpovídá stejnojmenným registrům v konfiguračním prostoru PCI zařízení. Jelikož může být ovladač napsán pro více zařízení, je tato struktura inicializována jako prvek pole, které je zakončeno prvkem prázdným. Různé způsoby inicializace mohou vypadat následovně:
 
 \begin{verbatim}
- 1 |  #define PCI_VENDOR_ID_HUMUSOFT          0x186c
- 2 |  #define PCI_DEVICE_ID_MF624             0x0624
- 3 |  #define PCI_DEVICE_ID_MF614             0x0614
- 4 |  #define PCI_SUBVENDOR_ID_HUMUSOFT       0x186c
- 5 |  #define PCI_SUBDEVICE_MF624             0x0624
- 6 |  
- 7 |  static struct pci_device_id mf624_pci_id[] = {
- 8 |      {
- 9 |          .vendor = PCI_VENDOR_ID_HUMUSOFT,
-10 |          .device = PCI_DEVICE_ID_MF624,
-11 |          .subvendor = PCI_SUBVENDOR_ID_HUMUSOFT,
-12 |          .subdevice = PCI_SUBDEVICE_MF624,
-13 |      },
-14 |
-15 |      { PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF614, 
-16 |          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-17 |
-18 |      { 0, } /* seznam je vždy zakončen prázdným prvkem */
-19 |  };
 1 |  #define PCI_VENDOR_ID_HUMUSOFT          0x186c
 2 |  #define PCI_DEVICE_ID_MF624             0x0624
 3 |  #define PCI_DEVICE_ID_MF614             0x0614
 4 |  #define PCI_SUBVENDOR_ID_HUMUSOFT       0x186c
 5 |  #define PCI_SUBDEVICE_MF624             0x0624
 6 |  
 7 |  static struct pci_device_id mf624_pci_id[] = {
 8 |      {
 9 |          .vendor = PCI_VENDOR_ID_HUMUSOFT,
+ 10 |          .device = PCI_DEVICE_ID_MF624,
+ 11 |          .subvendor = PCI_SUBVENDOR_ID_HUMUSOFT,
+ 12 |          .subdevice = PCI_SUBDEVICE_MF624,
+ 13 |      },
+ 14 |
+ 15 |      { PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF614, 
+ 16 |          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ 17 |
+ 18 |      { 0, } /* seznam je vždy zakončen prázdným prvkem */
+ 19 |  };
 \end{verbatim}
 
 V případě, že je u zařízení rozhodující Vendor ID, ale na Subvendor ID nezáleží, je možné použít makro \texttt{PCI\_ANY\_ID} (to platí 
@@ -832,13 +837,13 @@ Tato struktura obsahuje základní informace o ovladači -- základní proměnn
 
 Příklad, jak může být struktura \texttt{pci\_driver} inicializována a následně zaregistrována:
 \begin{verbatim}
- 1 |  static struct pci_driver mf624_pci_driver = {
- 2 |      .name = "mf624",
- 3 |      .id_table = mf624_pci_id,
- 4 |      .probe = mf624_pci_probe, 
- 5 |      .remove = mf624_pci_remove,
- 6 |  };
- 7 |  pci_register_driver(&mf624_pci_driver);
 1 |  static struct pci_driver mf624_pci_driver = {
 2 |      .name = "mf624",
 3 |      .id_table = mf624_pci_id,
 4 |      .probe = mf624_pci_probe, 
 5 |      .remove = mf624_pci_remove,
 6 |  };
 7 |  pci_register_driver(&mf624_pci_driver);
 \end{verbatim}
 
 
@@ -862,12 +867,12 @@ Nejprve je potřeba operační systém požádat o výlučný přístup ke zdroj
 
 \ibox{\texttt{unsigned long pci\_resource\_start(struct pci\_dev *dev, int bar);}}
 
-V případě, že volání \texttt{pci\_request\_regions()} proběhlo úspěšně, je již možné získat přístup přímo k jednotlivým regionům karty. Fyzickou adresu jednotlivých regionů lze zjistit voláním funkce \texttt{pci\_resource\_start()}, kde se jako druhý parametr uvede číslo BAR registru určujícího region (tj. 0--5). 
+V případě, že volání \texttt{pci\_request\_regions()} proběhlo úspěšně, je již možné získat přístup přímo k jednotlivým regionům karty. Fyzickou adresu jednotlivých regionů lze zjistit voláním funkce \texttt{pci\_resource\_start()}, kde se jako druhý parametr uvede číslo BAR registru určují\-cího region (tj. 0--5). 
 %Volání této funkce má pouze informativní charakter
 
 \ibox{\texttt{unsigned long pci\_resource\_len(struct pci\_dev *dev, int bar);}}
 
-V případě, že je potřeba zjistit velikost daného paměťového nebo I/O regionu, slouží k tomu funkce \texttt{pci\_resource\_len()}.
+V případě, že je potřeba zjistit velikost daného paměťového nebo I/O regionu, slouží k~tomu funkce \texttt{pci\_resource\_len()}.
 
 \ibox{\texttt{void \_\_iomem *pci\_ioremap\_bar(struct pci\_dev *pdev, int bar);}}
 
@@ -893,7 +898,7 @@ Tato funkce by se měla postarat o úklid všech naalokovaných prostředků. M
 Poté co se ovladači podařilo získat přístup ke zdrojům zařízení, je nutné využít speciálních volání pro zápis/čtení do/z těchto zdrojů.
 
 \subsection{Vstupně-výstupní adresní prostor}
-Stejně jako program v jazyku symbolických instrukcí využívá pro přístup k vstupně-výstupnímu adresnímu prostoru (tj. I/O portům) zvláštní instrukce, je nutné využít speciální funkce v programech psaných ve \textit{vyšších} programovacích jazycích. V případě čtení jsou v jádře k dispozici tři volání:
+Stejně jako program v jazyku symbolických instrukcí využívá pro přístup k vstupně-výstupnímu adresnímu prostoru (tj. I/O portům) zvláštní instrukce, je nutné využít speciální funkce v programech psaných ve \textit{vyšších} programovacích jazycích. V případě čtení jsou v~jádře k dispozici tři volání:
 
 \ibox{\texttt{unsigned inb(unsigned port);}}
 
@@ -916,9 +921,9 @@ Třetí písmeno, stejně jako u funkcí pro čtení, značí o kolika-bitový p
 Funkce se stejným \textit{prototypem} jsou k dispozici i v uživatelském prostoru (potřebný hlavičkový soubor je \texttt{<sys/io.h>}).
 
 \subsection{Paměťový adresní prostor}
-I přesto, že se k přístupu k paměti zařízení mapované do paměťového adresního prostoru používá virtuální adresa, stejně jako k přístupu do operační paměti, není možné k paměti zařízení přistupovat přímo \textit{přes ukazatel}. Důvodem je to, že buď překladač (při kompilaci) nebo procesor (za běhu) zoptimalizují\footnote{Tyto optimalizace, v případě přístupu k operační paměti, urychlují vykonávání programu, aniž by negativně ovlivnily jeho funkci. V případě zápisu/čtení do/z registrů, u kterých mohou tyto operace vyvolávat tzv. \textit{side effects}, již může dojít k nesprávné funkci programu.
+I přesto, že se k přístupu k paměti zařízení mapované do paměťového adresního prostoru používá virtuální adresa, stejně jako k přístupu do operační paměti, není možné k paměti zařízení přistupovat přímo \textit{přes ukazatel}. Důvodem je to, že buď překladač (při kompilaci) nebo procesor (za běhu) zoptimalizují\footnote{Tyto optimalizace, v~případě přístupu k operační paměti, urychlují vykonávání programu, aniž by negativně ovlivnily jeho funkci. V případě zápisu/čtení do/z registrů, u kterých mohou tyto operace vyvolávat tzv. \textit{side effects}, již může dojít k nesprávné funkci programu.
 
-Příklad optimalizace: V programu se do jedné paměťové buňky ihned po sobě zapíší dvě různé hodnoty, poté se výsledná hodnota přečte -- optimalizace možná u klasického programu je taková, že se ve skutečnosti provede pouze druhý zápis, protože ten první nemá žádný efekt (hodnota je ihned přepsána druhým zápisem). V případě přístupu do registru zařízení může zápis například spouštět převod A/D převodníků -- po optimalizaci se však provede pouze jednou, nikoliv dvakrát.} sekvenci zápisů/čtení do/z paměti zařízení takovým způsobem, že se výsledek bude lišit od toho, jak to bylo v programu zamýšleno.
+Příklad optimalizace: V programu se do jedné paměťové buňky ihned po sobě zapíší dvě různé hodnoty, poté se výsledná hodnota přečte -- optimalizace možná u klasického programu je taková, že se ve skutečnosti provede pouze druhý zápis, protože ten první nemá žádný efekt (hodnota je ihned přepsána druhým zápisem). V~případě přístupu do registru zařízení může zápis například spouštět převod A/D převodníků -- po optimalizaci se však provede pouze jednou, nikoliv dvakrát.} sekvenci zápisů/čtení do/z paměti zařízení takovým způsobem, že se výsledek bude lišit od toho, jak to bylo v programu zamýšleno.
 
 Těmto optimalizacím lze nejsnáze zabránit použitím volání pro čtení:
 
@@ -946,26 +951,27 @@ nebo v případě PCI zařízení funkce
 se paměť chová jakoby byla v paměťovém adresním prostoru a je nutné pro přístup k ní používat volání popsaná v této kapitole.
 
 
-Pro přístup k paměti zařízení z uživatelského prostoru bohužel žádná sada funkcí není. Je potřeba nadefinovat funkce vlastní, které přistupují k paměti skrze ukazatel, který je ale označen jako \texttt{volatile}. To opět zabrání překladači v optimalizaci kódu manipulujícího s ukazatelem.
+Pro přístup k paměti zařízení z uživatelského prostoru bohužel žádná sada funkcí není. Je potřeba nadefinovat funkce vlastní, které přistupují k paměti skrze ukazatel, který je ale označen jako \texttt{volatile}. To opět zabrání překladači v optimalizaci kódu manipulujícího s~ukazatelem.
 
 Příklad jak takové funkce mohou vypadat:
 
 \begin{verbatim}
-  1 | static inline void mf624_write32(uint32_t val, uint32_t *ptr)
-  2 | {
-  3 |     *(volatile uint32_t*) ptr = val;
-  4 | }
-  5 | static inline int32_t mf624_read32(uint32_t *ptr)
-  6 | {
-  7 |     return (volatile uint32_t) *ptr;
-  8 | }
+  1 |  static inline void mf624_write32(uint32_t val, uint32_t *ptr)
+  2 |  {
+  3 |      *(volatile uint32_t*) ptr = val;
+  4 |  }
+  5 |  static inline int32_t mf624_read32(uint32_t *ptr)
+  6 |  {
+  7 |      return (volatile uint32_t) *ptr;
+  8 |  }
 \end{verbatim}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\newpage
 \section{UIO ovladač}
-V případě, že je vytvářen ovladač pro linuxové jádro, mělo by být rozhodnuto, kterého subsystému se stane součástí -- např. zda jde o jednoduché znakové zařízení, síťovou kartu nebo zvukovou kartu. Tato volba určí, kterou sadu pomocných funkcí bude moci ovladač používat a jakým způsobem bude zpřístupněno zařízení do uživatelského prostoru.
+V~případě, že je vytvářen ovladač pro linuxové jádro, mělo by být rozhodnuto, kterého subsystému se stane součástí -- např. zda jde o jednoduché znakové zařízení, síťovou kartu nebo zvukovou kartu. Tato volba určí, kterou sadu pomocných funkcí bude moci ovladač používat a jakým způsobem bude zpřístupněno zařízení do uživatelského prostoru.
 
-V případě, že zařízení nelze snadno zařadit do žádné kategorie (jedná-li se například o neobvyklou průmyslovou PCI kartu), je možné vytvořit tzv. UIO (\textit{Userspace I/O}) ovladač. Tento ovladač se skládá ze dvou částí: jednoduchého jaderného modulu a aplikace v uživatelském prostoru (viz diagram ma obrázku \ref{uio_diagram}).
+V~případě, že zařízení nelze snadno zařadit do žádné kategorie (jedná-li se například o~neobvyklou průmyslovou PCI kartu), je možné vytvořit tzv. UIO (\textit{Userspace I/O}) ovladač. Tento ovladač se skládá ze dvou částí: jednoduchého jaderného modulu a aplikace v uživatel\-ském prostoru (viz diagram ma obrázku \ref{uio_diagram}).
 
 \begin{figure}[h!]
        \begin{center}
@@ -1001,7 +1007,7 @@ Mezi její hlavní položky patří:
 \begin{description}
 \item[\texttt{const char *name}]~\\Název ovladače. Většinou se shoduje s názvem modulu.
 \item[\texttt{const char *version}]~\\Verze ovladače v textové podobě.
-\item[\texttt{struct uio\_mem mem[MAX\_UIO\_MAPS]}]~\\Pole struktur obsahujících informace o regionech PCI zařízení mapovaných do paměťového prostoru (bude podrobně vysvětleno dále).
+\item[\texttt{struct uio\_mem mem[MAX\_UIO\_MAPS]}]~\\Pole struktur obsahujících informace o regionech PCI zařízení mapovaných do paměťo\-vého prostoru (bude podrobně vysvětleno dále).
 \item[\texttt{struct uio\_port port[MAX\_UIO\_PORT\_REGIONS]}]~\\Pole struktur obsahujících informace o regionech PCI zařízení mapovaných do vstupně-výstupního prostoru (bude podrobně vysvětleno dále).
 \end{description}
 
@@ -1029,26 +1035,26 @@ Struktura \texttt{struct uio\_port} obsahuje položky:
 
 Příklad, jak taková jednoduchá inicializace struktury \texttt{struct uio\_info} včetně registrace může vypadat (bez ošetření chybových stavů):
 \begin{verbatim}
- 1 |  /* struct pci_dev *dev */
- 2 |  struct uio_info *info;
- 3 |  info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
- 4 |  
- 5 |  info->name = "mf624";
- 6 |  info->version = "0.0.1";
- 7 |  
- 8 |  info->mem[0].name = "PCI chipset, ...";
- 9 |  info->mem[0].addr = pci_resource_start(dev, 0);
-10 |  info->mem[0].size = pci_resource_len(dev, 0);
-11 |  info->mem[0].memtype = UIO_MEM_PHYS;
-12 |  info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
-13 |  
-14 |  info->port[0].name = "Board programming registers";
-15 |  info->port[0].porttype = UIO_PORT_X86;
-16 |  info->port[0].start = pci_resource_start(dev, 1);
-17 |  info->port[0].size = pci_resource_len(dev, 1);
-18 |  
-19 |  uio_register_device(&dev->dev, info);
-20 |  pci_set_drvdata(dev, info);
 1 |  /* struct pci_dev *dev */
 2 |  struct uio_info *info;
 3 |  info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
 4 |  
 5 |  info->name = "mf624";
 6 |  info->version = "0.0.1";
 7 |  
 8 |  info->mem[0].name = "PCI chipset, ...";
 9 |  info->mem[0].addr = pci_resource_start(dev, 0);
+ 10 |  info->mem[0].size = pci_resource_len(dev, 0);
+ 11 |  info->mem[0].memtype = UIO_MEM_PHYS;
+ 12 |  info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
+ 13 |  
+ 14 |  info->port[0].name = "Board programming registers";
+ 15 |  info->port[0].porttype = UIO_PORT_X86;
+ 16 |  info->port[0].start = pci_resource_start(dev, 1);
+ 17 |  info->port[0].size = pci_resource_len(dev, 1);
+ 18 |  
+ 19 |  uio_register_device(&dev->dev, info);
+ 20 |  pci_set_drvdata(dev, info);
 \end{verbatim}
 
 \ibox{\texttt{void pci\_set\_drvdata(struct pci\_dev *pdev, void *data)}}
@@ -1061,19 +1067,19 @@ Funkce \texttt{pci\_get\_drvdata()} slouží k \textit{získání} dat uložený
 
 Příklad použití:
 \begin{verbatim}
- 1 |  static void mf624_pci_remove(struct pci_dev *dev)
- 2 |  {
- 3 |      struct uio_info *info = pci_get_drvdata(dev);
- 4 |      /* ... */
- 5 |  }
 1 |  static void mf624_pci_remove(struct pci_dev *dev)
 2 |  {
 3 |      struct uio_info *info = pci_get_drvdata(dev);
 4 |      /* ... */
 5 |  }
 \end{verbatim}
 
 
 \subsection{Program v uživatelském prostoru}
 Poté, co je jaderná část UIO ovladače úspěšně zkompilována a zavedena do systému, ve kterém se nachází požadované zařízení, je rozhraní mezi tímto modulem a uživatelským prostorem tvořeno:
 \begin{itemize}
-\item souborem \texttt{/dev/uio0\footnote{Pro názornost je v textu uvedeno konkrétní zařízení \texttt{uio0}. V případě, že systém obsahuje více aktivních UIO ovladačů, jsou postupně číslovány od 0 výše.}}.
-\item složkou \texttt{/sys/class/uio/uio0}, která obsahuje informace o regionech, které jsou zpřístupněny skrze UIO modul v jádře.
+\item souborem \texttt{/dev/uio0\footnote{Pro názornost je v textu uvedeno konkrétní zařízení \texttt{uio0}. V~případě, že systém obsahuje více aktivních UIO ovladačů, jsou postupně číslovány od 0 výše.}}.
+\item složkou \texttt{/sys/class/uio/uio0}, která obsahuje informace o regionech, které jsou zpří\-stup\-něny skrze UIO modul v jádře.
 \end{itemize}
 
 \subsubsection{Obsah složky \texttt{/sys/class/uio/uio0}}
@@ -1099,26 +1105,26 @@ Tato funkce slouží k \textit{namapování} souboru nebo zařízení do operač
 
 Příklad, jak takové volání může vypadat (bez ošetření chybových stavů):
 \begin{verbatim}
- 1 |  #define BAR2_offset       (1 * sysconf(_SC_PAGESIZE))
- 2 |  
- 3 |  void* mf624_BAR2 = NULL;
- 4 |  int device_fd = open("/dev/uio0", O_RDWR);
- 5 |  
- 6 |  mf624_BAR2 = mmap(0, 1 * sysconf(_SC_PAGESIZE), 
- 7 |                    PROT_READ | PROT_WRITE, MAP_SHARED, 
- 8 |                    device_fd, BAR2_offset);
 1 |  #define BAR2_offset       (1 * sysconf(_SC_PAGESIZE))
 2 |  
 3 |  void* mf624_BAR2 = NULL;
 4 |  int device_fd = open("/dev/uio0", O_RDWR);
 5 |  
 6 |  mf624_BAR2 = mmap(0, 1 * sysconf(_SC_PAGESIZE), 
 7 |                    PROT_READ | PROT_WRITE, MAP_SHARED, 
 8 |                    device_fd, BAR2_offset);
 \end{verbatim}
 
 S adresou vrácenou voláním \texttt{mmap()} však není možné vždy ihned pracovat. Může se stát, že mapovaný region PCI zařízení (reprezentovaný zařízením \texttt{/dev/uio0}, na které je \texttt{mmap()} volán) je menší než je velikost celé stránky, \texttt{mmap()} však vrací ukazatel zarovnaný na velikost stránky. Je tedy potřeba se v rámci této stránky posunout na tu část, která odpovídá požadovanému regionu.
 
 Jak velký je potřeba udělat \textit{posun} pomůže zjistit soubor \texttt{/sys/class/uio/uio0/maps/map1/addr}\footnote{Pro názornost je uvedena konkrétní cesta -- jedná se tedy o \textit{druhý} paměťový region zařízení \textit{uio0}.} -- ten obsahuje fyzickou adresu požadovaného regionu. Z té je možné následujícím trikem získat ukazatel, se kterým je již možné pracovat (nejnižší bity totiž budou zachovány z fyzické adresy):
 \begin{verbatim}
-mf624_BAR2 += (BAR2_phys_addr & (sysconf(_SC_PAGESIZE) - 1));
-  |                \-- Fyzická adresa
-   \-- Ukazatel vrácený voláním mmap()                 
+  mf624_BAR2 += (BAR2_phys_addr & (sysconf(_SC_PAGESIZE) - 1));
+    |                \-- Fyzická adresa
+     \-- Ukazatel vrácený voláním mmap()                 
 \end{verbatim}
 
-\subsection{Přístup k paměti zařízení}
+\subsubsection{Přístup k paměti zařízení}
 Jelikož se jedná o paměť zařízení, je potřeba i v uživatelském prostoru k této paměti přistupovat pomocí speciálních funkcí. Ty jsou popsány v kapitole \ref{iofce}.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1170,7 +1176,7 @@ Každé podporované funcki zařízení/karty by měla odpovídat jedna struktur
 \item[\texttt{int type}]~\\ Označuje druh \textit{podzařízení}. Na výběr jsou např. možnosti: 
 \texttt{COMEDI\_SUBD\_AI} (analogový vstup), \texttt{COMEDI\_SUBD\_AO} (analogový výstup), \texttt{COMEDI\_SUBD\_DI} (digitální vstup), \texttt{COMEDI\_SUBD\_DO} (digitální výstup).
 
-\item[\texttt{int subdev\_flags}]~\\ Označuje základní vlastnost podzařízení. Nejpoužívanější hodnoty: \texttt{SDF\_READABLE} (z podzařízení může být čteno), \texttt{SDF\_WRITABLE} (do podzařízení může být zapisováno).
+\item[\texttt{int subdev\_flags}]~\\ Označuje základní vlastnost podzařízení. Nejpoužívanější hodnoty: \texttt{SDF\_READABLE} (z~pod\-zařízení může být čteno), \texttt{SDF\_WRITABLE} (do podzařízení může být zapisováno).
 
 \item[\texttt{int n\_chan}]~\\ Počet kanálů podzařízení (např. pro 8 digitálních vstupů bude tato hodnota 8).
 
@@ -1194,7 +1200,7 @@ Alokace paměti pro struktury se provede voláním \texttt{alloc\_subdevices()},
 V případě dealokace zdrojů ovladače není potřeba tuto paměť dealokovat -- o uvolnění paměti se postará Comedi subsystém. 
 
 \subsection{Funkce pro čtení a zápis z/do podzařízení}
-Funkce pro čtení, zápis a konfiguraci A/D, D/A převodníků a digitálních vstupů a výstupů mají stejné parametry. Jsou to: \texttt{(struct comedi\_device *dev, 
+Funkce pro čtení, zápis a konfiguraci A/D, D/A převodníků a~digitálních vstupů a~výstupů mají stejné parametry. Jsou to: \texttt{(struct comedi\_device *dev, 
 struct comedi\_sub- device *s, struct comedi\_insn *insn, unsigned int *data)};
 
 V prvním parametru je předán ukazatel na strukturu reprezentující Comedi zařízení. Díky tomu je možné prostřednictvím její proměnné \texttt{private} získat ukazatel na strukturu obsahující privátní data ovladače.
@@ -1204,7 +1210,7 @@ Druhý parametr je ukazatel na strukturu reprezentující podzařízení. Tato s
 Třetí parametr obsahuje ukazatel na strukturu popisující danou \textit{instrukci}, která má být provedena. Důležité položky, které tato struktura obsahuje:
 \begin{description}
 \item[\texttt{unsigned int n}]~\\Udává počet instrukcí, které mají být provedeny
-\item[\texttt{unsigned int chanspec}]~\\Obsahuje informace o kanálu podzařízení, na kterém má být operace provedena. V jedné proměnné typu \texttt{unsigned int} je obsaženo více údajů, proto je potřeba ke čtení používat speciální makro
+\item[\texttt{unsigned int chanspec}]~\\Obsahuje informace o kanálu podzařízení, na kterém má být operace provedena. V~jedné proměnné typu \texttt{unsigned int} je obsaženo více údajů, proto je potřeba ke čtení používat speciální makro
 \texttt{CR\_CHAN()}, které vrací číslo zvoleného kanálu.
 \end{description}
 
@@ -1229,60 +1235,69 @@ Prvním parametrem všech funkcí je ukazatel na \texttt{comedi\_t}. Druhým je
 
 Ukázka jednoduchého userspace programu:
 \begin{verbatim}
 1 |  #include <stdio.h>
 2 |  #include <comedilib.h>
 3 |  #define MF614_DO_SUBDEV      1 /* Je potřeba vědět, jak je 
 4 |                                    implementováno v ovladači */
 5 |  
 6 |  int main(int argc, char* argv[])
 7 |  {
 8 |      comedi_t* comedi_dev;
 9 |  
- 10 |      comedi_dev = comedi_open("/dev/comedi0");
- 11 |      if (comedi_dev == NULL) {
- 12 |          comedi_perror("comedi_open");
- 13 |          return 1;
- 14 |      }
- 15 |
- 16 |      /* Zápis 1 na 0. kanál digitálního výstupu */  
- 17 |      comedi_dio_write(comedi_dev, MF614_DO_SUBDEV, 0, 1);
- 18 |      sleep(1);
- 19 |      comedi_dio_write(comedi_dev, MF614_DO_SUBDEV, 0, 0);
- 20 |      sleep(1);
- 21 |      comedi_dio_write(comedi_dev, MF614_DO_SUBDEV, 0, 1);
- 22 |      
- 23 |      return 0;
- 24 |  }
+ 1 |  #include <stdio.h>
+ 2 |  #include <comedilib.h>
+ 3 |  #define MF614_DO_SUBDEV      1 /* Je potřeba vědět, jak je 
+ 4 |                                    implementováno v ovladači */
+ 5 |  
+ 6 |  int main(int argc, char* argv[])
+ 7 |  {
+ 8 |      comedi_t* comedi_dev;
+ 9 |  
+10 |      comedi_dev = comedi_open("/dev/comedi0");
+11 |      if (comedi_dev == NULL) {
+12 |          comedi_perror("comedi_open");
+13 |          return 1;
+14 |      }
+15 |
+16 |      /* Zápis 1 na 0. kanál digitálního výstupu */  
+17 |      comedi_dio_write(comedi_dev, MF614_DO_SUBDEV, 0, 1);
+18 |      sleep(1);
+19 |      comedi_dio_write(comedi_dev, MF614_DO_SUBDEV, 0, 0);
+20 |      sleep(1);
+21 |      comedi_dio_write(comedi_dev, MF614_DO_SUBDEV, 0, 1);
+22 |      
+23 |      return 0;
+24 |  }
 \end{verbatim}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \chapter{Implementace karty Humusoft MF624 v Qemu}\label{qemu}
-Měřící karta Humusoft MF624 je hardware vhodný pro výklad principů implementace ovladačů. Nevýhodou může být její cena. Pro účely výuky proto byly do emulačního software Qemu implementovány základní funkce této měřící karty -- konkrétně se jedná o A/D převodníky, D/A převodníky a digitální vstupy a výstupy. Takto modifikovaná verze qemu může pří implementaci základního ovladače plně nahradit původní kartu.
+Měřící karta Humusoft MF624 je hardware vhodný pro výklad principů implementace ovladačů PCI zařízení. Nevýhodou může být její cena. Pro účely výuky proto byly do emulačního software Qemu implementovány základní funkce této měřící karty -- konkrétně se jedná o A/D převodníky, D/A převodníky a digitální vstupy a výstupy. Takto modifikovaná verze qemu může pří implementaci základního ovladače plně nahradit původní kartu.
 
-Kromě částečné implementace karty MF624 do Qemu je součástí tohoto \textit{virtuálního hardware} grafická aplikace, která má na starosti nastavování vstupních hodnot a zobrazování výstupních hodnot do/z karty.
+Kromě částečné implementace karty MF624 do Qemu je součástí tohoto \textit{virtuálního hardware} grafická aplikace, která má na starosti nastavování vstupních hodnot a zobrazování výstupních hodnot do/z karty (obr. \ref{qemu_diagram}).
 
 
+\begin{figure}[h!]
+       \begin{center}
+       \includegraphics[width=100mm]{img/qemu.pdf}
+       \caption{Diagram znázorňující princip funkce implementované karty MF624 v Qemu}
+       \label{qemu_diagram}
+       \end{center}
+\end{figure}
+
 \section{Qemu}
 Qemu je emulátor různých procesorových architektur. Od klasických virtualizačních nás\-tro\-jů se odlišuje tím, že podporuje velké kromě IA-32 architektury také např. ARM, SPARC, PowerPC, MIPS, m68k. Qemu umožňuje kromě \textit{plné emulace} (kdy je spuštěn celý operační systém) tzv. \textit{uživatelskou emulaci}, kdy je v uživatelském prostoru spuštěn program zkompilovaný pro jinou architekturu. Uživatelská emulace je možná pouze pro operační systém GNU/Linux.
 
 \subsection{Kompilace, instalace}
 Po stažení a rozbalení zdrojových kódů některé ze stabilních verzí emulátoru Qemu je potřeba spustit příkaz (na počítači architektury AI-32):
 \begin{verbatim}
-    $ ./configure --enable-system  --target-list=i386-softmmu
+  $ ./configure --enable-system  --target-list=i386-softmmu
 \end{verbatim}
 
 V případě, že spuštěný skript neohlásí žádné chybějící knihovny, je možné spustit  samotnou kompilaci:
 \begin{verbatim}
-    $ make
+  $ make
 \end{verbatim}
 
 \subsection{Kompilace virtuální karty Humusoft MF624}
-V případě, že je potřeba zkompilovat virtuální kartu MF624, je potřeba  před kompilací překopírovat zdrojový soubor implementující zařízení do složky \texttt{/hw} a do souboru \texttt{Makefile.objs} (nachází se v kořenovém adresáři se zdrojovými kódy) přidat řádek \begin{verbatim}
-    hw-obj-$(CONFIG_PCI) += mf624.o
+V případě, že je potřeba zkompilovat virtuální kartu MF624, je potřeba  před kompilací překopírovat zdrojový soubor implementující zařízení do složky \texttt{/hw} a do souboru \texttt{Makefile.objs} (nachází se v kořenovém adresáři se zdrojovými kódy) přidat řádek
+\begin{verbatim}
+  hw-obj-$(CONFIG_PCI) += mf624.o
 \end{verbatim}
 Poté je již možné spustit příkaz
 \begin{verbatim}
-    $ make
+  $ make
 \end{verbatim}
 
 
@@ -1293,15 +1308,15 @@ V případě správně zkompilované virtuální karty MF624, je možné ji spus
 
 Příklad spuštění:
 \begin{verbatim}
-    $ ./qemu -device mf624 -hda ../os_images/debian.qcow --boot c 
-    MF624 Loaded.
-    Waiting on port 55555 for MF624 client to connect
-    Client connected
+  $ ./qemu -device mf624 -hda ../os_images/debian.qcow --boot c 
+  MF624 Loaded.
+  Waiting on port 55555 for MF624 client to connect
+  Client connected
 \end{verbatim}
 
 Příklad ovládání vstupů a zobrazování výstupů karty pomocí aplikace \texttt{telnet}:
 \begin{verbatim}
-$ telnet localhost 55555
+  $ telnet localhost 55555
   Trying ::1...
   Trying 127.0.0.1...
   Connected to localhost.
@@ -1317,15 +1332,15 @@ $ telnet localhost 55555
 \section{Qt grafiké rozhraní}\label{qt_gui_ch}
 Pro komunikaci s virtuální kartou MF624 bylo implementováno jednoduché grafické rozhraní, které má na starosti vykreslování hodnot výstupů karty (nastavovaných ovladačem běžícím v operačním systému virtualizovaném Qemu) a posílání nastavovaných vstupních hodnot zpět virtuální kartě.
 
-Komunikace mezi virtuální kartou a grafickou aplikací probíhá pomocí TCP/IP protokolu. Přenášené informace jseou textového charakteru, ve formátu \texttt{REGISTR=HODNOTA}.
+Komunikace mezi virtuální kartou a grafickou aplikací probíhá pomocí TCP/IP protokolu. Přenášené informace jsou textového charakteru, ve formátu \texttt{REGISTR=HODNOTA}.
 
 Na obrázku \ref{qt_gui} je vidět vzhled grafické aplikace.
 
 \subsection{Kompilace, použití}
-Grafická aplikace je vytvořena za pomoci grafického knihovny Qt. V případě, že jsou v systému nainstalovány vývojářské verze Qt knihoven, včetně vývojářských nástrojů, stačí pro kompilaci spustit
+Grafická aplikace je vytvořena za pomoci grafického knihovny Qt. V případě, že jsou v~systému nainstalovány vývojářské verze Qt knihoven, včetně vývojářských nástrojů, stačí pro kompilaci spustit
 \begin{verbatim}
-    $ qmake
-    $ make
+  $ qmake
+  $ make
 \end{verbatim}
 
 Použití aplikace by mělo být intuitivní. Položky, u kterých není možné měnit jejich hodnotu, jsou záměrně pouze pro čtení (zobrazují výstupní hodnoty).