1 |
27 |
unneback |
//=============================================================================
|
2 |
|
|
//
|
3 |
|
|
// ps2kbdmou_ecos.c
|
4 |
|
|
//
|
5 |
|
|
// eCos support for a PS/2 keyboard and mouse.
|
6 |
|
|
//
|
7 |
|
|
//=============================================================================
|
8 |
|
|
//####ECOSGPLCOPYRIGHTBEGIN####
|
9 |
|
|
// -------------------------------------------
|
10 |
|
|
// This file is part of eCos, the Embedded Configurable Operating System.
|
11 |
|
|
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
|
12 |
|
|
//
|
13 |
|
|
// eCos is free software; you can redistribute it and/or modify it under
|
14 |
|
|
// the terms of the GNU General Public License as published by the Free
|
15 |
|
|
// Software Foundation; either version 2 or (at your option) any later version.
|
16 |
|
|
//
|
17 |
|
|
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
|
18 |
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19 |
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
20 |
|
|
// for more details.
|
21 |
|
|
//
|
22 |
|
|
// You should have received a copy of the GNU General Public License along
|
23 |
|
|
// with eCos; if not, write to the Free Software Foundation, Inc.,
|
24 |
|
|
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
25 |
|
|
//
|
26 |
|
|
// As a special exception, if other files instantiate templates or use macros
|
27 |
|
|
// or inline functions from this file, or you compile this file and link it
|
28 |
|
|
// with other works to produce a work based on this file, this file does not
|
29 |
|
|
// by itself cause the resulting work to be covered by the GNU General Public
|
30 |
|
|
// License. However the source code for this file must still be made available
|
31 |
|
|
// in accordance with section (3) of the GNU General Public License.
|
32 |
|
|
//
|
33 |
|
|
// This exception does not invalidate any other reasons why a work based on
|
34 |
|
|
// this file might be covered by the GNU General Public License.
|
35 |
|
|
//
|
36 |
|
|
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
|
37 |
|
|
// at http://sources.redhat.com/ecos/ecos-license/
|
38 |
|
|
// -------------------------------------------
|
39 |
|
|
//####ECOSGPLCOPYRIGHTEND####
|
40 |
|
|
//=============================================================================
|
41 |
|
|
//#####DESCRIPTIONBEGIN####
|
42 |
|
|
//
|
43 |
|
|
// Author(s): bartv
|
44 |
|
|
// Date: 2002-04-04
|
45 |
|
|
// Purpose: Implement basic keyboard and mouse support for microwindows
|
46 |
|
|
// only, interacting directly with the hardware.
|
47 |
|
|
//
|
48 |
|
|
//####DESCRIPTIONEND####
|
49 |
|
|
//=============================================================================
|
50 |
|
|
|
51 |
|
|
#include <pkgconf/system.h>
|
52 |
|
|
#include <cyg/infra/cyg_ass.h>
|
53 |
|
|
#include <cyg/infra/diag.h>
|
54 |
|
|
#include <cyg/hal/hal_io.h>
|
55 |
|
|
#include <cyg/hal/hal_intr.h>
|
56 |
|
|
#include <cyg/hal/drv_api.h>
|
57 |
|
|
#include <cyg/kernel/kapi.h>
|
58 |
|
|
#include <microwin/device.h>
|
59 |
|
|
|
60 |
|
|
#ifdef CYGPKG_KERNEL
|
61 |
|
|
# include <cyg/kernel/kapi.h>
|
62 |
|
|
#endif
|
63 |
|
|
|
64 |
|
|
// ----------------------------------------------------------------------------
|
65 |
|
|
// Configuration options. For now local to this file.
|
66 |
|
|
#define CYGDBG_DEVS_PS2KBDMOUSE_VERBOSE 1
|
67 |
|
|
|
68 |
|
|
#ifdef CYGDBG_DEVS_PS2KBDMOUSE_VERBOSE
|
69 |
|
|
# define DBG(format, args...) diag_printf(format, ## args)
|
70 |
|
|
#else
|
71 |
|
|
# define DBG(format, args...)
|
72 |
|
|
#endif
|
73 |
|
|
|
74 |
|
|
// ----------------------------------------------------------------------------
|
75 |
|
|
// The hardware.
|
76 |
|
|
//
|
77 |
|
|
// On PC's with PS/2 hardware both the mouse and the keyboard are
|
78 |
|
|
// handled through a single keyboard controller chip. There are four
|
79 |
|
|
// registers: status, control, input and output. There are also 8-bit
|
80 |
|
|
// input and output ports which can be manipulated by writing certain
|
81 |
|
|
// control messages. The registers are accessed via the I/O bus.
|
82 |
|
|
//
|
83 |
|
|
// Output means keyboard controller -> cpu.
|
84 |
|
|
// Input means cpu -> keyboard controller.
|
85 |
|
|
//
|
86 |
|
|
// So you need to do a HAL_READ_UINT() to the output register,
|
87 |
|
|
// and a HAL_WRITE_UINT8 to the input register. They are actually
|
88 |
|
|
// at the same address...
|
89 |
|
|
//
|
90 |
|
|
// The following information was extracted from "The Indispensable
|
91 |
|
|
// PC Hardware Book" by Messmer, third edition, chapter 34.
|
92 |
|
|
|
93 |
|
|
#define KC_OUTPUT 0x060
|
94 |
|
|
#define KC_INPUT 0x060
|
95 |
|
|
#define KC_CONTROL 0x064
|
96 |
|
|
#define KC_STATUS 0x064
|
97 |
|
|
|
98 |
|
|
// Bits in the status register.
|
99 |
|
|
#define KC_STATUS_PARE (0x01 << 7)
|
100 |
|
|
#define KC_STATUS_TIM (0x01 << 6)
|
101 |
|
|
#define KC_STATUS_AUXB (0x01 << 5)
|
102 |
|
|
#define KC_STATUS_KEYL (0x01 << 4)
|
103 |
|
|
#define KC_STATUS_CD (0x01 << 3)
|
104 |
|
|
#define KC_STATUS_SYSF (0x01 << 2)
|
105 |
|
|
#define KC_STATUS_INPB (0x01 << 1)
|
106 |
|
|
#define KC_STATUS_OUTB (0x01 << 0)
|
107 |
|
|
|
108 |
|
|
// Commands that can be written to the control register,
|
109 |
|
|
// plus for some the results that would come back.
|
110 |
|
|
#define KC_CONTROL_NULL -1
|
111 |
|
|
#define KC_CONTROL_DISABLE_AUX 0x00A7
|
112 |
|
|
#define KC_CONTROL_ENABLE_AUX 0x00A8
|
113 |
|
|
#define KC_CONTROL_CHECK_AUX 0x00A9
|
114 |
|
|
#define KC_CONTROL_CHECK_AUX_OK 0x000
|
115 |
|
|
#define KC_CONTROL_CHECK_AUX_CLOCK_LOW 0x001
|
116 |
|
|
#define KC_CONTROL_CHECK_AUX_CLOCK_HIGH 0x002
|
117 |
|
|
#define KC_CONTROL_CHECK_AUX_DATA_LOW 0x003
|
118 |
|
|
#define KC_CONTROL_CHECK_AUX_DATA_HIGH 0x004
|
119 |
|
|
#define KC_CONTROL_CHECK_AUX_NONE 0x0FF
|
120 |
|
|
#define KC_CONTROL_SELF_TEST 0x00AA
|
121 |
|
|
#define KC_CONTROL_SELF_TEST_OK 0x055
|
122 |
|
|
#define KC_CONTROL_CHECK_KBD 0x00AB
|
123 |
|
|
#define KC_CONTROL_CHECK_KBD_OK 0x000
|
124 |
|
|
#define KC_CONTROL_CHECK_KBD_CLOCK_LOW 0x001
|
125 |
|
|
#define KC_CONTROL_CHECK_KBD_CLOCK_HIGH 0x002
|
126 |
|
|
#define KC_CONTROL_CHECK_KBD_DATA_LOW 0x003
|
127 |
|
|
#define KC_CONTROL_CHECK_KBD_DATA_HIGH 0x004
|
128 |
|
|
#define KC_CONTROL_CHECK_KBD_ERROR 0x0FF
|
129 |
|
|
#define KC_CONTROL_DISABLE_KBD 0x00AD
|
130 |
|
|
#define KC_CONTROL_ENABLE_KBD 0x00AE
|
131 |
|
|
#define KC_CONTROL_READ_INPUT_PORT 0x00C0
|
132 |
|
|
#define KC_CONTROL_READ_INPUT_PORT_LOW 0x00C1
|
133 |
|
|
#define KC_CONTROL_READ_INPUT_PORT_HIGH 0x00C2
|
134 |
|
|
#define KC_CONTROL_READ_OUTPUT_PORT 0x00D0
|
135 |
|
|
#define KC_CONTROL_WRITE_OUTPUT_PORT 0x00D1
|
136 |
|
|
#define KC_CONTROL_WRITE_KBD_OUTPUT 0x00D2
|
137 |
|
|
#define KC_CONTROL_WRITE_AUX_OUTPUT 0x00D3
|
138 |
|
|
#define KC_CONTROL_WRITE_AUX 0x00D4
|
139 |
|
|
#define KC_CONTROL_READ_TEST_INPUT 0x00E0
|
140 |
|
|
#define KC_CONTROL_PULSE 0x00F0
|
141 |
|
|
|
142 |
|
|
// Additional commands, not from the book...
|
143 |
|
|
#define KC_CONTROL_READ_MODE 0x0020
|
144 |
|
|
#define KC_CONTROL_WRITE_MODE 0x0060
|
145 |
|
|
#define KC_MODE_KBD_INT (0x01 << 0)
|
146 |
|
|
#define KC_MODE_MOU_INT (0x01 << 1)
|
147 |
|
|
#define KC_MODE_SYS (0x01 << 2)
|
148 |
|
|
#define KC_MODE_NO_KEYLOCK (0x01 << 3)
|
149 |
|
|
#define KC_MODE_DISABLE_KBD (0x01 << 4)
|
150 |
|
|
#define KC_MODE_ENABLE_KBD (0x01 << 5)
|
151 |
|
|
#define KC_MODE_KCC (0x01 << 6)
|
152 |
|
|
#define KC_MODE_RFU (0x01 << 7)
|
153 |
|
|
|
154 |
|
|
// The input port
|
155 |
|
|
#define KC_INPUT_LOCK (0x01 << 7)
|
156 |
|
|
#define KC_INPUT_CM (0x01 << 6)
|
157 |
|
|
#define KC_INPUT_CM_MONO (0x01 << 6)
|
158 |
|
|
#define KC_INPUT_CM_COLOR (0x00 << 6)
|
159 |
|
|
#define KC_INPUT_CM_COLOUR (0x00 << 6)
|
160 |
|
|
#define KC_INPUT_AUX (0x01 << 1)
|
161 |
|
|
#define KC_INPUT_KBD (0x01 << 0)
|
162 |
|
|
|
163 |
|
|
// And the output port
|
164 |
|
|
#define KC_OUTPUT_KBDO (0x01 << 7)
|
165 |
|
|
#define KC_OUTPUT_KCLK (0x01 << 6)
|
166 |
|
|
#define KC_OUTPUT_AUXB (0x01 << 5)
|
167 |
|
|
#define KC_OUTPUT_OUTB (0x01 << 4)
|
168 |
|
|
#define KC_OUTPUT_ACLK (0x01 << 3)
|
169 |
|
|
#define KC_OUTPUT_AXDO (0x01 << 2)
|
170 |
|
|
#define KC_OUTPUT_GA20 (0x01 << 1)
|
171 |
|
|
#define KC_OUTPUT_SYSR (0x01 << 0)
|
172 |
|
|
|
173 |
|
|
// Data from the keyboard
|
174 |
|
|
#define KC_KBD_OVERFLOW 0x000
|
175 |
|
|
#define KC_KBD_KEY_ERROR 0x0FF
|
176 |
|
|
#define KC_KBD_MFII_ID 0x0041AB
|
177 |
|
|
#define KC_KBD_BAT_COMPLETE 0x0AA
|
178 |
|
|
#define KC_KBD_ECHO 0x0EE
|
179 |
|
|
#define KC_KBD_ACK 0x0FA
|
180 |
|
|
#define KC_KBD_BAT_ERROR 0x0FC
|
181 |
|
|
#define KC_KBD_RESEND 0x0FE
|
182 |
|
|
#define KC_KBD_SCANCODE_MIN 0x001
|
183 |
|
|
// Likely to be incorrect for some modern keyboards
|
184 |
|
|
#define KC_KBD_SCANCODE_MAX 0x058
|
185 |
|
|
|
186 |
|
|
// Commands that can be sent to the keyboard. These
|
187 |
|
|
// are just written to the input register. Some of
|
188 |
|
|
// them will be followed by additional data.
|
189 |
|
|
#define KC_KBDC_LED_ONOFF 0x0ED
|
190 |
|
|
#define KC_KBDC_ECHO 0x0EE
|
191 |
|
|
#define KC_KBDC_SETSCAN 0x0F0
|
192 |
|
|
#define KC_KBDC_IDENTIFY 0x0F2
|
193 |
|
|
#define KC_KBDC_SETREPEAT 0x0F3
|
194 |
|
|
#define KC_KBDC_ENABLE 0x0F4
|
195 |
|
|
#define KC_KBDC_STANDARD_DISABLE 0x0F5
|
196 |
|
|
#define KC_KBDC_STANDARD_ENABLE 0x0F6
|
197 |
|
|
#define KC_KBDC_RESEND 0x0FE
|
198 |
|
|
#define KC_KBDC_RESET 0x0FF
|
199 |
|
|
|
200 |
|
|
// And commands that can be sent to the mouse. These
|
201 |
|
|
// involve a controller write followed by another
|
202 |
|
|
// write to the input register.
|
203 |
|
|
#define KC_MOUSEC_RESET_SCALING 0x0E6
|
204 |
|
|
#define KC_MOUSEC_SET_SCALING 0x0E7
|
205 |
|
|
#define KC_MOUSEC_SET_RESOLUTION 0x0E8
|
206 |
|
|
#define KC_MOUSEC_STATUS 0x0E9
|
207 |
|
|
#define KC_MOUSEC_SET_STREAM_MODE 0x0EA
|
208 |
|
|
#define KC_MOUSEC_READ_DATA 0x0EB
|
209 |
|
|
#define KC_MOUSEC_RESET_WRAP_MODE 0x0EC
|
210 |
|
|
#define KC_MOUSEC_SET_WRAP_MODE 0x0EE
|
211 |
|
|
#define KC_MOUSEC_SET_REMOTE_MODE 0x0F0
|
212 |
|
|
#define KC_MOUSEC_IDENTIFY 0x0F2
|
213 |
|
|
#define KC_MOUSEC_SET_SAMPLE_RATE 0x0F3
|
214 |
|
|
#define KC_MOUSEC_ENABLE 0x0F4
|
215 |
|
|
#define KC_MOUSEC_DISABLE 0x0F5
|
216 |
|
|
#define KC_MOUSEC_SET_STANDARD 0x0F6
|
217 |
|
|
#define KC_MOUSEC_RESEND 0x0FE
|
218 |
|
|
#define KC_MOUSEC_RESET 0x0FF
|
219 |
|
|
|
220 |
|
|
// Data back from the mouse. Some special characters.
|
221 |
|
|
#define KC_MOUSE_ACK 0x0FA
|
222 |
|
|
#define KC_MOUSE_RESEND 0x0FE
|
223 |
|
|
|
224 |
|
|
// ----------------------------------------------------------------------------
|
225 |
|
|
// The low-level stuff. Managing the PS/2 hardware is actually quite
|
226 |
|
|
// messy if you want a robust implementation because of the various
|
227 |
|
|
// ack's, resend requests, etc.
|
228 |
|
|
|
229 |
|
|
// The keyboard device. The interrupt handler is responsible for storing
|
230 |
|
|
// key press and release events in a circular buffer. The poll and read code
|
231 |
|
|
// will then try to convert these events into something closer to what
|
232 |
|
|
// microwindows expects. There is an assumption that the poll() and read()
|
233 |
|
|
// code will be called often enough that there is no risk of overflow.
|
234 |
|
|
|
235 |
|
|
// A circular buffer of scancodes.
|
236 |
|
|
#define PS2KBD_SCANCODE_BUFSIZE 64
|
237 |
|
|
static unsigned char ps2kbd_scancode_buffer[PS2KBD_SCANCODE_BUFSIZE];
|
238 |
|
|
static volatile int ps2kbd_scancode_buffer_head = 0; // new data written here
|
239 |
|
|
static volatile int ps2kbd_scancode_buffer_tail = 0; // old data extracted from here
|
240 |
|
|
|
241 |
|
|
// The current mouse state. Just maintain the current X and Y deltas,
|
242 |
|
|
// button state,, and a delta flag. The hardware will generate
|
243 |
|
|
// eight-byte mouse data packets, and when a complete packet has been
|
244 |
|
|
// received the interrupt handler will update the values and set the
|
245 |
|
|
// delta flag.
|
246 |
|
|
|
247 |
|
|
#define PS2MOU_DATA_BUFSIZE 12
|
248 |
|
|
static MWCOORD ps2mou_dx = 0;
|
249 |
|
|
static MWCOORD ps2mou_dy = 0;
|
250 |
|
|
static int ps2mou_buttons = 0;
|
251 |
|
|
static volatile int ps2mou_changed = 0;
|
252 |
|
|
|
253 |
|
|
static unsigned char ps2mou_buffer[PS2MOU_DATA_BUFSIZE];
|
254 |
|
|
static int ps2mou_buffer_index = 0;
|
255 |
|
|
|
256 |
|
|
// Sending commands. In theory there are a number of variations of
|
257 |
|
|
// these.
|
258 |
|
|
//
|
259 |
|
|
// 1) commands to be sent directly to the controller. The control byte
|
260 |
|
|
// goes to KC_CONTROL, and any additional bytes go to KC_INPUT.
|
261 |
|
|
// The hardware will either ACK the additional bytes or request
|
262 |
|
|
// a resend. Any replies can be read from KC_OUTPUT, and errors
|
263 |
|
|
// are possible.
|
264 |
|
|
//
|
265 |
|
|
// For replies, it is not clear how to distinguish between keyboard
|
266 |
|
|
// events that happen at just the wrong moment and the reply data.
|
267 |
|
|
//
|
268 |
|
|
// 2) commands for the keyboard. These just get written directly to
|
269 |
|
|
// the input buffer, one character at a time with ACKs or resends
|
270 |
|
|
// in between.
|
271 |
|
|
//
|
272 |
|
|
// 3) commands for the mouse. These involve a write of 0xD4 to the
|
273 |
|
|
// control port followed by a write to the input buffer. The latter
|
274 |
|
|
// results in ACKs or resends.
|
275 |
|
|
|
276 |
|
|
static unsigned char* ps2_command = NULL;
|
277 |
|
|
static int ps2_command_mouse = 0;
|
278 |
|
|
static int ps2_command_index = 0;
|
279 |
|
|
static int ps2_command_length = 0;
|
280 |
|
|
static volatile int ps2_command_ack = 0;
|
281 |
|
|
static int ps2_command_mouse_waiting_for_ack = 0;
|
282 |
|
|
|
283 |
|
|
// ----------------------------------------------------------------------------
|
284 |
|
|
// Decoding of mouse packets. There are lots of different rodent or
|
285 |
|
|
// rodent-like devices out there, all implementing subtly different
|
286 |
|
|
// protocols. A general-purpose solution would try to cope with all
|
287 |
|
|
// of them. The eCos approach would be to allow just one to be
|
288 |
|
|
// configured statically.
|
289 |
|
|
|
290 |
|
|
// Support for Synaptics touchpads and compatible. This assumes
|
291 |
|
|
// default relative format. Byte 0 contains various flags and
|
292 |
|
|
// the button state. Byte 1 contains X-offset, byte 2 contains
|
293 |
|
|
// the y-offset.
|
294 |
|
|
|
295 |
|
|
static int ps2mou_packet_size = 3;
|
296 |
|
|
static void
|
297 |
|
|
ps2mou_synaptics_translate(void)
|
298 |
|
|
{
|
299 |
|
|
int new_buttons = 0;
|
300 |
|
|
int dx, dy;
|
301 |
|
|
|
302 |
|
|
// The packet consists of six bytes. Bit 3 of the first packet
|
303 |
|
|
// should be set. If that condition is not satisfied then we
|
304 |
|
|
// are in trouble and we may need to perform some sort of reset.
|
305 |
|
|
if (0 == (ps2mou_buffer[0] & 0x08)) {
|
306 |
|
|
// FIXME: perform some sort of reset to get the world
|
307 |
|
|
// back in sync.
|
308 |
|
|
return;
|
309 |
|
|
}
|
310 |
|
|
// Byte 0 holds the button flags.
|
311 |
|
|
if (0 != (ps2mou_buffer[0] & (0x01 << 0))) {
|
312 |
|
|
new_buttons = MWBUTTON_L;
|
313 |
|
|
}
|
314 |
|
|
if (0 != (ps2mou_buffer[0] & (0x01 << 1))) {
|
315 |
|
|
new_buttons |= MWBUTTON_R;
|
316 |
|
|
}
|
317 |
|
|
ps2mou_buttons = new_buttons;
|
318 |
|
|
|
319 |
|
|
dx = ps2mou_buffer[1];
|
320 |
|
|
if (0 != (ps2mou_buffer[0] & (0x001 << 4))) {
|
321 |
|
|
// Negative number.
|
322 |
|
|
if (0 != (ps2mou_buffer[0] & (0x01 << 6))) {
|
323 |
|
|
// -ve overflow
|
324 |
|
|
dx = -256;
|
325 |
|
|
} else {
|
326 |
|
|
dx = 0 - (256 - dx);
|
327 |
|
|
}
|
328 |
|
|
} else if (0 != (ps2mou_buffer[0] & (0x01 << 6))) {
|
329 |
|
|
// +ve overflow
|
330 |
|
|
dx = 256;
|
331 |
|
|
}
|
332 |
|
|
ps2mou_dx += dx;
|
333 |
|
|
|
334 |
|
|
dy = ps2mou_buffer[2];
|
335 |
|
|
if (0 != (ps2mou_buffer[0] & (0x01 << 5))) {
|
336 |
|
|
// Negative number.
|
337 |
|
|
if (0 != (ps2mou_buffer[0] & (0x01 << 7))) {
|
338 |
|
|
// -ve overflow
|
339 |
|
|
dy = -256;
|
340 |
|
|
} else {
|
341 |
|
|
// -ve signed, bottom byte only
|
342 |
|
|
dy = 0 - (256 - dy);
|
343 |
|
|
}
|
344 |
|
|
} else if (0 != (ps2mou_buffer[0] & (0x01 << 7))) {
|
345 |
|
|
// +ve overflow
|
346 |
|
|
dy = 256;
|
347 |
|
|
}
|
348 |
|
|
ps2mou_dy += dy;
|
349 |
|
|
|
350 |
|
|
ps2mou_changed = 1;
|
351 |
|
|
}
|
352 |
|
|
|
353 |
|
|
// Mouse data. A PS/2 mouse sends events in the form of
|
354 |
|
|
// eight-byte packets. Some of the fields are officially
|
355 |
|
|
// reserved and ignored for now.
|
356 |
|
|
#define KC_MOUSE_DATA_FLAGS 0x00
|
357 |
|
|
#define KC_MOUSE_DATA_FLAGS_YOV (0x01 << 7)
|
358 |
|
|
#define KC_MOUSE_DATA_FLAGS_XOV (0x01 << 6)
|
359 |
|
|
#define KC_MOUSE_DATA_FLAGS_YNG (0x01 << 5)
|
360 |
|
|
#define KC_MOUSE_DATA_FLAGS_XNG (0x01 << 4)
|
361 |
|
|
#define KC_MOUSE_DATA_FLAGS_RIG (0x01 << 1)
|
362 |
|
|
#define KC_MOUSE_DATA_FLAGS_LEF (0x01 << 0)
|
363 |
|
|
#define KC_MOUSE_DATA_X 0x02
|
364 |
|
|
#define KC_MOUSE_DATA_Y 0x04
|
365 |
|
|
#define KC_MOUSE_DATA_SIZE 0x08
|
366 |
|
|
|
367 |
|
|
// ----------------------------------------------------------------------------
|
368 |
|
|
// An interrupt has occurred. Usually this means that there is data
|
369 |
|
|
// in the output register, although errors are possible as well. The
|
370 |
|
|
// data can be keyboard scancodes, parts of a mouse packet, or
|
371 |
|
|
// replies to control messages.
|
372 |
|
|
//
|
373 |
|
|
// For now errors are ignored, including parity and timeout errors. In
|
374 |
|
|
// theory these are supposed to be handled by requesting a resend. In
|
375 |
|
|
// practice that seems to cause as many complications as it might
|
376 |
|
|
// solve. For example what should happen if there is already a command
|
377 |
|
|
// being sent?
|
378 |
|
|
//
|
379 |
|
|
// The controller interrupts at two separate vectors, one for keyboard
|
380 |
|
|
// and another for mouse. If nested interrupts are enabled this could
|
381 |
|
|
// cause problems with nested calls to ps2_isr() updating the global
|
382 |
|
|
// data in the wrong order. It may be necessary to have a volatile flag
|
383 |
|
|
// to detect nesting, accompanied by an early acknowledge and return to
|
384 |
|
|
// the interrupted interrupt handler.
|
385 |
|
|
|
386 |
|
|
static cyg_uint32
|
387 |
|
|
ps2_isr(cyg_vector_t isr_vector, cyg_addrword_t isr_data)
|
388 |
|
|
{
|
389 |
|
|
int status;
|
390 |
|
|
unsigned char data;
|
391 |
|
|
|
392 |
|
|
CYG_UNUSED_PARAM(cyg_addrword_t, isr_data);
|
393 |
|
|
|
394 |
|
|
HAL_READ_UINT8(KC_STATUS, status);
|
395 |
|
|
while (status & KC_STATUS_OUTB) {
|
396 |
|
|
HAL_READ_UINT8(KC_OUTPUT, data);
|
397 |
|
|
|
398 |
|
|
if (status & KC_STATUS_AUXB) {
|
399 |
|
|
// Data from the mouse. This will be either an ACK for a
|
400 |
|
|
// command, a resend request, or a byte for the current
|
401 |
|
|
// packet. When a complete 8-byte packet has been received
|
402 |
|
|
// it can be processed. When an ACK is received the next
|
403 |
|
|
// byte for the current command should get sent, or on
|
404 |
|
|
// completion the sending code can be woken up.
|
405 |
|
|
//
|
406 |
|
|
// The mouse can also send back other data, e.g. in response
|
407 |
|
|
// to a determine-status request. These are disallowed
|
408 |
|
|
// because there is no obvious way of separating out such
|
409 |
|
|
// data from a current mouse packet being transferred.
|
410 |
|
|
//
|
411 |
|
|
// There may also be special bytes sent for disconnect and
|
412 |
|
|
// reconnect. It is not clear how to distinguish those
|
413 |
|
|
// from packet data either.
|
414 |
|
|
if (ps2_command_mouse_waiting_for_ack && ((KC_MOUSE_ACK == data) || (KC_MOUSE_RESEND == data))) {
|
415 |
|
|
int tmp;
|
416 |
|
|
|
417 |
|
|
if (KC_MOUSE_ACK == data) {
|
418 |
|
|
// Is there another byte to be sent?
|
419 |
|
|
ps2_command_index++;
|
420 |
|
|
if (ps2_command_index < ps2_command_length) {
|
421 |
|
|
// Send the next byte for the current command
|
422 |
|
|
do {
|
423 |
|
|
HAL_READ_UINT8(KC_STATUS, tmp);
|
424 |
|
|
} while (tmp & KC_STATUS_INPB);
|
425 |
|
|
HAL_WRITE_UINT8(KC_CONTROL, KC_CONTROL_WRITE_AUX);
|
426 |
|
|
do {
|
427 |
|
|
HAL_READ_UINT8(KC_STATUS, tmp);
|
428 |
|
|
} while (tmp & KC_STATUS_INPB);
|
429 |
|
|
HAL_WRITE_UINT8(KC_INPUT, ps2_command[ps2_command_index]);
|
430 |
|
|
} else {
|
431 |
|
|
// The whole command has been sent and acknowledged.
|
432 |
|
|
// Allow the polling thread to resume.
|
433 |
|
|
ps2_command_index = 0;
|
434 |
|
|
ps2_command_length = 0;
|
435 |
|
|
ps2_command = NULL;
|
436 |
|
|
ps2_command_ack = 1;
|
437 |
|
|
ps2_command_mouse_waiting_for_ack = 0;
|
438 |
|
|
}
|
439 |
|
|
} else {
|
440 |
|
|
// A resend request for the current byte.
|
441 |
|
|
do {
|
442 |
|
|
HAL_READ_UINT8(KC_STATUS, tmp);
|
443 |
|
|
} while (tmp & KC_STATUS_INPB);
|
444 |
|
|
HAL_WRITE_UINT8(KC_CONTROL, KC_CONTROL_WRITE_AUX);
|
445 |
|
|
do {
|
446 |
|
|
HAL_READ_UINT8(KC_STATUS, tmp);
|
447 |
|
|
} while (tmp & KC_STATUS_INPB);
|
448 |
|
|
HAL_WRITE_UINT8(KC_INPUT, ps2_command[ps2_command_index]);
|
449 |
|
|
}
|
450 |
|
|
} else {
|
451 |
|
|
ps2mou_buffer[ps2mou_buffer_index++] = data;
|
452 |
|
|
if (ps2mou_packet_size == ps2mou_buffer_index) {
|
453 |
|
|
// A complete packet has been received.
|
454 |
|
|
ps2mou_synaptics_translate();
|
455 |
|
|
ps2mou_buffer_index = 0; // Ready for the next packet
|
456 |
|
|
}
|
457 |
|
|
}
|
458 |
|
|
} else {
|
459 |
|
|
// Data from the keyboard. Usually this will be a scancode.
|
460 |
|
|
// There are a number of other possibilities such as
|
461 |
|
|
// echo replies, resend requests, and acks.
|
462 |
|
|
if ((KC_KBD_ACK == data) && (NULL != ps2_command) && !ps2_command_mouse_waiting_for_ack) {
|
463 |
|
|
// Send the next byte for the current command, or
|
464 |
|
|
// else we have completed.
|
465 |
|
|
ps2_command_index++;
|
466 |
|
|
if (ps2_command_index < ps2_command_length) {
|
467 |
|
|
int tmp;
|
468 |
|
|
do {
|
469 |
|
|
HAL_READ_UINT8(KC_STATUS, tmp);
|
470 |
|
|
} while (tmp & KC_STATUS_INPB);
|
471 |
|
|
HAL_WRITE_UINT8(KC_INPUT, ps2_command[ps2_command_index]);
|
472 |
|
|
} else {
|
473 |
|
|
ps2_command_index = 0;
|
474 |
|
|
ps2_command_length = 0;
|
475 |
|
|
ps2_command = NULL;
|
476 |
|
|
ps2_command_ack = 1;
|
477 |
|
|
}
|
478 |
|
|
} else if ((KC_KBD_RESEND == data) && (NULL != ps2_command) && !ps2_command_mouse_waiting_for_ack) {
|
479 |
|
|
int tmp;
|
480 |
|
|
do {
|
481 |
|
|
HAL_READ_UINT8(KC_STATUS, tmp);
|
482 |
|
|
} while (tmp & KC_STATUS_INPB);
|
483 |
|
|
HAL_WRITE_UINT8(KC_INPUT, ps2_command[ps2_command_index]);
|
484 |
|
|
} else {
|
485 |
|
|
if (((ps2kbd_scancode_buffer_head + 1) % PS2KBD_SCANCODE_BUFSIZE) == ps2kbd_scancode_buffer_tail) {
|
486 |
|
|
// Already full. The data has to be discarded.
|
487 |
|
|
} else {
|
488 |
|
|
ps2kbd_scancode_buffer[ps2kbd_scancode_buffer_head] = data;
|
489 |
|
|
ps2kbd_scancode_buffer_head = (ps2kbd_scancode_buffer_head + 1) % PS2KBD_SCANCODE_BUFSIZE;
|
490 |
|
|
}
|
491 |
|
|
}
|
492 |
|
|
}
|
493 |
|
|
|
494 |
|
|
// Just in case the keyboard controller is fast enough to send another byte,
|
495 |
|
|
// go around again.
|
496 |
|
|
HAL_READ_UINT8(KC_STATUS, status);
|
497 |
|
|
}
|
498 |
|
|
|
499 |
|
|
// The interrupt has been fully handled. For now there is no point
|
500 |
|
|
// in running a DSR.
|
501 |
|
|
cyg_drv_interrupt_acknowledge(isr_vector);
|
502 |
|
|
return CYG_ISR_HANDLED;
|
503 |
|
|
}
|
504 |
|
|
|
505 |
|
|
// For now the DSR does nothing.
|
506 |
|
|
static void
|
507 |
|
|
ps2_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
|
508 |
|
|
{
|
509 |
|
|
CYG_UNUSED_PARAM(cyg_vector_t, vector);
|
510 |
|
|
CYG_UNUSED_PARAM(cyg_ucount32, count);
|
511 |
|
|
CYG_UNUSED_PARAM(cyg_addrword_t, data);
|
512 |
|
|
}
|
513 |
|
|
|
514 |
|
|
|
515 |
|
|
// Sending out a command. The controller command, if any, gets sent here.
|
516 |
|
|
// This is followed by the first byte for the keyboard or mouse. The
|
517 |
|
|
// remaining bytes and any retransmits will be handled by the interrupt
|
518 |
|
|
// handler.
|
519 |
|
|
static void
|
520 |
|
|
ps2_send_command(int controller_command, unsigned char* command, int length, int mouse)
|
521 |
|
|
{
|
522 |
|
|
int status;
|
523 |
|
|
|
524 |
|
|
CYG_PRECONDITION(NULL == ps2_command, "Only one send command is allowed at a time");
|
525 |
|
|
CYG_PRECONDITION((KC_CONTROL_NULL != controller_command) || (NULL != command), "no-op");
|
526 |
|
|
CYG_PRECONDITION(!mouse || (KC_CONTROL_NULL == controller_command), "cannot combine controller and mouse commands");
|
527 |
|
|
|
528 |
|
|
ps2_command = command;
|
529 |
|
|
ps2_command_index = 0;
|
530 |
|
|
ps2_command_length = length;
|
531 |
|
|
ps2_command_mouse = 0;
|
532 |
|
|
ps2_command_ack = 0;
|
533 |
|
|
|
534 |
|
|
if (KC_CONTROL_NULL != controller_command) {
|
535 |
|
|
do {
|
536 |
|
|
HAL_READ_UINT8(KC_STATUS, status);
|
537 |
|
|
} while (status & KC_STATUS_INPB);
|
538 |
|
|
HAL_WRITE_UINT8(KC_CONTROL, controller_command);
|
539 |
|
|
}
|
540 |
|
|
|
541 |
|
|
if (length > 0) {
|
542 |
|
|
if (mouse) {
|
543 |
|
|
do {
|
544 |
|
|
HAL_READ_UINT8(KC_STATUS, status);
|
545 |
|
|
} while (status & KC_STATUS_INPB);
|
546 |
|
|
HAL_WRITE_UINT8(KC_CONTROL, KC_CONTROL_WRITE_AUX);
|
547 |
|
|
}
|
548 |
|
|
do {
|
549 |
|
|
HAL_READ_UINT8(KC_STATUS, status);
|
550 |
|
|
} while (status & KC_STATUS_INPB);
|
551 |
|
|
HAL_WRITE_UINT8(KC_INPUT, command[0]);
|
552 |
|
|
}
|
553 |
|
|
}
|
554 |
|
|
|
555 |
|
|
// For now there is little difference between polled and non-polled
|
556 |
|
|
// mode, they both just spin until the ACK byte is received. The
|
557 |
|
|
// polled version just calls the interrupt handler as well. This is
|
558 |
|
|
// probably acceptable for now because commands only get sent during
|
559 |
|
|
// initialization, but eventually the non-polled version should be
|
560 |
|
|
// using a synch primitive signalled by the dsr.
|
561 |
|
|
//
|
562 |
|
|
// ACKs are only generated when there is data to be sent, not for
|
563 |
|
|
// operations on the control register.
|
564 |
|
|
//
|
565 |
|
|
// For keyboard commands there is no real problem because the ACK
|
566 |
|
|
// character 0xFA does not match a valid scancode. For the mouse
|
567 |
|
|
// things are more difficult because 0xFA could be present in the
|
568 |
|
|
// data, e.g. as a fairly large movement. Therefore the interrupt
|
569 |
|
|
// handler needs to know whether or not a mouse ACK is expected.
|
570 |
|
|
// It is assumed that the ACK and any actual 0xFA data get sent
|
571 |
|
|
// within a byte of each other so that the 0xFA still ends up in
|
572 |
|
|
// the right place in the buffer.
|
573 |
|
|
//
|
574 |
|
|
// A couple of commands do not result in an ACK. For the mouse this
|
575 |
|
|
// includes reset-wrap-mode and reset. For the keyboard this includes
|
576 |
|
|
// echo. These commands are not currently used, so there is no need
|
577 |
|
|
// to worry about the special cases.
|
578 |
|
|
|
579 |
|
|
static void
|
580 |
|
|
ps2_send_command_poll(int controller_command, unsigned char* command, int length, int mouse)
|
581 |
|
|
{
|
582 |
|
|
if ((NULL != command) && mouse) {
|
583 |
|
|
ps2_command_mouse_waiting_for_ack = 1;
|
584 |
|
|
}
|
585 |
|
|
ps2_send_command(controller_command, command, length, mouse);
|
586 |
|
|
if (NULL != command) {
|
587 |
|
|
for ( ; !ps2_command_ack; ) {
|
588 |
|
|
ps2_isr( CYGNUM_HAL_INTERRUPT_KEYBOARD, 0);
|
589 |
|
|
}
|
590 |
|
|
ps2_command_ack = 0;
|
591 |
|
|
}
|
592 |
|
|
}
|
593 |
|
|
|
594 |
|
|
static void
|
595 |
|
|
ps2_send_command_wait(int controller_command, unsigned char* command, int length, int mouse)
|
596 |
|
|
{
|
597 |
|
|
if ((NULL != command) && mouse) {
|
598 |
|
|
ps2_command_mouse_waiting_for_ack = 1;
|
599 |
|
|
}
|
600 |
|
|
ps2_send_command(controller_command, command, length, mouse);
|
601 |
|
|
if (NULL != command) {
|
602 |
|
|
for ( ; !ps2_command_ack; )
|
603 |
|
|
;
|
604 |
|
|
ps2_command_ack = 0;
|
605 |
|
|
}
|
606 |
|
|
}
|
607 |
|
|
|
608 |
|
|
|
609 |
|
|
// ----------------------------------------------------------------------------
|
610 |
|
|
// Hardware initialization and the interrupt handling.
|
611 |
|
|
|
612 |
|
|
static cyg_handle_t ps2kbd_interrupt_handle;
|
613 |
|
|
static cyg_interrupt ps2kbd_interrupt_data;
|
614 |
|
|
static cyg_handle_t ps2mouse_interrupt_handle;
|
615 |
|
|
static cyg_interrupt ps2mouse_interrupt_data;
|
616 |
|
|
|
617 |
|
|
static void
|
618 |
|
|
ps2_initialize(void)
|
619 |
|
|
{
|
620 |
|
|
unsigned char buf[2];
|
621 |
|
|
int status, data;
|
622 |
|
|
|
623 |
|
|
// Only perform initialization once, not for both kbd and mouse.
|
624 |
|
|
static int initialized = 0;
|
625 |
|
|
if (initialized) {
|
626 |
|
|
return;
|
627 |
|
|
}
|
628 |
|
|
initialized++;
|
629 |
|
|
|
630 |
|
|
// Start by masking out the interrupts. Other code such as the HAL
|
631 |
|
|
// or RedBoot may think it currently owns the keyboard, and I do
|
632 |
|
|
// not want any interference from them while setting up the
|
633 |
|
|
// interrupt handlers.
|
634 |
|
|
cyg_drv_interrupt_mask_intunsafe(CYGNUM_HAL_INTERRUPT_KEYBOARD);
|
635 |
|
|
cyg_drv_interrupt_mask_intunsafe(CYGNUM_HAL_INTERRUPT_IRQ12);
|
636 |
|
|
|
637 |
|
|
// Install my own interrupt handler, overwriting anything that might
|
638 |
|
|
// be there already.
|
639 |
|
|
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_KEYBOARD, 0, 0,
|
640 |
|
|
&ps2_isr, &ps2_dsr, &ps2kbd_interrupt_handle, &ps2kbd_interrupt_data);
|
641 |
|
|
cyg_drv_interrupt_attach(ps2kbd_interrupt_handle);
|
642 |
|
|
cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_IRQ12, 0, 0,
|
643 |
|
|
&ps2_isr, &ps2_dsr, &ps2mouse_interrupt_handle, &ps2mouse_interrupt_data);
|
644 |
|
|
cyg_drv_interrupt_attach(ps2mouse_interrupt_handle);
|
645 |
|
|
|
646 |
|
|
// Get the device into a known state.
|
647 |
|
|
ps2_send_command(KC_CONTROL_DISABLE_AUX, NULL, 0, 0);
|
648 |
|
|
ps2_send_command(KC_CONTROL_DISABLE_KBD, NULL, 0, 0);
|
649 |
|
|
|
650 |
|
|
// Discard any current data.
|
651 |
|
|
HAL_READ_UINT8(KC_STATUS, status);
|
652 |
|
|
while (status & KC_STATUS_OUTB) {
|
653 |
|
|
HAL_READ_UINT8(KC_OUTPUT, data);
|
654 |
|
|
HAL_READ_UINT8(KC_STATUS, status);
|
655 |
|
|
}
|
656 |
|
|
|
657 |
|
|
// Now restart and reset the keyboard.
|
658 |
|
|
ps2_send_command(KC_CONTROL_ENABLE_KBD, NULL, 0, 0);
|
659 |
|
|
buf[0] = KC_KBDC_STANDARD_DISABLE;
|
660 |
|
|
ps2_send_command_poll(KC_CONTROL_NULL, buf, 1, 0);
|
661 |
|
|
buf[0] = KC_KBDC_LED_ONOFF;
|
662 |
|
|
buf[1] = 0;
|
663 |
|
|
ps2_send_command_poll(KC_CONTROL_NULL, buf, 2, 0);
|
664 |
|
|
// The keyboard-specific initialization can now reenable the keyboard
|
665 |
|
|
// using enable
|
666 |
|
|
|
667 |
|
|
// Similarly for a mouse
|
668 |
|
|
// Standard mode means 100 samples/s, 1:1 scaling, stream mode, 4 counts/mm resolution,
|
669 |
|
|
// and transferdisabled. Stream mode is important, that means mouse data will
|
670 |
|
|
// be immediately available rather than requiring separate control messages to
|
671 |
|
|
// read a packet.
|
672 |
|
|
ps2_send_command(KC_CONTROL_ENABLE_AUX, NULL, 0, 0);
|
673 |
|
|
buf[0] = KC_MOUSEC_SET_STANDARD;
|
674 |
|
|
ps2_send_command_poll(KC_CONTROL_NULL, buf, 1, 1);
|
675 |
|
|
buf[0] = KC_MOUSEC_SET_SAMPLE_RATE;
|
676 |
|
|
buf[1] = 0x0A;
|
677 |
|
|
ps2_send_command_poll(KC_CONTROL_NULL, buf, 2, 1);
|
678 |
|
|
|
679 |
|
|
// WRITE_MODE does not appear to involve an ACK
|
680 |
|
|
ps2_send_command_poll(KC_CONTROL_WRITE_MODE, NULL, 0, 0);
|
681 |
|
|
do {
|
682 |
|
|
HAL_READ_UINT8(KC_STATUS, status);
|
683 |
|
|
} while (status & KC_STATUS_INPB);
|
684 |
|
|
HAL_WRITE_UINT8(KC_INPUT, KC_MODE_KBD_INT | KC_MODE_MOU_INT | KC_MODE_SYS | KC_MODE_KCC);
|
685 |
|
|
|
686 |
|
|
cyg_drv_interrupt_unmask_intunsafe(CYGNUM_HAL_INTERRUPT_KEYBOARD);
|
687 |
|
|
cyg_drv_interrupt_unmask_intunsafe(CYGNUM_HAL_INTERRUPT_IRQ12);
|
688 |
|
|
}
|
689 |
|
|
|
690 |
|
|
// ----------------------------------------------------------------------------
|
691 |
|
|
static int
|
692 |
|
|
PS2Mouse_Open(MOUSEDEVICE* pmd)
|
693 |
|
|
{
|
694 |
|
|
unsigned char buf[1];
|
695 |
|
|
ps2_initialize();
|
696 |
|
|
buf[0] = KC_MOUSEC_ENABLE;
|
697 |
|
|
ps2_send_command_wait(KC_CONTROL_NULL, buf, 1, 1);
|
698 |
|
|
}
|
699 |
|
|
|
700 |
|
|
// Closing the mouse is equivalent to disabling. It is assumed that we
|
701 |
|
|
// are not in the middle of a packet transfer, which could really
|
702 |
|
|
// confuse things.
|
703 |
|
|
static void
|
704 |
|
|
PS2Mouse_Close(void)
|
705 |
|
|
{
|
706 |
|
|
unsigned char buf[1];
|
707 |
|
|
buf[0] = KC_MOUSEC_SET_STANDARD;
|
708 |
|
|
ps2_send_command_wait(KC_CONTROL_NULL, buf, 1, 1);
|
709 |
|
|
ps2mou_buffer_index = 0;
|
710 |
|
|
}
|
711 |
|
|
|
712 |
|
|
static int
|
713 |
|
|
PS2Mouse_GetButtonInfo(void)
|
714 |
|
|
{
|
715 |
|
|
return MWBUTTON_L | MWBUTTON_R;
|
716 |
|
|
}
|
717 |
|
|
|
718 |
|
|
// The mouse is used in its default setup, which means 1:1 scaling.
|
719 |
|
|
// Setting the threshold to 5 seems to match most other drivers...
|
720 |
|
|
static void
|
721 |
|
|
PS2Mouse_GetDefaultAccel(int* pscale, int* pthresh)
|
722 |
|
|
{
|
723 |
|
|
if (NULL != pscale) {
|
724 |
|
|
*pscale = 1;
|
725 |
|
|
}
|
726 |
|
|
if (NULL != pthresh) {
|
727 |
|
|
*pthresh = 5;
|
728 |
|
|
}
|
729 |
|
|
}
|
730 |
|
|
|
731 |
|
|
static int
|
732 |
|
|
PS2Mouse_Read(MWCOORD* dx_arg, MWCOORD* dy_arg, MWCOORD* dz_arg, int* bp_arg)
|
733 |
|
|
{
|
734 |
|
|
int result = 0;
|
735 |
|
|
MWCOORD dx = 0;
|
736 |
|
|
MWCOORD dy = 0;
|
737 |
|
|
int buttons = 0;
|
738 |
|
|
|
739 |
|
|
cyg_drv_isr_lock();
|
740 |
|
|
if (ps2mou_changed) {
|
741 |
|
|
dx = ps2mou_dx;
|
742 |
|
|
dy = 0 - ps2mou_dy; // microwindows directions are the opposite from the hardware
|
743 |
|
|
buttons = ps2mou_buttons;
|
744 |
|
|
ps2mou_dx = 0;
|
745 |
|
|
ps2mou_dy = 0;
|
746 |
|
|
ps2mou_changed = 0;
|
747 |
|
|
result = 1;
|
748 |
|
|
}
|
749 |
|
|
cyg_drv_isr_unlock();
|
750 |
|
|
if (result) {
|
751 |
|
|
if (NULL != dx_arg) {
|
752 |
|
|
*dx_arg = dx;
|
753 |
|
|
}
|
754 |
|
|
if (NULL != dy_arg) {
|
755 |
|
|
*dy_arg = dy;
|
756 |
|
|
}
|
757 |
|
|
if (NULL != dz_arg) {
|
758 |
|
|
*dz_arg = 0;
|
759 |
|
|
}
|
760 |
|
|
if (NULL != bp_arg) {
|
761 |
|
|
*bp_arg = buttons;
|
762 |
|
|
}
|
763 |
|
|
}
|
764 |
|
|
return result;
|
765 |
|
|
}
|
766 |
|
|
|
767 |
|
|
static int
|
768 |
|
|
PS2Mouse_Poll(void)
|
769 |
|
|
{
|
770 |
|
|
return 0 != ps2mou_changed;
|
771 |
|
|
}
|
772 |
|
|
|
773 |
|
|
MOUSEDEVICE mousedev = {
|
774 |
|
|
PS2Mouse_Open,
|
775 |
|
|
PS2Mouse_Close,
|
776 |
|
|
PS2Mouse_GetButtonInfo,
|
777 |
|
|
PS2Mouse_GetDefaultAccel,
|
778 |
|
|
PS2Mouse_Read,
|
779 |
|
|
PS2Mouse_Poll
|
780 |
|
|
};
|
781 |
|
|
|
782 |
|
|
// ----------------------------------------------------------------------------
|
783 |
|
|
// Extracting data from the scancode buffer and turning it into
|
784 |
|
|
// ASCII. This is only called from thread context by the poll() and
|
785 |
|
|
// read() routines, although the scancode buffer is updated in ISR
|
786 |
|
|
// context.
|
787 |
|
|
|
788 |
|
|
// The current keyboard event, if any. This involves processing
|
789 |
|
|
// the scancodes held in the circular buffer and translating them
|
790 |
|
|
// to ASCII.
|
791 |
|
|
static MWKEY ps2kbd_current_key = MWKEY_UNKNOWN;
|
792 |
|
|
static MWKEYMOD ps2kbd_current_modifiers = 0;
|
793 |
|
|
static MWSCANCODE ps2kbd_current_scancode = 0;
|
794 |
|
|
static int ps2kbd_current_keydown = 0;
|
795 |
|
|
|
796 |
|
|
// Translation between scancodes and characters, i.e. keymaps.
|
797 |
|
|
// For now a relatively simple approach is used. The keymaps
|
798 |
|
|
// only cope with shifted vs. unshifted. The control key
|
799 |
|
|
// is handled specially. Anything cleverer is left to microwindows.
|
800 |
|
|
//
|
801 |
|
|
// Microwindows excepts key events in the form of MWKEY's, which
|
802 |
|
|
// are unsigned shorts. Special keys such as the function keys
|
803 |
|
|
// have suitable #define's in mwtypes.h.
|
804 |
|
|
//
|
805 |
|
|
// There is a complication with PC keyboards in that some keys
|
806 |
|
|
// generate multi-byte sequences, usually starting with 0xE0
|
807 |
|
|
|
808 |
|
|
typedef struct ps2kbd_keymap_entry {
|
809 |
|
|
MWKEY normal;
|
810 |
|
|
MWKEY shifted;
|
811 |
|
|
} ps2kbd_keymap_entry;
|
812 |
|
|
|
813 |
|
|
// This keymap is for a Dell Inspiron laptop with a Japanese
|
814 |
|
|
// keyboard. It may not match exactly with other keyboards,
|
815 |
|
|
// but is probably good enough for now.
|
816 |
|
|
|
817 |
|
|
static const ps2kbd_keymap_entry ps2kbd_keymap[] = {
|
818 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // Scancode 0 unused
|
819 |
|
|
{ MWKEY_ESCAPE, MWKEY_ESCAPE },
|
820 |
|
|
{ '1', '!' },
|
821 |
|
|
{ '2', '"' },
|
822 |
|
|
{ '3', '#' },
|
823 |
|
|
{ '4', '$' },
|
824 |
|
|
{ '5', '%' },
|
825 |
|
|
{ '6', '&' },
|
826 |
|
|
{ '7', '\'' },
|
827 |
|
|
{ '8', '(' },
|
828 |
|
|
{ '9', ')' }, // Scancode 10
|
829 |
|
|
{ '0', '~' },
|
830 |
|
|
{ '-', '=' },
|
831 |
|
|
{ '^', '_' },
|
832 |
|
|
{ MWKEY_BACKSPACE, MWKEY_BACKSPACE },
|
833 |
|
|
{ MWKEY_TAB, MWKEY_TAB },
|
834 |
|
|
{ 'q', 'Q' }, // 0x10
|
835 |
|
|
{ 'w', 'W' },
|
836 |
|
|
{ 'e', 'E' },
|
837 |
|
|
{ 'r', 'R' },
|
838 |
|
|
{ 't', 'T' }, // 20
|
839 |
|
|
{ 'y', 'Y' },
|
840 |
|
|
{ 'u', 'U' },
|
841 |
|
|
{ 'i', 'I' },
|
842 |
|
|
{ 'o', 'O' },
|
843 |
|
|
{ 'p', 'P' },
|
844 |
|
|
{ '@', '`' },
|
845 |
|
|
{ '[', '{' },
|
846 |
|
|
{ MWKEY_ENTER, MWKEY_ENTER },
|
847 |
|
|
{ MWKEY_LCTRL, MWKEY_LCTRL },
|
848 |
|
|
{ 'a', 'A' }, // 30
|
849 |
|
|
{ 's', 'S' },
|
850 |
|
|
{ 'd', 'D' }, // 0x20
|
851 |
|
|
{ 'f', 'F' },
|
852 |
|
|
{ 'g', 'G' },
|
853 |
|
|
{ 'h', 'H' },
|
854 |
|
|
{ 'j', 'J' },
|
855 |
|
|
{ 'k', 'K' },
|
856 |
|
|
{ 'l', 'L' },
|
857 |
|
|
{ ';', '+' },
|
858 |
|
|
{ ':', '*' }, // 40
|
859 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // Japanese-only, top-left below escape
|
860 |
|
|
{ MWKEY_LSHIFT, MWKEY_LSHIFT },
|
861 |
|
|
{ ']', '}' },
|
862 |
|
|
{ 'z', 'Z' },
|
863 |
|
|
{ 'x', 'X' },
|
864 |
|
|
{ 'c', 'C' },
|
865 |
|
|
{ 'v', 'V' },
|
866 |
|
|
{ 'b', 'B' }, // 0x30
|
867 |
|
|
{ 'n', 'N' },
|
868 |
|
|
{ 'm', 'M' }, // 50
|
869 |
|
|
{ ',', '<' },
|
870 |
|
|
{ '.', '>' },
|
871 |
|
|
{ '/', '?' },
|
872 |
|
|
{ MWKEY_RSHIFT, MWKEY_RSHIFT },
|
873 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // unused ?
|
874 |
|
|
{ MWKEY_LALT, MWKEY_LALT },
|
875 |
|
|
{ ' ', ' ' }, // space bar
|
876 |
|
|
{ MWKEY_CAPSLOCK, MWKEY_CAPSLOCK },
|
877 |
|
|
{ MWKEY_F1, MWKEY_F1 },
|
878 |
|
|
{ MWKEY_F2, MWKEY_F2 }, // 60
|
879 |
|
|
{ MWKEY_F3, MWKEY_F3 },
|
880 |
|
|
{ MWKEY_F4, MWKEY_F4 },
|
881 |
|
|
{ MWKEY_F5, MWKEY_F5 },
|
882 |
|
|
{ MWKEY_F6, MWKEY_F6 }, // 0x40
|
883 |
|
|
{ MWKEY_F7, MWKEY_F7 },
|
884 |
|
|
{ MWKEY_F8, MWKEY_F8 },
|
885 |
|
|
{ MWKEY_F9, MWKEY_F9 },
|
886 |
|
|
{ MWKEY_F10, MWKEY_F10 },
|
887 |
|
|
{ MWKEY_NUMLOCK, MWKEY_NUMLOCK },
|
888 |
|
|
{ MWKEY_SCROLLOCK, MWKEY_SCROLLOCK }, // 70
|
889 |
|
|
{ MWKEY_KP7, MWKEY_KP7 }, // Keypad, not actually present on laptop
|
890 |
|
|
{ MWKEY_KP8, MWKEY_KP8 }, // But accessible via Fn and some centre keys
|
891 |
|
|
{ MWKEY_KP9, MWKEY_KP9 },
|
892 |
|
|
{ MWKEY_KP_MINUS, MWKEY_KP_MINUS },
|
893 |
|
|
{ MWKEY_KP4, MWKEY_KP4 },
|
894 |
|
|
{ MWKEY_KP5, MWKEY_KP5 },
|
895 |
|
|
{ MWKEY_KP6, MWKEY_KP6 },
|
896 |
|
|
{ MWKEY_KP_PLUS, MWKEY_KP_PLUS },
|
897 |
|
|
{ MWKEY_KP1, MWKEY_KP1 },
|
898 |
|
|
{ MWKEY_KP2, MWKEY_KP2 }, // 80, 0x50
|
899 |
|
|
{ MWKEY_KP3, MWKEY_KP3 },
|
900 |
|
|
{ MWKEY_KP0, MWKEY_KP0 },
|
901 |
|
|
{ MWKEY_KP_PERIOD, MWKEY_KP_PERIOD },
|
902 |
|
|
// There are now big gaps
|
903 |
|
|
// F11 and F12 are 0x57 and 0x58
|
904 |
|
|
// 0x70, 0x79 and 0x7b are Japanese compose keys.
|
905 |
|
|
// 0x73 is backslash and another _
|
906 |
|
|
// 0x7d is yen and pipe.
|
907 |
|
|
// These could be handled by special-case code in the scancode
|
908 |
|
|
// translation routine, but at 4 bytes per table entry
|
909 |
|
|
// it is probably just as efficient to extend the table.
|
910 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 84, 0x53
|
911 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
912 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
913 |
|
|
{ MWKEY_F11, MWKEY_F11 },
|
914 |
|
|
{ MWKEY_F12, MWKEY_F12 },
|
915 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
916 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 90
|
917 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
918 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
919 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
920 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
921 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
922 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 0x60
|
923 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
924 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
925 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
926 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 100
|
927 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
928 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
929 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
930 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
931 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
932 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
933 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
934 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
935 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
936 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 110
|
937 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
938 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 0x70
|
939 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
940 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
941 |
|
|
{ '\\', '_' },
|
942 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
943 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
944 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
945 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
946 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN }, // 120
|
947 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
948 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
949 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
950 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
951 |
|
|
{ MWKEY_UNKNOWN, '|' }, // 125
|
952 |
|
|
// In theory there could also be 126 and 127, but those are unused.
|
953 |
|
|
// But putting them into the table avoids a special case test in the code,
|
954 |
|
|
// for a cost of only eight bytes.
|
955 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
956 |
|
|
{ MWKEY_UNKNOWN, MWKEY_UNKNOWN },
|
957 |
|
|
};
|
958 |
|
|
|
959 |
|
|
// Now for the E0 sequences. The standard ones are in the range 0x47 to 0x53
|
960 |
|
|
// 0xE0, 0x5B is the Left Windows key. 0x5C would normally be the right one.
|
961 |
|
|
// 0xE0, 0x5D is the Menu key. The
|
962 |
|
|
// The Dell has some additional ones for the dvd player, ignored.
|
963 |
|
|
// PrintScreen generates a simple sequence 0xE0, 0x2A, 0xE0, 0x37, 0xE0, 0xB7, 0xE0, 0xAA
|
964 |
|
|
// Break generates 0xE1, 0x1D, 0x45, 0xE1, 0x9D, 0xC5
|
965 |
|
|
|
966 |
|
|
#define PS2KBD_E0_MIN 0x47
|
967 |
|
|
static const MWKEY ps2kbd_e0_map[] = {
|
968 |
|
|
MWKEY_HOME, // 0x47
|
969 |
|
|
MWKEY_UP, // 0x48
|
970 |
|
|
MWKEY_PAGEUP, // 0x49
|
971 |
|
|
MWKEY_UNKNOWN,
|
972 |
|
|
MWKEY_LEFT, // 0x4B
|
973 |
|
|
MWKEY_UNKNOWN,
|
974 |
|
|
MWKEY_RIGHT, // 0x4D
|
975 |
|
|
MWKEY_UNKNOWN,
|
976 |
|
|
MWKEY_END, // 0x4F
|
977 |
|
|
MWKEY_DOWN, // 0x50
|
978 |
|
|
MWKEY_PAGEDOWN, // 0x51
|
979 |
|
|
MWKEY_INSERT, // 0x52
|
980 |
|
|
MWKEY_DELETE, // 0x53
|
981 |
|
|
MWKEY_UNKNOWN,
|
982 |
|
|
MWKEY_UNKNOWN,
|
983 |
|
|
MWKEY_UNKNOWN,
|
984 |
|
|
MWKEY_UNKNOWN,
|
985 |
|
|
MWKEY_UNKNOWN,
|
986 |
|
|
MWKEY_UNKNOWN,
|
987 |
|
|
MWKEY_UNKNOWN,
|
988 |
|
|
MWKEY_LMETA, // 0x5B
|
989 |
|
|
MWKEY_RMETA, // 0x5C
|
990 |
|
|
MWKEY_MENU // 0x5D
|
991 |
|
|
};
|
992 |
|
|
#define PS2KBD_E0_MAX 0x5D
|
993 |
|
|
|
994 |
|
|
// Modifier translations. All modifiers are supported by
|
995 |
|
|
// this table, even though the keyboard may not actually
|
996 |
|
|
// have all of them.
|
997 |
|
|
typedef struct ps2kbd_modifier_entry {
|
998 |
|
|
MWKEY key;
|
999 |
|
|
MWKEYMOD modifier;
|
1000 |
|
|
int toggle;
|
1001 |
|
|
} ps2kbd_modifier_entry;
|
1002 |
|
|
|
1003 |
|
|
static const ps2kbd_modifier_entry ps2kbd_modifier_map[] = {
|
1004 |
|
|
{ MWKEY_LSHIFT, MWKMOD_LSHIFT, 0 },
|
1005 |
|
|
{ MWKEY_RSHIFT, MWKMOD_RSHIFT, 0 },
|
1006 |
|
|
{ MWKEY_LCTRL, MWKMOD_LCTRL, 0 },
|
1007 |
|
|
{ MWKEY_RCTRL, MWKMOD_RCTRL, 0 },
|
1008 |
|
|
{ MWKEY_LALT, MWKMOD_LALT, 0 },
|
1009 |
|
|
{ MWKEY_RALT, MWKMOD_RALT, 0 },
|
1010 |
|
|
{ MWKEY_LMETA, MWKMOD_LMETA, 0 },
|
1011 |
|
|
{ MWKEY_RMETA, MWKMOD_RMETA, 0 },
|
1012 |
|
|
{ MWKEY_NUMLOCK, MWKMOD_NUM, 1 },
|
1013 |
|
|
{ MWKEY_CAPSLOCK, MWKMOD_CAPS, 1 },
|
1014 |
|
|
{ MWKEY_ALTGR, MWKMOD_ALTGR, 0 },
|
1015 |
|
|
{ MWKEY_SCROLLOCK, MWKMOD_SCR, 1 },
|
1016 |
|
|
{ MWKEY_UNKNOWN, MWKMOD_NONE }
|
1017 |
|
|
};
|
1018 |
|
|
|
1019 |
|
|
static void
|
1020 |
|
|
ps2kbd_process_scancodes(void)
|
1021 |
|
|
{
|
1022 |
|
|
static int e0_seen = 0;
|
1023 |
|
|
static MWKEY pending_up = MWKEY_UNKNOWN;
|
1024 |
|
|
static int pending_scancode = 0;
|
1025 |
|
|
static int discard = 0;
|
1026 |
|
|
int scancode;
|
1027 |
|
|
int i;
|
1028 |
|
|
|
1029 |
|
|
CYG_PRECONDITION(MWKEY_UNKNOWN == ps2kbd_current_key, "There should be no pending key");
|
1030 |
|
|
|
1031 |
|
|
if (MWKEY_UNKNOWN != pending_up) {
|
1032 |
|
|
ps2kbd_current_key = pending_up;
|
1033 |
|
|
ps2kbd_current_scancode = pending_scancode;
|
1034 |
|
|
ps2kbd_current_keydown = 0;
|
1035 |
|
|
pending_up = MWKEY_UNKNOWN;
|
1036 |
|
|
return;
|
1037 |
|
|
}
|
1038 |
|
|
|
1039 |
|
|
while (MWKEY_UNKNOWN == ps2kbd_current_key) {
|
1040 |
|
|
// The ISR will manipulate the scancode buffer directly, so
|
1041 |
|
|
// interrupts have to be disabled temporarily.
|
1042 |
|
|
scancode = -1;
|
1043 |
|
|
cyg_drv_isr_lock();
|
1044 |
|
|
if (ps2kbd_scancode_buffer_head != ps2kbd_scancode_buffer_tail) {
|
1045 |
|
|
scancode = ps2kbd_scancode_buffer[ps2kbd_scancode_buffer_tail];
|
1046 |
|
|
ps2kbd_scancode_buffer_tail = (ps2kbd_scancode_buffer_tail + 1) % PS2KBD_SCANCODE_BUFSIZE;
|
1047 |
|
|
}
|
1048 |
|
|
cyg_drv_isr_unlock();
|
1049 |
|
|
|
1050 |
|
|
if (scancode == -1) {
|
1051 |
|
|
// No more data to be processed.
|
1052 |
|
|
break;
|
1053 |
|
|
}
|
1054 |
|
|
|
1055 |
|
|
// Are we in one of the special sequences, where bytes should be
|
1056 |
|
|
// discarded?
|
1057 |
|
|
if (discard > 0) {
|
1058 |
|
|
discard -= 1;
|
1059 |
|
|
continue;
|
1060 |
|
|
}
|
1061 |
|
|
|
1062 |
|
|
// A real scancode has been extracted. Are we in an E0 sequence?
|
1063 |
|
|
if (e0_seen) {
|
1064 |
|
|
e0_seen = 0;
|
1065 |
|
|
ps2kbd_current_keydown = (0 == (scancode & 0x0080));
|
1066 |
|
|
scancode &= 0x007F;
|
1067 |
|
|
if ((scancode >= PS2KBD_E0_MIN) && (scancode <= PS2KBD_E0_MAX)) {
|
1068 |
|
|
ps2kbd_current_key = ps2kbd_e0_map[scancode - PS2KBD_E0_MIN];
|
1069 |
|
|
ps2kbd_current_scancode = 0x80 + scancode - PS2KBD_E0_MIN; // Invent a key scancode
|
1070 |
|
|
}
|
1071 |
|
|
// We may or may not have a valid keycode at this time, so go
|
1072 |
|
|
// around the loop again to check for MWKEY_UNKNOWN
|
1073 |
|
|
continue;
|
1074 |
|
|
}
|
1075 |
|
|
|
1076 |
|
|
// Is this the start of an E0 sequence?
|
1077 |
|
|
if (0x00E0 == scancode) {
|
1078 |
|
|
e0_seen = 1;
|
1079 |
|
|
continue;
|
1080 |
|
|
}
|
1081 |
|
|
|
1082 |
|
|
// How about E1?
|
1083 |
|
|
if (0x00E1 == scancode) {
|
1084 |
|
|
// For now there is only one key which generates E1 sequences
|
1085 |
|
|
ps2kbd_current_key = MWKEY_BREAK;
|
1086 |
|
|
ps2kbd_current_keydown = 1;
|
1087 |
|
|
ps2kbd_current_scancode = 0x00E1; // Invent another key scancode
|
1088 |
|
|
pending_up = MWKEY_BREAK;
|
1089 |
|
|
pending_scancode = 0x00E1;
|
1090 |
|
|
discard = 5;
|
1091 |
|
|
return;
|
1092 |
|
|
}
|
1093 |
|
|
|
1094 |
|
|
// Must be an ordinary key.
|
1095 |
|
|
ps2kbd_current_keydown = (0 == (scancode & 0x0080));
|
1096 |
|
|
scancode &= 0x007F;
|
1097 |
|
|
ps2kbd_current_scancode = scancode;
|
1098 |
|
|
ps2kbd_current_key = ps2kbd_keymap[scancode].normal;
|
1099 |
|
|
|
1100 |
|
|
// Detect the modifier keys.
|
1101 |
|
|
for (i = 0; MWKEY_UNKNOWN != ps2kbd_modifier_map[i].key; i++) {
|
1102 |
|
|
if (ps2kbd_current_key == ps2kbd_modifier_map[i].key) {
|
1103 |
|
|
// capslock etc. behave differently. Toggle the current
|
1104 |
|
|
// status on the keyup event, ignore key down (because
|
1105 |
|
|
// of hardware autorepeat).
|
1106 |
|
|
if (ps2kbd_modifier_map[i].toggle) {
|
1107 |
|
|
if (!ps2kbd_current_keydown) {
|
1108 |
|
|
ps2kbd_current_modifiers ^= ps2kbd_modifier_map[i].modifier;
|
1109 |
|
|
}
|
1110 |
|
|
} else if (ps2kbd_current_keydown) {
|
1111 |
|
|
ps2kbd_current_modifiers |= ps2kbd_modifier_map[i].modifier;
|
1112 |
|
|
} else {
|
1113 |
|
|
ps2kbd_current_modifiers &= ~ps2kbd_modifier_map[i].modifier;
|
1114 |
|
|
}
|
1115 |
|
|
break;
|
1116 |
|
|
}
|
1117 |
|
|
}
|
1118 |
|
|
|
1119 |
|
|
// Cope with some of the modifiers.
|
1120 |
|
|
if (0 != (ps2kbd_current_modifiers & (MWKMOD_LCTRL | MWKMOD_RCTRL))) {
|
1121 |
|
|
// Control key. a-z and A-Z go to ctrl-A - ctrl-Z, i.e. 1 to 26
|
1122 |
|
|
// Other characters in the range 64 to 96, e.g. [ and ], also
|
1123 |
|
|
// get translated. This includes the A-Z range.
|
1124 |
|
|
if ((64 <= ps2kbd_current_key) && (ps2kbd_current_key < 96)) {
|
1125 |
|
|
ps2kbd_current_key -= 64;
|
1126 |
|
|
} else if (('a' <= ps2kbd_current_key) && (ps2kbd_current_key <= 'z')) {
|
1127 |
|
|
ps2kbd_current_key -= 96;
|
1128 |
|
|
}
|
1129 |
|
|
} else if (ps2kbd_current_modifiers & (MWKMOD_LSHIFT | MWKMOD_RSHIFT)) {
|
1130 |
|
|
// Pick up the shift entry from the keymap
|
1131 |
|
|
ps2kbd_current_key = ps2kbd_keymap[scancode].shifted;
|
1132 |
|
|
}
|
1133 |
|
|
|
1134 |
|
|
if (ps2kbd_current_modifiers & MWKMOD_CAPS) {
|
1135 |
|
|
// Capslock only affects a-z and A-z
|
1136 |
|
|
if ( ('a' <= ps2kbd_current_key) && (ps2kbd_current_key <= 'z')) {
|
1137 |
|
|
ps2kbd_current_key = (ps2kbd_current_key -'a') + 'A';
|
1138 |
|
|
} else if (('A' <= ps2kbd_current_key) && (ps2kbd_current_key <= 'Z')) {
|
1139 |
|
|
ps2kbd_current_key = (ps2kbd_current_key -'A') + 'a';
|
1140 |
|
|
}
|
1141 |
|
|
}
|
1142 |
|
|
|
1143 |
|
|
// If we have found a real key, the loop will exit.
|
1144 |
|
|
// Otherwise try again.
|
1145 |
|
|
}
|
1146 |
|
|
}
|
1147 |
|
|
|
1148 |
|
|
static int
|
1149 |
|
|
PS2Kbd_Open(KBDDEVICE* pkbd)
|
1150 |
|
|
{
|
1151 |
|
|
unsigned char buf[1];
|
1152 |
|
|
ps2_initialize();
|
1153 |
|
|
buf[0] = KC_KBDC_ENABLE;
|
1154 |
|
|
ps2_send_command_wait(KC_CONTROL_NULL, buf, 1, 0);
|
1155 |
|
|
}
|
1156 |
|
|
|
1157 |
|
|
static void
|
1158 |
|
|
PS2Kbd_Close(void)
|
1159 |
|
|
{
|
1160 |
|
|
unsigned char buf[1];
|
1161 |
|
|
buf[0] = KC_KBDC_STANDARD_DISABLE;
|
1162 |
|
|
ps2_send_command_wait(KC_CONTROL_NULL, buf, 1, 0);
|
1163 |
|
|
}
|
1164 |
|
|
|
1165 |
|
|
static void
|
1166 |
|
|
PS2Kbd_GetModifierInfo(MWKEYMOD* modifiers, MWKEYMOD* curmodifiers)
|
1167 |
|
|
{
|
1168 |
|
|
if (NULL != modifiers) {
|
1169 |
|
|
*modifiers = MWKMOD_LSHIFT | MWKMOD_RSHIFT | MWKMOD_LCTRL | MWKMOD_RCTRL |
|
1170 |
|
|
MWKMOD_LALT | MWKMOD_RALT | MWKMOD_LMETA | MWKMOD_RMETA |
|
1171 |
|
|
MWKMOD_NUM | MWKMOD_CAPS | MWKMOD_ALTGR | MWKMOD_SCR;
|
1172 |
|
|
}
|
1173 |
|
|
if (NULL != curmodifiers) {
|
1174 |
|
|
*modifiers = ps2kbd_current_modifiers;
|
1175 |
|
|
}
|
1176 |
|
|
}
|
1177 |
|
|
|
1178 |
|
|
// Note: it is assumed that there are no concurrent calls to
|
1179 |
|
|
// the poll and read functions.
|
1180 |
|
|
static int
|
1181 |
|
|
PS2Kbd_Poll(void)
|
1182 |
|
|
{
|
1183 |
|
|
if (MWKEY_UNKNOWN == ps2kbd_current_key) {
|
1184 |
|
|
ps2kbd_process_scancodes();
|
1185 |
|
|
}
|
1186 |
|
|
return MWKEY_UNKNOWN != ps2kbd_current_key;
|
1187 |
|
|
}
|
1188 |
|
|
|
1189 |
|
|
// Return -1 on error, 0 for no data, 1 for a keypress, 2 for a keyrelease.
|
1190 |
|
|
static int
|
1191 |
|
|
PS2Kbd_Read(MWKEY* buf, MWKEYMOD* modifiers, MWSCANCODE* scancode)
|
1192 |
|
|
{
|
1193 |
|
|
if (MWKEY_UNKNOWN == ps2kbd_current_key) {
|
1194 |
|
|
ps2kbd_process_scancodes();
|
1195 |
|
|
if (MWKEY_UNKNOWN == ps2kbd_current_key) {
|
1196 |
|
|
return 0;
|
1197 |
|
|
}
|
1198 |
|
|
}
|
1199 |
|
|
|
1200 |
|
|
if (NULL != buf) {
|
1201 |
|
|
*buf = ps2kbd_current_key;
|
1202 |
|
|
}
|
1203 |
|
|
if (NULL != modifiers) {
|
1204 |
|
|
*modifiers = ps2kbd_current_modifiers;
|
1205 |
|
|
}
|
1206 |
|
|
if (NULL != scancode) {
|
1207 |
|
|
*scancode = ps2kbd_current_scancode;
|
1208 |
|
|
}
|
1209 |
|
|
ps2kbd_current_key = MWKEY_UNKNOWN;
|
1210 |
|
|
return ps2kbd_current_keydown ? 1 : 2;
|
1211 |
|
|
}
|
1212 |
|
|
|
1213 |
|
|
KBDDEVICE kbddev = {
|
1214 |
|
|
PS2Kbd_Open,
|
1215 |
|
|
PS2Kbd_Close,
|
1216 |
|
|
PS2Kbd_GetModifierInfo,
|
1217 |
|
|
PS2Kbd_Read,
|
1218 |
|
|
PS2Kbd_Poll
|
1219 |
|
|
};
|
1220 |
|
|
|
1221 |
|
|
#if 0
|
1222 |
|
|
// ----------------------------------------------------------------------------
|
1223 |
|
|
// This code can be used for testing the mouse and keyboard without all
|
1224 |
|
|
// of microwindows present (although the microwindows headers must still be
|
1225 |
|
|
// visible).
|
1226 |
|
|
|
1227 |
|
|
#include <stdio.h>
|
1228 |
|
|
#include <ctype.h>
|
1229 |
|
|
int
|
1230 |
|
|
main(int argc, char** argv)
|
1231 |
|
|
{
|
1232 |
|
|
PS2Kbd_Open(&kbddev);
|
1233 |
|
|
PS2Mouse_Open(&mousedev);
|
1234 |
|
|
for ( ; ; ) {
|
1235 |
|
|
while (PS2Mouse_Poll()) {
|
1236 |
|
|
MWCOORD dx, dy, dz;
|
1237 |
|
|
int buttons;
|
1238 |
|
|
PS2Mouse_Read(&dx, &dy, &dz, &buttons);
|
1239 |
|
|
printf("Mouse movement: dx %d, dy %d, dz %d, buttons 0x%02x\n", dx, dy, dz, buttons);
|
1240 |
|
|
}
|
1241 |
|
|
while (PS2Kbd_Poll()) {
|
1242 |
|
|
MWKEY key;
|
1243 |
|
|
MWKEYMOD modifiers;
|
1244 |
|
|
MWSCANCODE scancode;
|
1245 |
|
|
int which;
|
1246 |
|
|
which = PS2Kbd_Read(&key, &modifiers, &scancode);
|
1247 |
|
|
printf("Keyboard event: %s, key %c (%d) (0x%02x), modifiers 0x%02x, scancode %d (0x%02x)\n",
|
1248 |
|
|
(1 == which) ? "press" : "release", isprint(key) ? key : '?', key, key, modifiers, scancode, scancode);
|
1249 |
|
|
}
|
1250 |
|
|
}
|
1251 |
|
|
}
|
1252 |
|
|
#endif
|