OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [or1ksim/] [peripheral/] [ps2kbd.c] - Diff between revs 87 and 224

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 87 Rev 224
/* ps2kbd.c -- Very simple (and limited) PS/2 keyboard simulation
/* ps2kbd.c -- Very simple (and limited) PS/2 keyboard simulation
 
 
   Copyright (C) 2002 Marko Mlinar, markom@opencores.org
   Copyright (C) 2002 Marko Mlinar, markom@opencores.org
   Copyright (C) 2008 Embecosm Limited
   Copyright (C) 2008 Embecosm Limited
 
 
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
 
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
 
 
   This program is free software; you can redistribute it and/or modify it
   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the Free
   under the terms of the GNU General Public License as published by the Free
   Software Foundation; either version 3 of the License, or (at your option)
   Software Foundation; either version 3 of the License, or (at your option)
   any later version.
   any later version.
 
 
   This program is distributed in the hope that it will be useful, but WITHOUT
   This program is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   more details.
   more details.
 
 
   You should have received a copy of the GNU General Public License along
   You should have received a copy of the GNU General Public License along
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
/* This program is commented throughout in a fashion suitable for processing
/* This program is commented throughout in a fashion suitable for processing
   with Doxygen. */
   with Doxygen. */
 
 
 
 
/* Autoconf and/or portability configuration */
/* Autoconf and/or portability configuration */
#include "config.h"
#include "config.h"
#include "port.h"
#include "port.h"
 
 
/* System includes */
/* System includes */
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdio.h>
 
 
/* Package includes */
/* Package includes */
#include "arch.h"
#include "arch.h"
#include "pic.h"
#include "pic.h"
#include "sim-config.h"
#include "sim-config.h"
#include "abstract.h"
#include "abstract.h"
#include "sched.h"
#include "sched.h"
#include "toplevel-support.h"
#include "toplevel-support.h"
#include "sim-cmd.h"
#include "sim-cmd.h"
 
 
 
 
/* Device registers */
/* Device registers */
#define KBD_CTRL              4
#define KBD_CTRL              4
#define KBD_DATA              0
#define KBD_DATA              0
#define KBD_SPACE             8
#define KBD_SPACE             8
 
 
/* Keyboard commands */
/* Keyboard commands */
#define KBD_KCMD_RST       0xFF
#define KBD_KCMD_RST       0xFF
#define KBD_KCMD_DK        0xF5
#define KBD_KCMD_DK        0xF5
#define KBD_KCMD_EK        0xF4
#define KBD_KCMD_EK        0xF4
#define KBD_KCMD_ECHO      0xFF
#define KBD_KCMD_ECHO      0xFF
#define KBD_KCMD_SRL       0xED
#define KBD_KCMD_SRL       0xED
 
 
/* Keyboard responses */
/* Keyboard responses */
#define KBD_KRESP_RSTOK    0xAA
#define KBD_KRESP_RSTOK    0xAA
#define KBD_KRESP_ECHO     0xEE
#define KBD_KRESP_ECHO     0xEE
#define KBD_KRESP_ACK      0xFA
#define KBD_KRESP_ACK      0xFA
 
 
/* Controller commands */
/* Controller commands */
#define KBD_CCMD_RCB       0x20
#define KBD_CCMD_RCB       0x20
#define KBD_CCMD_WCB       0x60
#define KBD_CCMD_WCB       0x60
#define KBD_CCMD_ST1       0xAA
#define KBD_CCMD_ST1       0xAA
#define KBD_CCMD_ST2       0xAB
#define KBD_CCMD_ST2       0xAB
#define KBD_CCMD_DKI       0xAD
#define KBD_CCMD_DKI       0xAD
#define KBD_CCMD_EKI       0xAE
#define KBD_CCMD_EKI       0xAE
 
 
/* Status register bits */
/* Status register bits */
#define KBD_STATUS_OBF     0x01
#define KBD_STATUS_OBF     0x01
#define KBD_STATUS_IBF     0x02
#define KBD_STATUS_IBF     0x02
#define KBD_STATUS_SYS     0x04
#define KBD_STATUS_SYS     0x04
#define KBD_STATUS_A2      0x08
#define KBD_STATUS_A2      0x08
#define KBD_STATUS_INH     0x10
#define KBD_STATUS_INH     0x10
#define KBD_STATUS_MOBF    0x20
#define KBD_STATUS_MOBF    0x20
#define KBD_STATUS_TO      0x40
#define KBD_STATUS_TO      0x40
#define KBD_STATUS_PERR    0x80
#define KBD_STATUS_PERR    0x80
 
 
/* Command byte register bits */
/* Command byte register bits */
#define KBD_CCMDBYTE_INT   0x01
#define KBD_CCMDBYTE_INT   0x01
#define KBD_CCMDBYTE_INT2  0x02
#define KBD_CCMDBYTE_INT2  0x02
#define KBD_CCMDBYTE_SYS   0x04
#define KBD_CCMDBYTE_SYS   0x04
#define KBD_CCMDBYTE_EN    0x10
#define KBD_CCMDBYTE_EN    0x10
#define KBD_CCMDBYTE_EN2   0x20
#define KBD_CCMDBYTE_EN2   0x20
#define KBD_CCMDBYTE_XLAT  0x40
#define KBD_CCMDBYTE_XLAT  0x40
 
 
/* Length of internal scan code fifo */
/* Length of internal scan code fifo */
#define KBD_MAX_BUF       0x100
#define KBD_MAX_BUF       0x100
 
 
/* Keyboard is checked every KBD_SLOWDOWN cycle */
/* Keyboard is checked every KBD_SLOWDOWN cycle */
#define KBD_BAUD_RATE      1200
#define KBD_BAUD_RATE      1200
 
 
/* ASCII to scan code conversion table */
/* ASCII to scan code conversion table */
const static struct
const static struct
{
{
  /* Whether shift must be pressed */
  /* Whether shift must be pressed */
  unsigned char shift;
  unsigned char shift;
  /* Scan code to be generated */
  /* Scan code to be generated */
  unsigned char code;
  unsigned char code;
} scan_table[128] =
} scan_table[128] =
{
{
/* 0 - 15 */
/* 0 - 15 */
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x0E},
  0, 0x0E},
  {
  {
  0, 0x0F},
  0, 0x0F},
  {
  {
  0, 0x1C},
  0, 0x1C},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
