linux-user: fix ppc target_stat64 st_blocks layout
[qemu] / hw / syborg_pointer.c
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("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)