📄 ps2kbdmou_ecos.c
字号:
// Start by masking out the interrupts. Other code such as the HAL
// or RedBoot may think it currently owns the keyboard, and I do
// not want any interference from them while setting up the
// interrupt handlers.
cyg_drv_interrupt_mask_intunsafe(CYGNUM_HAL_INTERRUPT_KEYBOARD);
cyg_drv_interrupt_mask_intunsafe(CYGNUM_HAL_INTERRUPT_IRQ12);
// Install my own interrupt handler, overwriting anything that might
// be there already.
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_KEYBOARD, 0, 0,
&ps2_isr, &ps2_dsr, &ps2kbd_interrupt_handle, &ps2kbd_interrupt_data);
cyg_drv_interrupt_attach(ps2kbd_interrupt_handle);
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_IRQ12, 0, 0,
&ps2_isr, &ps2_dsr, &ps2mouse_interrupt_handle, &ps2mouse_interrupt_data);
cyg_drv_interrupt_attach(ps2mouse_interrupt_handle);
// Get the device into a known state.
ps2_send_command(KC_CONTROL_DISABLE_AUX, NULL, 0, 0);
ps2_send_command(KC_CONTROL_DISABLE_KBD, NULL, 0, 0);
// Discard any current data.
HAL_READ_UINT8(KC_STATUS, status);
while (status & KC_STATUS_OUTB) {
HAL_READ_UINT8(KC_OUTPUT, data);
HAL_READ_UINT8(KC_STATUS, status);
}
// Now restart and reset the keyboard.
ps2_send_command(KC_CONTROL_ENABLE_KBD, NULL, 0, 0);
buf[0] = KC_KBDC_STANDARD_DISABLE;
ps2_send_command_poll(KC_CONTROL_NULL, buf, 1, 0);
buf[0] = KC_KBDC_LED_ONOFF;
buf[1] = 0;
ps2_send_command_poll(KC_CONTROL_NULL, buf, 2, 0);
// The keyboard-specific initialization can now reenable the keyboard
// using enable
// Similarly for a mouse
// Standard mode means 100 samples/s, 1:1 scaling, stream mode, 4 counts/mm resolution,
// and transferdisabled. Stream mode is important, that means mouse data will
// be immediately available rather than requiring separate control messages to
// read a packet.
ps2_send_command(KC_CONTROL_ENABLE_AUX, NULL, 0, 0);
buf[0] = KC_MOUSEC_SET_STANDARD;
ps2_send_command_poll(KC_CONTROL_NULL, buf, 1, 1);
buf[0] = KC_MOUSEC_SET_SAMPLE_RATE;
buf[1] = 0x0A;
ps2_send_command_poll(KC_CONTROL_NULL, buf, 2, 1);
// WRITE_MODE does not appear to involve an ACK
ps2_send_command_poll(KC_CONTROL_WRITE_MODE, NULL, 0, 0);
do {
HAL_READ_UINT8(KC_STATUS, status);
} while (status & KC_STATUS_INPB);
HAL_WRITE_UINT8(KC_INPUT, KC_MODE_KBD_INT | KC_MODE_MOU_INT | KC_MODE_SYS | KC_MODE_KCC);
cyg_drv_interrupt_unmask_intunsafe(CYGNUM_HAL_INTERRUPT_KEYBOARD);
cyg_drv_interrupt_unmask_intunsafe(CYGNUM_HAL_INTERRUPT_IRQ12);
}
// ----------------------------------------------------------------------------
static int
PS2Mouse_Open(MOUSEDEVICE* pmd)
{
unsigned char buf[1];
ps2_initialize();
buf[0] = KC_MOUSEC_ENABLE;
ps2_send_command_wait(KC_CONTROL_NULL, buf, 1, 1);
}
// Closing the mouse is equivalent to disabling. It is assumed that we
// are not in the middle of a packet transfer, which could really
// confuse things.
static void
PS2Mouse_Close(void)
{
unsigned char buf[1];
buf[0] = KC_MOUSEC_SET_STANDARD;
ps2_send_command_wait(KC_CONTROL_NULL, buf, 1, 1);
ps2mou_buffer_index = 0;
}
static int
PS2Mouse_GetButtonInfo(void)
{
return MWBUTTON_L | MWBUTTON_R;
}
// The mouse is used in its default setup, which means 1:1 scaling.
// Setting the threshold to 5 seems to match most other drivers...
static void
PS2Mouse_GetDefaultAccel(int* pscale, int* pthresh)
{
if (NULL != pscale) {
*pscale = 1;
}
if (NULL != pthresh) {
*pthresh = 5;
}
}
static int
PS2Mouse_Read(MWCOORD* dx_arg, MWCOORD* dy_arg, MWCOORD* dz_arg, int* bp_arg)
{
int result = 0;
MWCOORD dx = 0;
MWCOORD dy = 0;
int buttons = 0;
cyg_drv_isr_lock();
if (ps2mou_changed) {
dx = ps2mou_dx;
dy = 0 - ps2mou_dy; // microwindows directions are the opposite from the hardware
buttons = ps2mou_buttons;
ps2mou_dx = 0;
ps2mou_dy = 0;
ps2mou_changed = 0;
result = 1;
}
cyg_drv_isr_unlock();
if (result) {
if (NULL != dx_arg) {
*dx_arg = dx;
}
if (NULL != dy_arg) {
*dy_arg = dy;
}
if (NULL != dz_arg) {
*dz_arg = 0;
}
if (NULL != bp_arg) {
*bp_arg = buttons;
}
}
return result;
}
static int
PS2Mouse_Poll(void)
{
return 0 != ps2mou_changed;
}
MOUSEDEVICE mousedev = {
PS2Mouse_Open,
PS2Mouse_Close,
PS2Mouse_GetButtonInfo,
PS2Mouse_GetDefaultAccel,
PS2Mouse_Read,
PS2Mouse_Poll
};
// ----------------------------------------------------------------------------
// Extracting data from the scancode buffer and turning it into
// ASCII. This is only called from thread context by the poll() and
// read() routines, although the scancode buffer is updated in ISR
// context.
// The current keyboard event, if any. This involves processing
// the scancodes held in the circular buffer and translating them
// to ASCII.
static MWKEY ps2kbd_current_key = MWKEY_UNKNOWN;
static MWKEYMOD ps2kbd_current_modifiers = 0;
static MWSCANCODE ps2kbd_current_scancode = 0;
static int ps2kbd_current_keydown = 0;
// Translation between scancodes and characters, i.e. keymaps.
// For now a relatively simple approach is used. The keymaps
// only cope with shifted vs. unshifted. The control key
// is handled specially. Anything cleverer is left to microwindows.
//
// Microwindows excepts key events in the form of MWKEY's, which
// are unsigned shorts. Special keys such as the function keys
// have suitable #define's in mwtypes.h.
//
// There is a complication with PC keyboards in that some keys
// generate multi-byte sequences, usually starting with 0xE0
typedef struct ps2kbd_keymap_entry {
MWKEY normal;
MWKEY shifted;
} ps2kbd_keymap_entry;
// This keymap is for a Dell Inspiron laptop with a Japanese
// keyboard. It may not match exactly with other keyboards,
// but is probably good enough for now.
static const ps2kbd_keymap_entry ps2kbd_keymap[] = {
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // Scancode 0 unused
{ MWKEY_ESCAPE, MWKEY_ESCAPE },
{ '1', '!' },
{ '2', '"' },
{ '3', '#' },
{ '4', '$' },
{ '5', '%' },
{ '6', '&' },
{ '7', '\'' },
{ '8', '(' },
{ '9', ')' }, // Scancode 10
{ '0', '~' },
{ '-', '=' },
{ '^', '_' },
{ MWKEY_BACKSPACE, MWKEY_BACKSPACE },
{ MWKEY_TAB, MWKEY_TAB },
{ 'q', 'Q' }, // 0x10
{ 'w', 'W' },
{ 'e', 'E' },
{ 'r', 'R' },
{ 't', 'T' }, // 20
{ 'y', 'Y' },
{ 'u', 'U' },
{ 'i', 'I' },
{ 'o', 'O' },
{ 'p', 'P' },
{ '@', '`' },
{ '[', '{' },
{ MWKEY_ENTER, MWKEY_ENTER },
{ MWKEY_LCTRL, MWKEY_LCTRL },
{ 'a', 'A' }, // 30
{ 's', 'S' },
{ 'd', 'D' }, // 0x20
{ 'f', 'F' },
{ 'g', 'G' },
{ 'h', 'H' },
{ 'j', 'J' },
{ 'k', 'K' },
{ 'l', 'L' },
{ ';', '+' },
{ ':', '*' }, // 40
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // Japanese-only, top-left below escape
{ MWKEY_LSHIFT, MWKEY_LSHIFT },
{ ']', '}' },
{ 'z', 'Z' },
{ 'x', 'X' },
{ 'c', 'C' },
{ 'v', 'V' },
{ 'b', 'B' }, // 0x30
{ 'n', 'N' },
{ 'm', 'M' }, // 50
{ ',', '<' },
{ '.', '>' },
{ '/', '?' },
{ MWKEY_RSHIFT, MWKEY_RSHIFT },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // unused ?
{ MWKEY_LALT, MWKEY_LALT },
{ ' ', ' ' }, // space bar
{ MWKEY_CAPSLOCK, MWKEY_CAPSLOCK },
{ MWKEY_F1, MWKEY_F1 },
{ MWKEY_F2, MWKEY_F2 }, // 60
{ MWKEY_F3, MWKEY_F3 },
{ MWKEY_F4, MWKEY_F4 },
{ MWKEY_F5, MWKEY_F5 },
{ MWKEY_F6, MWKEY_F6 }, // 0x40
{ MWKEY_F7, MWKEY_F7 },
{ MWKEY_F8, MWKEY_F8 },
{ MWKEY_F9, MWKEY_F9 },
{ MWKEY_F10, MWKEY_F10 },
{ MWKEY_NUMLOCK, MWKEY_NUMLOCK },
{ MWKEY_SCROLLOCK, MWKEY_SCROLLOCK }, // 70
{ MWKEY_KP7, MWKEY_KP7 }, // Keypad, not actually present on laptop
{ MWKEY_KP8, MWKEY_KP8 }, // But accessible via Fn and some centre keys
{ MWKEY_KP9, MWKEY_KP9 },
{ MWKEY_KP_MINUS, MWKEY_KP_MINUS },
{ MWKEY_KP4, MWKEY_KP4 },
{ MWKEY_KP5, MWKEY_KP5 },
{ MWKEY_KP6, MWKEY_KP6 },
{ MWKEY_KP_PLUS, MWKEY_KP_PLUS },
{ MWKEY_KP1, MWKEY_KP1 },
{ MWKEY_KP2, MWKEY_KP2 }, // 80, 0x50
{ MWKEY_KP3, MWKEY_KP3 },
{ MWKEY_KP0, MWKEY_KP0 },
{ MWKEY_KP_PERIOD, MWKEY_KP_PERIOD },
// There are now big gaps
// F11 and F12 are 0x57 and 0x58
// 0x70, 0x79 and 0x7b are Japanese compose keys.
// 0x73 is backslash and another _
// 0x7d is yen and pipe.
// These could be handled by special-case code in the scancode
// translation routine, but at 4 bytes per table entry
// it is probably just as efficient to extend the table.
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 84, 0x53
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_F11, MWKEY_F11 },
{ MWKEY_F12, MWKEY_F12 },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 90
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 0x60
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 100
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 110
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 0x70
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
{ '\\', '_' },
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -