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

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

  ViewVC Help
Powered by ViewVC 1.1.26