• Please review our updated Terms and Rules here

AT&T 6300 (Olivetti M24) mouse software compatibility query

AlG

Member
Joined
Jan 2, 2017
Messages
15
Location
United Kingdom
Hello, I've got a query about the compatibility of the keyboard connected mouse for the Olivetti M24/AT&T 6300. I was just wondering what other people experiences with it were.

Following advice on this forum, I've re-wired an Atarti ST mouse to work with the AT&T6300 keyboard.
Without a driver, it's working, and providing arrow key input and responding to button presses.
With the mouse driver (AT&T version 1.0), it's also working, but only on a sub-set of programs. It works (as a full mouse) in the provided configuration program and Microsoft Works. But it doesn't work on lemmings or Monkey Island.

Is this expected behaviour, and if so is there a work-around? Is it just that the mouse has limited support?
Are there any other drivers that work with the mouse?

I'm running DOS 3.3 and BIOS version 1.36, if that makes any difference.

Thanks,

Alastair
 
I have the original Olivetti mouse, but signal wise it is exactly the same as Atari ST/PC (PC 1-3) or Commodore Amiga (just two wires swapped compared to ATARI) and even some Schneider Euro PC.

It's running fine with Windows 1.0, 2.0 and GEM when I select there the Olivetti Keyboard mouse driver (it's independent from the dos driver). The DOS driver works fine with Norton Commander and PC-Tools, but until yet I haven't tryed some games using the mouse.

As basically your mouse adapter works, I don't think you have done something wrong. Don't forget, that mouse driver is very old and that mouse was not very common even on M24/6300, maybe it's incompatible in some way to some newer software.
 
Hello, I've got a query about the compatibility of the keyboard connected mouse for the Olivetti M24/AT&T 6300. I was just wondering what other people experiences with it were.

Following advice on this forum, I've re-wired an Atarti ST mouse to work with the AT&T6300 keyboard.
Without a driver, it's working, and providing arrow key input and responding to button presses.
With the mouse driver (AT&T version 1.0), it's also working, but only on a sub-set of programs. It works (as a full mouse) in the provided configuration program and Microsoft Works. But it doesn't work on lemmings or Monkey Island.

Hi Alastair,
From your description about the two game it seems that mouse is not working at all. I had a similar experience re-writing mouse driver for Olivetti Prodest PC1 (similar @ M24 keyboard mouse).
The PC1 mouse uses keyboard scan codes for emulation mouse key. (I Think M24 uses scan codes also for movement).
The problem with these two games (Monkey & Lemmings) is that thy hook int09 (keyboard interrupt) WITHOUT calling it back.
So the original mouse driver cannot catch special scancode and (in my case) didn't operate mouse click. BAD programming indeed. Buy maybe they need all single MHz power from the processor. ;)
I re-wrote my driver to check hook int09 periodically and take it back if necessary.
The good news is that they are the only games I found that have this problem!
 
Great sleuthing! I never thought about it before, but it makes perfect sense: Because the mouse is keyboard-based, if the keyboard interrupt is stolen by the game, then the mouse cannot work.

Simone, did you ever make your rewritten driver available? I'd like to include it in public archives.

AIG, I've have mostly excellent compatibility with the mouse and its driver when used in period-appropriate environments (ie. anything made for the 6300's lifetime, like 1990 and earlier).
 
Thanks for all the informative reply’s.

It’s good to know it’s not a wide spread issue and it only affects a few bits of software. It’s typical that I chose to use those two pieces of software to test the mouse ;).

Simone, it’s interesting to know the technical reason for the mouse not working. I’m assuming it also explains why the mouse doesn’t work using its ‘non-driver’ functionality in these pieces of software. Out of interest, did you rewrite the Prodest PC1 driver just for these pieces of software, or were you already doing it for something else?.
- Al
 
Great sleuthing! I never thought about it before, but it makes perfect sense: Because the mouse is keyboard-based, if the keyboard interrupt is stolen by the game, then the mouse cannot work.

Simone, did you ever make your rewritten driver available? I'd like to include it in public archives.

Hi Trixter, here is the mouse driver with a test program I wrote in TP7: https://www.dropbox.com/s/gib1bau7cy6hvad/MOUSEPC1.zip?dl=0

However it works only with Olivetti Prodest PC1 because of its peculiar chips (is driven by video chip for cursor movement).
And the difference from original driver is that the cursor is painted by the graphic card itself (hardware sprite) so also in textmode we have a graphic cursor:
16114682_1852790014939412_6096858600287420564_n.jpg

or better in this video: https://www.youtube.com/watch?v=-8K92o8dMmk&feature=youtu.be

AIG: I rewrote the driver to use less ram (it was 10k and mine is 2k) and gain some speed from the graphic cursor... then I find those two games that have problem (monkey is one of my favourite) and adjusted the driver to get it work. basically I checked int09 and get it twice but with a different entry preserving original call address when returning to dos to avoid problems.

The "bug" was originated because none of the modern mouse driver uses int09 anymore...
 
If you provide the source, maybe I or someone can add 6300/M24 support. Or, maybe just the source for your int09-regrabbing code so I can see how you did it, and then maybe I can RE the 6300 mouse driver and add just that section.

Interestingly the 6300 Mouse driver MOUSE.DOC warns about not taking over the keyboard (and also confirms the mouse and driver were OEM Logitech):

**Notice to System Programmers**


System programmers who intercept the keyboard hardware interrupt
(int 9) or the video i/o software interrupt (int 10h) should
exercise utmost care, and note the following:


The mouse driver itself intercepts these two interrupts.


The mouse driver expects to receive all the codes which are
relevant for the mouse from the keyboard. If a program which
intercepts the keyboard interrupt is loaded after the driver the
following codes from the keyboard should fall through and be
left available for the mouse driver:




-2-
LOGITECH - mouse.doc for AT&T v.1.0 2/85



77h, 78h, 79h, F7h, F8h, F9h
7Ah, 7Bh, 7Ch, 7Dh, FAh, FBh, FCh, FDh,
FEh and the next 2 codes which follow an
occurrence of FEh (FEh is the prefix character
for mouse movement reports).


Codes 74h, 75h, 76h, F4h, F5h, F6h are reserved for future use
by mouse software.


All other codes are left by the mouse driver to the next
interrupt handler on the chain (presumably the ROM resident
keyboard interrupt handler).

To check for the presence in memory of the LOGITECH mouse driver
one should check for a "signature" at the offset 10h from the
entry of software interrupt S1. The signature is the string
"LOGITECH MOUSE DRIVER".
 
Last edited:
If you provide the source, maybe I or someone can add 6300/M24 support. Or, maybe just the source for your int09-regrabbing code so I can see how you did it, and then maybe I can RE the 6300 mouse driver and add just that section.

Interestingly the 6300 Mouse driver MOUSE.DOC warns about not taking over the keyboard (and also confirms the mouse and driver were OEM Logitech):

Of course:
If you need the txt file, PM to me!

Code:
;*****************************************************************************
;*	   		  .-= MOUSE PC1 Project =-.			     *
;* Int33h mouse hook for PC1 - NECV40 0.97 by Simone Riminucci (C) 2016	     *
;* Started: 29.11.2016							     *
;* Last updated 21.02.2017						     *
;* Tested on: OLIVETTI PRODEST PC1 (NEC V40 XT, 512/640kB)		     *
;*	     								     *
;* Only 1904 byte Resident!						     *
;* Compile with NASM (186 code)						     *
;* Hardware Mouse pointer using YAMAHA V6335D special registers !	     *
;*****************************************************************************

CPU 186 			;code compatability