/* 16 - 31 */
/* 16 - 31 */
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x01},
  0, 0x01},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
  {
  {
  0, 0x00},
  0, 0x00},
/* 32 - 47 */
/* 32 - 47 */
  {
  {
  0, 0x39},
  0, 0x39},
  {
  {
  1, 0x02},
  1, 0x02},
  {
  {
  1, 0x28},
  1, 0x28},
  {
  {
  1, 0x04},
  1, 0x04},
  {
  {
  1, 0x05},
  1, 0x05},
  {
  {
  1, 0x06},
  1, 0x06},
  {
  {
  1, 0x08},
  1, 0x08},
  {
  {
  0, 0x28},
  0, 0x28},
  {
  {
  1, 0x0A},
  1, 0x0A},
  {
  {
  1, 0x0B},
  1, 0x0B},
  {
  {
  1, 0x09},
  1, 0x09},
  {
  {
  1, 0x0D},
  1, 0x0D},
  {
  {
  0, 0x33},
  0, 0x33},
  {
  {
  0, 0x0C},
  0, 0x0C},
  {
  {
  0, 0x34},
  0, 0x34},
  {
  {
  0, 0x35},
  0, 0x35},
/* 48 - 63 */
/* 48 - 63 */
  {
  {
  0, 0x0B},
  0, 0x0B},
  {
  {
  0, 0x02},
  0, 0x02},
  {
  {
  0, 0x03},
  0, 0x03},
  {
  {
  0, 0x04},
  0, 0x04},
  {
  {
  0, 0x05},
  0, 0x05},
  {
  {
  0, 0x06},
  0, 0x06},
  {
  {
  0, 0x07},
  0, 0x07},
  {
  {
  0, 0x08},
  0, 0x08},
  {
  {
  0, 0x09},
  0, 0x09},
  {
  {
  0, 0x0A},
  0, 0x0A},
  {
  {
  1, 0x27},
  1, 0x27},
  {
  {
  0, 0x27},
  0, 0x27},
  {
  {
  1, 0x33},
  1, 0x33},
  {
  {
  0, 0x0D},
  0, 0x0D},
  {
  {
  1, 0x34},
  1, 0x34},
  {
  {
  1, 0x35},
  1, 0x35},
/* 64 - 79 */
/* 64 - 79 */
  {
  {
  1, 0x03},
  1, 0x03},
  {
  {
  1, 0x1E},
  1, 0x1E},
  {
  {
  1, 0x30},
  1, 0x30},
  {
  {
  1, 0x2E},
  1, 0x2E},
  {
  {
  1, 0x20},
  1, 0x20},
  {
  {
  1, 0x12},
  1, 0x12},
  {
  {
  1, 0x21},
  1, 0x21},
  {
  {
  1, 0x22},
  1, 0x22},
  {
  {
  1, 0x23},
  1, 0x23},
  {
  {
  1, 0x17},
  1, 0x17},
  {
  {
  1, 0x24},
  1, 0x24},
  {
  {
  1, 0x25},
  1, 0x25},
  {
  {
  1, 0x26},
  1, 0x26},
  {
  {
  1, 0x32},
  1, 0x32},
  {
  {
  1, 0x31},
  1, 0x31},
  {
  {
  1, 0x18},
  1, 0x18},
