Statistics
| Branch: | Revision:

root / hw / milkymist-softusb.c @ ba7cb5a8

History | View | Annotate | Download (9.3 kB)

1 87a381ec Michael Walle
/*
2 87a381ec Michael Walle
 *  QEMU model of the Milkymist SoftUSB block.
3 87a381ec Michael Walle
 *
4 87a381ec Michael Walle
 *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
5 87a381ec Michael Walle
 *
6 87a381ec Michael Walle
 * This library is free software; you can redistribute it and/or
7 87a381ec Michael Walle
 * modify it under the terms of the GNU Lesser General Public
8 87a381ec Michael Walle
 * License as published by the Free Software Foundation; either
9 87a381ec Michael Walle
 * version 2 of the License, or (at your option) any later version.
10 87a381ec Michael Walle
 *
11 87a381ec Michael Walle
 * This library is distributed in the hope that it will be useful,
12 87a381ec Michael Walle
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 87a381ec Michael Walle
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 87a381ec Michael Walle
 * Lesser General Public License for more details.
15 87a381ec Michael Walle
 *
16 87a381ec Michael Walle
 * You should have received a copy of the GNU Lesser General Public
17 87a381ec Michael Walle
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 87a381ec Michael Walle
 *
19 87a381ec Michael Walle
 *
20 87a381ec Michael Walle
 * Specification available at:
21 87a381ec Michael Walle
 *   not available yet
22 87a381ec Michael Walle
 */
