videoctl.c revision 1.4 1 1.4 mlelstv /* $NetBSD: videoctl.c,v 1.4 2025/04/12 07:54:39 mlelstv Exp $ */
2 1.1 jmcneill
3 1.1 jmcneill /*-
4 1.1 jmcneill * Copyright (c) 2010 Jared D. McNeill <jmcneill (at) invisible.ca>
5 1.1 jmcneill * All rights reserved.
6 1.1 jmcneill *
7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without
8 1.1 jmcneill * modification, are permitted provided that the following conditions
9 1.1 jmcneill * are met:
10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright
11 1.1 jmcneill * notice, this list of conditions and the following disclaimer.
12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the
14 1.1 jmcneill * documentation and/or other materials provided with the distribution.
15 1.1 jmcneill *
16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE.
27 1.1 jmcneill */
28 1.1 jmcneill
29 1.1 jmcneill #include <sys/cdefs.h>
30 1.1 jmcneill __COPYRIGHT("@(#) Copyright (c) 2010\
31 1.1 jmcneill Jared D. McNeill <jmcneill (at) invisible.ca>. All rights reserved.");
32 1.4 mlelstv __RCSID("$NetBSD: videoctl.c,v 1.4 2025/04/12 07:54:39 mlelstv Exp $");
33 1.1 jmcneill
34 1.1 jmcneill #include <sys/types.h>
35 1.4 mlelstv #include <sys/endian.h>
36 1.1 jmcneill #include <sys/ioctl.h>
37 1.1 jmcneill #include <sys/videoio.h>
38 1.1 jmcneill
39 1.1 jmcneill #include <err.h>
40 1.1 jmcneill #include <errno.h>
41 1.1 jmcneill #include <fcntl.h>
42 1.1 jmcneill #include <limits.h>
43 1.1 jmcneill #include <paths.h>
44 1.1 jmcneill #include <stdio.h>
45 1.1 jmcneill #include <string.h>
46 1.1 jmcneill #include <stdbool.h>
47 1.1 jmcneill #include <stdlib.h>
48 1.1 jmcneill #include <unistd.h>
49 1.1 jmcneill #include <util.h>
50 1.4 mlelstv #include <vis.h>
51 1.1 jmcneill
52 1.2 joerg __dead static void usage(void);
53 1.1 jmcneill static void video_print(const char *);
54 1.1 jmcneill static void video_print_all(void);
55 1.1 jmcneill static bool video_print_caps(const char *);
56 1.1 jmcneill static bool video_print_formats(const char *);
57 1.1 jmcneill static bool video_print_inputs(const char *);
58 1.1 jmcneill static bool video_print_audios(const char *);
59 1.1 jmcneill static bool video_print_standards(const char *);
60 1.1 jmcneill static bool video_print_tuners(const char *);
61 1.1 jmcneill static bool video_print_ctrl(uint32_t);
62 1.1 jmcneill static void video_set(const char *);
63 1.1 jmcneill static bool video_set_ctrl(uint32_t, int32_t);
64 1.1 jmcneill static const char * video_cid2name(uint32_t);
65 1.1 jmcneill static uint32_t video_name2cid(const char *);
66 1.1 jmcneill
67 1.1 jmcneill static const char *video_dev = NULL;
68 1.1 jmcneill static int video_fd = -1;
69 1.1 jmcneill static bool aflag = false;
70 1.1 jmcneill static bool wflag = false;
71 1.1 jmcneill
72 1.1 jmcneill static const struct {
73 1.1 jmcneill uint32_t id;
74 1.1 jmcneill const char *name;
75 1.1 jmcneill } videoctl_cid_names[] = {
76 1.1 jmcneill { V4L2_CID_BRIGHTNESS, "brightness" },
77 1.1 jmcneill { V4L2_CID_CONTRAST, "contrast" },
78 1.1 jmcneill { V4L2_CID_SATURATION, "saturation" },
79 1.1 jmcneill { V4L2_CID_HUE, "hue" },
80 1.1 jmcneill { V4L2_CID_AUDIO_VOLUME, "audio_volume" },
81 1.1 jmcneill { V4L2_CID_AUDIO_BALANCE, "audio_balance" },
82 1.1 jmcneill { V4L2_CID_AUDIO_BASS, "audio_bass" },
83 1.1 jmcneill { V4L2_CID_AUDIO_TREBLE, "audio_treble" },
84 1.1 jmcneill { V4L2_CID_AUDIO_MUTE, "audio_mute" },
85 1.1 jmcneill { V4L2_CID_AUDIO_LOUDNESS, "audio_loudness" },
86 1.1 jmcneill { V4L2_CID_BLACK_LEVEL, "black_level" },
87 1.1 jmcneill { V4L2_CID_AUTO_WHITE_BALANCE, "auto_white_balance" },
88 1.1 jmcneill { V4L2_CID_DO_WHITE_BALANCE, "do_white_balance" },
89 1.1 jmcneill { V4L2_CID_RED_BALANCE, "red_balance" },
90 1.1 jmcneill { V4L2_CID_BLUE_BALANCE, "blue_balance" },
91 1.1 jmcneill { V4L2_CID_GAMMA, "gamma" },
92 1.1 jmcneill { V4L2_CID_WHITENESS, "whiteness" },
93 1.1 jmcneill { V4L2_CID_EXPOSURE, "exposure" },
94 1.1 jmcneill { V4L2_CID_AUTOGAIN, "autogain" },
95 1.1 jmcneill { V4L2_CID_GAIN, "gain" },
96 1.1 jmcneill { V4L2_CID_HFLIP, "hflip" },
97 1.1 jmcneill { V4L2_CID_VFLIP, "vflip" },
98 1.1 jmcneill { V4L2_CID_HCENTER, "hcenter" },
99 1.1 jmcneill { V4L2_CID_VCENTER, "vcenter" },
100 1.1 jmcneill { V4L2_CID_POWER_LINE_FREQUENCY, "power_line_frequency" },
101 1.1 jmcneill { V4L2_CID_HUE_AUTO, "hue_auto" },
102 1.1 jmcneill { V4L2_CID_WHITE_BALANCE_TEMPERATURE, "white_balance_temperature" },
103 1.1 jmcneill { V4L2_CID_SHARPNESS, "sharpness" },
104 1.1 jmcneill { V4L2_CID_BACKLIGHT_COMPENSATION, "backlight_compensation" },
105 1.1 jmcneill };
106 1.1 jmcneill
107 1.1 jmcneill int
108 1.1 jmcneill main(int argc, char *argv[])
109 1.1 jmcneill {
110 1.1 jmcneill int ch;
111 1.1 jmcneill
112 1.1 jmcneill setprogname(argv[0]);
113 1.1 jmcneill
114 1.1 jmcneill while ((ch = getopt(argc, argv, "ad:w")) != -1) {
115 1.1 jmcneill switch (ch) {
116 1.1 jmcneill case 'a':
117 1.1 jmcneill aflag = true;
118 1.1 jmcneill break;
119 1.1 jmcneill case 'd':
120 1.1 jmcneill video_dev = strdup(optarg);
121 1.1 jmcneill break;
122 1.1 jmcneill case 'w':
123 1.1 jmcneill wflag = true;
124 1.1 jmcneill break;
125 1.1 jmcneill default:
126 1.1 jmcneill usage();
127 1.1 jmcneill /* NOTREACHED */
128 1.1 jmcneill }
129 1.1 jmcneill }
130 1.1 jmcneill argc -= optind;
131 1.1 jmcneill argv += optind;
132 1.1 jmcneill
133 1.1 jmcneill if (wflag && aflag)
134 1.1 jmcneill usage();
135 1.1 jmcneill /* NOTREACHED */
136 1.1 jmcneill if (wflag && argc == 0)
137 1.1 jmcneill usage();
138 1.1 jmcneill /* NOTREACHED */
139 1.1 jmcneill if (aflag && argc > 0)
140 1.1 jmcneill usage();
141 1.1 jmcneill /* NOTREACHED */
142 1.1 jmcneill if (!wflag && !aflag && argc == 0)
143 1.1 jmcneill usage();
144 1.1 jmcneill /* NOTREACHED */
145 1.1 jmcneill
146 1.1 jmcneill if (video_dev == NULL)
147 1.1 jmcneill video_dev = _PATH_VIDEO0;
148 1.1 jmcneill
149 1.1 jmcneill video_fd = open(video_dev, wflag ? O_RDWR : O_RDONLY);
150 1.1 jmcneill if (video_fd == -1)
151 1.1 jmcneill err(EXIT_FAILURE, "couldn't open '%s'", video_dev);
152 1.1 jmcneill
153 1.1 jmcneill if (aflag) {
154 1.1 jmcneill video_print_all();
155 1.1 jmcneill } else if (wflag) {
156 1.1 jmcneill while (argc > 0) {
157 1.1 jmcneill video_set(argv[0]);
158 1.1 jmcneill --argc;
159 1.1 jmcneill ++argv;
160 1.1 jmcneill }
161 1.1 jmcneill } else {
162 1.1 jmcneill while (argc > 0) {
163 1.1 jmcneill video_print(argv[0]);
164 1.1 jmcneill --argc;
165 1.1 jmcneill ++argv;
166 1.1 jmcneill }
167 1.1 jmcneill }
168 1.1 jmcneill
169 1.1 jmcneill close(video_fd);
170 1.1 jmcneill
171 1.1 jmcneill return EXIT_SUCCESS;
172 1.1 jmcneill }
173 1.1 jmcneill
174 1.1 jmcneill static void
175 1.1 jmcneill usage(void)
176 1.1 jmcneill {
177 1.1 jmcneill fprintf(stderr, "usage: %s [-d file] name ...\n", getprogname());
178 1.1 jmcneill fprintf(stderr, "usage: %s [-d file] -w name=value ...\n",
179 1.1 jmcneill getprogname());
180 1.1 jmcneill fprintf(stderr, "usage: %s [-d file] -a\n", getprogname());
181 1.1 jmcneill exit(EXIT_FAILURE);
182 1.1 jmcneill }
183 1.1 jmcneill
184 1.1 jmcneill static void
185 1.1 jmcneill video_print_all(void)
186 1.1 jmcneill {
187 1.1 jmcneill video_print_caps(NULL);
188 1.1 jmcneill video_print_formats(NULL);
189 1.1 jmcneill video_print_inputs(NULL);
190 1.1 jmcneill video_print_audios(NULL);
191 1.1 jmcneill video_print_standards(NULL);
192 1.1 jmcneill video_print_tuners(NULL);
193 1.1 jmcneill video_print_ctrl(0);
194 1.1 jmcneill }
195 1.1 jmcneill
196 1.1 jmcneill static bool
197 1.1 jmcneill video_print_caps(const char *name)
198 1.1 jmcneill {
199 1.1 jmcneill struct v4l2_capability cap;
200 1.1 jmcneill char capbuf[128];
201 1.1 jmcneill int error;
202 1.1 jmcneill bool found = false;
203 1.1 jmcneill
204 1.1 jmcneill if (strtok(NULL, ".") != NULL)
205 1.1 jmcneill return false;
206 1.1 jmcneill
207 1.1 jmcneill /* query capabilities */
208 1.1 jmcneill error = ioctl(video_fd, VIDIOC_QUERYCAP, &cap);
209 1.1 jmcneill if (error == -1)
210 1.1 jmcneill err(EXIT_FAILURE, "VIDIOC_QUERYCAP failed");
211 1.1 jmcneill
212 1.1 jmcneill if (!name || strcmp(name, "card") == 0) {
213 1.1 jmcneill printf("info.cap.card=%s\n", cap.card);
214 1.1 jmcneill found = true;
215 1.1 jmcneill }
216 1.1 jmcneill if (!name || strcmp(name, "driver") == 0) {
217 1.1 jmcneill printf("info.cap.driver=%s\n", cap.driver);
218 1.1 jmcneill found = true;
219 1.1 jmcneill }
220 1.1 jmcneill if (!name || strcmp(name, "bus_info") == 0) {
221 1.1 jmcneill printf("info.cap.bus_info=%s\n", cap.bus_info);
222 1.1 jmcneill found = true;
223 1.1 jmcneill }
224 1.1 jmcneill if (!name || strcmp(name, "version") == 0) {
225 1.1 jmcneill printf("info.cap.version=%u.%u.%u\n",
226 1.1 jmcneill (cap.version >> 16) & 0xff,
227 1.1 jmcneill (cap.version >> 8) & 0xff,
228 1.1 jmcneill cap.version & 0xff);
229 1.1 jmcneill found = true;
230 1.1 jmcneill }
231 1.1 jmcneill if (!name || strcmp(name, "capabilities") == 0) {
232 1.1 jmcneill snprintb(capbuf, sizeof(capbuf), V4L2_CAP_BITMASK,
233 1.1 jmcneill cap.capabilities);
234 1.1 jmcneill printf("info.cap.capabilities=%s\n", capbuf);
235 1.1 jmcneill found = true;
236 1.1 jmcneill }
237 1.1 jmcneill
238 1.1 jmcneill return found;
239 1.1 jmcneill }
240 1.1 jmcneill
241 1.1 jmcneill static bool
242 1.4 mlelstv video_print_one_format(unsigned long fmtnum, unsigned long sizenum)
243 1.1 jmcneill {
244 1.1 jmcneill struct v4l2_fmtdesc fmtdesc;
245 1.4 mlelstv struct v4l2_frmsizeenum framesize;
246 1.4 mlelstv unsigned long n;
247 1.1 jmcneill int error;
248 1.1 jmcneill
249 1.1 jmcneill fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
250 1.4 mlelstv fmtdesc.index = fmtnum;
251 1.4 mlelstv error = ioctl(video_fd, VIDIOC_ENUM_FMT, &fmtdesc);
252 1.4 mlelstv if (error)
253 1.4 mlelstv return false;
254 1.4 mlelstv
255 1.4 mlelstv printf("info.format.%u=%s\n", fmtdesc.index,
256 1.4 mlelstv fmtdesc.description);
257 1.4 mlelstv
258 1.4 mlelstv if (sizenum == ULONG_MAX)
259 1.4 mlelstv n = 0;
260 1.4 mlelstv else
261 1.4 mlelstv n = sizenum;
262 1.4 mlelstv
263 1.4 mlelstv while (n <= sizenum) {
264 1.4 mlelstv framesize.index = n++;
265 1.4 mlelstv framesize.pixel_format = fmtdesc.pixelformat;
266 1.4 mlelstv error = ioctl(video_fd, VIDIOC_ENUM_FRAMESIZES, &framesize);
267 1.4 mlelstv if (error)
268 1.4 mlelstv break;
269 1.4 mlelstv
270 1.4 mlelstv switch (framesize.type) {
271 1.4 mlelstv case V4L2_FRMIVAL_TYPE_DISCRETE:
272 1.4 mlelstv case V4L2_FRMIVAL_TYPE_CONTINUOUS:
273 1.4 mlelstv printf("info.format.%u.size.%u=%ux%u\n",
274 1.4 mlelstv fmtdesc.index, framesize.index,
275 1.4 mlelstv framesize.discrete.width,
276 1.4 mlelstv framesize.discrete.height);
277 1.4 mlelstv break;
278 1.4 mlelstv case V4L2_FRMIVAL_TYPE_STEPWISE:
279 1.4 mlelstv printf("info.format.%u.size.%u=(%u,%u,%u)x(%u,%u,%u)\n",
280 1.4 mlelstv fmtdesc.index, framesize.index,
281 1.4 mlelstv framesize.stepwise.min_width,
282 1.4 mlelstv framesize.stepwise.max_width,
283 1.4 mlelstv framesize.stepwise.step_width,
284 1.4 mlelstv framesize.stepwise.min_height,
285 1.4 mlelstv framesize.stepwise.max_height,
286 1.4 mlelstv framesize.stepwise.step_height);
287 1.4 mlelstv break;
288 1.4 mlelstv default:
289 1.4 mlelstv printf("info.format.%u.size.%u=type %u\n",
290 1.4 mlelstv fmtdesc.index, framesize.index,
291 1.4 mlelstv framesize.type);
292 1.4 mlelstv }
293 1.4 mlelstv }
294 1.4 mlelstv
295 1.4 mlelstv return true;
296 1.4 mlelstv }
297 1.4 mlelstv
298 1.4 mlelstv static bool
299 1.4 mlelstv video_print_formats(const char *name)
300 1.4 mlelstv {
301 1.4 mlelstv unsigned long n, m = ULONG_MAX;
302 1.4 mlelstv const char *p;
303 1.4 mlelstv
304 1.1 jmcneill if (name == NULL) {
305 1.1 jmcneill /* enumerate formats */
306 1.4 mlelstv for (n = 0; ; n++) {
307 1.4 mlelstv if (!video_print_one_format(n, m))
308 1.1 jmcneill break;
309 1.1 jmcneill }
310 1.1 jmcneill } else {
311 1.4 mlelstv p = strtok(NULL, ".");
312 1.1 jmcneill n = strtoul(name, NULL, 10);
313 1.1 jmcneill if (n == ULONG_MAX)
314 1.1 jmcneill return false;
315 1.4 mlelstv
316 1.4 mlelstv if (p != NULL) {
317 1.4 mlelstv if (strcmp(p, "size") == 0) {
318 1.4 mlelstv p = strtok(NULL, ".");
319 1.4 mlelstv if (p != NULL) {
320 1.4 mlelstv m = strtoul(p, NULL, 10);
321 1.4 mlelstv if (m == ULONG_MAX)
322 1.4 mlelstv return false;
323 1.4 mlelstv }
324 1.4 mlelstv } else
325 1.4 mlelstv return false;
326 1.4 mlelstv }
327 1.4 mlelstv
328 1.4 mlelstv
329 1.4 mlelstv video_print_one_format(n, m);
330 1.1 jmcneill }
331 1.1 jmcneill
332 1.1 jmcneill return true;
333 1.1 jmcneill }
334 1.1 jmcneill
335 1.1 jmcneill static bool
336 1.1 jmcneill video_print_inputs(const char *name)
337 1.1 jmcneill {
338 1.1 jmcneill struct v4l2_input input;
339 1.1 jmcneill int error;
340 1.1 jmcneill
341 1.1 jmcneill if (name == NULL) {
342 1.1 jmcneill /* enumerate inputs */
343 1.1 jmcneill for (input.index = 0; ; input.index++) {
344 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMINPUT, &input);
345 1.1 jmcneill if (error)
346 1.1 jmcneill break;
347 1.1 jmcneill printf("info.input.%u=%s\n", input.index, input.name);
348 1.1 jmcneill printf("info.input.%u.type=", input.index);
349 1.1 jmcneill switch (input.type) {
350 1.1 jmcneill case V4L2_INPUT_TYPE_TUNER:
351 1.1 jmcneill printf("tuner\n");
352 1.1 jmcneill break;
353 1.1 jmcneill case V4L2_INPUT_TYPE_CAMERA:
354 1.1 jmcneill printf("baseband\n");
355 1.1 jmcneill break;
356 1.1 jmcneill default:
357 1.1 jmcneill printf("unknown (%d)\n", input.type);
358 1.1 jmcneill break;
359 1.1 jmcneill }
360 1.1 jmcneill }
361 1.1 jmcneill } else {
362 1.1 jmcneill unsigned long n;
363 1.1 jmcneill char *s;
364 1.1 jmcneill
365 1.1 jmcneill n = strtoul(name, NULL, 10);
366 1.1 jmcneill if (n == ULONG_MAX)
367 1.1 jmcneill return false;
368 1.1 jmcneill input.index = n;
369 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMINPUT, &input);
370 1.1 jmcneill if (error)
371 1.1 jmcneill return false;
372 1.1 jmcneill
373 1.1 jmcneill s = strtok(NULL, ".");
374 1.1 jmcneill if (s == NULL) {
375 1.1 jmcneill printf("info.input.%u=%s\n", input.index, input.name);
376 1.1 jmcneill } else if (strcmp(s, "type") == 0) {
377 1.1 jmcneill if (strtok(NULL, ".") != NULL)
378 1.1 jmcneill return false;
379 1.1 jmcneill printf("info.input.%u.type=", input.index);
380 1.1 jmcneill switch (input.type) {
381 1.1 jmcneill case V4L2_INPUT_TYPE_TUNER:
382 1.1 jmcneill printf("tuner\n");
383 1.1 jmcneill break;
384 1.1 jmcneill case V4L2_INPUT_TYPE_CAMERA:
385 1.1 jmcneill printf("baseband\n");
386 1.1 jmcneill break;
387 1.1 jmcneill default:
388 1.1 jmcneill printf("unknown (%d)\n", input.type);
389 1.1 jmcneill break;
390 1.1 jmcneill }
391 1.1 jmcneill } else
392 1.1 jmcneill return false;
393 1.1 jmcneill }
394 1.1 jmcneill
395 1.1 jmcneill return true;
396 1.1 jmcneill }
397 1.1 jmcneill
398 1.1 jmcneill static bool
399 1.1 jmcneill video_print_audios(const char *name)
400 1.1 jmcneill {
401 1.1 jmcneill struct v4l2_audio audio;
402 1.1 jmcneill int error;
403 1.1 jmcneill
404 1.1 jmcneill if (name == NULL) {
405 1.1 jmcneill /* enumerate audio */
406 1.1 jmcneill for (audio.index = 0; ; audio.index++) {
407 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMAUDIO, &audio);
408 1.1 jmcneill if (error)
409 1.1 jmcneill break;
410 1.1 jmcneill printf("info.audio.%u=%s\n", audio.index, audio.name);
411 1.1 jmcneill printf("info.audio.%u.stereo=%d\n", audio.index,
412 1.1 jmcneill audio.capability & V4L2_AUDCAP_STEREO ? 1 : 0);
413 1.1 jmcneill printf("info.audio.%u.avl=%d\n", audio.index,
414 1.1 jmcneill audio.capability & V4L2_AUDCAP_AVL ? 1 : 0);
415 1.1 jmcneill }
416 1.1 jmcneill } else {
417 1.1 jmcneill unsigned long n;
418 1.1 jmcneill char *s;
419 1.1 jmcneill
420 1.1 jmcneill n = strtoul(name, NULL, 10);
421 1.1 jmcneill if (n == ULONG_MAX)
422 1.1 jmcneill return false;
423 1.1 jmcneill audio.index = n;
424 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMAUDIO, &audio);
425 1.1 jmcneill if (error)
426 1.1 jmcneill return false;
427 1.1 jmcneill
428 1.1 jmcneill s = strtok(NULL, ".");
429 1.1 jmcneill if (s == NULL) {
430 1.1 jmcneill printf("info.audio.%u=%s\n", audio.index, audio.name);
431 1.1 jmcneill } else if (strcmp(s, "stereo") == 0) {
432 1.1 jmcneill if (strtok(NULL, ".") != NULL)
433 1.1 jmcneill return false;
434 1.1 jmcneill printf("info.audio.%u.stereo=%d\n", audio.index,
435 1.1 jmcneill audio.capability & V4L2_AUDCAP_STEREO ? 1 : 0);
436 1.1 jmcneill } else if (strcmp(s, "avl") == 0) {
437 1.1 jmcneill if (strtok(NULL, ".") != NULL)
438 1.1 jmcneill return false;
439 1.1 jmcneill printf("info.audio.%u.avl=%d\n", audio.index,
440 1.1 jmcneill audio.capability & V4L2_AUDCAP_AVL ? 1 : 0);
441 1.1 jmcneill } else
442 1.1 jmcneill return false;
443 1.1 jmcneill }
444 1.1 jmcneill
445 1.1 jmcneill return true;
446 1.1 jmcneill }
447 1.1 jmcneill
448 1.1 jmcneill static bool
449 1.1 jmcneill video_print_standards(const char *name)
450 1.1 jmcneill {
451 1.1 jmcneill struct v4l2_standard std;
452 1.1 jmcneill int error;
453 1.1 jmcneill
454 1.1 jmcneill if (name == NULL) {
455 1.1 jmcneill /* enumerate standards */
456 1.1 jmcneill for (std.index = 0; ; std.index++) {
457 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMSTD, &std);
458 1.1 jmcneill if (error)
459 1.1 jmcneill break;
460 1.1 jmcneill printf("info.standard.%u=%s\n", std.index, std.name);
461 1.1 jmcneill }
462 1.1 jmcneill } else {
463 1.1 jmcneill unsigned long n;
464 1.1 jmcneill
465 1.1 jmcneill if (strtok(NULL, ".") != NULL)
466 1.1 jmcneill return false;
467 1.1 jmcneill
468 1.1 jmcneill n = strtoul(name, NULL, 10);
469 1.1 jmcneill if (n == ULONG_MAX)
470 1.1 jmcneill return false;
471 1.1 jmcneill std.index = n;
472 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMSTD, &std);
473 1.1 jmcneill if (error)
474 1.1 jmcneill return false;
475 1.1 jmcneill printf("info.standard.%u=%s\n", std.index, std.name);
476 1.1 jmcneill }
477 1.1 jmcneill
478 1.1 jmcneill return true;
479 1.1 jmcneill }
480 1.1 jmcneill
481 1.1 jmcneill static bool
482 1.1 jmcneill video_print_tuners(const char *name)
483 1.1 jmcneill {
484 1.1 jmcneill struct v4l2_tuner tuner;
485 1.1 jmcneill int error;
486 1.1 jmcneill
487 1.1 jmcneill if (name == NULL) {
488 1.1 jmcneill /* enumerate tuners */
489 1.1 jmcneill for (tuner.index = 0; ; tuner.index++) {
490 1.1 jmcneill error = ioctl(video_fd, VIDIOC_G_TUNER, &tuner);
491 1.1 jmcneill if (error)
492 1.1 jmcneill break;
493 1.1 jmcneill printf("info.tuner.%u=%s\n", tuner.index, tuner.name);
494 1.1 jmcneill }
495 1.1 jmcneill } else {
496 1.1 jmcneill unsigned long n;
497 1.1 jmcneill
498 1.1 jmcneill if (strtok(NULL, ".") != NULL)
499 1.1 jmcneill return false;
500 1.1 jmcneill
501 1.1 jmcneill n = strtoul(name, NULL, 10);
502 1.1 jmcneill if (n == ULONG_MAX)
503 1.1 jmcneill return false;
504 1.1 jmcneill tuner.index = n;
505 1.1 jmcneill error = ioctl(video_fd, VIDIOC_G_TUNER, &tuner);
506 1.1 jmcneill if (error)
507 1.1 jmcneill return false;
508 1.1 jmcneill printf("info.tuner.%u=%s\n", tuner.index, tuner.name);
509 1.1 jmcneill }
510 1.1 jmcneill
511 1.1 jmcneill return true;
512 1.1 jmcneill }
513 1.1 jmcneill
514 1.1 jmcneill static void
515 1.1 jmcneill video_print(const char *name)
516 1.1 jmcneill {
517 1.1 jmcneill char *buf, *s, *s2 = NULL;
518 1.1 jmcneill bool found = false;
519 1.1 jmcneill
520 1.1 jmcneill buf = strdup(name);
521 1.1 jmcneill s = strtok(buf, ".");
522 1.1 jmcneill if (s == NULL)
523 1.1 jmcneill return;
524 1.1 jmcneill
525 1.1 jmcneill if (strcmp(s, "info") == 0) {
526 1.1 jmcneill s = strtok(NULL, ".");
527 1.1 jmcneill if (s)
528 1.1 jmcneill s2 = strtok(NULL, ".");
529 1.1 jmcneill if (s == NULL || strcmp(s, "cap") == 0) {
530 1.1 jmcneill found = video_print_caps(s2);
531 1.1 jmcneill }
532 1.1 jmcneill if (s == NULL || strcmp(s, "format") == 0) {
533 1.1 jmcneill found = video_print_formats(s2);
534 1.1 jmcneill }
535 1.1 jmcneill if (s == NULL || strcmp(s, "input") == 0) {
536 1.1 jmcneill found = video_print_inputs(s2);
537 1.1 jmcneill }
538 1.1 jmcneill if (s == NULL || strcmp(s, "audio") == 0) {
539 1.1 jmcneill found = video_print_audios(s2);
540 1.1 jmcneill }
541 1.1 jmcneill if (s == NULL || strcmp(s, "standard") == 0) {
542 1.1 jmcneill found = video_print_standards(s2);
543 1.1 jmcneill }
544 1.1 jmcneill if (s == NULL || strcmp(s, "tuner") == 0) {
545 1.1 jmcneill found = video_print_tuners(s2);
546 1.1 jmcneill }
547 1.1 jmcneill } else if (strcmp(s, "ctrl") == 0) {
548 1.1 jmcneill s = strtok(NULL, ".");
549 1.1 jmcneill if (s)
550 1.1 jmcneill s2 = strtok(NULL, ".");
551 1.1 jmcneill
552 1.1 jmcneill if (s == NULL)
553 1.1 jmcneill found = video_print_ctrl(0);
554 1.1 jmcneill else if (s && !s2)
555 1.1 jmcneill found = video_print_ctrl(video_name2cid(s));
556 1.1 jmcneill }
557 1.1 jmcneill
558 1.1 jmcneill free(buf);
559 1.1 jmcneill if (!found)
560 1.1 jmcneill fprintf(stderr, "%s: field %s does not exist\n",
561 1.1 jmcneill getprogname(), name);
562 1.1 jmcneill }
563 1.1 jmcneill
564 1.1 jmcneill static bool
565 1.1 jmcneill video_print_ctrl(uint32_t ctrl_id)
566 1.1 jmcneill {
567 1.1 jmcneill struct v4l2_control ctrl;
568 1.1 jmcneill const char *ctrlname;
569 1.1 jmcneill bool found = false;
570 1.1 jmcneill int error;
571 1.1 jmcneill
572 1.1 jmcneill for (ctrl.id = V4L2_CID_BASE; ctrl.id != V4L2_CID_LASTP1; ctrl.id++) {
573 1.1 jmcneill if (ctrl_id != 0 && ctrl_id != ctrl.id)
574 1.1 jmcneill continue;
575 1.1 jmcneill error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
576 1.1 jmcneill if (error)
577 1.1 jmcneill continue;
578 1.1 jmcneill ctrlname = video_cid2name(ctrl.id);
579 1.1 jmcneill if (ctrlname)
580 1.1 jmcneill printf("ctrl.%s=%d\n", ctrlname, ctrl.value);
581 1.1 jmcneill else
582 1.1 jmcneill printf("ctrl.%08x=%d\n", ctrl.id, ctrl.value);
583 1.1 jmcneill found = true;
584 1.1 jmcneill }
585 1.1 jmcneill
586 1.1 jmcneill return found;
587 1.1 jmcneill }
588 1.1 jmcneill
589 1.1 jmcneill static void
590 1.1 jmcneill video_set(const char *name)
591 1.1 jmcneill {
592 1.1 jmcneill char *buf, *key, *value;
593 1.1 jmcneill bool found = false;
594 1.1 jmcneill long n;
595 1.1 jmcneill
596 1.1 jmcneill if (strchr(name, '=') == NULL) {
597 1.1 jmcneill fprintf(stderr, "%s: No '=' in %s\n", getprogname(), name);
598 1.1 jmcneill exit(EXIT_FAILURE);
599 1.1 jmcneill }
600 1.1 jmcneill
601 1.1 jmcneill buf = strdup(name);
602 1.1 jmcneill key = strtok(buf, "=");
603 1.1 jmcneill if (key == NULL)
604 1.1 jmcneill usage();
605 1.1 jmcneill /* NOTREACHED */
606 1.1 jmcneill value = strtok(NULL, "");
607 1.1 jmcneill if (value == NULL)
608 1.1 jmcneill usage();
609 1.1 jmcneill /* NOTREACHED */
610 1.1 jmcneill
611 1.1 jmcneill if (strncmp(key, "info.", strlen("info.")) == 0) {
612 1.1 jmcneill fprintf(stderr, "'info' subtree read-only\n");
613 1.1 jmcneill found = true;
614 1.1 jmcneill goto done;
615 1.1 jmcneill }
616 1.1 jmcneill if (strncmp(key, "ctrl.", strlen("ctrl.")) == 0) {
617 1.1 jmcneill char *ctrlname = key + strlen("ctrl.");
618 1.1 jmcneill uint32_t ctrl_id = video_name2cid(ctrlname);
619 1.1 jmcneill
620 1.1 jmcneill n = strtol(value, NULL, 0);
621 1.1 jmcneill if (n == LONG_MIN || n == LONG_MAX)
622 1.1 jmcneill goto done;
623 1.1 jmcneill found = video_set_ctrl(ctrl_id, n);
624 1.1 jmcneill }
625 1.1 jmcneill
626 1.1 jmcneill done:
627 1.1 jmcneill free(buf);
628 1.1 jmcneill if (!found)
629 1.1 jmcneill fprintf(stderr, "%s: field %s does not exist\n",
630 1.1 jmcneill getprogname(), name);
631 1.1 jmcneill }
632 1.1 jmcneill
633 1.1 jmcneill static bool
634 1.1 jmcneill video_set_ctrl(uint32_t ctrl_id, int32_t value)
635 1.1 jmcneill {
636 1.1 jmcneill struct v4l2_control ctrl;
637 1.1 jmcneill const char *ctrlname;
638 1.1 jmcneill int32_t ovalue;
639 1.1 jmcneill int error;
640 1.1 jmcneill
641 1.1 jmcneill ctrlname = video_cid2name(ctrl_id);
642 1.1 jmcneill
643 1.1 jmcneill ctrl.id = ctrl_id;
644 1.1 jmcneill error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
645 1.1 jmcneill if (error)
646 1.1 jmcneill return false;
647 1.1 jmcneill ovalue = ctrl.value;
648 1.1 jmcneill ctrl.value = value;
649 1.1 jmcneill error = ioctl(video_fd, VIDIOC_S_CTRL, &ctrl);
650 1.1 jmcneill if (error)
651 1.1 jmcneill err(EXIT_FAILURE, "VIDIOC_S_CTRL failed for '%s'", ctrlname);
652 1.1 jmcneill error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
653 1.1 jmcneill if (error)
654 1.1 jmcneill err(EXIT_FAILURE, "VIDIOC_G_CTRL failed for '%s'", ctrlname);
655 1.1 jmcneill
656 1.1 jmcneill if (ctrlname)
657 1.1 jmcneill printf("ctrl.%s: %d -> %d\n", ctrlname, ovalue, ctrl.value);
658 1.1 jmcneill else
659 1.1 jmcneill printf("ctrl.%08x: %d -> %d\n", ctrl.id, ovalue, ctrl.value);
660 1.1 jmcneill
661 1.1 jmcneill return true;
662 1.1 jmcneill }
663 1.1 jmcneill
664 1.1 jmcneill static const char *
665 1.1 jmcneill video_cid2name(uint32_t id)
666 1.1 jmcneill {
667 1.1 jmcneill unsigned int i;
668 1.1 jmcneill
669 1.1 jmcneill for (i = 0; i < __arraycount(videoctl_cid_names); i++)
670 1.1 jmcneill if (videoctl_cid_names[i].id == id)
671 1.1 jmcneill return videoctl_cid_names[i].name;
672 1.1 jmcneill
673 1.1 jmcneill return NULL;
674 1.1 jmcneill }
675 1.1 jmcneill
676 1.1 jmcneill static uint32_t
677 1.1 jmcneill video_name2cid(const char *name)
678 1.1 jmcneill {
679 1.1 jmcneill unsigned int i;
680 1.1 jmcneill
681 1.1 jmcneill for (i = 0; i < __arraycount(videoctl_cid_names); i++)
682 1.1 jmcneill if (strcmp(name, videoctl_cid_names[i].name) == 0)
683 1.1 jmcneill return videoctl_cid_names[i].id;
684 1.1 jmcneill
685 1.1 jmcneill return (uint32_t)-1;
686 1.1 jmcneill }
687