HW TUT










Asembler: DOS: Wykrywanie sprzętu











Wykrywanie sprzętu


Niektóre programy nie tylko zajmują się przetwarzaniem danych, ale muszą też współpracować
ze sprzętem, na przykład wykorzystać port szeregowy czy równoległy do przesyłania danych
(czy to na drukarkę, czy do innego urządzenia). W tym artykule pokażę, jak wykrywać
część urządzeń zainstalowanych w komputerze. Dobrze mieć spis przerwań Ralfa Brown'a pod ręką.


Wykrywanie ilości zainstalowanej pamięci RAM

(przeskocz wykrywanie pamięci)

UWAGA: NIE należy badać pamięci RAM, zapisując do niej
określone bity pod każdy możliwy adres i sprawdzając, czy uda się odczytać te same bity
(brak pamięci sygnalizowany jest odczytaniem FF). Część urządzeń w komputerze (zwłaszcza PCI)
jest mapowana do pamięci i zapisywanie do pewnych obszarów jest równoznaczne z zapisywaniem
do tych urządzeń, co może je poważnie uszkodzić!

Do odkrycia zainstalowanej ilości pamięci RAM można skorzystać z następujących funkcji
BIOSu:
int 15h z EAX=0e820h, int 15h z EAX=0000E820h oraz int 12h (najlepiej w tej kolejności).

Pierwsza z nich korzysta z 32-bitowych rejestrów, więc dopiero od procesora 386 można
sprawdzać, czy jest dostępna. Kolejne uruchomienia tej funkcji zwracają informacje o
kolejnych obszarach pamięci i ich typie, tworząc tym samym BIOSową mapę pamięci.
Ta funkcja przyjmuje następujące argumenty:

EAX = 0000E820h
EDX = 534D4150h (stała)
ES:DI - adres bufora o następującej strukturze:

8 bajtów na adres obszaru pamięci
8 bajtów na długość tego obszaru pamięci
4 bajty na typ obszaru pamięci

ECX - długość bufora spod ES:DI w bajtach (minimum to 20)
EBX = adres początkowy, od którego BIOS ma zacząć sprawdzanie. Na początku jest to zero.

Jeśli wywołanie się powiedzie, funkcja zwraca, co następuje:

flaga CF=0
wskazany bufor zostaje wypełniony danymi
EBX = następny adres, skąd kopiować (podajemy go w EBX jako początkowy do kolejnego wywołania)
lub 00000000h jeśli koniec
ECX = długość zwróconych informacji w bajtach

W przypadku niepowodzenia flaga CF=1. Przykładowe wwywołanie wygląda tak:

mov ax, cs
mov es, ax ; jeśli 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 żadnych argumentów (poza numerem funkcji w AX) i zwraca ilość
pamięci rozszerzonej od 1 MB do 16 MB, w kilobajtach, w AX. Jeśli wywołanie się nie powiedzie,
flaga CF=1. Przykładowe wwywołanie wygląda tak:

mov ax, 0E801h
int 15h
jc blad

; tu operujemy na danych

blad:



Trzecia funkcja (przerwanie int 12h) w ogóle nie przyjmuje żadnych argumentów,
a zwraca liczbę kilobajtów ciągłej pamięci od bezwzględnego adresu 00000h.




Wykrywanie portów szeregowych
i równoległych

(przeskocz wykrywanie portów)

Wykrywanie portów, o których wie BIOS, jest bardzo łatwe. Wystarczy zajrzeć do BDA
(BIOS Data Area), czyli segmentu numer 40h, zawierajacego dane BIOSu.
Adresy kolejnych portów szeregowych (maksymalnie czterech) jako 16-bitowe słowa
można znaleźć pod adresami 0040h:0000h, 0040h:0002h, 0040h:0004h, 0040h:0006h (choć ten
ostatni adres może służyć do innych celów na nowszych komputerach), zaś adresy
kolejnych portów równoległych (maksymalnie czterech) jako 16-bitowe słowa znajdują się pod
adresami 0040h:0008h, 0040h:000Ah, 0040h:000Ch, 0040h:000Eh.

