AMIGA REVIEW obsah časopisu online!
  Domov     Software     Hry     Obaly     Download  

Devices

Jan Hlavatý

Obsluha softwarových zařízení Amigy

Vítejte u dalšího pokračování série o systému a assembleru. Vinou zákeřné nemoci jsem byl nucen jeden díl vynechat. Nepanikařte, nic se neděje, cenné informace si s sebou do hrobu nevezmu... Takže: Z minula už něco víte o multitaskingu a komunikaci mezi jednotlivými triky pomocí portů a messages. V tomto povídání se podíváme na praktické využití těchto prostředků v obsluze softwarových zařízení Amigy - devices.

Co je to device?
Device je ve své podstatě program, ovládající většinou nějaký hardware. Device je schopno vykonávat určité příkazy specifické pro daný typ ovládaného hardware (nebo software) způsobem jednotným pro všechna devices v systému. Běží obvykle jako samostatný task (např. "trackdisk.device" ovládající disketové mechaniky), v některých případech rutiny device běží jako ovladače přerušení (např. "serial.device" ovládající přenos dat po sériovém portu). Některá základní systémová devices jsou umístěna přímo v ROM systému, jiná jsou uložena na systémovém disku v adresáři "DEVS:". Pokud se podíváte do tohoto adresáře, najdete tam například u OS 3.1:
- clipboard.device: Umožňuje výměnu dat mezi programy. Například když v DPaintu nakreslenou ikonu pomocí funkce "copy" přenesete do clipboardu a následně ji vložíte do programu "iconedit" funkcí "paste", děje se to prostřednictvím tohoto device.
- mfm.device: Nadstavba trackdisk.device,umožňuje čtení a zápis disket naformátovaných pro PC (je využíváno pro PC0:)
- parallel.device: Zařízení obsluhující paralelní port. Přes něj probíhá např. tisk na tiskárnách s rozhraním Centronics (většina). Pozor! Obsluhu tiskáren má na starosti jiné zařízení ("printer.device"), parallel.device se pouze stará o přenos dat mezi počítačem a hardwarem připojeným na paralelní port.
- printer.device: Toto zařízení obsluhuje tiskárny, a to standardním způsobem pro všechny podporované tiskárny. Je schopno vytisknout kus textu a dokonce i kus grafiky! Tomuto zařízení stačí sdělit "vytiskni mi tohle", a ono už samo podle nastavených preferencí a ovladače tiskárny provede akci způsobem specifickým pro konkrétní nastavenou tiskárnu. Při tisku textu lze v textu používat standardní ANSI řídící kódy tiskáren, které jsou automaticky ovladačem překládány na konkrétní řídící kódy tiskárny.
- serial.device: Toto zařízení obsluhuje sériový port. Nejobvyklejším použitím tohoto zařízení je komunikace s modemem. Toto device umí nejen posílat data nastavenou přenosovou rychlostí, ale postará se i o handshaking, ať už softwarový (xON/xOFF) nebo hardwarový (RTS/CTS).
V ROM jsou umístěna další devices:
- gameport.device: Toto device obsluhuje joystickové porty - zprostředkovává čtení myši a joysticku z obou portů.
- timer.device: Toto důležité device slouží k měření časových intervalů několika různými způsoby.
- keyboard.device: Obsluhuje klávesnici - umožňuje načítat stisknuté klávesy tak jak jsou postupně mačkány a uvolňovány, nebo načíst celou mapu stisknutých kláves. Navíc umožňuje instalovat handler, který je schopen po stisku ctrl-amiga-amiga (RESET) urychleně provést nějakou akci. Toho využívá například trackdisk.device - tam reset handler zakáže jakýkoliv zápis na disk, aby nemohlo dojít k poškození formátu právě zapisované stopy.
- input.device: Toto je bod, kde se sbíhají všechny vstupní události jako jsou pohyby myši, stisky kláves, hlášení o vložení diskety a pod., které pak odtud putují do systému - tedy především k intuitionu. Toto zařízení umožňuje instalovat handler, který bude prohlížet všechny přicházející události (input events), provádět různé akce a případně některé ze vstupních událostí odstraňovat.
- ramdrive.device: Toto zařízení umožňuje používání RAM-disku, který je schopen přežít reset (označuje se "RAD:").
- trackdisk.device: Obsluhuje všechny čtyři možné disketové mechaniky, a to nejen normální 3.5" DD, ale i 5.25" a 3.5" HD. Umožňuje zapínat a vypínat motory mechanik, formátovat, načítat a zapisovat stopy ve standardním amiga formátu, zjišťovat informace o typu mechanik a navíc má speciální "raw" funkce, umožňující číst a zapisovat stopy i v jiném, nestandardním formátu.
- carddisk.device: Existuje u Amig vybavených PCMCIA slotem. Umožňuje používat RAM-kartu stejným způsobem jako disketu.
- scsi.device: Obsluhuje harddisk na AT-BUS sběrnici v A600/A1200. Navenek se tváří jako SCSI zařízení.
- console.device: Toto zařízení je schopno vytvořit znakově orientovaný textový vstup/výstup, jak ho známe např. z oken Shellu. Podporuje standard ANSI.