23 87a381ec Michael Walle
24 87a381ec Michael Walle
#include "hw.h"
25 87a381ec Michael Walle
#include "sysbus.h"
26 87a381ec Michael Walle
#include "trace.h"
27 87a381ec Michael Walle
#include "console.h"
28 87a381ec Michael Walle
#include "usb.h"
29 87a381ec Michael Walle
#include "qemu-error.h"
30 87a381ec Michael Walle
31 87a381ec Michael Walle
enum {
32 87a381ec Michael Walle
    R_CTRL = 0,
33 87a381ec Michael Walle
    R_MAX
34 87a381ec Michael Walle
};
35 87a381ec Michael Walle
36 87a381ec Michael Walle
enum {
37 87a381ec Michael Walle
    CTRL_RESET = (1<<0),
38 87a381ec Michael Walle
};
39 87a381ec Michael Walle
40 87a381ec Michael Walle
#define COMLOC_DEBUG_PRODUCE 0x1000
41 87a381ec Michael Walle
#define COMLOC_DEBUG_BASE    0x1001
42 87a381ec Michael Walle
#define COMLOC_MEVT_PRODUCE  0x1101
43 87a381ec Michael Walle
#define COMLOC_MEVT_BASE     0x1102
44 87a381ec Michael Walle
#define COMLOC_KEVT_PRODUCE  0x1142
45 87a381ec Michael Walle
#define COMLOC_KEVT_BASE     0x1143
46 87a381ec Michael Walle
47 87a381ec Michael Walle
struct MilkymistSoftUsbState {
48 87a381ec Michael Walle
    SysBusDevice busdev;
49 87a381ec Michael Walle
    USBBus usbbus;
50 87a381ec Michael Walle
    USBPort usbport[2];
51 87a381ec Michael Walle
    USBDevice *usbdev;
52 87a381ec Michael Walle
53 87a381ec Michael Walle
    qemu_irq irq;
54 87a381ec Michael Walle
55 87a381ec Michael Walle
    /* device properties */
56 87a381ec Michael Walle
    uint32_t pmem_base;
57 87a381ec Michael Walle
    uint32_t pmem_size;
58 87a381ec Michael Walle
    uint32_t dmem_base;
59 87a381ec Michael Walle
    uint32_t dmem_size;
60 87a381ec Michael Walle
61 87a381ec Michael Walle
    /* device registers */
62 87a381ec Michael Walle
    uint32_t regs[R_MAX];
63 87a381ec Michael Walle
64 87a381ec Michael Walle
    /* mouse state */
65 87a381ec Michael Walle
    int mouse_dx;
66 87a381ec Michael Walle
    int mouse_dy;
67 87a381ec Michael Walle
    int mouse_dz;
68 87a381ec Michael Walle
    uint8_t mouse_buttons_state;
69 87a381ec Michael Walle
70 87a381ec Michael Walle
    /* keyboard state */
71 87a381ec Michael Walle
    uint8_t kbd_usb_buffer[8];
72 87a381ec Michael Walle
};
73 87a381ec Michael Walle
typedef struct MilkymistSoftUsbState MilkymistSoftUsbState;
74 87a381ec Michael Walle
75 87a381ec Michael Walle
static uint32_t softusb_read(void *opaque, target_phys_addr_t addr)
76 87a381ec Michael Walle
{
77 87a381ec Michael Walle
    MilkymistSoftUsbState *s = opaque;
78 87a381ec Michael Walle
    uint32_t r = 0;
79 87a381ec Michael Walle
80 87a381ec Michael Walle
    addr >>= 2;
81 87a381ec Michael Walle
    switch (addr) {
82 87a381ec Michael Walle
    case R_CTRL:
83 87a381ec Michael Walle
        r = s->regs[addr];
84 87a381ec Michael Walle
        break;
85 87a381ec Michael Walle
86 87a381ec Michael Walle
    default:
87 87a381ec Michael Walle
        error_report("milkymist_softusb: read access to unknown register 0x"
88 87a381ec Michael Walle
                TARGET_FMT_plx, addr << 2);
89 87a381ec Michael Walle
        break;
90 87a381ec Michael Walle
    }
91 87a381ec Michael Walle
92 87a381ec Michael Walle
    trace_milkymist_softusb_memory_read(addr << 2, r);
93 87a381ec Michael Walle
94 87a381ec Michael Walle
    return r;
95 87a381ec Michael Walle
}
96 87a381ec Michael Walle
97 87a381ec Michael Walle
static void
98 87a381ec Michael Walle
softusb_write(void *opaque, target_phys_addr_t addr, uint32_t value)
99 87a381ec Michael Walle
{
100 87a381ec Michael Walle
    MilkymistSoftUsbState *s = opaque;
101 87a381ec Michael Walle
102 87a381ec Michael Walle
    trace_milkymist_softusb_memory_write(addr, value);
103 87a381ec Michael Walle
104 87a381ec Michael Walle
    addr >>= 2;
105 87a381ec Michael Walle
    switch (addr) {
106 87a381ec Michael Walle
    case R_CTRL:
107 87a381ec Michael Walle
        s->regs[addr] = value;
108 87a381ec Michael Walle
        break;
109 87a381ec Michael Walle
110 87a381ec Michael Walle
    default:
111 87a381ec Michael Walle
        error_report("milkymist_softusb: write access to unknown register 0x"
112 87a381ec Michael Walle
                TARGET_FMT_plx, addr << 2);
113 87a381ec Michael Walle
        break;
114 87a381ec Michael Walle
    }
115 87a381ec Michael Walle
}
116 87a381ec Michael Walle
117 87a381ec Michael Walle
static CPUReadMemoryFunc * const softusb_read_fn[] = {
118 87a381ec Michael Walle
    NULL,
119 87a381ec Michael Walle
    NULL,
120 87a381ec Michael Walle
    &softusb_read,
121 87a381ec Michael Walle
};
122 87a381ec Michael Walle
123 87a381ec Michael Walle
static CPUWriteMemoryFunc * const softusb_write_fn[] = {
124 87a381ec Michael Walle
    NULL,
125 87a381ec Michael Walle
    NULL,
126 87a381ec Michael Walle
    &softusb_write,
127 87a381ec Michael Walle
};
128 87a381ec Michael Walle
129 87a381ec Michael Walle
static inline void softusb_read_dmem(MilkymistSoftUsbState *s,
130 87a381ec Michael Walle
        uint32_t offset, uint8_t *buf, uint32_t len)
