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 1765

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 1557 nogj
void kbd_write8 (oraddr_t addr, uint8_t value, void *dat)
135 805 markom
{
136 1371 nogj
  struct kbd_state *kbd = dat;
137 1486 nogj
  switch (addr) {
138 684 lampret
    case KBD_CTRL:
139 1371 nogj
      kbd->ccmd = value & 0xff;
140
      if (kbd->ccmd == KBD_CCMD_RCB)
141
          kbd->kresp = 0x1;
142
      if (kbd->ccmd == KBD_CCMD_ST1)
143
          kbd->kresp = 0x1;
144
      if (kbd->ccmd == KBD_CCMD_ST2)
145
          kbd->kresp = 0x1;
146
      if (kbd->ccmd == KBD_CCMD_DKI)
147
        kbd->ccmdbyte |= KBD_CCMDBYTE_EN;
148
      if (kbd->ccmd == KBD_CCMD_EKI)
149
        kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN;
150 684 lampret
      if (config.sim.verbose)
151 1350 nogj
        PRINTF("kbd_write8(%"PRIxADDR") %"PRIx32"\n", addr, value);
152 805 markom
      break;
153 684 lampret
    case KBD_DATA:
154 1371 nogj
      if (kbd->ccmd == KBD_CCMD_WCB) {
155
        kbd->ccmdbyte = value & 0xff;
156
        kbd->ccmd = 0x00;
157 684 lampret
      } else
158 1371 nogj
        kbd->kcmd = value & 0xff;
159
      if (kbd->kcmd == KBD_KCMD_DK)
160
        kbd->ccmdbyte |= KBD_CCMDBYTE_EN;
161
      if (kbd->kcmd == KBD_KCMD_EK)
162
        kbd->ccmdbyte &= ~KBD_CCMDBYTE_EN;
163
      kbd->kresp = 0x1;
164
      kbd->ccmd = 0x00;
165 684 lampret
      if (config.sim.verbose)
166 1350 nogj
        PRINTF("kbd_write8(%"PRIxADDR") %"PRIx32"\n", addr, value);
167 805 markom
      break;
168
    default:
169 1350 nogj
      fprintf (stderr, "Write out of keyboard space (0x%"PRIxADDR")!\n", addr);
170 805 markom
      break;
171
  }
172
}
173
 
174
/* Read a register */
175 1557 nogj
uint8_t kbd_read8 (oraddr_t addr, void *dat)
176 805 markom
{
177 1371 nogj
  struct kbd_state *kbd = dat;
178 1486 nogj
  switch (addr) {
179 684 lampret
    case KBD_CTRL: {
180
      unsigned long c = 0x0;
181 1371 nogj
      if (kbd->kresp || kbd->buf_count)
182 684 lampret
        c |= KBD_STATUS_OBF;
183 1371 nogj
      c |= kbd->ccmdbyte & KBD_CCMDBYTE_SYS;
184 684 lampret
      c |= KBD_STATUS_INH;
185
      if (config.sim.verbose)
186 1350 nogj
        PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, c);
187 684 lampret
      return c;
188
    }
189
    case KBD_DATA:
190 1371 nogj
      if (kbd->ccmd) {
191 1557 nogj
        unsigned long rc = 0;
192 1371 nogj
        if (kbd->ccmd == KBD_CCMD_RCB)
193
          rc = kbd->ccmdbyte;
194
        if (kbd->ccmd == KBD_CCMD_ST1)
195 684 lampret
          rc = 0x55;
196 1371 nogj
        if (kbd->ccmd == KBD_CCMD_ST2)
197 684 lampret
          rc = 0x00;
198 1371 nogj
        kbd->ccmd = 0x00;
199
        kbd->kresp = 0x0;
200 684 lampret
        if (config.sim.verbose)
201 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, rc);
202 684 lampret
        return rc;
203
      }
