blob: 7c4181a143d34ba01711e895a02fcca6b463b84a [file] [log] [blame]
Philippe De Muyter0cc96142014-11-03 21:27:40 +01001/*
2 * Copyright (c) 2014 Philippe De Muyter <phdm@macqel.be>
3 * Copyright (c) 2014 William Manley <will@williammanley.net>
4 * Copyright (c) 2011 Peter Zotov <whitequark@whitequark.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "defs.h"
31
Dmitry V. Levin1e568142016-05-03 22:30:41 +000032#include DEF_MPERS_TYPE(struct_v4l2_buffer)
33#include DEF_MPERS_TYPE(struct_v4l2_create_buffers)
34#include DEF_MPERS_TYPE(struct_v4l2_ext_control)
35#include DEF_MPERS_TYPE(struct_v4l2_ext_controls)
36#include DEF_MPERS_TYPE(struct_v4l2_format)
37#include DEF_MPERS_TYPE(struct_v4l2_framebuffer)
38#include DEF_MPERS_TYPE(struct_v4l2_input)
39#include DEF_MPERS_TYPE(struct_v4l2_standard)
40
Philippe De Muyter0cc96142014-11-03 21:27:40 +010041#include <stdint.h>
42#include <sys/ioctl.h>
Dmitry V. Levin0f4ad302015-02-22 02:13:04 +000043#include <linux/types.h>
Philippe De Muyter0cc96142014-11-03 21:27:40 +010044#include <linux/videodev2.h>
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +000045
Dmitry V. Levin1e568142016-05-03 22:30:41 +000046typedef struct v4l2_buffer struct_v4l2_buffer;
47typedef struct v4l2_create_buffers struct_v4l2_create_buffers;
48typedef struct v4l2_ext_control struct_v4l2_ext_control;
49typedef struct v4l2_ext_controls struct_v4l2_ext_controls;
50typedef struct v4l2_format struct_v4l2_format;
51typedef struct v4l2_framebuffer struct_v4l2_framebuffer;
52typedef struct v4l2_input struct_v4l2_input;
53typedef struct v4l2_standard struct_v4l2_standard;
54
55#include MPERS_DEFS
56
Philippe De Muyter0cc96142014-11-03 21:27:40 +010057/* some historical constants */
58#ifndef V4L2_CID_HCENTER
59#define V4L2_CID_HCENTER (V4L2_CID_BASE+22)
60#endif
61#ifndef V4L2_CID_VCENTER
62#define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
63#endif
64#ifndef V4L2_CID_BAND_STOP_FILTER
65#define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33)
66#endif
67
Philippe De Muyter0cc96142014-11-03 21:27:40 +010068#define FMT_FRACT "%u/%u"
69#define ARGS_FRACT(x) ((x).numerator), ((x).denominator)
70
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +000071#define FMT_RECT "{left=%d, top=%d, width=%u, height=%u}"
Philippe De Muyter0cc96142014-11-03 21:27:40 +010072#define ARGS_RECT(x) (x).left, (x).top, (x).width, (x).height
73
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +000074static void
75print_pixelformat(uint32_t fourcc)
Philippe De Muyter0cc96142014-11-03 21:27:40 +010076{
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +000077 const union {
Dmitry V. Levinf0a5b082015-01-25 00:27:00 +000078 uint32_t pixelformat;
79 unsigned char cc[sizeof(uint32_t)];
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +000080 } u = { .pixelformat = htole32(fourcc) };
Dmitry V. Levinf0a5b082015-01-25 00:27:00 +000081 unsigned int i;
82
83 tprints("v4l2_fourcc(");
84 for (i = 0; i < sizeof(u.cc); ++i) {
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +000085 unsigned char c = u.cc[i];
Dmitry V. Levinf0a5b082015-01-25 00:27:00 +000086
87 if (i)
88 tprints(", ");
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +000089 if (c == '\'' || c == '\\') {
Dmitry V. Levinf0a5b082015-01-25 00:27:00 +000090 char sym[] = {
91 '\'',
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +000092 '\\',
93 c,
94 '\'',
95 '\0'
96 };
97 tprints(sym);
98 } else if (c >= ' ' && c <= 0x7e) {
99 char sym[] = {
100 '\'',
101 c,
102 '\'',
103 '\0'
Dmitry V. Levinf0a5b082015-01-25 00:27:00 +0000104 };
105 tprints(sym);
106 } else {
107 char hex[] = {
108 '\'',
109 '\\',
110 'x',
111 "0123456789abcdef"[c >> 4],
112 "0123456789abcdef"[c & 0xf],
113 '\'',
114 '\0'
115 };
116 tprints(hex);
117 }
118 }
119 tprints(")");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100120}
121
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000122#include "xlat/v4l2_device_capabilities_flags.h"
123
124static int
125print_v4l2_capability(struct tcb *tcp, const long arg)
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100126{
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000127 struct v4l2_capability caps;
128
129 if (entering(tcp))
130 return 0;
131 tprints(", ");
132 if (umove_or_printaddr(tcp, arg, &caps))
133 return 1;
134 tprints("{driver=");
135 print_quoted_string((const char *) caps.driver,
136 sizeof(caps.driver), QUOTE_0_TERMINATED);
137 tprints(", card=");
138 print_quoted_string((const char *) caps.card,
139 sizeof(caps.card), QUOTE_0_TERMINATED);
140 tprints(", bus_info=");
141 print_quoted_string((const char *) caps.bus_info,
142 sizeof(caps.bus_info), QUOTE_0_TERMINATED);
143 tprintf(", version=%u.%u.%u, capabilities=",
144 (caps.version >> 16) & 0xFF,
145 (caps.version >> 8) & 0xFF,
146 caps.version & 0xFF);
147 printflags(v4l2_device_capabilities_flags, caps.capabilities,
148 "V4L2_CAP_???");
149#ifdef V4L2_CAP_DEVICE_CAPS
150 tprints(", device_caps=");
151 printflags(v4l2_device_capabilities_flags, caps.device_caps,
152 "V4L2_CAP_???");
153#endif
154 tprints("}");
155 return 1;
156}
157
158#include "xlat/v4l2_buf_types.h"
159#include "xlat/v4l2_format_description_flags.h"
160
161static int
162print_v4l2_fmtdesc(struct tcb *tcp, const long arg)
163{
164 struct v4l2_fmtdesc f;
165
166 if (entering(tcp)) {
167 tprints(", ");
168 if (umove_or_printaddr(tcp, arg, &f))
169 return RVAL_DECODED | 1;
170 tprintf("{index=%u, type=", f.index);
171 printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
172 return 0;
173 }
174
175 if (!syserror(tcp) && !umove(tcp, arg, &f)) {
176 tprints(", flags=");
177 printflags(v4l2_format_description_flags, f.flags,
178 "V4L2_FMT_FLAG_???");
179 tprints(", description=");
180 print_quoted_string((const char *) f.description,
181 sizeof(f.description),
182 QUOTE_0_TERMINATED);
183 tprints(", pixelformat=");
184 print_pixelformat(f.pixelformat);
185 }
186 tprints("}");
187 return 1;
188}
189
190#include "xlat/v4l2_fields.h"
191#include "xlat/v4l2_colorspaces.h"
192
193static void
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000194print_v4l2_format_fmt(const char *prefix, const struct_v4l2_format *f)
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000195{
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100196 switch (f->type) {
197 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000198 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
199 tprints(prefix);
200 tprintf("fmt.pix={width=%u, height=%u, pixelformat=",
201 f->fmt.pix.width, f->fmt.pix.height);
202 print_pixelformat(f->fmt.pix.pixelformat);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100203 tprints(", field=");
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000204 printxval(v4l2_fields, f->fmt.pix.field, "V4L2_FIELD_???");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100205 tprintf(", bytesperline=%u, sizeimage=%u, colorspace=",
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000206 f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
207 printxval(v4l2_colorspaces, f->fmt.pix.colorspace,
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100208 "V4L2_COLORSPACE_???");
209 tprints("}");
210 break;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100211#if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
212 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
213 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: {
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100214 unsigned int i, max;
215
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000216 tprints(prefix);
217 tprintf("fmt.pix_mp={width=%u, height=%u, pixelformat=",
218 f->fmt.pix_mp.width, f->fmt.pix_mp.height);
219 print_pixelformat(f->fmt.pix_mp.pixelformat);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100220 tprints(", field=");
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000221 printxval(v4l2_fields, f->fmt.pix_mp.field, "V4L2_FIELD_???");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100222 tprints(", colorspace=");
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000223 printxval(v4l2_colorspaces, f->fmt.pix_mp.colorspace,
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100224 "V4L2_COLORSPACE_???");
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000225 tprints(", plane_fmt=[");
226 max = f->fmt.pix_mp.num_planes;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100227 if (max > VIDEO_MAX_PLANES)
228 max = VIDEO_MAX_PLANES;
229 for (i = 0; i < max; i++) {
230 if (i > 0)
231 tprints(", ");
232 tprintf("{sizeimage=%u, bytesperline=%u}",
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000233 f->fmt.pix_mp.plane_fmt[i].sizeimage,
234 f->fmt.pix_mp.plane_fmt[i].bytesperline);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100235 }
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000236 tprintf("], num_planes=%u}", (unsigned) f->fmt.pix_mp.num_planes);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100237 break;
238 }
239#endif
240
241 /* TODO: Complete this switch statement */
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000242#if 0
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100243 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
Dmitry V. Levin197db572015-01-09 04:53:19 +0000244#if HAVE_DECL_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100245 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
Dmitry V. Levin197db572015-01-09 04:53:19 +0000246#endif
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000247 tprints(prefix);
248 tprints("fmt.win={???}");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100249 break;
250
251 case V4L2_BUF_TYPE_VBI_CAPTURE:
252 case V4L2_BUF_TYPE_VBI_OUTPUT:
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000253 tprints(prefix);
254 tprints("fmt.vbi={???}");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100255 break;
256
257 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
258 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000259 tprints(prefix);
260 tprints("fmt.sliced={???}");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100261 break;
262
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000263#if HAVE_DECL_V4L2_BUF_TYPE_SDR_CAPTURE
264 case V4L2_BUF_TYPE_SDR_CAPTURE:
265 case V4L2_BUF_TYPE_SDR_OUTPUT:
266 tprints(prefix);
267 tprints("fmt.sdr={???}");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100268 break;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000269#endif
270#endif
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100271 }
272}
273
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000274static int
275print_v4l2_format(struct tcb *tcp, const long arg, const bool is_get)
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100276{
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000277 struct_v4l2_format f;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000278
279 if (entering(tcp)) {
280 tprints(", ");
281 if (umove_or_printaddr(tcp, arg, &f))
282 return RVAL_DECODED | 1;
283 tprints("{type=");
284 printxval(v4l2_buf_types, f.type, "V4L2_BUF_TYPE_???");
285 if (is_get)
286 return 0;
287 print_v4l2_format_fmt(", ", &f);
288 } else {
289 if (!syserror(tcp) && !umove(tcp, arg, &f)) {
290 const char *delim = is_get ? ", " : " => ";
291 print_v4l2_format_fmt(delim, &f);
292 }
293 tprints("}");
294 }
295 return 1;
296}
297
298#include "xlat/v4l2_memories.h"
299
300static int
301print_v4l2_requestbuffers(struct tcb *tcp, const long arg)
302{
303 struct v4l2_requestbuffers reqbufs;
304
305 if (entering(tcp)) {
306 tprints(", ");
307 if (umove_or_printaddr(tcp, arg, &reqbufs))
308 return RVAL_DECODED | 1;
309 tprintf("{count=%u, type=", reqbufs.count);
310 printxval(v4l2_buf_types, reqbufs.type, "V4L2_BUF_TYPE_???");
311 tprints(", memory=");
312 printxval(v4l2_memories, reqbufs.memory, "V4L2_MEMORY_???");
313 tprints("}");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100314 return 0;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000315 } else {
316 static char outstr[sizeof("{count=}") + sizeof(int) * 3];
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100317
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000318 if (syserror(tcp) || umove(tcp, arg, &reqbufs) < 0)
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100319 return 1;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000320 sprintf(outstr, "{count=%u}", reqbufs.count);
321 tcp->auxstr = outstr;
322 return 1 + RVAL_STR;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100323 }
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000324}
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100325
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000326#include "xlat/v4l2_buf_flags.h"
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100327
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000328static int
329print_v4l2_buffer(struct tcb *tcp, const unsigned int code, const long arg)
330{
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000331 struct_v4l2_buffer b;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000332
333 if (entering(tcp)) {
334 tprints(", ");
335 if (umove_or_printaddr(tcp, arg, &b))
336 return RVAL_DECODED | 1;
337 tprints("{type=");
338 printxval(v4l2_buf_types, b.type, "V4L2_BUF_TYPE_???");
339 if (code != VIDIOC_DQBUF)
340 tprintf(", index=%u", b.index);
341 } else {
342 if (!syserror(tcp) && umove(tcp, arg, &b) == 0) {
343 if (code == VIDIOC_DQBUF)
344 tprintf(", index=%u", b.index);
345 tprints(", memory=");
346 printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
347
348 if (b.memory == V4L2_MEMORY_MMAP) {
349 tprintf(", m.offset=%#x", b.m.offset);
350 } else if (b.memory == V4L2_MEMORY_USERPTR) {
351 tprintf(", m.userptr=%#lx",
352 (unsigned long) b.m.userptr);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100353 }
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100354
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000355 tprintf(", length=%u, bytesused=%u, flags=",
356 b.length, b.bytesused);
357 printflags(v4l2_buf_flags, b.flags, "V4L2_BUF_FLAG_???");
358 if (code == VIDIOC_DQBUF)
359 tprintf(", timestamp = {%ju.%06ju}",
360 (uintmax_t)b.timestamp.tv_sec,
361 (uintmax_t)b.timestamp.tv_usec);
362 tprints(", ...");
363 }
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100364 tprints("}");
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000365 }
366 return 1;
367}
368
369static int
370print_v4l2_framebuffer(struct tcb *tcp, const long arg)
371{
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000372 struct_v4l2_framebuffer b;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000373
374 tprints(", ");
375 if (!umove_or_printaddr(tcp, arg, &b)) {
376 tprintf("{capability=%#x, flags=%#x, base=%#lx}",
377 b.capability, b.flags, (unsigned long) b.base);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100378 }
379
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000380 return RVAL_DECODED | 1;
381}
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100382
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000383static int
384print_v4l2_buf_type(struct tcb *tcp, const long arg)
385{
386 int type;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100387
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000388 tprints(", ");
389 if (!umove_or_printaddr(tcp, arg, &type)) {
390 tprints("[");
391 printxval(v4l2_buf_types, type, "V4L2_BUF_TYPE_???");
392 tprints("]");
393 }
394 return RVAL_DECODED | 1;
395}
396
397#include "xlat/v4l2_streaming_capabilities.h"
398#include "xlat/v4l2_capture_modes.h"
399
400static int
401print_v4l2_streamparm(struct tcb *tcp, const long arg, const bool is_get)
402{
403 struct v4l2_streamparm s;
404
405 if (entering(tcp)) {
406 tprints(", ");
407 if (umove_or_printaddr(tcp, arg, &s))
408 return RVAL_DECODED | 1;
409 tprints("{type=");
410 printxval(v4l2_buf_types, s.type, "V4L2_BUF_TYPE_???");
411 switch (s.type) {
412 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
413 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
414 if (is_get)
415 return 0;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100416 tprints(", ");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100417 break;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000418 default:
419 tprints("}");
420 return RVAL_DECODED | 1;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100421 }
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000422 } else {
423 if (syserror(tcp) || umove(tcp, arg, &s) < 0) {
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100424 tprints("}");
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000425 return 1;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100426 }
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000427 tprints(is_get ? ", " : " => ");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100428 }
429
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000430 if (s.type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
431 tprints("parm.capture={capability=");
432 printflags(v4l2_streaming_capabilities,
433 s.parm.capture.capability, "V4L2_CAP_???");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100434
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000435 tprints(", capturemode=");
436 printflags(v4l2_capture_modes,
437 s.parm.capture.capturemode, "V4L2_MODE_???");
438
439 tprintf(", timeperframe=" FMT_FRACT,
440 ARGS_FRACT(s.parm.capture.timeperframe));
441
442 tprintf(", extendedmode=%u, readbuffers=%u}",
443 s.parm.capture.extendedmode,
444 s.parm.capture.readbuffers);
445 } else {
446 tprints("parm.output={capability=");
447 printflags(v4l2_streaming_capabilities,
448 s.parm.output.capability, "V4L2_CAP_???");
449
450 tprintf(", outputmode=%u", s.parm.output.outputmode);
451
452 tprintf(", timeperframe=" FMT_FRACT,
453 ARGS_FRACT(s.parm.output.timeperframe));
454
455 tprintf(", extendedmode=%u, writebuffers=%u}",
456 s.parm.output.extendedmode,
457 s.parm.output.writebuffers);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100458 }
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000459 if (exiting(tcp))
460 tprints("}");
461 return 1;
462}
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100463
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000464static int
465print_v4l2_standard(struct tcb *tcp, const long arg)
466{
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000467 struct_v4l2_standard s;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100468
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000469 if (entering(tcp)) {
470 tprints(", ");
471 if (umove_or_printaddr(tcp, arg, &s))
472 return RVAL_DECODED | 1;
473 tprintf("{index=%u", s.index);
474 } else {
475 if (!syserror(tcp) && !umove(tcp, arg, &s)) {
476 tprints(", name=");
477 print_quoted_string((const char *) s.name,
478 sizeof(s.name),
479 QUOTE_0_TERMINATED);
480 tprintf(", frameperiod=" FMT_FRACT,
481 ARGS_FRACT(s.frameperiod));
482 tprintf(", framelines=%d", s.framelines);
483 }
484 tprints("}");
485 }
486 return 1;
487}
488
489#include "xlat/v4l2_input_types.h"
490
491static int
492print_v4l2_input(struct tcb *tcp, const long arg)
493{
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000494 struct_v4l2_input i;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000495
496 if (entering(tcp)) {
497 tprints(", ");
498 if (umove_or_printaddr(tcp, arg, &i))
499 return RVAL_DECODED | 1;
500 tprintf("{index=%u", i.index);
501 } else {
502 if (!syserror(tcp) && !umove(tcp, arg, &i)) {
Dmitry V. Levin1de59cf2015-01-26 02:45:09 +0000503 tprints(", name=");
504 print_quoted_string((const char *) i.name,
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000505 sizeof(i.name),
506 QUOTE_0_TERMINATED);
Dmitry V. Levin1de59cf2015-01-26 02:45:09 +0000507 tprints(", type=");
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100508 printxval(v4l2_input_types, i.type,
509 "V4L2_INPUT_TYPE_???");
510 }
511 tprints("}");
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000512 }
513 return 1;
514}
515
516#include "xlat/v4l2_control_ids.h"
517
518static int
519print_v4l2_control(struct tcb *tcp, const long arg, const bool is_get)
520{
521 struct v4l2_control c;
522
523 if (entering(tcp)) {
524 tprints(", ");
525 if (umove_or_printaddr(tcp, arg, &c))
526 return RVAL_DECODED | 1;
527 tprints("{id=");
528 printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
529 if (!is_get)
530 tprintf(", value=%d", c.value);
531 return 0;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100532 }
533
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000534 if (!syserror(tcp) && !umove(tcp, arg, &c)) {
535 tprints(is_get ? ", " : " => ");
536 tprintf("value=%d", c.value);
537 }
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100538
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000539 tprints("}");
540 return 1;
541}
542
543#include "xlat/v4l2_control_types.h"
544#include "xlat/v4l2_control_flags.h"
545
546static int
547print_v4l2_queryctrl(struct tcb *tcp, const long arg)
548{
549 struct v4l2_queryctrl c;
550
551 if (entering(tcp)) {
552 tprints(", ");
553 if (umove_or_printaddr(tcp, arg, &c))
554 return RVAL_DECODED | 1;
555 tprints("{id=");
556 } else {
557 if (syserror(tcp) || umove(tcp, arg, &c) < 0) {
558 tprints("}");
559 return 1;
560 }
561 if (tcp->auxstr)
562 tprints(" => ");
563 }
564
565 if (entering(tcp) || tcp->auxstr) {
566#ifdef V4L2_CTRL_FLAG_NEXT_CTRL
567 tcp->auxstr = (c.id & V4L2_CTRL_FLAG_NEXT_CTRL) ? "" : NULL;
568 if (tcp->auxstr) {
569 tprints("V4L2_CTRL_FLAG_NEXT_CTRL|");
570 c.id &= ~V4L2_CTRL_FLAG_NEXT_CTRL;
571 }
572#endif
573 printxval(v4l2_control_ids, c.id, "V4L2_CID_???");
574 }
575
576 if (exiting(tcp)) {
577 tprints(", type=");
578 printxval(v4l2_control_types, c.type, "V4L2_CTRL_TYPE_???");
579 tprints(", name=");
580 print_quoted_string((const char *) c.name,
581 sizeof(c.name),
582 QUOTE_0_TERMINATED);
583 tprintf(", minimum=%d, maximum=%d, step=%d"
584 ", default_value=%d, flags=",
585 c.minimum, c.maximum, c.step, c.default_value);
586 printflags(v4l2_control_flags, c.flags, "V4L2_CTRL_FLAG_???");
587 tprints("}");
588 }
589 return 1;
590}
591
592static int
593print_v4l2_cropcap(struct tcb *tcp, const long arg)
594{
595 struct v4l2_cropcap c;
596
597 if (entering(tcp)) {
598 tprints(", ");
599 if (umove_or_printaddr(tcp, arg, &c))
600 return RVAL_DECODED | 1;
601 tprints("{type=");
602 printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
603 return 0;
604 }
605 if (!syserror(tcp) && !umove(tcp, arg, &c)) {
606 tprintf(", bounds=" FMT_RECT
607 ", defrect=" FMT_RECT
608 ", pixelaspect=" FMT_FRACT,
609 ARGS_RECT(c.bounds),
610 ARGS_RECT(c.defrect),
611 ARGS_FRACT(c.pixelaspect));
612 }
613 tprints("}");
614 return 1;
615}
616
617static int
618print_v4l2_crop(struct tcb *tcp, const long arg, const bool is_get)
619{
620 struct v4l2_crop c;
621
622 if (entering(tcp)) {
623 tprints(", ");
624 if (umove_or_printaddr(tcp, arg, &c))
625 return RVAL_DECODED | 1;
626 tprints("{type=");
627 printxval(v4l2_buf_types, c.type, "V4L2_BUF_TYPE_???");
628 if (is_get)
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100629 return 0;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000630 tprintf(", c=" FMT_RECT, ARGS_RECT(c.c));
631 } else {
632 if (!syserror(tcp) && !umove(tcp, arg, &c))
633 tprintf(", c=" FMT_RECT, ARGS_RECT(c.c));
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100634 }
635
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000636 tprints("}");
637 return RVAL_DECODED | 1;
638}
639
640#ifdef VIDIOC_S_EXT_CTRLS
641static int
642print_v4l2_ext_control_array(struct tcb *tcp, const unsigned long addr,
643 const unsigned count)
644{
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000645 struct_v4l2_ext_control ctrl;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000646 const unsigned long size = count * sizeof(ctrl);
647 const unsigned long end = addr + size;
648 int rc = 0;
649
650 if (!addr || end <= addr || size / sizeof(ctrl) != count) {
651 printaddr(addr);
652 return -1;
653 }
654 const unsigned long abbrev_end =
655 (abbrev(tcp) && max_strlen < count) ?
656 addr + max_strlen * sizeof(ctrl) : end;
657 unsigned long cur;
658 for (cur = addr; cur < end; cur += sizeof(ctrl)) {
659 if (cur != addr)
660 tprints(", ");
661
662 if (umove(tcp, cur, &ctrl)) {
663 printaddr(cur);
664 rc = -1;
665 break;
666 }
667
668 if (cur == addr)
669 tprints("[");
670
671 if (cur >= abbrev_end) {
672 tprints("...");
673 cur = end;
674 break;
675 }
676
677 tprints("{id=");
678 printxval(v4l2_control_ids, ctrl.id, "V4L2_CID_???");
679# if HAVE_DECL_V4L2_CTRL_TYPE_STRING
680 tprintf(", size=%u", ctrl.size);
681 if (ctrl.size > 0) {
682 tprints(", string=");
683 printstr(tcp, (long) ctrl.string, ctrl.size);
684 } else
685# endif
686 tprintf(", value=%d, value64=%lld", ctrl.value,
687 (long long) ctrl.value64);
688 tprints("}");
689 }
690 if (cur != addr)
691 tprints("]");
692 return rc;
693}
694
695#include "xlat/v4l2_control_classes.h"
696
697static int
698print_v4l2_ext_controls(struct tcb *tcp, const long arg, const bool is_get)
699{
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000700 struct_v4l2_ext_controls c;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000701
702 if (entering(tcp)) {
703 tprints(", ");
704 if (umove_or_printaddr(tcp, arg, &c))
705 return RVAL_DECODED | 1;
706 tprints("{ctrl_class=");
707 printxval(v4l2_control_classes, c.ctrl_class,
708 "V4L2_CTRL_CLASS_???");
709 tprintf(", count=%u", c.count);
710 if (!c.count) {
711 tprints("}");
712 return RVAL_DECODED | 1;
713 }
714 if (is_get)
715 return 0;
716 tprints(", ");
717 } else {
718 if (umove(tcp, arg, &c) < 0) {
719 tprints("}");
720 return 1;
721 }
722 tprints(is_get ? ", " : " => ");
723 }
724
725 tprints("controls=");
726 int fail = print_v4l2_ext_control_array(tcp,
727 (unsigned long) c.controls,
728 c.count);
729
730 if (exiting(tcp) && syserror(tcp))
731 tprintf(", error_idx=%u", c.error_idx);
732
733 if (exiting(tcp) || fail) {
734 tprints("}");
735 return RVAL_DECODED | 1;
736 }
737 return 1;
738}
739#endif /* VIDIOC_S_EXT_CTRLS */
740
741#ifdef VIDIOC_ENUM_FRAMESIZES
742# include "xlat/v4l2_framesize_types.h"
743
744static int
745print_v4l2_frmsizeenum(struct tcb *tcp, const long arg)
746{
747 struct v4l2_frmsizeenum s;
748
749 if (entering(tcp)) {
750 tprints(", ");
751 if (umove_or_printaddr(tcp, arg, &s))
752 return RVAL_DECODED | 1;
753 tprintf("{index=%u, pixel_format=", s.index);
754 print_pixelformat(s.pixel_format);
755 return 0;
756 }
757
758 if (!syserror(tcp) && !umove(tcp, arg, &s)) {
759 tprints(", type=");
760 printxval(v4l2_framesize_types, s.type, "V4L2_FRMSIZE_TYPE_???");
761 switch (s.type) {
762 case V4L2_FRMSIZE_TYPE_DISCRETE:
763 tprintf(", discrete={width=%u, height=%u}",
764 s.discrete.width, s.discrete.height);
765 break;
766 case V4L2_FRMSIZE_TYPE_STEPWISE:
767 tprintf(", stepwise={min_width=%u, max_width=%u, "
768 "step_width=%u, min_height=%u, max_height=%u, "
769 "step_height=%u}",
770 s.stepwise.min_width, s.stepwise.max_width,
771 s.stepwise.step_width, s.stepwise.min_height,
772 s.stepwise.max_height, s.stepwise.step_height);
773 break;
774 }
775 }
776 tprints("}");
777 return 1;
778}
779#endif /* VIDIOC_ENUM_FRAMESIZES */
780
Dmitry V. Levin197db572015-01-09 04:53:19 +0000781#ifdef VIDIOC_ENUM_FRAMEINTERVALS
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000782# include "xlat/v4l2_frameinterval_types.h"
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100783
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000784static int
785print_v4l2_frmivalenum(struct tcb *tcp, const long arg)
786{
787 struct v4l2_frmivalenum f;
788
789 if (entering(tcp)) {
790 tprints(", ");
791 if (umove_or_printaddr(tcp, arg, &f))
792 return RVAL_DECODED | 1;
793 tprintf("{index=%u, pixel_format=", f.index);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100794 print_pixelformat(f.pixel_format);
795 tprintf(", width=%u, height=%u", f.width, f.height);
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000796 return 0;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100797 }
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000798 if (!syserror(tcp) && !umove(tcp, arg, &f)) {
799 tprints(", type=");
800 printxval(v4l2_frameinterval_types, f.type,
801 "V4L2_FRMIVAL_TYPE_???");
802 switch (f.type) {
803 case V4L2_FRMIVAL_TYPE_DISCRETE:
804 tprintf(", discrete=" FMT_FRACT,
805 ARGS_FRACT(f.discrete));
806 break;
807 case V4L2_FRMIVAL_TYPE_STEPWISE:
808 case V4L2_FRMSIZE_TYPE_CONTINUOUS:
809 tprintf(", stepwise={min=" FMT_FRACT ", max="
810 FMT_FRACT ", step=" FMT_FRACT "}",
811 ARGS_FRACT(f.stepwise.min),
812 ARGS_FRACT(f.stepwise.max),
813 ARGS_FRACT(f.stepwise.step));
814 break;
815 }
816 }
817 tprints("}");
818 return 1;
819}
Dmitry V. Levin197db572015-01-09 04:53:19 +0000820#endif /* VIDIOC_ENUM_FRAMEINTERVALS */
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100821
Dmitry V. Levinfffe50d2015-08-26 11:55:05 +0000822#ifdef VIDIOC_CREATE_BUFS
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000823static int
824print_v4l2_create_buffers(struct tcb *tcp, const long arg)
825{
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000826 struct_v4l2_create_buffers b;
Philippe De Muyter6779e712015-04-18 15:06:43 +0200827
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000828 if (entering(tcp)) {
829 tprints(", ");
830 if (umove_or_printaddr(tcp, arg, &b))
831 return RVAL_DECODED | 1;
832 tprintf("{count=%u, memory=", b.count);
833 printxval(v4l2_memories, b.memory, "V4L2_MEMORY_???");
834 tprints(", format={type=");
835 printxval(v4l2_buf_types, b.format.type,
836 "V4L2_BUF_TYPE_???");
837 print_v4l2_format_fmt(", ",
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000838 (struct_v4l2_format *) &b.format);
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000839 tprints("}}");
840 return 0;
841 } else {
842 static const char fmt[] = "{index=%u, count=%u}";
843 static char outstr[sizeof(fmt) + sizeof(int) * 6];
Philippe De Muyter6779e712015-04-18 15:06:43 +0200844
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000845 if (syserror(tcp) || umove(tcp, arg, &b) < 0)
846 return 1;
847 sprintf(outstr, fmt, b.index, b.count);
848 tcp->auxstr = outstr;
849 return 1 + RVAL_STR;
Philippe De Muyter6779e712015-04-18 15:06:43 +0200850 }
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000851}
Dmitry V. Levinfffe50d2015-08-26 11:55:05 +0000852#endif /* VIDIOC_CREATE_BUFS */
Philippe De Muyter6779e712015-04-18 15:06:43 +0200853
Dmitry V. Levin1e568142016-05-03 22:30:41 +0000854MPERS_PRINTER_DECL(int, v4l2_ioctl)(struct tcb *tcp, const unsigned int code, const long arg)
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000855{
856 if (!verbose(tcp))
857 return RVAL_DECODED;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100858
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000859 switch (code) {
860 case VIDIOC_QUERYCAP: /* R */
861 return print_v4l2_capability(tcp, arg);
862
863 case VIDIOC_ENUM_FMT: /* RW */
864 return print_v4l2_fmtdesc(tcp, arg);
865
866 case VIDIOC_G_FMT: /* RW */
867 case VIDIOC_S_FMT: /* RW */
868 case VIDIOC_TRY_FMT: /* RW */
869 return print_v4l2_format(tcp, arg, code == VIDIOC_G_FMT);
870
871 case VIDIOC_REQBUFS: /* RW */
872 return print_v4l2_requestbuffers(tcp, arg);
873
874 case VIDIOC_QUERYBUF: /* RW */
875 case VIDIOC_QBUF: /* RW */
876 case VIDIOC_DQBUF: /* RW */
877 return print_v4l2_buffer(tcp, code, arg);
878
879 case VIDIOC_G_FBUF: /* R */
880 if (entering(tcp))
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100881 return 0;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000882 /* fall through */
883 case VIDIOC_S_FBUF: /* W */
884 return print_v4l2_framebuffer(tcp, arg);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100885
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000886 case VIDIOC_STREAMON: /* W */
887 case VIDIOC_STREAMOFF: /* W */
888 return print_v4l2_buf_type(tcp, arg);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100889
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000890 case VIDIOC_G_PARM: /* RW */
891 case VIDIOC_S_PARM: /* RW */
892 return print_v4l2_streamparm(tcp, arg, code == VIDIOC_G_PARM);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100893
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000894 case VIDIOC_G_STD: /* R */
895 if (entering(tcp))
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100896 return 0;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000897 /* fall through */
898 case VIDIOC_S_STD: /* W */
899 tprints(", ");
900 printnum_int64(tcp, arg, "%#" PRIx64);
901 return RVAL_DECODED | 1;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100902
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000903 case VIDIOC_ENUMSTD: /* RW */
904 return print_v4l2_standard(tcp, arg);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100905
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000906 case VIDIOC_ENUMINPUT: /* RW */
907 return print_v4l2_input(tcp, arg);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100908
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000909 case VIDIOC_G_CTRL: /* RW */
910 case VIDIOC_S_CTRL: /* RW */
911 return print_v4l2_control(tcp, arg, code == VIDIOC_G_CTRL);
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100912
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000913 case VIDIOC_QUERYCTRL: /* RW */
914 return print_v4l2_queryctrl(tcp, arg);
915
916 case VIDIOC_G_INPUT: /* R */
917 if (entering(tcp))
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100918 return 0;
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000919 /* fall through */
920 case VIDIOC_S_INPUT: /* RW */
921 tprints(", ");
922 printnum_int(tcp, arg, "%u");
923 return RVAL_DECODED | 1;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100924
Dmitry V. Levin0a47ff72016-05-01 17:25:24 +0000925 case VIDIOC_CROPCAP: /* RW */
926 return print_v4l2_cropcap(tcp, arg);
927
928 case VIDIOC_G_CROP: /* RW */
929 case VIDIOC_S_CROP: /* W */
930 return print_v4l2_crop(tcp, arg, code == VIDIOC_G_CROP);
931
932#ifdef VIDIOC_S_EXT_CTRLS
933 case VIDIOC_S_EXT_CTRLS: /* RW */
934 case VIDIOC_TRY_EXT_CTRLS: /* RW */
935 case VIDIOC_G_EXT_CTRLS: /* RW */
936 return print_v4l2_ext_controls(tcp, arg,
937 code == VIDIOC_G_EXT_CTRLS);
938#endif /* VIDIOC_S_EXT_CTRLS */
939
940#ifdef VIDIOC_ENUM_FRAMESIZES
941 case VIDIOC_ENUM_FRAMESIZES: /* RW */
942 return print_v4l2_frmsizeenum(tcp, arg);
943#endif /* VIDIOC_ENUM_FRAMESIZES */
944
945#ifdef VIDIOC_ENUM_FRAMEINTERVALS
946 case VIDIOC_ENUM_FRAMEINTERVALS: /* RW */
947 return print_v4l2_frmivalenum(tcp, arg);
948#endif /* VIDIOC_ENUM_FRAMEINTERVALS */
949
950#ifdef VIDIOC_CREATE_BUFS
951 case VIDIOC_CREATE_BUFS: /* RW */
952 return print_v4l2_create_buffers(tcp, arg);
953#endif /* VIDIOC_CREATE_BUFS */
954
955 default:
956 return RVAL_DECODED;
Philippe De Muyter0cc96142014-11-03 21:27:40 +0100957 }
958}