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

Subversion Repositories or1k

[/] [or1k/] [branches/] [stable_0_2_x/] [or1ksim/] [peripheral/] [ps2kbd.c] - Blame information for rev 1469

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 805 markom
/* ps2kbd.c -- Very simple (and limited) PS/2 keyboard simulation
2
   Copyright (C) 2002 Marko Mlinar, markom@opencores.org
3 684 lampret
 
4 805 markom
This file is part of OpenRISC 1000 Architectural Simulator.
5
 
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
10
 
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
 
20
#include <stdlib.h>
21
#include <stdio.h>
22
#include <string.h>
23 1350 nogj
 
24
#include "config.h"
25
 
26
#ifdef HAVE_INTTYPES_H
27
#include <inttypes.h>
28
#endif
29
 
30
#include "port.h"
31
#include "arch.h"
32 805 markom
#include "ps2kbd.h"
33
#include "sim-config.h"
34
#include "abstract.h"
35
#include "sched.h"
36 1308 phoenix
#include "pic.h"
37 805 markom
 
38
/* ASCII to scan code conversion table */
39
const static struct {
40
  /* Whether shift must be pressed */
41
  unsigned char shift;
42
  /* Scan code to be generated */
43
  unsigned char code;
44
} scan_table [128] = {
45
/* 0 - 15 */
46
{0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
47
{0, 0x0E}, {0, 0x0F}, {0, 0x1C}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
48
/* 16 - 31 */
49
{0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
50
{0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x01}, {0, 0x00}, {0, 0x00}, {0, 0x00}, {0, 0x00},
51
/* 32 - 47 */
52
{0, 0x39}, {1, 0x02}, {1, 0x28}, {1, 0x04}, {1, 0x05}, {1, 0x06}, {1, 0x08}, {0, 0x28},
53
{1, 0x0A}, {1, 0x0B}, {1, 0x09}, {1, 0x0D}, {0, 0x33}, {0, 0x0C}, {0, 0x34}, {0, 0x35},
54
/* 48 - 63 */
55
{0, 0x0B}, {0, 0x02}, {0, 0x03}, {0, 0x04}, {0, 0x05}, {0, 0x06}, {0, 0x07}, {0, 0x08},
56
{0, 0x09}, {0, 0x0A}, {1, 0x27}, {0, 0x27}, {1, 0x33}, {0, 0x0D}, {1, 0x34}, {1, 0x35},
57
/* 64 - 79 */
58
{1, 0x03}, {1, 0x1E}, {1, 0x30}, {1, 0x2E}, {1, 0x20}, {1, 0x12}, {1, 0x21}, {1, 0x22},
59
{1, 0x23}, {1, 0x17}, {1, 0x24}, {1, 0x25}, {1, 0x26}, {1, 0x32}, {1, 0x31}, {1, 0x18},
60
/* 80 - 95 */
61
{1, 0x19}, {1, 0x10}, {1, 0x13}, {1, 0x1F}, {1, 0x14}, {1, 0x16}, {1, 0x2F}, {1, 0x11},
62
{1, 0x2D}, {1, 0x15}, {1, 0x2C}, {0, 0x1A}, {0, 0x2B}, {0, 0x1B}, {1, 0x07}, {1, 0x0C},
63
/* 96 - 111 */
64
{0, 0x29}, {0, 0x1E}, {0, 0x30}, {0, 0x2E}, {0, 0x20}, {0, 0x12}, {0, 0x21}, {0, 0x22},
65
{0, 0x23}, {0, 0x17}, {0, 0x24}, {0, 0x25}, {0, 0x26}, {0, 0x32}, {0, 0x31}, {0, 0x18},
66
/* 112 - 127 */
67
{0, 0x19}, {0, 0x10}, {0, 0x13}, {0, 0x1F}, {0, 0x14}, {0, 0x16}, {0, 0x2F}, {0, 0x11},
68
{0, 0x2D}, {0, 0x15}, {0, 0x2C}, {1, 0x1A}, {1, 0x2B}, {1, 0x1B}, {1, 0x29}, {0, 0x00}
69
};
70
 
71 1371 nogj
struct kbd_state {
72
  /* Temporary buffer to store incoming scan codes */
73
  uint8_t buf[KBD_MAX_BUF];
74 805 markom
 
75 1371 nogj
  /* Number of scan codes in buffer */
76
  unsigned long buf_count;
77
  unsigned long buf_head;
78
  unsigned long buf_tail;
79 805 markom
 
80 1371 nogj
  /* Input stream */
81
  FILE *rxfs;
82 805 markom
 
83 1371 nogj
  /* Controller Command (write into 0x64) */
84
  int ccmd;
85 684 lampret
 
86 1371 nogj
  /* Keyboard Command (write into 0x60) */
87
  uint8_t kcmd;
88 684 lampret
 
89 1371 nogj
  /* Controller Command Byte */
90
  uint8_t ccmdbyte;
91 684 lampret
 
92 1371 nogj
  /* Keyboard response pending */
93
  unsigned long kresp;
94 684 lampret
 
95 1371 nogj
  /* Keyboard slowdown factor */
96
  long slowdown;
97 805 markom
 
98 1371 nogj
  /* Cofiguration */
99 1461 nogj
  int enabled;
100 1371 nogj
  int irq;
101
  oraddr_t baseaddr;
102
  char *rxfile;
103
};
104
 
105
static void kbd_put (struct kbd_state *kbd, unsigned char c)
106 805 markom
{
107 1371 nogj
  if (kbd->buf_count >= KBD_MAX_BUF) {
108 805 markom
    fprintf (stderr, "WARNING: Keyboard buffer overflow.\n");
109
  } else {
110 1371 nogj
    kbd->buf[kbd->buf_head] = c;
111
    kbd->buf_head = (kbd->buf_head + 1) % KBD_MAX_BUF;
112
    kbd->buf_count++;
113 805 markom
  }
114
}
115
 
116
/* Decodes ascii code c into multiple scan codes, placed into buf, length is returned */
117 1371 nogj
static void scan_decode (struct kbd_state *kbd, unsigned char c)
118 805 markom
{
119
  /* Do not handle special characters and extended ascii */
120
  if (c >= 128 || !scan_table[c].code)
121
    return;
122
 
123
  /* Make shift? */
124 1371 nogj
  if (scan_table[c].shift) kbd_put (kbd, 0x2a);
125 805 markom
  /* Make char */
126 1371 nogj
  kbd_put (kbd, scan_table[c].code);
127 805 markom
  /* Break char */
128 1371 nogj
  kbd_put (kbd, scan_table[c].code | 0x80);
129 805 markom
  /* Break shift? */
130 1371 nogj
  if (scan_table[c].shift) kbd_put (kbd, 0xaa);
131 805 markom
}
132
 
133
/* Write a register */
134 1359 nogj
void kbd_write8 (oraddr_t addr, uint32_t value, void *dat)
135 805 markom
{
136 1371 nogj
  struct kbd_state *kbd = dat;
137
  int a = (addr - kbd->baseaddr);
138 805 markom
  switch (a) {
139 684 lampret
    case KBD_CTRL:
140 1371 nogj
      kbd->ccmd = value & 0xff;
141
      if (kbd->ccmd == KBD_CCMD_RCB)
142
          kbd->kresp = 0x1;
143
      if (kbd->ccmd == KBD_CCMD_ST1)
144
          kbd->kresp = 0x1;
145
      if (kbd->ccmd == KBD_CCMD_ST2)
146
          kbd->kresp = 0x1;
147
      if (kbd->ccmd == KBD_CCMD_DKI)
148
        kbd->ccmdbyte |= KBD_CCMDBYTE_EN;
149
      if (kbd->ccmd == KBD_CCMD_EKI)
150
        kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN;
151 684 lampret
      if (config.sim.verbose)
152 1350 nogj
        PRINTF("kbd_write8(%"PRIxADDR") %"PRIx32"\n", addr, value);
153 805 markom
      break;
154 684 lampret
    case KBD_DATA:
155 1371 nogj
      if (kbd->ccmd == KBD_CCMD_WCB) {
156
        kbd->ccmdbyte = value & 0xff;
157
        kbd->ccmd = 0x00;
158 684 lampret
      } else
159 1371 nogj
        kbd->kcmd = value & 0xff;
160
      if (kbd->kcmd == KBD_KCMD_DK)
161
        kbd->ccmdbyte |= KBD_CCMDBYTE_EN;
162
      if (kbd->kcmd == KBD_KCMD_EK)
163
        kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN;
164
      kbd->kresp = 0x1;
165
      kbd->ccmd = 0x00;
166 684 lampret
      if (config.sim.verbose)
167 1350 nogj
        PRINTF("kbd_write8(%"PRIxADDR") %"PRIx32"\n", addr, value);
168 805 markom
      break;
169
    default:
170 1350 nogj
      fprintf (stderr, "Write out of keyboard space (0x%"PRIxADDR")!\n", addr);
171 805 markom
      break;
172
  }
173
}
174
 
175
/* Read a register */
176 1359 nogj
uint32_t kbd_read8 (oraddr_t addr, void *dat)
177 805 markom
{
178 1371 nogj
  struct kbd_state *kbd = dat;
179
  int a = (addr - kbd->baseaddr);
180 805 markom
  switch (a) {
181 684 lampret
    case KBD_CTRL: {
182
      unsigned long c = 0x0;
183 1371 nogj
      if (kbd->kresp || kbd->buf_count)
184 684 lampret
        c |= KBD_STATUS_OBF;
185 1371 nogj
      c |= kbd->ccmdbyte & KBD_CCMDBYTE_SYS;
186 684 lampret
      c |= KBD_STATUS_INH;
187
      if (config.sim.verbose)
188 1350 nogj
        PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, c);
189 684 lampret
      return c;
190
    }
191
    case KBD_DATA:
192 1371 nogj
      if (kbd->ccmd) {
193 684 lampret
        unsigned long rc;
194 1371 nogj
        if (kbd->ccmd == KBD_CCMD_RCB)
195
          rc = kbd->ccmdbyte;
196
        if (kbd->ccmd == KBD_CCMD_ST1)
197 684 lampret
          rc = 0x55;
198 1371 nogj
        if (kbd->ccmd == KBD_CCMD_ST2)
199 684 lampret
          rc = 0x00;
200 1371 nogj
        kbd->ccmd = 0x00;
201
        kbd->kresp = 0x0;
202 684 lampret
        if (config.sim.verbose)
203 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, rc);
204 684 lampret
        return rc;
205
      }
206 1371 nogj
      else if (kbd->kresp) {
207 684 lampret
        unsigned long rc;
208 1371 nogj
        if (kbd->kresp == 0x2) {
209
          kbd->kresp = 0x0;
210 684 lampret
          rc = KBD_KRESP_RSTOK;
211 1371 nogj
        } else if (kbd->kcmd == KBD_KCMD_RST) {
212
          kbd->kresp = 0x2;
213 684 lampret
          rc = KBD_KRESP_ACK;
214 1371 nogj
        } else if (kbd->kcmd == KBD_KCMD_ECHO) {
215
          kbd->kresp = 0x0;
216 684 lampret
          rc = KBD_KRESP_ECHO;
217
        } else {
218 1371 nogj
          kbd->kresp = 0x0;
219 684 lampret
          rc = KBD_KRESP_ACK;
220
        }
221 1371 nogj
        kbd->kcmd = 0x00;
222 684 lampret
        if (config.sim.verbose)
223 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, rc);
224 684 lampret
        return rc;
225 1371 nogj
      } else if (kbd->buf_count) {
226
        unsigned long c = kbd->buf[kbd->buf_tail];
227
        kbd->buf_tail = (kbd->buf_tail + 1) % KBD_MAX_BUF;
228
        kbd->buf_count--;
229
        kbd->kresp = 0x0;
230 684 lampret
        if (config.sim.verbose)
231 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, c);
232 805 markom
        return c;
233
      }
