• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     V4L2 API subdev ioctl tests.
3 
4     Copyright (C) 2018  Hans Verkuil <hverkuil-cisco@xs4all.nl>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335  USA
19  */
20 
21 #include <map>
22 #include <set>
23 
24 #include <sys/types.h>
25 
26 #include "v4l2-compliance.h"
27 
28 #define VALID_SUBDEV_CAPS (V4L2_SUBDEV_CAP_RO_SUBDEV | V4L2_SUBDEV_CAP_STREAMS)
29 
testSubDevCap(struct node * node)30 int testSubDevCap(struct node *node)
31 {
32 	v4l2_subdev_capability caps;
33 
34 	memset(&caps, 0xff, sizeof(caps));
35 	// Must always be there
36 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_QUERYCAP, &caps));
37 	if (has_mmu)
38 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_QUERYCAP, nullptr) != EFAULT);
39 	fail_on_test(check_0(caps.reserved, sizeof(caps.reserved)));
40 	fail_on_test((caps.version >> 16) < 5);
41 	fail_on_test(caps.capabilities & ~VALID_SUBDEV_CAPS);
42 	node->is_ro_subdev = caps.capabilities & V4L2_SUBDEV_CAP_RO_SUBDEV;
43 	return 0;
44 }
45 
testSubDevEnumFrameInterval(struct node * node,unsigned which,unsigned pad,unsigned code,unsigned width,unsigned height)46 static int testSubDevEnumFrameInterval(struct node *node, unsigned which,
47 				       unsigned pad, unsigned code,
48 				       unsigned width, unsigned height)
49 {
50 	struct v4l2_subdev_frame_interval_enum fie;
51 	unsigned num_ivals;
52 	int ret;
53 
54 	memset(&fie, 0, sizeof(fie));
55 	fie.which = which;
56 	fie.pad = pad;
57 	fie.stream = 0;
58 	fie.code = code;
59 	fie.width = width;
60 	fie.height = height;
61 	ret = doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie);
62 	node->has_subdev_enum_fival |= (ret != ENOTTY) << which;
63 	if (ret == ENOTTY)
64 		return ret;
65 	if (which)
66 		fail_on_test(node->enum_frame_interval_pad != (int)pad);
67 	else
68 		fail_on_test(node->enum_frame_interval_pad >= 0);
69 	node->enum_frame_interval_pad = pad;
70 	fie.which = ~0;
71 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != EINVAL);
72 	fie.which = which;
73 	fie.index = ~0;
74 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != EINVAL);
75 	fie.pad = node->entity.pads;
76 	fie.index = 0;
77 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != EINVAL);
78 	fie.width = ~0;
79 	fie.pad = pad;
80 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != EINVAL);
81 	fie.height = ~0;
82 	fie.width = width;
83 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != EINVAL);
84 	memset(&fie, 0xff, sizeof(fie));
85 	fie.which = which;
86 	fie.pad = pad;
87 	fie.stream = 0;
88 	fie.code = code;
89 	fie.width = width;
90 	fie.height = height;
91 	fie.index = 0;
92 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie));
93 	fail_on_test(check_0(fie.reserved, sizeof(fie.reserved)));
94 	fail_on_test(fie.which != which);
95 	fail_on_test(fie.pad != pad);
96 	fail_on_test(fie.code != code);
97 	fail_on_test(fie.width != width);
98 	fail_on_test(fie.height != height);
99 	fail_on_test(fie.index);
100 	fail_on_test(fie.interval.numerator == ~0U || fie.interval.denominator == ~0U);
101 	do {
102 		fie.index++;
103 		ret = doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie);
104 	} while (!ret);
105 	fail_on_test(ret != EINVAL);
106 
107 	num_ivals = fie.index;
108 	for (unsigned i = 0; i < num_ivals; i++) {
109 		fie.index = i;
110 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie));
111 		fail_on_test(fie.which != which);
112 		fail_on_test(fie.pad != pad);
113 		fail_on_test(fie.code != code);
114 		fail_on_test(fie.width != width);
115 		fail_on_test(fie.height != height);
116 		fail_on_test(fie.index != i);
117 		fail_on_test(!fie.interval.numerator);
118 		fail_on_test(!fie.interval.denominator);
119 	}
120 	return 0;
121 }
122 
testSubDevEnumFrameSize(struct node * node,unsigned which,unsigned pad,unsigned stream,unsigned code)123 static int testSubDevEnumFrameSize(struct node *node, unsigned which,
124 				   unsigned pad, unsigned stream, unsigned code)
125 {
126 	struct v4l2_subdev_frame_size_enum fse;
127 	unsigned num_sizes;
128 	int ret;
129 
130 	memset(&fse, 0, sizeof(fse));
131 	fse.which = which;
132 	fse.pad = pad;
133 	fse.stream = stream;
134 	fse.code = code;
135 	ret = doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse);
136 	node->has_subdev_enum_fsize |= (ret != ENOTTY) << which;
137 	if (ret == ENOTTY) {
138 		struct v4l2_subdev_frame_interval_enum fie;
139 
140 		memset(&fie, 0, sizeof(fie));
141 		fie.which = which;
142 		fie.pad = pad;
143 		fie.stream = stream;
144 		fie.code = code;
145 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != ENOTTY);
146 		return ret;
147 	}
148 	fse.which = ~0;
149 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse) != EINVAL);
150 	fse.which = which;
151 	fse.index = ~0;
152 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse) != EINVAL);
153 	fse.pad = node->entity.pads;
154 	fse.index = 0;
155 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse) != EINVAL);
156 	memset(&fse, 0xff, sizeof(fse));
157 	fse.which = which;
158 	fse.pad = pad;
159 	fse.stream = stream;
160 	fse.code = code;
161 	fse.index = 0;
162 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse));
163 	fail_on_test(check_0(fse.reserved, sizeof(fse.reserved)));
164 	fail_on_test(fse.which != which);
165 	fail_on_test(fse.pad != pad);
166 	fail_on_test(fse.code != code);
167 	fail_on_test(fse.index);
168 	fail_on_test(!fse.min_width || !fse.min_height);
169 	fail_on_test(fse.min_width == ~0U || fse.min_height == ~0U);
170 	fail_on_test(!fse.max_width || !fse.max_height);
171 	fail_on_test(fse.max_width == ~0U || fse.max_height == ~0U);
172 	fail_on_test(fse.min_width > fse.max_width);
173 	fail_on_test(fse.min_height > fse.max_height);
174 	do {
175 		fse.index++;
176 		ret = doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse);
177 	} while (!ret);
178 	fail_on_test(ret != EINVAL);
179 
180 	num_sizes = fse.index;
181 	for (unsigned i = 0; i < num_sizes; i++) {
182 		fse.index = i;
183 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse));
184 		fail_on_test(fse.which != which);
185 		fail_on_test(fse.pad != pad);
186 		fail_on_test(fse.code != code);
187 		fail_on_test(fse.index != i);
188 		fail_on_test(!fse.min_width || !fse.min_height);
189 		fail_on_test(!fse.max_width || !fse.max_height);
190 		fail_on_test(fse.min_width > fse.max_width);
191 		fail_on_test(fse.min_height > fse.max_height);
192 
193 		ret = testSubDevEnumFrameInterval(node, which, pad, code,
194 						  fse.min_width, fse.min_height);
195 		fail_on_test(ret && ret != ENOTTY);
196 		ret = testSubDevEnumFrameInterval(node, which, pad, code,
197 						  fse.max_width, fse.max_height);
198 		fail_on_test(ret && ret != ENOTTY);
199 	}
200 	return 0;
201 }
202 
testSubDevEnum(struct node * node,unsigned which,unsigned pad,unsigned stream)203 int testSubDevEnum(struct node *node, unsigned which, unsigned pad, unsigned stream)
204 {
205 	struct v4l2_subdev_mbus_code_enum mbus_core_enum;
206 	unsigned num_codes;
207 	int ret;
208 
209 	memset(&mbus_core_enum, 0, sizeof(mbus_core_enum));
210 	mbus_core_enum.which = which;
211 	mbus_core_enum.pad = pad;
212 	mbus_core_enum.stream = stream;
213 	ret = doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum);
214 	node->has_subdev_enum_code |= (ret != ENOTTY) << which;
215 	if (ret == ENOTTY) {
216 		struct v4l2_subdev_frame_size_enum fse;
217 		struct v4l2_subdev_frame_interval_enum fie;
218 
219 		memset(&fse, 0, sizeof(fse));
220 		memset(&fie, 0, sizeof(fie));
221 		fse.which = which;
222 		fse.pad = pad;
223 		fse.stream = stream;
224 		fie.which = which;
225 		fie.pad = pad;
226 		fie.stream = stream;
227 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse) != ENOTTY);
228 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != ENOTTY);
229 		return ret;
230 	}
231 	mbus_core_enum.which = ~0;
232 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum) != EINVAL);
233 	mbus_core_enum.which = which;
234 	mbus_core_enum.index = ~0;
235 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum) != EINVAL);
236 	mbus_core_enum.pad = node->entity.pads;
237 	mbus_core_enum.stream = stream;
238 	mbus_core_enum.index = 0;
239 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum) != EINVAL);
240 	memset(&mbus_core_enum, 0xff, sizeof(mbus_core_enum));
241 	mbus_core_enum.which = which;
242 	mbus_core_enum.pad = pad;
243 	mbus_core_enum.stream = stream;
244 	mbus_core_enum.index = 0;
245 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum));
246 	fail_on_test(check_0(mbus_core_enum.reserved, sizeof(mbus_core_enum.reserved)));
247 	fail_on_test(mbus_core_enum.code == ~0U);
248 	fail_on_test(mbus_core_enum.pad != pad);
249 	fail_on_test(mbus_core_enum.stream != stream);
250 	fail_on_test(mbus_core_enum.index);
251 	fail_on_test(mbus_core_enum.which != which);
252 	do {
253 		mbus_core_enum.index++;
254 		ret = doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum);
255 	} while (!ret);
256 	fail_on_test(ret != EINVAL);
257 
258 	num_codes = mbus_core_enum.index;
259 	for (unsigned i = 0; i < num_codes; i++) {
260 		mbus_core_enum.index = i;
261 		mbus_core_enum.code = 0;
262 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum));
263 		fail_on_test(!mbus_core_enum.code);
264 		fail_on_test(mbus_core_enum.which != which);
265 		fail_on_test(mbus_core_enum.pad != pad);
266 		fail_on_test(mbus_core_enum.stream != stream);
267 		fail_on_test(mbus_core_enum.index != i);
268 
269 		ret = testSubDevEnumFrameSize(node, which, pad, stream, mbus_core_enum.code);
270 		fail_on_test(ret && ret != ENOTTY);
271 	}
272 	return 0;
273 }
274 
testSubDevFrameInterval(struct node * node,unsigned which,unsigned pad,unsigned stream)275 int testSubDevFrameInterval(struct node *node, unsigned which, unsigned pad, unsigned stream)
276 {
277 	struct v4l2_subdev_frame_interval fival;
278 	struct v4l2_fract ival;
279 	bool has_which = node->has_ival_uses_which();
280 	int ret;
281 
282 	if (!has_which)
283 		which = V4L2_SUBDEV_FORMAT_ACTIVE;
284 	memset(&fival, 0xff, sizeof(fival));
285 	fival.pad = pad;
286 	fival.stream = stream;
287 	if (has_which)
288 		fival.which = which;
289 	ret = doioctl(node, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &fival);
290 	if (has_which)
291 		node->has_subdev_frame_interval |= (ret != ENOTTY) << which;
292 	if (ret == ENOTTY) {
293 		fail_on_test(node->enum_frame_interval_pad >= 0);
294 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival) != ENOTTY);
295 		return ret;
296 	}
297 
298 	if (!has_which)
299 		warn_once("V4L2_SUBDEV_CLIENT_CAP_INTERVAL_USES_WHICH is not supported\n");
300 
301 	fail_on_test(node->frame_interval_pad >= 0);
302 	fail_on_test(node->enum_frame_interval_pad != (int)pad);
303 	node->frame_interval_pad = pad;
304 	fail_on_test(check_0(fival.reserved, sizeof(fival.reserved)));
305 	if (has_which)
306 		fail_on_test(fival.which != which);
307 	fail_on_test(fival.pad != pad);
308 	fail_on_test(fival.stream != stream);
309 	fail_on_test(!fival.interval.numerator);
310 	fail_on_test(!fival.interval.denominator);
311 	fail_on_test(fival.interval.numerator == ~0U || fival.interval.denominator == ~0U);
312 	ival = fival.interval;
313 	memset(fival.reserved, 0xff, sizeof(fival.reserved));
314 	if (node->is_ro_subdev) {
315 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival) != EPERM);
316 		return 0;
317 	}
318 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival));
319 	if (has_which)
320 		fail_on_test(fival.which != which);
321 	fail_on_test(fival.pad != pad);
322 	fail_on_test(fival.stream != stream);
323 	fail_on_test(ival.numerator != fival.interval.numerator);
324 	fail_on_test(ival.denominator != fival.interval.denominator);
325 	fail_on_test(check_0(fival.reserved, sizeof(fival.reserved)));
326 	memset(&fival, 0, sizeof(fival));
327 	fival.pad = pad;
328 	fival.stream = stream;
329 	if (has_which)
330 		fival.which = which;
331 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &fival));
332 	if (has_which)
333 		fail_on_test(fival.which != which);
334 	fail_on_test(fival.pad != pad);
335 	fail_on_test(fival.stream != stream);
336 	fail_on_test(ival.numerator != fival.interval.numerator);
337 	fail_on_test(ival.denominator != fival.interval.denominator);
338 
339 	if (has_which) {
340 		fival.which = ~0;
341 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &fival) != EINVAL);
342 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival) != EINVAL);
343 		fival.which = which;
344 	}
345 	fival.pad = node->entity.pads;
346 	fival.stream = stream;
347 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &fival) != EINVAL);
348 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival) != EINVAL);
349 	fival.pad = pad;
350 	fival.stream = stream;
351 	fival.interval = ival;
352 	fival.interval.numerator = 0;
353 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival));
354 	fail_on_test(!fival.interval.numerator);
355 	fail_on_test(!fival.interval.denominator);
356 	fival.interval = ival;
357 	fival.interval.denominator = 0;
358 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival));
359 	fail_on_test(!fival.interval.numerator);
360 	fail_on_test(!fival.interval.denominator);
361 	fival.interval = ival;
362 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival));
363 	return 0;
364 }
365 
checkMBusFrameFmt(struct node * node,struct v4l2_mbus_framefmt & fmt)366 static int checkMBusFrameFmt(struct node *node, struct v4l2_mbus_framefmt &fmt)
367 {
368 	fail_on_test(check_0(fmt.reserved, sizeof(fmt.reserved)));
369 	fail_on_test(fmt.width == 0 || fmt.width > 65536);
370 	fail_on_test(fmt.height == 0 || fmt.height > 65536);
371 	fail_on_test(fmt.code == 0 || fmt.code == ~0U);
372 	fail_on_test(fmt.field == ~0U);
373 	if (!node->is_passthrough_subdev) {
374 		// Passthrough subdevs just copy this info, they don't validate
375 		// it. TODO: this does not take colorspace converters into account!
376 		fail_on_test(fmt.colorspace == ~0U);
377 		//TBD fail_on_test(!fmt.colorspace);
378 		fail_on_test(fmt.ycbcr_enc == 0xffff);
379 		fail_on_test(fmt.quantization == 0xffff);
380 		fail_on_test(fmt.xfer_func == 0xffff);
381 		fail_on_test(!fmt.colorspace &&
382 			     (fmt.ycbcr_enc || fmt.quantization || fmt.xfer_func));
383 	}
384 	return 0;
385 }
386 
testSubDevFormat(struct node * node,unsigned which,unsigned pad,unsigned stream)387 int testSubDevFormat(struct node *node, unsigned which, unsigned pad, unsigned stream)
388 {
389 	struct v4l2_subdev_format fmt;
390 	struct v4l2_subdev_format s_fmt;
391 	int ret;
392 
393 	memset(&fmt, 0, sizeof(fmt));
394 	fmt.which = which;
395 	fmt.pad = pad;
396 	fmt.stream = stream;
397 	ret = doioctl(node, VIDIOC_SUBDEV_G_FMT, &fmt);
398 	node->has_subdev_fmt |= (ret != ENOTTY) << which;
399 	if (ret == ENOTTY) {
400 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FMT, &fmt) != ENOTTY);
401 		return ret;
402 	}
403 	fmt.which = ~0;
404 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FMT, &fmt) != EINVAL);
405 	fmt.which = 0;
406 	fmt.pad = node->entity.pads;
407 	fmt.stream = stream;
408 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FMT, &fmt) != EINVAL);
409 	memset(&fmt, 0xff, sizeof(fmt));
410 	fmt.which = which;
411 	fmt.pad = pad;
412 	fmt.stream = stream;
413 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FMT, &fmt));
414 	fail_on_test(check_0(fmt.reserved, sizeof(fmt.reserved)));
415 	fail_on_test(fmt.which != which);
416 	fail_on_test(fmt.pad != pad);
417 	fail_on_test(fmt.stream != stream);
418 	fail_on_test(checkMBusFrameFmt(node, fmt.format));
419 	s_fmt = fmt;
420 	memset(s_fmt.reserved, 0xff, sizeof(s_fmt.reserved));
421 	memset(s_fmt.format.reserved, 0xff, sizeof(s_fmt.format.reserved));
422 	ret = doioctl(node, VIDIOC_SUBDEV_S_FMT, &s_fmt);
423 	if (node->is_ro_subdev && which == V4L2_SUBDEV_FORMAT_ACTIVE) {
424 		fail_on_test(ret != EPERM);
425 		return 0;
426 	}
427 	fail_on_test(ret && ret != ENOTTY);
428 	fail_on_test(s_fmt.which != which);
429 	fail_on_test(s_fmt.pad != pad);
430 	fail_on_test(s_fmt.stream != stream);
431 	if (ret) {
432 		warn("VIDIOC_SUBDEV_G_FMT is supported but not VIDIOC_SUBDEV_S_FMT\n");
433 		return 0;
434 	}
435 	fail_on_test(check_0(s_fmt.reserved, sizeof(s_fmt.reserved)));
436 	fail_on_test(checkMBusFrameFmt(node, s_fmt.format));
437 	fail_on_test(s_fmt.format.width != fmt.format.width);
438 	fail_on_test(s_fmt.format.height != fmt.format.height);
439 	fail_on_test(s_fmt.format.code != fmt.format.code);
440 	fail_on_test(s_fmt.format.field != fmt.format.field);
441 	fail_on_test(s_fmt.format.colorspace != fmt.format.colorspace);
442 	fail_on_test(s_fmt.format.ycbcr_enc != fmt.format.ycbcr_enc);
443 	fail_on_test(s_fmt.format.quantization != fmt.format.quantization);
444 	fail_on_test(s_fmt.format.xfer_func != fmt.format.xfer_func);
445 
446 	s_fmt.format.code = ~0U;
447 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FMT, &s_fmt));
448 	fail_on_test(s_fmt.format.code == ~0U);
449 	fail_on_test(!s_fmt.format.code);
450 
451 	// Restore fmt
452 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FMT, &fmt));
453 	return 0;
454 }
455 
456 struct target_info {
457 	__u32 target;
458 	bool allowed;
459 	bool readonly;
460 	bool found;
461 };
462 
463 static target_info targets[] = {
464 	{ V4L2_SEL_TGT_CROP, true },
465 	{ V4L2_SEL_TGT_CROP_DEFAULT, true, true },
466 	{ V4L2_SEL_TGT_CROP_BOUNDS, true, true },
467 	{ V4L2_SEL_TGT_NATIVE_SIZE, true },
468 	{ V4L2_SEL_TGT_COMPOSE, true },
469 	{ V4L2_SEL_TGT_COMPOSE_DEFAULT, false, true },
470 	{ V4L2_SEL_TGT_COMPOSE_BOUNDS, true, true },
471 	{ V4L2_SEL_TGT_COMPOSE_PADDED, false, true },
472 	{ ~0U },
473 };
474 
testSubDevSelection(struct node * node,unsigned which,unsigned pad,unsigned stream)475 int testSubDevSelection(struct node *node, unsigned which, unsigned pad, unsigned stream)
476 {
477 	struct v4l2_subdev_selection sel;
478 	struct v4l2_subdev_selection s_sel;
479 	struct v4l2_subdev_crop crop;
480 	bool is_sink = node->pads[pad].flags & MEDIA_PAD_FL_SINK;
481 	bool have_sel = false;
482 	int ret;
483 
484 	targets[V4L2_SEL_TGT_NATIVE_SIZE].readonly = is_sink;
485 	memset(&crop, 0, sizeof(crop));
486 	crop.pad = pad;
487 	crop.stream = stream;
488 	crop.which = which;
489 	memset(&sel, 0, sizeof(sel));
490 	sel.which = which;
491 	sel.pad = pad;
492 	sel.stream = stream;
493 	sel.target = V4L2_SEL_TGT_CROP;
494 	ret = doioctl(node, VIDIOC_SUBDEV_G_SELECTION, &sel);
495 	node->has_subdev_selection |= (ret != ENOTTY) << which;
496 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_CROP, &crop) != ret);
497 	if (ret == ENOTTY) {
498 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_SELECTION, &sel) != ENOTTY);
499 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_CROP, &crop) != ENOTTY);
500 		return ret;
501 	}
502 	fail_on_test(check_0(crop.reserved, sizeof(crop.reserved)));
503 	fail_on_test(crop.which != which);
504 	fail_on_test(crop.pad != pad);
505 	fail_on_test(crop.stream != stream);
506 	fail_on_test(memcmp(&crop.rect, &sel.r, sizeof(sel.r)));
507 
508 	for (unsigned tgt = 0; targets[tgt].target != ~0U; tgt++) {
509 		targets[tgt].found = false;
510 		memset(&sel, 0xff, sizeof(sel));
511 		sel.which = which;
512 		sel.pad = pad;
513 		sel.stream = stream;
514 		sel.target = tgt;
515 		ret = doioctl(node, VIDIOC_SUBDEV_G_SELECTION, &sel);
516 		targets[tgt].found = !ret;
517 		fail_on_test(ret && ret != EINVAL);
518 		if (ret)
519 			continue;
520 		have_sel = true;
521 		fail_on_test(!targets[tgt].allowed);
522 		fail_on_test(check_0(sel.reserved, sizeof(sel.reserved)));
523 		fail_on_test(sel.which != which);
524 		fail_on_test(sel.pad != pad);
525 		fail_on_test(sel.stream != stream);
526 		fail_on_test(sel.target != tgt);
527 		fail_on_test(!sel.r.width);
528 		fail_on_test(sel.r.width == ~0U);
529 		fail_on_test(!sel.r.height);
530 		fail_on_test(sel.r.height == ~0U);
531 		fail_on_test(sel.r.top == ~0);
532 		fail_on_test(sel.r.left == ~0);
533 		sel.which = ~0;
534 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_SELECTION, &sel) != EINVAL);
535 		sel.which = 0;
536 		sel.pad = node->entity.pads;
537 		sel.stream = stream;
538 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_SELECTION, &sel) != EINVAL);
539 		sel.which = which;
540 		sel.pad = pad;
541 		sel.stream = stream;
542 		s_sel = sel;
543 		memset(s_sel.reserved, 0xff, sizeof(s_sel.reserved));
544 		ret = doioctl(node, VIDIOC_SUBDEV_S_SELECTION, &s_sel);
545 		if (node->is_ro_subdev && which == V4L2_SUBDEV_FORMAT_ACTIVE)
546 			fail_on_test(ret != EPERM);
547 		if (tgt == V4L2_SEL_TGT_CROP) {
548 			crop.rect = sel.r;
549 			memset(crop.reserved, 0xff, sizeof(crop.reserved));
550 			fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_CROP, &crop) != ret);
551 			if (!ret) {
552 				fail_on_test(check_0(crop.reserved, sizeof(crop.reserved)));
553 				fail_on_test(crop.which != which);
554 				fail_on_test(crop.pad != pad);
555 				fail_on_test(crop.stream != stream);
556 				fail_on_test(memcmp(&crop.rect, &sel.r, sizeof(sel.r)));
557 			}
558 		}
559 		if (node->is_ro_subdev && which == V4L2_SUBDEV_FORMAT_ACTIVE)
560 			continue;
561 		fail_on_test(!ret && targets[tgt].readonly);
562 		fail_on_test(s_sel.which != which);
563 		fail_on_test(s_sel.pad != pad);
564 		fail_on_test(s_sel.stream != stream);
565 		if (ret && !targets[tgt].readonly && tgt != V4L2_SEL_TGT_NATIVE_SIZE)
566 			warn("VIDIOC_SUBDEV_G_SELECTION is supported for target %u but not VIDIOC_SUBDEV_S_SELECTION\n", tgt);
567 		if (ret)
568 			continue;
569 		fail_on_test(check_0(s_sel.reserved, sizeof(s_sel.reserved)));
570 		fail_on_test(s_sel.flags != sel.flags);
571 		fail_on_test(s_sel.r.top != sel.r.top);
572 		fail_on_test(s_sel.r.left != sel.r.left);
573 		fail_on_test(s_sel.r.width != sel.r.width);
574 		fail_on_test(s_sel.r.height != sel.r.height);
575 	}
576 
577 	return have_sel ? 0 : ENOTTY;
578 }
579 
testSubDevRouting(struct node * node,unsigned which)580 int testSubDevRouting(struct node *node, unsigned which)
581 {
582 	const uint32_t all_route_flags_mask = V4L2_SUBDEV_ROUTE_FL_ACTIVE;
583 	struct v4l2_subdev_routing routing = {};
584 	struct v4l2_subdev_route routes[NUM_ROUTES_MAX] = {};
585 	unsigned int i;
586 	int ret;
587 
588 	routing.which = which;
589 	routing.routes = (uintptr_t)&routes;
590 	routing.len_routes = 0;
591 	routing.num_routes = 0;
592 	memset(routing.reserved, 0xff, sizeof(routing.reserved));
593 
594 	/* First test that G_ROUTING returns success even when len_routes is 0. */
595 
596 	ret = doioctl(node, VIDIOC_SUBDEV_G_ROUTING, &routing);
597 	fail_on_test(ret);
598 	fail_on_test(routing.num_routes > NUM_ROUTES_MAX);
599 	fail_on_test(check_0(routing.reserved, sizeof(routing.reserved)));
600 
601 	if (!routing.num_routes)
602 		return 0;
603 
604 	/*
605 	 * Then get the actual routes, and verify that the num_routes gets
606 	 * updated to the correct number.
607 	 */
608 
609 	uint32_t num_routes = routing.num_routes;
610 	routing.len_routes = NUM_ROUTES_MAX;
611 	routing.num_routes = 0;
612 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_ROUTING, &routing));
613 	fail_on_test(routing.num_routes != num_routes);
614 
615 	/* Check the validity of route pads and flags */
616 
617 	if (node->pads) {
618 		for (i = 0; i < routing.num_routes; ++i) {
619 			const struct v4l2_subdev_route *route = &routes[i];
620 			const struct media_pad_desc *sink;
621 			const struct media_pad_desc *source;
622 
623 			fail_on_test(route->sink_pad >= node->entity.pads);
624 			fail_on_test(route->source_pad >= node->entity.pads);
625 
626 			sink = &node->pads[route->sink_pad];
627 			source = &node->pads[route->source_pad];
628 
629 			fail_on_test(!(sink->flags & MEDIA_PAD_FL_SINK));
630 			fail_on_test(!(source->flags & MEDIA_PAD_FL_SOURCE));
631 			fail_on_test(route->flags & ~all_route_flags_mask);
632 		}
633 	}
634 
635 	/*
636 	 * Set the same routes back, which should always succeed and report the
637 	 * same number of routes.
638 	 */
639 
640 	memset(routing.reserved, 0xff, sizeof(routing.reserved));
641 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_ROUTING, &routing));
642 	fail_on_test(routing.num_routes != num_routes);
643 	fail_on_test(check_0(routing.reserved, sizeof(routing.reserved)));
644 
645 	/* Test setting invalid pads */
646 
647 	if (node->pads) {
648 		for (i = 0; i < routing.num_routes; ++i) {
649 			struct v4l2_subdev_route *route = &routes[i];
650 
651 			route->sink_pad = node->entity.pads + 1;
652 		}
653 
654 		memset(routing.reserved, 0xff, sizeof(routing.reserved));
655 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_ROUTING, &routing) != EINVAL);
656 	}
657 
658 	return 0;
659 }
660