Jeśli dodatkowo chcecie wykryć rodzaj portu szeregowego, polecam kod darmowego sterownika
myszy dla DOSa - CuteMouse (a szczególnie plik comtest.asm).
Sterownik jest napisany w asemblerze i można
go pobrać oraz obejrzeć jego kod źródłowy za darmo.

Wykryć rodzaj portów równoległych można za pomocą układów nimi sterujących, na przykład
Intel 82091AA Advanced Integrated Peripheral (porty 22h-23h). Kod dla
tego układu może wyglądać następująco:

mov al, 20h ; numer rejestru, który chcemy odczytać
out 22h, al ; wysyłamy go na port adresu
out 0edh, al ; opóźnienie
in al, 23h ; odczytujemy dane z portu danych

Informacje o portach równoległych znajdują się w bitach 5 i 6 odczytanego bajtu.
Jeśli bity te mają wartość 0, to porty równoległe pracują w trybie zgodności z ISA,
jeśli 1 - w trybie zgodności z PS/2, jeśli 2 - w trybie
EPP, jeśli 3 - w trybie
ECP.


Wykrywanie karty dźwiękowej 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 zapisać coś do jednego z 244 rejestru
karty, wysyłamy jego numer na port 388h, po czym wysyłamy dane na port 389h.
Algorytm wykrywania karty składa się z następujących kroków (źródło:
Programming the AdLib/Sound Blaster FM Music Chips, Version 2.0 (24 Feb 1992),
Copyright © 1991, 1992 by Jeffrey S. Lee):

wyzerowanie obu czasomierzy poprzez zapisanie 60h do rejestru 4.
włączenie przerwań, zapisując 80h do rejestru 4. UWAGA: to musi być krok oddzielny od
pierwszego
odczytanie stanu karty (port 388h) i zachowanie wyniku
zapisanie FFh do rejestru 2 (czasomierz 1)
uruchomienie czasomierza 1 poprzez zapisanie 21h do rejestru 4. Czasomierz 1 będzie
zwiększał wartość zapisaną do rejestru 2 o 1 co każde 80 mikrosekund.
odczekanie co najmniej 80 mikrosekund
odczytanie stanu karty (port 388h) i zachowanie wyniku
wyzerowanie czasomierzy i przerwań (krok 1 i 2)
wyniki kroków 3 i 7 ANDować bitowo z wartością E0h. Wynikiem z kroku 3 powinna być wartość
0, a z kroku 7 - C0h. Jeśli obie się zgadzają, w komputerze zainstalowana jest
karta AdLib.

Między każdym zapisem do portu adresu i wysłaniem danych należy odczekać 12 cykli karty.
Po zapisaniu danych należy odczekać 84 cykle karty, zanim jakakolwiek kolejna operacja
będzie mogła zostać wykonana. Ale że wygodniej jest operować w języku operacji niż cykli
procesora karty, te czasy oczekiwania wynoszą odpowiednio: 6 i 35 razy czas potrzebny na
odczytanie portu adresu. Ja w razie czego użyję odpowiednio: 10 i 40 operacji.

Do wykrywania karty AdLib może posłużyć więc następujący 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 wyników (kroki 3 i 7) na raz
je jest_adlib

; tu nie ma AdLib

gdzie makro pisz_adlib wygląda tak:


%imacro pisz_adlib 2 ; %1 - numer rejestru, %2 - dane do wysłania
mov dx, 388h
mov al, %1
out dx, al
mov cx, 10
%%loop1: ; opóźnienie pierwsze
in al, dx
loop %%loop1
inc dx ; port 389h
mov al, %2
out dx, al
dec dx
mov cx, 40
%%loop2: ; opóźnienie drugie
in al, dx
loop %%loop2
%endm


Wykrywanie karty dźwiękowej
SoundBlaster

(przeskocz wykrywanie SB)

