На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS

Дорогие друзья! Поздравляем вас с Новым 2018 годом!

Всем удачи, успеха и благополучия!
В новом году ожидаем новых рекордов при подсчёте количества ёлочек на экране ;)


msm.ru
! Перед отправкой сообщения внимательно прочтите правила раздела!!!
1. Все статьи должны быть оформлены согласно Правил оформления статей.
2. Любые обсуждения должны происходить в специальной теме, обсуждение в любых других темах раздела запрещены.
3. Запрещается писать статьи о создании и распространении вирусов, троянов и других вредоносных программ!
4. За грамотно написанные и правильно оформленные статьи авторы награждаются DigiMoney.

Дополнительные ссылки:
Желаю творческих успехов! ;)
Модераторы: Jin X
  
    > Драйвер клавиатуры, x86, TASM, DOS, Hardware
      Драйвер клавиатуры

      При написании своих ОС, или при переходе в защищенный режим становится проблематичным использовать прерывания BIOS для работы с клавиатурой. Но создать свой драйвер несложно, хотя разработчики клавиатур постарались, чтобы жизнь программистам не казалась совсем уж медом :)
      Разумеется будет рассмотрен только второй режим работы клавиатуры - для PC/AT. В этом режиме клавиатуру можно разбить на следующие группы, по генерируемым скан-кодам:
      • Основная. Это та, что зародилась еще на 84-х клавишной XT. При нажатии клавиши в компьютер посылается однобайтный скан-код, который еще нужно перевести в ASCII. При отжатии посылается тот же код, но с установленным старшим битом.
      • Расширенная. При нажатии посылается 2 байта, первый - E0h, затем скан-код, совпадающий с одной из клавиш основной клавиатуры. При отжатии так же посылается код E0h, а затем скан-код, с установленным старшим битом.
      • Цифровая. Как и основная, посылает однобайтный скан-код, за исключением клавиш Enter и '/', которые посылают расширенные коды.
      • Дополнительная. Генерирует последовательность из четырех байт, начинающихся с E0h,2Ah,E0h, далее следует скан-код, совпадающий с одной из клавиш цифровой клавиатуры. При отжатии сначала посылается байт E0h, затем скан-код, с установленным старшим битом, а затем последовательность из E0h и AAh (2Ah с установленным старшим битом), т.е. в обратном порядке. В режиме автоповтора посылается последовательность из двух байт - E0h и скан-кода клавиши. Заметим, что код 2Ah совпадает со скан-кодом клавиши Left Shift.
      • Клавиша Pause/Break. Стоит особняком, поскольку генерирует шесть байт, состоящих из кодов нажатия и отжатия (E1h, 1Dh, 45h, E1h, 9Dh, C5h). Соответственно при отжатии ничего не генерируется.
      • Клавиши Win, Applications, Power, Sleep, Wake Up. Генерируют расширенный код, соответственно и обрабатываются так же.
      Но не все так плохо. Если повнимательнее присмотреться к таблице скан-кодов, то нетрудно заметить что, отбросив комбинацию <E0h, 2Ah>, мы сможем обрабатывать клавиши дополнительной клавиатуры как расширенные, что значительно облегчает задачу, поскольку остается учитывать только поступление байт E0h и E1h.
      Ниже представлен код драйвера, для примера, написанный под DOS. Чем-то напоминает обработчик BIOS, но не обрабатывает комбинации клавиш. Поддерживает смену раскладки клавиатуры (Eng/Rus).
      ExpandedWrap disabled
                .model tiny, pascal
                .8086
         
         
        ;+---------------------------------------------------------------------------+
        ;|                объявление экспортируемых функций драйвера                 |
        ;+---------------------------------------------------------------------------+
        public key_Install              ; инициализация драйвера
        public key_Uninstall            ; выгрузка и восстановление старого
        public key_Wait8042In           ; ожидает готовности входного буфера i8042
        public key_Wait8042Out          ; ожидает готовности выходного буфера i8042
        public key_Put                  ; добавляет очередной символ и его скэн-код в очередь
        public key_Get                  ; чтение символа из буфера клавиатуры
        public key_Status               ; чтение флагов состояния регистровых клавиш
         
         
        ;+---------------------------------------------------------------------------+
        ;|                                 константы                                 |
        ;+---------------------------------------------------------------------------+
          ; биты состояния регистровых клавиш клавиатуры (Status[0])
          LSHIFT        equ     01h     ; левый Shift
          RSHIFT        equ     02h     ; правый Shift
          LCONTROL      equ     04h     ; левый Ctrl
          RCONTROL      equ     08h     ; правый Ctrl
          LALT          equ     10h     ; левый Alt
          RALT          equ     20h     ; правый Alt
          INSERT        equ     40h     ; Insert
          SYSREQ        equ     80h     ; PrtSc/SysRq
         
          ; биты состояния драйвера и управления светодиодами (Status[1])
          E0            equ     01h     ; предыдущий скэн-код был E0h
          E1            equ     02h     ; предыдущий скэн-код был E1h
          RUSLAT        equ     04h     ; Eng/Rus раскладка
          PAUSE         equ     08h     ; Pause/Break
          SCROLLLOCK    equ     20h     ; ScrollLock
          NUMLOCK       equ     40h     ; NumLock
          CAPSLOCK      equ     80h     ; CapsLock
         
         
        ;+---------------------------------------------------------------------------+
        ;|                                  данные                                   |
        ;+---------------------------------------------------------------------------+
        .data
          ; таблицы перекодировки, местами не менять!
          Symb:
            db  0 ,1bh,'1','2','3','4','5','6','7','8','9','0','-','=', 8 , 9
            db 'q','w','e','r','t','y','u','i','o','p','[',']', 13, -1,'a','s'
            db 'd','f','g','h','j','k','l',';',"'",'`', -1,'\','z','x','c','v'
            db 'b','n','m',',','.','/', -1,'*', -1,' ', -1, 0 , 0 , 0 , 0 , 0
            db  0 , 0 , 0 , 0 , 0 , -1, -1, 0 , 0 , 0 ,'-', 0 , 0 , 0 ,'+', 0
            db  0 , 0 , -1, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
            db 32 dup (0)
          SymbRus:
            db  0 ,1bh,'1','2','3','4','5','6','7','8','9','0','-','=', 8 , 9
            db 'й','ц','у','к','е','н','г','ш','щ','з','х','ъ', 13, -1,'ф','ы'
            db 'в','а','п','р','о','л','д','ж','э',')', -1,'\','я','ч','с','м'
            db 'и','т','ь','б','ю','ё', -1,'*', -1,' ', -1, 0 , 0 , 0 , 0 , 0
            db  0 , 0 , 0 , 0 , 0 , -1, -1, 0 , 0 , 0 ,'-', 0 , 0 , 0 ,'+', 0
            db  0 , 0 , -1, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
            db 32 dup (0)
          SymbShift:
            db  0 ,1bh,'!','@','#','$','%','^','&','*','(',')','_','+', 8 , 9
            db 'Q','W','E','R','T','Y','U','I','O','P','{','}', 13, -1,'A','S'
            db 'D','F','G','H','J','K','L',':','"','~', -1,'|','Z','X','C','V'
            db 'B','N','M','<','>','?', -1,'*', -1,' ', -1, 0 , 0 , 0 , 0 , 0
            db  0 , 0 , 0 , 0 , 0 , -1, -1,'7','8','9','-','4','5','6','+','1'
            db '2','3','0','.', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
            db 32 dup (0)
          SymbRusShift:
            db  0 ,1bh,'!','"','/','$',':',',','.',';','?','%','_','+', 8 , 9
            db 'Й','Ц','У','К','Е','Н','Г','Ш','Щ','З','Х','Ъ', 13, -1,'Ф','Ы'
            db 'В','А','П','Р','О','Л','Д','Ж','Э','(', -1,'|','Я','Ч','С','М'
            db 'И','Т','Ь','Б','Ю','Ё', -1,'*', -1,' ', -1, 0 , 0 , 0 , 0 , 0
            db  0 , 0 , 0 , 0 , 0 , -1, -1,'7','8','9','-','4','5','6','+','1'
            db '2','3','0','.', 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
            db 32 dup (0)
         
         
          ; код переключения раскладки клавиатуры (Rus/Eng)
          LangSwitch    db 1Dh          ; клавиша       - Ctrl
                        db RCONTROL     ; флаги         - правый
         
         
        ;+---------------------------------------------------------------------------+
        ;|                       неинициализированные данные                         |
        ;+---------------------------------------------------------------------------+
        .data?
          ; состояние клавиатуры
          Status        db ?            ; состояние регистровых клавиш
                        db ?            ; состояние драйвера и светодиодов
         
          ; буфер драйвера клавиатуры
          buf_tail      dw ?            ; указатель на последний введенный символ
          buf_head      dw ?            ; указатель на первый введенный символ
          buf_code      dw 32 dup(?)    ; сам буфер
          buf_end       equ ($-buf_code)/2
         
          ; адрес старого обработчика прерываний клавиатуры
          oldOfsIRQ1    dw ?            ; его смещение
          oldSegIRQ1    dw ?            ; и сегмент
          ; старое состояние светодиодов
          oldLed        db ?
         
         
        ;+---------------------------------------------------------------------------+
        ;|                                    код                                    |
        ;+---------------------------------------------------------------------------+
        .code
         
        ; обработчик IRQ 1 - прерывания, генерируемого контроллером клавиатуры
        key_Handler proc
                ; сохраняем используемые нами регистры и настраиваем регистр DS на сегмент данных
                push    ds es ax bx cx dx si di bp
                push    cs
                pop     ds              ; ds - наш сегмент данных (для модели TINY)
                ; получаем пришедший байт
                mov     dx, 60h
                in      al, dx
                mov     ah, al
            ; для IBM XT и более ранних моделей необходимо уведомить контроллер клавиатуры
            ; о приеме данных, через порт 61h. если не предполагается поддержка таких
            ; древних компьютеров, то можно смело убрать следующие 6 строк кода.
                inc     dx
                in      al, dx
                or      al, 80h         ; устанавливаем режим "только чтение"
                out     dx, al          ; отсылаем контроллеру
                and     al, 7fh         ; отменяем режим "только чтение"
                out     dx, al          ; теперь контроллер готов к посылке следующего байта
            ; разрешаем прерывания, поскольку задерживать их крайне нежелательно
                mov     al, 20h         ; al - команда EOI (End Of Interrupt)
                out     20h, al         ; отсылает ее контроллеру прерываний
                sti
         
            ; теперь вызываем функцию 4fh, прерывания 15h.
            ; эта функция доступна на всех ЭВМ, кроме PC, PCjr, XT
            ; от 11/08/82 и AT от 01/10/84.
                mov     al, 4fh
                xchg    al, ah          ; al - скэн-код / ah - номер функции
                int     15h
            ; на выходе:
            ;   флаг CF = 0 - игнорировать скан-код
            ;             1 - занести скан-код в буфер клавиатуры
            ;        AL = скан-код (старый или подмененный)
                jnc     @@iret
         
            ; начинаем обработку пришедшего символа
                xor     bx, bx          ; номер таблицы перекодировки
                mov     ah, al
         
                test    Status[1], E1   ; если установлен бит E1,
                jnz     @@pause         ; <- то идет прием кодов Pause/Break
         
            ; если у скэн-кода установлен старший бит, то пришел код отжатой клавиши
            ; или начало последовательности кодов расширенной/дополнительной клавиатуры
                or      al, al
                jns     @@isextcode
                cmp     al, 0e0h        ; E0h - первый байт скэн-кода расширенной/доп. клавиатуры
                jne     @@ispause
                or      Status[1], E0   ; устанавливаем признак приема расширенного скэн-кода
                jmp     @@iret          ; и будем дожидаться собственно байта скэн-кода клавиши
            @@ispause:
                cmp     al, 0e1h        ; E1h - начальный байт Pause/Break
                jne     @@keyup
                or      Status[1], E1   ; устанавливаем признак приема скэн-кода от Pause/Break
                jmp     @@iret          ; и ждем остальную последовательнось байт
            @@keyup:
                call    key_Release     ; из отжатых нас интересуют Ctrl, Alt и Shift
                jmp     @@exit
         
            @@isextcode:
                test    Status[1], E0   ; если установлен бит E0, то идет прием очередного
                jnz     @@extcode       ; байта скэн-кода клавиши расширенной/доп. клавиатуры
         
            ; получен однобайтовый код основной клавиатуры,
            ; пытаемся преобразовать его в ascii символ, с учетом состояния регистровых клавиш
                test    Status[1], RUSLAT
                jz      @@isshift
                inc     bx
            @@isshift:
                test    Status[0], (LSHIFT or RSHIFT)
                jz      @@isnumlock
                inc     bx
                inc     bx
            @@isnumlock:                ; если включен NumLock, то обрабатываем немного по другому
                test    Status[1], NUMLOCK
                jz      @@xlat
                cmp     al, 47h         ; на цифровой клавиатуре?
                jb      @@xlat
                cmp     al, 53h
                ja      @@xlat
                neg     bx              ; меняем 0|1 таблицу на 2|3 таблицу
                add     bx, 3
            @@xlat:
                shl     bx, 7           ; bx = bx * 128 = bx * sizeof(таблица перекодировки)
                add     bx, offset Symb
                xlat                    ; al = bx[al] = SymbTable[al]
                cmp     al, -1          ; это регистровая клавиша?
                je      @@keydown       ; <- да, нужно изменить ее статус
                test    Status[1], CAPSLOCK
                jz      @@savecode
                call    key_ChangeReg   ; при включенном SapsLock меняем регистр клавиш
            @@savecode:
                call    key_Put         ; ложим получившийся код в буфер
            @@exit:
                and     Status[1], not E0
            @@iret:
                pop     bp di si dx cx bx ax es ds
                iret
         
            ; обработка нажатия Pause/Break (последовательность кодов - E1h,1Dh,45h,E1h,9Dh,C5h)
            @@pause:
                cmp     al, 0c5h        ; это конец последовательности?
                jne     @@exit
                and     Status[1], not E1
                xor     Status[1], PAUSE; меняем состояние на противоположное
                jmp     @@exit
         
            ; пришел код расширенной/доп. клавиатуры
            @@extcode:
                cmp     al, 2ah
                je      @@exit          ; <- пропускаем код E0h,2Ah
         
            ; выясняем, не регистровая ли клавиша нажата?
            @@keydown:
                mov     al, ah          ; команды с регистром AL короче на один байт :)
                mov     dh, LALT
                cmp     al, 38h         ; нажат Alt?
                je      @@isrightdn
                ja      @@isled         ; коды 3Ah и выше принадлежат клавишам управления светодиодами
                mov     dh, LSHIFT
                cmp     al, 2ah         ; нажат левый Shift?
                je      @@savedn
                mov     dh, RSHIFT
                cmp     al, 36h         ; нажат правый Shift?
                je      @@savedn
                mov     dh, LCONTROL
                cmp     al, 1dh         ; нажат Ctrl?
                je      @@isrightdn
                cmp     al, 37h         ; нажат Print Screen?
                jne     @@unccode
                xor     Status[0], SYSREQ
                jmp     @@exit
            @@isrightdn:
                test    Status[1], E0   ; если предыдущий код был E0h
                jz      @@savedn        ; то это правый Ctrl/Alt
                add     dh, dh          ; сдвигаем бит влево (делаем клавишу правой)
            @@savedn:
                or      Status[0], dh   ; устанавливаем бит нажатой регистровой клавиши
                jmp     @@exit          ; и уходим
         
            ; проверяем на нажатие клавиши управления светодиодами и Insert
            @@isled:
                mov     dh, SCROLLLOCK
                cmp     al, 46h         ; нажат ScrollLock?
                je      @@led
                mov     dh, NUMLOCK
                cmp     al, 45h         ; нажат NumLock?
                je      @@led
                mov     dh, CAPSLOCK
                cmp     al, 3ah         ; нажат CapsLock?
                je      @@led
                cmp     al, 52h         ; а может Insert?
                jne     @@unccode       ; <- это не регистровая клавиша, просто заносим в буфер
                xor     Status[0], INSERT
                jmp     @@unccode       ; <- Insert тоже кладем в буфер
            @@led:
                xor     Status[1], dh   ; переключаем бит клавиши в противоположное состояние
                call    key_SwitchLed
                jmp     @@exit
         
            ; сюда попадают все остальные коды расширенной/доп. клавиатуры
            @@unccode:
                xor     al, al          ; обнуляем код ascii-символа
                jmp     @@savecode      ; и сохраняем скэн-код в буфер
         
          ; пришел код отжатия клавиши (в регистре AL), уточняем какой
          key_Release:
                test    Status[1], E0
                jnz     @@isrshift      ; <- пропускаем код E0h,AAh(2ah+80h)
                mov     dh, not LSHIFT
                cmp     al, 2ah+80h     ; отжат левый Shift?
                je      @@islang
            @@isrshift:
                mov     dh, not RSHIFT
                cmp     al, 36h+80h     ; отжат правый Shift?
                je      @@islang
                mov     dh, not LCONTROL
                cmp     al, 1dh+80h     ; отжат Ctrl?
                je      @@isrightup
                mov     dh, not LALT
                cmp     al, 38h+80h     ; отжат Alt?
                jne     @@doneup
            @@isrightup:
                test    Status[1], E0   ; если предыдущий код был E0h
                jz      @@islang        ; то это правый Ctrl/Alt
                rol     dh, 1           ; сдвигаем бит влево (делаем клавишу правой)
            @@islang:
                ; проверяем на наличие переключения раскладки клавиатуры (Rus/Eng)
                and     al, 7fh         ; сбрасываем бит отжатия клавиши
                cmp     al, LangSwitch[0]
                jne     @@saveup
                mov     al, LangSwitch[1]
                and     al, Status[0]
                cmp     al, LangSwitch[1]
                jne     @@saveup
                xor     Status[1], RUSLAT
                call    key_SetBorder   ; отмечаем текущий режим цветом бордюра
            @@saveup:
                and     Status[0], dh   ; убираем бит нажатия клавиши
            @@doneup:
                retn
        key_Handler endp
         
         
        ; изменяет регистр букв (строчные/прописные) в регистре AL
        key_ChangeReg proc
                cmp     al, 'ё'
                ja      @@done
                cmp     al, 'Ё'
                jb      @@next
                xor     al, 1
                ret
            @@next:
                cmp     al, 'р'
                jae     @@50
                cmp     al, 'п'
                ja      @@done
                cmp     al, 'а'
                jae     @@20
                cmp     al, 'Р'
                jae     @@50
                cmp     al, 'А'
                jae     @@20
                cmp     al, 'z'
                ja      @@done
                cmp     al, 'a'
                jae     @@20
                cmp     al,'Z'
                ja      @@done
                cmp     al,'A'
                jae     @@20
            @@done:
                ret
            @@50:
                xor     al, 50h
            @@20:
                xor     al, 20h
                ret
        key_ChangeReg endp
         
         
        ; зажигает/гасит светодиоды
        key_SwitchLed proc
          uses ax
                call    key_Wait8042In  ; ждем готовности входного буфера клавиатуры
                mov     al, 0edh        ; команда установки светодиодов
                out     60h, al
                call    key_Wait8042In
                mov     al, Status[1]
                shr     al, 8-3         ; выделяем биты, отвечающие за состояние светодиодов
                out     60h, al
                ret
        key_SwitchLed endp
         
         
        ; устанавливает цвет бордюра экрана, в зависимости от текущей раскладки (Rus/Eng)
        key_SetBorder proc
          uses dx, ax
                mov     dx, 3dah        ; очищаем индекс регистра 3c0h
                in      al, dx
                mov     dx, 3c0h
                mov     al, 31h
                out     dx, al
                mov     al, Status[1]
                and     al, RUSLAT
                out     dx, al
                ret
        key_SetBorder endp
         
         
        ; ожидает готовности входного буфера i8042
        ; на выходе:
        ;     флаг ZF:  0 - ошибка тайм-аута
        ;               1 - все ок, буфер свободен
        key_Wait8042In proc
          uses cx
                or      cx, -1          ; защита от зацикливания
            @@waitin:
                in      al, 64h         ; читаем регистр состояния клавиатуры
                test    al, 10b         ; буфер 8042 свободен?
                loopnz  @@waitin
                ret
        key_Wait8042In endp
         
         
        ; ожидает готовности выходного буфера i8042
        ; на выходе:
        ;     флаг ZF:  1 - ошибка тайм-аута
        ;               0 - все ок, буфер свободен
        key_Wait8042Out proc
          uses cx
                or      cx, -1          ; защита от зацикливания
            @@waitout:
                in      al, 64h         ; читаем регистр состояния клавиатуры
                test    al, 1b          ; буфер 8042 свободен?
                loopz   @@waitout
                ret
        key_Wait8042Out endp
         
         
        ; добавляет очередной символ и его скэн-код в очередь буфера драйвера клавиатуры
        ; на входе:
        ;       al      - ASCII символ или 0
        ;       ah      - скэн-код
        key_Put proc
          uses bx, dx
                cli                     ; нас нельзя прерывать :)
                mov     bx, [buf_tail]
                mov     dx, bx
                inc     dx              ; dx - следующая позиция в буфере
                cmp     dx, buf_end     ; нет ли выхода за пределы буфера?
                jb      @@isover
                xor     dx, dx          ; вышли, переходим в его начало
            @@isover:
                shl     bx, 1           ; bx = bx*2
                cmp     dx, [buf_head]  ; есть ли место в буфере?
                je      @@overflow
                mov     buf_code[bx], ax; пересылаем в буфер
                mov     [buf_tail], dx  ; сохраняем новую позицию
                sti
                ret
            @@overflow: ; произошло переполнение буфера, символ будет потерян
                sti
                ret
        key_Put endp
         
         
        ; чтение символа и его скэн-кода из буфера клавиатуры
        ; на выходе:
        ;       флаг ZF - 0, если символ считан
        ;               - 1, если буфер пуст
        ;       al      - ASCII символ или 0 (при ZF=0)
        ;       ah      - скэн-код (при ZF=0)
        key_Get proc
          uses bx, dx
                cli                     ; нас нельзя прерывать :)
                mov     bx, [buf_head]
                mov     dx, bx
                cmp     bx, [buf_tail]  ; буфер пуст?
                je      @@empty         ; <-- да
                ; извлекаем очередной символ и его скэн-код
                shl     bx, 1           ; bx = bx*2
                inc     dx              ; dx - следующая позиция в буфере
                mov     ax, buf_code[bx]; получаем очередной символ и скэн-код
                cmp     dx, buf_end     ; нет ли выхода за пределы буфера?
                jb      @@save
                xor     dx, dx          ; был, переходим в начало буфера
            @@save:
                mov     [buf_head], dx
                or      ax, ax          ; сбрасываем флаг ZF
                sti
                ret
            @@empty:                    ; буфер пуст, возвращаем взведенный флаг ZF
                sti
                ret
        key_Get endp
         
         
        ; чтение флагов состояния регистровых клавиш
        ; на выходе:
        ;       al      - флаг регистровых клавиш
        ;       ah      - флаг состояния драйвера и светодиодов
        key_Status proc
                mov     al, Status[0]
                mov     ah, Status[1]
                ret
        key_Status endp
         
         
         
        ; инициализирует внутренние переменные и устанавливает свой обработчик прерываний клавиатуры
        key_Install proc
          uses ax, es
                xor     ax, ax
                mov     es, ax          ; es - сегмент данных BIOS
                ; инициализируем переменные
                mov     Status[0], al
                mov     Status[1], al
                mov     [buf_head], ax
                mov     [buf_tail], ax
                ; сохраняем статус светодиодов
                mov     al, es: [417h]
                mov     [oldLed], al
                ; гасим светодиоды
                call    key_SwitchLed
                ; сохраняем прежний вектор обработчика прерывания клавиатуры
                cli
                mov     ax, es: [9*4]   ; IRQ 1 аппаратно накладывается на 9-й вектор
                mov     [oldOfsIRQ1], ax
                mov     ax, es: [9*4+2]
                mov     [oldSegIRQ1], ax
                ; устанавливаем свой
                mov     ax, offset key_Handler
                mov     es: [9*4], ax
                mov     es: [9*4+2], cs
                sti
                ret
        key_Install endp
         
         
        ; восстанавливает прежний обработчик прерываний клавиатуры
        key_Uninstall proc
          uses ax, es
                ; восстанавливаем IRQ
                cli
                xor     ax, ax
                mov     es, ax          ; es - сегмент данных BIOS
                mov     ax, [oldOfsIRQ1]
                mov     es: [9*4], ax
                mov     ax, [oldSegIRQ1]
                mov     es: [9*4+2], ax
                sti
                ; восстанавливаем состояние светодиодов
                mov     al, [oldLed]
                shl     al, 1
                mov     Status[1], al
                call    key_SwitchLed
                ret
        key_Uninstall endp
         
        end

      Компилируется так:
      ExpandedWrap disabled
        tasm /m3 key.asm

      В аттаче таблица скан-кодов, а так же небольшой пример - установка временных характеристик клавиатуры.
      Особая благодарность 7in X, за предоставленные сорсы, которые навели на пару интересных идей, по реализации драйвера.
      Прикреплённый файлПрикреплённый файлKEYDRV.ZIP (14.86 Кбайт, скачиваний: 478)
        Добрый день!

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

        Мне кажется, что это из-за модели памяти TINY в модулях на асме. И там нужно указать LARGE.
        Но если изменить модель памяти, то tasm начинает ругаться:

        (первые 4 ошибки - указывают на место описания таблицы перекодировки скан кодов)
        **Error** key.asm(44) CS unreachable from current segment
        **Error** key.asm(52) CS unreachable from current segment
        **Error** key.asm(60) CS unreachable from current segment
        **Error** key.asm(68) CS unreachable from current segment
        **Error** key.asm(139) Relative jump out of range by O002h bytes
        **Error** key.asm(146) Relative jump out of range by O002h bytes
        (последние две - на джампы в процедуре key_Handler)

        Подскажите, пожалуйста, что нужно поменять в коде обработчика, если изменять модель памяти на large?

        Или может нужно в Паскале по-другому объявлять процедуры? (я пробовал указывать near; - не помогло... Покажите, пожалуйста, как нужно правильно объявить в Паскале все PUBLIC процедуры из этого обработчика...)
        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
        0 пользователей:


        Рейтинг@Mail.ru
        [ Script Execution time: 0,1304 ]   [ 17 queries used ]   [ Generated: 19.01.18, 17:46 GMT ]