2
* QEMU model of the Milkymist SoftUSB block.
4
* Copyright (c) 2010 Michael Walle <michael@walle.cc>
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.
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.
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/>.
20
* Specification available at:
29
#include "qemu-error.h"
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
47
struct MilkymistSoftUsbState {
52
MemoryRegion regs_region;
57
/* device properties */
63
/* device registers */
67
uint8_t mouse_hid_buffer[4];
70
uint8_t kbd_hid_buffer[8];
72
typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
74
static uint64_t softusb_read(void *opaque, target_phys_addr_t addr,
77
MilkymistSoftUsbState *s = opaque;
87
error_report("milkymist_softusb: read access to unknown register 0x"
88
TARGET_FMT_plx, addr << 2);
92
trace_milkymist_softusb_memory_read(addr << 2, r);
98
softusb_write(void *opaque, target_phys_addr_t addr, uint64_t value,
101
MilkymistSoftUsbState *s = opaque;
103
trace_milkymist_softusb_memory_write(addr, value);
108
s->regs[addr] = value;
112
error_report("milkymist_softusb: write access to unknown register 0x"
113
TARGET_FMT_plx, addr << 2);
118
static const MemoryRegionOps softusb_mmio_ops = {
119
.read = softusb_read,
120
.write = softusb_write,
121
.endianness = DEVICE_NATIVE_ENDIAN,
123
.min_access_size = 4,
124
.max_access_size = 4,
128
static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
129
uint32_t offset, uint8_t *buf, uint32_t len)
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);
137
cpu_physical_memory_read(s->dmem_base + offset, buf, len);
140
static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
141
uint32_t offset, uint8_t *buf, uint32_t len)
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);
149
cpu_physical_memory_write(s->dmem_base + offset, buf, len);
152
static inline void softusb_read_pmem(MilkymistSoftUsbState *s,
153
uint32_t offset, uint8_t *buf, uint32_t len)
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);
161
cpu_physical_memory_read(s->pmem_base + offset, buf, len);
164
static inline void softusb_write_pmem(MilkymistSoftUsbState *s,
165
uint32_t offset, uint8_t *buf, uint32_t len)
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);
173
cpu_physical_memory_write(s->pmem_base + offset, buf, len);
176
static void softusb_mouse_changed(MilkymistSoftUsbState *s)
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);
184
softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
186
trace_milkymist_softusb_pulse_irq();
187
qemu_irq_pulse(s->irq);
190
static void softusb_kbd_changed(MilkymistSoftUsbState *s)
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);
198
softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
200
trace_milkymist_softusb_pulse_irq();
201
qemu_irq_pulse(s->irq);
204
static void softusb_kbd_hid_datain(HIDState *hs)
206
MilkymistSoftUsbState *s = container_of(hs, MilkymistSoftUsbState, hid_kbd);
209
/* if device is in reset, do nothing */
210
if (s->regs[R_CTRL] & CTRL_RESET) {
214
len = hid_keyboard_poll(hs, s->kbd_hid_buffer, sizeof(s->kbd_hid_buffer));
217
softusb_kbd_changed(s);
221
static void softusb_mouse_hid_datain(HIDState *hs)
223
MilkymistSoftUsbState *s =
224
container_of(hs, MilkymistSoftUsbState, hid_mouse);
227
/* if device is in reset, do nothing */
228
if (s->regs[R_CTRL] & CTRL_RESET) {
232
len = hid_pointer_poll(hs, s->mouse_hid_buffer,
233
sizeof(s->mouse_hid_buffer));
236
softusb_mouse_changed(s);
240
static void milkymist_softusb_reset(DeviceState *d)
242
MilkymistSoftUsbState *s =
243
container_of(d, MilkymistSoftUsbState, busdev.qdev);
246
for (i = 0; i < R_MAX; i++) {
249
memset(s->kbd_hid_buffer, 0, sizeof(s->kbd_hid_buffer));
250
memset(s->mouse_hid_buffer, 0, sizeof(s->mouse_hid_buffer));
252
hid_reset(&s->hid_kbd);
253
hid_reset(&s->hid_mouse);
256
s->regs[R_CTRL] = CTRL_RESET;
259
static int milkymist_softusb_init(SysBusDevice *dev)
261
MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
263
sysbus_init_irq(dev, &s->irq);
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);
269
/* register pmem and dmem */
270
memory_region_init_ram(&s->pmem, NULL, "milkymist-softusb.pmem",
272
sysbus_add_memory(dev, s->pmem_base, &s->pmem);
273
memory_region_init_ram(&s->dmem, NULL, "milkymist-softusb.dmem",
275
sysbus_add_memory(dev, s->dmem_base, &s->dmem);
277
hid_init(&s->hid_kbd, HID_KEYBOARD, softusb_kbd_hid_datain);
278
hid_init(&s->hid_mouse, HID_MOUSE, softusb_mouse_hid_datain);
283
static const VMStateDescription vmstate_milkymist_softusb = {
284
.name = "milkymist-softusb",
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()
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[]) {
306
"pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000
309
"pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000
312
"dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000
315
"dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000
317
DEFINE_PROP_END_OF_LIST(),
321
static void milkymist_softusb_register(void)
323
sysbus_register_withprop(&milkymist_softusb_info);
326
device_init(milkymist_softusb_register)