Hi,
I'd recommend using a reliable time base for your time-outs - the "mov ecx,0xFFFF; loop" will depend on the speed of the computer and isn't anywhere near long enough (unless you've got a 3 MHz CPU, or Bochs).
After sending 0xFF (reset device) you'll get an ACK fairly quickly, but then need to wait ages for the BAT results - for this I've got 2 seperate "get byte" routines, one for normal use with a 100 mS timeout and one for the BAT results with a 600 mS timeout. Your code (on a real computer) would give up waiting for the BAT results well before they're likely to arrive.
At the start you've got code to flush the output buffer (lines 9 and 61), which calls "__kbd8042obw" (wait for output buffer to become full). This will cause at least one timeout - it'd be better to use something like:
Code: Select all
;;*-------------------------------------------------------;;
;;void __kbd8042_force_output_empty()
;; CF = 0 - output buffer empty
;; CF = 1 - timeout
__kbd8042obw
push ecx
mov ecx, 0xffff ;;timeout
@kbd2p1:
in al, 0x64 ;;check status
test al, 00000001b ;;output buffer
je @kbd2p2
in al, 0x60
loop kbd2p1
stc
pop ecx
ret
@kbd2p1:
clc
pop ecx
ret
For the changes you make to the command byte (line 41) you do "and ah, 10111100b". On most controllers this would leave the clock signals to each device how they were previously, where it's probably best to either deliberately enable them or deliberately disable them. On older controllers there is no second device, and bit 5 doesn't control a clock signal. Instead it's used for communcations parameters and should be clear. Anyway, for these reasons I do "and ah, 10001100b" so I know any devices do have their clock signals enabled, and that it's not going to mess up older single-channel controllers.
AFAIK the default setting for the command byte on modern computers is for the clock to be enabled for the first channel, but disabled for the second channel. In this case your "i8042DeviceBdet__" code will be disabling an already disabled clock signal
.
I think the test in "i8042DeviceBdet__" is backwards. Sending command 0xA7 should disable the second device's clock signal (but it's ignored on older single-channel controllers). This causes the second device's clock bit in the controller command byte to become set (if the second channel is supported).
For this you'd want the following:
Code: Select all
;;extract the 2nd bit indicating if the IRQ (clock signal) for device B is enabled
;; "If clock signal to device B is still enabled, then assume the PS/2
;; controller is an older "single device" controller rather than
;; a "dual device" controller, and mark device B as unusable."
mov ah, al
and al, 00000010b
jnz @CONT23 ;Second channel present if bit is set
jmp @IDBI99 ;Else second channel not present
@CONT23:
If there is a second channel, then you'd want to re-enable it's clock signal again. You seem to be setting the controller command byte with the same value read previously, and then sending the 0xA8 command. You could enable the clock when you set the command byte (do an "and al, 10001100b" at line 320) and not send the 0xA8 at all, or you could send the 0xA8 and not worry about setting the controller command byte. You don't need both (they do the same thing).
Before I go further than this I normally disable scanning of any devices. The reason for this is that if someone presses a key or moves the mouse while you're expecting data from the other device then the unexpected data can block the data you are expecting from being received. Your code "i8042DeviceBdet__" doesn't disable device A scanning, so if someone presses a key at the wrong time it'll cause the results of the interface test, reset and/or identify to timeout.
For the identify command you should get data from a PS/2 mouse. On Bochs you don't get anything after the ACK, but on every real computer I tried and QEMU you do. I keep trying to receive ID bytes until I get a timeout, and use "shl edx,8; mov dl,al" for each byte. In this case bochs returns edx=0xFA (nothing after the ACK), a standard 2 button mouse returns edx=0xFA00 (1 byte after the ACK) and a standard keyboard returns "0xFAAB83" (2 bytes after the ACK).
Also, you don't need to do the "jmp short $+2" stuff unless you support 80386 CPUs..
Cheers,
Brendan