Softwarová obsluha devices
Pokud jde o vnitřní strukturu, jsou devices podobná sdíleným knihovnám. Stejně jako ony mají svou bázi se skokovými vektory na negativních offsetech a datovými strukturami na pozitivních offsetech. Volání funkcí devices je však koncipováno odlišně vzhledem k tomu, že device bývá obvykle samostatný task který přijímá příkazy od ostatních tasků a postupně je zpracovává. Naproti tomu u knihoven volaná funkce proběhne přímo v tasku který ji volá jako podprogram. Existují samozřejmě výjimky - např. "timer.device" má několik "knihovních" funkcí navíc pro práci s časem. Taktéž tzv. quick-io mód předávání příkazů je výjimkou - viz dále.
K tomu, abyste mohli poslat nějakému device příkaz, potřebujete tzv. IORequest strukturu. To je v podstatě message rozšířené o několik údajů jako je příkaz, parametry příkazu, místo pro návratový chybový kód a identifikace konkrétní jednotky (unit) zařízení které je příkaz určen. Jednotlivá konkrétní devices si pak k této "základní" datové struktuře přidávají další položky specifické pro toto zařízení. Každé device tedy obvykle mívá svou vlastní definici struktury IORequest.
Takto vypadá minimální IORequest struktura, jak ji vyžaduje exec.library: (viz exec/io.i)
STRUCTURE IO, MN_SIZE ;strukt. message
APTR IO_DEVICE ;pointer na bázi device
APTR IO_UNIT ;unit device (interní)
UWORD IO_COMMAND ;příkaz pro device
UBYTE IO_FLAGS ;spec. příznaky
BYTE IO_ERROR ;návratový kód
LABEL IO_SIZE ;velikost min. struktury

Tato minimální IO struktura je pak standardně rozšířena o tato pole:
ULONG IO_ACTUAL ;aktuální počet přenesených byte
ULONG IO_LENGTH ;požadovaný počet přenesených byte
APTR IO_DATA ;pointer na io buffer
ULONG IO_OFFSET ;offset od začátku média
LABEL IOSTD_SIZE ;velikost IOSTD struktury

