/[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

Annotation of /trunk/src/devices/dev_pckbc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 6 - (hide 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 dpavlin 4 /*
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 dpavlin 6 * $Id: dev_pckbc.c,v 1.45 2005/06/02 15:42:49 debug Exp $
29 dpavlin 4 *
30 dpavlin 6 * Standard 8042 PC keyboard controller (and a 8242WB PS2 keyboard/mouse
31     * controller), including the 8048 keyboard chip.
32 dpavlin 4 *
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 dpavlin 6 int pc_style_flag;
78 dpavlin 4
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 dpavlin 6 int output_byte;
88 dpavlin 4 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 dpavlin 6 #define STATE_LDOUTPUT 4
99     #define STATE_RDOUTPUT 5
100 dpavlin 4
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 dpavlin 6 else
128     d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN;
129 dpavlin 4 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 dpavlin 6 int old_head;
142 dpavlin 4 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 dpavlin 6 * 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 dpavlin 4 */
165    
166 dpavlin 6 old_head = d->head[p];
167    
168 dpavlin 4 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 dpavlin 6 /* 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 dpavlin 4 /* 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 dpavlin 6 int port_nr, ch, ints_enabled;
292 dpavlin 4
293 dpavlin 6 if (d->in_use && console_charavail(d->console_handle)) {
294 dpavlin 4 ch = console_readchar(d->console_handle);
295     if (ch >= 0)
296     ascii_to_pc_scancodes(ch, d);
297     }
298    
299 dpavlin 6 ints_enabled = d->rx_int_enable;
300    
301 dpavlin 4 /* TODO: mouse movements? */
302    
303 dpavlin 6 if (d->cmdbyte & KC8_KDISABLE)
304     ints_enabled = 0;
305    
306 dpavlin 4 for (port_nr=0; port_nr<2; port_nr++) {
307 dpavlin 6 /* 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 dpavlin 4 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 dpavlin 6 *
323     * Handle commands to the 8048 in the emulated keyboard.
324 dpavlin 4 */
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 dpavlin 6 fatal("[ pckbc: UNIMPLEMENTED 8048 command 0x%02x ]\n", cmd);
369 dpavlin 4 }
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 dpavlin 6 if (relative_addr >= 0x60) {
397 dpavlin 4 relative_addr -= 0x60;
398 dpavlin 6 if (relative_addr != 0)
399     relative_addr = 1;
400     } else if (d->type == PCKBC_8242) {
401     /* 8242 PS2-style: */
402 dpavlin 4 /* 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 dpavlin 6 } 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 dpavlin 4 } else {
426 dpavlin 6 /* Others... Non-Jazz ARC-based machines etc. */
427     if (relative_addr != 0)
428 dpavlin 4 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 dpavlin 6 switch (d->state) {
440     case STATE_RDCMDBYTE:
441 dpavlin 4 odata = d->cmdbyte;
442     d->state = STATE_NORMAL;
443 dpavlin 6 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 dpavlin 4 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 dpavlin 6 /* debug("[ pckbc: read from DATA: 0x%02x ]\n",
457     odata); */
458 dpavlin 4 } else {
459     debug("[ pckbc: write to DATA:");
460     for (i=0; i<len; i++)
461     debug(" %02x", data[i]);
462     debug(" ]\n");
463    
464 dpavlin 6 switch (d->state) {
465     case STATE_LDCMDBYTE:
466 dpavlin 4 d->cmdbyte = idata;
467     d->rx_int_enable = d->cmdbyte &
468     (KC8_KENABLE | KC8_MENABLE) ? 1 : 0;
469     d->state = STATE_NORMAL;
470 dpavlin 6 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 dpavlin 4 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 dpavlin 6 d->state == STATE_RDCMDBYTE ||
489     d->state == STATE_RDOUTPUT)
490 dpavlin 4 odata |= KBS_DIB;
491 dpavlin 6
492     if (d->state == STATE_RDCMDBYTE)
493     odata |= KBS_OCMD;
494    
495     odata |= KBS_NOSEC;
496 dpavlin 4 /* 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 dpavlin 6 case 0xa7:
513     d->cmdbyte |= KC8_MDISABLE;
514     break;
515     case 0xa8:
516     d->cmdbyte &= ~KC8_MDISABLE;
517     break;
518 dpavlin 4 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 dpavlin 6 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 dpavlin 4 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 dpavlin 6 int in_use, int pc_style_flag)
707 dpavlin 4 {
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 dpavlin 6 d->pc_style_flag = pc_style_flag;
728 dpavlin 4 d->console_handle = console_start_slave_inputonly(machine, "pckbc");
729 dpavlin 6 d->rx_int_enable = 1;
730     d->output_byte = 0x02; /* A20 enable on PCs */
731 dpavlin 4
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