2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
5 Desc: The main keyboard class.
9 /****************************************************************************************/
11 #define AROS_ALMOST_COMPATIBLE
13 #include <proto/exec.h>
14 #include <proto/utility.h>
15 #include <proto/oop.h>
16 #include <proto/kernel.h>
17 #include <aros/system.h>
18 #include <aros/symbolsets.h>
20 #include <exec/alerts.h>
21 #include <exec/memory.h>
22 #include <hidd/hidd.h>
23 #include <hidd/keyboard.h>
24 #include <hardware/custom.h>
25 #include <devices/inputevent.h>
26 #include <devices/rawkeycodes.h>
29 #include "kbd_common.h"
33 #include <aros/debug.h>
35 /****************************************************************************************/
39 void kbd_process_key(struct kbd_data
*, UBYTE
,
40 struct ExecBase
*SysBase
);
42 void kbd_updateleds();
45 /****************************************************************************************/
49 /****************************************************************************************/
51 #include "stdkeytable.h"
53 /****************************************************************************************/
55 #include "e0keytable.h"
57 /****************************************************************************************/
58 static void kbd_keyint(struct kbd_data
*data
, void *unused
)
60 UBYTE keycode
; /* Recent Keycode get */
61 UBYTE info
= 0; /* Data from info reg */
65 for(; ((info
= kbd_read_status()) & KBD_STATUS_OBF
) && work
; work
--)
67 /* data from information port */
68 if (info
& KBD_STATUS_MOUSE_OBF
)
71 ** Data from PS/2 mouse. Hopefully this gets through to mouse interrupt
72 ** if we break out of loop here :-\
76 keycode
= kbd_read_input();
78 D(bug("ki: keycode %d (%x)\n", keycode
, keycode
));
79 if (info
& (KBD_STATUS_GTO
| KBD_STATUS_PERR
))
81 /* Ignore errors and messages for mouse -> eat status/error byte */
85 kbd_process_key(data
, keycode
, SysBase
);
86 } /* for(; ((info = kbd_read_status()) & KBD_STATUS_OBF) && work; work--) */
88 D(if (!work
) bug("kbd.hidd: controller jammed (0x%02X).\n", info
);)
93 OOP_Object
* PCKbd__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
95 struct TagItem
*tag
, *tstate
;
97 APTR callbackdata
= NULL
;
101 EnterFunc(bug("Kbd::New()\n"));
103 #if __WORDSIZE == 32 /* FIXME: REMOVEME: just a debugging thing for the weird s-key problem */
104 SysBase
->ex_Reserved2
[1] = (ULONG
)std_keytable
;
106 if (XSD(cl
)->kbdhidd
) /* Cannot open twice */
107 ReturnPtr("Kbd::New", OOP_Object
*, NULL
); /* Should have some error code here */
109 tstate
= msg
->attrList
;
110 D(bug("Kbd: tstate: %p, tag=%x\n", tstate
, tstate
->ti_Tag
));
112 while ((tag
= NextTagItem(&tstate
)))
116 D(bug("Kbd: Got tag %d, data %x\n", tag
->ti_Tag
, tag
->ti_Data
));
118 if (IS_HIDDKBD_ATTR(tag
->ti_Tag
, idx
))
120 D(bug("Kbd hidd tag\n"));
123 case aoHidd_Kbd_IrqHandler
:
124 callback
= (APTR
)tag
->ti_Data
;
125 D(bug("Got callback %p\n", (APTR
)tag
->ti_Data
));
128 case aoHidd_Kbd_IrqHandlerData
:
129 callbackdata
= (APTR
)tag
->ti_Data
;
130 D(bug("Got data %p\n", (APTR
)tag
->ti_Data
));
135 } /* while (tags to process) */
137 if (NULL
== callback
)
138 ReturnPtr("Kbd::New", OOP_Object
*, NULL
); /* Should have some error code here */
140 /* Only continue if there appears to be a keyboard controller */
142 last_code
= kbd_clear_input();
143 kbd_write_command_w(KBD_CTRLCMD_SELF_TEST
);
144 reset_success
= kbd_wait_for_input();
147 if (reset_success
== 0x55)
149 /* Add some descriptional tags to our attributes */
150 struct TagItem kbd_tags
[] =
152 {aHidd_Name
, (IPTR
)"i8042.hidd" },
153 {aHidd_HardwareName
, (IPTR
)"IBM AT-compatible keyboard"},
154 {TAG_MORE
, (IPTR
)msg
->attrList
}
156 struct pRoot_New new_msg
=
162 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, &new_msg
.mID
);
165 struct kbd_data
*data
= OOP_INST_DATA(cl
, o
);
167 data
->kbd_callback
= (VOID (*)(APTR
, UWORD
))callback
;
168 data
->callbackdata
= callbackdata
;
169 data
->prev_amigacode
= -2;
170 data
->prev_keycode
= 0;
173 kbd_reset(); /* Reset the keyboard */
178 * Report last key received before keyboard was reset, so that
179 * keyboard.device knows about any key currently held down
182 kbd_process_key(data
, (UBYTE
)last_code
, SysBase
);
184 /* Install keyboard interrupt */
185 data
->irq
= KrnAddIRQHandler(1, kbd_keyint
, data
, NULL
);
187 ReturnPtr("Kbd::New", OOP_Object
*, o
);
190 D(else bug("Keyboard controller not detected\n");)
195 VOID
PCKbd__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
197 struct kbd_data
*data
= OOP_INST_DATA(cl
, o
);
199 KrnRemIRQHandler(data
->irq
);
200 XSD(cl
)->kbdhidd
= NULL
;
202 OOP_DoSuperMethod(cl
, o
, msg
);
205 /****************************************************************************************/
207 #define WaitForInput \
208 ({ int timeout=1000; \
211 info = kbd_read_status(); \
214 } while((info & KBD_STATUS_OBF));\
215 inb(0x80); /* Read from port 0x80, the debug port, to add some delay */ \
218 /****************************************************************************************/
220 #define FLAG_LCTRL 0x00000008
221 #define FLAG_RCTRL 0x00000010
222 #define FLAG_LALT 0x00000020
223 #define FLAG_RALT 0x00000040
224 #define FLAG_LSHIFT 0x00000080
225 #define FLAG_RSHIFT 0x00000100
226 #define FLAG_LMETA 0x00000200
227 #define FLAG_RMETA 0x00000400
228 #define FLAG_DEL 0x00000800
230 /****************************************************************************************/
232 void kbd_updateleds(ULONG kbd_keystate
)
235 kbd_write_output_w(KBD_OUTCMD_SET_LEDS
);
238 kbd_write_output_w(kbd_keystate
& 0x07);
245 void kbd_process_key(struct kbd_data
*data
, UBYTE keycode
,
246 struct ExecBase
*SysBase
)
248 ULONG kbd_keystate
= data
->kbd_keystate
;
254 if ((keycode
== KBD_REPLY_ACK
) || (keycode
== KBD_REPLY_RESEND
))
260 if ((keycode
== 0xE0) || (keycode
== 0xE1))
262 /* Extended keycodes: E0 gets followed by one code, E1 by two */
263 data
->prev_keycode
= keycode
;
267 if ((keycode
== 0x00) || (keycode
== 0xFF))
269 /* 00 is error. FF is sent by some keyboards -> ignore it. */
270 data
->prev_keycode
= 0;
276 downkeycode
= keycode
& 0x7F;
277 releaseflag
= keycode
& 0x80;
279 if (data
->prev_keycode
)
281 if (data
->prev_keycode
== 0xE0)
283 data
->prev_keycode
= 0;
284 event
= 0x4000 | keycode
;
286 if (downkeycode
< NUM_E0KEYS
)
288 amigacode
= e0_keytable
[downkeycode
];
289 if (amigacode
!= NOKEY
) amigacode
|= releaseflag
;
291 } /* if (data->prev_keycode == 0xE0) */
294 /* Check Pause key: 0xE1 0x1D 0x45 0xE1 0x9D 0xC5 */
295 if ((data
->prev_keycode
== 0xE1) && (downkeycode
== 0x1D))
297 /* let's remember, that we still need third key */
298 data
->prev_keycode
= 0x1234;
301 else if ((data
->prev_keycode
== 0x1234) && (downkeycode
== 0x45))
303 /* Got third key and yes, it is Pause */
304 amigacode
= 0x6E | releaseflag
;
305 data
->prev_keycode
= 0;
310 data
->prev_keycode
= 0;
314 } /* if (data->prev_keycode == 0xE0) else ... */
316 } /* if (data->prev_keycode) */
319 /* Normal single byte keycode */
321 if (downkeycode
< NUM_STDKEYS
)
323 amigacode
= std_keytable
[downkeycode
];
324 if (amigacode
!= NOKEY
) amigacode
|= releaseflag
;
331 kbd_keystate
^= 0x02; /* Toggle Numlock bit */
332 kbd_updateleds(kbd_keystate
);
336 kbd_keystate
^= 0x01; /* Toggle Scrolllock bit */
337 kbd_updateleds(kbd_keystate
);
341 kbd_keystate
^= 0x04; /* Toggle Capslock bit */
342 kbd_updateleds(kbd_keystate
);
346 kbd_keystate
|= FLAG_LSHIFT
;
349 case (K_LShift
| 0x80):
350 kbd_keystate
&= ~FLAG_LSHIFT
;
354 kbd_keystate
|= FLAG_RSHIFT
;
357 case (K_RShift
| 0x80):
358 kbd_keystate
&= ~FLAG_RSHIFT
;
362 kbd_keystate
|= FLAG_LCTRL
;
365 case (K_LCtrl
| 0x80):
366 kbd_keystate
&= ~FLAG_LCTRL
;
370 kbd_keystate
|= FLAG_RCTRL
;
373 case (K_RCtrl
| 0x80):
374 kbd_keystate
&= ~FLAG_RCTRL
;
378 kbd_keystate
|= FLAG_LMETA
;
381 case (K_LMeta
| 0x80):
382 kbd_keystate
&= ~FLAG_LMETA
;
387 kbd_keystate
|= FLAG_RMETA
;
390 case (K_RMeta
| 0x80):
391 case (K_Menu
| 0x80):
392 kbd_keystate
&= ~FLAG_RMETA
;
396 kbd_keystate
|= FLAG_LALT
;
399 case (K_LAlt
| 0x80):
400 kbd_keystate
&= ~FLAG_LALT
;
404 kbd_keystate
|= FLAG_RALT
;
407 case (K_RAlt
| 0x80):
408 kbd_keystate
&= ~FLAG_RALT
;
412 kbd_keystate
|= FLAG_DEL
;
416 kbd_keystate
&= ~FLAG_DEL
;
419 } /* switch(event) */
421 if ((kbd_keystate
& (FLAG_LCTRL
| FLAG_RCTRL
)) != 0
422 && (kbd_keystate
& (FLAG_LALT
| FLAG_RALT
)) != 0
423 && (kbd_keystate
& FLAG_DEL
) != 0)
425 ShutdownA(SD_ACTION_COLDREBOOT
);
428 if ((kbd_keystate
& (FLAG_LCTRL
| FLAG_LMETA
| FLAG_RMETA
))
429 == (FLAG_LCTRL
| FLAG_LMETA
| FLAG_RMETA
))
431 amigacode
= 0x78; /* Reset */
434 D(bug("ki: amigacode %d (%x) last %d (%x)\n", amigacode
, amigacode
,
435 data
->prev_amigacode
, data
->prev_amigacode
));
437 /* Update keystate */
438 data
->kbd_keystate
= kbd_keystate
;
441 if (amigacode
== 0x78) // Reset request
445 if (amigacode
== NOKEY
) return;
447 if (amigacode
== data
->prev_amigacode
)
450 ** Must be a repeated key. Ignore it, because we have our
451 ** own kbd repeating in input.device
456 data
->prev_amigacode
= amigacode
;
458 D(bug("ki: ********************* c %d (%x)\n", amigacode
, amigacode
));
460 /* Pass the code to handler */
461 data
->kbd_callback(data
->callbackdata
, amigacode
);
466 /****************************************************************************************/
468 /* FIXME: This should go somewhere higher but D(bug()) is not possible there */
474 /****************************************************************************************/
477 * Please leave this routine as is for now.
478 * It works and that is all that matters right now.
481 /****************************************************************************************/
487 kbd_write_command_w(KBD_CTRLCMD_SELF_TEST
); /* Initialize and test keyboard controller */
489 if (kbd_wait_for_input() != 0x55)
491 D(bug("Kbd: Controller test failed!\n"));
495 kbd_write_command_w(KBD_CTRLCMD_KBD_TEST
);
497 if (kbd_wait_for_input() != 0)
499 D(bug("Kbd: Keyboard test failed!\n"));
503 kbd_write_command_w(KBD_CTRLCMD_KBD_ENABLE
); /* enable keyboard */
505 D(bug("Kbd: Keyboard enabled!\n"));
509 kbd_write_output_w(KBD_OUTCMD_RESET
);
510 status
= kbd_wait_for_input();
512 if (status
== KBD_REPLY_ACK
)
515 if (status
!= KBD_REPLY_RESEND
)
517 D(bug("Kbd: Keyboard reset failed! (1)\n"));
522 if (kbd_wait_for_input() != KBD_REPLY_POR
)
524 D(bug("Kbd: Keyboard reset failed! (2)\n"));
530 kbd_write_output_w(KBD_OUTCMD_DISABLE
);
531 status
= kbd_wait_for_input();
533 if (status
== KBD_REPLY_ACK
)
536 if (status
!= KBD_REPLY_RESEND
)
538 D(bug("Kbd: Keyboard disable failed!\n"));
543 kbd_write_command_w(KBD_CTRLCMD_WRITE_MODE
); /* Write mode */
546 kbd_write_output_w( KBD_MODE_KCC
| // set parameters: scan code to pc conversion,
547 KBD_MODE_KBD_INT
| // enable mouse and keyboard,
548 KBD_MODE_DISABLE_MOUSE
| // enable IRQ 1 & 12.
551 kbd_write_output_w( KBD_MODE_KCC
| KBD_MODE_KBD_INT
);
554 kbd_write_output_w(KBD_OUTCMD_ENABLE
);
556 D(bug("Kbd: enabled ints\n"));
558 if (kbd_wait_for_input() != KBD_REPLY_ACK
)
560 D(bug("Kbd: No REPLY_ACK !!!\nReturning FALSE !!!!\n"));
564 D(bug("Kbd: Successfully reset keyboard!\n"));
569 /****************************************************************************************/