2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
5 Desc: PS/2 mouse driver.
9 /****************************************************************************************/
11 #include <asm/speaker.h>
12 #include <proto/exec.h>
13 #include <proto/utility.h>
14 #include <proto/oop.h>
17 #include <exec/alerts.h>
18 #include <exec/memory.h>
20 #include <hidd/hidd.h>
21 #include <hidd/mouse.h>
22 #include <devices/inputevent.h>
24 #include <SDI/SDI_interrupt.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 #define TIMER_RPROK 3599597124UL
48 int mouse_wait_for_input(void);
50 /****************************************************************************************/
52 int mouse_ps2reset(struct mouse_data
*);
54 /****************************************************************************************/
56 static ULONG
usec2tick(ULONG usec
)
59 ULONG prok
= TIMER_RPROK
;
60 asm volatile("movl $0,%%eax; divl %2":"=a"(ret
):"d"(usec
),"m"(prok
));
64 static void mouse_usleep(LONG usec
)
67 usec
= usec2tick(usec
);
71 oldtick
+= inb(0x42) << 8;
77 tick
+= inb(0x42) << 8;
79 usec
-= (oldtick
- tick
);
80 if (tick
> oldtick
) usec
-= 0x10000;
85 unsigned char handle_mouse_event(void)
87 unsigned char status
= mouse_read_status();
88 unsigned int work
= 10000;
90 while (status
& KBD_STATUS_OBF
)
94 status
= mouse_read_status();
97 //printf(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n",status);
105 * Wait until we can write to a peripheral again. Any input that comes in
106 * while we're waiting is discarded.
108 void mouse_wait(void)
110 ULONG timeout
= 1000; /* 1 sec should be enough */
114 unsigned char status
= handle_mouse_event();
115 if (! (status
& KBD_STATUS_IBF
))
123 void mouse_write_cmd(int cmd
)
126 mouse_write_command(KBD_CTRLCMD_WRITE_MODE
);
128 mouse_write_output(cmd
);
131 void mouse_write_ack(int val
)
134 mouse_write_command(KBD_CTRLCMD_WRITE_MOUSE
);
136 mouse_write_output(val
);
137 mouse_wait_for_input();
140 void mouse_write_noack(int val
)
143 mouse_write_command(KBD_CTRLCMD_WRITE_MOUSE
);
145 mouse_write_output(val
);
148 void mouse_write_output_w(int data
)
151 mouse_write_output(data
);
154 void mouse_write_command_w(int data
)
157 mouse_write_command(data
);
160 #define KBD_NO_DATA (-1)
161 #define KBD_BAD_DATA (-2)
163 int mouse_read_data(void)
165 LONG retval
= KBD_NO_DATA
;
168 status
= mouse_read_status();
169 if (status
& KBD_STATUS_OBF
)
171 UBYTE data
= mouse_read_input();
174 if (status
& (KBD_STATUS_GTO
| KBD_STATUS_PERR
))
175 retval
= KBD_BAD_DATA
;
181 int mouse_clear_input(void)
183 int maxread
= 100, code
, lastcode
= KBD_NO_DATA
;
188 status
= mouse_read_status();
189 if ((code
= mouse_read_data()) == KBD_NO_DATA
)
191 if (!(status
& KBD_STATUS_MOUSE_OBF
))
198 int mouse_wait_for_input(void)
200 ULONG timeout
= 1000;
204 int retval
= mouse_read_data();
212 /****************************************************************************************/
214 AROS_INTH1(mouse_ps2int
,struct mouse_data
*, data
)
218 struct pHidd_Mouse_Event
*e
= &data
->u
.ps2
.event
;
221 UBYTE info
, mousecode
, *mouse_data
;
223 info
= mouse_read_status();
225 for(; ((info
= mouse_read_status()) & KBD_STATUS_OBF
) && work
; work
--)
227 if (!(info
& KBD_STATUS_MOUSE_OBF
))
230 ** Data from keyboard. Hopefully this gets through to keyboard interrupt
231 ** if we break out of for loop here :-\
236 mousecode
= mouse_read_input();
238 if (info
& (KBD_STATUS_GTO
| KBD_STATUS_PERR
))
240 /* Ignore errors and messages for keyboard -> eat status/error byte */
244 /* Mouse Packet Byte */
246 mouse_data
= data
->u
.ps2
.mouse_data
;
248 data
->u
.ps2
.expected_mouse_acks
= 0;
249 mouse_data
[data
->u
.ps2
.mouse_collected_bytes
] = mousecode
;
251 /* Packet validity check. Bit 3 of first mouse packet byte must be set */
253 if ((mouse_data
[0] & 8) == 0)
255 data
->u
.ps2
.mouse_collected_bytes
= 0;
259 data
->u
.ps2
.mouse_collected_bytes
++;
261 if (data
->u
.ps2
.mouse_collected_bytes
!= data
->u
.ps2
.mouse_packetsize
)
263 /* Mouse Packet not yet complete */
267 /* We have a complete mouse packet :-) */
269 data
->u
.ps2
.mouse_collected_bytes
= 0;
272 * Let's see whether these data can be right...
274 * D7 D6 D5 D4 D3 D2 D1 D0
275 * YV XV YS XS 1 M R L
276 * X7 . . . . . . X1 (X)
277 * Y7 . . . . . . Y1 (Y)
279 * XV,YV : overflow in x/y direction
280 * XS,YS : most significant bit of X and Y: represents sign
281 * X,Y : displacement in x and y direction (8 least significant bits).
283 * X, XS, Y and YS make up two 9-bit two's complement fields.
287 D(bug("Got the following: 1. byte: 0x%x, dx=%d, dy=%d\n",
293 e
->x
= mouse_data
[1];
294 e
->y
= mouse_data
[2];
296 if (mouse_data
[0] & 0x10) e
->x
-= 256;
297 if (mouse_data
[0] & 0x20) e
->y
-= 256;
299 /* dy is reversed! */
304 e
->button
= vHidd_Mouse_NoButton
;
305 e
->type
= vHidd_Mouse_Motion
;
307 data
->mouse_callback(data
->callbackdata
, e
);
310 buttonstate
= mouse_data
[0] & 0x07;
312 if ((buttonstate
& LEFT_BUTTON
) != (data
->buttonstate
& LEFT_BUTTON
))
314 e
->button
= vHidd_Mouse_Button1
;
315 e
->type
= (buttonstate
& LEFT_BUTTON
) ? vHidd_Mouse_Press
: vHidd_Mouse_Release
;
317 data
->mouse_callback(data
->callbackdata
, e
);
320 if ((buttonstate
& RIGHT_BUTTON
) != (data
->buttonstate
& RIGHT_BUTTON
))
322 e
->button
= vHidd_Mouse_Button2
;
323 e
->type
= (buttonstate
& RIGHT_BUTTON
) ? vHidd_Mouse_Press
: vHidd_Mouse_Release
;
325 data
->mouse_callback(data
->callbackdata
, e
);
328 if ((buttonstate
& MIDDLE_BUTTON
) != (data
->buttonstate
& MIDDLE_BUTTON
))
330 e
->button
= vHidd_Mouse_Button3
;
331 e
->type
= (buttonstate
& MIDDLE_BUTTON
) ? vHidd_Mouse_Press
: vHidd_Mouse_Release
;
333 data
->mouse_callback(data
->callbackdata
, e
);
336 data
->buttonstate
= buttonstate
;
338 #if INTELLIMOUSE_SUPPORT
340 e
->y
= (mouse_data
[3] & 8) ? (mouse_data
[3] & 15) - 16 : (mouse_data
[3] & 15);
344 e
->type
= vHidd_Mouse_WheelMotion
;
345 e
->button
= vHidd_Mouse_NoButton
;
347 data
->mouse_callback(data
->callbackdata
, e
);
351 } /* for(; ((info = mouse_read_status()) & KBD_STATUS_OBF) && work; work--) */
355 D(bug("mouse.hidd: controller jammed (0x%02X).\n", info
));
363 /****************************************************************************************/
365 int test_mouse_ps2(OOP_Class
*cl
, OOP_Object
*o
)
367 struct mouse_data
*data
= OOP_INST_DATA(cl
, o
);
368 struct Library
*kbd_hidd
;
369 struct Interrupt
*irq
;
372 /* Test for a PS/2 controller */
373 if ((kbd_hidd
= OpenLibrary("kbd.hidd", 0)) == NULL
)
375 CloseLibrary(kbd_hidd
);
377 irq
= &data
->u
.ps2
.irq
;
379 irq
->is_Node
.ln_Type
= NT_INTERRUPT
;
380 irq
->is_Node
.ln_Pri
= 127;
381 irq
->is_Node
.ln_Name
= "PS/2 mouse class irq";
382 irq
->is_Code
= (VOID_FUNC
)mouse_ps2int
;
383 irq
->is_Data
= (APTR
)data
;
385 AddIntServer(INTB_KERNEL
+ 12, irq
);
388 result
= mouse_ps2reset(data
);
391 /* If mouse_ps2reset() returned non-zero value, there is vaild PS/2 mouse */
396 /* Either no PS/2 mouse or problems with it */
397 /* Remove mouse interrupt */
398 RemIntServer(INTB_KERNEL
+ 12, irq
);
400 /* Report no PS/2 mouse */
404 void dispose_mouse_ps2(OOP_Class
*cl
, OOP_Object
*o
) {
405 struct mouse_data
*data
= OOP_INST_DATA(cl
, o
);
407 RemIntServer(INTB_KERNEL
+ 12, &data
->u
.ps2
.irq
);
410 /****************************************************************************************/
412 void getps2State(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Mouse_Event
*event
)
415 struct mouse_data
*data
= OOP_INST_DATA(cl
, o
);
418 /* The following doesn't seem to do anything useful */
419 mouse_write(KBD_OUTCMD_DISABLE
);
420 /* switch to remote mode */
421 mouse_write(KBD_OUTCMD_SET_REMOTE_MODE
);
423 ack
= data
->u
.ps2
.expected_mouse_acks
+1;
424 mouse_write(KBD_OUTCMD_READ_DATA
);
425 while (data
->u
.ps2
.expected_mouse_acks
>=ack
)
427 /* switch back to stream mode */
428 mouse_write(KBD_OUTCMD_SET_STREAM_MODE
);
429 mouse_write(KBD_OUTCMD_ENABLE
);
433 /****************************************************************************************/
435 static int detect_aux()
442 mouse_write_command(KBD_CTRLCMD_WRITE_AUX_OBUF
);
445 mouse_write_output(0x5a);
449 unsigned char status
= mouse_read_status();
451 if (status
& KBD_STATUS_OBF
)
453 (void) mouse_read_input();
454 if (status
& KBD_STATUS_MOUSE_OBF
)
465 D(bug("PS/2 Auxilliary port %sdetected\n", retval
? "" : "not "));
469 /****************************************************************************************/
471 static int query_mouse(UBYTE
*buf
, int size
, int timeout
)
477 UBYTE status
= mouse_read_status();
479 if (status
& KBD_STATUS_OBF
)
481 UBYTE c
= mouse_read_input();
483 if ((c
!= KBD_REPLY_ACK
) && (status
& KBD_STATUS_MOUSE_OBF
))
493 } while ((--timeout
) && (ret
< size
));
499 /****************************************************************************************/
501 static int detect_intellimouse(void)
505 /* Try to switch into IMPS2 mode */
507 mouse_write_ack(KBD_OUTCMD_SET_RATE
);
508 mouse_write_ack(200);
509 mouse_write_ack(KBD_OUTCMD_SET_RATE
);
510 mouse_write_ack(100);
511 mouse_write_ack(KBD_OUTCMD_SET_RATE
);
513 mouse_write_ack(KBD_OUTCMD_GET_ID
);
514 mouse_write_noack(KBD_OUTCMD_GET_ID
);
516 query_mouse(&id
, 1, 20);
518 return ((id
== 3) || (id
== 4)) ? id
: 0;
521 /****************************************************************************************/
523 #define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
524 #define AUX_INTS_ON (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
526 /****************************************************************************************/
528 int mouse_ps2reset(struct mouse_data
*data
)
531 * The commands are for the mouse and nobody else.
534 mouse_write_command_w(KBD_CTRLCMD_MOUSE_ENABLE
);
537 * Check for a mouse port.
543 * Unfortunately on my computer these commands cause
544 * the mouse not to work at all if they are issued
545 * in a different order. So please keep it that way.
550 * Turn interrupts off and the keyboard as well since the
551 * commands are all for the mouse.
553 mouse_write_cmd(AUX_INTS_OFF
);
554 mouse_write_command_w(KBD_CTRLCMD_KBD_DISABLE
);
557 mouse_write_ack(KBD_OUTCMD_RESET
);
558 mouse_wait_for_input(); /* Test result (0xAA) */
559 mouse_wait_for_input(); /* Mouse type */
561 data
->u
.ps2
.mouse_protocol
= PS2_PROTOCOL_STANDARD
;
562 data
->u
.ps2
.mouse_packetsize
= 3;
564 #if INTELLIMOUSE_SUPPORT
565 if (detect_intellimouse())
567 data
->u
.ps2
.mouse_protocol
= PS2_PROTOCOL_INTELLIMOUSE
;
568 data
->u
.ps2
.mouse_packetsize
= 4;
573 * Now the commands themselves.
575 mouse_write_ack(KBD_OUTCMD_SET_RATE
);
576 mouse_write_ack(100);
577 mouse_write_ack(KBD_OUTCMD_SET_RES
);
579 mouse_write_ack(KBD_OUTCMD_SET_SCALE11
);
581 /* Enable Aux device (and re-enable keyboard) */
583 mouse_write_command_w(KBD_CTRLCMD_KBD_ENABLE
);
584 mouse_write_ack(KBD_OUTCMD_ENABLE
);
585 mouse_write_cmd(AUX_INTS_ON
);
588 * According to the specs there is an external
589 * latch that holds the level-sensitive interrupt
590 * request until the CPU reads port 0x60.
591 * If this is not read then the mouse does not
592 * work on my computer.- Stefan
597 D(bug("[Mouse] Found and initialized PS/2 mouse!\n"));
602 /****************************************************************************************/