;%define DEBUG
;%define CALL_OLD_INT33
BIOS_DATA_SEG	EQU 40h
driverversion	equ 303h	;imitated Microsoft driver version

%include "constant.inc"    ; Stuff that never changes.

%macro TEST1 2	;test 1 bit (n. CL). ZF is set if bit is zero.
		; out CY=0 V=0, ZF as needed
	%ifn %2=CL
	   %error "Only CL as second parameter"
	%endif

	db 0Fh

	%if %1=AL
	  db 10h
	  db 0C0h
	%elif %1=AX 
	  db 11h
	  db 0C0h 
	%else 
    	  %error "Invalid Parameter" 
	%endif
%endmacro

%macro SET1 2	;set 1 bit (n. CL). if ZF is set the bit go to zero.
	%ifn %2=CL
	   %error "Only CL as second parameter"
	%endif

	db 0Fh

	%if %1=AL
	  db 14h
	  db 0C0h
	%elif %1=AH 
	  db 14h
	  db 0C4h 
	%elif %1=AX 
	  db 15h
	  db 0C0h 
	%else 
    	  %error "Invalid Parameter" 
	%endif
%endmacro

;************** Program header ***************************************************

	ORG	100h		;use if compiling .COM file
	jmp	start

cmdlineflags	db 0

KeyStatus       db 0
Old_INT08       dd 0                    	;old INT
Old_INT09       dd 0  				;old INT

%ifdef CALL_OLD_INT33
Old_INT33       dd 0  				;old INT
%endif

Old_INT09_MONK	dd 0                    	;old INT
Already_in_user	db 0
Cursor_Flag	db 0FFh
MIN_HRange	dw 0
MAX_HRange	dw 639
MIN_VRange	dw 0
MAX_VRange	dw 199
Hor_Ratio	dw 8
Vert_Ratio	dw 8
X_Mult_Ratio    dw 8
Y_Mult_Ratio    dw 8 
CenterX		dw 15
CenterY		dw 15
H_Mickey_Count	dw 0
V_Mickey_Count	dw 0
Max_speed_D2    dw 2
Max_Speed_D     dw 35h
Button_Status		dw 0
LB_Count_press		dw 0
LB_PosX_last_press 	dw 0
LB_PosY_last_press 	dw 0
LB_Count_releases 	dw 0
LB_PosX_last_release 	dw 0
LB_PosY_last_release 	dw 0
RB_Count_press		dw 0
RB_PosX_last_press 	dw 0
RB_PosY_last_press 	dw 0
RB_Count_releases 	dw 0
RB_PosX_last_release 	dw 0
RB_PosY_last_release 	dw 0
shift_X_Pos		db 1
shift_ratioX		db 0
shift_ratioY		db 0
MouseX_Sum		dw 160
MouseY_Sum		dw 100
Cursor_attribute	db 0F0h
Last_mask		db 0	
User_Event_Mask		db 0	; Changed: Cursor pos,left press, left rel, right press, right rel
Event_Handler_Addr 	dd 63620000h
ORG_AX		dw 0
ORG_BX		dw 0
ORG_CX		dw 0
ORG_DX		dw 0
ORG_DI		dw 0
ORG_SI		dw 0
ORG_ES		dw 0

screenmask	dw 0011111111111111b	; 0
		dw 0001111111111111b	; 2
		dw 0000111111111111b	; 4
		dw 0000011111111111b	; 6
		dw 0000001111111111b	; 8
		dw 0000000111111111b	; 10
		dw 0000000011111111b	; 12
		dw 0000000001111111b	; 14
		dw 0000000000111111b	; 16
		dw 0000000000011111b	; 18
		dw 0000000000001111b	; 20
		dw 0000000011111111b	; 22
		dw 0001000011111111b	; 24
		dw 0111100001111111b	; 26
		dw 1111100001111111b	; 28
		dw 1111110001111111b	; 30	

cursormask	dw 0000000000000000b	; 0
		dw 0100000000000000b	; 2
		dw 0110000000000000b	; 4
		dw 0111000000000000b	; 6
		dw 0111100000000000b	; 8
		dw 0111110000000000b	; 10
		dw 0111111000000000b	; 12
		dw 0111111100000000b	; 14
		dw 0111111110000000b	; 16
		dw 0111111111000000b	; 18
		dw 0111111000000000b	; 20
		dw 0100011000000000b	; 22
		dw 0000011000000000b	; 24
		dw 0000001100000000b	; 26
		dw 0000001100000000b	; 28
		dw 0000000000000000b	; 30

