]> rtime.felk.cvut.cz Git - mf6xx.git/commitdiff
Diploma thesis text.
authorRostislav Lisovy <lisovy@gmail.com>
Tue, 19 Apr 2011 20:45:29 +0000 (22:45 +0200)
committerRostislav Lisovy <lisovy@gmail.com>
Tue, 19 Apr 2011 20:45:29 +0000 (22:45 +0200)
doc/diploma_thesis/text/dip_text.tex

index 3763e50078e346a90fb2e9f5f676ca5d0f2cdf55..ee0263e66d4f6b3b2a1e3ef91cd4d80cc5afba56 100644 (file)
@@ -1,3 +1,9 @@
+%FIXME
+% vlna
+% \caption{} bez tečky na konci
+% \item[] a \item s tečkou na konci
+% odsazování zdrojáků
+
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \chapter{Úvod}
 \section{Motivace, cíl}
@@ -74,7 +80,7 @@ Hlavní rozdíly mezi chováním paměťové buňky a registru zařízení jsou:
 \begin{figure}[h!]
        \begin{center}
        \includegraphics[width=100mm]{img/mmio.pdf}
-       \caption{Paměťový a vstupně-výstupní prostor u architektury IA-32.}
+       \caption{Paměťový a vstupně-výstupní prostor u architektury IA-32}
        \label{mmio}
        \end{center}
 \end{figure}
@@ -90,7 +96,7 @@ PCI (\textit{Peripheral Component Interconnect}) je standard paralelní sběrnic
 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.
 
 \subsection{Historie}
-V roce 1990 začala práce na specifikaci PCI v laboratořích firmy Intel. První specifikace definující jak komunikační protokol, tak vzhled konektoru a slotu, byla zveřejněna 30. dubna 1993 (jedná se o PCI 2.0). PCI sběrnice se poté začala objevovat v počítačích architektury PC XT a Power Macintosh.
+V roce 1990 začala práce na specifikaci PCI v laboratořích firmy Intel. První specifikace definující jak komunikační protokol, tak vzhled konektoru a slotu, byla zveřejněna 30. dubna 1993 (jedná se o PCI 2.0). PCI sběrnice se poté začala objevovat v počítačích architektury PC XT a PowerPC.
 
 V pozdějších letech se původní standard dočkal vylepšení -- zvýšení šířky paralelní sběrnice z 32 bitů na 64 bitů a zrychlení z 33 MHz na 66 Mhz a výše. Tyto pokročilejší verze se však příliš neujaly.
 \subsection{Konektory}
@@ -110,7 +116,7 @@ Pro spojení mezi kartou a sběrnicí je potřeba pouze konektor na straně sbě
 \end{figure}
 
 
-\subsection{Dynamická konfigurace a konfigurační adresní prostor}
+\subsection{Dynamická konfigurace a konfigurační adresní prostor}\label{pci_conf}
 Mezi hlavní výhody PCI sběrnice (oproti její předchůdkyni -- sběrnicic 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 jednolivá 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čteovladač zařízení, který je součástí opračního systému.
@@ -131,7 +137,7 @@ Registry \texttt{Vendor ID}, \texttt{Device ID} (příp. ještě \texttt{Subsyst
 \begin{figure}[h!]
        \begin{center}
        \includegraphics[width=80mm]{img/pci-config-space2.pdf}
-       \caption{Obsah 256 bajtů konfiguračního prostoru PCI karty (zvýrazněny jsou nejdůležitější registry).}
+       \caption{Obsah 256 bajtů konfiguračního prostoru PCI karty (zvýrazněny jsou nejdůležitější registry)}
        \label{sa1}
        \end{center}
 \end{figure}
@@ -348,7 +354,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ů, 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ý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. 
 
 \begin{table}[h!]
        \begin{center}
@@ -391,12 +397,12 @@ Po nahlédnutí do manuálu (dostupný ze stránek výrobce: \url{http://www2.hu
        \hline BADR2 + 0x10 & \textbf{STATUS} -- Status register & \\   
        \hline 
        \end{tabular} 
-       \caption{Paměťové a vstupně-výstupní regiony, které využívá karta MF614}
+       \caption{Registry karty MF614 názežící digitálním vstupům/výstupům a analogovým vstupům/výstupům}
        \label{tab_mf614_regs}
        \end{center}
 \end{table}
 
-Jednotlivé registry v těchto regionech jsou 8bitové, proto je potřeba při čtení/zápisu používat pouze 8bitové funkce. Např. 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:
+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;
@@ -608,7 +614,7 @@ Při psaní základního modulu pro jádro Linux nejsou patrné větší rozdíl
 \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í nikdo, kdo by se postaral o naalokovanou paměť. FIXME
-\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 poškození síťových karet Intel e1000e: \url{http://www.abclinuxu.cz/clanky/jaderne-noviny/jaderne-noviny-22.-10.-2008\#pricina-chyby-poskozujici-e1000e}}.
+\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. FIXME.
 \end{description}
 
@@ -616,74 +622,93 @@ Při psaní základního modulu pro jádro Linux nejsou patrné větší rozdíl
 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é dealokace. FIXME
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\section{Ovladače PCI zařízení}
+\section{Ovladače PCI zařízení}\label{pci_driv}
 \ibox{Jako nejlepší reference jednotlivých funkcí slouží zdrojové kódy jádra. Pro prohlížení zdrojových kódů jádra mohu doporučit online \textit{The Linux Cross Reference} -- \\
-\url{http://lxr.linux.no/}.}
+\url{http://lxr.linux.no/linux/}.}
+
+Ovladače PCI zařízení jsou ve většině případů kompilovány jako jaderné moduly, dynmicky 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 prosotru) 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}.
+
+\subsection{Struktura \texttt{struct pci\_device\_id}}\label{pci_dev_id}
+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 |  };
+\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í 
+i pro Subdevice ID).
+
+\ibox{\texttt{MODULE\_DEVICE\_TABLE(type, struct pci\_device\_id* name);}}
 
-První věc, kterou ovladač PCI zařízení potřebuje udělat, aby se stal součástí systému, je registrace do seznamu všech PCI ovladačů v operačním systému. To se provede voláním funkce \texttt{pci\_register\_driver()}, které se jako parametr předá ukazatel na strukturu \texttt{struct pci\_driver}. 
+Tato struktura se -- pro nástroje v uživatelském prostoru vytvářející seznamy ovladačů -- exportuje pomocí makra \texttt{MODULE\_DEVICE\_TABLE(pci, mf624\_pci\_id)}, kde první parametr určuje typ zařízení a druhý je ukazatel na seznam typu \texttt{struct pci\_device\_id}.
 
 \subsection{Struktura \texttt{struct pci\_driver}}
-Tato struktura obsahuje základní informace o našem ovladači. Mezi hlavní položky patří:
+Pro to, aby mohl se mohl ovladač PCI zařízení stát součástí jaderného PCI subsystému, je potřeba ho do zaregistrovat. To se provede voláním funkce \texttt{pci\_register\_driver()}, které se jako parametr předá ukazatel na strukturu \texttt{struct pci\_driver}. 
+
+Tato struktura obsahuje základní informace o ovladači -- základní proměnné a ukazatele na funkce. Mezi hlavní položky patří:
 \begin{description}
 \item[\texttt{const char name*}]~\\Název ovladače. Tento název by měl být unikátní mezi všemi ovladači PCI zařízení. Většinou je totožný s názvem modulu.
-\item[\texttt{const struct pci\_device\_id *id\_table}]~\\Pole struktur popisujících, pro která zařízení je ovladač vytvořen (jednotlivé položky struktury jsou popsány níže).
+\item[\texttt{const struct pci\_device\_id *id\_table}]~\\Pole struktur popisujících, pro která zařízení je ovladač vytvořen (viz kap. \ref{pci_dev_id}).
 \item[\texttt{int (*probe) (struct pci\_dev *dev, const struct pci\_device\_id *id)}]~\\Ukazatel na funkci, která je volána PCI subsystémem, v případě, že je přítomno zařízení, pro které je tento ovladač vytvořen.
 \item[\texttt{void (*remove) (struct pci\_dev *dev)}]~\\Ukazatel na funkci, která je volána poté, co je tento ovladač odstraňován ze seznamu ovladačů aktuálně používaných PCI subsystémem.
 \end{description}
 
 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 |  };
-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}
 
-\subsection{Struktura \texttt{struct pci\_device\_id}}
-Jak již bylo zmíněno, 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. Možná inicializace vypadá následovně:
-
-\begin{verbatim}
- 1 |  #define PCI_VENDOR_ID_HUMUSOFT          0x186c
- 2 |  #define PCI_DEVICE_ID_MF624             0x0624
- 3 |  #define PCI_SUBVENDOR_ID_HUMUSOFT       0x186c
- 4 |  #define PCI_SUBDEVICE_DEVICE            0x0624
- 5 |  
- 6 |  static struct pci_device_id mf624_pci_id[] = {
- 7 |      {
- 8 |          .vendor = PCI_VENDOR_ID_HUMUSOFT,
- 9 |          .device = PCI_DEVICE_ID_MF624,
-10 |          .subvendor = PCI_SUBVENDOR_ID_HUMUSOFT,
-11 |          .subdevice = PCI_SUBDEVICE_DEVICE,
-12 |      },
-13 |      { 0, } /* seznam je vždy zakončen prázdným prvkem */
-14 |  };
-\end{verbatim}
 
-
-\subsection{Funkce \texttt{probe()}}
+\subsection{Funkce \texttt{probe()}}\label{pci_init}
 \ibox{\texttt{int probe(struct pci\_dev *dev, const struct pci\_device\_id *id);}}
 
-Funkce \texttt{probe()} náležící danému ovladači zařízení je volána poté, co subsystém PCI zařízení zjistí, že se v systému nachází zařízení, pro které je tento ovladač určen. Tato funkce má na starosti inicializaci zařízení.
+Funkce \texttt{probe()} náležící danému ovladači zařízení je volána poté, co jaderný subsystém PCI zařízení zjistí, že se v systému nachází zařízení, pro které je tento ovladač určen. Tato funkce má na starosti inicializaci zařízení.
 
-V prvním parametru PCI subsystém předává strukturu \texttt{struct pci\_dev}, která repre\-zentuje fyzické zařízení. V druhém parametru je předána struktura, na základě byl zvolen daný ovladač.
+Prvním parametrem funkce předává PCI subsystém ukazatel na strukturu \texttt{struct pci\_dev}, která repre\-zentuje fyzické zařízení. V druhém parametru je předán ukazatel na strukturu, na základě které byl zvolen daný ovladač (viz kap. \ref{pci_dev_id}).
 
 \ibox{\texttt{pci\_enable\_device(struct pci\_dev *dev);}}
 
-V rámci inicializace je nejprve potřeba zavolat funkci \texttt{pci\_enable\_device()} -- ta se postará o inicializaci karty na úrovni hardware -- např.: přiřazení linky přerušení, zresetování registrů karty a její probuzení. Poté již můžeme začít přistupovat ke zdrojům zařízení.
+V rámci inicializace ovladače je nejprve potřeba zavolat funkci \texttt{pci\_enable\_device()} -- ta se postará o inicializaci karty na úrovni hardware -- např.: přiřazení linky přerušení, zresetování registrů karty a její probuzení. Poté je již možné začít přistupovat ke zdrojům zařízení.
 
 \subsection{Přístup ke zdrojům karty}
-Jak bylo popsáno v kapitole \ref{pcich}, PCI zařízení může využívat až 6 paměťových nebo vstupně-výstupních regionů (označovaných jako \textit{zdroje} karty). Jejich alokace do paměťového nebo I/O prostoru počítače je zajištěna dynamicky PCI mostem. Pro přístup do nich si musí ovladač zařízení zjistit jejich adresu a vyžádat si u operačního systému výlučný přístup
+Jak bylo popsáno v kapitole \ref{pci_conf}, PCI zařízení může využívat až 6 paměťových nebo vstupně-výstupních regionů (označovaných jako \textit{zdroje} karty). Jejich alokace do paměťového nebo I/O prostoru počítače je zajištěna dynamicky PCI mostem. Pro přístup do regionů si musí ovladač zařízení zjistit jejich adresu a vyžádat si u operačního systému \textit{výlučný přístup}
 
 \ibox{\texttt{int pci\_request\_regions(struct pci\_dev *pdev, const char *res\_name);}}
 
-Nejprve je potřeba operační systém požádat o výlučný přístup ke zdrojům zařízení. To se provede voláním funkce \texttt{pci\_request\_regions()}. V případě, že ovladači není přístup umožněn (jiný ovladač přistupuje ke stejné kartě nebo po jeho odstranění nedošlo k uvolnění zdrojů karty), ovladač by měl korektním způsobem ukončit svoji funkci a nesnažit se k zařízení přistupovat.
+Nejprve je potřeba operační systém požádat o výlučný přístup ke zdrojům zařízení. To se provede voláním funkce \texttt{pci\_request\_regions()}. Je-li návratová hodnota zavolané funkce negativní, není ovladači umožněn přístup (jiný ovladač přistupuje ke stejné kartě nebo po jeho odstranění nedošlo k uvolnění zdrojů karty). V takovém případě by ovladač měl korektním způsobem ukončit svoji funkci a nesnažit se k zařízení přistupovat.
 
 \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ů zjistíme 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);}}
 
