2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
5 Desc: PS/2 mouse driver.
9 /****************************************************************************************/
11 #include <proto/exec.h>
12 #include <proto/kernel.h>
13 #include <proto/utility.h>
14 #include <proto/oop.h>
16 #include <hidd/hidd.h>
17 #include <hidd/mouse.h>
18 #include <devices/inputevent.h>
21 #include "kbd_common.h"
24 #include <aros/debug.h>
26 /****************************************************************************************/
28 /* defines for buttonstate */
31 #define RIGHT_BUTTON 2
32 #define MIDDLE_BUTTON 4
34 /****************************************************************************************/
36 int mouse_ps2reset(struct mouse_data
*);
38 /****************************************************************************************/
40 static void mouse_ps2int(struct mouse_data
*data
, void *unused
)
42 struct pHidd_Mouse_Event
*e
= &data
->event
;
45 UBYTE info
, mousecode
, *mouse_data
;
47 info
= kbd_read_status();
49 for(; ((info
= kbd_read_status()) & KBD_STATUS_OBF
) && work
; work
--)
51 if (!(info
& KBD_STATUS_MOUSE_OBF
))
54 ** Data from keyboard. Hopefully this gets through to keyboard interrupt
55 ** if we break out of for loop here :-\
60 mousecode
= kbd_read_input();
62 if (info
& (KBD_STATUS_GTO
| KBD_STATUS_PERR
))
64 /* Ignore errors and messages for keyboard -> eat status/error byte */
68 /* Mouse Packet Byte */
70 mouse_data
= data
->mouse_data
;
72 data
->expected_mouse_acks
= 0;
73 mouse_data
[data
->mouse_collected_bytes
] = mousecode
;
75 /* Packet validity check. Bit 3 of first mouse packet byte must be set */
77 if ((mouse_data
[0] & 8) == 0)
79 data
->mouse_collected_bytes
= 0;
83 data
->mouse_collected_bytes
++;
85 if (data
->mouse_collected_bytes
!= data
->mouse_packetsize
)
87 /* Mouse Packet not yet complete */
91 /* We have a complete mouse packet :-) */
93 data
->mouse_collected_bytes
= 0;
96 * Let's see whether these data can be right...
98 * D7 D6 D5 D4 D3 D2 D1 D0
100 * X7 . . . . . . X1 (X)
101 * Y7 . . . . . . Y1 (Y)
103 * XV,YV : overflow in x/y direction
104 * XS,YS : most significant bit of X and Y: represents sign
105 * X,Y : displacement in x and y direction (8 least significant bits).
107 * X, XS, Y and YS make up two 9-bit two's complement fields.
111 D(bug("Got the following: 1. byte: 0x%x, dx=%d, dy=%d\n",
117 e
->x
= mouse_data
[1];
118 e
->y
= mouse_data
[2];
120 if (mouse_data
[0] & 0x10) e
->x
-= 256;
121 if (mouse_data
[0] & 0x20) e
->y
-= 256;
123 /* dy is reversed! */
128 e
->button
= vHidd_Mouse_NoButton
;
129 e
->type
= vHidd_Mouse_Motion
;
131 data
->mouse_callback(data
->callbackdata
, e
);
134 buttonstate
= mouse_data
[0] & 0x07;
136 if ((buttonstate
& LEFT_BUTTON
) != (data
->buttonstate
& LEFT_BUTTON
))
138 e
->button
= vHidd_Mouse_Button1
;
139 e
->type
= (buttonstate
& LEFT_BUTTON
) ? vHidd_Mouse_Press
: vHidd_Mouse_Release
;
141 data
->mouse_callback(data
->callbackdata
, e
);
144 if ((buttonstate
& RIGHT_BUTTON
) != (data
->buttonstate
& RIGHT_BUTTON
))
146 e
->button
= vHidd_Mouse_Button2
;
147 e
->type
= (buttonstate
& RIGHT_BUTTON
) ? vHidd_Mouse_Press
: vHidd_Mouse_Release
;
149 data
->mouse_callback(data
->callbackdata
, e
);
152 if ((buttonstate
& MIDDLE_BUTTON
) != (data
->buttonstate
& MIDDLE_BUTTON
))
154 e
->button
= vHidd_Mouse_Button3
;
155 e
->type
= (buttonstate
& MIDDLE_BUTTON
) ? vHidd_Mouse_Press
: vHidd_Mouse_Release
;
157 data
->mouse_callback(data
->callbackdata
, e
);
160 data
->buttonstate
= buttonstate
;
162 #if INTELLIMOUSE_SUPPORT
164 e
->y
= (mouse_data
[3] & 8) ? (mouse_data
[3] & 15) - 16 : (mouse_data
[3] & 15);
168 e
->type
= vHidd_Mouse_WheelMotion
;
169 e
->button
= vHidd_Mouse_NoButton
;
171 data
->mouse_callback(data
->callbackdata
, e
);
175 } /* for(; ((info = kbd_read_status()) & KBD_STATUS_OBF) && work; work--) */
177 D(if (!work
) bug("mouse.hidd: controller jammed (0x%02X).\n", info
);)
180 /****************************************************************************************/
182 int test_mouse_ps2(OOP_Class
*cl
, OOP_Object
*o
)
184 struct mouse_data
*data
= OOP_INST_DATA(cl
, o
);
187 data
->irq
= KrnAddIRQHandler(12, mouse_ps2int
, data
, NULL
);
190 result
= mouse_ps2reset(data
);
193 /* If mouse_ps2reset() returned non-zero value, there is valid PS/2 mouse */
198 /* Either no PS/2 mouse or problems with it */
199 /* Remove mouse interrupt */
200 KrnRemIRQHandler(data
->irq
);
202 /* Report no PS/2 mouse */
206 /****************************************************************************************/
208 void getps2State(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Mouse_Event
*event
)
211 struct mouse_data
*data
= OOP_INST_DATA(cl
, o
);
214 /* The following doesn't seem to do anything useful */
215 aux_write(KBD_OUTCMD_DISABLE
);
216 /* switch to remote mode */
217 aux_write(KBD_OUTCMD_SET_REMOTE_MODE
);
219 ack
= data
->expected_mouse_acks
+1;
220 aux_write(KBD_OUTCMD_READ_DATA
);
221 while (data
->expected_mouse_acks
>=ack
)
223 /* switch back to stream mode */
224 aux_write(KBD_OUTCMD_SET_STREAM_MODE
);
225 aux_write(KBD_OUTCMD_ENABLE
);
229 /****************************************************************************************/
231 static int detect_aux()
238 kbd_write_command(KBD_CTRLCMD_WRITE_AUX_OBUF
);
241 kbd_write_output(0x5a);
245 unsigned char status
= kbd_read_status();
247 if (status
& KBD_STATUS_OBF
)
249 (void) kbd_read_input();
250 if (status
& KBD_STATUS_MOUSE_OBF
)
261 D(bug("PS/2 Auxilliary port %sdetected\n", retval
? "" : "not "));
265 /****************************************************************************************/
267 static int query_mouse(UBYTE
*buf
, int size
, int timeout
)
273 UBYTE status
= kbd_read_status();
275 if (status
& KBD_STATUS_OBF
)
277 UBYTE c
= kbd_read_input();
279 if ((c
!= KBD_REPLY_ACK
) && (status
& KBD_STATUS_MOUSE_OBF
))
289 } while ((--timeout
) && (ret
< size
));
295 /****************************************************************************************/
297 static int detect_intellimouse(void)
301 /* Try to switch into IMPS2 mode */
303 aux_write_ack(KBD_OUTCMD_SET_RATE
);
305 aux_write_ack(KBD_OUTCMD_SET_RATE
);
307 aux_write_ack(KBD_OUTCMD_SET_RATE
);
309 aux_write_ack(KBD_OUTCMD_GET_ID
);
310 aux_write_noack(KBD_OUTCMD_GET_ID
);
312 query_mouse(&id
, 1, 20);
314 return ((id
== 3) || (id
== 4)) ? id
: 0;
317 /****************************************************************************************/
319 #define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
320 #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
322 /****************************************************************************************/
324 int mouse_ps2reset(struct mouse_data
*data
)
326 int result
, timeout
= 100;
329 * The commands are for the mouse and nobody else.
332 kbd_write_command_w(KBD_CTRLCMD_MOUSE_ENABLE
);
335 * Check for a mouse port.
341 * Unfortunately on my computer these commands cause
342 * the mouse not to work at all if they are issued
343 * in a different order. So please keep it that way.
348 * Turn interrupts off and the keyboard as well since the
349 * commands are all for the mouse.
351 kbd_write_cmd(AUX_INTS_OFF
);
352 kbd_write_command_w(KBD_CTRLCMD_KBD_DISABLE
);
355 aux_write_ack(KBD_OUTCMD_RESET
);
356 result
= aux_wait_for_input(); /* Test result (0xAA) */
357 while (result
== 0xfa && --timeout
)
359 /* somehow the ACK isn't always swallowed above */
361 result
= aux_wait_for_input();
363 aux_wait_for_input(); /* Mouse type */
367 /* No mouse. Re-enable keyboard and return failure */
368 kbd_write_command_w(KBD_CTRLCMD_KBD_ENABLE
);
369 aux_write_ack(KBD_OUTCMD_ENABLE
);
373 data
->mouse_protocol
= PS2_PROTOCOL_STANDARD
;
374 data
->mouse_packetsize
= 3;
376 #if INTELLIMOUSE_SUPPORT
377 if (detect_intellimouse())
379 D(bug("[Mouse] PS/2 Intellimouse detected\n"));
380 data
->mouse_protocol
= PS2_PROTOCOL_INTELLIMOUSE
;
381 data
->mouse_packetsize
= 4;
386 * Now the commands themselves.
388 aux_write_ack(KBD_OUTCMD_SET_RATE
);
390 aux_write_ack(KBD_OUTCMD_SET_RES
);
392 aux_write_ack(KBD_OUTCMD_SET_SCALE11
);
394 /* Enable Aux device (and re-enable keyboard) */
396 kbd_write_command_w(KBD_CTRLCMD_KBD_ENABLE
);
397 aux_write_ack(KBD_OUTCMD_ENABLE
);
398 kbd_write_cmd(AUX_INTS_ON
);
401 * According to the specs there is an external
402 * latch that holds the level-sensitive interrupt
403 * request until the CPU reads port 0x60.
404 * If this is not read then the mouse does not
405 * work on my computer.- Stefan
410 D(bug("[Mouse] Found and initialized PS/2 mouse!\n"));
415 /****************************************************************************************/