Int33_sub_index	dw Fun_00	; Reset/Query driver Presence
		dw Fun_01	; Display Pointer
		dw Fun_02	; Hide Pointer
		dw Fun_03	; Query	Position & Buttons
		dw Fun_04	; Move Pointer
		dw Fun_05	; Query	Button Pressed count
					; BX = 0  left button
					;      1  right	button
					;
					;
					;	  on return:
					;	  BX = count of	button presses (0-32767), set to zero after call
					;	  CX = horizontal position at last press
					;	  DX = vertical	position at last press
					;	  AX = status:
					;		  |F-8|7|6|5|4|3|2|1|0|	 Button	Status
					;		    |  | | | | | | | `---- left	button (1 = pressed)
					;		    |  | | | | | | `----- right	button (1 = pressed)
					;		    `------------------- unused
		dw Fun_06	; Get Mouse Button Release Information
					;
					; BL=Button
					;
					; on return:
					;	  BX = count of	button releases	(0-32767), set to zero after call
					;	  CX = horizontal position at last release
					;	  DX = vertical	position at last release
					;	  AX = status
		dw Fun_07	; Set Horizontal range
					; CX = minimum H pos
					; DX = maximum H pos
		dw Fun_08	; Set Vertical range
					; CX = minimum V pos
					; DX = maximum V pos
		dw Fun_09	; Set graphic pointer shape
					; BX = horizontal hot spot (-16	to 16)
					; CX = vertical	hot spot (-16 to 16)
					; ES:DX	= pointer to screen and	cursor masks (16 byte bitmap)
		dw Fun_0A	; Set text pointer mask
		dw Fun_0B	; Query	last motion distance
		dw Fun_0C	; Set Event Handler
		dw no_fun	; Enable Light Pen Emulation
		dw no_fun	; Disable Light	Pen Emulation
		dw Fun_0F	; Set Pointer Speed
					; CX= Horizontal Ratio
					; DX= Vertical Ratio
		dw no_fun	; Set Exclusion	Area
		dw Fun_11	; GET NUMBER OF BUTTONS (special PC1 MOUSE procedure)
		dw no_fun
		dw Fun_13	; Set max for Speed Doubling
		dw Fun_14	; Exchange Event Handler

INT_08:
	pusha
	push	ds
	
	push 	cs		;variable segment!
	pop	ds
	mov     byte [Last_mask], 0
	call	read_M_delta_coord
	cmp	bl, 00h			; Value	00h or FFh = WAS MOVED!
	jz	go3
	cmp	byte [Cursor_Flag], 0	; default -1 (FF) not visible
					; visible=0
	jnz	go2
update_cur:
	cli
	mov	dx, 3DDh
	mov	al, 60h+80h		;sistemiamo solo lo sprite per ora...
	out	dx, al
	inc	dx
	mov     ax, [MouseX_Sum]
	shr	ax, 1
	add	ax, [CenterX]
	xchg	al, ah
	out	dx,al
	xchg	al, ah
	out	dx,al
	mov     ax, [MouseY_Sum]
	add	ax, [CenterY]
	xchg	al, ah
	out	dx,al
	xchg	al, ah
	out	dx,al
	sti
	cmp	bl, 0Fh			;me lo posso permettere perchè ho eliminato MOV mem,imm e CMP mem,imm -> CMP reg,imm
	jz	return_to_fun04		;adjust_cursor was on-going
go2:	or      byte [Last_mask], 1	; signal cursor movement to mask

	push    es
	call    Call_User	; there is X or Y movement!
	pop     es


go3:	pop	ds
	popa

	jmp	far [cs:Old_INT08]

%macro CHECK_THRES 0	;test for AX < [Max_speed_D2] in valore assoluto SENZA jump! (prima ce ne erano 2!!!)
		; AX shifted if |AX| > [Max_speed_D2] - CX Corrupted - speed optimized
	push	AX
	mov	CX, AX
	SHR	CX, 0Fh
	xor	AX, CX
	sub	AX, CX
	cmp	ax, [Max_speed_D2]	;carry set if Below [Max_speed_D2]
	cmc				;set if Higher of [Max_speed_D2]
	xor	cl, cl
	rcl	cl, 1		;cl=1 if carry set, 0 otherwise
	pop	ax		;tiriamo fuori il valore originale
	shl	ax, cl
%endmacro

read_M_delta_coord:		; (BL) lo uso come "was moved!"
	mov	BL, 0		; was moved = no
	mov	al, 10h		; load CTRC register
	out	0D4h,al
	in 	al, 0D5h
	cmp	al, 0
	je	rm2		; non è cambiata la "X"
	cbw                     ; Converts byte in AL to word Value in AX by extending sign of AL throughout register AH.
	neg 	ax		; negative! la X è sepre negativa, non so perchè
	dec	BX
	add     [H_Mickey_Count], ax		;here the mickey are NOT doubled!
	CHECK_THRES
	mov	CL, byte [shift_ratioX]		;shifting is better than IMUL/IDIV 50+34=84 Clock!!! 
	shl	ax, cl
	add     ax, [MouseX_Sum]
	call	Verify_in_HRange
	mov     [MouseX_Sum], ax
 rm2:	mov	al, 11h		; load CTRC register
	out	0D4h,al
	in 	al, 0D5h
	cbw
	cmp	ax, 0
	je	rm4
	dec	BX		; was moved = sì più corto ancora: 1 solo byte
	CHECK_THRES
 rm3:	add     [V_Mickey_Count], ax		;here the mickey are NOT shifted
	mov	CL, byte [shift_ratioY]		;shifting is better than IMUL/IDIV 50+34=84 Clock!!! 
	shl	ax, cl
	add     ax, [MouseY_Sum]
	call	Verify_in_VRange
	mov     [MouseY_Sum], ax
return_to_fun04: 	;sì è pulcioso, si risparmia un'altro byte se è meno lontano di 127 byte!
rm4:	ret

; NOTA: non uso pushf/popf perchè sono già salvate da INT09 procedure

INT_09bis:	push	ax		
		call	Has_been_pressed_a_Mkey
		or	al, al
		jnz	pressed
		pop	ax
		jmp	far [cs:Old_INT09_MONK]

INT_09:		push	ax
		call	Has_been_pressed_a_Mkey
		or	al, al
		jz	GoTo_OldInt
pressed:	pusha
		push	es
		push	ds
		push	cs	;RIGHT SEGMENT FOR DATA
		pop	ds
		;mov	bx, cs
		;mov	ds, bx
		;mov	es, bx
		mov	ah, [KeyStatus]
		test	al, 4
		jnz	short loc_DE6
		test	al, 80h
		jnz	short loc_DE0
		or	ah, 2
		jmp	short loc_DF3

loc_DE0:				
		and	ah, 1
		jmp	short loc_DF3

loc_DE6:	test	al, 80h
		jnz	short loc_DF0
		or	ah, 1
		jmp	short loc_DF3

loc_DF0:	and	ah, 2

loc_DF3:	and	ah, 3
		mov	[KeyStatus], ah
		mov	al, ah
		mov	byte [Last_mask], 0
		call    Update_keyCount
		call	Call_User
		pop	ds
		pop	es
		popa
		pop	ax	;pre-interrupt AX preserved!
		iret
; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

GoTo_OldInt:	pop	ax
		jmp	far [cs:Old_INT09]

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

;corrupt only AX!
Has_been_pressed_a_Mkey:
		in	al, 64h		; AT Keyboard controller 8042.
		and	al, 0D0h
		jz	short loc_1C2C
		xor	ax, ax
		ret

loc_1C2C:	in	al, 60h		; AT Keyboard controller 8042.
		mov	ah, al
		cli
		mov	al, 61h		; Ok, key processed!
		out	20h, al		; Interrupt controller,	8259A.
		sti
		mov	al, ah
no_fun:		ret

no_user_fun:	
		retf

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

Update_keyCount:		;AL= xxxxxLxR

		mov	bx, [Button_Status]
		mov	byte [Button_Status],	al

		xor	cx, cx	;azzeriamo  CH  CL - CH tiene i bit RRLL, CL il numero di shift da fare
		xor	al, bl
		shr	al, 1	;tasto SX: Carry =1 se cambiato =0 se non cambiato rispetto al vecchio status
		rcr	ch, 1	;inseriamo questo valore nel byte, al primo posto (+ significativo)
		shr	ah, 1	; Carry =1 se Pressed =0 se released
		rcl	cl, 1	; Qui CL diventa 1 se il tasto è pressed!
		shr	ch, cl	; Se pressed è il quarto bit da mettere a 1, quindi lo spingo ancora avanti tipo "01000000"
				; finito con il tasto sinistro = CH="LL000000"
		mov	cl, 0
		shr	ah, 1	; Carry =1 se Pressed =0 se released
		cmc		; Toggles (inverts) the Carry Flag
		rcl	cl, 1	; Qui CL diventa 1 se il tasto è released!
		shr	ch, cl	; aggiungiamo uno zero se è released -> "0LL0000", altrimenti invariato

		shr	al, 1	; tasto DX: Carry =1 se cambiato =0 se non cambiato rispetto al vecchio status
		rcr	ch, 1	; lo aggiungiamo al solito a sx: adesso abbiamo: "RLL00000" o "RRLL0000"
		xor	cl, 1	; Inverto CL: se era 0 diventa 1 e viceversa
		shr	ch, cl	; quindi aggiungiamo uno zero se è pressed -> "0RLL0000", altrimenti invariato

		shr	ch, 4   ;adesso abbiamo in CH i 4 bit 0000RRLL
		mov	dh, ch
		mov	dl, ch
		shl	dl, 1	;DL è pronto per andare in [last_mask] '000RRLL0'

		mov	si, [MouseX_Sum]
		mov	di, [MouseY_Sum]
		
		xor	bx, bx
		mov	cl, 4	;4 passaggi LB_Press, LB_Release, RB_Press, RB_Release
.next		shr	dh, 1
		jc	.updatePR
.cont		add	bx, LB_Count_releases-LB_Count_press
		loop	.next

		mov	byte [Last_mask], dl
		ret

.updatePR	inc	word [LB_Count_press+bx]
		mov	word [LB_PosX_last_press+bx], si
		mov	word [LB_PosY_last_press+bx], di
		jmp 	.cont

; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

INT_33:
%ifdef CALL_OLD_INT33
	or      ah, ah
	jnz     call_old33_if_exist
%endif
	sti        
	call    Call_Subfun
end_int33:	
	iret

call_old33_if_exist:
%ifdef CALL_OLD_INT33
	cmp     word [cs:Old_INT33+2], 0
	jz      end_int33
	jmp     far [cs:Old_INT33]
%endif

; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Install_INT09_MONK:
	cli
	mov     ax, 3509h
	int     21h             ; DOS - 2+ - GET INTERRUPT VECTOR
				; AL = interrupt number
				; Return: ES:BX = value of interrupt vector
	mov     word [Old_INT09_MONK], bx
	mov     word [Old_INT09_MONK+2], es
	mov     dx, INT_09bis ; Int 09 (BIS) Entry Point
	mov     ax, 2509h
	int     21h             ; DOS - SET INTERRUPT VECTOR
				; AL = interrupt number
				; DS:DX = new vector to be used for specified interrupt
	sti
	ret

; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;check for INT_09 hook!
Check_INT09_MONK:
		xor	ax, ax
		mov	es, ax
		mov	ax, cs
		cmp     word [ES:09h*4+2], ax	;check for int09 data segment
		je	allok
		;SEMPLIFICO: se non è nel segmento la cambio altrimenti lascio stare!
		;mov     ax, 3509h
		;int     21h             ; DOS - 2+ - GET INTERRUPT VECTOR
		;			; AL = interrupt number
		;			; Return: ES:BX = value of interrupt vector
		;mov	ax, cs
		;mov	cx, es
		;cmp     ax, cx		
		;jne	install_newint	;qualcuno (monkey?) ha cambiato l'int 09
		;mov	cx, INT_09
		;cmp     cx, bx
		;je	allok
		;mov	cx, INT_09bis
		;cmp     cx, bx
		;je	allok
install_newint:	call	Install_INT09_MONK
		
allok:		ret

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

Reset_pointer_and_var:
		xor	ax, ax				;mov mem, ax è più veloce e occupa meno di mov mem,0
		mov	bx, 8				;per i valori da 8
		mov     word [MouseX_Sum], 320
		mov     word [MouseY_Sum], 100
		mov     word [Hor_Ratio], bx
		mov     word [Vert_Ratio], bx
		mov     byte [Already_in_user], al
		mov	byte [User_Event_Mask], al
		mov	word [Event_Handler_Addr+2], cs
		mov	dx, no_user_fun
		mov	word [Event_Handler_Addr], dx
		mov     word [H_Mickey_Count], ax ; horizontal mickey count (-32768 to 32767)
		mov     word [V_Mickey_Count], ax
		mov     word [X_Mult_Ratio], bx
		mov     word [Y_Mult_Ratio], bx
		mov     byte [CenterX], 15
		mov     byte [CenterY], 15
		mov     byte [Max_speed_D2], 2
		mov     byte [Max_Speed_D], 35h

		mov     word [MIN_VRange], ax
		mov     word [MIN_HRange], ax
		mov	BYTE [shift_X_Pos], al

		;check for INT_09 hook!
		call	Check_INT09_MONK
		
		mov     ah, 0Fh
		int     10h             ; - VIDEO - GET CURRENT VIDEO MODE
					; Return: AH = number of columns on screen
					; AL = current video mode
					; BH = current active display page
		mov     word [MAX_VRange], 199
		mov     word [MAX_HRange], 639
		cmp	al, 06h
		je	cnt1
		mov	BYTE [shift_X_Pos], 1

cnt1:		lea     si, [screenmask]
		call 	Copy_cursor_shape	; Copy cursor addressed by DS:SI 
		call	TransMult
		ret

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Reset/Query driver Presence

Fun_00:		mov	[Cursor_Flag], byte 0
		call	Fun_02
		call	Reset_pointer_and_var
		xor	ax,ax
		mov	byte [User_Event_Mask], al ; Changed: Cursor pos,left press, left rel,	right press, right rel
		dec	ax		;mov	ax, 0FFFFh	;INSTALLED
		mov	[ORG_AX], ax
		mov	ax, 2		;0FFFFh	;2 Buttons	
		mov	[ORG_BX], ax
		ret

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Display Pointer

Fun_01		cmp	byte [Cursor_Flag], 0	; default -1 (FF) not visible
						; visible=0
		jz	end_fun_01		; già visibile
		inc	byte [Cursor_Flag]
		jnz	end_fun_01

		mov	ah, byte [Cursor_attribute]	
		mov 	al, 68h+80h
		out	0DDh,AX		;DD->AL DE->AH
		jmp 	adjust_cur		

end_fun_01:	ret


; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Hide Pointer

Fun_02		dec	byte [Cursor_Flag]
		;cmp	byte [Cursor_Flag], 0FFh	; default -1 (FF) not visible
							; visible=0
		;jnz	end_fun_02			; always HIDE!

		mov 	al, 68h+80h
		mov	ah, 0Fh		;cursor transparent
		out	0DDh,AX		;DD->AL DE->AH

end_fun_02:	ret


; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Query	Position & Buttons

Fun_03:		;pushf			; out:
					; CX = Horizontal (X) position
					; DX = Vertical	(Y) position
					; BX = Button Status (bit 0-1=L-R)
		mov	ax, [Button_Status]
		mov	[ORG_BX], ax
		mov	ax, [MouseX_Sum]
		mov	[ORG_CX], ax
		mov	ax, [MouseY_Sum]
		mov	[ORG_DX], ax
		;popf
		;check for INT_09 hook!
		call	Check_INT09_MONK
		ret


; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Move Pointer

Fun_04:		mov	ax, dx
		call	Verify_in_VRange ; Verify if pointer in	Vertical Range
					; if not then move
		mov	bx, ax
		mov	ax, cx
		call	Verify_in_HRange ; Verify if pointer in	Horizontal Range
					 ; if not then move
		mov	[MouseX_Sum],	ax
		mov	[MouseY_Sum],	bx

		cmp	byte [Cursor_Flag], 0	; default -1 (FF) not visible
						; visible=0
		jnz	endfun4
		
adjust_cur	mov	BL, 0Fh			;usede to call/ret on update_cursor ^^
		call 	update_cur
			
endfun4:
		ret

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Query	Button Pressed count
; BX = 0  left button
;      1  right	button
;
;
;	  on return:
;	  BX = count of	button presses (0-32767), set to zero after call
;	  CX = horizontal position at last press
;	  DX = vertical	position at last press
;	  AX = status:
;		  |F-8|7|6|5|4|3|2|1|0|	 Button	Status
;		    |  | | | | | | | `---- left	button (1 = pressed)
;		    |  | | | | | | `----- right	button (1 = pressed)
;		    `------------------- unused

