1 /*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2014 Analog Devices, Inc.
5 * Author: Paul Cercueil <paul.cercueil@analog.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * */
18
19 #include "debug.h"
20 #include "iio-private.h"
21
22 #include <errno.h>
23 #include <libxml/tree.h>
24 #include <string.h>
25
add_attr_to_channel(struct iio_channel * chn,xmlNode * n)26 static int add_attr_to_channel(struct iio_channel *chn, xmlNode *n)
27 {
28 xmlAttr *attr;
29 char *name = NULL, *filename = NULL;
30 struct iio_channel_attr *attrs;
31
32 for (attr = n->properties; attr; attr = attr->next) {
33 if (!strcmp((char *) attr->name, "name")) {
34 name = iio_strdup((char *) attr->children->content);
35 } else if (!strcmp((char *) attr->name, "filename")) {
36 filename = iio_strdup((char *) attr->children->content);
37 } else {
38 WARNING("Unknown field \'%s\' in channel %s\n",
39 attr->name, chn->id);
40 }
41 }
42
43 if (!name) {
44 ERROR("Incomplete attribute in channel %s\n", chn->id);
45 goto err_free;
46 }
47
48 if (!filename) {
49 filename = iio_strdup(name);
50 if (!filename)
51 goto err_free;
52 }
53
54 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
55 sizeof(struct iio_channel_attr));
56 if (!attrs)
57 goto err_free;
58
59 attrs[chn->nb_attrs].filename = filename;
60 attrs[chn->nb_attrs++].name = name;
61 chn->attrs = attrs;
62 return 0;
63
64 err_free:
65 if (name)
66 free(name);
67 if (filename)
68 free(filename);
69 return -1;
70 }
71
add_attr_to_device(struct iio_device * dev,xmlNode * n,enum iio_attr_type type)72 static int add_attr_to_device(struct iio_device *dev, xmlNode *n, enum iio_attr_type type)
73 {
74 xmlAttr *attr;
75 char **attrs, *name = NULL;
76
77 for (attr = n->properties; attr; attr = attr->next) {
78 if (!strcmp((char *) attr->name, "name")) {
79 name = iio_strdup((char *) attr->children->content);
80 } else {
81 WARNING("Unknown field \'%s\' in device %s\n",
82 attr->name, dev->id);
83 }
84 }
85
86 if (!name) {
87 ERROR("Incomplete attribute in device %s\n", dev->id);
88 goto err_free;
89 }
90
91 switch(type) {
92 case IIO_ATTR_TYPE_DEBUG:
93 attrs = realloc(dev->debug_attrs,
94 (1 + dev->nb_debug_attrs) * sizeof(char *));
95 break;
96 case IIO_ATTR_TYPE_DEVICE:
97 attrs = realloc(dev->attrs,
98 (1 + dev->nb_attrs) * sizeof(char *));
99 break;
100 case IIO_ATTR_TYPE_BUFFER:
101 attrs = realloc(dev->buffer_attrs,
102 (1 + dev->nb_buffer_attrs) * sizeof(char *));
103 break;
104 default:
105 attrs = NULL;
106 break;
107 }
108 if (!attrs)
109 goto err_free;
110
111 switch(type) {
112 case IIO_ATTR_TYPE_DEBUG:
113 attrs[dev->nb_debug_attrs++] = name;
114 dev->debug_attrs = attrs;
115 break;
116 case IIO_ATTR_TYPE_DEVICE:
117 attrs[dev->nb_attrs++] = name;
118 dev->attrs = attrs;
119 break;
120 case IIO_ATTR_TYPE_BUFFER:
121 attrs[dev->nb_buffer_attrs++] = name;
122 dev->buffer_attrs = attrs;
123 break;
124 }
125
126 return 0;
127
128 err_free:
129 if (name)
130 free(name);
131 return -1;
132 }
133
setup_scan_element(struct iio_channel * chn,xmlNode * n)134 static void setup_scan_element(struct iio_channel *chn, xmlNode *n)
135 {
136 xmlAttr *attr;
137
138 for (attr = n->properties; attr; attr = attr->next) {
139 const char *name = (const char *) attr->name,
140 *content = (const char *) attr->children->content;
141 if (!strcmp(name, "index")) {
142 chn->index = atol(content);
143 } else if (!strcmp(name, "format")) {
144 char e, s;
145 if (strchr(content, 'X')) {
146 sscanf(content, "%ce:%c%u/%uX%u>>%u", &e, &s,
147 &chn->format.bits,
148 &chn->format.length,
149 &chn->format.repeat,
150 &chn->format.shift);
151 } else {
152 chn->format.repeat = 1;
153 sscanf(content, "%ce:%c%u/%u>>%u", &e, &s,
154 &chn->format.bits,
155 &chn->format.length,
156 &chn->format.shift);
157 }
158 chn->format.is_be = e == 'b';
159 chn->format.is_signed = (s == 's' || s == 'S');
160 chn->format.is_fully_defined = (s == 'S' || s == 'U' ||
161 chn->format.bits == chn->format.length);
162 } else if (!strcmp(name, "scale")) {
163 chn->format.with_scale = true;
164 chn->format.scale = atof(content);
165 } else {
166 WARNING("Unknown attribute \'%s\' in <scan-element>\n",
167 name);
168 }
169 }
170 }
171
create_channel(struct iio_device * dev,xmlNode * n)172 static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
173 {
174 xmlAttr *attr;
175 struct iio_channel *chn = zalloc(sizeof(*chn));
176 if (!chn)
177 return NULL;
178
179 chn->dev = dev;
180
181 /* Set the default index value < 0 (== no index) */
182 chn->index = -ENOENT;
183
184 for (attr = n->properties; attr; attr = attr->next) {
185 const char *name = (const char *) attr->name,
186 *content = (const char *) attr->children->content;
187 if (!strcmp(name, "name")) {
188 chn->name = iio_strdup(content);
189 } else if (!strcmp(name, "id")) {
190 chn->id = iio_strdup(content);
191 } else if (!strcmp(name, "type")) {
192 if (!strcmp(content, "output"))
193 chn->is_output = true;
194 else if (strcmp(content, "input"))
195 WARNING("Unknown channel type %s\n", content);
196 } else {
197 WARNING("Unknown attribute \'%s\' in <channel>\n",
198 name);
199 }
200 }
201
202 if (!chn->id) {
203 ERROR("Incomplete <attribute>\n");
204 goto err_free_channel;
205 }
206
207 for (n = n->children; n; n = n->next) {
208 if (!strcmp((char *) n->name, "attribute")) {
209 if (add_attr_to_channel(chn, n) < 0)
210 goto err_free_channel;
211 } else if (!strcmp((char *) n->name, "scan-element")) {
212 chn->is_scan_element = true;
213 setup_scan_element(chn, n);
214 } else if (strcmp((char *) n->name, "text")) {
215 WARNING("Unknown children \'%s\' in <channel>\n",
216 n->name);
217 continue;
218 }
219 }
220
221 iio_channel_init_finalize(chn);
222
223 return chn;
224
225 err_free_channel:
226 free_channel(chn);
227 return NULL;
228 }
229
create_device(struct iio_context * ctx,xmlNode * n)230 static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
231 {
232 xmlAttr *attr;
233 struct iio_device *dev = zalloc(sizeof(*dev));
234 if (!dev)
235 return NULL;
236
237 dev->ctx = ctx;
238
239 for (attr = n->properties; attr; attr = attr->next) {
240 if (!strcmp((char *) attr->name, "name")) {
241 dev->name = iio_strdup(
242 (char *) attr->children->content);
243 } else if (!strcmp((char *) attr->name, "id")) {
244 dev->id = iio_strdup((char *) attr->children->content);
245 } else {
246 WARNING("Unknown attribute \'%s\' in <device>\n",
247 attr->name);
248 }
249 }
250
251 if (!dev->id) {
252 ERROR("Unable to read device ID\n");
253 goto err_free_device;
254 }
255
256 for (n = n->children; n; n = n->next) {
257 if (!strcmp((char *) n->name, "channel")) {
258 struct iio_channel **chns,
259 *chn = create_channel(dev, n);
260 if (!chn) {
261 ERROR("Unable to create channel\n");
262 goto err_free_device;
263 }
264
265 chns = realloc(dev->channels, (1 + dev->nb_channels) *
266 sizeof(struct iio_channel *));
267 if (!chns) {
268 ERROR("Unable to allocate memory\n");
269 free(chn);
270 goto err_free_device;
271 }
272
273 chns[dev->nb_channels++] = chn;
274 dev->channels = chns;
275 } else if (!strcmp((char *) n->name, "attribute")) {
276 if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_DEVICE) < 0)
277 goto err_free_device;
278 } else if (!strcmp((char *) n->name, "debug-attribute")) {
279 if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_DEBUG) < 0)
280 goto err_free_device;
281 } else if (!strcmp((char *) n->name, "buffer-attribute")) {
282 if (add_attr_to_device(dev, n, IIO_ATTR_TYPE_BUFFER) < 0)
283 goto err_free_device;
284 } else if (strcmp((char *) n->name, "text")) {
285 WARNING("Unknown children \'%s\' in <device>\n",
286 n->name);
287 continue;
288 }
289 }
290
291 dev->words = (dev->nb_channels + 31) / 32;
292 if (dev->words) {
293 dev->mask = calloc(dev->words, sizeof(*dev->mask));
294 if (!dev->mask) {
295 errno = ENOMEM;
296 goto err_free_device;
297 }
298 }
299
300 return dev;
301
302 err_free_device:
303 free_device(dev);
304 return NULL;
305 }
306
xml_clone(const struct iio_context * ctx)307 static struct iio_context * xml_clone(const struct iio_context *ctx)
308 {
309 return xml_create_context_mem(ctx->xml, strlen(ctx->xml));
310 }
311
312 static const struct iio_backend_ops xml_ops = {
313 .clone = xml_clone,
314 };
315
parse_context_attr(struct iio_context * ctx,xmlNode * n)316 static int parse_context_attr(struct iio_context *ctx, xmlNode *n)
317 {
318 xmlAttr *attr;
319 const char *name = NULL, *value = NULL;
320
321 for (attr = n->properties; attr; attr = attr->next) {
322 if (!strcmp((const char *) attr->name, "name")) {
323 name = (const char *) attr->children->content;
324 } else if (!strcmp((const char *) attr->name, "value")) {
325 value = (const char *) attr->children->content;
326 }
327 }
328
329 if (!name || !value)
330 return -EINVAL;
331 else
332 return iio_context_add_attr(ctx, name, value);
333 }
334
iio_create_xml_context_helper(xmlDoc * doc)335 static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
336 {
337 unsigned int i;
338 xmlNode *root, *n;
339 xmlAttr *attr;
340 int err = -ENOMEM;
341 struct iio_context *ctx = zalloc(sizeof(*ctx));
342 if (!ctx)
343 goto err_set_errno;
344
345 ctx->name = "xml";
346 ctx->ops = &xml_ops;
347
348 root = xmlDocGetRootElement(doc);
349 if (strcmp((char *) root->name, "context")) {
350 ERROR("Unrecognized XML file\n");
351 err = -EINVAL;
352 goto err_free_ctx;
353 }
354
355 for (attr = root->properties; attr; attr = attr->next) {
356 if (!strcmp((char *) attr->name, "description"))
357 ctx->description = iio_strdup(
358 (char *) attr->children->content);
359 else if (strcmp((char *) attr->name, "name"))
360 WARNING("Unknown parameter \'%s\' in <context>\n",
361 (char *) attr->children->content);
362 }
363
364 for (n = root->children; n; n = n->next) {
365 struct iio_device **devs, *dev;
366
367 if (!strcmp((char *) n->name, "context-attribute")) {
368 err = parse_context_attr(ctx, n);
369 if (err)
370 goto err_free_devices;
371 else
372 continue;
373 } else if (strcmp((char *) n->name, "device")) {
374 if (strcmp((char *) n->name, "text"))
375 WARNING("Unknown children \'%s\' in "
376 "<context>\n", n->name);
377 continue;
378 }
379
380 dev = create_device(ctx, n);
381 if (!dev) {
382 ERROR("Unable to create device\n");
383 goto err_free_devices;
384 }
385
386 devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
387 sizeof(struct iio_device *));
388 if (!devs) {
389 ERROR("Unable to allocate memory\n");
390 free(dev);
391 goto err_free_devices;
392 }
393
394 devs[ctx->nb_devices++] = dev;
395 ctx->devices = devs;
396 }
397
398 err = iio_context_init(ctx);
399 if (err)
400 goto err_free_devices;
401
402 return ctx;
403
404 err_free_devices:
405 for (i = 0; i < ctx->nb_devices; i++)
406 free_device(ctx->devices[i]);
407 if (ctx->nb_devices)
408 free(ctx->devices);
409 for (i = 0; i < ctx->nb_attrs; i++) {
410 free(ctx->attrs[i]);
411 free(ctx->values[i]);
412 }
413 free(ctx->attrs);
414 free(ctx->values);
415 err_free_ctx:
416 free(ctx);
417 err_set_errno:
418 errno = -err;
419 return NULL;
420 }
421
xml_create_context(const char * xml_file)422 struct iio_context * xml_create_context(const char *xml_file)
423 {
424 struct iio_context *ctx;
425 xmlDoc *doc;
426
427 LIBXML_TEST_VERSION;
428
429 doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
430 if (!doc) {
431 ERROR("Unable to parse XML file\n");
432 errno = EINVAL;
433 return NULL;
434 }
435
436 ctx = iio_create_xml_context_helper(doc);
437 xmlFreeDoc(doc);
438 return ctx;
439 }
440
xml_create_context_mem(const char * xml,size_t len)441 struct iio_context * xml_create_context_mem(const char *xml, size_t len)
442 {
443 struct iio_context *ctx;
444 xmlDoc *doc;
445
446 LIBXML_TEST_VERSION;
447
448 doc = xmlReadMemory(xml, (int) len, NULL, NULL, XML_PARSE_DTDVALID);
449 if (!doc) {
450 ERROR("Unable to parse XML file\n");
451 errno = EINVAL;
452 return NULL;
453 }
454
455 ctx = iio_create_xml_context_helper(doc);
456 xmlFreeDoc(doc);
457 return ctx;
458 }
459