/[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 14 - (show annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 23554 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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

  ViewVC Help
Powered by ViewVC 1.1.26