/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 24580 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26