Karta SoundBlaster może być zaprogramowana do korzystania z różnych portów podstawowych.
Najczęściej spotykana wartość to 220h, ale możliwe są też między innymi 210h, 230h,
240h, 250h, 260h i 280h. Struktura jest podobna, jak w karcie AdLib: zakładając, że
port bazowy to 220h, to dla lewego kanału portem adresu jest 220h, a portem danych - 221h,
zaś dla prawego - odpowiednio 222h i 223h. Porty karty AdLib - 388h i 389h - służą do operacji na
obu kanałach.
Wykrywanie tej karty przebiega tak samo, jak dla karty AdLib (procedura 9 kroków powyżej),
ale skoro porty bazowe mogą być różne, proponuję następującą modyfikację makra do wysyłania 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: ; opóźnienie pierwsze
in al, dx
loop %%loop1
inc dx ; port danych
mov al, %3
out dx, al
dec dx
mov cx, 35
%%loop2: ; opóźnienie drugie
in al, dx
loop %%loop2

%endm



Wykrywanie zainstalowanych dysków twardych

(przeskocz wykrywanie dysków)

Jeśli BIOS wykryje jakieś dyski twarde, ich liczbę wpisuje do komórki pamięci pod adresem
0040h:007Eh (1 bajt).
Zakresy portów kontrolerów dysków twardych to:
01F0h-01F7h (pierwszy kontroler), 0170h-0177h (drugi). Są jeszcze 2 kontrolery, opisane
jako EIDE: 01E8h-01EFh (trzeci kontroler) i 168h-016Fh (czwarty).

Każdy kontroler może obsłużyć dwa dyski - Master i Slave.
Wyboru dysku, na którym wykonywane są operacje, dokonuje się, zapisując do portu baza+6 (gdzie baza
to 01F0h, 0170h, 01E8h lub 168h). Bity 7 i 5 muszą być równe 1, a bitem czwartym wybiera się
dysk (0=pierwszy, 1=drugi).
Komendy wysyła się do portu baza+7, a dane (po 512 bajtów)
odczytuje się z portu bazowego. Przed wysłaniem komend należy sprawdzić, czy kontroler lub
dysk nie są zajęte. Robi się to odczytując port stanu, będący zarazem portem komend (czyli baza+7).
Bit 7 mówi, czy kontroler jest zajęty (powinien być równy zero), bit 6 - czy dysk jest gotowy
do operacji (powinien być równy 1), bit 4 - czy dysk przeszedł na właściwą pozycję (powinien
być równy 1). Reszta bitów jest nieistotna, jeśli chodzi o wysyłanie komend.
Portu statusu można użyć też, obok portu baza+1, do wykrywania błędów.

Możemy już więc napisać taki oto kod:

mov dx, 1f7h
spr_dysk:
in al, dx
cmp al, 50h ; dysk gotowy, kontroler niezajęty
jnz spr_dysk

Gdy dysk jest gotów na przyjmowanie komend, można zacząć wysyłać nasze żądania. Najpierw
ustawiamy, do którego dysku będziemy chcieli wysyłać dane:


mov dx, 1f6h
mov al, 10100000b ; bit 4 = 0, wiec pierwszy dysk
out dx, al

Po tym, w razie czego, sprawdzamy ponownie gotowość dysku poprzednim kodem. Jeśli dysk jest
gotów, wysyłamy komendę:


mov dx, 1f7h
mov al, 0ech ; kod rozkazu identyfikacji
out dx, al

Przed odczytaniem danych musimy jednak sprawdzić nie tylko, czy dysk już jest gotów (czy
skończył przetwarzać żądanie), ale też to, czy dane już są gotowe do odebrania. Sprawdzamy to
podobnie, jak poprzednio, zamieniając tylko 50h na 58h (co dodatkowo sprawdza, czy
bufor sektorów dysku wymaga obsługi - czyli czy są już dla nas dane):


mov dx, 1f7h
spr_dysk:
in al, dx
cmp al, 58h ; dysk gotowy, kontroler niezajęty, są dane
jnz spr_dysk