/* 80 - 95 */
/* 80 - 95 */
  {
  {
  1, 0x19},
  1, 0x19},
  {
  {
  1, 0x10},
  1, 0x10},
  {
  {
  1, 0x13},
  1, 0x13},
  {
  {
  1, 0x1F},
  1, 0x1F},
  {
  {
  1, 0x14},
  1, 0x14},
  {
  {
  1, 0x16},
  1, 0x16},
  {
  {
  1, 0x2F},
  1, 0x2F},
  {
  {
  1, 0x11},
  1, 0x11},
  {
  {
  1, 0x2D},
  1, 0x2D},
  {
  {
  1, 0x15},
  1, 0x15},
  {
  {
  1, 0x2C},
  1, 0x2C},
  {
  {
  0, 0x1A},
  0, 0x1A},
  {
  {
  0, 0x2B},
  0, 0x2B},
  {
  {
  0, 0x1B},
  0, 0x1B},
  {
  {
  1, 0x07},
  1, 0x07},
  {
  {
  1, 0x0C},
  1, 0x0C},
/* 96 - 111 */
/* 96 - 111 */
  {
  {
  0, 0x29},
  0, 0x29},
  {
  {
  0, 0x1E},
  0, 0x1E},
  {
  {
  0, 0x30},
  0, 0x30},
  {
  {
  0, 0x2E},
  0, 0x2E},
  {
  {
  0, 0x20},
  0, 0x20},
  {
  {
  0, 0x12},
  0, 0x12},
  {
  {
  0, 0x21},
  0, 0x21},
  {
  {
  0, 0x22},
  0, 0x22},
  {
  {
  0, 0x23},
  0, 0x23},
  {
  {
  0, 0x17},
  0, 0x17},
  {
  {
  0, 0x24},
  0, 0x24},
  {
  {
  0, 0x25},
  0, 0x25},
  {
  {
  0, 0x26},
  0, 0x26},
  {
  {
  0, 0x32},
  0, 0x32},
  {
  {
  0, 0x31},
  0, 0x31},
  {
  {
  0, 0x18},
  0, 0x18},
