/[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 4 by dpavlin, Mon Oct 8 16:18:00 2007 UTC revision 12 by dpavlin, Mon Oct 8 16:18:38 2007 UTC
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *     *  
27   *   *
28   *  $Id: dev_pckbc.c,v 1.37 2005/02/22 06:26:10 debug Exp $   *  $Id: dev_pckbc.c,v 1.48 2005/08/16 06:49:27 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.   *  controller), including the 8048 keyboard chip.
32   *   *
33   *   *
34   *  TODO: Finish the rewrite for 8242.   *  TODO: Finish the rewrite for 8242.
# Line 49  Line 49 
49    
50    
51  /*  #define PCKBC_DEBUG  */  /*  #define PCKBC_DEBUG  */
52    /*  #define debug fatal  */
53    
54    
55  #define MAX_8042_QUEUELEN       256  #define MAX_8042_QUEUELEN       256
# Line 69  Line 70 
70  struct pckbc_data {  struct pckbc_data {
71          int             console_handle;          int             console_handle;
72          int             in_use;          int             in_use;
         int             any_command_used;  
73    
74          int             reg[DEV_PCKBC_LENGTH];          int             reg[DEV_PCKBC_LENGTH];
75          int             keyboard_irqnr;          int             keyboard_irqnr;
76          int             mouse_irqnr;          int             mouse_irqnr;
77          int             type;          int             type;
78            int             pc_style_flag;
79    
80          /*  TODO: one of these for each port?  */          /*  TODO: one of these for each port?  */
81          int             clocksignal;          int             clocksignal;
# Line 84  struct pckbc_data { Line 85  struct pckbc_data {
85          int             keyscanning_enabled;          int             keyscanning_enabled;
86          int             state;          int             state;
87          int             cmdbyte;          int             cmdbyte;
88            int             output_byte;
89          int             last_scancode;          int             last_scancode;
90    
91          unsigned        key_queue[2][MAX_8042_QUEUELEN];          unsigned        key_queue[2][MAX_8042_QUEUELEN];
# Line 94  struct pckbc_data { Line 96  struct pckbc_data {
96  #define STATE_LDCMDBYTE                 1  #define STATE_LDCMDBYTE                 1
97  #define STATE_RDCMDBYTE                 2  #define STATE_RDCMDBYTE                 2
98  #define STATE_WAITING_FOR_TRANSLTABLE   3  #define STATE_WAITING_FOR_TRANSLTABLE   3
99    #define STATE_LDOUTPUT                  4
100    #define STATE_RDOUTPUT                  5
101    
102    
103  /*  /*
# Line 121  int pckbc_get_code(struct pckbc_data *d, Line 125  int pckbc_get_code(struct pckbc_data *d,
125  {  {
126          if (d->head[port] == d->tail[port])          if (d->head[port] == d->tail[port])
127                  fatal("[ pckbc: queue empty, port %i! ]\n", port);                  fatal("[ pckbc: queue empty, port %i! ]\n", port);
128            else
129          d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN;                  d->tail[port] = (d->tail[port]+1) % MAX_8042_QUEUELEN;
130          return d->key_queue[port][d->tail[port]];          return d->key_queue[port][d->tail[port]];
131  }  }
132    
# Line 135  int pckbc_get_code(struct pckbc_data *d, Line 139  int pckbc_get_code(struct pckbc_data *d,
139   */   */
140  static void ascii_to_pc_scancodes(int a, struct pckbc_data *d)  static void ascii_to_pc_scancodes(int a, struct pckbc_data *d)
141  {  {
142            int old_head;
143          int p = 0;      /*  port  */          int p = 0;      /*  port  */
144          int shift = 0, ctrl = 0;          int shift = 0, ctrl = 0;
145    
# Line 151  static void ascii_to_pc_scancodes(int a, Line 156  static void ascii_to_pc_scancodes(int a,
156                  pckbc_add_code(d, 0x1d, p);                  pckbc_add_code(d, 0x1d, p);
157    
158          /*          /*
159           *  TODO: Release for all of these?           *  Note: The ugly hack used to add release codes for all of these
160             *  keys is as follows:  we remember how much of the kbd buf that
161             *  is in use here, before we add any scancode. After we've added
162             *  one or more scancodes (ie an optional shift + another key)
163             *  then we duplicate the last scancode | 0x80 _if_ the kbd buf
164             *  was altered.
165           */           */
166    
167            old_head = d->head[p];
168    
169          if (a==27)      pckbc_add_code(d, 0x01, p);          if (a==27)      pckbc_add_code(d, 0x01, p);
170    
171          if (a=='1')     pckbc_add_code(d, 0x02, p);          if (a=='1')     pckbc_add_code(d, 0x02, p);
# Line 259  static void ascii_to_pc_scancodes(int a, Line 271  static void ascii_to_pc_scancodes(int a,
271    
272          if (a==' ')     pckbc_add_code(d, 0x39, p);          if (a==' ')     pckbc_add_code(d, 0x39, p);
273    
274            /*  Add release code, if a key was pressed:  */
275            if (d->head[p] != old_head) {
276                    int code = d->key_queue[p][d->head[p]] | 0x80;
277                    pckbc_add_code(d, code, p);
278            }
279    
280          /*  Release ctrl:  */          /*  Release ctrl:  */
281          if (ctrl)          if (ctrl)
282                  pckbc_add_code(d, 0x1d + 0x80, p);                  pckbc_add_code(d, 0x1d + 0x80, p);
# Line 271  static void ascii_to_pc_scancodes(int a, Line 289  static void ascii_to_pc_scancodes(int a,
289  void dev_pckbc_tick(struct cpu *cpu, void *extra)  void dev_pckbc_tick(struct cpu *cpu, void *extra)
290  {  {
291          struct pckbc_data *d = extra;          struct pckbc_data *d = extra;
292          int port_nr;          int port_nr, ch, ints_enabled;
         int ch;  
293    
294          if (d->in_use && d->any_command_used &&          if (d->in_use && console_charavail(d->console_handle)) {
             console_charavail(d->console_handle)) {  
295                  ch = console_readchar(d->console_handle);                  ch = console_readchar(d->console_handle);
296                  if (ch >= 0)                  if (ch >= 0)
297                          ascii_to_pc_scancodes(ch, d);                          ascii_to_pc_scancodes(ch, d);
298          }          }
299    
300            ints_enabled = d->rx_int_enable;
301    
302          /*  TODO: mouse movements?  */          /*  TODO: mouse movements?  */
303    
304            if (d->cmdbyte & KC8_KDISABLE)
305                    ints_enabled = 0;
306    
307          for (port_nr=0; port_nr<2; port_nr++) {          for (port_nr=0; port_nr<2; port_nr++) {
308                  /*  Cause receive interrupt,                  /*  Cause receive interrupt, if there's something in the
309                      if there's something in the receive buffer:  */                      receive buffer: (Otherwise deassert the interrupt.)  */
310                  if (d->head[port_nr] != d->tail[port_nr] && d->rx_int_enable) {                  if (d->head[port_nr] != d->tail[port_nr] && ints_enabled) {
311                            debug("[ pckbc: interrupt port %i ]\n", port_nr);
312                          cpu_interrupt(cpu, port_nr==0? d->keyboard_irqnr                          cpu_interrupt(cpu, port_nr==0? d->keyboard_irqnr
313                              : d->mouse_irqnr);                              : d->mouse_irqnr);
314                  } else {                  } else {
# Line 299  void dev_pckbc_tick(struct cpu *cpu, voi Line 321  void dev_pckbc_tick(struct cpu *cpu, voi
321    
322  /*  /*
323   *  dev_pckbc_command():   *  dev_pckbc_command():
324     *
325     *  Handle commands to the 8048 in the emulated keyboard.
326   */   */
327  static void dev_pckbc_command(struct pckbc_data *d, int port_nr)  static void dev_pckbc_command(struct pckbc_data *d, int port_nr)
328  {  {
329          int cmd = d->reg[PC_CMD];          int cmd = d->reg[PC_CMD];
330    
         d->any_command_used = 1;  
   
331          if (d->type == PCKBC_8242)          if (d->type == PCKBC_8242)
332                  cmd = d->reg[PS2_TXBUF];                  cmd = d->reg[PS2_TXBUF];
333    
# Line 345  static void dev_pckbc_command(struct pck Line 367  static void dev_pckbc_command(struct pck
367                  pckbc_add_code(d, KBR_RSTDONE, port_nr);                  pckbc_add_code(d, KBR_RSTDONE, port_nr);
368                  break;                  break;
369          default:          default:
370                  fatal("[ pckbc: UNIMPLEMENTED command 0x%02x ]\n", cmd);                  fatal("[ pckbc: UNIMPLEMENTED 8048 command 0x%02x ]\n", cmd);
371          }          }
372  }  }
373    
# Line 373  int dev_pckbc_access(struct cpu *cpu, st Line 395  int dev_pckbc_access(struct cpu *cpu, st
395  #endif  #endif
396    
397          /*  For JAZZ-based machines:  */          /*  For JAZZ-based machines:  */
398          if (relative_addr >= 0x60)          if (relative_addr >= 0x60) {
399                  relative_addr -= 0x60;                  relative_addr -= 0x60;
400                    if (relative_addr != 0)
401          /*  8242 PS2-style:  */                          relative_addr = 1;
402          if (d->type == PCKBC_8242) {          } else if (d->type == PCKBC_8242) {
403                    /*  8242 PS2-style:  */
404                  /*  when using 8-byte alignment...  */                  /*  when using 8-byte alignment...  */
405                  relative_addr /= sizeof(uint64_t);                  relative_addr /= sizeof(uint64_t);
406                  /*  port_nr = 0 for keyboard, 1 for mouse  */                  /*  port_nr = 0 for keyboard, 1 for mouse  */
407                  port_nr = (relative_addr >> 2);                  port_nr = (relative_addr >> 2);
408                  relative_addr &= 3;                  relative_addr &= 3;
409                  relative_addr += PS2;                  relative_addr += PS2;
410            } else if (d->pc_style_flag) {
411                    /*  PC-style:  */
412                    if (relative_addr != 0 && relative_addr != 4) {
413                            /*  TODO (port 0x61)  */
414                            odata = 0x21;
415    {
416    static int x = 0;
417    x++;
418    if (x&1)
419                            odata ^= 0x10;
420    }
421                            if (writeflag == MEM_READ)
422                                    memory_writemax64(cpu, data, len, odata);
423                            return 0;
424                    }
425                    if (relative_addr != 0)
426                            relative_addr = 1;
427          } else {          } else {
428                  /*  The relative_addr is either 0 or 1,                  /*  Others... Non-Jazz ARC-based machines etc.  */
429                      but some machines use longer registers than one byte                  if (relative_addr != 0)
                     each, so this will make things simpler for us:  */  
                 if (relative_addr)  
430                          relative_addr = 1;                          relative_addr = 1;
431          }          }
432    
# Line 400  int dev_pckbc_access(struct cpu *cpu, st Line 438  int dev_pckbc_access(struct cpu *cpu, st
438    
439          case 0:         /*  data  */          case 0:         /*  data  */
440                  if (writeflag==MEM_READ) {                  if (writeflag==MEM_READ) {
441                          if (d->state == STATE_RDCMDBYTE) {                          switch (d->state) {
442                            case STATE_RDCMDBYTE:
443                                  odata = d->cmdbyte;                                  odata = d->cmdbyte;
444                                  d->state = STATE_NORMAL;                                  d->state = STATE_NORMAL;
445                          } else {                                  break;
446                                  if (d->head[0] != d->tail[0]) {                          case STATE_RDOUTPUT:
447                                    odata = d->output_byte;
448                                    d->state = STATE_NORMAL;
449                                    break;
450                            default:if (d->head[0] != d->tail[0]) {
451                                          odata = pckbc_get_code(d, 0);                                          odata = pckbc_get_code(d, 0);
452                                          d->last_scancode = odata;                                          d->last_scancode = odata;
453                                  } else {                                  } else {
# Line 412  int dev_pckbc_access(struct cpu *cpu, st Line 455  int dev_pckbc_access(struct cpu *cpu, st
455                                          d->last_scancode |= 0x80;                                          d->last_scancode |= 0x80;
456                                  }                                  }
457                          }                          }
458                          debug("[ pckbc: read from DATA: 0x%02x ]\n", odata);                          /*  debug("[ pckbc: read from DATA: 0x%02x ]\n",
459                                odata);  */
460                  } else {                  } else {
461                          debug("[ pckbc: write to DATA:");                          debug("[ pckbc: write to DATA:");
462                          for (i=0; i<len; i++)                          for (i=0; i<len; i++)
463                                  debug(" %02x", data[i]);                                  debug(" %02x", data[i]);
464                          debug(" ]\n");                          debug(" ]\n");
465    
466                          if (d->state == STATE_LDCMDBYTE) {                          switch (d->state) {
467                            case STATE_LDCMDBYTE:
468                                  d->cmdbyte = idata;                                  d->cmdbyte = idata;
469                                  d->rx_int_enable = d->cmdbyte &                                  d->rx_int_enable = d->cmdbyte &
470                                      (KC8_KENABLE | KC8_MENABLE) ? 1 : 0;                                      (KC8_KENABLE | KC8_MENABLE) ? 1 : 0;
471                                  d->state = STATE_NORMAL;                                  d->state = STATE_NORMAL;
472                          } else {                                  break;
473                                  d->reg[relative_addr] = idata;                          case STATE_LDOUTPUT:
474                                    d->output_byte = idata;
475                                    d->state = STATE_NORMAL;
476                                    break;
477                            default:d->reg[relative_addr] = idata;
478                                  dev_pckbc_command(d, port_nr);                                  dev_pckbc_command(d, port_nr);
479                          }                          }
480                  }                  }
# Line 438  int dev_pckbc_access(struct cpu *cpu, st Line 487  int dev_pckbc_access(struct cpu *cpu, st
487    
488                          /*  "Data in buffer" bit  */                          /*  "Data in buffer" bit  */
489                          if (d->head[0] != d->tail[0] ||                          if (d->head[0] != d->tail[0] ||
490                              d->state == STATE_RDCMDBYTE)                              d->state == STATE_RDCMDBYTE ||
491                                d->state == STATE_RDOUTPUT)
492                                  odata |= KBS_DIB;                                  odata |= KBS_DIB;
493                          /*  odata |= KBS_OCMD;  */  
494                            if (d->state == STATE_RDCMDBYTE)
495                                    odata |= KBS_OCMD;
496    
497                            odata |= KBS_NOSEC;
498                          /*  debug("[ pckbc: read from CTL status port: "                          /*  debug("[ pckbc: read from CTL status port: "
499                              "0x%02x ]\n", (int)odata);  */                              "0x%02x ]\n", (int)odata);  */
500                  } else {                  } else {
# Line 457  int dev_pckbc_access(struct cpu *cpu, st Line 511  int dev_pckbc_access(struct cpu *cpu, st
511                          case K_LDCMDBYTE:                          case K_LDCMDBYTE:
512                                  d->state = STATE_LDCMDBYTE;                                  d->state = STATE_LDCMDBYTE;
513                                  break;                                  break;
514                            case 0xa7:
515                                    d->cmdbyte |= KC8_MDISABLE;
516                                    break;
517                            case 0xa8:
518                                    d->cmdbyte &= ~KC8_MDISABLE;
519                                    break;
520                          case 0xa9:      /*  test auxiliary port  */                          case 0xa9:      /*  test auxiliary port  */
521                                  debug("[ pckbc: CONTROL 0xa9, TODO ]\n");                                  debug("[ pckbc: CONTROL 0xa9, TODO ]\n");
522                                  break;                                  break;
523                          case 0xaa:      /*  keyboard self-test  */                          case 0xaa:      /*  keyboard self-test  */
524                                  pckbc_add_code(d, 0x55, port_nr);                                  pckbc_add_code(d, 0x55, port_nr);
525                                  break;                                  break;
526                            case 0xad:
527                                    d->cmdbyte |= KC8_KDISABLE;
528                                    break;
529                            case 0xae:
530                                    d->cmdbyte &= ~KC8_KDISABLE;
531                                    break;
532                            case 0xd0:
533                                    d->state = STATE_RDOUTPUT;
534                                    break;
535                            case 0xd1:
536                                    d->state = STATE_LDOUTPUT;
537                                    break;
538                          case 0xd4:      /*  write to auxiliary port  */                          case 0xd4:      /*  write to auxiliary port  */
539                                  debug("[ pckbc: CONTROL 0xd4, TODO ]\n");                                  debug("[ pckbc: CONTROL 0xd4, TODO ]\n");
540                                  break;                                  break;
# Line 633  int dev_pckbc_access(struct cpu *cpu, st Line 705  int dev_pckbc_access(struct cpu *cpu, st
705   */   */
706  int dev_pckbc_init(struct machine *machine, struct memory *mem,  int dev_pckbc_init(struct machine *machine, struct memory *mem,
707          uint64_t baseaddr, int type, int keyboard_irqnr, int mouse_irqnr,          uint64_t baseaddr, int type, int keyboard_irqnr, int mouse_irqnr,
708          int in_use)          int in_use, int pc_style_flag)
709  {  {
710          struct pckbc_data *d;          struct pckbc_data *d;
711          int len = DEV_PCKBC_LENGTH;          int len = DEV_PCKBC_LENGTH;
# Line 645  int dev_pckbc_init(struct machine *machi Line 717  int dev_pckbc_init(struct machine *machi
717          }          }
718          memset(d, 0, sizeof(struct pckbc_data));          memset(d, 0, sizeof(struct pckbc_data));
719    
720            if (type == PCKBC_8242)
721                    len = 0x40;
722    
723          if (type == PCKBC_JAZZ) {          if (type == PCKBC_JAZZ) {
724                  type = PCKBC_8042;                  type = PCKBC_8042;
725                  len = DEV_PCKBC_LENGTH + 0x60;                  len = DEV_PCKBC_LENGTH + 0x60;
# Line 654  int dev_pckbc_init(struct machine *machi Line 729  int dev_pckbc_init(struct machine *machi
729          d->keyboard_irqnr = keyboard_irqnr;          d->keyboard_irqnr = keyboard_irqnr;
730          d->mouse_irqnr    = mouse_irqnr;          d->mouse_irqnr    = mouse_irqnr;
731          d->in_use         = in_use;          d->in_use         = in_use;
732            d->pc_style_flag  = pc_style_flag;
733          d->console_handle = console_start_slave_inputonly(machine, "pckbc");          d->console_handle = console_start_slave_inputonly(machine, "pckbc");
734            d->rx_int_enable  = 1;
735            d->output_byte    = 0x02;       /*  A20 enable on PCs  */
736    
737          memory_device_register(mem, "pckbc", baseaddr,          memory_device_register(mem, "pckbc", baseaddr,
738              len, dev_pckbc_access, d, MEM_DEFAULT, NULL);              len, dev_pckbc_access, d, MEM_DEFAULT, NULL);

Legend:
Removed from v.4  
changed lines
  Added in v.12

  ViewVC Help
Powered by ViewVC 1.1.26