Většina devices používá IOSTD strukturu rozšířenou ještě o soukromá pole daného device. Význam standardních položek IOSTD je následující:
- message: normální message s řádně vyplněným MN_REPLYPORTem atd. Toto message je použito pro předávání IORequestu mezi volajícím taskem a device. Po ukončení zpracování IORequestu je message vráceno volajícímu tasku pomocí ReplyMsg().
- IO_DEVICE, IO_UNIT: Tato dvě pole jsou vyplněna při otevření device. IO_DEVICE obvykle obsahuje bázi device (podobně jako bázi knihovny), odtud lze získat bázi device v případě že device má nějaké "knihovní" funkce - ty se pak volají stejně jako funkce sdílených knihoven pomocí offsetu a této báze. IO_UNIT je privátní pointer na jednotku daného device. Pokud jsou datové struktury (nebo jejich část) jednotek daného device veřejně známy, lze k nim přistupovat přes tento pointer.
- IO_COMMAND: Sem vyplňujete kódy příkazů pro device. Tyto kódy jsou popsány u každého device zvlášť a stejný kód nemusí nutně dělat u různých devices to samé. Obvykle existují určité skupiny devices s velmi podobnou funkcí a stejnou sadou příkazů - např. skupina "serial.device", kam patří všechny ovladače sériových portů (např. "8n1.device", "BaudBandit.device", "artser.device", nebo skupina "trackdisk.device", kam patří zařízení pro obsluhu disket v různých formátech (např. "diskspare.device", "mfm.device"). Tím že jsou alternativní devices stoprocentně kompatibilní s původní verzí device v systému je zajištěno snadné rozšiřování hardware a vylepšování software. Pozor, IO_COMMAND je WORD! Kdysi jsem zapomenuvše na to při svých experimentech udělal pár ošklivých těžko odhalitelných chyb!
- IO_FLAGS: Některé speciální příznaky používané různě podle typu device, plus příznak IOF_QUICK (viz dále)
- IO_ERROR: Návratový kód příkazu 0 znamená úspěch, jiná hodnota chybu. Stejnou hodnotu vrací funkce DoIO() po jejím provedení (je odtud).
- IO_ACTUAL: Obsahuje obvykle počet skutečně přenesených byte (např. než vznikla chyba)
- IO_LENGTH: Sem se obvykle vyplní počet byte který se má přenést mezi bufferem a device.
- IO_DATA: Sem vyplníte adresu bufferu který budete používat.
- IO_OFFSET: Určuje začátek datové oblasti na device
Konkrétní postup při používání device je tedy následující:
1. Připravíte si odpovídající IORequest strukturu, vyplníte adresu portu pro odpověď v message které je součástí IORequestu. Pokud port ještě nemáte, musíte si ho vytvořit (např. funkcí CreateMsgPort()). Tento port bude použit po ukončení příkazu k odeslání IORequestu zpět volajícímu tasku. Tím je zajištěna možnost čekání na dokončení příkazu pomocí funkce Wait()..
2. Otevřete device pomocí funkce execu OpenDevice(). Tato funkce vyžaduje v A0 jméno otevíraného device (např. "trackdisk.device"), v D0 číslo jednotky (unit) u devices, v A1 ukazatel na váš IORequest a v D1 příznaky (flags) které jsou specifické pro dané device (např. u "trackdisk.device" lze pomocí flags zajistit, aby v případě že odpovídající disketová mechanika není normální 3.5" DD se device neotevřelo a vrátila se chyba). Voláním funkce OpenDevice se vyplní položky IO_DEVICE a IO_UNIT ve vašem IORequestu.
3. Do položky IO_COMMAND vyplníte kód příkazu, který chcete aby device provedlo. Většina devices podporuje základní příkazy jako CMD_READ a CMD_WRITE. Navíc ještě mívá každé device několik specifických příkazů, které nejdou "zaškatulkovat" mezi standardní obecné příkazy. Další položky IORequestu pak vyplníte parametry podle toho, jaký příkaz provádíte.
4. Pro provedení příkazu zavoláte na IORequest funkci execu DoIO(). Tato funkce vyžaduje v A1 ukazatel na IORequest s vyplněným příkazem. Vrací chybový kód (0=úspěch).
5. Po skončení práce s device musíte device uzavřít funkcí exec CloseDevice(). Opět v A1 je pointer na IORequest. V tomto okamžiku už nesmí device zpracovávat žádný váš příkaz (což při použití DoIO() ani není možné)
Toto je klasický způsob volání příkazů device. Pro některé případy je však potřeba volat příkazy device asynchronně. Například si vezměte situaci: Chcete načíst znak ze sériového portu. Pokud vám řekněme do 10 sekund žádný znak nepřijde, chcete s tím přestat a stěžovat si uživateli, že vám nic nepřišlo. Abyste mohli něco takového udělat, potřebujete mít dva IORequesty jeden pro "serial.device" a druhý pro "timer.device". Zařízení "serial.device" nařídíte aby načetlo jeden znak, zařízení "timer.device" požádáte o odměření časového intervalu 10 sec. Pak už jenom koukáte, který IORequest bude dokončen dříve - když čtení znaku, je všechno OK - přerušíte čekání na druhém IORequestu a jste hotovi. Pokud je dřív hotov IORequest od "timer.device", prošel časový interval přerušíte IORequest na "serial.device" a uživateli nahlásíte chybu.
Aby bylo toto realizovatelné, potřebujete další funkce execu:
SendIO() - pošle IORequest na device a okamžitě se vrátí. Device současně začne zpracovávat požadovaný příkaz. V A1 je ukazatel na IORequest, funkce nic nevrací.
CheckIO() - Funkce se podívá, jestli už IORequest jehož adresa je v A1 není náhodou dokončen. Vrací nulu pokud ještě zpracovávání IORequestu nebylo ukončeno. Pokud už byl IORequest dokončen, je momentálně umístěn na vašem portu a je třeba ho odtamtud odstranit funkcí GetMsg() (pokud už se tak nestalo).
AbortIO() - Požádá device o přerušení zpracování IORequestu v A1. Pozor! Po zavolání této funkce je třeba ještě počkat na dokončení IORequestu!
WaitIO() - Počká na dokončení zpracovávání IORequestu (v A1) pomocí funkce Wait(). To je vhodné pokud čekáte na dokončení jediného IORequestu. Pokud jich je více, je lepší nastavit messages v IORequestech tak aby replyporty ukazovaly na stejný port a čekat na tomto portu.
V souvislosti s těmito funkcemi se zmíním také o tzv. quick-io (zrychleném) způsobu volání příkazů pomocí IORequestu. Normální způsob spočívá v poslání message jinému tasku, který po dokončení jeho zpracování message vrátí funkcí ReplyMsg() zpět na replyport. To má obvykle za následek přepínání tasků, což nějakou dobu trvá. Pokud je příkaz device dostatečně jednoduchý aby byl proveditelný okamžitě a nezávisle na čase (např. dotaz na "serial.device", kolik má v bufferu ještě načtených znaků, což je pouhé vrácení obsahu interní proměnné "serial.device"), pak je výhodné použít právě quick-io mód. To uděláte takto:
- V IORequestu v položce IO_FLAGS nastavíte před voláním BeginIO() bit IOB_QUICK. Tak device pozná, že byste chtěli použít quick-io. Pozor! Zdaleka ne všechny příkazy device lze provést v módu quick-io!
- Zavoláte na IORequest funkci BeginIO(). Po skončení této funkce se podíváte do IO_FLAGS, je-li bit IOB_QUICK stále ještě nastaven. Pokud ano, je příkaz už proveden! Pokud byl IOB_QUICK vynulován, nelze tento příkaz provést v quick-io a IORequest bude zpracován normálním způsobem, tj. zrovna se zpracovává a musíte počkat na jeho dokončení a vrácení na váš port. Mód quick-io je tedy podobný volání knihovních funkcí, protože zpracování IORequestu probíhá na vašem tasku a ne na tasku device.
Tolik teorie, a příště uvedu seznam některých devices s jejich příkazy a podíváme se na jejich praktické využití. Zatím tady máte malinký ale plně funkční (a užitečný) příkládek na otevírání devices. Nevolají se v něm žádné příkazy device, ale je tam ukázána technika přístupu k datovým strukturám jednotlivých units "trackdisk.device". Prográmek zapne "neťukající" mód u všech čtyř možných mechanik. Tento mód "trackdisk.device" existuje u OS 2.04+. Mechaniky po spuštění prográmku ještě asi dvakrát kliknou, než "trackdisk.device" zjistí, že nastala nějaká změna. Zároveň si všimněte "nové" syntaxe zápisu adresových módů, která se používá u 68020+ (a lze ji klidně použít místo staré). Všechny novější assemblery by měly novou syntaxi umět...

;==========================
; Tento program zmeni mod klikani
; disk. mechanik u OS 2.04+
;==========================
_LVOOpenDevice = -444
_LVOCloseDevice = -450
incdir "include:"
include "devices/trackdisk.i"
section prg,code
START moveq #0,D0
bsr.b ModifyUnit
moveq #1,D0
bsr.b ModifyUnit
moveq #2,D0
bsr.b ModifyUnit
moveq #3,D0
bsr.b ModifyUnit
moveq #0,D0
rts

ModifyUnit
move.l (4),W,A6
lea (tdname).L,A0
lea (iorq).L,A1
moveq #1,D1
jsr (_LVOOpenDevice,A6)
tst.l D0
bne.b .none
lea (iorq).L,A1
move.l (IO_UNIT,A1),A0
bset #0,(TDU_PUBFLAGS,A0)
jsr (_LVOCloseDevice,A6)
.none rts
tdname dc.b "trackdisk.device",0
iorq dc.b IOTD_SIZE,0

Vytlačiť článok



Pozn.: články boli naskenované ako text a preto obsahujú aj zopár chýb. Taktiež neručíme za zdrojové kódy (Asm, C, Arexx, AmigaGuide, Html) a odkazy na web. Dúfame, že napriek tomu vám táto databáza dobre poslúži.

Žiadna časť nesmie byť reprodukovaná alebo inak šírená bez písomného povolenia vydavatela © ATLANTIDA Publishing



none

AMIGA REVIEW

57 ( 11-12 / 2000 )
56 ( 9-10 / 2000 )
55 ( 7-8 / 2000 )
54 ( 5-6 / 2000 )
53 ( 3-4 / 2000 )
52 ( 1-2 / 2000 )
 
51 ( 12 / 1999 )
50 ( 11 / 1999 )
49 ( 10 / 1999 )
48 ( 9 / 1999 )
46-47 ( 7-8 / 1999 )
45 ( 6 / 1999 )
44 ( 5 / 1999 )
43 ( 4 / 1999 )
42 ( 3 / 1999 )
41 ( 2 / 1999 )
40 ( 1 / 1999 )
 
39 ( 12 / 1998 )
38 ( 11 / 1998 )
37 ( 10 / 1998 )
36 ( 9 / 1998 )
35 ( x / 1998 )
34 ( x / 1998 )
33 ( 1-2 / 1998 )
 
32 ( 11-12 / 1997 )
31 ( 9-10 / 1997 )
30 ( 7-8 / 1997 )
29 ( 6 / 1997 )
28 ( 5 / 1997 )
27 ( 4 / 1997 )
26 ( 3 / 1997 )
25 ( 2 / 1997 )
24 ( 1 / 1997 )
 
23 ( 12 / 1996 )
22 ( 11 / 1996 )
21 ( 10 / 1996 )
20 ( 9 / 1996 )
18-19 ( 7-8 / 1996 )
17 ( 6 / 1996 )
16 ( 5 / 1996 )
15 ( 4 / 1996 )
14 ( 3 / 1996 )
13 ( 2 / 1996 )
12 ( 1 / 1996 )
 
11 ( 12 / 1995 )
10 ( 11 / 1995 )
9 ( 10 / 1995 )
8 ( 9 / 1995 )
7 ( 7 / 1995 )
6 ( 5 / 1995 )

ATLANTIDA NEWS

5 ( 3 / 1995 )
4 ( 1 / 1995 )
 
3 ( 11 / 1994 )
2 ( 9 / 1994 )
1 ( 7 / 1994 )
0 ( 5 / 1994 )