/[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 30 - (hide annotations)
Mon Oct 8 16:20:40 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.1325 2006/08/15 15:38:37 debug Exp $
20060723	More Transputer instructions (pfix, nfix, opr, mint, ldl, ldlp,
		eqc, rev, ajw, stl, stlf, sthf, sub, ldnl, ldnlp, ldpi, move,
		wcnt, add, bcnt).
		Adding more SPARC instructions (andcc, addcc, bl, rdpr).
		Progress on the igsfb framebuffer used by NetBSD/netwinder.
		Enabling 8-bit fills in dev_fb.
		NetBSD/netwinder 3.0.1 can now run from a disk image :-)
20060724	Cleanup/performance fix for 64-bit virtual translation table
		updates (by removing the "timestamp" stuff). A full NetBSD/pmax
		3.0.1 install for R4400 has dropped from 667 seconds to 584 :)
		Fixing the igsfb "almost vga" color (it is 24-bit, not 18-bit).
		Adding some MIPS instruction combinations (3*lw, and 3*addu).
		The 8048 keyboard now turns off interrupt enable between the
		KBR_ACK and the KBR_RSTDONE, to work better with Linux 2.6.
		Not causing PPC DEC interrupts if PPC_NO_DEC is set for a
		specific CPU; NetBSD/bebox gets slightly further than before.
		Adding some more SPARC instructions: branches, udiv.
20060725	Refreshing dev_pckbc.c a little.
		Cleanups for the SH emulation mode, and adding the first
		"compact" (16-bit) instructions: various simple movs, nop,
		shll, stc, or, ldc.
20060726	Adding dummy "pcn" (AMD PCnet NIC) PCI glue.
20060727	Various cleanups; removing stuff from cpu.h, such as
		running_translated (not really meaningful anymore), and
		page flags (breaking into the debugger clears all translations
		anyway).
		Minor MIPS instruction combination updates.
20060807	Expanding the 3*sw and 3*lw MIPS instruction combinations to
		work with 2* and 4* too, resulting in a minor performance gain.
		Implementing a usleep hack for the RM52xx/MIPS32/MIPS64 "wait"
		instruction (when emulating 1 cpu).
20060808	Experimenting with some more MIPS instruction combinations.
		Implementing support for showing a (hardcoded 12x22) text
		cursor in igsfb.
20060809	Simplifying the NetBSD/evbmips (Malta) install instructions
		somewhat (by using a NetBSD/pmax ramdisk install kernel).
20060812	Experimenting more with the MIPS 'wait' instruction.
		PCI configuration register writes can now be handled, which
		allow PCI IDE controllers to work with NetBSD/Malta 3.0.1 and
		NetBSD/cobalt 3.0.1. (Previously only NetBSD 2.1 worked.)
20060813	Updating dev_gt.c based on numbers from Alec Voropay, to enable
		Linux 2.6 to use PCI on Malta.
		Continuing on Algor interrupt stuff.
20060814	Adding support for routing ISA interrupts to two different
		interrupts, making it possible to run NetBSD/algor :-)
20060814-15	Testing for the release.

==============  RELEASE 0.4.2  ==============


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 30 * $Id: dev_pckbc.c,v 1.69 2006/07/25 18:58:02 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     return 0;
662     }
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