204 1371 nogj
      else if (kbd->kresp) {
205 684 lampret
        unsigned long rc;
206 1371 nogj
        if (kbd->kresp == 0x2) {
207
          kbd->kresp = 0x0;
208 684 lampret
          rc = KBD_KRESP_RSTOK;
209 1371 nogj
        } else if (kbd->kcmd == KBD_KCMD_RST) {
210
          kbd->kresp = 0x2;
211 684 lampret
          rc = KBD_KRESP_ACK;
212 1371 nogj
        } else if (kbd->kcmd == KBD_KCMD_ECHO) {
213
          kbd->kresp = 0x0;
214 684 lampret
          rc = KBD_KRESP_ECHO;
215
        } else {
216 1371 nogj
          kbd->kresp = 0x0;
217 684 lampret
          rc = KBD_KRESP_ACK;
218
        }
219 1371 nogj
        kbd->kcmd = 0x00;
220 684 lampret
        if (config.sim.verbose)
221 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, rc);
222 684 lampret
        return rc;
223 1371 nogj
      } else if (kbd->buf_count) {
224
        unsigned long c = kbd->buf[kbd->buf_tail];
225
        kbd->buf_tail = (kbd->buf_tail + 1) % KBD_MAX_BUF;
226
        kbd->buf_count--;
227
        kbd->kresp = 0x0;
228 684 lampret
        if (config.sim.verbose)
229 1350 nogj
          PRINTF("kbd_read8(%"PRIxADDR") %lx\n", addr, c);
230 805 markom
        return c;
231
      }
232 1371 nogj
      kbd->kresp = 0x0;
233 684 lampret
      if (config.sim.verbose)
234 1350 nogj
        PRINTF("kbd_read8(%"PRIxADDR") fifo empty\n", addr);
235 805 markom
      return 0;
236
    default:
237 1350 nogj
      fprintf (stderr, "Read out of keyboard space (0x%"PRIxADDR")!\n", addr);
238 805 markom
      return 0;
239
  }
240
}
241
 
242
 
243
/* Simulation hook. Must be called every couple of clock cycles to simulate incomming data. */
244 1371 nogj
void kbd_job(void *dat)
245 805 markom
{
246 1371 nogj
  struct kbd_state *kbd = dat;
247 805 markom
  int c;
248
  int kbd_int = 0;
249 1371 nogj
 
250 805 markom
  /* Check if there is something waiting, and decode it into kdb_buf */
251 1371 nogj
  if((c = fgetc(kbd->rxfs)) != EOF) {
252
    scan_decode (kbd, c);
253 805 markom
  }
254 1371 nogj
  kbd_int = kbd->kresp || kbd->buf_count ? kbd->ccmdbyte & KBD_CCMDBYTE_INT : 0;
255 1567 nogj
/*
256 805 markom
  if (config.sim.verbose && kbd_int)
257 1308 phoenix
    PRINTF("Keyboard Interrupt.... kbd_kresp %lx  kbd_buf_count %lx \n",
258 1371 nogj
           kbd->kresp, kbd->buf_count);
259 1567 nogj
*/
260 1371 nogj
  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 1486 nogj
  struct mem_ops ops;
346 1371 nogj
 
347 1461 nogj
  if(!kbd->enabled) {
348
    free(dat);
349
    return;
350
  }
351
 
352 1486 nogj
  memset(&ops, 0, sizeof(struct mem_ops));
353
 
354
  ops.readfunc8 = kbd_read8;
355
  ops.writefunc8 = kbd_write8;
356
  ops.read_dat8 = dat;
357
  ops.write_dat8 = dat;
358
 
359
  /* FIXME: Correct delay? */
360
  ops.delayr = 2;
361
  ops.delayw = 2;
362
 
363
  reg_mem_area(kbd->baseaddr, KBD_SPACE, 0, &ops);
364 1371 nogj
  reg_sim_reset(kbd_reset, dat);
365
  reg_sim_stat(kbd_info, dat);
366
}
367
 
368 1358 nogj
void reg_kbd_sec(void)
369
{
370 1371 nogj
  struct config_section *sec = reg_config_sec("kbd", kbd_sec_start, kbd_sec_end);
371 1358 nogj
 
372 1461 nogj
  reg_config_param(sec, "baseaddr", paramt_addr, kbd_baseaddr);
373
  reg_config_param(sec, "enabled", paramt_int, kbd_enabled);
374 1358 nogj
  reg_config_param(sec, "irq", paramt_int, kbd_irq);
375
  reg_config_param(sec, "rxfile", paramt_str, kbd_rxfile);
376
}

powered by: WebSVN 2.1.0

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