/[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 24 - (show annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 24590 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


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.65 2006/03/04 12:38:48 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,
907 PCKBC_TICKSHIFT, 0.0);
908
909 return d->console_handle;
910 }
911

  ViewVC Help
Powered by ViewVC 1.1.26