dev_pckbc.cc Source File

Back to the index.

dev_pckbc.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2009 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  * COMMENT: 8042 PC keyboard controller (+ 8242WB Keyboard/Mouse controller)
29  *
30  * This module includes emulation of the 8048 keyboard chip too.
31  *
32  * Quick source of good info: http://my.execpc.com/~geezer/osd/kbd/kbd.txt
33  *
34  *
35  * TODOs:
36  * Finish the rewrite for 8242.
37  */
38 
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #include "console.h"
44 #include "cpu.h"
45 #include "devices.h"
46 #include "machine.h"
47 #include "memory.h"
48 #include "misc.h"
49 
50 #include "thirdparty/kbdreg.h"
51 
52 
53 /* #define PCKBC_DEBUG */
54 /* #define debug fatal */
55 
56 
57 #define MAX_8042_QUEUELEN 256
58 
59 #define PC_DATA 0
60 #define PC_CMD 0
61 #define PC_STATUS 1
62 
63 #define PS2_TXBUF 0
64 #define PS2_RXBUF 1
65 #define PS2_CONTROL 2
66 #define PS2_STATUS 3
67 
68 #define PS2 100
69 
70 #define PCKBC_TICKSHIFT 15
71 
72 struct pckbc_data {
74  int in_use;
75 
77 
81  int type;
83 
84  /* TODO: one of these for each port? */
88 
91  int state;
92  int cmdbyte;
95 
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 #define STATE_WAITING_FOR_RATE 4
105 #define STATE_WAITING_FOR_ONEKEY_MB 5
106 #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 
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  else
138  d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN;
139  return d->key_queue[port][d->tail[port]];
140 }
141 
142 
143 /*
144  * 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  * ascii_to_scancodes_type2():
278  *
279  * Conversion from ASCII codes to default (US) keyboard scancodes.
280  * (See http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html)
281  *
282  * NOTE/TODO: This seems to be type 2, not type 1.
283  */
284 static void ascii_to_pc_scancodes_type2(int a, struct pckbc_data *d)
285 {
286  int old_head;
287  int p = 0; /* port */
288  int shift = 0, ctrl = 0;
289 
290  if (d->translation_table == 3) {
291  ascii_to_pc_scancodes_type3(a, d);
292  return;
293  }
294 
295  if (d->translation_table != 2) {
296  fatal("[ ascii_to_pc_scancodes: unimplemented type! ]\n");
297  return;
298  }
299 
300  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  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  if (a=='~') { a = '`'; shift = 1; }
325 
326  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  * 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  */
342 
343  old_head = d->head[p];
344 
345  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  if (a=='`') pckbc_add_code(d, 0x29, p);
411  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  /* 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  /* Release ctrl: */
434  if (ctrl)
435  pckbc_add_code(d, 0x1d + 0x80, p);
436 }
437 
438 
440 {
441  struct pckbc_data *d = (struct pckbc_data *) extra;
442  int port_nr, ch, ints_enabled;
443 
444  if (d->in_use && console_charavail(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 
461  if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) {
462  debug("[ pckbc: interrupt port %i ]\n", port_nr);
463  if (port_nr == 0)
465  else
467  d->currently_asserted[port_nr] = 1;
468  } else {
469  if (d->currently_asserted[port_nr]) {
470  if (port_nr == 0)
472  else
474  }
475  d->currently_asserted[port_nr] = 0;
476  }
477  }
478 }
479 
480 
481 /*
482  * dev_pckbc_command():
483  *
484  * Handle commands to the 8048 in the emulated keyboard.
485  */
486 static void dev_pckbc_command(struct pckbc_data *d, int port_nr)
487 {
488  int cmd = d->reg[PC_CMD];
489 
490  if (d->type == PCKBC_8242)
491  cmd = d->reg[PS2_TXBUF];
492 
494  debug("[ pckbc: (port %i) switching to translation table "
495  "0x%02x ]\n", port_nr, cmd);
496  switch (cmd) {
497  case 2:
498  case 3: d->translation_table = cmd;
499  break;
500  default:fatal("[ pckbc: (port %i) translation table "
501  "0x%02x is NOT YET IMPLEMENTED ]\n",
502  port_nr, cmd);
503  }
504  pckbc_add_code(d, KBR_ACK, port_nr);
505  d->state = STATE_NORMAL;
506  return;
507  }
508 
509  if (d->state == STATE_WAITING_FOR_RATE) {
510  debug("[ pckbc: (port %i) received Typematic Rate data: "
511  "0x%02x ]\n", port_nr, cmd);
512  pckbc_add_code(d, KBR_ACK, port_nr);
513  d->state = STATE_NORMAL;
514  return;
515  }
516 
518  debug("[ pckbc: (port %i) received One-key make/break data: "
519  "0x%02x ]\n", port_nr, cmd);
520  pckbc_add_code(d, KBR_ACK, port_nr);
521  d->state = STATE_NORMAL;
522  return;
523  }
524 
525  if (d->state == STATE_WAITING_FOR_AUX) {
526  debug("[ pckbc: (port %i) received aux data: "
527  "0x%02x ]\n", port_nr, cmd);
528  /* Echo back. */
529  pckbc_add_code(d, cmd, port_nr);
530  d->state = STATE_NORMAL;
531  return;
532  }
533 
534  if (d->state == STATE_WAITING_FOR_AUX_OUT) {
535  debug("[ pckbc: (port %i) received aux out data: "
536  "0x%02x ]\n", port_nr, cmd);
537  /* Echo back. */
538  pckbc_add_code(d, cmd, port_nr);
539  d->state = STATE_NORMAL;
540  return;
541  }
542 
543  switch (cmd) {
544 
545  case 0x00:
546  /*
547  * TODO: What does this do? This is possibly due to an
548  * error in the handling of some other command code.
549  */
550  pckbc_add_code(d, KBR_ACK, port_nr);
551  break;
552 
553  case KBC_MODEIND: /* Set LEDs */
554  /* Just ACK, no LEDs are actually set. */
555  pckbc_add_code(d, KBR_ACK, port_nr);
556  break;
557 
558  case KBC_SETTABLE:
559  pckbc_add_code(d, KBR_ACK, port_nr);
561  break;
562 
563  case KBC_ENABLE:
564  d->keyscanning_enabled = 1;
565  pckbc_add_code(d, KBR_ACK, port_nr);
566  break;
567 
568  case KBC_DISABLE:
569  d->keyscanning_enabled = 0;
570  pckbc_add_code(d, KBR_ACK, port_nr);
571  break;
572 
573  case KBC_SETDEFAULT:
574  pckbc_add_code(d, KBR_ACK, port_nr);
575  break;
576 
577  case KBC_GETID:
578  /* Get keyboard ID. NOTE/TODO: Ugly hardcoded answer. */
579  pckbc_add_code(d, KBR_ACK, port_nr);
580  pckbc_add_code(d, 0xab, port_nr);
581  pckbc_add_code(d, 0x41, port_nr);
582  break;
583 
584  case KBC_TYPEMATIC:
585  /* Set typematic (auto-repeat) delay/speed: */
586  pckbc_add_code(d, KBR_ACK, port_nr);
588  break;
589 
590  case KBC_ALLKEYS_TMB:
591  /* "Make all keys typematic/make/break" */
592  pckbc_add_code(d, KBR_ACK, port_nr);
593  break;
594 
595  case KBC_ONEKEY_MB:
596  /* "Make one key typematic/make/break" */
597  pckbc_add_code(d, KBR_ACK, port_nr);
599  break;
600 
601  case KBC_RESET:
602  pckbc_add_code(d, KBR_ACK, port_nr);
603  pckbc_add_code(d, KBR_RSTDONE, port_nr);
604  /*
605  * Disable interrupts during reset, or Linux 2.6
606  * prints warnings about spurious interrupts.
607  */
608  d->rx_int_enable = 0;
609  break;
610 
611  default:
612  fatal("[ pckbc: (port %i) UNIMPLEMENTED 8048 command"
613  " 0x%02x ]\n", port_nr, cmd);
614  exit(1);
615  }
616 }
617 
618 
620 {
621  struct pckbc_data *d = (struct pckbc_data *) extra;
622  uint64_t idata = 0, odata = 0;
623  int port_nr = 0;
624  size_t i;
625 
626  if (writeflag == MEM_WRITE)
627  idata = memory_readmax64(cpu, data, len);
628 
629 #ifdef PCKBC_DEBUG
630  if (writeflag == MEM_WRITE)
631  fatal("[ pckbc: write to addr 0x%x: 0x%x ]\n",
632  (int)relative_addr, (int)idata);
633  else
634  fatal("[ pckbc: read from addr 0x%x ]\n",
635  (int)relative_addr);
636 #endif
637 
638  /* For JAZZ-based machines: */
639  if (relative_addr >= 0x60) {
640  relative_addr -= 0x60;
641  if (relative_addr != 0)
642  relative_addr = 1;
643  } else if (d->type == PCKBC_8242) {
644  /* 8242 PS2-style: */
645  /* when using 8-byte alignment... */
646  relative_addr /= sizeof(uint64_t);
647  /* port_nr = 0 for keyboard, 1 for mouse */
648  port_nr = (relative_addr >> 2);
649  relative_addr &= 3;
650  relative_addr += PS2;
651  } else if (d->pc_style_flag) {
652  /* PC-style: */
653  if (relative_addr != 0 && relative_addr != 4) {
654  /* TODO (port 0x61) */
655  odata = 0x21;
656 {
657 static int x = 0;
658 x++;
659 if (x&1)
660  odata ^= 0x10;
661 }
662  if (writeflag == MEM_READ)
663  memory_writemax64(cpu, data, len, odata);
664  return 1;
665  }
666  if (relative_addr != 0)
667  relative_addr = 1;
668  } else {
669  /* Others... Non-Jazz ARC-based machines etc. */
670  if (relative_addr != 0)
671  relative_addr = 1;
672  }
673 
674  switch (relative_addr) {
675 
676  /*
677  * 8042 (PC):
678  */
679 
680  case 0: /* data */
681  if (writeflag==MEM_READ) {
682  switch (d->state) {
683  case STATE_RDCMDBYTE:
684  odata = d->cmdbyte;
685  d->state = STATE_NORMAL;
686  break;
687  case STATE_RDOUTPUT:
688  odata = d->output_byte;
689  d->state = STATE_NORMAL;
690  break;
691  default:if (d->head[0] != d->tail[0]) {
692  odata = pckbc_get_code(d, 0);
693  d->last_scancode = odata;
694  } else {
695  odata = d->last_scancode;
696  d->last_scancode |= 0x80;
697  }
698  }
699  /* debug("[ pckbc: read from DATA: 0x%02x ]\n",
700  (int)odata); */
701  } else {
702  debug("[ pckbc: write to DATA:");
703  for (i=0; i<len; i++)
704  debug(" %02x", data[i]);
705  debug(" ]\n");
706 
707  switch (d->state) {
708  case STATE_LDCMDBYTE:
709  d->cmdbyte = idata;
710  d->rx_int_enable = d->cmdbyte &
711  (KC8_KENABLE | KC8_MENABLE) ? 1 : 0;
712  d->state = STATE_NORMAL;
713  break;
714  case STATE_LDOUTPUT:
715  d->output_byte = idata;
716  d->state = STATE_NORMAL;
717  break;
718  default:d->reg[relative_addr] = idata;
719  dev_pckbc_command(d, port_nr);
720  }
721  }
722  break;
723  case 1: /* control */
724  if (writeflag==MEM_READ) {
725  dev_pckbc_tick(cpu, d);
726 
727  odata = 0;
728 
729  /* "Data in buffer" bit */
730  if (d->head[0] != d->tail[0] ||
731  d->state == STATE_RDCMDBYTE ||
732  d->state == STATE_RDOUTPUT)
733  odata |= KBS_DIB;
734 
735  if (d->state == STATE_RDCMDBYTE)
736  odata |= KBS_OCMD;
737 
738  odata |= KBS_NOSEC;
739  /* debug("[ pckbc: read from CTL status port: "
740  "0x%02x ]\n", (int)odata); */
741  } else {
742  debug("[ pckbc: write to CTL:");
743  for (i=0; i<len; i++)
744  debug(" %02x", data[i]);
745  debug(" ]\n");
746  d->reg[relative_addr] = idata;
747 
748  switch (idata) {
749  case 0x10:
750  case 0x11:
751  /* TODO: For now, don't print warnings about
752  these. NetBSD sends these. */
753  break;
754  case K_RDCMDBYTE:
755  d->state = STATE_RDCMDBYTE;
756  break;
757  case K_LDCMDBYTE:
758  d->state = STATE_LDCMDBYTE;
759  break;
760  case 0xa7:
761  d->cmdbyte |= KC8_MDISABLE;
762  break;
763  case 0xa8:
764  d->cmdbyte &= ~KC8_MDISABLE;
765  break;
766  case 0xa9: /* test auxiliary port */
767  debug("[ pckbc: CONTROL 0xa9, TODO ]\n");
768  break;
769  case 0xaa: /* keyboard self-test */
770  pckbc_add_code(d, 0x55, port_nr);
771  break;
772  case 0xab: /* keyboard interface self-test */
773  pckbc_add_code(d, 0x00, port_nr);
774  break;
775  case 0xad:
776  d->cmdbyte |= KC8_KDISABLE;
777  break;
778  case 0xae:
779  d->cmdbyte &= ~KC8_KDISABLE;
780  break;
781  case 0xd0:
782  d->state = STATE_RDOUTPUT;
783  break;
784  case 0xd1:
785  d->state = STATE_LDOUTPUT;
786  break;
787  case 0xd3: /* write to auxiliary device
788  output buffer */
789  debug("[ pckbc: CONTROL 0xd3, TODO ]\n");
791  break;
792  case 0xd4: /* write to auxiliary port */
793  debug("[ pckbc: CONTROL 0xd4, TODO ]\n");
795  break;
796  default:
797  fatal("[ pckbc: unknown CONTROL 0x%x ]\n",
798  (int)idata);
799  d->state = STATE_NORMAL;
800  }
801  }
802  break;
803 
804  /*
805  * 8242 (PS2):
806  */
807 
808  case PS2 + PS2_TXBUF:
809  if (writeflag==MEM_READ) {
810  odata = random() & 0xff;
811  debug("[ pckbc: read from port %i, PS2_TXBUF: "
812  "0x%x ]\n", port_nr, (int)odata);
813  } else {
814  debug("[ pckbc: write to port %i, PS2_TXBUF: "
815  "0x%llx ]\n", port_nr, (long long)idata);
816 
817  /* Handle keyboard commands: */
818  d->reg[PS2_TXBUF] = idata;
819  dev_pckbc_command(d, port_nr);
820  }
821  break;
822 
823  case PS2 + PS2_RXBUF:
824  if (writeflag==MEM_READ) {
825  /* TODO: What should be returned if no data
826  is available? */
827  odata = random() & 0xff;
828  if (d->head[port_nr] != d->tail[port_nr])
829  odata = pckbc_get_code(d, port_nr);
830  debug("[ pckbc: read from port %i, PS2_RXBUF: "
831  "0x%02x ]\n", port_nr, (int)odata);
832  } else {
833  debug("[ pckbc: write to port %i, PS2_RXBUF: "
834  "0x%llx ]\n", port_nr, (long long)idata);
835  }
836  break;
837 
838  case PS2 + PS2_CONTROL:
839  if (writeflag==MEM_READ) {
840  debug("[ pckbc: read from port %i, PS2_CONTROL"
841  " ]\n", port_nr);
842  } else {
843  debug("[ pckbc: write to port %i, PS2_CONTROL:"
844  " 0x%llx ]\n", port_nr, (long long)idata);
845  d->clocksignal = (idata & 0x10) ? 1 : 0;
846  d->rx_int_enable = (idata & 0x08) ? 1 : 0;
847  d->tx_int_enable = (idata & 0x04) ? 1 : 0;
848  }
849  break;
850 
851  case PS2 + PS2_STATUS:
852  if (writeflag==MEM_READ) {
853  /* 0x08 = transmit buffer empty */
854  odata = d->clocksignal + 0x08;
855 
856  if (d->head[port_nr] != d->tail[port_nr]) {
857  /* 0x10 = receicer data available (?) */
858  odata |= 0x10;
859  }
860 
861  debug("[ pckbc: read from port %i, PS2_STATUS: "
862  "0x%llx ]\n", port_nr, (long long)odata);
863  } else {
864  debug("[ pckbc: write to port %i, PS2_STATUS: "
865  "0x%llx ]\n", port_nr, (long long)idata);
866  }
867  break;
868 
869  default:
870  if (writeflag==MEM_READ) {
871  debug("[ pckbc: read from unimplemented reg %i ]\n",
872  (int)relative_addr);
873  odata = d->reg[relative_addr % DEV_PCKBC_LENGTH];
874  } else {
875  debug("[ pckbc: write to unimplemented reg %i:",
876  (int)relative_addr);
877  for (i=0; i<len; i++)
878  debug(" %02x", data[i]);
879  debug(" ]\n");
880  d->reg[relative_addr % DEV_PCKBC_LENGTH] = idata;
881  }
882  }
883 
884  /* SGI? TODO: fix */
885  if (len == 8)
886  odata |= (odata << 8) | (odata << 16) | (odata << 24) |
887  (odata << 32) | (odata << 40) | (odata << 48) |
888  (odata << 56);
889 
890  if (writeflag == MEM_READ)
891  memory_writemax64(cpu, data, len, odata);
892 
893  dev_pckbc_tick(cpu, d);
894 
895  return 1;
896 }
897 
898 
899 /*
900  * dev_pckbc_init():
901  *
902  * Type should be PCKBC_8042 or PCKBC_8242.
903  */
904 int dev_pckbc_init(struct machine *machine, struct memory *mem,
905  uint64_t baseaddr, int type, char *keyboard_irqpath,
906  char *mouse_irqpath, int in_use, int pc_style_flag)
907 {
908  struct pckbc_data *d;
909  int len = DEV_PCKBC_LENGTH;
910 
911  CHECK_ALLOCATION(d = (struct pckbc_data *) malloc(sizeof(struct pckbc_data)));
912  memset(d, 0, sizeof(struct pckbc_data));
913 
914  if (type == PCKBC_8242)
915  len = 0x18;
916 
917  if (type == PCKBC_JAZZ) {
918  type = PCKBC_8042;
919  len = DEV_PCKBC_LENGTH + 0x60;
920  }
921 
922  INTERRUPT_CONNECT(keyboard_irqpath, d->irq_keyboard);
923  INTERRUPT_CONNECT(mouse_irqpath, d->irq_mouse);
924 
925  d->type = type;
926  d->in_use = in_use;
928  d->translation_table = 2;
929  d->rx_int_enable = 1;
930  d->output_byte = 0x02; /* A20 enable on PCs */
931 
933  machine, "pckbc", d->in_use);
934 
935  memory_device_register(mem, "pckbc", baseaddr,
936  len, dev_pckbc_access, d, DM_DEFAULT, NULL);
937  machine_add_tickfunction(machine, dev_pckbc_tick, d,
939 
940  return d->console_handle;
941 }
942 
#define KBR_RSTDONE
Definition: kbdreg.h:88
uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
Definition: memory.cc:55
DEVICE_ACCESS(pckbc)
Definition: dev_pckbc.cc:619
void fatal(const char *fmt,...)
Definition: main.cc:152
#define PS2_STATUS
Definition: dev_pckbc.cc:66
int console_start_slave_inputonly(struct machine *machine, const char *consolename, int use_for_input)
Definition: console.cc:714
int console_handle
Definition: dev_pckbc.cc:73
#define DM_DEFAULT
Definition: memory.h:130
#define PCKBC_TICKSHIFT
Definition: dev_pckbc.cc:70
#define KBC_SETTABLE
Definition: kbdreg.h:77
#define KBC_MODEIND
Definition: kbdreg.h:79
int clocksignal
Definition: dev_pckbc.cc:85
int tail[2]
Definition: dev_pckbc.cc:97
#define PS2
Definition: dev_pckbc.cc:68
#define KBS_OCMD
Definition: kbdreg.h:45
unsigned key_queue[2][MAX_8042_QUEUELEN]
Definition: dev_pckbc.cc:96
int tx_int_enable
Definition: dev_pckbc.cc:87
int cmdbyte
Definition: dev_pckbc.cc:92
struct interrupt irq_mouse
Definition: dev_pckbc.cc:79
#define MEM_READ
Definition: memory.h:116
#define KBR_ACK
Definition: kbdreg.h:84
#define STATE_RDOUTPUT
Definition: dev_pckbc.cc:109
struct interrupt irq_keyboard
Definition: dev_pckbc.cc:78
#define PC_CMD
Definition: dev_pckbc.cc:60
#define STATE_WAITING_FOR_AUX
Definition: dev_pckbc.cc:106
#define PCKBC_8042
Definition: devices.h:320
#define KC8_MDISABLE
Definition: kbdreg.h:59
int console_readchar(int handle)
Definition: console.cc:385
#define STATE_WAITING_FOR_RATE
Definition: dev_pckbc.cc:104
#define KBS_NOSEC
Definition: kbdreg.h:46
int keyscanning_enabled
Definition: dev_pckbc.cc:89
#define CHECK_ALLOCATION(ptr)
Definition: misc.h:239
#define KBC_ONEKEY_MB
Definition: kbdreg.h:70
#define STATE_LDCMDBYTE
Definition: dev_pckbc.cc:101
int console_charavail(int handle)
Definition: console.cc:336
#define KBC_ALLKEYS_TMB
Definition: kbdreg.h:71
#define K_LDCMDBYTE
Definition: kbdreg.h:56
#define K_RDCMDBYTE
Definition: kbdreg.h:55
u_short data
Definition: siireg.h:79
int rx_int_enable
Definition: dev_pckbc.cc:86
#define STATE_WAITING_FOR_ONEKEY_MB
Definition: dev_pckbc.cc:105
int head[2]
Definition: dev_pckbc.cc:97
#define STATE_WAITING_FOR_AUX_OUT
Definition: dev_pckbc.cc:107
#define STATE_WAITING_FOR_TRANSLTABLE
Definition: dev_pckbc.cc:103
#define PCKBC_JAZZ
Definition: devices.h:322
#define INTERRUPT_ASSERT(istruct)
Definition: interrupt.h:74
#define KBC_ENABLE
Definition: kbdreg.h:74
int output_byte
Definition: dev_pckbc.cc:93
#define MEM_WRITE
Definition: memory.h:117
#define STATE_RDCMDBYTE
Definition: dev_pckbc.cc:102
#define PS2_CONTROL
Definition: dev_pckbc.cc:65
int last_scancode
Definition: dev_pckbc.cc:94
#define debug
Definition: dev_adb.cc:57
DEVICE_TICK(pckbc)
Definition: dev_pckbc.cc:439
#define KBS_DIB
Definition: kbdreg.h:42
#define INTERRUPT_CONNECT(name, istruct)
Definition: interrupt.h:77
Definition: cpu.h:326
int reg[DEV_PCKBC_LENGTH]
Definition: dev_pckbc.cc:76
#define MAX_8042_QUEUELEN
Definition: dev_pckbc.cc:57
#define KC8_MENABLE
Definition: kbdreg.h:63
void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len, uint64_t data)
Definition: memory.cc:89
int in_use
Definition: dev_pckbc.cc:74
int translation_table
Definition: dev_pckbc.cc:90
#define KBC_RESET
Definition: kbdreg.h:68
void memory_device_register(struct memory *mem, const char *, uint64_t baseaddr, uint64_t len, int(*f)(struct cpu *, struct memory *, uint64_t, unsigned char *, size_t, int, void *), void *extra, int flags, unsigned char *dyntrans_data)
Definition: memory.cc:339
#define KBC_DISABLE
Definition: kbdreg.h:73
void pckbc_add_code(struct pckbc_data *d, int code, int port)
Definition: dev_pckbc.cc:117
#define KBC_GETID
Definition: kbdreg.h:76
#define PCKBC_8242
Definition: devices.h:321
int dev_pckbc_access(struct cpu *cpu, struct memory *mem, uint64_t relative_addr, unsigned char *data, size_t len, int writeflag, void *)
#define PS2_RXBUF
Definition: dev_pckbc.cc:64
#define KBC_TYPEMATIC
Definition: kbdreg.h:75
Definition: memory.h:75
#define STATE_NORMAL
Definition: dev_pckbc.cc:100
int currently_asserted[2]
Definition: dev_pckbc.cc:80
void machine_add_tickfunction(struct machine *machine, void(*func)(struct cpu *, void *), void *extra, int clockshift)
Definition: machine.cc:280
#define STATE_LDOUTPUT
Definition: dev_pckbc.cc:108
int dev_pckbc_init(struct machine *machine, struct memory *mem, uint64_t baseaddr, int type, char *keyboard_irqpath, char *mouse_irqpath, int in_use, int pc_style_flag)
Definition: dev_pckbc.cc:904
#define KC8_KDISABLE
Definition: kbdreg.h:60
#define KC8_KENABLE
Definition: kbdreg.h:64
#define KBC_SETDEFAULT
Definition: kbdreg.h:72
int pc_style_flag
Definition: dev_pckbc.cc:82
#define PS2_TXBUF
Definition: dev_pckbc.cc:63
int pckbc_get_code(struct pckbc_data *d, int port)
Definition: dev_pckbc.cc:133
#define INTERRUPT_DEASSERT(istruct)
Definition: interrupt.h:75
#define DEV_PCKBC_LENGTH
Definition: devices.h:319

Generated on Sun Sep 30 2018 16:05:18 for GXemul by doxygen 1.8.13