Statistics
| Branch: | Revision:

root / hw / syborg_pointer.c @ 4ff658fb

History | View | Annotate | Download (6.9 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 const VMStateDescription vmstate_event_data = {
156
    .name = "dbma_channel",
157
    .version_id = 0,
158
    .minimum_version_id = 0,
159
    .minimum_version_id_old = 0,
160
    .fields      = (VMStateField[]) {
161
        VMSTATE_INT32(x, event_data),
162
        VMSTATE_INT32(y, event_data),
163
        VMSTATE_INT32(z, event_data),
164
        VMSTATE_INT32(pointer_buttons, event_data),
165
        VMSTATE_END_OF_LIST()
166
    }
167
};
168

    
169
static const VMStateDescription vmstate_syborg_pointer = {
170
    .name = "syborg_pointer",
171
    .version_id = 1,
172
    .minimum_version_id = 1,
173
    .minimum_version_id_old = 1,
174
    .fields      = (VMStateField[]) {
175
        VMSTATE_UINT32_EQUAL(fifo_size, SyborgPointerState),
176
        VMSTATE_UINT32_EQUAL(absolute, SyborgPointerState),
177
        VMSTATE_INT32(int_enabled, SyborgPointerState),
178
        VMSTATE_INT32(read_pos, SyborgPointerState),
179
        VMSTATE_INT32(read_count, SyborgPointerState),
180
        VMSTATE_STRUCT_VARRAY_UINT32(event_fifo, SyborgPointerState, fifo_size,
181
                                     1, vmstate_event_data, event_data),
182
        VMSTATE_END_OF_LIST()
183
    }
184
};
185

    
186
static int syborg_pointer_init(SysBusDevice *dev)
187
{
188
    SyborgPointerState *s = FROM_SYSBUS(SyborgPointerState, dev);
189
    int iomemtype;
190

    
191
    sysbus_init_irq(dev, &s->irq);
192
    iomemtype = cpu_register_io_memory(syborg_pointer_readfn,
193
                                       syborg_pointer_writefn, s,
194
                                       DEVICE_NATIVE_ENDIAN);
195
    sysbus_init_mmio(dev, 0x1000, iomemtype);
196

    
197
    if (s->fifo_size <= 0) {
198
        fprintf(stderr, "syborg_pointer: fifo too small\n");
199
        s->fifo_size = 16;
200
    }
201
    s->event_fifo = qemu_mallocz(s->fifo_size * sizeof(s->event_fifo[0]));
202

    
203
    qemu_add_mouse_event_handler(syborg_pointer_event, s, s->absolute,
204
                                 "Syborg Pointer");
205

    
206
    vmstate_register(&dev->qdev, -1, &vmstate_syborg_pointer, s);
207
    return 0;
208
}
209

    
210
static SysBusDeviceInfo syborg_pointer_info = {
211
    .init = syborg_pointer_init,
212
    .qdev.name  = "syborg,pointer",
213
    .qdev.size  = sizeof(SyborgPointerState),
214
    .qdev.props = (Property[]) {
215
        DEFINE_PROP_UINT32("fifo-size", SyborgPointerState, fifo_size, 16),
216
        DEFINE_PROP_UINT32("absolute",  SyborgPointerState, absolute,   1),
217
        DEFINE_PROP_END_OF_LIST(),
218
    }
219
};
220

    
221
static void syborg_pointer_register_devices(void)
222
{
223
    sysbus_register_withprop(&syborg_pointer_info);
224
}
225

    
226
device_init(syborg_pointer_register_devices)