Zabawa diodami na klawiaturze pod Linuksem

Aby uczynić swój program bardziej atrakcyjnym wzrokowo i pochwalić się swoimi umiejętnościami, można sprawić, aby diody na klawiaturze wskazujące stan Num Lock, Caps Lock, Scroll Lock zaczęły migotać w jakimś rytmie.
Teraz pokażę, jak to zrobić.

Do manipulowania urządzeniem znakowym (klawiaturą) posłużymy się funkcją systemową sys_ioctl (numer 54). Najpierw jednak trzeba się dowiedzieć, jakich komend możemy używać. W tym celu udajemy się do pliku /usr/include/linux/kd.h lub do manuala, jeśli mamy w nim stronę ioctl_list, a w nim mamy (po angielsku):


(przeskocz komendy)
	#define KDGETLED 0x4B31  /*zwróć bieżący stan diód */
	#define KDSETLED 0x4B32  /*ustaw stan diód (światełek, nie flag)*/
	#define LED_SCR  0x01    /*dioda scroll lock */
	#define LED_NUM  0x02    /*dioda num lock */
	#define LED_CAP  0x04    /*dioda caps lock */

Jedną z tych dwóch pierwszych wartości wpiszemy do ECX.
Tymczasem w EBX musimy mieć deskryptor otwartego pliku /dev/console (do zapisu) lub wartość 1, która oznacza standardowe urządzenie wyjścia - STDOUT.
W EDX podajemy ostatni parametr: wartość 0-7 jeśli ustawiamy stan diód lub wskaźnik (adres) na zmienną typu DWORD, która otrzyma bieżąca wartość stanu diód (także 0-7).

Widać więc, co musi zrobić nasz program: zachować bieżący stan diód, dowolnie je pozmieniać (i zadbać by efekt był widoczny - robić pauzy), po czym przywrócić poprzedni stan.
Oto, jak taki program mógłby wyglądać (używanie załączników z mojej biblioteki nie jest konieczne - w kodzie mówię, jak i co zamienić).


(przeskocz przykładowy 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 korzystać:
%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 błędu, to jedziemy dalej

				; w przypadku błędu korzystamy ze STDOUT
	mov	eax, stdout	; stdout = 1

; 2. pobieramy aktualny stan diód

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

	mov	eax, sys_ioctl	; sys_ioctl = 54 - manipulacja urządzeniem
	mov	ecx, KDGETLED	; pobierz stan diód
	mov	edx, stare_diody	; adres DWORDa, który otrzyma
					; aktualny stan diód
	int	80h

	mov	eax, sys_ioctl	; sys_ioctl = 54
	mov	ecx, KDSETLED	; ustawiamy stan diód
	mov	edx, 7		; wszystkie włączone
	int	80h

        mov	cx, 7
        mov	dx, 0a120h	; opóźnienie pół sekundy
	call	pauza

; przywracamy poprzedni stan diód

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

	cmp	ebx, stdout	; czy otworzyliśmy konsolę, 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 pauzująca 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 = pozostała 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. Pamiętajcie, że istnieje aż 8 różnych kombinacji stanów diód i można przecież robić różne odstępy czasowe między zmianą stanu.

Miłej zabawy.


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