Tvùrce webu je i pro tebe! Postav tøeba web. Bez grafika. Bez kodéra. Hned.
wz

KEYBOARD.ASM

Keyboard Driver


; =============================================================================
;
;                            Litos - Keyboard driver
;
; =============================================================================

%ifdef DEBUG
;%define	DEBUG_SCAN		; monitor keyboard scan code
%endif

		CODE_SECTION	32

; ------------- Character mapping code
; B5..B7: key category
;	0: control keys with ASCII control code: Esc, Tab
;	1: single characters: SpaceBar /*-+
;	2: alphabetic characters (with CapsLock): A..Z
;	3: numeric keys 0..9 (with NumLock): 0..9
;	4: double characters (with Shift): 0..9, `-=[]\;',./
;	5: control keys without ASCII code: Home, End...
;	6: modifiers and special keys: Shift, CapsLock, NumLock,...

KC_CTRL		EQU	0<<5	; control keys with ASCII code (hardcoded)
KC_SING		EQU	1<<5	; single characters
KC_ALPH		EQU	2<<5	; alphabetic characters (+CapsLock) (hardcoded)
KC_NUM		EQU	3<<5	; numeric keys (+NumLock)
KC_DBL		EQU	4<<5	; double characters (+Shift)
KC_VIRT		EQU	5<<5	; control keys without ASCII code
KC_MOD		EQU	6<<5	; modifiers and special keys

KCM_NO		EQU	KC_VIRT	; unknown scan code

; ------------- Modifiers and special keys

KCM_LSHI	EQU	0	; Left Shift
KCM_RSHI	EQU	1	; Right Shift
KCM_LCTR	EQU	2	; Left Ctrl
KCM_RCTR	EQU	3	; Right Ctrl
KCM_LALT	EQU	4	; Left Alt
KCM_RALT	EQU	5	; Right Alt
KCM_NUML	EQU	6	; NumLock
KCM_CAPS	EQU	7	; CapsLock
KCM_SCRL	EQU	8	; ScrollLock
KCM_BACK	EQU	9	; \ | extended
KCM_RWIN	EQU	10	; Right Win
KCM_INSE	EQU	11	; Insert
KCM_PAUS	EQU	12	; Pause
KCM_0INS	EQU	13	; [0 Ins]

; -----------------------------------------------------------------------------
;                     Lock/unlock 8042 keyboard controller
; -----------------------------------------------------------------------------
; NOTES:	Use macro KEYBLOCK to lock, KEYBUNLOCK to unlock.
; -----------------------------------------------------------------------------

; ------------- Keyboard lock function

%ifdef	SMP
		LOCK_LockFnc KeybLock,KeyboardLock ; keyboard lock function
%endif

; ------------- Macro - call keyboard lock function

%macro		KEYBLOCK 0
%ifdef	SMP
		call	KeybLock	; call keyboard lock function
%endif
%endmacro

; ------------- Macro - keyboard unlock (it saves flags)

%macro		KEYBUNLOCK 0
%ifdef	SMP
		LOCK_Unlock KeyboardLock ; unlock keyboard
%endif
%endmacro

; -----------------------------------------------------------------------------
;                            Send byte to keyboard
; -----------------------------------------------------------------------------
; INPUT:	AL = byte to send
; -----------------------------------------------------------------------------

; ------------- Push registers

KeybSendByte:	push	eax		; push EAX
		push	ecx		; push ECX

; ------------- Wait for byte to accept (1.5 us one loop, aprox. 500 us total)

		mov	ecx,350		; ECX <- timeout counter (aprox.500 us)
KeybSendByte2:	in	al,64h		; read keyboard controller status
		test	al,B1		; is input buffer full?
		loopnz	KeybSendByte2	; wait for freeing input buffer

; ------------- Pop registers

		pop	ecx		; pop ECX
		pop	eax		; pop EAX

; ------------- Send byte

		out	60h,al		; send byte to keyboard
		ret

; -----------------------------------------------------------------------------
;                         Send data to keyboard
; -----------------------------------------------------------------------------
; INPUT:	AL = byte to send
;		EBX = return address if response OK (KeybSendOK = completed)
; NOTES:	It does not lock keyboard. Interupts must be disabled.
; -----------------------------------------------------------------------------

; ------------- Send data with completion address

KeybSendDataEnd:push	dword KeybSendOK ; push completion address into stack

; ------------- Send data with return address in [ESP]

KeybSendDataRet:pop	ebx		; EBX <- return address

; ------------- Acknowledge routine

KeybSendData:	mov	[KeybSendACK],ebx ; acknowledge routine

; ------------- Initialize error service

		mov	byte [KeybSendRepeat],5 ; error counter
		mov	dword [KeybSendNACK],KeybSendDataN ; non acknowledge
		call	KeybSendStartTO	; start time-out timer

; ------------- Store last byte sent

		mov	[KeybSendLast],al ; store last byte sent

; ------------- Send data to keyboard

		jmp	short KeybSendByte ; send byte to keyboard

; ============= Stop sending data - error

KeybSendErr:	and	byte [KeybFlags+1],~(KEYB_PRESENT>>8) ; not present

; ============= Stop sending data - completed

KeybSendOK: 	mov	dword [KeybSendNACK],KeybIntNoSend ; non-acknowledge
		mov	dword [KeybSendACK],KeybIntNoSend ; acknowledge
		push	ebx		; push EBX
		mov	ebx,KeybSendAlarm ; EBX <- alarm structure
		mov	dword [ebx+ALARM_Func],KeybSendNone ; callback
		call	AlarmStop	; stop alarm timer
		pop	ebx		; pop EBX
		and	byte [KeybFlags+1],~(KEYB_SENDING>>8) ; clear send flag
		ret

; ============= Non-acknowledge callback routine

KeybSendDataN:	dec	byte [KeybSendRepeat] ; error counter
		jz	KeybSendErr	; it was last attempt
		push	ebx		; push EBX
		mov	ebx,KeybSendAlarm ; EBX <- alarm structure
		call	AlarmStop	; stop alarm timer
		pop	ebx		; pop EBX

; ------------- Repeat last command

KeybSendDataRep:call	KeybSendStartTO	; start time-out timer
		push	eax		; push EAX
		mov	al,[KeybSendLast] ; AL <- last byte sent
		call	KeybSendByte	; re-send last byte
		pop	eax		; pop EAX
		ret

; ============= Start time-out timer

KeybSendStartTO:push	eax		; push EAX
		push	ebx		; push EBX
		push	ecx		; push ECX

		xor	eax,eax		; EAX <- 0
		mov	al,200		; EAX <- 200, time-out in [ms]
		mov	ebx,KeybSendAlarm ; EBX <- alarm structure
		xor	ecx,ecx		; ECX <- 0, no repeat
		mov	dword [ebx+ALARM_Func],KeybSendDataTO ; callback
		call	AlarmSetInt	; set alarm interval
		call	AlarmStart	; start alarm timer

		pop	ecx		; pop ECX
		pop	ebx		; pop EBX
		pop	eax		; pop EAX
KeybSendNone:	ret			; alarm callback - no function

; ============= Alarm callback - timeout

KeybSendDataTO:	KEYBLOCK		; lock keyboard
		dec	byte [KeybSendRepeat] ; error counter
		jz	KeybSendDataTO2	; it was last attempt
		call	KeybSendDataRep	; repeat last command
		KEYBUNLOCK		; unlock keyboard
		ret

KeybSendDataTO2:call	KeybSendErr	; error
		KEYBUNLOCK		; unlock keyboard
		ret

; -----------------------------------------------------------------------------
;                             Setup keyboard
; -----------------------------------------------------------------------------
; NOTES:	This function only starts setup sequence or sets request.
; 		It locks keyboard controller.
; -----------------------------------------------------------------------------

; ------------- Disable interrupts

KeybSetSetup:	pushf			; push flags
		cli			; disable interrupts

; ------------- Lock keyboard

		KEYBLOCK		; lock keyboard

; ------------- Set setup request

		or	byte [KeybFlags+1],KEYB_SENDSET>>8 ; set setup request

; ------------- Test and set sending flag

		bts	dword [KeybFlags],KEYB_SEND_BIT ; test and set sending
		jc	KeybSetSetup2	; data is sending

; ------------- Clear setup request flag

		and	byte [KeybFlags+1],~(KEYB_SENDSET>>8); clear setup flag

; ------------- Push registers

		push	eax		; push EAX
		push	ebx		; push EBX

; ------------- Send command

		mov	al,KEYCMD_ENABLE ; command
		mov	ebx,KeybSendOK	; continue address
		call	KeybSendData	; send data to keyboard

; ------------- Pop registers

		pop	ebx		; pop EBX
		pop	eax		; pop EAX

; ------------- Unlock keyboard

KeybSetSetup2:	KEYBUNLOCK		; unlock keyboard

; ------------- Enable interrupts

		popf			; pop flags
		ret

; -----------------------------------------------------------------------------
;                                Set LEDs
; -----------------------------------------------------------------------------
; NOTES:	This function only starts LEDs sequence or sets LEDs request.
; 		It locks keyboard controller.
; -----------------------------------------------------------------------------

; ------------- Disable interrupts

KeybSetLED:	pushf			; push flags
		cli			; disable interrupts

; ------------- Lock keyboard

		KEYBLOCK		; lock keyboard

; ------------- Set LED request

		or	byte [KeybFlags+1],KEYB_SENDLED>>8 ; set LED request

; ------------- Test and set sending flag

		bts	dword [KeybFlags],KEYB_SEND_BIT ; test and set sending
		jc	KeybSetLED2	; data is sending

; ------------- Clear LEDs request flag

		and	byte [KeybFlags+1],~(KEYB_SENDLED>>8) ; clear LED flag

; ------------- Push registers

		push	eax		; push EAX
		push	ebx		; push EBX

; ------------- Send command

		mov	al,KEYCMD_SETLED ; command
		mov	ebx,KeybSetLED4	; continue address
		call	KeybSendData	; send data to keyboard

; ------------- Pop registers

		pop	ebx		; pop EBX
		pop	eax		; pop EAX

; ------------- Unlock keyboard

KeybSetLED2:	KEYBUNLOCK		; unlock keyboard

; ------------- Enable interrupts

		popf			; pop flags
		ret

; ------------- Send LEDs

KeybSetLED4:	mov	al,[KeybFlags]	; AL <- keyboard flags
		and	al,B0+B1+B2	; mask LED bits
KeybSetLED6:	call	KeybSendDataRet	; send data to keyboard

; Here it jumps after receiving ACK.

; ------------- Re-enable keyboard

		mov	al,KEYCMD_ENABLE ; command
		jmp	KeybSendDataEnd	; re-enable keyboard

; -----------------------------------------------------------------------------
;                             Set typematic rate
; -----------------------------------------------------------------------------
; NOTES:	This function starts typematic rate sequence or sets request.
; 		It locks keyboard controller.
; -----------------------------------------------------------------------------

; ------------- Disable interrupts

KeybSetRate:	pushf			; push flags
		cli			; disable interrupts

; ------------- Lock keyboard

		KEYBLOCK		; lock keyboard

; ------------- Set rate request

		or	byte [KeybFlags+1],KEYB_SENDRATE>>8 ; set rate request

; ------------- Test and set sending flag

		bts	dword [KeybFlags],KEYB_SEND_BIT ; test and set sending
		jc	KeybSetRate2	; data is sending

; ------------- Clear rate request flag

		and	byte [KeybFlags+1],~(KEYB_SENDRATE>>8); clear rate flag

; ------------- Push registers

		push	eax		; push EAX
		push	ebx		; push EBX

; ------------- Send command

		mov	al,KEYCMD_SETRATE ; command
		mov	ebx,KeybSetRate4 ; continue address
		call	KeybSendData	; send data to keyboard

; ------------- Pop registers

		pop	ebx		; pop EBX
		pop	eax		; pop EAX

; ------------- Unlock keyboard

KeybSetRate2:	KEYBUNLOCK		; unlock keyboard

; ------------- Enable interrupts

		popf			; pop flags
		ret

; ------------- Send typematic rate

KeybSetRate4:	mov	al,[KeybRate]	; AL <- typematic rate
		jmp	short KeybSetLED6 ; send data to keyboard

; -----------------------------------------------------------------------------
;                         Debug: monitor scan code
; -----------------------------------------------------------------------------
; INPUT:	AL = scan code
; -----------------------------------------------------------------------------

%ifdef DEBUG_SCAN

; ------------- Push registers

KeyIntDeb:	push	eax		; push EAX
		push	ebx		; push EBX
		push	ecx		; push ECX
		push	edx		; push EDX

; ------------- Prepare display descriptor

		mov	ebx,EGADrvDDPB ;CurDDPB	; EBX <- display descriptor
;		or	byte [ebx+DDPB_Flags],DDPB_SINGLELF

; ------------- Change output position

		call	TXTGetPos	; get output position
		push	ecx		; push ECX (position)
		push	edx		; push EDX (row)
		mov	ecx,[KeybDebOutPos] ; output position
		mov	edx,[KeybDebOutPos+4] ; output row
		call	TXTSetPos	; set output position

; ------------- Display first HEX character

		push	eax		; push EAX
		shr	al,4		; AL <- high nibble
		add	al,"0"		; AL <- convert high nibble to ASCII
		cmp	al,"9"		; is it HEX character?
		jbe	KeybIntDeb2	; it is not HEX character
		add	al,7		; convert to HEX character 'A'..'F'
KeybIntDeb2:	call	TXTDispChar	; display character
		pop	eax		; pop EAX

; ------------- Display second HEX character

		push	eax		; push EAX
		and	al,0fh		; AL <- low nibble
		add	al,"0"		; AL <- convert low nibble to ASCII
		cmp	al,"9"		; is it HEX character?
		jbe	KeybIntDeb4	; it is not HEX character
		add	al,7		; convert to HEX character 'A'..'F'
KeybIntDeb4:	call	TXTDispChar	; display character
		pop	eax		; pop EAX

; ------------- Display space

		mov	ah,al		; AH <- scan code
		mov	al," "		; AL <- external separator
		cmp	ah,0e1h		; prefix?
		je	KeybIntDel6	; prefix
		cmp	ah,0e0h		; prefix?
		je	KeybIntDel6	; prefix
		or	ah,ah		; key is up?
		js	KeybIntDel8	; key is up
KeybIntDel6:	mov	al,"-"		; AL <- internal separator
KeybIntDel8:	call	TXTDispCtrl	; display separator

; ------------- Return output position

		call	TXTGetPos	; get output position
		mov	[KeybDebOutPos],ecx ; output position
		mov	[KeybDebOutPos+4],edx ; output row
		pop	edx		; pop EDX (row)
		pop	ecx		; pop ECX (position)
		call	TXTSetPos	; set output position

; ------------- Pop registers

		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	ebx		; pop EBX
		pop	eax		; pop EAX
		ret
%endif

; -----------------------------------------------------------------------------
;                               Keyboard interrupt
; -----------------------------------------------------------------------------
; NOTES: Only CPU0 can accept keyboard interrupt to ensure right order of data.
; -----------------------------------------------------------------------------
; Registers:	AL = scan code
;		AH = controller status
;		EBX = key code
;		ECX = counter of inputs
;		EDX = console descriptor
;		EDI = keyboard flags

; ------------- Push registers

KeybInt:	pusha			; push all registers
		push	ds		; push DS
		push	es		; push ES

; ------------- Initialize registers

		mov	eax,SYSTEM_DS	; EAX <- system data segment
		mov	ds,eax		; DS <- system data segment
		mov	es,eax		; ES <- system data segment
		cld			; direction up

; ------------- Lock keyboard controller

		KEYBLOCK		; lock keyboard controller

; ------------- Prepare pointer to keyboard flags (-> EDI)

		mov	edi,KeybFlags	; EDI <- keyboard flags

; ------------- Check if controller has any data

		mov	ecx,100		; ECX <- maximal number of loops
KeybInt2:	in	al,64h		; read keyboard controller status
		test	al,B0		; any data byte pending?
		jz	near KeybInt8	; no data byte ready
		mov	ah,al		; AH <- save controller status

; ------------- Read keyboard data (-> AL)

		in	al,60h		; AL <- read data byte from keyboard

; ------------- DEBUG: Monitor scan code
%ifdef DEBUG_SCAN
		call	KeyIntDeb	; monitor scan code
%endif
; ------------- Check data error

		test	ah,B6+B7	; data error?
		jnz	short KeybInt33	; data error, get next data byte

; ------------- Set keyboard present flag

		or	byte [edi+1],KEYB_PRESENT>>8 ; keyboard present

; ------------- Check if it is mouse data

		test	ah,B5		; is it mouse data?
		jnz	near KeybInt5	; it is mouse data

; ------------- Acknowledge (service can destroy EAX and EBX)

		cmp	al,KEYSTATE_ACK	; command acknowledge?
		jne	short KeybInt22	; not command acknowledge
		call	dword [KeybSendACK] ; ACK response
		jmp	short KeybInt33	; next data byte

; ------------- Not acknowledge (service can destroy EAX and EBX)

KeybInt22:	cmp	al,KEYSTATE_NACK ; command non-acknowledge?
		jne	short KeybInt3	; not command non-acknowledge
		call	dword [KeybSendNACK] ; NACK response
		jmp	short KeybInt33	; next data byte

; ------------- Callback - not waiting for reply

KeybIntNoSend:	pop	ebx		; destroy CALL return address

; ------------- Shift global random generator with an event

KeybInt3:	RNDSHIFTADD eax		; shift global random generator

; ------------- Prefix 1

		cmp	al,KEYSTATE_PREF ; extended prefix?
		jne	short KeybInt32	; not extended prefix
KeybInt31:	or	byte [edi+1],KEYB_EXT>>8 ; set extended prefix
		jmp	short KeybInt33	; next data byte

; ------------- Prefix 2

KeybInt32:	cmp	al,KEYSTATE_PREF2 ; extended prefix2?
		jne	short KeybInt34	; not extended prefix 2
		or	byte [edi+1],KEYB_EXT2>>8 ; set extended prefix 2
KeybInt33:	jmp	short KeybInt7	; next data byte

; ------------- Prefix 2 service (ignore next scan code and set prefix 1)

KeybInt34:	btr	dword [edi],KEYB_EXT2_BIT ; extended prefix 2?
		jc	short KeybInt31	; prefix 2, change to prefix 1

; ------------- Prepare key code (-> EBX)

		movzx	ebx,al		; EBX <- scan code
		shl	bl,1		; clear release key bit
		btr	dword [edi],KEYB_EXT_BIT ; test extended prefix
		rcr	bl,1		; BL <- bit 7, extended prefix
		
; ------------- Get mapping code (-> ESI)

		movzx	esi,byte [KeybMapTab+ebx] ; ESI <- mapping code

; ------------- Set release flag and change pressed flag

		or	al,al		; is key released?
		jns	short KeybInt36	; key is not released
		btr	dword [KeybMap],ebx ; reset press flag
		or	bh,KEYCODE_UP	; set released flag
		jmp	short KeybInt38

KeybInt36:	bts	dword [KeybMap],ebx ; set press flag

; ------------- Add modifiers

KeybInt38:	mov	al,[KeybFlags]	; AL <- keyboard flags
		shr	al,4		; AL <- shift modifiers
		and	al,B0+B1+B2	; mask modifiers
		or	bh,al		; add modifiers to the flags

; ------------- Shift key code to finish position (-> EBX)

		shl	ebx,16		; shift scan code

; ------------- Jump to key service

		mov	eax,esi		; EAX <- key mapping code
		shr	esi,5		; ESI <- key category
		jmp	dword [KeybIntTab+esi*4] ; jump to service

; ------------- Mouse service

KeybInt5:	; TODO

		jmp	short KeybInt7

; ------------- DEBUG: Monitor scan code

KeybIntSet:
%ifdef DEBUG_SCAN
		or	ebx,ebx		; is it pressed key?
		js	KeybIntSet24	; it is not press
		bt	ebx,VIRTKEY_CHAR_BIT ; is it valid ASCII?
		jnc	KeybIntSet24	; it is not ASCII
		mov	al,bl		; AL <- ASCII character
		cmp	al,CR		; is it CR?
		jne	KeybIntSet22	; it is not CR
		mov	al,LF		; substitute CR with LF
KeybIntSet22:	push	ebx		; push EBX
		mov	ebx,EGADrvDDPB ;CurDDPB	; EBX <- display descriptor
		call	TXTDispCtrl	; display character
		pop	ebx		; pop EBX
KeybIntSet24:
%endif

; ------------- Store key code
; TODO: national remap key code

		xchg	eax,ebx		; EAX <- key code
		call	KeybWrite	; write key code into buffer

; ------------- Read next data byte

KeybInt7:	dec	ecx		; loop counter
		jnz	near KeybInt2	; read next data byte

; ------------- Unlock keyboard controller

KeybInt8:	KEYBUNLOCK		; unlock keyboard controller

; ------------- Enable keyboard interrupt

		IRQLOCK			; lock 8259A interrupt controller
		in	al,21h		; release interrupt controller 1
		mov	al,60h+KEYB_IRQ ; AL <- keyboard IRQ
		out	20h,al		; acknowledge interrupt
		IRQUNLOCK		; unlock 8259A interrupt controller

; ------------- Send data to keyboard

		test	byte [KeybFlags+1],KEYB_REQMASK>>8 ; any request?
		jz	KeybInt9	; no request
		test	byte [KeybFlags+1],KEYB_SENDING>>8 ; sending data?
		jnz	KeybInt9	; sending data

; ------------- Send setup

		test	byte [KeybFlags+1],KEYB_SENDSET>>8 ; send setup?
		jz	KeybInt82	; no setup
		call	KeybSetSetup	; setup keyboard
		jmp	short KeybInt9

; ------------- Send LED state

KeybInt82:	test	byte [KeybFlags+1],KEYB_SENDLED>>8 ; send LED?
		jz	KeybInt84	; no LED
		call	KeybSetLED	; setup LED
		jmp	short KeybInt9

; ------------- Send rate

KeybInt84:	test	byte [KeybFlags+1],KEYB_SENDRATE>>8 ; send rate?
		jz	KeybInt9	; no rate
		call	KeybSetRate	; setup rate

; ------------- Pop registers

KeybInt9:	pop	es		; pop ES
		pop	ds		; pop DS
		popa			; pop all registers
		iret

; ============= Keyboard service - control keys with ASCII code

KeybIntCTRL:	mov	bl,al		; BL <- virtual code
KeybIntSetChar:	bts	ebx,KEYCODE_CHAR_BIT+24 ; set character flag
		jmp	KeybIntSet ; store key code

; ============= Keyboard service - single characters

KeybIntSING:	and	al,1fh		; EAX <- key 
		mov	bl,[KeyMapTabSing+eax] ; BL <- character code
		jmp	short KeybIntSetChar ; store key code

; ============= Keyboard service - alphabetic characters

KeybIntALPH:	test	byte [edi],KEYB_CAPS ; is Caps Lock on?
		jnz	KeybIntALPH2	; Caps Lock is on
		xor	al,20h		; shift to lower letter
KeybIntALPH2:	test	byte [edi],KEYB_SHIFT ; is Left or Right Shift on?
		jz	KeybIntALPH4	; Shift is not on
		xor	al,20h		; shift letter
KeybIntALPH4:	test	byte [edi],KEYB_CTRL ; is Left or Right Ctrl on?
		jz	KeybIntALPH6	; Ctrl is not on
		and	al,1fh		; change to control character
KeybIntALPH6:	mov	bl,al		; BL <- character code
		jmp	short KeybIntSetChar ; store key code

; ============= Keyboard service - numeric keys

KeybIntNUM:	and	al,1fh		; EAX <- key subcode
		test	byte [edi],KEYB_NUM ; is NumLock on?
		jz	KeybIntNUM4	; NumLock is not on
		test	byte [edi],KEYB_SHIFT|KEYB_CTRL ; modifier?
		jnz	KeybIntNUM6	; change to control code
KeybIntNUM2:	mov	bl,[KeyMapTabNum1+eax] ; BL <- character code
		jmp	short KeybIntSetChar ; store key code

KeybIntNUM4:	test	byte [edi],KEYB_SHIFT|KEYB_CTRL ; modifier?
		jnz	KeybIntNUM2	; change to character code
KeybIntNUM6:	mov	bl,[KeyMapTabNum2+eax] ; BL <- virtual code
		jmp	short KeybIntSetVirt ; store key code
		
; ============= Keyboard service - double characters

KeybIntDBL:	and	al,1fh		; EAX <- key subcode
		mov	esi,KeyMapTabDbl2 ; table with Shift
		test	byte [edi],KEYB_SHIFT ; is Shift on?
		jnz	KeybIntDBL2	; Shift is on
		mov	esi,KeyMapTabDbl1 ; table without Shift
KeybIntDBL2:	mov	bl,[esi+eax]	; BL <- character code
		jmp	short KeybIntSetChar ; store key code

; ============= Keyboard service - key without ASCII code

KeybIntVIRT:	mov	eax,ebx		; EAX <- key code
		shr	eax,16		; AL <- scan code
		mov	bl,al		; BL <- virtual key code
		jmp	short KeybIntSetVirt ; store key code

; ============= Keyboard service - modifiers

KeybIntMOD:	and	al,1fh		; EAX <- key subcode
		jmp	dword [KeybIntModTab+eax*4] ; jump to service

; ============= Modifiers service - Left and Right Shift

KeybModRSHI:
KeybModLSHI:    mov	bl,KEY_SHIFT	; BL <- virtual key code
		or	ebx,ebx		; key is pressed?
		js	KeybModSHI2	; key si not pressed
		bts	ebx,VIRTKEY_SHIFT_BIT ; set Shift flag
		or	byte [edi],KEYB_SHIFT ; set Shift flag
		jmp	short KeybIntSetVirt ; store key code

KeybModSHI2:	btr	ebx,VIRTKEY_SHIFT_BIT ; reset Shift flag
		and	byte [edi],~KEYB_SHIFT ; clear Shift flag
		jmp	short KeybIntSetVirt ; store key code

; ============= Modifiers service - Left and Right Ctrl

KeybModRCTR:
KeybModLCTR:	mov	bl,KEY_CTRL	; BL <- virtual key code
		or	ebx,ebx		; key is pressed?
		js	KeybModCTR2	; key si not pressed
		bts	ebx,VIRTKEY_CTRL_BIT ; set Ctrl flag
		or	byte [edi],KEYB_CTRL ; set Ctrl flag
		jmp	short KeybIntSetVirt ; store key code

KeybModCTR2:	btr	ebx,VIRTKEY_CTRL_BIT ; reset Ctrl flag
		and	byte [edi],~KEYB_CTRL ; clear Ctrl flag
		jmp	short KeybIntSetVirt ; store key code

; ============= Modifiers service - Left and Right Alt

KeybModRALT:
KeybModLALT:	mov	bl,KEY_ALT	; BL <- virtual key code
		or	ebx,ebx		; key is pressed?
		js	KeybModALT2	; key si not pressed
		bts	ebx,VIRTKEY_ALT_BIT ; set Alt flag
		or	byte [edi],KEYB_ALT ; set Alt flag
		jmp	short KeybIntSetVirt ; store key code

KeybModALT2:	btr	ebx,VIRTKEY_ALT_BIT ; reset Alt flag
		and	byte [edi],~KEYB_ALT ; clear Alt flag
		jmp	short KeybIntSetVirt ; store key code

; ============= Modifiers service - NumLock

KeybModNUML:	mov	bl,KEY_NUMLOCK	; BL <- virtual key code
		or	ebx,ebx		; is key pressed?
		js	KeybIntSetVirt	; key is not pressed
		xor	byte [edi],KEYB_NUM ; flip NumLock flag
KeybModNUML2:	or	byte [edi+1],KEYB_SENDLED>>8 ; set LEDs request
KeybIntSetVirt:	jmp	KeybIntSet	; store key code

; ============= Modifiers service - CapsLock

KeybModCAPS:	mov	bl,KEY_CAPSLOCK	; BL <- virtual key code
		or	ebx,ebx		; is key pressed?
		js	KeybIntSetVirt	; key is not pressed
		xor	byte [edi],KEYB_CAPS ; flip CapsLock flag
		jmp	short KeybModNUML2 ; store key code

; ============= Modifiers service - ScrollLock

KeybModSCRL:	bts	ebx,KEYCODE_CHAR_BIT+24 ; set character flag
		mov	bl,KEY_SCROLL	; BL <- virtual key code
		or	ebx,ebx		; is key pressed?
		js	KeybIntSetVirt	; key is not pressed
		xor	byte [edi],KEYB_SCROLL ; flip ScrollLock flag
		jmp	short KeybModNUML2 ; store key code

; ============= Modifiers service - \ | extended

KeybModBACK:	mov	bl,KEY_BACKSLASH ; BL <- virtual key code
		jmp	KeybIntSetChar	; store key code

; ============= Modifiers service - Right Win

KeybModRWIN:	bts	ebx,KEYCODE_CHAR_BIT+24 ; set character flag
		mov	bl,KEY_WIN	; BL <- virtual key code
		jmp	short KeybIntSetVirt ; store key code

; ============= Modifiers service - Pause

KeybModPAUS:	mov	bl,KEY_PAUSE	; BL <- virtual key code
		or	ebx,ebx		; is key pressed?
		js	KeybModPAUS2	; key is not pressed
		xor	byte [edi],KEYB_PAUSE ; flip Pause flag
KeybModPAUS2:	jmp	short KeybIntSetVirt ; store key code

; ============= Modifiers service - [0 Ins]

KeybMod0INS:	test	byte [edi],KEYB_NUM ; is NumLock on?
		jz	KeybMod0INS4	; NumLock is not on
		test	byte [edi],KEYB_SHIFT|KEYB_CTRL ; modifier?
		jnz	short KeybModINSE ; change to control code
KeybMod0INS2:	mov	bl,"0"		; BL <- character code
		bts	ebx,KEYCODE_CHAR_BIT+24 ; set character flag
		jmp	KeybIntSetChar	; store key code

KeybMod0INS4:	test	byte [edi],KEYB_SHIFT|KEYB_CTRL ; modifier?
		jnz	KeybMod0INS2	; change to character code

; KeybModINSE must follow

; ============= Modifiers service - Insert

KeybModINSE:	mov	bl,KEY_INSERT	; BL <- virtual key code
		or	ebx,ebx		; is key pressed?
		js	KeybModINSE2	; key is not pressed
		xor	byte [edi],KEYB_INSERT ; flip Insert flag
KeybModINSE2:	jmp	short KeybIntSetVirt ; store key code

; -----------------------------------------------------------------------------
;                       Write key into all focused buffers
; -----------------------------------------------------------------------------
; INPUT:	EAX = key code
; -----------------------------------------------------------------------------

; ------------- Push registers

KeybWrite:	push	ebx		; push EBX
		push	ecx		; push ECX
		push	edx		; push EDX
		push	esi		; push ESI

; ------------- Prepare mask of consoles for active consoles (-> EDX)

		mov	edx,[KeybConMask] ; EDX <- mask of consoles
		mov	ebx,edx		; EBX <- push mask of consoles
		and	edx,[ConActMask] ; EDX <- active consoles
		jnz	KeybWrite2	; found any valid console

; ------------- Prepare mask of consoles for open consoles (-> EDX)

		mov	edx,ebx		; EDX <- mask of consoles
		and	edx,[ConOpenMask] ; EDX <- open consoles
		jnz	KeybWrite2	; found any valid console

; ------------- Prepare mask of consoles for any console (-> EDX)

		mov	edx,ebx		; EDX <- mask of any console

; ------------- Index of first console (-> EBX, ECX)

KeybWrite2:	bsf	ebx,edx		; EBX <- index of first console
		jz	KeybWrite8	; no console
		mov	cl,bl		; CL <- index of first console
		shr	edx,cl		; destroy unneeded bits
		mov	esi,[KeybBuffAddr+ebx*4-4] ; ESI <- console buffer-1

; ------------- Check if use this console

KeybWrite4:	add	esi,KEYBBUF_size ; ESI <- next keyboard buffer
		shr	edx,1		; shift mask of consoles
		jnc	KeybWrite6	; don't use this console

; ------------- Write to one console

		mov	ebx,[esi+KBUF_WKeyData] ; EBX <- private data
		call	dword [esi+KBUF_WKeyFnc] ; write to one console

; ------------- Next console

		or	edx,edx		; any other console?
KeybWrite6:	jnz	KeybWrite4	; next console

; ------------- Pop registers

KeybWrite8:	pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	ebx		; pop EBX
		ret

; -----------------------------------------------------------------------------
;                       Write key into keyboard buffer
; -----------------------------------------------------------------------------
; INPUT:	EAX = key code
;		EBX = keyboard buffer
; -----------------------------------------------------------------------------

; ------------- Push registers

KeybWriteKey:	push	ecx		; push ECX

; ------------- Disable interrupts

		pushf			; push flags
		cli			; disable interrupts

; ------------- Lock keyboard buffer (in EBX)
%ifdef SMP
		call	SpinLock	; lock keyboard buffer
%endif
; ------------- Write key code into buffer and shift write offset

		movzx	ecx,byte [ebx+KBUF_Write] ; ECX <- write offset
		mov	[ebx+KBUF_Buff+ecx],eax ; store key code into buffer
		add	cl,4		; ECX <- next write offset
		mov	[ebx+KBUF_Write],cl ; store new write offset

; ------------- Shift key code read offset if buffer is full

		cmp	cl,[ebx+KBUF_ReadKey] ; is key code buffer full?
		jne	KeybWriteKey2	; buffer is not full
		add	byte [ebx+KBUF_ReadKey],4 ; shift key code read offset

; ------------- Shift character read offset if buffer is full

KeybWriteKey2:	cmp	cl,[ebx+KBUF_ReadChar] ; is character buffer full?
		jne	KeybWriteKey4	; buffer is not full
		add	byte [ebx+KBUF_ReadChar],4; shift character read offset

; ------------- Unlock keyboard buffer and enable interrupts

KeybWriteKey4:
%ifdef SMP
		LOCK_Unlock ebx		; unlock keyboard buffer
%endif
		popf			; pop flags

; ------------- Pop registers

		pop	ecx		; pop ECX
		ret

; -----------------------------------------------------------------------------
;                       Read key from keyboard buffer
; -----------------------------------------------------------------------------
; INPUT:	EBX = keyboard buffer
; OUTPUT:	EAX = key code (if NC, EAX = 0 on CY)
;		CY = no character ready (EAX = 0 on CY)
; -----------------------------------------------------------------------------

; ------------- Disable interrupts

KeybReadKey:	pushf			; push flags
		cli			; disable interrupts

; ------------- Lock keyboard buffer (in EBX)
%ifdef SMP
		call	SpinLock	; lock keyboard buffer
%endif
; ------------- Check if there is next key code

		movzx	eax,byte [ebx+KBUF_ReadKey] ; EAX <- read offset
		cmp	al,[ebx+KBUF_Write] ; any key code?
		je	KeybReadKey6	; buffer is empty

; ------------- Get next key code (-> EAX)

		mov	eax,[ebx+KBUF_Buff+eax] ; EAX <- next key code
		add	byte [ebx+KBUF_ReadKey],4 ; shift read offset

; ------------- OK: Unlock keyboard buffer and enable interrupts
%ifdef SMP
		LOCK_Unlock ebx		; unlock keyboard buffer
%endif
		popf			; pop flags
		clc			; clear error flag
		ret

; ------------- ERROR: Unlock keyboard buffer and enable interrupts

KeybReadKey6:
%ifdef SMP
		LOCK_Unlock ebx		; unlock keyboard buffer
%endif
		popf			; pop flags
		xor	eax,eax		; EAX <- 0, invalid key code
		stc			; set error flag
		ret

; -----------------------------------------------------------------------------
;                     Read character from keyboard buffer
; -----------------------------------------------------------------------------
; INPUT:	EBX = keyboard buffer
; OUTPUT:	AL = character (if NC, AL = 0 on CY)
;		CY = no character ready (AL = 0 on CY)
; -----------------------------------------------------------------------------

; ------------- Push registers

KeybReadChar:	push	ecx		; push ECX

; ------------- Disable interrupts

		pushf			; push flags
		cli			; disable interrupts

; ------------- Lock keyboard buffer (in EBX)
%ifdef SMP
		call	SpinLock	; lock keyboard buffer
%endif
; ------------- Read character from cache (-> AL)

		mov	al,[ebx+KBUF_Cache] ; AL <- character from cache
		btr	dword [ebx+KBUF_Flags],KBUF_CACHE_BIT ; cached?
		jc	KeybReadChar6	; character is cached

; ------------- Check if there is another key code

KeybReadChar2:	movzx	ecx,byte [ebx+KBUF_ReadChar] ; ECX <- read offset
		cmp	cl,[ebx+KBUF_Write] ; any key code?
		je	KeybReadChar8	; buffer is empty

; ------------- Get next key code (-> ECX)

		mov	ecx,[ebx+KBUF_Buff+ecx] ; ECX <- next key code
		add	byte [ebx+KBUF_ReadChar],4 ; shift read offset

; ------------- Check if it is valid character

		or	ecx,ecx		; is key pressed?
		js	KeybReadChar2	; no, key is released
		bt	ecx,KEYCODE_CHAR_BIT+24 ; is it character key?
		jnc	KeybReadChar2	; it is not character key

; ------------- Save second byte of character code

		bt	ecx,KEYCODE_CH16_BIT+24 ; is it 16-bit character?
		jnc	KeybReadChar4	; it is not 16-bit character
		mov	[ebx+KBUF_Cache],ch ; save second byte of character
		or	byte [ebx+KBUF_Flags],KBUF_CACHE ; set cache bit

; ------------- Character is OK

KeybReadChar4:	mov	al,cl		; AL <- read character

; ------------- OK: Unlock keyboard buffer and enable interrupts

KeybReadChar6:
%ifdef SMP
		LOCK_Unlock ebx		; unlock keyboard buffer
%endif
		popf			; pop flags

; ------------- OK: pop registers

		clc			; clear error flag
		pop	ecx		; pop ECX
		ret

; ------------- ERROR: Unlock keyboard buffer and enable interrupts

KeybReadChar8:
%ifdef SMP
		LOCK_Unlock ebx		; unlock keyboard buffer
%endif
		popf			; pop flags

; ------------- ERROR: Pop registers

		mov	al,0		; AL <- 0, invalid character
		stc			; set error flag
		pop	ecx		; pop ECX
		ret

; -----------------------------------------------------------------------------
;                   Multi-read characters from keyboard buffer
; -----------------------------------------------------------------------------
; INPUT:	EAX = input buffer
;		EBX = keyboard buffer
;		ECX = buffer size
; OUTPUT:	ECX = number of read bytes (if NC, ECX = 0 on CY)
;		CY = no character ready (ECX = 0 on CY)
; -----------------------------------------------------------------------------

; ------------- Push registers

KeybMReadChar:	push	edx		; push EDX
		push	esi		; push ESI

; ------------- Disable interrupts

		pushf			; push flags
		cli			; disable interrupts

; ------------- Lock keyboard buffer (in EBX)
%ifdef SMP
		call	SpinLock	; lock keyboard buffer
%endif
; ------------- Read character from cache (-> DL)

		xor	esi,esi		; ESI <- 0, character counter
KeybMReadChar2:	mov	dl,[ebx+KBUF_Cache] ; AL <- character from cache
		btr	dword [ebx+KBUF_Flags],KBUF_CACHE_BIT ; cached?
		jc	KeybMReadChar6	; character is cached

; ------------- Check if there is another key code

KeybMReadChar4:	movzx	edx,byte [ebx+KBUF_ReadChar] ; EDX <- read offset
		cmp	dl,[ebx+KBUF_Write] ; any key code?
		je	KeybMReadChar8	; buffer is empty

; ------------- Get next key code (-> EDX)

		mov	edx,[ebx+KBUF_Buff+edx] ; EDX <- next key code
		add	byte [ebx+KBUF_ReadChar],4 ; shift read offset

; ------------- Check if it is valid character

		or	edx,edx		; is key pressed?
		js	KeybMReadChar4	; no, key is released
		bt	edx,KEYCODE_CHAR_BIT+24 ; is it character key?
		jnc	KeybMReadChar4	; it is not character key

; ------------- Save second byte of character code

		bt	edx,KEYCODE_CH16_BIT+24 ; is it 16-bit character?
		jnc	KeybMReadChar6	; it is not 16-bit character
		mov	[ebx+KBUF_Cache],dh ; save second byte of character
		or	byte [ebx+KBUF_Flags],KBUF_CACHE ; set cache bit

; ------------- Store character into buffer

KeybMReadChar6:	mov	[eax+esi],dl	; store character into buffer
		inc	esi		; increase counter of characters
		loop	KeybMReadChar2	; next character

; ------------- Unlock keyboard buffer and enable interrupts

KeybMReadChar8:
%ifdef SMP
		LOCK_Unlock ebx		; unlock keyboard buffer
%endif
		popf			; pop flags

; ------------- Check number of read characters

		mov	ecx,esi		; ECX <- number of bytes
		cmp	ecx,byte 1	; any data read?

; ------------- Pop registers

		pop	esi		; pop ESI
		pop	edx		; pop EDX
		ret

; -----------------------------------------------------------------------------
;                        Initialise keyboard driver
; -----------------------------------------------------------------------------

; ------------- Install keyboard driver

KeybInit:	mov	ebx,KeybDPB	; EBX <- driver parameter block
		call	DrvLstInsert	; insert driver into list

; ------------- Prepare buffer for next console

		mov	ebx,KeybBuff	; EBX <- first keyboard input buffer
		xor	ecx,ecx		; ECX <- console index
		xor	edx,edx		; EDX <- 0
		inc	edx		; EDX <- 1, console mask
KeybInit2:
%ifdef SMP
		LOCK3_Init ebx		; initialize buffer lock
%endif
		mov	[ebx+KBUF_WKeyData],ebx ; private data
		mov	dword [ebx+KBUF_WKeyFnc],KeybWriteKey ; write function
		mov	[ebx+KBUF_Index],cl ; store console index
		test	edx,[KeybConMask] ; install for this console?
		jz	KeybInit4	; no

; ------------- Install keyboard console interface

		mov	eax,KeybReadChar ; EAX <- read function
		call	ConRegRead	; install read
		mov	eax,KeybReadKey	; EAX <- key-read function
		call	ConRegKRead	; install key-read
		mov	eax,KeybMReadChar ; EAX <- multi-read function
		call	ConRegMRead	; install multi-read

; ------------- Next keyboard buffer

KeybInit4:	add	ebx,KEYBBUF_size ; EBX <- next keyboard input buffer
		inc	ecx		; ECX <- increase console index
		shl	edx,1		; EDX <- next console mask
		jnz	KeybInit2	; next console
		ret

; -----------------------------------------------------------------------------
;                                   Data
; -----------------------------------------------------------------------------

		DATA_SECTION

; ------------- Mask of consoles using this keyboard

		align	4, db 0
KeybConMask:	dd	-1		; mask of consoles using this keyboard

; ------------- Keyboard driver

		align	8, db 0
KeybDPB:	RBTREENODE		; red-black tree node
		SPINLOCK		; driver lock
		db	0, DRV_INP_KEYB	; index, class and subclass
		db	DPB_STATIC,0	; flags and class flags
		db	0,0,0,1		; driver version
		dd	DrvVendorName	; pointer to vendor name
		dd	KeybName	; pointer to driver name
		dd	KeybModel	; pointer to model name
		dd	EmptySText	; modul path
		dd	DrvStdFuncTab	; pointer to function table
		LISTHEAD		; resource list

KeybName:	STEXT	'Keyboard'
KeybModel:	STEXT	'Standard 101/102-key keyboard'

; ------------- IRQ handler for keyboard

		align	8, db 0
KeybIRQHandler:	LISTHEAD		; link to next IRQ handler
		dd	0		; pointer to IRQ descriptor
		dw	IRQ_PRIVATE|IRQ_ACTIVE ; IRQ flags
		db	1		; current IRQ number
		db	1		; recomended best IRQ number
		dd	B1		; mask of usable IRQs (1=enabled)
		dd	0		; user data (NULL=disabled)
		dd	0		; counter for slow interrupts
		dd	KeybInt		; fast handler (NULL=none)
		dd	0		; slow handler (NULL=none)
		dd	0		; callback (NULL=none)

; ------------- 8042 keyboard controller lock
%ifdef SMP
		align	4, db 0
KeyboardLock:	SPINLOCK		; 8042 keyboard controller lock
%endif

; ------------- DEBUG: Scan codes output position

%ifdef DEBUG_SCAN
		align	4, db 0
KeybDebOutPos:	dd	0,10
%endif

; ------------- Communication with keyboard

		align	8, db 0
KeybSendAlarm:	ALARMTIMER KeybSendNone,0 ; alarm structure for time-out
KeybSendACK:	dd	KeybIntNoSend	; callback if ACK response
KeybSendNACK:	dd	KeybIntNoSend	; callback if NACK response
KeybSendRepeat:	db	1		; repeat counter to send data
KeybSendLast:	db	0		; last byte sent

; ------------- Keyboard driver flags

		align	4, db 0
KeybFlags:	dd	KEYB_DEFAULT	; keyboard driver flags

; ------------- Keyboard typematic rate

KeybRate:	db	0 + (0<<5)	; current keyboard typematic rate

; ------------- Keyboard character mapping table, no modifiers

KeybMapTab:	db	0	+KC_VIRT	; 00: no key
		db	ESC			; 01: Esc
		db	0	+KC_DBL		; 02: 1 !
		db	1	+KC_DBL		; 03: 2 @
		db	2	+KC_DBL		; 04: 3 #
		db	3	+KC_DBL		; 05: 4 $
		db	4	+KC_DBL		; 06: 5 %
		db	5	+KC_DBL		; 07: 6 ^
		db	6	+KC_DBL		; 08: 7 &
		db	7	+KC_DBL		; 09: 8 *
		db	8	+KC_DBL		; 0A: 9 (
		db	9	+KC_DBL		; 0B: 0 )
		db	10	+KC_DBL		; 0C: - _
		db	11	+KC_DBL		; 0D: = +
		db	BS			; 0E: Backspace
		db	TAB			; 0F: Tab
		db	'Q'			; 10: Q
		db	'W'			; 11: W
		db	'E'			; 12: E
		db	'R'			; 13: R
		db	'T'			; 14: T
		db	'Y'			; 15: Y
		db	'U'			; 16: U
		db	'I'			; 17: I
		db	'O'			; 18: O
		db	'P'			; 19: P
		db	12	+KC_DBL		; 1A: [ {
		db	13	+KC_DBL		; 1B: ] }
		db	CR			; 1C: Enter
		db	KCM_LCTR+KC_MOD		; 1D: Left Ctrl
		db	'A'			; 1E: A
		db	'S'			; 1F: S
		db	'D'			; 20: D
		db	'F'			; 21: F
		db	'G'			; 22: G
		db	'H'			; 23: H
		db	'J'			; 24: J
		db	'K'			; 25: K
		db	'L'			; 26: L
		db	14	+KC_DBL		; 27: ; :
		db	15	+KC_DBL		; 28: ' "
		db	16	+KC_DBL		; 29: ` ~
		db	KCM_LSHI+KC_MOD		; 2A: Left Shift
		db	17	+KC_DBL		; 2B: \ |
		db	'Z'			; 2C: Z
		db	'X'			; 2D: X
		db	'C'			; 2E: C
		db	'V'			; 2F: V
		db	'B'			; 30: B
		db	'N'			; 31: N
		db	'M'			; 32: M
		db	18	+KC_DBL		; 33: , <
		db	19	+KC_DBL		; 34: . >
		db	20	+KC_DBL		; 35: / ?
		db	KCM_RSHI+KC_MOD		; 36: Right Shift
		db	0	+KC_SING	; 37: Gray [*]
		db	KCM_LALT+KC_MOD		; 38: Left Alt
		db	1	+KC_SING	; 39: SpaceBar
		db	KCM_CAPS+KC_MOD		; 3A: CapsLock
		db	0	+KC_VIRT	; 3B: F1
		db	0	+KC_VIRT	; 3C: F2
		db	0	+KC_VIRT	; 3D: F3
		db	0	+KC_VIRT	; 3E: F4
		db	0	+KC_VIRT	; 3F: F5
		db	0	+KC_VIRT	; 40: F6
		db	0	+KC_VIRT	; 41: F7
		db	0	+KC_VIRT	; 42: F8
		db	0	+KC_VIRT	; 43: F9
		db	0	+KC_VIRT	; 44: F10
		db	KCM_NUML+KC_MOD		; 45: NumLock
		db	KCM_SCRL+KC_MOD		; 46: ScrollLock
		db	0	+KC_NUM		; 47: [7 Home]
		db	1	+KC_NUM		; 48: [8 Up]
		db	2	+KC_NUM		; 49: [9 PgUp]
		db	2	+KC_SING	; 4A: Gray [-]
		db	3	+KC_NUM		; 4B: [4 Left]
		db	4	+KC_NUM		; 4C: [5]
		db	5	+KC_NUM		; 4D: [6 Right]
		db	3	+KC_SING	; 4E: Gray [+]
		db	6	+KC_NUM		; 4F: [1 End]
		db	7	+KC_NUM		; 50: [2 Down]
		db	8	+KC_NUM		; 51: [3 PgDn]
		db	KCM_0INS+KC_MOD		; 52: [0 Ins]
		db	9	+KC_NUM		; 53: [. Del]
		db	0	+KC_VIRT	; 54: SysRq
		db	KCM_NO			; 55: ----
		db	KCM_BACK+KC_MOD		; 56: \ | alternative
		db	0	+KC_VIRT	; 57: F11
		db	0	+KC_VIRT	; 58: F12
		times 5+B7-59h db  KCM_NO	; 59 to 04+B7: ----
		db	0	+KC_VIRT	; 05+B7: Messenger
		db	KCM_NO			; 06+B7: ----
		db	0	+KC_VIRT	; 07+B7: Edit Redo
		db	0	+KC_VIRT	; 08+B7: Edit Undo
		db	0	+KC_VIRT	; 09+B7: Application Left
		db	0	+KC_VIRT	; 0A+B7: Edit Paste
		db	0	+KC_VIRT	; 0B+B7: Scroll Normal
		times 10h-0Ch db  KCM_NO	; 0C+B7 to 0F+B7: ----
		db	0	+KC_VIRT	; 10+B7: Media Prev
		db	0	+KC_VIRT	; 11+B7: Scroll Fast
		db	0	+KC_VIRT	; 12+B7: Scroll Faster
		db	0	+KC_VIRT	; 13+B7: Word
		db	0	+KC_VIRT	; 14+B7: Excel
		db	0	+KC_VIRT	; 15+B7: Calendar
		db	0	+KC_VIRT	; 16+B7: Log Off
		db	0	+KC_VIRT	; 17+B7: Edit Cut
		db	0	+KC_VIRT	; 18+B7: Edit Copy
		db	0	+KC_VIRT	; 19+B7: Media Next
		times 2		db  KCM_NO	; 1A+B7, 1B+B7: ----
		db	CR			; 1C+B7: Gray [Enter]
		db	KCM_RCTR+KC_MOD		; 1D+B7: Right Ctrl
		db	0	+KC_VIRT	; 1E+B7: Application Right
		db	0	+KC_VIRT	; 1F+B7: Scroll Fastest
		db	0	+KC_VIRT	; 20+B7: Volume Mute
		db	0	+KC_VIRT	; 21+B7: Calculator
		db	0	+KC_VIRT	; 22+B7: Media Play
		db	0	+KC_VIRT	; 23+B7: Spell
		db	0	+KC_VIRT	; 24+B7: Media Stop
		times 2ah-25h	db  KCM_NO	; 25+B7 to 29+B7: ----
		db	KCM_LSHI+KC_MOD		; 2A+B7: fake Left Shift
		times 2eh-2bh	db  KCM_NO	; 2B+B7 to 2D+B7: ----
		db	0	+KC_VIRT	; 2E+B7: Volune-
		db	KCM_NO			; 2F+B7: ----
		db	0	+KC_VIRT	; 30+B7: Volune+
		db	KCM_NO			; 31+B7: ----
		db	0	+KC_VIRT	; 32+B7: WWW Home
		times 2		db  KCM_NO	; 33+B7, 34+B7: ----
		db	4	+KC_SING	; 35+B7: Gray [/]
		db	KCM_RSHI+KC_MOD		; 36+B7: fake Right Shift
		db	0	+KC_VIRT	; 37+B7: PrintScr
		db	KCM_RALT+KC_MOD		; 38+B7: Right Alt
		times 2		db  KCM_NO	; 39+B7, 3A+B7: ----
		db	0	+KC_VIRT	; 3B+B7: Help
		db	0	+KC_VIRT	; 3C+B7: My Music
		db	0	+KC_VIRT	; 3D+B7: Task Pane
		db	0	+KC_VIRT	; 3E+B7: File New
		db	0	+KC_VIRT	; 3F+B7: File Open
		db	0	+KC_VIRT	; 40+B7: File Close
		db	0	+KC_VIRT	; 41+B7: Email Reply
		db	0	+KC_VIRT	; 42+B7: Email Forward
		db	0	+KC_VIRT	; 43+B7: Email Send
		db	KCM_NO			; 44+B7: ----
		db	KCM_PAUS+KC_MOD		; 45+B7: Pause
		db	0	+KC_VIRT	; 46+B7: Break
		db	0	+KC_VIRT	; 47+B7: Home
		db	0	+KC_VIRT	; 48+B7: Up
		db	0	+KC_VIRT	; 49+B7: Page Up
		db	KCM_NO			; 4A+B7: ----
		db	0	+KC_VIRT	; 4B+B7: Left
		db	KCM_NO			; 4C+B7: ----
		db	0	+KC_VIRT	; 4D+B7: Right
		db	KCM_NO			; 4E+B7: ----
		db	0	+KC_VIRT	; 4F+B7: End
		db	0	+KC_VIRT	; 50+B7: Down
		db	0	+KC_VIRT	; 51+B7: Page Down
		db	KCM_INSE+KC_MOD		; 52+B7: Insert
		db	0	+KC_VIRT	; 53+B7: Delete
		times 57h-54h	db  KCM_NO	; 54+B7 to 56+B7: ----
		db	0	+KC_VIRT	; 57+B7: File Save
		db	0	+KC_VIRT	; 58+B7: File Print
		times 2		db  KCM_NO	; 59+B7, 5A+B7: ----
		db	0	+KC_VIRT	; 5B+B7: Left Win
		db	KCM_RWIN+KC_MOD		; 5C+B7: Right Win
		db	0	+KC_VIRT	; 5D+B7: Win Menu
		db	0	+KC_VIRT	; 5E+B7: Power
		db	0	+KC_VIRT	; 5F+B7: Sleep
		times 63h-60h	db  KCM_NO	; 60+B7: to 62+B7: ----
		db	0	+KC_VIRT	; 63+B7: Wake Up
		db	0	+KC_VIRT	; 64+B7: My Picture
		db	0	+KC_VIRT	; 65+B7: File Search
		db	0	+KC_VIRT	; 66+B7: WWW Favorites
		db	0	+KC_VIRT	; 67+B7: WWW Refresh
		db	0	+KC_VIRT	; 68+B7: WWW Stop
		db	0	+KC_VIRT	; 69+B7: WWW Forward
		db	0	+KC_VIRT	; 6A+B7: WWW Back
		db	0	+KC_VIRT	; 6B+B7: My Computer
		db	0	+KC_VIRT	; 6C+B7: E-mail
		db	0	+KC_VIRT	; 6D+B7: Media Select
		times 255-6Eh	db  KCM_NO	; 6E+B7: to FF+B7: ----

; ------------- Keyboard character map - single characters

KeyMapTabSing:	db	'* -+/'

; ------------- Keyboard character map - numeric keys

KeyMapTabNum1:	db	'789456123.'		; with NumLock
KeyMapTabNum2:	db	KEY_HOME		; without NumLock
		db	KEY_UP
		db	KEY_PAGEUP
		db	KEY_LEFT
		db	KEY_NONE
		db	KEY_RIGHT
		db	KEY_END
		db	KEY_DOWN
		db	KEY_PAGEDOWN
		db	KEY_DELETE

; ------------- Keyboard character map - double characters

KeyMapTabDbl1:	db	'1234567890-=[];',27h,'`\,./'	; without Shift
KeyMapTabDbl2:	db	'!@#$%^&*()_+{}:',22h,'~|<>?'	; with Shift

; ------------- Keyboard service jump table

		align	4, db 0
KeybIntTab:	dd	KeybIntCTRL		; control keys with ASCII code
		dd	KeybIntSING		; single characters
		dd	KeybIntALPH		; alphabetic characters
		dd	KeybIntNUM		; numeric keys
		dd	KeybIntDBL		; double characters
		dd	KeybIntVIRT		; key without ASCII code
		dd	KeybIntMOD		; modifiers

; ------------- Modifiers jump table

		align	4, db 0
KeybIntModTab:	dd	KeybModLSHI		; Left Shift
		dd	KeybModRSHI		; Right Shift
		dd	KeybModLCTR		; Left Ctrl
		dd	KeybModRCTR		; Right Ctrl
		dd	KeybModLALT		; Left Alt
		dd	KeybModRALT		; Right Alt
		dd	KeybModNUML		; NumLock
		dd	KeybModCAPS		; CapsLock
		dd	KeybModSCRL		; ScrollLock
		dd	KeybModBACK		; \ | extended
		dd	KeybModRWIN		; Right Win
		dd	KeybModINSE		; Insert
		dd	KeybModPAUS		; Pause
		dd	KeybMod0INS		; [0 Ins]

; ------------- Pointers to keyboard input buffers (+ one invalid)

		align	4, db 0
		dd	KeybBuff - KEYBBUF_size	; invalid address
KeybBuffAddr:
%assign	KBUFINX	0
%rep	CONSOLE_NUM
		dd	KeybBuff + KEYBBUF_size*KBUFINX
%assign	KBUFINX	KBUFINX+1
%endrep

; -----------------------------------------------------------------------------
;                            Uninitialized data
; -----------------------------------------------------------------------------

		BSS_SECTION

; ------------- Keyboard map of pressed key (1=key is pressed)

		align	4, resb 1
KeybMap:	resb	256/8		; keyboard map

; ------------- Keyboard input buffers

		align	4, resb 1
KeybBuff:	resb	KEYBBUF_size*CONSOLE_NUM ; keyboard input buffers

Back to source browser