/[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 18 - (hide annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 23622 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26