It seems to be working now all of a sudden by making one small change at the end of the test bit of code (after ps2 init) I resend ea to the mouse to enable stream mode. Bochs is rock solid.
So now both emulators are working. I've checked my BIOS and it doesn't have any ps/2 emulation options.
I've got an image/iso for cd we can try.. this silly forum won't let me attach it (200kb)... PM it?
I'm about to reboot and try with both usb's unplugged and then plugged in.. see what happens.
update code here...
Code: Select all
;======================================================================================
; Call before writing to 60h/64h.
;======================================================================================
kybd_ctrl_in_empty:
mov ecx,100000
clc
kybd_wait0:
in al,64h
test al,02h
jz short kybd_wait0_done
dec ecx
jnz short kybd_wait0
stc
kybd_wait0_done:
ret
;======================================================================================
; Call before reading from 60h.
;======================================================================================
kybd_ctrl_out_full:
mov ecx,100000
clc
kybd_wait1:
in al,64h
test al,01h
jnz short kybd_wait1_done
dec ecx
jnz short kybd_wait1
stc
kybd_wait1_done:
ret
;======================================================================================
; Empty the 8042 output buffer.
;======================================================================================
kybd_wait_8042:
in al,64h
test al,01h
jz short no_8042_data
in al,60h
jmp kybd_wait_8042
no_8042_data:
ret
;======================================================================================
; Wait for keyboard controller or mouse to return ACK.
;======================================================================================
kybd_wait_ack:
mov ecx,100000
clc
kybd_wait2:
in al,60h
cmp al,0fah
je short kybd_wait2_done
dec ecx
jnz short kybd_wait2
stc
kybd_wait2_done:
ret
;======================================================================================
; Wait for Keyboard/Mouse to send Reset 0aah,00h
;======================================================================================
kybd_wait_reset_ack:
mov ecx,100000
clc
kybd_wait3:
in al,60h ; This should be 0aah BAT passed.
cmp al,0aah
je short reset_ackok
dec ecx
jnz short kybd_wait3
stc
ret
reset_ackok:
in al,60h ; Read in 00h too.
ret
;======================================================================================
; Write to PS2 Device B (mouse).
; -> Command Byte in BL.
;======================================================================================
ps2_deviceB_write:
call kybd_ctrl_in_empty
mov al,0d4h
out 64h,al
call kybd_ctrl_in_empty
mov al,bl
out 60h,al
ret
;======================================================================================
; Return Device B ID
; -> BL is ID.
;======================================================================================
ps2_get_deviceB_id:
mov bl,0f2h ; Get MouseID command.
call ps2_deviceB_write
call kybd_wait_ack
call kybd_ctrl_out_full ; Wait for more data to be ready.
in al,60h ; Read MouseID byte.
ret
;======================================================================================
; Sample Rate in BL
; (10,20,40,60,80,100,200)
;======================================================================================
ps2_deviceB_set_sample:
push rbx
mov bl,0f3h ; Set Packet Sample-Rate Command.
call ps2_deviceB_write
call kybd_wait_ack
pop rbx
call ps2_deviceB_write
call kybd_wait_ack
ret
;======================================================================================
; Resolution in BL
; (0=1pixel/mm,1=2pixel/mm,2=4pixel/mm,3=8pixel/mm)
;======================================================================================
ps2_deviceB_set_resolution:
push rbx
mov bl,0e8h ; Set Packet Sample-Rate Command.
call ps2_deviceB_write
call kybd_wait_ack
pop rbx
call ps2_deviceB_write
call kybd_wait_ack
ret
;======================================================================================
; Set PS/2 Device B (Mouse) Scaling 2:1
;======================================================================================
ps2_deviceB_set_scaling21:
mov bl,0e7h
call ps2_deviceB_write
call kybd_wait_ack
ret
;======================================================================================
; Set PS/2 Device B (Mouse) Scaling 1:1
;======================================================================================
ps2_deviceB_set_scaling11:
mov bl,0e6h
call ps2_deviceB_write
call kybd_wait_ack
ret
;======================================================================================
; Enable PS/2 Device B (Mouse).
;======================================================================================
ps2_deviceB_enable:
mov bl,0f4h
call ps2_deviceB_write
call kybd_wait_ack
ret
;======================================================================================
; Disable PS/2 Device B (Mouse).
;======================================================================================
ps2_deviceB_disable:
mov bl,0f5h
call ps2_deviceB_write
call kybd_wait_ack
ret
;======================================================================================
; Initialize the PS/2 Controller Interface and Attached Devices.
;======================================================================================
ps2_ctrl_init:
;--------------------------------------------------------
; Begin Initialization - Determine PS2 Controller Type.
;--------------------------------------------------------
call kybd_ctrl_in_empty ; Wait for keyboard controller to be ready to receive a command.
mov al,0a8h ; Enable PS2 Aux Port and Mouse.
out 64h,al
call kybd_wait_ack
call kybd_wait_8042 ; Ensure we empty out the 8042 data port if it still has data in it.
call kybd_ctrl_in_empty ; Wait for keyboard controller to be ready to receive a command.
jnc short ps2_init00
mov [ps2_init_failed],1 ; Timeout when trying to communicate with ps2 controller.
ret
ps2_init00:
mov al,020h ; Send command 20h (read configuration byte).
out 64h,al
call kybd_ctrl_out_full ; Wait for the data to be ready.
jnc short ps2_init01
mov [ps2_init_failed],1 ; Timeout when trying to communicate with ps2 controller.
ret
ps2_init01:
in al,60h ; read configuration byte (no ACK).
call kybd_ctrl_in_empty ; Wait for keyboard controller to be ready to receive a command.
jnc short ps2_init02
mov [ps2_init_failed],1 ; Timeout when trying to communicate with ps2 controller.
ret
ps2_init02:
mov al,060h ; Send command 60h (set configuration byte).
out 64h,al
call kybd_ctrl_in_empty
jnc short ps2_init03
mov [ps2_init_failed],1 ; Timeout when trying to communicate with ps2 controller.
ret
ps2_init03:
mov al,00000100b ; New configuration byte (Enable PS/2 device A and B and BAT flag).
out 60h,al
call kybd_ctrl_in_empty
jnc short ps2_init04
mov [ps2_init_failed],1 ; Timeout when trying to communicate with ps2 controller.
ret
ps2_init04:
mov al,0a7h ; Send command a7h (disable device B).
out 64h,al
call kybd_ctrl_in_empty ; Wait for keyboard controller to be ready to receive a command.
jnc short ps2_init05
mov [ps2_init_failed],1 ; Timeout when trying to communicate with ps2 controller.
ret
ps2_init05:
mov al,020h ; Send command 20h (read configuration byte).
out 64h,al
call kybd_ctrl_out_full ; Wait for the data to be ready.
jnc short ps2_init06
mov [ps2_init_failed],1 ; Timeout when trying to communicate with ps2 controller.
ret
ps2_init06:
in al,60h ; read configuration byte.
test al,00100000b ; Is Device B still Enabled?
jnz short dual_ps2
;--------------------------------------------------------
; Single Port PS/2 Controller.
;--------------------------------------------------------
mov [ps2_ctrl_type],0
mov [ps2_deviceB_type],0 ; Since single port, device B must be none.
mov [ps2_deviceB_use],0 ; Ensure Device B is marked as unusable.
jmp short got_ps2_type
;--------------------------------------------------------
; Dual Port PS/2 Controller.
;--------------------------------------------------------
dual_ps2:
mov [ps2_ctrl_type],1
call kybd_wait_8042 ; Ensure the output buffer is empty.
call kybd_ctrl_in_empty ; Wait for keyboard controller to be ready to receive a command.
jnc short ps2_init07
mov [ps2_init_failed],1 ; Timeout when trying to communicate with ps2 controller.
ret
ps2_init07:
mov al,060h
out 64h,al
call kybd_ctrl_in_empty ; Wait for keyboard controller to be ready to receive a command.
jnc short ps2_init08
mov [ps2_init_failed],1 ; Timeout when trying to communicate with ps2 controller.
ret
ps2_init08:
mov al,00001100b ; Re-Enable both devices but leave IRQs off.
out 60h,al
mov [ps2_deviceA_use],1 ; Ensure so-far that both devices are flagged usable.
mov [ps2_deviceB_use],1
;--------------------------------------------------------
; We now know if the PS2 Controller is single/dual device
; -> Perform Interface tests on attached devices.
; -> From here it's safe to ignore the general
; -> PS2 timeouts as it should be in place.
; -> We'll ack. device specific timeouts now.
;--------------------------------------------------------
got_ps2_type:
call kybd_wait_8042
call kybd_ctrl_in_empty
mov al,0f5h ; Disable scanning for device A (keyboard).
out 60h,al
call kybd_wait_ack
cmp [ps2_deviceB_use],0
je short no_disable_devB ; No Device B so skip.
call kybd_ctrl_in_empty ; Disable packet sending (mouse) / disable device B.
mov al,0d4h
out 64h,al
call kybd_ctrl_in_empty
mov al,0f5h
out 60h,al
call kybd_wait_ack
;--------------------------------------------------------
; Perform Interface Test on Device A.
;--------------------------------------------------------
no_disable_devB:
call kybd_wait_8042
call kybd_ctrl_in_empty
mov al,0abh ; Device A Interface Test command.
out 64h,al
call kybd_ctrl_out_full
in al,60h
mov [ps2_deviceA_res],al
mov al,[ps2_deviceA_res]
test al,al
jz short devA_int_ok
mov [ps2_deviceA_use],0 ; Device A Interface Test failed, mark device unusable.
devA_int_ok:
cmp [ps2_deviceB_use],0
je short reset_devA ; No device B so skip.
;--------------------------------------------------------
; Perform Interface Test on Device B.
;--------------------------------------------------------
call kybd_wait_8042
call kybd_ctrl_in_empty
mov al,0a9h ; Test Mouse Port (Device B) command.
out 64h,al
call kybd_ctrl_out_full
in al,60h
mov [ps2_deviceB_res],al
mov al,[ps2_deviceB_res]
test al,al
jz short reset_devA
mov [ps2_deviceB_use],0 ; Device B Interface Test failed, mark device unsuable.
;--------------------------------------------------------
; Perform Reset of Device A.
;--------------------------------------------------------
reset_devA:
call kybd_wait_8042
call kybd_ctrl_in_empty
mov al,0ffh ; Reset device A command.
out 60h,al
call kybd_wait_reset_ack ; Keyboard might not ACK reset, so wait for 0aah instead.
jnc short ps2_init09
mov [ps2_deviceA_type],0 ; ACK from Device A failed, mark it as unusable for now.
mov [ps2_deviceA_use],0
jmp short reset_devB
ps2_init09:
call kybd_ctrl_out_full
in al,60h ; This should be 0aah BAT passed.
cmp al,0aah
je short reset_devB ; The BAT passed and we had ACK, device is responding ok.
mov [ps2_deviceA_use],0 ; Reset of Device A failed so mark it not usable.
;--------------------------------------------------------
; Perform Reset of Device B if present.
;--------------------------------------------------------
reset_devB:
cmp [ps2_deviceB_use],0
je short no_devB_reset ; Only attempt device B reset if present and working.
call kybd_wait_8042
call kybd_ctrl_in_empty
mov al,0d4h
out 64h,al
call kybd_ctrl_in_empty
mov al,0ffh
out 60h,al
call kybd_wait_reset_ack ; Reset Command might not ACK, rather wait for 0aah.
jnc short no_devB_reset
mov [ps2_deviceB_use],0 ; Reset of Device A failed, so mark it not usable.
mov [ps2_deviceB_type],0
;--------------------------------------------------------
; Disable Scanning on Device A again.
; -> Only if device responded to reset (use=1).
;--------------------------------------------------------
no_devB_reset:
cmp [ps2_deviceA_use],1
jne short no_descanA
call kybd_ctrl_in_empty
mov al,0f5h ; Disable scanning for device A (keyboard).
out 60h,al
call kybd_wait_ack
jnc short no_descanA
mov [ps2_deviceA_use],0 ; Disable Device A scanning failed, mark as unusable.
;--------------------------------------------------------
; Disable Scanning on Device B again.
; -> Only if device responded to reset (use=1).
;--------------------------------------------------------
no_descanA:
cmp [ps2_deviceB_use],1
jne short no_descanB
call kybd_ctrl_in_empty ; Disable packet sending (mouse) / disable device B.
mov al,0d4h
out 64h,al
call kybd_ctrl_in_empty
mov al,0f5h
out 60h,al
call kybd_wait_ack
jnc short no_descanB
mov [ps2_deviceB_use],0 ; Disable Device B scanning failed, mark as unusable.
;--------------------------------------------------------
; Identify Device A if it's still usable.
;--------------------------------------------------------
no_descanB:
cmp [ps2_deviceA_use],1
jne short identifyB ; Only identify device A if still present and usable.
call kybd_wait_8042
call kybd_ctrl_in_empty
mov al,0f2h ; Send the get keyboard ID command to encoder.
out 60h,al
mov rdi,offset ps2_deviceA_type
mov dword [rdi],0 ; Ensure device type is 0.
call kybd_wait_ack ; Wait for the ACK byte 0fah.
jnc short ps2_idA00
mov [ps2_deviceA_type],0 ; ACK from Device A failed, mark it as unusable for now.
mov [ps2_deviceA_use],0
jmp short identifyB ; Go on to Device B identification.
ps2_idA00:
mov [rdi+0],al ; byte 0 = 0fah.
call kybd_ctrl_out_full
jc short identifyB ; If this happens ID was only 1 byte.
in al,60h
cmp al,0fah
je short ps2_idA00 ; Sometimes we get a double ACK? so ignore it..
mov [rdi+1],al ; byte 1 = ?
call kybd_ctrl_out_full
jc short identifyB ; ID was 2 bytes long.
in al,60h
mov [rdi+2],al ; byte 2 = ?
call kybd_ctrl_out_full
jc short identifyB ; ID was 3 bytes long.
in al,60h
mov [rdi+3],al ; byte 3 = ? (shouldn't happen as ids are 3 bytes or less).
;--------------------------------------------------------
; Identify Device B if it's still usable.
;--------------------------------------------------------
identifyB:
cmp [ps2_deviceB_use],1
jne short no_devB_identify ; No device B present or responding so skip identify.
call kybd_wait_8042
call kybd_ctrl_in_empty
mov al,0d4h
out 64h,al
call kybd_ctrl_in_empty
mov al,0f2h ; Send Get Mouse ID / identify command.
out 60h,al
mov rdi,offset ps2_deviceB_type
mov dword [rdi],0
call kybd_wait_ack ; Wait for the ACK byte 0fah.
jnc short ps2_idB00
mov [ps2_deviceB_type],0 ; ACK from Device B failed, mark it as unusable for now.
mov [ps2_deviceB_use],0
jmp short no_devB_identify ; Identify Device B Failed.
ps2_idB00:
mov [rdi+0],al ; byte 0 = 0fah.
call kybd_ctrl_out_full
jc short no_devB_identify ; If this happens ID was only 1 byte.
in al,60h
cmp al,0fah
je short ps2_idB00 ; Sometimes we get a double ACK? so ignore it..
mov [rdi+1],al ; byte 1 = ?
call kybd_ctrl_out_full
jc short no_devB_identify ; ID was 2 bytes long.
in al,60h
mov [rdi+2],al ; byte 2 = ?
call kybd_ctrl_out_full
jc short no_devB_identify ; ID was 3 bytes long.
in al,60h
mov [rdi+3],al ; byte 3 = ? (shouldn't happen as ids are 3 bytes or less).
;--------------------------------------------------------
; If Device B is a PS2 Mouse and
; it's ID = 0, perform mouse specific init sequence
; to determin enhanced type (wheel, 5 button).
;--------------------------------------------------------
no_devB_identify:
cmp [ps2_deviceB_use],1 ; No Device B so skip.
jne short ps2_done
cmp [ps2_deviceB_type],000000fah ; Mouse ID reported seems to be correct, no need to determine enhanced state.
jne short ps2_done
mov bl,200
call ps2_deviceB_set_sample
mov bl,100
call ps2_deviceB_set_sample
mov bl,80
call ps2_deviceB_set_sample
call ps2_get_deviceB_id
cmp al,3
jne short ps2_done ; ID remained 0 so we've got a std. PS/2 mouse.
mov [ps2_deviceB_packet],4 ; Update the packet size as we know we have at least a scroll wheel.
mov rdi,offset ps2_deviceB_type
mov [rdi+1],al ; Store the updated ID byte.
mov bl,200
call ps2_deviceB_set_sample
mov bl,200
call ps2_deviceB_set_sample
mov bl,80
call ps2_deviceB_set_sample
call ps2_get_deviceB_id
cmp al,4
jne short ps2_done ; ID remained 3 so we've got a PS/2 mouse with scroll wheel.
mov [ps2_deviceB_packet],4 ; Update the packet size as we know we have a scroll wheel + 5 buttons.
mov rdi,offset ps2_deviceB_type
mov [rdi+1],al ; Store the updated ID byte.
ps2_done:
; HERE IS TEST CODE as on my setup I know dev.B is ok and a mouse...
INSTALL_IRQ_HANDLER 12,ps2_mouse_handler
;call kybd_ctrl_in_empty
;mov al,0a8h
;out 64h,al
;call kybd_wait_ack
mov rdi,offset ps2_deviceB_type
mov al,[rdi+1]
mov [mouse_id],al
mov eax,[ps2_deviceB_packet]
mov [mouse_packet_size],eax
mov [mouse_cycle],0
call kybd_ctrl_in_empty
mov al,20h
out 64h,al
call kybd_wait_ack
call kybd_ctrl_out_full
in al,60h
or al,00001110b
and al,11011111b
mov bl,al
push rbx
call kybd_ctrl_in_empty
mov al,60h
out 64h,al
call kybd_wait_ack
call kybd_ctrl_in_empty
pop rbx
mov al,bl
out 60h,al
call kybd_wait_ack
call kybd_ctrl_in_empty
mov bl,0eah ; Ensure stream mode is enabled.
call ps2_deviceB_write
call kybd_wait_ack
call ps2_deviceB_enable ; Packets can now be delivered to the PS/2 controller.
MONITOR_WRITE_BYTE [ps2_init_failed],00ff0000h
MONITOR_WRITE_BYTE [ps2_ctrl_type],00ffff00h
MONITOR_WRITE_DWORD [ps2_deviceA_type],00f0ff00h
MONITOR_WRITE_DWORD [ps2_deviceB_type],00ff00f0h
MONITOR_WRITE_BYTE [ps2_deviceA_res],00ffff0fh
MONITOR_WRITE_BYTE [ps2_deviceB_res],00fffff0h
MONITOR_WRITE_BYTE [ps2_deviceA_use],00ffff00h
MONITOR_WRITE_BYTE [ps2_deviceB_use],00ffff00h
ret
;######################################################################################
; PS/2 Controller Driver Data / Variables.
;######################################################################################
; Possible Identification ID's returned.
;0xFA AT keyboard with translation (not possible for device B)
;0xFA, 0xAB, 0x41 MF2 keyboard with translation (not possible for device B)
;0xFA, 0xAB, 0xC1 MF2 keyboard with translation (not possible for device B)
;0xFA, 0xAB, 0x83 MF2 keyboard without translation
;0xFA, 0x00 Standard mouse
;0xFA, 0x03 Mouse with a scroll wheel
;0xFA, 0x04 5 button mouse with a scroll wheel
;0xFA, 0x08 Typhoon 6byte packet mouse
ps2_init_failed db 0 ; [ 0 = ps2 controller is ready, 1 = ps2 controller init failed ]
ps2_ctrl_type db 0 ; [ 0 = single port, 1 = dual port ]
ps2_deviceA_type dd 0 ; [ 0 = none, else use table above ]
ps2_deviceB_type dd 0 ; [ 0 = none, else use table above ]
ps2_deviceA_res db 0 ; [ Result Byte from device A interface test (0=ok) all else = h/w failure ]
ps2_deviceB_res db 0 ; [ Result Byte from device B interface test (0=ok) all else = h/w failure ]
ps2_deviceA_use db 1 ; [ 0 = Not usable, 1 = usable ]
ps2_deviceB_use db 1 ; [ 0 = Not usable, 1 = usable ]
ps2_deviceA_packet dd 1 ; [ Size in bytes of Device A packet ]
ps2_deviceB_packet dd 3 ; [ Size in bytes of Device B packet ]