2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: PS/2 mouse driver.
9 /****************************************************************************************/
12 #include <asm/speaker.h>
13 #include <proto/exec.h>
14 #include <proto/utility.h>
15 #include <proto/oop.h>
18 #include <exec/alerts.h>
19 #include <exec/memory.h>
21 #include <hidd/hidd.h>
22 #include <hidd/mouse.h>
24 #include <devices/inputevent.h>
29 #include <aros/debug.h>
31 /****************************************************************************************/
36 #define HiddMouseAB (MSD(cl)->hiddMouseAB)
38 /* defines for buttonstate */
41 #define RIGHT_BUTTON 2
42 #define MIDDLE_BUTTON 4
44 /****************************************************************************************/
46 /* from Drivers/keyboard/kbd_common.c */
48 #warning "it is probably better to get rid of calling functions from external module"
50 int kbd_read_data(void);
52 void kbd_write_cmd(int cmd
);
53 void aux_write_ack(int val
);
54 void aux_write_noack(int val
);
55 void kbd_write_command_w(int data
);
57 /****************************************************************************************/
59 void mouse_usleep(ULONG usec
);
61 /****************************************************************************************/
63 void mouse_ps2int(HIDDT_IRQ_Handler
*, HIDDT_IRQ_HwInfo
*);
64 int mouse_ps2reset(struct mouse_data
*);
66 /****************************************************************************************/
68 int test_mouse_ps2(OOP_Class
*cl
, OOP_Object
*o
)
70 struct mouse_data
*data
= OOP_INST_DATA(cl
, o
);
73 if ((data
->u
.ps2
.irqhidd
= OOP_NewObject(NULL
, CLID_Hidd_IRQ
, NULL
)))
75 HIDDT_IRQ_Handler
*irq
;
77 data
->u
.ps2
.irq
= irq
= AllocMem(sizeof(HIDDT_IRQ_Handler
), MEMF_CLEAR
| MEMF_PUBLIC
);
82 irq
->h_Node
.ln_Pri
= 127;
83 irq
->h_Node
.ln_Name
= "PS/2 mouse class irq";
84 irq
->h_Code
= mouse_ps2int
;
85 irq
->h_Data
= (APTR
)data
;
87 HIDD_IRQ_AddHandler(data
->u
.ps2
.irqhidd
, irq
, vHidd_IRQ_Mouse
);
90 result
= mouse_ps2reset(data
);
93 /* If mouse_ps2reset() returned non-zero value, there is vaild PS/2 mouse */
98 /* Either no PS/2 mouse or problems with it */
99 /* Remove mouse interrupt */
100 HIDD_IRQ_RemHandler(data
->u
.ps2
.irqhidd
, irq
);
101 /* Free IRQ structure as it's not needed anymore */
102 FreeMem(irq
, sizeof(HIDDT_IRQ_Handler
));
104 /* Dispose IRQ object */
105 OOP_DisposeObject(data
->u
.ps2
.irqhidd
);
107 /* Report no PS/2 mouse */
111 void dispose_mouse_ps2(OOP_Class
*cl
, OOP_Object
*o
) {
112 struct mouse_data
*data
= OOP_INST_DATA(cl
, o
);
114 HIDD_IRQ_RemHandler(data
->u
.ps2
.irqhidd
, data
->u
.ps2
.irq
);
115 FreeMem(data
->u
.ps2
.irq
, sizeof(HIDDT_IRQ_Handler
));
116 OOP_DisposeObject(data
->u
.ps2
.irqhidd
);
119 /****************************************************************************************/
121 #define AUX_RECONNECT 170
124 #define aux_write(val) \
125 ({ data->u.ps2.expected_mouse_acks++; \
126 aux_write_ack(val); \
129 /****************************************************************************************/
131 void getps2Event(struct getps2data
*, struct pHidd_Mouse_Event
*);
133 void getps2State(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Mouse_Event
*event
) {
134 struct mouse_data
*data
= OOP_INST_DATA(cl
, o
);
137 aux_write(KBD_OUTCMD_DISABLE
);
138 /* switch to remote mode */
139 aux_write(KBD_OUTCMD_SET_REMOTE_MODE
);
141 ack
= data
->u
.ps2
.expected_mouse_acks
+1;
142 aux_write(KBD_OUTCMD_READ_DATA
);
143 while (data
->u
.ps2
.expected_mouse_acks
>=ack
)
145 /* switch back to sream mode */
146 aux_write(KBD_OUTCMD_SET_STREAM_MODE
);
147 aux_write(KBD_OUTCMD_ENABLE
);
150 /****************************************************************************************/
159 kbd_write_command(KBD_CTRLCMD_WRITE_AUX_OBUF
);
162 kbd_write_output(0x5a);
166 unsigned char status
= kbd_read_status();
168 if (status
& KBD_STATUS_OBF
)
170 (void) kbd_read_input();
171 if (status
& KBD_STATUS_MOUSE_OBF
)
185 /****************************************************************************************/
187 static int query_mouse(UBYTE
*buf
, int size
, int timeout
)
193 UBYTE status
= kbd_read_status();
195 if (status
& KBD_STATUS_OBF
)
197 UBYTE c
= kbd_read_input();
199 if ((c
!= KBD_REPLY_ACK
) && (status
& KBD_STATUS_MOUSE_OBF
))
209 } while ((--timeout
) && (ret
< size
));
216 /****************************************************************************************/
218 static int detect_intellimouse(void)
222 /* Try to switch into IMPS2 mode */
224 aux_write_ack(KBD_OUTCMD_SET_RATE
);
226 aux_write_ack(KBD_OUTCMD_SET_RATE
);
228 aux_write_ack(KBD_OUTCMD_SET_RATE
);
230 aux_write_ack(KBD_OUTCMD_GET_ID
);
231 aux_write_noack(KBD_OUTCMD_GET_ID
);
233 query_mouse(&id
, 1, 20);
235 return ((id
== 3) || (id
== 4)) ? id
: 0;
238 /****************************************************************************************/
241 #define SysBase (hw->sysBase)
244 void mouse_ps2int(HIDDT_IRQ_Handler
*irq
, HIDDT_IRQ_HwInfo
*hw
)
246 struct mouse_data
*data
=(struct mouse_data
*)irq
->h_Data
;
247 struct pHidd_Mouse_Event
*e
= &data
->u
.ps2
.event
;
250 UBYTE info
, mousecode
, *mouse_data
;
252 info
= kbd_read_status();
254 for(; ((info
= kbd_read_status()) & KBD_STATUS_OBF
) && work
; work
--)
256 if (!(info
& KBD_STATUS_MOUSE_OBF
))
259 ** Data from keyboard. Hopefully this gets through to keyboard interrupt
260 ** if we break out of for loop here :-\
265 mousecode
= kbd_read_input();
267 if (info
& (KBD_STATUS_GTO
| KBD_STATUS_PERR
))
269 /* Ignore errors and messages for keyboard -> eat status/error byte */
273 if ((mousecode
== AUX_ACK
) && (data
->u
.ps2
.expected_mouse_acks
))
275 D(bug(" Got a mouse ACK!\n"));
276 data
->u
.ps2
.expected_mouse_acks
--;
281 if (mousecode
== AUX_RECONNECT
)
283 data
->u
.ps2
.mouse_collected_bytes
= 0;
286 aux_write(KBD_OUTCMD_ENABLE
);
290 /* Mouse Packet Byte */
292 mouse_data
= data
->u
.ps2
.mouse_data
;
294 data
->u
.ps2
.expected_mouse_acks
= 0;
295 mouse_data
[data
->u
.ps2
.mouse_collected_bytes
] = mousecode
;
297 /* Packet validity check. Bit 3 of first mouse packet byte must be set */
299 if ((mouse_data
[0] & 8) == 0)
301 data
->u
.ps2
.mouse_collected_bytes
= 0;
305 data
->u
.ps2
.mouse_collected_bytes
++;
307 if (data
->u
.ps2
.mouse_collected_bytes
!= data
->u
.ps2
.mouse_packetsize
)
309 /* Mouse Packet not yet complete */
313 /* We have a complete mouse packet :-) */
315 data
->u
.ps2
.mouse_collected_bytes
= 0;
318 * Let's see whether these data can be right...
320 * D7 D6 D5 D4 D3 D2 D1 D0
321 * YV XV YS X2 1 M R L
322 * X7 . . . . . . X1 (X, signed)
323 * Y7 . . . . . . Y1 (Y, signed)
325 * YV,XV : over flow in x/y direction
326 * XS,YS : represents sign of X and Y
327 * X,Y : displacement in x and y direction.
328 * X and Y are signed, XS, YS are there to double check the
329 * sign and correctnes of the collected data (?).
331 * http://www.hut.fi/~then/mytexts/mouse.htm
335 D(bug("Got the following: 1. byte: 0x%x, dx=%d, dy=%d\n",
341 e
->x
= mouse_data
[1];
342 e
->y
= mouse_data
[2];
344 if (mouse_data
[0] & 0x10) e
->x
-= 256;
345 if (mouse_data
[0] & 0x20) e
->y
-= 256;
347 /* dy is reversed! */
352 e
->button
= vHidd_Mouse_NoButton
;
353 e
->type
= vHidd_Mouse_Motion
;
355 data
->mouse_callback(data
->callbackdata
, e
);
358 buttonstate
= mouse_data
[0] & 0x07;
360 if ((buttonstate
& LEFT_BUTTON
) != (data
->buttonstate
& LEFT_BUTTON
))
362 e
->button
= vHidd_Mouse_Button1
;
363 e
->type
= (buttonstate
& LEFT_BUTTON
) ? vHidd_Mouse_Press
: vHidd_Mouse_Release
;
365 data
->mouse_callback(data
->callbackdata
, e
);
368 if ((buttonstate
& RIGHT_BUTTON
) != (data
->buttonstate
& RIGHT_BUTTON
))
370 e
->button
= vHidd_Mouse_Button2
;
371 e
->type
= (buttonstate
& RIGHT_BUTTON
) ? vHidd_Mouse_Press
: vHidd_Mouse_Release
;
373 data
->mouse_callback(data
->callbackdata
, e
);
376 if ((buttonstate
& MIDDLE_BUTTON
) != (data
->buttonstate
& MIDDLE_BUTTON
))
378 e
->button
= vHidd_Mouse_Button3
;
379 e
->type
= (buttonstate
& MIDDLE_BUTTON
) ? vHidd_Mouse_Press
: vHidd_Mouse_Release
;
381 data
->mouse_callback(data
->callbackdata
, e
);
384 data
->buttonstate
= buttonstate
;
386 #if INTELLIMOUSE_SUPPORT
388 e
->y
= (mouse_data
[3] & 8) ? (mouse_data
[3] & 15) - 16 : (mouse_data
[3] & 15);
392 e
->type
= vHidd_Mouse_WheelMotion
;
393 e
->button
= vHidd_Mouse_NoButton
;
395 data
->mouse_callback(data
->callbackdata
, e
);
399 } /* for(; ((info = kbd_read_statues()) & KBD_STATUS_OBF) && work; work--) */
403 D(bug("kbd.hidd: controller jammed (0x%02X).\n", info
));
408 /****************************************************************************************/
411 #define SysBase (*(struct ExecBase **)4L)
413 #define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
414 #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
416 /****************************************************************************************/
418 int mouse_ps2reset(struct mouse_data
*data
)
421 * The commands are for the mouse and nobody else.
424 kbd_write_command_w(KBD_CTRLCMD_MOUSE_ENABLE
);
426 if (!kbd_detect_aux())
430 * Unfortunatley on my computer these commands cause
431 * the mouse not to work at all if they are issued
432 * in a different order. So please keep it that way.
437 * Turn interrupts off and the keyboard as well since the
438 * commands are all for the mouse.
440 kbd_write_cmd(AUX_INTS_OFF
);
441 kbd_write_command_w(KBD_CTRLCMD_KBD_DISABLE
);
443 data
->u
.ps2
.mouse_protocol
= PS2_PROTOCOL_STANDARD
;
444 data
->u
.ps2
.mouse_packetsize
= 3;
446 #if INTELLIMOUSE_SUPPORT
447 if (detect_intellimouse())
449 data
->u
.ps2
.mouse_protocol
= PS2_PROTOCOL_INTELLIMOUSE
;
450 data
->u
.ps2
.mouse_packetsize
= 4;
455 * Now the commands themselves.
457 aux_write(KBD_OUTCMD_SET_RATE
);
459 aux_write(KBD_OUTCMD_SET_RES
);
461 aux_write(KBD_OUTCMD_SET_SCALE11
);
463 /* Enable Aux device */
465 kbd_write_command_w(KBD_CTRLCMD_KBD_ENABLE
);
466 aux_write(KBD_OUTCMD_ENABLE
);
467 kbd_write_cmd(AUX_INTS_ON
);
470 * According to the specs there is an external
471 * latch that holds the level-sensitive interrupt
472 * request until the CPU readsport 0x60.
473 * If this is not read then the mouse does not
474 * work on my computer.- Stefan
479 D(bug("[Mouse] Found and initialized PS/2 mouse!\n"));
484 /****************************************************************************************/