Fun_05:		cmp	bx, 1
		ja	Fun05_end
		jb	Fun_05Out
		mov	bx, RB_Count_press-LB_Count_press	;0=SX o delta=DX
Fun_05Out:	xor	ax, ax
		xchg	ax, [LB_Count_press+BX]		;così azzero anche COUNT con un'unica istruzione, veloce!
		mov	[ORG_BX],	ax
		mov	ax, [LB_PosX_last_press+BX]
		mov	[ORG_CX],	ax
		mov	ax, [LB_PosY_last_press+BX]
		mov	[ORG_DX],	ax
		mov	ax, [Button_Status]
		mov	[ORG_AX],	ax
Fun05_end:	ret


; Get Mouse Button Release Information
;
; BL=Button
;
; on return:
;	  BX = count of	button releases	(0-32767), set to zero after call
;	  CX = horizontal position at last release
;	  DX = vertical	position at last release
;	  AX = status

Fun_06:
		cmp	bx, 1
		ja	Fun05_end
		jb	.phase2		;se bx=0 don't add L/R offset
		mov	bx, RB_Count_press-LB_Count_press
.phase2		add	bx, LB_Count_releases-LB_Count_press
		jmp	Fun_05Out


; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Set Horizontal range
; CX = minimum H pos
; DX = maximum H pos

