/[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

Diff of /trunk/src/devices/dev_pckbc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 14 by dpavlin, Mon Oct 8 16:18:51 2007 UTC revision 30 by dpavlin, Mon Oct 8 16:20:40 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2006  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *     *  
27   *   *
28   *  $Id: dev_pckbc.c,v 1.51 2005/09/27 23:55:44 debug Exp $   *  $Id: dev_pckbc.c,v 1.69 2006/07/25 18:58:02 debug Exp $
29   *     *  
30   *  Standard 8042 PC keyboard controller (and a 8242WB PS2 keyboard/mouse   *  Standard 8042 PC keyboard controller (and a 8242WB PS2 keyboard/mouse
31   *  controller), including the 8048 keyboard chip.   *  controller), including the 8048 keyboard chip.
32   *   *
33     *  Quick source of good info: http://my.execpc.com/~geezer/osd/kbd/kbd.txt
34   *   *
35   *  TODO: Finish the rewrite for 8242.   *
36     *  TODOs:
37     *      Finish the rewrite for 8242.
38   */   */
39    
40  #include <stdio.h>  #include <stdio.h>
# Line 98  struct pckbc_data { Line 101  struct pckbc_data {
101  #define STATE_LDCMDBYTE                 1  #define STATE_LDCMDBYTE                 1
102  #define STATE_RDCMDBYTE                 2  #define STATE_RDCMDBYTE                 2
103  #define STATE_WAITING_FOR_TRANSLTABLE   3  #define STATE_WAITING_FOR_TRANSLTABLE   3
104  #define STATE_WAITING_FOR_F3            4  #define STATE_WAITING_FOR_RATE          4
105  #define STATE_WAITING_FOR_FC            5  #define STATE_WAITING_FOR_ONEKEY_MB     5
106  #define STATE_LDOUTPUT                  6  #define STATE_WAITING_FOR_AUX           6
107  #define STATE_RDOUTPUT                  7  #define STATE_WAITING_FOR_AUX_OUT       7
108    #define STATE_LDOUTPUT                  8
109    #define STATE_RDOUTPUT                  9
110    
111    
112  /*  /*
# Line 269  static void ascii_to_pc_scancodes_type3( Line 274  static void ascii_to_pc_scancodes_type3(
274    
275    
276  /*  /*
277   *  ascii_to_scancodes():   *  ascii_to_scancodes_type2():
278   *   *
279   *  Conversion from ASCII codes to default (US) keyboard scancodes.   *  Conversion from ASCII codes to default (US) keyboard scancodes.
280   *  (See http://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html)   *  (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(int a, struct pckbc_data *d)  static void ascii_to_pc_scancodes_type2(int a, struct pckbc_data *d)
285  {  {
286          int old_head;          int old_head;
287          int p = 0;      /*  port  */          int p = 0;      /*  port  */
# Line 285  static void ascii_to_pc_scancodes(int a, Line 292  static void ascii_to_pc_scancodes(int a,
292                  return;                  return;
293          }          }
294    
295          if (d->translation_table != 1) {          if (d->translation_table != 2) {
296                  fatal("[ ascii_to_pc_scancodes: unimplemented type! ]\n");                  fatal("[ ascii_to_pc_scancodes: unimplemented type! ]\n");
297                  return;                  return;
298          }          }
# Line 314  static void ascii_to_pc_scancodes(int a, Line 321  static void ascii_to_pc_scancodes(int a,
321          if (a=='<')  {  a = ','; shift = 1; }          if (a=='<')  {  a = ','; shift = 1; }
322          if (a=='>')  {  a = '.'; shift = 1; }          if (a=='>')  {  a = '.'; shift = 1; }
323          if (a=='?')  {  a = '/'; shift = 1; }          if (a=='?')  {  a = '/'; shift = 1; }
324            if (a=='~')  {  a = '`'; shift = 1; }
325    
326          if (shift)          if (shift)
327                  pckbc_add_code(d, 0x2a, p);                  pckbc_add_code(d, 0x2a, p);
# Line 399  static void ascii_to_pc_scancodes(int a, Line 407  static void ascii_to_pc_scancodes(int a,
407    
408          if (a==';')     pckbc_add_code(d, 0x27, p);          if (a==';')     pckbc_add_code(d, 0x27, p);
409          if (a=='\'')    pckbc_add_code(d, 0x28, p);          if (a=='\'')    pckbc_add_code(d, 0x28, p);
410          if (a=='~')     pckbc_add_code(d, 0x29, p);          if (a=='`')     pckbc_add_code(d, 0x29, p);
411          if (a=='\\')    pckbc_add_code(d, 0x2b, p);          if (a=='\\')    pckbc_add_code(d, 0x2b, p);
412    
413          if (a=='z')     pckbc_add_code(d, 0x2c, p);          if (a=='z')     pckbc_add_code(d, 0x2c, p);
# Line 439  void dev_pckbc_tick(struct cpu *cpu, voi Line 447  void dev_pckbc_tick(struct cpu *cpu, voi
447          if (d->in_use && console_charavail(d->console_handle)) {          if (d->in_use && console_charavail(d->console_handle)) {
448                  ch = console_readchar(d->console_handle);                  ch = console_readchar(d->console_handle);
449                  if (ch >= 0)                  if (ch >= 0)
450                          ascii_to_pc_scancodes(ch, d);                          ascii_to_pc_scancodes_type2(ch, d);
451          }          }
452    
453          ints_enabled = d->rx_int_enable;          ints_enabled = d->rx_int_enable;
# Line 452  void dev_pckbc_tick(struct cpu *cpu, voi Line 460  void dev_pckbc_tick(struct cpu *cpu, voi
460          for (port_nr=0; port_nr<2; port_nr++) {          for (port_nr=0; port_nr<2; port_nr++) {
461                  /*  Cause receive interrupt, if there's something in the                  /*  Cause receive interrupt, if there's something in the
462                      receive buffer: (Otherwise deassert the interrupt.)  */                      receive buffer: (Otherwise deassert the interrupt.)  */
463                    int irq = port_nr==0? d->keyboard_irqnr : d->mouse_irqnr;
464    
465                  if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) {                  if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) {
466                          debug("[ pckbc: interrupt port %i ]\n", port_nr);                          debug("[ pckbc: interrupt port %i ]\n", port_nr);
467                          cpu_interrupt(cpu, port_nr==0? d->keyboard_irqnr                          cpu_interrupt(cpu, irq);
                             : d->mouse_irqnr);  
468                          d->currently_asserted[port_nr] = 1;                          d->currently_asserted[port_nr] = 1;
469                  } else {                  } else {
470                          if (d->currently_asserted[port_nr])                          if (d->currently_asserted[port_nr])
471                                  cpu_interrupt_ack(cpu, port_nr==0?                                  cpu_interrupt_ack(cpu, irq);
                                     d->keyboard_irqnr : d->mouse_irqnr);  
472                          d->currently_asserted[port_nr] = 0;                          d->currently_asserted[port_nr] = 0;
473                  }                  }
474          }          }
# Line 483  static void dev_pckbc_command(struct pck Line 491  static void dev_pckbc_command(struct pck
491                  debug("[ pckbc: (port %i) switching to translation table "                  debug("[ pckbc: (port %i) switching to translation table "
492                      "0x%02x ]\n", port_nr, cmd);                      "0x%02x ]\n", port_nr, cmd);
493                  switch (cmd) {                  switch (cmd) {
494                  case 1:                  case 2:
495                  case 3: d->translation_table = cmd;                  case 3: d->translation_table = cmd;
496                          break;                          break;
497                  default:fatal("[ pckbc: (port %i) translation table "                  default:fatal("[ pckbc: (port %i) translation table "
498                      "0x%02x is NOT YET IMPLEMENTED ]\n", port_nr, cmd);                              "0x%02x is NOT YET IMPLEMENTED ]\n",
499                                port_nr, cmd);
500                  }                  }
501                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
502                  d->state = STATE_NORMAL;                  d->state = STATE_NORMAL;
503                  return;                  return;
504          }          }
505    
506          if (d->state == STATE_WAITING_FOR_F3) {          if (d->state == STATE_WAITING_FOR_RATE) {
507                  debug("[ pckbc: (port %i) received '0xf3' data: "                  debug("[ pckbc: (port %i) received Typematic Rate data: "
508                      "0x%02x ]\n", port_nr, cmd);                      "0x%02x ]\n", port_nr, cmd);
509                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
510                  d->state = STATE_NORMAL;                  d->state = STATE_NORMAL;
511                  return;                  return;
512          }          }
513    
514          if (d->state == STATE_WAITING_FOR_FC) {          if (d->state == STATE_WAITING_FOR_ONEKEY_MB) {
515                  debug("[ pckbc: (port %i) received '0xfc' data: "                  debug("[ pckbc: (port %i) received One-key make/break data: "
516                      "0x%02x ]\n", port_nr, cmd);                      "0x%02x ]\n", port_nr, cmd);
517                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
518                  d->state = STATE_NORMAL;                  d->state = STATE_NORMAL;
519                  return;                  return;
520          }          }
521    
522            if (d->state == STATE_WAITING_FOR_AUX) {
523                    debug("[ pckbc: (port %i) received aux data: "
524                        "0x%02x ]\n", port_nr, cmd);
525                    /*  Echo back.  */
526                    pckbc_add_code(d, cmd, port_nr);
527                    d->state = STATE_NORMAL;
528                    return;
529            }
530    
531            if (d->state == STATE_WAITING_FOR_AUX_OUT) {
532                    debug("[ pckbc: (port %i) received aux out data: "
533                        "0x%02x ]\n", port_nr, cmd);
534                    /*  Echo back.  */
535                    pckbc_add_code(d, cmd, port_nr);
536                    d->state = STATE_NORMAL;
537                    return;
538            }
539    
540          switch (cmd) {          switch (cmd) {
541    
542          case 0x00:          case 0x00:
543                    /*
544                     *  TODO: What does this do? This is possibly due to an
545                     *  error in the handling of some other command code.
546                     */
547                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
548                  break;                  break;
549    
550          case KBC_MODEIND:       /*  Set LEDs  */          case KBC_MODEIND:       /*  Set LEDs  */
551                  /*  Just ACK, no LEDs are actually set.  */                  /*  Just ACK, no LEDs are actually set.  */
552                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
553                  break;                  break;
554    
555          case KBC_SETTABLE:          case KBC_SETTABLE:
556                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
557                  d->state = STATE_WAITING_FOR_TRANSLTABLE;                  d->state = STATE_WAITING_FOR_TRANSLTABLE;
558                  break;                  break;
559    
560          case KBC_ENABLE:          case KBC_ENABLE:
561                  d->keyscanning_enabled = 1;                  d->keyscanning_enabled = 1;
562                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
563                  break;                  break;
564    
565          case KBC_DISABLE:          case KBC_DISABLE:
566                  d->keyscanning_enabled = 0;                  d->keyscanning_enabled = 0;
567                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
568                  break;                  break;
569    
570          case KBC_SETDEFAULT:          case KBC_SETDEFAULT:
571                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
572                  break;                  break;
573          case 0xf3:  
574            case KBC_GETID:
575                    /*  Get keyboard ID.  NOTE/TODO: Ugly hardcoded answer.  */
576                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
577                  d->state = STATE_WAITING_FOR_F3;                  pckbc_add_code(d, 0xab, port_nr);
578                    pckbc_add_code(d, 0x41, port_nr);
579                  break;                  break;
580          case 0xfa:      /*  Just ack?  */  
581            case KBC_TYPEMATIC:
582                    /*  Set typematic (auto-repeat) delay/speed:  */
583                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
584                    d->state = STATE_WAITING_FOR_RATE;
585                  break;                  break;
586          case 0xfc:  
587            case KBC_ALLKEYS_TMB:
588                    /*  "Make all keys typematic/make/break"  */
589                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
                 d->state = STATE_WAITING_FOR_FC;  
590                  break;                  break;
591    
592            case KBC_ONEKEY_MB:
593                    /*  "Make one key typematic/make/break"  */
594                    pckbc_add_code(d, KBR_ACK, port_nr);
595                    d->state = STATE_WAITING_FOR_ONEKEY_MB;
596                    break;
597    
598          case KBC_RESET:          case KBC_RESET:
599                  pckbc_add_code(d, KBR_ACK, port_nr);                  pckbc_add_code(d, KBR_ACK, port_nr);
600                  pckbc_add_code(d, KBR_RSTDONE, port_nr);                  pckbc_add_code(d, KBR_RSTDONE, port_nr);
601                    /*
602                     *  Disable interrupts during reset, or Linux 2.6
603                     *  prints warnings about spurious interrupts.
604                     */
605                    d->rx_int_enable = 0;
606                  break;                  break;
607    
608          default:          default:
609                  fatal("[ pckbc: (port %i) UNIMPLEMENTED 8048 command"                  fatal("[ pckbc: (port %i) UNIMPLEMENTED 8048 command"
610                      " 0x%02x ]\n", port_nr, cmd);                      " 0x%02x ]\n", port_nr, cmd);
611                    exit(1);
612          }          }
613  }  }
614    
615    
616  /*  DEVICE_ACCESS(pckbc)
  *  dev_pckbc_access():  
  */  
 int dev_pckbc_access(struct cpu *cpu, struct memory *mem,  
         uint64_t relative_addr, unsigned char *data, size_t len,  
         int writeflag, void *extra)  
