~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to hw/milkymist-softusb.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  QEMU model of the Milkymist SoftUSB block.
 
3
 *
 
4
 *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
 
5
 *
 
6
 * This library is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU Lesser General Public
 
8
 * License as published by the Free Software Foundation; either
 
9
 * version 2 of the License, or (at your option) any later version.
 
10
 *
 
11
 * This library 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 GNU
 
14
 * Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 
18
 *
 
19
 *
 
20
 * Specification available at:
 
21
 *   not available yet
 
22
 */
 
23
 
 
24
#include "hw.h"
 
25
#include "sysbus.h"
 
26
#include "trace.h"
 
27
#include "console.h"
 
28
#include "hid.h"
 
29
#include "qemu-error.h"
 
30
 
 
31
enum {
 
32
    R_CTRL = 0,
 
33
    R_MAX
 
34
};
 
35
 
 
36
enum {
 
37
    CTRL_RESET = (1<<0),
 
38
};
 
39
 
 
40
#define COMLOC_DEBUG_PRODUCE 0x1000
 
41
#define COMLOC_DEBUG_BASE    0x1001
 
42
#define COMLOC_MEVT_PRODUCE  0x1101
 
43
#define COMLOC_MEVT_BASE     0x1102
 
44
#define COMLOC_KEVT_PRODUCE  0x1142
 
45
#define COMLOC_KEVT_BASE     0x1143
 
46
 
 
47
struct MilkymistSoftUsbState {
 
48
    SysBusDevice busdev;
 
49
    HIDState hid_kbd;
 
50
    HIDState hid_mouse;
 
51
 
 
52
    MemoryRegion regs_region;
 
53
    MemoryRegion pmem;
 
54
    MemoryRegion dmem;
 
55
    qemu_irq irq;
 
56
 
 
57
    /* device properties */
 
58
    uint32_t pmem_base;
 
59
    uint32_t pmem_size;
 
60
    uint32_t dmem_base;
 
61
    uint32_t dmem_size;
 
62
 
 
63
    /* device registers */
 
64
    uint32_t regs[R_MAX];
 
65
 
 
66
    /* mouse state */
 
67
    uint8_t mouse_hid_buffer[4];
 
68
 
 
69
    /* keyboard state */
 
70
    uint8_t kbd_hid_buffer[8];
 
71
};
 
72
typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
 
73
 
 
74
static uint64_t softusb_read(void *opaque, target_phys_addr_t addr,
 
75
                             unsigned size)
 
76
{
 
77
    MilkymistSoftUsbState *s = opaque;
 
78
    uint32_t r = 0;
 
79
 
 
80
    addr >>= 2;
 
81
    switch (addr) {
 
82
    case R_CTRL:
 
83
        r = s->regs[addr];
 
84
        break;
 
85
 
 
86
    default:
 
87
        error_report("milkymist_softusb: read access to unknown register 0x"
 
88
                TARGET_FMT_plx, addr << 2);
 
89
        break;
 
90
    }
 
91
 
 
92
    trace_milkymist_softusb_memory_read(addr << 2, r);
 
93
 
 
94
    return r;
 
95
}
 
96
 
 
97
static void
 
98
softusb_write(void *opaque, target_phys_addr_t addr, uint64_t value,
 
99
              unsigned size)
 
100
{
 
101
    MilkymistSoftUsbState *s = opaque;
 
102
 
 
103
    trace_milkymist_softusb_memory_write(addr, value);
 
104
 
 
105
    addr >>= 2;
 
106
    switch (addr) {
 
107
    case R_CTRL:
 
108
        s->regs[addr] = value;
 
109
        break;
 
110
 
 
111
    default:
 
112
        error_report("milkymist_softusb: write access to unknown register 0x"
 
113
                TARGET_FMT_plx, addr << 2);
 
114
        break;
 
115
    }
 
116
}
 
117
 
 
118
static const MemoryRegionOps softusb_mmio_ops = {
 
119
    .read = softusb_read,
 
120
    .write = softusb_write,
 
121
    .endianness = DEVICE_NATIVE_ENDIAN,
 
122
    .valid = {
 
123
        .min_access_size = 4,
 
124
        .max_access_size = 4,
 
125
    },
 
126
};
 
