Page 1 of 2

ps2 mosue and keyboard interfacing

Posted: Wed Apr 15, 2009 5:33 am
by johnsa
So I've gotten a large chunk of my ps2 kybd and mouse driver done and they're working nicely in bochs/qemu etc. Some wierd things happen on real h/w as follows:

In theory I should be able to check bit 5 (0x20 mask) when reading 64h status to see if the data byte at 60h is from the keyboard or the mouse, this works in the emulators but not on real hardware.
For example in the mouse handler IRQ code:

in al,64h
test al,01h ; Wait for the output buffer to be full with data.
jz no_mouse_byte
;test al,20h ; Ensure the data byte that is ready is for the mouse.
;jz no_mouse_byte

Doesn't work on real h/w... the test al,20h for both mouse (JZ) and kybd (JNZ) just stops the keyboard IRQ code from ever happening.. not sure what the deal is there...

The next wierd thing is ... I'm using a USB mouse and I have a touchpad on the laptop. In theory the touchpad should work as a traditional ps2 mouse and the USB mouse should emulate a PS2 but according to the wiki, docs etc. it shouldn't fire IRQ12 but a differently assigned one from the USB BUS. However on my real h/w (laptop) it does fire IRQ12..

Then comes the last bit of wierdness... The mouse packet (assuming 3 byte default mode) has two deltas, x and y. In terms of the mouse, according to the docs, X should refer to vertical movement and Y to horizontal... in the emulator this seems to be switched around, so X is the same as screen X (horiz). and Y is vertical... not sure if anyone else has noticed this?
On the real h/w using the usb mouse.. irq12 fires and it would seem that indeed the x/y are switched.. it also bugs out quite badly..

Re: ps2 mosue and keyboard interfacing

Posted: Wed Apr 15, 2009 6:49 am
by johnsa
Ok.. so I've solved some of the issues, If I take out the test al,20h from both kybd and mouse they both work again. If I only enable one or the other, then they work perfectly. Once both are enabled together they compete obviously and go a bit haywire.. hence the test al,20h (bit 5) test from 64h read in the respective handlers.. Is there another way to ensure that mouse data only goes to it's handler and the same for kybd?

Re: ps2 mosue and keyboard interfacing

Posted: Wed Apr 15, 2009 12:06 pm
by kay10
Something about X and Y coordinates:
I don't want to say the docs are completely wrong,
but my math skills tell me that X is the horizontal axis and Y the vertical one.
So the emulator reacts right.
Please correct me if I'm wrong.

Re: ps2 mosue and keyboard interfacing

Posted: Wed Apr 15, 2009 12:13 pm
by johnsa
You are correct.. x/y are the right way around..
the problem i'm having is that if the keyboard driver is running at the same time as the ps2 mouse driver they both go haywire.
kybd on irq1, ps2 mouse on irq 12.
I have two seperate handlers for each and I was trying to use bit 5 (20h) when checking port 64h to ensure each handler only deals with it's own data. It works in the emulators but not on real h/w. I presuming that bit isn't being used on the real system..

Here are the two starting parts of the handlers:

Code: Select all


MOUSE_HANDLER:
in al,64h
test al,1
jz no_data_for_mouse_yet
test al,20h
jz not_a_mouse_data_byte
.
.
.
not_a_mouse_data_byte:
no_data_for_mouse_yet:
ret

and the keyboard handler does exactly the same except the test al,20h uses a jnz instead.. these handlers are chain-called by my main IRQ handler's, which already handle the EOI's etc.. with iretq, so these handlers just use normal rets (in case anyone was going to point that out). :)
Either one works perfectly on it's own... activate both.. and poof! on real h/w... fine in emulators.

Re: ps2 mosue and keyboard interfacing

Posted: Thu Apr 16, 2009 1:51 am
by johnsa
anyone? :)

I've scoured the net looking for examples of how one could avoid this conflict or what might cause it ... haven't had any luck yet

Re: ps2 mosue and keyboard interfacing

Posted: Thu Apr 16, 2009 4:17 am
by Brendan
Hi,

If the PS/2 controller tells you there's a byte from the keyboard (IRQ1) then you can assume there's a byte from the keyboard; and if the PS/2 controller tells you there's a byte from the mouse (IRQ12) then you can assume there's a byte from the mouse. In both cases you don't need to check anything - the PS/2 controller already told you it's there.

