Statistics
| Branch: | Revision:

root / hw / syborg_pointer.c @ 0be71e32

History | View | Annotate | Download (7.1 kB)

1
/*
2
 * Syborg pointing device (mouse/touchscreen)
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
enum {
30
    POINTER_ID          = 0,
31
    POINTER_LATCH       = 1,
32
    POINTER_FIFO_COUNT  = 2,
33
    POINTER_X           = 3,
34
    POINTER_Y           = 4,
35
    POINTER_Z           = 5,
36
    POINTER_BUTTONS     = 6,
37
    POINTER_INT_ENABLE  = 7,
38
    POINTER_FIFO_SIZE   = 8
39
};
40

    
41
typedef struct {
42
    int x, y, z, pointer_buttons;
43
} event_data;
44

    
45
typedef struct {
46
    SysBusDevice busdev;
47
    int int_enabled;
48
    uint32_t fifo_size;
49
    event_data *event_fifo;
50
    int read_pos, read_count;
51
    qemu_irq irq;
52
    uint32_t absolute;
53
} SyborgPointerState;
54

    
55
static void syborg_pointer_update(SyborgPointerState *s)
56
{
57
    qemu_set_irq(s->irq, s->read_count && s->int_enabled);
58
}
59

    
60
static uint32_t syborg_pointer_read(void *opaque, target_phys_addr_t offset)
61
{
62
    SyborgPointerState *s = (SyborgPointerState *)opaque;
63

    
64
    offset &= 0xfff;
65
    switch (offset >> 2) {
66
    case POINTER_ID:
67
        return s->absolute ? SYBORG_ID_TOUCHSCREEN : SYBORG_ID_MOUSE;
68
    case POINTER_FIFO_COUNT:
69
        return s->read_count;
70
    case POINTER_X:
71
        return s->event_fifo[s->read_pos].x;
72
    case POINTER_Y:
73
        return s->event_fifo[s->read_pos].y;
74
    case POINTER_Z:
75
        return s->event_fifo[s->read_pos].z;
76
    case POINTER_BUTTONS:
77
        return s->event_fifo[s->read_pos].pointer_buttons;
78
    case POINTER_INT_ENABLE:
79
        return s->int_enabled;
80
    case POINTER_FIFO_SIZE:
81
        return s->fifo_size;
82
    default:
83
        cpu_abort(cpu_single_env, "syborg_pointer_read: Bad offset %x\n",
84
                  (int)offset);
85
        return 0;
86
    }
87
}
88

    
89
static void syborg_pointer_write(void *opaque, target_phys_addr_t offset,
90
                                 uint32_t value)
91
{
92
    SyborgPointerState *s = (SyborgPointerState *)opaque;
93

    
94
    offset &= 0xfff;
95
    switch (offset >> 2) {
96
    case POINTER_LATCH:
97
        if (s->read_count > 0) {
98
            s->read_count--;
99
            if (++s->read_pos == s->fifo_size)
100
                s->read_pos = 0;
101
        }
102
        break;
103
    case POINTER_INT_ENABLE:
104
        s->int_enabled = value;
105
        break;
106
    default:
107
        cpu_abort(cpu_single_env, "syborg_pointer_write: Bad offset %x\n",
108
                  (int)offset);
109
    }
110
    syborg_pointer_update(s);
111
}
112

    
113
static CPUReadMemoryFunc * const syborg_pointer_readfn[] = {
114
   syborg_pointer_read,
115
   syborg_pointer_read,
116
   syborg_pointer_read
117
};
118

    
119
static CPUWriteMemoryFunc * const syborg_pointer_writefn[] = {
120
   syborg_pointer_write,
121
   syborg_pointer_write,
122
   syborg_pointer_write
123
};
124

    
125
static void syborg_pointer_event(void *opaque, int dx, int dy, int dz,
126
                                 int buttons_state)
127
{
128
    SyborgPointerState *s = (SyborgPointerState *)opaque;
129
    int slot = s->read_pos + s->read_count;
130

    
131
    /* This first FIFO entry is used to store current register state.  */
132
    if (s->read_count < s->fifo_size - 1) {
133
        s->read_count++;
134
        slot++;
135
    }
136

    
137
    if (slot >= s->fifo_size)
138
          slot -= s->fifo_size;
