]> rtime.felk.cvut.cz Git - mf6xx.git/blob - doc/diploma_thesis/text/dip_text.tex
8a620ca2ee990cc24e90c5693f12db99a471a1ec
[mf6xx.git] / doc / diploma_thesis / text / dip_text.tex
1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 \chapter{Úvod}
3 \section{Motivace, cíl}
4 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.
5
6 Text popisuje základní aspekty práce s PCI zařízeními v jádře Linux a uvádí dva konkrétní způsoby implementace ovladače zařízení PCI. Text obsahuje pouze nezbytné množství teorie, která je podložená četnými příklady pro snadnější pochopení čtenářem. 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í. V případě dalšího zájmu o problematiku může čtenář sáhnout po knize \cite{devicedriver}.
7
8 Kromě samotného popisu vývoje PCI ovladačů je cílem práce částečně implementovat funkce karty Humusoft MF624 do emulačního programu Qemu tak, aby si případný zájemce mohl vše vyzkoušet, aniž by fyzicky vlastnil hardware.
9
10 \section{Dostupné materiály}
11 V českém jazyce dosud vyšla pouze jedna tištěná kniha, která se zabývá problematikou vývoje pro jádro Linux. Jedná se o knihu \cite{jadrosystemu} od Lukáše Jelínka. Je dělena do 3 základních částí:
12 \begin{itemize}
13 \item \textit{Vnější rozhraní jádra}
14 \item \textit{Vývoj ovladačů}
15 \item \textit{Pohled dovnitř jádra}
16 \end{itemize}
17
18 Jednotlivá témata jsou popsána pouze stručně (kniha je koncipována spíše jako příručka než jako učebnice) a pro studenta nižšího ročníku, neznalého vývoje jaderných ovladačů zařízení nemá příliš velký přínos.
19
20 Za nejpřínosnější knihu, zabývající se psaním ovladačů pro Linux, považuji anglicky psanou knihu \cite{devicedriver} od autorů Jonathan Corbet, Alessandro Rubini a Greg Kroah-Hartman. Knihu je možné stáhnout zdarma ve formátu PDF\footnote{\url{http://lwn.net/Kernel/LDD3/}}.
21
22 \begin{figure}[h!]
23         \begin{center}
24         \begin{minipage}[b]{0.4\linewidth}
25                 \includegraphics[width=50mm]{img/jadro-systemu-linux.jpg}
26         \end{minipage}
27         \begin{minipage}[b]{0.4\linewidth}
28                 \includegraphics[width=50mm]{img/lddrivers.jpg}
29         \end{minipage}
30         \caption{\textit{Vlevo}: Kniha Lukáše Jelínka (v českém jazyce). 
31                 \textit{Vpravo}: kniha od autorů Jonathan Corbet, Alessandro Rubini a Greg Kroah-Hartman (v anglickém jazyce)}
32         \label{knihy}
33         \end{center}
34 \end{figure}
35
36
37
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39 \chapter{Hardware}
40 \section{Základní principy komunikace s hardwarem}
41 Jak je možné ovládat hardwarové periferie pomocí programu (software) je nejsnazší ukázat na příkladu jednočipového počítače.
42
43 \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é. Je obvyklé, aby mikrokontrolér obsahoval tzv. GPIO piny. 
44 \begin{description}
45 \item[GPIO piny (General Purpose Input/Output)] -- u těchto pinů je možné nastavit, zda má být jejich hodnota čtena (slouží jako vstupní piny -- skrze ně vstupuje informace) nebo zda chceme jejich hodnotu nastavovat (tj. výstupní piny).%
46 %\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.
47 %\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).
48 \end{description}%
49 }
50
51 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 ovliňuje stav hardware. V dokumentaci ke konkrétnímu mikrokontroleru/\-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 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}}
52
53 \begin{figure}[h!]
54         \begin{center}
55         \includegraphics[width=130mm]{img/gpio.pdf}
56         \caption{Registr odpovídající GPIO pinům. Změnou tohoto registru je možné měnit chování GPIO pinů}
57         \label{gpio_pins}
58         \end{center}
59 \end{figure}
60
61
62 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. 
63
64 \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}.)}
65
66 Hlavní rozdíly mezi chováním paměťové buňky a registru zařízení jsou:
67 \begin{itemize}
68 \item Změnou hodnoty registru je možné měnit stav zařízení/periferie odpovídající danému registru.
69 \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.
70 \item V případě čtení z registru může být spuštěn tzv. \textbf{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). Side effects mohou nastat i při zápisu do registru. 
71 \item Při zápisu a čtení do/z registru si je nutné přesně rozlišovat, kolikabitové operace zápisu/čtení smějí být použity (8-, 16-, 32bitové).
72 \end{itemize}
73
74 \begin{figure}[h!]
75         \begin{center}
76         \includegraphics[width=100mm]{img/mmio.pdf}
77         \caption{Paměťový a vstupně-výstupní prostor u architektury IA-32.}
78         \label{mmio}
79         \end{center}
80 \end{figure}
81
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
83 \clearpage
84 %\newpage
85 \section{PCI sběrnice}\label{pcich}
86 %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í.
87
88 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řenost zpráv oproti přímé komunikaci mezi zařízeními\footnote{Příklad: FIXME}
89
90 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.
91
92 \subsection{Historie}
93 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.
94
95 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.
96 \subsection{Konektory}
97 Pro spojení mezi kartou a sběrnicí je potřeba pouze konektor na straně sběrnice -- tzv. slot. V závislosti na napájecím napětí (3,3 V nebo 5 V) jsou na kartách klíčovací zářezy -- tyto zařezy znemoňují zasunutí \textit{napěťově} nekompatibilní karty do slotu. Jsou však karty, které mají tyto zářezy oba, díky čemuž může být karta použita v libovolném slotu (Obr. \ref{pci}).
98
99 \begin{figure}[h!]
100         \begin{center}
101         \begin{minipage}[b]{0.4\linewidth}
102                 \includegraphics[width=57mm]{img/pci_schema2.png}
103         \end{minipage}
104         \begin{minipage}[b]{0.4\linewidth}
105                 \includegraphics[width=50mm]{img/pci2.jpg}
106         \end{minipage}
107         \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ů}
108         \label{pci}
109         \end{center}
110 \end{figure}
111
112
113 \subsection{Dynamická konfigurace a konfigurační adresní prostor}
114 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.
115
116 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.
117
118
119 Kromě výše zmíněných 6 BAR registrů, obsahují PCI zařízení i následujícíc registry:
120 \begin{description}
121 \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}}
122 \item[Device ID]~\\Obsahuje 16bitové číslo identifikující model zařízení. Hodnotu tohoto identifikátoru si volí sám výrobce zařízení.
123 \item[Class code]~\\Označuje druh zařízení -- zda se jedná např. o grafickou kartu, zvukovou kartu nebo kartu zpracovávající signál.
124 \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 tomot registru.
125 \item[Subsystem ID]~\\Opět se jedná o údaj podobný \texttt{Device ID} sloužící k rolišení karet postavených na univerzálním řadiči.
126 \end{description}
127
128 Registry \texttt{Vendor ID}, \texttt{Device ID} (příp. ještě \texttt{Subsystem Vendor ID} a \texttt{Subsystem ID}) slouží operačnímu systému k jednoznačné identifikaci zažízení, při volbě správného ovladače.
129
130
131 \begin{figure}[h!]
132         \begin{center}
133         \includegraphics[width=80mm]{img/pci-config-space2.pdf}
134         \caption{Obsah 256 bajtů konfiguračního prostoru PCI karty (zvýrazněny jsou nejdůležitější registry).}
135         \label{sa1}
136         \end{center}
137 \end{figure}
138
139 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.
140
141 \subsection{Přerušení}
142 Sběrnice PCI obsahuje čtyři linky přerušení a všechny z nich jsou dostupné každému zařízení. Přerušení mohou být sdílená, tudíž o jedno přerušení se může dělit více zařízení. Pro snazší sdílení přerušení jsou úrovňově spouštěná (oproti hranovému spouštění nedochází k promeškání přerušení).
143
144 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.
145
146 \subsection{Budoucnost}
147 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 narozdíl od PCI seriová 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.
148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
149 \section{Humusoft MF624}
150 \begin{figure}[h!]
151         \begin{center}
152         \includegraphics[width=150mm]{img/mf624.jpg}
153         \caption{Měřící karta Humusoft MF624}
154         \label{mf624}
155         \end{center}
156 \end{figure}
157
158 Měřící karta Humusoft MF624 (obr. \ref{mf624}), připojitelná k počítači pomocí PCI sběrnice, má pro účely výkladu psaní ovladačů několik nesporných výhod:
159 \begin{itemize}
160 \item Komunikace (na úrovni ovladače) s kartou probíhá snadno pochopitelným, přímo\-čarým způsobem, kdy je pouze zapisováno (nebo čteno) do registrů karty (bude vysvětleno dále).
161 \item Je možné si ověřit správnou funkci napsaného ovladače -- např. připojením LED diody k digitálnímu výstupu nebo měřením napětí na výstupu D/A převodníku.
162 \end{itemize}
163
164 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ě jsou použity A/D převodníky, resp. digitální vstupy). Kartu je možné použít pro řízení akčního členu/zařízení -- k dispozici jsou D/A převodníky a digitální výstupy.
165
166 Karta disponuje následujícícmi funkcemi (v popisu implementace ovladačů se omezím pouze na A/D, D/A převodníky a digitální vstupy/výstupy):
167 \begin{itemize}
168 \item 8 digitálních vstupů
169 \item 8 digitálních výstupů
170 \item 8 14bitových A/D převodníků
171 \item 8 14bitových D/A převodníků
172 \item 4 časovače/čítače
173 \item 4 vstupy inkrementálních snímačů
174 \end{itemize}
175
176 \subsection{Komunikace s kartou}\label{hum_komunikace}
177 Komunikace s kartou není nijak složitá -- zjednodušeně by se dala popsat následovně:
178 \begin{itemize}
179 \item V případě čtení hodnoty digitálních vstupů, přečte se hodnota registru určeného právě digitálním vstupům -- v případě zápisu na digitální výstupy, se zapíše do registru určeného digitálním výstupům.
180 \item V případě čtení hodnoty A/D převodníku, se nejprve zapíše do konfiguračního registru A/D převodníku hodnota odpovídající požadované konfiguraci. Poté se již z registru náležícího A/D převodníku vyčte požadovaná hodnota.
181 \end{itemize}
182
183 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: \url{http://www2.humusoft.cz/www/datacq/manuals/mf624um.pdf}.
184
185 Na straně 11 je k vidění první důležitá tabulka (zde tab. \ref{tab_bar}):
186
187 \begin{table}[h!]
188         \begin{center}
189         \begin{tabular}{|p{2cm}|p{4cm}|c|c|}
190         \hline \textbf{Region} & \textbf{Function} & \textbf{Size (bytes)} & \textbf{Width (bytes)} \\ 
191         \hline BADR0 (memory mapped) & PCI chipset, interrupts, status bits, special functions & 32 & 32 \\ 
192         \hline BADR1 (memory mapped) & A/D, D/A, digital I/O & 128 & 16/32 \\ 
193         \hline BADR2 (memory mapped) & Counter/timer chip & 128 & 32 \\ 
194         \hline 
195         \end{tabular} 
196         \caption{Paměťové regiony, které PCI karta využívá}
197         \label{tab_bar}
198         \end{center}
199 \end{table}
200
201 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 -- na počítačích s procesorem rodiny IA-32 a s operačním systémem GNU/Linux však karta využívá BAR0, BAR2 a BAR4. Důvod rozdílu mezi skutečností a manuálem není jasný. Na tuto skutečnost se musí při implementaci ovladače brát zřetel.} mapované do paměťového adresního prostoru -- o velikostech 32, 128 a 128 bajtů. Pro čtení/zápis z/do nich je potřeba používat 32-, 16-, 32bitové operace\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.}
202
203 \subsection{Digitální vstupy a výstupy}
204 Z tabulky \ref{tab_bar} lze vyčíst informaci, že registry ovládající digitální vstupy a výstupy leží 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}.
205
206 \begin{table}[h!]
207         \begin{center}
208         \begin{tabular}{|p{17mm}|c|c|}
209         \hline \textbf{Address (BADR1 offset)} & \textbf{Read} & \textbf{Write} \\ 
210         \hline 0x00 & \textbf{ADDATA} -- A/D data & ADCTRL -- A/D control \\ 
211         \hline 0x02 & \textbf{ADDATA} -- A/D data mirror &  \\ 
212         \hline 0x04 & \textbf{ADDATA} -- A/D data mirror &  \\ 
213         \hline 0x06 & \textbf{ADDATA} -- A/D data mirror &  \\ 
214         \hline 0x08 & \textbf{ADDATA} -- A/D data mirror &  \\ 
215         \hline 0x0A & \textbf{ADDATA} -- A/D data mirror &  \\ 
216         \hline 0x0C & \textbf{ADDATA} -- A/D data mirror &  \\ 
217         \hline 0x0E & \textbf{ADDATA} -- A/D data mirror &  \\ 
218         \hline 0x10 & \textbf{DIN} -- Digital input & \textbf{DOUT} -- Digital output \\ 
219         \hline 0x20 & \textbf{ADSTART} -- A/D SW trigger & \textbf{DA0} -- D/A 0 data \\ 
220         \hline 0x22 &  & \textbf{DA1} -- D/A 1 data \\ 
221         \hline 0x24 &  & \textbf{DA2} -- D/A 2 data \\ 
222         \hline 0x26 &  & \textbf{DA3} -- D/A 3 data \\ 
223         \hline 0x28 &  & \textbf{DA4} -- D/A 4 data \\ 
224         \hline 0x2A &  & \textbf{DA5} -- D/A 5 data \\ 
225         \hline 0x2C &  & \textbf{DA6} -- D/A 6 data \\ 
226         \hline 0x2E &  & \textbf{DA7} -- D/A 7 data \\ 
227         \hline 
228         \end{tabular} 
229         \caption{Registry karty obsažené v regionu BAR1}
230         \label{tab_bar1}
231         \end{center}
232 \end{table}
233
234 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).
235
236 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}). 
237 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.
238
239 \begin{table}[h!]
240         \begin{center}
241         \begin{tabular}{|c|c|c|}
242         \hline \textbf{Bit} & \textbf{Description} & \textbf{Default} \\ 
243         \hline 7:0 & \textbf{Digital input 7:0.} Reads digital input port. & 1 \\ 
244         \hline 15:8 & Reserved & N/A \\ 
245         \hline 
246         \end{tabular} 
247         \caption{DIN -- Digital Input Register Format}
248         \label{tab_din}
249         \end{center}
250 \end{table}
251
252 \begin{table}[h!]
253         \begin{center}
254         \begin{tabular}{|c|c|c|}
255         \hline \textbf{Bit} & \textbf{Description} & \textbf{Default} \\ 
256         \hline 7:0 & \textbf{Digital output 7:0.} Writes to digital output port. & 0 \\ 
257         \hline 15:8 & Reserved & N/A \\ 
258         \hline 
259         \end{tabular} 
260         \caption{DOUT -- Digital Output Register Format}
261         \label{tab_dout}
262         \end{center}
263 \end{table}
264
265
266 \subsection{A/D převodníky}
267 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:
268
269 \begin{itemize}
270 \item Nejprve se v registru ADCTRL zvolí, které A/D převodníky mají být čteny. 
271 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.
272 \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á.
273 \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).
274 \item Výslednou hodnotu je možné přečíst z registru ADDATA, který je typu FIFO. To znamná, že opětovným čtením jednoho registru vyčteme jednotlivé naměřené hodnoty z aktivovaných A/D převodníků v pořádí od 0 k 7.
275
276 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.
277 \end{itemize}
278
279 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}.
280
281
282 \begin{table}[h!]
283         \begin{center}
284         \begin{tabular}{|c|c|}
285         \hline \textbf{Digitální hodnota} & \textbf{Analogová hodnota} \\ 
286         \hline 0x3FFF & -0.0012 V \\ 
287         \hline 0x2000 & -10.0000 V \\ 
288         \hline 0x1FFF &  9.9988 V \\ 
289         \hline 0x0000 &  0.0000 V \\ 
290         \hline 
291         \end{tabular} 
292         \caption{Kódování vstupních hodnot A/D převodníku}
293         \label{tab_adval}
294         \end{center}
295 \end{table}
296
297 \subsection{D/A převodníky}
298 Karta MF624 obsahuje také osm 14bitových D/A převodníků s rozsahem $\pm$10 V.
299
300 Nastavení výstupních hodnot D/A převodníků může probíhat následujícícm způsobem:
301
302 \begin{itemize}
303 \item Hodnota v aditivním kódu (tabulka \ref{tab_daval}) se zapíše do jednoho z osmi registrů DA0--DA7 odpovídajícího D/A převodníku, který má být nastaven.
304 \item Bit DACEN (26. bit) registru GPIOC je potřeba nastavit na 1, jinak jsou výstupy D/A převodníků připojeny na \textit{zem}.
305 \item Bit LDAC (23. bit) registru GPIOC je potřeba nastavit na 0, aby byl spuštěn samotný převod D/A převodníků (jinak zůstane zapsaná hodnota pouze v registru, výstupní hodnota D/A převodníku zůstane nezměněna).
306 \end{itemize}
307
308
309 \begin{table}[h!]
310         \begin{center}
311         \begin{tabular}{|c|c|}
312         \hline \textbf{Digitální hodnota} & \textbf{Analogová hodnota} \\ 
313         \hline 0x3FFF &  9.9988 V \\ 
314         \hline 0x2000 &  0.0000 V \\ 
315         \hline 0x1FFF & -0.0012 V \\ 
316         \hline 0x0000 & -10.0000 V \\ 
317         \hline 
318         \end{tabular} 
319         \caption{Kódování vstupních hodnot A/D převodníku}
320         \label{tab_daval}
321         \end{center}
322 \end{table}
323
324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325 \chapter{Implementace ovladačů}
326 \section{Operační systém GNU/Linux}
327 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.
328
329 \subsection{Práce s PCI zařízeními z uživatelského prostoru}
330 FIXME popsat lspci (parametry a příklady) a /sys/bus/pci
331
332 \subsection{Základní jaderný modul}
333 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.
334
335 Jak se takový jaderný modul může vypadat, je nejlepší si ukázat na příkladu:
336 \begin{verbatim}
337  1 |  #include <linux/init.h>
338  2 |  #include <linux/module.h>
339  3 | 
340  4 |  static int hello_init(void)
341  5 |  {
342  6 |      printk("Hello, world!\n");
343  7 |      return 0;
344  8 |  }
345  9 | 
346 10 |  static void hello_exit(void)
347 11 |  {
348 12 |      printk("Goodbye, cruel world!\n");
349 13 |  }
350 14 | 
351 15 |  module_init(hello_init);
352 16 |  module_exit(hello_exit);
353 17 |  
354 18 |  MODULE_LICENSE("Dual BSD/GPL");
355 \end{verbatim}
356
357 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).
358 \begin{description}
359 \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.
360 \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()}.
361
362 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$
363 \item[řádku 15] -- ten obsahuje makro \texttt{module\_init()}, kterému řekneme právě to, která funkce se má po načtení spustit.
364 \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$
365 \item[řádcích 10--13.] Tato funkce nemá na starost nic jiného než výpis krátkého textu do logu jádra.
366 \end{description}
367
368 \subsection{Kompilace modulu}
369 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}:
370 \begin{verbatim}
371 1 |  KERNEL_VER=`uname -r`
372 2 |  obj-m += hello.o
373 3 |
374 4 |  all:
375 5 |      make -C /lib/modules/$(KERNEL_VER)/build M=$(PWD) modules
376 6 |  clean:
377 7 |      make -C /lib/modules/$(KERNEL_VER)/build M=$(PWD) clean
378 \end{verbatim}
379 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:
380
381 \begin{description}
382 \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í)
383 \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)
384 \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}).
385 \end{description}
386
387 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:
388 \begin{verbatim}
389 $ make
390 make -C /lib/modules/`uname -r`/build M=/tmp/kernel_module_example modules
391 make[1]: Entering directory `/usr/src/linux-headers-2.6.35-28-generic'
392   CC [M]  /tmp/kernel_module_example/hello.o
393   Building modules, stage 2.
394   MODPOST 1 modules
395   CC      /tmp/hello.mod.o
396   LD [M]  /tmp/hello.ko
397 make[1]: Leaving directory `/usr/src/linux-headers-2.6.35-28-generic'
398 \end{verbatim}
399 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}
400
401 \begin{verbatim}
402 $ ls
403 hello.c  hello.ko  hello.mod.c  hello.mod.o  hello.o  
404 Makefile  modules.order  Module.symvers
405 \end{verbatim}
406
407 \subsection{Zavedení modulu}
408 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:
409 \begin{verbatim}
410 $ sudo insmod ./hello.ko 
411 \end{verbatim}
412
413 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:
414 \begin{verbatim}
415 $ dmesg | tail -1
416 [ 9245.757491] Hello, world!
417 \end{verbatim}
418 A skutečně je posledním řádkem v logu text vypsaný zavedeným modulem.
419
420 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).
421 \begin{verbatim}
422 $ sudo rmmod hello 
423
424 $ dmesg | tail -1
425 [ 9612.256929] Goodbye, cruel world!
426 \end{verbatim}
427 V logu je opět nachází text vypisovaný modulem při uvolňování z jádra.
428
429
430 \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.}
431
432 \subsection{Na co si dávat pozor}
433 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ří:
434
435 \begin{description}
436 \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.
437 \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
438 \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}}.
439 \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.
440 \end{description}
441
442 \subsection{Příkaz GOTO}
443 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
444
445 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446 \section{Ovladače PCI zařízení}
447 \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} -- \\
448 \url{http://lxr.linux.no/}.}
449
450 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}. 
451
452 \subsection{Struktura \texttt{struct pci\_driver}}
453 Tato struktura obsahuje základní informace o našem ovladači. Mezi hlavní položky patří:
454 \begin{description}
455 \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.
456 \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).
457 \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.
458 \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.
459 \end{description}
460
461 Příklad, jak může být struktura \texttt{pci\_driver} inicializována a následně zaregistrována:
462 \begin{verbatim}
463 1 |  static struct pci_driver mf624_pci_driver = {
464 2 |      .name = "mf624",
465 3 |      .id_table = mf624_pci_id,
466 4 |      .probe = mf624_pci_probe, 
467 5 |     .remove = mf624_pci_remove,
468 6 |  };
469 pci_register_driver(&mf624_pci_driver);
470 \end{verbatim}
471
472 \subsection{Struktura \texttt{struct pci\_device\_id}}
473 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ě:
474
475 \begin{verbatim}
476  1 |  #define PCI_VENDOR_ID_HUMUSOFT          0x186c
477  2 |  #define PCI_DEVICE_ID_MF624             0x0624
478  3 |  #define PCI_SUBVENDOR_ID_HUMUSOFT       0x186c
479  4 |  #define PCI_SUBDEVICE_DEVICE            0x0624
480  5 |  
481  6 |  static struct pci_device_id mf624_pci_id[] = {
482  7 |      {
483  8 |          .vendor = PCI_VENDOR_ID_HUMUSOFT,
484  9 |          .device = PCI_DEVICE_ID_MF624,
485 10 |          .subvendor = PCI_SUBVENDOR_ID_HUMUSOFT,
486 11 |          .subdevice = PCI_SUBDEVICE_DEVICE,
487 12 |      },
488 13 |      { 0, } /* seznam je vždy zakončen prázdným prvkem */
489 14 |  };
490 \end{verbatim}
491
492
493 \subsection{Funkce \texttt{probe()}}
494 \ibox{\texttt{int probe(struct pci\_dev *dev, const struct pci\_device\_id *id);}}
495
496 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í.
497
498 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č.
499
500 \ibox{\texttt{pci\_enable\_device(struct pci\_dev *dev);}}
501
502 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í.
503
504 \subsection{Přístup ke zdrojům karty}
505 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. 
506
507 \ibox{\texttt{int pci\_request\_regions(struct pci\_dev *pdev, const char *res\_name);}}
508
509 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.
510
511 \ibox{\texttt{unsigned long pci\_resource\_start(struct pci\_dev *dev, int bar);}}
512
513 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).
514
515 \ibox{\texttt{unsigned long pci\_resource\_len(struct pci\_dev *dev, int bar);}}
516
517 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()}.
518
519 \ibox{\texttt{void \_\_iomem *pci\_ioremap\_bar(struct pci\_dev *pdev, int bar);}}
520
521 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()}.
522
523 K ukazateli, který vrátí volání \texttt{pci\_ioremap\_bar()} je již možné pomocí speciálních funkcí přistupovat.
524
525 \ibox{FIXME povídání o out-of-order execution a cache a proč musíme používat speciální funkce}
526
527 \subsection{Funkce \texttt{remove()}}
528
529 \ibox{\texttt{void remove(struct pci\_dev *dev);}}
530
531 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.
532
533 Tato funkce by se měla postarat o úklid všech naalokovaných prostředků apod. Měla by obsahovat volání:
534 \begin{description}
535 \item[\texttt{iounmap()}]~\\Uvolnění virtuální paměti namapované voláním \texttt{pci\_ioremap\_bar()}.
536 \item[\texttt{pci\_release\_regions()}]~\\Uvolnění zdrojů karty, které byly zarezervovány voláním \texttt{pci\_request\_regions()}.
537 \item[\texttt{pci\_disable\_device()}]~\\Opak k volání \texttt{pci\_enable\_device()}.
538 \end{description}
539
540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541 \section{Přístup k paměti zařízení}
542 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ů.
543
544 \subsection{Vstupně-výstupní adresní prostor}
545 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í:
546
547 \ibox{\texttt{unsigned inb(unsigned port);}}
548
549 \ibox{\texttt{unsigned inw(unsigned port);}}
550
551 \ibox{\texttt{unsigned inl(unsigned port);}}
552
553 Třetí písmeno značí o \textit{kolikabitové} čtení se jedná: b = 8 b, w = 16 b, l = 32 b.
554
555 Pro zápis je možné využít volání:
556 \ibox{\texttt{void outb(unsigned char byte, unsigned port);}}
557
558 \ibox{\texttt{void outw(unsigned char byte, unsigned port);}}
559
560 \ibox{\texttt{void outl(unsigned char byte, unsigned port);}}
561
562
563 Třetí písmeno, stejně jako u funkcí pro čtení, značí o kolikabitový přístup se jedná.
564
565 Stejná volání je možné používat i z uživatelského prostoru (potřebný hlavičkový soubor je \texttt{<sys/io.h>}).
566 \subsection{Paměťový adresní prostor}
567 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.
568
569 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.
570
571 Těmto optimalizacím lze nejsnáze zabránit použitím volání:
572
573 \ibox{\texttt{unsigned int ioread8(void *addr);}}
574
575 \ibox{\texttt{unsigned int ioread16(void *addr);}}
576
577 \ibox{\texttt{unsigned int ioread32(void *addr);}}
578
579 pro čtení a volání
580
581 \ibox{\texttt{void iowrite8(u8 value, void *addr);}}
582
583 \ibox{\texttt{void iowrite16(u16 value, void *addr);}}
584
585 \ibox{\texttt{void iowrite32(u32 value, void *addr);}}
586
587 pro zápis. Číslo na konci funkce označuje o kolikabitový přístup se jedná.
588
589 V případě, že se na paměť ve vstupně-výstupním adresním prostoru zavolá funkce 
590 \ibox{\texttt{void *ioport\_map(unsigned long port, unsigned int count);}} 
591 nebo v případě PCI zařízení funkce
592 \ibox{\texttt{void \_\_iomem *pci\_iomap(struct pci\_dev *dev, int bar, unsigned long maxlen);}}
593
594 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í.
595
596 Z uživatelského prostoru je potřeba používat volání FIXME.
597
598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
599 \section{UIO ovladač}
600 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.
601
602 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á).
603
604 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.
605
606 \subsection{Jaderný modul}
607 Jaderný modul UIO ovladače by měl obsahovat:
608 \begin{itemize}
609 \item Funkci volanou PCI subsystémem při registraci ovladače
610 \item Volání funkcí pro namapování regionů zařízení
611 \item Inicializaci struktury \texttt{struct uio\_info} a registraci do UIO subsystému
612 \item Funkce pro \textit{úklid} a uvolnění regionů karty
613 \end{itemize}
614
615 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}.
616
617 \ibox{\texttt{int uio\_register\_device(struct device *parent, struct uio\_info *info);}}
618
619 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}.
620
621 \subsubsection{Struktura \texttt{struct uio\_info}}
622 Mezi její hlavní položky patří:
623 \begin{description}
624 \item[\texttt{const char *name}]~\\Název ovladače
625 \item[\texttt{const char *version}]~\\Verze ovladače
626 \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
627 \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.
628 %\item[\texttt{}]
629 \end{description}
630
631 \subsubsection{Struktura \texttt{struct uio\_mem} a \texttt{struct uio\_port}}
632 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.
633
634 Struktura \texttt{struct uio\_mem} obsahuje položky:
635 \begin{description}
636 \item[\texttt{const char *name}]~\\Textový popis daného regionu (viditelný z uživatelského prostoru).
637 \item[\texttt{unsigned long addr}]~\\Fyzická adresa regionu získaná voláním \texttt{pci\_resource\_start()}.
638 \item[\texttt{unsigned long size}]~\\Délka regionu. Nejsnáze získaná voláním \texttt{pci\_resource\_len()}.
639 \item[\texttt{int memtype}]~\\Typ paměti. Pro fyzickou paměť na zařízení se použije \texttt{UIO\_MEM\_PHYS}.
640 \item[\texttt{void \_\_iomem *internal\_addr}]~\\Virtuální adresa získaná voláním \texttt{pci\_ioremap\_bar()}
641 \end{description}
642
643 Struktura \texttt{struct uio\_port} obsahuje položky:
644 \begin{description}
645 \item[\texttt{const char *name}]~\\Textový popis daného regionu (viditelný z uživatelského prostoru).
646 \item[\texttt{unsigned long start}]~\\Fyzická adresa regionu získaná voláním \texttt{pci\_resource\_start()}.
647 \item[\texttt{unsigned long size}]~\\Délka regionu. Nejsnáze získaná voláním \texttt{pci\_resource\_len()}.
648 \item[\texttt{int porttype}]~\\Typ portu. Pro porty na architektuře IA-32 se použije \texttt{UIO\_PORT\_X86}
649 \end{description}
650
651 ~\\
652
653 Příklad, jak taková jednoduchá inicializace struktury \texttt{struct uio\_info} včetně registrace může vypadat (bez ošetření chybných stavů):
654 \begin{verbatim}
655  1 |  /* struct pci_dev *dev */
656  2 |  struct uio_info *info;
657  3 |  info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
658  4 |  
659  5 |  info->name = "mf624";
660  6 |  info->version = "0.0.1";
661  7 |  
662  8 |  info->mem[0].name = "PCI chipset, ...";
663  9 |  info->mem[0].addr = pci_resource_start(dev, 0);
664 10 |  info->mem[0].size = pci_resource_len(dev, 0);
665 11 |  info->mem[0].memtype = UIO_MEM_PHYS;
666 12 |  info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
667 13 |  
668 14 |  info->port[0].name = "Board programming registers";
669 15 |  info->port[0].porttype = UIO_PORT_X86;
670 16 |  info->port[0].start = pci_resource_start(dev, 1);
671 17 |  info->port[0].size = pci_resource_len(dev, 1);
672 18 |  
673 19 |  uio_register_device(&dev->dev, info);
674 20 |  pci_set_drvdata(dev, info);
675 \end{verbatim}
676
677 \ibox{\texttt{void pci\_set\_drvdata(struct pci\_dev *pdev, void *data)}}
678
679 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}
680
681 \subsection{Program v uživatelském prostoru}
682 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:
683 \begin{itemize}
684 \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.}}.
685 \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.
686 \end{itemize}
687
688 \subsubsection{Obsah složky \texttt{/sys/class/uio/uio0}}
689 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).
690
691 \subsubsection{Soubor \texttt{/dev/uio0}}
692 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()}.
693
694 \ibox{\texttt{void *mmap(void *addr, size\_t length, int prot, int flags, int fd, off\_t offset);}}
695
696 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ěť.
697  
698 \begin{description}
699 \item[Parametr \texttt{addr}] -- v případě, že není nulový -- určí, na jakou adresu by měla být paměť mapována.
700 \item[Parametr \texttt{length}] udává velikost mapované paměti v násobcích velikosti paměťové stránky. 
701 \item[Parametr \texttt{prot}] obsahuje příznaky definující, zda bude mapovaná paměť pro čtení/zápis, apod.
702 \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}).
703 \item[Parametr \texttt{fd}] obsahuje \textit{filedescriptor} na zařízení, které má být namapováno (v tomto případě \texttt{/dev/uio0}).
704 \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.
705 \end{description}
706
707 Příklad, jak takové volání může vypadat (bez ošetření chybných stavů):
708 \begin{verbatim}
709 1 |  #define BAR2_offset       (1 * sysconf(_SC_PAGESIZE))
710 2 |  void* mf624_BAR2 = NULL;
711 3 |  int device_fd = open("/dev/uio0", O_RDWR);
712 4 |  
713 5 |  mf624_BAR2 = mmap(0, 1 * sysconf(_SC_PAGESIZE), 
714 6 |                    PROT_READ | PROT_WRITE, MAP_SHARED, 
715 7 |                    device_fd, BAR2_offset);
716 \end{verbatim}
717
718 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.
719
720 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):
721 \begin{verbatim}
722 mf624_BAR2 += (BAR2_phys_addr & (sysconf(_SC_PAGESIZE) - 1));
723   |                \-- Fyzická adresa
724   \-- Ukazatel vrácený voláním mmap()                 
725 \end{verbatim}
726
727 \subsection{Přístup k paměti zařízení}
728 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í.
729 FIXME
730
731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
732 \section{Comedi ovladač}
733 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.
734
735 Pro ovladače měřících karet existuje v Linuxu subsystém -- tzv. Comedi (Control and Measurement Device Interface).
736 \subsection{Registrace Comedi ovladače}
737 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).
738
739 \subsection{Struktura \texttt{struct comedi\_driver}}
740 Tato struktura obsahuje ukazatele na funkce, které jsou zavolány při nahrání resp. uvolnění ovladače.
741 Položky struktury jsou:
742 \begin{description}
743 \item[\texttt{const char *driver\_name;}]~\\Obsahuje textový název ovladače.
744 \item[\texttt{struct module *module;}]~\\Ukazatel na modul, kterému tato struktura náleží. Inicializuje se makrem \texttt{THIS\_MODULE}.
745 \item[\texttt{int (*attach) (struct comedi\_device *, struct comedi\_devconfig *);}]~\\Ukazatel na funkci, která má být zavolána po načtení modulu
746 \item[\texttt{int (*detach) (struct comedi\_device *);}]~\\Ukazatel na funkci, která má být zavolána při uvolňování modulu
747 \end{description}
748
749
750 \subsection{Registrace struktury \texttt{struct pci\_device\_id}}
751 V případě UIO ovladače, byla vytvořena struktura \texttt{struct pci\_driver}, jejíž jeden parametr byl ukazatel na strukturu \texttt{struct pci\_device\_id}. V případě Comedi ovladače se struktura \texttt{struct pci\_driver} nevytváří, proto je potřeba registrovat strukturu \texttt{struct pci\_device\_id} zvlášť.
752
753 \ibox{\texttt{MODULE\_DEVICE\_TABLE(type, struct pci\_device\_id* name);}}
754
755 Po inicializaci správnými hodnotami se pro registraci zavolá makro \texttt{MODULE\_DEVICE\_TABLE(type, name)}, kde se prvním parametrem určí, o jaké se jedná zařízení (v tomto případě \uv{pci}) a druhým parametrem se předá ukazatel na strukturu \texttt{struct pci\_device\_id}.
756
757
758 Příklad základní registrace zařízení:
759 \begin{verbatim}
760  1 |  static struct pci_device_id mf624_pci_table[] = {
761  2 |      { /* ... */ },
762  3 |      { 0 }
763  4 |  };
764  5 |  MODULE_DEVICE_TABLE(pci, mf624_pci_table);
765  6 |  
766  7 |  static struct comedi_driver driver_mf624 = {
767  8 |      driver_name:  "mf624",
768  9 |      module:       THIS_MODULE,
769 10 |      attach:       mf624_attach,
770 11 |      detach:       mf624_detach,
771 12 |  };
772 13 |  
773 14 |  COMEDI_INITCLEANUP(driver_mf624);
774 \end{verbatim}
775
776 \subsection{Funkce \texttt{attach}}
777 FIXME procházení všech karet
778
779 \texttt{struct comedi\_subdevice}
780
781 \subsection{Funkce \texttt{detach}}
782
783 \subsection{Struktura popisující vlastnosti zařízení}
784 %Výše byly popsány struktury a funkce potřebné pro samotnou registraci Comedi ovladače. Dále je potřeba se zabývat 
785 \subsection{Struktura pro privátní data}
786
787
788 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789 \chapter{Testování}
790 \section{UIO ovladač, Comedi ovladač}
791 Jednotlivé ovladače jsou tvořeny samostatnými jadernými moduly, které pouze využívají volání jednotlivých subsystémů -- neexportují žádné \textit{symboly} ani nemění globální proměnné. V tomto případě nebylo nutné provádět regresní testování.
792
793 Testování správnosti funkce ovladačů probíhala přímo na hardware, za pomoci \textit{univerzální svorkovnice TB620} (obrázek \ref{svorkovnice}).
794
795 \begin{figure}[h!]
796         \begin{center}
797         \includegraphics[width=120mm]{img/svorkovnice.jpg}
798         \caption{Svorkovnice TB620.}
799         \label{svorkovnice}
800         \end{center}
801 \end{figure}
802
803 \vspace{1cm}
804 Základní propojení na svorkovnici, které se osvědčilo, bylo:
805 \begin{itemize}
806 \item 2 $\times$ LED pro nejnižší bity DOUT
807 \item 2 $\times$ 1k$\Omega$ rezistory mezi 5 V a nejnižšími bity DIN
808 \item 2. bit DIN dynamicky spojován s GND nebo pomocí 1k$\Omega$ rezistoru s 5 V
809 \item Měření multimetrem výstupní hodnoty z DAC (většinou DAC0 nebo DAC1)
810 \item ADC0 spojen s GND, ADC1 spojen pomocí 1k$\Omega$ rezistoru s DAC0
811 \end{itemize}
812
813 Konzistence jádra byla testována opětovným načítáním a uvolňováním jednotlivých ovladačů.
814
815 \section{Qemu virtuální hardware, Qt grafické rozhraní}
816
817
818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
819 \chapter{Závěr}
820
821
822 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
823 \appendix
824 \chapter{Qemu a Humusoft MF624}\label{qemu}
825 Měřící karta Humusoft MF624 je hardware vhodný pro výklad principů 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. Takto modifikovaná verze qemu může pří implementaci základního ovladače plně nahradit původní kartu.
826
827 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.
828
829
830 \section{Qemu}
831 \subsection*{Kompilace, instalace}
832 Nejprve je potřeba řádně zkompilovat některé ze stabilních vydání emulátoru Qemu.
833
834 \subsection*{Použití}
835 Komunikace mezi virtuální kartou implementovanou v Qemu a grafickým programem probíhá pomocí TCP/IP protokolu.
836
837 \section{Qt grafiké rozhraní}
838 Na obrázku \ref{qt_gui} je 
839
840 Aplikaci je nutné spouštět až po stuštění Qemu ....
841
842 \begin{figure}[h!]
843         \begin{center}
844         \includegraphics[width=70mm]{img/qt_gui.png}
845         \caption{(FIXME aktualni verzi). Vzhled grafikcé aplikace pro ovládání vstupů virtuální karty MF624}
846         \label{qt_gui}
847         \end{center}
848 \end{figure}