/[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 6 - (show annotations)
Mon Oct 8 16:18:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 19757 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


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

  ViewVC Help
Powered by ViewVC 1.1.26