

			   BBMouseServDoc Rev 1.0

		      (C) Copyright 1995 Remi Lenoir

			 BBMouseServDoc is FREEWARE



Hi BridgeBoard users,

All the software written by Commodore for the BridgeBoard was targeted at 
DOS/Windows 2.x/3.x. This is a problem for people using the various unix 
flavors available (Linux, BSD, NeXt, etc...) or any other "non-standard" 
(if I *dare* to say so) OS. It is likely to be a problem even for people 
using Windows as future versions might not support "amouse3.drv" any more.

The keyboard is not a problem as it is handled on the BB by a customized
8042 making it transparent to the BIOS.

However, the mouse is handled by software and the driver provided for DOS,
although it might work under OS2, will not work under OS like Unix. I 
personaly use DOS/Windows on my BB but this really bothers me to think that
some people have to use a dedicated mouse for the PC side and that all the 
talent that went into designing the BB is sitting here waiting to be 
exploited.

As I also wanted to understand Janus a little better, I reverse engineered 
the DOS version of the mouse driver (AMOUSE.COM).

This document will describe the information the Amiga sends to the PC, 
explain how it is sent and how the PC can retrieve it.


Ok, here we go.

The Amiga provides the PC with the following structure through the dual-port
memory:

struct MouseServ	/* I had to find a name... */
{
	WORD	MouseX;
	WORD	MouseY;
	UWORD	LeftButtonDownCounter;
	UWORD	RightButtonDownCounter;
	UWORD	LeftButtonUpCounter;
	UWORD	RightButtonUpCounter;
	UWORD	ActualButtonsState;
	UBYTE	Unknown;
	UBYTE	UpdateCounter;
};

// WORD and UWORD are 16 bit values, UBYTE are 8 bit values.


MouseX:

The horizontal position in absolute coordinate


MouseY:

The vertical position in absolute coordinate


LeftButtonDownCounter:

This field is incremented each time the left mouse button is pressed.


RightButtonDownCounter:

This field is incremented each time the right mouse button is pressed.


LeftButtonUpCounter:

This field is incremented each time the left mouse button is released.


RightButtonUpCounter:

This field is incremented each time the right mouse button is released.


ActualButtonsState:

The present state of the left and right buttons. Bit 0 is the left
button and bit 1 is the right button.


Unknown:

I wasn't able to determine the meaning of this field. It doesn't seem to
be used by AMOUSE.COM. Could it be a Semaphore ?


UpdateCounter:

This field is incremented each time a field of the structure is updated 
(the UpdateCounter field excluded of course...). It is also incremented
once a second no matter what happens (see later).


Number of Buttons:
------------------

AMOUSE.COM supports only two buttons and I suppose MouseServ to be alike.


Show me, show me!
-----------------

To better illustrate what the fields contain, I wrote a little program that
checks their contents every 10ms (you might want to check them more oftenly
in your driver). This demo program also demonstrates how to call Janus, have
the amiga launch the mouse server and access the mouse/buttons information.


How it works:
-------------

When AMOUSE.COM is started, it calls the PC side of Janus and asks for the 
mouse service to be started. Janus then calls its Amiga side and asks it to
launch the mouse server. Amiga Janus then launches MouseServ (Amiga services
are located in SYS:PC/Services and identified by a unique number pair located
in their ToolType area).

After being launched, MouseServ allocates some memory in the dual-ported RAM
that will be used to send the mouse movements/buttons info to the PC side.

When 'Left Amiga P' is pressed, MouseServ intercepts the mouse events and
send them to AMOUSE.COM (thru the dual-port RAM). When 'Left Amiga P' is
pressed again, MouseServ stops intercepting the mouse events and let them go
to Intuition again. As far as I understand, there is no handshake between the
Amiga and the PC except the initial Janus GetBase/GetService (the PC asking 
the Amiga to load the mouse server). 

The Amiga doesn't send a signal (ie: interrupt) to the PC to tell that new
values are available. It's up to the PC to check the variables in the 
dual-ported RAM at regular intervals to know about the changes.

But how exactly does AMOUSE.COM know that the mouse has moved ? Well, it 
hooks in the timer interrupt of the PC and, at each interrupt, checks to see
if the UpdateCounter field changed. If yes, it means new data were written to
the dual-ported RAM. In that case, AMOUSE.COM copies the data to an internal 
buffer and sets all the fields of the data in the dual-port RAM to zero 
except "ButtonAcutalState" and "UpdateCounter". It then translates the mouse
movememts/button state in the format expected by the application. 

- aside

AMOUSE.COM actually does a lot more as it provides the services located
in INT 33H which is dedicated to the mouse driver. It also takes care of 
displaying the cursor (hooks in the video interrupt INT 09H) and more.
It's really an unbelievable mess what a DOS mouse driver has to do...

- end of aside

The PC applications have two ways of knowing about the change. A synchronous
way in which they poll the mouse driver and an asynchronous way in which
they ask the mouse driver to notify them when specified events take place.
First way: the programs call a function of the mouse driver, that reports
the mouse position and the buttons state, when they want to know about 
the mouse. Second way: they provide the mouse driver with a pointer to a 
handler and a condition upon which the mouse driver has to call the 
handler (ie: when left button is pressed).

