В моём случае был <<Ой>>, точнее даже <<йОп>> =((( попробую в цикле писать много, авось дёрнется. Хотя хотелось бы более чёткие указания...
Аналогично. Может я что не так делаю? Может надо на сях через inb и outb? Может, для начала, сделать это с прявязкой к ОС? Я иссяк =( Но ведь пишут же как-то люди...
Я код использую приведённый выше, ну если вы настаиваете Код (Text): _asm { push dx push ax // E Down mov al, 0d2h out 64h, al mov dl, 30h mov al, dl out 60h, al //E Up mov al, 0d2h out 64h, al mov dl, 30h add dl, 80h mov al, dl out 60h, al pop ax pop dx } Эксперименты провожу на WinPXsp2 (соответственно вызываю код из нулевого кольца). Выход в нулевое кольцо взял в гугле, его тоже надо приводить? P.S. Как только задача будет решена для XP меня заставят её делать для *NIX, вот по этому очень хочется порты, хотя может вы посоветуете что-то другое.
Было упоминание С, кроме того было интересно именно оформление вызова. Нет, но его работоспособность/глюки тоже могут влиять. Теперь по сути кода. Самое главное - не вижу ожиданий готовности 8042. Вы ему пихаете в глотку до того, как он что-то успевает прожевать. Это не Xeon, а гораздо более медленная железяка. Именно поэтому я настаивал. В том коде, кстати, задержки были хотя бы упомянуты ("ждать"). Код (Text): mov dl, 30h mov al, dl out 60h, al Зачем через dl? Код (Text): push dx push ax ... pop ax pop dx Это все как компилируется? Как 32 бита? Тогда почему сохраняем только 16 бит? Нет, работать будет в любом случае. Просто непонятно.
Vic3Dexe, полностью с Вами согласен, код странный, просто не мой. Я уже перепробовал по всякому, и ждать готовности только перед посылкой 0D2h и перед каждой операцией с портом, результат всегда одинаковый. Режим 32 бита, собираю из консоли <<cl>>. Вечером приведу код выхода в нулевое кольцо и вариант с задержками. Спасибо что всë ещë это читаете.
Без обид, но частично дело в этом. Копипаст до добра не доводит Код не странный, он вполне себе, но недописаный явно. Еще, нужны не просто задержки (особенно умиляют задержки циклом времен 8086), а ожидание готовности (IBF, OBF): Код (Text): ReadyR: in al,64h test al,1 jz ReadyR ;можно читать из 0060h (OBF=1, в выходном буфере 8042 есть данные) Код (Text): ReadyW: in al,64h test al,2 jnz ReadyW ;можно писать в 0060h (IBF=0, входной буфер 8042 свободен) Ессно, если что-то пойдет не так, тут мы и повесимся, поэтому нуно прикрутить какой-нить таймаут. Не надо, в нем все равно никто не будет разбираться, речь вообще не о нем. Рекомендую взять qemu, повесить на него дос, и из-под доса пробовать (учитывая, что в qemu есть встроенный дебужник, которым можно смотреть регистры, память и т.п. - вообще сказка), а уже потом переносить на 0 кольцо.
Да, и еще. Надеюсь, есть понимание, что 0 кольцо<>DOS? А то вспомнил, что вы пытались там что-то с инт16 делать...
Я тоже копаюсь с клавой, в других ветвях этого форума нашел ответы на поставленный в данной теме вопрос, проверил все работает как часы. Являюсь полностью зеленым в Ассемблере, пытался докопаться что работает и как, не мог бы кто нибудь помочь и подкорректировать мои коменты? Вот код. Код (Text): _asm { pusha ;пишет что-то в регистр ax ? cli ;отключает прерывание? mov dl, key ;в регистр дл записывает значения аргумента, чтоб протом ;его передать через out? почему нельзя сразу там это сделать? mov ecx,10000h ;счетчик для цикла, будет уменьшаться WaitWhlFull: in al, 64h ;смотрим в нужный порт test al, 1 ;пока первый бит равен 1 - продолжаем цикл loopnz WaitWhlFull ;цикл от метки WaitWhlFull: , каждый раз уменьшает есх пока аl = 1 или есх=0 mov ecx,10000h ;сбрасывает счеткик TstCmdPortLp1: in al, 64h test al, 2 ;пока второй бит равен 1 ( 1 0 ) - продолжаем цикл loopnz TstCmdPortLp1 ;порт готов принимать информацию, пишем в порт mov al, 0d2h out 64h, al ;пишем значение al в нужный порт микроконтроллера - метку о том, что работает кейборд mov ecx,10000h TstCmdPortLp2: in al, 64h test al, 2 ;2 потому что 0d2h? loopnz TstCmdPortLp2 ; ждем пока информация поступит в порт? mov al, dl out 60h, al ;пишем значение сканкода кнопки sti ;запрещает прерывание popa ;неясно мне) выбирает значение из стека? } в данный момент я копаюсь с мышкой. Насколько я знаю вместо 0d2h надо вводить 0d3h, и посылать 4 байта сразу (если мышь с колесиком), по очереди? Инфы нашел в инете крайне мало. Первый байт несет инфу о кликах второй и третий о движении и четвертый о колесике. Мне нужен только первый. Никто не подскажет как корректно это сделать? Кроме 0d3h не надо тест проверки изменять?
Andrej По работе отдельных команд читаем IA-32 SDM (качается с сайта интела, ВСЕ команды подробно описаны в томах 2А, 2В). Если читать лень - http://wasm.ru/forum/viewforum.php?id=23 - раздел для начинающих. По работе клавы: - "2 потому что 0d2h?" - нет, см. выше, я приводил код, там видно что проверяется в 64 порту и зачем. - "пишем значение al в нужный порт микроконтроллера - метку о том, что работает кейборд" - сами-то поняли, что написали? Я нет. - "ждем пока информация поступит в порт?" - ждем пока 8042 прожует команду и будет готов принять для нее данные. Из написанного текста и комментариев, кстати, абсолютно неясно, что вы пытаетесь сделать.
Цель моих пытаний - корректно сэмулировать нажатие мышки. Я нашел код который может заинтересовать автора темы, и который, я так понял, тоже не является профессионалом в ассемблере. Решил код закомментировать, но у меня мало компетенции для этого. В комментариях просто попытка разобраться что к чему ... теперь мне ясно что независимо от того, какая была команда 0d2h или 0d3h проверка на то можно ли писать в 60h (test al, 2) (прожевал ли 64h свою команду) не изменяется. Если просто заменить команду 0d2h на 0d3h и посылать сканкоды мышки - то мышь заклинивает. Если посылать по очереди несколько команд то мышка подвисает периодически но все равно сама ниче не делает, а еще клавиатурные светодиоды иногда мигают ... по-идее мышка посылает Несколько пакетов по очереди и они все вместе описывают состояние мышки. Посылает туда же, в кеборд контроллер 8042. А еще вычитал вот здесь http://ftp.utcluj.ro/pub/users/cemil/asm/CH20.pdf, что есть команда 0d4h - "Writes the next data byte (60h) to the mouse (auxiliary) device". Первое, что приходит на ум - первый байт писать после команды 0d3h, а потом еще два (или три если мышь с колесиком) после команды 0d4h. А может все писать после 0d4h? Может кто знает что к чему? Просто для меня все это необычно, так как мало опыта (я имею хороший опыт только в c++), и может я просто не понимаю элементарных принятых алгоритмов, а кому-то здесь "все и так ясно". Вечером, как вернусь с работы попробую реализовать эти свои две гипотезы ...
Дело не в опыте в ассемблере, асм - это инструмент, и, как и любой другой, постигается чтением мануала на него (IA-32 SDM). Решение же данной задачи к познаниям в асме не имеет ни малейшего отношения, т.к. нужно знать не асм, а работу связки 8042-клава-мышь (опять же, читаем спецификации). Короче говоря, отделяем алгоритм от его реализации и не путаем их. =) Также неплохо знать буржуйский, т.к. вот это вот отправит засунутый в 60 порт байт прямиком в мышЪ (ну или любой внешний девайс, воткнутый в мышиный порт). Оно ей (мыши) надо? Конкретно же по эмуляции действий мыши не подскажу, до работы с сим девайсом пока выше int 33h не поднялся (за ненадобностью). В качестве идеи могу посоветовать проанализировать посылки реальной мыши, а затем эмулировать их, предварительно вырубив настоящую (программно).
Vic3Dexe Дополню - это осуществляется перехватом векторов обработки прерываний мыши. Andrej Желательно вообще написать свои процедуры обработки. Полностью. Потом вызывая их вручную, получите эмуляцию. За одно поймете всю соль. Да, делать все это желательно в DOS (для образовательных целей). А так же попутно почитывая Кулакова "Программирование на аппаратном уровне". Про то как работают мышки. Для начала будет более чем достаточно.
ребят clotho и Andrej, с одной строны могу помочь, с другой лень и некогда отписывать и описывать... поэтому принял решение дать Вам готовые сорцы из своего проектика ОСи. То что Вы сейчас разгребаете интересное, полезное и трудное занятие требуещее кропотливости работы с устройствами + аккуратное. Сам прошёл десятки ребутов при оседлании KBC. Отлаживал и познавал под досом, чего и Вам желаю + маны вкуривать строго обязательно. Обязательно нужно усвоить, что клава и мышь для Вас это один и тот же KBC, вычитывание данных ИЗ которого вне зависимости клавные дела это или мышиные ПЕРВО-НАПЕРВО! Это собственно и есть готовность принимать Ваши приказы, т.к. вычитка порта 0x60 (и порой неоднократная!) дает возможность сразу засылать спецкоманды из манов.... Короче вместо того чтобы пухнуть мозгами от ваших ваяний :0) попотейте Вы ))) но от рабочего и комментированного сурса 3-х обработчиков IRQ 0, 1, 12. Здесь Вам много лишнего может показаться, но дошедший мозгом до конца вкусит истинный дзен, факт! Рекомендую вкусить, хотябы находя ОТВЕТЫ на свои вопросы + пытливость типа "нафига именно так", поможет приподнять завесу над нюанасами. Рекомендую создать мониторинговую ДОСовкую прожку с этими инклудами и юзаньем ИМЕННО 3-х обработчиков в ней, НЕ советую отказываться от этого, т.к. несмотря на то, что они (т.е. именно все 3) работают в асинхронном временном так сказать континиуме, они выполняют ряд аппаратно-программных задач и фич, включая, например, перезапуск клавы, мыши, обслуга светодиодов клавы, чувствование смены мыши PS/2 на ходу (брехни что НЕЛЬЗЯ этого делать доказательство сии сорцы), вычитка ID мыши.... моного чего творил с ними лет 5 назад. При использовании в своих разработках ссылки на автора джентльменски приветствуются! Конечно там завязки на структурки имеются, но пытливым это не помеха, маны курить (знать) все одно надо... Итак, погнали. Таймерное, оно же системное у меня тюкает с частотой 1000Гц а не 18,2.... ну типа нУнА так и всё Код (Text): ALIGN 4 IRQ_0: ; Системный таймер push ds push es pushad mov eax, 0x20 ;сигнал EOI mov edx, eax out dx, al mov eax, SYS_VAR mov ds, ax mov es, ax inc [iTMR0.Cnt1000Hz] ;---------------------------------------------------------- ; проверка Буфера Клавиатуры mov eax, [iKBD.HeadBuffWR] ; mov edx, [iKBD.HeadBuffRD] ; cmp eax, edx ; je @emptyBuffKBD mov eax, [edx] ; взять код символа из буфера клавиатуры add edx, 4 cmp edx, iKBD.EndBuff jc @notEndBuffKBD mov edx, iKBD.StartBuff @notEndBuffKBD: mov [iKBD.HeadBuffRD], edx ; символ из буфера клавиатуры взят в EAX cmp al, 0x1B ; = ESC = REBOOT !!!! jne @sysk mov al, 0xFE out 0x64, al jmp @qqirq1 @sysk: cmp al, "1" jne @1 push eax mov eax, Melody1 jmp @pMel @1: cmp al, "2" jne @2 push eax mov eax, Melody2 jmp @pMel @2: cmp al, "3" jne @3 mov eax, Melody3 push eax jmp @pMel @3: cmp al, "4" jne @4 push eax mov eax, Melody4 jmp @pMel @4: cmp al, "5" jne @5 push eax mov eax, Melody5 jmp @pMel @5: cmp al, "6" jne @6 push eax mov eax, Melody6 jmp @pMel @6: cmp al, "7" jne @7 push eax mov eax, Melody7 jmp @pMel @7: cmp al, "8" jne @8 push eax mov eax, Melody8 jmp @pMel @8: cmp al, "9" jne @9 push eax mov eax, Melody9 jmp @pMel @9: cmp al, "0" jne @10 push eax mov eax, Melody10 @pMel: mov bx, SYS_TXT_RING0 call SetNewLineNotes pop eax jmp @qqirq1 @10: cmp al, " " jne @qqirq1 push eax call StopNote pop eax ; mov edi, 0x18A00 ; mov ax, cs ; call printHexDword ; add edi, 2 ; mov eax, @@1 ; call printHexDword ; add edi, 2 ; pushfd ; pop eax ; call printHexDword ; mov eax, 0x01020304 ; xor ebx, ebx ; div ebx ;@@1: ; mov es, bx ; mov [es:0], al ; jmp @qqirq1 ;;;;;;;;;;;;;;;;;;;;;;;; @qqirq1: mov edi, 0x18140 call printHexDword @emptyBuffKBD: ;---------------------------------------------------------- mov ebp, [iTMR0.Cnt1000Hz] ; выполнение следущих процедур по такту 1000 Гц call @TickTimer0 ;---------------------------------------------------------- dec [iTMR0.Cnt4Hz] jne @restMousePS2 ; получаем тут периодичность входа 4 раза в секунду ; проверка флагов и пошаговая подготовка реинициализации клавиатуры dec [iKBD.CntStatCnct] ; уменьшим счетчик-флаг отключения клавиатуры mov ebx, [iKBD.CntStatCnct] ; уменьшим счетчик-флаг отключения клавиатуры jne @stp2RestKBD @repRestKBD: mov [iKBD.CntStatCnct], Cnt1RestKBD ; общий счетчик процесса рестарта клавиатуры mov dword [iKBD.ByteID], 0x020000FF ; активация ловушки ID байт mov [iKBD.HeadBuffWR], iKBD.StartBuff ; инициализация циклического буфера клавиатуры mov [iKBD.HeadBuffRD], iKBD.StartBuff mov ax, 0x64AD ; выключим клавиатуру и ее прерывания jmp @AddNewCmdKBC @stp2RestKBD: cmp ebx, Cnt2RestKBD jne @stp3RestKBD mov ax, 0x64AE ; включим клавиатуру и ее прерывания в KBC call AddNewCmdKBC ; поместим в очередь команду mov ax, 0x60FF ; сброс клавиатуры jmp @AddNewCmdKBC @stp3RestKBD: cmp ebx, Cnt3RestKBD jne @stp4RestKBD mov word [iKBD.ByteID], 0x00FF ; активация ловушки ID байт mov ax, 0x60F4 ; код команды включения клавиатуры call AddNewCmdKBC ; поместим в очередь команду mov al, [iKBD.StatSwitch] ; восстановим текущее рабочее состояние светодиодной индикации клавиатуры call SetLEDsKBD jmp @nonNewTaskKBC @stp4RestKBD: cmp ebx, Cnt4RestKBD jne @echoKBD cmp [iKBD.PrefixCode], 0 ; клавиатура уже отвечает ? je @repRestKBD ; Нет, повторить сброс mov ax, 0x60F3 ; код команды установки параметров клавиатуры call AddNewCmdKBC mov al, [iKBD.Setting] ; загрузим текущие установки параметров клавиатуры and al, 0x7F ; бит 7 = 0 call AddNewCmdKBC ; поместим в очередь команду mov ax, 0x60F2 ; код команды чтения ID байт клавиатуры jmp @AddNewCmdKBC @echoKBD: cmp ebx, CntEchoKBD jnc @nonNewTaskKBC mov ax, 0x60EE ; коды порта и команды эха клавиатуры jmp @AddNewCmdKBC ;---------------------------------------------------------- ; проверка флагов и пошаговая подготовка реинициализации Mouse PS/2 @restMousePS2: cmp [iTMR0.Cnt4Hz], 0x80 jne @nonNewTaskKBC dec [iMOUSE_PS2.StatCnct] mov ebx,[iMOUSE_PS2.StatCnct] jne @stpReset0MousePS2 mov [iMOUSE_PS2.StatCnct], CntRestMouse mov [iMOUSE_PS2.CntNxtReset], CntResetMouse mov [iMOUSE_PS2.PozNxtTstRate], dword iMOUSE_PS2.LineTstRate mov [iMOUSE_PS2.HeadBuff], dword iMOUSE_PS2.ReciveDump ; голову указателя буфера в начало mov [iMOUSE_PS2.WaitByteID], 0xFF mov [iMOUSE_PS2.ByteID], 0xFF mov [iMOUSE_PS2.CntPacket], 0 mov ax, 0x64A7 ; выключим мышь call AddNewCmdKBC ; поместим в очередь команду inc eax ;= 0x64A8 включим мышь jmp @AddNewCmdKBC @stpReset0MousePS2: cmp ebx, [iMOUSE_PS2.CntNxtReset] jne @stpNxtNumRateMousePS2 @stpReset1MousePS2: mov [iMOUSE_PS2.WaitByteID], 0xFF mov [iMOUSE_PS2.ByteID], 0xFF mov [iMOUSE_PS2.CntPacket], 0 mov [iMOUSE_PS2.LenPacket], 0 mov ax, 0x64D4 call AddNewCmdKBC mov ax, 0x60FF ; dec ebx @IncNumRate: dec ebx mov [iMOUSE_PS2.CntNumRate], ebx jmp @AddNewCmdKBC @stpNxtNumRateMousePS2: cmp ebx, [iMOUSE_PS2.CntNumRate] jne @stpSettingMousePS2 mov ax, 0x64D4 call AddNewCmdKBC mov ax, 0x60F3 call AddNewCmdKBC mov ax, 0x64D4 call AddNewCmdKBC mov esi, [iMOUSE_PS2.PozNxtTstRate] mov ax, [esi] inc esi cmp ah, 0xFE jne @pokeNewRate inc esi mov ah, [esi] inc esi mov [iMOUSE_PS2.WaitByteID], ah ; ожидаемый байт ID от мыши mov [iMOUSE_PS2.StatCnct], Cnt0SettingMouse + 1 cmp byte [esi], 0 je @endTabRate dec [iMOUSE_PS2.StatCnct] ; = Cnt0SettingMouse @endTabRate: inc ebx mov [iMOUSE_PS2.CntNxtReset], ebx @pokeNewRate: mov [iMOUSE_PS2.PozNxtTstRate], esi mov ah, 0x60 jmp @IncNumRate @stpSettingMousePS2: cmp ebx, Cnt0SettingMouse je @pokeSetting cmp ebx, Cnt1ReadIDmouse je @pokeCmdReadIDmousePS2 cmp ebx, Cnt1SettingMouse jne @stpReadIDmousePS2 mov al, [iMOUSE_PS2.ByteID] cmp al, [iMOUSE_PS2.WaitByteID] je @pokeSetting mov ebx, [iMOUSE_PS2.CntNxtReset] mov [iMOUSE_PS2.StatCnct], ebx jmp @stpReset1MousePS2 @pokeSetting: mov ax, 0x64D4 call AddNewCmdKBC mov ax, 0x60F5 call AddNewCmdKBC mov ax, 0x64D4 call AddNewCmdKBC mov ax, 0x60E8 call AddNewCmdKBC mov ax, 0x64D4 call AddNewCmdKBC mov ah, 0x60 mov al, [iMOUSE_PS2.Setting] ; 8 count/mm push eax and al, 3 call AddNewCmdKBC mov ax, 0x64D4 call AddNewCmdKBC pop eax shr al, 2 and al, 1 or al, 0xE6 ; = 0x60E7 = 2:1 call AddNewCmdKBC mov ax, 0x64D4 call AddNewCmdKBC mov ax, 0x60F3 call AddNewCmdKBC mov ax, 0x64D4 call AddNewCmdKBC mov ah, 0x60 mov al, [iMOUSE_PS2.UserRate] mov [iMOUSE_PS2.StatCnct], Cnt2ReadIDmouse jmp @AddNewCmdKBC @stpReadIDmousePS2: cmp ebx, Cnt2ReadIDmouse jnc @nonNewTaskKBC @pokeCmdReadIDmousePS2: mov ax, 0x64D4 call AddNewCmdKBC mov ax, 0x60F4 call AddNewCmdKBC mov ax, 0x64D4 call AddNewCmdKBC mov ax, 0x60F2 mov [iMOUSE_PS2.ByteID], al ; = 0xF2 @AddNewCmdKBC: call AddNewCmdKBC @nonNewTaskKBC: ;---------------------------------------------------------- ; разбор очереди команд контроллера клавиатуры-мыши PS/2 ;---------------------------------------------------------- mov bx, [iTMR0.FlagTskTmr] ; читаем флаги таймерных задач по такту 100Гц or bx, bx ; есть какие либо таймерные системные задачи ? je @nonCmdKBC ; Нет, переход по метке test bx, FlagCmdKBC ; есть задачи работы с командами для KBC клавиатуры и мыши PS/2 ? je @nonCmdKBC ; Нет, переход по метке mov esi, [iKBC.HeadCmdKBC] ; берем адрес головы строки команд in al, 0x64 ; читаем статус состояния контроллера клавиатуры и мыши PS/2 test al, 2 ; имеется ли готовность принять команды ? jne @nonCmdKBC ; Нет, переход по метке mov ax, [ esi ] ; берем в AX очередную команду, для выполнения cmp ax, 0x64D4 ; это команда назначена для мыши PS/2 ? jne @pokeCmdKBC cmp [iMOUSE_PS2.CntPacket], 0 ; мышь PS/2 генерирует информационный пакет ? jne @nonCmdKBC @pokeCmdKBC: xor dx, dx ; DX = 0 mov dl, ah ; DX = адрес порта вывода для команды(данных) (это 60h либо 64h) out dx, al ; поместим в порт контроллера AL байт cmp ax, 0x64AE ; требуется включить клавиатуру ? jne @non64AE in al, 0x21 and al, 0xFD out 0x21, al jmp @nxtStepCmdKBC @non64AE: cmp ax, 0x64AD ; требуется выключить клавиатуру ? jne @non64AD in al, 0x21 or al, 2 ; маскировать IRQ1 out 0x21, al jmp @nxtStepCmdKBC @non64AD: cmp ax, 0x64A8 ; требуется включить клавиатуру ? jne @non64A8 in al, 0xA1 and al, 0xEF out 0xA1, al jmp @nxtStepCmdKBC @non64A8: cmp ax, 0x64A7 jne @nxtStepCmdKBC in al, 0xA1 or al, 0x10 ; маскировать IRQ12 out 0xA1, al @nxtStepCmdKBC: add esi, 2 ; переместим указатель головы на следующий шаг очереди команд cmp esi, [iKBC.EndCmdKBC] ; следующая команда пустая т.е. очередь вычерпана ? jne @nonStepCmdKBC ; Нет, переход на сохранение текущего адреса головы очереди команд and [iTMR0.FlagTskTmr], not FlagCmdKBC ; сброс флага наличия команд клавиатуры и мыши PS/2 mov esi, iKBC.LineCmdKBC ; установка указателя головы в начальное состояние mov [iKBC.EndCmdKBC], esi ; сохранить текущий адрес головы строки команд @nonStepCmdKBC: mov [iKBC.HeadCmdKBC], esi ; сохранить текущий адрес головы строки команд @nonCmdKBC: ;---------------------------------------------------------- popad pop es pop ds IRET Клавка вкусняшка, между прочим Код (Text): ALIGN 4 IRQ_1: push ds push eax push ebx push edx xor eax, eax xor ebx, ebx in al, 0x60 ; читаем порт клавиатуры push eax mov eax, 0x20 mov edx, eax out dx, al mov eax, SYS_VAR mov ds, ax mov edx, iKBD.PrefixCode pop eax mov ah, al cmp [iKBD.ByteID], 0xFF ; > 0 ? ловушка используется ? je @waitID mov [iKBD.CntStatCnct], CntWatchDogKBD ; взводим антизависатор, т.к. клавиатура функционирует нормально! cmp al, 0xEE ; принят тестовый байт эха ? jnc @UpcodEE cmp byte [edx], 0xE1 ; это признак работы с кодами клавиши "Pause" ? je @DoKeyPause ; Да, переход на обработчик кодов "Pause" cmp byte [edx], 0xE0 ; это признак работы с 2x байтными кодами ? je @DoDoubleCode ; Да, переход на обработчик уникального второго байта cmp al, 0xE0 ; это первый байт 2х байтного кода клавиши ? je @SavePrefixCode ; Да, переход и фиксация байта 0xE0, как префикса-сигнатуры cmp al, 0xE1 ; это первый байт исключительных байт кода для "Pause" ? jne @nonFixCode ; Нет, переход дальше ; Да, переход и фиксация байта 0xE1 как префикса-сигнатуры этого исключения @SavePrefixCode: ; сохранение префикса mov [edx], al ; фиксируем код в [PrefixCode] jmp @nonUseCode @waitID: cmp byte [edx], 0xAB ; PrefixCode je @saveID cmp al, 0xAB ; это второй сигнатурный байт-префикс ? (перед ID байтами) je @SavePrefixCode cmp al, 0xFA ; принят байт эха клавиатуры ? je @SavePrefixCode jmp @nonUseCode ; код не используется вообще, выход! @saveID: mov [iKBD.ByteID], al ; запомним ID байт mov [edx], bl ; обнулим [PrefixCode] jmp @nonUseCode @UpcodEE: cmp al, 0xFE ; принят байт признака отключения клавиатуры ? jne @nonUseCode ; Нет, значит байт не использовать вообще mov [iKBD.ByteID], 0xFF ; = 0 активация ловушки ID байт mov [iKBD.CntStatCnct], 1 ; принудительно делаем реинициализацию клавиатуры jmp @nonUseCode ; код не используется вообще, выход! @DoKeyPause: cmp al, 0x45 ; нажатие "Pause" ? je @trfrmCodePause cmp al, 0xC5 ; отжатие "Pause" ? jne @nonUseCode @trfrmCodePause: mov [edx], bl ; установим [PrefixCode] = 0 -- признак однобайтного формата and al, 0x80 ; трансформация в эквивалентные коды 0x00/0x80 jmp @ReadCodeMap1 ; теперь работаем с символьными кодами таблицы перекодировки @DoDoubleCode: mov [edx], bl ; установим [PrefixCode] = 0 -- признак однобайтного формата inc edx ; теперь ESI указывает на [StatDopKeys] test al, 0x80 ; это нажатие? je @n1UPkey ; если да, переход mov [iKBD.LastSwKey], bl ; сброс фиксации кода последней нажатой доп-клавиши... @n1UPkey: and al, 0x7F ; удалим различие кодов нажития и отжатия (приравнивание) cmp al, 0x2A ; это обрамляющие байты 4х байтных посылок скан-кода ? je @nonUseCode ; если да, то код не используется вообще, выход! mov bl, CORR_TAB2 ; константа для коррекции и компактности прилегающих таблиц перекодировки скан-кодов 1й и 2й mov al, 8 ; AL = 8 как маска бита статуса для левого "WIN" cmp ah, 0x5B ; нажат ли левый "WIN" ? je @saveStByte cmp ah, 0xDB ; отжат ли левый "WIN" ? je @clrStByte mov al, 128 ; AL = 128 как маска бита статуса для правого "WIN" cmp ah, 0x5C ; нажат ли правый "WIN" ? je @saveStByte cmp ah, 0xDC ; отжат ли правый "WIN" ? je @clrStByte mov al, 32 ; AL = 32 как маска бита статуса для правого "CTRL" cmp ah, 0x52 ; это нажата клавиша "Insert" ? jne @chkDopKey mov al, 4 ; AL = 4 -- бит 4 в [StatSwitch] для "Insert" inc edx ; теперь ESI указывает на [StatSwitch] @chgStByte: ; изменим состояние переключателя cmp ah, [iKBD.LastSwKey] ; она уже нажата и в удержании? je @nonUseCode ; если да, то код не используется вообще, выход! mov [iKBD.LastSwKey], ah ; сброс фиксации кода последней нажатой доп-клавиши... push eax xor ah, ah btc word [edx], ax ; изменим на противоположное состояние бит номер AX в StatSwitch or byte [edx], 0x80 ; установим флаг изменения индикаторов LEDs pop eax jmp @ReadCodeMap1 ; теперь работаем с символьными кодами таблицы перекодировки @nonFixCode: ; значит это однобайтный скан-код, который в AH, а AL = 0 test ah, 0x80 je @n2UPkey mov [iKBD.LastSwKey], bl @n2UPkey: inc edx ; теперь ESI указывает на [StatDopKeys] inc eax ; AL = 1 как маска бита статуса для левого "SHIFT" cmp ah, 0x2A ; нажат ли левый "SHIFT" ? je @saveStByte cmp ah, 0xAA ; отжат ли левый "SHIFT" ? je @clrStByte mov al, 16 ; AL = 16 как маска бита статуса для правого "SHIFT" cmp ah, 0x36 ; нажат ли правый "SHIFT" ? je @saveStByte cmp ah, 0xB6 ; отжат ли правый "SHIFT" ? je @clrStByte mov al, 2 ; AL = 2 как маска бита статуса для левого "CTRL" @chkDopKey: cmp ah, 0x1D ; нажат ли какой либо "CTRL" ? je @saveStByte cmp ah, 0x9D ; отжат ли какой либо "CTRL" ? je @clrStByte add al, al cmp ah, 0x38 ; нажат ли какой либо "ALT" ? jne @nonDownALT @saveStByte: ; установка бита по маске в AL cmp ah, [iKBD.LastSwKey] je @nonUseCode mov [iKBD.LastSwKey], ah or byte [edx], al ; установим нужный бит статуса в StatDopKeys jmp @ReadCodeMap1 ; теперь работаем с символьными кодами таблицы перекодировки @clrStByte: ; сброс бита по маске в AL not al and byte [edx], al ; обнулим нужный бит статуса в StatDopKeys jmp @ReadCodeMap1 @nonDownALT: cmp ah, 0xB8 ; отжат ли какой либо "ALT" ? je @clrStByte ;............................. ; проверим нажатие и изменяем состояния статусов клавиш переключателей: ; "Scroll Lock", "Num Lock", "Caps Lock" ;............................. inc edx ; ESI указывает на байт состояния переключателей xor al, al ; AL = 0 -- бит 0 в [StatSwitch] cmp ah, 0x46 ; нажат ли "Scroll Lock" ? je @chgStByte inc eax ; AL = 1 -- бит 1 в [StatSwitch] cmp ah, 0x45 ; нажат ли "Num Lock" ? je @chgStByte inc eax ; AL = 3 -- бит 2 в [StatSwitch] cmp ah, 0x3A ; нажат ли "Caps Lock" ? je @chgStByte @ReadCodeMap1: ; собственно чтение кода клавиши из таблицы посредством смещения в AH=полученному скан-коду клавиатуры mov al, ah test [iKBD.Setting], 0x80 ; бит 7 установлен ? КЛИК используется ? je @nonCLICK cmp [iSPK.AdrLineNotes], 0 jne @nonCLICK test al, 0x80 ; это код нажатия ? jne @nonCLICK mov edx, [iSPK.AdrClicKEYs] mov [iSPK.AdrLineNotes], edx mov dx, [iSPK.SegClicKEYs] mov [iSPK.SegLineNotes], dx mov dword [iSPK.CntDelayNote], 1 @nonCLICK: push eax ; важно сохраненить AL and al, 0x7F ; обнуляем бит 7, погасив признак отжатия movzx eax, al ; EAX = смещение в таблице символьных кодов mov edx, iKBD.KEYsCodeMap ; ESI указывает на таблицу кодов для однобайтных скан-кодов клавиш add edx, eax ; ESI = адрес со смещением от начала на величину скан-кода add edx, ebx ; ESI = адрес с дополнительным смещением если скан-код был с началом 0xE0 pop eax ; восстановить AL not ax ; инвертировать биты AL and ax, 0x80 ; в AL выделяем 7й бит, будет = "1" при нажатой клавише or ax, word [iKBD.StatDopKeys] ; дополним статусами вспомогательных клавиш и переключателей btr word [iKBD.StatDopKeys], 15 ; было ли изменение переключателей ? jnc @nonChangeLEDs ; Нет, игнорируем новую установку LEDs cmp [iSPK.LedStat], byte 0 ; работает ли иллюминация клавиатуры ? jne @nonChangeLEDs ; Да, игнорируем новую индикацию LEDs mov ebx, [iKBC.EndCmdKBC] ; берем адрес конца строки команд mov [ebx], dword 0x600060ED ; помещаем в очередь команду и данные LEDs для выполнения контроллером клавиатуры mov [ebx+2], ah ; поместим статусы переключателей в очередь and [ebx+2], byte 7 ; обязательно обнулим лишние биты add [iKBC.EndCmdKBC], 4 ; новая позиция конца очереди команд or [iTMR0.FlagTskTmr], FlagCmdKBC ; выставим флаг обработки строки соманд клавиатуры @nonChangeLEDs: shl eax, 8 ; смещаем все биты вверх на байт mov al, [edx] ; читаем код клавиши по фактическому адресу таблицы ; AL = код клавиши ; AH - бит 7 нажатие/отжатие = "1"/"0" данной клавиши, ; биты 5..0 из [StateShiftCtrlAlt] т.е. статусы вспомогательных клавиш ; 24..16 биты EAX = [StateSwitchKBD] т.е. статусы переключателей mov edx, [iKBD.HeadBuffWR] mov [edx], eax ; помещаем в буффер новый код символа add edx, 4 cmp edx, iKBD.EndBuff jc @nonEndBuffKBD mov edx, iKBD.StartBuff @nonEndBuffKBD: mov [iKBD.HeadBuffWR], edx @nonUseCode: ; "ХОЛОСТОЙ" выход из процедуры pop edx pop ebx pop eax pop ds IRET Зверюга гызун живёт здесь Код (Text): ALIGN 4 IRQ_12: push ds pushad in al, 0x60 ; читаем из KBC очередной байт от мыши! push eax mov eax, 0x20 ; EIO mov edx, eax out 0xA0, al out dx, al mov eax, SYS_VAR mov ds, ax pop eax cmp [iMOUSE_PS2.CntPacket], 0 ; это начало нового пакета от мыши? (т.е. первый из трех?) jne @save ; нет, значит это продолжение приема пакета, только сохраняем cmp [iMOUSE_PS2.StatCnct], Cnt2ReadIDmouse + 1 jc @CheckByteID cmp [iMOUSE_PS2.StatCnct], CntWatchDogMouse + 1 jc @chkAskByte @CheckByteID: cmp al, 9 jnc @q cmp [iMOUSE_PS2.ByteID], 0xF2 jne @q mov [iMOUSE_PS2.ByteID], al cmp [iMOUSE_PS2.StatCnct], Cnt2ReadIDmouse jnc @q mov [iMOUSE_PS2.StatCnct], CntWatchDogMouse mov [iMOUSE_PS2.WaitByteID], al mov ah, 6 cmp al, 8 je @FixLenPacket mov ah, 4 cmp al, ah je @FixLenPacket cmp al, 3 je @FixLenPacket dec ah ; = 3 @FixLenPacket: mov [iMOUSE_PS2.LenPacket], ah jmp @q @chkAskByte: cmp al, 0xFA jne @qcmp ; это префикс-байт "служебного" ответа, игнорируем mov [iMOUSE_PS2.StatCnct], CntWatchDogMouse jmp @q @qcmp: jnc @q ;@firstByte: ; проверим структурку первого байта пакета на правильность ; и отсутствие переполнения счетчиков перемещения X и Y mov ah, al and ah, 0xC8 ; выделим биты переполнения и бит признака cmp ah, 8 ; "правильный" первый байт пакета теперь всегда должен быть = 8 jne @q ; иначе бракуем, считая ложным! ; очень вероятно что в AL "правильный" первый байт пакета от мыши mov dl, [iMOUSE_PS2.LenPacket] mov [iMOUSE_PS2.CntPacket], dl ; @save: mov [iMOUSE_PS2.StatCnct], CntWatchDogMouse mov edi, [iMOUSE_PS2.HeadBuff] ; возьмем текущий указатель mov [edi], al ; сохраним очередной принятый байт inc edi mov [iMOUSE_PS2.HeadBuff], edi ; сохраним новый указатель головы буфера dec [iMOUSE_PS2.CntPacket] ; уменьшим количество принятых пакета jne @q mov [iMOUSE_PS2.HeadBuff], dword iMOUSE_PS2.ReciveDump ; голову указателя буфера в начало ; выяснить статусы и координаты мыши mov esi, iMOUSE_PS2.ReciveDump ; начало буфера приема mov edi, iMOUSE_PS2.Buttons ; указатель на текущую координату X мыши xor eax, eax xor ebx, ebx mov al, [esi] ; возьмем первый байт пакета mov bl, [esi+3] ; возьмем четвертый байт пакета (колесо) cmp [iMOUSE_PS2.WaitByteID], 4 jne @noID4 mov ah, bl and bl, 0x0F ; выделить биты-параметры поворота колес and ah, 0x30 ; выделить статусы дополнительных двух кнопок jmp @memNewZ @noID4: cmp [iMOUSE_PS2.WaitByteID], 3 jne @saveButtons @memNewZ: mov [iMOUSE_PS2.Z], bx @saveButtons: inc esi mov bl, al ; сохраним оригинальное значение в BL and al, 0xF ; выделить статусы кнопок и бит признака or al, ah mov [edi], al ; сохранить статусы кнопок в [Buttons] inc edi xor eax, eax mov al, [esi] ; взять 8 бит счетчика приращения X inc esi or al, al ; имеется изменение по оси X ? je @calcMouseY ; если нет, то перейдем к разбору по Y ; определим новую X позицию мыши mov bp, [edi] ; возьмем в BP текущую координату из [_X_Mouse] mov dx, word [iMOUSE_PS2.X_Zoom] ; взять масштабный коэффициент мыши по X test bl, 0x10 ; каков знак X приращения ? je @pozitivX ; преход по метке, если положительный not al ; т.к. негативное перемещение инвертируем величину приращения inc ax ; корреккция на 1 mul dl ; учтем масштабный коэффициент перемещения по X xchg ax, bp ; развернули для удобства действий sub ax, bp ; вычтем и получим новую координату X jnc @memNewX ; перебор за ноль ? xor ax, ax ; это так, поэтому делаем X = 0 @memNewX: mov [edi], ax ; сохранить новую координату в [_X_Mouse] add edi, 2 jmp @calcMouseY ; перейдем к определению Y координаты @pozitivX: mul dl ; учтем масштабный коэффициент перемещения по X add ax, bp ; прирастим и получим новую координату X cmp ax, [iSCREEN.With] ; нет ли теперь выхода за правую границу экрана? jc @memNewX ; если нет, то переход на сохранение нового значения X add edi, 2 ; ничего не сохраняем, т.к. текущая координата X мыши уже на краю экрана, просто корректировка указателя ; определим новую Y позицию мыши @calcMouseY: xor ax, ax mov al, [esi] ; взять 8 бит счетчика приращения Y inc esi or al, al ; имеется изменение по оси Y ? je @calcRET ; если нет, то обходим разбор Y ; тут EDI уже указывает на координату [_Y_Mouse] mov bp, [edi] ; возьмем в BP текущую координату из [_Y_Mouse] test bl, 0x20 ; каков знак Y приращения? je @pozitivY not al ; т.к. негативное перемещение инвертируем величину приращения inc ax ; корреккция на 1 mul dh ; учтем масштабный коэффициент перемещения по Y add ax, bp ; увеличим Y, т.к. эта ось "смотрит" вниз cmp ax, [iSCREEN.High] ; нет ли теперь выхода за нижнюю границу экрана? jc @memNewY ; если нет, то переход на сохранение нового значения Y add edi, 2 ; ничего не сохраняем, т.к. текущая координата Y мыши уже на нижнем краю экрана, просто корректировка указателя jmp @calcRET @pozitivY: mul dh ; учтем масштабный коэффициент перемещения по Y xchg ax, bp ; развернули для удобства действий sub ax, bp ; вычтем и получим новую координату Y jnc @memNewY ; перебор за ноль ? xor ax, ax ; это так, поэтому делаем Y = 0 @memNewY: mov [edi], ax ; сохранить новую координату в [_Y_Mouse] add edi, 2 @calcRET: @q: mov ax, 0x20 ; EIO out 0xA0, al mov dx, ax out dx, al popad pop ds IRET довесочек Код (Text): ALIGN 4 SetLEDsKBD: push eax mov ax, 0x60ED call AddNewCmdKBC pop eax and al, 7 mov ah, 0x60 AddNewCmdKBC: mov edx, [iKBC.EndCmdKBC] ; берем адрес головы строки команд cmp edx, iKBC.EndLineCmd-2 ; очередь заполнена до конца ? jnc @retAddNewCmdKBC mov [edx], ax ; помещаем в очередь новую команду для выполнения add [iKBC.EndCmdKBC], 2 ; переместим указатель головы or [iTMR0.FlagTskTmr], FlagCmdKBC ; выставим флаг обработки строки соманд клавиатуры @retAddNewCmdKBC: RET Курились следующие маны (подборка) doc.rar Непременно радостных Успехов! ;o)