1 /*
2  * libiio - Library for interfacing industrial I/O (IIO) devices
3  *
4  * Copyright (C) 2016 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 #include "iio-config.h"
19 #include "iio-private.h"
20 
21 #include <errno.h>
22 #include <stdbool.h>
23 #include <string.h>
24 
25 struct iio_scan_context {
26 #ifdef WITH_USB_BACKEND
27 	struct iio_scan_backend_context *usb_ctx;
28 #endif
29 	bool scan_local;
30 };
31 
iio_context_info_get_description(const struct iio_context_info * info)32 const char * iio_context_info_get_description(
33 		const struct iio_context_info *info)
34 {
35 	return info->description;
36 }
37 
iio_context_info_get_uri(const struct iio_context_info * info)38 const char * iio_context_info_get_uri(
39 		const struct iio_context_info *info)
40 {
41 	return info->uri;
42 }
43 
iio_scan_context_get_info_list(struct iio_scan_context * ctx,struct iio_context_info *** info)44 ssize_t iio_scan_context_get_info_list(struct iio_scan_context *ctx,
45 		struct iio_context_info ***info)
46 {
47 	struct iio_scan_result scan_result = { 0, NULL };
48 
49 #ifdef WITH_LOCAL_BACKEND
50 	if (ctx->scan_local) {
51 		int ret = local_context_scan(&scan_result);
52 		if (ret < 0) {
53 			if (scan_result.info)
54 				iio_context_info_list_free(scan_result.info);
55 			return ret;
56 		}
57 	}
58 #endif
59 
60 #ifdef WITH_USB_BACKEND
61 	if (ctx->usb_ctx) {
62 		int ret = usb_context_scan(ctx->usb_ctx, &scan_result);
63 		if (ret < 0) {
64 			if (scan_result.info)
65 				iio_context_info_list_free(scan_result.info);
66 			return ret;
67 		}
68 	}
69 #endif
70 
71 	*info = scan_result.info;
72 
73 	return (ssize_t) scan_result.size;
74 }
75 
iio_context_info_list_free(struct iio_context_info ** list)76 void iio_context_info_list_free(struct iio_context_info **list)
77 {
78 	struct iio_context_info **it;
79 
80 	if (!list)
81 		return;
82 
83 	for (it = list; *it; it++) {
84 		struct iio_context_info *info = *it;
85 
86 		if (info->description)
87 			free(info->description);
88 		if (info->uri)
89 			free(info->uri);
90 		free(info);
91 	}
92 
93 	free(list);
94 }
95 
iio_scan_result_add(struct iio_scan_result * scan_result,size_t num)96 struct iio_context_info ** iio_scan_result_add(
97 		struct iio_scan_result *scan_result, size_t num)
98 {
99 	struct iio_context_info **info;
100 	size_t old_size, new_size;
101 	size_t i;
102 
103 	old_size = scan_result->size;
104 	new_size = old_size + num;
105 
106 	info = realloc(scan_result->info, (new_size + 1) * sizeof(*info));
107 	if (!info)
108 		return NULL;
109 
110 	scan_result->info = info;
111 	scan_result->size = new_size;
112 
113 	for (i = old_size; i < new_size; i++) {
114 		/* Make sure iio_context_info_list_free won't overflow */
115 		info[i + 1] = NULL;
116 
117 		info[i] = zalloc(sizeof(**info));
118 		if (!info[i])
119 			return NULL;
120 	}
121 
122 	return &info[old_size];
123 }
124 
iio_create_scan_context(const char * backend,unsigned int flags)125 struct iio_scan_context * iio_create_scan_context(
126 		const char *backend, unsigned int flags)
127 {
128 	struct iio_scan_context *ctx;
129 
130 	/* "flags" must be zero for now */
131 	if (flags != 0) {
132 		errno = EINVAL;
133 		return NULL;
134 	}
135 
136 	ctx = calloc(1, sizeof(*ctx));
137 	if (!ctx) {
138 		errno = ENOMEM;
139 		return NULL;
140 	}
141 
142 	if (!backend || !strcmp(backend, "local"))
143 		ctx->scan_local = true;
144 
145 #ifdef WITH_USB_BACKEND
146 	if (!backend || !strcmp(backend, "usb"))
147 		ctx->usb_ctx = usb_context_scan_init();
148 #endif
149 
150 	return ctx;
151 }
152 
iio_scan_context_destroy(struct iio_scan_context * ctx)153 void iio_scan_context_destroy(struct iio_scan_context *ctx)
154 {
155 #ifdef WITH_USB_BACKEND
156 	if (ctx->usb_ctx)
157 		usb_context_scan_free(ctx->usb_ctx);
158 #endif
159 	free(ctx);
160 }
161 
162 #ifdef WITH_MATLAB_BINDINGS_API
163 
164 struct iio_scan_block {
165 	struct iio_scan_context *ctx;
166 	struct iio_context_info **info;
167 	ssize_t ctx_cnt;
168 };
169 
iio_scan_block_scan(struct iio_scan_block * blk)170 ssize_t iio_scan_block_scan(struct iio_scan_block *blk)
171 {
172 	iio_context_info_list_free(blk->info);
173 	blk->info = NULL;
174 	blk->ctx_cnt = iio_scan_context_get_info_list(blk->ctx, &blk->info);
175 	return blk->ctx_cnt;
176 }
177 
iio_scan_block_get_info(struct iio_scan_block * blk,unsigned int index)178 struct iio_context_info *iio_scan_block_get_info(
179 		struct iio_scan_block *blk, unsigned int index)
180 {
181 	if (!blk->info || (ssize_t)index >= blk->ctx_cnt) {
182 		errno = EINVAL;
183 		return NULL;
184 	}
185 	return blk->info[index];
186 }
187 
iio_create_scan_block(const char * backend,unsigned int flags)188 struct iio_scan_block *iio_create_scan_block(
189 		const char *backend, unsigned int flags)
190 {
191 	struct iio_scan_block *blk;
192 
193 	blk = calloc(1, sizeof(*blk));
194 	if (!blk) {
195 		errno = ENOMEM;
196 		return NULL;
197 	}
198 
199 	blk->ctx = iio_create_scan_context(backend, flags);
200 	if (!blk->ctx) {
201 		free(blk);
202 		return NULL;
203 	}
204 
205 	return blk;
206 }
207 
iio_scan_block_destroy(struct iio_scan_block * blk)208 void iio_scan_block_destroy(struct iio_scan_block *blk)
209 {
210 	iio_context_info_list_free(blk->info);
211 	iio_scan_context_destroy(blk->ctx);
212 	free(blk);
213 }
214 #endif
215