@@ -693,9 +718,7 @@ V případě, že je potřeba zjistit velikost daného paměťového nebo I/O re
 
 S ukazatelem, který vrátí funkce \texttt{pci\_request\_regions()} však není možné přímo pracovat -- je to toiž \textbf{fyzická adresa} daného regionu, ke které neumí procesor přímo přistupovat. Aby tato fyzická adresa byla přemapována na adresu \textbf{virtuální}, je potřeba zavolat funkci \texttt{pci\_ioremap\_bar()}.
 
-K ukazateli, který vrátí volání \texttt{pci\_ioremap\_bar()} je již možné pomocí speciálních funkcí přistupovat.
-
-\ibox{FIXME povídání o out-of-order execution a cache a proč musíme používat speciální funkce}
+K ukazateli, který vrátí volání \texttt{pci\_ioremap\_bar()} je již možné pomocí speciálních funkcí (popsány v kap. \ref{iofce}) přistupovat.
 
 \subsection{Funkce \texttt{remove()}}
 
@@ -703,7 +726,7 @@ K ukazateli, který vrátí volání \texttt{pci\_ioremap\_bar()} je již možn
 
 Funkce je volána, když PCI subsystém ze svého seznamu odstraňuje strukturu \texttt{struct pci\_dev} reprezentující dané zařízení, nebo v případě, že dochází k uvolnění modulu.
 
-Tato funkce by se měla postarat o úklid všech naalokovaných prostředků apod. Měla by obsahovat volání:
+Tato funkce by se měla postarat o úklid všech naalokovaných prostředků. Měla by obsahovat volání:
 \begin{description}
 \item[\texttt{iounmap()}]~\\Uvolnění virtuální paměti namapované voláním \texttt{pci\_ioremap\_bar()}.
 \item[\texttt{pci\_release\_regions()}]~\\Uvolnění zdrojů karty, které byly zarezervovány voláním \texttt{pci\_request\_regions()}.
@@ -711,7 +734,7 @@ Tato funkce by se měla postarat o úklid všech naalokovaných prostředků apo
 \end{description}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-\section{Přístup k paměti zařízení}
+\section{Přístup k paměti zařízení}\label{iofce}
 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}
@@ -735,13 +758,14 @@ Pro zápis je možné využít volání:
 
 Třetí písmeno, stejně jako u funkcí pro čtení, značí o kolikabitový přístup se jedná.
 
-Stejná volání je možné používat i z uživatelského prostoru (potřebný hlavičkový soubor je \texttt{<sys/io.h>}).
+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.
 
 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í:
+Těmto optimalizacím lze nejsnáze zabránit použitím volání pro čtení:
 
 \ibox{\texttt{unsigned int ioread8(void *addr);}}
 
@@ -749,7 +773,7 @@ Těmto optimalizacím lze nejsnáze zabránit použitím volání:
 
 \ibox{\texttt{unsigned int ioread32(void *addr);}}
 
-pro čtení a volání
+a pro zápis:
 
 \ibox{\texttt{void iowrite8(u8 value, void *addr);}}
 
@@ -757,24 +781,38 @@ pro čtení a volání
 
 \ibox{\texttt{void iowrite32(u32 value, void *addr);}}
 
-pro zápis. Číslo na konci funkce označuje o kolikabitový přístup se jedná.
+Číslo na konci funkce označuje o kolikabitový přístup se jedná.
 
 V případě, že se na paměť ve vstupně-výstupním adresním prostoru zavolá funkce 
 \ibox{\texttt{void *ioport\_map(unsigned long port, unsigned int count);}} 
 nebo v případě PCI zařízení funkce
-\ibox{\texttt{void \_\_iomem *pci\_iomap(struct pci\_dev *dev, int bar, unsigned long maxlen);}}
+\ibox{\texttt{void *pci\_iomap(struct pci\_dev *dev, int bar, unsigned long maxlen);}}
 
-je tato paměť \textit{přemapována} do paměťového adresního prostoru a je nutné pro přístup k ní používat výše popsaná volání.
+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.
 
-Z uživatelského prostoru je potřeba používat volání FIXME.
+
+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 | }
+\end{verbatim}
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 \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 uřčí, 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 jde o PCI zařízení, které nelze snadno zařadit do žádné kategorie (jedná-li se například o neobvyklou průmyslovou kartu), je možné použít tzv. UIO (\textit{Userspace I/O}) ovladač. Tento ovladač se skládá ze dvou částí: jaderného modulu a aplikace v uživatelském prostoru. Mezi jeho hlavní výhody patří to, že v jádře je obsažena pouze malá obecná část, která zpřístupňuje zdroje zařízení do uživatelského prostoru (její implementace je poměrně snadná).
+V případě, že jde o PCI zařízení, které nelze snadno zařadit do žádné kategorie (jedná-li se například o neobvyklou průmyslovou 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. 
 
-Druhou částí je aplikace v uživateském prosotru, která přistupuje k jednotlivým zdrojům karty a tvoří hlavní logiku ovladače. Většina vývoje tedy probíhá v uživatelském prostoru, čímž klesá riziko narušení stability jádra.
+Mezi jeho hlavní výhody patří to, že v jádře je obsažena pouze malá obecná část, která zpřístupňuje zdroje zařízení do uživatelského prostoru (její implementace je poměrně snadná). Druhou částí je aplikace v uživateském prostoru, která přistupuje k jednotlivým zdrojům karty a tvoří hlavní logiku ovladače. Většina vývoje tedy probíhá v uživatelském prostoru, čímž klesá riziko narušení stability jádra.
 
 \subsection{Jaderný modul}
 Jaderný modul UIO ovladače by měl obsahovat:
@@ -785,23 +823,25 @@ Jaderný modul UIO ovladače by měl obsahovat:
 \item Funkce pro \textit{úklid} a uvolnění regionů karty
 \end{itemize}
 
-Většina z těchto úkonů již byla popsána v kapitole \ref{pcich} a jsou zcela standardní pro jakýkoliv ovladač PCI zažízení, navíc je zde pouze \textit{registrace do UIO subsystému}.
+Většina z těchto úkonů již byla popsána v kapitole \ref{pci_driv} a jsou zcela standardní pro jakýkoliv ovladač PCI zažízení. Co nebylo dosud popsáno je pouze úkon \textit{registrace do UIO subsystému}.
 
 \ibox{\texttt{int uio\_register\_device(struct device *parent, struct uio\_info *info);}}
 
-Ta se provede zavoláním funkce \texttt{uio\_register\_device()}, které se jako první parametr předá \textit{rodič} struktury \texttt{struct pci\_dev} struktury -- tj. ukazatel na její položku \texttt{dev}.\footnote{FIXME; WTF is this?} Druhý parametr předá ukazatel na strukturu \texttt{struct uio\_info}.
+Registrace UIO ovladače se provede zavoláním funkce \texttt{uio\_register\_device()}, které se jako první parametr předá \textit{rodič} FIXME struktury \texttt{struct pci\_dev} struktury -- tj. ukazatel na její položku \texttt{dev}. Druhý parametr předá ukazatel na strukturu \texttt{struct uio\_info}.
 
 \subsubsection{Struktura \texttt{struct uio\_info}}
+
+Jedná se o strukturu vyplněnou informacemi o zařízení, která je předána při registraci UIO subsystému.
 Mezi její hlavní položky patří:
 \begin{description}
-\item[\texttt{const char *name}]~\\Název ovladače
-\item[\texttt{const char *version}]~\\Verze ovladače
-\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
-\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.
+\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\_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).
 %\item[\texttt{}]
 \end{description}
 
