qemu

Форк
0
/
virtio-input-host.c 
263 строки · 7.3 Кб
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/osdep.h"
8
#include "qapi/error.h"
9
#include "qemu/module.h"
10
#include "qemu/sockets.h"
11

12
#include "hw/virtio/virtio.h"
13
#include "hw/qdev-properties.h"
14
#include "hw/virtio/virtio-input.h"
15

16
#include <sys/ioctl.h>
17
#include "standard-headers/linux/input.h"
18

19
/* ----------------------------------------------------------------- */
20

21
static struct virtio_input_config virtio_input_host_config[] = {
22
    { /* empty list */ },
23
};
24

25
static void virtio_input_host_event(void *opaque)
26
{
27
    VirtIOInputHost *vih = opaque;
28
    VirtIOInput *vinput = VIRTIO_INPUT(vih);
29
    struct virtio_input_event virtio;
30
    struct input_event evdev;
31
    int rc;
32

33
    for (;;) {
34
        rc = read(vih->fd, &evdev, sizeof(evdev));
35
        if (rc != sizeof(evdev)) {
36
            break;
37
        }
38

39
        virtio.type  = cpu_to_le16(evdev.type);
40
        virtio.code  = cpu_to_le16(evdev.code);
41
        virtio.value = cpu_to_le32(evdev.value);
42
        virtio_input_send(vinput, &virtio);
43
    }
44
}
45

46
static void virtio_input_bits_config(VirtIOInputHost *vih,
47
                                     int type, int count)
48
{
49
    virtio_input_config bits;
50
    int rc, i, size = 0;
51

52
    memset(&bits, 0, sizeof(bits));
53
    rc = ioctl(vih->fd, EVIOCGBIT(type, count/8), bits.u.bitmap);
54
    if (rc < 0) {
55
        return;
56
    }
57

58
    for (i = 0; i < count/8; i++) {
59
        if (bits.u.bitmap[i]) {
60
            size = i+1;
61
        }
62
    }
63
    if (size == 0) {
64
        return;
65
    }
66

67
    bits.select = VIRTIO_INPUT_CFG_EV_BITS;
68
    bits.subsel = type;
69
    bits.size   = size;
70
    virtio_input_add_config(VIRTIO_INPUT(vih), &bits);
71
}
72

73
static void virtio_input_abs_config(VirtIOInputHost *vih, int axis)
74
{
75
    virtio_input_config config;
76
    struct input_absinfo absinfo;
77
    int rc;
78

79
    rc = ioctl(vih->fd, EVIOCGABS(axis), &absinfo);
80
    if (rc < 0) {
81
        return;
82
    }
83

84
    memset(&config, 0, sizeof(config));
85
    config.select = VIRTIO_INPUT_CFG_ABS_INFO;
86
    config.subsel = axis;
87
    config.size   = sizeof(virtio_input_absinfo);
88

89
    config.u.abs.min  = cpu_to_le32(absinfo.minimum);
90
    config.u.abs.max  = cpu_to_le32(absinfo.maximum);
91
    config.u.abs.fuzz = cpu_to_le32(absinfo.fuzz);
92
    config.u.abs.flat = cpu_to_le32(absinfo.flat);
93
    config.u.abs.res  = cpu_to_le32(absinfo.resolution);
94

95
    virtio_input_add_config(VIRTIO_INPUT(vih), &config);
96
}
97

98
static void virtio_input_host_realize(DeviceState *dev, Error **errp)
99
{
100
    VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev);
101
    VirtIOInput *vinput = VIRTIO_INPUT(dev);
102
    virtio_input_config id, *abs;
103
    struct input_id ids;
104
    int rc, ver, i, axis;
105
    uint8_t byte;
106

107
    if (!vih->evdev) {
108
        error_setg(errp, "evdev property is required");
109
        return;
110
    }
111

112
    vih->fd = open(vih->evdev, O_RDWR);
113
    if (vih->fd < 0)  {
114
        error_setg_file_open(errp, errno, vih->evdev);
115
        return;
116
    }
117
    if (!g_unix_set_fd_nonblocking(vih->fd, true, NULL)) {
118
        error_setg_errno(errp, errno, "Failed to set FD nonblocking");
119
        goto err_close;
120
    }
121

122
    rc = ioctl(vih->fd, EVIOCGVERSION, &ver);
123
    if (rc < 0) {
124
        error_setg(errp, "%s: is not an evdev device", vih->evdev);
125
        goto err_close;
126
    }
127

128
    rc = ioctl(vih->fd, EVIOCGRAB, 1);
129
    if (rc < 0) {
130
        error_setg_errno(errp, errno, "%s: failed to get exclusive access",
131
                         vih->evdev);
132
        goto err_close;
133
    }
134

135
    memset(&id, 0, sizeof(id));
136
    ioctl(vih->fd, EVIOCGNAME(sizeof(id.u.string)-1), id.u.string);
137
    id.select = VIRTIO_INPUT_CFG_ID_NAME;
