1 /*
2 * Copyright (C) 2016 EPAM Systems Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #include "libxl_internal.h"
16
17 #include <xen/io/kbdif.h>
18
libxl__device_vkb_setdefault(libxl__gc * gc,uint32_t domid,libxl_device_vkb * vkb,bool hotplug)19 static int libxl__device_vkb_setdefault(libxl__gc *gc, uint32_t domid,
20 libxl_device_vkb *vkb, bool hotplug)
21 {
22 if (vkb->backend_type == LIBXL_VKB_BACKEND_UNKNOWN) {
23 vkb->backend_type = LIBXL_VKB_BACKEND_QEMU;
24 }
25
26 return libxl__resolve_domid(gc, vkb->backend_domname, &vkb->backend_domid);
27 }
28
libxl__device_vkb_dm_needed(void * e,uint32_t domid)29 static int libxl__device_vkb_dm_needed(void *e, uint32_t domid)
30 {
31 libxl_device_vkb *elem = e;
32
33 return elem->backend_type == LIBXL_VKB_BACKEND_QEMU;
34 }
35
libxl__set_xenstore_vkb(libxl__gc * gc,uint32_t domid,libxl_device_vkb * vkb,flexarray_t * back,flexarray_t * front,flexarray_t * ro_front)36 static int libxl__set_xenstore_vkb(libxl__gc *gc, uint32_t domid,
37 libxl_device_vkb *vkb,
38 flexarray_t *back, flexarray_t *front,
39 flexarray_t *ro_front)
40 {
41 if (vkb->unique_id) {
42 flexarray_append_pair(back, XENKBD_FIELD_UNIQUE_ID, vkb->unique_id);
43 }
44
45 if (vkb->feature_disable_keyboard) {
46 flexarray_append_pair(back, XENKBD_FIELD_FEAT_DSBL_KEYBRD,
47 GCSPRINTF("%u", vkb->feature_disable_keyboard));
48 }
49
50 if (vkb->feature_disable_pointer) {
51 flexarray_append_pair(back, XENKBD_FIELD_FEAT_DSBL_POINTER,
52 GCSPRINTF("%u", vkb->feature_disable_pointer));
53 }
54
55 if (vkb->feature_abs_pointer) {
56 flexarray_append_pair(back, XENKBD_FIELD_FEAT_ABS_POINTER,
57 GCSPRINTF("%u", vkb->feature_abs_pointer));
58 }
59
60 if (vkb->feature_raw_pointer) {
61 flexarray_append_pair(back, XENKBD_FIELD_FEAT_RAW_POINTER,
62 GCSPRINTF("%u", vkb->feature_raw_pointer));
63 }
64
65 if (vkb->feature_multi_touch) {
66 flexarray_append_pair(back, XENKBD_FIELD_FEAT_MTOUCH,
67 GCSPRINTF("%u", vkb->feature_multi_touch));
68 flexarray_append_pair(back, XENKBD_FIELD_MT_WIDTH,
69 GCSPRINTF("%u", vkb->multi_touch_width));
70 flexarray_append_pair(back, XENKBD_FIELD_MT_HEIGHT,
71 GCSPRINTF("%u", vkb->multi_touch_height));
72 flexarray_append_pair(back, XENKBD_FIELD_MT_NUM_CONTACTS,
73 GCSPRINTF("%u", vkb->multi_touch_num_contacts));
74 }
75
76 if (vkb->width) {
77 flexarray_append_pair(back, XENKBD_FIELD_WIDTH,
78 GCSPRINTF("%u", vkb->width));
79 }
80
81 if (vkb->height) {
82 flexarray_append_pair(back, XENKBD_FIELD_HEIGHT,
83 GCSPRINTF("%u", vkb->height));
84 }
85
86 return 0;
87 }
88
libxl__vkb_from_xenstore(libxl__gc * gc,const char * libxl_path,libxl_devid devid,libxl_device_vkb * vkb)89 static int libxl__vkb_from_xenstore(libxl__gc *gc, const char *libxl_path,
90 libxl_devid devid,
91 libxl_device_vkb *vkb)
92 {
93 const char *be_path, *fe_path, *tmp;
94 libxl__device dev;
95 int rc;
96
97 vkb->devid = devid;
98
99 rc = libxl__xs_read_mandatory(gc, XBT_NULL,
100 GCSPRINTF("%s/backend", libxl_path),
101 &be_path);
102 if (rc) goto out;
103
104 rc = libxl__xs_read_mandatory(gc, XBT_NULL,
105 GCSPRINTF("%s/frontend", libxl_path),
106 &fe_path);
107 if (rc) goto out;
108
109 rc = libxl__backendpath_parse_domid(gc, be_path, &vkb->backend_domid);
110 if (rc) goto out;
111
112 rc = libxl__parse_backend_path(gc, be_path, &dev);
113 if (rc) goto out;
114
115 vkb->backend_type = dev.backend_kind == LIBXL__DEVICE_KIND_VINPUT ?
116 LIBXL_VKB_BACKEND_LINUX : LIBXL_VKB_BACKEND_QEMU;
117
118 vkb->unique_id = xs_read(CTX->xsh, XBT_NULL, GCSPRINTF("%s/"XENKBD_FIELD_UNIQUE_ID, be_path), NULL);
119
120 rc = libxl__xs_read_checked(gc, XBT_NULL,
121 GCSPRINTF("%s/"XENKBD_FIELD_FEAT_DSBL_KEYBRD,
122 be_path), &tmp);
123 if (rc) goto out;
124
125 if (tmp) {
126 vkb->feature_disable_keyboard = strtoul(tmp, NULL, 0);
127 }
128
129 rc = libxl__xs_read_checked(gc, XBT_NULL,
130 GCSPRINTF("%s/"XENKBD_FIELD_FEAT_DSBL_POINTER,
131 be_path), &tmp);
132 if (rc) goto out;
133
134 if (tmp) {
135 vkb->feature_disable_pointer = strtoul(tmp, NULL, 0);
136 }
137
138 rc = libxl__xs_read_checked(gc, XBT_NULL,
139 GCSPRINTF("%s/"XENKBD_FIELD_FEAT_ABS_POINTER,
140 be_path), &tmp);
141 if (rc) goto out;
142
143 if (tmp) {
144 vkb->feature_abs_pointer = strtoul(tmp, NULL, 0);
145 }
146
147 rc = libxl__xs_read_checked(gc, XBT_NULL,
148 GCSPRINTF("%s/"XENKBD_FIELD_FEAT_RAW_POINTER,
149 be_path), &tmp);
150 if (rc) goto out;
151
152 if (tmp) {
153 vkb->feature_raw_pointer = strtoul(tmp, NULL, 0);
154 }
155
156 rc = libxl__xs_read_checked(gc, XBT_NULL,
157 GCSPRINTF("%s/"XENKBD_FIELD_FEAT_MTOUCH,
158 be_path), &tmp);
159 if (rc) goto out;
160
161 if (tmp) {
162 vkb->feature_multi_touch = strtoul(tmp, NULL, 0);
163 }
164
165 rc = libxl__xs_read_checked(gc, XBT_NULL,
166 GCSPRINTF("%s/"XENKBD_FIELD_MT_WIDTH,
167 be_path), &tmp);
168 if (rc) goto out;
169
170 if (tmp) {
171 vkb->multi_touch_width = strtoul(tmp, NULL, 0);
172 }
173
174 rc = libxl__xs_read_checked(gc, XBT_NULL,
175 GCSPRINTF("%s/"XENKBD_FIELD_MT_HEIGHT,
176 be_path), &tmp);
177 if (rc) goto out;
178
179 if (tmp) {
180 vkb->multi_touch_height = strtoul(tmp, NULL, 0);
181 }
182
183 rc = libxl__xs_read_checked(gc, XBT_NULL,
184 GCSPRINTF("%s/"XENKBD_FIELD_MT_NUM_CONTACTS,
185 be_path), &tmp);
186 if (rc) goto out;
187
188 if (tmp) {
189 vkb->multi_touch_num_contacts = strtoul(tmp, NULL, 0);
190 }
191
192 rc = libxl__xs_read_checked(gc, XBT_NULL,
193 GCSPRINTF("%s/"XENKBD_FIELD_WIDTH,
194 be_path), &tmp);
195 if (rc) goto out;
196
197 if (tmp) {
198 vkb->width = strtoul(tmp, NULL, 0);
199 }
200
201 rc = libxl__xs_read_checked(gc, XBT_NULL,
202 GCSPRINTF("%s/"XENKBD_FIELD_HEIGHT,
203 be_path), &tmp);
204 if (rc) goto out;
205
206 if (tmp) {
207 vkb->height = strtoul(tmp, NULL, 0);
208 }
209
210 rc = 0;
211
212 out:
213
214 return rc;
215 }
216
libxl__device_from_vkb(libxl__gc * gc,uint32_t domid,libxl_device_vkb * type,libxl__device * device)217 static int libxl__device_from_vkb(libxl__gc *gc, uint32_t domid,
218 libxl_device_vkb *type, libxl__device *device)
219 {
220 device->backend_devid = type->devid;
221 device->backend_domid = type->backend_domid;
222 device->backend_kind = type->backend_type == LIBXL_VKB_BACKEND_LINUX ?
223 LIBXL__DEVICE_KIND_VINPUT : LIBXL__DEVICE_KIND_VKBD;
224 device->devid = type->devid;
225 device->domid = domid;
226 device->kind = LIBXL__DEVICE_KIND_VKBD;
227
228 return 0;
229 }
230
libxl_device_vkb_add(libxl_ctx * ctx,uint32_t domid,libxl_device_vkb * vkb,const libxl_asyncop_how * ao_how)231 int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb,
232 const libxl_asyncop_how *ao_how)
233 {
234 AO_CREATE(ctx, domid, ao_how);
235 int rc;
236
237 rc = libxl__device_add(gc, domid, &libxl__vkb_devtype, vkb);
238 if (rc) {
239 LOGD(ERROR, domid, "Unable to add vkb device");
240 goto out;
241 }
242
243 out:
244 libxl__ao_complete(egc, ao, rc);
245 return AO_INPROGRESS;
246 }
247
libxl_devid_to_device_vkb(libxl_ctx * ctx,uint32_t domid,int devid,libxl_device_vkb * vkb)248 int libxl_devid_to_device_vkb(libxl_ctx *ctx, uint32_t domid,
249 int devid, libxl_device_vkb *vkb)
250 {
251 GC_INIT(ctx);
252
253 libxl_device_vkb *vkbs = NULL;
254 int n, i;
255 int rc;
256
257 libxl_device_vkb_init(vkb);
258
259 vkbs = libxl__device_list(gc, &libxl__vkb_devtype, domid, &n);
260
261 if (!vkbs) { rc = ERROR_NOTFOUND; goto out; }
262
263 for (i = 0; i < n; ++i) {
264 if (devid == vkbs[i].devid) {
265 libxl_device_vkb_copy(ctx, vkb, &vkbs[i]);
266 rc = 0;
267 goto out;
268 }
269 }
270
271 rc = ERROR_NOTFOUND;
272
273 out:
274
275 if (vkbs)
276 libxl__device_list_free(&libxl__vkb_devtype, vkbs, n);
277
278 GC_FREE;
279 return rc;
280 }
281
libxl_device_vkb_getinfo(libxl_ctx * ctx,uint32_t domid,const libxl_device_vkb * vkb,libxl_vkbinfo * info)282 int libxl_device_vkb_getinfo(libxl_ctx *ctx, uint32_t domid,
283 const libxl_device_vkb *vkb,
284 libxl_vkbinfo *info)
285 {
286 GC_INIT(ctx);
287 char *libxl_path, *dompath, *devpath;
288 char *val;
289 int rc;
290
291 libxl_vkbinfo_init(info);
292 dompath = libxl__xs_get_dompath(gc, domid);
293 info->devid = vkb->devid;
294
295 devpath = libxl__domain_device_frontend_path(gc, domid, info->devid,
296 LIBXL__DEVICE_KIND_VKBD);
297 libxl_path = libxl__domain_device_libxl_path(gc, domid, info->devid,
298 LIBXL__DEVICE_KIND_VKBD);
299
300 info->backend = xs_read(ctx->xsh, XBT_NULL,
301 GCSPRINTF("%s/backend", libxl_path),
302 NULL);
303 if (!info->backend) { rc = ERROR_FAIL; goto out; }
304
305 rc = libxl__backendpath_parse_domid(gc, info->backend, &info->backend_id);
306 if (rc) goto out;
307
308 val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", devpath));
309 info->state = val ? strtoul(val, NULL, 10) : -1;
310
311 info->frontend = xs_read(ctx->xsh, XBT_NULL,
312 GCSPRINTF("%s/frontend", libxl_path),
313 NULL);
314 info->frontend_id = domid;
315
316 val = libxl__xs_read(gc, XBT_NULL,
317 GCSPRINTF("%s/"XENKBD_FIELD_EVT_CHANNEL, devpath));
318 info->evtch = val ? strtoul(val, NULL, 10) : -1;
319
320 val = libxl__xs_read(gc, XBT_NULL,
321 GCSPRINTF("%s/"XENKBD_FIELD_RING_GREF, devpath));
322 info->rref = val ? strtoul(val, NULL, 10) : -1;
323
324 rc = 0;
325
326 out:
327 GC_FREE;
328 return rc;
329 }
330
331 static LIBXL_DEFINE_UPDATE_DEVID(vkb)
332
333 #define libxl__add_vkbs NULL
334 #define libxl_device_vkb_compare NULL
335
336 LIBXL_DEFINE_DEVICE_LIST(vkb)
337 LIBXL_DEFINE_DEVICE_REMOVE(vkb)
338
339 DEFINE_DEVICE_TYPE_STRUCT(vkb, VKBD,
340 .skip_attach = 1,
341 .dm_needed = libxl__device_vkb_dm_needed,
342 .set_xenstore_config = (device_set_xenstore_config_fn_t)
343 libxl__set_xenstore_vkb,
344 .from_xenstore = (device_from_xenstore_fn_t)libxl__vkb_from_xenstore
345 );
346
347 /*
348 * Local variables:
349 * mode: C
350 * c-basic-offset: 4
351 * indent-tabs-mode: nil
352 * End:
353 */
354