/[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 32 - (hide annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 25286 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


1 dpavlin 4 /*
2 dpavlin 22 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 dpavlin 4 *
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 32 * $Id: dev_pckbc.c,v 1.70 2006/08/22 15:13:03 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 dpavlin 30 * Quick source of good info: http://my.execpc.com/~geezer/osd/kbd/kbd.txt
34 dpavlin 4 *
35 dpavlin 30 *
36     * TODOs:
37     * Finish the rewrite for 8242.
38 dpavlin 4 */
39    
40     #include <stdio.h>
41     #include <stdlib.h>
42     #include <string.h>
43    
44     #include "console.h"
45     #include "cpu.h"
46     #include "devices.h"
47     #include "machine.h"
48     #include "memory.h"
49     #include "misc.h"
50    
51     #include "kbdreg.h"
52    
53    
54     /* #define PCKBC_DEBUG */
55 dpavlin 12 /* #define debug fatal */
56 dpavlin 4
57    
58     #define MAX_8042_QUEUELEN 256
59    
60     #define PC_DATA 0
61     #define PC_CMD 0
62     #define PC_STATUS 1
63    
64     #define PS2_TXBUF 0
65     #define PS2_RXBUF 1
66     #define PS2_CONTROL 2
67     #define PS2_STATUS 3
68    
69     #define PS2 100
70    
71 dpavlin 14 #define PCKBC_TICKSHIFT 15
72 dpavlin 4
73     struct pckbc_data {
74     int console_handle;
75     int in_use;
76    
77     int reg[DEV_PCKBC_LENGTH];
78     int keyboard_irqnr;
79     int mouse_irqnr;
80 dpavlin 14 int currently_asserted[2];
81 dpavlin 4 int type;
82 dpavlin 6 int pc_style_flag;
83 dpavlin 4
84     /* TODO: one of these for each port? */
85     int clocksignal;
86     int rx_int_enable;
87     int tx_int_enable;
88    
89     int keyscanning_enabled;
90 dpavlin 14 int translation_table;
91 dpavlin 4 int state;
92     int cmdbyte;
93 dpavlin 6 int output_byte;
94 dpavlin 4 int last_scancode;
95    
96     unsigned key_queue[2][MAX_8042_QUEUELEN];
97     int head[2], tail[2];
98     };
99    
100     #define STATE_NORMAL 0
101     #define STATE_LDCMDBYTE 1
102     #define STATE_RDCMDBYTE 2
103     #define STATE_WAITING_FOR_TRANSLTABLE 3
104 dpavlin 30 #define STATE_WAITING_FOR_RATE 4
105     #define STATE_WAITING_FOR_ONEKEY_MB 5
106 dpavlin 20 #define STATE_WAITING_FOR_AUX 6
107     #define STATE_WAITING_FOR_AUX_OUT 7
108     #define STATE_LDOUTPUT 8
109     #define STATE_RDOUTPUT 9
110 dpavlin 4
111    
112     /*
113     * pckbc_add_code():
114     *
115     * Adds a byte to the data queue.
116     */
117     void pckbc_add_code(struct pckbc_data *d, int code, int port)
118     {
119     /* Add at the head, read at the tail: */
120     d->head[port] = (d->head[port]+1) % MAX_8042_QUEUELEN;
121     if (d->head[port] == d->tail[port])
122     fatal("[ pckbc: queue overrun, port %i! ]\n", port);
123    
124     d->key_queue[port][d->head[port]] = code;
125     }
126    
127    
128     /*
129     * pckbc_get_code():
130     *
131     * Reads a byte from a data queue.
132     */
133     int pckbc_get_code(struct pckbc_data *d, int port)
134     {
135     if (d->head[port] == d->tail[port])
136     fatal("[ pckbc: queue empty, port %i! ]\n", port);
137 dpavlin 6 else
138     d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN;
139 dpavlin 4 return d->key_queue[port][d->tail[port]];
140     }
141    
142    
143     /*
144 dpavlin 14 * ascii_to_scancodes_type3():
145     *
146     * Conversion from ASCII codes to default (US) keyboard scancodes.
147     * (See http://www.computer-engineering.org/ps2keyboard/scancodes3.html)
148     */
149     static void ascii_to_pc_scancodes_type3(int a, struct pckbc_data *d)
150     {
151     int old_head;
152     int p = 0; /* port */
153     int shift = 0, ctrl = 0;
154    
155     if (a >= 'A' && a <= 'Z') { a += 32; shift = 1; }
156     if ((a >= 1 && a <= 26) && (a!='\n' && a!='\t' && a!='\b' && a!='\r'))
157     { a += 96; ctrl = 1; }
158     if (a=='!') { a = '1'; shift = 1; }
159     if (a=='@') { a = '2'; shift = 1; }
160     if (a=='#') { a = '3'; shift = 1; }
161     if (a=='$') { a = '4'; shift = 1; }
162     if (a=='%') { a = '5'; shift = 1; }
163     if (a=='^') { a = '6'; shift = 1; }
164     if (a=='&') { a = '7'; shift = 1; }
165     if (a=='*') { a = '8'; shift = 1; }
166     if (a=='(') { a = '9'; shift = 1; }
167     if (a==')') { a = '0'; 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     if (a=='"') { a = '\''; shift = 1; }
174     if (a=='|') { a = '\\'; shift = 1; }
175     if (a=='<') { a = ','; shift = 1; }
176     if (a=='>') { a = '.'; shift = 1; }
177     if (a=='?') { a = '/'; shift = 1; }
178    
179     if (shift)
180     pckbc_add_code(d, 0x12, p);
181     if (ctrl)
182     pckbc_add_code(d, 0x11, p);
183    
184     /*
185     * Note: The ugly hack used to add release codes for all of these
186     * keys is as follows: we remember how much of the kbd buf that
187     * is in use here, before we add any scancode. After we've added
188     * one or more scancodes (ie an optional shift + another key)
189     * then we add 0xf0 + the last scancode _if_ the kbd buf was altered.
190     */
191    
192     old_head = d->head[p];
193    
194     if (a==27) pckbc_add_code(d, 0x08, p);
195    
196     if (a=='1') pckbc_add_code(d, 0x16, p);
197     if (a=='2') pckbc_add_code(d, 0x1e, p);
198     if (a=='3') pckbc_add_code(d, 0x26, p);
199     if (a=='4') pckbc_add_code(d, 0x25, p);
200     if (a=='5') pckbc_add_code(d, 0x2e, p);
201     if (a=='6') pckbc_add_code(d, 0x36, p);
202     if (a=='7') pckbc_add_code(d, 0x3d, p);
203     if (a=='8') pckbc_add_code(d, 0x3e, p);
204     if (a=='9') pckbc_add_code(d, 0x46, p);
205     if (a=='0') pckbc_add_code(d, 0x45, p);
206     if (a=='-') pckbc_add_code(d, 0x4e, p);
207     if (a=='=') pckbc_add_code(d, 0x55, p);
208    
209     if (a=='\b') pckbc_add_code(d, 0x29, p);
210    
211     if (a=='\t') pckbc_add_code(d, 0x0d, p);
212     if (a=='q') pckbc_add_code(d, 0x15, p);
213     if (a=='w') pckbc_add_code(d, 0x1d, p);
214     if (a=='e') pckbc_add_code(d, 0x24, p);
215     if (a=='r') pckbc_add_code(d, 0x2d, p);
216     if (a=='t') pckbc_add_code(d, 0x2c, p);
217     if (a=='y') pckbc_add_code(d, 0x35, p);
218     if (a=='u') pckbc_add_code(d, 0x3c, p);
219     if (a=='i') pckbc_add_code(d, 0x43, p);
220     if (a=='o') pckbc_add_code(d, 0x44, p);
221     if (a=='p') pckbc_add_code(d, 0x4d, p);
222    
223     if (a=='[') pckbc_add_code(d, 0x54, p);
224     if (a==']') pckbc_add_code(d, 0x5b, p);
225    
226     if (a=='\n' || a=='\r') pckbc_add_code(d, 0x5a, p);
227    
228     if (a=='a') pckbc_add_code(d, 0x1c, p);
229     if (a=='s') pckbc_add_code(d, 0x1b, p);
230     if (a=='d') pckbc_add_code(d, 0x23, p);
231     if (a=='f') pckbc_add_code(d, 0x2b, p);
232     if (a=='g') pckbc_add_code(d, 0x34, p);
233     if (a=='h') pckbc_add_code(d, 0x33, p);
234     if (a=='j') pckbc_add_code(d, 0x3b, p);
235     if (a=='k') pckbc_add_code(d, 0x42, p);
236     if (a=='l') pckbc_add_code(d, 0x4b, p);
237    
238     if (a==';') pckbc_add_code(d, 0x4c, p);
239     if (a=='\'') pckbc_add_code(d, 0x52, p);
240     /* if (a=='~') pckbc_add_code(d, 0x29, p); ? */
241     if (a=='\\') pckbc_add_code(d, 0x5c, p);
242    
243     if (a=='z') pckbc_add_code(d, 0x1a, p);
244     if (a=='x') pckbc_add_code(d, 0x22, p);
245     if (a=='c') pckbc_add_code(d, 0x21, p);
246     if (a=='v') pckbc_add_code(d, 0x2a, p);
247     if (a=='b') pckbc_add_code(d, 0x32, p);
248     if (a=='n') pckbc_add_code(d, 0x31, p);
249     if (a=='m') pckbc_add_code(d, 0x3a, p);
250    
251     if (a==',') pckbc_add_code(d, 0x41, p);
252     if (a=='.') pckbc_add_code(d, 0x49, p);
253     if (a=='/') pckbc_add_code(d, 0x4a, p);
254    
255     if (a==' ') pckbc_add_code(d, 0x29, p);
256    
257     /* Add release code, if a key was pressed: */
258     if (d->head[p] != old_head) {
259     int code = d->key_queue[p][d->head[p]];
260     pckbc_add_code(d, 0xf0, p);
261     pckbc_add_code(d, code, p);
262     }
263    
264     /* Release shift and ctrl: */
265     if (shift) {
266     pckbc_add_code(d, 0xf0, p);
267     pckbc_add_code(d, 0x12, p);
268     }
269     if (ctrl) {
270     pckbc_add_code(d, 0xf0, p);
271     pckbc_add_code(d, 0x11, p);
272     }
273     }
274    
275    
276     /*
277 dpavlin 20 * ascii_to_scancodes_type2():
278 dpavlin 4 *
279     * Conversion from ASCII codes to default (US) keyboard scancodes.
280     * (See http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html)
281 dpavlin 20 *
282     * NOTE/TODO: This seems to be type 2, not type 1.
283 dpavlin 4 */
284 dpavlin 20 static void ascii_to_pc_scancodes_type2(int a, struct pckbc_data *d)
285 dpavlin 4 {
286 dpavlin 6 int old_head;
287 dpavlin 4 int p = 0; /* port */
288     int shift = 0, ctrl = 0;
289    
290 dpavlin 14 if (d->translation_table == 3) {
291     ascii_to_pc_scancodes_type3(a, d);
292     return;
293     }
294    
295 dpavlin 20 if (d->translation_table != 2) {
296 dpavlin 14 fatal("[ ascii_to_pc_scancodes: unimplemented type! ]\n");
297     return;
298     }
299    
300 dpavlin 4 if (a >= 'A' && a <= 'Z') { a += 32; shift = 1; }
301     if ((a >= 1 && a <= 26) && (a!='\n' && a!='\t' && a!='\b' && a!='\r'))
302     { a += 96; ctrl = 1; }
303    
304 dpavlin 14 if (a=='!') { a = '1'; shift = 1; }
305     if (a=='@') { a = '2'; shift = 1; }
306     if (a=='#') { a = '3'; shift = 1; }
307     if (a=='$') { a = '4'; shift = 1; }
308     if (a=='%') { a = '5'; shift = 1; }
309     if (a=='^') { a = '6'; shift = 1; }
310     if (a=='&') { a = '7'; shift = 1; }
311     if (a=='*') { a = '8'; shift = 1; }
312     if (a=='(') { a = '9'; shift = 1; }
313     if (a==')') { a = '0'; shift = 1; }
314     if (a=='_') { a = '-'; shift = 1; }
315     if (a=='+') { a = '='; shift = 1; }
316     if (a=='{') { a = '['; shift = 1; }
317     if (a=='}') { a = ']'; shift = 1; }
318     if (a==':') { a = ';'; shift = 1; }
319     if (a=='"') { a = '\''; shift = 1; }
320     if (a=='|') { a = '\\'; shift = 1; }
321     if (a=='<') { a = ','; shift = 1; }
322     if (a=='>') { a = '.'; shift = 1; }
323     if (a=='?') { a = '/'; shift = 1; }
324 dpavlin 18 if (a=='~') { a = '`'; shift = 1; }
325 dpavlin 14
326 dpavlin 4 if (shift)
327     pckbc_add_code(d, 0x2a, p);
328     else
329     pckbc_add_code(d, 0x2a + 0x80, p);
330    
331     if (ctrl)
332     pckbc_add_code(d, 0x1d, p);
333    
334     /*
335 dpavlin 6 * Note: The ugly hack used to add release codes for all of these
336     * keys is as follows: we remember how much of the kbd buf that
337     * is in use here, before we add any scancode. After we've added
338     * one or more scancodes (ie an optional shift + another key)
339     * then we duplicate the last scancode | 0x80 _if_ the kbd buf
340     * was altered.
341 dpavlin 4 */
342    
343 dpavlin 6 old_head = d->head[p];
344    
345 dpavlin 4 if (a==27) pckbc_add_code(d, 0x01, p);
346    
347     if (a=='1') pckbc_add_code(d, 0x02, p);
348     if (a=='2') pckbc_add_code(d, 0x03, p);
349     if (a=='3') pckbc_add_code(d, 0x04, p);
350     if (a=='4') pckbc_add_code(d, 0x05, p);
351     if (a=='5') pckbc_add_code(d, 0x06, p);
352     if (a=='6') pckbc_add_code(d, 0x07, p);
353     if (a=='7') pckbc_add_code(d, 0x08, p);
354     if (a=='8') pckbc_add_code(d, 0x09, p);
355     if (a=='9') pckbc_add_code(d, 0x0a, p);
356     if (a=='0') pckbc_add_code(d, 0x0b, p);
357     if (a=='-') pckbc_add_code(d, 0x0c, p);
358     if (a=='=') pckbc_add_code(d, 0x0d, p);
359    
360     if (a=='!') { pckbc_add_code(d, 0x2a, p);
361     pckbc_add_code(d, 0x02, p); }
362     if (a=='@') { pckbc_add_code(d, 0x2a, p);
363     pckbc_add_code(d, 0x03, p); }
364     if (a=='#') { pckbc_add_code(d, 0x2a, p);
365     pckbc_add_code(d, 0x04, p); }
366     if (a=='$') { pckbc_add_code(d, 0x2a, p);
367     pckbc_add_code(d, 0x05, p); }
368     if (a=='%') { pckbc_add_code(d, 0x2a, p);
369     pckbc_add_code(d, 0x06, p); }
370     if (a=='^') { pckbc_add_code(d, 0x2a, p);
371     pckbc_add_code(d, 0x07, p); }
372     if (a=='&') { pckbc_add_code(d, 0x2a, p);
373     pckbc_add_code(d, 0x08, p); }
374     if (a=='*') { pckbc_add_code(d, 0x2a, p);
375     pckbc_add_code(d, 0x09, p); }
376     if (a=='(') { pckbc_add_code(d, 0x2a, p);
377     pckbc_add_code(d, 0x0a, p); }
378    
379     if (a=='\b') pckbc_add_code(d, 0x0e, p);
380    
381     if (a=='\t') pckbc_add_code(d, 0x0f, p);
382     if (a=='q') pckbc_add_code(d, 0x10, p);
383     if (a=='w') pckbc_add_code(d, 0x11, p);
384     if (a=='e') pckbc_add_code(d, 0x12, p);
385     if (a=='r') pckbc_add_code(d, 0x13, p);
386     if (a=='t') pckbc_add_code(d, 0x14, p);
387     if (a=='y') pckbc_add_code(d, 0x15, p);
388     if (a=='u') pckbc_add_code(d, 0x16, p);
389     if (a=='i') pckbc_add_code(d, 0x17, p);
390     if (a=='o') pckbc_add_code(d, 0x18, p);
391     if (a=='p') pckbc_add_code(d, 0x19, p);
392    
393     if (a=='[') pckbc_add_code(d, 0x1a, p);
394     if (a==']') pckbc_add_code(d, 0x1b, p);
395    
396     if (a=='\n' || a=='\r') pckbc_add_code(d, 0x1c, p);
397    
398     if (a=='a') pckbc_add_code(d, 0x1e, p);
399     if (a=='s') pckbc_add_code(d, 0x1f, p);
400     if (a=='d') pckbc_add_code(d, 0x20, p);
401     if (a=='f') pckbc_add_code(d, 0x21, p);
402     if (a=='g') pckbc_add_code(d, 0x22, p);
403     if (a=='h') pckbc_add_code(d, 0x23, p);
404     if (a=='j') pckbc_add_code(d, 0x24, p);
405     if (a=='k') pckbc_add_code(d, 0x25, p);
406     if (a=='l') pckbc_add_code(d, 0x26, p);
407    
408     if (a==';') pckbc_add_code(d, 0x27, p);
409     if (a=='\'') pckbc_add_code(d, 0x28, p);
410 dpavlin 18 if (a=='`') pckbc_add_code(d, 0x29, p);
411 dpavlin 4 if (a=='\\') pckbc_add_code(d, 0x2b, p);
412    
413     if (a=='z') pckbc_add_code(d, 0x2c, p);
414     if (a=='x') pckbc_add_code(d, 0x2d, p);
415     if (a=='c') pckbc_add_code(d, 0x2e, p);
416     if (a=='v') pckbc_add_code(d, 0x2f, p);
417     if (a=='b') pckbc_add_code(d, 0x30, p);
418     if (a=='n') pckbc_add_code(d, 0x31, p);
419     if (a=='m') pckbc_add_code(d, 0x32, p);
420    
421     if (a==',') pckbc_add_code(d, 0x33, p);
422     if (a=='.') pckbc_add_code(d, 0x34, p);
423     if (a=='/') pckbc_add_code(d, 0x35, p);
424    
425     if (a==' ') pckbc_add_code(d, 0x39, p);
426    
427 dpavlin 6 /* Add release code, if a key was pressed: */
428     if (d->head[p] != old_head) {
429     int code = d->key_queue[p][d->head[p]] | 0x80;
430     pckbc_add_code(d, code, p);
431     }
432    
433 dpavlin 4 /* Release ctrl: */
434     if (ctrl)
435     pckbc_add_code(d, 0x1d + 0x80, p);
436     }
437    
438    
439     /*
440     * dev_pckbc_tick():
441     */
442     void dev_pckbc_tick(struct cpu *cpu, void *extra)
443     {
444     struct pckbc_data *d = extra;
445 dpavlin 6 int port_nr, ch, ints_enabled;
446 dpavlin 4
447 dpavlin 6 if (d->in_use && console_charavail(d->console_handle)) {
448 dpavlin 4 ch = console_readchar(d->console_handle);
449     if (ch >= 0)
450 dpavlin 20 ascii_to_pc_scancodes_type2(ch, d);
451 dpavlin 4 }
452    
453 dpavlin 6 ints_enabled = d->rx_int_enable;
454    
455 dpavlin 4 /* TODO: mouse movements? */
456    
457 dpavlin 6 if (d->cmdbyte & KC8_KDISABLE)
458     ints_enabled = 0;
459    
460 dpavlin 4 for (port_nr=0; port_nr<2; port_nr++) {
461 dpavlin 6 /* Cause receive interrupt, if there's something in the
462     receive buffer: (Otherwise deassert the interrupt.) */
463 dpavlin 30 int irq = port_nr==0? d->keyboard_irqnr : d->mouse_irqnr;
464    
465 dpavlin 6 if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) {
466 dpavlin 12 debug("[ pckbc: interrupt port %i ]\n", port_nr);
467 dpavlin 30 cpu_interrupt(cpu, irq);
468 dpavlin 14 d->currently_asserted[port_nr] = 1;
469 dpavlin 4 } else {
470 dpavlin 14 if (d->currently_asserted[port_nr])
471 dpavlin 30 cpu_interrupt_ack(cpu, irq);
472 dpavlin 14 d->currently_asserted[port_nr] = 0;
473 dpavlin 4 }
474     }
475     }
476    
477    
478     /*
479     * dev_pckbc_command():
480 dpavlin 6 *
481     * Handle commands to the 8048 in the emulated keyboard.
482 dpavlin 4 */
483     static void dev_pckbc_command(struct pckbc_data *d, int port_nr)
484     {
485     int cmd = d->reg[PC_CMD];
486    
487     if (d->type == PCKBC_8242)
488     cmd = d->reg[PS2_TXBUF];
489    
490     if (d->state == STATE_WAITING_FOR_TRANSLTABLE) {
491 dpavlin 14 debug("[ pckbc: (port %i) switching to translation table "
492     "0x%02x ]\n", port_nr, cmd);
493     switch (cmd) {
494 dpavlin 20 case 2:
495 dpavlin 14 case 3: d->translation_table = cmd;
496     break;
497     default:fatal("[ pckbc: (port %i) translation table "
498 dpavlin 20 "0x%02x is NOT YET IMPLEMENTED ]\n",
499     port_nr, cmd);
500 dpavlin 14 }
501 dpavlin 4 pckbc_add_code(d, KBR_ACK, port_nr);
502     d->state = STATE_NORMAL;
503     return;
504     }
505    
506 dpavlin 30 if (d->state == STATE_WAITING_FOR_RATE) {
507     debug("[ pckbc: (port %i) received Typematic Rate data: "
508 dpavlin 14 "0x%02x ]\n", port_nr, cmd);
509     pckbc_add_code(d, KBR_ACK, port_nr);
510     d->state = STATE_NORMAL;
511     return;
512     }
513    
514 dpavlin 30 if (d->state == STATE_WAITING_FOR_ONEKEY_MB) {
515     debug("[ pckbc: (port %i) received One-key make/break data: "
516 dpavlin 14 "0x%02x ]\n", port_nr, cmd);
517     pckbc_add_code(d, KBR_ACK, port_nr);
518     d->state = STATE_NORMAL;
519     return;
520     }
521    
522 dpavlin 20 if (d->state == STATE_WAITING_FOR_AUX) {
523     debug("[ pckbc: (port %i) received aux data: "
524     "0x%02x ]\n", port_nr, cmd);
525     /* Echo back. */
526     pckbc_add_code(d, cmd, port_nr);
527     d->state = STATE_NORMAL;
528     return;
529     }
530    
531     if (d->state == STATE_WAITING_FOR_AUX_OUT) {
532     debug("[ pckbc: (port %i) received aux out data: "
533     "0x%02x ]\n", port_nr, cmd);
534     /* Echo back. */
535     pckbc_add_code(d, cmd, port_nr);
536     d->state = STATE_NORMAL;
537     return;
538     }
539    
540 dpavlin 4 switch (cmd) {
541 dpavlin 30
542 dpavlin 4 case 0x00:
543 dpavlin 30 /*
544     * TODO: What does this do? This is possibly due to an
545     * error in the handling of some other command code.
546     */
547 dpavlin 4 pckbc_add_code(d, KBR_ACK, port_nr);
548     break;
549 dpavlin 30
550 dpavlin 4 case KBC_MODEIND: /* Set LEDs */
551     /* Just ACK, no LEDs are actually set. */
552     pckbc_add_code(d, KBR_ACK, port_nr);
553     break;
554 dpavlin 30
555 dpavlin 4 case KBC_SETTABLE:
556     pckbc_add_code(d, KBR_ACK, port_nr);
557     d->state = STATE_WAITING_FOR_TRANSLTABLE;
558     break;
559 dpavlin 30
560 dpavlin 4 case KBC_ENABLE:
561     d->keyscanning_enabled = 1;
562     pckbc_add_code(d, KBR_ACK, port_nr);
563     break;
564 dpavlin 30
565 dpavlin 4 case KBC_DISABLE:
566     d->keyscanning_enabled = 0;
567     pckbc_add_code(d, KBR_ACK, port_nr);
568     break;
569 dpavlin 30
570 dpavlin 4 case KBC_SETDEFAULT:
571     pckbc_add_code(d, KBR_ACK, port_nr);
572     break;
573 dpavlin 30
574     case KBC_GETID:
575     /* Get keyboard ID. NOTE/TODO: Ugly hardcoded answer. */
576 dpavlin 14 pckbc_add_code(d, KBR_ACK, port_nr);
577 dpavlin 30 pckbc_add_code(d, 0xab, port_nr);
578     pckbc_add_code(d, 0x41, port_nr);
579 dpavlin 14 break;
580 dpavlin 30
581     case KBC_TYPEMATIC:
582     /* Set typematic (auto-repeat) delay/speed: */
583 dpavlin 14 pckbc_add_code(d, KBR_ACK, port_nr);
584 dpavlin 30 d->state = STATE_WAITING_FOR_RATE;
585 dpavlin 14 break;
586 dpavlin 30
587     case KBC_ALLKEYS_TMB:
588     /* "Make all keys typematic/make/break" */
589 dpavlin 14 pckbc_add_code(d, KBR_ACK, port_nr);
590     break;
591 dpavlin 30
592     case KBC_ONEKEY_MB:
593     /* "Make one key typematic/make/break" */
594     pckbc_add_code(d, KBR_ACK, port_nr);
595     d->state = STATE_WAITING_FOR_ONEKEY_MB;
596     break;
597    
598 dpavlin 4 case KBC_RESET:
599     pckbc_add_code(d, KBR_ACK, port_nr);
600     pckbc_add_code(d, KBR_RSTDONE, port_nr);
601 dpavlin 30 /*
602     * Disable interrupts during reset, or Linux 2.6
603     * prints warnings about spurious interrupts.
604     */
605     d->rx_int_enable = 0;
606 dpavlin 4 break;
607 dpavlin 30
608 dpavlin 4 default:
609 dpavlin 14 fatal("[ pckbc: (port %i) UNIMPLEMENTED 8048 command"
610     " 0x%02x ]\n", port_nr, cmd);
611 dpavlin 30 exit(1);
612 dpavlin 4 }
613     }
614    
615    
616 dpavlin 22 DEVICE_ACCESS(pckbc)
617 dpavlin 4 {
618     uint64_t idata = 0, odata = 0;
619 dpavlin 22 int port_nr = 0;
620     size_t i;
621 dpavlin 4 struct pckbc_data *d = extra;
622    
623 dpavlin 18 if (writeflag == MEM_WRITE)
624     idata = memory_readmax64(cpu, data, len);
625 dpavlin 4
626     #ifdef PCKBC_DEBUG
627     if (writeflag == MEM_WRITE)
628     fatal("[ pckbc: write to addr 0x%x: 0x%x ]\n",
629     (int)relative_addr, (int)idata);
630     else
631     fatal("[ pckbc: read from addr 0x%x ]\n",
632     (int)relative_addr);
633     #endif
634    
635     /* For JAZZ-based machines: */
636 dpavlin 6 if (relative_addr >= 0x60) {
637 dpavlin 4 relative_addr -= 0x60;
638 dpavlin 6 if (relative_addr != 0)
639     relative_addr = 1;
640     } else if (d->type == PCKBC_8242) {
641     /* 8242 PS2-style: */
642 dpavlin 4 /* when using 8-byte alignment... */
643     relative_addr /= sizeof(uint64_t);
644     /* port_nr = 0 for keyboard, 1 for mouse */
645     port_nr = (relative_addr >> 2);
646     relative_addr &= 3;
647     relative_addr += PS2;
648 dpavlin 6 } else if (d->pc_style_flag) {
649     /* PC-style: */
650     if (relative_addr != 0 && relative_addr != 4) {
651     /* TODO (port 0x61) */
652     odata = 0x21;
653     {
654     static int x = 0;
655     x++;
656     if (x&1)
657     odata ^= 0x10;
658     }
659     if (writeflag == MEM_READ)
660     memory_writemax64(cpu, data, len, odata);
661 dpavlin 32 return 1;
662 dpavlin 6 }
663     if (relative_addr != 0)
664     relative_addr = 1;
665 dpavlin 4 } else {
666 dpavlin 6 /* Others... Non-Jazz ARC-based machines etc. */
667     if (relative_addr != 0)
668 dpavlin 4 relative_addr = 1;
669     }
670    
671     switch (relative_addr) {
672    
673     /*
674     * 8042 (PC):
675     */
676    
677     case 0: /* data */
678     if (writeflag==MEM_READ) {
679 dpavlin 6 switch (d->state) {
680     case STATE_RDCMDBYTE:
681 dpavlin 4 odata = d->cmdbyte;
682     d->state = STATE_NORMAL;
683 dpavlin 6 break;
684     case STATE_RDOUTPUT:
685     odata = d->output_byte;
686     d->state = STATE_NORMAL;
687     break;
688     default:if (d->head[0] != d->tail[0]) {
689 dpavlin 4 odata = pckbc_get_code(d, 0);
690     d->last_scancode = odata;
691     } else {
692     odata = d->last_scancode;
693     d->last_scancode |= 0x80;
694     }
695     }
696 dpavlin 6 /* debug("[ pckbc: read from DATA: 0x%02x ]\n",
697 dpavlin 20 (int)odata); */
698 dpavlin 4 } else {
699     debug("[ pckbc: write to DATA:");
700     for (i=0; i<len; i++)
701     debug(" %02x", data[i]);
702     debug(" ]\n");
703    
704 dpavlin 6 switch (d->state) {
705     case STATE_LDCMDBYTE:
706 dpavlin 4 d->cmdbyte = idata;
707     d->rx_int_enable = d->cmdbyte &
708     (KC8_KENABLE | KC8_MENABLE) ? 1 : 0;
709     d->state = STATE_NORMAL;
710 dpavlin 6 break;
711     case STATE_LDOUTPUT:
712     d->output_byte = idata;
713     d->state = STATE_NORMAL;
714     break;
715     default:d->reg[relative_addr] = idata;
716 dpavlin 4 dev_pckbc_command(d, port_nr);
717     }
718     }
719     break;
720     case 1: /* control */
721     if (writeflag==MEM_READ) {
722     dev_pckbc_tick(cpu, d);
723    
724     odata = 0;
725    
726     /* "Data in buffer" bit */
727     if (d->head[0] != d->tail[0] ||
728 dpavlin 6 d->state == STATE_RDCMDBYTE ||
729     d->state == STATE_RDOUTPUT)
730 dpavlin 4 odata |= KBS_DIB;
731 dpavlin 6
732     if (d->state == STATE_RDCMDBYTE)
733     odata |= KBS_OCMD;
734    
735     odata |= KBS_NOSEC;
736 dpavlin 4 /* debug("[ pckbc: read from CTL status port: "
737     "0x%02x ]\n", (int)odata); */
738     } else {
739     debug("[ pckbc: write to CTL:");
740     for (i=0; i<len; i++)
741     debug(" %02x", data[i]);
742     debug(" ]\n");
743     d->reg[relative_addr] = idata;
744    
745     switch (idata) {
746 dpavlin 20 case 0x10:
747     case 0x11:
748     /* TODO: For now, don't print warnings about
749     these. NetBSD sends these. */
750     break;
751 dpavlin 4 case K_RDCMDBYTE:
752     d->state = STATE_RDCMDBYTE;
753     break;
754     case K_LDCMDBYTE:
755     d->state = STATE_LDCMDBYTE;
756     break;
757 dpavlin 6 case 0xa7:
758     d->cmdbyte |= KC8_MDISABLE;
759     break;
760     case 0xa8:
761     d->cmdbyte &= ~KC8_MDISABLE;
762     break;
763 dpavlin 4 case 0xa9: /* test auxiliary port */
764     debug("[ pckbc: CONTROL 0xa9, TODO ]\n");
765     break;
766     case 0xaa: /* keyboard self-test */
767     pckbc_add_code(d, 0x55, port_nr);
768     break;
769 dpavlin 20 case 0xab: /* keyboard interface self-test */
770     pckbc_add_code(d, 0x00, port_nr);
771     break;
772 dpavlin 6 case 0xad:
773     d->cmdbyte |= KC8_KDISABLE;
774     break;
775     case 0xae:
776     d->cmdbyte &= ~KC8_KDISABLE;
777     break;
778     case 0xd0:
779     d->state = STATE_RDOUTPUT;
780     break;
781     case 0xd1:
782     d->state = STATE_LDOUTPUT;
783     break;
784 dpavlin 20 case 0xd3: /* write to auxiliary device
785     output buffer */
786     debug("[ pckbc: CONTROL 0xd3, TODO ]\n");
787     d->state = STATE_WAITING_FOR_AUX_OUT;
788     break;
789 dpavlin 4 case 0xd4: /* write to auxiliary port */
790     debug("[ pckbc: CONTROL 0xd4, TODO ]\n");
791 dpavlin 20 d->state = STATE_WAITING_FOR_AUX;
792 dpavlin 4 break;
793     default:
794     fatal("[ pckbc: unknown CONTROL 0x%x ]\n",
795 dpavlin 20 (int)idata);
796 dpavlin 4 d->state = STATE_NORMAL;
797     }
798     }
799     break;
800    
801     /*
802     * 8242 (PS2):
803     */
804    
805     case PS2 + PS2_TXBUF:
806     if (writeflag==MEM_READ) {
807     odata = random() & 0xff;
808     debug("[ pckbc: read from port %i, PS2_TXBUF: "
809     "0x%x ]\n", port_nr, (int)odata);
810     } else {
811     debug("[ pckbc: write to port %i, PS2_TXBUF: "
812     "0x%llx ]\n", port_nr, (long long)idata);
813    
814     /* Handle keyboard commands: */
815 dpavlin 14 d->reg[PS2_TXBUF] = idata;
816     dev_pckbc_command(d, port_nr);
817 dpavlin 4 }
818     break;
819    
820     case PS2 + PS2_RXBUF:
821     if (writeflag==MEM_READ) {
822     /* TODO: What should be returned if no data
823     is available? */
824     odata = random() & 0xff;
825     if (d->head[port_nr] != d->tail[port_nr])
826     odata = pckbc_get_code(d, port_nr);
827     debug("[ pckbc: read from port %i, PS2_RXBUF: "
828     "0x%02x ]\n", port_nr, (int)odata);
829     } else {
830     debug("[ pckbc: write to port %i, PS2_RXBUF: "
831     "0x%llx ]\n", port_nr, (long long)idata);
832     }
833     break;
834    
835     case PS2 + PS2_CONTROL:
836     if (writeflag==MEM_READ) {
837     debug("[ pckbc: read from port %i, PS2_CONTROL"
838     " ]\n", port_nr);
839     } else {
840     debug("[ pckbc: write to port %i, PS2_CONTROL:"
841     " 0x%llx ]\n", port_nr, (long long)idata);
842     d->clocksignal = (idata & 0x10) ? 1 : 0;
843     d->rx_int_enable = (idata & 0x08) ? 1 : 0;
844     d->tx_int_enable = (idata & 0x04) ? 1 : 0;
845     }
846     break;
847    
848     case PS2 + PS2_STATUS:
849     if (writeflag==MEM_READ) {
850     /* 0x08 = transmit buffer empty */
851     odata = d->clocksignal + 0x08;
852    
853     if (d->head[port_nr] != d->tail[port_nr]) {
854     /* 0x10 = receicer data available (?) */
855     odata |= 0x10;
856     }
857    
858     debug("[ pckbc: read from port %i, PS2_STATUS: "
859     "0x%llx ]\n", port_nr, (long long)odata);
860     } else {
861     debug("[ pckbc: write to port %i, PS2_STATUS: "
862     "0x%llx ]\n", port_nr, (long long)idata);
863     }
864     break;
865    
866     default:
867     if (writeflag==MEM_READ) {
868     debug("[ pckbc: read from unimplemented reg %i ]\n",
869     (int)relative_addr);
870     odata = d->reg[relative_addr];
871     } else {
872     debug("[ pckbc: write to unimplemented reg %i:",
873     (int)relative_addr);
874     for (i=0; i<len; i++)
875     debug(" %02x", data[i]);
876     debug(" ]\n");
877     d->reg[relative_addr] = idata;
878     }
879     }
880    
881 dpavlin 20 /* SGI? TODO: fix */
882 dpavlin 14 if (len == 8)
883     odata |= (odata << 8) | (odata << 16) | (odata << 24) |
884     (odata << 32) | (odata << 40) | (odata << 48) |
885     (odata << 56);
886    
887 dpavlin 4 if (writeflag == MEM_READ)
888     memory_writemax64(cpu, data, len, odata);
889    
890     dev_pckbc_tick(cpu, d);
891    
892     return 1;
893     }
894    
895    
896     /*
897     * dev_pckbc_init():
898     *
899     * Type should be PCKBC_8042 or PCKBC_8242.
900     */
901     int dev_pckbc_init(struct machine *machine, struct memory *mem,
902     uint64_t baseaddr, int type, int keyboard_irqnr, int mouse_irqnr,
903 dpavlin 6 int in_use, int pc_style_flag)
904 dpavlin 4 {
905     struct pckbc_data *d;
906     int len = DEV_PCKBC_LENGTH;
907    
908     d = malloc(sizeof(struct pckbc_data));
909     if (d == NULL) {
910     fprintf(stderr, "out of memory\n");
911     exit(1);
912     }
913     memset(d, 0, sizeof(struct pckbc_data));
914    
915 dpavlin 12 if (type == PCKBC_8242)
916 dpavlin 22 len = 0x18;
917 dpavlin 12
918 dpavlin 4 if (type == PCKBC_JAZZ) {
919     type = PCKBC_8042;
920     len = DEV_PCKBC_LENGTH + 0x60;
921     }
922    
923 dpavlin 14 d->type = type;
924     d->keyboard_irqnr = keyboard_irqnr;
925     d->mouse_irqnr = mouse_irqnr;
926     d->in_use = in_use;
927     d->pc_style_flag = pc_style_flag;
928 dpavlin 20 d->translation_table = 2;
929 dpavlin 14 d->rx_int_enable = 1;
930     d->output_byte = 0x02; /* A20 enable on PCs */
931 dpavlin 4
932 dpavlin 22 d->console_handle = console_start_slave_inputonly(
933     machine, "pckbc", d->in_use);
934    
935 dpavlin 4 memory_device_register(mem, "pckbc", baseaddr,
936 dpavlin 20 len, dev_pckbc_access, d, DM_DEFAULT, NULL);
937 dpavlin 24 machine_add_tickfunction(machine, dev_pckbc_tick, d,
938     PCKBC_TICKSHIFT, 0.0);
939 dpavlin 4
940     return d->console_handle;
941     }
942    

  ViewVC Help
Powered by ViewVC 1.1.26