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 1461

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 884 markom
      runtime.sim.cont_run = 0;
172 805 markom
      break;
173
  }
174
}
175
 
176
/* Read a register */
177 1359 nogj
uint32_t kbd_read8 (oraddr_t addr, void *dat)
178 805 markom
{
179 1371 nogj
  struct kbd_state *kbd = dat;
180
  int a = (addr - kbd->baseaddr);
181 805 markom
  switch (a) {
182 684 lampret
    case KBD_CTRL: {
183
      unsigned long c = 0x0;
184 1371 nogj
      if (kbd->kresp || kbd->buf_count)
185 684 lampret
        c |= KBD_STATUS_OBF;
186 1371 nogj
      c |= kbd->ccmdbyte & KBD_CCMDBYTE_SYS;
187 684 lampret
      c |= KBD_STATUS_INH;
188
      if (config.sim.verbose)
189 1350 nogj
        PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, c);
190 684 lampret
      return c;
191
    }
192
    case KBD_DATA:
193 1371 nogj
      if (kbd->ccmd) {
194 684 lampret
        unsigned long rc;
195 1371 nogj
        if (kbd->ccmd == KBD_CCMD_RCB)
196
          rc = kbd->ccmdbyte;
197
        if (kbd->ccmd == KBD_CCMD_ST1)
198 684 lampret
          rc = 0x55;
199 1371 nogj
        if (kbd->ccmd == KBD_CCMD_ST2)
200 684 lampret
          rc = 0x00;
201 1371 nogj
        kbd->ccmd = 0x00;
202
        kbd->kresp = 0x0;
203 684 lampret
        if (config.sim.verbose)
204 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, rc);
205 684 lampret
        return rc;
206
      }
207 1371 nogj
      else if (kbd->kresp) {
208 684 lampret
        unsigned long rc;
209 1371 nogj
        if (kbd->kresp == 0x2) {
210
          kbd->kresp = 0x0;
211 684 lampret
          rc = KBD_KRESP_RSTOK;
212 1371 nogj
        } else if (kbd->kcmd == KBD_KCMD_RST) {
213
          kbd->kresp = 0x2;
214 684 lampret
          rc = KBD_KRESP_ACK;
215 1371 nogj
        } else if (kbd->kcmd == KBD_KCMD_ECHO) {
216
          kbd->kresp = 0x0;
217 684 lampret
          rc = KBD_KRESP_ECHO;
218
        } else {
219 1371 nogj
          kbd->kresp = 0x0;
220 684 lampret
          rc = KBD_KRESP_ACK;
221
        }
222 1371 nogj
        kbd->kcmd = 0x00;
223 684 lampret
        if (config.sim.verbose)
224 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, rc);
225 684 lampret
        return rc;
226 1371 nogj
      } else if (kbd->buf_count) {
227
        unsigned long c = kbd->buf[kbd->buf_tail];
228
        kbd->buf_tail = (kbd->buf_tail + 1) % KBD_MAX_BUF;
229
        kbd->buf_count--;
230
        kbd->kresp = 0x0;
231 684 lampret
        if (config.sim.verbose)
232 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, c);
233 805 markom
        return c;
234
      }
235 1371 nogj
      kbd->kresp = 0x0;
236 684 lampret
      if (config.sim.verbose)
237 1350 nogj
        PRINTF("kbd_read8(%"PRIxADDR") fifo empty\n", addr);
238 805 markom
      return 0;
239
    default:
240 1350 nogj
      fprintf (stderr, "Read out of keyboard space (0x%"PRIxADDR")!\n", addr);
241 884 markom
      runtime.sim.cont_run = 0;
242 805 markom
      return 0;
243
  }
244
}
245
 
246
 
247
/* Simulation hook. Must be called every couple of clock cycles to simulate incomming data. */
248 1371 nogj
void kbd_job(void *dat)
249 805 markom
{
250 1371 nogj
  struct kbd_state *kbd = dat;
251 805 markom
  int c;
252
  int kbd_int = 0;
253 1371 nogj
 
254 805 markom
  /* Check if there is something waiting, and decode it into kdb_buf */
255 1371 nogj
  if((c = fgetc(kbd->rxfs)) != EOF) {
256
    scan_decode (kbd, c);
257 805 markom
  }
258 1371 nogj
  kbd_int = kbd->kresp || kbd->buf_count ? kbd->ccmdbyte & KBD_CCMDBYTE_INT : 0;
259 805 markom
  if (config.sim.verbose && kbd_int)
260 1308 phoenix
    PRINTF("Keyboard Interrupt.... kbd_kresp %lx  kbd_buf_count %lx \n",
261 1371 nogj
           kbd->kresp, kbd->buf_count);
262
  if (kbd_int) report_interrupt(kbd->irq);
263 1390 nogj
  SCHED_ADD(kbd_job, dat, kbd->slowdown);
264 805 markom
}
265
 
