/[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 34 - (show annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 25445 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26