virt-acpi-build: add always-on property for timer
[qemu/ar7.git] / hw / input / virtio-input.c
blobf12ed8a50476f7ddfef6ba63bebf2dbfae1245cc
1 /*
2 * This work is licensed under the terms of the GNU GPL, version 2 or
3 * (at your option) any later version. See the COPYING file in the
4 * top-level directory.
5 */
7 #include "qemu/osdep.h"
8 #include "qemu/iov.h"
10 #include "hw/qdev.h"
11 #include "hw/virtio/virtio.h"
12 #include "hw/virtio/virtio-input.h"
14 #include "standard-headers/linux/input.h"
16 /* ----------------------------------------------------------------- */
18 void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
20 VirtQueueElement elem;
21 unsigned have, need;
22 int i, len;
24 if (!vinput->active) {
25 return;
28 /* queue up events ... */
29 if (vinput->qindex == vinput->qsize) {
30 vinput->qsize++;
31 vinput->queue = realloc(vinput->queue, vinput->qsize *
32 sizeof(virtio_input_event));
34 vinput->queue[vinput->qindex++] = *event;
36 /* ... until we see a report sync ... */
37 if (event->type != cpu_to_le16(EV_SYN) ||
38 event->code != cpu_to_le16(SYN_REPORT)) {
39 return;
42 /* ... then check available space ... */
43 need = sizeof(virtio_input_event) * vinput->qindex;
44 virtqueue_get_avail_bytes(vinput->evt, &have, NULL, need, 0);
45 if (have < need) {
46 vinput->qindex = 0;
47 fprintf(stderr, "%s: ENOSPC in vq, dropping events\n", __func__);
48 return;
51 /* ... and finally pass them to the guest */
52 for (i = 0; i < vinput->qindex; i++) {
53 if (!virtqueue_pop(vinput->evt, &elem)) {
54 /* should not happen, we've checked for space beforehand */
55 fprintf(stderr, "%s: Huh? No vq elem available ...\n", __func__);
56 return;
58 len = iov_from_buf(elem.in_sg, elem.in_num,
59 0, vinput->queue+i, sizeof(virtio_input_event));
60 virtqueue_push(vinput->evt, &elem, len);
62 virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt);
63 vinput->qindex = 0;
66 static void virtio_input_handle_evt(VirtIODevice *vdev, VirtQueue *vq)
68 /* nothing */
71 static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq)
73 VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
74 VirtIOInput *vinput = VIRTIO_INPUT(vdev);
75 virtio_input_event event;
76 VirtQueueElement elem;
77 int len;
79 while (virtqueue_pop(vinput->sts, &elem)) {
80 memset(&event, 0, sizeof(event));
81 len = iov_to_buf(elem.out_sg, elem.out_num,
82 0, &event, sizeof(event));
83 if (vic->handle_status) {
84 vic->handle_status(vinput, &event);
86 virtqueue_push(vinput->sts, &elem, len);
88 virtio_notify(vdev, vinput->sts);
91 static virtio_input_config *virtio_input_find_config(VirtIOInput *vinput,
92 uint8_t select,
93 uint8_t subsel)
95 VirtIOInputConfig *cfg;
97 QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
98 if (select == cfg->config.select &&
99 subsel == cfg->config.subsel) {
100 return &cfg->config;
103 return NULL;
106 void virtio_input_add_config(VirtIOInput *vinput,
107 virtio_input_config *config)
109 VirtIOInputConfig *cfg;
111 if (virtio_input_find_config(vinput, config->select, config->subsel)) {
112 /* should not happen */
113 fprintf(stderr, "%s: duplicate config: %d/%d\n",
114 __func__, config->select, config->subsel);
115 abort();
118 cfg = g_new0(VirtIOInputConfig, 1);
119 cfg->config = *config;
120 QTAILQ_INSERT_TAIL(&vinput->cfg_list, cfg, node);
123 void virtio_input_init_config(VirtIOInput *vinput,
124 virtio_input_config *config)
126 int i = 0;
128 QTAILQ_INIT(&vinput->cfg_list);
129 while (config[i].select) {
130 virtio_input_add_config(vinput, config + i);
131 i++;
135 void virtio_input_idstr_config(VirtIOInput *vinput,
136 uint8_t select, const char *string)
138 virtio_input_config id;
140 if (!string) {
141 return;
143 memset(&id, 0, sizeof(id));
144 id.select = select;
145 id.size = snprintf(id.u.string, sizeof(id.u.string), "%s", string);
146 virtio_input_add_config(vinput, &id);
149 static void virtio_input_get_config(VirtIODevice *vdev, uint8_t *config_data)
151 VirtIOInput *vinput = VIRTIO_INPUT(vdev);
152 virtio_input_config *config;
154 config = virtio_input_find_config(vinput, vinput->cfg_select,
155 vinput->cfg_subsel);
156 if (config) {
157 memcpy(config_data, config, vinput->cfg_size);
158 } else {
159 memset(config_data, 0, vinput->cfg_size);
163 static void virtio_input_set_config(VirtIODevice *vdev,
164 const uint8_t *config_data)
166 VirtIOInput *vinput = VIRTIO_INPUT(vdev);
167 virtio_input_config *config = (virtio_input_config *)config_data;
169 vinput->cfg_select = config->select;
170 vinput->cfg_subsel = config->subsel;
171 virtio_notify_config(vdev);
174 static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f,
175 Error **errp)
177 return f;
180 static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val)
182 VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
183 VirtIOInput *vinput = VIRTIO_INPUT(vdev);
185 if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
186 if (!vinput->active) {
187 vinput->active = true;
188 if (vic->change_active) {
189 vic->change_active(vinput);
195 static void virtio_input_reset(VirtIODevice *vdev)
197 VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
198 VirtIOInput *vinput = VIRTIO_INPUT(vdev);
200 if (vinput->active) {
201 vinput->active = false;
202 if (vic->change_active) {
203 vic->change_active(vinput);
208 static void virtio_input_device_realize(DeviceState *dev, Error **errp)
210 VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
211 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
212 VirtIOInput *vinput = VIRTIO_INPUT(dev);
213 VirtIOInputConfig *cfg;
214 Error *local_err = NULL;
216 if (vic->realize) {
217 vic->realize(dev, &local_err);
218 if (local_err) {
219 error_propagate(errp, local_err);
220 return;
224 virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SERIAL,
225 vinput->serial);
227 QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
228 if (vinput->cfg_size < cfg->config.size) {
229 vinput->cfg_size = cfg->config.size;
232 vinput->cfg_size += 8;
233 assert(vinput->cfg_size <= sizeof(virtio_input_config));
235 virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT,
236 vinput->cfg_size);
237 vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt);
238 vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts);
241 static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
243 VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
244 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
245 Error *local_err = NULL;
247 if (vic->unrealize) {
248 vic->unrealize(dev, &local_err);
249 if (local_err) {
250 error_propagate(errp, local_err);
251 return;
254 virtio_cleanup(vdev);
257 static Property virtio_input_properties[] = {
258 DEFINE_PROP_STRING("serial", VirtIOInput, serial),
259 DEFINE_PROP_END_OF_LIST(),
262 static void virtio_input_class_init(ObjectClass *klass, void *data)
264 DeviceClass *dc = DEVICE_CLASS(klass);
265 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
267 dc->props = virtio_input_properties;
268 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
269 vdc->realize = virtio_input_device_realize;
270 vdc->unrealize = virtio_input_device_unrealize;
271 vdc->get_config = virtio_input_get_config;
272 vdc->set_config = virtio_input_set_config;
273 vdc->get_features = virtio_input_get_features;
274 vdc->set_status = virtio_input_set_status;
275 vdc->reset = virtio_input_reset;
278 static const TypeInfo virtio_input_info = {
279 .name = TYPE_VIRTIO_INPUT,
280 .parent = TYPE_VIRTIO_DEVICE,
281 .instance_size = sizeof(VirtIOInput),
282 .class_size = sizeof(VirtIOInputClass),
283 .class_init = virtio_input_class_init,
284 .abstract = true,
287 /* ----------------------------------------------------------------- */
289 static void virtio_register_types(void)
291 type_register_static(&virtio_input_info);
294 type_init(virtio_register_types)