/[gxemul]/upstream/0.4.1/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

Contents of /upstream/0.4.1/src/devices/dev_pckbc.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26