234 1371 nogj
      kbd->kresp = 0x0;
235 684 lampret
      if (config.sim.verbose)
236 1350 nogj
        PRINTF("kbd_read8(%"PRIxADDR") fifo empty\n", addr);
237 805 markom
      return 0;
238
    default:
239 1350 nogj
      fprintf (stderr, "Read out of keyboard space (0x%"PRIxADDR")!\n", addr);
240 805 markom
      return 0;
241
  }
242
}
243
 
244
 
245
/* Simulation hook. Must be called every couple of clock cycles to simulate incomming data. */
246 1371 nogj
void kbd_job(void *dat)
247 805 markom
{
248 1371 nogj
  struct kbd_state *kbd = dat;
249 805 markom
  int c;
250
  int kbd_int = 0;
251 1371 nogj
 
252 805 markom
  /* Check if there is something waiting, and decode it into kdb_buf */
253 1371 nogj
  if((c = fgetc(kbd->rxfs)) != EOF) {
254
    scan_decode (kbd, c);
255 805 markom
  }
256 1371 nogj
  kbd_int = kbd->kresp || kbd->buf_count ? kbd->ccmdbyte & KBD_CCMDBYTE_INT : 0;
257 805 markom
  if (config.sim.verbose && kbd_int)
258 1308 phoenix
    PRINTF("Keyboard Interrupt.... kbd_kresp %lx  kbd_buf_count %lx \n",
259 1371 nogj
           kbd->kresp, kbd->buf_count);
260
  if (kbd_int) report_interrupt(kbd->irq);
261 1390 nogj
  SCHED_ADD(kbd_job, dat, kbd->slowdown);
262 805 markom
}
263
 