Fun_07:		call	Invert		; Invert CX/DX if necessary (DX<CX)
		;pushf
		cli
		mov	[MIN_HRange], cx
		mov	[MAX_HRange], dx
		mov	ax, [MouseX_Sum]
		call	Verify_in_HRange ; Verify if pointer in	Horizontal Range
					 ; if not then move
		mov	[MouseX_Sum],	ax
		;popf
		jmp	adjust_cur


; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Set Vertical range
; CX = minimum V pos
; DX = maximum V pos

Fun_08		call	Invert		; Invert CX/DX if necessary (DX<CX)
		;pushf
		cli
		mov	[MIN_VRange], cx
		mov	[MAX_VRange], dx
		mov	ax, [MouseY_Sum]
		call	Verify_in_VRange ; Verify if pointer in	Vertical Range
					; if not then move
		mov	[MouseY_Sum],	ax
		;popf
		jmp	adjust_cur

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Set graphic pointer shape
; BX = horizontal hot spot (-16	to 16)
; CX = vertical	hot spot (-16 to 16)
; ES:DX	= pointer to screen and	cursor masks (16 byte bitmap)

Fun_09:		cli
		neg	bx
		add	bx, 16
		mov	[CenterX], bx
		neg	cx
		add	cx, 16
		mov	[CenterY], cx
		push	ds
		mov	si, dx
		mov	ax, [ORG_ES]
		mov	ds, ax
		pop	es
		call	Copy_cursor_shape
		push	es
		pop	ds
		sti
		jmp	adjust_cur		;è cambiato il centro!
		;ret


; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Copy cursor addressed by DS:SI 

Copy_cursor_shape:		
	mov	dx, 0DDh		;sistemiamo lo sprite...
	xor	ax, ax
	out	dx, al
	inc	dx
	cld

	mov     cx, 20h		;32 valori word (64 byte)
.copy_next:
	lodsw                   ; Load Cursor value
	cmp	cx, 10h		; if first 32 byte
	jbe	.ok		; also slow down a little the procedure: too fast in a "0-wait-state" PC1!
	not	ax		; invert it -> also is some byte less (8 byte!)
.ok:	xchg	ah,al
	out 	dx, al
	xchg	ah,al
	out 	dx, al
	loop    .copy_next       ; Load Values

	ret

; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦

; Normally Set text pointer mask
; but in this special driver set the graphics cursor color attribute
; BX = FF , then CX = AND/XOR attribute. F0 = white/black not trasparent.
; DX = 1 -> blink

Fun_0A:		cmp     bl, 0FFh 
		jnz     endfun
		mov 	byte [Cursor_attribute], cl
		mov	al, 64h+80h		;register 64h
		out	0DDh, al
		xchg	al, dl
		or	al, 110b	;set mask/and/xor = ON
		out	0DEh, al
		dec	byte [Cursor_Flag]
		jmp 	Fun_01
;endfun0A:	ret

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Query	last motion distance

Fun_0B:		;pushf
		cli
		xor	ax, ax			;così azzeriamo in un passaggio solo!
		xchg	ax, [H_Mickey_Count] ; horizontal	mickey count (-32768 to	32767)
		mov	[ORG_CX],	ax
		xor	ax, ax
		xchg	ax, [V_Mickey_Count] ; vertical mickey count (-32768 to 32767)
		mov	[ORG_DX],	ax
		;popf
endfun:		ret

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Set Event Handler

Fun_0C:		;pushf
		cli
		mov	word [Event_Handler_Addr], dx
		mov	dx, [ORG_ES]
		mov	word [Event_Handler_Addr+2], dx
		and	cl, 7Fh		; exclude high bit (7)
		mov	byte [User_Event_Mask], cl ; Changed: Cursor pos,left press, left rel,	right press, right rel
		;popf
		sti
		ret

;Fun_0D:		ret
;Fun_0E:		ret
 
; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦

; Set Pointer Speed
; CX= Horizontal Ratio
; DX= Vertical Ratio

Fun_0F: 	;cmp	cx,0
		;je	EndFun10	;una divisione per /0 avrebbe esiti funesti!
		;cmp	dx,0
		;je	EndFun10
		;mov     [Hor_Ratio], cx
		;mov     [Vert_Ratio], dx

		xchg	ax, cx		;se porto tutto su AX risparmio 1 byte ogni operazione!
		cmp	ax, word 0000h
		je	.skipHor	;una divisione per /0 avrebbe esiti funesti!
		mov     [Hor_Ratio], ax
.skipHor	xchg	ax, dx
		cmp	ax, word 0000h		;una divisione per /0 avrebbe esiti funesti!
		je	EndFun		;pulcioso, ma risparmio 1 byte
		mov     [Vert_Ratio], ax
		jmp	TransMult	

;Fun_10:		ret

; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦

; Get driver type
; return_ AX= 33h
Fun_11:		mov	ax, 33h		;Special PC1 mouse driver
		mov	[ORG_AX], ax
		mov	al, 2
		mov	[ORG_BX], ax	;number of buttons
EndFun:		ret

;Fun_12:		ret

; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦

; Set max for Speed Doubling

Fun_13:		xchg    ax, dx
		mov     [Max_Speed_D], ax
		add     ax, 11h
		mov     bx, 23h
		xor     dx, dx
		div     bx
		mov     [Max_speed_D2], ax
		ret


; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Exchange Event Handler

Fun_14:		;pushf
		cli
		mov	ax, word [Event_Handler_Addr]
		mov	[ORG_DX],	ax
		mov	word [Event_Handler_Addr], dx
		mov	dx, [ORG_ES]
		mov	ax, word [Event_Handler_Addr+2]
		mov	[ORG_ES],	ax
		mov	word [Event_Handler_Addr+2], dx
		xor	ax, ax
		mov	al, byte [User_Event_Mask] ; Changed: Cursor pos,left press, left rel,	right press, right rel
		mov	[ORG_CX],	ax
		and	cl, 7Fh
		mov	byte [User_Event_Mask], cl ; Changed: Cursor pos,left press, left rel,	right press, right rel
		sti
		;popf
EndFun14:	ret

;Fun_15:		ret
;Fun_16:		ret
;Fun_17:		ret
;Fun_18:		ret
;Fun_19:		ret

 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦

; Transform multiplier in SHIFT-LEFT
; me ne sbatto dei risultati che hanno un rapporto Mult/Ratio < 1 anche perchè il mouse è già lento così di suo
; [shift_X_Pos] già considerato!

TransMult:	mov 	al, byte [shift_X_Pos]		;parto da questo valore
		mov	byte [shift_ratioX], al
		mov     ax, [X_Mult_Ratio]
		xor	dx, dx
		div	word [Hor_Ratio]
.redo1:		shr	AX, 1
		cmp	ax, 0
		je	.ok1
		inc	byte [shift_ratioX]
		jmp	.redo1
		
.ok1:		mov	byte [shift_ratioY], 0
		mov     ax, [Y_Mult_Ratio]
		xor	dx, dx
		div	word [Vert_Ratio]
.redo2:		shr	AX, 1
		cmp	ax, 0
		je	EndFun14	;.ok2 - pulcioso ma risparmio!
		inc	byte [shift_ratioY]
		jmp	.redo2
;.ok2:		ret

 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦

; Set mouse sensivity
;         BX = horizontal coordinates per pixel
;         CX = vertical coordinates per pixel
;         DX = double speed threshold

Fun_1A:		shr	bx, 2
		mov     [X_Mult_Ratio], bx
		shr	cx, 2
		mov     [Y_Mult_Ratio], cx
		call	TransMult
		jmp     Fun_13          ; Set max for Speed Doubling

; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦

;adjust_mult:	mov     bl, 0Ah
;		div     bl
;		xor     ah, ah
;		cmp     al, 0Ah
;		jbe     short loc_B9B
;		mov     al, 0Ah
;loc_B9B:	mov     bx, moltiplic
;		;add     bx, ax
;		;mov     al, [bx]	;qui uso XLAT = mov al, [BX+AL]
;		XLAT
;		ret
; ---------------------------------------------------------------------------
;moltiplic       db 1, 2, 3, 4, 6, 8, 0Ah, 0Eh, 12h, 16h, 1Eh


; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦

; Query Mouse Sensivity

Fun_1B:		;mov     ax, [Hor_CoordXPixel]
		mov     ax, [X_Mult_Ratio]
		shl	ax, 2
		mov     [ORG_BX], ax
		;mov     ax, [Ver_CoordXPixel]
		mov     ax, [Y_Mult_Ratio]
		shl	ax, 2
		mov     [ORG_CX], ax
		mov     ax, [Max_Speed_D]
		mov     [ORG_DX], ax
		ret

;Fun_1C:		ret

;Fun_1D:	mov     [CRT_page_num], bx
;		ret

;Fun_1E:	mov     ax, [CRT_page_num]
;             	mov    [ORG_BX], ax
;		ret

;Fun_1F:		ret
;Fun_20:		ret
;Fun_21:		ret
;Fun_22:		ret

; LANGUAGE = ITA!!! :)
Fun_23:		mov     word [ORG_BX], 08h
		ret

; 24 - Get software version, mouse type and IRQ
; Out:	[AX] = 24h/FFFFh	(installed/error)
;	[BX]			(version)
;	[CL]			(IRQ #/0=PS/2)
;	[CH] = 1=bus/2=serial/3=InPort/4=PS2/5=HP (mouse type)
; Use:	driverversion
Fun_24:		mov     word [ORG_BX], driverversion
		mov	word [ORG_CX], 0309h	;inport, IRQ=09
		ret

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; Call INT 33 subfunction in AX

Call_Subfun:	push	bp
		push	ds
		push	cs	;right segment!
		pop	ds
		mov	[ORG_AX], ax
		mov	[ORG_BX], bx
		mov	[ORG_CX], cx
		mov	[ORG_DX], dx
		mov	[ORG_DI], di
		mov	[ORG_SI], si
		mov	[ORG_ES], es
		push	ds
		pop	es
		cmp	ax, 14h
		ja	short OtherFuns	; other functions!
		push	si
		mov	si, ax
		shl	si, 1
		mov	ax, [Int33_sub_index+si]
		pop	si
call_it:	call	ax
		jmp	short loc_6F5

; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
; 2A - Get cursor hot spot
; Out:	[AX]			(cursor visibility counter)
;	[BX]			(hot spot X)
;	[CX]			(hot spot Y)
;	[DX] = 1=bus/2=serial/3=InPort/4=PS2/5=HP (mouse type)	
;		cmp	al, 2Ah
;		jnz	short Fun_4D
;		mov	ax, [Cursor_Flag]
;		mov	[ORG_AX], AX
;		mov	ax, 16
;		sub	ax, [CenterX]
;		mov	[ORG_BX], AX
;		mov	ax, 16
;		sub	ax, [CenterY]
;		mov	[ORG_CX], AX
;		mov	word [ORG_DX], 3	;inport mouse
;		jmp	short loc_6F5

Fun_4D:		; Pointer to Microsoft Label!
		mov	word [ORG_DI], Copyright1983
		mov	[ORG_ES], cs
		ret

Fun_6D:		jnz	short loc_6F5
		mov	[ORG_DI], word magicnumber ;word 204h
		mov	[ORG_ES], cs
		ret

execute:	shl	bx,1
		call	[CS:other_address+bX]
		jmp	short loc_6F5	

OtherFuns:	mov	bx, 4
more:		cmp 	al, [other_num+bx]
		jz	execute
		dec	bx
		jnz	more

loc_6F5:
		mov	ax, [ORG_ES]
		mov	es, ax
		mov	si, [ORG_SI]
		mov	di, [ORG_DI]
		mov	dx, [ORG_DX]
		mov	cx, [ORG_CX]
		mov	bx, [ORG_BX]
		mov	ax, [ORG_AX]
		pop	ds
		pop	bp
		ret

other_address: 	dw Fun_1A, Fun_1B, Fun_23, Fun_24, Fun_4D, Fun_6D
other_num	db 1Ah, 1Bh, 23h, 24h, 4Dh, 6Dh

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ


Call_User:
		cmp	byte [Already_in_user], 0FFh
		jz	endend
		mov	byte [Already_in_user], 0FFh
		xor	ax,ax
		mov	al, byte [Last_mask]
		and	al, byte [User_Event_Mask] ; Changed: Cursor pos,left press, left rel,	right press, right rel
		mov	bp, Event_Handler_Addr ;	   Custom Event Handler
		jz	no_sub
		call	CALL_FUN_AT_BP	; call function	(save all registers)
					; @ BasePointer
no_sub:		mov	byte [Already_in_user], 0

endend:		ret

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

; call function	(save all registers)
; @ BasePointer

CALL_FUN_AT_BP:	
		mov	bx, [Button_Status]
		mov	cx, [MouseX_Sum]
		mov	dx, [MouseY_Sum]
		mov	si, word [H_Mickey_Count] ; horizontal	mickey count (-32768 to	32767)
		mov	di, word [V_Mickey_Count] ; vertical mickey count (-32768 to 32767)
		;pushf
		sti
		call	far [cs:bp]
		;popf
		PUSH	CS		;return to my DS segment
		POP	DS
		ret


 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦

 ; Invert CX/DX if necessary (DX<CX)

Invert:		cmp     cx, dx
		jl      short locret_D05
		xchg    cx, dx
locret_D05: 	ret


; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

;Input:     AX=Vertical Pos
; Verify if pointer in Vertical	Range
; if not then move
; Corrupt AX, DX

Verify_in_VRange:
		;push	dx
                mov     dx, [CS:MIN_VRange]
		cmp	ax, dx
		jl	short .set
                mov     dx, [CS:MAX_VRange]
		cmp	ax, dx
		jle	short .skip

.set:
		mov	ax, dx

.skip:		;pop	dx
		ret

; ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ S U B	R O U T	I N E ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ

;Input:     AX=Horizontal Pos
; Verify if pointer in Horizontal Range
; if not then move
; Corrupt AX, DX

Verify_in_HRange:
		;push	dx
                mov     dx, [CS:MIN_HRange]
		cmp	ax, dx
		jl	short set2
                mov     dx, [CS:MAX_HRange]
		cmp	ax, dx
		jle	short skip3

set2:
		mov	ax, dx

skip3:		;pop 	dx
		ret

;************** Constants / Costanti ****************************************
Copyright1983 db 'Copyright 1983 Microsoft ***'
magicnumber db 55h, 64h
; ========================== END OF RESIDENT PART =========================

notresident:
db '*** This is a PC1 mouse driver by Riminucci Simone (c) 2016, but some software expect here the upper string!'
welcome DB      'þ MOUSE-PC1 Driver ver. 0.97 - Simone Riminucci (C) 2016',0Dh,0Ah,'$'
already	DB	'Û²²±±±°°°°     Un driver Š gi… installato     °°°°±±±²²Û',0Dh,0Ah,'$'
EGAVGA	DB	'Û²²±±±°°°° EGA/VGA Patch installata (funz. avanzate disab.) °°°°±±±²²Û',0Dh,0Ah,'$'
ForceIn db 	'F: Il driver sar… installato sopra uno esistente',0Dh,0Ah,'$'
SiamoSpiacenti  db 'Non Š stato possibile installare il driver del mouse',0Dh,0Ah
		db 'Questo mouse driver funziona solo su OLIVETTI PRODEST PC1. ',0Ah, 0Dh,'$'
aSpiacentiIlMou db 'Û²²±±±°°°°     Attenzione:  il mouse NON Š connesso.     °°°°±±±²²Û',0Ah,0Dh,'$'

helpmsg	db	0Ah,0Dh,"Parametri:",0Ah,0Dh
	db	0Ah,0Dh
	db	"/I - Non verificare se su Olivetti Prodest PC1",0Ah,0Dh
	db	"/M - Mostra subito il cursore in DOS",0Ah,0Dh
	db	"/F - Forza l'installazione anche su driver esistente",0Ah,0Dh
	db	"/E - Forza l'installazione della Patch EGA/VGA",0Ah,0Dh
	db	"$"

Equipment_Addr 	dw 0A1h

start:
	push	cs
	pop	ds
	lea     dx, [welcome] ; "Benvenuti"...
	mov     ah, 9
	int     21h             ; DOS - PRINT STRING	

	call    process_cmdline         ; grab switches, etc

	test	byte [cmdlineflags], help
	jnz	display_help

	test	byte [cmdlineflags], nocheck
	jnz	skipcheck

	call	check_for_PC1
	or      ax, ax
	jz      not_PC1

skipcheck:	
	mov 	AX,0000h	;intallation check if already installed
	int	33h
	cmp	AX,0FFFFh
%ifndef DEBUG
	jne	cont0
	test	byte [cmdlineflags], forceinst
	jz	terminate
	lea     dx, [ForceIn] ; ">Forced!"...
	mov     ah, 9
	int     21h             ; DOS - PRINT STRING
%endif

cont0:	
	cli
	call    set_mouse_keyb			; Set keyboard chip 8042
						; to respond to mouse click -> scancode
						; Left Button   77h
						; Middle Button 78h
						; Right Button  79h
	or      al, al
%ifndef DEBUG
	jz      short print_mouse_non_connesso
%endif
	call    Install_INT08
	call    Install_INT09
	call    Install_INT33
	
	call	reset_V6355D
        call    Reset_pointer_and_var
	
	test	byte [cmdlineflags], showcurs
	jz	skipshow
        call    Fun_01

skipshow:
        STI

terminate_but_stay_resident:

cont3:		
	mov     ah, 51h         ;Get application's PSP address
        int     21h		;we get it in bx
	mov     es, bx
	mov     es, [es:2Ch]    ;Get address of environment block.
	mov     ah, 49h         ;DOS deallocate block call.
	int     21h		;get rid of PSP!

	mov	dx, notresident		; only resident part will be saved

	mov	cl, 4
	shr	dx, cl			; paragraph to keep
	inc	dx			; 1 paragraph more... safer for roundings

	MOV	AX, 3100h	;
	INT 	21h		;stay resident and exit

terminate:
	lea     dx, [already] ; "Già installato!"...
	mov     ah, 9
	int     21h             ; DOS - PRINT STRING
error:
	MOV 	AX, 4C01h	;AH 4C = Exit to DOS, ERRORLEVEL AL 01
	INT	21h

print_mouse_non_connesso:
	lea     dx, [aSpiacentiIlMou] ; "Non connesso!"...
	mov     ah, 9
	int     21h             ; DOS - PRINT STRING
	MOV 	AX, 4C02h	;AH 4C = Exit to DOS, ERRORLEVEL AL 02
	INT	21h

reset_V6355D:
	cli
	;mov 	dx, 3DDh
	;mov 	al, 65h+80h
	;out	dx, al
	;inc	dx
	;mov	al, 89h		;mouse enable
	;out	dx, al
	push	ds
	mov     bx, [Equipment_Addr]                               
	mov     ax, BIOS_DATA_SEG
	mov     ds, ax
	mov     al, [bx]
	pop	ds
	test	byte [cmdlineflags], forceEGA
	jnz	.force
	test	al, 1
	jz	.cont
.force	and     al, 0FEh        ; azzera l'ultimo bit
	;;;;mov     [bx], al	; lo riscrivo indietro in modo che non venga più cambiato!?!?
	or      byte [cmdlineflags], forceEGA  ; mi segno che era quello!
	out     68h, al         ; così "accende" lo schermo V6355D e il counter del mouse
	in	al, 0D1h
	cmp	al, 0FFh	; questo controllo è utile solo per computer non-pc1
	jnz	.wmsg
	test	byte [cmdlineflags], nocheck
	jz	not_PC1
.wmsg	lea     dx, [EGAVGA] ; "EGA/VGA Patch installed"...
	mov     ah, 9
	int     21h             ; DOS - PRINT STRING	

.cont	mov 	dx, 3DDh
	mov 	al, 64h+80h
	out	dx, al
	inc	dx
	mov	al, 6h		;mouse AND & XOR enable
	out	dx, al
	sti
        ret

check_for_PC1:

PC1_Equipment_Addr 	EQU 89h
PC1HD_Equipment_Addr 	EQU 0A1h

	push    bx
	push    ds
	mov     ax, 0F000h
	mov     ds, ax
	mov     bx, 0FFFDh      ; penultimi due byte del BIOS
	mov     ax, [bx]
	pop	ds
	mov	bl, PC1HD_Equipment_Addr
	cmp     ax, 0FE44h      ; PC1 - Floppy
	jz      short pc1dd
	cmp     ax, 0FE49h      ; PC1 - Unknown
	jz      short loc_2B1C
	cmp     ax, 0FE4Ah      ; PC1 - HD
	jnz     short loc_2B22

pc1dd:	mov	bl, PC1_Equipment_Addr

loc_2B1C:                               
	mov     ax, 0FFh
	jmp     short loc_2B25

loc_2B22:                               
	mov     ax, 0

loc_2B25:                                                          
	mov	[Equipment_Addr],bl   
	pop     bx
	ret

not_PC1:
	lea     dx, [SiamoSpiacenti] ; "Siamo spiacenti di non poter installare"...
	mov     ah, 9
	int     21h             ; DOS - PRINT STRING
				; DS:DX -> string terminated by "$"
	jmp	error

Value_for_8042  db 12h, 77h, 78h, 79h, 1	;valori dei tre tasti del mouse: 77h 78h 79h

set_mouse_keyb:
	cli
	mov     al, 12h
	push    ax
	mov     dx, 64h
wait_8042:
	in      al, dx          ; AT Keyboard controller 8042.
	and     al, 2
	jnz     short wait_8042
	pop     ax
	out     dx, al          ; AT Keyboard controller 8042.
wait_8042f:
	in      al, 64h         ; AT Keyboard controller 8042.
	and     al, 1
	jz      short wait_8042f
	in      al, 60h         ; AT Keyboard controller 8042.
	and     al, 1
	jnz     short skip
	push    si
	lea     si, [Value_for_8042]
	mov     cx, 5
	cld
load_next:
	lodsb                   ; Load Value: 12h 77h 78h 79h 01
	push    ax
	mov     dx, 64h
wait_8042g:
	in      al, dx          ; AT Keyboard controller 8042.
	and     al, 2
	jnz     short wait_8042g
	pop     ax
	mov     dx, 60h
	out     dx, al          ; AT Keyboard controller 8042.
	loop    load_next       ; Load Value: 12h 77h 78h 79h 01
	mov     ax, 0FFh
	pop     si
	sti
	ret
skip:	xor	ax, ax
	sti
	ret

;===========================================================================
;Procedure: ucase
;Purpose:   Converts character in AL to uppercase.
;           
;Input:     AL=character
;           
;Output:    AL=uppercase character (if a-z)
;           All other registers preserved.  (flags too)
;
;Processing: test valid range (a-z), set to upper, exit
;---------------------------------------------------------------------------
ucase:
	pushf
	cmp al,"a"                  ;if  it's not a-z, skipit
	jb noupper
	cmp al,"z"
	ja noupper
	and al,5fh                  ;strip off a few bits to make it upper
noupper:        
	popf
	ret

;##################### start cmd line interpret ####################

; command line flags
help		EQU	BIT0		; help requested
nocheck		EQU	BIT1		; don't check for PC1
showcurs	EQU	BIT2		; show cursor at loading
forceinst	EQU	BIT3		; forced install over an existing driver
forceEGA	EQU	BIT4		; force EGA/VGA book
debug		EQU	BIT5		; debug bit
koverride	EQU	BIT5		; debug bit
writeprotect	EQU	BIT6		; write protected bit
noint10		EQU	BIT7		; light INT10 hook (composit)


process_cmdline:

        push    ds
        push    bx
        push    si

        mov     ah, 51h
        int     21h
        mov     ds, bx
	mov 	cx, bx

        mov     si, 80h
	mov 	bh, 0
	mov	bl, byte [si]
        add     si, bx
        inc     si

        mov     byte [si], NULL             ;zero terminate

        mov     si, 81h

cmdlineloop:
	mov	ds,cx
        lodsb			;Transfers string element addressed by DS:SI to the accumulator
	push	cs
	pop	ds
        cmp     al, " "                 ; found a space?
        jz      cmdlineloop
        cmp     al, NULL                ; found end of line?
        jz      exitpc
        cmp     al, "-"                 ; found a flag?
        jz      checkflags
        cmp     al, "/"                 ; found a flag?
        jz      checkflags

        ; unknow skip but show help
	or      byte [cmdlineflags], help
	jmp 	cmdlineloop
exitpc: pop     si
        pop     bx
        pop     ds
        
        ret

checkflags:
	mov	ds,cx
        lodsb			;Transfers string element addressed by DS:SI to the accumulator
	push	cs
	pop	ds
        cmp     al, " "                 ; false flag
        jz      cmdlineloop
        cmp     al, NULL                ; found end of line?
        jz      exitpc
        cmp     al, "-"                 ; found a double flag?
        jz      checkflags
        cmp     al, "/"                 ; found a double flag?
        jz      checkflags

        ; must be a flag

	call	ucase

	cmp	al, "?"
	jz	sethelp

	cmp	al, "H"
	jz	sethelp

	cmp	al, "I"
	jz	setignorenotPC1

	cmp	al, "M"
	jz	setshowcursor

	cmp	al, "F"
	jz	setforceinst

	cmp	al, "E"
	jz	setforceEGA

	jmp     cmdlineloop             ; nothing we care about, continue
                                        ; could jump to help msg
sethelp:
        or      byte [cmdlineflags], help
        jmp     checkflags              ; allows flags to be stacked

setignorenotPC1:
        or      byte [cmdlineflags], nocheck
        jmp     checkflags              ; allows flags to be stacked

setshowcursor:
        or      byte [cmdlineflags], showcurs
        jmp     checkflags              ; allows flags to be stacked

setforceinst:
        or      byte [cmdlineflags], forceinst
        jmp     checkflags              ; allows flags to be stacked

setforceEGA:
        or      byte [cmdlineflags], forceEGA
        jmp     checkflags              ; allows flags to be stacked

;##################### end cmd line interpret ####################


Install_INT08:
	cli
	mov     ax, 3508h
	int     21h             ; DOS - 2+ - GET INTERRUPT VECTOR
				; AL = interrupt number
				; Return: ES:BX = value of interrupt vector
	mov     word [Old_INT08], bx
	mov     word [Old_INT08+2], es
	mov     dx, INT_08 ; Int 08 Entry Point
	mov     ax, 2508h
	int     21h             ; DOS - SET INTERRUPT VECTOR
				; AL = interrupt number
				; DS:DX = new vector to be used for specified interrupt
	sti
	ret


Install_INT09:
	cli
	mov     ax, 3509h
	int     21h             ; DOS - 2+ - GET INTERRUPT VECTOR
				; AL = interrupt number
				; Return: ES:BX = value of interrupt vector
	mov     word [Old_INT09], bx
	mov     word [Old_INT09+2], es
	mov     dx, INT_09 ; Int 09 Entry Point
	mov     ax, 2509h
	int     21h             ; DOS - SET INTERRUPT VECTOR
				; AL = interrupt number
				; DS:DX = new vector to be used for specified interrupt
	sti
	ret

Install_INT33:
	cli
%ifdef CALL_OLD_INT33
	push    ds
	xor     ax, ax
	mov     ds, ax
	mov     si, 0CCh
	mov     bx, [si]
	mov     cx, [si+2]
	pop     ds
	mov     [Old_INT33], bx
	mov     [Old_INT33+2], cx
%endif
	lea     dx, [INT_33]      ; Int33 Entry Point
	mov     al, 33h
	mov     ah, 25h		; DOS - SET INTERRUPT VECTOR
	int     21h             ; AL = interrupt number
	ret			; DS:DX = new vector to be used for specified interrupt


display_help:

	mov	ah, 9
	lea	dx, [helpmsg]			; display help message
	int	21h
	
exit	mov	ax, 4c02h			; end
	int	21h

END:

Sorry but I made some comment in Italian...

if can help there are two subs that take the problem:

; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

Install_INT09_MONK:
cli
mov ax, 3509h
int 21h ; DOS - 2+ - GET INTERRUPT VECTOR
; AL = interrupt number
; Return: ES:BX = value of interrupt vector
mov word [Old_INT09_MONK], bx
mov word [Old_INT09_MONK+2], es
mov dx, INT_09bis ; Int 09 (BIS) Entry Point
mov ax, 2509h
int 21h ; DOS - SET INTERRUPT VECTOR
; AL = interrupt number
; DS:DX = new vector to be used for specified interrupt
sti
ret

; ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

;check for INT_09 hook!
Check_INT09_MONK:
xor ax, ax
mov es, ax
mov ax, cs
cmp word [ES:09h*4+2], ax ;check for int09 data segment
je allok
;SEMPLIFICO: se non è nel segmento la cambio altrimenti lascio stare!
;mov ax, 3509h
;int 21h ; DOS - 2+ - GET INTERRUPT VECTOR
; ; AL = interrupt number
; ; Return: ES:BX = value of interrupt vector
;mov ax, cs
;mov cx, es
;cmp ax, cx
;jne install_newint ;qualcuno (monkey?) ha cambiato l'int 09
;mov cx, INT_09
;cmp cx, bx
;je allok
;mov cx, INT_09bis
;cmp cx, bx
;je allok
install_newint: call Install_INT09_MONK

allok: ret


Check_INT09_MONK is called from mouse reset function and resolved Monkey problem (the sub's name hint it)
But Lemmings needed a supplemental check, and I called it from "Fun 03: Query Position & Buttons". I lost some cycle but Solved the problem.
 
Last edited:
Hey AlG,

Ive found your thread via Google and I would like to know how to rewire an Atari ST or Amiga mouse to fit my M24SP.

Thank you!
 
Just by comparing the signals... Each of these mice have two x and two y signals plus two mouse buttons. They all need 5V and gnd. I have posted in this forum the pinout of all the three mouseports. But until now I haven't made adapters for myself.
 
Back
Top