⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ps2kbdmou_ecos.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 4 页
字号:
//=============================================================================
//
//      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 + -