-\subsubsection{Struktura \texttt{struct uio\_mem} a \texttt{struct uio\_port}}
+\subsubsection{Struktura \texttt{struct uio\_mem} a \texttt{struct uio\_port}}\label{uio_mem_port}
 Tyto struktury obsahují imformace o regionech zařízení. Které (a kolik) z těchto dvou struktur budou inicializovány záleží na tom, zda karta mapuje regiony do paměťového nebo vstupně-výstupního prostoru.
 
 Struktura \texttt{struct uio\_mem} obsahuje položky:
@@ -810,7 +850,7 @@ Struktura \texttt{struct uio\_mem} obsahuje položky:
 \item[\texttt{unsigned long addr}]~\\Fyzická adresa regionu získaná voláním \texttt{pci\_resource\_start()}.
 \item[\texttt{unsigned long size}]~\\Délka regionu. Nejsnáze získaná voláním \texttt{pci\_resource\_len()}.
 \item[\texttt{int memtype}]~\\Typ paměti. Pro fyzickou paměť na zařízení se použije \texttt{UIO\_MEM\_PHYS}.
-\item[\texttt{void \_\_iomem *internal\_addr}]~\\Virtuální adresa získaná voláním \texttt{pci\_ioremap\_bar()}
+\item[\texttt{void \_\_iomem *internal\_addr}]~\\Virtuální adresa získaná voláním \texttt{pci\_ioremap\_bar()}.
 \end{description}
 
 Struktura \texttt{struct uio\_port} obsahuje položky:
@@ -818,12 +858,12 @@ Struktura \texttt{struct uio\_port} obsahuje položky:
 \item[\texttt{const char *name}]~\\Textový popis daného regionu (viditelný z uživatelského prostoru).
 \item[\texttt{unsigned long start}]~\\Fyzická adresa regionu získaná voláním \texttt{pci\_resource\_start()}.
 \item[\texttt{unsigned long size}]~\\Délka regionu. Nejsnáze získaná voláním \texttt{pci\_resource\_len()}.
-\item[\texttt{int porttype}]~\\Typ portu. Pro porty na architektuře IA-32 se použije \texttt{UIO\_PORT\_X86}
+\item[\texttt{int porttype}]~\\Typ portu. Pro porty na architektuře IA-32 se použije \texttt{UIO\_PORT\_X86}.
 \end{description}
 
 ~\\
 
-Příklad, jak taková jednoduchá inicializace struktury \texttt{struct uio\_info} včetně registrace může vypadat (bez ošetření chybných stavů):
+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;
@@ -849,48 +889,65 @@ Příklad, jak taková jednoduchá inicializace struktury \texttt{struct uio\_in
 
 \ibox{\texttt{void pci\_set\_drvdata(struct pci\_dev *pdev, void *data)}}
 
-Na posledním řádku je, dosud nepopsané, volání \texttt{pci\_set\_drvdata()}. To (v tomto případě) zajistí, že struktura \texttt{struct uio\_info} se stane součástí struktury reprezentující zařízení (\texttt{struct pci\_dev}) -- což umožní přístup ke struktuče \texttt{struct uio\_info} z funkcí jako je například funkce \texttt{remove()}, která jako parametr získá ukazatel na strukturu \texttt{struct pci\_dev}
+Na posledním řádku je, dosud nepopsané, volání \texttt{pci\_set\_drvdata()}. To (v tomto případě) zajistí, že struktura \texttt{struct uio\_info} se stane součástí struktury reprezentující zařízení (\texttt{struct pci\_dev}) -- což umožní pozdější přístup ke struktuře \texttt{struct uio\_info} z funkcí jako je například \texttt{remove()}, která jako parametr získá ukazatel na strukturu \texttt{struct pci\_dev}.
+
+\ibox{\texttt{static inline void *pci\_get\_drvdata(struct pci\_dev *pdev)}}
+
+Funkce \texttt{pci\_get\_drvdata()} slouží k \textit{získání} dat uložených do struktury \texttt{struct pci\_dev} pomocí volání \texttt{pci\_set\_drvdata()}.
+
+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 |  }
+\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 v textu uvádím 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 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.
 \end{itemize}
 
 \subsubsection{Obsah složky \texttt{/sys/class/uio/uio0}}