131 87a381ec Michael Walle
{
132 87a381ec Michael Walle
    if (offset + len >= s->dmem_size) {
133 87a381ec Michael Walle
        error_report("milkymist_softusb: read dmem out of bounds "
134 87a381ec Michael Walle
                "at offset 0x%x, len %d\n", offset, len);
135 87a381ec Michael Walle
        return;
136 87a381ec Michael Walle
    }
137 87a381ec Michael Walle
138 87a381ec Michael Walle
    cpu_physical_memory_read(s->dmem_base + offset, buf, len);
139 87a381ec Michael Walle
}
140 87a381ec Michael Walle
141 87a381ec Michael Walle
static inline void softusb_write_dmem(MilkymistSoftUsbState *s,
142 87a381ec Michael Walle
        uint32_t offset, uint8_t *buf, uint32_t len)
143 87a381ec Michael Walle
{
144 87a381ec Michael Walle
    if (offset + len >= s->dmem_size) {
145 87a381ec Michael Walle
        error_report("milkymist_softusb: write dmem out of bounds "
146 87a381ec Michael Walle
                "at offset 0x%x, len %d\n", offset, len);
147 87a381ec Michael Walle
        return;
148 87a381ec Michael Walle
    }
149 87a381ec Michael Walle
150 87a381ec Michael Walle
    cpu_physical_memory_write(s->dmem_base + offset, buf, len);
151 87a381ec Michael Walle
}
152 87a381ec Michael Walle
153 87a381ec Michael Walle
static inline void softusb_read_pmem(MilkymistSoftUsbState *s,
154 87a381ec Michael Walle
        uint32_t offset, uint8_t *buf, uint32_t len)
155 87a381ec Michael Walle
{
156 87a381ec Michael Walle
    if (offset + len >= s->pmem_size) {
157 87a381ec Michael Walle
        error_report("milkymist_softusb: read pmem out of bounds "
158 87a381ec Michael Walle
                "at offset 0x%x, len %d\n", offset, len);
159 87a381ec Michael Walle
        return;
160 87a381ec Michael Walle
    }
161 87a381ec Michael Walle
162 87a381ec Michael Walle
    cpu_physical_memory_read(s->pmem_base + offset, buf, len);
163 87a381ec Michael Walle
}
164 87a381ec Michael Walle
165 87a381ec Michael Walle
static inline void softusb_write_pmem(MilkymistSoftUsbState *s,
166 87a381ec Michael Walle
        uint32_t offset, uint8_t *buf, uint32_t len)
167 87a381ec Michael Walle
{
168 87a381ec Michael Walle
    if (offset + len >= s->pmem_size) {
169 87a381ec Michael Walle
        error_report("milkymist_softusb: write pmem out of bounds "
170 87a381ec Michael Walle
                "at offset 0x%x, len %d\n", offset, len);
171 87a381ec Michael Walle
        return;
172 87a381ec Michael Walle
    }
173 87a381ec Michael Walle
174 87a381ec Michael Walle
    cpu_physical_memory_write(s->pmem_base + offset, buf, len);
175 87a381ec Michael Walle
}
176 87a381ec Michael Walle
177 87a381ec Michael Walle
static void softusb_mouse_changed(MilkymistSoftUsbState *s)
178 87a381ec Michael Walle
{
179 87a381ec Michael Walle
    uint8_t m;
180 87a381ec Michael Walle
    uint8_t buf[4];
181 87a381ec Michael Walle
182 87a381ec Michael Walle
    buf[0] = s->mouse_buttons_state;
183 87a381ec Michael Walle
    buf[1] = s->mouse_dx;
184 87a381ec Michael Walle
    buf[2] = s->mouse_dy;
185 87a381ec Michael Walle
    buf[3] = s->mouse_dz;
186 87a381ec Michael Walle
187 87a381ec Michael Walle
    softusb_read_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
188 87a381ec Michael Walle
    trace_milkymist_softusb_mevt(m);
189 87a381ec Michael Walle
    softusb_write_dmem(s, COMLOC_MEVT_BASE + 4 * m, buf, 4);
190 87a381ec Michael Walle
    m = (m + 1) & 0xf;
191 87a381ec Michael Walle
    softusb_write_dmem(s, COMLOC_MEVT_PRODUCE, &m, 1);
192 87a381ec Michael Walle
193 87a381ec Michael Walle
    trace_milkymist_softusb_pulse_irq();
194 87a381ec Michael Walle
    qemu_irq_pulse(s->irq);
195 87a381ec Michael Walle
}
196 87a381ec Michael Walle
197 87a381ec Michael Walle
static void softusb_kbd_changed(MilkymistSoftUsbState *s)
198 87a381ec Michael Walle
{
199 87a381ec Michael Walle
    uint8_t m;
200 87a381ec Michael Walle
201 87a381ec Michael Walle
    softusb_read_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
202 87a381ec Michael Walle
    trace_milkymist_softusb_kevt(m);
203 87a381ec Michael Walle
    softusb_write_dmem(s, COMLOC_KEVT_BASE + 8 * m, s->kbd_usb_buffer, 8);
204 87a381ec Michael Walle
    m = (m + 1) & 0x7;
205 87a381ec Michael Walle
    softusb_write_dmem(s, COMLOC_KEVT_PRODUCE, &m, 1);
206 87a381ec Michael Walle
207 87a381ec Michael Walle
    trace_milkymist_softusb_pulse_irq();
208 87a381ec Michael Walle
    qemu_irq_pulse(s->irq);
209 87a381ec Michael Walle
}
210 87a381ec Michael Walle
211 87a381ec Michael Walle
static void softusb_mouse_event(void *opaque,
212 87a381ec Michael Walle
       int dx, int dy, int dz, int buttons_state)