/* 112 - 127 */
/* 112 - 127 */
  {
  {
  0, 0x19},
  0, 0x19},
  {
  {
  0, 0x10},
  0, 0x10},
  {
  {
  0, 0x13},
  0, 0x13},
  {
  {
  0, 0x1F},
  0, 0x1F},
  {
  {
  0, 0x14},
  0, 0x14},
  {
  {
  0, 0x16},
  0, 0x16},
  {
  {
  0, 0x2F},
  0, 0x2F},
  {
  {
  0, 0x11},
  0, 0x11},
  {
  {
  0, 0x2D},
  0, 0x2D},
  {
  {
  0, 0x15},
  0, 0x15},
  {
  {
  0, 0x2C},
  0, 0x2C},
  {
  {
  1, 0x1A},
  1, 0x1A},
  {
  {
  1, 0x2B},
  1, 0x2B},
  {
  {
  1, 0x1B},
  1, 0x1B},
  {
  {
  1, 0x29},
  1, 0x29},
  {
  {
  0, 0x00}
  0, 0x00}
};
};
 
 
struct kbd_state
struct kbd_state
{
{
  /* Temporary buffer to store incoming scan codes */
  /* Temporary buffer to store incoming scan codes */
  uint8_t buf[KBD_MAX_BUF];
  uint8_t buf[KBD_MAX_BUF];
 
 
  /* Number of scan codes in buffer */
  /* Number of scan codes in buffer */
  unsigned long buf_count;
  unsigned long buf_count;
  unsigned long buf_head;
  unsigned long buf_head;
  unsigned long buf_tail;
  unsigned long buf_tail;
 
 
  /* Input stream */
  /* Input stream */
  FILE *rxfs;
  FILE *rxfs;
 
 
  /* Controller Command (write into 0x64) */
  /* Controller Command (write into 0x64) */
  int ccmd;
  int ccmd;
 
 
  /* Keyboard Command (write into 0x60) */
  /* Keyboard Command (write into 0x60) */
  uint8_t kcmd;
  uint8_t kcmd;
 
 
  /* Controller Command Byte */
  /* Controller Command Byte */
  uint8_t ccmdbyte;
  uint8_t ccmdbyte;
 
 
  /* Keyboard response pending */
  /* Keyboard response pending */
  unsigned long kresp;
  unsigned long kresp;
 
 
  /* Keyboard slowdown factor */
  /* Keyboard slowdown factor */
  long slowdown;
  long slowdown;
 
 
  /* Cofiguration */
  /* Cofiguration */
  int enabled;
  int enabled;
  int irq;
  int irq;
  oraddr_t baseaddr;
  oraddr_t baseaddr;
  char *rxfile;
  char *rxfile;
};
};
 
 
static void
static void
kbd_put (struct kbd_state *kbd, unsigned char c)
kbd_put (struct kbd_state *kbd, unsigned char c)
{
{
  if (kbd->buf_count >= KBD_MAX_BUF)
  if (kbd->buf_count >= KBD_MAX_BUF)
    {
    {
      fprintf (stderr, "WARNING: Keyboard buffer overflow.\n");
      fprintf (stderr, "WARNING: Keyboard buffer overflow.\n");
    }
    }
  else
  else
    {
    {
      kbd->buf[kbd->buf_head] = c;
      kbd->buf[kbd->buf_head] = c;
      kbd->buf_head = (kbd->buf_head + 1) % KBD_MAX_BUF;
      kbd->buf_head = (kbd->buf_head + 1) % KBD_MAX_BUF;
      kbd->buf_count++;
      kbd->buf_count++;
    }
    }
}
}
 
 
/* Decodes ascii code c into multiple scan codes, placed into buf, length is returned */
/* Decodes ascii code c into multiple scan codes, placed into buf, length is returned */
static void
static void
scan_decode (struct kbd_state *kbd, unsigned char c)
scan_decode (struct kbd_state *kbd, unsigned char c)
{
{
  /* Do not handle special characters and extended ascii */
  /* Do not handle special characters and extended ascii */
  if (c >= 128 || !scan_table[c].code)
  if (c >= 128 || !scan_table[c].code)
    return;
    return;
 
 
  /* Make shift? */
  /* Make shift? */
  if (scan_table[c].shift)
  if (scan_table[c].shift)
    kbd_put (kbd, 0x2a);
    kbd_put (kbd, 0x2a);
  /* Make char */
  /* Make char */
  kbd_put (kbd, scan_table[c].code);
  kbd_put (kbd, scan_table[c].code);
  /* Break char */
  /* Break char */
  kbd_put (kbd, scan_table[c].code | 0x80);
  kbd_put (kbd, scan_table[c].code | 0x80);
  /* Break shift? */
  /* Break shift? */
  if (scan_table[c].shift)
  if (scan_table[c].shift)
    kbd_put (kbd, 0xaa);
    kbd_put (kbd, 0xaa);
}
}
 
 
/* Write a register */
/* Write a register */
static void
static void
kbd_write8 (oraddr_t addr, uint8_t value, void *dat)
kbd_write8 (oraddr_t addr, uint8_t value, void *dat)
{
{
  struct kbd_state *kbd = dat;
  struct kbd_state *kbd = dat;
  switch (addr)
  switch (addr)
    {
    {
    case KBD_CTRL:
    case KBD_CTRL:
      kbd->ccmd = value & 0xff;
      kbd->ccmd = value & 0xff;
      if (kbd->ccmd == KBD_CCMD_RCB)
      if (kbd->ccmd == KBD_CCMD_RCB)
        kbd->kresp = 0x1;
        kbd->kresp = 0x1;
      if (kbd->ccmd == KBD_CCMD_ST1)
      if (kbd->ccmd == KBD_CCMD_ST1)
        kbd->kresp = 0x1;
        kbd->kresp = 0x1;
      if (kbd->ccmd == KBD_CCMD_ST2)
      if (kbd->ccmd == KBD_CCMD_ST2)
        kbd->kresp = 0x1;
        kbd->kresp = 0x1;
      if (kbd->ccmd == KBD_CCMD_DKI)
      if (kbd->ccmd == KBD_CCMD_DKI)
        {
        {
          clear_interrupt (kbd->irq);
          clear_interrupt (kbd->irq);
          kbd->ccmdbyte |= KBD_CCMDBYTE_EN;
          kbd->ccmdbyte |= KBD_CCMDBYTE_EN;
        }
        }
      if (kbd->ccmd == KBD_CCMD_EKI)
      if (kbd->ccmd == KBD_CCMD_EKI)
        kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN;
        kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN;
      if (config.sim.verbose)
      if (config.sim.verbose)
        PRINTF ("kbd_write8(%" PRIxADDR ") %02x\n", addr, value);
        PRINTF ("kbd_write8(%" PRIxADDR ") %02x\n", addr, value);
      break;
      break;
    case KBD_DATA:
    case KBD_DATA:
      if (kbd->ccmd == KBD_CCMD_WCB)
      if (kbd->ccmd == KBD_CCMD_WCB)
        {
        {
          kbd->ccmdbyte = value & 0xff;
          kbd->ccmdbyte = value & 0xff;
          kbd->ccmd = 0x00;
          kbd->ccmd = 0x00;
        }
        }
      else
      else
        kbd->kcmd = value & 0xff;
        kbd->kcmd = value & 0xff;
      if (kbd->kcmd == KBD_KCMD_DK)
      if (kbd->kcmd == KBD_KCMD_DK)
        kbd->ccmdbyte |= KBD_CCMDBYTE_EN;
        kbd->ccmdbyte |= KBD_CCMDBYTE_EN;
      if (kbd->kcmd == KBD_KCMD_EK)
      if (kbd->kcmd == KBD_KCMD_EK)
        kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN;
        kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN;
      kbd->kresp = 0x1;
      kbd->kresp = 0x1;
      kbd->ccmd = 0x00;
      kbd->ccmd = 0x00;
      if (config.sim.verbose)
      if (config.sim.verbose)
        PRINTF ("kbd_write8(%" PRIxADDR ") %02x\n", addr, value);
        PRINTF ("kbd_write8(%" PRIxADDR ") %02x\n", addr, value);
      break;
      break;
    default:
    default:
      fprintf (stderr, "Write out of keyboard space (0x%" PRIxADDR ")!\n",
      fprintf (stderr, "Write out of keyboard space (0x%" PRIxADDR ")!\n",
               addr);
               addr);
      break;
      break;
    }
    }
}
}
 
 
/* Read a register */
/* Read a register */
static uint8_t
static uint8_t
kbd_read8 (oraddr_t addr, void *dat)
kbd_read8 (oraddr_t addr, void *dat)
{
{
  struct kbd_state *kbd = dat;
  struct kbd_state *kbd = dat;
  switch (addr)
  switch (addr)
    {
    {
    case KBD_CTRL:
    case KBD_CTRL:
      {
      {
        unsigned long c = 0x0;
        unsigned long c = 0x0;
        if (kbd->kresp || kbd->buf_count)
        if (kbd->kresp || kbd->buf_count)
          c |= KBD_STATUS_OBF;
          c |= KBD_STATUS_OBF;
        c |= kbd->ccmdbyte & KBD_CCMDBYTE_SYS;
        c |= kbd->ccmdbyte & KBD_CCMDBYTE_SYS;
        c |= KBD_STATUS_INH;
        c |= KBD_STATUS_INH;
        if (config.sim.verbose)
        if (config.sim.verbose)
          PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, c);
          PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, c);
        return c;
        return c;
      }
      }
    case KBD_DATA:
    case KBD_DATA:
      clear_interrupt (kbd->irq);
      clear_interrupt (kbd->irq);
      if (kbd->ccmd)
      if (kbd->ccmd)
        {
        {
          unsigned long rc = 0;
          unsigned long rc = 0;
          if (kbd->ccmd == KBD_CCMD_RCB)
          if (kbd->ccmd == KBD_CCMD_RCB)
            rc = kbd->ccmdbyte;
            rc = kbd->ccmdbyte;
          if (kbd->ccmd == KBD_CCMD_ST1)
          if (kbd->ccmd == KBD_CCMD_ST1)
            rc = 0x55;
            rc = 0x55;
          if (kbd->ccmd == KBD_CCMD_ST2)
          if (kbd->ccmd == KBD_CCMD_ST2)
            rc = 0x00;
            rc = 0x00;
          kbd->ccmd = 0x00;
          kbd->ccmd = 0x00;
          kbd->kresp = 0x0;
          kbd->kresp = 0x0;
          if (config.sim.verbose)
          if (config.sim.verbose)
            PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, rc);
            PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, rc);
          return rc;
          return rc;
        }
        }
      else if (kbd->kresp)
      else if (kbd->kresp)
        {
        {
          unsigned long rc;
          unsigned long rc;
          if (kbd->kresp == 0x2)
          if (kbd->kresp == 0x2)
            {
            {
              kbd->kresp = 0x0;
              kbd->kresp = 0x0;
              rc = KBD_KRESP_RSTOK;
              rc = KBD_KRESP_RSTOK;
            }
            }
          else if (kbd->kcmd == KBD_KCMD_RST)
          else if (kbd->kcmd == KBD_KCMD_RST)
            {
            {
              kbd->kresp = 0x2;
              kbd->kresp = 0x2;
              rc = KBD_KRESP_ACK;
              rc = KBD_KRESP_ACK;
            }
            }
          else if (kbd->kcmd == KBD_KCMD_ECHO)
          else if (kbd->kcmd == KBD_KCMD_ECHO)
            {
            {
              kbd->kresp = 0x0;
              kbd->kresp = 0x0;
              rc = KBD_KRESP_ECHO;
              rc = KBD_KRESP_ECHO;
            }
            }
          else
          else
            {
            {
              kbd->kresp = 0x0;
              kbd->kresp = 0x0;
              rc = KBD_KRESP_ACK;
              rc = KBD_KRESP_ACK;
            }
            }
          kbd->kcmd = 0x00;
          kbd->kcmd = 0x00;
          if (config.sim.verbose)
          if (config.sim.verbose)
            PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, rc);
            PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, rc);
          return rc;
          return rc;
        }
        }
      else if (kbd->buf_count)
      else if (kbd->buf_count)
        {
        {
          unsigned long c = kbd->buf[kbd->buf_tail];
          unsigned long c = kbd->buf[kbd->buf_tail];
          kbd->buf_tail = (kbd->buf_tail + 1) % KBD_MAX_BUF;
          kbd->buf_tail = (kbd->buf_tail + 1) % KBD_MAX_BUF;
          kbd->buf_count--;
          kbd->buf_count--;
          kbd->kresp = 0x0;
          kbd->kresp = 0x0;
          if (config.sim.verbose)
          if (config.sim.verbose)
            PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, c);
            PRINTF ("kbd_read8(%" PRIxADDR ") %lx\n", addr, c);
          return c;
          return c;
        }
        }
      kbd->kresp = 0x0;
      kbd->kresp = 0x0;
      if (config.sim.verbose)
      if (config.sim.verbose)
        PRINTF ("kbd_read8(%" PRIxADDR ") fifo empty\n", addr);
        PRINTF ("kbd_read8(%" PRIxADDR ") fifo empty\n", addr);
      return 0;
      return 0;
    default:
    default:
      fprintf (stderr, "Read out of keyboard space (0x%" PRIxADDR ")!\n",
      fprintf (stderr, "Read out of keyboard space (0x%" PRIxADDR ")!\n",
               addr);
               addr);
      return 0;
      return 0;
    }
    }
}
}
 
 
 
 
/* Simulation hook. Must be called every couple of clock cycles to simulate incomming data. */
/* Simulation hook. Must be called every couple of clock cycles to simulate incomming data. */
static void
static void
kbd_job (void *dat)
kbd_job (void *dat)
{
{
  struct kbd_state *kbd = dat;
  struct kbd_state *kbd = dat;
  int c;
  int c;
  int kbd_int = 0;
  int kbd_int = 0;
 
 
  /* Check if there is something waiting, and decode it into kdb_buf */
  /* Check if there is something waiting, and decode it into kdb_buf */
  if ((c = fgetc (kbd->rxfs)) != EOF)
  if ((c = fgetc (kbd->rxfs)) != EOF)
    {
    {
      scan_decode (kbd, c);
      scan_decode (kbd, c);
    }
    }
  kbd_int = kbd->kresp
  kbd_int = kbd->kresp
    || kbd->buf_count ? kbd->ccmdbyte & KBD_CCMDBYTE_INT : 0;
    || kbd->buf_count ? kbd->ccmdbyte & KBD_CCMDBYTE_INT : 0;
/*
/*
  if (config.sim.verbose && kbd_int)
  if (config.sim.verbose && kbd_int)
    PRINTF("Keyboard Interrupt.... kbd_kresp %lx  kbd_buf_count %lx \n",
    PRINTF("Keyboard Interrupt.... kbd_kresp %lx  kbd_buf_count %lx \n",
           kbd->kresp, kbd->buf_count);
           kbd->kresp, kbd->buf_count);
*/
*/
  if (kbd_int)
  if (kbd_int)
    report_interrupt (kbd->irq);
    report_interrupt (kbd->irq);
  SCHED_ADD (kbd_job, dat, kbd->slowdown);
  SCHED_ADD (kbd_job, dat, kbd->slowdown);
}
}
 
 
/* Reset all (simulated) ps2 controlers/keyboards */
/* Reset all (simulated) ps2 controlers/keyboards */
static void
static void
kbd_reset (void *dat)
kbd_reset (void *dat)
{
{
  struct kbd_state *kbd = dat;
  struct kbd_state *kbd = dat;
  long int system_kfreq =
  long int system_kfreq =
    (long) ((1000000000.0 / (double) config.sim.clkcycle_ps));
    (long) ((1000000000.0 / (double) config.sim.clkcycle_ps));
 
 
  system_kfreq = (system_kfreq < 1) ? 1 : system_kfreq;
  system_kfreq = (system_kfreq < 1) ? 1 : system_kfreq;
 
 
  kbd->buf_count = 0;
  kbd->buf_count = 0;
  kbd->buf_head = 0;
  kbd->buf_head = 0;
  kbd->buf_tail = 0;
  kbd->buf_tail = 0;
  kbd->kresp = 0x0;
  kbd->kresp = 0x0;
  kbd->ccmdbyte = 0x65;         /* We reset into default normal operation. */
  kbd->ccmdbyte = 0x65;         /* We reset into default normal operation. */
 
 
  if (!(kbd->rxfs = fopen (kbd->rxfile, "r"))
  if (!(kbd->rxfs = fopen (kbd->rxfile, "r"))
      && !(kbd->rxfs = fopen (kbd->rxfile, "r+")))
      && !(kbd->rxfs = fopen (kbd->rxfile, "r+")))
    {
    {
      /* Bug 1723 fixed: Clearer message */
      /* Bug 1723 fixed: Clearer message */
      fprintf (stderr,
      fprintf (stderr,
               "Warning: PS2 keyboard unable to open RX file stream.\n");
               "Warning: PS2 keyboard unable to open RX file stream.\n");
      return;
      return;
    }
    }
  kbd->slowdown = (long) ((system_kfreq * 1000.0) / KBD_BAUD_RATE);
  kbd->slowdown = (long) ((system_kfreq * 1000.0) / KBD_BAUD_RATE);
  if (kbd->slowdown <= 0)
  if (kbd->slowdown <= 0)
    kbd->slowdown = 1;
    kbd->slowdown = 1;
  SCHED_ADD (kbd_job, dat, kbd->slowdown);
  SCHED_ADD (kbd_job, dat, kbd->slowdown);
}
}
 
 
 
 
static void
static void
kbd_info (void *dat)
kbd_info (void *dat)
{
{
  struct kbd_state *kbd = dat;
  struct kbd_state *kbd = dat;
  PRINTF ("kbd_kcmd: %x\n", kbd->kcmd);
  PRINTF ("kbd_kcmd: %x\n", kbd->kcmd);
  PRINTF ("kbd_ccmd: %x\n", kbd->ccmd);
  PRINTF ("kbd_ccmd: %x\n", kbd->ccmd);
  PRINTF ("kbd_ccmdbyte: %x\n", kbd->ccmdbyte);
  PRINTF ("kbd_ccmdbyte: %x\n", kbd->ccmdbyte);
  PRINTF ("kbd_kresp: %lx\n", kbd->kresp);
  PRINTF ("kbd_kresp: %lx\n", kbd->kresp);
  PRINTF ("kbd_buf_count: %lx\n", kbd->buf_count);
  PRINTF ("kbd_buf_count: %lx\n", kbd->buf_count);
}
}
 
 
/*----------------------------------------------------[ KBD Configuration ]---*/
/*----------------------------------------------------[ KBD Configuration ]---*/
 
 
 
 
static void
static void
kbd_enabled (union param_val val, void *dat)
kbd_enabled (union param_val val, void *dat)
{
{
  struct kbd_state *kbd = dat;
  struct kbd_state *kbd = dat;
  kbd->enabled = val.int_val;
  kbd->enabled = val.int_val;
}
}
 
 
 
 
static void
static void
kbd_baseaddr (union param_val val, void *dat)
kbd_baseaddr (union param_val val, void *dat)
{
{
  struct kbd_state *kbd = dat;
  struct kbd_state *kbd = dat;
  kbd->baseaddr = val.addr_val;
  kbd->baseaddr = val.addr_val;
}
}
 
 
 
 
static void
static void
kbd_irq (union param_val val, void *dat)
kbd_irq (union param_val val, void *dat)
{
{
  struct kbd_state *kbd = dat;
  struct kbd_state *kbd = dat;
  kbd->irq = val.int_val;
  kbd->irq = val.int_val;
}
}
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Set the keyboard input file
/*!Set the keyboard input file
 
 
   Free any previously allocated value.
   Free any previously allocated value.
 
 
   @param[in] val  The value to use
   @param[in] val  The value to use
   @param[in] dat  The config data structure                                 */
   @param[in] dat  The config data structure                                 */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void
static void
kbd_rxfile (union param_val val, void *dat)
kbd_rxfile (union param_val val, void *dat)
{
{
  struct kbd_state *kbd = dat;
  struct kbd_state *kbd = dat;
 
 
  if (NULL != kbd->rxfile)
  if (NULL != kbd->rxfile)
    {
    {
      free (kbd->rxfile);
      free (kbd->rxfile);
      kbd->rxfile = NULL;
      kbd->rxfile = NULL;
    }
    }
 
 
  if (!(kbd->rxfile = strdup (val.str_val)))
  if (!(kbd->rxfile = strdup (val.str_val)))
    {
    {
      fprintf (stderr, "Peripheral KBD: Run out of memory\n");
      fprintf (stderr, "Peripheral KBD: Run out of memory\n");
      exit (-1);
      exit (-1);
    }
    }
}                               /* kbd_rxfile() */
}                               /* kbd_rxfile() */
 
 
 
 
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/*!Initialize a new keyboard configuration
/*!Initialize a new keyboard configuration
 
 
   ALL parameters are set explicitly to default values.                      */
   ALL parameters are set explicitly to default values.                      */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
static void *
static void *
kbd_sec_start ()
kbd_sec_start ()
{
{
  struct kbd_state *new = malloc (sizeof (struct kbd_state));
  struct kbd_state *new = malloc (sizeof (struct kbd_state));
 
 
  if (!new)
  if (!new)
    {
    {
      fprintf (stderr, "Peripheral KBD: Run out of memory\n");
      fprintf (stderr, "Peripheral KBD: Run out of memory\n");
      exit (-1);
      exit (-1);
    }
    }
 
 
  new->enabled = 1;
  new->enabled = 1;
  new->baseaddr = 0;
  new->baseaddr = 0;
  new->irq = 0;
  new->irq = 0;
  new->rxfile = strdup ("kbd_in");
  new->rxfile = strdup ("kbd_in");
 
 
  new->buf_count = 0;
  new->buf_count = 0;
  new->buf_head = 0;
  new->buf_head = 0;
  new->buf_tail = 0;
  new->buf_tail = 0;
  new->rxfs = NULL;
  new->rxfs = NULL;
 
 
  return new;
  return new;
 
 
}                               /* kbd_sec_start() */
}                               /* kbd_sec_start() */
 
 
 
 
static void
static void
kbd_sec_end (void *dat)
kbd_sec_end (void *dat)
{
{
  struct kbd_state *kbd = dat;
  struct kbd_state *kbd = dat;
  struct mem_ops ops;
  struct mem_ops ops;
 
 
  if (!kbd->enabled)
  if (!kbd->enabled)
    {
    {
      free (kbd->rxfile);
      free (kbd->rxfile);
      free (kbd);
      free (kbd);
      return;
      return;
    }
    }
 
 
  memset (&ops, 0, sizeof (struct mem_ops));
  memset (&ops, 0, sizeof (struct mem_ops));
 
 
  ops.readfunc8 = kbd_read8;
  ops.readfunc8 = kbd_read8;
  ops.writefunc8 = kbd_write8;
  ops.writefunc8 = kbd_write8;
  ops.read_dat8 = dat;
  ops.read_dat8 = dat;
  ops.write_dat8 = dat;
  ops.write_dat8 = dat;
 
 
  /* FIXME: Correct delay? */
  /* FIXME: Correct delay? */
  ops.delayr = 2;
  ops.delayr = 2;
  ops.delayw = 2;
  ops.delayw = 2;
 
 
  reg_mem_area (kbd->baseaddr, KBD_SPACE, 0, &ops);
  reg_mem_area (kbd->baseaddr, KBD_SPACE, 0, &ops);
  reg_sim_reset (kbd_reset, dat);
  reg_sim_reset (kbd_reset, dat);
  reg_sim_stat (kbd_info, dat);
  reg_sim_stat (kbd_info, dat);
}
}
 
 
void
void
reg_kbd_sec ()
reg_kbd_sec ()
{
{
  struct config_section *sec =
  struct config_section *sec =
    reg_config_sec ("kbd", kbd_sec_start, kbd_sec_end);
    reg_config_sec ("kbd", kbd_sec_start, kbd_sec_end);
 
 
  reg_config_param (sec, "baseaddr", paramt_addr, kbd_baseaddr);
  reg_config_param (sec, "baseaddr", PARAMT_ADDR, kbd_baseaddr);
  reg_config_param (sec, "enabled", paramt_int, kbd_enabled);
  reg_config_param (sec, "enabled",  PARAMT_INT, kbd_enabled);
  reg_config_param (sec, "irq", paramt_int, kbd_irq);
  reg_config_param (sec, "irq",      PARAMT_INT, kbd_irq);
  reg_config_param (sec, "rxfile", paramt_str, kbd_rxfile);
  reg_config_param (sec, "rxfile",   PARAMT_STR, kbd_rxfile);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.