264 1350 nogj
/* Reset all (simulated) ps2 controlers/keyboards */
265 1371 nogj
void kbd_reset (void *dat)
266 805 markom
{
267 1371 nogj
  struct kbd_state *kbd = dat;
268
 
269
  kbd->buf_count = 0;
270
  kbd->buf_head = 0;
271
  kbd->buf_tail = 0;
272
  kbd->kresp = 0x0;
273
  kbd->ccmdbyte = 0x65; /* We reset into default normal operation. */
274 805 markom
 
275 1371 nogj
  if (!(kbd->rxfs = fopen(kbd->rxfile, "r"))
276
      && !(kbd->rxfs = fopen(kbd->rxfile, "r+"))) {
277 1446 nogj
    fprintf (stderr, "WARNING: Unable to open RX file stream.\n");
278 1371 nogj
    return;
279 805 markom
  }
280 1371 nogj
  kbd->slowdown = (long) ((config.sim.system_kfreq * 1000.) / KBD_BAUD_RATE);
281
  if (kbd->slowdown <= 0) kbd->slowdown = 1;
282 1390 nogj
  SCHED_ADD(kbd_job, dat, kbd->slowdown);
283 805 markom
}
284 684 lampret
 
285 805 markom
 
286 1371 nogj
void kbd_info(void *dat)
287 684 lampret
{
288 1371 nogj
  struct kbd_state *kbd = dat;
289
  PRINTF("kbd_kcmd: %x\n", kbd->kcmd);
290
  PRINTF("kbd_ccmd: %x\n", kbd->ccmd);
291
  PRINTF("kbd_ccmdbyte: %x\n", kbd->ccmdbyte);
292
  PRINTF("kbd_kresp: %lx\n", kbd->kresp);
293
  PRINTF("kbd_buf_count: %lx\n", kbd->buf_count);
294 684 lampret
}
295 1358 nogj
 