-Tato složka obsahuje soubory převážně pouze pro čtení. Obsahuje podložku \texttt{maps}, ve které se nachází pro každý region PCI zařízení mapovaný do paměti (zpřístupněný jaderným ovladačem) složka obsahující soubory popisující tyto regiony (Soubor \texttt{addr} obsahuje fyzickou adresu regionu; \texttt{name} slovní pojmenování; \texttt{size} velikost regionu).
+Tato složka obsahuje soubory převážně pouze pro čtení. Obsahuje podsložku \texttt{maps}, ve které se nachází pro každý region PCI zařízení mapovaný do paměti (zpřístupněný jaderným ovladačem) složka obsahující soubory popisující tyto regiony (Soubor \texttt{addr} obsahuje fyzickou adresu regionu; \texttt{name} slovní pojmenování; \texttt{size} velikost regionu).
+
+V případě, že jsou zpřístupněny regiony rařízení, které jsou mapovány do vstupně-výstupního adresního prostoru, nacházejí se jednotlivé podsložky a soubory popisující regiony ve složce \texttt{portio}.
 
 \subsubsection{Soubor \texttt{/dev/uio0}}
-Tento soubor je využíván k samotnému přístupu k regionům karty. K souboru se přistupuje pomocí volání \texttt{mmap()}.
+Tento soubor tvoří rozhraní mezi jaderným subsystémem UIO a uživatelským prostorem. Skrze něj je přistupováno k regionům karty. K souboru se přistupuje pomocí volání \texttt{mmap()}.
 
 \ibox{\texttt{void *mmap(void *addr, size\_t length, int prot, int flags, int fd, off\_t offset);}}
 
-Tato funkce slouží k \textit{namapování} souboru nebo zařízení do operační paměti. V případě, že funkci zavoláme na soubor, proběhne-li vše správně, návratová hodnota bude obsahovat ukazatel do paměti, kam je možné přistu\-povat k obsahu souboru pomocí ukazatelové aritmetiky -- stejně, jako by to byla paměť.
+Tato funkce slouží k \textit{namapování} souboru nebo zařízení do operační paměti. V případě, že je funkce zavolána na soubor, proběhne-li vše správně, návratová hodnota bude obsahovat ukazatel do paměti, kam je možné přistu\-povat k obsahu souboru pomocí ukazatelové aritmetiky -- stejně, jako by to byla paměť.
  
 \begin{description}
-\item[Parametr \texttt{addr}] -- v případě, že není nulový -- určí, na jakou adresu by měla být paměť mapována.
-\item[Parametr \texttt{length}] udává velikost mapované paměti v násobcích velikosti paměťové stránky. 
-\item[Parametr \texttt{prot}] obsahuje příznaky definující, zda bude mapovaná paměť pro čtení/zápis, apod.
-\item[Parametr \texttt{flags}] pomocí příznaku určuje, zda se mají změny zapisovat pouze do \textit{lokální kopie} (příznak \texttt{MAP\_PRIVATE}) nebo zda mají být zapisovány do původního souboru/zařízení (příznak \texttt{MAP\_SHARED}).
-\item[Parametr \texttt{fd}] obsahuje \textit{filedescriptor} na zařízení, které má být namapováno (v tomto případě \texttt{/dev/uio0}).
-\item[Parametr \texttt{offset}] určuje, zda se zaný soubor/zařízení začne mapovat od posunuté adresy. V případě UIO ovladače je možné jako offset používat násobky velikosti paměťové stránky -- tento offset určí, který z regionů zpřístupněných jadernou částí ovladače má být namapován.
+\item[Parametr \texttt{addr}]~\\V případě, že není nulový, určí na jakou adresu by měla být paměť mapována.
+\item[Parametr \texttt{length}]~\\ Udává velikost mapované paměti v násobcích velikosti paměťové stránky. 
+\item[Parametr \texttt{prot}]~\\ Obsahuje příznaky definující, zda bude mapovaná paměť pro čtení/zápis, apod.
+\item[Parametr \texttt{flags}]~\\ Pomocí příznaku určuje, zda se mají změny zapisovat pouze do \textit{lokální kopie} (příznak \texttt{MAP\_PRIVATE}) nebo zda mají být zapisovány do původního souboru/zařízení (příznak \texttt{MAP\_SHARED}).
+\item[Parametr \texttt{fd}]~\\ Obsahuje \textit{filedescriptor} na zařízení, které má být namapováno (v tomto případě file\-desc\-riptor vrácený voláním \texttt{open("/dev/uio0", ... );}).
+\item[Parametr \texttt{offset}]~\\ Určuje, zda se zaný soubor/zařízení začne mapovat od posunuté adresy. V případě UIO ovladače je možné jako offset používat násobky velikosti paměťové stránky -- tento offset určí, který z regionů zpřístupněných jadernou částí ovladače má být namapován.
 \end{description}
 
-Příklad, jak takové volání může vypadat (bez ošetření chybných stavů):
+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 |  void* mf624_BAR2 = NULL;
-3 |  int device_fd = open("/dev/uio0", O_RDWR);
-4 |  
-5 |  mf624_BAR2 = mmap(0, 1 * sysconf(_SC_PAGESIZE), 
-6 |                    PROT_READ | PROT_WRITE, MAP_SHARED, 
-7 |                    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 uvádím konkrétní cestu -- 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):
+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
@@ -898,16 +955,15 @@ mf624_BAR2 += (BAR2_phys_addr & (sysconf(_SC_PAGESIZE) - 1));
 \end{verbatim}
 
 \subsection{Přístup k paměti zařízení}
-Podobně jakou u jaderného modulu komunikujícího s pamětí zařízení, je potřeba i v uživatelském prostoru k této paměti přistupovat pomocí speciálních funkcí.
-FIXME
+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}.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\newpage
 \section{Comedi ovladač}
 UIO ovladač dává uživateli možnost využít 100 \% všech funkcí zařízení -- daní za to je pomalejší odezva než v případě plnohodnotného jaderného ovladače.
 
 Pro ovladače měřících karet existuje v Linuxu subsystém -- tzv. Comedi (Control and Measurement Device Interface).
-\subsection{Registrace Comedi ovladače}
-V případě Comedi ovladače se namísto volání \texttt{module\_init()} a \texttt{module\_exit()} zavolá makro \texttt{COMEDI\_INITCLEANUP()}, kterému se jako parametr předá struktura \texttt{struct comedi\_driver} (toto makro však ve skutečnosti volá výše zmíněné standardní funkce).
+\subsection{Registrace ovladače}
 
 \subsection{Struktura \texttt{struct comedi\_driver}}
 Tato struktura obsahuje ukazatele na funkce, které jsou zavolány při nahrání resp. uvolnění ovladače.
@@ -930,20 +986,7 @@ Po inicializaci správnými hodnotami se pro registraci zavolá makro \texttt{MO
 
 Příklad základní registrace zařízení:
 \begin{verbatim}
- 1 |  static struct pci_device_id mf624_pci_table[] = {
- 2 |      { /* ... */ },
- 3 |      { 0 }
- 4 |  };
- 5 |  MODULE_DEVICE_TABLE(pci, mf624_pci_table);
- 6 |  
- 7 |  static struct comedi_driver driver_mf624 = {
- 8 |      driver_name:  "mf624",
- 9 |      module:       THIS_MODULE,
-10 |      attach:       mf624_attach,
-11 |      detach:       mf624_detach,
-12 |  };
-13 |  
-14 |  COMEDI_INITCLEANUP(driver_mf624);
+
 \end{verbatim}
 
 \subsection{Funkce \texttt{attach}}
@@ -968,7 +1011,7 @@ Testování správnosti funkce ovladačů probíhala přímo na hardware, za pom
 \begin{figure}[h!]
        \begin{center}
        \includegraphics[width=120mm]{img/svorkovnice.jpg}
-       \caption{Svorkovnice TB620.}
+       \caption{Svorkovnice TB620}
        \label{svorkovnice}
        \end{center}
 \end{figure}