1 /*
2     V4L2 API subdev ioctl tests.
3 
4     Copyright (C) 2018  Hans Verkuil <hans.verkuil@cisco.com>
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 <unistd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <inttypes.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <errno.h>
31 #include <sys/ioctl.h>
32 #include <assert.h>
33 
34 #include "v4l2-compliance.h"
35 
testSubDevEnumFrameInterval(struct node * node,unsigned which,unsigned pad,unsigned code,unsigned width,unsigned height)36 static int testSubDevEnumFrameInterval(struct node *node, unsigned which,
37 				       unsigned pad, unsigned code,
38 				       unsigned width, unsigned height)
39 {
40 	struct v4l2_subdev_frame_interval_enum fie;
41 	unsigned num_ivals;
42 	int ret;
43 
44 	memset(&fie, 0, sizeof(fie));
45 	fie.which = which;
46 	fie.pad = pad;
47 	fie.code = code;
48 	fie.width = width;
49 	fie.height = height;
50 	ret = doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie);
51 	node->has_subdev_enum_fival |= (ret != ENOTTY) << which;
52 	if (ret == ENOTTY)
53 		return ret;
54 	if (which)
55 		fail_on_test(node->enum_frame_interval_pad != (int)pad);
56 	else
57 		fail_on_test(node->enum_frame_interval_pad >= 0);
58 	node->enum_frame_interval_pad = pad;
59 	fie.which = ~0;
60 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != EINVAL);
61 	fie.which = which;
62 	fie.index = ~0;
63 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != EINVAL);
64 	fie.pad = node->entity.pads;
65 	fie.index = 0;
66 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != EINVAL);
67 	fie.width = ~0;
68 	fie.pad = pad;
69 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != EINVAL);
70 	fie.height = ~0;
71 	fie.width = width;
72 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != EINVAL);
73 	memset(&fie, 0xff, sizeof(fie));
74 	fie.which = which;
75 	fie.pad = pad;
76 	fie.code = code;
77 	fie.width = width;
78 	fie.height = height;
79 	fie.index = 0;
80 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie));
81 	fail_on_test(check_0(fie.reserved, sizeof(fie.reserved)));
82 	fail_on_test(fie.which != which);
83 	fail_on_test(fie.pad != pad);
84 	fail_on_test(fie.code != code);
85 	fail_on_test(fie.width != width);
86 	fail_on_test(fie.height != height);
87 	fail_on_test(fie.index);
88 	fail_on_test(fie.interval.numerator == ~0U || fie.interval.denominator == ~0U);
89 	do {
90 		fie.index++;
91 		ret = doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie);
92 	} while (!ret);
93 	fail_on_test(ret != EINVAL);
94 
95 	num_ivals = fie.index;
96 	for (unsigned i = 0; i < num_ivals; i++) {
97 		fie.index = i;
98 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie));
99 		fail_on_test(fie.which != which);
100 		fail_on_test(fie.pad != pad);
101 		fail_on_test(fie.code != code);
102 		fail_on_test(fie.width != width);
103 		fail_on_test(fie.height != height);
104 		fail_on_test(fie.index != i);
105 		fail_on_test(!fie.interval.numerator);
106 		fail_on_test(!fie.interval.denominator);
107 	}
108 	return 0;
109 }
110 
testSubDevEnumFrameSize(struct node * node,unsigned which,unsigned pad,unsigned code)111 static int testSubDevEnumFrameSize(struct node *node, unsigned which,
112 				   unsigned pad, unsigned code)
113 {
114 	struct v4l2_subdev_frame_size_enum fse;
115 	unsigned num_sizes;
116 	int ret;
117 
118 	memset(&fse, 0, sizeof(fse));
119 	fse.which = which;
120 	fse.pad = pad;
121 	fse.code = code;
122 	ret = doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse);
123 	node->has_subdev_enum_fsize |= (ret != ENOTTY) << which;
124 	if (ret == ENOTTY) {
125 		struct v4l2_subdev_frame_interval_enum fie;
126 
127 		memset(&fie, 0, sizeof(fie));
128 		fie.which = which;
129 		fie.pad = pad;
130 		fie.code = code;
131 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != ENOTTY);
132 		return ret;
133 	}
134 	fse.which = ~0;
135 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse) != EINVAL);
136 	fse.which = which;
137 	fse.index = ~0;
138 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse) != EINVAL);
139 	fse.pad = node->entity.pads;
140 	fse.index = 0;
141 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse) != EINVAL);
142 	memset(&fse, 0xff, sizeof(fse));
143 	fse.which = which;
144 	fse.pad = pad;
145 	fse.code = code;
146 	fse.index = 0;
147 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse));
148 	fail_on_test(check_0(fse.reserved, sizeof(fse.reserved)));
149 	fail_on_test(fse.which != which);
150 	fail_on_test(fse.pad != pad);
151 	fail_on_test(fse.code != code);
152 	fail_on_test(fse.index);
153 	fail_on_test(!fse.min_width || !fse.min_height);
154 	fail_on_test(fse.min_width == ~0U || fse.min_height == ~0U);
155 	fail_on_test(!fse.max_width || !fse.max_height);
156 	fail_on_test(fse.max_width == ~0U || fse.max_height == ~0U);
157 	fail_on_test(fse.min_width > fse.max_width);
158 	fail_on_test(fse.min_height > fse.max_height);
159 	do {
160 		fse.index++;
161 		ret = doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse);
162 	} while (!ret);
163 	fail_on_test(ret != EINVAL);
164 
165 	num_sizes = fse.index;
166 	for (unsigned i = 0; i < num_sizes; i++) {
167 		fse.index = i;
168 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse));
169 		fail_on_test(fse.which != which);
170 		fail_on_test(fse.pad != pad);
171 		fail_on_test(fse.code != code);
172 		fail_on_test(fse.index != i);
173 		fail_on_test(!fse.min_width || !fse.min_height);
174 		fail_on_test(!fse.max_width || !fse.max_height);
175 		fail_on_test(fse.min_width > fse.max_width);
176 		fail_on_test(fse.min_height > fse.max_height);
177 
178 		ret = testSubDevEnumFrameInterval(node, which, pad, code,
179 						  fse.min_width, fse.min_height);
180 		fail_on_test(ret && ret != ENOTTY);
181 		ret = testSubDevEnumFrameInterval(node, which, pad, code,
182 						  fse.max_width, fse.max_height);
183 		fail_on_test(ret && ret != ENOTTY);
184 	}
185 	return 0;
186 }
187 
testSubDevEnum(struct node * node,unsigned which,unsigned pad)188 int testSubDevEnum(struct node *node, unsigned which, unsigned pad)
189 {
190 	struct v4l2_subdev_mbus_code_enum mbus_core_enum;
191 	unsigned num_codes;
192 	int ret;
193 
194 	memset(&mbus_core_enum, 0, sizeof(mbus_core_enum));
195 	mbus_core_enum.which = which;
196 	mbus_core_enum.pad = pad;
197 	ret = doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum);
198 	node->has_subdev_enum_code |= (ret != ENOTTY) << which;
199 	if (ret == ENOTTY) {
200 		struct v4l2_subdev_frame_size_enum fse;
201 		struct v4l2_subdev_frame_interval_enum fie;
202 
203 		memset(&fse, 0, sizeof(fse));
204 		memset(&fie, 0, sizeof(fie));
205 		fse.which = which;
206 		fse.pad = pad;
207 		fie.which = which;
208 		fie.pad = pad;
209 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &fse) != ENOTTY);
210 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL, &fie) != ENOTTY);
211 		return ret;
212 	}
213 	mbus_core_enum.which = ~0;
214 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum) != EINVAL);
215 	mbus_core_enum.which = which;
216 	mbus_core_enum.index = ~0;
217 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum) != EINVAL);
218 	mbus_core_enum.pad = node->entity.pads;
219 	mbus_core_enum.index = 0;
220 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum) != EINVAL);
221 	memset(&mbus_core_enum, 0xff, sizeof(mbus_core_enum));
222 	mbus_core_enum.which = which;
223 	mbus_core_enum.pad = pad;
224 	mbus_core_enum.index = 0;
225 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum));
226 	fail_on_test(check_0(mbus_core_enum.reserved, sizeof(mbus_core_enum.reserved)));
227 	fail_on_test(mbus_core_enum.code == ~0U);
228 	fail_on_test(mbus_core_enum.pad != pad);
229 	fail_on_test(mbus_core_enum.index);
230 	fail_on_test(mbus_core_enum.which != which);
231 	do {
232 		mbus_core_enum.index++;
233 		ret = doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum);
234 	} while (!ret);
235 	fail_on_test(ret != EINVAL);
236 
237 	num_codes = mbus_core_enum.index;
238 	for (unsigned i = 0; i < num_codes; i++) {
239 		mbus_core_enum.index = i;
240 		mbus_core_enum.code = 0;
241 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &mbus_core_enum));
242 		fail_on_test(!mbus_core_enum.code);
243 		fail_on_test(mbus_core_enum.which != which);
244 		fail_on_test(mbus_core_enum.pad != pad);
245 		fail_on_test(mbus_core_enum.index != i);
246 
247 		ret = testSubDevEnumFrameSize(node, which, pad, mbus_core_enum.code);
248 		fail_on_test(ret && ret != ENOTTY);
249 	}
250 	return 0;
251 }
252 
testSubDevFrameInterval(struct node * node,unsigned pad)253 int testSubDevFrameInterval(struct node *node, unsigned pad)
254 {
255 	struct v4l2_subdev_frame_interval fival;
256 	struct v4l2_fract ival;
257 	int ret;
258 
259 	memset(&fival, 0xff, sizeof(fival));
260 	fival.pad = pad;
261 	ret = doioctl(node, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &fival);
262 	if (ret == ENOTTY) {
263 		fail_on_test(node->enum_frame_interval_pad >= 0);
264 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival) != ENOTTY);
265 		return ret;
266 	}
267 	fail_on_test(node->frame_interval_pad >= 0);
268 	fail_on_test(node->enum_frame_interval_pad != (int)pad);
269 	node->frame_interval_pad = pad;
270 	fail_on_test(check_0(fival.reserved, sizeof(fival.reserved)));
271 	fail_on_test(fival.pad != pad);
272 	fail_on_test(!fival.interval.numerator);
273 	fail_on_test(!fival.interval.denominator);
274 	fail_on_test(fival.interval.numerator == ~0U || fival.interval.denominator == ~0U);
275 	ival = fival.interval;
276 	memset(fival.reserved, 0xff, sizeof(fival.reserved));
277 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival));
278 	fail_on_test(fival.pad != pad);
279 	fail_on_test(ival.numerator != fival.interval.numerator);
280 	fail_on_test(ival.denominator != fival.interval.denominator);
281 	fail_on_test(check_0(fival.reserved, sizeof(fival.reserved)));
282 	memset(&fival, 0, sizeof(fival));
283 	fival.pad = pad;
284 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &fival));
285 	fail_on_test(fival.pad != pad);
286 	fail_on_test(ival.numerator != fival.interval.numerator);
287 	fail_on_test(ival.denominator != fival.interval.denominator);
288 
289 	fival.pad = node->entity.pads;
290 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FRAME_INTERVAL, &fival) != EINVAL);
291 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival) != EINVAL);
292 	fival.pad = pad;
293 	fival.interval = ival;
294 	fival.interval.numerator = 0;
295 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival));
296 	fail_on_test(!fival.interval.numerator);
297 	fail_on_test(!fival.interval.denominator);
298 	fival.interval = ival;
299 	fival.interval.denominator = 0;
300 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival));
301 	fail_on_test(!fival.interval.numerator);
302 	fail_on_test(!fival.interval.denominator);
303 	fival.interval = ival;
304 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FRAME_INTERVAL, &fival));
305 	return 0;
306 }
307 
checkMBusFrameFmt(struct node * node,struct v4l2_mbus_framefmt & fmt)308 static int checkMBusFrameFmt(struct node *node, struct v4l2_mbus_framefmt &fmt)
309 {
310 	fail_on_test(check_0(fmt.reserved, sizeof(fmt.reserved)));
311 	fail_on_test(fmt.width == 0 || fmt.width > 65536);
312 	fail_on_test(fmt.height == 0 || fmt.height > 65536);
313 	fail_on_test(fmt.code == 0 || fmt.code == ~0U);
314 	fail_on_test(fmt.field == ~0U);
315 	if (!node->is_passthrough_subdev) {
316 		// Passthrough subdevs just copy this info, they don't validate
317 		// it. TODO: this does not take colorspace converters into account!
318 		fail_on_test(fmt.colorspace == ~0U);
319 		//TBD fail_on_test(!fmt.colorspace);
320 		fail_on_test(fmt.ycbcr_enc == 0xffff);
321 		fail_on_test(fmt.quantization == 0xffff);
322 		fail_on_test(fmt.xfer_func == 0xffff);
323 		fail_on_test(!fmt.colorspace &&
324 			     (fmt.ycbcr_enc || fmt.quantization || fmt.xfer_func));
325 	}
326 	return 0;
327 }
328 
testSubDevFormat(struct node * node,unsigned which,unsigned pad)329 int testSubDevFormat(struct node *node, unsigned which, unsigned pad)
330 {
331 	struct v4l2_subdev_format fmt;
332 	struct v4l2_subdev_format s_fmt;
333 	int ret;
334 
335 	memset(&fmt, 0, sizeof(fmt));
336 	fmt.which = which;
337 	fmt.pad = pad;
338 	ret = doioctl(node, VIDIOC_SUBDEV_G_FMT, &fmt);
339 	node->has_subdev_fmt |= (ret != ENOTTY) << which;
340 	if (ret == ENOTTY) {
341 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FMT, &fmt) != ENOTTY);
342 		return ret;
343 	}
344 	fmt.which = ~0;
345 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FMT, &fmt) != EINVAL);
346 	fmt.which = 0;
347 	fmt.pad = node->entity.pads;
348 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FMT, &fmt) != EINVAL);
349 	memset(&fmt, 0xff, sizeof(fmt));
350 	fmt.which = which;
351 	fmt.pad = pad;
352 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_FMT, &fmt));
353 	fail_on_test(check_0(fmt.reserved, sizeof(fmt.reserved)));
354 	fail_on_test(fmt.which != which);
355 	fail_on_test(fmt.pad != pad);
356 	fail_on_test(checkMBusFrameFmt(node, fmt.format));
357 	s_fmt = fmt;
358 	memset(s_fmt.reserved, 0xff, sizeof(s_fmt.reserved));
359 	memset(s_fmt.format.reserved, 0xff, sizeof(s_fmt.format.reserved));
360 	ret = doioctl(node, VIDIOC_SUBDEV_S_FMT, &s_fmt);
361 	fail_on_test(ret && ret != ENOTTY);
362 	fail_on_test(s_fmt.which != which);
363 	fail_on_test(s_fmt.pad != pad);
364 	if (ret) {
365 		warn("VIDIOC_SUBDEV_G_FMT is supported but not VIDIOC_SUBDEV_S_FMT\n");
366 		return 0;
367 	}
368 	fail_on_test(check_0(s_fmt.reserved, sizeof(s_fmt.reserved)));
369 	fail_on_test(checkMBusFrameFmt(node, s_fmt.format));
370 	fail_on_test(s_fmt.format.width != fmt.format.width);
371 	fail_on_test(s_fmt.format.height != fmt.format.height);
372 	fail_on_test(s_fmt.format.code != fmt.format.code);
373 	fail_on_test(s_fmt.format.field != fmt.format.field);
374 	fail_on_test(s_fmt.format.colorspace != fmt.format.colorspace);
375 	fail_on_test(s_fmt.format.ycbcr_enc != fmt.format.ycbcr_enc);
376 	fail_on_test(s_fmt.format.quantization != fmt.format.quantization);
377 	fail_on_test(s_fmt.format.xfer_func != fmt.format.xfer_func);
378 
379 	s_fmt.format.code = ~0U;
380 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FMT, &s_fmt));
381 	fail_on_test(s_fmt.format.code == ~0U);
382 	fail_on_test(!s_fmt.format.code);
383 
384 	// Restore fmt
385 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_FMT, &fmt));
386 	return 0;
387 }
388 
389 struct target_info {
390 	uint32_t target;
391 	bool allowed;
392 	bool readonly;
393 	bool found;
394 };
395 
396 static target_info targets[] = {
397 	{ V4L2_SEL_TGT_CROP, true },
398 	{ V4L2_SEL_TGT_CROP_DEFAULT, true, true },
399 	{ V4L2_SEL_TGT_CROP_BOUNDS, true, true },
400 	{ V4L2_SEL_TGT_NATIVE_SIZE, true },
401 	{ V4L2_SEL_TGT_COMPOSE, true },
402 	{ V4L2_SEL_TGT_COMPOSE_DEFAULT, false, true },
403 	{ V4L2_SEL_TGT_COMPOSE_BOUNDS, true, true },
404 	{ V4L2_SEL_TGT_COMPOSE_PADDED, false, true },
405 	{ ~0U },
406 };
407 
testSubDevSelection(struct node * node,unsigned which,unsigned pad)408 int testSubDevSelection(struct node *node, unsigned which, unsigned pad)
409 {
410 	struct v4l2_subdev_selection sel;
411 	struct v4l2_subdev_selection s_sel;
412 	struct v4l2_subdev_crop crop;
413 	bool is_sink = node->pads[pad].flags & MEDIA_PAD_FL_SINK;
414 	bool have_sel = false;
415 	int ret;
416 
417 	targets[V4L2_SEL_TGT_NATIVE_SIZE].readonly = is_sink;
418 	memset(&crop, 0, sizeof(crop));
419 	crop.pad = pad;
420 	crop.which = which;
421 	memset(&sel, 0, sizeof(sel));
422 	sel.which = which;
423 	sel.pad = pad;
424 	sel.target = V4L2_SEL_TGT_CROP;
425 	ret = doioctl(node, VIDIOC_SUBDEV_G_SELECTION, &sel);
426 	node->has_subdev_selection |= (ret != ENOTTY) << which;
427 	fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_CROP, &crop) != ret);
428 	if (ret == ENOTTY) {
429 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_SELECTION, &sel) != ENOTTY);
430 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_CROP, &crop) != ENOTTY);
431 		return ret;
432 	}
433 	fail_on_test(check_0(crop.reserved, sizeof(crop.reserved)));
434 	fail_on_test(crop.which != which);
435 	fail_on_test(crop.pad != pad);
436 	fail_on_test(memcmp(&crop.rect, &sel.r, sizeof(sel.r)));
437 
438 	for (unsigned tgt = 0; targets[tgt].target != ~0U; tgt++) {
439 		targets[tgt].found = false;
440 		memset(&sel, 0xff, sizeof(sel));
441 		sel.which = which;
442 		sel.pad = pad;
443 		sel.target = tgt;
444 		ret = doioctl(node, VIDIOC_SUBDEV_G_SELECTION, &sel);
445 		targets[tgt].found = !ret;
446 		fail_on_test(ret && ret != EINVAL);
447 		if (ret)
448 			continue;
449 		have_sel = true;
450 		fail_on_test(!targets[tgt].allowed);
451 		fail_on_test(check_0(sel.reserved, sizeof(sel.reserved)));
452 		fail_on_test(sel.which != which);
453 		fail_on_test(sel.pad != pad);
454 		fail_on_test(sel.target != tgt);
455 		fail_on_test(!sel.r.width);
456 		fail_on_test(sel.r.width == ~0U);
457 		fail_on_test(!sel.r.height);
458 		fail_on_test(sel.r.height == ~0U);
459 		fail_on_test(sel.r.top == ~0);
460 		fail_on_test(sel.r.left == ~0);
461 		sel.which = ~0;
462 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_SELECTION, &sel) != EINVAL);
463 		sel.which = 0;
464 		sel.pad = node->entity.pads;
465 		fail_on_test(doioctl(node, VIDIOC_SUBDEV_G_SELECTION, &sel) != EINVAL);
466 		sel.which = which;
467 		sel.pad = pad;
468 		s_sel = sel;
469 		memset(s_sel.reserved, 0xff, sizeof(s_sel.reserved));
470 		ret = doioctl(node, VIDIOC_SUBDEV_S_SELECTION, &s_sel);
471 		if (tgt == V4L2_SEL_TGT_CROP) {
472 			crop.rect = sel.r;
473 			memset(crop.reserved, 0xff, sizeof(crop.reserved));
474 			fail_on_test(doioctl(node, VIDIOC_SUBDEV_S_CROP, &crop) != ret);
475 			if (!ret) {
476 				fail_on_test(check_0(crop.reserved, sizeof(crop.reserved)));
477 				fail_on_test(crop.which != which);
478 				fail_on_test(crop.pad != pad);
479 				fail_on_test(memcmp(&crop.rect, &sel.r, sizeof(sel.r)));
480 			}
481 		}
482 		fail_on_test(!ret && targets[tgt].readonly);
483 		fail_on_test(s_sel.which != which);
484 		fail_on_test(s_sel.pad != pad);
485 		if (ret && !targets[tgt].readonly && tgt != V4L2_SEL_TGT_NATIVE_SIZE)
486 			warn("VIDIOC_SUBDEV_G_SELECTION is supported for target %u but not VIDIOC_SUBDEV_S_SELECTION\n", tgt);
487 		if (ret)
488 			continue;
489 		fail_on_test(check_0(s_sel.reserved, sizeof(s_sel.reserved)));
490 		fail_on_test(s_sel.flags != sel.flags);
491 		fail_on_test(s_sel.r.top != sel.r.top);
492 		fail_on_test(s_sel.r.left != sel.r.left);
493 		fail_on_test(s_sel.r.width != sel.r.width);
494 		fail_on_test(s_sel.r.height != sel.r.height);
495 	}
496 
497 	return have_sel ? 0 : ENOTTY;
498 }
499