296
/*----------------------------------------------------[ KBD Configuration ]---*/
297
void kbd_baseaddr(union param_val val, void *dat)
298
{
299 1371 nogj
  struct kbd_state *kbd = dat;
300
  kbd->baseaddr = val.addr_val;
301 1358 nogj
}
302
 
303
void kbd_irq(union param_val val, void *dat)
304
{
305 1371 nogj
  struct kbd_state *kbd = dat;
306
  kbd->irq = val.int_val;
307 1358 nogj
}
308
 
309
void kbd_rxfile(union param_val val, void *dat)
310
{
311 1371 nogj
  struct kbd_state *kbd = dat;
312
  if(!(kbd->rxfile = strdup(val.str_val))) {
313
    fprintf(stderr, "Peripheral KBD: Run out of memory\n");
314
    exit(-1);
315
  }
316 1358 nogj
}
317
 
318 1461 nogj
void kbd_enabled(union param_val val, void *dat)
319
{
320
  struct kbd_state *kbd = dat;
321
  kbd->enabled = val.int_val;
322
}
323
 
324 1371 nogj
void *kbd_sec_start(void)
325
{
326
  struct kbd_state *new = malloc(sizeof(struct kbd_state));
327
 
328
  if(!new) {
329
    fprintf(stderr, "Peripheral KBD: Run out of memory\n");
330
    exit(-1);
331
  }
332
 
333
  new->buf_count = 0;
334
  new->buf_head = 0;
335
  new->buf_tail = 0;
336
  new->rxfs = NULL;
337 1461 nogj
  new->enabled = 1;
338 1371 nogj
 
339
  return new;
340
}
341
 
342
void kbd_sec_end(void *dat)
343
{
344
  struct kbd_state *kbd = dat;
345
 
346 1461 nogj
  if(!kbd->enabled) {
347
    free(dat);
348
    return;
349
  }
350
 
351 1371 nogj
  register_memoryarea(kbd->baseaddr, KBD_SPACE, 1, 0, kbd_read8, kbd_write8, dat);
352
  reg_sim_reset(kbd_reset, dat);
353
  reg_sim_stat(kbd_info, dat);
354
}
355
 
356 1358 nogj
void reg_kbd_sec(void)
357
{
358 1371 nogj
  struct config_section *sec = reg_config_sec("kbd", kbd_sec_start, kbd_sec_end);
359 1358 nogj
 
360 1461 nogj
  reg_config_param(sec, "baseaddr", paramt_addr, kbd_baseaddr);
361
  reg_config_param(sec, "enabled", paramt_int, kbd_enabled);
362 1358 nogj
  reg_config_param(sec, "irq", paramt_int, kbd_irq);
363
  reg_config_param(sec, "rxfile", paramt_str, kbd_rxfile);
364
}

powered by: WebSVN 2.1.0

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