/[gxemul]/trunk/src/devices/dev_pckbc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/devices/dev_pckbc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (show annotations)
Mon Oct 8 16:20:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 25286 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


1 /*
2 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: dev_pckbc.c,v 1.69 2006/07/25 18:58:02 debug Exp $
29 *
30 * Standard 8042 PC keyboard controller (and a 8242WB PS2 keyboard/mouse
31 * controller), including the 8048 keyboard chip.
32 *
33 * Quick source of good info: http://my.execpc.com/~geezer/osd/kbd/kbd.txt
34 *
35 *
36 * TODOs:
37 * Finish the rewrite for 8242.
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include "console.h"
45 #include "cpu.h"
46 #include "devices.h"
47 #include "machine.h"
48 #include "memory.h"
49 #include "misc.h"
50
51 #include "kbdreg.h"
52
53
54 /* #define PCKBC_DEBUG */
55 /* #define debug fatal */
56
57
58 #define MAX_8042_QUEUELEN 256
59
60 #define PC_DATA 0
61 #define PC_CMD 0
62 #define PC_STATUS 1
63
64 #define PS2_TXBUF 0
65 #define PS2_RXBUF 1
66 #define PS2_CONTROL 2
67 #define PS2_STATUS 3
68
69 #define PS2 100
70
71 #define PCKBC_TICKSHIFT 15
72
73 struct pckbc_data {
74 int console_handle;
75 int in_use;
76
77 int reg[DEV_PCKBC_LENGTH];
78 int keyboard_irqnr;
79 int mouse_irqnr;
80 int currently_asserted[2];
81 int type;
82 int pc_style_flag;
83
84 /* TODO: one of these for each port? */
85 int clocksignal;
86 int rx_int_enable;
87 int tx_int_enable;
88
89 int keyscanning_enabled;
90 int translation_table;
91 int state;
92 int cmdbyte;
93 int output_byte;
94 int last_scancode;
95
96 unsigned key_queue[2][MAX_8042_QUEUELEN];
97 int head[2], tail[2];
98 };
99
100 #define STATE_NORMAL 0
101 #define STATE_LDCMDBYTE 1
102 #define STATE_RDCMDBYTE 2
103 #define STATE_WAITING_FOR_TRANSLTABLE 3
104 #define STATE_WAITING_FOR_RATE 4
105 #define STATE_WAITING_FOR_ONEKEY_MB 5
106 #define STATE_WAITING_FOR_AUX 6
107 #define STATE_WAITING_FOR_AUX_OUT 7
108 #define STATE_LDOUTPUT 8
109 #define STATE_RDOUTPUT 9
110
111
112 /*
113 * pckbc_add_code():
114 *
115 * Adds a byte to the data queue.
116 */
117 void pckbc_add_code(struct pckbc_data *d, int code, int port)
118 {
119 /* Add at the head, read at the tail: */
120 d->head[port] = (d->head[port]+1) % MAX_8042_QUEUELEN;
121 if (d->head[port] == d->tail[port])
122 fatal("[ pckbc: queue overrun, port %i! ]\n", port);
123
124 d->key_queue[port][d->head[port]] = code;
125 }
126
127
128 /*
129 * pckbc_get_code():
130 *
131 * Reads a byte from a data queue.
132 */
133 int pckbc_get_code(struct pckbc_data *d, int port)
134 {
135 if (d->head[port] == d->tail[port])
136 fatal("[ pckbc: queue empty, port %i! ]\n", port);
137 else
138 d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN;
139 return d->key_queue[port][d->tail[port]];
140 }
141
142
143 /*
144 * ascii_to_scancodes_type3():
145 *
146 * Conversion from ASCII codes to default (US) keyboard scancodes.
147 * (See http://www.computer-engineering.org/ps2keyboard/scancodes3.html)
148 */
149 static void ascii_to_pc_scancodes_type3(int a, struct pckbc_data *d)
150 {
151 int old_head;
152 int p = 0; /* port */
153 int shift = 0, ctrl = 0;
154
155 if (a >= 'A' && a <= 'Z') { a += 32; shift = 1; }
156 if ((a >= 1 && a <= 26) && (a!='\n' && a!='\t' && a!='\b' && a!='\r'))
157 { a += 96; ctrl = 1; }
158 if (a=='!') { a = '1'; shift = 1; }
159 if (a=='@') { a = '2'; shift = 1; }
160 if (a=='#') { a = '3'; shift = 1; }
161 if (a=='$') { a = '4'; shift = 1; }
162 if (a=='%') { a = '5'; shift = 1; }
163 if (a=='^') { a = '6'; shift = 1; }
164 if (a=='&') { a = '7'; shift = 1; }
165 if (a=='*') { a = '8'; shift = 1; }
166 if (a=='(') { a = '9'; shift = 1; }
167 if (a==')') { a = '0'; shift = 1; }
168 if (a=='_') { a = '-'; shift = 1; }
169 if (a=='+') { a = '='; shift = 1; }
170 if (a=='{') { a = '['; shift = 1; }
171 if (a=='}') { a = ']'; shift = 1; }
172 if (a==':') { a = ';'; shift = 1; }
173 if (a=='"') { a = '\''; shift = 1; }
174 if (a=='|') { a = '\\'; shift = 1; }
175 if (a=='<') { a = ','; shift = 1; }
176 if (a=='>') { a = '.'; shift = 1; }
177 if (a=='?') { a = '/'; shift = 1; }
178
179 if (shift)
180 pckbc_add_code(d, 0x12, p);
181 if (ctrl)
182 pckbc_add_code(d, 0x11, p);
183
184 /*
185 * Note: The ugly hack used to add release codes for all of these
186 * keys is as follows: we remember how much of the kbd buf that
187 * is in use here, before we add any scancode. After we've added
188 * one or more scancodes (ie an optional shift + another key)
189 * then we add 0xf0 + the last scancode _if_ the kbd buf was altered.
190 */
191
192 old_head = d->head[p];
193
194 if (a==27) pckbc_add_code(d, 0x08, p);
195
196 if (a=='1') pckbc_add_code(d, 0x16, p);
197 if (a=='2') pckbc_add_code(d, 0x1e, p);
198 if (a=='3') pckbc_add_code(d, 0x26, p);
199 if (a=='4') pckbc_add_code(d, 0x25, p);
200 if (a=='5') pckbc_add_code(d, 0x2e, p);
201 if (a=='6') pckbc_add_code(d, 0x36, p);
202 if (a=='7') pckbc_add_code(d, 0x3d, p);
203 if (a=='8') pckbc_add_code(d, 0x3e, p);
204 if (a=='9') pckbc_add_code(d, 0x46, p);
205 if (a=='0') pckbc_add_code(d, 0x45, p);
206 if (a=='-') pckbc_add_code(d, 0x4e, p);
207 if (a=='=') pckbc_add_code(d, 0x55, p);
208
209 if (a=='\b') pckbc_add_code(d, 0x29, p);
210
211 if (a=='\t') pckbc_add_code(d, 0x0d, p);
212 if (a=='q') pckbc_add_code(d, 0x15, p);
213 if (a=='w') pckbc_add_code(d, 0x1d, p);
214 if (a=='e') pckbc_add_code(d, 0x24, p);
215 if (a=='r') pckbc_add_code(d, 0x2d, p);
216 if (a=='t') pckbc_add_code(d, 0x2c, p);
217 if (a=='y') pckbc_add_code(d, 0x35, p);
218 if (a=='u') pckbc_add_code(d, 0x3c, p);
219 if (a=='i') pckbc_add_code(d, 0x43, p);
220 if (a=='o') pckbc_add_code(d, 0x44, p);
221 if (a=='p') pckbc_add_code(d, 0x4d, p);
222
223 if (a=='[') pckbc_add_code(d, 0x54, p);
224 if (a==']') pckbc_add_code(d, 0x5b, p);
225
226 if (a=='\n' || a=='\r') pckbc_add_code(d, 0x5a, p);
227
228 if (a=='a') pckbc_add_code(d, 0x1c, p);
229 if (a=='s') pckbc_add_code(d, 0x1b, p);
230 if (a=='d') pckbc_add_code(d, 0x23, p);
231 if (a=='f') pckbc_add_code(d, 0x2b, p);
232 if (a=='g') pckbc_add_code(d, 0x34, p);
233 if (a=='h') pckbc_add_code(d, 0x33, p);
234 if (a=='j') pckbc_add_code(d, 0x3b, p);
235 if (a=='k') pckbc_add_code(d, 0x42, p);
236 if (a=='l') pckbc_add_code(d, 0x4b, p);
237
238 if (a==';') pckbc_add_code(d, 0x4c, p);
239 if (a=='\'') pckbc_add_code(d, 0x52, p);
240 /* if (a=='~') pckbc_add_code(d, 0x29, p); ? */
241 if (a=='\\') pckbc_add_code(d, 0x5c, p);
242
243 if (a=='z') pckbc_add_code(d, 0x1a, p);
244 if (a=='x') pckbc_add_code(d, 0x22, p);
245 if (a=='c') pckbc_add_code(d, 0x21, p);
246 if (a=='v') pckbc_add_code(d, 0x2a, p);
247 if (a=='b') pckbc_add_code(d, 0x32, p);
248 if (a=='n') pckbc_add_code(d, 0x31, p);
249 if (a=='m') pckbc_add_code(d, 0x3a, p);
250
251 if (a==',') pckbc_add_code(d, 0x41, p);
252 if (a=='.') pckbc_add_code(d, 0x49, p);
253 if (a=='/') pckbc_add_code(d, 0x4a, p);
254
255 if (a==' ') pckbc_add_code(d, 0x29, p);
256
257 /* Add release code, if a key was pressed: */
258 if (d->head[p] != old_head) {
259 int code = d->key_queue[p][d->head[p]];
260 pckbc_add_code(d, 0xf0, p);
261 pckbc_add_code(d, code, p);
262 }
263
264 /* Release shift and ctrl: */
265 if (shift) {
266 pckbc_add_code(d, 0xf0, p);
267 pckbc_add_code(d, 0x12, p);
268 }
269 if (ctrl) {
270 pckbc_add_code(d, 0xf0, p);
271 pckbc_add_code(d, 0x11, p);
272 }
273 }
274
275
276 /*
277 * ascii_to_scancodes_type2():
278 *
279 * Conversion from ASCII codes to default (US) keyboard scancodes.
280 * (See http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html)
281 *
282 * NOTE/TODO: This seems to be type 2, not type 1.
283 */
284 static void ascii_to_pc_scancodes_type2(int a, struct pckbc_data *d)
285 {
286 int old_head;
287 int p = 0; /* port */
288 int shift = 0, ctrl = 0;
289
290 if (d->translation_table == 3) {
291 ascii_to_pc_scancodes_type3(a, d);
292 return;
293 }
294
295 if (d->translation_table != 2) {
296 fatal("[ ascii_to_pc_scancodes: unimplemented type! ]\n");
297 return;
298 }
299
300 if (a >= 'A' && a <= 'Z') { a += 32; shift = 1; }
301 if ((a >= 1 && a <= 26) && (a!='\n' && a!='\t' && a!='\b' && a!='\r'))
302 { a += 96; ctrl = 1; }
303
304 if (a=='!') { a = '1'; shift = 1; }
305 if (a=='@') { a = '2'; shift = 1; }
306 if (a=='#') { a = '3'; shift = 1; }
307 if (a=='$') { a = '4'; shift = 1; }
308 if (a=='%') { a = '5'; shift = 1; }
309 if (a=='^') { a = '6'; shift = 1; }
310 if (a=='&') { a = '7'; shift = 1; }
311 if (a=='*') { a = '8'; shift = 1; }
312 if (a=='(') { a = '9'; shift = 1; }
313 if (a==')') { a = '0'; shift = 1; }
314 if (a=='_') { a = '-'; shift = 1; }
315 if (a=='+') { a = '='; shift = 1; }
316 if (a=='{') { a = '['; shift = 1; }
317 if (a=='}') { a = ']'; shift = 1; }
318 if (a==':') { a = ';'; shift = 1; }
319 if (a=='"') { a = '\''; shift = 1; }
320 if (a=='|') { a = '\\'; shift = 1; }
321 if (a=='<') { a = ','; shift = 1; }
322 if (a=='>') { a = '.'; shift = 1; }
323 if (a=='?') { a = '/'; shift = 1; }
324 if (a=='~') { a = '`'; shift = 1; }
325
326 if (shift)
327 pckbc_add_code(d, 0x2a, p);
328 else
329 pckbc_add_code(d, 0x2a + 0x80, p);
330
331 if (ctrl)
332 pckbc_add_code(d, 0x1d, p);
333
334 /*
335 * Note: The ugly hack used to add release codes for all of these
336 * keys is as follows: we remember how much of the kbd buf that
337 * is in use here, before we add any scancode. After we've added
338 * one or more scancodes (ie an optional shift + another key)
339 * then we duplicate the last scancode | 0x80 _if_ the kbd buf
340 * was altered.
341 */
342
343 old_head = d->head[p];
344
345 if (a==27) pckbc_add_code(d, 0x01, p);
346
347 if (a=='1') pckbc_add_code(d, 0x02, p);
348 if (a=='2') pckbc_add_code(d, 0x03, p);
349 if (a=='3') pckbc_add_code(d, 0x04, p);
350 if (a=='4') pckbc_add_code(d, 0x05, p);
351 if (a=='5') pckbc_add_code(d, 0x06, p);
352 if (a=='6') pckbc_add_code(d, 0x07, p);
353 if (a=='7') pckbc_add_code(d, 0x08, p);
354 if (a=='8') pckbc_add_code(d, 0x09, p);
355 if (a=='9') pckbc_add_code(d, 0x0a, p);
356 if (a=='0') pckbc_add_code(d, 0x0b, p);
357 if (a=='-') pckbc_add_code(d, 0x0c, p);
358 if (a=='=') pckbc_add_code(d, 0x0d, p);
359
360 if (a=='!') { pckbc_add_code(d, 0x2a, p);
361 pckbc_add_code(d, 0x02, p); }
362 if (a=='@') { pckbc_add_code(d, 0x2a, p);
363 pckbc_add_code(d, 0x03, p); }
364 if (a=='#') { pckbc_add_code(d, 0x2a, p);
365 pckbc_add_code(d, 0x04, p); }
366 if (a=='$') { pckbc_add_code(d, 0x2a, p);
367 pckbc_add_code(d, 0x05, p); }
368 if (a=='%') { pckbc_add_code(d, 0x2a, p);
369 pckbc_add_code(d, 0x06, p); }
370 if (a=='^') { pckbc_add_code(d, 0x2a, p);
371 pckbc_add_code(d, 0x07, p); }
372 if (a=='&') { pckbc_add_code(d, 0x2a, p);
373 pckbc_add_code(d, 0x08, p); }
374 if (a=='*') { pckbc_add_code(d, 0x2a, p);
375 pckbc_add_code(d, 0x09, p); }
376 if (a=='(') { pckbc_add_code(d, 0x2a, p);
377 pckbc_add_code(d, 0x0a, p); }
378
379 if (a=='\b') pckbc_add_code(d, 0x0e, p);
380
381 if (a=='\t') pckbc_add_code(d, 0x0f, p);
382 if (a=='q') pckbc_add_code(d, 0x10, p);
383 if (a=='w') pckbc_add_code(d, 0x11, p);
384 if (a=='e') pckbc_add_code(d, 0x12, p);
385 if (a=='r') pckbc_add_code(d, 0x13, p);
386 if (a=='t') pckbc_add_code(d, 0x14, p);
387 if (a=='y') pckbc_add_code(d, 0x15, p);
388 if (a=='u') pckbc_add_code(d, 0x16, p);
389 if (a=='i') pckbc_add_code(d, 0x17, p);
390 if (a=='o') pckbc_add_code(d, 0x18, p);
391 if (a=='p') pckbc_add_code(d, 0x19, p);
392
393 if (a=='[') pckbc_add_code(d, 0x1a, p);
394 if (a==']') pckbc_add_code(d, 0x1b, p);
395
396 if (a=='\n' || a=='\r') pckbc_add_code(d, 0x1c, p);
397
398 if (a=='a') pckbc_add_code(d, 0x1e, p);
399 if (a=='s') pckbc_add_code(d, 0x1f, p);
400 if (a=='d') pckbc_add_code(d, 0x20, p);
401 if (a=='f') pckbc_add_code(d, 0x21, p);
402 if (a=='g') pckbc_add_code(d, 0x22, p);
403 if (a=='h') pckbc_add_code(d, 0x23, p);
404 if (a=='j') pckbc_add_code(d, 0x24, p);
405 if (a=='k') pckbc_add_code(d, 0x25, p);
406 if (a=='l') pckbc_add_code(d, 0x26, p);
407
408 if (a==';') pckbc_add_code(d, 0x27, p);
409 if (a=='\'') pckbc_add_code(d, 0x28, p);
410 if (a=='`') pckbc_add_code(d, 0x29, p);
411 if (a=='\\') pckbc_add_code(d, 0x2b, p);
412
413 if (a=='z') pckbc_add_code(d, 0x2c, p);
414 if (a=='x') pckbc_add_code(d, 0x2d, p);
415 if (a=='c') pckbc_add_code(d, 0x2e, p);
416 if (a=='v') pckbc_add_code(d, 0x2f, p);
417 if (a=='b') pckbc_add_code(d, 0x30, p);
418 if (a=='n') pckbc_add_code(d, 0x31, p);
419 if (a=='m') pckbc_add_code(d, 0x32, p);
420
421 if (a==',') pckbc_add_code(d, 0x33, p);
422 if (a=='.') pckbc_add_code(d, 0x34, p);
423 if (a=='/') pckbc_add_code(d, 0x35, p);
424
425 if (a==' ') pckbc_add_code(d, 0x39, p);
426
427 /* Add release code, if a key was pressed: */
428 if (d->head[p] != old_head) {
429 int code = d->key_queue[p][d->head[p]] | 0x80;
430 pckbc_add_code(d, code, p);
431 }
432
433 /* Release ctrl: */
434 if (ctrl)
435 pckbc_add_code(d, 0x1d + 0x80, p);
436 }
437
438
439 /*
440 * dev_pckbc_tick():
441 */
442 void dev_pckbc_tick(struct cpu *cpu, void *extra)
443 {
444 struct pckbc_data *d = extra;
445 int port_nr, ch, ints_enabled;
446
447 if (d->in_use && console_charavail(d->console_handle)) {
448 ch = console_readchar(d->console_handle);
449 if (ch >= 0)
450 ascii_to_pc_scancodes_type2(ch, d);
451 }
452
453 ints_enabled = d->rx_int_enable;
454
455 /* TODO: mouse movements? */
456
457 if (d->cmdbyte & KC8_KDISABLE)
458 ints_enabled = 0;
459
460 for (port_nr=0; port_nr<2; port_nr++) {
461 /* Cause receive interrupt, if there's something in the
462 receive buffer: (Otherwise deassert the interrupt.) */
463 int irq = port_nr==0? d->keyboard_irqnr : d->mouse_irqnr;
464
465 if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) {
466 debug("[ pckbc: interrupt port %i ]\n", port_nr);
467 cpu_interrupt(cpu, irq);
468 d->currently_asserted[port_nr] = 1;
469 } else {
470 if (d->currently_asserted[port_nr])
471 cpu_interrupt_ack(cpu, irq);
472 d->currently_asserted[port_nr] = 0;
473 }
474 }
475 }
476
477
478 /*
479 * dev_pckbc_command():
480 *
481 * Handle commands to the 8048 in the emulated keyboard.
482 */
483 static void dev_pckbc_command(struct pckbc_data *d, int port_nr)
484 {
485 int cmd = d->reg[PC_CMD];
486
487 if (d->type == PCKBC_8242)
488 cmd = d->reg[PS2_TXBUF];
489
490 if (d->state == STATE_WAITING_FOR_TRANSLTABLE) {
491 debug("[ pckbc: (port %i) switching to translation table "
492 "0x%02x ]\n", port_nr, cmd);
493 switch (cmd) {
494 case 2:
495 case 3: d->translation_table = cmd;
496 break;
497 default:fatal("[ pckbc: (port %i) translation table "
498 "0x%02x is NOT YET IMPLEMENTED ]\n",
499 port_nr, cmd);
500 }
501 pckbc_add_code(d, KBR_ACK, port_nr);
502 d->state = STATE_NORMAL;
503 return;
504 }
505
506 if (d->state == STATE_WAITING_FOR_RATE) {
507 debug("[ pckbc: (port %i) received Typematic Rate data: "
508 "0x%02x ]\n", port_nr, cmd);
509 pckbc_add_code(d, KBR_ACK, port_nr);
510 d->state = STATE_NORMAL;
511 return;
512 }
513
514 if (d->state == STATE_WAITING_FOR_ONEKEY_MB) {
515 debug("[ pckbc: (port %i) received One-key make/break data: "
516 "0x%02x ]\n", port_nr, cmd);
517 pckbc_add_code(d, KBR_ACK, port_nr);
518 d->state = STATE_NORMAL;
519 return;
520 }
521
522 if (d->state == STATE_WAITING_FOR_AUX) {
523 debug("[ pckbc: (port %i) received aux data: "
524 "0x%02x ]\n", port_nr, cmd);
525 /* Echo back. */
526 pckbc_add_code(d, cmd, port_nr);
527 d->state = STATE_NORMAL;
528 return;
529 }
530
531 if (d->state == STATE_WAITING_FOR_AUX_OUT) {
532 debug("[ pckbc: (port %i) received aux out data: "
533 "0x%02x ]\n", port_nr, cmd);
534 /* Echo back. */
535 pckbc_add_code(d, cmd, port_nr);
536 d->state = STATE_NORMAL;
537 return;
538 }
539
540 switch (cmd) {
541
542 case 0x00:
543 /*
544 * TODO: What does this do? This is possibly due to an
545 * error in the handling of some other command code.
546 */
547 pckbc_add_code(d, KBR_ACK, port_nr);
548 break;
549
550 case KBC_MODEIND: /* Set LEDs */
551 /* Just ACK, no LEDs are actually set. */
552 pckbc_add_code(d, KBR_ACK, port_nr);
553 break;
554
555 case KBC_SETTABLE:
556 pckbc_add_code(d, KBR_ACK, port_nr);
557 d->state = STATE_WAITING_FOR_TRANSLTABLE;
558 break;
559
560 case KBC_ENABLE:
561 d->keyscanning_enabled = 1;
562 pckbc_add_code(d, KBR_ACK, port_nr);
563 break;
564
565 case KBC_DISABLE:
566 d->keyscanning_enabled = 0;
567 pckbc_add_code(d, KBR_ACK, port_nr);
568 break;
569
570 case KBC_SETDEFAULT:
571 pckbc_add_code(d, KBR_ACK, port_nr);
572 break;
573
574 case KBC_GETID:
575 /* Get keyboard ID. NOTE/TODO: Ugly hardcoded answer. */
576 pckbc_add_code(d, KBR_ACK, port_nr);
577 pckbc_add_code(d, 0xab, port_nr);
578 pckbc_add_code(d, 0x41, port_nr);
579 break;
580
581 case KBC_TYPEMATIC:
582 /* Set typematic (auto-repeat) delay/speed: */
583 pckbc_add_code(d, KBR_ACK, port_nr);
584 d->state = STATE_WAITING_FOR_RATE;
585 break;
586
587 case KBC_ALLKEYS_TMB:
588 /* "Make all keys typematic/make/break" */
589 pckbc_add_code(d, KBR_ACK, port_nr);
590 break;
591
592 case KBC_ONEKEY_MB:
593 /* "Make one key typematic/make/break" */
594 pckbc_add_code(d, KBR_ACK, port_nr);
595 d->state = STATE_WAITING_FOR_ONEKEY_MB;
596 break;
597
598 case KBC_RESET:
599 pckbc_add_code(d, KBR_ACK, port_nr);
600 pckbc_add_code(d, KBR_RSTDONE, port_nr);
601 /*
602 * Disable interrupts during reset, or Linux 2.6
603 * prints warnings about spurious interrupts.
604 */
605 d->rx_int_enable = 0;
606 break;
607
608 default:
609 fatal("[ pckbc: (port %i) UNIMPLEMENTED 8048 command"
610 " 0x%02x ]\n", port_nr, cmd);
611 exit(1);
612 }
613 }
614
615
616 DEVICE_ACCESS(pckbc)
617 {
618 uint64_t idata = 0, odata = 0;
619 int port_nr = 0;
620 size_t i;
621 struct pckbc_data *d = extra;
622
623 if (writeflag == MEM_WRITE)
624 idata = memory_readmax64(cpu, data, len);
625
626 #ifdef PCKBC_DEBUG
627 if (writeflag == MEM_WRITE)
628 fatal("[ pckbc: write to addr 0x%x: 0x%x ]\n",
629 (int)relative_addr, (int)idata);
630 else
631 fatal("[ pckbc: read from addr 0x%x ]\n",
632 (int)relative_addr);
633 #endif
634
635 /* For JAZZ-based machines: */
636 if (relative_addr >= 0x60) {
637 relative_addr -= 0x60;
638 if (relative_addr != 0)
639 relative_addr = 1;
640 } else if (d->type == PCKBC_8242) {
641 /* 8242 PS2-style: */
642 /* when using 8-byte alignment... */
643 relative_addr /= sizeof(uint64_t);
644 /* port_nr = 0 for keyboard, 1 for mouse */
645 port_nr = (relative_addr >> 2);
646 relative_addr &= 3;
647 relative_addr += PS2;
648 } else if (d->pc_style_flag) {
649 /* PC-style: */
650 if (relative_addr != 0 && relative_addr != 4) {
651 /* TODO (port 0x61) */
652 odata = 0x21;
653 {
654 static int x = 0;
655 x++;
656 if (x&1)
657 odata ^= 0x10;
658 }
659 if (writeflag == MEM_READ)
660 memory_writemax64(cpu, data, len, odata);
661 return 0;
662 }
663 if (relative_addr != 0)
664 relative_addr = 1;
665 } else {
666 /* Others... Non-Jazz ARC-based machines etc. */
667 if (relative_addr != 0)
668 relative_addr = 1;
669 }
670
671 switch (relative_addr) {
672
673 /*
674 * 8042 (PC):
675 */
676
677 case 0: /* data */
678 if (writeflag==MEM_READ) {
679 switch (d->state) {
680 case STATE_RDCMDBYTE:
681 odata = d->cmdbyte;
682 d->state = STATE_NORMAL;
683 break;
684 case STATE_RDOUTPUT:
685 odata = d->output_byte;
686 d->state = STATE_NORMAL;
687 break;
688 default:if (d->head[0] != d->tail[0]) {
689 odata = pckbc_get_code(d, 0);
690 d->last_scancode = odata;
691 } else {
692 odata = d->last_scancode;
693 d->last_scancode |= 0x80;
694 }
695 }
696 /* debug("[ pckbc: read from DATA: 0x%02x ]\n",
697 (int)odata); */
698 } else {
699 debug("[ pckbc: write to DATA:");
700 for (i=0; i<len; i++)
701 debug(" %02x", data[i]);
702 debug(" ]\n");
703
704 switch (d->state) {
705 case STATE_LDCMDBYTE:
706 d->cmdbyte = idata;
707 d->rx_int_enable = d->cmdbyte &
708 (KC8_KENABLE | KC8_MENABLE) ? 1 : 0;
709 d->state = STATE_NORMAL;
710 break;
711 case STATE_LDOUTPUT:
712 d->output_byte = idata;
713 d->state = STATE_NORMAL;
714 break;
715 default:d->reg[relative_addr] = idata;
716 dev_pckbc_command(d, port_nr);
717 }
718 }
719 break;
720 case 1: /* control */
721 if (writeflag==MEM_READ) {
722 dev_pckbc_tick(cpu, d);
723
724 odata = 0;
725
726 /* "Data in buffer" bit */
727 if (d->head[0] != d->tail[0] ||
728 d->state == STATE_RDCMDBYTE ||
729 d->state == STATE_RDOUTPUT)
730 odata |= KBS_DIB;
731
732 if (d->state == STATE_RDCMDBYTE)
733 odata |= KBS_OCMD;
734
735 odata |= KBS_NOSEC;
736 /* debug("[ pckbc: read from CTL status port: "
737 "0x%02x ]\n", (int)odata); */
738 } else {
739 debug("[ pckbc: write to CTL:");
740 for (i=0; i<len; i++)
741 debug(" %02x", data[i]);
742 debug(" ]\n");
743 d->reg[relative_addr] = idata;
744
745 switch (idata) {
746 case 0x10:
747 case 0x11:
748 /* TODO: For now, don't print warnings about
749 these. NetBSD sends these. */
750 break;
751 case K_RDCMDBYTE:
752 d->state = STATE_RDCMDBYTE;
753 break;
754 case K_LDCMDBYTE:
755 d->state = STATE_LDCMDBYTE;
756 break;
757 case 0xa7:
758 d->cmdbyte |= KC8_MDISABLE;
759 break;
760 case 0xa8:
761 d->cmdbyte &= ~KC8_MDISABLE;
762 break;
763 case 0xa9: /* test auxiliary port */
764 debug("[ pckbc: CONTROL 0xa9, TODO ]\n");
765 break;
766 case 0xaa: /* keyboard self-test */
767 pckbc_add_code(d, 0x55, port_nr);
768 break;
769 case 0xab: /* keyboard interface self-test */
770 pckbc_add_code(d, 0x00, port_nr);
771 break;
772 case 0xad:
773 d->cmdbyte |= KC8_KDISABLE;
774 break;
775 case 0xae:
776 d->cmdbyte &= ~KC8_KDISABLE;
777 break;
778 case 0xd0:
779 d->state = STATE_RDOUTPUT;
780 break;
781 case 0xd1:
782 d->state = STATE_LDOUTPUT;
783 break;
784 case 0xd3: /* write to auxiliary device
785 output buffer */
786 debug("[ pckbc: CONTROL 0xd3, TODO ]\n");
787 d->state = STATE_WAITING_FOR_AUX_OUT;
788 break;
789 case 0xd4: /* write to auxiliary port */
790 debug("[ pckbc: CONTROL 0xd4, TODO ]\n");
791 d->state = STATE_WAITING_FOR_AUX;
792 break;
793 default:
794 fatal("[ pckbc: unknown CONTROL 0x%x ]\n",
795 (int)idata);
796 d->state = STATE_NORMAL;
797 }
798 }
799 break;
800
801 /*
802 * 8242 (PS2):
803 */
804
805 case PS2 + PS2_TXBUF:
806 if (writeflag==MEM_READ) {
807 odata = random() & 0xff;
808 debug("[ pckbc: read from port %i, PS2_TXBUF: "
809 "0x%x ]\n", port_nr, (int)odata);
810 } else {
811 debug("[ pckbc: write to port %i, PS2_TXBUF: "
812 "0x%llx ]\n", port_nr, (long long)idata);
813
814 /* Handle keyboard commands: */
815 d->reg[PS2_TXBUF] = idata;
816 dev_pckbc_command(d, port_nr);
817 }
818 break;
819
820 case PS2 + PS2_RXBUF:
821 if (writeflag==MEM_READ) {
822 /* TODO: What should be returned if no data
823 is available? */
824 odata = random() & 0xff;
825 if (d->head[port_nr] != d->tail[port_nr])
826 odata = pckbc_get_code(d, port_nr);
827 debug("[ pckbc: read from port %i, PS2_RXBUF: "
828 "0x%02x ]\n", port_nr, (int)odata);
829 } else {
830 debug("[ pckbc: write to port %i, PS2_RXBUF: "
831 "0x%llx ]\n", port_nr, (long long)idata);
832 }
833 break;
834
835 case PS2 + PS2_CONTROL:
836 if (writeflag==MEM_READ) {
837 debug("[ pckbc: read from port %i, PS2_CONTROL"
838 " ]\n", port_nr);
839 } else {
840 debug("[ pckbc: write to port %i, PS2_CONTROL:"
841 " 0x%llx ]\n", port_nr, (long long)idata);
842 d->clocksignal = (idata & 0x10) ? 1 : 0;
843 d->rx_int_enable = (idata & 0x08) ? 1 : 0;
844 d->tx_int_enable = (idata & 0x04) ? 1 : 0;
845 }
846 break;
847
848 case PS2 + PS2_STATUS:
849 if (writeflag==MEM_READ) {
850 /* 0x08 = transmit buffer empty */
851 odata = d->clocksignal + 0x08;
852
853 if (d->head[port_nr] != d->tail[port_nr]) {
854 /* 0x10 = receicer data available (?) */
855 odata |= 0x10;
856 }
857
858 debug("[ pckbc: read from port %i, PS2_STATUS: "
859 "0x%llx ]\n", port_nr, (long long)odata);
860 } else {
861 debug("[ pckbc: write to port %i, PS2_STATUS: "
862 "0x%llx ]\n", port_nr, (long long)idata);
863 }
864 break;
865
866 default:
867 if (writeflag==MEM_READ) {
868 debug("[ pckbc: read from unimplemented reg %i ]\n",
869 (int)relative_addr);
870 odata = d->reg[relative_addr];
871 } else {
872 debug("[ pckbc: write to unimplemented reg %i:",
873 (int)relative_addr);
874 for (i=0; i<len; i++)
875 debug(" %02x", data[i]);
876 debug(" ]\n");
877 d->reg[relative_addr] = idata;
878 }
879 }
880
881 /* SGI? TODO: fix */
882 if (len == 8)
883 odata |= (odata << 8) | (odata << 16) | (odata << 24) |
884 (odata << 32) | (odata << 40) | (odata << 48) |
885 (odata << 56);
886
887 if (writeflag == MEM_READ)
888 memory_writemax64(cpu, data, len, odata);
889
890 dev_pckbc_tick(cpu, d);
891
892 return 1;
893 }
894
895
896 /*
897 * dev_pckbc_init():
898 *
899 * Type should be PCKBC_8042 or PCKBC_8242.
900 */
901 int dev_pckbc_init(struct machine *machine, struct memory *mem,
902 uint64_t baseaddr, int type, int keyboard_irqnr, int mouse_irqnr,
903 int in_use, int pc_style_flag)
904 {
905 struct pckbc_data *d;
906 int len = DEV_PCKBC_LENGTH;
907
908 d = malloc(sizeof(struct pckbc_data));
909 if (d == NULL) {
910 fprintf(stderr, "out of memory\n");
911 exit(1);
912 }
913 memset(d, 0, sizeof(struct pckbc_data));
914
915 if (type == PCKBC_8242)
916 len = 0x18;
917
918 if (type == PCKBC_JAZZ) {
919 type = PCKBC_8042;
920 len = DEV_PCKBC_LENGTH + 0x60;
921 }
922
923 d->type = type;
924 d->keyboard_irqnr = keyboard_irqnr;
925 d->mouse_irqnr = mouse_irqnr;
926 d->in_use = in_use;
927 d->pc_style_flag = pc_style_flag;
928 d->translation_table = 2;
929 d->rx_int_enable = 1;
930 d->output_byte = 0x02; /* A20 enable on PCs */
931
932 d->console_handle = console_start_slave_inputonly(
933 machine, "pckbc", d->in_use);
934
935 memory_device_register(mem, "pckbc", baseaddr,
936 len, dev_pckbc_access, d, DM_DEFAULT, NULL);
937 machine_add_tickfunction(machine, dev_pckbc_tick, d,
938 PCKBC_TICKSHIFT, 0.0);
939
940 return d->console_handle;
941 }
942

  ViewVC Help
Powered by ViewVC 1.1.26