127
 
 
128
static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
 
129
        uint32_t offset, uint8_t *buf, uint32_t len)
 
130
{
 
131
    if (offset + len >= s->dmem_size) {
 
132
        error_report("milkymist_softusb: read dmem out of bounds "
 
133
                "at offset 0x%x, len %d", offset, len);
 
134
        return;
 
135
    }
 
136
 
 
137
    cpu_physical_memory_read(s->dmem_base + offset, buf, len);
 
138
}
 
139
 
 
140
static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
 
141
        uint32_t offset, uint8_t *buf, uint32_t len)
 
142
{
 
143
    if (offset + len >= s->dmem_size) {
 
144
        error_report("milkymist_softusb: write dmem out of bounds "
 
145
                "at offset 0x%x, len %d", offset, len);
 
146
        return;
 
147
    }
 
148
 
 
149
    cpu_physical_memory_write(s->dmem_base + offset, buf, len);
 
150
}
 
151
 
 
152
static inline void softusb_read_pmem(MilkymistSoftUsbState *s,
 
153
        uint32_t offset, uint8_t *buf, uint32_t len)
 
154
{
 
155
    if (offset + len >= s->pmem_size) {
 
156
        error_report("milkymist_softusb: read pmem out of bounds "
 
157
                "at offset 0x%x, len %d", offset, len);
 
158
        return;
 
159
    }
 
160
 
 
161
    cpu_physical_memory_read(s->pmem_base + offset, buf, len);
 
162
}
 
163
 
 
164
static inline void softusb_write_pmem(MilkymistSoftUsbState *s,
 
165
        uint32_t offset, uint8_t *buf, uint32_t len)
 
166
{
 
167
    if (offset + len >= s->pmem_size) {
 
168
        error_report("milkymist_softusb: write pmem out of bounds "
 
169
                "at offset 0x%x, len %d", offset, len);
 
170
        return;
 
171
    }
 
172
 
 
173
    cpu_physical_memory_write(s->pmem_base + offset, buf, len);
 
174
}
 
175
 
 
176
static void softusb_mouse_changed(MilkymistSoftUsbState *s)
 
177
{
 
178
    uint8_t m;
 
179
 
 
180
    softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
 
181
    trace_milkymist_softusb_mevt(m);
 
182
    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, s->mouse_hid_buffer, 4);
 
183
    m = (m + 1) & 0xf;
 
184
    softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
 
185
 
 
186
    trace_milkymist_softusb_pulse_irq();
 
187
    qemu_irq_pulse(s->irq);
 
188
}
 
189
 
 
190
static void softusb_kbd_changed(MilkymistSoftUsbState *s)
 
191
{
 
192
    uint8_t m;
 
193
 
 
194
    softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
 
195
    trace_milkymist_softusb_kevt(m);
 
196
    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_hid_buffer, 8);
 
197
    m = (m + 1) & 0x7;
 
198
    softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
 
199
 
 
200
    trace_milkymist_softusb_pulse_irq();
 
201
    qemu_irq_pulse(s->irq);
 
202
}
 
203
 
 
204
static void softusb_kbd_hid_datain(HIDState *hs)
 
205
{
 
206
    MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
 
207
    int len;
 
208
 
 
209
    /* if device is in reset, do nothing */
 
210
    if (s->regs[R_CTRL] & CTRL_RESET) {
 
211
        return;
 
212
    }
 
213
 
 
214
    len = hid_keyboard_poll(hs, s->kbd_hid_buffer, sizeof(s->kbd_hid_buffer));
 
215
 
 
216
    if (len == 8) {
 
217
        softusb_kbd_changed(s);
 
218
    }
 
219
}
 
220
 
 
221
static void softusb_mouse_hid_datain(HIDState *hs)
 
222
{
 
223
    MilkymistSoftUsbState *s =
 
224
            container_of(hs, MilkymistSoftUsbState, hid_mouse);
 
225
    int len;
 
226
 
 
227
    /* if device is in reset, do nothing */
 
228
    if (s->regs[R_CTRL] & CTRL_RESET) {
 
229
        return;
 
230
    }
 
231
 
 
232
    len = hid_pointer_poll(hs, s->mouse_hid_buffer,
 
233
            sizeof(s->mouse_hid_buffer));
 
234
 
 
235
    if (len == 4) {
 
236
        softusb_mouse_changed(s);
 
237
    }
 
238
}
 
