Re: MD XMSXXXX0 zakazane???

Autor: Gregorio Kus (Grego_at_RMnet.it)
Data: Wed 26 Feb 1997 - 06:20:16 MET


On Tue, 25 Feb 1997 23:00:38 +0100 (CET), Tomasz Leszczynski wrote:

>On 25 Feb 97 at 18:31, Wojciech Galazka pisal(a):
>
>> Tomasz Leszczynski wrote:
>> >
>> > Jak??? Czy robi sie to jakims przerwaniem DOS'a, czy tez jest to
>> > wynik procedury instalowania nowego urzadzenia i czy da sie napisac
>> > dzielko, ktoremu wystarczy podac nazwe do zastrzezenia i juz.
>>
>> napisac driver (calkiem prosty)
>
>Mozna prosic o wiecej szczegolow :-) Albo ewentualnie odeslanie do
>jakiejs literatury (mam spis przerwan DOS'a ale nic tam nie
>znalazlem). Byc moze zle szukalem.

Device driver dla DOS'a piszemy jak normalny program typu .COM
z jednym wyjatkiem - poniewaz PSP (Program Segment Prefix)
nie jest potrzebny wiec zaczynamy od 0 (zamiast ORG 100H piszemy
ORG 0 albo wogole nic). Jak kazdy program deklarujemy go jako
FAR procedure.

Device driver zaczyna sie od tzw. device header. Jest to 18 bajtowa
struktura danych podzielona na 5 pol.
1. DD zawsze -1 (0FFFFFFFFH). To pole jest uzywane przez DOS
   dla utworzenia "chain" wszystkich driverow. W miejsce to DOS
   wstawia adres nastepnego drivera lub zostawia -1 jesli ten wlasnie
   jest ostatni.
2. DW - driver's attribute. Nie bede tu rozpisywal znaczenia wszystkich
   bitow (dokladniej - tylko siedem ma znaczenie). Najprosciej zostawic
   wylacznie bit 15 ustawiony a pozostale wyzerowane. Oznacza to
   "non standard character device without IOCTL support"
3. DW - adres "strategy routine"
4. DW - adres "interrupt routine"
5. DB - osmioznakowa nazwa (jesli krotsza to uzupelniona spacjami)
   [oczywiscie left-justified]

Resumme':

Kod rozpoczynajacy nasz dumb device driver bedzie wygladal nastepujaco:

CSEG SEGMENT PUBLIC CODE
        ORG 0
        ASSUME CS:CSEG, DS:CSEG, ES:CSEG
MY_DEV PROC FAR
        DD 0FFFFFFFFH
        DW 8000H
        DW STRATEGY
        DW INTERRUPT
        DB 'DUPA ' ; to pozwalam zmienic

Device strategy routine moze sie skladac z 5 zaledwie wierszy.
Jest to procedura wolana tylko raz w czasie ladowania drivera przez DOS.
Nie jest zasadzie jej zadaniem wykonywania jakiejs inicjalizacji
(tym zajmuje sie procedura INIT, o czym pozniej) lecz wylacznie
zapamietanie polozenia tzw. request header ktory DOS przydziela
kazdemu device. Request header ma zmienna dlugosc (zaleznie od
rodzaju operacji) ale pierwsze 13 bajtow ma stale znaczenie:

1. DB - rozmiar request header'a
2. DB - unit code (device number przydzielany urzadzeniom blokowym)
3. DB - command code (numer odpowiadajacy najnowszej komendzie
        wyslanej do drivera)
4. DW - status (powinien byc ustwiany za kazdym wywolaniem drivera.
        jesli bit 15 jest ustawiony to w dolnym bajcie powinien
        sie znalezc kod bledu.
5. 8 DB reserved area (tego sobie uzywa DOS na swoje ciemne cele)
6. x DB data area o zmiennej dlugosci.

wracajac do device strategy routine:
wystarczy cos w rodzaju ponizszego:

STRATEGY:MOV CS:SAV_ES,ES
         MOV CS:SAV_BX,BX
         RET
SAV_ES DW ?
SAV_BX DW ?

natomiast jesli chodzi o device interrupt handler sprawa jest ciut
bardziej skomplikowana. (nawet nazwa jest mylaca [jest taka ze wzgledow
historycznych] gdyz drivery nie funkcjonuja juz jako interrupts
[nawet sw, ktore same w sobie prawdziwymi przerwaniami nie sa] lecz
jako normalne procedury, wiec koncza sie zwyklym RET)

Kazdy device driver moze wykonywac 13 rodzajow funkcji i dla kazdego
z nich musi miec obsluge (chcby tylko "pusta~") a dla pierwszej musi
miec obsluge "prawdziwa". Pierwsza funkcja jest oczywiscie inicjalizacja
ktora musi robic co najmniej jedna rzecz: podac DOSowi adres konca kodu
drivera (nie zawsze caly kod drivera musi stac sie rezydentny).
Funkcje puste musza odpowiedziec DOSowi ustawiajac bity 15,8,1,0 w polu
statusowym request header'a. (15 oznacza blad, 8 ze driver funkcjonuje
poprawnie, 0 i 1 daja~ error code=3 czyli "command unknown")

Reasumujac otrzymamy cos w rodzaju:
INTERRUPT PUSH ES
          PUSH DS
          PUSH AX
          PUSH BX
          PUSH CX
          PUSH DX
          PUSH SI
          PUSH DI
          PUSH BP
          MOV AX, CS:SAV_ES ; w ES:BX znajdzie sie adres request header'a
          MOV ES, AX
          MOV BX, CX:SAV_BX
          MOV AL,ES:[BX+2] ; pobranie 'command code'
          SHL AL,1 ; *2 bo tablica ma alementy typu word
          SUB AH, AH ; mozna uzyc XOR :-)
          LEA DI, FUNCTIONS
          ADD DI, AX
          JMP WORD PTR [DI] ; skok do funkcji o zadanym numerze

FUNCTIONS LABEL WORD
          DW INITIALIZE
          DW CHECK_MEDIA
          DW MAKE_BPB
          DW IOCTL_IN
          DW INPUT_DATA
          DW NONDESTRUCTIVE_IN
          DW INPUT_STATUS
          DW CLEAR_INPUT
          DW OUTPUT_DATA
          DW OUTPUT_VERIFY
          DW OUTPUT_STATUS
          DW CLEAR_OUTPUT
          DW IOCTL_OUT

; funkcje nieuzywane w naszym driverze

CHECK_MEDIA:
MAKE_BPB:
IOCTL_IN:
INPUT_DATA:
NONDESTRUCTIVE_IN:
INPUT_STATUS:
CLEAR_INPUT:
OUTPUT_DATA:
OUTPUT_VERIFY:
OUTPUT_STATUS:
CLEAR_OUTPUT:
IOCTL_OUT: OR ES:WORD PTR[BX+3],8103H ; status word := 'command unknown'
            JMP QUIT

; jedyna funkcja uzyta:
INITIALIZE: LEA AX, END_OF_PROGRAM
            MOV ES:WORD PTR[BX+14],AX ; aby przekazac DOSowi segment:offeset
            MOV ES:WORD PTR[BX+16],CS ; konca kodu rezydentnego
            OR ES:WORD PTR[BX+3],100H ; bit 8 ustawiony oznacza 'done'
                                          ; inaczej mowiac informuje ze driver
                                          ; dziala poprawnie
QUIT: POP BP
            POP DI
            POP SI
            POP DX
            POP CX
            POP BX
            POP AX
            POP DS
            POP ES
            RET

END_OF_PROGRAM:
MY_DEV: ENDP
CSEG ENDS
            END MY_DEV

/---------------------------------------------------------------------

po zebraniu tego wszystkiego do kupy bierzemy w obroty assembler
potem linker, a otrzymany w wybiku ich dzialania plik binarny
pakujemy jako DEVICE= w CONFIG.SYS

i w ten to oto prosty :-) sposob uzyskujemy oczekiwany efekt:
nikt nam nie zalozy kartoteki DUPA.

Grego

--
/-----------------------------------------------------------------
Gregorio Kus         Grego_at_RMnet.it           Grego_at_cyberspace.org
ROMA, Italy          2ndAdmin_at_iName.com       Grego_at_FreeNet.hut.fi
Anonymous Mail Service - http://free.rmnet.it/~grego/AnonMail.html


To archiwum zostało wygenerowane przez hypermail 2.1.7 : Tue 18 May 2004 - 15:56:21 MET DST