; uncaps.asm
; beta 01: BIOS エリアの書き込みではうまくいかない.
; beta 02: keybord にコマンド送信
; beta 03: debug 用 VRAM 出力つきで安定したようだ。

; 2011.03.13 beta03

;参考文献
;http://w...content-available-to-author-only...o.jp/dp/4756101305/
;http://w...content-available-to-author-only...o.jp/dp/4756101062/
;



;for MASM6
;assembling
;----------------------------------------------------
;ASFLAGS = -nologo -Cx -c
;LD = link
;LDFLAGS = /NOL /NOI
;PROGRAM = uncaps.com
;OBJS = uncaps.obj
;.asm.obj:
;	@$(AS) $(ASFLAGS) $< > error.txt
;$(PROGRAM) : $(OBJS)
;	@$(LD) /t $(LDFLAGS) $(OBJS), $(PROGRAM);
;----------------------------------------------------

VRAMOFFSET2         equ     2 * (80 * 24 + 78)
DebugVRAMOut        MACRO   v
                    push    ax
                    push    ds
                    push    bx

                    mov     bh, 0
                    mov     ax, 0A000h
                    mov     ds, ax
                    mov     word ptr ds:[VRAMOFFSET2], v

                    pop     bx
                    pop     ds
                    pop     ax
endm

;----------------------------------------------------
            dosseg
            .model      tiny

LF          equ         0ah
CR          equ         0dh
TAB         equ         09h
SPACE       equ         20h

            .code
            org         002ch
envseg      label       word

            org         0081h
cmdtail     label       byte

            org         0100h

;---------------------------------------------------------
; regident-al part
entry:      jmp         main

ID          db          'UNCAPS'
ID_len      equ         $ - ID

old09       label       dword
old09_off   dw          ?
old09_seg   dw          ?

old2f       label       dword
old2f_off   dw          ?
old2f_seg   dw          ?

in09flag    db          0
func_no     db          ?       ; 使用するファンクション番号

;------------------------------------------------------
; int 09h handler


KbReceiveData       proc    near
                    mov     cx,8000H
RdyCheckLoop:
                    in      al,0043H
                    test    al,02H
                    jnz     Ready
                    loop    RdyCheckLoop
                    stc
                    ret
Ready:
                    mov     dx,005FH
                    mov     cx,18H
ReceiveLoop:
                    out     dx,al
                    loop    ReceiveLoop
;
                    in      al,0043H
                    and     al,38H
                    jnz     ReceiveError
                    mov     al,00010110B
                    out     0043H,al
                    mov     cx,0007H
@@WaitLoop3:        out     dx,al
                    loop    @@WaitLoop3
                    in      al,0041H
                    clc
                    ret
ReceiveError:
                    mov     al,00010100B
                    out     0043H,al
                    mov     cx,0007H
@@WaitLoop4:        out     dx,al
                    loop    @@WaitLoop4
                    in      al,0041H
                    stc
                    ret
KbReceiveData       endp

KBSendCommand       proc        near
;input register-ah
SendRetry:
                mov     al,00010111B
                out     0043H,al
                mov     dx, 005FH
                mov     cx, 0007H
@@WaitLoop1:
                out     dx, al
                loop    @@WaitLoop1

                mov     al, ah
                out     0041H, al
                mov     cx, 0007H
@@WaitLoop2:
                out     dx, al
                loop    @@WaitLoop2
;
                mov     al, 00010110B
                out     0043H, al
;
                mov     bl, 00H
AckRetry:
                call    KbReceiveData
                jc      TimeOut
                cmp     al, 0faH
                jne     NotAck
                clc
                ret
NotAck:
                cmp     al,0FCH
                je      SendRetry
                inc     bl
                cmp     bl, 04H
                jne     AckRetry
TimeOut:
                stc
                ret
KBSendCommand   endp

CAPSWORK    equ         053ah

Send8251CapsOff     proc        near
;inhibit kb interrupt
;DebugVRAMOut    'D'
                    or          al, 02h
                    out         0002h, al
;send 9d for LED
;DebugVRAMOut    'E'
                    mov         ah, 9dh
                    call        KBSendCommand
                    jc          @@send_end
;
;DebugVRAMOut    'F'
                    mov         ax, 0000h
                    mov         ds, ax
                    mov         ah, ds:[CAPSWORK]
                    shl         ah, 1
                    and         ah, 08h
                    or          ah, 70h
                    call        KBSendCommand
@@send_end:
;DebugVRAMOut    'G'
                    mov         ah, 03H
                    int         18H

;DebugVRAMOut    'H'
                    cli
                    in          al, 0002H
                    and         al, NOT 02H
                    out         0002H,al
                    sti
;DebugVRAMOut    'I'
;wait 50ms
                    mov         dx, 005fh
                    mov         cx, 1000h
@@waitloop:
                    out         dx, al
                    loop        @@Waitloop
;DebugVRAMOut    'J'
                    ret
Send8251CapsOff     endp

CAPSMASK    equ         02h
VRAMOFFSET  equ         2 * (80 * 24 + 79)

myint09		proc		far

			cmp			cs:in09flag, 0
			jne			@@nop09
			inc			cs:in09flag
			
            pushf
			call		cs:[old09]

			push		ax
			push		ds
            push        dx
            push        cx
            push        bx

DebugVRAMOut    'A'
			mov			ax, 0000h
			mov			ds, ax
			mov			al, ds:[CAPSWORK]
            and         al, CAPSMASK
            mov         ax, 0A000h
            mov         ds, ax
            jnz          @@capson
@@capsoff:
            jp          @@capsnext
@@capson:

DebugVRAMOut    'B'
            call        Send8251CapsOff
DebugVRAMOut    'C'

@@capsnext:
;insted call KB BIOS-reset int 18h-03h in Send8251CapsOff
;            mov         ax, 0000h
;            mov         ds, ax
;            mov         al, ds:[CAPSWORK]
;            and         al, not CAPSMASK
;           mov         ds:[CAPSWORK], al

            pop         bx
            pop         cx
            pop         dx
			pop			ds
			pop			ax

			dec			cs:in09flag
@@nop09:
            iret
myint09		endp

;-------------------------------------------------------------
myint2F		proc		far
			cmp			ah, cs:func_no
			jne			@@chain
			
			cmp			al, 00h
			je			@@f00
			cmp			al, 01h
			je			@@f01
			jmp			@@exit2F
@@f00:
			mov			ax, cs			;return al=0ffh, es:di=IDstring
			mov			es, ax
			mov			di, offset ID
			mov			al, 0ffh
			jmp			@@exit2F		;ax != 0000h
@@f01:
			mov			dx, cs

			mov			ax, 3509h
			int			21h
			mov			ax, es
			sub			ax, dx
			jnz			@@exit2F		;ax != 0000h
			
			mov			ax, 352fh
			int			21h
			mov			ax, es
			sub			ax, dx
			jnz			@@exit2F		;ax != 0000h
			
			mov			es, dx;			;ax == 0000h
@@exit2F:
			iret
@@chain:
			jmp			cs:[old2F]
myint2F		endp

TSRSIZE		equ			$ - entry + 256

;======================================================================
;initialize

				.data
msg_stay		db		'uncap が常駐しました.', CR, LF, '$'
msg_release		db		'uncap を解放しました.', CR, LF, '$'
msg_notexist	db		'uncap は常駐していません.', CR, LF, '$'
msg_already		db		'uncap はすでに常駐しています.', CR, LF, '$'
msg_hooked		db		'uncap: INT 09h/2Fh のいずれかがフックされ'
				db		'解放できません.', CR, LF, '$'
msg_funcfull	db		'uncap: INT 2Fh に未使用ファンクションがありません.'
				db		CR, LF, '$'

				.code
main			proc		near

				mov			si, offset cmdtail
				cld
@@getarg:
				lodsb
				cmp			al, SPACE
				je			@@getarg
				cmp			al, TAB
				je			@@getarg
				mov			ah, al		; ah = 引数の最初の文字
				lodsb					; al = 引数の次の文字
				cmp			ax, '-r'
				je			@@release
@@stay:
				call		TSRcheck
				jc			@@skip1
				jmp			@@already
@@skip1:
				call		getfunc
				jnc			@@skip2
				jmp			@@funcfull
@@skip2:
                mov         func_no, ah
				mov			ax, 3509h
				int			21h
				mov			old09_off, bx
				mov			old09_seg, es
				
				mov			ax, 352fh
				int			21h
				mov			old2F_off, bx
				mov			old2F_seg, es
				
				mov			dx, offset myint09
				mov			ax, 2509h
				int			21h

				mov			dx, offset myint2f
				mov			ax, 252fh
				int			21h

				mov			es, envseg
				mov			ah, 49h
				int			21h
				
				mov			dx, offset msg_stay
				mov			ah, 09h
				int			21h
				
				mov			dx, (TSRSIZE + 15) / 16
				mov			ax, 3100h
				int			21h

@@release:
				call		TSRcheck
				jc			@@notexist
				
				mov			ah, func_no
				mov			al, 01h
				int			2fh
				or			ax, ax
				jnz			@@hooked
				
				push		ds

				lds			dx, es:[old09]	; ds:dx <= old vec
				mov			ax, 2509h
				int			21h
				
				lds			dx, es:[old2f]	; ds:dx <= old vec
				mov			ax, 252fh
				int			21h

				pop			ds

                mov         ah, 49h
                int         21h

				mov			dx, offset msg_release
				mov			ah, 09h
				int			21h
				
				mov			ax, 4c00h
				int			21h
				
@@already:
				mov			dx, offset msg_already
				jmp			@@error
@@funcfull:
				mov			dx, offset msg_funcfull
				jmp			@@error
@@notexist:
				mov			dx, offset msg_notexist
				jmp			@@error
@@hooked:
				mov			dx, offset msg_hooked
@@error:
				mov			ah, 09h
				int			21h
				mov			ax, 4c01h
				int			21h

main			endp

;--------------------------------------------------------
TSRcheck		proc		near
				mov			ah, 0c0h
@@tc_loop:
				push		ax
				mov			al, 00h
				int			2fh
				cmp			al, 0ffh
				pop			ax
				jne			@@tc_nextfunc
                                            ;if residented
                                            ;es:di="uncaps"
				mov			si, offset ID
				mov			cx, ID_len
				cld
				repz		cmpsb
				jz			@@tc_found
@@tc_nextfunc:
				inc			ah
				jnz			@@tc_loop
@@tc_notfound:
				stc
				ret
@@tc_found:
				mov			func_no, ah
				clc
				ret
TSRcheck		endp

;-----------------------------------------------------
getfunc			proc		near
				mov			ah, 0c0h
@@fc_loop:
				push		ax
				mov			al, 00h
				int			2fh
				cmp			al, 00h
				pop			ax
				je			@@fc_found
				inc			ah
				jnz			@@fc_loop
@@fc_notfound:
				stc
				ret
@@fc_found:
				clc
				ret
getfunc			endp
				end			entry
;
;
; 2011.03.13 beta03