266 1350 nogj
/* Reset all (simulated) ps2 controlers/keyboards */
267 1371 nogj
void kbd_reset (void *dat)
268 805 markom
{
269 1371 nogj
  struct kbd_state *kbd = dat;
270
 
271
  kbd->buf_count = 0;
272
  kbd->buf_head = 0;
273
  kbd->buf_tail = 0;
274
  kbd->kresp = 0x0;
275
  kbd->ccmdbyte = 0x65; /* We reset into default normal operation. */
276 805 markom
 
277 1371 nogj
  if (!(kbd->rxfs = fopen(kbd->rxfile, "r"))
278
      && !(kbd->rxfs = fopen(kbd->rxfile, "r+"))) {
279 1446 nogj
    fprintf (stderr, "WARNING: Unable to open RX file stream.\n");
280 1371 nogj
    return;
281 805 markom
  }
282 1371 nogj
  kbd->slowdown = (long) ((config.sim.system_kfreq * 1000.) / KBD_BAUD_RATE);
283
  if (kbd->slowdown <= 0) kbd->slowdown = 1;
284 1390 nogj
  SCHED_ADD(kbd_job, dat, kbd->slowdown);
285 805 markom
}
286 684 lampret
 
287 805 markom
 
288 1371 nogj
void kbd_info(void *dat)
289 684 lampret
{
290 1371 nogj
  struct kbd_state *kbd = dat;
291
  PRINTF("kbd_kcmd: %x\n", kbd->kcmd);
292
  PRINTF("kbd_ccmd: %x\n", kbd->ccmd);
293
  PRINTF("kbd_ccmdbyte: %x\n", kbd->ccmdbyte);
294
  PRINTF("kbd_kresp: %lx\n", kbd->kresp);
295
  PRINTF("kbd_buf_count: %lx\n", kbd->buf_count);
296 684 lampret
}
297 1358 nogj
 
298
/*----------------------------------------------------[ KBD Configuration ]---*/
299
void kbd_baseaddr(union param_val val, void *dat)
300
{
301 1371 nogj
  struct kbd_state *kbd = dat;
302
  kbd->baseaddr = val.addr_val;
303 1358 nogj
}
304
 
305
void kbd_irq(union param_val val, void *dat)
306
{
307 1371 nogj
  struct kbd_state *kbd = dat;
308
  kbd->irq = val.int_val;
309 1358 nogj
}
310
 
311
void kbd_rxfile(union param_val val, void *dat)
312
{
313 1371 nogj
  struct kbd_state *kbd = dat;
314
  if(!(kbd->rxfile = strdup(val.str_val))) {
315
    fprintf(stderr, "Peripheral KBD: Run out of memory\n");
316
    exit(-1);
317
  }
318 1358 nogj
}
319
 
320 1461 nogj
void kbd_enabled(union param_val val, void *dat)
321
{
322
  struct kbd_state *kbd = dat;
323
  kbd->enabled = val.int_val;
324
}
325
 
326 1371 nogj
void *kbd_sec_start(void)
327
{
328
  struct kbd_state *new = malloc(sizeof(struct kbd_state));
329
 
330
  if(!new) {
331
    fprintf(stderr, "Peripheral KBD: Run out of memory\n");
332
    exit(-1);
333
  }
334
 
335
  new->buf_count = 0;
336
  new->buf_head = 0;
337
  new->buf_tail = 0;
338
  new->rxfs = NULL;
339 1461 nogj
  new->enabled = 1;
340 1371 nogj
 
341
  return new;
342
}
343
 
344
void kbd_sec_end(void *dat)
345
{
346
  struct kbd_state *kbd = dat;
347
 
348 1461 nogj
  if(!kbd->enabled) {
349
    free(dat);
350
    return;
351
  }
352
 
353 1371 nogj
  register_memoryarea(kbd->baseaddr, KBD_SPACE, 1, 0, kbd_read8, kbd_write8, dat);
354
  reg_sim_reset(kbd_reset, dat);
355
  reg_sim_stat(kbd_info, dat);
356
}
357
 
358 1358 nogj
void reg_kbd_sec(void)
359
{
360 1371 nogj
  struct config_section *sec = reg_config_sec("kbd", kbd_sec_start, kbd_sec_end);
361 1358 nogj
 
362 1461 nogj
  reg_config_param(sec, "baseaddr", paramt_addr, kbd_baseaddr);
363
  reg_config_param(sec, "enabled", paramt_int, kbd_enabled);
364 1358 nogj
  reg_config_param(sec, "irq", paramt_int, kbd_irq);
365
  reg_config_param(sec, "rxfile", paramt_str, kbd_rxfile);
366
}

powered by: WebSVN 2.1.0

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