   #Start Contents English version

                  Zabawa diodami na klawiaturze pod Linuksem

   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.

   Do manipulowania urzadzeniem znakowym (klawiatura) posluzymy sie
   funkcja systemowa sys_ioctl (numer 54). Najpierw jednak trzeba sie
   dowiedziec, jakich komend mozemy uzywac. W tym celu udajemy sie do
   pliku /usr/include/linux/kd.h lub do manuala, jesli mamy w nim strone
   ioctl_list, a w nim mamy (po angielsku):
   (przeskocz komendy)
        #define KDGETLED 0x4B31  /*zwroc biezacy stan diod */
        #define KDSETLED 0x4B32  /*ustaw stan diod (swiatelek, nie flag)*/
        #define LED_SCR  0x01    /*dioda scroll lock */
        #define LED_NUM  0x02    /*dioda num lock */
        #define LED_CAP  0x04    /*dioda caps lock */

   Jedna z tych dwoch pierwszych wartosci wpiszemy do ECX.
   Tymczasem w EBX musimy miec deskryptor otwartego pliku /dev/console
   (do zapisu) lub wartosc 1, ktora oznacza standardowe urzadzenie
   wyjscia - STDOUT.
   W EDX podajemy ostatni parametr: wartosc 0-7 jesli ustawiamy stan diod
   lub wskaznik (adres) na zmienna typu DWORD, ktora otrzyma biezaca
   wartosc stanu diod (takze 0-7).

   Widac wiec, co musi zrobic nasz program: zachowac biezacy stan diod,
   dowolnie je pozmieniac (i zadbac by efekt byl widoczny - robic pauzy),
   po czym przywrocic poprzedni stan.
   Oto, jak taki program moglby wygladac (uzywanie zalacznikow z mojej
   biblioteki nie jest konieczne - w kodzie mowie, jak i co zamienic).
   (przeskocz przykladowy program)
; Program manipuluje diodami klawiatury
;
; Autor: Bogdan D.
; Kontakt: bogdandr (at) op (dot) pl
;
; nasm -f elf klaw.asm
; ld -s -o klaw klaw.o


section .text

                ; nie musicie z tego korzystac:
%include "bibl/incl/linuxbsd/nasm/n_system.inc"
%include "bibl/incl/linuxbsd/nasm/n_const.inc"

%define KDGETLED        0x4b31
%define KDSETLED        0x4b32

global _start

_start:

; 1. otwieramy /dev/console, w trybie tylko do zapisu lub
; korzystamy ze STDOUT

        mov     eax, sys_open   ; sys_open = 5 (otwieramy plik)
        mov     ebx, konsola    ; adres nazwy pliku
        mov     ecx, O_WRONLY   ; O_WRONLY = 01
        mov     edx, 777q       ; RWX dla wszystkich
        int     80h

        cmp     eax, 0
        jge     .ok             ; jak nie ma bledu, to jedziemy dalej

                                ; w przypadku bledu korzystamy ze STDOUT
        mov     eax, stdout     ; stdout = 1

; 2. pobieramy aktualny stan diod

.ok:
        mov     ebx, eax        ; EBX = deskryptor pliku

        mov     eax, sys_ioctl  ; sys_ioctl = 54 - manipulacja urzadzeniem
        mov     ecx, KDGETLED   ; pobierz stan diod
        mov     edx, stare_diody        ; adres DWORDa, ktory otrzyma
                                        ; aktualny stan diod
        int     80h

        mov     eax, sys_ioctl  ; sys_ioctl = 54
        mov     ecx, KDSETLED   ; ustawiamy stan diod
        mov     edx, 7          ; wszystkie wlaczone
        int     80h

        mov     cx, 7
        mov     dx, 0a120h      ; opoznienie pol sekundy
        call    pauza

; przywracamy poprzedni stan diod

        mov     eax, sys_ioctl
        mov     ecx, KDSETLED           ; ustawiamy stan diod
        mov     edx, [stare_diody]      ; EDX = poprzedni stan diod
        int     80h

        cmp     ebx, stdout     ; czy otworzylismy konsole, czy STDOUT?
        jle     .koniec         ; nie zamykamy STDOUT

        mov     eax, sys_close  ; zamykamy otwarty plik konsoli
        int     80h

.koniec:
        wyjscie                 ; czyli
                                ;       mov     eax, 1
                                ;       xor     ebx, ebx
                                ;       int     80h


pauza:                  ; procedura pauzujaca przez CX:DX milisekund
        push    ebx
        push    ecx
        push    edx

        mov     ax, cx
        shl     eax, 16
        mov     ebx, 1000000
        mov     ax, dx          ; EAX = CX:DX
        xor     edx, edx
        div     ebx             ; CX:DX dzielimy przez milion
        mov     [t1 + timespec.tv_sec], eax     ; EAX = liczba sekund

        mov     ebx, 1000
        mov     eax, edx        ; EAX = pozostala liczba mikrosekund
        mul     ebx
        mov     [t1 + timespec.tv_nsec], eax    ; EAX = liczba nanosekund

        mov     eax, sys_nanosleep      ; funkcja numer 162
        mov     ebx, t1
        mov     ecx, t2
        int     80h

        pop     edx
        pop     ecx
        pop     ebx

        ret

section .data

stare_diody     dd      0
konsola         db      "/dev/console",0

; Struktura timespec jest zdefiniowana w pliku n_system.inc
;struc timespec
;               .tv_sec:                resd 1
;               .tv_nsec:               resd 1
;endstruc

t1 istruc timespec
t2 istruc timespec

   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)
