URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [tags/] [nog_patch_68/] [or1ksim/] [peripheral/] [ps2kbd.c] - Rev 670
Go to most recent revision | Compare with Previous | Blame | View Log
/* ps2kbd.c -- Very simple (and limited) PS/2 keyboard simulation Copyright (C) 2002 Marko Mlinar, markom@opencores.org This file is part of OpenRISC 1000 Architectural Simulator. 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 Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include "ps2kbd.h" #include "sim-config.h" #include "abstract.h" /* ASCII to scan code conversion table */ const static struct { /* Whether shift must be pressed */ unsigned char shift; /* Scan code to be generated */ unsigned char code; } scan_table [128] = { /* 0 - 15 */ {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}, /* 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, 0x01}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, /* 32 - 47 */ {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}, /* 48 - 63 */ {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}, /* 64 - 79 */ {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}, /* 80 - 95 */ {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}, /* 96 - 111 */ {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}, /* 112 - 127 */ {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} }; /* Temporary buffer to store incoming scan codes */ static unsigned char kbd_buf[KBD_MAX_BUF] = {0}; /* Number of scan codes in buffer */ static unsigned long kbd_buf_count = 0; static unsigned long kbd_buf_head = 0; static unsigned long kbd_buf_tail = 0; /* Input stream */ static FILE *kbd_rxfs = NULL; static void kbd_put (unsigned char c) { if (kbd_buf_count >= KBD_MAX_BUF) { fprintf (stderr, "WARNING: Keyboard buffer overflow.\n"); } else { kbd_buf[kbd_buf_head] = c; kbd_buf_head = (kbd_buf_head + 1) % KBD_MAX_BUF; kbd_buf_count++; } } /* Decodes ascii code c into multiple scan codes, placed into buf, length is returned */ static void scan_decode (unsigned char c) { /* Do not handle special characters and extended ascii */ if (c >= 128 || !scan_table[c].code) return; /* Make shift? */ if (scan_table[c].shift) kbd_put (0x2a); /* Make char */ kbd_put (scan_table[c].code); /* Break char */ kbd_put (scan_table[c].code | 0x80); /* Break shift? */ if (scan_table[c].shift) kbd_put (0xaa); } /* Write a register */ void kbd_write8 (unsigned long addr, unsigned long value) { int a = (addr - config.kbd.baseaddr); switch (a) { case KBD_CTRL: break; case KBD_DATA: break; default: fprintf (stderr, "Write out of keyboard space (0x%08x)!\n", addr); cont_run = 0; break; } } /* Read a register */ unsigned long kbd_read8 (unsigned long addr) { int a = (addr - config.kbd.baseaddr); switch (a) { case KBD_CTRL: return 0; break; case KBD_DATA: if (kbd_buf_count) { unsigned long c = kbd_buf[kbd_buf_tail]; kbd_buf_tail = (kbd_buf_tail + 1) % KBD_MAX_BUF; kbd_buf_count--; return c; } return 0; default: fprintf (stderr, "Read out of keyboard space (0x%08x)!\n", addr); cont_run = 0; return 0; } } /* Reset all VGAs */ void kbd_reset () { if (config.kbd.enabled) { kbd_buf_count = 0; kbd_buf_head = 0; kbd_buf_tail = 0; register_memoryarea(config.kbd.baseaddr, KBD_SPACE, 1, kbd_read8, kbd_write8); if (!(kbd_rxfs = fopen(config.kbd.rxfile, "r")) && !(kbd_rxfs = fopen(config.kbd.rxfile, "r+"))) { fprintf (stderr, "WARNING: Keyboard has problems with RX file stream.\n"); } } } /* Simulation hook. Must be called every clock cycle to simulate incomming data. */ void kbd_clock() { int c; /* Check if there is something waiting, and decode it into kdb_buf */ if((c = fgetc(kbd_rxfs)) != EOF) { scan_decode (c); } if (kbd_buf_count) report_interrupt(config.kbd.irq); }
Go to most recent revision | Compare with Previous | Blame | View Log