Bit 5 is there for polling. You should be able to use bit 5 in the IRQ handlers to double check, but...

When the keyboard and mouse are USB devices, the BIOS uses SMM code to emulate PS/2 devices. I've seen plenty of people reporting problems with this emulation - basically once you start doing anything a little unusual you start relying on emulation code in the BIOS that's probably never been tested properly. Almost nobody uses polling for keyboard and almost nobody tests bit 5 in their IRQ handlers, so the chance of bit 5 being emulated properly by the BIOS is a lot less likely.


Cheers,

Brendan

Re: ps2 mosue and keyboard interfacing

Posted: Thu Apr 16, 2009 5:28 am
by johnsa
Im not convinced that the bit 5 thing is supported, at least not in all real systems, and as you say the SMM bios code is likely to be dodgy.
I see your point about using that for a polling model, which I certainly wouldn't be using. Both kybd and mouse code are using their respective irq's and handlers.
I removed the bit 5 check totally and the whole thing still works beautifully in both bochs and qemu, still have the issue on real h/w that when both are active - neither work, but disable on or the other and the other works perfectly on it's own. So I know the kybd code is "right", and the mouse code is "right", but something about having them on together isn't happy. I happen to do the kybd init first, then the mouse init.

Code: Select all


init_kybd_driver:
	; Perform full keyboard diagnostics / self-test.
	call kybd_ctrl_self_test
	test al,al
	jz short kybd_ok0
	ret
kybd_ok0:
	call kybd_ctrl_interface_test
	test al,al
	jz short kybd_ok1
	ret
kybd_ok1:
	
	; Install our customer IRQ1 ISR.
	INSTALL_IRQ_HANDLER 1,ps2_kybd_handler

	; Ensure the keyboard controller is enabled and the output buffer is empty.
	; -> This will allow IRQ1 to fire, as it won't with a full buffer.	
	call kybd_enable
	call wait_kybd_out_empty
	
	; Ensure all LEDs are off and the states are stored.
	call kybd_clear_leds
	mov [_ps2_numlock],0
	mov [_ps2_capslock],0
	mov [_ps2_scrolllock],0
	mov [ps2_led_states],0
	
	xor al,al
	ret

and then

Code: Select all

init_ps2_mouse_driver:

	call wait_mouse_in_empty
	mov al,0a8h
	out 64h,al
	
	call wait_mouse_in_empty
	mov al,020h							; Read Command (compaq status byte).
	out 64h,al
	call wait_mouse_out_full
	in al,60h
	or al,00000010b						; Enable IRQ12 (bit 1).
	mov bl,al
	call wait_mouse_in_empty
	mov al,060h							; Write Command (compaq status byte).
	out 64h,al
	call wait_mouse_in_empty
	mov al,bl
	out 60h,al
	
	mov bl,0f6h							; Tell the mouse to use default settings.
	call ps2_mouse_write
	call ps2_mouse_read
	
	mov bl,0f4h							; Enable the mouse.
	call ps2_mouse_write
	call ps2_mouse_read
	
	; Install our PS2 (IRQ12) Mouse Handler.
	INSTALL_IRQ_HANDLER 12,ps2_mouse_handler

	ret
I don't see anything in the init code that could cause a conflict.. and assuming that when the IRQ1 or 12 is fired the byte read from 60h doesn't need to be checked to see if it's a mouse or kybd byte then this should all be 100%.

MOUSE HANDLER CODE: (note it has some non reentrant stuff and some excessive things just for testing related to screen pos etc)

Code: Select all


ps2_mouse_handler:
	push rsi

	in al,64h
	test al,01h						; Wait for the output buffer to be full with data.
	jz no_mouse_byte
	
	in al,60h						; Read a data byte.
	mov rsi,offset mouse_packet
	xor rbx,rbx
	mov bl,[mouse_cycle]
	add rsi,rbx
	mov [rsi],al
	
	add [mouse_cycle],1
	cmp byte [mouse_cycle],3		; Only if we've had all 3 data bytes should we do anything.
	jne no_mouse_byte

	; We now have the full data-packet, let's process it.
	mov [mouse_cycle],0				; Reset the cycle value.
	mov rsi,offset mouse_packet
	mov bl,[rsi]					; Read the flags byte.
	test bl,80h
	jnz no_mouse_byte				; Ignore Y Overflow.
	test bl,40h
	jnz no_mouse_byte				; Ignore X Overflow.
	
	; Obtain the Mouse Deltas.	
	xor eax,eax
	mov al,[rsi+2]					; Y-Delta
	test bl,20h						; Is the Y-Delta Negative Flag Set?
	jz short no_neg_y
	or eax,0ffffff00h
no_neg_y:
	mov [mouse_delta_y],eax
	
	xor eax,eax
	mov al,[rsi+1]					; X-Delta
	test bl,10h						; Is the X-Delta Negative Flag Set?
	jz short no_neg_x
	or eax,0ffffff00h
no_neg_x:
	mov [mouse_delta_x],eax	

	mov byte [mouse_button0_state],0
	mov byte [mouse_button1_state],0
	mov byte [mouse_button2_state],0
	
	; Update the primary 3 button states.
	test bl,04h
	jz no_middle_button_press
	mov byte [mouse_button2_state],1
	push rbx	
	MONITOR_WRITE k_mouse0,000044ffh
	pop rbx
no_middle_button_press:
	test bl,02h
	jz no_right_button_press
	mov byte [mouse_button1_state],1
	push rbx
	MONITOR_WRITE k_mouse1,000044ffh
	pop rbx	
no_right_button_press:
	test bl,01h
	jz no_button_press
	mov byte [mouse_button0_state],1
	push rbx	
	MONITOR_WRITE k_mouse2,000044ffh
	pop rbx
no_button_press:

	; Update the Mouse/Screen Coordinates.
	mov eax,[mouse_delta_x]
	add [mouse_x],eax
	mov eax,[mouse_delta_y]
	sub [mouse_y],eax
	
	cmp [mouse_x],799
	jl cx0
	mov [mouse_x],0
	jmp m_pos_constrainedx	
cx0:
	cmp [mouse_x],0
	jge m_pos_constrainedx
	mov [mouse_x],799
m_pos_constrainedx:
	cmp [mouse_y],599
	jl cy0
	mov [mouse_y],0
	jmp m_pos_constrainedy	
cy0:
	cmp [mouse_y],0
	jge m_pos_constrainedy
	mov [mouse_y],599
m_pos_constrainedy:

	; Draw test pixels.
	push rdi
	mov rdi,[kmonitor_view_addr]
	xor rax,rax
	mov eax,[mouse_y]
	imul eax,(800*4)
	add rdi,rax
	xor rax,rax
	mov eax,[mouse_x]
	shl eax,2
	add rdi,rax
	mov eax,0025ff9fh
	mov [rdi],eax
	pop rdi
	
no_mouse_byte:
	pop rsi
	ret
and kybd handler:

Code: Select all

ps2_kybd_handler:
	
	; Wait for full buffer and read scan-code.
	;----------------------------------------------------
	in al,KYBD_CTRL_STATUS_REG
	test al,KYBD_CTRL_STATUS_MASK_OUT_BUF
	jz ps2_buffer_not_full_yet
	
	call kybd_enc_read_buffer		; Read the scan-code into AL.
	mov [_ps2_scancode],al			; Store it.

	; Check for extended scan-codes.
	;----------------------------------------------------
	mov byte [_ps2_extended],0		; Set extended scan-code state to default.
check_ext_scan0:
	cmp al,0e0h
	jne short check_ext_scan1
	mov byte [_ps2_extended],1		; Store that it is an extended scancode.
	jmp handle_ext_codes	
check_ext_scan1:
	cmp al,0e1h
	jne short check_ext_done
	mov byte [_ps2_extended],1		; Store that it is an extended scancode.
	jmp handle_ext_codes	
check_ext_done:
	
	; Handle LED Modifier Toggle Keys.
	;----------------------------------------------------
	cmp al,SCANCODES0_CAPS_MAKE
	jne short scan0_01
	cmp [_ps2_capslock],0
	jne short scan0_00
	mov byte [_ps2_capslock],1
	mov bh,[ps2_led_states]
	or bh,00000100b
	mov [ps2_led_states],bh
	call kybd_set_leds
	jmp scancodes_done
scan0_00:
	mov byte [_ps2_capslock],0
	mov bh,[ps2_led_states]
	and bh,11111011b
	mov [ps2_led_states],bh
	call kybd_set_leds
	jmp scancodes_done
scan0_01:

	cmp al,SCANCODES0_NUMLOCK_MAKE
	jne short scan0_03
	cmp [_ps2_numlock],0
	jne short scan0_02
	mov byte [_ps2_numlock],1
	mov bh,[ps2_led_states]
	or bh,00000010b
	mov [ps2_led_states],bh
	call kybd_set_leds
	jmp scancodes_done
scan0_02:
	mov byte [_ps2_numlock],0
	mov bh,[ps2_led_states]
	and bh,11111101b
	mov [ps2_led_states],bh
	call kybd_set_leds
	jmp scancodes_done
scan0_03:

	cmp al,SCANCODES0_SCROLLLOCK_MAKE
	jne short scan0_05
	cmp [_ps2_scrolllock],0
	jne short scan0_04
	mov byte [_ps2_scrolllock],1
	mov bh,[ps2_led_states]
	or bh,00000001b
	mov [ps2_led_states],bh
	call kybd_set_leds
	jmp scancodes_done
scan0_04:
	mov byte [_ps2_scrolllock],0
	mov bh,[ps2_led_states]
	and bh,11111110b
	mov [ps2_led_states],bh
	call kybd_set_leds
	jmp scancodes_done
scan0_05:

	cmp al,0fah	; ignore keyboard cmd ack in buffer?
	je short ps2_buffer_not_full_yet
	
	; Set corresponding key to on for a make code.
	xor ebx,ebx
	mov bl,al
	mov byte [key_states+ebx],1
	
	; Set the key to off for a break code.
	xor ebx,ebx
	mov bl,al
	mov byte [key_states+ebx],0
		
scancodes_done:

	call ps2_kybd_get_ascii
	xor ah,ah
	call generic_kybd_handler
	
	MONITOR_WRITE_BYTE [_ps2_scancode],00ff0000h
	
handle_ext_codes:

ps2_buffer_not_full_yet:
	
	ret

Re: ps2 mosue and keyboard interfacing

Posted: Fri Apr 17, 2009 4:07 am
by johnsa
Ok so I tried making a few more changes, added in support in the handlers to check if there is more than 1 byte's worth of data waiting at 60h and if so read it immediately else terminate the handler and wait for the next irq. Once again it works perfectly under the emulators (bochs, qemu) .. still .. and if one or the other (either kybd or mouse) is running on real h/w it works.. if both are active.. it's now gone from haywire to nothing.. neither kybd or mouse do anything at all.. as if the irq's don't even get called anymore.. this is driving me nuts!

Re: ps2 mosue and keyboard interfacing

Posted: Fri Apr 17, 2009 10:35 am
by johnsa
OK did some more fiddling and move code around and this was the result.. quite puzzling:

;Original steps..
Disable PIC
Init Keyboard
Enable PIC

Disable PIC
Init Mouse
Enable PIC

This worked under the emulators but not on my real h/w... so I tried:

Disable PIC
Init Keyboard
Init Mouse
Enable PIC

This no longer worked under bochs anymore either.. still worked under qemu.. then:

Disable PIC
Init Mouse
Init Keyboard
Enable PIC

This now worked under the emulators AND on my real h/w (dell laptop)... tried it on another desktop machine and absolutely nothing.. no kybd or mouse firing.

Has anyone actually gotten a legacy mouse (ps2 and or usb emulated) / kybd (ps2 and or usb emulated) setup working together on all machines?!

Re: ps2 mosue and keyboard interfacing

Posted: Fri Apr 17, 2009 12:55 pm
by Brendan
Hi,
johnsa wrote:Has anyone actually gotten a legacy mouse (ps2 and or usb emulated) / kybd (ps2 and or usb emulated) setup working together on all machines?!
In the past, I've gotten PS/2 keyboards and mouses working, including auto-detecting if there's one or 2 PS/2 ports, auto-detecting which devices are plugged into which PS/2 ports and supporting any combination of devices (e.g. dual keyboard, dual mouse, etc); and working on all computers and all emulators I had at the time. Unfortunately this was a several years ago and I'm not sure where the code went (I shifted to a new computer 3 times and started the OS again from scratch a few times too).

