]>
Commit | Line | Data |
---|---|---|
006a5ede 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-common.h" | |
8 | #include "qemu/sockets.h" | |
9 | ||
10 | #include "hw/qdev.h" | |
11 | #include "hw/virtio/virtio.h" | |
12 | #include "hw/virtio/virtio-input.h" | |
13 | ||
14 | #include "standard-headers/linux/input.h" | |
15 | ||
16 | /* ----------------------------------------------------------------- */ | |
17 | ||
18 | static struct virtio_input_config virtio_input_host_config[] = { | |
19 | { /* empty list */ }, | |
20 | }; | |
21 | ||
22 | static void virtio_input_host_event(void *opaque) | |
23 | { | |
24 | VirtIOInputHost *vih = opaque; | |
25 | VirtIOInput *vinput = VIRTIO_INPUT(vih); | |
26 | struct virtio_input_event virtio; | |
27 | struct input_event evdev; | |
28 | int rc; | |
29 | ||
30 | for (;;) { | |
31 | rc = read(vih->fd, &evdev, sizeof(evdev)); | |
32 | if (rc != sizeof(evdev)) { | |
33 | break; | |
34 | } | |
35 | ||
36 | virtio.type = cpu_to_le16(evdev.type); | |
37 | virtio.code = cpu_to_le16(evdev.code); | |
38 | virtio.value = cpu_to_le32(evdev.value); | |
39 | virtio_input_send(vinput, &virtio); | |
40 | } | |
41 | } | |
42 | ||
43 | static void virtio_input_bits_config(VirtIOInputHost *vih, | |
44 | int type, int count) | |
45 | { | |
46 | virtio_input_config bits; | |
47 | int rc, i, size = 0; | |
48 | ||
49 | memset(&bits, 0, sizeof(bits)); | |
50 | rc = ioctl(vih->fd, EVIOCGBIT(type, count/8), bits.u.bitmap); | |
51 | if (rc < 0) { | |
52 | return; | |
53 | } | |
54 | ||
55 | for (i = 0; i < count/8; i++) { | |
56 | if (bits.u.bitmap[i]) { | |
57 | size = i+1; | |
58 | } | |
59 | } | |
60 | if (size == 0) { | |
61 | return; | |
62 | } | |
63 | ||
64 | bits.select = VIRTIO_INPUT_CFG_EV_BITS; | |
65 | bits.subsel = type; | |
66 | bits.size = size; | |
67 | virtio_input_add_config(VIRTIO_INPUT(vih), &bits); | |
68 | } | |
69 | ||
70 | static void virtio_input_host_realize(DeviceState *dev, Error **errp) | |
71 | { | |
72 | VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev); | |
73 | VirtIOInput *vinput = VIRTIO_INPUT(dev); | |
74 | virtio_input_config id; | |
75 | struct input_id ids; | |
76 | int rc, ver; | |
77 | ||
78 | if (!vih->evdev) { | |
79 | error_setg(errp, "evdev property is required"); | |
80 | return; | |
81 | } | |
82 | ||
83 | vih->fd = open(vih->evdev, O_RDWR); | |
84 | if (vih->fd < 0) { | |
85 | error_setg_file_open(errp, errno, vih->evdev); | |
86 | return; | |
87 | } | |
88 | qemu_set_nonblock(vih->fd); | |
89 | ||
90 | rc = ioctl(vih->fd, EVIOCGVERSION, &ver); | |
91 | if (rc < 0) { | |
92 | error_setg(errp, "%s: is not an evdev device", vih->evdev); | |
93 | goto err_close; | |
94 | } | |
95 | ||
96 | rc = ioctl(vih->fd, EVIOCGRAB, 1); | |
97 | if (rc < 0) { | |
98 | error_setg_errno(errp, errno, "%s: failed to get exclusive access", | |
99 | vih->evdev); | |
100 | goto err_close; | |
101 | } | |
102 | ||
103 | memset(&id, 0, sizeof(id)); | |
104 | ioctl(vih->fd, EVIOCGNAME(sizeof(id.u.string)-1), id.u.string); | |
105 | id.select = VIRTIO_INPUT_CFG_ID_NAME; | |
106 | id.size = strlen(id.u.string); | |
107 | virtio_input_add_config(vinput, &id); | |
108 | ||
109 | if (ioctl(vih->fd, EVIOCGID, &ids) == 0) { | |
110 | memset(&id, 0, sizeof(id)); | |
111 | id.select = VIRTIO_INPUT_CFG_ID_DEVIDS; | |
112 | id.size = sizeof(struct virtio_input_devids); | |
113 | id.u.ids.bustype = cpu_to_le16(ids.bustype); | |
114 | id.u.ids.vendor = cpu_to_le16(ids.vendor); | |
115 | id.u.ids.product = cpu_to_le16(ids.product); | |
116 | id.u.ids.version = cpu_to_le16(ids.version); | |
117 | virtio_input_add_config(vinput, &id); | |
118 | } | |
119 | ||
120 | virtio_input_bits_config(vih, EV_KEY, KEY_CNT); | |
121 | virtio_input_bits_config(vih, EV_REL, REL_CNT); | |
122 | virtio_input_bits_config(vih, EV_ABS, ABS_CNT); | |
123 | virtio_input_bits_config(vih, EV_MSC, MSC_CNT); | |
124 | virtio_input_bits_config(vih, EV_SW, SW_CNT); | |
125 | ||
126 | qemu_set_fd_handler(vih->fd, virtio_input_host_event, NULL, vih); | |
127 | return; | |
128 | ||
129 | err_close: | |
130 | close(vih->fd); | |
131 | vih->fd = -1; | |
132 | return; | |
133 | } | |
134 | ||
135 | static void virtio_input_host_unrealize(DeviceState *dev, Error **errp) | |
136 | { | |
137 | VirtIOInputHost *vih = VIRTIO_INPUT_HOST(dev); | |
138 | ||
139 | if (vih->fd > 0) { | |
140 | qemu_set_fd_handler(vih->fd, NULL, NULL, NULL); | |
141 | close(vih->fd); | |
142 | } | |
143 | } | |
144 | ||
145 | static const VMStateDescription vmstate_virtio_input_host = { | |
146 | .name = "virtio-input-host", | |
147 | .unmigratable = 1, | |
148 | }; | |
149 | ||
150 | static Property virtio_input_host_properties[] = { | |
151 | DEFINE_PROP_STRING("evdev", VirtIOInputHost, evdev), | |
152 | DEFINE_PROP_END_OF_LIST(), | |
153 | }; | |
154 | ||
155 | static void virtio_input_host_class_init(ObjectClass *klass, void *data) | |
156 | { | |
157 | VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass); | |
158 | DeviceClass *dc = DEVICE_CLASS(klass); | |
159 | ||
160 | dc->vmsd = &vmstate_virtio_input_host; | |
161 | dc->props = virtio_input_host_properties; | |
162 | vic->realize = virtio_input_host_realize; | |
163 | vic->unrealize = virtio_input_host_unrealize; | |
164 | } | |
165 | ||
166 | static void virtio_input_host_init(Object *obj) | |
167 | { | |
168 | VirtIOInput *vinput = VIRTIO_INPUT(obj); | |
169 | ||
170 | virtio_input_init_config(vinput, virtio_input_host_config); | |
171 | } | |
172 | ||
173 | static const TypeInfo virtio_input_host_info = { | |
174 | .name = TYPE_VIRTIO_INPUT_HOST, | |
175 | .parent = TYPE_VIRTIO_INPUT, | |
176 | .instance_size = sizeof(VirtIOInputHost), | |
177 | .instance_init = virtio_input_host_init, | |
178 | .class_init = virtio_input_host_class_init, | |
179 | }; | |
180 | ||
181 | /* ----------------------------------------------------------------- */ | |
182 | ||
183 | static void virtio_register_types(void) | |
184 | { | |
185 | type_register_static(&virtio_input_host_info); | |
186 | } | |
187 | ||
188 | type_init(virtio_register_types) |