138
    id.size = strlen(id.u.string);
139
    virtio_input_add_config(vinput, &id);
140

141
    if (ioctl(vih->fd, EVIOCGID, &ids) == 0) {
142
        memset(&id, 0, sizeof(id));
143
        id.select = VIRTIO_INPUT_CFG_ID_DEVIDS;
144
        id.size = sizeof(struct virtio_input_devids);
145
        id.u.ids.bustype = cpu_to_le16(ids.bustype);
146
        id.u.ids.vendor  = cpu_to_le16(ids.vendor);
147
        id.u.ids.product = cpu_to_le16(ids.product);
148
        id.u.ids.version = cpu_to_le16(ids.version);
149
        virtio_input_add_config(vinput, &id);
150
    }
151

152
    virtio_input_bits_config(vih, EV_KEY, KEY_CNT);
153
    virtio_input_bits_config(vih, EV_REL, REL_CNT);
154
    virtio_input_bits_config(vih, EV_ABS, ABS_CNT);
155
    virtio_input_bits_config(vih, EV_MSC, MSC_CNT);
156
    virtio_input_bits_config(vih, EV_SW,  SW_CNT);
157
    virtio_input_bits_config(vih, EV_LED, LED_CNT);
158

159
    abs = virtio_input_find_config(VIRTIO_INPUT(vih),
160
        VIRTIO_INPUT_CFG_EV_BITS, EV_ABS);
161
    if (abs) {
162
        for (i = 0; i < abs->size; i++) {
163
            byte = abs->u.bitmap[i];
164
            axis = 8 * i;
165
            while (byte) {
166
                if (byte & 1) {
167
                    virtio_input_abs_config(vih, axis);
168
                }
169
                axis++;
170
                byte >>= 1;
171
            }
172
        }
173
    }
174

175
    qemu_set_fd_handler(vih->fd, virtio_input_host_event, NULL, vih);
176
    return;
177

178
err_close:
179
    close(vih->fd);
180
    vih->fd = -1;
181
    return;
182
}
183

184
static void virtio_input_host_unrealize(DeviceState *dev)
185
{
186
    VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev);
187

188
    if (vih->fd > 0) {
189
        qemu_set_fd_handler(vih->fd, NULL, NULL, NULL);
190
        close(vih->fd);
191
    }
192
}
193

194
static void virtio_input_host_handle_status(VirtIOInput *vinput,
195
                                            virtio_input_event *event)
196
{
197
    VirtIOInputHost *vih = VIRTIO_INPUT_HOST(vinput);
198
    struct input_event evdev;
199
    struct timeval tval;
200
    int rc;
201

202
    if (gettimeofday(&tval, NULL)) {
203
        perror("virtio_input_host_handle_status: gettimeofday");
204
        return;
205
    }
206

207
    evdev.input_event_sec = tval.tv_sec;
208
    evdev.input_event_usec = tval.tv_usec;
209
    evdev.type = le16_to_cpu(event->type);
210
    evdev.code = le16_to_cpu(event->code);
211
    evdev.value = le32_to_cpu(event->value);
212

213
    rc = write(vih->fd, &evdev, sizeof(evdev));
214
    if (rc == -1) {
215
        perror("virtio_input_host_handle_status: write");
216
    }
217
}
218

219
static const VMStateDescription vmstate_virtio_input_host = {
220
    .name = "virtio-input-host",
221
    .unmigratable = 1,
222
};
223

224
static Property virtio_input_host_properties[] = {
225
    DEFINE_PROP_STRING("evdev", VirtIOInputHost, evdev),
226
    DEFINE_PROP_END_OF_LIST(),
227
};
228

229
static void virtio_input_host_class_init(ObjectClass *klass, void *data)
230
{
231
    VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass);
232
    DeviceClass *dc = DEVICE_CLASS(klass);
233

234
    dc->vmsd           = &vmstate_virtio_input_host;
235
    device_class_set_props(dc, virtio_input_host_properties);
236
    vic->realize       = virtio_input_host_realize;
237
    vic->unrealize     = virtio_input_host_unrealize;
238
    vic->handle_status = virtio_input_host_handle_status;
239
}
240

241
static void virtio_input_host_init(Object *obj)
242
{
243
    VirtIOInput *vinput = VIRTIO_INPUT(obj);
244

245
    virtio_input_init_config(vinput, virtio_input_host_config);
246
}
247

248
static const TypeInfo virtio_input_host_info = {
249
    .name          = TYPE_VIRTIO_INPUT_HOST,
250
    .parent        = TYPE_VIRTIO_INPUT,
251
    .instance_size = sizeof(VirtIOInputHost),
252
    .instance_init = virtio_input_host_init,
253
    .class_init    = virtio_input_host_class_init,
254
};
255

256
/* ----------------------------------------------------------------- */
257

258
static void virtio_register_types(void)
259
{
260
    type_register_static(&virtio_input_host_info);
261
}
262

263
type_init(virtio_register_types)
264

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.