/[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 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 24701 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


1 /*
2 * Copyright (C) 2003-2005 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.60 2005/11/25 04:25:26 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 int dev_pckbc_access(struct cpu *cpu, struct memory *mem,
586 uint64_t relative_addr, unsigned char *data, size_t len,
587 int writeflag, void *extra)
588 {
589 uint64_t idata = 0, odata = 0;
590 int i, port_nr = 0;
591 struct pckbc_data *d = extra;
592
593 if (writeflag == MEM_WRITE)
594 idata = memory_readmax64(cpu, data, len);
595
596 #ifdef PCKBC_DEBUG
597 if (writeflag == MEM_WRITE)
598 fatal("[ pckbc: write to addr 0x%x: 0x%x ]\n",
599 (int)relative_addr, (int)idata);
600 else
601 fatal("[ pckbc: read from addr 0x%x ]\n",
602 (int)relative_addr);
603 #endif
604
605 /* For JAZZ-based machines: */
606 if (relative_addr >= 0x60) {
607 relative_addr -= 0x60;
608 if (relative_addr != 0)
609 relative_addr = 1;
610 } else if (d->type == PCKBC_8242) {
611 /* 8242 PS2-style: */
612 /* when using 8-byte alignment... */
613 relative_addr /= sizeof(uint64_t);
614 /* port_nr = 0 for keyboard, 1 for mouse */
615 port_nr = (relative_addr >> 2);
616 relative_addr &= 3;
617 relative_addr += PS2;
618 } else if (d->pc_style_flag) {
619 /* PC-style: */
620 if (relative_addr != 0 && relative_addr != 4) {
621 /* TODO (port 0x61) */
622 odata = 0x21;
623 {
624 static int x = 0;
625 x++;
626 if (x&1)
627 odata ^= 0x10;
628 }
629 if (writeflag == MEM_READ)
630 memory_writemax64(cpu, data, len, odata);
631 return 0;
632 }
633 if (relative_addr != 0)
634 relative_addr = 1;
635 } else {
636 /* Others... Non-Jazz ARC-based machines etc. */
637 if (relative_addr != 0)
638 relative_addr = 1;
639 }
640
641 switch (relative_addr) {
642
643 /*
644 * 8042 (PC):
645 */
646
647 case 0: /* data */
648 if (writeflag==MEM_READ) {
649 switch (d->state) {
650 case STATE_RDCMDBYTE:
651 odata = d->cmdbyte;
652 d->state = STATE_NORMAL;
653 break;
654 case STATE_RDOUTPUT:
655 odata = d->output_byte;
656 d->state = STATE_NORMAL;
657 break;
658 default:if (d->head[0] != d->tail[0]) {
659 odata = pckbc_get_code(d, 0);
660 d->last_scancode = odata;
661 } else {
662 odata = d->last_scancode;
663 d->last_scancode |= 0x80;
664 }
665 }
666 /* debug("[ pckbc: read from DATA: 0x%02x ]\n",
667 (int)odata); */
668 } else {
669 debug("[ pckbc: write to DATA:");
670 for (i=0; i<len; i++)
671 debug(" %02x", data[i]);
672 debug(" ]\n");
673
674 switch (d->state) {
675 case STATE_LDCMDBYTE:
676 d->cmdbyte = idata;
677 d->rx_int_enable = d->cmdbyte &
678 (KC8_KENABLE | KC8_MENABLE) ? 1 : 0;
679 d->state = STATE_NORMAL;
680 break;
681 case STATE_LDOUTPUT:
682 d->output_byte = idata;
683 d->state = STATE_NORMAL;
684 break;
685 default:d->reg[relative_addr] = idata;
686 dev_pckbc_command(d, port_nr);
687 }
688 }
689 break;
690 case 1: /* control */
691 if (writeflag==MEM_READ) {
692 dev_pckbc_tick(cpu, d);
693
694 odata = 0;
695
696 /* "Data in buffer" bit */
697 if (d->head[0] != d->tail[0] ||
698 d->state == STATE_RDCMDBYTE ||
699 d->state == STATE_RDOUTPUT)
700 odata |= KBS_DIB;
701
702 if (d->state == STATE_RDCMDBYTE)
703 odata |= KBS_OCMD;
704
705 odata |= KBS_NOSEC;
706 /* debug("[ pckbc: read from CTL status port: "
707 "0x%02x ]\n", (int)odata); */
708 } else {
709 debug("[ pckbc: write to CTL:");
710 for (i=0; i<len; i++)
711 debug(" %02x", data[i]);
712 debug(" ]\n");
713 d->reg[relative_addr] = idata;
714
715 switch (idata) {
716 case 0x10:
717 case 0x11:
718 /* TODO: For now, don't print warnings about
719 these. NetBSD sends these. */
720 break;
721 case K_RDCMDBYTE:
722 d->state = STATE_RDCMDBYTE;
723 break;
724 case K_LDCMDBYTE:
725 d->state = STATE_LDCMDBYTE;
726 break;
727 case 0xa7:
728 d->cmdbyte |= KC8_MDISABLE;
729 break;
730 case 0xa8:
731 d->cmdbyte &= ~KC8_MDISABLE;
732 break;
733 case 0xa9: /* test auxiliary port */
734 debug("[ pckbc: CONTROL 0xa9, TODO ]\n");
735 break;
736 case 0xaa: /* keyboard self-test */
737 pckbc_add_code(d, 0x55, port_nr);
738 break;
739 case 0xab: /* keyboard interface self-test */
740 pckbc_add_code(d, 0x00, port_nr);
741 break;
742 case 0xad:
743 d->cmdbyte |= KC8_KDISABLE;
744 break;
745 case 0xae:
746 d->cmdbyte &= ~KC8_KDISABLE;
747 break;
748 case 0xd0:
749 d->state = STATE_RDOUTPUT;
750 break;
751 case 0xd1:
752 d->state = STATE_LDOUTPUT;
753 break;
754 case 0xd3: /* write to auxiliary device
755 output buffer */
756 debug("[ pckbc: CONTROL 0xd3, TODO ]\n");
757 d->state = STATE_WAITING_FOR_AUX_OUT;
758 break;
759 case 0xd4: /* write to auxiliary port */
760 debug("[ pckbc: CONTROL 0xd4, TODO ]\n");
761 d->state = STATE_WAITING_FOR_AUX;
762 break;
763 default:
764 fatal("[ pckbc: unknown CONTROL 0x%x ]\n",
765 (int)idata);
766 d->state = STATE_NORMAL;
767 }
768 }
769 break;
770
771 /*
772 * 8242 (PS2):
773 */
774
775 case PS2 + PS2_TXBUF:
776 if (writeflag==MEM_READ) {
777 odata = random() & 0xff;
778 debug("[ pckbc: read from port %i, PS2_TXBUF: "
779 "0x%x ]\n", port_nr, (int)odata);
780 } else {
781 debug("[ pckbc: write to port %i, PS2_TXBUF: "
782 "0x%llx ]\n", port_nr, (long long)idata);
783
784 /* Handle keyboard commands: */
785 d->reg[PS2_TXBUF] = idata;
786 dev_pckbc_command(d, port_nr);
787 }
788 break;
789
790 case PS2 + PS2_RXBUF:
791 if (writeflag==MEM_READ) {
792 /* TODO: What should be returned if no data
793 is available? */
794 odata = random() & 0xff;
795 if (d->head[port_nr] != d->tail[port_nr])
796 odata = pckbc_get_code(d, port_nr);
797 debug("[ pckbc: read from port %i, PS2_RXBUF: "
798 "0x%02x ]\n", port_nr, (int)odata);
799 } else {
800 debug("[ pckbc: write to port %i, PS2_RXBUF: "
801 "0x%llx ]\n", port_nr, (long long)idata);
802 }
803 break;
804
805 case PS2 + PS2_CONTROL:
806 if (writeflag==MEM_READ) {
807 debug("[ pckbc: read from port %i, PS2_CONTROL"
808 " ]\n", port_nr);
809 } else {
810 debug("[ pckbc: write to port %i, PS2_CONTROL:"
811 " 0x%llx ]\n", port_nr, (long long)idata);
812 d->clocksignal = (idata & 0x10) ? 1 : 0;
813 d->rx_int_enable = (idata & 0x08) ? 1 : 0;
814 d->tx_int_enable = (idata & 0x04) ? 1 : 0;
815 }
816 break;
817
818 case PS2 + PS2_STATUS:
819 if (writeflag==MEM_READ) {
820 /* 0x08 = transmit buffer empty */
821 odata = d->clocksignal + 0x08;
822
823 if (d->head[port_nr] != d->tail[port_nr]) {
824 /* 0x10 = receicer data available (?) */
825 odata |= 0x10;
826 }
827
828 debug("[ pckbc: read from port %i, PS2_STATUS: "
829 "0x%llx ]\n", port_nr, (long long)odata);
830 } else {
831 debug("[ pckbc: write to port %i, PS2_STATUS: "
832 "0x%llx ]\n", port_nr, (long long)idata);
833 }
834 break;
835
836 default:
837 if (writeflag==MEM_READ) {
838 debug("[ pckbc: read from unimplemented reg %i ]\n",
839 (int)relative_addr);
840 odata = d->reg[relative_addr];
841 } else {
842 debug("[ pckbc: write to unimplemented reg %i:",
843 (int)relative_addr);
844 for (i=0; i<len; i++)
845 debug(" %02x", data[i]);
846 debug(" ]\n");
847 d->reg[relative_addr] = idata;
848 }
849 }
850
851 /* SGI? TODO: fix */
852 if (len == 8)
853 odata |= (odata << 8) | (odata << 16) | (odata << 24) |
854 (odata << 32) | (odata << 40) | (odata << 48) |
855 (odata << 56);
856
857 if (writeflag == MEM_READ)
858 memory_writemax64(cpu, data, len, odata);
859
860 dev_pckbc_tick(cpu, d);
861
862 return 1;
863 }
864
865
866 /*
867 * dev_pckbc_init():
868 *
869 * Type should be PCKBC_8042 or PCKBC_8242.
870 */
871 int dev_pckbc_init(struct machine *machine, struct memory *mem,
872 uint64_t baseaddr, int type, int keyboard_irqnr, int mouse_irqnr,
873 int in_use, int pc_style_flag)
874 {
875 struct pckbc_data *d;
876 int len = DEV_PCKBC_LENGTH;
877
878 d = malloc(sizeof(struct pckbc_data));
879 if (d == NULL) {
880 fprintf(stderr, "out of memory\n");
881 exit(1);
882 }
883 memset(d, 0, sizeof(struct pckbc_data));
884
885 if (type == PCKBC_8242)
886 len = 0x40;
887
888 if (type == PCKBC_JAZZ) {
889 type = PCKBC_8042;
890 len = DEV_PCKBC_LENGTH + 0x60;
891 }
892
893 d->type = type;
894 d->keyboard_irqnr = keyboard_irqnr;
895 d->mouse_irqnr = mouse_irqnr;
896 d->in_use = in_use;
897 d->pc_style_flag = pc_style_flag;
898 if (d->in_use)
899 d->console_handle =
900 console_start_slave_inputonly(machine, "pckbc");
901 d->translation_table = 2;
902 d->rx_int_enable = 1;
903 d->output_byte = 0x02; /* A20 enable on PCs */
904
905 memory_device_register(mem, "pckbc", baseaddr,
906 len, dev_pckbc_access, d, DM_DEFAULT, NULL);
907 machine_add_tickfunction(machine, dev_pckbc_tick, d, PCKBC_TICKSHIFT);
908
909 return d->console_handle;
910 }
911

  ViewVC Help
Powered by ViewVC 1.1.26