Assembler - язык неограниченных возможностей
0e1cc9b4

Клавиатура


Контроллеру клавиатуры соответствуют порты с номерами от 60h до 6Fh, хотя для всех стандартных операций достаточно портов 60h и 61h.

64h для чтения: регистр состояния клавиатуры, возвращает следующий байт:

бит 7: ошибка четности при передаче данных с клавиатуры

бит 6: тайм-аут при приеме

бит 5: тайм-аут при передаче

бит 4: клавиатура закрыта ключом

бит 3: данные, записанные в регистр ввода, — команда

бит 2: самотестирование закончено

бит 1: в буфере ввода есть данные (для контроллера клавиатуры)

бит 0: в буфере вывода есть данные (для компьютера)

При записи в этот порт он играет роль дополнительного регистра управления клавиатурой, но его команды сильно различаются для разных плат и разных BIOS, и мы не будем его подробно рассматривать.

61h для чтения и записи — регистр управления клавиатурой. Если в старший бит этого порта записать значение 1, клавиатура будет заблокирована, если 0 — разблокирована. Другие биты этого порта менять нельзя, так как они управляют другими устройствами (в частности динамиком). Чтобы изменить состояние клавиатуры, надо считать байт из порта, изменить бит 7 и снова записать в порт 61h этот байт.

60h для чтения — порт данных клавиатуры. При чтении из него можно получить скан-код последней нажатой клавиши (см. приложение 1) — именно так лучше всего реализовывать резидентные программы, перехватывающие прерывание IRQ1, так как по этому коду можно определять момент нажатия и отпускания любой клавиши, включая такие клавиши, как Shift/Ctrl/Alt или даже Pause (скан-код отпускания клавиши равен скан-коду нажатия плюс 80h):



int09h_handler: in al,60h ; прочитать скан-код клавиши, cmp al,hot_key ; если это наша "горячая" ; клавиша, jne not_our_key ; перейти к нашему ; обработчику [...] ; наши действия здесь not_our_key: jmp old_int09h ; вызов старого обработчика

Мы пока не можем завершить обработчик просто командой IRET, потому что, во-первых, обработчик аппаратного прерывания клавиатуры должен установить бит 7 порта 61h, а затем вернуть его в исходное состояние, например так:

in al,61h push ax or al,80h out 61h,al pop ax out 61h,al


А во-вторых, он должен сообщить контроллеру прерываний, что обработка аппаратного прерывания закончилась командами

mov al,20h out 20h,al

60h для записи — регистр управления клавиатурой. Байт, записанный в этот порт (если бит 1 в порту 64h равен 0), интерпретируется как команда. Некоторые команды состоят из более чем одного байта — тогда следует дождаться обнуления зтого бита еще раз перед тем, как посылать следующий байт. Перечислим наиболее стандартные команды.

Команда EDh 0?h — изменить состояние светодиодов клавиатуры. Второй байт этой команды определяет новое состояние:

бит 0 — состояние Scroll Lock (1 — включена, 0 — выключена)

бит 1 — состояние Num Lock

бит 2 — состояние Caps Lock

При этом состояние переключателей, которое хранит BIOS в байтах состояния клавиатуры, не изменяется, и при первой возможности обработчик прерывания клавиатуры BIOS восстановит состояние светодиодов.

Команда EEh — эхо-запрос. Клавиатура отвечает скан-кодом EEh.

Команда F3h ??h — Установить параметры режима автоповтора:

бит 7 второго байта команды — 0

биты 6 – 5 устанавливают паузу перед началом автоповтора:

00 = 250ms, 01 = 500ms, 10 = 750ms, 11 = 1000ms

биты 4 – 0 устанавливают скорость автоповтора (символов в секунду):

00000 = 30,0     01111 = 8,0

00010 = 24,0     10010 = 6,0

00100 = 20,0     10100 = 5,0

00111 = 16,0     10111 = 4,0

01000 = 15,0     11010 = 3,0

01010 = 12,0     11111 = 2,0

01100 = 10,0

Все промежуточные значения также имеют смысл и соответствуют промежуточным скоростям, например 00001 = 26,7.

Команда F4h — включить клавиатуру.

Команда F5h — выключить клавиатуру.

Команда F6h — установить параметры по умолчанию.



Команда FEh — послать последний скан-код еще раз.

Команда FFh — выполнить самотестирование.

Клавиатура отвечает на все команды, кроме EEh и FEh, скан-кодом FAh (подтверждение), который поглощается стандартным обработчиком BIOS, так что, если мы не замещаем полностью стандартный обработчик, о его обработке можно не беспокоиться.

В качестве примера работы с клавиатурой напрямую рассмотрим простую программу, выполняющую переключение светодиодов.

; mig.asm ; циклически переключает светодиоды клавиатуры

.model tiny .code org 100h ; СОМ-программа start proc near mov ah,2 ; функция 02 прерывания 1Ah int 1Ah ; получить текущее время mov ch,dh ; сохранить текущую секунду в СН mov cl,0100b ; CL = состояние светодиодов клавиатуры main_loop: call change_LEDs ; установить светодиоды в соответствии с CL shl cl,1 ; следующий светодиод, test cl,1000b ; если единица вышла в бит 3, jz continue mov cl,0001b ; вернуть ее в бит 0, continue: mov ah,1 ; проверить, не была ли нажата клавиша, int 16h jnz exit_loop ; если да - выйти из программы push cx mov ah,2 ; функция 02 прерывания 1Ah int 1Ah ; получить текущее время pop сх cmp ch,dh ; сравнить текущую секунду в DH с СН, mov ch,dh ; скопировать ее в любом случае, je continue ; если это была та же самая секунда - не ; переключать светодиоды, jmp short main_loop ; иначе - переключить светодиоды exit_loop: mov ah,0 ; выход из цикла - была нажата клавиша, int 16h ; считать ее ret ; и завершить программу start endp

; процедура change_LEDs ; устанавливает состояние светодиодов клавиатуры в соответствии с числом в CL change_LEDs proc near call wait_KBin ; ожидание возможности посылки команды mov al,0EDh out 60h,al ; команда клавиатуры EDh call wait_KBin ; ожидание возможности посылки команды mov al,cl out 60h,al ; новое состояние светодиодов ret change_LEDs endp

; процедура wait_KBin ; ожидание возможности ввода команды для клавиатуры wait_KBin proc near in al,64h ; прочитать слово состояния test al,0010b ; бит 1 равен 1? jnz wait_KBin ; если нет - ждать, ret ; если да - выйти wait_KBin endp end start


Содержание раздела