Statistics
| Branch: | Revision:

root / hw / syborg_keyboard.c @ 4af39611

History | View | Annotate | Download (6.7 kB)

1
/*
2
 * Syborg keyboard controller.
3
 *
4
 * Copyright (c) 2008 CodeSourcery
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

    
25
#include "sysbus.h"
26
#include "console.h"
27
#include "syborg.h"
28

    
29
//#define DEBUG_SYBORG_KEYBOARD
30

    
31
#ifdef DEBUG_SYBORG_KEYBOARD
32
#define DPRINTF(fmt, ...) \
33
do { printf("syborg_keyboard: " fmt , ##args); } while (0)
34
#define BADF(fmt, ...) \
35
do { fprintf(stderr, "syborg_keyboard: error: " fmt , ## __VA_ARGS__); \
36
    exit(1);} while (0)
37
#else
38
#define DPRINTF(fmt, ...) do {} while(0)
39
#define BADF(fmt, ...) \
40
do { fprintf(stderr, "syborg_keyboard: error: " fmt , ## __VA_ARGS__); \
41
} while (0)
42
#endif
43

    
44
enum {
45
    KBD_ID          = 0,
46
    KBD_DATA        = 1,
47
    KBD_FIFO_COUNT  = 2,
48
    KBD_INT_ENABLE  = 3,
49
    KBD_FIFO_SIZE   = 4
50
};
51

    
52
typedef struct {
53
    SysBusDevice busdev;
54
    int int_enabled;
55
    int extension_bit;
56
    int fifo_size;
57
    uint32_t *key_fifo;
58
    int read_pos, read_count;
59
    qemu_irq irq;
60
} SyborgKeyboardState;
61

    
62
static void syborg_keyboard_update(SyborgKeyboardState *s)
63
{
64
    int level = s->read_count && s->int_enabled;
65
    DPRINTF("Update IRQ %d\n", level);
66
    qemu_set_irq(s->irq, level);
67
}
68

    
69
static uint32_t syborg_keyboard_read(void *opaque, target_phys_addr_t offset)
70
{
71
    SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
72
    int c;
73

    
74
    DPRINTF("reg read %d\n", (int)offset);
75
    offset &= 0xfff;
76
    switch (offset >> 2) {
77
    case KBD_ID:
78
        return SYBORG_ID_KEYBOARD;
79
    case KBD_FIFO_COUNT:
80
        return s->read_count;
81
    case KBD_DATA:
82
        if (s->read_count == 0) {
83
            c = -1;
84
            DPRINTF("FIFO underflow\n");
85
        } else {
86
            c = s->key_fifo[s->read_pos];
87
            DPRINTF("FIFO read 0x%x\n", c);
88
            s->read_count--;
89
            s->read_pos++;
90
            if (s->read_pos == s->fifo_size)
91
                s->read_pos = 0;
92
        }
93
        syborg_keyboard_update(s);
94
        return c;
95
    case KBD_INT_ENABLE:
96
        return s->int_enabled;
97
    case KBD_FIFO_SIZE:
98
        return s->fifo_size;
99
    default:
100
        cpu_abort(cpu_single_env, "syborg_keyboard_read: Bad offset %x\n",
101
                  (int)offset);
102
        return 0;
103
    }
104
}
105

    
106
static void syborg_keyboard_write(void *opaque, target_phys_addr_t offset,
107
                                  uint32_t value)
108
{
109
    SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
110

    
111
    DPRINTF("reg write %d\n", (int)offset);
112
    offset &= 0xfff;
113
    switch (offset >> 2) {
114
    case KBD_INT_ENABLE:
115
        s->int_enabled = value;
116
        syborg_keyboard_update(s);
117
        break;
118
    default:
119
        cpu_abort(cpu_single_env, "syborg_keyboard_write: Bad offset %x\n",
120
                  (int)offset);
121
    }
122
}
123

    
124
static CPUReadMemoryFunc *syborg_keyboard_readfn[] = {
125
     syborg_keyboard_read,
126
     syborg_keyboard_read,
127
     syborg_keyboard_read
128
};
129

    
130
static CPUWriteMemoryFunc *syborg_keyboard_writefn[] = {
131
     syborg_keyboard_write,
132
     syborg_keyboard_write,
133
     syborg_keyboard_write
134
};
135

    
136
static void syborg_keyboard_event(void *opaque, int keycode)
137
{
138
    SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
139
    int slot;
140
    uint32_t val;
141

    
142
    /* Strip off 0xe0 prefixes and reconstruct the full scancode.  */
