   #Start Contents

                         Zabawa diodami na klawiaturze

   Aby uczynic swoj program bardziej atrakcyjnym wzrokowo i pochwalic sie
   swoimi umiejetnosciami, mozna sprawic, aby diody na klawiaturze
   wskazujace stan Num Lock, Caps Lock, Scroll Lock zaczely migotac w
   jakims rytmie.
   Teraz pokaze, jak to zrobic.

   Najpierw, tradycyjnie, spojrzymy w spis portow dolaczony do Listy
   Przerwan Ralfa Brown'a. Potrzebny nam bedzie podstawowy port
   kontrolera klawiatury, port 60h:
   (przeskocz port 60h)
        0060 RW KB controller data port or keyboard input buffer (ISA, EISA)
                should only be read from after status port bit0 = 1
                should only be written to if status port bit1 = 0

   Jak widac, trzeba tez znalezc jakis port statusu. Jest to port 64h:
   (przeskocz port 64h)
        Bitfields for keyboard controller read status (ISA, EISA):
        Bit(s)  Description     (Table P0398)
         7      parity error on transmission from keyboard
         6      receive timeout
         5      transmit timeout
         4      keyboard interface inhibited by keyboard lock
                or by password server mode
         3      =1 data written to input register is command (PORT 0064h)
                =0 data written to input register is data (PORT 0060h)
         2      system flag status: 0=power up or reset  1=selftest OK
         1      input buffer full (input 60/64 has data for 8042)
                no write access allowed until bit clears
         0      output buffer full (output 60 has data for system)
                bit is cleared after read access

   Tak wiec, potrzebna nam bedzie procedura sprawdzajaca, czy mozna pisac
   do portu klawiatury. Sprobujmy ja napisac:
   (przeskocz procedure sprawdzajaca zajetosc portu)
        ; wersja TASM
        czy_mozna_pisac         proc    near
                push eax
        sprawdzaj:
                in al,64h
                and al,2                ; sprawdzamy bit nr. 1
                jnz sprawdzaj           ; jesli rozny od zera, to
                                        ; sprawdzaj do skutku

                pop eax
                ret
        czy_mozna_pisac         endp

   Teraz wersja NASM/FASM:
   (przeskocz wersje NASM/FASM tej procedury)
        ; wersja NASM
        czy_mozna_pisac:
                push eax
        sprawdzaj:
                in al,64h
                and al,2                ; sprawdzamy bit nr. 1
                jnz sprawdzaj           ; jesli rozny od zera, to
                                        ;sprawdzaj do skutku

                pop eax
                ret

   Ta powinna wystarczyc.
   Trzeba jeszcze znalezc polecenie kontrolera klawiatury, ktore
   kontroluje stan diod. Jest to bajt EDh:
   (przeskocz komende ustawiania diod)
        EDh            set/reset mode indicators Caps Num Scrl
                       bit 2 = CapsLk, bit 1 = NumLk, bit 0 = ScrlLk
                        all other bits must be zero.

   Mozemy juz zaczac cos pisac:
   (przeskocz pierwszy program)
        call czy_mozna_pisac
        MOV AL,0EDh
        OUT 60h,AL
        XOR AL,AL               ;zadna dioda sie nie pali
        OUT 60h,AL
        call czy_mozna_pisac
        MOV AL,0EDh
        OUT 60h,AL
        MOV AL,2                ;Num Lock
        OUT 60h,AL
        call czy_mozna_pisac
        MOV AL,0EDh
        OUT 60h,AL
        MOV AL,1                ;Scroll Lock
        OUT 60h,AL
        call czy_mozna_pisac
        MOV AL,0EDh
        OUT 60h,AL
        MOV AL,6                ;Caps+Num
        OUT 60h,AL

   To byl tylko przyklad. No wiec uruchamiamy go i co? Bzyk! I juz nasz
   program sie zakonczyl. Moze komus udalo sie zaobserwowac efekty (z
   wyjatkiem ostatniego, ktory jest trwaly). To stawia 2 pytania:
    1. Jak sprawic, zeby trwalo to dluzej?
    2. Jak powrocic do stanu pierwotnego, zgodnego z prawda?

   Odpowiedzia na pierwsze pytanie jest juz uzyta raz przeze mnie w innym
   artykule funkcja 86h przerwania 15h. Przypomne: CX:DX = liczba
   mikrosekund przerwy, ktora chcemy uzyskac.
   Po dodaniu niezbednych linijek program moze wygladac tak:
   (przeskocz program z opoznieniami)
        MOV AH,86h
        MOV CX,0Fh
        MOV DX,4240h

        call czy_mozna_pisac
        MOV AL,0EDh
        OUT 60h,AL
        XOR AL,AL               ;zadna dioda sie nie pali
        OUT 60h,AL
        INT 15h
        ;MOV AH,86h
        ;INT 15h
        call czy_mozna_pisac
        MOV AL,0EDh
        OUT 60h,AL
        MOV AL,2                ;Num Lock
        OUT 60h,AL
        MOV AH,86h
        INT 15h
        ;MOV AH,86h
        ;INT 15h

   i tak dalej...
   Jesli zauwazycie, ze to nic nie daje, to odkomentujcie drugie
   wywolania przerwania. Rejestr AH musi byc przed kazdym wywolaniem
   przywracany, gdyz przerwanie go modyfikuje.

   A co z drugim pytaniem?
   Z pomoca tym razem przychodzi spis przerwan. Patrzymy:
   (przeskocz opis funkcji 2 przerwania 16h)
        INT 16 - KEYBOARD - GET SHIFT FLAGS
                AH = 02h
        Return: AL = shift flags (see #00582)
                AH destroyed by many BIOSes

        Bitfields for keyboard shift flags:
        Bit(s)  Description     (Table 00582)
         7      Insert active
         6      CapsLock active
         5      NumLock active
         4      ScrollLock active
         3      Alt key pressed
         2      Ctrl key pressed
         1      left shift key pressed
         0      right shift key pressed

   Nasz programik bedzie wiec wygladal mniej-wiecej tak:
   (przeskocz program z opoznieniami i z przywracaniem stanu)
                MOV AH,2
                INT 16h
                MOV BH,AL               ; zachowujemy stary stan klawiatury

                MOV AH,86h
                MOV CX,0Fh
                MOV DX,4240h


                call czy_mozna_pisac
                MOV AL,0EDh
                OUT 60h,AL
                XOR AL,AL               ;zadna dioda sie nie pali
                OUT 60h,AL
                INT 15h
                ;MOV AH,86h
                ;INT 15h
                ...
                ...

                XOR AL,AL
                TEST BH,01000000b       ; czy Caps byl wlaczony?
                JZ nie_caps
                OR AL,4                 ; tak, ustaw bit 2
        nie_caps:
                TEST BH,00100000b       ; czy Num?
                JZ nie_num
                OR AL,2
        nie_num:
                TEST BH,00010000b       ; czy Scroll?
                JZ koniec
                OR AL,1
        koniec:
                MOV BL,AL
                MOV AL,0EDh
                OUT 60h,AL
                MOV AL,BL
                OUT 60h,AL
                ...

   Dalsze eksperymenty pozostawiam czytelnikom. Pamietajcie, ze istnieje
   az 8 roznych kombinacji stanow diod i mozna przeciez robic rozne
   odstepy czasowe miedzy zmiana stanu.

   Milej zabawy.

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