1*ded935eaSrillig /* $NetBSD: videoctl.c,v 1.3 2021/02/19 11:39:11 rillig Exp $ */
2190912dcSjmcneill
3190912dcSjmcneill /*-
4190912dcSjmcneill * Copyright (c) 2010 Jared D. McNeill <jmcneill@invisible.ca>
5190912dcSjmcneill * All rights reserved.
6190912dcSjmcneill *
7190912dcSjmcneill * Redistribution and use in source and binary forms, with or without
8190912dcSjmcneill * modification, are permitted provided that the following conditions
9190912dcSjmcneill * are met:
10190912dcSjmcneill * 1. Redistributions of source code must retain the above copyright
11190912dcSjmcneill * notice, this list of conditions and the following disclaimer.
12190912dcSjmcneill * 2. Redistributions in binary form must reproduce the above copyright
13190912dcSjmcneill * notice, this list of conditions and the following disclaimer in the
14190912dcSjmcneill * documentation and/or other materials provided with the distribution.
15190912dcSjmcneill *
16190912dcSjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17190912dcSjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18190912dcSjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19190912dcSjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20190912dcSjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21190912dcSjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22190912dcSjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23190912dcSjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24190912dcSjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25190912dcSjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26190912dcSjmcneill * POSSIBILITY OF SUCH DAMAGE.
27190912dcSjmcneill */
28190912dcSjmcneill
29190912dcSjmcneill #include <sys/cdefs.h>
30190912dcSjmcneill __COPYRIGHT("@(#) Copyright (c) 2010\
31190912dcSjmcneill Jared D. McNeill <jmcneill@invisible.ca>. All rights reserved.");
32*ded935eaSrillig __RCSID("$NetBSD: videoctl.c,v 1.3 2021/02/19 11:39:11 rillig Exp $");
33190912dcSjmcneill
34190912dcSjmcneill #include <sys/types.h>
35190912dcSjmcneill #include <sys/ioctl.h>
36190912dcSjmcneill #include <sys/videoio.h>
37190912dcSjmcneill
38190912dcSjmcneill #include <err.h>
39190912dcSjmcneill #include <errno.h>
40190912dcSjmcneill #include <fcntl.h>
41190912dcSjmcneill #include <limits.h>
42190912dcSjmcneill #include <paths.h>
43190912dcSjmcneill #include <stdio.h>
44190912dcSjmcneill #include <string.h>
45190912dcSjmcneill #include <stdbool.h>
46190912dcSjmcneill #include <stdlib.h>
47190912dcSjmcneill #include <unistd.h>
48190912dcSjmcneill #include <util.h>
49190912dcSjmcneill
506818646aSjoerg __dead static void usage(void);
51190912dcSjmcneill static void video_print(const char *);
52190912dcSjmcneill static void video_print_all(void);
53190912dcSjmcneill static bool video_print_caps(const char *);
54190912dcSjmcneill static bool video_print_formats(const char *);
55190912dcSjmcneill static bool video_print_inputs(const char *);
56190912dcSjmcneill static bool video_print_audios(const char *);
57190912dcSjmcneill static bool video_print_standards(const char *);
58190912dcSjmcneill static bool video_print_tuners(const char *);
59190912dcSjmcneill static bool video_print_ctrl(uint32_t);
60190912dcSjmcneill static void video_set(const char *);
61190912dcSjmcneill static bool video_set_ctrl(uint32_t, int32_t);
62190912dcSjmcneill static const char * video_cid2name(uint32_t);
63190912dcSjmcneill static uint32_t video_name2cid(const char *);
64190912dcSjmcneill
65190912dcSjmcneill static const char *video_dev = NULL;
66190912dcSjmcneill static int video_fd = -1;
67190912dcSjmcneill static bool aflag = false;
68190912dcSjmcneill static bool wflag = false;
69190912dcSjmcneill
70190912dcSjmcneill static const struct {
71190912dcSjmcneill uint32_t id;
72190912dcSjmcneill const char *name;
73190912dcSjmcneill } videoctl_cid_names[] = {
74190912dcSjmcneill { V4L2_CID_BRIGHTNESS, "brightness" },
75190912dcSjmcneill { V4L2_CID_CONTRAST, "contrast" },
76190912dcSjmcneill { V4L2_CID_SATURATION, "saturation" },
77190912dcSjmcneill { V4L2_CID_HUE, "hue" },
78190912dcSjmcneill { V4L2_CID_AUDIO_VOLUME, "audio_volume" },
79190912dcSjmcneill { V4L2_CID_AUDIO_BALANCE, "audio_balance" },
80190912dcSjmcneill { V4L2_CID_AUDIO_BASS, "audio_bass" },
81190912dcSjmcneill { V4L2_CID_AUDIO_TREBLE, "audio_treble" },
82190912dcSjmcneill { V4L2_CID_AUDIO_MUTE, "audio_mute" },
83190912dcSjmcneill { V4L2_CID_AUDIO_LOUDNESS, "audio_loudness" },
84190912dcSjmcneill { V4L2_CID_BLACK_LEVEL, "black_level" },
85190912dcSjmcneill { V4L2_CID_AUTO_WHITE_BALANCE, "auto_white_balance" },
86190912dcSjmcneill { V4L2_CID_DO_WHITE_BALANCE, "do_white_balance" },
87190912dcSjmcneill { V4L2_CID_RED_BALANCE, "red_balance" },
88190912dcSjmcneill { V4L2_CID_BLUE_BALANCE, "blue_balance" },
89190912dcSjmcneill { V4L2_CID_GAMMA, "gamma" },
90190912dcSjmcneill { V4L2_CID_WHITENESS, "whiteness" },
91190912dcSjmcneill { V4L2_CID_EXPOSURE, "exposure" },
92190912dcSjmcneill { V4L2_CID_AUTOGAIN, "autogain" },
93190912dcSjmcneill { V4L2_CID_GAIN, "gain" },
94190912dcSjmcneill { V4L2_CID_HFLIP, "hflip" },
95190912dcSjmcneill { V4L2_CID_VFLIP, "vflip" },
96190912dcSjmcneill { V4L2_CID_HCENTER, "hcenter" },
97190912dcSjmcneill { V4L2_CID_VCENTER, "vcenter" },
98190912dcSjmcneill { V4L2_CID_POWER_LINE_FREQUENCY, "power_line_frequency" },
99190912dcSjmcneill { V4L2_CID_HUE_AUTO, "hue_auto" },
100190912dcSjmcneill { V4L2_CID_WHITE_BALANCE_TEMPERATURE, "white_balance_temperature" },
101190912dcSjmcneill { V4L2_CID_SHARPNESS, "sharpness" },
102190912dcSjmcneill { V4L2_CID_BACKLIGHT_COMPENSATION, "backlight_compensation" },
103190912dcSjmcneill };
104190912dcSjmcneill
105190912dcSjmcneill int
main(int argc,char * argv[])106190912dcSjmcneill main(int argc, char *argv[])
107190912dcSjmcneill {
108190912dcSjmcneill int ch;
109190912dcSjmcneill
110190912dcSjmcneill setprogname(argv[0]);
111190912dcSjmcneill
112190912dcSjmcneill while ((ch = getopt(argc, argv, "ad:w")) != -1) {
113190912dcSjmcneill switch (ch) {
114190912dcSjmcneill case 'a':
115190912dcSjmcneill aflag = true;
116190912dcSjmcneill break;
117190912dcSjmcneill case 'd':
118190912dcSjmcneill video_dev = strdup(optarg);
119190912dcSjmcneill break;
120190912dcSjmcneill case 'w':
121190912dcSjmcneill wflag = true;
122190912dcSjmcneill break;
123190912dcSjmcneill default:
124190912dcSjmcneill usage();
125190912dcSjmcneill /* NOTREACHED */
126190912dcSjmcneill }
127190912dcSjmcneill }
128190912dcSjmcneill argc -= optind;
129190912dcSjmcneill argv += optind;
130190912dcSjmcneill
131190912dcSjmcneill if (wflag && aflag)
132190912dcSjmcneill usage();
133190912dcSjmcneill /* NOTREACHED */
134190912dcSjmcneill if (wflag && argc == 0)
135190912dcSjmcneill usage();
136190912dcSjmcneill /* NOTREACHED */
137190912dcSjmcneill if (aflag && argc > 0)
138190912dcSjmcneill usage();
139190912dcSjmcneill /* NOTREACHED */
140190912dcSjmcneill if (!wflag && !aflag && argc == 0)
141190912dcSjmcneill usage();
142190912dcSjmcneill /* NOTREACHED */
143190912dcSjmcneill
144190912dcSjmcneill if (video_dev == NULL)
145190912dcSjmcneill video_dev = _PATH_VIDEO0;
146190912dcSjmcneill
147190912dcSjmcneill video_fd = open(video_dev, wflag ? O_RDWR : O_RDONLY);
148190912dcSjmcneill if (video_fd == -1)
149190912dcSjmcneill err(EXIT_FAILURE, "couldn't open '%s'", video_dev);
150190912dcSjmcneill
151190912dcSjmcneill if (aflag) {
152190912dcSjmcneill video_print_all();
153190912dcSjmcneill } else if (wflag) {
154190912dcSjmcneill while (argc > 0) {
155190912dcSjmcneill video_set(argv[0]);
156190912dcSjmcneill --argc;
157190912dcSjmcneill ++argv;
158190912dcSjmcneill }
159190912dcSjmcneill } else {
160190912dcSjmcneill while (argc > 0) {
161190912dcSjmcneill video_print(argv[0]);
162190912dcSjmcneill --argc;
163190912dcSjmcneill ++argv;
164190912dcSjmcneill }
165190912dcSjmcneill }
166190912dcSjmcneill
167190912dcSjmcneill close(video_fd);
168190912dcSjmcneill
169190912dcSjmcneill return EXIT_SUCCESS;
170190912dcSjmcneill }
171190912dcSjmcneill
172190912dcSjmcneill static void
usage(void)173190912dcSjmcneill usage(void)
174190912dcSjmcneill {
175190912dcSjmcneill fprintf(stderr, "usage: %s [-d file] name ...\n", getprogname());
176190912dcSjmcneill fprintf(stderr, "usage: %s [-d file] -w name=value ...\n",
177190912dcSjmcneill getprogname());
178190912dcSjmcneill fprintf(stderr, "usage: %s [-d file] -a\n", getprogname());
179190912dcSjmcneill exit(EXIT_FAILURE);
180190912dcSjmcneill }
181190912dcSjmcneill
182190912dcSjmcneill static void
video_print_all(void)183190912dcSjmcneill video_print_all(void)
184190912dcSjmcneill {
185190912dcSjmcneill video_print_caps(NULL);
186190912dcSjmcneill video_print_formats(NULL);
187190912dcSjmcneill video_print_inputs(NULL);
188190912dcSjmcneill video_print_audios(NULL);
189190912dcSjmcneill video_print_standards(NULL);
190190912dcSjmcneill video_print_tuners(NULL);
191190912dcSjmcneill video_print_ctrl(0);
192190912dcSjmcneill }
193190912dcSjmcneill
194190912dcSjmcneill static bool
video_print_caps(const char * name)195190912dcSjmcneill video_print_caps(const char *name)
196190912dcSjmcneill {
197190912dcSjmcneill struct v4l2_capability cap;
198190912dcSjmcneill char capbuf[128];
199190912dcSjmcneill int error;
200190912dcSjmcneill bool found = false;
201190912dcSjmcneill
202190912dcSjmcneill if (strtok(NULL, ".") != NULL)
203190912dcSjmcneill return false;
204190912dcSjmcneill
205190912dcSjmcneill /* query capabilities */
206190912dcSjmcneill error = ioctl(video_fd, VIDIOC_QUERYCAP, &cap);
207190912dcSjmcneill if (error == -1)
208190912dcSjmcneill err(EXIT_FAILURE, "VIDIOC_QUERYCAP failed");
209190912dcSjmcneill
210190912dcSjmcneill if (!name || strcmp(name, "card") == 0) {
211190912dcSjmcneill printf("info.cap.card=%s\n", cap.card);
212190912dcSjmcneill found = true;
213190912dcSjmcneill }
214190912dcSjmcneill if (!name || strcmp(name, "driver") == 0) {
215190912dcSjmcneill printf("info.cap.driver=%s\n", cap.driver);
216190912dcSjmcneill found = true;
217190912dcSjmcneill }
218190912dcSjmcneill if (!name || strcmp(name, "bus_info") == 0) {
219190912dcSjmcneill printf("info.cap.bus_info=%s\n", cap.bus_info);
220190912dcSjmcneill found = true;
221190912dcSjmcneill }
222190912dcSjmcneill if (!name || strcmp(name, "version") == 0) {
223190912dcSjmcneill printf("info.cap.version=%u.%u.%u\n",
224190912dcSjmcneill (cap.version >> 16) & 0xff,
225190912dcSjmcneill (cap.version >> 8) & 0xff,
226190912dcSjmcneill cap.version & 0xff);
227190912dcSjmcneill found = true;
228190912dcSjmcneill }
229190912dcSjmcneill if (!name || strcmp(name, "capabilities") == 0) {
230190912dcSjmcneill snprintb(capbuf, sizeof(capbuf), V4L2_CAP_BITMASK,
231190912dcSjmcneill cap.capabilities);
232190912dcSjmcneill printf("info.cap.capabilities=%s\n", capbuf);
233190912dcSjmcneill found = true;
234190912dcSjmcneill }
235190912dcSjmcneill
236190912dcSjmcneill return found;
237190912dcSjmcneill }
238190912dcSjmcneill
239190912dcSjmcneill static bool
video_print_formats(const char * name)240190912dcSjmcneill video_print_formats(const char *name)
241190912dcSjmcneill {
242190912dcSjmcneill struct v4l2_fmtdesc fmtdesc;
243190912dcSjmcneill int error;
244190912dcSjmcneill
245190912dcSjmcneill fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
246190912dcSjmcneill if (name == NULL) {
247190912dcSjmcneill /* enumerate formats */
248190912dcSjmcneill for (fmtdesc.index = 0; ; fmtdesc.index++) {
249190912dcSjmcneill error = ioctl(video_fd, VIDIOC_ENUM_FMT, &fmtdesc);
250190912dcSjmcneill if (error)
251190912dcSjmcneill break;
252190912dcSjmcneill printf("info.format.%u=%s\n", fmtdesc.index,
253190912dcSjmcneill fmtdesc.description);
254190912dcSjmcneill }
255190912dcSjmcneill } else {
256190912dcSjmcneill unsigned long n;
257190912dcSjmcneill
258190912dcSjmcneill if (strtok(NULL, ".") != NULL)
259190912dcSjmcneill return false;
260190912dcSjmcneill
261190912dcSjmcneill n = strtoul(name, NULL, 10);
262190912dcSjmcneill if (n == ULONG_MAX)
263190912dcSjmcneill return false;
264190912dcSjmcneill fmtdesc.index = n;
265190912dcSjmcneill error = ioctl(video_fd, VIDIOC_ENUM_FMT, &fmtdesc);
266190912dcSjmcneill if (error)
267190912dcSjmcneill return false;
268190912dcSjmcneill printf("info.format.%u=%s\n", fmtdesc.index,
269190912dcSjmcneill fmtdesc.description);
270190912dcSjmcneill }
271190912dcSjmcneill
272190912dcSjmcneill return true;
273190912dcSjmcneill }
274190912dcSjmcneill
275190912dcSjmcneill static bool
video_print_inputs(const char * name)276190912dcSjmcneill video_print_inputs(const char *name)
277190912dcSjmcneill {
278190912dcSjmcneill struct v4l2_input input;
279190912dcSjmcneill int error;
280190912dcSjmcneill
281190912dcSjmcneill if (name == NULL) {
282190912dcSjmcneill /* enumerate inputs */
283190912dcSjmcneill for (input.index = 0; ; input.index++) {
284190912dcSjmcneill error = ioctl(video_fd, VIDIOC_ENUMINPUT, &input);
285190912dcSjmcneill if (error)
286190912dcSjmcneill break;
287190912dcSjmcneill printf("info.input.%u=%s\n", input.index, input.name);
288190912dcSjmcneill printf("info.input.%u.type=", input.index);
289190912dcSjmcneill switch (input.type) {
290190912dcSjmcneill case V4L2_INPUT_TYPE_TUNER:
291190912dcSjmcneill printf("tuner\n");
292190912dcSjmcneill break;
293190912dcSjmcneill case V4L2_INPUT_TYPE_CAMERA:
294190912dcSjmcneill printf("baseband\n");
295190912dcSjmcneill break;
296190912dcSjmcneill default:
297190912dcSjmcneill printf("unknown (%d)\n", input.type);
298190912dcSjmcneill break;
299190912dcSjmcneill }
300190912dcSjmcneill }
301190912dcSjmcneill } else {
302190912dcSjmcneill unsigned long n;
303190912dcSjmcneill char *s;
304190912dcSjmcneill
305190912dcSjmcneill n = strtoul(name, NULL, 10);
306190912dcSjmcneill if (n == ULONG_MAX)
307190912dcSjmcneill return false;
308190912dcSjmcneill input.index = n;
309190912dcSjmcneill error = ioctl(video_fd, VIDIOC_ENUMINPUT, &input);
310190912dcSjmcneill if (error)
311190912dcSjmcneill return false;
312190912dcSjmcneill
313190912dcSjmcneill s = strtok(NULL, ".");
314190912dcSjmcneill if (s == NULL) {
315190912dcSjmcneill printf("info.input.%u=%s\n", input.index, input.name);
316190912dcSjmcneill } else if (strcmp(s, "type") == 0) {
317190912dcSjmcneill if (strtok(NULL, ".") != NULL)
318190912dcSjmcneill return false;
319190912dcSjmcneill printf("info.input.%u.type=", input.index);
320190912dcSjmcneill switch (input.type) {
321190912dcSjmcneill case V4L2_INPUT_TYPE_TUNER:
322190912dcSjmcneill printf("tuner\n");
323190912dcSjmcneill break;
324190912dcSjmcneill case V4L2_INPUT_TYPE_CAMERA:
325190912dcSjmcneill printf("baseband\n");
326190912dcSjmcneill break;
327190912dcSjmcneill default:
328190912dcSjmcneill printf("unknown (%d)\n", input.type);
329190912dcSjmcneill break;
330190912dcSjmcneill }
331190912dcSjmcneill } else
332190912dcSjmcneill return false;
333190912dcSjmcneill }
334190912dcSjmcneill
335190912dcSjmcneill return true;
336190912dcSjmcneill }
337190912dcSjmcneill
338190912dcSjmcneill static bool
video_print_audios(const char * name)339190912dcSjmcneill video_print_audios(const char *name)
340190912dcSjmcneill {
341190912dcSjmcneill struct v4l2_audio audio;
342190912dcSjmcneill int error;
343190912dcSjmcneill
344190912dcSjmcneill if (name == NULL) {
345190912dcSjmcneill /* enumerate audio */
346190912dcSjmcneill for (audio.index = 0; ; audio.index++) {
347190912dcSjmcneill error = ioctl(video_fd, VIDIOC_ENUMAUDIO, &audio);
348190912dcSjmcneill if (error)
349190912dcSjmcneill break;
350190912dcSjmcneill printf("info.audio.%u=%s\n", audio.index, audio.name);
351190912dcSjmcneill printf("info.audio.%u.stereo=%d\n", audio.index,
352190912dcSjmcneill audio.capability & V4L2_AUDCAP_STEREO ? 1 : 0);
353190912dcSjmcneill printf("info.audio.%u.avl=%d\n", audio.index,
354190912dcSjmcneill audio.capability & V4L2_AUDCAP_AVL ? 1 : 0);
355190912dcSjmcneill }
356190912dcSjmcneill } else {
357190912dcSjmcneill unsigned long n;
358190912dcSjmcneill char *s;
359190912dcSjmcneill
360190912dcSjmcneill n = strtoul(name, NULL, 10);
361190912dcSjmcneill if (n == ULONG_MAX)
362190912dcSjmcneill return false;
363190912dcSjmcneill audio.index = n;
364190912dcSjmcneill error = ioctl(video_fd, VIDIOC_ENUMAUDIO, &audio);
365190912dcSjmcneill if (error)
366190912dcSjmcneill return false;
367190912dcSjmcneill
368190912dcSjmcneill s = strtok(NULL, ".");
369190912dcSjmcneill if (s == NULL) {
370190912dcSjmcneill printf("info.audio.%u=%s\n", audio.index, audio.name);
371190912dcSjmcneill } else if (strcmp(s, "stereo") == 0) {
372190912dcSjmcneill if (strtok(NULL, ".") != NULL)
373190912dcSjmcneill return false;
374190912dcSjmcneill printf("info.audio.%u.stereo=%d\n", audio.index,
375190912dcSjmcneill audio.capability & V4L2_AUDCAP_STEREO ? 1 : 0);
376190912dcSjmcneill } else if (strcmp(s, "avl") == 0) {
377190912dcSjmcneill if (strtok(NULL, ".") != NULL)
378190912dcSjmcneill return false;
379190912dcSjmcneill printf("info.audio.%u.avl=%d\n", audio.index,
380190912dcSjmcneill audio.capability & V4L2_AUDCAP_AVL ? 1 : 0);
381190912dcSjmcneill } else
382190912dcSjmcneill return false;
383190912dcSjmcneill }
384190912dcSjmcneill
385190912dcSjmcneill return true;
386190912dcSjmcneill }
387190912dcSjmcneill
388190912dcSjmcneill static bool
video_print_standards(const char * name)389190912dcSjmcneill video_print_standards(const char *name)
390190912dcSjmcneill {
391190912dcSjmcneill struct v4l2_standard std;
392190912dcSjmcneill int error;
393190912dcSjmcneill
394190912dcSjmcneill if (name == NULL) {
395190912dcSjmcneill /* enumerate standards */
396190912dcSjmcneill for (std.index = 0; ; std.index++) {
397190912dcSjmcneill error = ioctl(video_fd, VIDIOC_ENUMSTD, &std);
398190912dcSjmcneill if (error)
399190912dcSjmcneill break;
400190912dcSjmcneill printf("info.standard.%u=%s\n", std.index, std.name);
401190912dcSjmcneill }
402190912dcSjmcneill } else {
403190912dcSjmcneill unsigned long n;
404190912dcSjmcneill
405190912dcSjmcneill if (strtok(NULL, ".") != NULL)
406190912dcSjmcneill return false;
407190912dcSjmcneill
408190912dcSjmcneill n = strtoul(name, NULL, 10);
409190912dcSjmcneill if (n == ULONG_MAX)
410190912dcSjmcneill return false;
411190912dcSjmcneill std.index = n;
412190912dcSjmcneill error = ioctl(video_fd, VIDIOC_ENUMSTD, &std);
413190912dcSjmcneill if (error)
414190912dcSjmcneill return false;
415190912dcSjmcneill printf("info.standard.%u=%s\n", std.index, std.name);
416190912dcSjmcneill }
417190912dcSjmcneill
418190912dcSjmcneill return true;
419190912dcSjmcneill }
420190912dcSjmcneill
421190912dcSjmcneill static bool
video_print_tuners(const char * name)422190912dcSjmcneill video_print_tuners(const char *name)
423190912dcSjmcneill {
424190912dcSjmcneill struct v4l2_tuner tuner;
425190912dcSjmcneill int error;
426190912dcSjmcneill
427190912dcSjmcneill if (name == NULL) {
428190912dcSjmcneill /* enumerate tuners */
429190912dcSjmcneill for (tuner.index = 0; ; tuner.index++) {
430190912dcSjmcneill error = ioctl(video_fd, VIDIOC_G_TUNER, &tuner);
431190912dcSjmcneill if (error)
432190912dcSjmcneill break;
433190912dcSjmcneill printf("info.tuner.%u=%s\n", tuner.index, tuner.name);
434190912dcSjmcneill }
435190912dcSjmcneill } else {
436190912dcSjmcneill unsigned long n;
437190912dcSjmcneill
438190912dcSjmcneill if (strtok(NULL, ".") != NULL)
439190912dcSjmcneill return false;
440190912dcSjmcneill
441190912dcSjmcneill n = strtoul(name, NULL, 10);
442190912dcSjmcneill if (n == ULONG_MAX)
443190912dcSjmcneill return false;
444190912dcSjmcneill tuner.index = n;
445190912dcSjmcneill error = ioctl(video_fd, VIDIOC_G_TUNER, &tuner);
446190912dcSjmcneill if (error)
447190912dcSjmcneill return false;
448190912dcSjmcneill printf("info.tuner.%u=%s\n", tuner.index, tuner.name);
449190912dcSjmcneill }
450190912dcSjmcneill
451190912dcSjmcneill return true;
452190912dcSjmcneill }
453190912dcSjmcneill
454190912dcSjmcneill static void
video_print(const char * name)455190912dcSjmcneill video_print(const char *name)
456190912dcSjmcneill {
457190912dcSjmcneill char *buf, *s, *s2 = NULL;
458190912dcSjmcneill bool found = false;
459190912dcSjmcneill
460190912dcSjmcneill buf = strdup(name);
461190912dcSjmcneill s = strtok(buf, ".");
462190912dcSjmcneill if (s == NULL)
463190912dcSjmcneill return;
464190912dcSjmcneill
465190912dcSjmcneill if (strcmp(s, "info") == 0) {
466190912dcSjmcneill s = strtok(NULL, ".");
467190912dcSjmcneill if (s)
468190912dcSjmcneill s2 = strtok(NULL, ".");
469190912dcSjmcneill if (s == NULL || strcmp(s, "cap") == 0) {
470190912dcSjmcneill found = video_print_caps(s2);
471190912dcSjmcneill }
472190912dcSjmcneill if (s == NULL || strcmp(s, "format") == 0) {
473190912dcSjmcneill found = video_print_formats(s2);
474190912dcSjmcneill }
475190912dcSjmcneill if (s == NULL || strcmp(s, "input") == 0) {
476190912dcSjmcneill found = video_print_inputs(s2);
477190912dcSjmcneill }
478190912dcSjmcneill if (s == NULL || strcmp(s, "audio") == 0) {
479190912dcSjmcneill found = video_print_audios(s2);
480190912dcSjmcneill }
481190912dcSjmcneill if (s == NULL || strcmp(s, "standard") == 0) {
482190912dcSjmcneill found = video_print_standards(s2);
483190912dcSjmcneill }
484190912dcSjmcneill if (s == NULL || strcmp(s, "tuner") == 0) {
485190912dcSjmcneill found = video_print_tuners(s2);
486190912dcSjmcneill }
487190912dcSjmcneill } else if (strcmp(s, "ctrl") == 0) {
488190912dcSjmcneill s = strtok(NULL, ".");
489190912dcSjmcneill if (s)
490190912dcSjmcneill s2 = strtok(NULL, ".");
491190912dcSjmcneill
492190912dcSjmcneill if (s == NULL)
493190912dcSjmcneill found = video_print_ctrl(0);
494190912dcSjmcneill else if (s && !s2)
495190912dcSjmcneill found = video_print_ctrl(video_name2cid(s));
496190912dcSjmcneill }
497190912dcSjmcneill
498190912dcSjmcneill free(buf);
499190912dcSjmcneill if (!found)
500190912dcSjmcneill fprintf(stderr, "%s: field %s does not exist\n",
501190912dcSjmcneill getprogname(), name);
502190912dcSjmcneill }
503190912dcSjmcneill
504190912dcSjmcneill static bool
video_print_ctrl(uint32_t ctrl_id)505190912dcSjmcneill video_print_ctrl(uint32_t ctrl_id)
506190912dcSjmcneill {
507190912dcSjmcneill struct v4l2_control ctrl;
508190912dcSjmcneill const char *ctrlname;
509190912dcSjmcneill bool found = false;
510190912dcSjmcneill int error;
511190912dcSjmcneill
512190912dcSjmcneill for (ctrl.id = V4L2_CID_BASE; ctrl.id != V4L2_CID_LASTP1; ctrl.id++) {
513190912dcSjmcneill if (ctrl_id != 0 && ctrl_id != ctrl.id)
514190912dcSjmcneill continue;
515190912dcSjmcneill error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
516190912dcSjmcneill if (error)
517190912dcSjmcneill continue;
518190912dcSjmcneill ctrlname = video_cid2name(ctrl.id);
519190912dcSjmcneill if (ctrlname)
520190912dcSjmcneill printf("ctrl.%s=%d\n", ctrlname, ctrl.value);
521190912dcSjmcneill else
522190912dcSjmcneill printf("ctrl.%08x=%d\n", ctrl.id, ctrl.value);
523190912dcSjmcneill found = true;
524190912dcSjmcneill }
525190912dcSjmcneill
526190912dcSjmcneill return found;
527190912dcSjmcneill }
528190912dcSjmcneill
529190912dcSjmcneill static void
video_set(const char * name)530190912dcSjmcneill video_set(const char *name)
531190912dcSjmcneill {
532190912dcSjmcneill char *buf, *key, *value;
533190912dcSjmcneill bool found = false;
534190912dcSjmcneill long n;
535190912dcSjmcneill
536190912dcSjmcneill if (strchr(name, '=') == NULL) {
537190912dcSjmcneill fprintf(stderr, "%s: No '=' in %s\n", getprogname(), name);
538190912dcSjmcneill exit(EXIT_FAILURE);
539190912dcSjmcneill }
540190912dcSjmcneill
541190912dcSjmcneill buf = strdup(name);
542190912dcSjmcneill key = strtok(buf, "=");
543190912dcSjmcneill if (key == NULL)
544190912dcSjmcneill usage();
545190912dcSjmcneill /* NOTREACHED */
546190912dcSjmcneill value = strtok(NULL, "");
547190912dcSjmcneill if (value == NULL)
548190912dcSjmcneill usage();
549190912dcSjmcneill /* NOTREACHED */
550190912dcSjmcneill
551190912dcSjmcneill if (strncmp(key, "info.", strlen("info.")) == 0) {
552190912dcSjmcneill fprintf(stderr, "'info' subtree read-only\n");
553190912dcSjmcneill found = true;
554190912dcSjmcneill goto done;
555190912dcSjmcneill }
556190912dcSjmcneill if (strncmp(key, "ctrl.", strlen("ctrl.")) == 0) {
557190912dcSjmcneill char *ctrlname = key + strlen("ctrl.");
558190912dcSjmcneill uint32_t ctrl_id = video_name2cid(ctrlname);
559190912dcSjmcneill
560190912dcSjmcneill n = strtol(value, NULL, 0);
561190912dcSjmcneill if (n == LONG_MIN || n == LONG_MAX)
562190912dcSjmcneill goto done;
563190912dcSjmcneill found = video_set_ctrl(ctrl_id, n);
564190912dcSjmcneill }
565190912dcSjmcneill
566190912dcSjmcneill done:
567190912dcSjmcneill free(buf);
568190912dcSjmcneill if (!found)
569190912dcSjmcneill fprintf(stderr, "%s: field %s does not exist\n",
570190912dcSjmcneill getprogname(), name);
571190912dcSjmcneill }
572190912dcSjmcneill
573190912dcSjmcneill static bool
video_set_ctrl(uint32_t ctrl_id,int32_t value)574190912dcSjmcneill video_set_ctrl(uint32_t ctrl_id, int32_t value)
575190912dcSjmcneill {
576190912dcSjmcneill struct v4l2_control ctrl;
577190912dcSjmcneill const char *ctrlname;
578190912dcSjmcneill int32_t ovalue;
579190912dcSjmcneill int error;
580190912dcSjmcneill
581190912dcSjmcneill ctrlname = video_cid2name(ctrl_id);
582190912dcSjmcneill
583190912dcSjmcneill ctrl.id = ctrl_id;
584190912dcSjmcneill error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
585190912dcSjmcneill if (error)
586190912dcSjmcneill return false;
587190912dcSjmcneill ovalue = ctrl.value;
588190912dcSjmcneill ctrl.value = value;
589190912dcSjmcneill error = ioctl(video_fd, VIDIOC_S_CTRL, &ctrl);
590190912dcSjmcneill if (error)
591190912dcSjmcneill err(EXIT_FAILURE, "VIDIOC_S_CTRL failed for '%s'", ctrlname);
592190912dcSjmcneill error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
593190912dcSjmcneill if (error)
594190912dcSjmcneill err(EXIT_FAILURE, "VIDIOC_G_CTRL failed for '%s'", ctrlname);
595190912dcSjmcneill
596190912dcSjmcneill if (ctrlname)
597190912dcSjmcneill printf("ctrl.%s: %d -> %d\n", ctrlname, ovalue, ctrl.value);
598190912dcSjmcneill else
599190912dcSjmcneill printf("ctrl.%08x: %d -> %d\n", ctrl.id, ovalue, ctrl.value);
600190912dcSjmcneill
601190912dcSjmcneill return true;
602190912dcSjmcneill }
603190912dcSjmcneill
604190912dcSjmcneill static const char *
video_cid2name(uint32_t id)605190912dcSjmcneill video_cid2name(uint32_t id)
606190912dcSjmcneill {
607190912dcSjmcneill unsigned int i;
608190912dcSjmcneill
609190912dcSjmcneill for (i = 0; i < __arraycount(videoctl_cid_names); i++)
610190912dcSjmcneill if (videoctl_cid_names[i].id == id)
611190912dcSjmcneill return videoctl_cid_names[i].name;
612190912dcSjmcneill
613190912dcSjmcneill return NULL;
614190912dcSjmcneill }
615190912dcSjmcneill
616190912dcSjmcneill static uint32_t
video_name2cid(const char * name)617190912dcSjmcneill video_name2cid(const char *name)
618190912dcSjmcneill {
619190912dcSjmcneill unsigned int i;
620190912dcSjmcneill
621190912dcSjmcneill for (i = 0; i < __arraycount(videoctl_cid_names); i++)
622190912dcSjmcneill if (strcmp(name, videoctl_cid_names[i].name) == 0)
623190912dcSjmcneill return videoctl_cid_names[i].id;
624190912dcSjmcneill
625190912dcSjmcneill return (uint32_t)-1;
626190912dcSjmcneill }
627