What you'll have to do depends on the OS you are writing for but, it is very
likely that the driver will be required to detect a mouse/buttons movement 
and signal the OS in which case you'll have to do something close to 
AMOUSE.COM, like this:


Driver's Init:

 1 - Call Janus to start (autoload if necessary) the mouse server.

 2 - Init Copy_Of_UpdateCounter to 0

 3 - Set up a timer to check the dual-ported memory at regular intervals.


Driver's timer interrupt:

 A - Check if UpdateCounter changed since the last interrupt by comparing 
     the UpdateCounter field in the DualPort RAM against the copy maintained
     by the driver (Copy_Of_UpdateCounter).
     if they are different goto B (data were updated) else exit.

 B - Copy_Of_UpdateCounter = UpdateCounter of MouseServ structure.

 C - Make a copy of the MouseServ structure.

 D - If you want, set the MouseServ structure fields to zero (in the 
     dual-ported RAM). AMOUSE.COM doesn't set the "ActualButtonsState" and
     "UpdateCounter" field to zero.

 E - Check if UpdateCounter changed since B (same method as in A) in 
     which case the dual-ported memory was updated in between which in 
     turns means that the data we read might be corrupted.
     if they are different goto B else continue.

 F - OS specific code starts here using the copy of the MouseServ structure.

Notes:

1) In the demo program, I didn't zero the fields of the MouseServ structure 
   in the do-while loop (used to simulate the interrupt) to help the 
   understanding. Setting the fields to zero will directly indicate to the 
   driver the changes from the previous call but there is no obligation, that
   I know of, to do it.

2) As you can see, the PC could miss an event when it discards a structure
   because of corruption suspicion. That's why, I guess, the Amiga increments
   the UpdateCounter once a second even if no changes took place to make sure
   the PC always has the actual state of the mouse.


Janus:
------

Of course you need to know about Janus programming. The problem is that the
development kit is very difficult to find and people who have it can not 
disclose any information because of NDA (Non Disclosure Agreement). 
Nevertheless, I don't think there is anything wrong in making public a source
code that discloses just enough of Janus to load the mouse server, especially
when no more support/development is done on this product.


Demo Program:
-------------

The demo program, imaginatively named MyMouse, should clarify everything. 
It runs under DOS and was compiled using Borland Turbo C++ V3.0 although any
compiler should do. There might be some parts of the code that are compiler 
dependent so I'll explain them in the next paragraph.


Possible compiler dependancies:
-------------------------------

SYNOPSIS: void clrscr( void )
FUNCTION: clear the screen.

SYNOPSIS: void gotoxy( int column, int line )
FUNCTION: position the text cursor at column, line.

SYNOPSIS: void ctrlbrk( int (*handler)(void) )
FUNCTION: intercept CTRL_C and call the handler() function.

SYNOPSIS: void delay( unsigned time_in_ms )
FUNCTION: wait for time_in_ms milliseconds.

SYNOPSIS: int kbhit( void )
FUNCTION: check if a key was pressed (no waiting)

SYNOPSIS: void far *MK_FP( unsigned Segment, unsigned Offset )
FUNCTION: a macro to make a far pointer from a segment and an offset value.

SYNOPSIS: unsigned FP_SEG( void far *p )
FUNCTION: a macro to get the segment of a far address

SYNOPSIS: unsigned FP_OFF( void far *p )
FUNCTION: a macro to get the offset of a far address

SYNOPSIS: void intr( int intno, struct REGPACK *registers )
FUNCTION: execute 80x86 sotware interrupt intno.
          1 - Copies register values from REGPACK structure into CPU registers.
          2 - Execute software interrupt intno
          3 - Copies the CPU registers into the REGPACK structure.

note: struct REGPACK { /* unsigned is a 16 bit value */
                       unsigned r_ax, r_bx, r_cx, r_dx;
                       unsigned r_bp, r_si, r_di;
                       unsigned r_ds, r_es, r_flags;
                     };

You could use assembly language to execute an interrupt:

	push	es
	push	di
	push	dx
        mov	ah, 1		;Function = GetBase()
	mov	al, Service
	int	0x0B		;Call Janus
	mov	ParmSeg, es
	mov	ParmOff, di
	mov	BuffSeg, dx
	pop	dx
	pop	di
	pop	es


Development Configuration:
--------------------------

This is the system I used to develop MyMouse.

- A3000T with GVP 68040 accelerator.
- A2386SX25 with a TI486SLC2-50 CPU upgrade and 4MB of RAM.
- Janus Handler V36.85.
- Janus Library V36.83.
- Janus Handler is shadowed and its Segment is D000.
- SXServ V1.6, from Frank Mariak, available on Aminet.


The end:
--------

There should be now enough information to write a driver for any OS. This
documentation doesn't pretend to be complete nor accurate, just helpful...
If you have problems and/or questions, you can reach me by e-mail -in French 
or English- at remi@dvsystems.com or by posting in c.s.a.emulations which I
regularly check.

Have fun and write drivers!

Remi Lenoir

