1615 lines
41 KiB
NASM
1615 lines
41 KiB
NASM
|
title "Mouse detection"
|
|||
|
;++
|
|||
|
;
|
|||
|
; Copyright (c) 1989 Microsoft Corporation
|
|||
|
;
|
|||
|
; Module Name:
|
|||
|
;
|
|||
|
; mouse.asm
|
|||
|
;
|
|||
|
; Abstract:
|
|||
|
;
|
|||
|
; This module implements the assembley code necessary to determine
|
|||
|
; various mouse in the system.
|
|||
|
;
|
|||
|
; Author:
|
|||
|
;
|
|||
|
; Shie-Lin Tzong (shielint) 10-Dec-1991.
|
|||
|
; Most of the code is taken from win31 setup code(with modification.)
|
|||
|
;
|
|||
|
; Environment:
|
|||
|
;
|
|||
|
; x86 Real Mode.
|
|||
|
;
|
|||
|
; Revision History:
|
|||
|
;
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
.xlist
|
|||
|
include mouse.inc
|
|||
|
.list
|
|||
|
|
|||
|
.386
|
|||
|
extrn _Empty8042:proc
|
|||
|
extrn Write8042:proc
|
|||
|
extrn ReadKeyboard:proc
|
|||
|
extrn _ComPortAddress:word
|
|||
|
extrn _DisableSerialMice:word
|
|||
|
extrn _FastDetect:byte
|
|||
|
|
|||
|
_DATA SEGMENT PARA USE16 PUBLIC 'DATA'
|
|||
|
|
|||
|
LATLSBSave db ?
|
|||
|
LATMSBSave db ?
|
|||
|
LCRSave db ?
|
|||
|
MCRSave db ?
|
|||
|
IERSave db ?
|
|||
|
fSingle8259 db 0
|
|||
|
DWFinalCount dw 2 dup (0)
|
|||
|
DWCurrCount dw 2 dup (0)
|
|||
|
|
|||
|
NextComPort dw 0 ; Offset into ComPortAddress[]
|
|||
|
MouseInfo MouseInformation <0, 0, 0FFFFh, 0FFFFh, 0>
|
|||
|
|
|||
|
;
|
|||
|
; MouseDetected is used to indicate if any mouse has been detected.
|
|||
|
;
|
|||
|
|
|||
|
MouseDetected dw 0 ; initialize to no
|
|||
|
InPortIoBase dw 0 ; The Base addr for inport mouse
|
|||
|
|
|||
|
_DATA ends
|
|||
|
|
|||
|
_TEXT SEGMENT PARA USE16 PUBLIC 'CODE'
|
|||
|
ASSUME CS: _TEXT, DS:_DATA, SS:NOTHING
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; USHORT
|
|||
|
; LookForPS2Mouse (
|
|||
|
; VOID
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This function determines mouse type in the system.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; (eax): mouse Id.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
public _LookForPS2Mouse
|
|||
|
_LookForPS2Mouse proc near
|
|||
|
push bx
|
|||
|
push si
|
|||
|
push di
|
|||
|
|
|||
|
mov si, offset MouseInfo
|
|||
|
lea si, [si].DeviceId
|
|||
|
|
|||
|
call _Empty8042
|
|||
|
|
|||
|
int 11h
|
|||
|
test ax, 4 ; is bit 2 set?
|
|||
|
jz No_PS2_Mouse ; No, no PS/2 mouse.
|
|||
|
|
|||
|
xor di, di
|
|||
|
|
|||
|
;
|
|||
|
; Shortcut the rest of the detection and mouse reset if fast detect is set.
|
|||
|
;
|
|||
|
|
|||
|
cmp _FastDetect, 0
|
|||
|
jne short Is_PS2_Mouse
|
|||
|
|
|||
|
;
|
|||
|
; Old Olivetti M400-60 and M400-40 will have trouble reading floppy
|
|||
|
; and hard disk if the following call is made .
|
|||
|
;
|
|||
|
|
|||
|
mov ax, 0c201h ; reset PS/2 mouse
|
|||
|
int 15h
|
|||
|
jc short No_PS2_Mouse
|
|||
|
jmp short Is_PS2_Mouse
|
|||
|
|
|||
|
mov bh, 03 ; Packet size = 3 bytes
|
|||
|
mov ax, 0c205h ; init point device interface
|
|||
|
int 15h
|
|||
|
jc short No_PS2_Mouse
|
|||
|
|
|||
|
mov ax, 0c201h ; reset PS/2 mouse
|
|||
|
int 15h
|
|||
|
jc short No_PS2_Mouse
|
|||
|
|
|||
|
call _Empty8042
|
|||
|
|
|||
|
;
|
|||
|
; The following sequence of Int 15h calls will determine if a Logitech
|
|||
|
; PS/2 mouse is present. This information was obtained from Logitech.
|
|||
|
;
|
|||
|
|
|||
|
mov ax,0C203h ; Set resolution to 1 cnt/mm
|
|||
|
mov bh,0h
|
|||
|
int 15h
|
|||
|
jc Is_PS2_Mouse
|
|||
|
|
|||
|
mov ax,0C206h ; Set scaling to 1:1
|
|||
|
mov bh,1h
|
|||
|
int 15h
|
|||
|
jc Is_PS2_Mouse
|
|||
|
|
|||
|
mov ax,0C206h ; Set scaling to 1:1
|
|||
|
mov bh,1h
|
|||
|
int 15h
|
|||
|
jc Is_PS2_Mouse
|
|||
|
|
|||
|
mov ax,0C206h ; Set scaling to 1:1
|
|||
|
mov bh,1h
|
|||
|
int 15h
|
|||
|
jc Is_PS2_Mouse
|
|||
|
|
|||
|
mov ax,0C206h ; Get status
|
|||
|
mov bh,0h
|
|||
|
int 15h
|
|||
|
jc Is_PS2_Mouse
|
|||
|
|
|||
|
or cl,cl ; Is resolution 1 cnt/mm?
|
|||
|
jz Is_PS2_Mouse ; Yes, then not a Logitech.
|
|||
|
|
|||
|
;
|
|||
|
; If cl is not zero (i.e. 1 cnt/mm) then it is the number of buttons
|
|||
|
; and we've found a Logitech 3-button PS/2 mouse
|
|||
|
;
|
|||
|
|
|||
|
LT_PS2_Mouse:
|
|||
|
mov ax,LT_MOUSE + PS2_MOUSE
|
|||
|
jmp short PS2MouseFound
|
|||
|
|
|||
|
Is_PS2_Mouse:
|
|||
|
mov ax,MS_MOUSE + PS2_MOUSE
|
|||
|
jmp short PS2MouseFound
|
|||
|
|
|||
|
No_PS2_Mouse:
|
|||
|
mov bx, 0
|
|||
|
jmp ExitPs2Mouse
|
|||
|
|
|||
|
PS2MouseFound:
|
|||
|
|
|||
|
;
|
|||
|
; Set mouse type and subtype to mouse info structure
|
|||
|
;
|
|||
|
|
|||
|
mov bx, offset MouseInfo
|
|||
|
mov [bx].MouseSubtype, al
|
|||
|
mov [bx].MouseType, ah
|
|||
|
mov [bx].MouseIrq, 12
|
|||
|
mov [bx].MousePort, 0ffffh
|
|||
|
mov [bx].DeviceIdLength, di
|
|||
|
mov MouseDetected, bx
|
|||
|
|
|||
|
ExitPs2Mouse:
|
|||
|
|
|||
|
;
|
|||
|
; Drain 8042 input buffer and leave leave pointing device disabled.
|
|||
|
; We don't want user moves the mouse and hangs the system.
|
|||
|
;
|
|||
|
|
|||
|
call _Empty8042
|
|||
|
mov ax, bx
|
|||
|
pop di
|
|||
|
pop si
|
|||
|
pop bx
|
|||
|
ret
|
|||
|
|
|||
|
_LookForPS2Mouse endp
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; USHORT
|
|||
|
; LookForInportMouse (
|
|||
|
; VOID
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This function determines mouse type in the system.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; (eax): mouse Id.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
public _LookForInportMouse
|
|||
|
_LookForInportMouse proc near
|
|||
|
|
|||
|
push bx
|
|||
|
mov dx,INPORT_FIRST_PORT + 2 ; Get address of ID register.
|
|||
|
|
|||
|
inport_try_again:
|
|||
|
call TestForInport ; Does an InPort exist at this address?
|
|||
|
jnc inport_found ; No carry ! Inport found !
|
|||
|
|
|||
|
sub dx,4 ; Nope, try the next possible port.
|
|||
|
cmp dx,INPORT_LAST_PORT + 2
|
|||
|
jae inport_try_again
|
|||
|
|
|||
|
mov ax, 0 ; Fail to detect inport mouse
|
|||
|
jmp short no_inport
|
|||
|
|
|||
|
inport_found:
|
|||
|
|
|||
|
;
|
|||
|
; Set mouse type and subtype to mouse info structure
|
|||
|
;
|
|||
|
|
|||
|
mov ax,MS_MOUSE + INPORT_MOUSE
|
|||
|
mov cx, dx
|
|||
|
sub cx, 2
|
|||
|
mov bx, offset MouseInfo
|
|||
|
mov [bx].DeviceIdLength, 0
|
|||
|
mov [bx].MouseSubtype, al
|
|||
|
mov [bx].MouseType, ah
|
|||
|
mov [bx].MousePort, cx
|
|||
|
mov InportIoBase, cx
|
|||
|
mov MouseDetected, bx
|
|||
|
lea ax, [bx].MouseIrq
|
|||
|
push ax
|
|||
|
push cx ; Current Port
|
|||
|
call _InportMouseIrqDetection
|
|||
|
add sp, 4
|
|||
|
mov ax, offset MouseInfo
|
|||
|
|
|||
|
no_inport:
|
|||
|
pop bx
|
|||
|
ret
|
|||
|
|
|||
|
_LookForInportMouse endp
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; USHORT
|
|||
|
; LookForBusMouse (
|
|||
|
; VOID
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will attempt to find a bus mouse adaptor in the system
|
|||
|
; and will return the results of this search.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; (ax) = Mouse ID.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
public _LookForBusMouse
|
|||
|
_LookForBusMouse proc near
|
|||
|
|
|||
|
;
|
|||
|
; If We already found Inport mouse and its IO base is 23ch, it is
|
|||
|
; impossible to have a BUS mouse.
|
|||
|
;
|
|||
|
|
|||
|
cmp InportIoBase, BUS_MOUSE_BASE
|
|||
|
jne short @f
|
|||
|
mov ax, 0
|
|||
|
ret
|
|||
|
|
|||
|
@@:
|
|||
|
push bx
|
|||
|
|
|||
|
;
|
|||
|
; We determine if the bus mouse adaptor is present by attempting to
|
|||
|
; program the 8255A, and then seeing if we can write a value out to
|
|||
|
; Port B on the 8255A and get that value back. If we can, we assume
|
|||
|
; that we have a bus mouse adaptor.
|
|||
|
;
|
|||
|
|
|||
|
mov dx,BUS_INIT ; Get address of 8255A control port.
|
|||
|
mov al,BUS_INIT_VALUE ; Get proper value.
|
|||
|
DelayOut ; Set up 8255A.
|
|||
|
mov ax,0A5A5h ; Get a signature byte.
|
|||
|
address BUS_SIG BUS_INIT ; Get address of Port B.
|
|||
|
DelayOut ; Set Port B with signature.
|
|||
|
DelayIn ; Read back Port B.
|
|||
|
|
|||
|
cmp al,ah ; Does it match signature byte?
|
|||
|
jne No_Bus_Mouse ; Nope - no bus mouse adaptor
|
|||
|
|
|||
|
mov ax,MS_MOUSE + BUS_MOUSE
|
|||
|
jmp short Bus_Mouse_Found
|
|||
|
|
|||
|
No_Bus_Mouse:
|
|||
|
mov ax, 0 ; No Bus Mouse detected
|
|||
|
jmp short Bus_Exit
|
|||
|
|
|||
|
Bus_Mouse_Found:
|
|||
|
|
|||
|
;
|
|||
|
; Set mouse type and subtype to mouse info structure
|
|||
|
;
|
|||
|
|
|||
|
mov dx, BUS_MOUSE_BASE
|
|||
|
mov bx, offset MouseInfo
|
|||
|
mov [bx].DeviceIdLength, 0
|
|||
|
mov [bx].MouseSubtype, al
|
|||
|
mov [bx].MouseType, ah
|
|||
|
mov [bx].MousePort, dx
|
|||
|
mov MouseDetected, bx
|
|||
|
call BusMouseIrqDetection
|
|||
|
mov [bx].MouseIrq, ax ; if (ax) = 0xffff, no irq detected
|
|||
|
mov ax, offset MouseInfo ; return MouseInfor
|
|||
|
Bus_Exit:
|
|||
|
pop bx
|
|||
|
ret
|
|||
|
|
|||
|
_LookForBusMouse endp
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; USHORT
|
|||
|
; BusMouseIrqDetection (
|
|||
|
; USHORT Port
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will attempt to find the irq level associated with the
|
|||
|
; Bus mouse in the machine.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; (dx) = Bus mouse base I/O port.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; (ax) = Irq level. if (ax)= 0xffff, detection failed.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
BusMouseIrqDetection proc near
|
|||
|
|
|||
|
push bx
|
|||
|
|
|||
|
add dx, 2 ; use adaptor control port
|
|||
|
in al,dx ; Get irq 2-5 states
|
|||
|
IOdelay
|
|||
|
mov ah,al ; Save states
|
|||
|
mov cx,10000 ; Set loop count
|
|||
|
xor bh,bh ; Clear changes buffer
|
|||
|
|
|||
|
@@:
|
|||
|
in al,dx ; Get current states of irq 2-5
|
|||
|
IOdelay
|
|||
|
xor ah,al ; Compare with last state
|
|||
|
or bh,ah ; Mark any changes
|
|||
|
mov ah,al ; Previous := current state
|
|||
|
loop @B ; Keep looking
|
|||
|
|
|||
|
mov ax, 0ffffh
|
|||
|
or bh,bh ; Any irq found?
|
|||
|
jz short BusIntExit ; Branch if no interrupt was found
|
|||
|
|
|||
|
BusIntFound:
|
|||
|
mov ax,5 ; Assume irq5
|
|||
|
test bh,0001b ; Is it off?
|
|||
|
jnz short BusIntExit ; Yes..have irq5
|
|||
|
mov ax,2 ; Assume irq2
|
|||
|
test bh,1000b
|
|||
|
jnz short BusIntExit
|
|||
|
inc ax ; Try irq3
|
|||
|
test bh,0100b
|
|||
|
jnz short BusIntExit
|
|||
|
inc ax ; Must be irq4
|
|||
|
|
|||
|
BusIntExit: ; ax contains the IRQ number
|
|||
|
pop bx
|
|||
|
ret
|
|||
|
|
|||
|
BusMouseIrqDetection endp
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; USHORT
|
|||
|
; LookForSerialMouse (
|
|||
|
; VOID
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will attempt to find a serial mouse adaptor in the system
|
|||
|
; and will return the results of this search.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; (ax) = Mouse ID.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
public _LookForSerialMouse
|
|||
|
_LookForSerialMouse proc near
|
|||
|
|
|||
|
push di
|
|||
|
push bx
|
|||
|
|
|||
|
mov di, NextComPort ; Get untested comport
|
|||
|
cmp di, 8 ; Have we over the comport limit?
|
|||
|
jae short No_Serial_Mouse ; if above or e, yes, exit
|
|||
|
|
|||
|
serial_try_again:
|
|||
|
mov cx, di
|
|||
|
mov al, 1
|
|||
|
shr cx, 1
|
|||
|
inc cx
|
|||
|
shl ax, cl
|
|||
|
test _DisableSerialMice, ax ; Should we skip this com port?
|
|||
|
jnz short serial_next_port ; yes, try next one.
|
|||
|
|
|||
|
mov dx, _ComPortAddress[di] ; Get base address of COM port to test.
|
|||
|
or dx,dx ; Does this port exist?
|
|||
|
jz serial_next_port ; No, try next one.
|
|||
|
|
|||
|
serial_test_port:
|
|||
|
|
|||
|
;
|
|||
|
; The comport address is initialized by com detection routine. if the port
|
|||
|
; value is not zero, it means that the port exist.
|
|||
|
;
|
|||
|
|
|||
|
call TestForSerial ; Is a serial mouse attached to port?
|
|||
|
cmp ax,NO_MOUSE
|
|||
|
jne Serial_Mouse_Found ; Yes! found a serial mouse
|
|||
|
|
|||
|
serial_next_port: ; No serial mouse on this COM port.
|
|||
|
add di,2 ; move to the next possible port
|
|||
|
cmp di,8 ; Are we over com limit?
|
|||
|
jb serial_try_again ; if b, no, go test it.
|
|||
|
|
|||
|
mov NextComport, di
|
|||
|
No_Serial_Mouse:
|
|||
|
mov ax, 0 ; No serial mouse detected
|
|||
|
jmp short SerialMouseExit
|
|||
|
|
|||
|
Serial_Mouse_Found:
|
|||
|
mov NextComport, di
|
|||
|
add NextComport, 2 ; Next comport to test
|
|||
|
|
|||
|
shr di, 1 ; divide di by 2
|
|||
|
|
|||
|
;
|
|||
|
; Set mouse type and subtype to mouse info structure
|
|||
|
;
|
|||
|
|
|||
|
mov bx, offset MouseInfo
|
|||
|
mov [bx].DeviceIdLength, 0
|
|||
|
cmp ax, MS_MOUSE + SERIAL_MOUSE_WITH_WHEEL
|
|||
|
jnz short @f
|
|||
|
|
|||
|
mov [bx].DeviceIdLength, 7
|
|||
|
@@:
|
|||
|
mov [bx].MouseSubtype, al
|
|||
|
mov [bx].MouseType, ah
|
|||
|
mov [bx].MousePort, di
|
|||
|
mov [bx].MouseIrq, 0ffffh
|
|||
|
mov MouseDetected, bx
|
|||
|
mov ax, bx
|
|||
|
|
|||
|
SerialMouseExit:
|
|||
|
pop bx
|
|||
|
pop di
|
|||
|
ret
|
|||
|
|
|||
|
_LookForSerialMouse endp
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; BOOLEAN
|
|||
|
; TestForInport (
|
|||
|
; USHORT Port
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will attempt to find an InPort mouse at the given base
|
|||
|
; I/O address. Note that if an InPort is found, it will be left
|
|||
|
; in a state where it will not be generating any interrupts.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; Port (DX) - I/O address of Inport identification register.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; NC - An Inport was found
|
|||
|
; CY - No Inport was found
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
TestForInport PROC NEAR
|
|||
|
|
|||
|
push bx
|
|||
|
push si
|
|||
|
|
|||
|
;
|
|||
|
; Since the identification register alternates between returning back
|
|||
|
; the Inport chip signature and the version/revision, if we have an
|
|||
|
; InPort chip, the chip signature will be read in one of the following
|
|||
|
; two reads. If it isn't, we do not have an InPort chip.
|
|||
|
;
|
|||
|
|
|||
|
mov bl,INPORT_ID
|
|||
|
in al,dx ; Read ID register.
|
|||
|
cmp al,bl ; Is value the InPort chip signature?
|
|||
|
je possible_inport ; Yes, go make sure we have an InPort.
|
|||
|
in al,dx ; Read ID register again.
|
|||
|
cmp al,bl ; Is value the InPort chip signature?
|
|||
|
jne inport_not_found ; No, return error
|
|||
|
|
|||
|
;
|
|||
|
; At this point, we managed to read the InPort chip signature, so we have
|
|||
|
; a possible InPort chip. The next read from the ID register will
|
|||
|
; return the version/revision. We then make sure that the ID register
|
|||
|
; alternates between the chip signature and this version/revision. If
|
|||
|
; it does, we have an InPort chip.
|
|||
|
;
|
|||
|
|
|||
|
possible_inport:
|
|||
|
in al,dx ; Read version/revision.
|
|||
|
mov ah,al ; Save it.
|
|||
|
mov cx,5 ; Test ID register 5 times.
|
|||
|
|
|||
|
inport_check:
|
|||
|
in al,dx ; Read ID register.
|
|||
|
cmp al,bl ; Make sure it is the chip signature.
|
|||
|
jne inport_not_found ; If not, we don't have an InPort chip.
|
|||
|
in al,dx ; Read ID register.
|
|||
|
cmp al,ah ; Make sure version/revision is same.
|
|||
|
jne inport_not_found ; If not, we don't have an InPort chip.
|
|||
|
loop inport_check ; Test desired number of times.
|
|||
|
|
|||
|
clc
|
|||
|
pop si
|
|||
|
pop bx
|
|||
|
ret
|
|||
|
;
|
|||
|
; At this point, we know we have an InPort chip.
|
|||
|
;
|
|||
|
|
|||
|
inport_not_found: ; We don't have an InPort chip.
|
|||
|
stc ; Show failure.
|
|||
|
pop si
|
|||
|
pop bx
|
|||
|
ret ; Return to caller.
|
|||
|
|
|||
|
TestForInport ENDP
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; BOOLEAN
|
|||
|
; TestForSerial (
|
|||
|
; USHORT Port
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will attempt to find a serial mouse adaptor in the system
|
|||
|
; and will return the results of this search.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; (dx) = Port Address.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; (ax) = Mouse ID.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
TestForSerial PROC NEAR
|
|||
|
|
|||
|
call SaveCOMSetting
|
|||
|
|
|||
|
call SetupCOMForMouse ; Set up COM port to talk to mouse.
|
|||
|
|
|||
|
mov cx,SHORTDELAY ; Use a short delay time.
|
|||
|
call ResetSerialMouse ; Reset mouse to see if it is there.
|
|||
|
cmp ax,NO_MOUSE
|
|||
|
jne TFS_Found
|
|||
|
|
|||
|
;
|
|||
|
; If a mouse has been detected, most likely there won't be second mouse.
|
|||
|
; so we don't test for LONGDELAY to save some time
|
|||
|
;
|
|||
|
|
|||
|
cmp MouseDetected, 0
|
|||
|
jne short @f
|
|||
|
|
|||
|
mov cx,LONGDELAY ; Maybe the mouse is just slow.
|
|||
|
call ResetSerialMouse ; Reset mouse to see if it is there.
|
|||
|
cmp ax,NO_MOUSE
|
|||
|
jne TFS_Found
|
|||
|
|
|||
|
@@:
|
|||
|
call TestForLogitechSerial ; Maybe it's a Logitech Series C
|
|||
|
|
|||
|
TFS_Found:
|
|||
|
push ax ; Save return value
|
|||
|
call RestoreCOMSetting
|
|||
|
pop ax
|
|||
|
ret
|
|||
|
|
|||
|
TestForSerial ENDP
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; VOID
|
|||
|
; SaveCOMSetting (
|
|||
|
; USHORT Port
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will save the current state of the COM port given.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; Port (DX) - Base address of COM port.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
SaveCOMSetting PROC NEAR
|
|||
|
|
|||
|
push dx ; Save base I/O address.
|
|||
|
address LCR RXB ; Get address of Line Control Register.
|
|||
|
DelayIn ; Get current contents.
|
|||
|
mov [LCRSave],al ; Save them.
|
|||
|
or al,LC_DLAB ; Set up to access divisor latches.
|
|||
|
DelayOut
|
|||
|
address LATMSB LCR ; Get address of high word of divisor
|
|||
|
DelayIn ; latch and save its current contents.
|
|||
|
mov [LATMSBSave],al
|
|||
|
address LATLSB LATMSB ; Get address of low word of divisor
|
|||
|
DelayIn ; latch and save its current contents.
|
|||
|
mov [LATLSBSave],al
|
|||
|
address LCR LATLSB ; Get address of Line Control Register
|
|||
|
mov al,[LCRSave] ; and disable access to divisor.
|
|||
|
and al,NOT LC_DLAB
|
|||
|
DelayOut
|
|||
|
address MCR LCR ; Get address of Modem Control Register
|
|||
|
DelayIn ; and save its current contents.
|
|||
|
mov [MCRSave],al
|
|||
|
address IER MCR ; Get address of Interrupt Enable Reg-
|
|||
|
DelayIn ; ister and save its current contents.
|
|||
|
mov [IERSave],al
|
|||
|
pop dx ; Restore base I/O address.
|
|||
|
ret
|
|||
|
|
|||
|
SaveCOMSetting ENDP
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; VOID
|
|||
|
; RestoreCOMSetting (
|
|||
|
; USHORT Port
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will restore the current state of the COM port given.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; Port (DX) - Base address of COM port.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
RestoreCOMSetting PROC NEAR
|
|||
|
|
|||
|
push dx ; Save base I/O address.
|
|||
|
address LCR RXB ; Get address of Line Control Register.
|
|||
|
mov al,LC_DLAB ; Set up to access divisor latches.
|
|||
|
DelayOut
|
|||
|
address LATMSB LCR ; Get address of high word of divisor
|
|||
|
mov al,[LATMSBSave] ; and restore it.
|
|||
|
DelayOut
|
|||
|
address LATLSB LATMSB ; Get address of low word of divisor
|
|||
|
mov al,[LATLSBSave] ; and restore it.
|
|||
|
DelayOut
|
|||
|
address LCR LATLSB ; Get address of Line Control Register
|
|||
|
mov al,[LCRSave] ; and restore it, disabling access to
|
|||
|
and al,NOT LC_DLAB ; the divisor latches.
|
|||
|
DelayOut
|
|||
|
address MCR LCR ; Get addres of Modem Control Register
|
|||
|
mov al,[MCRSave] ; and restore it.
|
|||
|
DelayOut
|
|||
|
address IER MCR ; Get address of Interrupt Enable Reg-
|
|||
|
mov al,[IERSave] ; ister and restore it.
|
|||
|
DelayOut
|
|||
|
pop dx ; Restore base I/O address.
|
|||
|
ret
|
|||
|
|
|||
|
RestoreCOMSetting ENDP
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; VOID
|
|||
|
; SetupCOMForMouse (
|
|||
|
; USHORT Port
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will set up the given COM port so that it can talk to
|
|||
|
; a serial mouse.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; Port (DX) - Base address of COM port to set up.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; COM port set up, all interrupts disabled at COM port
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
SetupCOMForMouse PROC NEAR
|
|||
|
|
|||
|
push dx ; Save base I/O address.
|
|||
|
mov cx, 60h
|
|||
|
call SetBaudRate
|
|||
|
|
|||
|
address LCR RXB
|
|||
|
mov al,LC_BITS7 + LC_STOP1 + LC_PNONE
|
|||
|
DelayOut ; Set 7,n,1; disable access to divisor.
|
|||
|
address IER LCR ; Get address of Int. Enable Register
|
|||
|
xor al,al ; Disable all interrupts at the COM
|
|||
|
DelayOut ; port level.
|
|||
|
address LSR IER ; Get address of Line Status Reg.
|
|||
|
DelayIn ; Read it to clear any errors.
|
|||
|
pop dx ; Restore base I/O address
|
|||
|
ret
|
|||
|
|
|||
|
SetupCOMForMouse ENDP
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; USHORT
|
|||
|
; ResetSerialMouse (
|
|||
|
; USHORT Port,
|
|||
|
; USHORT Delay
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will reset a serial mouse on the given COM port and will
|
|||
|
; return an indication of whether a mouse responded or not.
|
|||
|
;
|
|||
|
; The function now also checks for the presence of a 'B' as well as an
|
|||
|
; 'M' to determine the presence of a pointing device. Also, if the 'M' is
|
|||
|
; followed by a '3' the serial mouse is a Logitech.
|
|||
|
;
|
|||
|
; Mouse returns M
|
|||
|
; Ballpoint returns B
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; Port (DX) - Base I/O address of COM port to use
|
|||
|
; Delay (CX) - Number of msecs to use for delays
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; (ax) = Mouse Type.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
ResetSerialMouse PROC NEAR
|
|||
|
|
|||
|
push dx ; Save environment.
|
|||
|
push si
|
|||
|
push di
|
|||
|
push es
|
|||
|
|
|||
|
address IER RXB ; Get address of Interrupt Enable Reg.
|
|||
|
DelayIn ; Get current contents of IER and
|
|||
|
push ax ; save them.
|
|||
|
push dx ; Save address of IER.
|
|||
|
xor al,al ; Disable all interrupts at the
|
|||
|
DelayOut ; COM port level.
|
|||
|
|
|||
|
address MCR IER ; Get address of Modem Control Reg.
|
|||
|
mov al,MC_DTR ; Set DTR active; RTS, OUT1, and OUT2
|
|||
|
DelayOut ; inactive. This powers down mouse.
|
|||
|
|
|||
|
push cx ; Save amount of time to delay.
|
|||
|
call SetupForWait ; Set up BX:CX and ES:DI properly for
|
|||
|
assume es:nothing ; upcoming delay loop.
|
|||
|
|
|||
|
address RXB MCR ; Get address of Receive Buffer.
|
|||
|
|
|||
|
;
|
|||
|
; Now, we wait the specified amount of time, throwing away any stray
|
|||
|
; data that we receive. This gives the mouse time to properly reset
|
|||
|
; itself.
|
|||
|
;
|
|||
|
|
|||
|
rsm_waitloop:
|
|||
|
in al, dx ; Read and ignore any stray data.
|
|||
|
call IsWaitOver ; Determine if we've delayed enough.
|
|||
|
jnc rsm_waitloop ; If not, keep waiting.
|
|||
|
|
|||
|
;
|
|||
|
; Wait is over.
|
|||
|
;
|
|||
|
|
|||
|
address LSR RXB ; Get address of Line Status Reg.
|
|||
|
DelayIn ; Read it to clear any errors.
|
|||
|
address MCR LSR ; Get address of Modem COntrol Reg.
|
|||
|
mov al,MC_DTR+MC_RTS ; Set DTR, RTS, and OUT2 active
|
|||
|
; OUT1 inactive.
|
|||
|
DelayOut ; This powers up the mouse.
|
|||
|
|
|||
|
pop cx ; Get amount of time to delay.
|
|||
|
call SetupForWait ; Set up BX:CX and ES:DI properly for
|
|||
|
assume es:nothing ; the upcoming delay loop.
|
|||
|
|
|||
|
;
|
|||
|
; We give the mouse the specified amount of time to respond by sending
|
|||
|
; us an M. If it doesn't, or we get more than 5 characters that aren't
|
|||
|
; an M, we return a failure indication.
|
|||
|
;
|
|||
|
|
|||
|
address LSR MCR ; Get address of Line Status Reg.
|
|||
|
mov si, 5 ; Read up to 5 chars from port.
|
|||
|
mov bl,'3' ; '3' will follow 'M' on Logitech.
|
|||
|
mov bh,'B' ; 'B' for BALLPOINT
|
|||
|
mov ah,'M' ; Get an M. (We avoid doing a cmp al,M
|
|||
|
; because the M could be left floating
|
|||
|
; due to capacitance.)
|
|||
|
rsm_getchar:
|
|||
|
DelayIn ; Get current status.
|
|||
|
test al,LS_DR ; Is there a character in Receive Buff?
|
|||
|
jnz rsm_gotchar ; Yes! Go and read it.
|
|||
|
call IsWaitOver ; No, determine if we've timed out.
|
|||
|
jnc rsm_getchar ; Haven't timed out; keep looking.
|
|||
|
|
|||
|
mov bx,NO_MOUSE
|
|||
|
jmp rsm_leave ; Timed out. Leave with NO_MOUSE.
|
|||
|
|
|||
|
rsm_gotchar:
|
|||
|
|
|||
|
address RXB LSR ; Get address of Receive Buffer.
|
|||
|
DelayIn ; Get character that was sent to us.
|
|||
|
cmp al,ah ; Is it an M?
|
|||
|
jne check_for_b
|
|||
|
|
|||
|
;
|
|||
|
; We received an 'M', now wait for next character to see if it is a '3'.
|
|||
|
;
|
|||
|
|
|||
|
mov cx,1 ; Wait between 55.5 and 111ms for
|
|||
|
call SetupForWait ; next character.
|
|||
|
address LSR RXB
|
|||
|
|
|||
|
rsm_waitfor3:
|
|||
|
DelayIn ; Get current status.
|
|||
|
test al,LS_DR ; Is there a character in Receive Buff?
|
|||
|
jnz rsm_gotchar3 ; Yes! Go and read it.
|
|||
|
call IsWaitOver ; No, determine if we've timed out.
|
|||
|
jnc rsm_waitfor3 ; Haven't timed out; keep looking.
|
|||
|
|
|||
|
;
|
|||
|
; Not a Logitech - must be a standard Microsoft compatible serial mouse.
|
|||
|
;
|
|||
|
|
|||
|
jmp rsm_notLT
|
|||
|
|
|||
|
rsm_gotchar3:
|
|||
|
address RXB LSR ; Get address of Receive Buffer.
|
|||
|
DelayIn ; Get character that was sent to us.
|
|||
|
cmp al,bl ; Is it a 3?
|
|||
|
jne short rsm_check_for_z
|
|||
|
|
|||
|
mov bx,LT_MOUSE + SERIAL_MOUSE ; Yes, we've found a Logitech M+
|
|||
|
jmp rsm_leave ; series, 3 button mouse
|
|||
|
|
|||
|
rsm_check_for_z:
|
|||
|
|
|||
|
;
|
|||
|
; Determine if this is Microsoft mouse with wheel.
|
|||
|
; 'M', 'Z', 0x40, 0x00, 0x00, 0x00, PnP String
|
|||
|
;
|
|||
|
cmp al, 'Z'
|
|||
|
jnz rsm_notLT
|
|||
|
|
|||
|
;
|
|||
|
; Check for 0x40, 0x00, 0x00, 0x00
|
|||
|
;
|
|||
|
|
|||
|
mov ebx, 040h
|
|||
|
mov cx, 4
|
|||
|
address LSR RXB
|
|||
|
rsm_get_byte:
|
|||
|
push cx
|
|||
|
mov cx,1 ; Wait between 55.5 and 111ms for
|
|||
|
call SetupForWait ; next character.
|
|||
|
@@:
|
|||
|
DelayIn ; Get current status.
|
|||
|
test al,LS_DR ; Is there a character in Receive Buff?
|
|||
|
jnz short @f ; Yes! Go and read it.
|
|||
|
|
|||
|
call IsWaitOver ; No, determine if we've timed out.
|
|||
|
jnc short @b ; Haven't timed out; keep looking.
|
|||
|
jmp rsm_notMZ
|
|||
|
|
|||
|
@@:
|
|||
|
address RXB LSR ; Get address of Receive Buffer.
|
|||
|
DelayIn ; Get character that was sent to us.
|
|||
|
cmp al,bl ; Is it a MS wheel?
|
|||
|
jnz rsm_notMZ
|
|||
|
|
|||
|
shr ebx, 8
|
|||
|
address LSR RXB
|
|||
|
pop cx
|
|||
|
sub cx, 1
|
|||
|
jnz rsm_get_byte
|
|||
|
|
|||
|
;
|
|||
|
; Next read PnP string for the MS wheel mouse
|
|||
|
; First skip 3 bytes: 08 + 2-byte Rev number
|
|||
|
;
|
|||
|
|
|||
|
mov cx, 3
|
|||
|
rsm_get_byte1:
|
|||
|
push cx
|
|||
|
mov cx,1 ; Wait between 55.5 and 111ms for
|
|||
|
call SetupForWait ; next character.
|
|||
|
@@:
|
|||
|
DelayIn ; Get current status.
|
|||
|
test al,LS_DR ; Is there a character in Receive Buff?
|
|||
|
jnz short @f ; Yes! Go and read it.
|
|||
|
|
|||
|
call IsWaitOver ; No, determine if we've timed out.
|
|||
|
jnc short @b ; Haven't timed out; keep looking.
|
|||
|
jmp rsm_notMZ
|
|||
|
|
|||
|
@@:
|
|||
|
address RXB LSR ; Get address of Receive Buffer.
|
|||
|
DelayIn ; Get character that was sent to us.
|
|||
|
address LSR RXB
|
|||
|
pop cx
|
|||
|
sub cx, 1
|
|||
|
jnz rsm_get_byte1
|
|||
|
|
|||
|
;
|
|||
|
; Next read 7 bytes PnpDevice id
|
|||
|
|
|||
|
mov si, offset MouseInfo
|
|||
|
lea si, [si].DeviceId
|
|||
|
|
|||
|
mov cx, 7
|
|||
|
rsm_get_byte2:
|
|||
|
push cx
|
|||
|
mov cx,1 ; Wait between 55.5 and 111ms for
|
|||
|
call SetupForWait ; next character.
|
|||
|
@@:
|
|||
|
DelayIn ; Get current status.
|
|||
|
test al,LS_DR ; Is there a character in Receive Buff?
|
|||
|
jnz short @f ; Yes! Go and read it.
|
|||
|
|
|||
|
call IsWaitOver ; No, determine if we've timed out.
|
|||
|
jnc short @b ; Haven't timed out; keep looking.
|
|||
|
jmp rsm_notMZ
|
|||
|
|
|||
|
@@:
|
|||
|
address RXB LSR ; Get address of Receive Buffer.
|
|||
|
DelayIn ; Get character that was sent to us.
|
|||
|
mov [si], al
|
|||
|
inc si
|
|||
|
address LSR RXB
|
|||
|
pop cx
|
|||
|
sub cx, 1
|
|||
|
jnz rsm_get_byte2
|
|||
|
|
|||
|
mov byte ptr [si], 0 ; add device id terminated null
|
|||
|
mov bx, MS_MOUSE + SERIAL_MOUSE_WITH_WHEEL
|
|||
|
jmp short rsm_leave ; We still have a standard serial mouse.
|
|||
|
|
|||
|
rsm_notMZ:
|
|||
|
pop cx
|
|||
|
rsm_notLT:
|
|||
|
mov bx,MS_MOUSE + SERIAL_MOUSE ; We didn't get the '3' after the 'M'
|
|||
|
jmp short rsm_leave ; We still have a standard serial mouse.
|
|||
|
|
|||
|
check_for_b:
|
|||
|
cmp al,bh ; Is it a B?
|
|||
|
jne rsm_next_char
|
|||
|
|
|||
|
mov bx,MS_BALLPOINT + SERIAL_MOUSE ; We've found a BallPoint Mouse
|
|||
|
jmp short rsm_leave
|
|||
|
|
|||
|
rsm_next_char:
|
|||
|
address LSR RXB ; Oh well. Get address of LSR again.
|
|||
|
dec si ; Have we read 5 chars yet?
|
|||
|
jnz rsm_getchar ; Nope, we'll give him another try.
|
|||
|
|
|||
|
;
|
|||
|
; We've read many characters - No a single 'M' or 'B' in the lot.
|
|||
|
;
|
|||
|
|
|||
|
mov bx,NO_MOUSE
|
|||
|
|
|||
|
rsm_leave:
|
|||
|
pop dx ; Get address of IER.
|
|||
|
pop ax ; Get old value of IER.
|
|||
|
DelayOut ; Restore IER.
|
|||
|
|
|||
|
pop es ; Restore environment.
|
|||
|
assume es:nothing
|
|||
|
pop di
|
|||
|
pop si
|
|||
|
pop dx
|
|||
|
mov ax,bx ; Set return value.
|
|||
|
ret
|
|||
|
|
|||
|
ResetSerialMouse ENDP
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; VOID
|
|||
|
; SetupForWait (
|
|||
|
; USHORT WaitTime
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure accepts the number of milliseconds that we will want
|
|||
|
; to delay for and will set things up for the wait.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; (CX) = Number of clock ticks to wait for.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
SetupForWait PROC NEAR
|
|||
|
|
|||
|
push ax ; Do your saving !
|
|||
|
push es
|
|||
|
|
|||
|
xor ax,ax
|
|||
|
mov es,ax ; Point to 40:6C = 0:46C
|
|||
|
|
|||
|
cli
|
|||
|
mov ax,es:[LW_ClockTickCount+2]
|
|||
|
mov [DWFinalCount+2],ax ; Save ending time (HiWord)
|
|||
|
mov ax,es:[LW_ClockTickCount] ; Get tick count in AX.
|
|||
|
sti
|
|||
|
|
|||
|
add ax,cx ; [Current + delay] = delay ends.
|
|||
|
mov [DWFinalCount],ax ; Save ending time (LoWord)
|
|||
|
jnc SFW_End
|
|||
|
|
|||
|
inc [DWFinalCount+2]
|
|||
|
|
|||
|
SFW_End:
|
|||
|
pop es ; Restore now !
|
|||
|
pop ax
|
|||
|
|
|||
|
ret
|
|||
|
|
|||
|
SetupForWait ENDP
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; BOOLEAN
|
|||
|
; IsWaitOver (
|
|||
|
; VOID
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure accepts the current time and the ending time and
|
|||
|
; return and indication of whether the current time is past
|
|||
|
; the ending time.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; carry clear Current time is not past ending time
|
|||
|
; carry set Current time is past ending time
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
IsWaitOver PROC NEAR
|
|||
|
|
|||
|
if 0
|
|||
|
push ax ; Preserve AX
|
|||
|
push es ; Preserve ES
|
|||
|
xor ax,ax
|
|||
|
mov es,ax ; Point to 40:6C = 0:46C
|
|||
|
|
|||
|
cli
|
|||
|
mov ax,es:[LW_ClockTickCount]
|
|||
|
mov [DWCurrCount],ax ; Save current time (LoWord)
|
|||
|
mov ax,es:[LW_ClockTickCount+2] ; Get tick count in AX.
|
|||
|
sti
|
|||
|
|
|||
|
cmp [DWFinalCount+2],ax ; Compare HiWords
|
|||
|
ja WaitNotOver ; Carry will be clear if wait
|
|||
|
; is not over.
|
|||
|
mov ax,es:[LW_ClockTickCount] ; Compare Lowords
|
|||
|
cmp [DWFinalCount],ax ; This will set CY accordingly
|
|||
|
|
|||
|
WaitNotOver:
|
|||
|
pop es ; Restore ES
|
|||
|
pop ax ; Restore AX
|
|||
|
ret
|
|||
|
|
|||
|
else
|
|||
|
|
|||
|
push ax ; Preserve AX
|
|||
|
push es ; Preserve ES
|
|||
|
xor ax,ax
|
|||
|
mov es,ax ; Point to 40:6C = 0:46C
|
|||
|
|
|||
|
cli
|
|||
|
mov ax,es:[LW_ClockTickCount]
|
|||
|
mov [DWCurrCount],ax ; Save current time (LoWord)
|
|||
|
mov ax,es:[LW_ClockTickCount+2] ; Get tick count in AX.
|
|||
|
sti
|
|||
|
|
|||
|
cmp [DWFinalCount+2],ax ; Compare HiWords
|
|||
|
jb WaitExit ; Time is up
|
|||
|
|
|||
|
jne WaitRollCheck ; If not equal check for
|
|||
|
|
|||
|
WaitLowCheck:
|
|||
|
mov ax,[DWCurrCount] ; Compare Lowords
|
|||
|
cmp [DWFinalCount],ax ; This will set CY accordingly
|
|||
|
|
|||
|
WaitExit:
|
|||
|
pop es ; Restore ES
|
|||
|
pop ax ; Restore AX
|
|||
|
ret
|
|||
|
|
|||
|
|
|||
|
WaitRollCheck:
|
|||
|
|
|||
|
; If the current time is less than the wait time we must check for
|
|||
|
; roll over. There are 18.2 * 60 * 60 * 24 or 0x1800b0 clock ticks in
|
|||
|
; a day. At midnight the counter rolls over to zero.
|
|||
|
|
|||
|
cmp ax,0
|
|||
|
jne WaitExit ; If current HiWord is not 0,
|
|||
|
; no roll over. Exit with
|
|||
|
; carry clear.
|
|||
|
|
|||
|
cmp [DWFinalCount+2],18h ; Is Final HiWord 0x18
|
|||
|
je short @f ; Yes, check LoWord for wrap.
|
|||
|
clc ; No, no roll over. Exit with
|
|||
|
; carry clear.
|
|||
|
jmp WaitExit
|
|||
|
|
|||
|
@@:
|
|||
|
mov ax,[DWFinalCount] ; Get final LoWord
|
|||
|
sub ax, 0b0h ; Check for wrap
|
|||
|
jb WaitExit ; No, no roll over. Exit with
|
|||
|
; cary set
|
|||
|
|
|||
|
; At this point we have determined that we have wrapped and that the
|
|||
|
; ending time is into the next day. Update the ending time
|
|||
|
|
|||
|
mov [DWFinalCount],ax ; Set final LoWord
|
|||
|
xor ax,ax
|
|||
|
mov [DWFinalCount+2],ax ; Zero final HiWord
|
|||
|
jmp WaitLowCheck ; Check LoWord
|
|||
|
|
|||
|
endif
|
|||
|
|
|||
|
IsWaitOver ENDP
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; USHORT
|
|||
|
; TestForLogitechSerial (
|
|||
|
; VOID
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will detect the presence of a Logitech Series C
|
|||
|
; serial mouse is present
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; (edx) = Port Address
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; (ax) = Mouse ID.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
|
|||
|
TestForLogitechSerial PROC NEAR
|
|||
|
|
|||
|
push di
|
|||
|
push bx
|
|||
|
sub sp, 10
|
|||
|
mov bx, sp
|
|||
|
mov word ptr [bx], 60h ; baud = 1200
|
|||
|
mov word ptr [bx + 2], 30h ; baud = 2400
|
|||
|
mov word ptr [bx + 4], 18h ; baud = 4800
|
|||
|
mov word ptr [bx + 6], 0ch ; baud = 9600
|
|||
|
mov word ptr [bx + 8], 0
|
|||
|
|
|||
|
;
|
|||
|
; Power up the C series mouse.
|
|||
|
;
|
|||
|
; Set both DTR and RTS to an active state
|
|||
|
; If DTR and RTS are already on, the power is on for at least 500ms
|
|||
|
; due to the MM serial mouse detection.
|
|||
|
;
|
|||
|
|
|||
|
address MCR RXB ; Get address of Modem Control Reg.
|
|||
|
DelayIn ; Get modem control byte
|
|||
|
|
|||
|
and al, MC_DTR + MC_RTS ; Check DTR and RTS
|
|||
|
cmp al, MC_DTR + MC_RTS
|
|||
|
je short @f ; the lines are high already
|
|||
|
|
|||
|
mov al, MC_DTR + MC_RTS ; Set DTR and RTS to an active state
|
|||
|
DelayOut ; and ...
|
|||
|
|
|||
|
mov cx,9 ; wait for 1/2 second to pwrup mouse
|
|||
|
call SetupForWait ; Set up BX:CX and ES:DI properly for
|
|||
|
assume es:nothing ; upcoming delay loop.
|
|||
|
; ask for current baud rate
|
|||
|
lt_waitloop1:
|
|||
|
call IsWaitOver ; Determine if we've delayed enough.
|
|||
|
jnc short lt_waitloop1
|
|||
|
|
|||
|
@@:
|
|||
|
;
|
|||
|
; Set the line control register to a format that the mouse can
|
|||
|
; understand (see below: the line is set after the report rate).
|
|||
|
;
|
|||
|
|
|||
|
address LCR MCR ; Get address of Line Control Reg.
|
|||
|
mov al,LC_BITS8 + LC_STOP1 + LC_PODD
|
|||
|
DelayOut
|
|||
|
|
|||
|
|
|||
|
;
|
|||
|
; Cycle through the different baud rates to detect the mouse.
|
|||
|
;
|
|||
|
|
|||
|
mov di, 0
|
|||
|
address RXB LCR
|
|||
|
|
|||
|
Tfs_Next_Baud:
|
|||
|
mov cx, [bx + di]
|
|||
|
cmp cx, 0
|
|||
|
je Tfs110 ; Reach the end of table
|
|||
|
|
|||
|
call SetBaudRate ; Set baud rate
|
|||
|
|
|||
|
;
|
|||
|
; Put the mouse in prompt mode.
|
|||
|
;
|
|||
|
|
|||
|
mov cl, 'D'
|
|||
|
call CSerWriteChar
|
|||
|
|
|||
|
|
|||
|
;
|
|||
|
; Set the MM protocol. This way we get the mouse to talk to us in a
|
|||
|
; specific format. This avoids receiving errors from the line
|
|||
|
; register.
|
|||
|
;
|
|||
|
|
|||
|
mov cl, 'S'
|
|||
|
call CSerWriteChar
|
|||
|
|
|||
|
address LCR RXB ; Get address of Line Control Reg.
|
|||
|
mov al,LC_BITS8 + LC_STOP1 + LC_PODD
|
|||
|
DelayOut
|
|||
|
|
|||
|
|
|||
|
;
|
|||
|
; Try to get the status byte.
|
|||
|
;
|
|||
|
|
|||
|
address RXB LCR
|
|||
|
mov cl, 's'
|
|||
|
call CSerWriteChar
|
|||
|
|
|||
|
;
|
|||
|
; Read back the status character.
|
|||
|
;
|
|||
|
|
|||
|
mov cx,2 ; Wait at least 55.5 ms for response.
|
|||
|
call SetupForWait
|
|||
|
assume es:nothing
|
|||
|
address LSR RXB
|
|||
|
|
|||
|
lt_waitloop2: ; (dx) = LSR reg
|
|||
|
DelayIn
|
|||
|
test al, LS_DR ; Is receiving buffer full?
|
|||
|
jnz short @f ; Yes, go read it.
|
|||
|
|
|||
|
lt_waitloop21: ; (dx) = LSR reg
|
|||
|
call IsWaitOver
|
|||
|
jnc short lt_waitloop2
|
|||
|
|
|||
|
address RXB LSR
|
|||
|
jmp short Tfs50
|
|||
|
|
|||
|
@@:
|
|||
|
address RXB LSR
|
|||
|
DelayIn
|
|||
|
cmp al, 04fh ; al = 4Fh means command understood
|
|||
|
je short Tfs100
|
|||
|
|
|||
|
address LSR RXB
|
|||
|
jmp short lt_waitloop21
|
|||
|
|
|||
|
Tfs50:
|
|||
|
add di, 2
|
|||
|
jmp Tfs_Next_Baud
|
|||
|
|
|||
|
Tfs100:
|
|||
|
|
|||
|
;
|
|||
|
; Found the C series mouse. Put the mouse back in a default mode.
|
|||
|
; The protocol is already set.
|
|||
|
;
|
|||
|
|
|||
|
;
|
|||
|
; Set to default baud rate 1200
|
|||
|
;
|
|||
|
|
|||
|
mov cl, '*'
|
|||
|
call CSerWriteChar
|
|||
|
mov cl, 'n'
|
|||
|
call CSerWriteChar
|
|||
|
|
|||
|
;
|
|||
|
; Wait for TX buffer empty
|
|||
|
;
|
|||
|
|
|||
|
mov cx, 1
|
|||
|
call SetupForWait
|
|||
|
address LSR RXB
|
|||
|
@@:
|
|||
|
DelayIn
|
|||
|
and al, LS_THRE + LS_TSRE
|
|||
|
cmp al, LS_THRE + LS_TSRE
|
|||
|
je short @f ; Wait for TX buffer empty
|
|||
|
call IsWaitOver
|
|||
|
jnc short @b
|
|||
|
|
|||
|
@@:
|
|||
|
address RXB LSR
|
|||
|
mov cx, 60h ; Set baud rate to 1200
|
|||
|
call SetBaudRate
|
|||
|
|
|||
|
;
|
|||
|
; Set mouse to default report rate
|
|||
|
;
|
|||
|
|
|||
|
mov cl, 'N'
|
|||
|
call CSerWriteChar
|
|||
|
|
|||
|
mov ax,LT_MOUSE + SERIAL_MOUSE
|
|||
|
jmp short lt_leave
|
|||
|
|
|||
|
Tfs110:
|
|||
|
mov ax,NO_MOUSE
|
|||
|
|
|||
|
lt_leave:
|
|||
|
add sp, 10 ; clear stack
|
|||
|
pop bx
|
|||
|
pop di
|
|||
|
ret
|
|||
|
|
|||
|
TestForLogitechSerial ENDP
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; VOID
|
|||
|
; SetBaudRate (
|
|||
|
; USHORT Port,
|
|||
|
; USHORT BaudRate
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will set up the given COM port so that it can talk to
|
|||
|
; a Logitech C series serial mouse.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; (DX) = COM Base address of COM port to set up.
|
|||
|
; (CX) = Baud Rate
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
SetBaudRate PROC NEAR
|
|||
|
push dx
|
|||
|
address LCR RXB ; Get address of Line Control Reg.
|
|||
|
DelayIn
|
|||
|
or al,LC_DLAB ; Set up to access divisor latches.
|
|||
|
DelayOut
|
|||
|
|
|||
|
address LATMSB LCR ; Get address of high word of divisor
|
|||
|
mov al, ch ; latch and set it with value for
|
|||
|
DelayOut ; specified baud.
|
|||
|
address LATLSB LATMSB ; Get address of low word of divisor
|
|||
|
mov al, cl ; latch and set it with value for
|
|||
|
DelayOut ; specified baud.
|
|||
|
|
|||
|
address LCR LATLSB ; Get address of Line Control Reg.
|
|||
|
DelayIn
|
|||
|
and al, NOT LC_DLAB ; Disable access divisor latches.
|
|||
|
DelayOut
|
|||
|
|
|||
|
mov cx, 1
|
|||
|
call SetupForWait
|
|||
|
@@:
|
|||
|
call IsWaitOver
|
|||
|
jnc short @b
|
|||
|
|
|||
|
pop dx
|
|||
|
ret
|
|||
|
|
|||
|
SetBaudRate ENDP
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; VOID
|
|||
|
; CSerWriteChar (
|
|||
|
; USHORT Port,
|
|||
|
; UCHAR Command
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will write a char/command to logitech C series mouse.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; (DX) = COM Base address of COM port to set up.
|
|||
|
; (CL) = Command
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
CserWriteChar proc near
|
|||
|
|
|||
|
push cx
|
|||
|
mov cx, 1
|
|||
|
call SetupForWait
|
|||
|
address LSR RXB
|
|||
|
@@:
|
|||
|
DelayIn
|
|||
|
and al, LS_THRE + LS_TSRE
|
|||
|
cmp al, LS_THRE + LS_TSRE
|
|||
|
je short @f ; Wait for TX buffer empty
|
|||
|
|
|||
|
call IsWaitOver
|
|||
|
jnc short @b
|
|||
|
|
|||
|
@@:
|
|||
|
address TXB LSR
|
|||
|
pop ax ; Send command
|
|||
|
DelayOut
|
|||
|
ret
|
|||
|
CserWriteChar endp
|
|||
|
|
|||
|
if 0
|
|||
|
|
|||
|
|
|||
|
;++
|
|||
|
;
|
|||
|
; VOID
|
|||
|
; FlushReceiveBuffer (
|
|||
|
; USHORT Port
|
|||
|
; )
|
|||
|
;
|
|||
|
; Routine Description:
|
|||
|
;
|
|||
|
; This procedure will flush receive buffer or until time out.
|
|||
|
;
|
|||
|
; Arguments:
|
|||
|
;
|
|||
|
; (DX) = COM Base address of COM port to set up.
|
|||
|
;
|
|||
|
; Return Value:
|
|||
|
;
|
|||
|
; None.
|
|||
|
;
|
|||
|
;--
|
|||
|
|
|||
|
FlushReceiveBuffer proc near
|
|||
|
|
|||
|
mov cx, 5
|
|||
|
call SetupForWait
|
|||
|
@@:
|
|||
|
address LSR RXB
|
|||
|
DelayIn
|
|||
|
test al, LS_DR
|
|||
|
jz short @f
|
|||
|
|
|||
|
address RXB LSR
|
|||
|
DelayIn
|
|||
|
call IsWaitOver
|
|||
|
jnc short @b
|
|||
|
|
|||
|
ret
|
|||
|
@@:
|
|||
|
address RXB LSR
|
|||
|
ret
|
|||
|
FlushReceiveBuffer endp
|
|||
|
|
|||
|
endif
|
|||
|
_TEXT ends
|
|||
|
|
|||
|
end
|