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