Po sprawdzeniu, że dane są dostępne, odbieramy je, lecz w nietypowy sposób: zamiast
odbierać po jednym bajcie, odbieramy pod dwa na raz, do rejestru AX, po czym zamieniamy
jego połówki miejscami. Jest to związane ze sposobem wysyłania danych przez dysk. Kod wygląda
tak:


mov cx, 512/2 ; tyle słów do przeczytania
mov dx, 1f0h ; stąd czytać
xor di, di ; wskaźnik do bufora
czytaj:
in ax, dx ; wczytaj 2 bajty
xchg al, ah ; zamień połówki miejscami
mov [bufor+di], ax ; zapisz wynik do bufora
add di, 2 ; przejdź na kolejną pozycję w buforze
loop czytaj
...
bufor: times 513 db 0 ; dość, by pomieścić 1 sektor

Dysk zwraca nam 512 bajtów. Model dysku znajdziecie pod adresem 14h w buforze, ma
on długość 10 słów (20 bajtów). Numer seryjny jest pod adresem 36h w buforze, ma
on długość 20 słów (40 bajtów). W obu tych przypadkach, jeśli pierwszym słowem
pod wskazanym adresem jest zero, to dysk nie podał tych informacji.

Pozyskanie tych informacji od napędów optycznych (CD, DVD) różni się tylko kodem
operacji - zamiast ECh jest to A1h.


Wykrywanie napędów dyskietek

(przeskocz wykrywanie napędów dyskietek)

Wykrywanie typów napędów dyskietek jest znacznie prostsze niż w przypadku dysków twardych.
W czasie uruchamiania komputera, BIOS wyszukuje napędy dyskietek i wpisuje je do CMOSu,
skąd można je łatwo odczytać. Ze te informacje odpowiada bajt numer 10h. Odczytanie go wygląda
tak:


mov al, 10h ; numer bajtu do odczytania
out 70h, al ; port adresu CMOSu
out 0edh, al ; opóźnienie
in al, 71h ; odczytanie wartości z portu danych CMOSu

Starsze 4 bity odczytanego bajtu odpowiadają pierwszemu napędowi, młodsze - drugiemu.
I tak: wartość 0 oznacza brak danego
napędu, 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)

Ogólnie wykrywanie myszy jako urządzenia może być dość skomplikowane, nie tylko ze
względu na różnorodność złączy (szeregowa, PS/2, USB), ale także ze względu na
różnorodność protokołów komunikacji z myszami. Wszystko to na szczęście jest
zawarte w otwartym sterowniku myszy dla DOSa - CuteMouse. Sterownik jest napisany w asemblerze i można
go pobrać oraz obejrzeć jego kod źródłowy za darmo.

Jeśli wystarczy Wam wiedzieć, czy jest załadowany jakikolwiek sterownik do myszy
(co wskazywałoby na istnienie myszy), wystarczy taki oto kod:


xor ax, ax
mov es, ax
les di, [es:33h << 2] ; sprawdź, czy wektor przerwania
; sterownika myszy nie jest zerem
mov ax, es
or ax, di
jz brak_myszy

mov al, [es:di]
cmp al, 0cfh ; sprawdź, czy procedura obsługi
; przerwania myszy nie składa się
; wyłącznie z instrukcji iret
je brak_myszy

xor ax, ax
int 33h ; sprawdź, czy sterownik zgłasza mysz
test ax, ax
jz brak_myszy



Spis treści off-line (Alt+1)
Spis treści on-line (Alt+2)
Ułatwienia dla niepełnosprawnych (Alt+0)





Wyszukiwarka

Podobne podstrony:
function hw mapid
function hw mv
function hw getchilddoccollobj
ART121 tut 2
phys tut 08
function hw array2objrec
function hw getanchors
function hw insertdocument
function hw dummy
function hw info
function hw gettext
function hw documentattributes
phys tut 12
DOS DIOD TUT
function hw objrec2array

więcej podobnych podstron