   #Start Contents

                              Wykrywanie sprzetu

   Niektore programy nie tylko zajmuja sie przetwarzaniem danych, ale
   musza tez wspolpracowac ze sprzetem, na przyklad wykorzystac port
   szeregowy czy rownolegly do przesylania danych (czy to na drukarke,
   czy do innego urzadzenia). W tym artykule pokaze, jak wykrywac czesc
   urzadzen zainstalowanych w komputerze. Dobrze miec spis przerwan Ralfa
   Brown'a pod reka.
     _________________________________________________________________

Wykrywanie ilosci zainstalowanej pamieci RAM

   (przeskocz wykrywanie pamieci)

   UWAGA: NIE nalezy badac pamieci RAM, zapisujac do niej okreslone bity
   pod kazdy mozliwy adres i sprawdzajac, czy uda sie odczytac te same
   bity (brak pamieci sygnalizowany jest odczytaniem FF). Czesc urzadzen
   w komputerze (zwlaszcza PCI) jest mapowana do pamieci i zapisywanie do
   pewnych obszarow jest rownoznaczne z zapisywaniem do tych urzadzen, co
   moze je powaznie uszkodzic!

   Do odkrycia zainstalowanej ilosci pamieci RAM mozna skorzystac z
   nastepujacych funkcji BIOSu: int 15h z EAX=0e820h, int 15h z
   EAX=0000E820h oraz int 12h (najlepiej w tej kolejnosci).

   Pierwsza z nich korzysta z 32-bitowych rejestrow, wiec dopiero od
   procesora 386 mozna sprawdzac, czy jest dostepna. Kolejne uruchomienia
   tej funkcji zwracaja informacje o kolejnych obszarach pamieci i ich
   typie, tworzac tym samym BIOSowa mape pamieci. Ta funkcja przyjmuje
   nastepujace argumenty:
     * EAX = 0000E820h
     * EDX = 534D4150h (stala)
     * ES:DI - adres bufora o nastepujacej strukturze:
          + 8 bajtow na adres obszaru pamieci
          + 8 bajtow na dlugosc tego obszaru pamieci
          + 4 bajty na typ obszaru pamieci
     * ECX - dlugosc bufora spod ES:DI w bajtach (minimum to 20)
     * EBX = adres poczatkowy, od ktorego BIOS ma zaczac sprawdzanie. Na
       poczatku jest to zero.

   Jesli wywolanie sie powiedzie, funkcja zwraca, co nastepuje:
     * flaga CF=0
     * wskazany bufor zostaje wypelniony danymi
     * EBX = nastepny adres, skad kopiowac (podajemy go w EBX jako
       poczatkowy do kolejnego wywolania) lub 00000000h jesli koniec
     * ECX = dlugosc zwroconych informacji w bajtach

   W przypadku niepowodzenia flaga CF=1. Przykladowe wywolanie wyglada
   tak:
        mov     ax, cs
        mov     es, ax          ; jesli bufor jest w sekcji kodu
        mov     eax, 0e820h
        mov     edx, 534D4150h
        xor     ebx, ebx
        mov     ecx, 20
        mov     di, bufor
        int     15h
        jc      blad

        ; tu operujemy na danych

blad:
...

bufor:
b_adres         dd 0, 0
b_dlugosc       dd 0, 0
b_typ           dd 0

   Druga funkcja nie przyjmuje zadnych argumentow (poza numerem funkcji w
   AX) i zwraca ilosc pamieci rozszerzonej od 1 MB do 16 MB, w
   kilobajtach, w AX. Jesli wywolanie sie nie powiedzie, flaga CF=1.
   Przykladowe wywolanie wyglada tak:
        mov     ax, 0E801h
        int     15h
        jc      blad

        ; tu operujemy na danych

blad:

   Trzecia funkcja (przerwanie int 12h) w ogole nie przyjmuje zadnych
   argumentow, a zwraca liczbe kilobajtow ciaglej pamieci od
   bezwzglednego adresu 00000h.
     _________________________________________________________________