143
    if (keycode == 0xe0 && !s->extension_bit) {
144
        DPRINTF("Extension bit\n");
145
        s->extension_bit = 0x80;
146
        return;
147
    }
148
    val = (keycode & 0x7f) | s->extension_bit;
149
    if (keycode & 0x80)
150
        val |= 0x80000000u;
151
    s->extension_bit = 0;
152

    
153
    DPRINTF("FIFO push 0x%x\n", val);
154
    slot = s->read_pos + s->read_count;
155
    if (slot >= s->fifo_size)
156
        slot -= s->fifo_size;
157

    
158
    if (s->read_count < s->fifo_size) {
159
        s->read_count++;
160
        s->key_fifo[slot] = val;
161
    } else {
162
        fprintf(stderr, "syborg_keyboard error! FIFO overflow\n");
163
    }
164

    
165
    syborg_keyboard_update(s);
166
}
167

    
168
static void syborg_keyboard_save(QEMUFile *f, void *opaque)
169
{
170
    SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
171
    int i;
172

    
173
    qemu_put_be32(f, s->fifo_size);
174
    qemu_put_be32(f, s->int_enabled);
175
    qemu_put_be32(f, s->extension_bit);
176
    qemu_put_be32(f, s->read_pos);
177
    qemu_put_be32(f, s->read_count);
178
    for (i = 0; i < s->fifo_size; i++) {
179
        qemu_put_be32(f, s->key_fifo[i]);
180
    }
181
}
182

    
183
static int syborg_keyboard_load(QEMUFile *f, void *opaque, int version_id)
184
{
185
    SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
186
    uint32_t val;
187
    int i;
188

    
189
    if (version_id != 1)
190
        return -EINVAL;
191

    
192
    val = qemu_get_be32(f);
193
    if (val != s->fifo_size)
194
        return -EINVAL;
195

    
196
    s->int_enabled = qemu_get_be32(f);
197
    s->extension_bit = qemu_get_be32(f);
198
    s->read_pos = qemu_get_be32(f);
199
    s->read_count = qemu_get_be32(f);
200
    for (i = 0; i < s->fifo_size; i++) {
201
        s->key_fifo[i] = qemu_get_be32(f);
202
    }
203
    return 0;
204
}
205

    
206
static void syborg_keyboard_init(SysBusDevice *dev)
207
{
208
    SyborgKeyboardState *s = FROM_SYSBUS(SyborgKeyboardState, dev);
209
    int iomemtype;
210

    
211
    sysbus_init_irq(dev, &s->irq);
212
    iomemtype = cpu_register_io_memory(0, syborg_keyboard_readfn,
213
                                       syborg_keyboard_writefn, s);
214
    sysbus_init_mmio(dev, 0x1000, iomemtype);
215
    s->fifo_size = qdev_get_prop_int(&dev->qdev, "fifo-size", 16);
216
    if (s->fifo_size <= 0) {
217
        fprintf(stderr, "syborg_keyboard: fifo too small\n");
218
        s->fifo_size = 16;
219
    }
220
    s->key_fifo = qemu_mallocz(s->fifo_size * sizeof(s->key_fifo[0]));
221

    
222
    qemu_add_kbd_event_handler(syborg_keyboard_event, s);
223

    
224
    register_savevm("syborg_keyboard", -1, 1,
225
                    syborg_keyboard_save, syborg_keyboard_load, s);
226
}
227

    
228
static void syborg_keyboard_register_devices(void)
229
{
230
    sysbus_register_dev("syborg,keyboard", sizeof(SyborgKeyboardState),
231
                        syborg_keyboard_init);
232
}
233

    
234
device_init(syborg_keyboard_register_devices)