778 lines
33 KiB
C
778 lines
33 KiB
C
// SPDX-License-Identifier: MPL-2.0
|
|
#include "devs/input/ps2.h"
|
|
#include "devs/input/kbd.h"
|
|
#include "irq/irq.h"
|
|
enum ps2_scancode_state {
|
|
PS2_SCANCODE_STATE_NORMAL,
|
|
PS2_SCANCODE_STATE_E0,
|
|
PS2_SCANCODE_STATE_E1
|
|
};
|
|
enum ps2_command_state {
|
|
PS2_COMMAND_STATE_IDLE,
|
|
PS2_COMMAND_STATE_WAIT_ACK,
|
|
PS2_COMMAND_STATE_WAIT_LED_ACK_1,
|
|
PS2_COMMAND_STATE_WAIT_LED_ACK_2,
|
|
PS2_COMMAND_STATE_WAIT_SC_SET_ACK_1,
|
|
PS2_COMMAND_STATE_WAIT_SC_SET_ACK_2,
|
|
PS2_COMMAND_STATE_WAIT_IDENTIFY_ACK,
|
|
PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_1,
|
|
PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_2,
|
|
PS2_COMMAND_STATE_WAIT_ECHO,
|
|
PS2_COMMAND_STATE_WAIT_RESET_ACK,
|
|
PS2_COMMAND_STATE_WAIT_RESET_RESULT
|
|
};
|
|
typedef struct {
|
|
enum ps2_scancode_state scancode_state;
|
|
enum ps2_command_state command_state;
|
|
sh_ps2_KBD_COMMAND current_command;
|
|
sh_uint8 last_byte;
|
|
sh_uint8 e1_bytes_left;
|
|
sh_uint8 e1_bytes_idx;
|
|
sh_uint8 e1_bytes_array[5];
|
|
sh_bool command_in_progress;
|
|
sh_uint8 keyboard_id[2];
|
|
sh_uint8 keyboard_id_len;
|
|
sh_bool scanning_enabled;
|
|
sh_bool shift_state;
|
|
sh_bool l_alt_state;
|
|
sh_bool r_alt_state;
|
|
sh_bool l_ctrl_state;
|
|
sh_bool r_ctrl_state;
|
|
sh_bool win_state;
|
|
sh_bool capslock_state;
|
|
sh_bool numlock_state;
|
|
sh_kbd_DRIVER_HANDLE *d_handle;
|
|
} ps2_state_template;
|
|
ps2_state_template ps2_state;
|
|
static void sh_ps2_send_keyboard_command(sh_uint8 cmd,sh_uint8 data,sh_bool has_data) {
|
|
ps2_state.current_command.command=cmd;
|
|
ps2_state.current_command.data=data;
|
|
ps2_state.current_command.has_data=has_data;
|
|
ps2_state.command_in_progress=SH_TRUE;
|
|
while (sh_ps2_cant_write());
|
|
sh_asm_outb(SH_PS2_PORT_DATA,cmd);
|
|
}
|
|
SH_STATUS sh_ps2_send_keyboard_command_wait(sh_uint8 cmd,sh_uint8 data,sh_bool has_data) {
|
|
sh_ps2_send_keyboard_command(cmd,data,has_data);
|
|
while (ps2_state.command_in_progress) {
|
|
asm volatile("hlt");
|
|
}
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
// Because we don't have a scheduler or kernel threads/worker, we can't properly update these leds for the moment
|
|
__attribute__((__unused__)) static void sh_ps2_update_leds() {
|
|
sh_uint8 led_byte=0;
|
|
if (ps2_state.numlock_state) {
|
|
led_byte|=SH_PS2_KBD_LEDS_NUM_LOCK;
|
|
}
|
|
if (ps2_state.capslock_state) {
|
|
led_byte|=SH_PS2_KBD_LEDS_CAPS_LOCK;
|
|
}
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_LED_ACK_1;
|
|
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_SET_LEDS,led_byte,SH_TRUE);
|
|
return;
|
|
}
|
|
static SH_STATUS sh_ps2_handle_command_response(sh_uint8 data) {
|
|
if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_ACK) {
|
|
if (data==SH_PS2_KBD_ACK) {
|
|
if (ps2_state.current_command.command==SH_PS2_KBD_COMMAND_DISABLE_SCANNING) {
|
|
ps2_state.scanning_enabled=SH_FALSE;
|
|
} else if (ps2_state.current_command.command==SH_PS2_KBD_COMMAND_ENABLE_SCANNING) {
|
|
ps2_state.scanning_enabled=SH_TRUE;
|
|
}
|
|
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
|
|
ps2_state.current_command.command=0;
|
|
ps2_state.current_command.data=0;
|
|
ps2_state.current_command.has_data=SH_FALSE;
|
|
ps2_state.command_in_progress=SH_FALSE;
|
|
return SH_STATUS_SUCCESS;
|
|
} else if (data==SH_PS2_KBD_RESEND) {
|
|
sh_ps2_send_keyboard_command(ps2_state.current_command.command,ps2_state.current_command.data,ps2_state.current_command.has_data);
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_ECHO) {
|
|
if (data==SH_PS2_KBD_COMMAND_ECHO) {
|
|
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
|
|
ps2_state.command_in_progress=SH_FALSE;
|
|
return SH_STATUS_SUCCESS;
|
|
} else {
|
|
sh_iprint(SH_DEBUG,"wrong echo\n");
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_IDENTIFY_ACK) {
|
|
if (data==SH_PS2_KBD_ACK) {
|
|
ps2_state.keyboard_id_len=0;
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_1;
|
|
return SH_STATUS_SUCCESS;
|
|
} else if (data==SH_PS2_KBD_RESEND) {
|
|
sh_ps2_send_keyboard_command(SH_PS2_KBD_COMMAND_IDENTIFY,0,SH_FALSE);
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_IDENTIFY_ACK;
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_1) {
|
|
ps2_state.keyboard_id[0]=data;
|
|
ps2_state.keyboard_id_len=1;
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_2;
|
|
return SH_STATUS_SUCCESS;
|
|
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_IDENTIFY_BYTE_2) {
|
|
ps2_state.keyboard_id[1]=data;
|
|
ps2_state.keyboard_id_len=2;
|
|
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
|
|
ps2_state.command_in_progress=SH_FALSE;
|
|
return SH_STATUS_SUCCESS;
|
|
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_LED_ACK_1) {
|
|
if (data==SH_PS2_KBD_ACK) {
|
|
while (sh_ps2_cant_write());
|
|
sh_asm_outb(SH_PS2_PORT_DATA,ps2_state.current_command.data);
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_LED_ACK_2;
|
|
return SH_STATUS_SUCCESS;
|
|
} else if (data==SH_PS2_KBD_RESEND) {
|
|
sh_ps2_send_keyboard_command(SH_PS2_KBD_COMMAND_SET_LEDS,ps2_state.current_command.data,SH_TRUE);
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_LED_ACK_1;
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_LED_ACK_2) {
|
|
if (data==SH_PS2_KBD_ACK) {
|
|
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
|
|
ps2_state.command_in_progress=SH_FALSE;
|
|
return SH_STATUS_SUCCESS;
|
|
} else if (data==SH_PS2_KBD_RESEND) {
|
|
while (sh_ps2_cant_write());
|
|
sh_asm_outb(SH_PS2_PORT_DATA,ps2_state.current_command.data);
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_RESET_ACK) {
|
|
if (data==SH_PS2_KBD_ACK) {
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_RESET_RESULT;
|
|
return SH_STATUS_SUCCESS;
|
|
} else if (data==SH_PS2_KBD_RESEND) {
|
|
sh_ps2_send_keyboard_command(SH_PS2_KBD_COMMAND_RESET,0,SH_FALSE);
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_RESET_ACK;
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_RESET_RESULT) {
|
|
if (data==0xAA || data==0xFC) {
|
|
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
|
|
ps2_state.command_in_progress=SH_FALSE;
|
|
return SH_STATUS_SUCCESS;
|
|
} else {
|
|
sh_iprintf(SH_DEBUG,"wrong reset\n");
|
|
}
|
|
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_SC_SET_ACK_1) {
|
|
if (data==SH_PS2_KBD_ACK) {
|
|
while (sh_ps2_cant_write());
|
|
sh_asm_outb(SH_PS2_PORT_DATA,ps2_state.current_command.data);
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_SC_SET_ACK_2;
|
|
return SH_STATUS_SUCCESS;
|
|
} else if (data==SH_PS2_KBD_RESEND) {
|
|
sh_ps2_send_keyboard_command(SH_PS2_KBD_COMMAND_SC_SET,ps2_state.current_command.data,SH_TRUE);
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_SC_SET_ACK_1;
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
} else if (ps2_state.command_state==PS2_COMMAND_STATE_WAIT_SC_SET_ACK_2) {
|
|
if (data==SH_PS2_KBD_ACK) {
|
|
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
|
|
ps2_state.command_in_progress=SH_FALSE;
|
|
return SH_STATUS_SUCCESS;
|
|
} else if (data==SH_PS2_KBD_RESEND) {
|
|
while (sh_ps2_cant_write());
|
|
sh_asm_outb(SH_PS2_PORT_DATA,ps2_state.current_command.data);
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
return SH_STATUS_INVALID_STATE;
|
|
}
|
|
static inline sh_bool sh_ps2_shift() {
|
|
return ps2_state.shift_state;
|
|
}
|
|
static inline sh_bool sh_ps2_alt() {
|
|
return ps2_state.l_alt_state || ps2_state.r_alt_state;
|
|
}
|
|
static inline sh_bool sh_ps2_ctrl() {
|
|
return ps2_state.l_ctrl_state || ps2_state.r_ctrl_state;
|
|
}
|
|
static void sh_ps2_handle_scancodes(sh_uint8 data) {
|
|
if (data==0xE0 && ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
|
|
ps2_state.scancode_state=PS2_SCANCODE_STATE_E0;
|
|
return;
|
|
} else if (data==0xE1 && ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
|
|
ps2_state.scancode_state=PS2_SCANCODE_STATE_E1;
|
|
ps2_state.e1_bytes_left=5;
|
|
ps2_state.e1_bytes_idx=0;
|
|
return;
|
|
}
|
|
if (ps2_state.scancode_state!=PS2_SCANCODE_STATE_E1) {
|
|
switch (data) {
|
|
case 0x1D: {
|
|
// ctrl pressed
|
|
if (ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_LCTRL,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.l_ctrl_state=SH_TRUE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_CTRL,sh_ps2_ctrl());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings ctrl flags: status=%8s\n",status);
|
|
}
|
|
return;
|
|
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E0) {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_RCTRL,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.r_ctrl_state=SH_TRUE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_CTRL,sh_ps2_ctrl());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings ctrl flags: status=%8s\n",status);
|
|
}
|
|
ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case 0x9D: {
|
|
// ctrl released
|
|
if (ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_LCTRL,
|
|
.pressed=SH_FALSE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.l_ctrl_state=SH_FALSE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_CTRL,sh_ps2_ctrl());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings ctrl flags: status=%8s\n",status);
|
|
}
|
|
return;
|
|
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E0) {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_RCTRL,
|
|
.pressed=SH_FALSE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.r_ctrl_state=SH_FALSE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_CTRL,sh_ps2_ctrl());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings ctrl flags: status=%8s\n",status);
|
|
}
|
|
ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case 0x36: {
|
|
// right shift pressed
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_RSHIFT,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.shift_state=SH_TRUE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_SHIFT,sh_ps2_shift());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings shift flags: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
case 0x2A: {
|
|
// left shift pressed
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_LSHIFT,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.shift_state=SH_TRUE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_SHIFT,sh_ps2_shift());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings shift flags: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
case 0xAA: {
|
|
// left shift released
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_LSHIFT,
|
|
.pressed=SH_FALSE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.shift_state=SH_FALSE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_SHIFT,sh_ps2_shift());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings shift flags: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
case 0xB6: {
|
|
// right shift released
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_RSHIFT,
|
|
.pressed=SH_FALSE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.shift_state=SH_FALSE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_SHIFT,sh_ps2_shift());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings shift flags: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
case 0x38: {
|
|
// alt pressed
|
|
if (ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_LALT,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.l_alt_state=SH_TRUE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_ALT,sh_ps2_alt());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings alt flags: status=%8s\n",status);
|
|
}
|
|
return;
|
|
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E0) {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_RALT,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.r_alt_state=SH_TRUE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_ALT,sh_ps2_alt());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings alt flags: status=%8s\n",status);
|
|
}
|
|
ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case 0xB8: {
|
|
// alt released
|
|
if (ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_LALT,
|
|
.pressed=SH_FALSE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.l_alt_state=SH_FALSE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_ALT,sh_ps2_alt());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings alt flags: status=%8s\n",status);
|
|
}
|
|
return;
|
|
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E0) {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_RALT,
|
|
.pressed=SH_FALSE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.r_alt_state=SH_FALSE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_ALT,sh_ps2_alt());
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings alt flags: status=%8s\n",status);
|
|
}
|
|
ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
case 0xC5: {
|
|
// numlock released
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_NUMLOCK,
|
|
.pressed=SH_FALSE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.numlock_state=ps2_state.numlock_state?SH_FALSE:SH_TRUE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_VER_NUM,ps2_state.numlock_state);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings numlock flags: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
case 0xBA: {
|
|
// capslock released
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_CAPSLOCK,
|
|
.pressed=SH_FALSE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
ps2_state.capslock_state=ps2_state.capslock_state?SH_FALSE:SH_TRUE;
|
|
status=sh_kbd_set_flag(ps2_state.d_handle,SH_KBD_FLAG_VER_MAJ,ps2_state.capslock_state);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error settings capslock flags: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
case 0x45: {
|
|
// numlock pressed
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_NUMLOCK,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
case 0x3A: {
|
|
// capslock pressed
|
|
sh_kbd_EVENT ev={
|
|
.scancode=SH_KBD_CONTEXT_CAPSLOCK,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_CONTEXT,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ps2_state.scancode_state==PS2_SCANCODE_STATE_NORMAL) {
|
|
if (data & (1u<<7)) {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=0x0000|data,
|
|
.pressed=SH_FALSE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_PS2_NORMAL,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
return;
|
|
} else {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=0x0000|data,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_PS2_NORMAL,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E0) {
|
|
if (data & (1u<<7)) {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=0xE000|data,
|
|
.pressed=SH_FALSE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_PS2_E0,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
return;
|
|
} else {
|
|
sh_kbd_EVENT ev={
|
|
.scancode=0xE000|data,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_PS2_E0,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
} else if (ps2_state.scancode_state==PS2_SCANCODE_STATE_E1) {
|
|
ps2_state.e1_bytes_array[ps2_state.e1_bytes_idx]=data;
|
|
ps2_state.e1_bytes_left--;
|
|
ps2_state.e1_bytes_idx++;
|
|
if (ps2_state.e1_bytes_idx==5 && ps2_state.e1_bytes_left==0) ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
|
|
sh_kbd_EVENT ev={
|
|
.scancode=0,
|
|
.pressed=SH_TRUE,
|
|
.context_shift_win=(ps2_state.win_state<<1)|(sh_ps2_shift()),
|
|
.context_alt=(ps2_state.l_alt_state<<1)|(ps2_state.r_alt_state),
|
|
.context_ctrl=(ps2_state.l_ctrl_state<<1)|(ps2_state.r_ctrl_state),
|
|
.context_lock_status=(ps2_state.capslock_state<<1)|(ps2_state.numlock_state),
|
|
.event_type=SH_EVENT_TYPE_KBD_PAUSE,
|
|
.timestamp=sh_tsc_get_kernel_current_tsc()
|
|
};
|
|
SH_STATUS status=sh_kbd_push_events(ps2_state.d_handle,&ev);
|
|
if (sh_status_error(status)) {
|
|
sh_iprintf(SH_WARNING,"Error pushing events: status=%8s\n",status);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
void sh_ps2_irq1_handler() {
|
|
sh_uint8 data;
|
|
if (!sh_ps2_output_ready()) return;
|
|
data=sh_asm_inb(SH_PS2_PORT_DATA);
|
|
ps2_state.last_byte=data;
|
|
if (ps2_state.command_in_progress) {
|
|
sh_ps2_handle_command_response(data);
|
|
return;
|
|
}
|
|
if (ps2_state.scanning_enabled) {
|
|
sh_ps2_handle_scancodes(data);
|
|
}
|
|
return;
|
|
}
|
|
SH_STATUS sh_ps2_driver_init() {
|
|
sh_asm_cli();
|
|
// flush output buffer
|
|
while (sh_ps2_output_ready()) {
|
|
sh_asm_inb(SH_PS2_PORT_DATA);
|
|
}
|
|
// debug log status and config byte
|
|
sh_printf(SH_DEBUG,"PS2 status byte initial value: 0x%1U\n",sh_ps2_read_status());
|
|
sh_printf(SH_DEBUG,"PS2 config byte initial value: 0x%1U\n",sh_ps2_read_config());
|
|
// disable ps2 ports
|
|
while (sh_ps2_cant_write());
|
|
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_PORT1_DISABLE);
|
|
while (sh_ps2_cant_write());
|
|
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_PORT2_DISABLE);
|
|
// reflush output buffer
|
|
while (sh_ps2_output_ready()) {
|
|
sh_asm_inb(SH_PS2_PORT_DATA);
|
|
}
|
|
// disable IRQs
|
|
sh_uint8 cfg=sh_ps2_read_config();
|
|
cfg&= (sh_uint8)~SH_PS2_CONFIG_PORT1_IRQ;
|
|
cfg&= (sh_uint8)~SH_PS2_CONFIG_PORT2_IRQ;
|
|
sh_ps2_write_config(cfg);
|
|
// ps2 self test
|
|
while (sh_ps2_cant_write());
|
|
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_PS2_SELF_TEST);
|
|
while (!sh_ps2_output_ready());
|
|
sh_uint8 result=sh_asm_inb(SH_PS2_PORT_DATA);
|
|
if (result!=SH_PS2_SELF_TEST_SUCCESS) return SH_STATUS_TEST_FAILED;
|
|
// port1 test
|
|
while (sh_ps2_cant_write());
|
|
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_PORT1_TEST);
|
|
while (!sh_ps2_output_ready());
|
|
result=sh_asm_inb(SH_PS2_PORT_DATA);
|
|
if (result!=SH_PS2_PORTS_SELF_TEST_SUCCESS) return SH_STATUS_TEST_FAILED;
|
|
// enable port1
|
|
while (sh_ps2_cant_write());
|
|
sh_asm_outb(SH_PS2_PORT_COMMAND,SH_PS2_COMMAND_PORT1_ENABLE);
|
|
// enable translation
|
|
cfg=sh_ps2_read_config();
|
|
cfg|=SH_PS2_CONFIG_TRANSLATION;
|
|
sh_ps2_write_config(cfg);
|
|
// initialize ps2_state struct
|
|
ps2_state.scancode_state=PS2_SCANCODE_STATE_NORMAL;
|
|
ps2_state.command_state=PS2_COMMAND_STATE_IDLE;
|
|
ps2_state.current_command.command=0;
|
|
ps2_state.current_command.data=0;
|
|
ps2_state.current_command.has_data=SH_FALSE;
|
|
ps2_state.last_byte=0;
|
|
ps2_state.e1_bytes_left=0;
|
|
ps2_state.command_in_progress=SH_FALSE;
|
|
ps2_state.keyboard_id[0]=0;
|
|
ps2_state.keyboard_id[1]=0;
|
|
ps2_state.keyboard_id_len=0;
|
|
ps2_state.shift_state=SH_FALSE;
|
|
ps2_state.l_alt_state=SH_FALSE;
|
|
ps2_state.r_alt_state=SH_FALSE;
|
|
ps2_state.l_ctrl_state=SH_FALSE;
|
|
ps2_state.r_ctrl_state=SH_FALSE;
|
|
ps2_state.win_state=SH_FALSE;
|
|
ps2_state.capslock_state=SH_FALSE;
|
|
ps2_state.numlock_state=SH_FALSE;
|
|
// enabling IRQ1
|
|
cfg=sh_ps2_read_config();
|
|
cfg|=(sh_uint8)SH_PS2_CONFIG_PORT1_IRQ;
|
|
sh_ps2_write_config(cfg);
|
|
SH_STATUS status=sh_irq_legacy_register_handler(1,&sh_ps2_irq1_handler);
|
|
if (sh_status_error(status)) return status;
|
|
sh_asm_sti();
|
|
// disabling scanning
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_ACK;
|
|
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_DISABLE_SCANNING,0,SH_FALSE);
|
|
// set leds
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_LED_ACK_1;
|
|
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_SET_LEDS,0,SH_TRUE);
|
|
// identify keyboard
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_IDENTIFY_ACK;
|
|
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_IDENTIFY,0,SH_FALSE);
|
|
sh_printf(SH_DEBUG,"PS2 identifier value : 0x%1U 0x%1U\n",ps2_state.keyboard_id[0],ps2_state.keyboard_id[1]);
|
|
// register ps2 keyboard
|
|
status=sh_kbd_register_ps2(SH_TRUE,&ps2_state.d_handle);
|
|
if (sh_status_error(status)) return status;
|
|
// enable scanning
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_ACK;
|
|
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_ENABLE_SCANNING,0,SH_FALSE);
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
SH_STATUS sh_ps2_disable_scanning() {
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_ACK;
|
|
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_DISABLE_SCANNING,0,SH_FALSE);
|
|
return SH_STATUS_SUCCESS;
|
|
}
|
|
SH_STATUS sh_ps2_enable_scanning() {
|
|
ps2_state.command_state=PS2_COMMAND_STATE_WAIT_ACK;
|
|
sh_ps2_send_keyboard_command_wait(SH_PS2_KBD_COMMAND_ENABLE_SCANNING,0,SH_FALSE);
|
|
return SH_STATUS_SUCCESS;
|
|
}
|