/* 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
|
|
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
|
|
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
(at your option) any later version.
|
(at your option) any later version.
|
|
|
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU General Public License for more details.
|
GNU General Public License for more details.
|
|
|
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <string.h>
|
#include <string.h>
|
|
|
#include "config.h"
|
#include "config.h"
|
|
|
#ifdef HAVE_INTTYPES_H
|
#ifdef HAVE_INTTYPES_H
|
#include <inttypes.h>
|
#include <inttypes.h>
|
#endif
|
#endif
|
|
|
#include "port.h"
|
#include "port.h"
|
#include "arch.h"
|
#include "arch.h"
|
#include "ps2kbd.h"
|
#include "ps2kbd.h"
|
#include "sim-config.h"
|
#include "sim-config.h"
|
#include "abstract.h"
|
#include "abstract.h"
|
#include "sched.h"
|
#include "sched.h"
|
#include "pic.h"
|
#include "pic.h"
|
|
|
/* 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, 0x0F}, {0, 0x1C}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
|
{0, 0x0E}, {0, 0x0F}, {0, 0x1C}, {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, 0x01}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
|
{0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x01}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
|
/* 32 - 47 */
|
/* 32 - 47 */
|
{0, 0x39}, {1, 0x02}, {1, 0x28}, {1, 0x04}, {1, 0x05}, {1, 0x06}, {1, 0x08}, {0, 0x28},
|
{0, 0x39}, {1, 0x02}, {1, 0x28}, {1, 0x04}, {1, 0x05}, {1, 0x06}, {1, 0x08}, {0, 0x28},
|
{1, 0x0A}, {1, 0x0B}, {1, 0x09}, {1, 0x0D}, {0, 0x33}, {0, 0x0C}, {0, 0x34}, {0, 0x35},
|
{1, 0x0A}, {1, 0x0B}, {1, 0x09}, {1, 0x0D}, {0, 0x33}, {0, 0x0C}, {0, 0x34}, {0, 0x35},
|
/* 48 - 63 */
|
/* 48 - 63 */
|
{0, 0x0B}, {0, 0x02}, {0, 0x03}, {0, 0x04}, {0, 0x05}, {0, 0x06}, {0, 0x07}, {0, 0x08},
|
{0, 0x0B}, {0, 0x02}, {0, 0x03}, {0, 0x04}, {0, 0x05}, {0, 0x06}, {0, 0x07}, {0, 0x08},
|
{0, 0x09}, {0, 0x0A}, {1, 0x27}, {0, 0x27}, {1, 0x33}, {0, 0x0D}, {1, 0x34}, {1, 0x35},
|
{0, 0x09}, {0, 0x0A}, {1, 0x27}, {0, 0x27}, {1, 0x33}, {0, 0x0D}, {1, 0x34}, {1, 0x35},
|
/* 64 - 79 */
|
/* 64 - 79 */
|
{1, 0x03}, {1, 0x1E}, {1, 0x30}, {1, 0x2E}, {1, 0x20}, {1, 0x12}, {1, 0x21}, {1, 0x22},
|
{1, 0x03}, {1, 0x1E}, {1, 0x30}, {1, 0x2E}, {1, 0x20}, {1, 0x12}, {1, 0x21}, {1, 0x22},
|
{1, 0x23}, {1, 0x17}, {1, 0x24}, {1, 0x25}, {1, 0x26}, {1, 0x32}, {1, 0x31}, {1, 0x18},
|
{1, 0x23}, {1, 0x17}, {1, 0x24}, {1, 0x25}, {1, 0x26}, {1, 0x32}, {1, 0x31}, {1, 0x18},
|
/* 80 - 95 */
|
/* 80 - 95 */
|
{1, 0x19}, {1, 0x10}, {1, 0x13}, {1, 0x1F}, {1, 0x14}, {1, 0x16}, {1, 0x2F}, {1, 0x11},
|
{1, 0x19}, {1, 0x10}, {1, 0x13}, {1, 0x1F}, {1, 0x14}, {1, 0x16}, {1, 0x2F}, {1, 0x11},
|
{1, 0x2D}, {1, 0x15}, {1, 0x2C}, {0, 0x1A}, {0, 0x2B}, {0, 0x1B}, {1, 0x07}, {1, 0x0C},
|
{1, 0x2D}, {1, 0x15}, {1, 0x2C}, {0, 0x1A}, {0, 0x2B}, {0, 0x1B}, {1, 0x07}, {1, 0x0C},
|
/* 96 - 111 */
|
/* 96 - 111 */
|
{0, 0x29}, {0, 0x1E}, {0, 0x30}, {0, 0x2E}, {0, 0x20}, {0, 0x12}, {0, 0x21}, {0, 0x22},
|
{0, 0x29}, {0, 0x1E}, {0, 0x30}, {0, 0x2E}, {0, 0x20}, {0, 0x12}, {0, 0x21}, {0, 0x22},
|
{0, 0x23}, {0, 0x17}, {0, 0x24}, {0, 0x25}, {0, 0x26}, {0, 0x32}, {0, 0x31}, {0, 0x18},
|
{0, 0x23}, {0, 0x17}, {0, 0x24}, {0, 0x25}, {0, 0x26}, {0, 0x32}, {0, 0x31}, {0, 0x18},
|
/* 112 - 127 */
|
/* 112 - 127 */
|
{0, 0x19}, {0, 0x10}, {0, 0x13}, {0, 0x1F}, {0, 0x14}, {0, 0x16}, {0, 0x2F}, {0, 0x11},
|
{0, 0x19}, {0, 0x10}, {0, 0x13}, {0, 0x1F}, {0, 0x14}, {0, 0x16}, {0, 0x2F}, {0, 0x11},
|
{0, 0x2D}, {0, 0x15}, {0, 0x2C}, {1, 0x1A}, {1, 0x2B}, {1, 0x1B}, {1, 0x29}, {0, 0x00}
|
{0, 0x2D}, {0, 0x15}, {0, 0x2C}, {1, 0x1A}, {1, 0x2B}, {1, 0x1B}, {1, 0x29}, {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 irq;
|
int irq;
|
oraddr_t baseaddr;
|
oraddr_t baseaddr;
|
char *rxfile;
|
char *rxfile;
|
};
|
};
|
|
|
static void kbd_put (struct kbd_state *kbd, unsigned char c)
|
static void 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 scan_decode (struct kbd_state *kbd, unsigned char c)
|
static void 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) kbd_put (kbd, 0x2a);
|
if (scan_table[c].shift) 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) kbd_put (kbd, 0xaa);
|
if (scan_table[c].shift) kbd_put (kbd, 0xaa);
|
}
|
}
|
|
|
/* Write a register */
|
/* Write a register */
|
void kbd_write8 (oraddr_t addr, uint32_t value, void *dat)
|
void kbd_write8 (oraddr_t addr, uint32_t value, void *dat)
|
{
|
{
|
struct kbd_state *kbd = dat;
|
struct kbd_state *kbd = dat;
|
int a = (addr - kbd->baseaddr);
|
int a = (addr - kbd->baseaddr);
|
switch (a) {
|
switch (a) {
|
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)
|
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") %"PRIx32"\n", addr, value);
|
PRINTF("kbd_write8(%"PRIxADDR") %"PRIx32"\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") %"PRIx32"\n", addr, value);
|
PRINTF("kbd_write8(%"PRIxADDR") %"PRIx32"\n", addr, value);
|
break;
|
break;
|
default:
|
default:
|
fprintf (stderr, "Write out of keyboard space (0x%"PRIxADDR")!\n", addr);
|
fprintf (stderr, "Write out of keyboard space (0x%"PRIxADDR")!\n", addr);
|
runtime.sim.cont_run = 0;
|
runtime.sim.cont_run = 0;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
/* Read a register */
|
/* Read a register */
|
uint32_t kbd_read8 (oraddr_t addr, void *dat)
|
uint32_t kbd_read8 (oraddr_t addr, void *dat)
|
{
|
{
|
struct kbd_state *kbd = dat;
|
struct kbd_state *kbd = dat;
|
int a = (addr - kbd->baseaddr);
|
int a = (addr - kbd->baseaddr);
|
switch (a) {
|
switch (a) {
|
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:
|
if (kbd->ccmd) {
|
if (kbd->ccmd) {
|
unsigned long rc;
|
unsigned long rc;
|
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", addr);
|
fprintf (stderr, "Read out of keyboard space (0x%"PRIxADDR")!\n", addr);
|
runtime.sim.cont_run = 0;
|
runtime.sim.cont_run = 0;
|
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. */
|
void kbd_job(void *dat)
|
void 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->buf_count ? kbd->ccmdbyte & KBD_CCMDBYTE_INT : 0;
|
kbd_int = kbd->kresp || 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) report_interrupt(kbd->irq);
|
if (kbd_int) report_interrupt(kbd->irq);
|
SCHED_ADD(kbd_job, dat, runtime.sim.cycles + kbd->slowdown);
|
SCHED_ADD(kbd_job, dat, kbd->slowdown);
|
}
|
}
|
|
|
/* Reset all (simulated) ps2 controlers/keyboards */
|
/* Reset all (simulated) ps2 controlers/keyboards */
|
void kbd_reset (void *dat)
|
void kbd_reset (void *dat)
|
{
|
{
|
struct kbd_state *kbd = dat;
|
struct kbd_state *kbd = dat;
|
|
|
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+"))) {
|
fprintf (stderr, "WARNING: Keyboard has problems with RX file stream.\n");
|
fprintf (stderr, "WARNING: Keyboard has problems with RX file stream.\n");
|
return;
|
return;
|
}
|
}
|
kbd->slowdown = (long) ((config.sim.system_kfreq * 1000.) / KBD_BAUD_RATE);
|
kbd->slowdown = (long) ((config.sim.system_kfreq * 1000.) / KBD_BAUD_RATE);
|
if (kbd->slowdown <= 0) kbd->slowdown = 1;
|
if (kbd->slowdown <= 0) kbd->slowdown = 1;
|
SCHED_ADD(kbd_job, dat, runtime.sim.cycles + kbd->slowdown);
|
SCHED_ADD(kbd_job, dat, kbd->slowdown);
|
}
|
}
|
|
|
|
|
void kbd_info(void *dat)
|
void 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 ]---*/
|
void kbd_baseaddr(union param_val val, void *dat)
|
void 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;
|
}
|
}
|
|
|
void kbd_irq(union param_val val, void *dat)
|
void 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;
|
}
|
}
|
|
|
void kbd_rxfile(union param_val val, void *dat)
|
void kbd_rxfile(union param_val val, void *dat)
|
{
|
{
|
struct kbd_state *kbd = dat;
|
struct kbd_state *kbd = dat;
|
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);
|
}
|
}
|
}
|
}
|
|
|
void *kbd_sec_start(void)
|
void *kbd_sec_start(void)
|
{
|
{
|
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->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;
|
}
|
}
|
|
|
void kbd_sec_end(void *dat)
|
void kbd_sec_end(void *dat)
|
{
|
{
|
struct kbd_state *kbd = dat;
|
struct kbd_state *kbd = dat;
|
|
|
register_memoryarea(kbd->baseaddr, KBD_SPACE, 1, 0, kbd_read8, kbd_write8, dat);
|
register_memoryarea(kbd->baseaddr, KBD_SPACE, 1, 0, kbd_read8, kbd_write8, dat);
|
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 reg_kbd_sec(void)
|
void reg_kbd_sec(void)
|
{
|
{
|
struct config_section *sec = reg_config_sec("kbd", kbd_sec_start, kbd_sec_end);
|
struct config_section *sec = reg_config_sec("kbd", kbd_sec_start, kbd_sec_end);
|
|
|
reg_config_param(sec, "baseaddr", paramt_int, kbd_baseaddr);
|
reg_config_param(sec, "baseaddr", paramt_int, kbd_baseaddr);
|
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);
|
}
|
}
|
|
|