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