]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/MEMM/MEMM/KBD.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / MEMM / MEMM / KBD.ASM
1
2
3 page 58,132
4 ;******************************************************************************
5 title KBD.ASM - - protected mode AT keyboard driver
6 ;******************************************************************************
7 ;
8 ; (C) Copyright MICROSOFT Corp. 1986
9 ;
10 ; Title: MEMMD.EXE - MICROSOFT Expanded Memory Manager 386 DEBUG Driver
11 ;
12 ; Module: KBD.ASM - - protected mode AT keyboard driver for debugger
13 ;
14 ; Version: 0.04
15 ;
16 ; Date: January 31, 1986
17 ;
18 ; Author:
19 ;
20 ;******************************************************************************
21 ;
22 ; Change log:
23 ;
24 ; DATE REVISION DESCRIPTION
25 ; -------- -------- -------------------------------------------------------
26 ; 01/31/86 Original
27 ; A- Removed STIs and changed CLI/STIs to keep interrupt
28 ; status stable (OFF) during debugger execution. The
29 ; specific problem was in reporting unexpected traps
30 ; fielded from Virtual Mode during DOS execution,
31 ; e.g. timer ticks.
32 ; B- Fixed Ctrl-NumLock, Ctrl-Alt-Del, Ctrl-Break, and
33 ; Shift-PrtSc
34 ; 05/12/86 C Cleanup and segment reorganization
35 ; 06/28/86 0.02 Name changed from MEMM386 to MEMM
36 ; 07/05/86 0.04 Moved to DCODE segment
37 ;
38 ;******************************************************************************
39 ;
40 ; Functional Description:
41 ;
42 ; THIS CODE IS USED BY THE DEBUGGER ONLY !
43 ;
44 ; This is a PC/AT keyboard driver capable of running
45 ; in protected mode. It does not require any ROM support.
46 ;
47 ; The major modifications are:
48 ;
49 ; - Remove foreign tables, use US only
50 ; - Hard code machine type rather than looking in ROM
51 ; - hard code BeepFreq, BeepDur
52 ; - removed KeyVector, put read-only data in CS
53 ; - removed Accent stuff, which had code writes
54 ; - removed code writes in foreign kbd
55 ; - removed INT 15h sysreq and post
56 ; - removed T&SR stuff, added buffer read routine "getc"
57 ; - made it polled, removed all interrupt stuff
58 ; - changed "data" segment to "romdata"
59 ;
60 ;
61 ; SCCSID = @(#)keybxx.asm 4.1 85/10/09
62 ;------------------------------------------------------
63 ;
64 ; KEYBXX - foreign keyboard driver.
65 ;
66 ; April 1985 by Michael Hanson
67 ; Copyright 1985 by Microsoft Corporation
68 ;
69 ; KeybXX is a keyboard handling program using tables
70 ; supplied in a separate file to do foreign language
71 ; keyboard support. It is the basis for the KEYB??.EXE
72 ; programs which use this program and the corresponding
73 ; table defined in KEYB??.ASM.
74 ;
75 ; KeybXX.OBJ must be linked with one of the Keyb??.OBJ
76 ; programs to work, the KEYB?? file must be first.
77 ; See the accompanying makefile for examples.
78 ;
79 ; Note: KEYB?? refers to any of KEYBFR ( French ),
80 ; KEYBGR (German), KEYBUK (United Kingdom),
81 ; KEYBIT (Italian), KEYBSP (Spanish) and
82 ; KEYBDV (Dvorak). These are the currently
83 ; defined data tables for KEYBXX.
84 ;
85 ; Compatability notes:
86 ; 1. The IBM foreign keyboard drivers don't return
87 ; anything for a CTRL-ALT space. This is not
88 ; what I expect from the manuals, but for
89 ; compatibility, KEYBXX doesn't return anything
90 ; in this case either.
91 ;
92 ; 2. For the AT the keyboard driver should do a post
93 ; call (int 15). The ROM keyboard driver does, but
94 ; IBM's foreign keyboard drivers appear not to.
95 ; Currently KEYBXX does a post code, though only
96 ; one is issued at any one time (that is, only 1 post
97 ; call for the 2 characters returned by an illegal
98 ; accent combination).
99 ;
100 ; This program is a modified version of the keyboard handler from -
101 ;
102 ; Microsoft Mach 10 Enhancement Software
103 ;
104 ; Copyright 1984 by Microsoft Corporation
105 ; Written June 1984 by Chris Peters
106 ;
107 ;******************************************************************************
108 .lfcond ; list false conditionals
109 .386p
110
111 include VDMseg.inc
112 include desc.inc
113 include kbd.inc
114
115
116 MASTER_IMR equ 21h ; mask port for master 8259
117
118 ;*** ROM BIOS data area, set up addresses
119 romdata segment use16 at 40h
120 org 17h
121 KeyState db ?
122 BreakState db ?
123 AltKey db ?
124 KbHead dw ?
125 KbTail dw ?
126 KbBuffer dw 16 dup (?)
127 KbBufferEnd label word
128
129 org 49h
130 VidMode db ?
131 org 65h
132 VidReg db ?
133
134 org 71h
135 fBreak db ?
136 fReset dw ?
137
138 org 80h
139 KbStart dw ?
140 KbEnd dw ?
141
142 org 97h
143 ATKbFlags db ?
144 romdata ends
145
146
147
148 ;*** Routines used by data table modules (Keyb??)
149 public SpecKey
150 public AlphaKey
151 public NormalKey
152 public Keys$2$13
153 public CapKey
154 public Cap$2$13
155 public FuncKey
156 public PadKey
157 public NumKey
158 public SpaceKey
159 public ShiftKey
160 public ScrollKey
161 public StateKey
162 ;public AccKey
163 public AltShiftKey
164 public BufferFull
165 public ReBoot
166 public XBoot
167 public PrintScreen
168 public SysReq
169
170
171
172
173 DCODE segment
174 assume cs:DCODE,ds:romdata,es:nothing
175
176
177 ;*** Tables for foreign language key layout
178 ; See Keyb?? files for more details
179
180
181 ;* Actual foreign language key layout
182 ; extrn ForeignTable :word
183
184
185 ;* Tables to map CNTRL ALT char
186 ; extrn AltChrs :byte
187 AltChrs label byte
188 ; extrn AltChrsEnd :byte
189 AltChrsEnd label byte
190
191 ; extrn AltMap :byte
192 AltMap label byte
193
194
195 ;* Tables to map accented characters
196 ; extrn AccentChTbl :word
197 AccentChTbl label word
198
199 ; extrn AccentMpTbl :word
200 AccentMpTbl label word
201
202
203 ;* Table of accent characters, shifted, ALTed and CTRLed.
204 ; defined using the AccChStruc struct
205 ; extrn AccChTbl :word
206 AccChTbl label word
207
208
209
210 ;*** Internal variables used by KEYBXX interrupt handler
211 ; KeyVector dd ? ; origin of keyboard decode table
212 ;PCType db ? ; type of PC running on
213 PCType db 0fch ; type of PC running on
214
215 PC_AT = 0FCh ;if anything else, assume PC/XT
216
217 ;Accent db 0 ; set for accent key, =0 for none.
218 ;AccentKey dw ? ; last accent key pressed
219
220 ; BeepFreq dw PCBeepFreq ;Count for beep half-cycle
221 BeepFreq dw ATBeepFreq ;Count for beep half-cycle
222 ; BeepDur dw PCBeepDur ;Count of half-cycles to beep
223 BeepDur dw ATBeepDur ;Count of half-cycles to beep
224
225
226 ;*** Normal keyboard table, used in CTRL-ALT F1 mode
227 ;
228 ; See Keyb?? files for structure information.
229 ;
230 ForeignTable label word
231 KeyMapTable label word
232 public KeyMapTable
233
234 db 0,0 ;0
235 dw BufferFull
236 db esc,esc ;1
237 dw SpecKey
238 db "1","!" ;2
239 dw Keys$2$13
240 db "2","@" ;3
241 dw Keys$2$13
242 db "3","#" ;4
243 dw Keys$2$13
244 db "4","$" ;5
245 dw Keys$2$13
246 db "5","%" ;6
247 dw Keys$2$13
248 db "6","^" ;7
249 dw Keys$2$13
250 db "7","&" ;8
251 dw Keys$2$13
252 db "8","*" ;9
253 dw Keys$2$13
254 db "9","(" ;10
255 dw Keys$2$13
256 db "0",")" ;11
257 dw Keys$2$13
258 db "-","_" ;12
259 dw Keys$2$13
260 db "=","+" ;13
261 dw Keys$2$13
262 db 8,127 ;14
263 dw SpecKey
264 db 9,0 ;15
265 dw NormalKey
266 db "q","Q" ;16
267 dw AlphaKey
268 db "w","W" ;17
269 dw AlphaKey
270 db "e","E" ;18
271 dw AlphaKey
272 db "r","R" ;19
273 dw AlphaKey
274 db "t","T" ;20
275 dw AlphaKey
276 db "y","Y" ;21
277 dw AlphaKey
278 db "u","U" ;22
279 dw AlphaKey
280 db "i","I" ;23
281 dw AlphaKey
282 db "o","O" ;24
283 dw AlphaKey
284 db "p","P" ;25
285 dw AlphaKey
286 db "[","{" ;26
287 dw NormalKey
288 db "]","}" ;27
289 dw NormalKey
290 db 13,10 ;28
291 dw SpecKey
292 db CtrlShift,(255-CtrlShift)
293 dw ShiftKey
294 db "a","A" ;30
295 dw AlphaKey
296 db "s","S" ;31
297 dw AlphaKey
298 db "d","D" ;32
299 dw AlphaKey
300 db "f","F" ;33
301 dw AlphaKey
302 db "g","G" ;34
303 dw AlphaKey
304 db "h","H" ;35
305 dw AlphaKey
306 db "j","J" ;36
307 dw AlphaKey
308 db "k","K" ;37
309 dw AlphaKey
310 db "l","L" ;38
311 dw AlphaKey
312 db ";",":" ;39
313 dw NormalKey
314 db "'",'"' ;40
315 dw NormalKey
316 db "`","~" ;41
317 dw NormalKey
318 db LeftShift,(255-LeftShift)
319 dw ShiftKey
320 db "\","|" ;43
321 dw NormalKey
322 db "z","Z" ;44
323 dw AlphaKey
324 db "x","X" ;45
325 dw AlphaKey
326 db "c","C" ;46
327 dw AlphaKey
328 db "v","V" ;47
329 dw AlphaKey
330 db "b","B" ;48
331 dw AlphaKey
332 db "n","N" ;49
333 dw AlphaKey
334 db "m","M" ;50
335 dw AlphaKey
336 db ",","<" ;51
337 dw NormalKey
338 db ".",">" ;52
339 dw NormalKey
340 db "/","?" ;53
341 dw NormalKey
342 db RightShift,(255-RightShift)
343 dw ShiftKey
344 db "*",114 ;55
345 dw PrintScreen
346 db AltShift,(255-AltShift) ;56
347 dw AltShiftKey
348 db " "," " ;57
349 dw SpaceKey
350 db CapsState,(255-CapsState)
351 dw StateKey
352 db 1,1 ;59
353 dw FuncKey
354 db 2,2 ;60
355 dw FuncKey
356 db 3,3 ;61
357 dw FuncKey
358 db 4,4 ;62
359 dw FuncKey
360 db 5,5 ;63
361 dw FuncKey
362 db 6,6 ;64
363 dw FuncKey
364 db 7,7 ;65
365 dw FuncKey
366 db 8,8 ;66
367 dw FuncKey
368 db 9,9 ;67
369 dw FuncKey
370 db 0,0 ;68
371 dw FuncKey
372 db NumState,(255-NumState) ;69
373 dw NumKey
374 db ScrollState,(255-ScrollState)
375 dw ScrollKey
376 db 0,"7" ;71
377 dw PadKey
378 db 1,"8" ;72
379 dw PadKey
380 db 2,"9" ;73
381 dw PadKey
382 db 3,"-" ;74
383 dw PadKey
384 db 4,"4" ;75
385 dw PadKey
386 db 5,"5" ;76
387 dw PadKey
388 db 6,"6" ;77
389 dw PadKey
390 db 7,"+" ;78
391 dw PadKey
392 db 8,"1" ;79
393 dw PadKey
394 db 9,"2" ;80
395 dw PadKey
396 db 10,"3" ;81
397 dw PadKey
398 db 11,"0" ;82
399 dw PadKey
400 db 12,"." ;83
401 dw ReBoot
402 db 0, 0 ;84 (On AT only)
403 dw SysReq
404
405
406
407 ;*** Tables for keypad with ALT and control
408 ; Same for foreign as normal
409 AltKeyPad label byte
410 db 7,8,9,-1
411 db 4,5,6,-1
412 db 1,2,3
413 db 0,-1
414
415 CtrlKeyPad label byte
416 db 119,-1,132,-1
417 db 115,-1,116,-1
418 db 117,-1,118
419 db -1,-1
420
421
422
423 ;*** Table for ALT alphabetical character
424 ;
425 ; Since uses alpha char as index, this is the same
426 ; for normal and foreign keyboards.
427 ;
428 AltTable label byte
429 ; a, b, c, d, e, f, g, h, i, j, k, l, m
430 db 30,48,46,32,18,33,34,35,23,36,37,38,50
431 ; n, o, p, q, r, s, t, u, v, w, x, y, z
432 db 49,24,25,16,19,31,20,22,47,17,45,21,44
433
434
435
436 SUBTTL Keyboard Interrupt Handler
437
438
439 ;*** Keyboard interrupt handler
440 ;
441 handler proc near
442
443 KbInt:
444 ;* sti
445 cld
446 push ax
447 push bx
448 push cx
449 push dx
450 push si
451 push di
452 push ds
453 push es
454
455 ; First see if there is any data in the kbd buffer.
456 ; Return to caller if not.
457
458 in al, KbStatus
459 test al, 1
460 jnz intr1
461 jmp RestoreRegs
462 intr1:
463
464 mov ax,romdata
465 mov ds,ax
466 call GetSCode ;Get scan code from keyboard in al
467 mov ah,al ;(ah) = scan code
468 cmp al,-1
469 jnz KbI1
470 jmp BufferFull ;go handle overrun code
471 KbI1:
472 mov bx,ax
473 and bx,7fh ;(bl) = scan code without break bit
474 cmp bl,84
475 jle KBI2
476 jmp KeyRet ;ignore code if not in range
477 KBI2:
478 shl bx,1 ;index into lookup table
479 shl bx,1
480 ;* Check for CTRL-ALT chars
481 test ah, 80h ;no CTRL-ALT remap on break code
482 jnz KbI23
483 ; cmp word ptr [KeyVector],offset KeyMapTable
484 ; je KbI23 ;Not foreign keyboard
485 jmp KbI23
486 test [KeyState], CtrlShift
487 jz KbI23
488 test [KeyState], AltShift
489 jz KbI23
490 push ax ; save scan code
491
492 ;* map CTRL-ALT char
493 ; look up chars in table, if found then put out corresponding
494 ; entry from map table.
495 mov si, offset AltChrs - 1 ;Set up index to lookup
496 KbI21:
497 inc si ; Advance to next entry
498 cmp si, offset AltChrsEnd
499 jae KbI22 ;at end of table, so no remap
500 cmp ah, cs:[si]
501 jne KbI21 ;this isn't it so loop
502 ; Found character, so do the mapping
503 sub si, offset AltChrs
504 add si, offset AltMap ;get index into remaped table
505 pop ax ;get scan code
506 mov al, cs:[si] ;get new character to use
507 jmp PutKRet
508 KbI22:
509 pop ax
510 KbI23:
511
512 ; les si,[KeyVector]
513 mov si, offset KeyMapTable
514 mov cx,cs:[si+bx] ;(cx) = lc, uc bytes
515 mov al,cl ;(al) = lc code for key
516 mov dl,[KeyState] ;(dl) = keyboard flags
517 jmp word ptr cs:[si+bx+2] ;Call appropriate key handler
518 ;***
519 ; for all key handler routines,
520 ;
521 ; (CX) = uc, lc code bytes from table
522 ; (DL) = keyboard flags byte (see equates above for bits)
523 ; (AL) = lc code from cl
524 ; (AH) = scan code from keyboard
525
526 handler endp
527
528
529 SUBTTL Key Routines
530
531 ;*** Key handling routines, called as specified by the key table
532
533 ;------------------------------------------------------
534 ;
535 ; Alphabetical key, caps lock works as do CTRL and ALT
536 ;
537 AlphaKey:
538 call NoBreak
539 test dl,AltShift
540 jz ak1
541 cbw
542 add bx,ax
543 mov ah,[AltTable+bx-"a"]
544 jmp MakeAlt
545
546 ak1: test dl,CtrlShift
547 jz ak2
548 sub al,"a"-1
549 jmp PutKRet
550
551 ak2: xor bh,bh
552 test dl,RightShift+LeftShift
553 jz ak3
554 or bh,CapsState
555 ak3: mov cl,dl
556 and cl,CapsState
557 xor bh,cl
558 jz ak4
559 mov al,ch
560 ak4: jmp PutKRet
561
562
563 ;------------------------------------------------------
564 ;
565 ; Keys that do something different when CTRL is down
566 ;
567 SpecKey:
568 call NoAlt
569 test dl,CtrlShift
570 jz bsp1
571 mov al,ch
572 bsp1: jmp PutKRet
573
574
575 ;-----------------------------------------------------
576 ;
577 ; Normal, Non Alphabetic key
578 ;
579 NormalKey: ;These return nothing on ALT
580 call NoAlt
581 test dl,CtrlShift
582 jz nk0
583 jmp short Ca20 ;ky21
584
585 Keys$2$13: ;Keys #2 - 13 have ALT codes 120,...
586 call NoBreak
587 test dl,AltShift
588 jz Ky2
589 add ah,120-2
590 jmp MakeAlt
591
592 ky2: test dl,CtrlShift
593 jnz Ca20 ;handle CTRL key same as for CapKey
594 nk0:
595 test dl,RightShift+LeftShift
596 jz nk1
597 mov al,ch
598 nk1: jmp PutKRet
599
600
601 ;-----------------------------------------------------
602 ;
603 ; Non Alphabetic key for which cap lock works
604 ;
605 CapKey: ; CAPLOCK works, ALT doesn't
606 call NoAlt
607 test dl,CtrlShift
608 jz ca5
609 jmp short ca20 ;ca3
610
611 Cap$2$13: ; KEYS 2-13 with CAPLOCK working
612 call NoBreak
613 test dl,AltShift
614 jz ca2
615 add ah,120-2
616 jmp MakeAlt
617
618 ca2: test dl,CtrlShift
619 jz ca5
620 ca20: cmp ah, 3 ;Keep CTRL keys at same scan code locations
621 jnz ca21
622 jmp MakeAlt
623 ca21: cmp ah, 7
624 jnz ca22
625 mov al, 30
626 jmp short ca7
627 ca22: cmp ah, 26
628 jnz ca23
629 mov al, 27
630 jmp short ca7
631 ca23: cmp ah, 27
632 jnz ca24
633 mov al, 29
634 jmp short ca7
635 ca24:
636 cmp ah, 43
637 jnz ca25
638 mov al, 28
639 jmp short ca7
640 ca25: cmp al, '-' ;Except for - key, which moves around.
641 jnz ca26
642 mov al, 31
643 jmp short ca7
644 ca26: jmp KeyRet
645
646
647 ca5: xor bh,bh
648 test dl,RightShift+LeftShift
649 jz ca6
650 or bh,CapsState
651 ca6: mov cl,dl
652 and cl,CapsState
653 xor bh,cl
654 jz ca7
655 mov al,ch
656 ca7: jmp PutKRet
657
658
659 ;---------------------------------------------------
660 ;
661 ; Scroll Lock, Caps Lock, Num Lock
662 ;
663 ScrollKey:
664 test ah,80h
665 jnz stk0
666 test dl,CtrlShift
667 jz stk1
668 mov ax,[KbStart]
669 mov [KbHead],ax
670 mov [KbTail],ax
671 mov [fBreak],80h
672 call EnableKB
673 ;*a int 1bh
674 ;*a xor ax,ax
675 mov ax,0003 ;*a simulate ^C
676 jmp PutKRet
677
678 NumKey: ; NUM LOCK key
679 test ah,80h
680 jnz stk0
681 test dl,CtrlShift
682 jz stk1
683 or [BreakState],HoldState ; CTRL NUMLOCK
684 call VideoOn
685 nlk1:
686 call handler ;*a (look for key since no interrupts)
687 test [BreakState],HoldState ; Wait for a key press
688 jnz nlk1
689 jmp RestoreRegs
690
691 StateKey: ; Toggle key
692 test ah,80h
693 jz stk1
694 stk0: and [BreakState],ch ; Indicate key no longer held down
695 jmp short shf4
696
697 stk1: mov ah,al
698 and al,[BreakState]
699 jnz shf4 ; Ignore if key already down
700 or [BreakState],ah ; Indicate key held down
701 xor dl,ah ; Toggle bit for this key
702 jmp short shf3 ; And go store it.
703
704
705 ;---------------------------------------------------
706 ;
707 ; Alt Shift
708 ;
709 AltShiftKey:
710 test ah,80h
711 jz shf2 ; Indicate that ALT key down
712 xor al,al
713 xchg al,[AltKey] ; Find numeric code entered
714 or al,al
715 jz shf1 ; Just reset indicator if none
716 and [KeyState],ch
717 xor ah,ah ; Make it a key with 0 scan code
718 jmp PutKRet
719
720 ;----------------------------------------------------
721 ;
722 ; Shift, Ctrl
723 ;
724 ShiftKey:
725 test ah,80h
726 jz shf2
727 shf1: and dl,ch ; Unset indicator bit for break code
728 jmp short shf3
729 shf2: or dl,al ; Set indicator bit for make code
730 shf3: mov [KeyState],dl
731 shf4: jmp KeyRet
732
733
734 ;----------------------------------------------------
735 ;
736 ; Reboot System?
737 ;
738 ReBoot: call NoBreak ; Del key pressed, check CTRL ALT DEL
739 test dl,AltShift
740 jz pdk2
741 test dl,CtrlShift
742 jz pdkx
743 XBoot: ; Reboot system.
744 mov ax,romdata ; ds = romdata segment
745 mov ds,ax
746 mov [fReset],1234h
747 ;*a
748 ;*a 02/12/86 - use shutdown code 10 and [40:67] to return to real mode
749 ;*a and enter the ROM at the CTRL-ALT-DEL entry point
750 ;*a
751 cli ; make sure
752 mov al,0Fh or 80h ; shutdown byte address/disable NMI
753 out 70h,al ; write CMOS address
754 jmp short $+2 ; (delay)
755 mov al,0Ah ; Shutdown code 10 = jump [dword @40:67]
756 out 71h,al ; write shutdown code to shutdown byte
757 ;
758 ; Set up entry point after the reset
759 ;
760 mov ds:[67h],0EA81h ; offset of CTRL-ALT-DEL entry point
761 mov ds:[67h+2],0F000h ; segment of CTRL-ALT-DEL entry point
762 ;
763 ; Reset the CPU
764 ;
765 mov al,0FEh ; FEh = pulse output bit 0 (286 reset)
766 out 64h,al ; command to 8042
767 hlt ; don't want to coast
768 ;*a
769 ;*a end inserted code
770 ;*a
771 ;*a mov ax,-1
772 ;*a push ax
773 ;*a xor ax,ax
774 ;*a push ax
775 ;*a xxx proc far
776 ;*a ret ; To reboot system, do a far return to FFFFh:0
777 ;*a xxx endp
778
779
780 ;----------------------------------------------------
781 ;
782 ; Key Pad Key
783 ;
784 PadKey:
785 mov bl,[AltKey]
786 call NoBreak2
787 test dl,AltShift
788 jz pdk2 ; Not entering a character number
789 xor bx,bx
790 mov bl,cl
791 mov cl,cs:AltKeyPad[bx] ; Get numeric value for this key
792 cmp cl,-1
793 jz pdk0 ; Start over if non-digit key
794 mov al,10
795 mul [AltKey]
796 add al,cl
797 jmp short pdk1
798 pdk0: xor ax,ax
799 pdk1: mov [AltKey],al
800 pdkx: jmp KeyRet
801
802 pdk2: mov al,0
803 test dl,CtrlShift
804 jz pdk3
805 xor bx,bx ; Lookup CTRL keypad key code
806 mov bl,cl
807 mov ah,cs:CtrlKeyPad[bx]
808 jmp short pdk6
809 pdk3: cmp ah,74 ; - key independent of shift state
810 jz pdk41
811 cmp ah,78 ; + key independent of shift state
812 jz pdk41
813 xor bx,bx
814 test dl,RightShift+LeftShift
815 jz pdk4
816 or bh,NumState
817 pdk4: mov cl,dl
818 and cl,NumState
819 xor bh,cl
820 jz pdk5
821 pdk41: mov al,ch ; use char2 if shifted or in numlock
822 pdk5: or al,al
823 jnz pdk7
824 pdk6: cmp ah,-1
825 jz pdk8 ; Ignore CTRL with keypad 2, etc.
826 cmp ah,76
827 jz pdk8
828 pdk7: jmp PutKRet
829 pdk8: jmp KeyRet
830
831
832 ;----------------------------------------------------
833 ;
834 ; Function Key
835 ;
836 FuncKey:
837 call NoBreak
838 test dl,AltShift+CtrlShift+LeftShift+RightShift
839 jz fk1 ; Normal function key
840 add ah,84-59
841 test dl,AltShift+CtrlShift
842 jz fk1 ; Shifted function key
843 add ah,10
844 test dl,AltShift
845 jz fk1 ; Just CTRL function key
846 add ah,10
847 test dl,CtrlShift
848 jz fk1 ; Just ALT function key
849 mov bx,offset KeyMapTable
850 cmp ah,104 ; CTRL ALT f1 to use normal keyboard
851 jz fk01
852 cmp ah,105 ; CTRL ALT f2 for foreign keyboard
853 jnz fk1 ; if not F1 or F2 then treat as ALT
854 mov bx,offset ForeignTable
855 fk01:
856 cli ; Change translation table used
857 ; mov word ptr [KeyVector],bx
858 ; mov word ptr [KeyVector+2],cs
859 jmp KeyRet
860
861 fk1: jmp MakeAlt
862
863
864 ;--------------------------------------------------------------------
865 ;
866 ; Print Screen Key
867 ;
868 PrintScreen:
869 call NoAlt
870 test dl,CtrlShift
871 jz ps1
872 mov ah,ch
873 jmp fk1
874 ps1: test dl,LeftShift+RightShift
875 jz pdk7
876 call VideoOn ;CTRL PrtSc - enable video and do Print Screen
877 ;*a int 5
878 jmp RestoreRegs
879
880
881 ;--------------------------------------------------------------------
882 ;
883 ; Space Key
884 ;
885 SpaceKey:
886 call NoBreak
887 test dl, CtrlShift
888 jz sp1
889 test dl, AltShift
890 jz sp1
891 jmp KeyRet ; Don't return anything on CTRL-ALT space
892 sp1:
893 jmp PutKRet
894
895
896 ;--------------------------------------------------------------------
897 ;
898 ; An accent key
899 ;
900 ; Each accent key is assumed to be accent both non-shifted
901 ; and shifted, and the accent number for the shifted should
902 ; be the next one up from the unshifted accent number.
903 ;
904 ;AccKey:
905 ; call NoBreak
906 ; cbw ;convert accent number to an index
907 ; mov bx, ax
908 ; dec bx
909 ; shl bx,1
910 ; shl bx,1 ;index to table of AccChStruc's
911 ; test dl, altshift
912 ; jz acc2 ;ALT not down
913 ; mov ax, [AccChTbl+bx].alt
914 ; jmp short acc5
915 ;acc2:
916 ; test dl, ctrlshift
917 ; jz acc3 ;just a normal or shifted keypress
918 ; mov ax, [AccChTbl+bx].ctrl
919 ; jmp short acc5
920 ;acc3:
921 ; test dl, leftshift+rightshift
922 ; jz acc4 ; not shifted (caps lock not used)
923 ; mov Accent,ch ; Get shifted accent number
924 ; mov ax, [AccChTbl+bx].shift
925 ; mov AccentKey, ax ; Save key and scn code next key int
926 ; jmp KeyRet
927 ;acc4:
928 ; mov Accent, al
929 ; mov ax, [AccChTbl+bx].normal
930 ; mov AccentKey, ax
931 ; jmp KeyRet
932 ;acc5:
933 ; jmp PutKRet
934 ;
935
936
937 ;--------------------------------------------------------------------
938 ;
939 ; System Request Key
940 ;
941 SysReq:
942 test ah, 80h
943 jnz sys2 ;this is break code
944 test BreakState, SysShift
945 jz sys1
946 jmp KeyRet ;Ignore if SysReq already down
947
948 sys1:
949 or BreakState, SysShift ;set held down flag
950 mov ax, 08500h
951 jmp short sys3
952 sys2:
953 and BreakState, Not SysShift ;turn off held down flag
954 mov ax, 08501h
955 sys3:
956 push ax ; Save SysReq action number
957 mov al,20h ; EOI to control port
958 ; out 20h,al
959 call EnableKB
960 pop ax
961 ; int 15h ; Indicate SysReq to BIOS
962 jmp RestoreRegs
963
964
965
966
967 ;*** Finish up processing of interrupt
968 ;
969
970 ;* Make this an ALT seq by removing chr code (ret scan code, 0)
971 MakeAlt:mov al,0
972
973 ;* Put Key in buffer and return
974 PutKRet:
975 ; cmp Accent, 0 ; check for accented char
976 ; je puk3 ;no accent pressed, just put out key
977 ; mov bl, Accent
978 ; dec bl ;make accent no an index
979 ; xor bh,bh
980 ; mov Accent, bh ;Accent only this character
981 ; shl bx,1 ;index into word table
982 ; mov si, AccentChTbl[bx] ;Get pointer to string for this accent
983 ; dec si ;Negate effect of initial inc in loop
984 ;puk1:
985 ; inc si
986 ; cmp al,cs:[si]
987 ; jz puk2 ;This is an accentable char - so remap
988 ; cmp byte ptr cs:[si], 0
989 ; jnz puk1 ;not done yet
990 ;
991 ;;* The character is not in this list, so do a beep and put
992 ;; out booth accent char and this char
993 ; call ErrBeep
994 ; mov bx,ax
995 ; mov ax,AccentKey ;Put out accent
996 ; call PutKey
997 ; mov ax,bx
998 ; cmp al, ' '
999 ; je puk4 ;Char is space, just beep and put out accent.
1000 ; jmp short puk3 ;Put out the character
1001 ;
1002 ;puk2:
1003 ; xor ah, ah ;Zero scan code for accented chrs
1004 ; cmp al, 0 ;for accented ALT chr put out 0, don't beep
1005 ; je puk3
1006 ; sub si, AccentChTbl[bx] ; Make index to map table
1007 ; add si, AccentMpTbl[bx]
1008 ; mov al, cs:[si] ; Get remapped char
1009 puk3:
1010 call PutKey
1011 puk4:
1012 cmp [PCType],PC_AT
1013 jnz KeyRet ; just return for non-AT
1014 cli
1015 mov al,20h ; EOI to control port
1016 ; out 20h,al
1017 call EnableKB
1018 ; mov ax, 09102h ; Send a post code
1019 ; int 15h
1020 jmp RestoreRegs
1021
1022
1023
1024 ;* Common validity check routines (Check for ALT, ignore break codes)
1025 ;
1026
1027 NoAlt: test dl,AltShift ; Don't allow ALT with this key
1028 jnz IgB1
1029 NoBreak: ; Ignore break code for this key
1030 mov bl,0
1031 NoBreak2:
1032 test ah,80h
1033 jnz IgB1
1034 test [BreakState],HoldState ; in hold state?
1035 jz IgB0 ; no...
1036 and [BreakState],(255-HoldState)
1037 jmp short IgB1
1038 IgB0: mov [AltKey],bl
1039 ret
1040 IgB1: pop ax ; pop off return address
1041 jmp short KeyRet
1042
1043
1044 ;* buffer is full, beep the speaker and return from interrupt
1045 BufferFull:
1046 cli
1047 mov al,20h
1048 ; out 20h,al
1049 call ErrBeep
1050 jmp short KeyRet1
1051
1052
1053 ;* Normal return from interrupt, handle EOI and enable KB
1054 KeyRet:
1055 cli
1056 mov al,20h
1057 ; out 20h,al
1058 KeyRet1:
1059 call EnableKB
1060 RestoreRegs:
1061 cli
1062 pop es
1063 pop ds
1064 pop di
1065 pop si
1066 pop dx
1067 pop cx
1068 pop bx
1069 pop ax
1070 ppp proc near
1071 ret
1072 ppp endp
1073 ; iret
1074
1075
1076 SUBTTL Subroutines
1077
1078
1079
1080
1081 ;*** VideoOn - enable keyboard and video
1082 ;
1083 ; ENTRY: Nothing
1084 ;
1085 ; EXIT: (dx), (al) destroyed.
1086 ;
1087 VideoOn proc near
1088 mov al,20h ; EOI to control port
1089 ; out 20h,al
1090 call EnableKB ; Enable AT keyboard
1091 cmp [VidMode],7
1092 jz vdo1 ; Do nothing for monochrome monitor
1093 mov al,[VidReg]
1094 mov dx,3d8h
1095 out dx,al ; Enable video controller
1096 vdo1: ret
1097 VideoOn endp
1098
1099
1100
1101
1102 ;*** EnableKB - Enable the keyboard interface on an AT, no effect on PC/XT.
1103 ;
1104 ; ENTRY: Nothing
1105 ;
1106 ; EXIT: (al) destroyed
1107 ;
1108 ; EFFECTS: Enables the Keyboard interface.
1109 ;
1110 EnableKB proc near
1111 cmp [PCType], PC_AT
1112 jne ena1 ;for non-AT simply ignore
1113 pushf ;* save interrupt status
1114 cli
1115 call WaitStatus
1116 mov al,0AEh ;output enable keyboard command
1117 out KbStatus,al
1118 popf ;* restore original interrupt status
1119 ;* sti
1120 ena1:
1121 ret
1122 EnableKB endp
1123
1124
1125
1126
1127 ;*** DisableKB - Disable the keyboard interface on an AT, no effect on PC/XT
1128 ;
1129 ; ENTRY: Nothing
1130 ;
1131 ; EXIT: (al) destroyed
1132 ;
1133 ; EFFECTS: Disables the Keyboard interface.
1134 ;
1135 DisableKB proc near
1136 cmp [PCType], PC_AT
1137 jne dis1 ; Ignore if not an AT
1138 pushf ;* save interrupt status
1139 cli
1140 call WaitStatus
1141 mov al,0ADh ;output disable command
1142 out KBStatus, al
1143 popf ;* restore original interrupt status
1144 ;* sti
1145 dis1:
1146 ret
1147 DisableKB endp
1148
1149
1150
1151
1152 ;*** ErrBeep - beep the speaker
1153 ;
1154 ; ENTRY: Nothing
1155 ;
1156 ; EXIT: Nothing
1157 ;
1158 ; USES: (ax) - to access I/O port
1159 ; (bx) - length of beep in cycles
1160 ; (cx) - counter for cycle length
1161 ;
1162 ; EFFECTS: Speaker is beeped
1163 ;
1164 ; WARNING: Uses in/out to keyboard port to beep speaker directly.
1165 ;
1166 ErrBeep proc near
1167 push ax
1168 push bx
1169 push cx
1170 mov bx,BeepDur ; count of speaker cycles
1171 in al,KbCtl
1172 push ax
1173 and al,0fch ; turn off bits 0 and 1 (speaker off)
1174 bee1: xor al,2 ; toggle speaker bit
1175 out KbCtl,al
1176 mov cx,BeepFreq
1177 bee2: loop bee2 ; wait for half cycle
1178 dec bx
1179 jnz bee1 ; keep cycling speaker
1180 pop ax ; restore speaker/keyboard port value
1181 out KbCtl,al
1182 pop cx
1183 pop bx
1184 pop ax
1185 ret
1186 ErrBeep endp
1187
1188
1189
1190
1191 ;*** PutKey - put key in the buffer
1192 ;
1193 ; ENTRY: (ax) = key code and scn code to go in buffer
1194 ;
1195 ; EXIT: (si), (di) destroyed.
1196 ; ints disabled.
1197 ;
1198 ; EFFECTS: KbTail updated
1199 ; (ax) put in buffer at end.
1200 ; On AT - do post call.
1201 ;
1202 ; If it isn't possible to put key in buffer (full) then beep
1203 ; and ignore.
1204 ; If (ax) = -1 then the key is not put in buffer.
1205 ;
1206 PutKey proc near
1207 cmp ax, -1 ; Code to ignore a key
1208 jz put2
1209 cli ; Make sure only ones using buffer now
1210 mov si,[KbTail]
1211 mov di,si ; Get old buffer end and save it
1212 inc si ; Advance pointer
1213 inc si
1214 cmp si,[KbEnd]
1215 jb put01
1216 mov si,[KbStart] ; Wrap to beginning if at end
1217 put01:
1218 cmp si,[KbHead]
1219 jnz put1 ; Buffer not Full
1220 pop ax ; Drop return address
1221 jmp BufferFull ; Go beep and return from interrupt
1222
1223 put1:
1224 mov [di],ax ; Put key in buffer at end
1225 mov [KbTail],si
1226 put2:
1227 ret
1228 PutKey endp
1229
1230
1231
1232
1233 ;*** GetSCode - read the scan code from the keyboard
1234 ;
1235 ; ENTRY: nothing
1236 ;
1237 ; EXIT: (al) = key scan code from keyboard
1238 ; (ah) destroyed
1239 ;
1240 ; USES: PCType - to use PC/AT sequence, for AT - handles LEDs
1241 ;
1242 GetSCode proc near
1243 cmp [PCType], PC_AT
1244 je gsc1 ;handle AT differently
1245 in al,KbData ;get key code
1246 xchg bx,ax ;save scan code
1247 in al,KbCtl ;acknowledge to keyboard
1248 mov ah,al
1249 or al,80h
1250 out KbCtl,al
1251 xchg ah,al
1252 out KbCtl,al
1253 xchg ax,bx ;(al) = scan code
1254 ret
1255
1256 gsc1: ;have to do handshake
1257 call DisableKB
1258 pushf ;* save interrupt status
1259 cli
1260 call WaitStatus
1261 in al,KbData ;read in character
1262 popf ;* restore original interrupt status
1263 ;* sti
1264
1265 ; check for and flag control bytes from keyboard
1266 cmp al,ATResend
1267 jne gsc2 ;it isn't a resend
1268 cli
1269 or [ATKbFlags], KbResend
1270 pop bx ;throw away return address
1271 jmp KeyRet ;and don't do anything more with key
1272
1273 gsc2:
1274 cmp al,ATAck
1275 jne gsc3 ;it isn't an ack
1276 cli
1277 or [ATKbFlags], KBAck
1278 pop bx ;throw away return address
1279 jmp KeyRet ;and don't do anything more with key
1280
1281 gsc3:
1282 call UpdateLeds ;update AT's leds
1283 ret
1284 GetSCode endp
1285
1286
1287
1288 ;*** Don't need to keep code after here when not running on an AT
1289 xt_endcode:
1290
1291
1292
1293 ;*** UpdateLeds - update the leds on the AT keyboard
1294 ;
1295 ; ENTRY: Nothing
1296 ;
1297 ; EXIT: All regs preserved
1298 ;
1299 ; EFFECTS: Sets the keyboard LEDs according to the status byte.
1300 ;
1301 ; WARNING: Assumes it is operating on an AT, must not be called for a PC.
1302 ;
1303 UpdateLeds proc near
1304 pushf ;* save interrupt status
1305 push ax
1306 cli
1307 mov ah, KeyState ; get the toggle key states
1308 and ah, CapsState + NumState + ScrollState
1309 rol ah, 1
1310 rol ah, 1
1311 rol ah, 1
1312 rol ah, 1 ; in format for ATKbFlags
1313 mov al, ATKbFlags
1314 and al, 07h
1315 cmp ah, al
1316 jz Updn1 ; No change in leds, so don't update
1317 test ATKbFlags, KBSndLed
1318 jnz Updn1 ; Already updating, so don't update
1319 or ATKbFlags, KBSndLed
1320 mov al, 20h
1321 ; out 20h, al ; send EOI
1322 mov al, 0EDh ; Set indicators command
1323 call SendByte
1324 test ATKbFlags, KBErr
1325 jnz Updn2
1326 mov al, ah ; Send indicator values
1327 call SendByte
1328 test ATKbFlags, KBErr
1329 jnz Updn2
1330 and ATKbFlags, 0F8h
1331 or ATKbFlags, ah ; Record indicators
1332 Updn2:
1333 and ATKbFlags, Not (KBSndLed + KBErr)
1334 Updn1:
1335 pop ax
1336 popf ;* restore original interrupt status
1337 ;* sti
1338 ret
1339 UpdateLeds endp
1340
1341
1342
1343
1344 ;*** SendByte - send a byte to the keyboard
1345 ;
1346 ; ENTRY: (al) - command/data to send
1347 ;
1348 ; EXIT: BreakState flags set according to success of operation.
1349 ; Ints disabled on completion.
1350 ;
1351 ; USES: (al) - byte to send.
1352 ; (ah) - count of retries.
1353 ; (cx) - time out counter on wait for response.
1354 ;
1355 ; Send the byte in al to the AT keyboard controller, and
1356 ; do handshaking to make sure they get there OK.
1357 ; Must not be called for the PC.
1358 ;
1359 SendByte proc near
1360 push ax
1361 push cx
1362 mov ah, 03 ; Set up count of retries
1363 Sen1:
1364 pushf ;* save interrupt status
1365 cli
1366 and ATKbFlags, Not (KBResend + KBAck + KBErr)
1367 push ax ; save byte to send
1368 call WaitStatus ; Wait for keyboard ready
1369 pop ax
1370 out KbData, al ; Send byte to keyboard
1371 popf ;* restore original interrupt status
1372 ;* sti
1373 mov cx,2000h ; Time out length, Approximate value for AT ROM
1374 Sen2: ; Wait for ACK
1375 call handler ;*a (look for key since no interrupts)
1376 test ATKbFlags, KBResend + KBAck
1377 jnz Sen4
1378 loop Sen2
1379 Sen3: ; Timed out - try to resend
1380 dec ah
1381 jnz Sen1
1382 or ATKbFlags, KBErr
1383 jmp Sen5
1384 Sen4:
1385 call handler ;*a (look for key since no interrupts)
1386 test ATKbFlags, KBResend
1387 jnz Sen3
1388 Sen5:
1389 cli
1390 pop cx
1391 pop ax
1392 ret
1393 SendByte endp
1394
1395
1396
1397
1398 ;*** WaitStatus - wait for status to indicate ready for new command
1399 ;
1400 ; ENTRY: Nothing
1401 ;
1402 ; EXIT: (AL) Destroyed.
1403 ;
1404 WaitStatus proc near
1405 push cx
1406 xor cx,cx
1407 wai1: ;wait for empty buffer
1408 in al,KbStatus
1409 test al,BufFull
1410 loopnz wai1
1411 pop cx
1412 ret
1413 WaitStatus endp
1414
1415 SUBTTL Initialization
1416
1417
1418
1419 ;* Initialization, called when run by DOS, doesn't stay resident.
1420 ;
1421 init_bios:
1422
1423 mov al,0ffh ; all OFF
1424 out MASTER_IMR,al
1425
1426 push ds
1427 push cs
1428 pop ds ; establish segment, since offsets are from cs
1429 mov dx,offset Kbint
1430 mov ax,2509h
1431 int 21h ;Set interrupt 9 (keyboard) vector
1432
1433 mov ax, romdata
1434 mov ds, ax
1435 init1: cmp [KbStart],0
1436 jnz init2 ;New PC/AT - KbStart already initialized
1437 pushf ;* save interrupt status
1438 cli ;For old PC - initialize pointers to KbBuffer
1439 mov ax,offset KbBuffer
1440 mov [KbStart],ax
1441 mov [KbHead],ax
1442 mov [KbTail],ax
1443 mov [KbEnd],offset KbBufferEnd
1444 popf ;* restore original interrupt status
1445 ;* sti
1446 init2: ; Start up in Foreign keyboard mode
1447 ; mov word ptr [KeyVector],offset ForeignTable
1448 ; mov word ptr [KeyVector+2],cs
1449
1450 ; mov [accent],0 ; No previous accent key pressed
1451
1452 ; Get PC type information and save in PCType flag
1453 ; assume ds:rom
1454
1455 ; mov ax, rom
1456 ; mov ds, ax
1457 ; mov al, [systid]
1458 ; mov [PCType], al
1459
1460 assume ds:romdata
1461 pop ds
1462
1463 ; mov dx,offset xt_endcode + 100h
1464 ; cmp [PCType], PC_AT
1465 ; jnz init6 ; Drop AT specific code
1466
1467 ;* Initialization specific to AT
1468 ; Set up speaker counts, exchange keys 41, 43
1469 ; And keep AT specific code when terminate
1470 ; mov [BeepFreq], ATBeepFreq
1471 ; mov [BeepDur], ATBeepDur
1472
1473 ; Reverse keys 41 and 43 for foreign keyboards
1474 ; mov ax, [ForeignTable + (41 * 4)] ; exchange char codes
1475 ; xchg ax, [ForeignTable + (43 * 4)]
1476 ; mov [ForeignTable + (41 * 4)], ax
1477 ; mov ax, [ForeignTable + (41 * 4) + 2] ;exchange function codes also
1478 ; xchg ax, [ForeignTable + (43 * 4) + 2]
1479 ; mov [ForeignTable + (41 * 4) + 2], ax
1480 ; Also handle for Ctrl Alt table
1481 ; mov si, offset AltChrs - 1
1482 ;init3: ;search AltChrs table
1483 ; inc si
1484 ; cmp si, offset AltChrsEnd
1485 ; jae init5 ;Done scaning - go terminate
1486 ; cmp byte ptr cs:[si], 43
1487 ; jnz init4
1488 ; mov byte ptr cs:[si], 41 ; found key 43 - replace with 41
1489 ; jmp init3
1490 ;init4:
1491 ; cmp byte ptr cs:[si], 41
1492 ; jnz init3
1493 ; mov byte ptr cs:[si], 43 ; found key 41 - replace with 43
1494 ; jmp init3
1495 ;
1496 ;init5:
1497 ; mov dx,offset init_bios + 100h ; Keep AT specific code
1498 init6:
1499 ; Terminate and stay resident, don't keep init code
1500 ; push ds ; adjust cs to psp
1501 ; mov bx, offset init7 + 100h ; by doing a far return to init7
1502 ; push bx
1503 ;xxxx proc far
1504 ; ret
1505 ;xxxx endp
1506 ;init7:
1507 ; int 27h
1508
1509 mov ah, 14
1510 mov al, 'i'
1511 int 10h
1512 ini1:
1513
1514 ;mov ah, 14
1515 ;mov al, 'h'
1516 ;int 10h
1517
1518 call handler
1519 ; call getc
1520 jz ini1
1521 mov ah, 14
1522 int 10h
1523 jmp ini1
1524
1525 DCODE ends
1526
1527 ;*** getc - read character out of keyboard buffer
1528 ;
1529 ; This routine gets characters from the buffer
1530 ; in the ROM data area.
1531 ;
1532 ; ENTRY
1533 ;
1534 ; EXIT AL - character
1535 ; AH - scan code
1536 ; 'Z' = 0
1537 ;
1538 ; or 'Z' = 1 if no code available
1539 ;
1540 ; USES flags
1541 ;
1542
1543 DCODE segment
1544
1545 assume cs:DCODE, ds:nothing, es:nothing, ss:nothing
1546
1547 public kgetc
1548 kgetc proc far
1549
1550 push bx
1551 push cx
1552 push dx
1553 push si
1554 push di
1555
1556 mov bx, 202h
1557 mov cx, 303h
1558 mov dx, 404h
1559 mov si, 505h
1560 mov di, 606h
1561
1562 call handler ; pull data into kbd buffer
1563
1564 mov bx, 2020h
1565 mov cx, 3030h
1566 mov dx, 4040h
1567 mov si, 5050h
1568 mov di, 6060h
1569
1570 push ds ; save caller's regs
1571 push bx
1572
1573 mov bx, romdata
1574 mov ds, bx ; DS -> ROM data area
1575
1576 cli
1577 mov bx, ds:[KbHead] ; bx = start of buffer
1578 cmp bx, ds:[KbTail] ; is buffer empty
1579 ;* sti
1580 jz ge1
1581
1582 cli
1583 mov ax, [bx] ; AX = character and scan code
1584 add bx, 2 ; step buffer pointer
1585 cmp bx, ds:[KbEnd] ; is it at end of buffer
1586 jne ge2
1587 mov bx, ds:[KbStart] ; move it back to start
1588 ge2:
1589 mov ds:[KbHead], bx ; store new start pointer
1590 ;* sti
1591 and bx, 0ffffh ; just to clear zero flag
1592 ge1:
1593 pop bx
1594 pop ds
1595
1596 pop di
1597 pop si
1598 pop dx
1599 pop cx
1600 pop bx
1601
1602 ret
1603
1604 kgetc endp
1605
1606 DCODE ends
1607 end
1608 \1a