📄 ps2kbdmou_ecos.c
字号:
new_buttons |= MWBUTTON_R;
}
ps2mou_buttons = new_buttons;
dx = ps2mou_buffer[1];
if (0 != (ps2mou_buffer[0] & (0x001 << 4))) {
// Negative number.
if (0 != (ps2mou_buffer[0] & (0x01 << 6))) {
// -ve overflow
dx = -256;
} else {
dx = 0 - (256 - dx);
}
} else if (0 != (ps2mou_buffer[0] & (0x01 << 6))) {
// +ve overflow
dx = 256;
}
ps2mou_dx += dx;
dy = ps2mou_buffer[2];
if (0 != (ps2mou_buffer[0] & (0x01 << 5))) {
// Negative number.
if (0 != (ps2mou_buffer[0] & (0x01 << 7))) {
// -ve overflow
dy = -256;
} else {
// -ve signed, bottom byte only
dy = 0 - (256 - dy);
}
} else if (0 != (ps2mou_buffer[0] & (0x01 << 7))) {
// +ve overflow
dy = 256;
}
ps2mou_dy += dy;
ps2mou_changed = 1;
}
// Mouse data. A PS/2 mouse sends events in the form of
// eight-byte packets. Some of the fields are officially
// reserved and ignored for now.
#define KC_MOUSE_DATA_FLAGS 0x00
#define KC_MOUSE_DATA_FLAGS_YOV (0x01 << 7)
#define KC_MOUSE_DATA_FLAGS_XOV (0x01 << 6)
#define KC_MOUSE_DATA_FLAGS_YNG (0x01 << 5)
#define KC_MOUSE_DATA_FLAGS_XNG (0x01 << 4)
#define KC_MOUSE_DATA_FLAGS_RIG (0x01 << 1)
#define KC_MOUSE_DATA_FLAGS_LEF (0x01 << 0)
#define KC_MOUSE_DATA_X 0x02
#define KC_MOUSE_DATA_Y 0x04
#define KC_MOUSE_DATA_SIZE 0x08
// ----------------------------------------------------------------------------
// An interrupt has occurred. Usually this means that there is data
// in the output register, although errors are possible as well. The
// data can be keyboard scancodes, parts of a mouse packet, or
// replies to control messages.
//
// For now errors are ignored, including parity and timeout errors. In
// theory these are supposed to be handled by requesting a resend. In
// practice that seems to cause as many complications as it might
// solve. For example what should happen if there is already a command
// being sent?
//
// The controller interrupts at two separate vectors, one for keyboard
// and another for mouse. If nested interrupts are enabled this could
// cause problems with nested calls to ps2_isr() updating the global
// data in the wrong order. It may be necessary to have a volatile flag
// to detect nesting, accompanied by an early acknowledge and return to
// the interrupted interrupt handler.
static cyg_uint32
ps2_isr(cyg_vector_t isr_vector, cyg_addrword_t isr_data)
{
int status;
unsigned char data;
CYG_UNUSED_PARAM(cyg_addrword_t, isr_data);
HAL_READ_UINT8(KC_STATUS, status);
while (status & KC_STATUS_OUTB) {
HAL_READ_UINT8(KC_OUTPUT, data);
if (status & KC_STATUS_AUXB) {
// Data from the mouse. This will be either an ACK for a
// command, a resend request, or a byte for the current
// packet. When a complete 8-byte packet has been received
// it can be processed. When an ACK is received the next
// byte for the current command should get sent, or on
// completion the sending code can be woken up.
//
// The mouse can also send back other data, e.g. in response
// to a determine-status request. These are disallowed
// because there is no obvious way of separating out such
// data from a current mouse packet being transferred.
//
// There may also be special bytes sent for disconnect and
// reconnect. It is not clear how to distinguish those
// from packet data either.
if (ps2_command_mouse_waiting_for_ack && ((KC_MOUSE_ACK == data) || (KC_MOUSE_RESEND == data))) {
int tmp;
if (KC_MOUSE_ACK == data) {
// Is there another byte to be sent?
ps2_command_index++;
if (ps2_command_index < ps2_command_length) {
// Send the next byte for the current command
do {
HAL_READ_UINT8(KC_STATUS, tmp);
} while (tmp & KC_STATUS_INPB);
HAL_WRITE_UINT8(KC_CONTROL, KC_CONTROL_WRITE_AUX);
do {
HAL_READ_UINT8(KC_STATUS, tmp);
} while (tmp & KC_STATUS_INPB);
HAL_WRITE_UINT8(KC_INPUT, ps2_command[ps2_command_index]);
} else {
// The whole command has been sent and acknowledged.
// Allow the polling thread to resume.
ps2_command_index = 0;
ps2_command_length = 0;
ps2_command = NULL;
ps2_command_ack = 1;
ps2_command_mouse_waiting_for_ack = 0;
}
} else {
// A resend request for the current byte.
do {
HAL_READ_UINT8(KC_STATUS, tmp);
} while (tmp & KC_STATUS_INPB);
HAL_WRITE_UINT8(KC_CONTROL, KC_CONTROL_WRITE_AUX);
do {
HAL_READ_UINT8(KC_STATUS, tmp);
} while (tmp & KC_STATUS_INPB);
HAL_WRITE_UINT8(KC_INPUT, ps2_command[ps2_command_index]);
}
} else {
ps2mou_buffer[ps2mou_buffer_index++] = data;
if (ps2mou_packet_size == ps2mou_buffer_index) {
// A complete packet has been received.
ps2mou_synaptics_translate();
ps2mou_buffer_index = 0; // Ready for the next packet
}
}
} else {
// Data from the keyboard. Usually this will be a scancode.
// There are a number of other possibilities such as
// echo replies, resend requests, and acks.
if ((KC_KBD_ACK == data) && (NULL != ps2_command) && !ps2_command_mouse_waiting_for_ack) {
// Send the next byte for the current command, or
// else we have completed.
ps2_command_index++;
if (ps2_command_index < ps2_command_length) {
int tmp;
do {
HAL_READ_UINT8(KC_STATUS, tmp);
} while (tmp & KC_STATUS_INPB);
HAL_WRITE_UINT8(KC_INPUT, ps2_command[ps2_command_index]);
} else {
ps2_command_index = 0;
ps2_command_length = 0;
ps2_command = NULL;
ps2_command_ack = 1;
}
} else if ((KC_KBD_RESEND == data) && (NULL != ps2_command) && !ps2_command_mouse_waiting_for_ack) {
int tmp;
do {
HAL_READ_UINT8(KC_STATUS, tmp);
} while (tmp & KC_STATUS_INPB);
HAL_WRITE_UINT8(KC_INPUT, ps2_command[ps2_command_index]);
} else {
if (((ps2kbd_scancode_buffer_head + 1) % PS2KBD_SCANCODE_BUFSIZE) == ps2kbd_scancode_buffer_tail) {
// Already full. The data has to be discarded.
} else {
ps2kbd_scancode_buffer[ps2kbd_scancode_buffer_head] = data;
ps2kbd_scancode_buffer_head = (ps2kbd_scancode_buffer_head + 1) % PS2KBD_SCANCODE_BUFSIZE;
}
}
}
// Just in case the keyboard controller is fast enough to send another byte,
// go around again.
HAL_READ_UINT8(KC_STATUS, status);
}
// The interrupt has been fully handled. For now there is no point
// in running a DSR.
cyg_drv_interrupt_acknowledge(isr_vector);
return CYG_ISR_HANDLED;
}
// For now the DSR does nothing.
static void
ps2_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
CYG_UNUSED_PARAM(cyg_vector_t, vector);
CYG_UNUSED_PARAM(cyg_ucount32, count);
CYG_UNUSED_PARAM(cyg_addrword_t, data);
}
// Sending out a command. The controller command, if any, gets sent here.
// This is followed by the first byte for the keyboard or mouse. The
// remaining bytes and any retransmits will be handled by the interrupt
// handler.
static void
ps2_send_command(int controller_command, unsigned char* command, int length, int mouse)
{
int status;
CYG_PRECONDITION(NULL == ps2_command, "Only one send command is allowed at a time");
CYG_PRECONDITION((KC_CONTROL_NULL != controller_command) || (NULL != command), "no-op");
CYG_PRECONDITION(!mouse || (KC_CONTROL_NULL == controller_command), "cannot combine controller and mouse commands");
ps2_command = command;
ps2_command_index = 0;
ps2_command_length = length;
ps2_command_mouse = 0;
ps2_command_ack = 0;
if (KC_CONTROL_NULL != controller_command) {
do {
HAL_READ_UINT8(KC_STATUS, status);
} while (status & KC_STATUS_INPB);
HAL_WRITE_UINT8(KC_CONTROL, controller_command);
}
if (length > 0) {
if (mouse) {
do {
HAL_READ_UINT8(KC_STATUS, status);
} while (status & KC_STATUS_INPB);
HAL_WRITE_UINT8(KC_CONTROL, KC_CONTROL_WRITE_AUX);
}
do {
HAL_READ_UINT8(KC_STATUS, status);
} while (status & KC_STATUS_INPB);
HAL_WRITE_UINT8(KC_INPUT, command[0]);
}
}
// For now there is little difference between polled and non-polled
// mode, they both just spin until the ACK byte is received. The
// polled version just calls the interrupt handler as well. This is
// probably acceptable for now because commands only get sent during
// initialization, but eventually the non-polled version should be
// using a synch primitive signalled by the dsr.
//
// ACKs are only generated when there is data to be sent, not for
// operations on the control register.
//
// For keyboard commands there is no real problem because the ACK
// character 0xFA does not match a valid scancode. For the mouse
// things are more difficult because 0xFA could be present in the
// data, e.g. as a fairly large movement. Therefore the interrupt
// handler needs to know whether or not a mouse ACK is expected.
// It is assumed that the ACK and any actual 0xFA data get sent
// within a byte of each other so that the 0xFA still ends up in
// the right place in the buffer.
//
// A couple of commands do not result in an ACK. For the mouse this
// includes reset-wrap-mode and reset. For the keyboard this includes
// echo. These commands are not currently used, so there is no need
// to worry about the special cases.
static void
ps2_send_command_poll(int controller_command, unsigned char* command, int length, int mouse)
{
if ((NULL != command) && mouse) {
ps2_command_mouse_waiting_for_ack = 1;
}
ps2_send_command(controller_command, command, length, mouse);
if (NULL != command) {
for ( ; !ps2_command_ack; ) {
ps2_isr( CYGNUM_HAL_INTERRUPT_KEYBOARD, 0);
}
ps2_command_ack = 0;
}
}
static void
ps2_send_command_wait(int controller_command, unsigned char* command, int length, int mouse)
{
if ((NULL != command) && mouse) {
ps2_command_mouse_waiting_for_ack = 1;
}
ps2_send_command(controller_command, command, length, mouse);
if (NULL != command) {
for ( ; !ps2_command_ack; )
;
ps2_command_ack = 0;
}
}
// ----------------------------------------------------------------------------
// Hardware initialization and the interrupt handling.
static cyg_handle_t ps2kbd_interrupt_handle;
static cyg_interrupt ps2kbd_interrupt_data;
static cyg_handle_t ps2mouse_interrupt_handle;
static cyg_interrupt ps2mouse_interrupt_data;
static void
ps2_initialize(void)
{
unsigned char buf[2];
int status, data;
// Only perform initialization once, not for both kbd and mouse.
static int initialized = 0;
if (initialized) {
return;
}
initialized++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -