📄 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 64static unsigned char ps2kbd_scancode_buffer[PS2KBD_SCANCODE_BUFSIZE];static volatile int ps2kbd_scancode_buffer_head = 0; // new data written herestatic 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 12static 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 voidps2mou_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 + -