]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/drivers/ps2kbdmou_ecos.c
Initial revision
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / drivers / ps2kbdmou_ecos.c
1 //=============================================================================
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