; Файл KBD.def ; Префикс KBD comment~ Контроллер клавиатуры Структура контроллера клавиатуры 8042, установленного на материнской плате ┌─────────┐ │ 8042 │ └────┬────┘ │ ┌────┐ │ │В │<──── Объём ОЗУ на системной плате \ Регистр │ ┌─────────┐ │ │х │ │ только записываемый состояния │<──/───┤Регистр ├<────o │о П│<──── Режим турбо │ порт -- только │ 8 │состояния│ │ │д о│ │ 60h (для команды) читаемый │ └─────────┘ │ │н р│<──── Тип монитора (Ч/Б или цветной) } 64h (для данных) порт 64h │ │<────┤о т│ │ В зависимости от того, │ ┌─────────┐ │ │й │<──── режимы изготовителя PC AT │ куда производится запись, o───/──>┤Входной │────>│ │ │ │ определяется данные │ 8 │буфер │ │ │ │<──── Замок клавиатуры / записываются или команда │ └─────────┘ │ └────┘ │ │ ┌────┐ \ Шина данных│ ┌─────────┐ │ │В ├────> Системный сброс * │ XD │<──/───┤Выходной │<────o │ы │ │ <───────────┘ 8 │буфер │ │ │х П├────> Gate A20 │ └─────────┘ │ │о о│ │ только читаемый │ │д р├────> + Выходной буфер полон } порт 60h ┌─────────┐ │ │н т│ │ │128 байт │<───>│ │о ├────> + Входной буфер пуст │ │озу │ o────>│Й │ │ └─────────┘ │ │ ├───o────> Синхросигнал клавиатуры │ │ │ │ │ │ │ │ ├───┼─o──> Данные клавиатуры / ┌─────────┐ │ └────┘ │ │ │2 К*8 │────>│ ┌─────┐ │ │ * на AT до 486-х процессоров │ПЗУ │ │<────┤T 0│<─┘ │ └─────────┘ │ │T 1│<───┘ │ └─────┘ Выходной буфер (8-разрядный регистр) доступен системе только как читаемый порт с адресом 60h, он ис- пользуется для передачи системе полученных от клавиатуры кодов сканирования и прочитанных по команде системы байтов данных. Выходной буфер должен быть прочитан только после того, как установлен признак "буфер полон" (Разряд 0 регистра состояния). Входной буфер (8-разрядный регистр) доступен системе только как записываемый порт с адресом 60h (устанав- ливается флажок, указывающий на последующую запись данных) или 64h (устанавливает флажок, указывающий на пос- ледующую запись команды). Данные, записанные в порт 60h, отсылаются клавиатуре, если не являются командой контроллера. Данные должны быть записаны во входной буфер только после того, как сброшен признак "буфер полон" (разряд 1 регистра состояния). Регистр состояния клавиатуры (8 разрядов) доступен системе только как читаемый порт с адресом 64h. Назна- чение разрядов приведено ниже. Разряды регистра состояния (только читаемый порт 64h). ┌──────┬────────────────────────────────────────────────────────────────────────────────────────────┐ │Разряд│ Назначение │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────┤ │ 0 │ 0 -- В выходном буфере нет новых данных; │ │ │ 1 -- Контроллер поместил новые данные в выходной буфер, но система ещё не приняла │ │ │ их, когда система прочитает значение порта 60h, разряд станет нулевым. │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────┤ │ 1 │ 0 -- входной буфер пуст (порт 60h или 64h) │ │ │ 1 -- система поместила данные во входной буфер, но контроллер их ещё не принял. После │ │ │ того, как контроллер их прочитает этот разряд станет нулевым. │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────┤ │ 2 │ 0 -- сброс по включению питания (холодный пуск); 1 -- программный сброс (горячий пуск). │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────┤ │ 3 │ 0 -- во входном буфере данные (запись производилась по адресу 60h) │ │ │ 1 -- во входном буфере команда (запись производилась по адресу 64h) │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────┤ │ 4 │ 0 -- защитный замок закрыт; 1 -- защитный замок открыт │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────┤ │ 5 │ 1 -- Тайм-аут передачи. Передача данных, начатая контроллером не завершена │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────┤ │ 6 │ 1 -- Тайм-аут приёма. Передача данных, начата клавиатурой, но не завершена в │ │ │ запрограммированный промежуток времени (2мс) │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────┤ │ 7 │ 1 -- Ошибка паритета. Последний байт данных был получен от клавиатуры с чётным паритетом. │ │ │ Клавиатура должна посылать байт с нечётным паритетом. │ └──────┴────────────────────────────────────────────────────────────────────────────────────────────┘ ┌────────┬────────────────────────────────────┐ │Разряды │ │ ├────────┤ Причина ошибки │ │ 7 6 5 │ │ ├────────┼────────────────────────────────────┤ │ 0 0 1 │ Нет синхроимпульса │ │ 0 1 1 │ Есть синхроимпульс, нет отклика │ │ 1 0 1 │ Есть синхроимпульс, ошибка паритета│ └─────────────────────────────────────────────┘ ~ QKBDState equ 64h ; Порт состояния контроллера клавиатуры (только читаемый) QKBDIn equ 64h ; Адрес входного буфера (только записываемый) QKBDOutp equ 60h ; Адрес выходного буфера (только читаемый) QeKBDCtrl1 equ 64h ; Командный порт контроллера клавиатуры 1. В него помещается первый командный байт QeKBDCtrl2 equ 60h ; Командный порт контроллера клавиатуры 2. В него помещается второй командный байт CmKBDOutFull equ 00000001b ; Выходной буфер полон, FKBDOutFull equ 0 ; если бит установлен CmKBDInpFull equ 00000010b ; Входной буфер полон, FKBDInpFull equ 1 ; если бит установлен CmKBDErr equ 11100000b ; Ошибка данных работы с клавиатурой FKBDErr equ 5 ;════════════════════════════════════════════════════════════════════════════════ ; Проверяет, свободен ли входной буфер (возможна ли запись в него), Если нет, то выход по метке BufFull. ; Портит CF. ; В AL помещается байт состояния контроллера клавиатуры KBDInpBufFree macro BufFull in al, QKBDState ; Читать регистр состояния клавиатуры bt eax, FKBDInpFull ; Если входной буфер полон, jc BufFull ; то переход по метке BufFull endm ;──────────────────────────────────────────────────────────────────────────────── ; Ждёт, когда выходной буфер станет свободным. ; Портит cf, al. ; В AL помещается байт состояния контроллера клавиатуры KBDWtInpBufFree macro local G G: in al, QKBDState ; bt eax, FKBDInpFull jc G endm ;──────────────────────────────────────────────────────────────────────────────── ; Проверяет, есть ли данные в выходном буфере. Если данных нет, то выход по метке ExErr. ; Портит AL KBDOutpBufFull macro ExErr in al, QKBDState bt eax, FKBDOutFull jnc ExErr endm ;──────────────────────────────────────────────────────────────────────────────── ; Освобождает выходной буфер ; Портит AL KBDOutpBufFree macro local K KBDOutpBufFull K in al, QKBDOutp K: endm ;──────────────────────────────────────────────────────────────────────────────── ; Ждёт, когда во входной буфер поступят данные. ; Портит AL KBDWtOuputBufFull macro local G G: KBDOutpBufFull G endm ;──────────────────────────────────────────────────────────────────────────────── ; Проверяет, есть ли данные в выходном буфере. Если данные есть, то выход по метке ExErr. ; Портит AL OutputBufFree macro ExErr in al, QKBDState bt eax, FKBDOutFull jc ExErr endm ;──────────────────────────────────────────────────────────────────────────────── ; Проверяет, произошла ли ошибка при работе с клавиатурой. Если да, то выход по метке ExErr. ; Портит AL KBDInterfaceError macro ExErr in al, QKBDState ; bt eax, FKBDErr jc ExErr endm ;════════════════════════════════════════════════════════════════════════════════ comment~ Разряды входного порта. Разряды выходного порта. Разряды выходного порта. ┌──────┬──────────────────────────────┐ ┌──────┬─────────────────────────┐ ┌──────┬─────────────────────────┐ │Разряд│ Назначение │ │Разряд│ Назначение │ │Разряд│ Назначение │ ├──────┼──────────────────────────────┤ ├──────┼─────────────────────────┤ ├──────┼─────────────────────────┤ │ 0 │ Резерв изготовителя │ │ 0 │ Системный сброс │ │ T0 │ Синхросигнал клавиатуры │ │ │ (состояние перемычки) │ │ 1 │ Gate A20 │ │ │ (вход) │ │ 1 │ Резерв изготовителя │ │ 2 │ Резерв изготовителя │ ├──────┼─────────────────────────┤ │ 2 │ Резерв изготовителя │ │ 3 │ Резерв изготовителя │ │ │ │ │ 3 │ Резерв изготовителя │ │ 4 │ Выходной буфер полон │ │ T1 │ Данные клавиатуры (вход)│ │ 4 │ Объём ОЗУ на системной плате │ │ 5 │ Входной буфер пуст │ └──────┴─────────────────────────┘ │ 5 │ Резерв изготовителя │ │ 6 │ Синхросигнал клавиатуры │ │ 6 │ Тип первичного монитора │ │ │ (выход) │ │ │ (0-цветной, 1-Ч/Б) │ │ 7 │ Данные клавиатуры │ │ 7 │ Замок клавиатуры (0-забло- │ │ │ (выход) │ │ │ кирована, 1-разблокирована)│ └──────┴─────────────────────────┘ └──────┴──────────────────────────────┘ ~ ; Разрды выходного порта FKBDPCReset equ 0h ; Системный сброс (флаг сброшен) FKBDGateA20 equ 1h ; Разрешить A20 (флаг установлен) comment~ Коды команд контроллера 8042 (порт вывода 64h) ┌────┬───────────────────────────────────────────────────────────────────────────────────────────────────────┐ │ Код│ Функция │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 20h│ Поместить текущий командный байт в порт 60h │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 60h│ Загрузить новый командный байт, это часть двухбайтовой операции. Чтобы записать новый командный │ │ │ байт необходимо: а) в порт 64h поместить 60h, б) записать в порт 60h командный байт. │ │ │ Командный байт определет режим работы контроллера клавиатуры. │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ A5h│ Специальное чтение. 8042 помещает в выходной буфер истинное значение выходного порта 2 за │ │ │ исключением разрядов 4 и 5, которым даётся следующее определение │ │ │ 5: =0 - клавиатура XT, =1 - клавиатура AT; │ │ │ 4: =0 - запрещено прерывание по заполнению выходного буфера, =1 - разрешено прерывание. │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ AAh│ Инициализация. 8042 инициализирует порты 1 и 2, запрещает клавиатуру и │ │ │ очищает указатели буфера. После этого, помещает в выходной буфер 55h │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ ABh│ Контроль интерфейса клавиатуры. Выходной буфер после тестирования будет содержать: 00h -- нет ошибок; │ │ │ 01h -- линии синхронизации клавиатуры остаётся нулевой; 02h -- линия синхронизации клавиатуры остаётся│ │ │ единичной; 03h -- линия данных клавиатуры остаётся нулевой; 04h -- линия данных клавиатуры остаётся │ │ │ единичной. │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ ACh│ Резерв для диагностики │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ ADh│ Запретить клавиатуру (устанавливает разряд 4 командного байта 8042, который запрещает интерфейс │ │ │ клавиатуры). До разрешения клавиатуры данные не передаются и не принимаются. │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ AEh│ Разрешить клавиатуру. Сбрасывает разряд 4 командного байта, который разрешает клавиатуру │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ C0h│ Прочитать входной порт. Передаёт содержимое входного порта в выходной │ │ │ буфер (порт 60h), использовать только при пустом выходном буфере │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ D0h│ Прочитать выходной порт. Передаёт содержимое выходного порта в выходной │ │ │ буфер (порт 60h), использовать только при пустом выходном буфере │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ D1h│ Поместить байт, записанный по адресу 60h в выходной порт, разряд 0 не должен быть нулевым, т. к. иначе│ │ │ система перезагрузится. │ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ E0h│ Прочитать входы TEST0 и TEST1. После выполнения 0-ой бит порта 60h содержит TEST0, а 1-ый бит -- TEST1│ ├────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤ │F0h-│ Пульсация разрядов выходного порта. Может быть вызвана пульсация разрядов 0-3 выходного порта (перевод│ │FFh │ в нулевое состояние на 2-6 мкс). Разряды 0--3 в этой команде указывают, какой разряд выходного порта │ │ │ должен пульсировать. │ └────┴───────────────────────────────────────────────────────────────────────────────────────────────────────┘~ ; Команды управления контроллером клавиатуры CeqKBDGetCmd equ 020h ; Читать командный байт из клавиатуры CeqKBDSetCmd equ 060h ; Послать команду в контроллер клавиатуры CeqKBDRdOutBuf equ 0a5h ; Читает выходной порт за исключением битов 4 и 5, кот-ые трактуются иначе (см. табл.) CeqKBDCtrlIni equ 0aah ; Инициализация портов, запрет кл-ры, очистка ук-лей буферов, затем в вых. буф. 55h CeqKBDChkIntrf equ 0abh ; Контроль интерфейса 00h - ошибок нет CeqKBDDumpRes equ 0ach ; Резерв диагностирования CeqKBDIntrfDes equ 0adh ; Запрет интерфейса клавиатуры CeqKBDIntrfEna equ 0aeh ; Разрешение клавиатуры CeqKBDRdInpPort equ 0c0h ; Читать входной порт CeqKBDRdOutPort equ 0d0h ; Читать выходной порт CeqKBDWrOutPort equ 0d1h ; Записать в выходной порт CeqKBDRdTestPort equ 0e0h ; Читать выходы клавиатуры CeqKBDPulsOutBuf equ 0f0h ; Пульсация разрядов 0-3 выходного порта F0h-FFh, последние четыре бита ; указывают какой разряд должен пульсировать ;════════════════════════════════════════════════════════════════════════════════ ; Сброс системы ; Портит: Все регистры, а заодно и всю имеющуюся ОЗУ (работает до 486) KBDPCReset macro KBDWtInpBufFree ; Дождаться, когда входной буфер будет пуст mov al, CeqKBDPulsOutBuf+1111b ; Послать команду пульсации нулевого разряда out QeKBDCtrl1, al ; выходного порта (подающего сигнал сброса системы) endm ;──────────────────────────────────────────────────────────────────────────────── ; Запретить клавиатуру, выдавать макрос при пустом входном буфере ; Портит AL KBDDesable macro mov al, CeqKBDIntrfDes out QeKBDCtrl1, al endm ;──────────────────────────────────────────────────────────────────────────────── ; Разрешить клавиатуру, выдавать макрос при пустом входном буфере ; Портит AL KBDEnable macro mov al, CeqKBDIntrfEna out QeKBDCtrl1, al endm ;──────────────────────────────────────────────────────────────────────────────── ; Установить линию GateA20 ; Вход JGateA20AlreadySet -- Метка, по которой выполняется переход, если A20 была ; установлена до выполнения макроса. Необязательный параметр ; Выход Нет ; Портит AX KBDSetA20 macro JGateA20AlreadySet KBDWtInpBufFree ; Дождёмся, когда входной буфер будет пуст KBDOutpBufFree ; Освободим выходной порт, если он занят ;──────────────────── mov al, CeqKBDRdOutPort ; и запишем обратно в выходной порт. out QeKBDCtrl1, al KBDWtOuputBufFull ; Дождёмся, когда в выходной буфер поступят данные in al, QKBDIn ; Прочитаем данные выходного порта bts eax, FKBDGateA20 ; Установим бит разрешающий линию GATE A20 ifnb ; Переход, если линия A20 уже установлена jc JGateA20AlreadySet endif mov ah, al ; Сохраним в безопасном месте mov al, CeqKBDWrOutPort out QeKBDCtrl1, al mov al, ah KBDWtInpBufFree out QeKBDCtrl2, al endm ;──────────────────────────────────────────────────────────────────────────────── ; Сбрость линию GateA20 ; Вход JGateA20AlreadyReset -- Метка, по которой выполняется переход, если A20 была ; сброшена до выполнения макроса. Необязательный параметр ; Выход Нет ; Портит AX KBDResetA20 macro JGateA20AlreadyReset ;──────────────────── ; входной буфер), освободим выходной буфер KBDWtInpBufFree ; Дождёмся, когда входной буфер будет пуст KBDOutpBufFree ; Освободим выходной порт, если он занят ;──────────────────── ; Прочитаем содержимое выходного порта, сбросим бит разрешающий GATE A20 ; и запишем обратно в выходной порт. mov al, CeqKBDRdOutPort out QeKBDCtrl1, al KBDWtOuputBufFull ; Дождёмся, когда в выходной буфер поступят данные in al, QKBDIn ; Прочитаем данные выходного порта btr eax, FKBDGateA20 ; Сбросим бит разрешающий линию GATE A20 ifnb ; Переход, если линия A20 уже сброшена jnc JGateA20AlreadyReset endif mov ah, al ; Сохраним в безопасном месте mov al, CeqKBDWrOutPort out QeKBDCtrl1, al mov al, ah KBDWtInpBufFree out QeKBDCtrl2, al endm ;──────────────────────────────────────────────────────────────────────────────── ; Сбросить систему KBDResetSystem macro KBDWtInpBufFree ; Дождёмся, когда входной буфер будет пуст mov al, CeqKBDWrOutPort out QeKBDCtrl1, al movnull eax KBDWtInpBufFree out QeKBDCtrl2, al endm ;════════════════════════════════════════════════════════════════════════════════ comment~ Назначение разрядов байта для команды 60h ┌──────┬────────────────────────────────────────────────────────────────────────────────────────────────────┐ │Разряд│ Назначение │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 0 │ 0 -- не генерировать прерывание по заполнению выходного буфера, 1 -- генерировать │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 1 │ Резерв, должен быть равным нулю │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 2 │ Системный флажок. Записывается во второй разряд регистра состояния. │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 3 │ 0 -- подчиниться защитному замку; 1 -- игнорировать защитный замок │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 4 │ 0 -- разрешить интерфейс клавиатуры; 1 -- запретить. │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 5 │ 0 -- использовать 11-разрядные коды клавиатуры (PC AT); 1 -- использовать коды клавиатуры, │ │ │ совместимые с PC XT │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 6 │ 0 -- не преобразовывать коды клавиатуры в IBM PC совместимый; │ │ │ 1 -- преобразовывать коды клавиатуры в совместимые с XT. │ ├──────┼────────────────────────────────────────────────────────────────────────────────────────────────────┤ │ 7 │ Резерв, должен быть равным нулю │ └──────┴────────────────────────────────────────────────────────────────────────────────────────────────────┘~ ;76543210 CmKBDIntEn equ 00000001b ; Разрешить прерывания CmKBDLockIgnore equ 00001000b ; Отменить блокировку замка CmKBDIntrfDes equ 00010000b ; Запретить интерфейс клавиатуры CmKBDKeybXT equ 00100000b ; Работать с XT клавиатурой CmKBDModeXT equ 01000000b ; Работать в режиме совместимости с XT клавиатурой и преобразовывать коды ;──────────────────────────────────────────────────────────────────────────────── ; Чтение командного байта контороллера клавиатуры ; Выход: al -- командный байт KBDRdCmdByte macro KBDWtInpBufFree ; Дождаться, когда входной буфер будет пуст (чтобы можно было записать команду) KBDOutpBufFree ; Освободить выходной буфер (в который длолжжны быть записаны данные) mov al, CeqKBDGetCmd ; Записать в порт 60h(?) значение 20h out QeKBDCtrl1, al KBDWtOuputBufFull ; Дождаться, когда прийдут данные in al, QKBDOutp ; Прочитать командный байт endm ;──────────────────────────────────────────────────────────────────────────────── ; Запись командного байта контороллера клавиатуры KBDWrCmdByte macro CmdByte errifidni , "Параметр CmdByte не должен быть al" KBDWtInpBufFree mov al, CeqKBDSetCmd out QeKBDCtrl1, al mov al, CmdByte out QeKBDCtrl2, al endm ;************************************************************ ;* Коды ответов контроллера клавиатуры * ;************************************************************ KBDEndOfInit equ 055h ; Окончание инициализации клавиатуры comment~ Для записи в выходной порт необходимо ввести команду D1h по адресу 64h, затем ввести нужное значение данных для выходного порта по адресу 60h. Чтобы прочитать значение выходного порта необходимо ввести команду D0h по адресу 64h, затем прочитать данные по адресу 60h. Команда должна вводиться только когда выходной буфер пуст. При изменении состояния бита, управляющего адресной линией A20, программа, чтобы нормально продолжать работу, должна быть уверена, что бит установлен правильно. Для этого рекомендуется в контроллер выдавать холостую команду после последовательности записи в порт нужного значения. После выполнения этой холостой команды программа может быть уверена, что предыдущая команда выполнена и разряд адреса A20 установлен аппаратно на требуемое значение. Нельзя использовать команду D1 для изменения любого разряда, кроме 1-го. Данные в выходном буфере (порт 60h) -- это данные клавиатуры, только если контроллер не получил определённую команду. 64h -- Прочитать регистр состояния 8042 64h -- вывести команду 8042 60h -- Прочитать данные клавиатуры или ответ на команду 60h -- Вывести данные на клавиатуру или второй байт команды~ comment~ Клавиатура. При каждой передаче команды или данных от системы на клавиатуру система требует подтверждения от кла- виатуры. Если только система не запретит вывод данных с клавиатуры, последняя даёт ответ в течение 20 мс. Если ответ клавиатуры недействителен или содержит ошибку паритета, система повторно посылает ей команду или данные. Двухбайтовые команды требуют особой обработки. Если переданы и подтверждены команды команды F3h, F0h или EDh, а также передан байт данных, но ответ оказался недействительным или с ошибкой паритета, то система передаст повторно и команду, и байт данных. Клавиатура AT имеет 3 режима работы: Режим 1 имитирует работу клавиатуры PC XT; Режим 2 (установлен по умолчанию) выдаёт те же коды, что и XT клавиатура за исключением кодов новых клавиш, режим 3 для каждой клавиши генерирует свой собственный код. Здесь будет рассматриваться в основном режим 3. В этом режиме должно быть запрещено преобразование кодов у контрол- лера клавиатуры, т. к. он не может обрабатывать этот набор кодов сканирования. BIOS также не может обрабаты- вать этот код сканирования, поэтому прикладная система, использующая этот режим, должна обрабатывать их сама. Каждой клавише присвоен свой уникальный 8-разрядный код нажатия, который передаётся при нажатии клавиши. Код отжатия состоит из двух байтов первый -- префикс отжатия (F0h), а второй идентичен коду нажатия данной клави- ши. В этом наборе кодов каждая клавиша посылает только один код сканирования и состояние любой клавиши не за- висит от состояния других. За исключением клавиши Pause все клавиши работают на нажатие/отжатие и являются повторяемыми (т.е. при нажатой и удерживаемой клавише через определённые промежутки клавиатура посылает код нажатия этой клавиши). Если нажаты и удерживаются несколько клавиш, то повторяется код только той клавиши, которая была нажата пос- ледней. После её отпускания коды повторений перестают пересылаться, даже если ещё остаются нажатые клавиши. Если клавиша нажата во время запрета клавиатуры, то в буфер клавиатуры поступает только первый код нажатия.~ ; Общение с клавиатурой происходит черз порт 60h QKEYB equ 60h ;_____________________________________________ ; Ждать ответа от клавиатуры ; Выход: al -- ответ клавиатуры KEYBReceive macro KBDWtOuputBufFull in al, QKEYB endm ;_____________________________________________ ; Ждать подтверждения от клавиатуры. ; Если ответ от клавиатуры отличен от ACK, осуществляется переход по метке JNotACK ; Если указан параметр JResend, то если от клавиатуры поступает ответ Resend, выполняется ; переход по метке JResend ; Выход: al -- ответ клавиатуры KEYBWtACK macro JNotACK:req, JResend KBDWtOuputBufFull in al, QKEYB ifnb cmp al, CKEYBReSend je JResend endif cmp al, CKeybACK jne JNotACK endm ;_____________________________________________ ; Послать команду клавиатуре. Команда может содержать до трёх байт. ; Команды задаются параметрами CMD, CMD1 и CMD2. Коды команд клавиатуры см. ниже. ; Если параметр DontWaitACK пустой, то перед посылкой очередного байта (CMD1 или CMD2) ; ожидается приём подтверждения от клавиатуры. (После посылки CMD2 подтверждения не ожидается) ; Если DontWaitACK не пустой (любое значение), то ответ от клавиатуры не ожидается. KEYBsend macro CMD:req, CMD1, CMD2, DontWaitACK local GErr GErr: KBDWtInpBufFree movreg al, CMD out QKEYB, al ifnb ifb KEYBWtACK GErr else KBDWtInpBufFree endif movreg al, CMD1 out QKEYB, al endif ifnb ifb KEYBWtACK GErr else KBDWtInpBufFree endif movreg al, CMD2 out QKEYB, al endif endm ;************************************************************ ;* Команды управления клавиатурой * ;************************************************************ CeqKEYBSetLEDs equ 0edh ; Установить индикаторы состояния. После получения команды возвращает ; ACK и ждёт байт конфигурации светодиодных индикаторов. После получения ; байта выдаёт ACK и возобновляет сканирование. Двухбайтная команда. CmKEYBScrollLock equ 00000001b ; Зажечь ScrollLock FKEYBScrollLock = 0 CmKEYBNumLock equ 00000010b ; Зажечь NumLock FKEYBNumLock = 1 CmKEYBCapsLock equ 00000100b ; Зажечь CapsLock FKEYBCapsLock = 2 MKEYBLeds equ 00000111b ; Маска светодиодов CeqKEYBecho equ 0eeh ; После получения этой команды клавиатура выдаёт echo. Используется для ; диагностики. Однобайтная команда. CeqKEYBMode equ 0f0h ; Выбрать альтернативный режим работы клавиатуры или указать текущий. Клавиатура ; подтверждает полученную команду ACK, сбрасывает выходные буферы и повторения ; клавиш и готовится к приёму байта конфигурации и устанавливает новый режим ; или возвращает текущий. ACK возвращает? Двухбайтная команда. CKEYBCurMode equ 00h ; Выдать текущий режим CKEYBXTMode equ 01h ; Эмуляция XT CKEYBATMode equ 02h ; Режим по умочанию CKEYBATExtMode equ 03h ; Расширенный режим ; KBDNop - EF-F1- резерв, холостые команды клавиатура принимает их, ; и выдаёт ответ KReSend, никаких других действий не предпринимает- ; ся. Однобайтная команда CeqKEYBNop equ 0f1h ;EF-F1- резерв - холостые команды CeqKEYBExtKBD equ 0f2h ; Идентификатор расширенной клавиатуры. Передаётся при включении клавиатуры, ; клавиатура отвечает ACK и передаёт идентификатор клавиатуры KAnsExt ; (двухбайтный ответ), начиная с младшего байта. Однобайтная команда. CeqKEYBSetDelay equ 0f3h ; Установить частоту повторения клавиш. Клавиатура возвращает ACK и ждёт ; байт частоты повторения и времени задержки. Двухбайтная команда. ; Время задержки (вермя, в течение которого клавиша должна быть удержана нажатой прежде, чем начнётся ; функция повторения) CKEYBWait250 equ 00000000b ; 250 мс CKEYBWait500 equ 00100000b ; 500 мс CKEYBWait750 equ 01000000b ; 750 мс CKEYBWait1000 equ 01100000b ; 1 000 мс ; Частота повторения (показывает, сколько раз в секунду клавиша повторяется) CKEYBRep30_0 equ 00000000b ; 30,0 CKEYBRep26_6 equ 00000001b ; 26,6 CKEYBRep24_0 equ 00000010b ; 24,0 CKEYBRep21_8 equ 00000011b ; 21,8 CKEYBRep20_0 equ 00000100b ; 20,0 CKEYBRep18_4 equ 00000101b ; 18,4 CKEYBRep17_1 equ 00000110b ; 17,1 CKEYBRep16_0 equ 00000111b ; 16,0 CKEYBRep15_0 equ 00001000b ; 15,0 CKEYBRep13_3 equ 00001001b ; 13,3 CKEYBRep12_0 equ 00001010b ; 12,0 CKEYBRep10_9 equ 00001011b ; 10,9 CKEYBRep10_0 equ 00001100b ; 10,0 CKEYBRep09_2 equ 00001101b ; 9,2 CKEYBRep08_6 equ 00001110b ; 8,6 CKEYBRep08_0 equ 00001111b ; 8,0 CKEYBRep07_5 equ 00010000b ; 7,5 CKEYBRep06_7 equ 00010001b ; 6,7 CKEYBRep06_0 equ 00010010b ; 6,0 CKEYBRep05_5 equ 00010011b ; 5,5 CKEYBRep05_0 equ 00010100b ; 5,0 CKEYBRep04_6 equ 00010101b ; 4,6 CKEYBRep04_3 equ 00010110b ; 4,3 CKEYBRep04_0 equ 00010111b ; 4,0 CKEYBRep03_7 equ 00011000b ; 3,7 CKEYBRep03_3 equ 00011001b ; 3,3 CKEYBRep03_0 equ 00011010b ; 3,0 CKEYBRep02_7 equ 00011011b ; 2,7 CKEYBRep02_5 equ 00011100b ; 2,5 CKEYBRep02_3 equ 00011101b ; 2,3 CKEYBRep02_1 equ 00011110b ; 2,1 CKEYBRep02_0 equ 00011111b ; 2,0 CeqKEYBEnable equ 0f4h ; Разрешить клавиатуру. Возвращает код ACK, сбрасывает выходной буфер ; и начинает сканирование. Однобайтная команда. CeqKEYBDesable equ 0f5h ; Запрет по умолчанию. Всё сбрасывает, включая повторения клавиш, сбрасывает ; последнюю повторяемую клавишу, возвращает ACK, ожидает дальнейших команд. ; Однобайтная команда. CeqKEYBSetDefault equ 0f6h ; Установить условия по умолчанию. Клавиатура посылает ACK, всё ; сбрасывает и продолжает сканирование Однобайтная команда. ; KSETKAR, KSETKAPF, KSETKAP, KSETKAPFR - установить все клавиши только повторение, только нажатие\отжатие, ; только нажатие, повторение\нажатие\отжатие. после получения подтверждает KACK, очищает выходной буфер и ; продолжает сканирование (если оно было разрешено ранее). используется только в режиме 3. Однобайтные ко- ; манды CeqKEYBSetKAR equ 0F7h ; Установить все клавиши только повторение CeqKEYBSetKAPF equ 0F8h ; Установить все клавиши только нажатие\отжатие CeqKEYBSetKAP equ 0F9h ; Установить все клавиши только нажатие CeqKEYBSetKAPFR equ 0FAh ; Установить все клавиши повторение\нажатие\отжатие ; KSetK1R, KSetK1PFR, KSetK1PFR - установить отдельные клавиши только повторение, только нажатие\отжатие, ; только нажатие. Клавиатура получает первый байт, посылает KACK, очищает выходной буфер, ждёт код клавиши ; (ScanCode), подтверждает его и ждёт следующей команды. Сканирование не возобновляется до тех пор, пока не ; получит команду KEnableKBD. Устанавливать можно несколько клавиш одновременно. Многобайтные команды. CeqKEYBSetK1R equ 0fbh ; установить отдельные клавиши только повторение *) CeqKEYBSetK1PF equ 0fch ; установить отдельные клавиши только нажатие\отжатие *) CeqKEYBSetK1P equ 0fdh ; установить отдельные клавиши нажатие *) ;*) Устаналивать можно несколько клавиш CeqKEYBResend equ 0feh ; Послать данные повторно. Клавиатура посылает последний байт, переданный системе. ; Если предыдущим был KResend, то передаётся байт переданный перед ним. ; Однобайтная команда CeqKEYBReset equ 0ffh ; Сброс. Клавиатура возвращает системе код ACK, и запрещается до получения ; следующей команды или принятия системой KACK. Однобайтная команда ;************************************************************ ;* Коды ответов клавиатуры * ;************************************************************ ; CKEYBOverFlow и CKEYBOverFlowXT - коды переполнения буфера клавиатуры или ошибки (если не удаётся идентифицировать ; замыкание контактов на клавиатуре) при работе в режимах 2,3 и режиме 1. Однобайтовый ответ. CKEYBOverflow equ 00h ; Переполнение в режимах 2,3 CKEYBOverFlowXT equ 0ffh ; Переполнение в режиме 1 CKEYBACK equ 0fah ; Подтверждение правильности команды (ACK). Передаётся в ответ на любую ; правильную команду за исключением echo и resend. Если клавиатура прерывается ; во время передачи KACK, то KACK отменяется и начинается приём новой команды. ; Однобайтовый ответ. CKEYBPower equ 0aah ; При включении питания клавиатура передаёт этот код системе. Передача ; любого другого указывает на неисправность клавиатуры. Однобайтовый ответ. CKEYBecho equ 0eeh ; Однобайтовый ответ на команду echo. CKEYBAnsExt equ 83abh ; Ответ на команду CeqKEYBExtKBD Первым передаётся младший байт. Двухбайтный ответ. CKEYBReSend equ 0feh ; После получения неправильных входных данных или данных с ошибкой паритета. ; Однобайтовый ответ. ;************************************************************ ;* Макросы * ;************************************************************ ; Конец отработки прерывания клавиатуры. KBDEndOfInterrupt macro SPKBDReaded IRQ_EOI KBD endm ;═══════════════════════════════════════════════════════════════════════════════ ; Сканкоды клавиш при работе клавиатуры в режиме 3. ; клавиша ; Англ. Русск ; Shift ;───────────────────────────────────────────────── CKBD3_0 equ 45h ; 0 ) ) CKBD3_1 equ 16h ; 1 ! ! CKBD3_2 equ 1eh ; 2 @ " CKBD3_3 equ 26h ; 3 # № CKBD3_4 equ 25h ; 4 $ ; CKBD3_5 equ 2eh ; 5 % : CKBD3_6 equ 36h ; 6 ^ , CKBD3_7 equ 3dh ; 7 & . CKBD3_8 equ 3eh ; 8 * * CKBD3_9 equ 46h ; 9 ( ( CKBD3_tilde equ 0eh ; ` ~ CKBD3_minus equ 4eh ; - _ CKBD3_equal equ 55h ; = + CKBD3_OpenBrace equ 54h ; [ { Х CKBD3_CloseBrace equ 5bh ; ] } Ъ CKBD3_Semicolon equ 4ch ; ; : Ж CKBD3_Apostophe equ 52h ; ' " Э CKBD3_comma equ 41h ; , < Б CKBD3_dot equ 49h ; . > Ю CKBD3_Slash equ 4ah ; / ? Ё CKBD3_BackSlash equ 5ch ; \ | ;──────────────────────────────────────────── CKBD3_q equ 15h ; q Q Й CKBD3_w equ 1dh ; w W Ц CKBD3_e equ 24h ; e E У CKBD3_r equ 2dh ; r R К CKBD3_t equ 2ch ; t T Е CKBD3_y equ 35h ; y Y Н CKBD3_u equ 3ch ; u U Г CKBD3_i equ 43h ; i I Ш CKBD3_o equ 44h ; o O Щ CKBD3_p equ 4dh ; p P З CKBD3_a equ 1ch ; a A Ф CKBD3_s equ 1bh ; s S Ы CKBD3_d equ 23h ; d D В CKBD3_f equ 2bh ; f f А CKBD3_g equ 34h ; g G П CKBD3_h equ 33h ; h H Р CKBD3_j equ 3bh ; j J О CKBD3_k equ 42h ; k K Л CKBD3_l equ 4bh ; l L Д CKBD3_z equ 1ah ; z Z Я CKBD3_x equ 22h ; x X Ч CKBD3_c equ 21h ; c C С CKBD3_v equ 2ah ; v V М CKBD3_b equ 32h ; b B И CKBD3_n equ 31h ; n N Т CKBD3_m equ 3ah ; m M Ь CKBD3_Space equ 29h ; ;──────────────────────────────────────────── CKBD3_Esc equ 08h ; Escape CKBD3_F1 equ 07h ; F1 CKBD3_F2 equ 0fh ; F2 CKBD3_F3 equ 17h ; F3 CKBD3_F4 equ 1fh ; F4 CKBD3_F5 equ 27h ; F5 CKBD3_F6 equ 2fh ; F6 CKBD3_F7 equ 37h ; F7 CKBD3_F8 equ 3fh ; F8 CKBD3_F9 equ 47h ; F9 CKBD3_F10 equ 4fh ; F10 CKBD3_F11 equ 56h ; F11 CKBD3_F12 equ 5eh ; F12 CKBD3_PrScr equ 57h ; Print Screen CKBD3_Pause equ 62h ; Pause ; Примечание. Согласно [1] работает только на нажатие. На моей клавиатуре ; в режиме 3 она программируется также, как и остальные клавиши (т. е. ; нажатие, нажатие/отжатие, нажатие/отжатие/повторение и т. д.) ;──────────────────────────────────────────── CKBD3_NumLck equ 76h ; Num Lock CKBD3_ScrlLck equ 5fh ; Scroll Lock CKBD3_CapsLck equ 14h ; Caps Lock ;──────────────────────────────────────────── CKBD3_LShift equ 12h ; Левый Shift CKBD3_LAlt equ 19h ; Левый Alt CKBD3_LCtrl equ 11h ; Левый Ctrl CKBD3_RShift equ 59h ; Правый Shift CKBD3_RAlt equ 38h ; Правый Alt CKBD3_RCtrl equ 58h ; Правый Ctrl ;──────────────────────────────────────────── CKBD3_Enter equ 5ah ; Enter CKBD3_Tab equ 0dh ; Tab CKBD3_Backspace equ 66h ; Backspace CKBD3_Insert equ 70h ; Вставка ; 67h (Для серой) CKBD3_Delete equ 71h ; Удалить ; 64h (Для серой) CKBD3_Left equ 6bh ; Стрелка влево ; 61h (Для серой) CKBD3_Right equ 74h ; Стрелка вправо ; 6ah (Для серой) CKBD3_Up equ 75h ; Стрелка вверх ; 63h (Для серой) CKBD3_Down equ 72h ; Стрелка вниз ; 60h (Для серой) CKBD3_PgUp equ 7dh ; Страница вверх ; 6fh (Для серой) CKBD3_PgDown equ 7ah ; Страница вниз ; 6dh (Для серой) CKBD3_Home equ 6ch ; В начало ; 6eh (Для серой) CKBD3_End equ 69h ; В конец ; 65h (Для серой) ;──────────────────────────────────────────── CKBD3_GrLeft equ 61h ; Стрелка влево на серой клавиатуре 4 CKBD3_GrRight equ 6ah ; Стрелка вправо на серой клавиатуре 6 CKBD3_GrUp equ 63h ; Стрелка вверх на серой клавиатуре 8 CKBD3_GrDown equ 60h ; Стрелка вниз на серой клавиатуре 2 CKBD3_GrPgUp equ 6fh ; Страница вверх на серой клавиатуре 9 CKBD3_GrPgDown equ 6dh ; Страница вниз на серой клавиатуре 3 CKBD3_GrHome equ 6eh ; Вначало на серой клавиатуре 7 CKBD3_GrEnd equ 65h ; Вконец на серой клавиатуре 1 CKBD3_GrInsert equ 67h ; Вставка на серой клавиатуре 0 CKBD3_GrDelete equ 64h ; Удалить на серой клавиатуре . CKBD3_Gr5 equ 73h ; центральная клавиша 5 CKBD3_GrEnter equ 79h ; серый ввод CKBD3_GrPlus equ 7ch ; серый + CKBD3_GrMinus equ 84h ; серый - (предположительно, необходимо уточнить) CKBD3_GrMultiply equ 7eh ; серый * CKBD3_GrDivide equ 77h ; серый / CKBD3_Lwin equ 8bh ; Левая клавиша Windows CKBD3_Rwin equ 8ch ; Правая клавиша Windows CKBD3_WinMenu equ 8dh ; Клавиша меню Windows ; Клавиши WakeUp, Sleep и Power в режиме 3 на моей клавиатуре не опознаются ;──────────────────────────────────────────── ; Особые коды CKBD3_Unpress equ 0f0h ; Код отпускания клавиши ;──────────────────────────────────────────── ;═══════════════════════════════════════════════════════════════════════════════ ; Сканкоды клавиш при работе клавиатуры в режиме 2 (с отключённой перекодировкой). ; клавиша ; Англ. Русск ; Shift ;───────────────────────────────────────────────── CKBD2_0 equ 45h ; 0 ) ) CKBD2_1 equ 16h ; 1 ! ! CKBD2_2 equ 1eh ; 2 @ " CKBD2_3 equ 26h ; 3 # № CKBD2_4 equ 25h ; 4 $ ; CKBD2_5 equ 2eh ; 5 % : CKBD2_6 equ 36h ; 6 ^ , CKBD2_7 equ 3dh ; 7 & . CKBD2_8 equ 3eh ; 8 * * CKBD2_9 equ 46h ; 9 ( ( CKBD2_tilde equ 0eh ; ` ~ CKBD2_minus equ 4eh ; - _ CKBD2_equal equ 55h ; = + CKBD2_OpenBrace equ 54h ; [ { Х CKBD2_CloseBrace equ 5bh ; ] } Ъ CKBD2_Semicolon equ 4ch ; ; : Ж CKBD2_Apostophe equ 52h ; ' " Э CKBD2_comma equ 41h ; , < Б CKBD2_dot equ 49h ; . > Ю CKBD2_Slash equ 4ah ; / ? ё CKBD2_BackSlash equ 5dh ; \ | ;──────────────────────────────────────────── CKBD2_q equ 15h ; q Q й CKBD2_w equ 1dh ; w W ц CKBD2_e equ 24h ; e E у CKBD2_r equ 2dh ; r R к CKBD2_t equ 2ch ; t T е CKBD2_y equ 35h ; y Y н CKBD2_u equ 3ch ; u U г CKBD2_i equ 43h ; i I ш CKBD2_o equ 44h ; o O щ CKBD2_p equ 4dh ; p P з CKBD2_a equ 1ch ; a A ф CKBD2_s equ 1bh ; s S ы CKBD2_d equ 23h ; d D в CKBD2_f equ 2bh ; f f а CKBD2_g equ 34h ; g G п CKBD2_h equ 33h ; h H р CKBD2_j equ 3bh ; j J о CKBD2_k equ 42h ; k K л CKBD2_l equ 4bh ; l L д CKBD2_z equ 1ah ; z Z я CKBD2_x equ 22h ; x X ч CKBD2_c equ 21h ; c C с CKBD2_v equ 2ah ; v V м CKBD2_b equ 32h ; b B и CKBD2_n equ 31h ; n N т CKBD2_m equ 3ah ; m M ь CKBD2_Space equ 29h ; ;──────────────────────────────────────────── CKBD2_Esc equ 76h ; Escape CKBD2_F1 equ 05h ; F1 CKBD2_F2 equ 06h ; F2 CKBD2_F3 equ 04h ; F3 CKBD2_F4 equ 0ch ; F4 CKBD2_F5 equ 03h ; F5 CKBD2_F6 equ 0bh ; F6 CKBD2_F7 equ 83h ; F7 CKBD2_F8 equ 0ah ; F8 CKBD2_F9 equ 01h ; F9 CKBD2_F10 equ 09h ; F10 CKBD2_F11 equ 78h ; F11 CKBD2_F12 equ 07h ; F12 CKBD2_PrScr equ 0e012e07ch ; Print Screen CKBD2_Pause equ 0e11477h ; Pause работает только на нажатие (?) ;──────────────────────────────────────────── CKBD2_NumLck equ 77h ; Num Lock CKBD2_ScrlLck equ 7eh ; Scroll Lock CKBD2_CapsLck equ 58h ; Caps Lock ;──────────────────────────────────────────── CKBD2_LShift equ 12h ; Левый Shift CKBD2_LAlt equ 11h ; Левый Alt CKBD2_LCtrl equ 14h ; Левый Ctrl CKBD2_RShift equ 59h ; Правый Shift CKBD2_RAlt equ 0e011h ; Правый Alt CKBD2_RCtrl equ 0e014h ; Правый Ctrl ;──────────────────────────────────────────── CKBD2_Enter equ 5ah ; Enter CKBD2_Tab equ 0dh ; Tab CKBD2_Backspace equ 66h ; Backspace CKBD2_Insert equ 0e070h ; Вставка ; 70h (Для серой) CKBD2_Delete equ 0e071h ; Удалить ; 71h (Для серой) CKBD2_Left equ 0e06bh ; Стрелка влево ; 6bh (Для серой) CKBD2_Right equ 0e074h ; Стрелка вправо ; 74h (Для серой) CKBD2_Up equ 0e075h ; Стрелка вверх ; 75h (Для серой) CKBD2_Down equ 0e072h ; Стрелка вниз ; 72h (Для серой) CKBD2_PgUp equ 0e07dh ; Страница вверх ; 7dh (Для серой) CKBD2_PgDown equ 0e07ah ; Страница вниз ; 7ah (Для серой) CKBD2_Home equ 0e06ch ; В начало ; 6ch (Для серой) CKBD2_End equ 0e069h ; В конец ; 69h (Для серой) ;──────────────────────────────────────────── CKBD2_GrLeft equ 6bh ; Стрелка влево на серой клавиатуре 4 CKBD2_GrRight equ 74h ; Стрелка вправо на серой клавиатуре 6 CKBD2_GrUp equ 75h ; Стрелка вверх на серой клавиатуре 8 CKBD2_GrDown equ 72h ; Стрелка вниз на серой клавиатуре 2 CKBD2_GrPgUp equ 7dh ; Страница вверх на серой клавиатуре 9 CKBD2_GrPgDown equ 7ah ; Страница вниз на серой клавиатуре 3 CKBD2_GrHome equ 6ch ; Вначало на серой клавиатуре 7 CKBD2_GrEnd equ 69h ; Вконец на серой клавиатуре 1 CKBD2_GrInsert equ 70h ; Вставка на серой клавиатуре 0 CKBD2_GrDelete equ 71h ; Удалить на серой клавиатуре . CKBD2_Gr5 equ 73h ; центральная клавиша 5 CKBD2_GrEnter equ 0e05ah ; серый "ВК" CKBD2_GrPlus equ 79h ; серый + CKBD2_GrMinus equ 7bh ; серый - (предположительно, необходимо уточнить) CKBD2_GrMultiply equ 7ch ; серый * CKBD2_GrDivide equ 0e04ah ; серый / CKBD2_LWin equ 0e01fh ; Левая клавиша windows CKBD2_RWin equ 0e027h ; Правая клавиша windows CKBD2_WinMenu equ 0e02fh ; Клавиша меню windows CKBD2_WakeUp equ 0e05eh ; Клавиша WakeUp CKBD2_Sleep equ 0e03fh ; Клавиша Sleep CKBD2_Power equ 0e037h ; Клавиша Power ;──────────────────────────────────────────── ; Особые коды CKBD2_Unpress equ 0f0h ; Код отпускания клавиши CKBD2_ExtCode equ 0e0h ; Код дополнительной клавиши CKBD2_ExtCode1 equ 0e1h ; Дополнительный код, выдаваемый только при нажатии ; клавиши Pause. ; Конец файла KBDdescr.mac