/[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 4 - (show annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 17896 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.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.37 2005/02/22 06:26:10 debug Exp $
29 *
30 * Standard 8042 PC keyboard controller, and a 8242WB PS2 keyboard/mouse
31 * controller.
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
53
54 #define MAX_8042_QUEUELEN 256
55
56 #define PC_DATA 0
57 #define PC_CMD 0
58 #define PC_STATUS 1
59
60 #define PS2_TXBUF 0
61 #define PS2_RXBUF 1
62 #define PS2_CONTROL 2
63 #define PS2_STATUS 3
64
65 #define PS2 100
66
67 #define PCKBC_TICKSHIFT 14
68
69 struct pckbc_data {
70 int console_handle;
71 int in_use;
72 int any_command_used;
73
74 int reg[DEV_PCKBC_LENGTH];
75 int keyboard_irqnr;
76 int mouse_irqnr;
77 int type;
78
79 /* TODO: one of these for each port? */
80 int clocksignal;
81 int rx_int_enable;
82 int tx_int_enable;
83
84 int keyscanning_enabled;
85 int state;
86 int cmdbyte;
87 int last_scancode;
88
89 unsigned key_queue[2][MAX_8042_QUEUELEN];
90 int head[2], tail[2];
91 };
92
93 #define STATE_NORMAL 0
94 #define STATE_LDCMDBYTE 1
95 #define STATE_RDCMDBYTE 2
96 #define STATE_WAITING_FOR_TRANSLTABLE 3
97
98
99 /*
100 * pckbc_add_code():
101 *
102 * Adds a byte to the data queue.
103 */
104 void pckbc_add_code(struct pckbc_data *d, int code, int port)
105 {
106 /* Add at the head, read at the tail: */
107 d->head[port] = (d->head[port]+1) % MAX_8042_QUEUELEN;
108 if (d->head[port] == d->tail[port])
109 fatal("[ pckbc: queue overrun, port %i! ]\n", port);
110
111 d->key_queue[port][d->head[port]] = code;
112 }
113
114
115 /*
116 * pckbc_get_code():
117 *
118 * Reads a byte from a data queue.
119 */
120 int pckbc_get_code(struct pckbc_data *d, int port)
121 {
122 if (d->head[port] == d->tail[port])
123 fatal("[ pckbc: queue empty, port %i! ]\n", port);
124
125 d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN;
126 return d->key_queue[port][d->tail[port]];
127 }
128
129
130 /*
131 * ascii_to_scancodes():
132 *
133 * Conversion from ASCII codes to default (US) keyboard scancodes.
134 * (See http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html)
135 */
136 static void ascii_to_pc_scancodes(int a, struct pckbc_data *d)
137 {
138 int p = 0; /* port */
139 int shift = 0, ctrl = 0;
140
141 if (a >= 'A' && a <= 'Z') { a += 32; shift = 1; }
142 if ((a >= 1 && a <= 26) && (a!='\n' && a!='\t' && a!='\b' && a!='\r'))
143 { a += 96; ctrl = 1; }
144
145 if (shift)
146 pckbc_add_code(d, 0x2a, p);
147 else
148 pckbc_add_code(d, 0x2a + 0x80, p);
149
150 if (ctrl)
151 pckbc_add_code(d, 0x1d, p);
152
153 /*
154 * TODO: Release for all of these?
155 */
156
157 if (a==27) pckbc_add_code(d, 0x01, p);
158
159 if (a=='1') pckbc_add_code(d, 0x02, p);
160 if (a=='2') pckbc_add_code(d, 0x03, p);
161 if (a=='3') pckbc_add_code(d, 0x04, p);
162 if (a=='4') pckbc_add_code(d, 0x05, p);
163 if (a=='5') pckbc_add_code(d, 0x06, p);
164 if (a=='6') pckbc_add_code(d, 0x07, p);
165 if (a=='7') pckbc_add_code(d, 0x08, p);
166 if (a=='8') pckbc_add_code(d, 0x09, p);
167 if (a=='9') pckbc_add_code(d, 0x0a, p);
168 if (a=='0') pckbc_add_code(d, 0x0b, p);
169 if (a=='-') pckbc_add_code(d, 0x0c, p);
170 if (a=='=') pckbc_add_code(d, 0x0d, p);
171
172 if (a=='!') { pckbc_add_code(d, 0x2a, p);
173 pckbc_add_code(d, 0x02, p); }
174 if (a=='@') { pckbc_add_code(d, 0x2a, p);
175 pckbc_add_code(d, 0x03, p); }
176 if (a=='#') { pckbc_add_code(d, 0x2a, p);
177 pckbc_add_code(d, 0x04, p); }
178 if (a=='$') { pckbc_add_code(d, 0x2a, p);
179 pckbc_add_code(d, 0x05, p); }
180 if (a=='%') { pckbc_add_code(d, 0x2a, p);
181 pckbc_add_code(d, 0x06, p); }
182 if (a=='^') { pckbc_add_code(d, 0x2a, p);
183 pckbc_add_code(d, 0x07, p); }
184 if (a=='&') { pckbc_add_code(d, 0x2a, p);
185 pckbc_add_code(d, 0x08, p); }
186 if (a=='*') { pckbc_add_code(d, 0x2a, p);
187 pckbc_add_code(d, 0x09, p); }
188 if (a=='(') { pckbc_add_code(d, 0x2a, p);
189 pckbc_add_code(d, 0x0a, p); }
190 if (a==')') { pckbc_add_code(d, 0x2a, p);
191 pckbc_add_code(d, 0x0b, p); }
192 if (a=='_') { pckbc_add_code(d, 0x2a, p);
193 pckbc_add_code(d, 0x0c, p); }
194 if (a=='+') { pckbc_add_code(d, 0x2a, p);
195 pckbc_add_code(d, 0x0d, p); }
196
197 if (a=='\b') pckbc_add_code(d, 0x0e, p);
198
199 if (a=='\t') pckbc_add_code(d, 0x0f, p);
200 if (a=='q') pckbc_add_code(d, 0x10, p);
201 if (a=='w') pckbc_add_code(d, 0x11, p);
202 if (a=='e') pckbc_add_code(d, 0x12, p);
203 if (a=='r') pckbc_add_code(d, 0x13, p);
204 if (a=='t') pckbc_add_code(d, 0x14, p);
205 if (a=='y') pckbc_add_code(d, 0x15, p);
206 if (a=='u') pckbc_add_code(d, 0x16, p);
207 if (a=='i') pckbc_add_code(d, 0x17, p);
208 if (a=='o') pckbc_add_code(d, 0x18, p);
209 if (a=='p') pckbc_add_code(d, 0x19, p);
210
211 if (a=='[') pckbc_add_code(d, 0x1a, p);
212 if (a=='{') { pckbc_add_code(d, 0x2a, p);
213 pckbc_add_code(d, 0x1a, p); }
214 if (a==']') pckbc_add_code(d, 0x1b, p);
215 if (a=='}') { pckbc_add_code(d, 0x2a, p);
216 pckbc_add_code(d, 0x1b, p); }
217
218 if (a=='\n' || a=='\r') pckbc_add_code(d, 0x1c, p);
219
220 if (a=='a') pckbc_add_code(d, 0x1e, p);
221 if (a=='s') pckbc_add_code(d, 0x1f, p);
222 if (a=='d') pckbc_add_code(d, 0x20, p);
223 if (a=='f') pckbc_add_code(d, 0x21, p);
224 if (a=='g') pckbc_add_code(d, 0x22, p);
225 if (a=='h') pckbc_add_code(d, 0x23, p);
226 if (a=='j') pckbc_add_code(d, 0x24, p);
227 if (a=='k') pckbc_add_code(d, 0x25, p);
228 if (a=='l') pckbc_add_code(d, 0x26, p);
229
230 if (a==';') pckbc_add_code(d, 0x27, p);
231 if (a==':') { pckbc_add_code(d, 0x2a, p);
232 pckbc_add_code(d, 0x27, p); }
233 if (a=='\'') pckbc_add_code(d, 0x28, p);
234 if (a=='"') { pckbc_add_code(d, 0x2a, p);
235 pckbc_add_code(d, 0x28, p); }
236 if (a=='~') pckbc_add_code(d, 0x29, p);
237
238 if (a=='\\') pckbc_add_code(d, 0x2b, p);
239 if (a=='|') { pckbc_add_code(d, 0x2a, p);
240 pckbc_add_code(d, 0x2b, p); }
241
242 if (a=='z') pckbc_add_code(d, 0x2c, p);
243 if (a=='x') pckbc_add_code(d, 0x2d, p);
244 if (a=='c') pckbc_add_code(d, 0x2e, p);
245 if (a=='v') pckbc_add_code(d, 0x2f, p);
246 if (a=='b') pckbc_add_code(d, 0x30, p);
247 if (a=='n') pckbc_add_code(d, 0x31, p);
248 if (a=='m') pckbc_add_code(d, 0x32, p);
249
250 if (a==',') pckbc_add_code(d, 0x33, p);
251 if (a=='<') { pckbc_add_code(d, 0x2a, p);
252 pckbc_add_code(d, 0x33, p); }
253 if (a=='.') pckbc_add_code(d, 0x34, p);
254 if (a=='>') { pckbc_add_code(d, 0x2a, p);
255 pckbc_add_code(d, 0x34, p); }
256 if (a=='/') pckbc_add_code(d, 0x35, p);
257 if (a=='?') { pckbc_add_code(d, 0x2a, p);
258 pckbc_add_code(d, 0x35, p); }
259
260 if (a==' ') pckbc_add_code(d, 0x39, p);
261
262 /* Release ctrl: */
263 if (ctrl)
264 pckbc_add_code(d, 0x1d + 0x80, p);
265 }
266
267
268 /*
269 * dev_pckbc_tick():
270 */
271 void dev_pckbc_tick(struct cpu *cpu, void *extra)
272 {
273 struct pckbc_data *d = extra;
274 int port_nr;
275 int ch;
276
277 if (d->in_use && d->any_command_used &&
278 console_charavail(d->console_handle)) {
279 ch = console_readchar(d->console_handle);
280 if (ch >= 0)
281 ascii_to_pc_scancodes(ch, d);
282 }
283
284 /* TODO: mouse movements? */
285
286 for (port_nr=0; port_nr<2; port_nr++) {
287 /* Cause receive interrupt,
288 if there's something in the receive buffer: */
289 if (d->head[port_nr] != d->tail[port_nr] && d->rx_int_enable) {
290 cpu_interrupt(cpu, port_nr==0? d->keyboard_irqnr
291 : d->mouse_irqnr);
292 } else {
293 cpu_interrupt_ack(cpu, port_nr==0? d->keyboard_irqnr
294 : d->mouse_irqnr);
295 }
296 }
297 }
298
299
300 /*
301 * dev_pckbc_command():
302 */
303 static void dev_pckbc_command(struct pckbc_data *d, int port_nr)
304 {
305 int cmd = d->reg[PC_CMD];
306
307 d->any_command_used = 1;
308
309 if (d->type == PCKBC_8242)
310 cmd = d->reg[PS2_TXBUF];
311
312 if (d->state == STATE_WAITING_FOR_TRANSLTABLE) {
313 debug("[ pckbc: switching to translation table 0x%02x ]\n",
314 cmd);
315 pckbc_add_code(d, KBR_ACK, port_nr);
316 d->state = STATE_NORMAL;
317 return;
318 }
319
320 switch (cmd) {
321 case 0x00:
322 pckbc_add_code(d, KBR_ACK, port_nr);
323 break;
324 case KBC_MODEIND: /* Set LEDs */
325 /* Just ACK, no LEDs are actually set. */
326 pckbc_add_code(d, KBR_ACK, port_nr);
327 break;
328 case KBC_SETTABLE:
329 pckbc_add_code(d, KBR_ACK, port_nr);
330 d->state = STATE_WAITING_FOR_TRANSLTABLE;
331 break;
332 case KBC_ENABLE:
333 d->keyscanning_enabled = 1;
334 pckbc_add_code(d, KBR_ACK, port_nr);
335 break;
336 case KBC_DISABLE:
337 d->keyscanning_enabled = 0;
338 pckbc_add_code(d, KBR_ACK, port_nr);
339 break;
340 case KBC_SETDEFAULT:
341 pckbc_add_code(d, KBR_ACK, port_nr);
342 break;
343 case KBC_RESET:
344 pckbc_add_code(d, KBR_ACK, port_nr);
345 pckbc_add_code(d, KBR_RSTDONE, port_nr);
346 break;
347 default:
348 fatal("[ pckbc: UNIMPLEMENTED command 0x%02x ]\n", cmd);
349 }
350 }
351
352
353 /*
354 * dev_pckbc_access():
355 */
356 int dev_pckbc_access(struct cpu *cpu, struct memory *mem,
357 uint64_t relative_addr, unsigned char *data, size_t len,
358 int writeflag, void *extra)
359 {
360 uint64_t idata = 0, odata = 0;
361 int i, port_nr = 0;
362 struct pckbc_data *d = extra;
363
364 idata = memory_readmax64(cpu, data, len);
365
366 #ifdef PCKBC_DEBUG
367 if (writeflag == MEM_WRITE)
368 fatal("[ pckbc: write to addr 0x%x: 0x%x ]\n",
369 (int)relative_addr, (int)idata);
370 else
371 fatal("[ pckbc: read from addr 0x%x ]\n",
372 (int)relative_addr);
373 #endif
374
375 /* For JAZZ-based machines: */
376 if (relative_addr >= 0x60)
377 relative_addr -= 0x60;
378
379 /* 8242 PS2-style: */
380 if (d->type == PCKBC_8242) {
381 /* when using 8-byte alignment... */
382 relative_addr /= sizeof(uint64_t);
383 /* port_nr = 0 for keyboard, 1 for mouse */
384 port_nr = (relative_addr >> 2);
385 relative_addr &= 3;
386 relative_addr += PS2;
387 } else {
388 /* The relative_addr is either 0 or 1,
389 but some machines use longer registers than one byte
390 each, so this will make things simpler for us: */
391 if (relative_addr)
392 relative_addr = 1;
393 }
394
395 switch (relative_addr) {
396
397 /*
398 * 8042 (PC):
399 */
400
401 case 0: /* data */
402 if (writeflag==MEM_READ) {
403 if (d->state == STATE_RDCMDBYTE) {
404 odata = d->cmdbyte;
405 d->state = STATE_NORMAL;
406 } else {
407 if (d->head[0] != d->tail[0]) {
408 odata = pckbc_get_code(d, 0);
409 d->last_scancode = odata;
410 } else {
411 odata = d->last_scancode;
412 d->last_scancode |= 0x80;
413 }
414 }
415 debug("[ pckbc: read from DATA: 0x%02x ]\n", odata);
416 } else {
417 debug("[ pckbc: write to DATA:");
418 for (i=0; i<len; i++)
419 debug(" %02x", data[i]);
420 debug(" ]\n");
421
422 if (d->state == STATE_LDCMDBYTE) {
423 d->cmdbyte = idata;
424 d->rx_int_enable = d->cmdbyte &
425 (KC8_KENABLE | KC8_MENABLE) ? 1 : 0;
426 d->state = STATE_NORMAL;
427 } else {
428 d->reg[relative_addr] = idata;
429 dev_pckbc_command(d, port_nr);
430 }
431 }
432 break;
433 case 1: /* control */
434 if (writeflag==MEM_READ) {
435 dev_pckbc_tick(cpu, d);
436
437 odata = 0;
438
439 /* "Data in buffer" bit */
440 if (d->head[0] != d->tail[0] ||
441 d->state == STATE_RDCMDBYTE)
442 odata |= KBS_DIB;
443 /* odata |= KBS_OCMD; */
444 /* debug("[ pckbc: read from CTL status port: "
445 "0x%02x ]\n", (int)odata); */
446 } else {
447 debug("[ pckbc: write to CTL:");
448 for (i=0; i<len; i++)
449 debug(" %02x", data[i]);
450 debug(" ]\n");
451 d->reg[relative_addr] = idata;
452
453 switch (idata) {
454 case K_RDCMDBYTE:
455 d->state = STATE_RDCMDBYTE;
456 break;
457 case K_LDCMDBYTE:
458 d->state = STATE_LDCMDBYTE;
459 break;
460 case 0xa9: /* test auxiliary port */
461 debug("[ pckbc: CONTROL 0xa9, TODO ]\n");
462 break;
463 case 0xaa: /* keyboard self-test */
464 pckbc_add_code(d, 0x55, port_nr);
465 break;
466 case 0xd4: /* write to auxiliary port */
467 debug("[ pckbc: CONTROL 0xd4, TODO ]\n");
468 break;
469 default:
470 fatal("[ pckbc: unknown CONTROL 0x%x ]\n",
471 idata);
472 d->state = STATE_NORMAL;
473 }
474 }
475 break;
476
477 /*
478 * 8242 (PS2):
479 */
480
481 /*
482 * BIG TODO: The following should be rewritten to use dev_pckbc_command()
483 * etc, like the 8042 code above does.
484 */
485
486 case PS2 + PS2_TXBUF:
487 if (writeflag==MEM_READ) {
488 odata = random() & 0xff;
489 debug("[ pckbc: read from port %i, PS2_TXBUF: "
490 "0x%x ]\n", port_nr, (int)odata);
491 } else {
492 debug("[ pckbc: write to port %i, PS2_TXBUF: "
493 "0x%llx ]\n", port_nr, (long long)idata);
494
495 /* Handle keyboard commands: */
496 switch (idata) {
497 /* These are incorrect, the second byte of
498 commands should be treated better: */
499 case 0x00: /* second byte of 0xed,
500 SGI-IP32's prom */
501 pckbc_add_code(d, 0x03, port_nr);/* ack (?) */
502 break;
503 case 0x14: /* second byte of 0xfc,
504 SGI-IP32's prom */
505 case 0x28: /* second byte of 0xf3,
506 SGI-IP32's prom */
507 case 0x76: /* third byte of 0xfc,
508 SGI-IP32's prom */
509 case 0x03: /* second byte of
510 ATKBD_CMD_GSCANSET (?) */
511 case 0x04:
512 pckbc_add_code(d, 0x03, port_nr);/* ? */
513 break;
514
515 /* Command bytes: */
516 case 0xf0: /* ATKBD_CMD_GSCANSET (?) */
517 pckbc_add_code(d, 0x03, port_nr);/* ? */
518 break;
519 case 0xf2: /* Get keyboard ID */
520 /* The keyboard should generate 2
521 status bytes. */
522 pckbc_add_code(d, 0xab, port_nr);
523 pckbc_add_code(d, 0x83, port_nr);
524 break;
525 case 0xed: /* "ATKBD_CMD_SETLEDS",
526 takes 1 byte arg */
527 case 0xf3: /* "PSMOUSE_CMD_SETRATE",
528 takes 1 byte arg */
529 case 0xf4: /* "ATKBD_CMD_ENABLE" (or
530 PSMOUSE_CMD_ENABLE), no args */
531 case 0xf5: /* "ATKBD_CMD_RESET_DIS" (keyboard,
532 according to Linux sources) */
533 case 0xf6: /* "PSMOUSE_CMD_RESET_DIS" (mouse,
534 according to Linux sources) */
535 /* TODO: what does this do? */
536 pckbc_add_code(d, 0xfa, port_nr);/* ack (?) */
537 break;
538 case 0xfa: /* "ATKBD_CMD_SETALL_MBR" (linux) */
539 pckbc_add_code(d, 0xfa, port_nr);/* ack (?) */
540 break;
541 case 0xfc: /* ? */
542 pckbc_add_code(d, 0xfa, port_nr);/* ack (?) */
543 break;
544 case 0xff: /* Keyboard reset */
545 /* The keyboard should generate 2
546 status bytes. */
547 pckbc_add_code(d, 0xfa, port_nr);/* ack (?) */
548 pckbc_add_code(d, 0xaa, port_nr);
549 /* battery ok (?) */
550 break;
551 default:
552 debug("[ pckbc: UNIMPLEMENTED keyboard command"
553 " 0x%02x (port %i) ]\n", (int)idata,
554 port_nr);
555 }
556 }
557 break;
558
559 case PS2 + PS2_RXBUF:
560 if (writeflag==MEM_READ) {
561 /* TODO: What should be returned if no data
562 is available? */
563 odata = random() & 0xff;
564 if (d->head[port_nr] != d->tail[port_nr])
565 odata = pckbc_get_code(d, port_nr);
566 debug("[ pckbc: read from port %i, PS2_RXBUF: "
567 "0x%02x ]\n", port_nr, (int)odata);
568 } else {
569 debug("[ pckbc: write to port %i, PS2_RXBUF: "
570 "0x%llx ]\n", port_nr, (long long)idata);
571 }
572 break;
573
574 case PS2 + PS2_CONTROL:
575 if (writeflag==MEM_READ) {
576 debug("[ pckbc: read from port %i, PS2_CONTROL"
577 " ]\n", port_nr);
578 } else {
579 debug("[ pckbc: write to port %i, PS2_CONTROL:"
580 " 0x%llx ]\n", port_nr, (long long)idata);
581 d->clocksignal = (idata & 0x10) ? 1 : 0;
582 d->rx_int_enable = (idata & 0x08) ? 1 : 0;
583 d->tx_int_enable = (idata & 0x04) ? 1 : 0;
584 }
585 break;
586
587 case PS2 + PS2_STATUS:
588 if (writeflag==MEM_READ) {
589 /* 0x08 = transmit buffer empty */
590 odata = d->clocksignal + 0x08;
591
592 if (d->head[port_nr] != d->tail[port_nr]) {
593 /* 0x10 = receicer data available (?) */
594 odata |= 0x10;
595 }
596
597 debug("[ pckbc: read from port %i, PS2_STATUS: "
598 "0x%llx ]\n", port_nr, (long long)odata);
599 } else {
600 debug("[ pckbc: write to port %i, PS2_STATUS: "
601 "0x%llx ]\n", port_nr, (long long)idata);
602 }
603 break;
604
605 default:
606 if (writeflag==MEM_READ) {
607 debug("[ pckbc: read from unimplemented reg %i ]\n",
608 (int)relative_addr);
609 odata = d->reg[relative_addr];
610 } else {
611 debug("[ pckbc: write to unimplemented reg %i:",
612 (int)relative_addr);
613 for (i=0; i<len; i++)
614 debug(" %02x", data[i]);
615 debug(" ]\n");
616 d->reg[relative_addr] = idata;
617 }
618 }
619
620 if (writeflag == MEM_READ)
621 memory_writemax64(cpu, data, len, odata);
622
623 dev_pckbc_tick(cpu, d);
624
625 return 1;
626 }
627
628
629 /*
630 * dev_pckbc_init():
631 *
632 * Type should be PCKBC_8042 or PCKBC_8242.
633 */
634 int dev_pckbc_init(struct machine *machine, struct memory *mem,
635 uint64_t baseaddr, int type, int keyboard_irqnr, int mouse_irqnr,
636 int in_use)
637 {
638 struct pckbc_data *d;
639 int len = DEV_PCKBC_LENGTH;
640
641 d = malloc(sizeof(struct pckbc_data));
642 if (d == NULL) {
643 fprintf(stderr, "out of memory\n");
644 exit(1);
645 }
646 memset(d, 0, sizeof(struct pckbc_data));
647
648 if (type == PCKBC_JAZZ) {
649 type = PCKBC_8042;
650 len = DEV_PCKBC_LENGTH + 0x60;
651 }
652
653 d->type = type;
654 d->keyboard_irqnr = keyboard_irqnr;
655 d->mouse_irqnr = mouse_irqnr;
656 d->in_use = in_use;
657 d->console_handle = console_start_slave_inputonly(machine, "pckbc");
658
659 memory_device_register(mem, "pckbc", baseaddr,
660 len, dev_pckbc_access, d, MEM_DEFAULT, NULL);
661 machine_add_tickfunction(machine, dev_pckbc_tick, d, PCKBC_TICKSHIFT);
662
663 return d->console_handle;
664 }
665

  ViewVC Help
Powered by ViewVC 1.1.26