home *** CD-ROM | disk | FTP | other *** search
- Name MSLK250
- ; MSLK250.ASM - A simple driver program for the DEC LK250 keyboard on IBM AT's
- ; Author: Terry Kennedy, St. Peter's College, Terry@spcvxa.Bitnet.
- ;
- ; Edit history
- ; Last edit 17 Oct 1989
- ; 17 Oct 1989 Add test for pre-80286 cpu and jmp $+2 breathers. [jrd]
- ; 16 Oct 1989 Sync USU, SPC versions; add initialization tests. [tmk]
- ; 9 Oct 1989 Add building instructions etc. [jrd]
- ;
- ; Purpose: Allow access to LK250 features without requiring the user to have
- ; any DEC drivers loaded.
- ;
- ; Method: Intercept INT 15 subfunction 4F (SysReq) and 50 (Control). If en-
- ; tered via 4F, place substitute scan code in buffer if the keypress
- ; was for a key we're remapping *and* we are active. If entered via
- ; 50, perform control function as follows:
- ;
- ; AL=00 - Disable substitution (keyboard "Special" [IBM] mode)
- ; AL=01 - Enable sunstitution (keyboard DEC mode)
- ; AL=02 - Send the byte in BL to the keyboard (caution: sending
- ; "random" bytes with this function can lock the key-
- ; board, necessitating a reboot.
- ;
- ; Construct final file MSLK250.COM by
- ; masm mslk250; reads file mslk250.asm, writes file mslk250.obj
- ; link mslk250; expect and ignore statement about no stack segment
- ; exe2bin mslk250 produces file mslk250.bin from mslk250.exe
- ; ren mslk250.bin mslk250.com rename the result to our runnable filename
- ; del mslk250.exe delete non-runnable intermediate files .exe & .obj
- ; del mslk250.obj
- ;
- ; mslk250 run mslk250.com to install the driver
- ;
- ;
- ; Date: 20-Aug-1989, X0.0-00 - Original version
- ; 26-Aug-1989, X0.0-01 - Pass Shift-PrtSc through even in DEC mode
- ; 16-Oct-1989, X0.0-02 - Add initialization tests suggested by jrd
- ; 17-Oct-1989, X0.0-03 - Add cpu test, add time between tests. jrd
- ;
- main group code
- ;
- data segment at 40h
- ;
- db 23 dup (?)
- shift db ?
- db 2 dup (?)
- head dw ?
- tail dw ?
- buff dw 16 dup (?)
- db 66 dup (?)
- bstart dw ?
- bend dw ?
- db 19 dup (?)
- kbflg2 db ?
- ;
- data ends
- ;
- code segment public para 'code'
- assume cs:main,ds:nothing
- ;
- org 100h ; making a.COM file
- ;
- begin: jmp start ; program starts here
- ;
- saved15 dd ? ; previous int 15 vector
- active db 0 ; are we translating?
- ;
- ; This is the new interrupt 15 routine.
- ;
- newi15 proc far
- assume ds:data
- cmp ah,50h ; control function?
- je ctlfnc ; if so...
- cmp ah,4fh ; keyboard intercept?
- jne bail ; nope, time to leave...
- cmp active,1 ; are we active?
- jne bail ; no, just exit...
- cmp al,01h ; Esc/PF1?
- je kpf1 ; if so
- cmp al,45h ; Num Lk/PF2?
- je kpf2 ; if so
- cmp al,46h ; Scrl Lk/PF3?
- je kpf3 ; if so
- cmp al,37h ; PrtSc / PF4?
- je kpf4 ; if so
- cmp al,54h ; is it a scan we handle?
- jl bail ; nope, bail out...
- cmp al,69h
- jg bail ; likewise...
- jmp putkey ; otherwise go save the key...
- ;
- kpf1: mov al,6ah ; make PF1 scan 6ah
- jmp putkey
- ;
- kpf2: mov al,6bh ; make PF2 scan 6bh
- jmp putkey
- ;
- kpf3: mov al,6ch ; make PF3 scan 6ch
- jmp putkey
- ;
- kpf4: push ds ; save user's [DS]
- mov ax,40h
- push ax
- pop ds
- mov al,shift ; get shift states
- pop ds ; restore user's [DS]
- and al,3 ; either shift state set?
- jz kpf4a ; nope, this key gets translated
- mov al,37h ; yes, we didn't want to translate it
- jmp bail ; oh, this is a bad pun...
- ;
- kpf4a: mov al,6dh ; make PF4 scan 6dh
- jmp putkey
- ;
- ; stuff a scancode into the keyboard buffer
- ;
- putkey: mov ah,al ; copy scan to someplace useful
- mov al,0
- push ds ; save user's [DS]
- mov bx,40h ; point to system space
- push bx
- pop ds
- mov bx,tail ; offset of buffer tail
- mov si,bx
- inc bx
- inc bx ; point to next free
- cmp bx,bend ; at end?
- jne nowrap ; if not...
- mov bx,bstart ; else wrap buffer
- nowrap: cmp bx,head ; buffer full?
- je bufull ; if so...
- mov [si],ax ; else store character
- mov tail,bx ; and update pointer
- bufull: pop ds ; restore [DS]
- clc ; say we did something...
- iret ; and exit
- ;
- bail: jmp [saved15]
- ;
- ; control functions: enable / disable translation, set LED's, set click
- ; volume, set auto-repeat rate
- ;
- ctlfnc: cmp al,0 ; disable translation?
- jne tst1 ; no
- mov active,al ; else do it
- mov al,0adh ; set keyboard mode
- call kbsend
- jmp exit ; and exit
- ;
- tst1: cmp al,1 ; enable translation?
- jne tst2 ; no
- mov active,al ; else do it
- mov al,0ach ; set keyboard mode
- call kbsend
- jmp exit ; and exit
- ;
- tst2: cmp al,2 ; send to keyboard?
- jne error ; nope, must be an error
- mov al,bl ; byte to [AL] for send
- call kbsend ; yes, send the byte out
- jmp exit ; and exit
- ;
- error: mov ax,0 ; say bad function
- iret ; and exit
- ;
- exit: mov ax,1234h ; say we did it
- iret ; and exit
- ;
- newi15 endp
- ;
- ; send a byte to the keyboard controller
- ;
- kbsend proc near
- push ax ; save some regs
- push bx
- push cx
- push ds ; save user's [DS]
- mov bx,40h ; point to system space
- push bx
- pop ds
- mov bh,al ; copy data byte for retry
- mov bl,3 ; set retry count
- sd0: cli
- and kbflg2,0cfh ; turn off ack, re-send bits
- sub cx,cx ; a nice big loop
- sd1: in al,64h
- jmp $+2 ; reduce looping rate
- test al,2
- loopnz sd1 ; if not ready
- mov al,bh
- out 60h,al ; send the command
- sti
- mov cx,2800h ; wait a bit
- sd3: test kbflg2,30h ; anything happen?
- jnz sd7 ; seems so, go handle
- jmp $+2 ; reduce looping rate
- loop sd3 ; else wait
- sd5: dec bl ; call it a retry if timed out
- jnz sd0 ; if we have another chance
- or kbflg2,80h ; otherwise fail it
- jmp sd9 ; and exit
- ;
- sd7: test kbflg2,10h ; got a proper ack?
- jz sd5 ; nope, re-send it
- sd9: pop ds
- pop cx
- pop bx
- pop ax
- ret
- ;
- kbsend endp
- ;
- endres label byte ; end of resident code
- ;
- ; Code after here will not remain resident
- ; Cpu test uses DOS's stack [jrd]
- start: ; begin with cpu test [jrd]
- push sp ; push DOS's SP, 8088's push old SP-2
- pop ax ; 286's and higher push old SP
- mov dx,offset main:cpumsg ; prepare bad news message
- cmp ax,sp ; pre versus post push SP's
- jne start0 ; ne = an 8088, sorry 'bout that [jrd]
- mov ax,5000h ; see if we are already loaded
- int 15h ; look for DOS->DEC mode driver
- cmp ax,1234h ; find marker 1234h
- jne start1 ; ne = marker not present, no driver
- mov dx,offset main:errmsg ; say we're already loaded
- start0: mov ah,9
- int 21h
- int 20h ; and bail out
- ;
- start1: mov ax,3515h ; get existing INT 15 vector
- int 21h
- mov word ptr [saved15],bx ; save it
- mov word ptr [saved15+2],es
- mov dx,offset main:newi15 ; set new INT 15 vector
- mov ax,2515h
- int 21h ; set new vector from DS:DX
- ;
- mov dx,offset main:lodmsg ; say we're loaded
- mov ah,9
- int 21h
- ;
- mov ax,ds:[2ch] ; de-allocate the environment
- mov es,ax ; load envirnoment segment into es
- mov ah,49h ; DOS function number
- int 21h ; free the environment memory
- ;
- mov dx,offset main:endres ; point to end of resident code
- add dx,0fh ; round up
- mov cl,4
- shr dx,cl ; convert to paragraphs (divide by 16)
- mov ax,3100h ; DOS function 31h, error code=0
- int 21h ; terminate and remain resident
- ;
- errmsg: db 0dh,0ah,'MSLK250 is already loaded',0dh,0ah,07h,'$'
- lodmsg: db 0dh,0ah,'MSLK250 X0.0-03 loaded',0dh,0ah,'$'
- cpumsg: db 0dh,0ah,'MSLK250 requires a 286 (AT) machine or higher'
- db 0dh,0ah,'$' ; wrong cpu type msg [jrd]
- ;
- code ends
- end begin ; start execution at BEGIN
-