139

    
140
    if (s->read_count == s->fifo_size && !s->absolute) {
141
        /* Merge existing entries.  */
142
        s->event_fifo[slot].x += dx;
143
        s->event_fifo[slot].y += dy;
144
        s->event_fifo[slot].z += dz;
145
    } else {
146
        s->event_fifo[slot].x = dx;
147
        s->event_fifo[slot].y = dy;
148
        s->event_fifo[slot].z = dz;
149
    }
150
    s->event_fifo[slot].pointer_buttons = buttons_state;
151

    
152
    syborg_pointer_update(s);
153
}
154

    
155
static void syborg_pointer_save(QEMUFile *f, void *opaque)
156
{
157
    SyborgPointerState *s = (SyborgPointerState *)opaque;
158
    int i;
159

    
160
    qemu_put_be32(f, s->fifo_size);
161
    qemu_put_be32(f, s->absolute);
162
    qemu_put_be32(f, s->int_enabled);
163
    qemu_put_be32(f, s->read_pos);
164
    qemu_put_be32(f, s->read_count);
165
    for (i = 0; i < s->fifo_size; i++) {
166
        qemu_put_be32(f, s->event_fifo[i].x);
167
        qemu_put_be32(f, s->event_fifo[i].y);
168
        qemu_put_be32(f, s->event_fifo[i].z);
169
        qemu_put_be32(f, s->event_fifo[i].pointer_buttons);
170
    }
171
}
172

    
173
static int syborg_pointer_load(QEMUFile *f, void *opaque, int version_id)
174
{
175
    SyborgPointerState *s = (SyborgPointerState *)opaque;
176
    uint32_t val;
177
    int i;
178

    
179
    if (version_id != 1)
180
        return -EINVAL;
181

    
182
    val = qemu_get_be32(f);
183
    if (val != s->fifo_size)
184
        return -EINVAL;
185

    
186
    val = qemu_get_be32(f);
187
    if (val != s->absolute)
188
        return -EINVAL;
189

    
190
    s->int_enabled = qemu_get_be32(f);
191
    s->read_pos = qemu_get_be32(f);
192
    s->read_count = qemu_get_be32(f);
193
    for (i = 0; i < s->fifo_size; i++) {
194
        s->event_fifo[i].x = qemu_get_be32(f);
195
        s->event_fifo[i].y = qemu_get_be32(f);
196
        s->event_fifo[i].z = qemu_get_be32(f);
197
        s->event_fifo[i].pointer_buttons = qemu_get_be32(f);
198
    }
199
    return 0;
200
}
201

    
202
static int syborg_pointer_init(SysBusDevice *dev)
203
{
204
    SyborgPointerState *s = FROM_SYSBUS(SyborgPointerState, dev);
205
    int iomemtype;
206

    
207
    sysbus_init_irq(dev, &s->irq);
208
    iomemtype = cpu_register_io_memory(syborg_pointer_readfn,
209
                                       syborg_pointer_writefn, s);
210
    sysbus_init_mmio(dev, 0x1000, iomemtype);
211

    
212
    if (s->fifo_size <= 0) {
213
        fprintf(stderr, "syborg_pointer: fifo too small\n");
214
        s->fifo_size = 16;
215
    }
216
    s->event_fifo = qemu_mallocz(s->fifo_size * sizeof(s->event_fifo[0]));
217

    
218
    qemu_add_mouse_event_handler(syborg_pointer_event, s, s->absolute,
219
                                 "Syborg Pointer");
220

    
221
    register_savevm(&dev->qdev, "syborg_pointer", -1, 1,
222
                    syborg_pointer_save, syborg_pointer_load, s);
223
    return 0;
224
}
225

    
226
static SysBusDeviceInfo syborg_pointer_info = {
227
    .init = syborg_pointer_init,
228
    .qdev.name  = "syborg,pointer",
229
    .qdev.size  = sizeof(SyborgPointerState),
230
    .qdev.props = (Property[]) {
231
        DEFINE_PROP_UINT32("fifo-size", SyborgPointerState, fifo_size, 16),
232
        DEFINE_PROP_UINT32("absolute",  SyborgPointerState, absolute,   1),
233
        DEFINE_PROP_END_OF_LIST(),
234
    }
235
};
236

    
237
static void syborg_pointer_register_devices(void)
238
{
239
    sysbus_register_withprop(&syborg_pointer_info);
240
}
241

    
242
device_init(syborg_pointer_register_devices)