2011-12-11 03:34:10 +04:00
|
|
|
/* vim: tabstop=4 shiftwidth=4 noexpandtab
|
|
|
|
*
|
2011-03-26 03:54:48 +03:00
|
|
|
* Low-level keyboard interrupt driver.
|
|
|
|
*
|
2012-01-25 23:50:30 +04:00
|
|
|
* Creates a device file (keyboard_pipe) that can be read
|
|
|
|
* to retreive keyboard events.
|
|
|
|
*
|
2011-04-15 06:02:44 +04:00
|
|
|
* Part of the ToAruOS Kernel
|
2012-01-25 23:50:30 +04:00
|
|
|
* Copyright 2011-2012 Kevin Lange
|
2011-03-26 03:54:48 +03:00
|
|
|
*
|
2012-01-25 23:50:30 +04:00
|
|
|
* TODO: Move this to a server
|
|
|
|
* TODO: Better handling of function keys
|
2011-03-26 03:54:48 +03:00
|
|
|
*/
|
|
|
|
|
2011-01-16 21:45:51 +03:00
|
|
|
#include <system.h>
|
2011-12-15 05:06:11 +04:00
|
|
|
#include <logging.h>
|
2012-01-25 10:19:52 +04:00
|
|
|
#include <fs.h>
|
|
|
|
#include <pipe.h>
|
|
|
|
#include <process.h>
|
2011-01-16 21:45:51 +03:00
|
|
|
|
2011-10-23 04:32:03 +04:00
|
|
|
#define KEY_UP_MASK 0x80
|
|
|
|
#define KEY_CODE_MASK 0x7F
|
|
|
|
#define KEY_CTRL_MASK 0x40
|
|
|
|
|
|
|
|
#define KEY_DEVICE 0x60
|
|
|
|
#define KEY_PENDING 0x64
|
|
|
|
|
2011-10-31 10:18:44 +04:00
|
|
|
#define KEYBOARD_NOTICES 0
|
2012-02-05 08:29:46 +04:00
|
|
|
#define KEYBOARD_IRQ 1
|
2011-10-31 10:18:44 +04:00
|
|
|
|
2011-04-15 06:02:44 +04:00
|
|
|
/* A bit-map to store the keyboard states */
|
2011-01-22 06:48:17 +03:00
|
|
|
struct keyboard_states {
|
|
|
|
uint32_t shift : 1;
|
|
|
|
uint32_t alt : 1;
|
|
|
|
uint32_t ctrl : 1;
|
|
|
|
} keyboard_state;
|
|
|
|
|
|
|
|
typedef void (*keyboard_handler_t)(int scancode);
|
2012-01-25 10:19:52 +04:00
|
|
|
fs_node_t * keyboard_pipe;
|
2011-01-22 06:48:17 +03:00
|
|
|
|
2011-01-16 21:45:51 +03:00
|
|
|
char kbd_us[128] = {
|
|
|
|
0, 27,
|
|
|
|
'1','2','3','4','5','6','7','8','9','0',
|
|
|
|
'-','=','\b',
|
|
|
|
'\t', /* tab */
|
|
|
|
'q','w','e','r','t','y','u','i','o','p','[',']','\n',
|
|
|
|
0, /* control */
|
|
|
|
'a','s','d','f','g','h','j','k','l',';','\'', '`',
|
|
|
|
0, /* left shift */
|
|
|
|
'\\','z','x','c','v','b','n','m',',','.','/',
|
|
|
|
0, /* right shift */
|
|
|
|
'*',
|
|
|
|
0, /* alt */
|
|
|
|
' ', /* space */
|
|
|
|
0, /* caps lock */
|
|
|
|
0, /* F1 [59] */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, /* ... F10 */
|
|
|
|
0, /* 69 num lock */
|
|
|
|
0, /* scroll lock */
|
|
|
|
0, /* home */
|
|
|
|
0, /* up */
|
|
|
|
0, /* page up */
|
|
|
|
'-',
|
|
|
|
0, /* left arrow */
|
|
|
|
0,
|
|
|
|
0, /* right arrow */
|
|
|
|
'+',
|
|
|
|
0, /* 79 end */
|
|
|
|
0, /* down */
|
|
|
|
0, /* page down */
|
|
|
|
0, /* insert */
|
|
|
|
0, /* delete */
|
|
|
|
0, 0, 0,
|
|
|
|
0, /* F11 */
|
|
|
|
0, /* F12 */
|
|
|
|
0, /* everything else */
|
|
|
|
};
|
|
|
|
|
2011-01-22 06:48:17 +03:00
|
|
|
char kbd_us_l2[128] = {
|
|
|
|
0, 27,
|
|
|
|
'!','@','#','$','%','^','&','*','(',')',
|
|
|
|
'_','+','\b',
|
|
|
|
'\t', /* tab */
|
|
|
|
'Q','W','E','R','T','Y','U','I','O','P','{','}','\n',
|
|
|
|
0, /* control */
|
|
|
|
'A','S','D','F','G','H','J','K','L',':','"', '~',
|
|
|
|
0, /* left shift */
|
|
|
|
'|','Z','X','C','V','B','N','M','<','>','?',
|
|
|
|
0, /* right shift */
|
|
|
|
'*',
|
|
|
|
0, /* alt */
|
|
|
|
' ', /* space */
|
|
|
|
0, /* caps lock */
|
|
|
|
0, /* F1 [59] */
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
|
|
|
0, /* ... F10 */
|
|
|
|
0, /* 69 num lock */
|
|
|
|
0, /* scroll lock */
|
|
|
|
0, /* home */
|
|
|
|
0, /* up */
|
|
|
|
0, /* page up */
|
|
|
|
'-',
|
|
|
|
0, /* left arrow */
|
|
|
|
0,
|
|
|
|
0, /* right arrow */
|
|
|
|
'+',
|
|
|
|
0, /* 79 end */
|
|
|
|
0, /* down */
|
|
|
|
0, /* page down */
|
|
|
|
0, /* insert */
|
|
|
|
0, /* delete */
|
|
|
|
0, 0, 0,
|
|
|
|
0, /* F11 */
|
|
|
|
0, /* F12 */
|
|
|
|
0, /* everything else */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-10-23 04:32:03 +04:00
|
|
|
/*
|
|
|
|
* "Normal" key handler
|
|
|
|
* Used for visible text keys and handles
|
|
|
|
* application of shift/alt/control
|
|
|
|
*
|
|
|
|
* Shells out to putch() to do most of the work.
|
|
|
|
*/
|
2011-01-22 06:48:17 +03:00
|
|
|
void norm(int scancode) {
|
2011-10-23 04:32:03 +04:00
|
|
|
if (scancode & KEY_UP_MASK) {
|
2011-01-22 06:48:17 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!kbd_us[scancode]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (keyboard_state.shift) {
|
|
|
|
putch(kbd_us_l2[scancode]);
|
|
|
|
} else if (keyboard_state.ctrl) {
|
2011-10-23 04:32:03 +04:00
|
|
|
int out = (int)(kbd_us_l2[scancode] - KEY_CTRL_MASK);
|
2011-02-08 03:22:03 +03:00
|
|
|
if (out < 0 || out > 0x1F) {
|
|
|
|
putch(kbd_us[scancode]);
|
|
|
|
} else {
|
|
|
|
putch((char)out);
|
|
|
|
}
|
2011-01-22 06:48:17 +03:00
|
|
|
} else {
|
|
|
|
putch(kbd_us[scancode]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-23 04:32:03 +04:00
|
|
|
/*
|
|
|
|
* Toggle Shift
|
|
|
|
*/
|
2011-01-22 06:48:17 +03:00
|
|
|
void shft(int scancode) {
|
2011-10-31 10:48:03 +04:00
|
|
|
keyboard_state.shift = !((scancode & KEY_UP_MASK) == KEY_UP_MASK);
|
2011-01-22 06:48:17 +03:00
|
|
|
}
|
|
|
|
|
2011-10-23 04:32:03 +04:00
|
|
|
/*
|
|
|
|
* Toggle Alt
|
|
|
|
*/
|
2011-01-22 06:48:17 +03:00
|
|
|
void altk(int scancode) {
|
2011-10-31 10:48:03 +04:00
|
|
|
keyboard_state.alt = !((scancode & KEY_UP_MASK) == KEY_UP_MASK);
|
2011-01-22 06:48:17 +03:00
|
|
|
}
|
|
|
|
|
2011-10-23 04:32:03 +04:00
|
|
|
/*
|
|
|
|
* Toggle Control
|
|
|
|
*/
|
2011-01-22 06:48:17 +03:00
|
|
|
void ctlk(int scancode) {
|
2011-10-31 10:48:03 +04:00
|
|
|
keyboard_state.ctrl = !((scancode & KEY_UP_MASK) == KEY_UP_MASK);
|
2011-01-22 06:48:17 +03:00
|
|
|
}
|
|
|
|
|
2011-10-23 04:32:03 +04:00
|
|
|
/*
|
|
|
|
* Function keys
|
|
|
|
*/
|
2011-01-22 06:48:17 +03:00
|
|
|
void func(int scancode) {
|
2011-10-23 04:32:03 +04:00
|
|
|
if (scancode & KEY_UP_MASK) {
|
2011-04-19 03:12:37 +04:00
|
|
|
return;
|
|
|
|
}
|
2011-10-31 10:18:44 +04:00
|
|
|
#if KEYBOARD_NOTICES
|
2011-03-25 08:09:23 +03:00
|
|
|
kprintf("[NOTICE] Function key %d pressed\n", scancode);
|
2011-10-31 10:18:44 +04:00
|
|
|
#endif
|
2011-03-25 08:09:23 +03:00
|
|
|
}
|
|
|
|
|
2011-10-23 04:32:03 +04:00
|
|
|
/*
|
|
|
|
* "Special" keys
|
|
|
|
* Extra keys on your keyboard will produce these
|
|
|
|
* sorts of key presses.
|
|
|
|
*/
|
2011-03-25 08:09:23 +03:00
|
|
|
void spec(int scancode) {
|
2011-10-23 04:32:03 +04:00
|
|
|
if (scancode & KEY_UP_MASK) {
|
2011-03-25 08:09:23 +03:00
|
|
|
return;
|
|
|
|
}
|
2011-04-19 03:12:37 +04:00
|
|
|
switch (scancode) {
|
|
|
|
case 75:
|
|
|
|
putch('\033');
|
|
|
|
putch('[');
|
|
|
|
putch('D');
|
|
|
|
break;
|
|
|
|
case 72:
|
|
|
|
putch('\033');
|
|
|
|
putch('[');
|
|
|
|
putch('A');
|
|
|
|
break;
|
|
|
|
case 77:
|
|
|
|
putch('\033');
|
|
|
|
putch('[');
|
|
|
|
putch('C');
|
|
|
|
break;
|
|
|
|
case 80:
|
|
|
|
putch('\033');
|
|
|
|
putch('[');
|
|
|
|
putch('B');
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
putch('\033');
|
|
|
|
default:
|
2011-10-31 10:18:44 +04:00
|
|
|
#if KEYBOARD_NOTICES
|
2011-04-19 03:12:37 +04:00
|
|
|
kprintf("[NOTICE] Special key %d pressed\n", scancode);
|
2011-10-31 10:18:44 +04:00
|
|
|
#endif
|
2011-04-19 03:12:37 +04:00
|
|
|
break;
|
|
|
|
}
|
2011-01-22 06:48:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
keyboard_handler_t key_method[] = {
|
2011-03-25 08:09:23 +03:00
|
|
|
/* 00 */ NULL, spec, norm, norm, norm, norm, norm, norm,
|
2011-01-22 06:48:17 +03:00
|
|
|
/* 08 */ norm, norm, norm, norm, norm, norm, norm, norm,
|
|
|
|
/* 10 */ norm, norm, norm, norm, norm, norm, norm, norm,
|
|
|
|
/* 18 */ norm, norm, norm, norm, norm, ctlk, norm, norm,
|
|
|
|
/* 20 */ norm, norm, norm, norm, norm, norm, norm, norm,
|
|
|
|
/* 28 */ norm, norm, shft, norm, norm, norm, norm, norm,
|
|
|
|
/* 30 */ norm, norm, norm, norm, norm, norm, shft, norm,
|
2011-03-25 08:09:23 +03:00
|
|
|
/* 38 */ altk, norm, spec, func, func, func, func, func,
|
|
|
|
/* 40 */ func, func, func, func, func, spec, spec, spec,
|
|
|
|
/* 48 */ spec, spec, spec, spec, spec, spec, spec, spec,
|
|
|
|
/* 50 */ spec, spec, spec, spec, spec, spec, spec, func,
|
|
|
|
/* 58 */ func, spec, spec, spec, spec, spec, spec, spec,
|
|
|
|
/* 60 */ spec, spec, spec, spec, spec, spec, spec, spec,
|
|
|
|
/* 68 */ spec, spec, spec, spec, spec, spec, spec, spec,
|
|
|
|
/* 70 */ spec, spec, spec, spec, spec, spec, spec, spec,
|
|
|
|
/* 78 */ spec, spec, spec, spec, spec, spec, spec, spec,
|
2011-01-22 06:48:17 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-10-31 10:48:03 +04:00
|
|
|
extern uint8_t mouse_cycle;
|
|
|
|
|
2011-01-16 21:45:51 +03:00
|
|
|
void
|
|
|
|
keyboard_handler(
|
|
|
|
struct regs *r
|
|
|
|
) {
|
|
|
|
unsigned char scancode;
|
2011-10-31 10:30:48 +04:00
|
|
|
keyboard_wait();
|
2011-10-23 04:32:03 +04:00
|
|
|
scancode = inportb(KEY_DEVICE);
|
2012-02-05 08:29:46 +04:00
|
|
|
irq_ack(KEYBOARD_IRQ);
|
2011-04-30 12:40:36 +04:00
|
|
|
if (keyboard_direct_handler) {
|
2011-05-01 10:51:48 +04:00
|
|
|
keyboard_direct_handler(scancode);
|
2011-04-30 12:40:36 +04:00
|
|
|
return;
|
|
|
|
}
|
2011-01-22 06:48:17 +03:00
|
|
|
keyboard_handler_t handler;
|
2011-10-31 10:48:03 +04:00
|
|
|
|
2011-10-23 04:32:03 +04:00
|
|
|
handler = key_method[(int)scancode & KEY_CODE_MASK];
|
2011-01-22 06:48:17 +03:00
|
|
|
if (handler) {
|
|
|
|
handler(scancode);
|
2011-01-16 21:45:51 +03:00
|
|
|
}
|
2012-02-05 08:29:46 +04:00
|
|
|
|
2011-01-16 21:45:51 +03:00
|
|
|
}
|
|
|
|
|
2012-01-25 23:50:30 +04:00
|
|
|
/*
|
|
|
|
* Install the keyboard driver and initialize the
|
|
|
|
* pipe device for userspace.
|
|
|
|
*/
|
2011-01-16 21:45:51 +03:00
|
|
|
void
|
|
|
|
keyboard_install() {
|
2011-12-27 05:23:58 +04:00
|
|
|
blog("Initializing PS/2 keyboard driver...");
|
2011-12-15 05:06:11 +04:00
|
|
|
LOG(INFO, "Initializing PS/2 keyboard driver");
|
2012-01-25 23:50:30 +04:00
|
|
|
|
|
|
|
/* Clear the buffer handlers */
|
2011-02-07 23:30:17 +03:00
|
|
|
keyboard_buffer_handler = NULL;
|
2011-04-30 12:40:36 +04:00
|
|
|
keyboard_direct_handler = NULL;
|
2012-01-25 10:19:52 +04:00
|
|
|
|
2012-01-25 23:50:30 +04:00
|
|
|
/* Create a device pipe */
|
2012-01-25 10:19:52 +04:00
|
|
|
keyboard_pipe = make_pipe(128);
|
2012-02-17 00:31:40 +04:00
|
|
|
current_process->fds->entries[0] = keyboard_pipe;
|
2012-01-25 10:19:52 +04:00
|
|
|
|
2012-01-25 23:50:30 +04:00
|
|
|
/* Install the interrupt handler */
|
2012-02-05 08:29:46 +04:00
|
|
|
irq_install_handler(KEYBOARD_IRQ, keyboard_handler);
|
2012-01-25 10:19:52 +04:00
|
|
|
|
2011-12-27 05:23:58 +04:00
|
|
|
bfinish(0);
|
2011-01-16 21:45:51 +03:00
|
|
|
}
|
|
|
|
|
2012-01-25 23:50:30 +04:00
|
|
|
/*
|
|
|
|
* Wait on the keyboard.
|
|
|
|
*/
|
2011-01-16 21:45:51 +03:00
|
|
|
void
|
|
|
|
keyboard_wait() {
|
2011-10-23 04:32:03 +04:00
|
|
|
while(inportb(KEY_PENDING) & 2);
|
2011-01-16 21:45:51 +03:00
|
|
|
}
|
2011-02-07 23:30:17 +03:00
|
|
|
|
|
|
|
/*
|
2012-01-25 23:50:30 +04:00
|
|
|
* Add a character to the device buffer.
|
2011-02-07 23:30:17 +03:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
putch(
|
|
|
|
unsigned char c
|
|
|
|
) {
|
|
|
|
if (keyboard_buffer_handler) {
|
|
|
|
keyboard_buffer_handler(c);
|
|
|
|
} else {
|
2012-01-25 10:19:52 +04:00
|
|
|
uint8_t buf[2];
|
|
|
|
buf[0] = c;
|
|
|
|
buf[1] = '\0';
|
|
|
|
write_fs(keyboard_pipe, 0, 1, buf);
|
2011-02-07 23:30:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-05 03:51:55 +04:00
|
|
|
/*
|
|
|
|
* Externally Set Keyboard States
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
set_kbd(
|
|
|
|
int shift,
|
|
|
|
int alt,
|
|
|
|
int ctrl
|
|
|
|
) {
|
|
|
|
keyboard_state.shift = shift;
|
|
|
|
keyboard_state.alt = alt;
|
|
|
|
keyboard_state.ctrl = ctrl;
|
|
|
|
}
|
|
|
|
|