213 87a381ec Michael Walle
{
214 87a381ec Michael Walle
    MilkymistSoftUsbState *s = opaque;
215 87a381ec Michael Walle
216 87a381ec Michael Walle
    /* if device is in reset, do nothing */
217 87a381ec Michael Walle
    if (s->regs[R_CTRL] & CTRL_RESET) {
218 87a381ec Michael Walle
        return;
219 87a381ec Michael Walle
    }
220 87a381ec Michael Walle
221 87a381ec Michael Walle
    trace_milkymist_softusb_mouse_event(dx, dy, dz, buttons_state);
222 87a381ec Michael Walle
223 87a381ec Michael Walle
    s->mouse_dx = dx;
224 87a381ec Michael Walle
    s->mouse_dy = dy;
225 87a381ec Michael Walle
    s->mouse_dz = dz;
226 87a381ec Michael Walle
    s->mouse_buttons_state = buttons_state;
227 87a381ec Michael Walle
228 87a381ec Michael Walle
    softusb_mouse_changed(s);
229 87a381ec Michael Walle
}
230 87a381ec Michael Walle
231 87a381ec Michael Walle
static void softusb_usbdev_datain(void *opaque)
232 87a381ec Michael Walle
{
233 87a381ec Michael Walle
    MilkymistSoftUsbState *s = opaque;
234 87a381ec Michael Walle
235 87a381ec Michael Walle
    USBPacket p;
236 87a381ec Michael Walle
237 87a381ec Michael Walle
    p.pid = USB_TOKEN_IN;
238 87a381ec Michael Walle
    p.devep = 1;
239 87a381ec Michael Walle
    p.data = s->kbd_usb_buffer;
240 87a381ec Michael Walle
    p.len = sizeof(s->kbd_usb_buffer);
241 87a381ec Michael Walle
    s->usbdev->info->handle_data(s->usbdev, &p);
242 87a381ec Michael Walle
243 87a381ec Michael Walle
    softusb_kbd_changed(s);
244 87a381ec Michael Walle
}
245 87a381ec Michael Walle
246 87a381ec Michael Walle
static void softusb_attach(USBPort *port)
247 87a381ec Michael Walle
{
248 87a381ec Michael Walle
}
249 87a381ec Michael Walle
250 87a381ec Michael Walle
static USBPortOps softusb_ops = {
251 87a381ec Michael Walle
    .attach = softusb_attach,
252 87a381ec Michael Walle
};
253 87a381ec Michael Walle
254 87a381ec Michael Walle
static void milkymist_softusb_reset(DeviceState *d)
255 87a381ec Michael Walle
{
256 87a381ec Michael Walle
    MilkymistSoftUsbState *s =
257 87a381ec Michael Walle
            container_of(d, MilkymistSoftUsbState, busdev.qdev);
258 87a381ec Michael Walle
    int i;
259 87a381ec Michael Walle
260 87a381ec Michael Walle
    for (i = 0; i < R_MAX; i++) {
261 87a381ec Michael Walle
        s->regs[i] = 0;
262 87a381ec Michael Walle
    }
263 87a381ec Michael Walle
    s->mouse_dx = 0;
264 87a381ec Michael Walle
    s->mouse_dy = 0;
265 87a381ec Michael Walle
    s->mouse_dz = 0;
266 87a381ec Michael Walle
    s->mouse_buttons_state = 0;
267 87a381ec Michael Walle
    memset(s->kbd_usb_buffer, 0, sizeof(s->kbd_usb_buffer));
268 87a381ec Michael Walle
269 87a381ec Michael Walle
    /* defaults */
270 87a381ec Michael Walle
    s->regs[R_CTRL] = CTRL_RESET;
271 87a381ec Michael Walle
}
272 87a381ec Michael Walle
273 87a381ec Michael Walle
static int milkymist_softusb_init(SysBusDevice *dev)
274 87a381ec Michael Walle
{
275 87a381ec Michael Walle
    MilkymistSoftUsbState *s = FROM_SYSBUS(typeof(*s), dev);
276 87a381ec Michael Walle
    int softusb_regs;
277 87a381ec Michael Walle
    ram_addr_t pmem_ram;
278 87a381ec Michael Walle
    ram_addr_t dmem_ram;
279 87a381ec Michael Walle
280 87a381ec Michael Walle
    sysbus_init_irq(dev, &s->irq);
281 87a381ec Michael Walle
282 87a381ec Michael Walle
    softusb_regs = cpu_register_io_memory(softusb_read_fn, softusb_write_fn, s,
283 87a381ec Michael Walle
            DEVICE_NATIVE_ENDIAN);
284 87a381ec Michael Walle
    sysbus_init_mmio(dev, R_MAX * 4, softusb_regs);
285 87a381ec Michael Walle
286 87a381ec Michael Walle
    /* register pmem and dmem */
287 87a381ec Michael Walle
    pmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.pmem", s->pmem_size);
288 87a381ec Michael Walle
    cpu_register_physical_memory(s->pmem_base, s->pmem_size,
289 87a381ec Michael Walle
            pmem_ram | IO_MEM_RAM);
290 87a381ec Michael Walle
    dmem_ram = qemu_ram_alloc(NULL, "milkymist_softusb.dmem", s->dmem_size);
291 87a381ec Michael Walle
    cpu_register_physical_memory(s->dmem_base, s->dmem_size,
292 87a381ec Michael Walle
            dmem_ram | IO_MEM_RAM);
293 87a381ec Michael Walle
294 87a381ec Michael Walle
    qemu_add_mouse_event_handler(softusb_mouse_event, s, 0, "Milkymist Mouse");
295 87a381ec Michael Walle
296 87a381ec Michael Walle
    /* create our usb bus */
297 87a381ec Michael Walle
    usb_bus_new(&s->usbbus, NULL);
298 87a381ec Michael Walle
299 87a381ec Michael Walle
    /* our two ports */
300 87a381ec Michael Walle
    usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops,
301 87a381ec Michael Walle
            USB_SPEED_MASK_LOW);
302 87a381ec Michael Walle
    usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops,
303 87a381ec Michael Walle
            USB_SPEED_MASK_LOW);
304 87a381ec Michael Walle
305 87a381ec Michael Walle
    /* and finally create an usb keyboard */
306 87a381ec Michael Walle
    s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd");
307 87a381ec Michael Walle
    usb_hid_datain_cb(s->usbdev, s, softusb_usbdev_datain);
308 87a381ec Michael Walle
    s->usbdev->info->handle_reset(s->usbdev);
309 87a381ec Michael Walle
310 87a381ec Michael Walle
    return 0;
311 87a381ec Michael Walle
}
312 87a381ec Michael Walle
313 87a381ec Michael Walle
static const VMStateDescription vmstate_milkymist_softusb = {
314 87a381ec Michael Walle
    .name = "milkymist-softusb",
315 87a381ec Michael Walle
    .version_id = 1,
316 87a381ec Michael Walle
    .minimum_version_id = 1,
317 87a381ec Michael Walle
    .minimum_version_id_old = 1,
318 87a381ec Michael Walle
    .fields      = (VMStateField[]) {
319 87a381ec Michael Walle
        VMSTATE_UINT32_ARRAY(regs, MilkymistSoftUsbState, R_MAX),
320 87a381ec Michael Walle
        VMSTATE_INT32(mouse_dx, MilkymistSoftUsbState),
321 87a381ec Michael Walle
        VMSTATE_INT32(mouse_dy, MilkymistSoftUsbState),
322 87a381ec Michael Walle
        VMSTATE_INT32(mouse_dz, MilkymistSoftUsbState),
323 87a381ec Michael Walle
        VMSTATE_UINT8(mouse_buttons_state, MilkymistSoftUsbState),
324 87a381ec Michael Walle
        VMSTATE_BUFFER(kbd_usb_buffer, MilkymistSoftUsbState),
325 87a381ec Michael Walle
        VMSTATE_END_OF_LIST()
326 87a381ec Michael Walle
    }
327 87a381ec Michael Walle
};
328 87a381ec Michael Walle
329 87a381ec Michael Walle
static SysBusDeviceInfo milkymist_softusb_info = {
330 87a381ec Michael Walle
    .init = milkymist_softusb_init,
331 87a381ec Michael Walle
    .qdev.name  = "milkymist-softusb",
332 87a381ec Michael Walle
    .qdev.size  = sizeof(MilkymistSoftUsbState),
333 87a381ec Michael Walle
    .qdev.vmsd  = &vmstate_milkymist_softusb,
334 87a381ec Michael Walle
    .qdev.reset = milkymist_softusb_reset,
335 87a381ec Michael Walle
    .qdev.props = (Property[]) {
336 87a381ec Michael Walle
        DEFINE_PROP_UINT32(
337 87a381ec Michael Walle
                "pmem_base", MilkymistSoftUsbState, pmem_base, 0xa0000000
338 87a381ec Michael Walle
        ),
339 87a381ec Michael Walle
        DEFINE_PROP_UINT32(
340 87a381ec Michael Walle
                "pmem_size", MilkymistSoftUsbState, pmem_size, 0x00001000
341 87a381ec Michael Walle
        ),
342 87a381ec Michael Walle
        DEFINE_PROP_UINT32(
343 87a381ec Michael Walle
                "dmem_base", MilkymistSoftUsbState, dmem_base, 0xa0020000
344 87a381ec Michael Walle
        ),
345 87a381ec Michael Walle
        DEFINE_PROP_UINT32(
346 87a381ec Michael Walle
                "dmem_size", MilkymistSoftUsbState, dmem_size, 0x00002000
347 87a381ec Michael Walle
        ),
348 87a381ec Michael Walle
        DEFINE_PROP_END_OF_LIST(),
349 87a381ec Michael Walle
    }
350 87a381ec Michael Walle
};
351 87a381ec Michael Walle
352 87a381ec Michael Walle
static void milkymist_softusb_register(void)
353 87a381ec Michael Walle
{
354 87a381ec Michael Walle
    sysbus_register_withprop(&milkymist_softusb_info);
355 87a381ec Michael Walle
}
356 87a381ec Michael Walle
357 87a381ec Michael Walle
device_init(milkymist_softusb_register)