239
 
 
240
static void milkymist_softusb_reset(DeviceState *d)
 
241
{
 
242
    MilkymistSoftUsbState *s =
 
243
            container_of(d, MilkymistSoftUsbState, busdev.qdev);
 
244
    int i;
 
245
 
 
246
    for (i = 0; i < R_MAX; i++) {
 
247
        s->regs[i] = 0;
 
248
    }
 
249
    memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
 
250
    memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
 
251
 
 
252
    hid_reset(&s->hid_kbd);
 
253
    hid_reset(&s->hid_mouse);
 
254
 
 
255
    /* defaults */
 
256
    s->regs[R_CTRL] = CTRL_RESET;
 
257
}
 
258
 
 
259
static int milkymist_softusb_init(SysBusDevice *dev)
 
260
{
 
261
    MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
 
262
 
 
263
    sysbus_init_irq(dev, &s->irq);
 
264
 
 
265
    memory_region_init_io(&s->regs_region, &softusb_mmio_ops, s,
 
266
                          "milkymist-softusb", R_MAX * 4);
 
267
    sysbus_init_mmio_region(dev, &s->regs_region);
 
268
 
 
269
    /* register pmem and dmem */
 
270
    memory_region_init_ram(&s->pmem, NULL, "milkymist-softusb.pmem",
 
271
                           s->pmem_size);
 
272
    sysbus_add_memory(dev, s->pmem_base, &s->pmem);
 
273
    memory_region_init_ram(&s->dmem, NULL, "milkymist-softusb.dmem",
 
274
                           s->dmem_size);
 
275
    sysbus_add_memory(dev, s->dmem_base, &s->dmem);
 
276
 
 
277
    hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
 
278
    hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
 
279
 
 
280
    return 0;
 
281
}
 
282
 
 
283
static const VMStateDescription vmstate_milkymist_softusb = {
 
284
    .name = "milkymist-softusb",
 
285
    .version_id = 1,
 
286
    .minimum_version_id = 1,
 
287
    .minimum_version_id_old = 1,
 
288
    .fields      = (VMStateField[]) {
 
289
        VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
 
290
        VMSTATE_HID_KEYBOARD_DEVICE(hid_kbd, MilkymistSoftUsbState),
 
291
        VMSTATE_HID_POINTER_DEVICE(hid_mouse, MilkymistSoftUsbState),
 
292
        VMSTATE_BUFFER(kbd_hid_buffer, MilkymistSoftUsbState),
 
293
        VMSTATE_BUFFER(mouse_hid_buffer, MilkymistSoftUsbState),
 
294
        VMSTATE_END_OF_LIST()
 
295
    }
 
296
};
 
297
 
 
298
static SysBusDeviceInfo milkymist_softusb_info = {
 
299
    .init = milkymist_softusb_init,
 
300
    .qdev.name  = "milkymist-softusb",
 
301
    .qdev.size  = sizeof(MilkymistSoftUsbState),
 
302
    .qdev.vmsd  = &vmstate_milkymist_softusb,
 
303
    .qdev.reset = milkymist_softusb_reset,
 
304
    .qdev.props = (Property[]) {
 
305
        DEFINE_PROP_UINT32(
 
306
                "pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000
 
307
        ),
 
308
        DEFINE_PROP_UINT32(
 
309
                "pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000
 
310
        ),
 
311
        DEFINE_PROP_UINT32(
 
312
                "dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000
 
313
        ),
 
314
        DEFINE_PROP_UINT32(
 
315
                "dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000
 
316
        ),
 
317
        DEFINE_PROP_END_OF_LIST(),
 
318
    }
 
319
};
 
320
 
 
321
static void milkymist_softusb_register(void)
 
322
{
 
323
    sysbus_register_withprop(&milkymist_softusb_info);
 
324
}
 
325
 
 
326
device_init(milkymist_softusb_register)