📄 ps2kbdmou_ecos.c
字号:
//=============================================================================
//
// ps2kbdmou_ecos.c
//
// eCos support for a PS/2 keyboard and mouse.
//
//=============================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): bartv
// Date: 2002-04-04
// Purpose: Implement basic keyboard and mouse support for microwindows
// only, interacting directly with the hardware.
//
//####DESCRIPTIONEND####
//=============================================================================
#include <pkgconf/system.h>
#include <cyg/infra/cyg_ass.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_io.h>
#include <cyg/hal/hal_intr.h>
#include <cyg/hal/drv_api.h>
#include <cyg/kernel/kapi.h>
#include <microwin/device.h>
#ifdef CYGPKG_KERNEL
# include <cyg/kernel/kapi.h>
#endif
// ----------------------------------------------------------------------------
// Configuration options. For now local to this file.
#define CYGDBG_DEVS_PS2KBDMOUSE_VERBOSE 1
#ifdef CYGDBG_DEVS_PS2KBDMOUSE_VERBOSE
# define DBG(format, args...) diag_printf(format, ## args)
#else
# define DBG(format, args...)
#endif
// ----------------------------------------------------------------------------
// The hardware.
//
// On PC's with PS/2 hardware both the mouse and the keyboard are
// handled through a single keyboard controller chip. There are four
// registers: status, control, input and output. There are also 8-bit
// input and output ports which can be manipulated by writing certain
// control messages. The registers are accessed via the I/O bus.
//
// Output means keyboard controller -> cpu.
// Input means cpu -> keyboard controller.
//
// So you need to do a HAL_READ_UINT() to the output register,
// and a HAL_WRITE_UINT8 to the input register. They are actually
// at the same address...
//
// The following information was extracted from "The Indispensable
// PC Hardware Book" by Messmer, third edition, chapter 34.
#define KC_OUTPUT 0x060
#define KC_INPUT 0x060
#define KC_CONTROL 0x064
#define KC_STATUS 0x064
// Bits in the status register.
#define KC_STATUS_PARE (0x01 << 7)
#define KC_STATUS_TIM (0x01 << 6)
#define KC_STATUS_AUXB (0x01 << 5)
#define KC_STATUS_KEYL (0x01 << 4)
#define KC_STATUS_CD (0x01 << 3)
#define KC_STATUS_SYSF (0x01 << 2)
#define KC_STATUS_INPB (0x01 << 1)
#define KC_STATUS_OUTB (0x01 << 0)
// Commands that can be written to the control register,
// plus for some the results that would come back.
#define KC_CONTROL_NULL -1
#define KC_CONTROL_DISABLE_AUX 0x00A7
#define KC_CONTROL_ENABLE_AUX 0x00A8
#define KC_CONTROL_CHECK_AUX 0x00A9
#define KC_CONTROL_CHECK_AUX_OK 0x000
#define KC_CONTROL_CHECK_AUX_CLOCK_LOW 0x001
#define KC_CONTROL_CHECK_AUX_CLOCK_HIGH 0x002
#define KC_CONTROL_CHECK_AUX_DATA_LOW 0x003
#define KC_CONTROL_CHECK_AUX_DATA_HIGH 0x004
#define KC_CONTROL_CHECK_AUX_NONE 0x0FF
#define KC_CONTROL_SELF_TEST 0x00AA
#define KC_CONTROL_SELF_TEST_OK 0x055
#define KC_CONTROL_CHECK_KBD 0x00AB
#define KC_CONTROL_CHECK_KBD_OK 0x000
#define KC_CONTROL_CHECK_KBD_CLOCK_LOW 0x001
#define KC_CONTROL_CHECK_KBD_CLOCK_HIGH 0x002
#define KC_CONTROL_CHECK_KBD_DATA_LOW 0x003
#define KC_CONTROL_CHECK_KBD_DATA_HIGH 0x004
#define KC_CONTROL_CHECK_KBD_ERROR 0x0FF
#define KC_CONTROL_DISABLE_KBD 0x00AD
#define KC_CONTROL_ENABLE_KBD 0x00AE
#define KC_CONTROL_READ_INPUT_PORT 0x00C0
#define KC_CONTROL_READ_INPUT_PORT_LOW 0x00C1
#define KC_CONTROL_READ_INPUT_PORT_HIGH 0x00C2
#define KC_CONTROL_READ_OUTPUT_PORT 0x00D0
#define KC_CONTROL_WRITE_OUTPUT_PORT 0x00D1
#define KC_CONTROL_WRITE_KBD_OUTPUT 0x00D2
#define KC_CONTROL_WRITE_AUX_OUTPUT 0x00D3
#define KC_CONTROL_WRITE_AUX 0x00D4
#define KC_CONTROL_READ_TEST_INPUT 0x00E0
#define KC_CONTROL_PULSE 0x00F0
// Additional commands, not from the book...
#define KC_CONTROL_READ_MODE 0x0020
#define KC_CONTROL_WRITE_MODE 0x0060
#define KC_MODE_KBD_INT (0x01 << 0)
#define KC_MODE_MOU_INT (0x01 << 1)
#define KC_MODE_SYS (0x01 << 2)
#define KC_MODE_NO_KEYLOCK (0x01 << 3)
#define KC_MODE_DISABLE_KBD (0x01 << 4)
#define KC_MODE_ENABLE_KBD (0x01 << 5)
#define KC_MODE_KCC (0x01 << 6)
#define KC_MODE_RFU (0x01 << 7)
// The input port
#define KC_INPUT_LOCK (0x01 << 7)
#define KC_INPUT_CM (0x01 << 6)
#define KC_INPUT_CM_MONO (0x01 << 6)
#define KC_INPUT_CM_COLOR (0x00 << 6)
#define KC_INPUT_CM_COLOUR (0x00 << 6)
#define KC_INPUT_AUX (0x01 << 1)
#define KC_INPUT_KBD (0x01 << 0)
// And the output port
#define KC_OUTPUT_KBDO (0x01 << 7)
#define KC_OUTPUT_KCLK (0x01 << 6)
#define KC_OUTPUT_AUXB (0x01 << 5)
#define KC_OUTPUT_OUTB (0x01 << 4)
#define KC_OUTPUT_ACLK (0x01 << 3)
#define KC_OUTPUT_AXDO (0x01 << 2)
#define KC_OUTPUT_GA20 (0x01 << 1)
#define KC_OUTPUT_SYSR (0x01 << 0)
// Data from the keyboard
#define KC_KBD_OVERFLOW 0x000
#define KC_KBD_KEY_ERROR 0x0FF
#define KC_KBD_MFII_ID 0x0041AB
#define KC_KBD_BAT_COMPLETE 0x0AA
#define KC_KBD_ECHO 0x0EE
#define KC_KBD_ACK 0x0FA
#define KC_KBD_BAT_ERROR 0x0FC
#define KC_KBD_RESEND 0x0FE
#define KC_KBD_SCANCODE_MIN 0x001
// Likely to be incorrect for some modern keyboards
#define KC_KBD_SCANCODE_MAX 0x058
// Commands that can be sent to the keyboard. These
// are just written to the input register. Some of
// them will be followed by additional data.
#define KC_KBDC_LED_ONOFF 0x0ED
#define KC_KBDC_ECHO 0x0EE
#define KC_KBDC_SETSCAN 0x0F0
#define KC_KBDC_IDENTIFY 0x0F2
#define KC_KBDC_SETREPEAT 0x0F3
#define KC_KBDC_ENABLE 0x0F4
#define KC_KBDC_STANDARD_DISABLE 0x0F5
#define KC_KBDC_STANDARD_ENABLE 0x0F6
#define KC_KBDC_RESEND 0x0FE
#define KC_KBDC_RESET 0x0FF
// And commands that can be sent to the mouse. These
// involve a controller write followed by another
// write to the input register.
#define KC_MOUSEC_RESET_SCALING 0x0E6
#define KC_MOUSEC_SET_SCALING 0x0E7
#define KC_MOUSEC_SET_RESOLUTION 0x0E8
#define KC_MOUSEC_STATUS 0x0E9
#define KC_MOUSEC_SET_STREAM_MODE 0x0EA
#define KC_MOUSEC_READ_DATA 0x0EB
#define KC_MOUSEC_RESET_WRAP_MODE 0x0EC
#define KC_MOUSEC_SET_WRAP_MODE 0x0EE
#define KC_MOUSEC_SET_REMOTE_MODE 0x0F0
#define KC_MOUSEC_IDENTIFY 0x0F2
#define KC_MOUSEC_SET_SAMPLE_RATE 0x0F3
#define KC_MOUSEC_ENABLE 0x0F4
#define KC_MOUSEC_DISABLE 0x0F5
#define KC_MOUSEC_SET_STANDARD 0x0F6
#define KC_MOUSEC_RESEND 0x0FE
#define KC_MOUSEC_RESET 0x0FF
// Data back from the mouse. Some special characters.
#define KC_MOUSE_ACK 0x0FA
#define KC_MOUSE_RESEND 0x0FE
// ----------------------------------------------------------------------------
// The low-level stuff. Managing the PS/2 hardware is actually quite
// messy if you want a robust implementation because of the various
// ack's, resend requests, etc.
// The keyboard device. The interrupt handler is responsible for storing
// key press and release events in a circular buffer. The poll and read code
// will then try to convert these events into something closer to what
// microwindows expects. There is an assumption that the poll() and read()
// code will be called often enough that there is no risk of overflow.
// A circular buffer of scancodes.
#define PS2KBD_SCANCODE_BUFSIZE 64
static unsigned char ps2kbd_scancode_buffer[PS2KBD_SCANCODE_BUFSIZE];
static volatile int ps2kbd_scancode_buffer_head = 0; // new data written here
static volatile int ps2kbd_scancode_buffer_tail = 0; // old data extracted from here
// The current mouse state. Just maintain the current X and Y deltas,
// button state,, and a delta flag. The hardware will generate
// eight-byte mouse data packets, and when a complete packet has been
// received the interrupt handler will update the values and set the
// delta flag.
#define PS2MOU_DATA_BUFSIZE 12
static MWCOORD ps2mou_dx = 0;
static MWCOORD ps2mou_dy = 0;
static int ps2mou_buttons = 0;
static volatile int ps2mou_changed = 0;
static unsigned char ps2mou_buffer[PS2MOU_DATA_BUFSIZE];
static int ps2mou_buffer_index = 0;
// Sending commands. In theory there are a number of variations of
// these.
//
// 1) commands to be sent directly to the controller. The control byte
// goes to KC_CONTROL, and any additional bytes go to KC_INPUT.
// The hardware will either ACK the additional bytes or request
// a resend. Any replies can be read from KC_OUTPUT, and errors
// are possible.
//
// For replies, it is not clear how to distinguish between keyboard
// events that happen at just the wrong moment and the reply data.
//
// 2) commands for the keyboard. These just get written directly to
// the input buffer, one character at a time with ACKs or resends
// in between.
//
// 3) commands for the mouse. These involve a write of 0xD4 to the
// control port followed by a write to the input buffer. The latter
// results in ACKs or resends.
static unsigned char* ps2_command = NULL;
static int ps2_command_mouse = 0;
static int ps2_command_index = 0;
static int ps2_command_length = 0;
static volatile int ps2_command_ack = 0;
static int ps2_command_mouse_waiting_for_ack = 0;
// ----------------------------------------------------------------------------
// Decoding of mouse packets. There are lots of different rodent or
// rodent-like devices out there, all implementing subtly different
// protocols. A general-purpose solution would try to cope with all
// of them. The eCos approach would be to allow just one to be
// configured statically.
// Support for Synaptics touchpads and compatible. This assumes
// default relative format. Byte 0 contains various flags and
// the button state. Byte 1 contains X-offset, byte 2 contains
// the y-offset.
static int ps2mou_packet_size = 3;
static void
ps2mou_synaptics_translate(void)
{
int new_buttons = 0;
int dx, dy;
// The packet consists of six bytes. Bit 3 of the first packet
// should be set. If that condition is not satisfied then we
// are in trouble and we may need to perform some sort of reset.
if (0 == (ps2mou_buffer[0] & 0x08)) {
// FIXME: perform some sort of reset to get the world
// back in sync.
return;
}
// Byte 0 holds the button flags.
if (0 != (ps2mou_buffer[0] & (0x01 << 0))) {
new_buttons = MWBUTTON_L;
}
if (0 != (ps2mou_buffer[0] & (0x01 << 1))) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -