commit 8b6f030f0a4b88eff65397aa571bc87da9b13b22
parent d0883db46fc7d063ee0e89a1856605187900acf6
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Sat, 24 Dec 2022 15:27:44 -0500
sys/mouse: new subsystem
see doc/mouse. Also finish making the PS/2 mouse work on PC, with cute little
debug figure being displayed on the grid!
Diffstat:
5 files changed, 133 insertions(+), 23 deletions(-)
diff --git a/fs/doc/grid.txt b/fs/doc/grid.txt
@@ -17,6 +17,10 @@ clear the next line and move the cursor there. If we're at the end of the
screen, we scroll if the underlying driver allows it. Otherwise, we wrap around
to the top.
+The grid subsystem defines the Grid structure as well as a "grid" structbind to
+it. During initialization, what you'll want to do is create an instance of the
+Grid from the driver and bind it to "grid".
+
## Spit mode
Sometimes, we want to write things to screen that are at a position other than
diff --git a/fs/doc/mouse.txt b/fs/doc/mouse.txt
@@ -0,0 +1,55 @@
+# Mouse subsystem
+
+The mouse subsystem periodically polls a mouse driver for movement and clicks
+and maintains its position in a two dimensional environment.
+
+To be able to properly follow updates from the device, this subsystem has to
+be called upon regularly, which you'll probably want to do in the Loop
+(sys/loop).
+
+The mouse subsystem defines the Mouse structure as well as a "mouse" structbind
+to it. During initialization, what you'll want to do is create an instance of
+the Mouse from the driver and bind it to "mouse".
+
+## Driver implementation
+
+To implement the mouse, we need an underlying driver to extend it and implement
+its methods, namely:
+
+:mouse@ ( -- dx dy btnflags )
+ Return the number of "units" (device dependant) by which the mouse moved since
+ we last called this method. "dx" is negative when going left. "dy" is negative
+ when going up. "btnflags" is a bitmask of the buttons that are currently
+ pushed. b0=left b1=right b2=middle.
+
+## API
+
+Constants:
+
+BTN_LEFT $01
+BTN_RIGHT $02
+BTN_MIDDLE $04
+
+Fields:
+
+x Current X pos before divisor is applied
+y Current Y pos before divisor is applied
+xmax Max X pos without divisor
+ymax Max Y pos without divisor
+divisor A divisor to apply to movement to make it go slower
+buttons Bitmask of buttons that are currently pressed
+clicks Bitmask of push/release cycles that occured since last :click@
+
+:x ( self -- n )
+ X with divisor applied
+
+:y ( self -- n )
+ Y with divisor applied
+
+:update ( self -- )
+ Fetch new data from :mouse@ and update fields accordingly.
+
+:configure ( xmax ymax divisor self -- )
+ Configure mouse with specified parameters.
+
+:click@ not implemented
diff --git a/fs/drv/pc/ps28042.fs b/fs/drv/pc/ps28042.fs
@@ -1,5 +1,6 @@
\ 8042 PS/2 Controller driver
\ We assume a 8042 controller with two functional ports
+require /sys/mouse.fs
?f<< /drv/pc/pic.fs
?f<< /asm/i386.fs
@@ -33,9 +34,7 @@ code isrIRQ1
\ accumulate information for the next 8042mouse@ call.
create _dx 0 ,
create _dy 0 ,
-\ The lowest byte of the flags indicate which buttons are *currently* pressed.
-\ The second byte of the flags indicate which button received a click (pressed
-\ then released) since the last 8042mouse@ call
+\ indicate which buttons are *currently* pressed.
create _btnflags 0 ,
\ first byte is a packet counter (we get 3 or 4 packets before completing the
@@ -44,7 +43,6 @@ create _btnflags 0 ,
create _pkt 0 ,
pc to L1 \ exit
- bl inc,
_pkt m) bx mov,
piceoi2,
bx pop, ax pop,
@@ -55,6 +53,7 @@ pc \ jz=packet 1, the dx packet
ax $ffffff00 i) or,
forward!
_dx m) ax add,
+ bl inc,
L1 abs>rel jmp,
pc \ ja=packet 2, the dy packet
bh $20 i) test,
@@ -62,6 +61,7 @@ pc \ ja=packet 2, the dy packet
ax $ffffff00 i) or,
forward!
_dy m) ax add,
+ bl bl xor,
L1 abs>rel jmp,
code isrIRQc
ax push, bx push,
@@ -72,26 +72,14 @@ code isrIRQc
( pc ) abs>rel ja,
( pc ) abs>rel jz,
\ packet=0, the flags packet
+ \ check if it's a header packet. If not, return early to sync again.
+ al $08 i) test, L1 abs>rel jz,
+ bl inc,
bh al mov,
- al $7 i) mov, \ the 3 buttons flags
- ah _btnflags m) mov,
- ah al xor,
+ al $7 i) and, \ the 3 buttons flags
_btnflags m) ax mov,
L1 abs>rel jmp,
-code 8042mouse@ ( -- dx dy btnflags )
- dx dx xor, cli,
- ax _dx m) mov, _dx m) dx mov,
- bx _dy m) mov, _dy m) dx mov,
- \ We keep "pressed" info around to be able to detect "click" events
- cx _btnflags m) mov, _btnflags m) $ff i) and,
- sti,
- bp CELLSZ 3 * i) sub,
- bp 8 d) ax mov,
- bp 4 d) bx mov,
- bp 0 d) cx mov,
- ret,
-
: _canread? PS2CMD pc@ 1 and ;
: _canwrite? PS2CMD pc@ 2 and not ;
: _waitread 10000 >r begin _canread? if leave then next ;
@@ -113,7 +101,6 @@ code 8042mouse@ ( -- dx dy btnflags )
$ae _writecmd \ enable 1st port
$a8 _writecmd \ enable 2nd port
0 _ridx ! 0 _widx ! ['] isrIRQ1 $21 setISR 1 pic1unmask
- 0 _dx ! 0 _dy ! 0 _btnflags ! 0 _pkt ! ['] isrIRQc $2c setISR 4 pic2unmask
$60 _writecmd $07 _writedata \ interrupt on both ports, both ports enabled
$ff _writedata \ send reset cmd to keyboard
_readdata $aa <> if abort" Keyboard self-test failed" then
@@ -125,10 +112,29 @@ code 8042mouse@ ( -- dx dy btnflags )
$ff _writeport2 _waitread _canread? if \ we have a mouse
\ we're going to receive a bunch of bytes. Just read them all and drop.
begin _readdata drop _waitread _canread? not until
+ 0 _dx ! 0 _dy ! 0 _btnflags ! 0 _pkt ! ['] isrIRQc $2c setISR 4 pic2unmask
\ Enable straming
$f4 _writeport2 _readdata $fa <> if abort" mouse init failed" then
then ;
-\ Reboot using the 8042 interface to the reset pin
-: reboot $FE $64 pc! ;
+extends Mouse struct[ PS2Mouse
+ code 8042mouse@ ( -- dx dy btnflags )
+ dx dx xor, cli,
+ ax _dx m) mov, _dx m) dx mov,
+ bx _dy m) mov, _dy m) dx mov,
+ \ We keep "pressed" info around to be able to detect "click" events
+ cx _btnflags m) mov, _btnflags m) $ff i) and,
+ sti,
+ \ The PS/2 mouse give a positive dy when going up. We want the opposite.
+ bx neg,
+ bp CELLSZ 3 * i) sub,
+ bp 8 d) ax mov,
+ bp 4 d) bx mov,
+ bp 0 d) cx mov,
+ ret,
+
+ : :new ( -- self ) :newbase ['] 8042mouse@ , ;
+]struct
+\ Reboot using the 8042 interface to the reset pin
+: reboot $fe $64 pc! ;
diff --git a/fs/sys/mouse.fs b/fs/sys/mouse.fs
@@ -0,0 +1,33 @@
+\ Mouse subsystem. see doc/mouse
+
+struct[ Mouse
+ $01 const BTN_LEFT
+ $02 const BTN_RIGHT
+ $04 const BTN_MIDDLE
+
+ sfield x
+ sfield y
+ sfield xmax
+ sfield ymax
+ sfield divisor
+ sfield buttons
+ sfield clicks
+ ssmethod :mouse@ ( -- dx dy btnflags )
+
+ : :x dup x swap divisor / ;
+ : :y dup y swap divisor / ;
+
+ \ Creates the first part of the grid structure, but leaves the last field
+ \ (method) to the caller.
+ : :newbase ( -- self ) here 0 , 0 , 640 , 480 , 1 , 0 , 0 , ;
+ : _bounds ( x-or-y maxval -- n ) over 0< if 2drop 0 else min then ;
+ : :update ( self -- ) >r \ V1=self
+ r@ :mouse@ r@ to buttons
+ r@ y + r@ ymax _bounds r@ to y
+ r@ x + r@ xmax _bounds r> to x ;
+ : :configure ( xmax ymax divisor self -- ) >r \ V1=self
+ dup r@ to divisor tuck * to r@ ymax * to r> xmax ;
+]struct
+
+0 structbind Mouse mouse
+: mouseupdate mouse :update ;
diff --git a/fs/xcomp/i386/pc/init.fs b/fs/xcomp/i386/pc/init.fs
@@ -38,6 +38,7 @@ pic$ idt$
f<< /fs/fat.fs
f<< /sys/kbd.fs
+f<< /sys/mouse.fs
f<< /drv/pc/ps28042.fs
f<< /sys/ps2.fs
@@ -45,6 +46,17 @@ f<< /sys/ps2.fs
' 8042kbd@? to (ps2@?)
' ps2keyset1? to key?
+8042mouse$
+PS2Mouse :new ' mouse rebind
+640 480 4 mouse :configure
+
+f<< /sys/loop.fs
+' mouseupdate loopadd
+: mousedbg
+ mouse :x 16 lshift mouse :y or grid :dbgnum1!
+ mouse buttons grid :dbgnum2! ;
+' mousedbg loopadd
+
f<< /drv/pc/a20.fs
a20$
f<< /drv/pc/vesa.fs