Wykrywanie portow szeregowych i rownoleglych

   (przeskocz wykrywanie portow)

   Wykrywanie portow, o ktorych wie BIOS, jest bardzo latwe. Wystarczy
   zajrzec do BDA (BIOS Data Area), czyli segmentu numer 40h,
   zawierajacego dane BIOSu.
   Adresy kolejnych portow szeregowych (maksymalnie czterech) jako
   16-bitowe slowa mozna znalezc pod adresami 0040h:0000h, 0040h:0002h,
   0040h:0004h, 0040h:0006h (choc ten ostatni adres moze sluzyc do innych
   celow na nowszych komputerach), zas adresy kolejnych portow
   rownoleglych (maksymalnie czterech) jako 16-bitowe slowa znajduja sie
   pod adresami 0040h:0008h, 0040h:000Ah, 0040h:000Ch, 0040h:000Eh.

   Jesli dodatkowo chcecie wykryc rodzaj portu szeregowego, polecam kod
   darmowego sterownika myszy dla DOSa - CuteMouse (a szczegolnie plik
   comtest.asm). Sterownik jest napisany w asemblerze i mozna go pobrac
   oraz obejrzec jego kod zrodlowy za darmo.

   Wykryc rodzaj portow rownoleglych mozna za pomoca ukladow nimi
   sterujacych, na przyklad "Intel 82091AA Advanced Integrated
   Peripheral" (porty 22h-23h). Kod dla tego ukladu moze wygladac
   nastepujaco:
        mov     al, 20h         ; numer rejestru, ktory chcemy odczytac
        out     22h, al         ; wysylamy go na port adresu
        out     0edh, al        ; opoznienie
        in      al, 23h         ; odczytujemy dane z portu danych

   Informacje o portach rownoleglych znajduja sie w bitach 5 i 6
   odczytanego bajtu. Jesli bity te maja wartosc 0, to porty rownolegle
   pracuja w trybie zgodnosci z ISA, jesli 1 - w trybie zgodnosci z PS/2,
   jesli 2 - w trybie EPP, jesli 3 - w trybie ECP.
     _________________________________________________________________

Wykrywanie karty dzwiekowej AdLib

   (przeskocz wykrywanie AdLib)

   Karta ta ma dwa podstawowe porty: port adresu i stanu - 388h (do
   odczytu i zapisu) oraz port danych - 389h (tylko do zapisu). By
   zapisac cos do jednego z 244 rejestru karty, wysylamy jego numer na
   port 388h, po czym wysylamy dane na port 389h. Algorytm wykrywania
   karty sklada sie z nastepujacych krokow (zrodlo: Programming the
   AdLib/Sound Blaster FM Music Chips, Version 2.0 (24 Feb 1992),
   Copyright (C) 1991, 1992 by Jeffrey S. Lee):
    1. wyzerowanie obu czasomierzy poprzez zapisanie 60h do rejestru 4.
    2. wlaczenie przerwan, zapisujac 80h do rejestru 4. UWAGA: to musi
       byc krok oddzielny od pierwszego
    3. odczytanie stanu karty (port 388h) i zachowanie wyniku
    4. zapisanie FFh do rejestru 2 (czasomierz 1)
    5. uruchomienie czasomierza 1 poprzez zapisanie 21h do rejestru 4.
       Czasomierz 1 bedzie zwiekszal wartosc zapisana do rejestru 2 o 1
       co kazde 80 mikrosekund.
    6. odczekanie co najmniej 80 mikrosekund
    7. odczytanie stanu karty (port 388h) i zachowanie wyniku
    8. wyzerowanie czasomierzy i przerwan (krok 1 i 2)
    9. wyniki krokow 3 i 7 ANDowac bitowo z wartoscia E0h. Wynikiem z
       kroku 3 powinna byc wartosc 0, a z kroku 7 - C0h. Jesli obie sie
       zgadzaja, w komputerze zainstalowana jest karta AdLib.

   Miedzy kazdym zapisem do portu adresu i wyslaniem danych nalezy
   odczekac 12 cykli karty. Po zapisaniu danych nalezy odczekac 84 cykle
   karty, zanim jakakolwiek kolejna operacja bedzie mogla zostac
   wykonana. Ale ze wygodniej jest operowac w jezyku operacji niz cykli
   procesora karty, te czasy oczekiwania wynosza odpowiednio: 6 i 35 razy
   czas potrzebny na odczytanie portu adresu. Ja w razie czego uzyje
   odpowiednio: 10 i 40 operacji.

   Do wykrywania karty AdLib moze posluzyc wiec nastepujacy kod:
        pisz_adlib 4, 60h
        pisz_adlib 4, 80h

        mov     dx, 388h
        in      al, dx
        mov     bl, al          ; zachowanie stanu w kroku 3

        pisz_adlib 2, 0FFh
        pisz_adlib 4, 21h

        mov     ah, 86h
        xor     cx, cx
        mov     dx, 100
        int     15h             ; wykonanie pauzy na 100 mikrosekund
        jc      blad

        mov     dx, 388h
        in      al, dx
        mov     bh, al          ; zachowanie stanu w kroku 7

        pisz_adlib 4, 60h
        pisz_adlib 4, 80h

        and     bx, 0E0E0h
        cmp     bx, 0C000h      ; sprawdzenie obu wynikow (kroki 3 i 7) na raz
        je      jest_adlib

        ; tu nie ma AdLib

   gdzie makro pisz_adlib wyglada tak:
%imacro pisz_adlib 2    ; %1 - numer rejestru, %2 - dane do wyslania
        mov     dx, 388h
        mov     al, %1
        out     dx, al
        mov     cx, 10
%%loop1:                ; opoznienie pierwsze
        in      al, dx
        loop    %%loop1
        inc     dx      ; port 389h
        mov     al, %2
        out     dx, al
        dec     dx
        mov     cx, 40
%%loop2:                ; opoznienie drugie
        in      al, dx
        loop    %%loop2
%endm
     _________________________________________________________________

Wykrywanie karty dzwiekowej SoundBlaster

   (przeskocz wykrywanie SB)

   Karta SoundBlaster moze byc zaprogramowana do korzystania z roznych
   portow podstawowych. Najczesciej spotykana wartosc to 220h, ale
   mozliwe sa tez miedzy innymi 210h, 230h, 240h, 250h, 260h i 280h.
   Struktura jest podobna, jak w karcie AdLib: zakladajac, ze port bazowy
   to 220h, to dla lewego kanalu portem adresu jest 220h, a portem danych
   - 221h, zas dla prawego - odpowiednio 222h i 223h. Porty karty AdLib -
   388h i 389h - sluza do operacji na obu kanalach.

   Wykrywanie tej karty przebiega tak samo, jak dla karty AdLib
   (procedura 9 krokow powyzej), ale skoro porty bazowe moga byc rozne,
   proponuje nastepujaca modyfikacje makra do wysylania danych:
%imacro pisz_sb 3       ; %1 - port bazowy, %2 - numer rejestru, %3 - dane
        mov     dx, %1
        mov     al, %2
        out     dx, al
        mov     cx, 6
%%loop1:                ; opoznienie pierwsze
        in      al, dx
        loop    %%loop1
        inc     dx      ; port danych
        mov     al, %3
        out     dx, al
        dec     dx
        mov     cx, 35
%%loop2:                ; opoznienie drugie
        in      al, dx
        loop    %%loop2

%endm
     _________________________________________________________________

Wykrywanie zainstalowanych dyskow twardych

   (przeskocz wykrywanie dyskow)

   Jesli BIOS wykryje jakies dyski twarde, ich liczbe wpisuje do komorki
   pamieci pod adresem 0040h:007Eh (1 bajt).
   Zakresy portow kontrolerow dyskow twardych to: 01F0h-01F7h (pierwszy
   kontroler), 0170h-0177h (drugi). Sa jeszcze 2 kontrolery, opisane jako
   EIDE: 01E8h-01EFh (trzeci kontroler) i 168h-016Fh (czwarty).

   Kazdy kontroler moze obsluzyc dwa dyski - Master i Slave. Wyboru
   dysku, na ktorym wykonywane sa operacje, dokonuje sie, zapisujac do
   portu baza+6 (gdzie baza to 01F0h, 0170h, 01E8h lub 168h). Bity 7 i 5
   musza byc rowne 1, a bitem czwartym wybiera sie dysk (0=pierwszy,
   1=drugi).

   Komendy wysyla sie do portu baza+7, a dane (po 512 bajtow) odczytuje
   sie z portu bazowego. Przed wyslaniem komend nalezy sprawdzic, czy
   kontroler lub dysk nie sa zajete. Robi sie to odczytujac port stanu,
   bedacy zarazem portem komend (czyli baza+7). Bit 7 mowi, czy kontroler
   jest zajety (powinien byc rowny zero), bit 6 - czy dysk jest gotowy do
   operacji (powinien byc rowny 1), bit 4 - czy dysk przeszedl na
   wlasciwa pozycje (powinien byc rowny 1). Reszta bitow jest nieistotna,
   jesli chodzi o wysylanie komend.
   Portu statusu mozna uzyc tez, obok portu baza+1, do wykrywania bledow.

   Mozemy juz wiec napisac taki oto kod:
        mov     dx, 1f7h
spr_dysk:
        in      al, dx
        cmp     al, 50h         ; dysk gotowy, kontroler niezajety
        jnz     spr_dysk

   Gdy dysk jest gotow na przyjmowanie komend, mozna zaczac wysylac nasze
   zadania. Najpierw ustawiamy, do ktorego dysku bedziemy chcieli wysylac
   dane:
        mov     dx, 1f6h
        mov     al, 10100000b   ; bit 4 = 0, wiec pierwszy dysk
        out     dx, al

   Po tym, w razie czego, sprawdzamy ponownie gotowosc dysku poprzednim
   kodem. Jesli dysk jest gotow, wysylamy komende:
        mov     dx, 1f7h
        mov     al, 0ech        ; kod rozkazu identyfikacji
        out     dx, al

   Przed odczytaniem danych musimy jednak sprawdzic nie tylko, czy dysk
   juz jest gotow (czy skonczyl przetwarzac zadanie), ale tez to, czy
   dane juz sa gotowe do odebrania. Sprawdzamy to podobnie, jak
   poprzednio, zamieniajac tylko 50h na 58h (co dodatkowo sprawdza, czy
   bufor sektorow dysku wymaga obslugi - czyli czy sa juz dla nas dane):
        mov     dx, 1f7h
