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/displif.h>
18 
libxl__device_vdispl_setdefault(libxl__gc * gc,uint32_t domid,libxl_device_vdispl * vdispl,bool hotplug)19 static int libxl__device_vdispl_setdefault(libxl__gc *gc, uint32_t domid,
20                                            libxl_device_vdispl *vdispl,
21                                            bool hotplug)
22 {
23     return libxl__resolve_domid(gc, vdispl->backend_domname,
24                                 &vdispl->backend_domid);
25 }
26 
libxl__vdispl_from_xenstore(libxl__gc * gc,const char * libxl_path,libxl_devid devid,libxl_device_vdispl * vdispl)27 static int libxl__vdispl_from_xenstore(libxl__gc *gc, const char *libxl_path,
28                                        libxl_devid devid,
29                                        libxl_device_vdispl *vdispl)
30 {
31     const char *be_path;
32     int rc;
33 
34     vdispl->devid = devid;
35     rc = libxl__xs_read_mandatory(gc, XBT_NULL,
36                                   GCSPRINTF("%s/backend", libxl_path),
37                                   &be_path);
38     if (rc) return rc;
39 
40     return libxl__backendpath_parse_domid(gc, be_path, &vdispl->backend_domid);
41 }
42 
libxl__update_config_vdispl(libxl__gc * gc,libxl_device_vdispl * dst,libxl_device_vdispl * src)43 static void libxl__update_config_vdispl(libxl__gc *gc,
44                                         libxl_device_vdispl *dst,
45                                         libxl_device_vdispl *src)
46 {
47     dst->devid = src->devid;
48     dst->be_alloc = src->be_alloc;
49 }
50 
libxl_device_vdispl_compare(const libxl_device_vdispl * d1,const libxl_device_vdispl * d2)51 static int libxl_device_vdispl_compare(const libxl_device_vdispl *d1,
52                                        const libxl_device_vdispl *d2)
53 {
54     return COMPARE_DEVID(d1, d2);
55 }
56 
libxl__device_vdispl_add(libxl__egc * egc,uint32_t domid,libxl_device_vdispl * vdispl,libxl__ao_device * aodev)57 static void libxl__device_vdispl_add(libxl__egc *egc, uint32_t domid,
58                                      libxl_device_vdispl *vdispl,
59                                      libxl__ao_device *aodev)
60 {
61     libxl__device_add_async(egc, domid, &libxl__vdispl_devtype, vdispl, aodev);
62 }
63 
libxl__set_xenstore_vdispl(libxl__gc * gc,uint32_t domid,libxl_device_vdispl * vdispl,flexarray_t * back,flexarray_t * front,flexarray_t * ro_front)64 static int libxl__set_xenstore_vdispl(libxl__gc *gc, uint32_t domid,
65                                       libxl_device_vdispl *vdispl,
66                                       flexarray_t *back, flexarray_t *front,
67                                       flexarray_t *ro_front)
68 {
69     int i;
70 
71     flexarray_append_pair(ro_front, XENDISPL_FIELD_BE_ALLOC,
72                           GCSPRINTF("%d", vdispl->be_alloc));
73 
74     for (i = 0; i < vdispl->num_connectors; i++) {
75         flexarray_append_pair(ro_front, GCSPRINTF("%d/"XENDISPL_FIELD_RESOLUTION, i),
76                               GCSPRINTF("%d"XENDISPL_RESOLUTION_SEPARATOR"%d", vdispl->connectors[i].width,
77                                                  vdispl->connectors[i].height));
78         flexarray_append_pair(ro_front, GCSPRINTF("%d/"XENDISPL_FIELD_UNIQUE_ID, i),
79                               vdispl->connectors[i].unique_id);
80     }
81 
82     return 0;
83 }
84 
libxl__device_vdispl_getconnectors(libxl_ctx * ctx,const char * path,libxl_vdisplinfo * info)85 static int libxl__device_vdispl_getconnectors(libxl_ctx *ctx,
86                                               const char *path,
87                                               libxl_vdisplinfo *info)
88 {
89     GC_INIT(ctx);
90     char *connector = NULL;
91     char *connector_path;
92     int i, rc;
93 
94     info->num_connectors = 0;
95 
96     connector_path = GCSPRINTF("%s/%d", path, info->num_connectors);
97 
98     while ((connector = xs_read(ctx->xsh, XBT_NULL, connector_path, NULL)) !=
99            NULL) {
100         free(connector);
101         connector_path = GCSPRINTF("%s/%d", path, ++info->num_connectors);
102     }
103 
104     info->connectors = libxl__calloc(NOGC, info->num_connectors,
105                                      sizeof(*info->connectors));
106 
107     for (i = 0; i < info->num_connectors; i++) {
108         char *value;
109         char *value_path;
110 
111         value_path = GCSPRINTF("%s/%d/"XENDISPL_FIELD_UNIQUE_ID, path, i);
112         info->connectors[i].unique_id = xs_read(ctx->xsh, XBT_NULL, value_path, NULL);
113         if (info->connectors[i].unique_id == NULL) { rc = ERROR_FAIL; goto out; }
114 
115         value_path = GCSPRINTF("%s/%d/"XENDISPL_FIELD_RESOLUTION, path, i);
116         value = xs_read(ctx->xsh, XBT_NULL, value_path, NULL);
117         if (value == NULL) { rc = ERROR_FAIL; goto out; }
118 
119         rc = sscanf(value, "%u"XENDISPL_RESOLUTION_SEPARATOR"%u", &info->connectors[i].width,
120                     &info->connectors[i].height);
121         free(value);
122 
123         if (rc != 2) {
124             rc = ERROR_FAIL; goto out;
125         }
126 
127         value_path = GCSPRINTF("%s/%d/"XENDISPL_FIELD_REQ_RING_REF, path, i);
128         value = xs_read(ctx->xsh, XBT_NULL, value_path, NULL);
129         info->connectors[i].req_rref = value ? strtoul(value, NULL, 10) : -1;
130         free(value);
131 
132         value_path = GCSPRINTF("%s/%d/"XENDISPL_FIELD_REQ_CHANNEL, path, i);
133         value = xs_read(ctx->xsh, XBT_NULL, value_path, NULL);
134         info->connectors[i].req_evtch = value ? strtoul(value, NULL, 10) : -1;
135         free(value);
136 
137         value_path = GCSPRINTF("%s/%d/"XENDISPL_FIELD_EVT_RING_REF, path, i);
138         value = xs_read(ctx->xsh, XBT_NULL, value_path, NULL);
139         info->connectors[i].evt_rref = value ? strtoul(value, NULL, 10) : -1;
140         free(value);
141 
142         value_path = GCSPRINTF("%s/%d/"XENDISPL_FIELD_EVT_CHANNEL, path, i);
143         value = xs_read(ctx->xsh, XBT_NULL, value_path, NULL);
144         info->connectors[i].evt_evtch = value ? strtoul(value, NULL, 10) : -1;
145         free(value);
146     }
147 
148     rc = 0;
149 
150 out:
151     return rc;
152 }
153 
libxl_device_vdispl_getinfo(libxl_ctx * ctx,uint32_t domid,const libxl_device_vdispl * vdispl,libxl_vdisplinfo * info)154 int libxl_device_vdispl_getinfo(libxl_ctx *ctx, uint32_t domid,
155                                 const libxl_device_vdispl *vdispl,
156                                 libxl_vdisplinfo *info)
157 {
158     GC_INIT(ctx);
159     char *libxl_path, *devpath;
160     char *val;
161     int rc;
162 
163     libxl_vdisplinfo_init(info);
164     info->devid = vdispl->devid;
165 
166     devpath = libxl__domain_device_frontend_path(gc, domid, info->devid,
167                                                  LIBXL__DEVICE_KIND_VDISPL);
168     libxl_path = libxl__domain_device_libxl_path(gc, domid, info->devid,
169                                                  LIBXL__DEVICE_KIND_VDISPL);
170 
171     info->backend = xs_read(ctx->xsh, XBT_NULL,
172                             GCSPRINTF("%s/backend", libxl_path),
173                             NULL);
174     if (!info->backend) { rc = ERROR_FAIL; goto out; }
175 
176     rc = libxl__backendpath_parse_domid(gc, info->backend, &info->backend_id);
177     if (rc) goto out;
178 
179     val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", devpath));
180     info->state = val ? strtoul(val, NULL, 10) : -1;
181 
182     info->frontend = xs_read(ctx->xsh, XBT_NULL,
183                              GCSPRINTF("%s/frontend", libxl_path),
184                              NULL);
185     info->frontend_id = domid;
186 
187     val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/"XENDISPL_FIELD_BE_ALLOC, devpath));
188     info->be_alloc = val ? strtoul(val, NULL, 10) : 0;
189 
190     rc = libxl__device_vdispl_getconnectors(ctx, devpath, info);
191     if (rc) goto out;
192 
193     rc = 0;
194 
195 out:
196      GC_FREE;
197      return rc;
198 }
199 
200 static LIBXL_DEFINE_DEVICE_FROM_TYPE(vdispl)
201 static LIBXL_DEFINE_UPDATE_DEVID(vdispl)
202 static LIBXL_DEFINE_DEVICES_ADD(vdispl)
203 
204 LIBXL_DEFINE_DEVID_TO_DEVICE(vdispl)
205 LIBXL_DEFINE_DEVICE_ADD(vdispl)
206 LIBXL_DEFINE_DEVICE_REMOVE(vdispl)
207 LIBXL_DEFINE_DEVICE_LIST(vdispl)
208 
209 DEFINE_DEVICE_TYPE_STRUCT(vdispl, VDISPL,
210     .update_config = (device_update_config_fn_t)libxl__update_config_vdispl,
211     .from_xenstore = (device_from_xenstore_fn_t)libxl__vdispl_from_xenstore,
212     .set_xenstore_config = (device_set_xenstore_config_fn_t)
213                            libxl__set_xenstore_vdispl
214 );
215 
216 /*
217  * Local variables:
218  * mode: C
219  * c-basic-offset: 4
220  * indent-tabs-mode: nil
221  * End:
222  */
223