Produkty Novinky Články Návody Kontakty

SAM9260 a grafický TFT displej - 7. framebuffer device

V předchozím dílu našeho seriálu o připojení grafického TFT displeje k procesorovém modulu SAM9260 jsme dokončili jednoduchý ovladač displeje pro operační systém Linux. Tento ovladač byl především testovací, měl za úkol ověřit možnost komunikovat s připojeným TFT displejem. Proto jej není možné použít jako grafický výstup pro aplikace s grafickým rozhraním např. pod systémem X Windows a ani není použitelný jako konzolové zařízení. Flintu do žita však házet nemusíme. Stačí, když zdrojový kód ovladače upravíme tak, aby fungoval jako ovladač framebufferového zařízení. A přesně o tom budou poslední dva díly.

Tučňák a grafika

Jak vlastně funguje grafické prostředí Linuxu? Co musím udělat proto, abych mohl na svém embedded zařízení pouštět aplikace s grafickým rozhraním? Ano, já se ptal stejně. V Linuxu jsou v zásadě dvě cesty, jak zobrazit ”okýnka” na monitoru nebo jiném zobrazovacím elementu (TFT displej, e-Ink papír, atd).
První cesta může být nasazení systému X Windows. Toto velmi propracované grafické prostředí definuje tzv. X-server, který má za úkol sbírat informace od vstupních zařízení (klávesnice, myš, touchpanel) a který zároveň zajišťuje zobrazování na výstupním zařízení (grafická karta + monitor, TFT displej). Logicky jako protějšek X-serveru jsou pak definovány tzv. X-klienti, což jsou jednotlivé aplikace s grafickým rozhraní, které komunikují s X-serverem a přijímají od něj události ze vstupního zařízení (stisk klávesy, pohyb myši) a zároveň mu zasílají k zobrazení svá grafická data. Komunikace probíhá v duchu X-protokolu přístupného na straně X-klienta přes sadu knihoven xlib a až na výjimky zásadně přes TCP/IP rozhraní. Je tedy jedno, jestli X-klienti a X-server běží na stejném počítači a komunikují místně (klasicky na desktopu), nebo jestli je od sebe dělí rozsáhlá podniková síť (grafický terminál a mainframe).
V cestě nasazení X Windows na embedded zařízení stojí však jejich vysoké systémové nároky a také poměrně dosti obtížný vývoj ovladačů pro dané vstupní a výstupní zařízení.
Naštěstí je možné se vydat i jinou cestou a zobrazovací zařízení zprovoznit v Linuxu jako tzv. framebufferové zařízení (framebuffer device). To je zařízení, které má speciální paměť - framebuffer, ve kterém je uložen právě jeden kompletní snímek obrazovky, tzn. informace o barvě všech pixelů celé plochy zobrazovacího zařízení, např. TFT displeje. Z pohledu aplikace v uživatelském prostoru se framebufferové zařízení chová jako každé jiné zařízení v Linuxu: přes jeho soubor zařízení v adresáři /dev (konkrétně /dev/fb*, kde * je číslo 0 až 31) je možné k němu, resp. k jeho framebufferu, přistupovat pomocí běžných souborových operací read(), write() apod. Nebo je možné, a to je preferovaný způsob, si framebuffer přes souborovou operaci mmap() namapovat do aplikace jako blok paměti a zapisovat grafická data přímo do něj. Úkolem framebufferového zařízení není pak nic jiného (s trochou nadsázky), než se postarat o zobrazení dat ze svého framebufferu. Vyčítání a změna parametrů framebufferového zařízení se řeší také přes souborové operace - konkrétně přes operaci ioctl() a jednotnou množinu několika IOCTL příkazů.
Tím, že se framebufferové zařízení chová jako soubor, se implementace jeho ovladače značně ulehčuje. Také je mnohem snazší vytvořit nad framebufferovým zařízením embedded alternativy k X Windows (nano-X, DirectFB) a dále pak odlehčené alternativy k navazujícím těžkotonážním GUI knihovnám typu GTK+ a Qt (např. FLTK, LiTE), které urychlují vývoj grafického rozhraní uživatelské aplikace - přeci jen vykreslování okýnek a ovládacích prvků do framebufferu přímo z aplikace není ideální způsob vývoje aplikace s GUI.
Z uvedených důvodů se zobrazovací zařízení ve světě embedded Linuxu implementují takřka výhradně jako framebufferová zařízení; koneckonců i při bootu desktopového Linuxu se ke grafické kartě přistupuje jako k framebufferovému zařízení. Tedy aspoň po dobu zobrazování loga s Tuxem a textových bootovacích hlášek.
X Windows vs. framebuffer

Vrstvy ovladače

Každý, kdo se rozhodne napsat si svůj první ovladač framebufferového zařízení, se chtě nechtě musí prokousat ekosystémem nebo chcete-li podpůrným kódem, který vývojáři jádra pro ovladače framebufferových zařízení připravili. Zkusíme se na to mrknout společně.
Ovladač framebufferového zařízení je rozdělený do tří vrstev. První vrstvu tvoří hlavičkový soubor include/linux/fb.h (jsme ve stromě zdrojového kódu linuxového jádra), který je jakýmsi obecným rozhraním z pohledu uživatelské aplikace. Zde jsou definovány struktury pro výměnu dat mezi uživatelskou aplikací a ovladačem a seznam dostupných IOCTL příkazů. Protože se tento soubor vkládá i do kódu ovladače, nalezneme zde i deklarace funkcí používaných při implementaci ovladače. Z definovaných struktur v souboru fb.h zmíním jen ty skutečně nejdůležitější:
  • struktura fb_info - definuje aktuální stav framebufferového zařízení. Každá funkce z nízkoúrovňového rozhraní ovladače obsahuje ukazatel na tuto strukturu jako parametr. Struktura fb_info tedy funguje podobně jako file descriptor (struktura FILE).
  • struktura fb_fix_screeninfo - zde jsou uloženy parametry framebufferového zařízení, které jsou platné pro daný mód (počáteční adresa a velikost framebufferu, barevné schémna apod.). Z uživatelského prostoru tyto parametry nelze měnit. Struktura fb_fix_screeninfo je členem struktury fb_info.
  • struktura fb_var_screeninfo - uchovává parametry framebufferového zařízení, které je možné z uživatelského prostoru měnit (rozlišení, barevnou hloubku atd.). Stejně tak slouží pro samotné předání nových hodnot těchto parametrů z uživatelského prostoru do ovladače. Struktura fb_var_screeninfo je členem struktury fb_info.
  • struktura fb_ops - definuje nízkoúrovňové rozhraní (sadu funkcí) ovladače framebufferového zařízení.
Další důležitý soubor je soubor drivers/video/fbmem.c. Ten tvoří jakousi mezivrstvu mezi uživatelským prostorem a ovladačem daného framebufferového zařízení. Na straně uživatelského prostoru poskytuje kód pro obsluhu systémových volání (souborových operací) jako open(), read()/write(), ioctl(), mmap() atd. Tato systémová volání pak na straně ovladače převádí na volání jeho nízkoúrovňového rozhraní.
Vedle toho soubor fbmem.c spolu s dalšími soubory obsahuje i výchozí implementaci nízkoúrovňového rozhraní ovladače framebufferového zařízení. Ano, až tak moc na nás vývojáři jádra byli hodní. Nám pak stačí dopsat jen kód pro obsluhu specifických vlastností daného framebufferové zařízení.
Poslední vrstvu tvoří soubor s naším vlastním kódem ovladače framebufferového zařízení. Zde musíme naimplementovat nízkoúrovňové rozhraní definované strukturou fb_ops (ne všechny funkce jsou povinné), ať už s pomocí funkcí v souboru fbmem.c nebo kompletně z gruntu po našem. Dále se musíme postarat o začlenění ovladače do ekosystému jádra - vyřešit inicializaci a úklid ovladače. Nesmí chybět ani funkce pro obsluhu IOCTL příkazů (nastavení parametrů, módu). A samozřejmě nikdo za nás nenapíše kód pro obsluhu samotného zobrazovacího zařízení a kód, který zajišťuje zobrazení dat z framebufferu.

Seznam dílů seriálu SAM9260 a grafický TFT displej