]> rtime.felk.cvut.cz Git - mf6xx.git/blob - doc/diploma_thesis/text/dip_text.tex
c8a41c7558d165ec9ef9a1195272ddad720e97d2
[mf6xx.git] / doc / diploma_thesis / text / dip_text.tex
1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 \chapter{Motivace, cíl}
3 Zadání této práce vzešlo z akademického prostředí a reaguje na nedostatek studijních materiálů v českém jazyce pro začátečníky, popisujících vývoj ovladačů (v tomto případě PCI zařízení) pro operační systém GNU/Linux.
4
5 Text obsahuje pouze nezbytné množství teorie, která je podložená četnými příklady pro snadnější pochopení čtenářem.
6
7 Pro čtenáře neznalého psaní programů těsně svázaných s hardwarem se snažím názorně vysvětlit základní principy a úskalí tohoto druhu programování.
8
9 V případě dalšího zájmu o problematiku může čtenář sáhnout po 
10 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11 \chapter{Hardware}
12 \section{Komunikace s hardwarem}
13 Jak je možné ovládat hardware pomocí programu (software) je nejsnazší ukázat na příkladu jednočipového počítače.
14
15 \ibox{Mikrokontrolér, neboli jednočipový počítač, má velikost pouze jednoho čipu. Obsahuje přitom procesor, paměť, vstupně-výstupní zařízení a jiné. Příklady zařízení obsažených v mikrokontroléru: 
16 \begin{description}
17 \item[GPIO piny (General Purpose Input/Output)] -- u těch je možné nastavit, zda chceme jejich hodnotu číst (a je k nim tedy připojeno jiné zařízení) nebo zda chceme jejich hodnotu nastavovat.
18 \item[A/D převodník] -- Převádí analogový (spojitý) signál na diskrétní (nespojitý). Příklad: Na vstup A/D převodníku přivedeme napětí 2,4 V. Z registru odpovídajícímu tomuto převodníku si v digitální podobě mikroprocesor vyčte hodnotu odpovídající 2,4.
19 \item[D/A převodník] -- Opačně od A/D převodníku převádí digitální signál na analogový. Příklad: Do registru odpovídajícímu D/A převodníku zapíše mikroprocesor hodnotu odpovídající např. 3,5 V. Na výstupu bude možné změřit napětí 3,5 V (s určitou malou odchylkou).
20 \end{description}
21
22
23 %\begin{figure}[h!]
24 %       \begin{center}
25 %       \includegraphics[width=80mm]{img/msp430g2x01.png}
26 %       \caption{Architektura velmi jednoduchého mikroprocesoru MSP430G2x01 firmy Texas Instruments.}
27 %       \label{microcontroller}
28 %       \end{center}
29 %\end{figure}
30
31 }
32
33 V případě, že budeme chtít změnit hodnotu GPIO pinu, je první možností 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 ovliňuje stav hardware. V dokumentaci ke konkrétnímu mikrokontrolerů/\-mikroprocesoru/\-programovatelnému integrovanému obvodu je uvedeno, jakou funkci mají jednotlivé bity registru.} GPIO pinu. Vnitřní uspořádání mikrokontroleru, dle adresy na kterou jsme zapisovali, 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 výstupní hodnoty 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}}
34
35 \begin{figure}[h!]
36         \begin{center}
37         \includegraphics[width=100mm]{img/mmio.pdf}
38         \caption{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.}
39         \label{mmio}
40         \end{center}
41 \end{figure}
42
43 Jiným přístupem je při zápisu/čtení do/ze zařízení použití jiné instrukce než kterou používáme pro paměťové operace -- tj. místo zápisu na adresu v paměťovém prostoru vyhrazenou pro GPIO, provedeme 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 přesně vědět jak široká (kolikabitová) slova smíme zapisovat/číst. 
44
45 \ibox{
46 Hlavní rozdíly mezi chováním paměťové buňky a registru zařízení jsou:
47 \begin{itemize}
48 \item Zápisem do registru můžeme měnit stav zařízení odpovídajícího registru.
49 \item V případě zápisu do registru a jeho okamžitém čtení, nemusí být přečtená hodnota shodná se zapisovanou -- v tom případě byla hodnota registru změněna hardwarem.
50 \item V případě čtení hodnoty registru může být spuštěn tzv. \textit{side effect}, kdy hardware na toto čtení reaguje změnou stavu, podobně jako by byl proveden zápis do registru (Příklad: Ihned po vyčtení hodnoty registru A/D převodníku se spustí nový převod a původní hodnota se přepíše novou).
51 \item Při zápisu a čtení do/z registru si musíme být vědomi toho, kolikabitové operace zápisu/čtení smíme používat (8-, 16-, 32bitové).
52 \end{itemize}
53 }
54 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55 \section{PCI sběrnice}\label{pcich}
56 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í.
57
58 \begin{figure}[h!]
59         \begin{center}
60         \begin{minipage}[b]{0.4\linewidth}
61                 \includegraphics[width=50mm]{img/pci_schema2.png}
62         \end{minipage}
63         \begin{minipage}[b]{0.4\linewidth}
64                 \includegraphics[width=50mm]{img/pci2.jpg}
65         \end{minipage}
66         \caption{\textit{Vlevo}: Schéma znázorňující rozdíly mezi konektory pro karty s napájením 3,3 V a 5 V. \textit{Vpravo}: Reálná fotografie PCI konektorů}
67         \label{pci}
68         \end{center}
69 \end{figure}
70
71 PCI (\textit{Peripheral Component Interconnect}) je standard paralelní sběrnice využívaný v počítačích nejrůznějších architektur. Mezi její hlavní výhody (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/I/O regionů potřebuje namapovat -- o samotné mapování se poté postará PCI most.
72
73 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 pro potřeby komunikace vyčte oprační systém.
74
75
76 \begin{figure}[h!]
77         \begin{center}
78         \includegraphics[width=100mm]{img/pci-config-space2.pdf}
79         \caption{Obsah 256 bajtů konfiguračního prostoru PCI karty (zvýrazněny jsou ty registry, jejichž znalost využijeme při vývoji ovladačů)}
80         \label{sa1}
81         \end{center}
82 \end{figure}
83
84 Zmínil jsem 6 BAR registrů, které každá z karet obsahuje. Mezi další registry, které je potřeba při implementaci ovladačů znát, patří:
85 \begin{description}
86 \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}}
87 \item[Device ID]~\\Obsahuje 16bitové číslo identifikující model zařízení. Hodnotu tohoto identifikátoru si volí sám výrobce zařízení.
88 \item[Class code]~\\Označuje druh zařízení -- zda se jedná např. o grafickou kartu, zvukovou kartu nebo kartu zpracovávající signál.
89 \item[Subsystem Vendor ID] -- Podobá se \texttt{Vendor ID}. V případě, že naše karta využívá PCI řadič třetí strany, jako \texttt{Vendor ID} se zobrazí ID výrobce tohoto řadiče. Abychom byli schopni naše zařízení odlišit od jiného, které využívá stejný řadič, ID našeho zařízení bude uloženo v tomot registru. (V případě, že v registru \texttt{Vendor ID} je skutečně naše ID, může být opět i v tomto registru).
90 \item[Subsystem ID]~\\Opět se jedná o údaj podobný \texttt{Device ID}. 
91 \end{description}
92
93 Tyto registry slouží operačnímu systému k jednoznačné identifikaci zažízení, při volbě správného ovladače.
94
95 Výše popsané registry (a ostatní, které nejsou pro čtenáře podstatné) se nacházejí v 256bitovém tzv. \textbf{konfiguračním adresním prostoru} karty (\textit{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.
96
97
98 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
99 \section{Humusoft MF624}
100 \begin{figure}[h!]
101         \begin{center}
102         \includegraphics[width=150mm]{img/mf624.jpg}
103         \caption{Měřící karta Humusoft MF624}
104         \label{sa1}
105         \end{center}
106 \end{figure}
107
108 Měřící karta Humusoft MF624 (dále jen MF624), připojitelná k počítači pomocí PCI sběrnice, má pro účely výkladu psaní ovladačů několik nesporných výhod:
109 \begin{itemize}
110 \item Komunikace (na úrovni ovladače) s kartou probíhá snadno pochopitelným, přímo\-čarým způsobem (bude vysvětleno dále).
111 \item Je snadné si ověřit správnou funkci napsaného ovladače -- např. připojením LED diody k digitálnímu výstupu.
112 \end{itemize}
113
114 Karta MF624 najde své uplatnění hlavně v laboratorním prostředí -- v případech, když je potřeba vytvořit styk mezi počítačem a senzorem/jiným zařízením, které poskytuje analogový, resp. digitální signál (v tom případě využijeme A/D převodníků, resp. digitálních vstupů). Kartu je možné použít pro řízení akčního členu/zařízení -- na výběr máme D/A převodníky a digitální výstupy.
115 Kromě výše popsaných funkcí disponuje karta dalšími funkcemi (v popisu implementace ovladačů se omezím pouze na A/D, D/A převodníky a digitální vstupy/výstupy):
116 \begin{itemize}
117 \item Časovač/čítač
118 \item Vstupy inkrementálních snímačů
119 \end{itemize}
120
121 \subsection{Komunikace s kartou}\label{hum_komunikace}
122 Komunikace s kartou probíhá celkem přímočarým způsobem:
123 \begin{itemize}
124 \item V případě, že chceme číst hodnoty digitálních vstupů, přečteme hodnotu registru určeného právě digitálním vstupům -- v případě zápisu na digitální výstupy, zapíšeme do registru určeného digitálním výstupům
125 \item V případě čtení A/D převodníku nejprve zapíšeme do konfiguračního registru A/D převodníku slovo odpovídající požadované konfiguraci. Poté již z registru náležícího A/D převodníku vyčteme požadovanou hodnotu.
126 \end{itemize}
127
128 Které registry karta obsahuje, jakou mají funkci a kde jsou umístěny je možné zjistit z manuálu ke kartě -- ten je možné stáhnout z oficiálních internetových stránek výrobce.\footnote{\url{http://www2.humusoft.cz/www/datacq/manuals/mf624um.pdf}}
129
130 Na straně 11 je k vidění první důležitá tabulka (zde tab. \ref{tab_bar}):
131
132 \begin{table}[h!]
133         \begin{center}
134         \begin{tabular}{|p{2cm}|p{4cm}|c|c|}
135         \hline \textbf{Region} & \textbf{Function} & \textbf{Size (bytes)} & \textbf{Width (bytes)} \\ 
136         \hline BADR0 (memory mapped) & PCI chipset, interrupts, status bits, special functions & 32 & 32 \\ 
137         \hline BADR1 (memory mapped) & A/D, D/A, digital I/O & 128 & 16/32 \\ 
138         \hline BADR2 (memory mapped) & Counter/timer chip & 128 & 32 \\ 
139         \hline 
140         \end{tabular} 
141         \caption{Paměťové regiony, které PCI karta využívá}
142         \label{tab_bar}
143         \end{center}
144 \end{table}
145
146 Z ní je patrné, že karta využívá 3 regiony\footnote{V manuálu je uvedeno, že se jedná o regiony odpovídající BAR0, BAR1 a BAR2 registrům -- skutečnost je však taková, že karta využívá regiony odpovídající registrům BAR0, BAR2 a BAR4. Rozdíl mezi skutečností a manuálem spočívá v tom, že v muálu jsou registry popsány tak, jak je vidí operační systém Microsoft Windows. Na tuto skutečnost se musí při implementaci ovladače brát zřetel. FIXME} mapované do paměťového adresního prostoru (sloupec 1) -- o velikostech 32, 128 a 128 bajtů (sloupce 3). Pro čtení/zápis z/do nich je potřeba používat 32-, 16-, 32bitové operace (sloupec 4).\footnote{V manuálu je uvedeno, že za určitých podmínek je možné k BAR1 přistupovat i pomocí 32bitových operací. V této práci bych se tomuto složitějšímu přístupu rád vyhnul. Částečná implementace karty MF624 do emulátoru Qemu (Popsaná v příloze \ref{qemu}) umožňuje \textbf{pouze} 16bitový přístup do BAR1 paměťového regionu.}
147
148 \subsection{Digitální vstupy a výstupy}
149 Z tabulky \ref{tab_bar} lze vyčíst informaci, že registry ovládající digitální vstupy a výstupy budou ležet zřejmě v regionu BAR1 (sloupec 2). Dále je potřeba se podívat na přehled registrů náležejících tomuto paměťovému regionu (v oficiálním manuálu na straně 12) -- tomu odpovídá tabulka (s menšími úpravami) \ref{tab_bar1}.
150
151 \begin{table}[h!]
152         \begin{center}
153         \begin{tabular}{|p{17mm}|c|c|}
154         \hline \textbf{Address (BADR1 offset)} & \textbf{Read} & \textbf{Write} \\ 
155         \hline 0x00 & \textbf{ADDATA} -- A/D data & ADCTRL -- A/D control \\ 
156         \hline 0x02 & \textbf{ADDATA} -- A/D data mirror &  \\ 
157         \hline 0x04 & \textbf{ADDATA} -- A/D data mirror &  \\ 
158         \hline 0x06 & \textbf{ADDATA} -- A/D data mirror &  \\ 
159         \hline 0x08 & \textbf{ADDATA} -- A/D data mirror &  \\ 
160         \hline 0x0A & \textbf{ADDATA} -- A/D data mirror &  \\ 
161         \hline 0x0C & \textbf{ADDATA} -- A/D data mirror &  \\ 
162         \hline 0x0E & \textbf{ADDATA} -- A/D data mirror &  \\ 
163         \hline 0x10 & \textbf{DIN} -- Digital input & \textbf{DOUT} -- Digital output \\ 
164         \hline 0x20 & \textbf{ADSTART} -- A/D SW trigger & \textbf{DA0} -- D/A 0 data \\ 
165         \hline 0x22 &  & \textbf{DA1} -- D/A 1 data \\ 
166         \hline 0x24 &  & \textbf{DA2} -- D/A 2 data \\ 
167         \hline 0x26 &  & \textbf{DA3} -- D/A 3 data \\ 
168         \hline 0x28 &  & \textbf{DA4} -- D/A 4 data \\ 
169         \hline 0x2A &  & \textbf{DA5} -- D/A 5 data \\ 
170         \hline 0x2C &  & \textbf{DA6} -- D/A 6 data \\ 
171         \hline 0x2E &  & \textbf{DA7} -- D/A 7 data \\ 
172         \hline 
173         \end{tabular} 
174         \caption{Registry karty obsažené v regionu BAR1}
175         \label{tab_bar1}
176         \end{center}
177 \end{table}
178
179 Na devátém řádku je napsáno \textit{DIN -- Digital input, DOUT -- Digital output} -- to značí registr, který se stará o nastavování digitálních výstupů a čtení digitálních vstupů (Všimněme si, že registr DIN a DOUT mají stejnou adresu i přesto, že na kartě jsou vstupy a výstupy realizovány oddělenými vodiči). 
180
181 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}). 
182 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 8bitů registru DOUT, horních 8 bitů je potřeba ignorovat.
183
184 \begin{table}[h!]
185         \begin{center}
186         \begin{tabular}{|c|c|c|}
187         \hline \textbf{Bit} & \textbf{Description} & \textbf{Default} \\ 
188         \hline 7:0 & \textbf{Digital input 7:0.} Reads digital input port. & 1 \\ 
189         \hline 15:8 & Reserved & N/A \\ 
190         \hline 
191         \end{tabular} 
192         \caption{DIN -- Digital Input Register Format}
193         \label{tab_din}
194         \end{center}
195 \end{table}
196
197 \begin{table}[h!]
198         \begin{center}
199         \begin{tabular}{|c|c|c|}
200         \hline \textbf{Bit} & \textbf{Description} & \textbf{Default} \\ 
201         \hline 7:0 & \textbf{Digital output 7:0.} Writes to digital output port. & 0 \\ 
202         \hline 15:8 & Reserved & N/A \\ 
203         \hline 
204         \end{tabular} 
205         \caption{DOUT -- Digital Output Register Format}
206         \label{tab_dout}
207         \end{center}
208 \end{table}
209
210
211 \subsection{A/D převodníky}
212 Karta MF624 obsahuje osm 14bitových A/D převodníků s pevně stanoveným rozsahem $\pm$10 V. Jejich vyčtení může probíhat následujícím způsobem:
213
214 \begin{itemize}
215 \item Nejprve se v registru ADCTRL zvolí, které A/D převodníky mají být čteny. 
216 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.
217 \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á.
218 \item V případě, že se provedl převod na všech zvolených A/D převodnících, je EOLC bit GPIOC registru nastaven na 0 (jinak je v 1).
219 \item Výslednou hodnotu je možné přečíst z registru ADDATA typu FIFO nebo mnohem jednodušší je čtení z jeho zrcadlených hodnot v registrech ADDATA0--ADDATA7 (v manuálu jsou označeny pouze jako \textit{BADR1 + 0x02} až \textit{BADR1 + 0x0E}).
220 \end{itemize}
221
222 Hodnota vyčtená z A/D převodníků je ve formátu dvojkového doplňku.
223
224 \subsection{D/A převodníky}
225 Karta MF624 obsahuje také osm 14bitových D/A převodníků s rozsahem $\pm$10 V.
226
227 Nastavení výstupních hodnot D/A převodníků může probíhat následujícícm způsobem:
228
229 \begin{itemize}
230 \item Hodnota v aditivním kódu (tabulka 23 v originálním manuálu) se zapíše do jednoho z osmi registrů DA0--DA7 odpovídajícího D/A převodníku, který chceme nastavovat
231 \item Bit DACEN registru GPIOC je potřeba nastavit na 0, jinak jsou výstupy D/A převodníků připojeny na \textit{zem}.
232 \item Bit LDAC registru GPIOC je potřeba nastavit na 0, aby byl spuštěn samotný převod D/A převodníků.
233 \end{itemize}
234
235
236
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238 \chapter{Implementace ovladačů}
239 \section{Operační systém GNU/Linux}
240 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 jeho otevřenost (a z toho plynoucí velké množství kvalitní dokumentace), rozšířenost (hlavně mezi vestavěnými zařízeními) a vysoká kvalita. Distribucí použitou při vývoji byl  Debian GNU/Linux (verze jádra Linux 2.6.35) -- popsané postupy by však měly fungovat i pro jiné distribuce.
241
242 \subsection{Principy psaní jaderných modulů}
243 Jádro operačního systému GNU/Linux je monolitické -- to znamená, že po zkompilování a slinkvá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.
244
245 Jak se takový jaderný modul může vypadat, je nejlepší si ukázat na příkladu:
246 \begin{verbatim}
247  1 |  #include <linux/init.h>
248  2 |  #include <linux/module.h>
249  3 | 
250  4 |  static int hello_init(void)
251  5 |  {
252  6 |      printk("Hello, world!\n");
253  7 |      return 0;
254  8 |  }
255  9 | 
256 10 |  static void hello_exit(void)
257 11 |  {
258 12 |      printk("Goodbye, cruel world!\n");
259 13 |  }
260 14 | 
261 15 |  module_init(hello_init);
262 16 |  module_exit(hello_exit);
263 17 |  
264 18 |  MODULE_LICENSE("Dual BSD/GPL");
265 \end{verbatim}
266
267 První věc, na kterou je potřeba upozornit je, že většina jaderných modulů (stejně jako zdrojových kódů jádra samotného) je psána v programovacím jazyce C (jedná se o mírně modifikovaný standard C90).
268 \begin{description}
269 \item[Řádky 1 a 2] obsahují vložení hlavičkových souborů -- obsahují prototypy volaných funkcí a jsou nutné pro tvorbu jaderného modulu.
270 \item[Na řádcích 4--8] je funkce, která bude spuštěna ihned po zavedení našeho modulu do jádra. Ta obsahuje pouze volání funkce \texttt{printk()}.
271
272 Pro jednoduchost můžeme s funkcí \texttt{printk()} pracovat jako s, pro čtenáře známou, funkcí \texttt{printf()} -- narozdíl od standardního výstupu se však text vypsaný funkcí \texttt{printk()} zapíše do \textit{logu} jádra. Jedním ze způsobů, jak ho zobrazit je pomocí programu \texttt{dmesg}.\\Jak se zařídí, že se tato funkce vykoná ihned po zavedení modulu do jádra? O to se postará příkaz na $\rightarrow$
273 \item[řádku 15] -- ten obsahuje makro \texttt{module\_init()}, kterému řekneme právě to, která funkce se má po načtení spustit.
274 \item[Řádek 16] obsahuje naopak makro, které udává, která funkce se má zavolat v případě, že se bude modul uvolňovat z jádra. V našem případě je to funkce na $\rightarrow$
275 \item[řádcích 10--13.] Tato funkce nemá na starost nic jiného než výpis krátkého textu do logu jádra.
276 \end{description}
277
278 \subsection{Kompilace modulu}
279 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 buď stáhneme přímo z \texttt{kernel.org} nebo v distribuci Debian nainstalujeme pomocí příkazu\\\texttt{apt-get install ... FIXME}}. K tomu poslouží následující \texttt{Makefile}:
280 \begin{verbatim}
281 1 |  KERNEL_VER=`uname -r`
282 2 |  obj-m += hello.o
283 3 |
284 4 |  all:
285 5 |      make -C /lib/modules/$(KERNEL_VER)/build M=$(PWD) modules
286 6 |  clean:
287 7 |      make -C /lib/modules/$(KERNEL_VER)/build M=$(PWD) clean
288 \end{verbatim}
289 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:
290
291 \begin{description}
292 \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í)
293 \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)
294 \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áří 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}).
295 \end{description}
296
297 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:
298 \begin{verbatim}
299 $ make
300 make -C /lib/modules/`uname -r`/build M=/tmp/kernel_module_example modules
301 make[1]: Entering directory `/usr/src/linux-headers-2.6.35-28-generic'
302   CC [M]  /tmp/kernel_module_example/hello.o
303   Building modules, stage 2.
304   MODPOST 1 modules
305   CC      /tmp/hello.mod.o
306   LD [M]  /tmp/hello.ko
307 make[1]: Leaving directory `/usr/src/linux-headers-2.6.35-28-generic'
308 \end{verbatim}
309 A v aktuálním adresáři se nachází kromě různých souborů, které vzniky při překladu, i potřebný \texttt{hello.ko}
310
311 \begin{verbatim}
312 $ ls
313 hello.c  hello.ko  hello.mod.c  hello.mod.o  hello.o  
314 Makefile  modules.order  Module.symvers
315 \end{verbatim}
316
317 \subsection{Zavedení modulu}
318 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:
319 \begin{verbatim}
320 $ sudo insmod ./hello.ko 
321 \end{verbatim}
322
323 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:
324 \begin{verbatim}
325 $ dmesg | tail -1
326 [ 9245.757491] Hello, world!
327 \end{verbatim}
328 A skutečně je posledním řádkem v logu text vypsaný zavedeným modulem.
329
330 Pro plné otestování funkčnosti ukázkového modulu, je potřeba ho z jádra uvolnit. K tomu slouží program \texttt{rmmod} (opět je potřeba spouštět se superuživatelskými privilegii).
331 \begin{verbatim}
332 $ sudo rmmod hello 
333
334 $ dmesg | tail -1
335 [ 9612.256929] Goodbye, cruel world!
336 \end{verbatim}
337 V logu je opět nachází text vypisovaný modulem při uvolňování z jádra.
338
339
340 \ibox{V případě, že se chystáme do jádra zavést modul, jehož jsme autoři a nejsme si jisti jeho funkčností, doporučuji si veškerou důležitou práci uložit 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.}
341 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 \section{Ovladače PCI zařízení}
343 %Než začneme implementovat skutečný ovladač pro kartu MF624 je potřeba si vysvětlit základní funkce pro práci s PCI zařízeními a vstupně-výstupním a paměťovým adresním prostorem.
344 \ibox{Následující popis není zcela vyčerpávající a obsahuje pouze to nejnutnější pro implementaci základního ovladače. Zájemce o problematiku mohu odkázat na literaturu FIXME nebo zdrojové kódy jádra\footnote{Pro prohlížení zdrojových kódů jádra mohu doporučit online \textit{the Linux Cross Reference} -- \url{http://lxr.linux.no/} FIXME footnote se nezobrazuje}}
345
346 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}. 
347
348 \subsection{Struktura \texttt{struct pci\_driver}}
349 Tato struktura obsahuje základní informace o našem ovladači. Mezi hlavní položky patří:
350 \begin{description}
351 \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.
352 \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).
353 \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.
354 \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.
355 \end{description}
356
357 Příklad, jak může být struktura \texttt{pci\_driver} inicializována a následně zaregistrována:
358 \begin{verbatim}
359 1 |  static struct pci_driver mf624_pci_driver = {
360 2 |      .name = "mf624",
361 3 |      .id_table = mf624_pci_id,
362 4 |      .probe = mf624_pci_probe, 
363 5 |     .remove = mf624_pci_remove,
364 6 |  };
365 pci_register_driver(&mf624_pci_driver);
366 \end{verbatim}
367
368 \subsection{Struktura \texttt{struct pci\_device\_id}}
369 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ě:
370
371 \begin{verbatim}
372  1 |  #define PCI_VENDOR_ID_HUMUSOFT          0x186c
373  2 |  #define PCI_DEVICE_ID_MF624             0x0624
374  3 |  #define PCI_SUBVENDOR_ID_HUMUSOFT       0x186c
375  4 |  #define PCI_SUBDEVICE_DEVICE            0x0624
376  5 |  
377  6 |  static struct pci_device_id mf624_pci_id[] = {
378  7 |      {
379  8 |          .vendor = PCI_VENDOR_ID_HUMUSOFT,
380  9 |          .device = PCI_DEVICE_ID_MF624,
381 10 |          .subvendor = PCI_SUBVENDOR_ID_HUMUSOFT,
382 11 |          .subdevice = PCI_SUBDEVICE_DEVICE,
383 12 |      },
384 13 |      { 0, } /* seznam je vždy zakončen prázdným prvkem */
385 14 |  };
386 \end{verbatim}
387
388
389 \subsection{Funkce \texttt{probe()}}
390 \ibox{\texttt{int probe(struct pci\_dev *dev, const struct pci\_device\_id *id);}}
391
392 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í.
393
394 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č.
395
396 \ibox{\texttt{pci\_enable\_device(struct pci\_dev *dev);}}
397
398 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í.
399
400 \subsection{Přístup ke zdrojům karty}
401 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. 
402
403 \ibox{\texttt{int pci\_request\_regions(struct pci\_dev *pdev, const char *res\_name);}}
404
405 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.
406
407 \ibox{\texttt{unsigned long pci\_resource\_start(struct pci\_dev *dev, int bar);}}
408
409 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).
410
411 \ibox{\texttt{unsigned long pci\_resource\_len(struct pci\_dev *dev, int bar);}}
412
413 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()}.
414
415 \ibox{\texttt{void \_\_iomem *pci\_ioremap\_bar(struct pci\_dev *pdev, int bar);}}
416
417 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()}.
418
419 K ukazateli, který vrátí volání \texttt{pci\_ioremap\_bar()} je již možné pomocí speciálních funkcí přistupovat.
420
421 \ibox{FIXME povídání o out-of-order execution a cache a proč musíme používat speciální funkce}
422
423 \subsection{Funkce \texttt{remove()}}
424
425 \ibox{\texttt{void remove(struct pci\_dev *dev);}}
426
427 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.
428
429 Tato funkce by se měla postarat o úklid všech naalokovaných prostředků apod. Měla by obsahovat volání:
430 \begin{description}
431 \item[\texttt{iounmap()}]~\\Uvolnění virtuální paměti namapované voláním \texttt{pci\_ioremap\_bar()}.
432 \item[\texttt{pci\_release\_regions()}]~\\Uvolnění zdrojů karty, které byly zarezervovány voláním \texttt{pci\_request\_regions()}.
433 \item[\texttt{pci\_disable\_device()}]~\\Opak k volání \texttt{pci\_enable\_device()}.
434 \end{description}
435
436  
437
438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439 \section{UIO ovladač}
440 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.
441
442 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á).
443
444 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.
445
446 \subsection{Jaderný modul}
447 Jaderný modul UIO ovladače by měl obsahovat:
448 \begin{itemize}
449 \item Funkci volanou PCI subsystémem při registraci ovladače
450 \item Volání funkcí pro namapování regionů zařízení
451 \item Inicializaci struktury \texttt{struct uio\_info} a registraci do UIO subsystému
452 \item Funkce pro \textit{úklid} a uvolnění regionů karty
453 \end{itemize}
454
455 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}.
456
457 \ibox{\texttt{int uio\_register\_device(struct device *parent, struct uio\_info *info);}}
458
459 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}.
460
461 \subsubsection{Struktura \texttt{struct uio\_info}}
462 Mezi její hlavní položky patří:
463 \begin{description}
464 \item[\texttt{const char *name}]~\\Název ovladače
465 \item[\texttt{const char *version}]~\\Verze ovladače
466 \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
467 \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.
468 %\item[\texttt{}]
469 \end{description}
470
471 \subsubsection{Struktura \texttt{struct uio\_mem} a \texttt{struct uio\_port}}
472 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.
473
474 Struktura \texttt{struct uio\_mem} obsahuje položky:
475 \begin{description}
476 \item[\texttt{const char *name}]~\\Textový popis daného regionu (viditelný z uživatelského prostoru).
477 \item[\texttt{unsigned long addr}]~\\Fyzická adresa regionu získaná voláním \texttt{pci\_resource\_start()}.
478 \item[\texttt{unsigned long size}]~\\Délka regionu. Nejsnáze získaná voláním \texttt{pci\_resource\_len()}.
479 \item[\texttt{int memtype}]~\\Typ paměti. Pro fyzickou paměť na zařízení se použije \texttt{UIO\_MEM\_PHYS}.
480 \item[\texttt{void \_\_iomem *internal\_addr}]~\\Virtuální adresa získaná voláním \texttt{pci\_ioremap\_bar()}
481 \end{description}
482
483 Struktura \texttt{struct uio\_port} obsahuje položky:
484 \begin{description}
485 \item[\texttt{const char *name}]~\\Textový popis daného regionu (viditelný z uživatelského prostoru).
486 \item[\texttt{unsigned long start}]~\\Fyzická adresa regionu získaná voláním \texttt{pci\_resource\_start()}.
487 \item[\texttt{unsigned long size}]~\\Délka regionu. Nejsnáze získaná voláním \texttt{pci\_resource\_len()}.
488 \item[\texttt{int porttype}]~\\Typ portu. Pro porty na architektuře IA-32 se použije \texttt{UIO\_PORT\_X86}
489 \end{description}
490
491 ~\\
492
493 Příklad, jak taková jednoduchá inicializace struktury \texttt{struct uio\_info} včetně registrace může vypadat (bez ošetření chybných stavů):
494 \begin{verbatim}
495  1 |  /* struct pci_dev *dev */
496  2 |  struct uio_info *info;
497  3 |  info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
498  4 |  
499  5 |  info->name = "mf624";
500  6 |  info->version = "0.0.1";
501  7 |  
502  8 |  info->mem[0].name = "PCI chipset, ...";
503  9 |  info->mem[0].addr = pci_resource_start(dev, 0);
504 10 |  info->mem[0].size = pci_resource_len(dev, 0);
505 11 |  info->mem[0].memtype = UIO_MEM_PHYS;
506 12 |  info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
507 13 |  
508 14 |  info->port[0].name = "Board programming registers";
509 15 |  info->port[0].porttype = UIO_PORT_X86;
510 16 |  info->port[0].start = pci_resource_start(dev, 1);
511 17 |  info->port[0].size = pci_resource_len(dev, 1);
512 18 |  
513 19 |  uio_register_device(&dev->dev, info);
514 20 |  pci_set_drvdata(dev, info);
515 \end{verbatim}
516
517 \ibox{\texttt{void pci\_set\_drvdata(struct pci\_dev *pdev, void *data)}}
518
519 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}
520
521 \subsection{Program v uživatelském prostoru}
522 Poté, co je jaderná část UIO ovladače úspěšně zkompilována a zavedena do systému, je rozhraní mezi tímto modulem a uživatelským prostorem tvořeno:
523 \begin{itemize}
524 \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.}}.
525 \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.
526 \end{itemize}
527
528 \subsubsection{Obsah složky \texttt{/sys/class/uio/uio0}}
529 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).
530
531 \subsubsection{Soubor \texttt{/dev/uio0}}
532 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()}.
533
534 \ibox{\texttt{void *mmap(void *addr, size\_t length, int prot, int flags, int fd, off\_t offset);}}
535
536 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ěť.
537  
538 \begin{description}
539 \item[Parametr \texttt{addr}] -- v případě, že není nulový -- určí, na jakou adresu by měla být paměť mapována.
540 \item[Parametr \texttt{length}] udává velikost mapované paměti v násobcích velikosti paměťové stránky. 
541 \item[Parametr \texttt{prot}] obsahuje příznaky definující, zda bude mapovaná paměť pro čtení/zápis, apod.
542 \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}).
543 \item[Parametr \texttt{fd}] obsahuje \textit{filedescriptor} na zařízení, které má být namapováno (v tomto případě \texttt{/dev/uio0}).
544 \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.
545 \end{description}
546
547 Příklad, jak takové volání může vypadat (bez ošetření chybných stavů):
548 \begin{verbatim}
549 1 |  #define BAR2_offset       (1 * sysconf(_SC_PAGESIZE))
550 2 |  void* mf624_BAR2 = NULL;
551 3 |  int device_fd = open("/dev/uio0", O_RDWR);
552 4 |  
553 5 |  mf624_BAR2 = mmap(0, 1 * sysconf(_SC_PAGESIZE), 
554 6 |                    PROT_READ | PROT_WRITE, MAP_SHARED, 
555 7 |                    device_fd, BAR2_offset);
556 \end{verbatim}
557
558 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.
559
560 Jak velký je potřeba udělat \textit{posun} pomůže zjistit soubor \texttt{/sys/class/uio/ /ui0/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):
561 \begin{verbatim}
562 mf624_BAR2 += (BAR2_phys_addr & (sysconf(_SC_PAGESIZE) - 1));
563   |                \-- Fyzická adresa
564   \-- Ukazatel vrácený voláním mmap()                 
565 \end{verbatim}
566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
567 \section{Comedi ovladač}
568 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.
569
570 Pro ovladače měřících karet existuje v Linuxu subsystém -- tzv. Comedi (Control and Measurement Device Interface).
571
572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
573 \chapter{Závěr}
574
575 %\appendix
576 %\chapter{Qemu a Humusoft MF624}\label{qemu}
577 %Měřící karta Humusoft MF624 je hardware vhodný pro výklad implementace ovladače, je ale poměrně drahý. 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.