I'm developing a simple OS and have a problem with ps/2 keyboard initialization. The initialization strategy for both keyboard controller and ps/2 controller are taken from Ben Lunt "FYSOS: Input and Output Devices".
It works nice in Bochs and on one of my test hardware - HP Elite Book with Intel Core i5. But on another laptop - HP Pavilion, Inter Core i5 - the "get scancode set" command runs into a problem: reading the 0x60 port first two times returns two acknowledge bytes, and reading it the third time (expecting the set number) does a timeout.
Is something wrong with my code or is it a bug in the hardware?
The source code below is for the keyboard controller initialization (omitting the steps supposed to go after the problematic fragment, also omitting the code of some obvious subroutines).
;the subroutine kernel_write_ps2 takes byte to write in AL and port address in DX, returns result code in EAX
;the subroutine kernel_read_ps2 (reads the 0x60 port), returns result code in EAX and the read byte in BL
;both subroutines timeout is 100 msec
dk_init:
call dk_set_ps2_for_init
;deactivating both ps/2 channels
mov al, 0xf5
call dk_send_command_wait_acknowledge
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
mov al, 0xf5
call dk_send_command_wait_acknowledge2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
;keyboard reset
mov al, 0xff
call dk_send_command_wait_acknowledge
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
mov eax, 750
call kernel_mdelay_pcc ;750 msec delay
call kernel_read_ps2 ;wait for output buffer and read
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
cmp bl, 0xaa
jz .echo
mov eax, G_SYSTEM_ERROR_KB_SELFTEST
jmp .exit
;echo-test
.echo:
mov dx, 0x60
mov al, 0xee
call kernel_write_ps2 ;wait for input buffer and write
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
call kernel_read_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
cmp bl, 0xee
jz .identify
mov eax, G_SYSTEM_ERROR_KB_ECHO
jmp .exit
;getting the keyboard id
.identify:
mov al, 0xf2
call dk_send_command_wait_acknowledge
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
call kernel_read_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
cmp bl, 0xab
jz .identify1
mov eax, G_SYSTEM_ERROR_KB_TYPE
jmp .exit
.identify1:
call kernel_read_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
call dk_get_scancode_set
;TODO: reenable things...
.exit:
ret
;--------------
dk_send_command_wait_acknowledge:
push ebx
push edx
mov dx, 0x60
call kernel_write_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
call kernel_read_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
cmp bl, 0xfa
jnz .error
mov eax, G_SYSTEM_ERROR_OK
jmp .exit
.error:
mov eax, G_SYSTEM_ERROR_KB_COMMAND_NOT_ACK
.exit:
pop edx
pop ebx
ret
;-------------
dk_send_command_wait_acknowledge2: ;for the second channel
push ebx
push edx
mov bl, al
mov dx, 0x64
mov al, 0xd4
call kernel_write_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
mov al, bl
mov dx, 0x60
call kernel_write_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
call kernel_read_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
cmp bl, 0xfa
jnz .error
mov eax, G_SYSTEM_ERROR_OK
jmp .exit
.error:
mov eax, G_SYSTEM_ERROR_KB_COMMAND_NOT_ACK
.exit:
pop edx
pop ebx
ret
;----------------
;disabling the interrupts for both channels and disabling translation
dk_set_ps2_for_init:
push ebx
push edx
mov dx, 0x64
mov al, 0x20
call kernel_write_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
call kernel_read_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
.change_config:
and bl, ~((1 << 6) | (1 << 1) | 1)
mov dx, 0x64
mov al, G_PS2_COMMAND_WRITE_RAM_0
call kernel_write_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
mov dx, 0x60
mov al, bl
call kernel_write_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
.exit:
pop edx
pop ebx
ret
;-------------
dk_get_scancode_set:
mov dx, 0x60
mov al, 0xf0
call kernel_write_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
mov dx, 0x60
mov al, 0
call kernel_write_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
call kernel_read_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
push eax
mov al, bl
call kernel_print_byte_hex ;printing for debugging purposes
pop eax
call kernel_read_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
push eax
mov al, bl
call kernel_print_byte_hex ;printing for debugging purposes
pop eax
call kernel_read_ps2
cmp eax, G_SYSTEM_ERROR_OK
jnz .exit
push eax
mov al, bl
call kernel_print_byte_hex ;printing for debugging purposes
pop eax
.exit:
ret