617  {  {
618          uint64_t idata = 0, odata = 0;          uint64_t idata = 0, odata = 0;
619          int i, port_nr = 0;          int port_nr = 0;
620            size_t i;
621          struct pckbc_data *d = extra;          struct pckbc_data *d = extra;
622    
623          idata = memory_readmax64(cpu, data, len);          if (writeflag == MEM_WRITE)
624                    idata = memory_readmax64(cpu, data, len);
625    
626  #ifdef PCKBC_DEBUG  #ifdef PCKBC_DEBUG
627          if (writeflag == MEM_WRITE)          if (writeflag == MEM_WRITE)
# Line 639  if (x&1) Line 694  if (x&1)
694                                  }                                  }
695                          }                          }
696                          /*  debug("[ pckbc: read from DATA: 0x%02x ]\n",                          /*  debug("[ pckbc: read from DATA: 0x%02x ]\n",
697                              odata);  */                              (int)odata);  */
698                  } else {                  } else {
699                          debug("[ pckbc: write to DATA:");                          debug("[ pckbc: write to DATA:");
700                          for (i=0; i<len; i++)                          for (i=0; i<len; i++)
# Line 688  if (x&1) Line 743  if (x&1)
743                          d->reg[relative_addr] = idata;                          d->reg[relative_addr] = idata;
744    
745                          switch (idata) {                          switch (idata) {
746                            case 0x10:
747                            case 0x11:
748                                    /*  TODO: For now, don't print warnings about
749                                        these. NetBSD sends these.  */
750                                    break;
751                          case K_RDCMDBYTE:                          case K_RDCMDBYTE:
752                                  d->state = STATE_RDCMDBYTE;                                  d->state = STATE_RDCMDBYTE;
753                                  break;                                  break;
# Line 706  if (x&1) Line 766  if (x&1)
766                          case 0xaa:      /*  keyboard self-test  */                          case 0xaa:      /*  keyboard self-test  */
767                                  pckbc_add_code(d, 0x55, port_nr);                                  pckbc_add_code(d, 0x55, port_nr);
768                                  break;                                  break;
769                            case 0xab:      /*  keyboard interface self-test  */
770                                    pckbc_add_code(d, 0x00, port_nr);
771                                    break;
772                          case 0xad:                          case 0xad:
773                                  d->cmdbyte |= KC8_KDISABLE;                                  d->cmdbyte |= KC8_KDISABLE;
774                                  break;                                  break;
# Line 718  if (x&1) Line 781  if (x&1)
781                          case 0xd1:                          case 0xd1:
782                                  d->state = STATE_LDOUTPUT;                                  d->state = STATE_LDOUTPUT;
783                                  break;                                  break;
784                            case 0xd3:      /*  write to auxiliary device
785                                                output buffer  */
786                                    debug("[ pckbc: CONTROL 0xd3, TODO ]\n");
787                                    d->state = STATE_WAITING_FOR_AUX_OUT;
788                                    break;
789                          case 0xd4:      /*  write to auxiliary port  */                          case 0xd4:      /*  write to auxiliary port  */
790                                  debug("[ pckbc: CONTROL 0xd4, TODO ]\n");                                  debug("[ pckbc: CONTROL 0xd4, TODO ]\n");
791                                    d->state = STATE_WAITING_FOR_AUX;
792                                  break;                                  break;
793                          default:                          default:
794                                  fatal("[ pckbc: unknown CONTROL 0x%x ]\n",                                  fatal("[ pckbc: unknown CONTROL 0x%x ]\n",
795                                      idata);                                      (int)idata);
796                                  d->state = STATE_NORMAL;                                  d->state = STATE_NORMAL;
797                          }                          }
798                  }                  }
# Line 809  if (x&1) Line 878  if (x&1)
878                  }                  }
879          }          }
880    
881          /*  SGI?  */          /*  SGI? TODO: fix  */
882          if (len == 8)          if (len == 8)
883                  odata |= (odata << 8) | (odata << 16) | (odata << 24) |                  odata |= (odata << 8) | (odata << 16) | (odata << 24) |
884                      (odata << 32) | (odata << 40) | (odata << 48) |                      (odata << 32) | (odata << 40) | (odata << 48) |
# Line 844  int dev_pckbc_init(struct machine *machi Line 913  int dev_pckbc_init(struct machine *machi
913          memset(d, 0, sizeof(struct pckbc_data));          memset(d, 0, sizeof(struct pckbc_data));
914    
915          if (type == PCKBC_8242)          if (type == PCKBC_8242)
916                  len = 0x40;                  len = 0x18;
917    
918          if (type == PCKBC_JAZZ) {          if (type == PCKBC_JAZZ) {
919                  type = PCKBC_8042;                  type = PCKBC_8042;
# Line 856  int dev_pckbc_init(struct machine *machi Line 925  int dev_pckbc_init(struct machine *machi
925          d->mouse_irqnr       = mouse_irqnr;          d->mouse_irqnr       = mouse_irqnr;
926          d->in_use            = in_use;          d->in_use            = in_use;
927          d->pc_style_flag     = pc_style_flag;          d->pc_style_flag     = pc_style_flag;
928          d->console_handle    = console_start_slave_inputonly(machine, "pckbc");          d->translation_table = 2;
         d->translation_table = 1;  
929          d->rx_int_enable     = 1;          d->rx_int_enable     = 1;
930          d->output_byte       = 0x02;    /*  A20 enable on PCs  */          d->output_byte       = 0x02;    /*  A20 enable on PCs  */
931    
932            d->console_handle = console_start_slave_inputonly(
933                machine, "pckbc", d->in_use);
934    
935          memory_device_register(mem, "pckbc", baseaddr,          memory_device_register(mem, "pckbc", baseaddr,
936              len, dev_pckbc_access, d, MEM_DEFAULT, NULL);              len, dev_pckbc_access, d, DM_DEFAULT, NULL);
937          machine_add_tickfunction(machine, dev_pckbc_tick, d, PCKBC_TICKSHIFT);          machine_add_tickfunction(machine, dev_pckbc_tick, d,
938                PCKBC_TICKSHIFT, 0.0);
939    
940          return d->console_handle;          return d->console_handle;
941  }  }

Legend:
Removed from v.14  
changed lines
  Added in v.30

  ViewVC Help
Powered by ViewVC 1.1.26