]> Git Repo - qemu.git/blame - hw/input/virtio-input.c
ivshmem: fix pci_ivshmem_exit()
[qemu.git] / hw / input / virtio-input.c
CommitLineData
f73ddbad
GH
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 */
6
7#include "qemu/iov.h"
8
9#include "hw/qdev.h"
10#include "hw/virtio/virtio.h"
11#include "hw/virtio/virtio-input.h"
12
13#include "standard-headers/linux/input.h"
14
15/* ----------------------------------------------------------------- */
16
17void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
18{
19 VirtQueueElement elem;
20 unsigned have, need;
21 int i, len;
22
d9460a75
GH
23 if (!vinput->active) {
24 return;
25 }
26
f73ddbad
GH
27 /* queue up events ... */
28 if (vinput->qindex == vinput->qsize) {
29 vinput->qsize++;
30 vinput->queue = realloc(vinput->queue, vinput->qsize *
31 sizeof(virtio_input_event));
32 }
33 vinput->queue[vinput->qindex++] = *event;
34
35 /* ... until we see a report sync ... */
36 if (event->type != cpu_to_le16(EV_SYN) ||
37 event->code != cpu_to_le16(SYN_REPORT)) {
38 return;
39 }
40
41 /* ... then check available space ... */
42 need = sizeof(virtio_input_event) * vinput->qindex;
43 virtqueue_get_avail_bytes(vinput->evt, &have, NULL, need, 0);
44 if (have < need) {
45 vinput->qindex = 0;
46 fprintf(stderr, "%s: ENOSPC in vq, dropping events\n", __func__);
47 return;
48 }
49
50 /* ... and finally pass them to the guest */
51 for (i = 0; i < vinput->qindex; i++) {
52 if (!virtqueue_pop(vinput->evt, &elem)) {
53 /* should not happen, we've checked for space beforehand */
54 fprintf(stderr, "%s: Huh? No vq elem available ...\n", __func__);
55 return;
56 }
57 len = iov_from_buf(elem.in_sg, elem.in_num,
58 0, vinput->queue+i, sizeof(virtio_input_event));
59 virtqueue_push(vinput->evt, &elem, len);
60 }
61 virtio_notify(VIRTIO_DEVICE(vinput), vinput->evt);
62 vinput->qindex = 0;
63}
64
65static void virtio_input_handle_evt(VirtIODevice *vdev, VirtQueue *vq)
66{
67 /* nothing */
68}
69
70static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq)
71{
72 VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
73 VirtIOInput *vinput = VIRTIO_INPUT(vdev);
74 virtio_input_event event;
75 VirtQueueElement elem;
76 int len;
77
78 while (virtqueue_pop(vinput->sts, &elem)) {
79 memset(&event, 0, sizeof(event));
80 len = iov_to_buf(elem.out_sg, elem.out_num,
81 0, &event, sizeof(event));
82 if (vic->handle_status) {
83 vic->handle_status(vinput, &event);
84 }
85 virtqueue_push(vinput->sts, &elem, len);
86 }
87 virtio_notify(vdev, vinput->sts);
88}
89
90static virtio_input_config *virtio_input_find_config(VirtIOInput *vinput,
91 uint8_t select,
92 uint8_t subsel)
93{
94 VirtIOInputConfig *cfg;
95
96 QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
97 if (select == cfg->config.select &&
98 subsel == cfg->config.subsel) {
99 return &cfg->config;
100 }
101 }
102 return NULL;
103}
104
105void virtio_input_add_config(VirtIOInput *vinput,
106 virtio_input_config *config)
107{
108 VirtIOInputConfig *cfg;
109
110 if (virtio_input_find_config(vinput, config->select, config->subsel)) {
111 /* should not happen */
112 fprintf(stderr, "%s: duplicate config: %d/%d\n",
113 __func__, config->select, config->subsel);
114 abort();
115 }
116
117 cfg = g_new0(VirtIOInputConfig, 1);
118 cfg->config = *config;
119 QTAILQ_INSERT_TAIL(&vinput->cfg_list, cfg, node);
120}
121
122void virtio_input_init_config(VirtIOInput *vinput,
123 virtio_input_config *config)
124{
125 int i = 0;
126
127 QTAILQ_INIT(&vinput->cfg_list);
128 while (config[i].select) {
129 virtio_input_add_config(vinput, config + i);
130 i++;
131 }
132}
133
134void virtio_input_idstr_config(VirtIOInput *vinput,
135 uint8_t select, const char *string)
136{
137 virtio_input_config id;
138
139 if (!string) {
140 return;
141 }
142 memset(&id, 0, sizeof(id));
143 id.select = select;
144 id.size = snprintf(id.u.string, sizeof(id.u.string), "%s", string);
145 virtio_input_add_config(vinput, &id);
146}
147
148static void virtio_input_get_config(VirtIODevice *vdev, uint8_t *config_data)
149{
150 VirtIOInput *vinput = VIRTIO_INPUT(vdev);
151 virtio_input_config *config;
152
153 config = virtio_input_find_config(vinput, vinput->cfg_select,
154 vinput->cfg_subsel);
155 if (config) {
156 memcpy(config_data, config, vinput->cfg_size);
157 } else {
158 memset(config_data, 0, vinput->cfg_size);
159 }
160}
161
162static void virtio_input_set_config(VirtIODevice *vdev,
163 const uint8_t *config_data)
164{
165 VirtIOInput *vinput = VIRTIO_INPUT(vdev);
166 virtio_input_config *config = (virtio_input_config *)config_data;
167
168 vinput->cfg_select = config->select;
169 vinput->cfg_subsel = config->subsel;
170 virtio_notify_config(vdev);
171}
172
9d5b731d
JW
173static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f,
174 Error **errp)
f73ddbad
GH
175{
176 return f;
177}
178
179static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val)
180{
181 VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
182 VirtIOInput *vinput = VIRTIO_INPUT(vdev);
183
184 if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
185 if (!vinput->active) {
186 vinput->active = true;
187 if (vic->change_active) {
188 vic->change_active(vinput);
189 }
190 }
191 }
192}
193
194static void virtio_input_reset(VirtIODevice *vdev)
195{
196 VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
197 VirtIOInput *vinput = VIRTIO_INPUT(vdev);
198
199 if (vinput->active) {
200 vinput->active = false;
201 if (vic->change_active) {
202 vic->change_active(vinput);
203 }
204 }
205}
206
207static void virtio_input_device_realize(DeviceState *dev, Error **errp)
208{
209 VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
210 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
211 VirtIOInput *vinput = VIRTIO_INPUT(dev);
212 VirtIOInputConfig *cfg;
213 Error *local_err = NULL;
214
215 if (vic->realize) {
216 vic->realize(dev, &local_err);
217 if (local_err) {
218 error_propagate(errp, local_err);
219 return;
220 }
221 }
222
223 virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SERIAL,
6f2b9a5b 224 vinput->serial);
f73ddbad
GH
225
226 QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
227 if (vinput->cfg_size < cfg->config.size) {
228 vinput->cfg_size = cfg->config.size;
229 }
230 }
231 vinput->cfg_size += 8;
232 assert(vinput->cfg_size <= sizeof(virtio_input_config));
233
234 virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT,
235 vinput->cfg_size);
236 vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt);
237 vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts);
238}
239
240static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
241{
242 VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
243 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
244 Error *local_err = NULL;
245
246 if (vic->unrealize) {
247 vic->unrealize(dev, &local_err);
248 if (local_err) {
249 error_propagate(errp, local_err);
250 return;
251 }
252 }
253 virtio_cleanup(vdev);
254}
255
6f2b9a5b
GH
256static Property virtio_input_properties[] = {
257 DEFINE_PROP_STRING("serial", VirtIOInput, serial),
258 DEFINE_PROP_END_OF_LIST(),
259};
260
f73ddbad
GH
261static void virtio_input_class_init(ObjectClass *klass, void *data)
262{
263 DeviceClass *dc = DEVICE_CLASS(klass);
264 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
265
6f2b9a5b 266 dc->props = virtio_input_properties;
f73ddbad
GH
267 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
268 vdc->realize = virtio_input_device_realize;
269 vdc->unrealize = virtio_input_device_unrealize;
270 vdc->get_config = virtio_input_get_config;
271 vdc->set_config = virtio_input_set_config;
272 vdc->get_features = virtio_input_get_features;
273 vdc->set_status = virtio_input_set_status;
274 vdc->reset = virtio_input_reset;
275}
276
277static const TypeInfo virtio_input_info = {
278 .name = TYPE_VIRTIO_INPUT,
279 .parent = TYPE_VIRTIO_DEVICE,
280 .instance_size = sizeof(VirtIOInput),
281 .class_size = sizeof(VirtIOInputClass),
282 .class_init = virtio_input_class_init,
283 .abstract = true,
284};
285
286/* ----------------------------------------------------------------- */
287
288static void virtio_register_types(void)
289{
290 type_register_static(&virtio_input_info);
291}
292
293type_init(virtio_register_types)
This page took 0.066327 seconds and 4 git commands to generate.