Testing the Mouse with Open Firmware

This describes how to use Open Firmware to perform simple tests of the PS/2 mouse interface. The intention of this writeup is to let you test the hardware with a real PS/2 mouse, not a touchpad, for the purpose of determining if the PS/2 hardware is fried.

This procedure as written won't work with a touchpad because the touchpad uses stream mode, whereas this code uses remote mode, which the touchpad doesn't support. If you want to try it with a touchpad, contact me (wmb@firmworks.com) and I'll tell you what to do.

There is a section at the bottom that explains the procedure in great detail, which may help you to learn more about Open Firmware and Forth.

Installing Open Firmware

Get ofw.tgz and extract it with

tar xfz ofw.tgz
It extracts to a file named ofw.bzi (it's tar'ed to protect it while downloading).

Copy that file to a USB FLASH key that contains an ext3 file system (i.e. an OLPB boot disk). E.g.:


$ mount /dev/sda1 /key
$ cp ofw.bzi /key/boot/ofw.bzi
Modify /key/boot/olpc-boot.sh to add the following lines before the /sbin/kbl-kexec line:

if [ -f /key/boot/ofw.bzi ] ; then
    read -p "Type o for Open Firmware or l for Linux: " WHICH
    [ $WHICH == "o" ] && /sbin/kbl-kexec /key/boot/ofw.bzi ""
fi
If the LinuxBIOS on your system is one of the old versions that is set up to boot from /bzImage instead of using olpc-boot.sh, copy ofw.bzi to /key/bzImage instead of to /boot/ofw.bzi .

Running Open Firmware

Connect a serial line to the OLPC board (Open Firmware can use the keyboard and screen, but a serial console gives you much more flexibility for debugging. You can scroll back, cut and paste code snippets, capture output, etc.).

Disconnect the PS/2 keyboard, thus forcing Open Firmware to use the serial console.

Insert the USB key and turn on the power. When you see the 'Type o for Open Firmware ...' prompt, type o. (If you are using a /bzImage version of LinuxBIOS, you won't have to do this.)

You should see a few lines of messages and then an 'ok' prompt.

Testing the Mouse

Connect a mouse to the PS/2 mouse port. Then type the following: Don't omit the spaces between words; in Forth, symbols must be separated by whitespace. But the number of spaces isn't important, as long as there is at least one.

ok select /mouse
ok : show-mouse   10 get-event  if  . . . cr  then  ;
ok show-mouse many
Move the mouse, click buttons, etc. If the mouse is working, you should see a stream of movement reports on the serial console. The first number on each line is the button bitmask, the second delta-y, the third delta-x.

If the PS/2 hardwire is fried, the most likely result is that the 'select' command will fail, because it has to communicate with the mouse to setup the operating mode.

How it Works

select /mouse
The 'select' command opens a device driver and also drags the command interpreter context into the device driver so you can play with the driver methods interactively.

'/mouse' is an Open Firmware 'device specifier' - essentially a path name in the 'device tree'. The fully-qualified path name is '/pci/isa@f/8042@i60/mouse@aux', but Open Firmware assumes that you are lazy and in a hurry, whereas the computer is eager to please you, so it searches the tree for you and finds a match. This facility is not specific to 'select' - all device tree searches work this way.

BTW, if you want to see where you are in the device tree, type 'pwd'. To list the whole device tree, type 'show-devs'.

: show-mouse
Here we are creating a new command named 'show-mouse'. The ':' command looks ahead on the input line, snarfs a (whitespace-delimited) word, enters a new name in the symbol table for the current context, and goes into compilation mode. Subsequently, stuff that you type will be compiled instead of executed.
10 get-event
'get-event' is one of the methods in the mouse driver. It expects to find a number on the stack, which is a timeout value (milliseconds). It pops that number (hex 10 in this case - hex because the default base for Open Firmware is 16) off the stack, then polls the mouse for up to that long.

If 'get-event' receives a mouse report before the timeout has expired, it pushes four numbers on the stack, specifically 'x y buttons true'. If the timeout expires, it pushes just one number 'false' (false is 0, well-formed true is -1, and test operators treat anything nonzero as true). Thus the number on top of the stack tells whether there is anything underneath.

The Forth documentation convention is to write


get-event  ( ms -- false | x y buttons true )
Everything before the '--' is an argument that 'get-event' removes from the stack, everything after is a result that 'get-event' pushes onto the stack.

if  . . . cr  then
'if {something} then' is a control construct. Informally, what happens is that it executes the body (the stuff between if and then) if the top of the stack (which it pops) is nonzero. (Obviously, 'endif' would be better than 'then'. This is just one of those things...)

The body in this case is '. . . cr'. '.' is a command that pops the stack and displays the numeric value. So '. . .' pops and displays three numbers, in this case 'buttons y x'. 'cr' is carriage return.

So the phrase 'if . . . cr then' handles the result of 'get-event'. If get-event timed out, it pushed 'false', so 'if' just skips past the 'then'. If get-event got something, it pushed 'true' on top of several numbers, so 'if' executes its body which displays those numbers on a line.

;
';' terminates the new procedure that is being compiled and returns to interactive state. The new procedure (which happens to be named 'show-mouse') is now available for use, just like every other procedure in the system. With the exception of about a hundred primitive procedures that are written in assembly language, the entire system is build up like this.

If you want to look at the definition of 'show-mouse' - or any other procedure for that matter, just type 'see show-mouse'.


show-mouse many
Now that we are back in interactive state (';' kicked us out of compilation state), typing 'show-mouse' just executes it. It does its job, polling the mouse for 16 milliseconds and displaying the report if one was available. But doing that once isn't particularly exciting. That's where 'many' comes in. 'many' is a nifty interpreter hack that checks to see if you have typed anything. If you have, it does nothing and the command line finishes. If you haven't typed anything, 'many' just rewinds the input stream to the beginning of the line, so the interpreter sees the 'show-mouse' again. And again.

You might be amused to see how simple the implementation of 'many' is. The clue for how to go about that is given above...

More Capabilities

I have a driver for the new OLPC touchpad that supports stream mode and advanced mode and simultaneous mode and knows how to decode all the different packet formats. If you need that, just tell me.