/[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 18 - (show annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 23622 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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.53 2005/10/26 14:37:04 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 if (a=='~') { a = '`'; shift = 1; }
318
319 if (shift)
320 pckbc_add_code(d, 0x2a, p);
321 else
322 pckbc_add_code(d, 0x2a + 0x80, p);
323
324 if (ctrl)
325 pckbc_add_code(d, 0x1d, p);
326
327 /*
328 * Note: The ugly hack used to add release codes for all of these
329 * keys is as follows: we remember how much of the kbd buf that
330 * is in use here, before we add any scancode. After we've added
331 * one or more scancodes (ie an optional shift + another key)
332 * then we duplicate the last scancode | 0x80 _if_ the kbd buf
333 * was altered.
334 */
335
336 old_head = d->head[p];
337
338 if (a==27) pckbc_add_code(d, 0x01, p);
339
340 if (a=='1') pckbc_add_code(d, 0x02, p);
341 if (a=='2') pckbc_add_code(d, 0x03, p);
342 if (a=='3') pckbc_add_code(d, 0x04, p);
343 if (a=='4') pckbc_add_code(d, 0x05, p);
344 if (a=='5') pckbc_add_code(d, 0x06, p);
345 if (a=='6') pckbc_add_code(d, 0x07, p);
346 if (a=='7') pckbc_add_code(d, 0x08, p);
347 if (a=='8') pckbc_add_code(d, 0x09, p);
348 if (a=='9') pckbc_add_code(d, 0x0a, p);
349 if (a=='0') pckbc_add_code(d, 0x0b, p);
350 if (a=='-') pckbc_add_code(d, 0x0c, p);
351 if (a=='=') pckbc_add_code(d, 0x0d, p);
352
353 if (a=='!') { pckbc_add_code(d, 0x2a, p);
354 pckbc_add_code(d, 0x02, p); }
355 if (a=='@') { pckbc_add_code(d, 0x2a, p);
356 pckbc_add_code(d, 0x03, p); }
357 if (a=='#') { pckbc_add_code(d, 0x2a, p);
358 pckbc_add_code(d, 0x04, p); }
359 if (a=='$') { pckbc_add_code(d, 0x2a, p);
360 pckbc_add_code(d, 0x05, p); }
361 if (a=='%') { pckbc_add_code(d, 0x2a, p);
362 pckbc_add_code(d, 0x06, p); }
363 if (a=='^') { pckbc_add_code(d, 0x2a, p);
364 pckbc_add_code(d, 0x07, p); }
365 if (a=='&') { pckbc_add_code(d, 0x2a, p);
366 pckbc_add_code(d, 0x08, p); }
367 if (a=='*') { pckbc_add_code(d, 0x2a, p);
368 pckbc_add_code(d, 0x09, p); }
369 if (a=='(') { pckbc_add_code(d, 0x2a, p);
370 pckbc_add_code(d, 0x0a, p); }
371
372 if (a=='\b') pckbc_add_code(d, 0x0e, p);
373
374 if (a=='\t') pckbc_add_code(d, 0x0f, p);
375 if (a=='q') pckbc_add_code(d, 0x10, p);
376 if (a=='w') pckbc_add_code(d, 0x11, p);
377 if (a=='e') pckbc_add_code(d, 0x12, p);
378 if (a=='r') pckbc_add_code(d, 0x13, p);
379 if (a=='t') pckbc_add_code(d, 0x14, p);
380 if (a=='y') pckbc_add_code(d, 0x15, p);
381 if (a=='u') pckbc_add_code(d, 0x16, p);
382 if (a=='i') pckbc_add_code(d, 0x17, p);
383 if (a=='o') pckbc_add_code(d, 0x18, p);
384 if (a=='p') pckbc_add_code(d, 0x19, p);
385
386 if (a=='[') pckbc_add_code(d, 0x1a, p);
387 if (a==']') pckbc_add_code(d, 0x1b, p);
388
389 if (a=='\n' || a=='\r') pckbc_add_code(d, 0x1c, p);
390
391 if (a=='a') pckbc_add_code(d, 0x1e, p);
392 if (a=='s') pckbc_add_code(d, 0x1f, p);
393 if (a=='d') pckbc_add_code(d, 0x20, p);
394 if (a=='f') pckbc_add_code(d, 0x21, p);
395 if (a=='g') pckbc_add_code(d, 0x22, p);
396 if (a=='h') pckbc_add_code(d, 0x23, p);
397 if (a=='j') pckbc_add_code(d, 0x24, p);
398 if (a=='k') pckbc_add_code(d, 0x25, p);
399 if (a=='l') pckbc_add_code(d, 0x26, p);
400
401 if (a==';') pckbc_add_code(d, 0x27, p);
402 if (a=='\'') pckbc_add_code(d, 0x28, p);
403 if (a=='`') pckbc_add_code(d, 0x29, p);
404 if (a=='\\') pckbc_add_code(d, 0x2b, p);
405
406 if (a=='z') pckbc_add_code(d, 0x2c, p);
407 if (a=='x') pckbc_add_code(d, 0x2d, p);
408 if (a=='c') pckbc_add_code(d, 0x2e, p);
409 if (a=='v') pckbc_add_code(d, 0x2f, p);
410 if (a=='b') pckbc_add_code(d, 0x30, p);
411 if (a=='n') pckbc_add_code(d, 0x31, p);
412 if (a=='m') pckbc_add_code(d, 0x32, p);
413
414 if (a==',') pckbc_add_code(d, 0x33, p);
415 if (a=='.') pckbc_add_code(d, 0x34, p);
416 if (a=='/') pckbc_add_code(d, 0x35, p);
417
418 if (a==' ') pckbc_add_code(d, 0x39, p);
419
420 /* Add release code, if a key was pressed: */
421 if (d->head[p] != old_head) {
422 int code = d->key_queue[p][d->head[p]] | 0x80;
423 pckbc_add_code(d, code, p);
424 }
425
426 /* Release ctrl: */
427 if (ctrl)
428 pckbc_add_code(d, 0x1d + 0x80, p);
429 }
430
431
432 /*
433 * dev_pckbc_tick():
434 */
435 void dev_pckbc_tick(struct cpu *cpu, void *extra)
436 {
437 struct pckbc_data *d = extra;
438 int port_nr, ch, ints_enabled;
439
440 if (d->in_use && console_charavail(d->console_handle)) {
441 ch = console_readchar(d->console_handle);
442 if (ch >= 0)
443 ascii_to_pc_scancodes(ch, d);
444 }
445
446 ints_enabled = d->rx_int_enable;
447
448 /* TODO: mouse movements? */
449
450 if (d->cmdbyte & KC8_KDISABLE)
451 ints_enabled = 0;
452
453 for (port_nr=0; port_nr<2; port_nr++) {
454 /* Cause receive interrupt, if there's something in the
455 receive buffer: (Otherwise deassert the interrupt.) */
456 if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) {
457 debug("[ pckbc: interrupt port %i ]\n", port_nr);
458 cpu_interrupt(cpu, port_nr==0? d->keyboard_irqnr
459 : d->mouse_irqnr);
460 d->currently_asserted[port_nr] = 1;
461 } else {
462 if (d->currently_asserted[port_nr])
463 cpu_interrupt_ack(cpu, port_nr==0?
464 d->keyboard_irqnr : d->mouse_irqnr);
465 d->currently_asserted[port_nr] = 0;
466 }
467 }
468 }
469
470
471 /*
472 * dev_pckbc_command():
473 *
474 * Handle commands to the 8048 in the emulated keyboard.
475 */
476 static void dev_pckbc_command(struct pckbc_data *d, int port_nr)
477 {
478 int cmd = d->reg[PC_CMD];
479
480 if (d->type == PCKBC_8242)
481 cmd = d->reg[PS2_TXBUF];
482
483 if (d->state == STATE_WAITING_FOR_TRANSLTABLE) {
484 debug("[ pckbc: (port %i) switching to translation table "
485 "0x%02x ]\n", port_nr, cmd);
486 switch (cmd) {
487 case 1:
488 case 3: d->translation_table = cmd;
489 break;
490 default:fatal("[ pckbc: (port %i) translation table "
491 "0x%02x is NOT YET IMPLEMENTED ]\n", port_nr, cmd);
492 }
493 pckbc_add_code(d, KBR_ACK, port_nr);
494 d->state = STATE_NORMAL;
495 return;
496 }
497
498 if (d->state == STATE_WAITING_FOR_F3) {
499 debug("[ pckbc: (port %i) received '0xf3' data: "
500 "0x%02x ]\n", port_nr, cmd);
501 pckbc_add_code(d, KBR_ACK, port_nr);
502 d->state = STATE_NORMAL;
503 return;
504 }
505
506 if (d->state == STATE_WAITING_FOR_FC) {
507 debug("[ pckbc: (port %i) received '0xfc' data: "
508 "0x%02x ]\n", port_nr, cmd);
509 pckbc_add_code(d, KBR_ACK, port_nr);
510 d->state = STATE_NORMAL;
511 return;
512 }
513
514 switch (cmd) {
515 case 0x00:
516 pckbc_add_code(d, KBR_ACK, port_nr);
517 break;
518 case KBC_MODEIND: /* Set LEDs */
519 /* Just ACK, no LEDs are actually set. */
520 pckbc_add_code(d, KBR_ACK, port_nr);
521 break;
522 case KBC_SETTABLE:
523 pckbc_add_code(d, KBR_ACK, port_nr);
524 d->state = STATE_WAITING_FOR_TRANSLTABLE;
525 break;
526 case KBC_ENABLE:
527 d->keyscanning_enabled = 1;
528 pckbc_add_code(d, KBR_ACK, port_nr);
529 break;
530 case KBC_DISABLE:
531 d->keyscanning_enabled = 0;
532 pckbc_add_code(d, KBR_ACK, port_nr);
533 break;
534 case KBC_SETDEFAULT:
535 pckbc_add_code(d, KBR_ACK, port_nr);
536 break;
537 case 0xf3:
538 pckbc_add_code(d, KBR_ACK, port_nr);
539 d->state = STATE_WAITING_FOR_F3;
540 break;
541 case 0xfa: /* Just ack? */
542 pckbc_add_code(d, KBR_ACK, port_nr);
543 break;
544 case 0xfc:
545 pckbc_add_code(d, KBR_ACK, port_nr);
546 d->state = STATE_WAITING_FOR_FC;
547 break;
548 case KBC_RESET:
549 pckbc_add_code(d, KBR_ACK, port_nr);
550 pckbc_add_code(d, KBR_RSTDONE, port_nr);
551 break;
552 default:
553 fatal("[ pckbc: (port %i) UNIMPLEMENTED 8048 command"
554 " 0x%02x ]\n", port_nr, cmd);
555 }
556 }
557
558
559 /*
560 * dev_pckbc_access():
561 */
562 int dev_pckbc_access(struct cpu *cpu, struct memory *mem,
563 uint64_t relative_addr, unsigned char *data, size_t len,
564 int writeflag, void *extra)
565 {
566 uint64_t idata = 0, odata = 0;
567 int i, port_nr = 0;
568 struct pckbc_data *d = extra;
569
570 if (writeflag == MEM_WRITE)
571 idata = memory_readmax64(cpu, data, len);
572
573 #ifdef PCKBC_DEBUG
574 if (writeflag == MEM_WRITE)
575 fatal("[ pckbc: write to addr 0x%x: 0x%x ]\n",
576 (int)relative_addr, (int)idata);
577 else
578 fatal("[ pckbc: read from addr 0x%x ]\n",
579 (int)relative_addr);
580 #endif
581
582 /* For JAZZ-based machines: */
583 if (relative_addr >= 0x60) {
584 relative_addr -= 0x60;
585 if (relative_addr != 0)
586 relative_addr = 1;
587 } else if (d->type == PCKBC_8242) {
588 /* 8242 PS2-style: */
589 /* when using 8-byte alignment... */
590 relative_addr /= sizeof(uint64_t);
591 /* port_nr = 0 for keyboard, 1 for mouse */
592 port_nr = (relative_addr >> 2);
593 relative_addr &= 3;
594 relative_addr += PS2;
595 } else if (d->pc_style_flag) {
596 /* PC-style: */
597 if (relative_addr != 0 && relative_addr != 4) {
598 /* TODO (port 0x61) */
599 odata = 0x21;
600 {
601 static int x = 0;
602 x++;
603 if (x&1)
604 odata ^= 0x10;
605 }
606 if (writeflag == MEM_READ)
607 memory_writemax64(cpu, data, len, odata);
608 return 0;
609 }
610 if (relative_addr != 0)
611 relative_addr = 1;
612 } else {
613 /* Others... Non-Jazz ARC-based machines etc. */
614 if (relative_addr != 0)
615 relative_addr = 1;
616 }
617
618 switch (relative_addr) {
619
620 /*
621 * 8042 (PC):
622 */
623
624 case 0: /* data */
625 if (writeflag==MEM_READ) {
626 switch (d->state) {
627 case STATE_RDCMDBYTE:
628 odata = d->cmdbyte;
629 d->state = STATE_NORMAL;
630 break;
631 case STATE_RDOUTPUT:
632 odata = d->output_byte;
633 d->state = STATE_NORMAL;
634 break;
635 default:if (d->head[0] != d->tail[0]) {
636 odata = pckbc_get_code(d, 0);
637 d->last_scancode = odata;
638 } else {
639 odata = d->last_scancode;
640 d->last_scancode |= 0x80;
641 }
642 }
643 /* debug("[ pckbc: read from DATA: 0x%02x ]\n",
644 odata); */
645 } else {
646 debug("[ pckbc: write to DATA:");
647 for (i=0; i<len; i++)
648 debug(" %02x", data[i]);
649 debug(" ]\n");
650
651 switch (d->state) {
652 case STATE_LDCMDBYTE:
653 d->cmdbyte = idata;
654 d->rx_int_enable = d->cmdbyte &
655 (KC8_KENABLE | KC8_MENABLE) ? 1 : 0;
656 d->state = STATE_NORMAL;
657 break;
658 case STATE_LDOUTPUT:
659 d->output_byte = idata;
660 d->state = STATE_NORMAL;
661 break;
662 default:d->reg[relative_addr] = idata;
663 dev_pckbc_command(d, port_nr);
664 }
665 }
666 break;
667 case 1: /* control */
668 if (writeflag==MEM_READ) {
669 dev_pckbc_tick(cpu, d);
670
671 odata = 0;
672
673 /* "Data in buffer" bit */
674 if (d->head[0] != d->tail[0] ||
675 d->state == STATE_RDCMDBYTE ||
676 d->state == STATE_RDOUTPUT)
677 odata |= KBS_DIB;
678
679 if (d->state == STATE_RDCMDBYTE)
680 odata |= KBS_OCMD;
681
682 odata |= KBS_NOSEC;
683 /* debug("[ pckbc: read from CTL status port: "
684 "0x%02x ]\n", (int)odata); */
685 } else {
686 debug("[ pckbc: write to CTL:");
687 for (i=0; i<len; i++)
688 debug(" %02x", data[i]);
689 debug(" ]\n");
690 d->reg[relative_addr] = idata;
691
692 switch (idata) {
693 case K_RDCMDBYTE:
694 d->state = STATE_RDCMDBYTE;
695 break;
696 case K_LDCMDBYTE:
697 d->state = STATE_LDCMDBYTE;
698 break;
699 case 0xa7:
700 d->cmdbyte |= KC8_MDISABLE;
701 break;
702 case 0xa8:
703 d->cmdbyte &= ~KC8_MDISABLE;
704 break;
705 case 0xa9: /* test auxiliary port */
706 debug("[ pckbc: CONTROL 0xa9, TODO ]\n");
707 break;
708 case 0xaa: /* keyboard self-test */
709 pckbc_add_code(d, 0x55, port_nr);
710 break;
711 case 0xad:
712 d->cmdbyte |= KC8_KDISABLE;
713 break;
714 case 0xae:
715 d->cmdbyte &= ~KC8_KDISABLE;
716 break;
717 case 0xd0:
718 d->state = STATE_RDOUTPUT;
719 break;
720 case 0xd1:
721 d->state = STATE_LDOUTPUT;
722 break;
723 case 0xd4: /* write to auxiliary port */
724 debug("[ pckbc: CONTROL 0xd4, TODO ]\n");
725 break;
726 default:
727 fatal("[ pckbc: unknown CONTROL 0x%x ]\n",
728 idata);
729 d->state = STATE_NORMAL;
730 }
731 }
732 break;
733
734 /*
735 * 8242 (PS2):
736 */
737
738 case PS2 + PS2_TXBUF:
739 if (writeflag==MEM_READ) {
740 odata = random() & 0xff;
741 debug("[ pckbc: read from port %i, PS2_TXBUF: "
742 "0x%x ]\n", port_nr, (int)odata);
743 } else {
744 debug("[ pckbc: write to port %i, PS2_TXBUF: "
745 "0x%llx ]\n", port_nr, (long long)idata);
746
747 /* Handle keyboard commands: */
748 d->reg[PS2_TXBUF] = idata;
749 dev_pckbc_command(d, port_nr);
750 }
751 break;
752
753 case PS2 + PS2_RXBUF:
754 if (writeflag==MEM_READ) {
755 /* TODO: What should be returned if no data
756 is available? */
757 odata = random() & 0xff;
758 if (d->head[port_nr] != d->tail[port_nr])
759 odata = pckbc_get_code(d, port_nr);
760 debug("[ pckbc: read from port %i, PS2_RXBUF: "
761 "0x%02x ]\n", port_nr, (int)odata);
762 } else {
763 debug("[ pckbc: write to port %i, PS2_RXBUF: "
764 "0x%llx ]\n", port_nr, (long long)idata);
765 }
766 break;
767
768 case PS2 + PS2_CONTROL:
769 if (writeflag==MEM_READ) {
770 debug("[ pckbc: read from port %i, PS2_CONTROL"
771 " ]\n", port_nr);
772 } else {
773 debug("[ pckbc: write to port %i, PS2_CONTROL:"
774 " 0x%llx ]\n", port_nr, (long long)idata);
775 d->clocksignal = (idata & 0x10) ? 1 : 0;
776 d->rx_int_enable = (idata & 0x08) ? 1 : 0;
777 d->tx_int_enable = (idata & 0x04) ? 1 : 0;
778 }
779 break;
780
781 case PS2 + PS2_STATUS:
782 if (writeflag==MEM_READ) {
783 /* 0x08 = transmit buffer empty */
784 odata = d->clocksignal + 0x08;
785
786 if (d->head[port_nr] != d->tail[port_nr]) {
787 /* 0x10 = receicer data available (?) */
788 odata |= 0x10;
789 }
790
791 debug("[ pckbc: read from port %i, PS2_STATUS: "
792 "0x%llx ]\n", port_nr, (long long)odata);
793 } else {
794 debug("[ pckbc: write to port %i, PS2_STATUS: "
795 "0x%llx ]\n", port_nr, (long long)idata);
796 }
797 break;
798
799 default:
800 if (writeflag==MEM_READ) {
801 debug("[ pckbc: read from unimplemented reg %i ]\n",
802 (int)relative_addr);
803 odata = d->reg[relative_addr];
804 } else {
805 debug("[ pckbc: write to unimplemented reg %i:",
806 (int)relative_addr);
807 for (i=0; i<len; i++)
808 debug(" %02x", data[i]);
809 debug(" ]\n");
810 d->reg[relative_addr] = idata;
811 }
812 }
813
814 /* SGI? */
815 if (len == 8)
816 odata |= (odata << 8) | (odata << 16) | (odata << 24) |
817 (odata << 32) | (odata << 40) | (odata << 48) |
818 (odata << 56);
819
820 if (writeflag == MEM_READ)
821 memory_writemax64(cpu, data, len, odata);
822
823 dev_pckbc_tick(cpu, d);
824
825 return 1;
826 }
827
828
829 /*
830 * dev_pckbc_init():
831 *
832 * Type should be PCKBC_8042 or PCKBC_8242.
833 */
834 int dev_pckbc_init(struct machine *machine, struct memory *mem,
835 uint64_t baseaddr, int type, int keyboard_irqnr, int mouse_irqnr,
836 int in_use, int pc_style_flag)
837 {
838 struct pckbc_data *d;
839 int len = DEV_PCKBC_LENGTH;
840
841 d = malloc(sizeof(struct pckbc_data));
842 if (d == NULL) {
843 fprintf(stderr, "out of memory\n");
844 exit(1);
845 }
846 memset(d, 0, sizeof(struct pckbc_data));
847
848 if (type == PCKBC_8242)
849 len = 0x40;
850
851 if (type == PCKBC_JAZZ) {
852 type = PCKBC_8042;
853 len = DEV_PCKBC_LENGTH + 0x60;
854 }
855
856 d->type = type;
857 d->keyboard_irqnr = keyboard_irqnr;
858 d->mouse_irqnr = mouse_irqnr;
859 d->in_use = in_use;
860 d->pc_style_flag = pc_style_flag;
861 d->console_handle = console_start_slave_inputonly(machine, "pckbc");
862 d->translation_table = 1;
863 d->rx_int_enable = 1;
864 d->output_byte = 0x02; /* A20 enable on PCs */
865
866 memory_device_register(mem, "pckbc", baseaddr,
867 len, dev_pckbc_access, d, MEM_DEFAULT, NULL);
868 machine_add_tickfunction(machine, dev_pckbc_tick, d, PCKBC_TICKSHIFT);
869
870 return d->console_handle;
871 }
872

  ViewVC Help
Powered by ViewVC 1.1.26