videoctl.c revision 1.2 1 1.2 joerg /* $NetBSD: videoctl.c,v 1.2 2011/09/16 15:39:30 joerg 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.2 joerg __RCSID("$NetBSD: videoctl.c,v 1.2 2011/09/16 15:39:30 joerg Exp $");
33 1.1 jmcneill
34 1.1 jmcneill #include <sys/types.h>
35 1.1 jmcneill #include <sys/ioctl.h>
36 1.1 jmcneill #include <sys/videoio.h>
37 1.1 jmcneill
38 1.1 jmcneill #include <err.h>
39 1.1 jmcneill #include <errno.h>
40 1.1 jmcneill #include <fcntl.h>
41 1.1 jmcneill #include <limits.h>
42 1.1 jmcneill #include <paths.h>
43 1.1 jmcneill #include <stdio.h>
44 1.1 jmcneill #include <string.h>
45 1.1 jmcneill #include <stdbool.h>
46 1.1 jmcneill #include <stdlib.h>
47 1.1 jmcneill #include <unistd.h>
48 1.1 jmcneill #include <util.h>
49 1.1 jmcneill
50 1.2 joerg __dead static void usage(void);
51 1.1 jmcneill static void video_print(const char *);
52 1.1 jmcneill static void video_print_all(void);
53 1.1 jmcneill static bool video_print_caps(const char *);
54 1.1 jmcneill static bool video_print_formats(const char *);
55 1.1 jmcneill static bool video_print_inputs(const char *);
56 1.1 jmcneill static bool video_print_audios(const char *);
57 1.1 jmcneill static bool video_print_standards(const char *);
58 1.1 jmcneill static bool video_print_tuners(const char *);
59 1.1 jmcneill static bool video_print_ctrl(uint32_t);
60 1.1 jmcneill static void video_set(const char *);
61 1.1 jmcneill static bool video_set_ctrl(uint32_t, int32_t);
62 1.1 jmcneill static const char * video_cid2name(uint32_t);
63 1.1 jmcneill static uint32_t video_name2cid(const char *);
64 1.1 jmcneill
65 1.1 jmcneill static const char *video_dev = NULL;
66 1.1 jmcneill static int video_fd = -1;
67 1.1 jmcneill static bool aflag = false;
68 1.1 jmcneill static bool wflag = false;
69 1.1 jmcneill
70 1.1 jmcneill static const struct {
71 1.1 jmcneill uint32_t id;
72 1.1 jmcneill const char *name;
73 1.1 jmcneill } videoctl_cid_names[] = {
74 1.1 jmcneill { V4L2_CID_BRIGHTNESS, "brightness" },
75 1.1 jmcneill { V4L2_CID_CONTRAST, "contrast" },
76 1.1 jmcneill { V4L2_CID_SATURATION, "saturation" },
77 1.1 jmcneill { V4L2_CID_HUE, "hue" },
78 1.1 jmcneill { V4L2_CID_AUDIO_VOLUME, "audio_volume" },
79 1.1 jmcneill { V4L2_CID_AUDIO_BALANCE, "audio_balance" },
80 1.1 jmcneill { V4L2_CID_AUDIO_BASS, "audio_bass" },
81 1.1 jmcneill { V4L2_CID_AUDIO_TREBLE, "audio_treble" },
82 1.1 jmcneill { V4L2_CID_AUDIO_MUTE, "audio_mute" },
83 1.1 jmcneill { V4L2_CID_AUDIO_LOUDNESS, "audio_loudness" },
84 1.1 jmcneill { V4L2_CID_BLACK_LEVEL, "black_level" },
85 1.1 jmcneill { V4L2_CID_AUTO_WHITE_BALANCE, "auto_white_balance" },
86 1.1 jmcneill { V4L2_CID_DO_WHITE_BALANCE, "do_white_balance" },
87 1.1 jmcneill { V4L2_CID_RED_BALANCE, "red_balance" },
88 1.1 jmcneill { V4L2_CID_BLUE_BALANCE, "blue_balance" },
89 1.1 jmcneill { V4L2_CID_GAMMA, "gamma" },
90 1.1 jmcneill { V4L2_CID_WHITENESS, "whiteness" },
91 1.1 jmcneill { V4L2_CID_EXPOSURE, "exposure" },
92 1.1 jmcneill { V4L2_CID_AUTOGAIN, "autogain" },
93 1.1 jmcneill { V4L2_CID_GAIN, "gain" },
94 1.1 jmcneill { V4L2_CID_HFLIP, "hflip" },
95 1.1 jmcneill { V4L2_CID_VFLIP, "vflip" },
96 1.1 jmcneill { V4L2_CID_HCENTER, "hcenter" },
97 1.1 jmcneill { V4L2_CID_VCENTER, "vcenter" },
98 1.1 jmcneill { V4L2_CID_POWER_LINE_FREQUENCY, "power_line_frequency" },
99 1.1 jmcneill { V4L2_CID_HUE_AUTO, "hue_auto" },
100 1.1 jmcneill { V4L2_CID_WHITE_BALANCE_TEMPERATURE, "white_balance_temperature" },
101 1.1 jmcneill { V4L2_CID_SHARPNESS, "sharpness" },
102 1.1 jmcneill { V4L2_CID_BACKLIGHT_COMPENSATION, "backlight_compensation" },
103 1.1 jmcneill };
104 1.1 jmcneill
105 1.1 jmcneill int
106 1.1 jmcneill main(int argc, char *argv[])
107 1.1 jmcneill {
108 1.1 jmcneill int ch;
109 1.1 jmcneill
110 1.1 jmcneill setprogname(argv[0]);
111 1.1 jmcneill
112 1.1 jmcneill while ((ch = getopt(argc, argv, "ad:w")) != -1) {
113 1.1 jmcneill switch (ch) {
114 1.1 jmcneill case 'a':
115 1.1 jmcneill aflag = true;
116 1.1 jmcneill break;
117 1.1 jmcneill case 'd':
118 1.1 jmcneill video_dev = strdup(optarg);
119 1.1 jmcneill break;
120 1.1 jmcneill case 'w':
121 1.1 jmcneill wflag = true;
122 1.1 jmcneill break;
123 1.1 jmcneill case 'h':
124 1.1 jmcneill default:
125 1.1 jmcneill usage();
126 1.1 jmcneill /* NOTREACHED */
127 1.1 jmcneill }
128 1.1 jmcneill }
129 1.1 jmcneill argc -= optind;
130 1.1 jmcneill argv += optind;
131 1.1 jmcneill
132 1.1 jmcneill if (wflag && aflag)
133 1.1 jmcneill usage();
134 1.1 jmcneill /* NOTREACHED */
135 1.1 jmcneill if (wflag && argc == 0)
136 1.1 jmcneill usage();
137 1.1 jmcneill /* NOTREACHED */
138 1.1 jmcneill if (aflag && argc > 0)
139 1.1 jmcneill usage();
140 1.1 jmcneill /* NOTREACHED */
141 1.1 jmcneill if (!wflag && !aflag && argc == 0)
142 1.1 jmcneill usage();
143 1.1 jmcneill /* NOTREACHED */
144 1.1 jmcneill
145 1.1 jmcneill if (video_dev == NULL)
146 1.1 jmcneill video_dev = _PATH_VIDEO0;
147 1.1 jmcneill
148 1.1 jmcneill video_fd = open(video_dev, wflag ? O_RDWR : O_RDONLY);
149 1.1 jmcneill if (video_fd == -1)
150 1.1 jmcneill err(EXIT_FAILURE, "couldn't open '%s'", video_dev);
151 1.1 jmcneill
152 1.1 jmcneill if (aflag) {
153 1.1 jmcneill video_print_all();
154 1.1 jmcneill } else if (wflag) {
155 1.1 jmcneill while (argc > 0) {
156 1.1 jmcneill video_set(argv[0]);
157 1.1 jmcneill --argc;
158 1.1 jmcneill ++argv;
159 1.1 jmcneill }
160 1.1 jmcneill } else {
161 1.1 jmcneill while (argc > 0) {
162 1.1 jmcneill video_print(argv[0]);
163 1.1 jmcneill --argc;
164 1.1 jmcneill ++argv;
165 1.1 jmcneill }
166 1.1 jmcneill }
167 1.1 jmcneill
168 1.1 jmcneill close(video_fd);
169 1.1 jmcneill
170 1.1 jmcneill return EXIT_SUCCESS;
171 1.1 jmcneill }
172 1.1 jmcneill
173 1.1 jmcneill static void
174 1.1 jmcneill usage(void)
175 1.1 jmcneill {
176 1.1 jmcneill fprintf(stderr, "usage: %s [-d file] name ...\n", getprogname());
177 1.1 jmcneill fprintf(stderr, "usage: %s [-d file] -w name=value ...\n",
178 1.1 jmcneill getprogname());
179 1.1 jmcneill fprintf(stderr, "usage: %s [-d file] -a\n", getprogname());
180 1.1 jmcneill exit(EXIT_FAILURE);
181 1.1 jmcneill }
182 1.1 jmcneill
183 1.1 jmcneill static void
184 1.1 jmcneill video_print_all(void)
185 1.1 jmcneill {
186 1.1 jmcneill video_print_caps(NULL);
187 1.1 jmcneill video_print_formats(NULL);
188 1.1 jmcneill video_print_inputs(NULL);
189 1.1 jmcneill video_print_audios(NULL);
190 1.1 jmcneill video_print_standards(NULL);
191 1.1 jmcneill video_print_tuners(NULL);
192 1.1 jmcneill video_print_ctrl(0);
193 1.1 jmcneill }
194 1.1 jmcneill
195 1.1 jmcneill static bool
196 1.1 jmcneill video_print_caps(const char *name)
197 1.1 jmcneill {
198 1.1 jmcneill struct v4l2_capability cap;
199 1.1 jmcneill char capbuf[128];
200 1.1 jmcneill int error;
201 1.1 jmcneill bool found = false;
202 1.1 jmcneill
203 1.1 jmcneill if (strtok(NULL, ".") != NULL)
204 1.1 jmcneill return false;
205 1.1 jmcneill
206 1.1 jmcneill /* query capabilities */
207 1.1 jmcneill error = ioctl(video_fd, VIDIOC_QUERYCAP, &cap);
208 1.1 jmcneill if (error == -1)
209 1.1 jmcneill err(EXIT_FAILURE, "VIDIOC_QUERYCAP failed");
210 1.1 jmcneill
211 1.1 jmcneill if (!name || strcmp(name, "card") == 0) {
212 1.1 jmcneill printf("info.cap.card=%s\n", cap.card);
213 1.1 jmcneill found = true;
214 1.1 jmcneill }
215 1.1 jmcneill if (!name || strcmp(name, "driver") == 0) {
216 1.1 jmcneill printf("info.cap.driver=%s\n", cap.driver);
217 1.1 jmcneill found = true;
218 1.1 jmcneill }
219 1.1 jmcneill if (!name || strcmp(name, "bus_info") == 0) {
220 1.1 jmcneill printf("info.cap.bus_info=%s\n", cap.bus_info);
221 1.1 jmcneill found = true;
222 1.1 jmcneill }
223 1.1 jmcneill if (!name || strcmp(name, "version") == 0) {
224 1.1 jmcneill printf("info.cap.version=%u.%u.%u\n",
225 1.1 jmcneill (cap.version >> 16) & 0xff,
226 1.1 jmcneill (cap.version >> 8) & 0xff,
227 1.1 jmcneill cap.version & 0xff);
228 1.1 jmcneill found = true;
229 1.1 jmcneill }
230 1.1 jmcneill if (!name || strcmp(name, "capabilities") == 0) {
231 1.1 jmcneill snprintb(capbuf, sizeof(capbuf), V4L2_CAP_BITMASK,
232 1.1 jmcneill cap.capabilities);
233 1.1 jmcneill printf("info.cap.capabilities=%s\n", capbuf);
234 1.1 jmcneill found = true;
235 1.1 jmcneill }
236 1.1 jmcneill
237 1.1 jmcneill return found;
238 1.1 jmcneill }
239 1.1 jmcneill
240 1.1 jmcneill static bool
241 1.1 jmcneill video_print_formats(const char *name)
242 1.1 jmcneill {
243 1.1 jmcneill struct v4l2_fmtdesc fmtdesc;
244 1.1 jmcneill int error;
245 1.1 jmcneill
246 1.1 jmcneill fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
247 1.1 jmcneill if (name == NULL) {
248 1.1 jmcneill /* enumerate formats */
249 1.1 jmcneill for (fmtdesc.index = 0; ; fmtdesc.index++) {
250 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUM_FMT, &fmtdesc);
251 1.1 jmcneill if (error)
252 1.1 jmcneill break;
253 1.1 jmcneill printf("info.format.%u=%s\n", fmtdesc.index,
254 1.1 jmcneill fmtdesc.description);
255 1.1 jmcneill }
256 1.1 jmcneill } else {
257 1.1 jmcneill unsigned long n;
258 1.1 jmcneill
259 1.1 jmcneill if (strtok(NULL, ".") != NULL)
260 1.1 jmcneill return false;
261 1.1 jmcneill
262 1.1 jmcneill n = strtoul(name, NULL, 10);
263 1.1 jmcneill if (n == ULONG_MAX)
264 1.1 jmcneill return false;
265 1.1 jmcneill fmtdesc.index = n;
266 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUM_FMT, &fmtdesc);
267 1.1 jmcneill if (error)
268 1.1 jmcneill return false;
269 1.1 jmcneill printf("info.format.%u=%s\n", fmtdesc.index,
270 1.1 jmcneill fmtdesc.description);
271 1.1 jmcneill }
272 1.1 jmcneill
273 1.1 jmcneill return true;
274 1.1 jmcneill }
275 1.1 jmcneill
276 1.1 jmcneill static bool
277 1.1 jmcneill video_print_inputs(const char *name)
278 1.1 jmcneill {
279 1.1 jmcneill struct v4l2_input input;
280 1.1 jmcneill int error;
281 1.1 jmcneill
282 1.1 jmcneill if (name == NULL) {
283 1.1 jmcneill /* enumerate inputs */
284 1.1 jmcneill for (input.index = 0; ; input.index++) {
285 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMINPUT, &input);
286 1.1 jmcneill if (error)
287 1.1 jmcneill break;
288 1.1 jmcneill printf("info.input.%u=%s\n", input.index, input.name);
289 1.1 jmcneill printf("info.input.%u.type=", input.index);
290 1.1 jmcneill switch (input.type) {
291 1.1 jmcneill case V4L2_INPUT_TYPE_TUNER:
292 1.1 jmcneill printf("tuner\n");
293 1.1 jmcneill break;
294 1.1 jmcneill case V4L2_INPUT_TYPE_CAMERA:
295 1.1 jmcneill printf("baseband\n");
296 1.1 jmcneill break;
297 1.1 jmcneill default:
298 1.1 jmcneill printf("unknown (%d)\n", input.type);
299 1.1 jmcneill break;
300 1.1 jmcneill }
301 1.1 jmcneill }
302 1.1 jmcneill } else {
303 1.1 jmcneill unsigned long n;
304 1.1 jmcneill char *s;
305 1.1 jmcneill
306 1.1 jmcneill n = strtoul(name, NULL, 10);
307 1.1 jmcneill if (n == ULONG_MAX)
308 1.1 jmcneill return false;
309 1.1 jmcneill input.index = n;
310 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMINPUT, &input);
311 1.1 jmcneill if (error)
312 1.1 jmcneill return false;
313 1.1 jmcneill
314 1.1 jmcneill s = strtok(NULL, ".");
315 1.1 jmcneill if (s == NULL) {
316 1.1 jmcneill printf("info.input.%u=%s\n", input.index, input.name);
317 1.1 jmcneill } else if (strcmp(s, "type") == 0) {
318 1.1 jmcneill if (strtok(NULL, ".") != NULL)
319 1.1 jmcneill return false;
320 1.1 jmcneill printf("info.input.%u.type=", input.index);
321 1.1 jmcneill switch (input.type) {
322 1.1 jmcneill case V4L2_INPUT_TYPE_TUNER:
323 1.1 jmcneill printf("tuner\n");
324 1.1 jmcneill break;
325 1.1 jmcneill case V4L2_INPUT_TYPE_CAMERA:
326 1.1 jmcneill printf("baseband\n");
327 1.1 jmcneill break;
328 1.1 jmcneill default:
329 1.1 jmcneill printf("unknown (%d)\n", input.type);
330 1.1 jmcneill break;
331 1.1 jmcneill }
332 1.1 jmcneill } else
333 1.1 jmcneill return false;
334 1.1 jmcneill }
335 1.1 jmcneill
336 1.1 jmcneill return true;
337 1.1 jmcneill }
338 1.1 jmcneill
339 1.1 jmcneill static bool
340 1.1 jmcneill video_print_audios(const char *name)
341 1.1 jmcneill {
342 1.1 jmcneill struct v4l2_audio audio;
343 1.1 jmcneill int error;
344 1.1 jmcneill
345 1.1 jmcneill if (name == NULL) {
346 1.1 jmcneill /* enumerate audio */
347 1.1 jmcneill for (audio.index = 0; ; audio.index++) {
348 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMAUDIO, &audio);
349 1.1 jmcneill if (error)
350 1.1 jmcneill break;
351 1.1 jmcneill printf("info.audio.%u=%s\n", audio.index, audio.name);
352 1.1 jmcneill printf("info.audio.%u.stereo=%d\n", audio.index,
353 1.1 jmcneill audio.capability & V4L2_AUDCAP_STEREO ? 1 : 0);
354 1.1 jmcneill printf("info.audio.%u.avl=%d\n", audio.index,
355 1.1 jmcneill audio.capability & V4L2_AUDCAP_AVL ? 1 : 0);
356 1.1 jmcneill }
357 1.1 jmcneill } else {
358 1.1 jmcneill unsigned long n;
359 1.1 jmcneill char *s;
360 1.1 jmcneill
361 1.1 jmcneill n = strtoul(name, NULL, 10);
362 1.1 jmcneill if (n == ULONG_MAX)
363 1.1 jmcneill return false;
364 1.1 jmcneill audio.index = n;
365 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMAUDIO, &audio);
366 1.1 jmcneill if (error)
367 1.1 jmcneill return false;
368 1.1 jmcneill
369 1.1 jmcneill s = strtok(NULL, ".");
370 1.1 jmcneill if (s == NULL) {
371 1.1 jmcneill printf("info.audio.%u=%s\n", audio.index, audio.name);
372 1.1 jmcneill } else if (strcmp(s, "stereo") == 0) {
373 1.1 jmcneill if (strtok(NULL, ".") != NULL)
374 1.1 jmcneill return false;
375 1.1 jmcneill printf("info.audio.%u.stereo=%d\n", audio.index,
376 1.1 jmcneill audio.capability & V4L2_AUDCAP_STEREO ? 1 : 0);
377 1.1 jmcneill } else if (strcmp(s, "avl") == 0) {
378 1.1 jmcneill if (strtok(NULL, ".") != NULL)
379 1.1 jmcneill return false;
380 1.1 jmcneill printf("info.audio.%u.avl=%d\n", audio.index,
381 1.1 jmcneill audio.capability & V4L2_AUDCAP_AVL ? 1 : 0);
382 1.1 jmcneill } else
383 1.1 jmcneill return false;
384 1.1 jmcneill }
385 1.1 jmcneill
386 1.1 jmcneill return true;
387 1.1 jmcneill }
388 1.1 jmcneill
389 1.1 jmcneill static bool
390 1.1 jmcneill video_print_standards(const char *name)
391 1.1 jmcneill {
392 1.1 jmcneill struct v4l2_standard std;
393 1.1 jmcneill int error;
394 1.1 jmcneill
395 1.1 jmcneill if (name == NULL) {
396 1.1 jmcneill /* enumerate standards */
397 1.1 jmcneill for (std.index = 0; ; std.index++) {
398 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMSTD, &std);
399 1.1 jmcneill if (error)
400 1.1 jmcneill break;
401 1.1 jmcneill printf("info.standard.%u=%s\n", std.index, std.name);
402 1.1 jmcneill }
403 1.1 jmcneill } else {
404 1.1 jmcneill unsigned long n;
405 1.1 jmcneill
406 1.1 jmcneill if (strtok(NULL, ".") != NULL)
407 1.1 jmcneill return false;
408 1.1 jmcneill
409 1.1 jmcneill n = strtoul(name, NULL, 10);
410 1.1 jmcneill if (n == ULONG_MAX)
411 1.1 jmcneill return false;
412 1.1 jmcneill std.index = n;
413 1.1 jmcneill error = ioctl(video_fd, VIDIOC_ENUMSTD, &std);
414 1.1 jmcneill if (error)
415 1.1 jmcneill return false;
416 1.1 jmcneill printf("info.standard.%u=%s\n", std.index, std.name);
417 1.1 jmcneill }
418 1.1 jmcneill
419 1.1 jmcneill return true;
420 1.1 jmcneill }
421 1.1 jmcneill
422 1.1 jmcneill static bool
423 1.1 jmcneill video_print_tuners(const char *name)
424 1.1 jmcneill {
425 1.1 jmcneill struct v4l2_tuner tuner;
426 1.1 jmcneill int error;
427 1.1 jmcneill
428 1.1 jmcneill if (name == NULL) {
429 1.1 jmcneill /* enumerate tuners */
430 1.1 jmcneill for (tuner.index = 0; ; tuner.index++) {
431 1.1 jmcneill error = ioctl(video_fd, VIDIOC_G_TUNER, &tuner);
432 1.1 jmcneill if (error)
433 1.1 jmcneill break;
434 1.1 jmcneill printf("info.tuner.%u=%s\n", tuner.index, tuner.name);
435 1.1 jmcneill }
436 1.1 jmcneill } else {
437 1.1 jmcneill unsigned long n;
438 1.1 jmcneill
439 1.1 jmcneill if (strtok(NULL, ".") != NULL)
440 1.1 jmcneill return false;
441 1.1 jmcneill
442 1.1 jmcneill n = strtoul(name, NULL, 10);
443 1.1 jmcneill if (n == ULONG_MAX)
444 1.1 jmcneill return false;
445 1.1 jmcneill tuner.index = n;
446 1.1 jmcneill error = ioctl(video_fd, VIDIOC_G_TUNER, &tuner);
447 1.1 jmcneill if (error)
448 1.1 jmcneill return false;
449 1.1 jmcneill printf("info.tuner.%u=%s\n", tuner.index, tuner.name);
450 1.1 jmcneill }
451 1.1 jmcneill
452 1.1 jmcneill return true;
453 1.1 jmcneill }
454 1.1 jmcneill
455 1.1 jmcneill static void
456 1.1 jmcneill video_print(const char *name)
457 1.1 jmcneill {
458 1.1 jmcneill char *buf, *s, *s2 = NULL;
459 1.1 jmcneill bool found = false;
460 1.1 jmcneill
461 1.1 jmcneill buf = strdup(name);
462 1.1 jmcneill s = strtok(buf, ".");
463 1.1 jmcneill if (s == NULL)
464 1.1 jmcneill return;
465 1.1 jmcneill
466 1.1 jmcneill if (strcmp(s, "info") == 0) {
467 1.1 jmcneill s = strtok(NULL, ".");
468 1.1 jmcneill if (s)
469 1.1 jmcneill s2 = strtok(NULL, ".");
470 1.1 jmcneill if (s == NULL || strcmp(s, "cap") == 0) {
471 1.1 jmcneill found = video_print_caps(s2);
472 1.1 jmcneill }
473 1.1 jmcneill if (s == NULL || strcmp(s, "format") == 0) {
474 1.1 jmcneill found = video_print_formats(s2);
475 1.1 jmcneill }
476 1.1 jmcneill if (s == NULL || strcmp(s, "input") == 0) {
477 1.1 jmcneill found = video_print_inputs(s2);
478 1.1 jmcneill }
479 1.1 jmcneill if (s == NULL || strcmp(s, "audio") == 0) {
480 1.1 jmcneill found = video_print_audios(s2);
481 1.1 jmcneill }
482 1.1 jmcneill if (s == NULL || strcmp(s, "standard") == 0) {
483 1.1 jmcneill found = video_print_standards(s2);
484 1.1 jmcneill }
485 1.1 jmcneill if (s == NULL || strcmp(s, "tuner") == 0) {
486 1.1 jmcneill found = video_print_tuners(s2);
487 1.1 jmcneill }
488 1.1 jmcneill } else if (strcmp(s, "ctrl") == 0) {
489 1.1 jmcneill s = strtok(NULL, ".");
490 1.1 jmcneill if (s)
491 1.1 jmcneill s2 = strtok(NULL, ".");
492 1.1 jmcneill
493 1.1 jmcneill if (s == NULL)
494 1.1 jmcneill found = video_print_ctrl(0);
495 1.1 jmcneill else if (s && !s2)
496 1.1 jmcneill found = video_print_ctrl(video_name2cid(s));
497 1.1 jmcneill }
498 1.1 jmcneill
499 1.1 jmcneill free(buf);
500 1.1 jmcneill if (!found)
501 1.1 jmcneill fprintf(stderr, "%s: field %s does not exist\n",
502 1.1 jmcneill getprogname(), name);
503 1.1 jmcneill }
504 1.1 jmcneill
505 1.1 jmcneill static bool
506 1.1 jmcneill video_print_ctrl(uint32_t ctrl_id)
507 1.1 jmcneill {
508 1.1 jmcneill struct v4l2_control ctrl;
509 1.1 jmcneill const char *ctrlname;
510 1.1 jmcneill bool found = false;
511 1.1 jmcneill int error;
512 1.1 jmcneill
513 1.1 jmcneill for (ctrl.id = V4L2_CID_BASE; ctrl.id != V4L2_CID_LASTP1; ctrl.id++) {
514 1.1 jmcneill if (ctrl_id != 0 && ctrl_id != ctrl.id)
515 1.1 jmcneill continue;
516 1.1 jmcneill error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
517 1.1 jmcneill if (error)
518 1.1 jmcneill continue;
519 1.1 jmcneill ctrlname = video_cid2name(ctrl.id);
520 1.1 jmcneill if (ctrlname)
521 1.1 jmcneill printf("ctrl.%s=%d\n", ctrlname, ctrl.value);
522 1.1 jmcneill else
523 1.1 jmcneill printf("ctrl.%08x=%d\n", ctrl.id, ctrl.value);
524 1.1 jmcneill found = true;
525 1.1 jmcneill }
526 1.1 jmcneill
527 1.1 jmcneill return found;
528 1.1 jmcneill }
529 1.1 jmcneill
530 1.1 jmcneill static void
531 1.1 jmcneill video_set(const char *name)
532 1.1 jmcneill {
533 1.1 jmcneill char *buf, *key, *value;
534 1.1 jmcneill bool found = false;
535 1.1 jmcneill long n;
536 1.1 jmcneill
537 1.1 jmcneill if (strchr(name, '=') == NULL) {
538 1.1 jmcneill fprintf(stderr, "%s: No '=' in %s\n", getprogname(), name);
539 1.1 jmcneill exit(EXIT_FAILURE);
540 1.1 jmcneill }
541 1.1 jmcneill
542 1.1 jmcneill buf = strdup(name);
543 1.1 jmcneill key = strtok(buf, "=");
544 1.1 jmcneill if (key == NULL)
545 1.1 jmcneill usage();
546 1.1 jmcneill /* NOTREACHED */
547 1.1 jmcneill value = strtok(NULL, "");
548 1.1 jmcneill if (value == NULL)
549 1.1 jmcneill usage();
550 1.1 jmcneill /* NOTREACHED */
551 1.1 jmcneill
552 1.1 jmcneill if (strncmp(key, "info.", strlen("info.")) == 0) {
553 1.1 jmcneill fprintf(stderr, "'info' subtree read-only\n");
554 1.1 jmcneill found = true;
555 1.1 jmcneill goto done;
556 1.1 jmcneill }
557 1.1 jmcneill if (strncmp(key, "ctrl.", strlen("ctrl.")) == 0) {
558 1.1 jmcneill char *ctrlname = key + strlen("ctrl.");
559 1.1 jmcneill uint32_t ctrl_id = video_name2cid(ctrlname);
560 1.1 jmcneill
561 1.1 jmcneill n = strtol(value, NULL, 0);
562 1.1 jmcneill if (n == LONG_MIN || n == LONG_MAX)
563 1.1 jmcneill goto done;
564 1.1 jmcneill found = video_set_ctrl(ctrl_id, n);
565 1.1 jmcneill }
566 1.1 jmcneill
567 1.1 jmcneill done:
568 1.1 jmcneill free(buf);
569 1.1 jmcneill if (!found)
570 1.1 jmcneill fprintf(stderr, "%s: field %s does not exist\n",
571 1.1 jmcneill getprogname(), name);
572 1.1 jmcneill }
573 1.1 jmcneill
574 1.1 jmcneill static bool
575 1.1 jmcneill video_set_ctrl(uint32_t ctrl_id, int32_t value)
576 1.1 jmcneill {
577 1.1 jmcneill struct v4l2_control ctrl;
578 1.1 jmcneill const char *ctrlname;
579 1.1 jmcneill int32_t ovalue;
580 1.1 jmcneill int error;
581 1.1 jmcneill
582 1.1 jmcneill ctrlname = video_cid2name(ctrl_id);
583 1.1 jmcneill
584 1.1 jmcneill ctrl.id = ctrl_id;
585 1.1 jmcneill error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
586 1.1 jmcneill if (error)
587 1.1 jmcneill return false;
588 1.1 jmcneill ovalue = ctrl.value;
589 1.1 jmcneill ctrl.value = value;
590 1.1 jmcneill error = ioctl(video_fd, VIDIOC_S_CTRL, &ctrl);
591 1.1 jmcneill if (error)
592 1.1 jmcneill err(EXIT_FAILURE, "VIDIOC_S_CTRL failed for '%s'", ctrlname);
593 1.1 jmcneill error = ioctl(video_fd, VIDIOC_G_CTRL, &ctrl);
594 1.1 jmcneill if (error)
595 1.1 jmcneill err(EXIT_FAILURE, "VIDIOC_G_CTRL failed for '%s'", ctrlname);
596 1.1 jmcneill
597 1.1 jmcneill if (ctrlname)
598 1.1 jmcneill printf("ctrl.%s: %d -> %d\n", ctrlname, ovalue, ctrl.value);
599 1.1 jmcneill else
600 1.1 jmcneill printf("ctrl.%08x: %d -> %d\n", ctrl.id, ovalue, ctrl.value);
601 1.1 jmcneill
602 1.1 jmcneill return true;
603 1.1 jmcneill }
604 1.1 jmcneill
605 1.1 jmcneill static const char *
606 1.1 jmcneill video_cid2name(uint32_t id)
607 1.1 jmcneill {
608 1.1 jmcneill unsigned int i;
609 1.1 jmcneill
610 1.1 jmcneill for (i = 0; i < __arraycount(videoctl_cid_names); i++)
611 1.1 jmcneill if (videoctl_cid_names[i].id == id)
612 1.1 jmcneill return videoctl_cid_names[i].name;
613 1.1 jmcneill
614 1.1 jmcneill return NULL;
615 1.1 jmcneill }
616 1.1 jmcneill
617 1.1 jmcneill static uint32_t
618 1.1 jmcneill video_name2cid(const char *name)
619 1.1 jmcneill {
620 1.1 jmcneill unsigned int i;
621 1.1 jmcneill
622 1.1 jmcneill for (i = 0; i < __arraycount(videoctl_cid_names); i++)
623 1.1 jmcneill if (strcmp(name, videoctl_cid_names[i].name) == 0)
624 1.1 jmcneill return videoctl_cid_names[i].id;
625 1.1 jmcneill
626 1.1 jmcneill return (uint32_t)-1;
627 1.1 jmcneill }
628