[Назад] [Далее]

5.10.1. Клавиатура

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

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

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

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

Клавиатура отвечает на все команды, кроме 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

п»ї
"target=_blank><\/a>") //-->