]> Git Repo - qemu.git/blob - hw/syborg_pointer.c
a0f8b32ab627c54c6e69485fd64b49abc9628684
[qemu.git] / 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     MemoryRegion iomem;
48     int int_enabled;
49     uint32_t fifo_size;
50     event_data *event_fifo;
51     int read_pos, read_count;
52     qemu_irq irq;
53     uint32_t absolute;
54 } SyborgPointerState;
55
56 static void syborg_pointer_update(SyborgPointerState *s)
57 {
58     qemu_set_irq(s->irq, s->read_count && s->int_enabled);
59 }
60
61 static uint64_t syborg_pointer_read(void *opaque, target_phys_addr_t offset,
62                                     unsigned size)
63 {
64     SyborgPointerState *s = (SyborgPointerState *)opaque;
65
66     offset &= 0xfff;
67     switch (offset >> 2) {
68     case POINTER_ID:
69         return s->absolute ? SYBORG_ID_TOUCHSCREEN : SYBORG_ID_MOUSE;
70     case POINTER_FIFO_COUNT:
71         return s->read_count;
72     case POINTER_X:
73         return s->event_fifo[s->read_pos].x;
74     case POINTER_Y:
75         return s->event_fifo[s->read_pos].y;
76     case POINTER_Z:
77         return s->event_fifo[s->read_pos].z;
78     case POINTER_BUTTONS:
79         return s->event_fifo[s->read_pos].pointer_buttons;
80     case POINTER_INT_ENABLE:
81         return s->int_enabled;
82     case POINTER_FIFO_SIZE:
83         return s->fifo_size;
84     default:
85         cpu_abort(cpu_single_env, "syborg_pointer_read: Bad offset %x\n",
86                   (int)offset);
87         return 0;
88     }
89 }
90
91 static void syborg_pointer_write(void *opaque, target_phys_addr_t offset,
92                                  uint64_t value, unsigned size)
93 {
94     SyborgPointerState *s = (SyborgPointerState *)opaque;
95
96     offset &= 0xfff;
97     switch (offset >> 2) {
98     case POINTER_LATCH:
99         if (s->read_count > 0) {
100             s->read_count--;
101             if (++s->read_pos == s->fifo_size)
102                 s->read_pos = 0;
103         }
104         break;
105     case POINTER_INT_ENABLE:
106         s->int_enabled = value;
107         break;
108     default:
109         cpu_abort(cpu_single_env, "syborg_pointer_write: Bad offset %x\n",
110                   (int)offset);
111     }
112     syborg_pointer_update(s);
113 }
114
115 static const MemoryRegionOps syborg_pointer_ops = {
116     .read = syborg_pointer_read,
117     .write = syborg_pointer_write,
118     .endianness = DEVICE_NATIVE_ENDIAN,
119 };
120
121 static void syborg_pointer_event(void *opaque, int dx, int dy, int dz,
122                                  int buttons_state)
123 {
124     SyborgPointerState *s = (SyborgPointerState *)opaque;
125     int slot = s->read_pos + s->read_count;
126
127     /* This first FIFO entry is used to store current register state.  */
128     if (s->read_count < s->fifo_size - 1) {
129         s->read_count++;
130         slot++;
131     }
132
133     if (slot >= s->fifo_size)
134           slot -= s->fifo_size;
135
136     if (s->read_count == s->fifo_size && !s->absolute) {
137         /* Merge existing entries.  */
138         s->event_fifo[slot].x += dx;
139         s->event_fifo[slot].y += dy;
140         s->event_fifo[slot].z += dz;
141     } else {
142         s->event_fifo[slot].x = dx;
143         s->event_fifo[slot].y = dy;
144         s->event_fifo[slot].z = dz;
145     }
146     s->event_fifo[slot].pointer_buttons = buttons_state;
147
148     syborg_pointer_update(s);
149 }
150
151 static const VMStateDescription vmstate_event_data = {
152     .name = "dbma_channel",
153     .version_id = 0,
154     .minimum_version_id = 0,
155     .minimum_version_id_old = 0,
156     .fields      = (VMStateField[]) {
157         VMSTATE_INT32(x, event_data),
158         VMSTATE_INT32(y, event_data),
159         VMSTATE_INT32(z, event_data),
160         VMSTATE_INT32(pointer_buttons, event_data),
161         VMSTATE_END_OF_LIST()
162     }
163 };
164
165 static const VMStateDescription vmstate_syborg_pointer = {
166     .name = "syborg_pointer",
167     .version_id = 1,
168     .minimum_version_id = 1,
169     .minimum_version_id_old = 1,
170     .fields      = (VMStateField[]) {
171         VMSTATE_UINT32_EQUAL(fifo_size, SyborgPointerState),
172         VMSTATE_UINT32_EQUAL(absolute, SyborgPointerState),
173         VMSTATE_INT32(int_enabled, SyborgPointerState),
174         VMSTATE_INT32(read_pos, SyborgPointerState),
175         VMSTATE_INT32(read_count, SyborgPointerState),
176         VMSTATE_STRUCT_VARRAY_UINT32(event_fifo, SyborgPointerState, fifo_size,
177                                      1, vmstate_event_data, event_data),
178         VMSTATE_END_OF_LIST()
179     }
180 };
181
182 static int syborg_pointer_init(SysBusDevice *dev)
183 {
184     SyborgPointerState *s = FROM_SYSBUS(SyborgPointerState, dev);
185
186     sysbus_init_irq(dev, &s->irq);
187     memory_region_init_io(&s->iomem, &syborg_pointer_ops, s,
188                           "pointer", 0x1000);
189     sysbus_init_mmio_region(dev, &s->iomem);
190
191     if (s->fifo_size <= 0) {
192         fprintf(stderr, "syborg_pointer: fifo too small\n");
193         s->fifo_size = 16;
194     }
195     s->event_fifo = g_malloc0(s->fifo_size * sizeof(s->event_fifo[0]));
196
197     qemu_add_mouse_event_handler(syborg_pointer_event, s, s->absolute,
198                                  "Syborg Pointer");
199
200     vmstate_register(&dev->qdev, -1, &vmstate_syborg_pointer, s);
201     return 0;
202 }
203
204 static SysBusDeviceInfo syborg_pointer_info = {
205     .init = syborg_pointer_init,
206     .qdev.name  = "syborg,pointer",
207     .qdev.size  = sizeof(SyborgPointerState),
208     .qdev.props = (Property[]) {
209         DEFINE_PROP_UINT32("fifo-size", SyborgPointerState, fifo_size, 16),
210         DEFINE_PROP_UINT32("absolute",  SyborgPointerState, absolute,   1),
211         DEFINE_PROP_END_OF_LIST(),
212     }
213 };
214
215 static void syborg_pointer_register_devices(void)
216 {
217     sysbus_register_withprop(&syborg_pointer_info);
218 }
219
220 device_init(syborg_pointer_register_devices)
This page took 0.028466 seconds and 2 git commands to generate.