spr_dysk:
        in      al, dx
        cmp     al, 58h         ; dysk gotowy, kontroler niezajety, sa dane
        jnz     spr_dysk

   Po sprawdzeniu, ze dane sa dostepne, odbieramy je, lecz w nietypowy
   sposob: zamiast odbierac po jednym bajcie, odbieramy pod dwa na raz,
   do rejestru AX, po czym zamieniamy jego polowki miejscami. Jest to
   zwiazane ze sposobem wysylania danych przez dysk. Kod wyglada tak:
        mov     cx, 512/2       ; tyle slow do przeczytania
        mov     dx, 1f0h        ; stad czytac
        xor     di, di          ; wskaznik do bufora
czytaj:
        in      ax, dx          ; wczytaj 2 bajty z portu DX
        xchg    al, ah          ; zamien polowki miejscami
        mov     [bufor+di], ax  ; zapisz wynik do bufora
        add     di, 2           ; przejdz na kolejna pozycje w buforze
        loop    czytaj
        ...
bufor:          times 513 db 0  ; dosc, by pomiescic 1 sektor

   Dysk zwraca nam 512 bajtow. Model dysku znajdziecie pod adresem 14h w
   buforze, ma on dlugosc 10 slow (20 bajtow). Numer seryjny jest pod
   adresem 36h w buforze, ma on dlugosc 20 slow (40 bajtow). W obu tych
   przypadkach, jesli pierwszym slowem pod wskazanym adresem jest zero,
   to dysk nie podal tych informacji.

   Pozyskanie tych informacji od napedow optycznych (CD, DVD) rozni sie
   tylko kodem operacji - zamiast ECh jest to A1h.
     _________________________________________________________________

Wykrywanie napedow dyskietek

   (przeskocz wykrywanie napedow dyskietek)

   Wykrywanie typow napedow dyskietek jest znacznie prostsze niz w
   przypadku dyskow twardych. W czasie uruchamiania komputera, BIOS
   wyszukuje napedy dyskietek i wpisuje je do CMOSu, skad mozna je latwo
   odczytac. Ze te informacje odpowiada bajt numer 10h. Odczytanie go
   wyglada tak:
        mov     al, 10h         ; numer bajtu do odczytania
        out     70h, al         ; port adresu CMOSu
        out     0edh, al        ; opoznienie
        in      al, 71h         ; odczytanie wartosci z portu danych CMOSu

   Starsze 4 bity odczytanego bajtu odpowiadaja pierwszemu napedowi,
   mlodsze - drugiemu. I tak: wartosc 0 oznacza brak danego napedu, 01h -
   5,25 cala 360 kB, 02h - 5,25 cala 1,2 MB, 03h - 3,5 cala 720 kB, 04h -
   3,5 cala 1,44 MB, 05h - 3,5 cala 2,88 MB.
     _________________________________________________________________

Wykrywanie myszy

   (przeskocz wykrywanie myszy)

   Ogolnie wykrywanie myszy jako urzadzenia moze byc dosc skomplikowane,
   nie tylko ze wzgledu na roznorodnosc zlaczy (szeregowa, PS/2, USB),
   ale takze ze wzgledu na roznorodnosc protokolow komunikacji z myszami.
   Wszystko to na szczescie jest zawarte w otwartym sterowniku myszy dla
   DOSa - CuteMouse. Sterownik jest napisany w asemblerze i mozna go
   pobrac oraz obejrzec jego kod zrodlowy za darmo.

   Jesli wystarczy Wam wiedziec, czy jest zaladowany jakikolwiek
   sterownik do myszy (co wskazywaloby na istnienie myszy), wystarczy
   taki oto kod:
        xor     ax, ax
        mov     es, ax
        les     di, [es:33h << 2]       ; sprawdz, czy wektor przerwania
                                        ; sterownika myszy nie jest zerem
        mov     ax, es
        or      ax, di
        jz      brak_myszy

        mov     al, [es:di]
        cmp     al, 0cfh                ; sprawdz, czy procedura obslugi
                                        ; przerwania myszy nie sklada sie
                                        ; wylacznie z instrukcji iret
        je      brak_myszy

        xor     ax, ax
        int     33h                     ; sprawdz, czy sterownik zglasza mysz
        test    ax, ax
        jz      brak_myszy

   Spis tresci off-line (klawisz dostepu 1)
   Spis tresci on-line (klawisz dostepu 2)
   Ulatwienia dla niepelnosprawnych (klawisz dostepu 0)
