Line 66... |
Line 66... |
/* 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 {
|
/* Temporary buffer to store incoming scan codes */
|
/* Temporary buffer to store incoming scan codes */
|
static unsigned char kbd_buf[KBD_MAX_BUF] = {0};
|
uint8_t buf[KBD_MAX_BUF];
|
|
|
/* Number of scan codes in buffer */
|
/* Number of scan codes in buffer */
|
static unsigned long kbd_buf_count = 0;
|
unsigned long buf_count;
|
static unsigned long kbd_buf_head = 0;
|
unsigned long buf_head;
|
static unsigned long kbd_buf_tail = 0;
|
unsigned long buf_tail;
|
|
|
/* Input stream */
|
/* Input stream */
|
static FILE *kbd_rxfs = NULL;
|
FILE *rxfs;
|
|
|
/* Controller Command (write into 0x64) */
|
/* Controller Command (write into 0x64) */
|
static int kbd_ccmd;
|
int ccmd;
|
|
|
/* Keyboard Command (write into 0x60) */
|
/* Keyboard Command (write into 0x60) */
|
static unsigned char kbd_kcmd;
|
uint8_t kcmd;
|
|
|
/* Controller Command Byte */
|
/* Controller Command Byte */
|
static unsigned char kbd_ccmdbyte;
|
uint8_t ccmdbyte;
|
|
|
/* Keyboard response pending */
|
/* Keyboard response pending */
|
static unsigned long kbd_kresp;
|
unsigned long kresp;
|
|
|
/* Keyboard slowdown factor */
|
/* Keyboard slowdown factor */
|
static long kbd_slowdown;
|
long slowdown;
|
|
|
static void kbd_put (unsigned char c)
|
/* Cofiguration */
|
|
int irq;
|
|
oraddr_t baseaddr;
|
|
char *rxfile;
|
|
};
|
|
|
|
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 (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 (0x2a);
|
if (scan_table[c].shift) kbd_put (kbd, 0x2a);
|
/* Make char */
|
/* Make char */
|
kbd_put (scan_table[c].code);
|
kbd_put (kbd, scan_table[c].code);
|
/* Break char */
|
/* Break char */
|
kbd_put (scan_table[c].code | 0x80);
|
kbd_put (kbd, scan_table[c].code | 0x80);
|
/* Break shift? */
|
/* Break shift? */
|
if (scan_table[c].shift) kbd_put (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)
|
{
|
{
|
int a = (addr - config.kbd.baseaddr);
|
struct kbd_state *kbd = dat;
|
|
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);
|
Line 165... |
Line 173... |
}
|
}
|
|
|
/* Read a register */
|
/* Read a register */
|
uint32_t kbd_read8 (oraddr_t addr, void *dat)
|
uint32_t kbd_read8 (oraddr_t addr, void *dat)
|
{
|
{
|
int a = (addr - config.kbd.baseaddr);
|
struct kbd_state *kbd = dat;
|
|
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);
|
Line 233... |
Line 242... |
}
|
}
|
}
|
}
|
|
|
|
|
/* 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(int param)
|
void kbd_job(void *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 (c);
|
scan_decode (kbd, c);
|
}
|
}
|
kbd_int = kbd_kresp || kbd_buf_count;
|
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(config.kbd.irq);
|
if (kbd_int) report_interrupt(kbd->irq);
|
SCHED_ADD(kbd_job, 0, runtime.sim.cycles + kbd_slowdown);
|
SCHED_ADD(kbd_job, dat, runtime.sim.cycles + kbd->slowdown);
|
}
|
}
|
|
|
/* Reset all (simulated) ps2 controlers/keyboards */
|
/* Reset all (simulated) ps2 controlers/keyboards */
|
void kbd_reset ()
|
void kbd_reset (void *dat)
|
{
|
{
|
if (config.kbd.enabled) {
|
struct kbd_state *kbd = dat;
|
kbd_buf_count = 0;
|
|
kbd_buf_head = 0;
|
|
kbd_buf_tail = 0;
|
|
kbd_kresp = 0x0;
|
|
kbd_ccmdbyte = 0x65; /* We reset into default normal operation. */
|
|
register_memoryarea(config.kbd.baseaddr, KBD_SPACE, 1, 0, kbd_read8, kbd_write8, NULL);
|
|
|
|
if (!(kbd_rxfs = fopen(config.kbd.rxfile, "r"))
|
kbd->buf_count = 0;
|
&& !(kbd_rxfs = fopen(config.kbd.rxfile, "r+"))) {
|
kbd->buf_head = 0;
|
|
kbd->buf_tail = 0;
|
|
kbd->kresp = 0x0;
|
|
kbd->ccmdbyte = 0x65; /* We reset into default normal operation. */
|
|
|
|
if (!(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");
|
config.kbd.enabled = 0;
|
return;
|
}
|
|
kbd_slowdown = (long) ((config.sim.system_kfreq * 1000.) / KBD_BAUD_RATE);
|
|
if (kbd_slowdown <= 0) kbd_slowdown = 1;
|
|
if (config.kbd.enabled) SCHED_ADD(kbd_job, 0, runtime.sim.cycles + kbd_slowdown);
|
|
}
|
}
|
|
kbd->slowdown = (long) ((config.sim.system_kfreq * 1000.) / KBD_BAUD_RATE);
|
|
if (kbd->slowdown <= 0) kbd->slowdown = 1;
|
|
SCHED_ADD(kbd_job, dat, runtime.sim.cycles + kbd->slowdown);
|
}
|
}
|
|
|
|
|
void kbd_info()
|
void kbd_info(void *dat)
|
{
|
{
|
PRINTF("kbd_kcmd: %x\n", kbd_kcmd);
|
struct kbd_state *kbd = dat;
|
PRINTF("kbd_ccmd: %x\n", kbd_ccmd);
|
PRINTF("kbd_kcmd: %x\n", kbd->kcmd);
|
PRINTF("kbd_ccmdbyte: %x\n", kbd_ccmdbyte);
|
PRINTF("kbd_ccmd: %x\n", kbd->ccmd);
|
PRINTF("kbd_kresp: %lx\n", kbd_kresp);
|
PRINTF("kbd_ccmdbyte: %x\n", kbd->ccmdbyte);
|
PRINTF("kbd_buf_count: %lx\n", kbd_buf_count);
|
PRINTF("kbd_kresp: %lx\n", kbd->kresp);
|
|
PRINTF("kbd_buf_count: %lx\n", kbd->buf_count);
|
}
|
}
|
|
|
/*----------------------------------------------------[ KBD Configuration ]---*/
|
/*----------------------------------------------------[ KBD Configuration ]---*/
|
void kbd_enabled(union param_val val, void *dat)
|
|
{
|
|
config.kbd.enabled = val.int_val;
|
|
}
|
|
|
|
void kbd_baseaddr(union param_val val, void *dat)
|
void kbd_baseaddr(union param_val val, void *dat)
|
{
|
{
|
config.kbd.baseaddr = val.addr_val;
|
struct kbd_state *kbd = dat;
|
|
kbd->baseaddr = val.addr_val;
|
}
|
}
|
|
|
void kbd_irq(union param_val val, void *dat)
|
void kbd_irq(union param_val val, void *dat)
|
{
|
{
|
config.kbd.irq = val.int_val;
|
struct kbd_state *kbd = dat;
|
|
kbd->irq = val.int_val;
|
}
|
}
|
|
|
void kbd_rxfile(union param_val val, void *dat)
|
void kbd_rxfile(union param_val val, void *dat)
|
{
|
{
|
strcpy(config.kbd.rxfile, val.str_val);
|
struct kbd_state *kbd = dat;
|
|
if(!(kbd->rxfile = strdup(val.str_val))) {
|
|
fprintf(stderr, "Peripheral KBD: Run out of memory\n");
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
void *kbd_sec_start(void)
|
|
{
|
|
struct kbd_state *new = malloc(sizeof(struct kbd_state));
|
|
|
|
if(!new) {
|
|
fprintf(stderr, "Peripheral KBD: Run out of memory\n");
|
|
exit(-1);
|
|
}
|
|
|
|
new->buf_count = 0;
|
|
new->buf_head = 0;
|
|
new->buf_tail = 0;
|
|
new->rxfs = NULL;
|
|
|
|
return new;
|
|
}
|
|
|
|
void kbd_sec_end(void *dat)
|
|
{
|
|
struct kbd_state *kbd = dat;
|
|
|
|
register_memoryarea(kbd->baseaddr, KBD_SPACE, 1, 0, kbd_read8, kbd_write8, dat);
|
|
reg_sim_reset(kbd_reset, 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", NULL, NULL);
|
struct config_section *sec = reg_config_sec("kbd", kbd_sec_start, kbd_sec_end);
|
|
|
reg_config_param(sec, "enabled", paramt_int, kbd_enabled);
|
|
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);
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|