/[gxemul]/upstream/0.3.3.2/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.3.3.2/src/devices/dev_pckbc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (show annotations)
Mon Oct 8 16:18:22 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 19757 byte(s)
0.3.3.2
1 /*
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 * $Id: dev_pckbc.c,v 1.45 2005/06/02 15:42:49 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
53
54 #define MAX_8042_QUEUELEN 256
55
56 #define PC_DATA 0
57 #define PC_CMD 0
58 #define PC_STATUS 1
59
60 #define PS2_TXBUF 0
61 #define PS2_RXBUF 1
62 #define PS2_CONTROL 2
63 #define PS2_STATUS 3
64
65 #define PS2 100
66
67 #define PCKBC_TICKSHIFT 14
68
69 struct pckbc_data {
70 int console_handle;
71 int in_use;
72
73 int reg[DEV_PCKBC_LENGTH];
74 int keyboard_irqnr;
75 int mouse_irqnr;
76 int type;
77 int pc_style_flag;
78
79 /* TODO: one of these for each port? */
80 int clocksignal;
81 int rx_int_enable;
82 int tx_int_enable;
83
84 int keyscanning_enabled;
85 int state;
86 int cmdbyte;
87 int output_byte;
88 int last_scancode;
89
90 unsigned key_queue[2][MAX_8042_QUEUELEN];
91 int head[2], tail[2];
92 };
93
94 #define STATE_NORMAL 0
95 #define STATE_LDCMDBYTE 1
96 #define STATE_RDCMDBYTE 2
97 #define STATE_WAITING_FOR_TRANSLTABLE 3
98 #define STATE_LDOUTPUT 4
99 #define STATE_RDOUTPUT 5
100
101
102 /*
103 * pckbc_add_code():
104 *
105 * Adds a byte to the data queue.
106 */
107 void pckbc_add_code(struct pckbc_data *d, int code, int port)
108 {
109 /* Add at the head, read at the tail: */
110 d->head[port] = (d->head[port]+1) % MAX_8042_QUEUELEN;
111 if (d->head[port] == d->tail[port])
112 fatal("[ pckbc: queue overrun, port %i! ]\n", port);
113
114 d->key_queue[port][d->head[port]] = code;
115 }
116
117
118 /*
119 * pckbc_get_code():
120 *
121 * Reads a byte from a data queue.
122 */
123 int pckbc_get_code(struct pckbc_data *d, int port)
124 {
125 if (d->head[port] == d->tail[port])
126 fatal("[ pckbc: queue empty, port %i! ]\n", port);
127 else
128 d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN;
129 return d->key_queue[port][d->tail[port]];
130 }
131
132
133 /*
134 * ascii_to_scancodes():
135 *
136 * Conversion from ASCII codes to default (US) keyboard scancodes.
137 * (See http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html)
138 */
139 static void ascii_to_pc_scancodes(int a, struct pckbc_data *d)
140 {
141 int old_head;
142 int p = 0; /* port */
143 int shift = 0, ctrl = 0;
144
145 if (a >= 'A' && a <= 'Z') { a += 32; shift = 1; }
146 if ((a >= 1 && a <= 26) && (a!='\n' && a!='\t' && a!='\b' && a!='\r'))
147 { a += 96; ctrl = 1; }
148
149 if (shift)
150 pckbc_add_code(d, 0x2a, p);
151 else
152 pckbc_add_code(d, 0x2a + 0x80, p);
153
154 if (ctrl)
155 pckbc_add_code(d, 0x1d, p);
156
157 /*
158 * Note: The ugly hack used to add release codes for all of these
159 * keys is as follows: we remember how much of the kbd buf that
160 * is in use here, before we add any scancode. After we've added
161 * one or more scancodes (ie an optional shift + another key)
162 * then we duplicate the last scancode | 0x80 _if_ the kbd buf
163 * was altered.
164 */
165
166 old_head = d->head[p];
167
168 if (a==27) pckbc_add_code(d, 0x01, p);
169
170 if (a=='1') pckbc_add_code(d, 0x02, p);
171 if (a=='2') pckbc_add_code(d, 0x03, p);
172 if (a=='3') pckbc_add_code(d, 0x04, p);
173 if (a=='4') pckbc_add_code(d, 0x05, p);
174 if (a=='5') pckbc_add_code(d, 0x06, p);
175 if (a=='6') pckbc_add_code(d, 0x07, p);
176 if (a=='7') pckbc_add_code(d, 0x08, p);
177 if (a=='8') pckbc_add_code(d, 0x09, p);
178 if (a=='9') pckbc_add_code(d, 0x0a, p);
179 if (a=='0') pckbc_add_code(d, 0x0b, p);
180 if (a=='-') pckbc_add_code(d, 0x0c, p);
181 if (a=='=') pckbc_add_code(d, 0x0d, p);
182
183 if (a=='!') { pckbc_add_code(d, 0x2a, p);
184 pckbc_add_code(d, 0x02, p); }
185 if (a=='@') { pckbc_add_code(d, 0x2a, p);
186 pckbc_add_code(d, 0x03, p); }
187 if (a=='#') { pckbc_add_code(d, 0x2a, p);
188 pckbc_add_code(d, 0x04, p); }
189 if (a=='$') { pckbc_add_code(d, 0x2a, p);
190 pckbc_add_code(d, 0x05, p); }
191 if (a=='%') { pckbc_add_code(d, 0x2a, p);
192 pckbc_add_code(d, 0x06, p); }
193 if (a=='^') { pckbc_add_code(d, 0x2a, p);
194 pckbc_add_code(d, 0x07, p); }
195 if (a=='&') { pckbc_add_code(d, 0x2a, p);
196 pckbc_add_code(d, 0x08, p); }
197 if (a=='*') { pckbc_add_code(d, 0x2a, p);
198 pckbc_add_code(d, 0x09, p); }
199 if (a=='(') { pckbc_add_code(d, 0x2a, p);
200 pckbc_add_code(d, 0x0a, p); }
201 if (a==')') { pckbc_add_code(d, 0x2a, p);
202 pckbc_add_code(d, 0x0b, p); }
203 if (a=='_') { pckbc_add_code(d, 0x2a, p);
204 pckbc_add_code(d, 0x0c, p); }
205 if (a=='+') { pckbc_add_code(d, 0x2a, p);
206 pckbc_add_code(d, 0x0d, p); }
207
208 if (a=='\b') pckbc_add_code(d, 0x0e, p);
209
210 if (a=='\t') pckbc_add_code(d, 0x0f, p);
211 if (a=='q') pckbc_add_code(d, 0x10, p);
212 if (a=='w') pckbc_add_code(d, 0x11, p);
213 if (a=='e') pckbc_add_code(d, 0x12, p);
214 if (a=='r') pckbc_add_code(d, 0x13, p);
215 if (a=='t') pckbc_add_code(d, 0x14, p);
216 if (a=='y') pckbc_add_code(d, 0x15, p);
217 if (a=='u') pckbc_add_code(d, 0x16, p);
218 if (a=='i') pckbc_add_code(d, 0x17, p);
219 if (a=='o') pckbc_add_code(d, 0x18, p);
220 if (a=='p') pckbc_add_code(d, 0x19, p);
221
222 if (a=='[') pckbc_add_code(d, 0x1a, p);
223 if (a=='{') { pckbc_add_code(d, 0x2a, p);
224 pckbc_add_code(d, 0x1a, p); }
225 if (a==']') pckbc_add_code(d, 0x1b, p);
226 if (a=='}') { pckbc_add_code(d, 0x2a, p);
227 pckbc_add_code(d, 0x1b, p); }
228
229 if (a=='\n' || a=='\r') pckbc_add_code(d, 0x1c, p);
230
231 if (a=='a') pckbc_add_code(d, 0x1e, p);
232 if (a=='s') pckbc_add_code(d, 0x1f, p);
233 if (a=='d') pckbc_add_code(d, 0x20, p);
234 if (a=='f') pckbc_add_code(d, 0x21, p);
235 if (a=='g') pckbc_add_code(d, 0x22, p);
236 if (a=='h') pckbc_add_code(d, 0x23, p);
237 if (a=='j') pckbc_add_code(d, 0x24, p);
238 if (a=='k') pckbc_add_code(d, 0x25, p);
239 if (a=='l') pckbc_add_code(d, 0x26, p);
240
241 if (a==';') pckbc_add_code(d, 0x27, p);
242 if (a==':') { pckbc_add_code(d, 0x2a, p);
243 pckbc_add_code(d, 0x27, p); }
244 if (a=='\'') pckbc_add_code(d, 0x28, p);
245 if (a=='"') { pckbc_add_code(d, 0x2a, p);
246 pckbc_add_code(d, 0x28, p); }
247 if (a=='~') pckbc_add_code(d, 0x29, p);
248
249 if (a=='\\') pckbc_add_code(d, 0x2b, p);
250 if (a=='|') { pckbc_add_code(d, 0x2a, p);
251 pckbc_add_code(d, 0x2b, p); }
252
253 if (a=='z') pckbc_add_code(d, 0x2c, p);
254 if (a=='x') pckbc_add_code(d, 0x2d, p);
255 if (a=='c') pckbc_add_code(d, 0x2e, p);
256 if (a=='v') pckbc_add_code(d, 0x2f, p);
257 if (a=='b') pckbc_add_code(d, 0x30, p);
258 if (a=='n') pckbc_add_code(d, 0x31, p);
259 if (a=='m') pckbc_add_code(d, 0x32, p);
260
261 if (a==',') pckbc_add_code(d, 0x33, p);
262 if (a=='<') { pckbc_add_code(d, 0x2a, p);
263 pckbc_add_code(d, 0x33, p); }
264 if (a=='.') pckbc_add_code(d, 0x34, p);
265 if (a=='>') { pckbc_add_code(d, 0x2a, p);
266 pckbc_add_code(d, 0x34, p); }
267 if (a=='/') pckbc_add_code(d, 0x35, p);
268 if (a=='?') { pckbc_add_code(d, 0x2a, p);
269 pckbc_add_code(d, 0x35, p); }
270
271 if (a==' ') pckbc_add_code(d, 0x39, p);
272
273 /* Add release code, if a key was pressed: */
274 if (d->head[p] != old_head) {
275 int code = d->key_queue[p][d->head[p]] | 0x80;
276 pckbc_add_code(d, code, p);
277 }
278
279 /* Release ctrl: */
280 if (ctrl)
281 pckbc_add_code(d, 0x1d + 0x80, p);
282 }
283
284
285 /*
286 * dev_pckbc_tick():
287 */
288 void dev_pckbc_tick(struct cpu *cpu, void *extra)
289 {
290 struct pckbc_data *d = extra;
291 int port_nr, ch, ints_enabled;
292
293 if (d->in_use && console_charavail(d->console_handle)) {
294 ch = console_readchar(d->console_handle);
295 if (ch >= 0)
296 ascii_to_pc_scancodes(ch, d);
297 }
298
299 ints_enabled = d->rx_int_enable;
300
301 /* TODO: mouse movements? */
302
303 if (d->cmdbyte & KC8_KDISABLE)
304 ints_enabled = 0;
305
306 for (port_nr=0; port_nr<2; port_nr++) {
307 /* Cause receive interrupt, if there's something in the
308 receive buffer: (Otherwise deassert the interrupt.) */
309 if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) {
310 cpu_interrupt(cpu, port_nr==0? d->keyboard_irqnr
311 : d->mouse_irqnr);
312 } else {
313 cpu_interrupt_ack(cpu, port_nr==0? d->keyboard_irqnr
314 : d->mouse_irqnr);
315 }
316 }
317 }
318
319
320 /*
321 * dev_pckbc_command():
322 *
323 * Handle commands to the 8048 in the emulated keyboard.
324 */
325 static void dev_pckbc_command(struct pckbc_data *d, int port_nr)
326 {
327 int cmd = d->reg[PC_CMD];
328
329 if (d->type == PCKBC_8242)
330 cmd = d->reg[PS2_TXBUF];
331
332 if (d->state == STATE_WAITING_FOR_TRANSLTABLE) {
333 debug("[ pckbc: switching to translation table 0x%02x ]\n",
334 cmd);
335 pckbc_add_code(d, KBR_ACK, port_nr);
336 d->state = STATE_NORMAL;
337 return;
338 }
339
340 switch (cmd) {
341 case 0x00:
342 pckbc_add_code(d, KBR_ACK, port_nr);
343 break;
344 case KBC_MODEIND: /* Set LEDs */
345 /* Just ACK, no LEDs are actually set. */
346 pckbc_add_code(d, KBR_ACK, port_nr);
347 break;
348 case KBC_SETTABLE:
349 pckbc_add_code(d, KBR_ACK, port_nr);
350 d->state = STATE_WAITING_FOR_TRANSLTABLE;
351 break;
352 case KBC_ENABLE:
353 d->keyscanning_enabled = 1;
354 pckbc_add_code(d, KBR_ACK, port_nr);
355 break;
356 case KBC_DISABLE:
357 d->keyscanning_enabled = 0;
358 pckbc_add_code(d, KBR_ACK, port_nr);
359 break;
360 case KBC_SETDEFAULT:
361 pckbc_add_code(d, KBR_ACK, port_nr);
362 break;
363 case KBC_RESET:
364 pckbc_add_code(d, KBR_ACK, port_nr);
365 pckbc_add_code(d, KBR_RSTDONE, port_nr);
366 break;
367 default:
368 fatal("[ pckbc: UNIMPLEMENTED 8048 command 0x%02x ]\n", cmd);
369 }
370 }
371
372
373 /*
374 * dev_pckbc_access():
375 */
376 int dev_pckbc_access(struct cpu *cpu, struct memory *mem,
377 uint64_t relative_addr, unsigned char *data, size_t len,
378 int writeflag, void *extra)
379 {
380 uint64_t idata = 0, odata = 0;
381 int i, port_nr = 0;
382 struct pckbc_data *d = extra;
383
384 idata = memory_readmax64(cpu, data, len);
385
386 #ifdef PCKBC_DEBUG
387 if (writeflag == MEM_WRITE)
388 fatal("[ pckbc: write to addr 0x%x: 0x%x ]\n",
389 (int)relative_addr, (int)idata);
390 else
391 fatal("[ pckbc: read from addr 0x%x ]\n",
392 (int)relative_addr);
393 #endif
394
395 /* For JAZZ-based machines: */
396 if (relative_addr >= 0x60) {
397 relative_addr -= 0x60;
398 if (relative_addr != 0)
399 relative_addr = 1;
400 } else if (d->type == PCKBC_8242) {
401 /* 8242 PS2-style: */
402 /* when using 8-byte alignment... */
403 relative_addr /= sizeof(uint64_t);
404 /* port_nr = 0 for keyboard, 1 for mouse */
405 port_nr = (relative_addr >> 2);
406 relative_addr &= 3;
407 relative_addr += PS2;
408 } else if (d->pc_style_flag) {
409 /* PC-style: */
410 if (relative_addr != 0 && relative_addr != 4) {
411 /* TODO (port 0x61) */
412 odata = 0x21;
413 {
414 static int x = 0;
415 x++;
416 if (x&1)
417 odata ^= 0x10;
418 }
419 if (writeflag == MEM_READ)
420 memory_writemax64(cpu, data, len, odata);
421 return 0;
422 }
423 if (relative_addr != 0)
424 relative_addr = 1;
425 } else {
426 /* Others... Non-Jazz ARC-based machines etc. */
427 if (relative_addr != 0)
428 relative_addr = 1;
429 }
430
431 switch (relative_addr) {
432
433 /*
434 * 8042 (PC):
435 */
436
437 case 0: /* data */
438 if (writeflag==MEM_READ) {
439 switch (d->state) {
440 case STATE_RDCMDBYTE:
441 odata = d->cmdbyte;
442 d->state = STATE_NORMAL;
443 break;
444 case STATE_RDOUTPUT:
445 odata = d->output_byte;
446 d->state = STATE_NORMAL;
447 break;
448 default:if (d->head[0] != d->tail[0]) {
449 odata = pckbc_get_code(d, 0);
450 d->last_scancode = odata;
451 } else {
452 odata = d->last_scancode;
453 d->last_scancode |= 0x80;
454 }
455 }
456 /* debug("[ pckbc: read from DATA: 0x%02x ]\n",
457 odata); */
458 } else {
459 debug("[ pckbc: write to DATA:");
460 for (i=0; i<len; i++)
461 debug(" %02x", data[i]);
462 debug(" ]\n");
463
464 switch (d->state) {
465 case STATE_LDCMDBYTE:
466 d->cmdbyte = idata;
467 d->rx_int_enable = d->cmdbyte &
468 (KC8_KENABLE | KC8_MENABLE) ? 1 : 0;
469 d->state = STATE_NORMAL;
470 break;
471 case STATE_LDOUTPUT:
472 d->output_byte = idata;
473 d->state = STATE_NORMAL;
474 break;
475 default:d->reg[relative_addr] = idata;
476 dev_pckbc_command(d, port_nr);
477 }
478 }
479 break;
480 case 1: /* control */
481 if (writeflag==MEM_READ) {
482 dev_pckbc_tick(cpu, d);
483
484 odata = 0;
485
486 /* "Data in buffer" bit */
487 if (d->head[0] != d->tail[0] ||
488 d->state == STATE_RDCMDBYTE ||
489 d->state == STATE_RDOUTPUT)
490 odata |= KBS_DIB;
491
492 if (d->state == STATE_RDCMDBYTE)
493 odata |= KBS_OCMD;
494
495 odata |= KBS_NOSEC;
496 /* debug("[ pckbc: read from CTL status port: "
497 "0x%02x ]\n", (int)odata); */
498 } else {
499 debug("[ pckbc: write to CTL:");
500 for (i=0; i<len; i++)
501 debug(" %02x", data[i]);
502 debug(" ]\n");
503 d->reg[relative_addr] = idata;
504
505 switch (idata) {
506 case K_RDCMDBYTE:
507 d->state = STATE_RDCMDBYTE;
508 break;
509 case K_LDCMDBYTE:
510 d->state = STATE_LDCMDBYTE;
511 break;
512 case 0xa7:
513 d->cmdbyte |= KC8_MDISABLE;
514 break;
515 case 0xa8:
516 d->cmdbyte &= ~KC8_MDISABLE;
517 break;
518 case 0xa9: /* test auxiliary port */
519 debug("[ pckbc: CONTROL 0xa9, TODO ]\n");
520 break;
521 case 0xaa: /* keyboard self-test */
522 pckbc_add_code(d, 0x55, port_nr);
523 break;
524 case 0xad:
525 d->cmdbyte |= KC8_KDISABLE;
526 break;
527 case 0xae:
528 d->cmdbyte &= ~KC8_KDISABLE;
529 break;
530 case 0xd0:
531 d->state = STATE_RDOUTPUT;
532 break;
533 case 0xd1:
534 d->state = STATE_LDOUTPUT;
535 break;
536 case 0xd4: /* write to auxiliary port */
537 debug("[ pckbc: CONTROL 0xd4, TODO ]\n");
538 break;
539 default:
540 fatal("[ pckbc: unknown CONTROL 0x%x ]\n",
541 idata);
542 d->state = STATE_NORMAL;
543 }
544 }
545 break;
546
547 /*
548 * 8242 (PS2):
549 */
550
551 /*
552 * BIG TODO: The following should be rewritten to use dev_pckbc_command()
553 * etc, like the 8042 code above does.
554 */
555
556 case PS2 + PS2_TXBUF:
557 if (writeflag==MEM_READ) {
558 odata = random() & 0xff;
559 debug("[ pckbc: read from port %i, PS2_TXBUF: "
560 "0x%x ]\n", port_nr, (int)odata);
561 } else {
562 debug("[ pckbc: write to port %i, PS2_TXBUF: "
563 "0x%llx ]\n", port_nr, (long long)idata);
564
565 /* Handle keyboard commands: */
566 switch (idata) {
567 /* These are incorrect, the second byte of
568 commands should be treated better: */
569 case 0x00: /* second byte of 0xed,
570 SGI-IP32's prom */
571 pckbc_add_code(d, 0x03, port_nr);/* ack (?) */
572 break;
573 case 0x14: /* second byte of 0xfc,
574 SGI-IP32's prom */
575 case 0x28: /* second byte of 0xf3,
576 SGI-IP32's prom */
577 case 0x76: /* third byte of 0xfc,
578 SGI-IP32's prom */
579 case 0x03: /* second byte of
580 ATKBD_CMD_GSCANSET (?) */
581 case 0x04:
582 pckbc_add_code(d, 0x03, port_nr);/* ? */
583 break;
584
585 /* Command bytes: */
586 case 0xf0: /* ATKBD_CMD_GSCANSET (?) */
587 pckbc_add_code(d, 0x03, port_nr);/* ? */
588 break;
589 case 0xf2: /* Get keyboard ID */
590 /* The keyboard should generate 2
591 status bytes. */
592 pckbc_add_code(d, 0xab, port_nr);
593 pckbc_add_code(d, 0x83, port_nr);
594 break;
595 case 0xed: /* "ATKBD_CMD_SETLEDS",
596 takes 1 byte arg */
597 case 0xf3: /* "PSMOUSE_CMD_SETRATE",
598 takes 1 byte arg */
599 case 0xf4: /* "ATKBD_CMD_ENABLE" (or
600 PSMOUSE_CMD_ENABLE), no args */
601 case 0xf5: /* "ATKBD_CMD_RESET_DIS" (keyboard,
602 according to Linux sources) */
603 case 0xf6: /* "PSMOUSE_CMD_RESET_DIS" (mouse,
604 according to Linux sources) */
605 /* TODO: what does this do? */
606 pckbc_add_code(d, 0xfa, port_nr);/* ack (?) */
607 break;
608 case 0xfa: /* "ATKBD_CMD_SETALL_MBR" (linux) */
609 pckbc_add_code(d, 0xfa, port_nr);/* ack (?) */
610 break;
611 case 0xfc: /* ? */
612 pckbc_add_code(d, 0xfa, port_nr);/* ack (?) */
613 break;
614 case 0xff: /* Keyboard reset */
615 /* The keyboard should generate 2
616 status bytes. */
617 pckbc_add_code(d, 0xfa, port_nr);/* ack (?) */
618 pckbc_add_code(d, 0xaa, port_nr);
619 /* battery ok (?) */
620 break;
621 default:
622 debug("[ pckbc: UNIMPLEMENTED keyboard command"
623 " 0x%02x (port %i) ]\n", (int)idata,
624 port_nr);
625 }
626 }
627 break;
628
629 case PS2 + PS2_RXBUF:
630 if (writeflag==MEM_READ) {
631 /* TODO: What should be returned if no data
632 is available? */
633 odata = random() & 0xff;
634 if (d->head[port_nr] != d->tail[port_nr])
635 odata = pckbc_get_code(d, port_nr);
636 debug("[ pckbc: read from port %i, PS2_RXBUF: "
637 "0x%02x ]\n", port_nr, (int)odata);
638 } else {
639 debug("[ pckbc: write to port %i, PS2_RXBUF: "
640 "0x%llx ]\n", port_nr, (long long)idata);
641 }
642 break;
643
644 case PS2 + PS2_CONTROL:
645 if (writeflag==MEM_READ) {
646 debug("[ pckbc: read from port %i, PS2_CONTROL"
647 " ]\n", port_nr);
648 } else {
649 debug("[ pckbc: write to port %i, PS2_CONTROL:"
650 " 0x%llx ]\n", port_nr, (long long)idata);
651 d->clocksignal = (idata & 0x10) ? 1 : 0;
652 d->rx_int_enable = (idata & 0x08) ? 1 : 0;
653 d->tx_int_enable = (idata & 0x04) ? 1 : 0;
654 }
655 break;
656
657 case PS2 + PS2_STATUS:
658 if (writeflag==MEM_READ) {
659 /* 0x08 = transmit buffer empty */
660 odata = d->clocksignal + 0x08;
661
662 if (d->head[port_nr] != d->tail[port_nr]) {
663 /* 0x10 = receicer data available (?) */
664 odata |= 0x10;
665 }
666
667 debug("[ pckbc: read from port %i, PS2_STATUS: "
668 "0x%llx ]\n", port_nr, (long long)odata);
669 } else {
670 debug("[ pckbc: write to port %i, PS2_STATUS: "
671 "0x%llx ]\n", port_nr, (long long)idata);
672 }
673 break;
674
675 default:
676 if (writeflag==MEM_READ) {
677 debug("[ pckbc: read from unimplemented reg %i ]\n",
678 (int)relative_addr);
679 odata = d->reg[relative_addr];
680 } else {
681 debug("[ pckbc: write to unimplemented reg %i:",
682 (int)relative_addr);
683 for (i=0; i<len; i++)
684 debug(" %02x", data[i]);
685 debug(" ]\n");
686 d->reg[relative_addr] = idata;
687 }
688 }
689
690 if (writeflag == MEM_READ)
691 memory_writemax64(cpu, data, len, odata);
692
693 dev_pckbc_tick(cpu, d);
694
695 return 1;
696 }
697
698
699 /*
700 * dev_pckbc_init():
701 *
702 * Type should be PCKBC_8042 or PCKBC_8242.
703 */
704 int dev_pckbc_init(struct machine *machine, struct memory *mem,
705 uint64_t baseaddr, int type, int keyboard_irqnr, int mouse_irqnr,
706 int in_use, int pc_style_flag)
707 {
708 struct pckbc_data *d;
709 int len = DEV_PCKBC_LENGTH;
710
711 d = malloc(sizeof(struct pckbc_data));
712 if (d == NULL) {
713 fprintf(stderr, "out of memory\n");
714 exit(1);
715 }
716 memset(d, 0, sizeof(struct pckbc_data));
717
718 if (type == PCKBC_JAZZ) {
719 type = PCKBC_8042;
720 len = DEV_PCKBC_LENGTH + 0x60;
721 }
722
723 d->type = type;
724 d->keyboard_irqnr = keyboard_irqnr;
725 d->mouse_irqnr = mouse_irqnr;
726 d->in_use = in_use;
727 d->pc_style_flag = pc_style_flag;
728 d->console_handle = console_start_slave_inputonly(machine, "pckbc");
729 d->rx_int_enable = 1;
730 d->output_byte = 0x02; /* A20 enable on PCs */
731
732 memory_device_register(mem, "pckbc", baseaddr,
733 len, dev_pckbc_access, d, MEM_DEFAULT, NULL);
734 machine_add_tickfunction(machine, dev_pckbc_tick, d, PCKBC_TICKSHIFT);
735
736 return d->console_handle;
737 }
738

  ViewVC Help
Powered by ViewVC 1.1.26