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