I didn't test to see if it worked for USB devices with BIOS PS/2 emulation. To be honest I didn't care if this would work or not - a good OS needs USB device drivers, and should disable any BIOS PS/2 emulation before attempting to initialize the PS/2 controller.

The way I did it was to begin with initializing the PS/2 controller - install dummy IRQ handlers, enable the IRQs in the PIC, disable IRQs in PS/2 controller, do controller self tests and detect how many PS/2 ports the controller supports, send a "do self test" command to each PS/2 port and see what device IDs come back (if any - it's good to have time-outs everywhere), then enable IRQs in the PS/2 controller, then start device drivers (using the device IDs returned by the devices to determine which device drivers to use for which PS/2 ports).

When a byte arrives the PS/2 controller's code sent it to the relevant device driver, and when the keyboard/mouse device driver wanted to send a byte it asked the PS/2 controller's driver to send it. The keyboard/mouse drivers don't need to do anything except sending/receiving bytes to/from the PS/2 controller driver; and don't need to care which PS/2 port they're connected to, and don't need access to any I/O ports, and don't mess with IRQs or the PS/2 controller's setup at all.

I think at least some of your problem is that your "init_kybd_driver" code messes with the PS/2 controller's configuration while the mouse driver is relying on the PS/2 controller's configuration...


Cheers,

Brendan

Re: ps2 mosue and keyboard interfacing

Posted: Fri Apr 17, 2009 1:13 pm
by Brendan
Hi,

I love these forums! :)

I remembered posting some detailed information about my old PS/2 code a long long time ago...


Cheers,

Brendan

Re: ps2 mosue and keyboard interfacing

Posted: Fri Apr 17, 2009 2:12 pm
by johnsa
sigh.. everytime i change the code around or touch one line the whole thing changes.. add an extra in al,60h dummy read somewhere and its all different..
I think.. that i'm just not going to bother with this.. haha.. it seems too unreliable and dodgy to even be a viable option anymore..especially with usb->ps2 type emulation.

So the 2 questions now are ..
#1... is it a viable option to assume no ps2 support at all anymore and go straight for pure usb? (after all the machines i have don't even have ps2 ports anymore)
#2... if one is true and we can assume usb is a much better standard with more features.. can we disable any usb->ps2 emulation for mouse/kybd programmatically? and is this necessary or can we just ignore port 60/64 altogether?

I think its time to spend more coding time on pci/usb hub stuff and work towards that for all hids... :)

Re: ps2 mosue and keyboard interfacing

Posted: Sat Apr 18, 2009 6:50 am
by Combuster
johnsa wrote:#1... is it a viable option to assume no ps2 support at all anymore and go straight for pure usb?
My new laptop has a native PS/2 keyboard (and it came to the stores about 8 months ago), so I'd definately say PS2 is still a requirement.

That and people not buying new keyboards/mice 'cause they still work. For my own collection, 12/13 boxes do not have USB keyboard or mouse connected (I use a pair of PS/2 kvm switches).

Re: ps2 mosue and keyboard interfacing

Posted: Sat Apr 18, 2009 7:38 am
by quok
Combuster wrote:
johnsa wrote:#1... is it a viable option to assume no ps2 support at all anymore and go straight for pure usb?
My new laptop has a native PS/2 keyboard (and it came to the stores about 8 months ago), so I'd definately say PS2 is still a requirement.

That and people not buying new keyboards/mice 'cause they still work. For my own collection, 12/13 boxes do not have USB keyboard or mouse connected (I use a pair of PS/2 kvm switches).
While my machine count isn't quite that high (4 desktop machines, 5 laptops, 1 thin client), 3 of the desktop machines use a PS/2 mouse/keyboard through a PS/2 KVM switch. The other desktop supports PS/2 as well as USB, but uses bluetooth instead. IIRC, it's one of those bluetooth devices that operates as a regular wireless USB keyboard/mouse until the bluetooth portion of it gets initialized. That means that I can use it during boot to change BIOS settings and such.

I'm fairly certain all my laptops have USB based keyboards and track pads however.

Re: ps2 mosue and keyboard interfacing

Posted: Sat Apr 18, 2009 8:21 am
by Firestryke31
I know my laptop's trackpad is PS/2, and I'm 60% sure my keyboard is too. It's about 1-2 years old. My desktop uses a PS/2 mouse and keyboard also, but that one's a bit older.