Ejemplo n.º 1
0
int main(int argc, char **argv)
{
	char *value, *subs;
	int i, forcedstride = 0;

	int fd = -1;

	/* command args */
	int ch;
	const char *device = "/dev/video0";	/* -d device */
	struct v4l2_capability vcap;	/* list_cap */
	struct v4l2_dbg_register set_reg;
	struct v4l2_dbg_register get_reg;
	struct v4l2_dbg_chip_info chip_info;
	const struct board_list *curr_bd = NULL;
	char short_options[26 * 2 * 3 + 1];
	int idx = 0;
	std::string reg_min_arg, reg_max_arg;
	std::string reg_set_arg;
	unsigned long long reg_min = 0, reg_max = 0;
	std::vector<std::string> get_regs;
	struct v4l2_dbg_match match;
	char *p;

	match.type = V4L2_CHIP_MATCH_BRIDGE;
	match.addr = 0;
	memset(&set_reg, 0, sizeof(set_reg));
	memset(&get_reg, 0, sizeof(get_reg));

	if (argc == 1) {
		usage();
		return 0;
	}
	for (i = 0; long_options[i].name; i++) {
		if (!isalpha(long_options[i].val))
			continue;
		short_options[idx++] = long_options[i].val;
		if (long_options[i].has_arg == required_argument) {
			short_options[idx++] = ':';
		} else if (long_options[i].has_arg == optional_argument) {
			short_options[idx++] = ':';
			short_options[idx++] = ':';
		}
	}
	while (1) {
		int option_index = 0;

		short_options[idx] = 0;
		ch = getopt_long(argc, argv, short_options,
				 long_options, &option_index);
		if (ch == -1)
			break;

		options[(int)ch] = 1;
		switch (ch) {
		case OptHelp:
			usage();
			return 0;

		case OptSetDevice:
			device = optarg;
			if (device[0] >= '0' && device[0] <= '9' && strlen(device) <= 3) {
				static char newdev[20];

				sprintf(newdev, "/dev/video%s", device);
				device = newdev;
			}
			break;

		case OptChip:
			if (!memcmp(optarg, "subdev", 6) && isdigit(optarg[6])) {
				match.type = V4L2_CHIP_MATCH_SUBDEV;
				match.addr = strtoul(optarg + 6, NULL, 0);
				break;
			}
			if (!memcmp(optarg, "bridge", 6)) {
				match.type = V4L2_CHIP_MATCH_BRIDGE;
				match.addr = strtoul(optarg + 6, NULL, 0);
				break;
			}
			match.type = V4L2_CHIP_MATCH_BRIDGE;
			match.addr = 0;
			break;

		case OptSetRegister:
			reg_set_arg = optarg;
			break;

		case OptGetRegister:
			get_regs.push_back(optarg);
			break;

		case OptSetStride:
			forcedstride = strtoull(optarg, 0L, 0);
			break;

		case OptListRegisters:
			subs = optarg;
			if (subs == NULL)
				break;

			while (*subs != '\0') {
				static const char * const subopts[] = {
					"min",
					"max",
					NULL
				};

				switch (parse_subopt(&subs, subopts, &value)) {
				case 0:
					reg_min_arg = value;
					//if (reg_max == 0)
					//	reg_max = reg_min + 0xff;
					break;
				case 1:
					reg_max_arg = value;
					break;
				}
			}
			break;

		case OptListSymbols:
			break;

		case ':':
			fprintf(stderr, "Option `%s' requires a value\n",
				argv[optind]);
			usage();
			return 1;

		case '?':
			fprintf(stderr, "Unknown argument `%s'\n",
				argv[optind]);
			usage();
			return 1;
		}
	}

	if ((fd = open(device, O_RDWR)) < 0) {
		fprintf(stderr, "Failed to open %s: %s\n", device,
			strerror(errno));
		exit(1);
	}

	doioctl(fd, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP");
	capabilities = vcap.capabilities;

	/* Information Opts */

	if (options[OptGetDriverInfo]) {
		printf("Driver info:\n");
		printf("\tDriver name   : %s\n", vcap.driver);
		printf("\tCard type     : %s\n", vcap.card);
		printf("\tBus info      : %s\n", vcap.bus_info);
		printf("\tDriver version: %d.%d.%d\n",
				vcap.version >> 16,
				(vcap.version >> 8) & 0xff,
				vcap.version & 0xff);
		printf("\tCapabilities  : 0x%08X\n", vcap.capabilities);
		printf("%s", cap2s(vcap.capabilities).c_str());
	}

	chip_info.name[0] = '\0';
	if (options[OptChip]) {
		/* try to figure out which chip it is */
		chip_info.match = match;
		if (doioctl(fd, VIDIOC_DBG_G_CHIP_INFO, &chip_info, "VIDIOC_DBG_G_CHIP_INFO") != 0)
			chip_info.name[0] = '\0';

		if (!strncasecmp(match.name, "ac97", 4)) {
			curr_bd = &boards[AC97_BOARD];
		} else {
			for (int board = ARRAY_SIZE(boards) - 1; board >= 0; board--) {
				if (!strcasecmp(chip_info.name, boards[board].name)) {
					curr_bd = &boards[board];
					break;
				}
			}
		}
	}

	/* Set options */

	if (options[OptSetRegister]) {
		set_reg.match = match;
		if (optind >= argc)
			usage();
		set_reg.reg = parse_reg(curr_bd, reg_set_arg);
		while (optind < argc) {
			unsigned size = 0;

			if (doioctl(fd, VIDIOC_DBG_G_REGISTER, &set_reg,
				    "VIDIOC_DBG_G_REGISTER") >= 0)
				size = set_reg.size;

			set_reg.val = strtoull(argv[optind++], NULL, 0);
			if (doioctl(fd, VIDIOC_DBG_S_REGISTER, &set_reg,
						"VIDIOC_DBG_S_REGISTER") >= 0) {
				const char *name = reg_name(curr_bd, set_reg.reg);

				printf("Register ");

				if (name)
					printf("%s (0x%08llx)", name, set_reg.reg);
				else
					printf("0x%08llx", set_reg.reg);

				printf(" set to 0x%llx\n", set_reg.val);
			} else {
				printf("Failed to set register 0x%08llx value 0x%llx: %s\n",
					set_reg.reg, set_reg.val, strerror(errno));
			}
			set_reg.reg += size ? : (forcedstride ? : 1);
		}
	}

	if (options[OptScanChips]) {
		chip_info.match.type = V4L2_CHIP_MATCH_BRIDGE;
		chip_info.match.addr = 0;

		while (doioctl(fd, VIDIOC_DBG_G_CHIP_INFO, &chip_info, "VIDIOC_DBG_G_CHIP_INFO") == 0 && chip_info.name[0]) {
			printf("bridge%d: ", chip_info.match.addr);
			print_name(&chip_info);
			chip_info.match.addr++;
		}

		chip_info.match.type = V4L2_CHIP_MATCH_SUBDEV;
		chip_info.match.addr = 0;
		while (doioctl(fd, VIDIOC_DBG_G_CHIP_INFO, &chip_info, "VIDIOC_DBG_G_CHIP_INFO") == 0 && chip_info.name[0]) {
			printf("subdev%d: ", chip_info.match.addr++);
			print_name(&chip_info);
		}
	}

	if (options[OptGetRegister]) {
		get_reg.match = match;
		printf("ioctl: VIDIOC_DBG_G_REGISTER\n");

		for (std::vector<std::string>::iterator iter = get_regs.begin();
				iter != get_regs.end(); ++iter) {
			get_reg.reg = parse_reg(curr_bd, *iter);
			if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &get_reg) < 0)
				fprintf(stderr, "ioctl: VIDIOC_DBG_G_REGISTER "
						"failed for 0x%llx\n", get_reg.reg);
			else {
				const char *name = reg_name(curr_bd, get_reg.reg);

				printf("Register ");

				if (name)
					printf("%s (0x%08llx)", name, get_reg.reg);
				else
					printf("0x%08llx", get_reg.reg);

				printf(" = %llxh (%lldd  %sb)\n",
					get_reg.val, get_reg.val, binary(get_reg.val));
			}
		}
	}

	if (options[OptListRegisters]) {
		std::string name;
		int stride = 1;

		get_reg.match = match;
		if (forcedstride) {
			stride = forcedstride;
		} else if (get_reg.match.type == V4L2_CHIP_MATCH_BRIDGE) {
			stride = 4;
		}
		printf("ioctl: VIDIOC_DBG_G_REGISTER\n");

		if (curr_bd) {
			if (reg_min_arg.empty())
				reg_min = 0;
			else
				reg_min = parse_reg(curr_bd, reg_min_arg);


			if (reg_max_arg.empty())
				reg_max = (1ll << 32) - 1;
			else
				reg_max = parse_reg(curr_bd, reg_max_arg);

			for (int i = 0; i < curr_bd->regs_size; i++) {
				if (reg_min_arg.empty() || ((curr_bd->regs[i].reg >= reg_min) && curr_bd->regs[i].reg <= reg_max)) {
					get_reg.reg = curr_bd->regs[i].reg;

					if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &get_reg) < 0)
						fprintf(stderr, "ioctl: VIDIOC_DBG_G_REGISTER "
								"failed for 0x%llx\n", get_reg.reg);
					else {
						const char *name = reg_name(curr_bd, get_reg.reg);

						printf("Register ");

						if (name)
							printf("%s (0x%08llx)", name, get_reg.reg);
						else
							printf("0x%08llx", get_reg.reg);

						printf(" = %llxh (%lldd  %sb)\n",
							get_reg.val, get_reg.val, binary(get_reg.val));
					}
				}
			}
			goto list_done;
		}

		if (!reg_min_arg.empty()) {
			reg_min = parse_reg(curr_bd, reg_min_arg);
			if (reg_max_arg.empty())
				reg_max = reg_min + 0xff;
			else
				reg_max = parse_reg(curr_bd, reg_max_arg);
			/* Explicit memory range: just do it */
			print_regs(fd, &get_reg, reg_min, reg_max, stride);
			goto list_done;
		}

		p = strchr(chip_info.name, ' ');
		if (p)
			*p = '\0';
		name = chip_info.name;

		if (name == "saa7115") {
			print_regs(fd, &get_reg, 0, 0xff, stride);
		} else if (name == "saa717x") {
			// FIXME: use correct reg regions
			print_regs(fd, &get_reg, 0, 0xff, stride);
		} else if (name == "saa7127") {
			print_regs(fd, &get_reg, 0, 0x7f, stride);
		} else if (name == "ov7670") {
			print_regs(fd, &get_reg, 0, 0x89, stride);
		} else if (name == "cx25840") {
			print_regs(fd, &get_reg, 0, 2, stride);
			print_regs(fd, &get_reg, 0x100, 0x15f, stride);
			print_regs(fd, &get_reg, 0x200, 0x23f, stride);
			print_regs(fd, &get_reg, 0x400, 0x4bf, stride);
			print_regs(fd, &get_reg, 0x800, 0x9af, stride);
		} else if (name == "cs5345") {
			print_regs(fd, &get_reg, 1, 0x10, stride);
		} else if (name == "cx23416") {
			print_regs(fd, &get_reg, 0x02000000, 0x020000ff, stride);
		} else if (name == "cx23418") {
			print_regs(fd, &get_reg, 0x02c40000, 0x02c409c7, stride);
		} else if (name == "cafe") {
			print_regs(fd, &get_reg, 0, 0x43, stride);
			print_regs(fd, &get_reg, 0x88, 0x8f, stride);
			print_regs(fd, &get_reg, 0xb4, 0xbb, stride);
			print_regs(fd, &get_reg, 0x3000, 0x300c, stride);
		} else {
			/* unknown chip, dump 0-0xff by default */
			print_regs(fd, &get_reg, 0, 0xff, stride);
		}
	}
list_done:

	if (options[OptLogStatus]) {
		static char buf[40960];
		int len = -1;

		if (doioctl(fd, VIDIOC_LOG_STATUS, NULL, "VIDIOC_LOG_STATUS") == 0) {
			printf("\nStatus Log:\n\n");
#ifdef HAVE_KLOGCTL
			len = klogctl(3, buf, sizeof(buf) - 1);
#endif
			if (len >= 0) {
				bool found_status = false;
				char *p = buf;
				char *q;

				buf[len] = 0;
				while ((q = strstr(p, "START STATUS"))) {
					found_status = true;
					p = q + 1;
				}
				if (found_status) {
					while (p > buf && *p != '<') p--;
					q = p;
					while ((q = strstr(q, "<6>"))) {
						memcpy(q, "   ", 3);
					}
					printf("%s", p);
				}
			}
		}
	}

	if (options[OptListSymbols]) {
		if (curr_bd == NULL) {
			printf("No symbols found for driver %s\n", vcap.driver);
		}
		else {
			printf("Symbols for driver %s:\n", curr_bd->name);
			for (int i = 0; i < curr_bd->regs_size; i++)
				printf("0x%08x: %s\n", curr_bd->regs[i].reg, curr_bd->regs[i].name);
			for (int i = 0; i < curr_bd->alt_regs_size; i++)
				printf("0x%08x: %s\n", curr_bd->alt_regs[i].reg, curr_bd->alt_regs[i].name);
		}
	}

	close(fd);
	exit(0);
}
Ejemplo n.º 2
0
int main(int argc, char **argv)
{
	int i;
	struct node node = { -1 };
	struct node video_node = { -1 };
	struct node video_node2 = { -1 };
	struct node radio_node = { -1, true };
	struct node radio_node2 = { -1, true };
	struct node vbi_node = { -1 };
	struct node vbi_node2 = { -1 };

	/* command args */
	int ch;
	const char *device = NULL;
	const char *video_device = NULL;		/* -d device */
	const char *radio_device = NULL;	/* -r device */
	const char *vbi_device = NULL;		/* -V device */
	struct v4l2_capability vcap;	/* list_cap */
	char short_options[26 * 2 * 2 + 1];
	int idx = 0;

	for (i = 0; long_options[i].name; i++) {
		if (!isalpha(long_options[i].val))
			continue;
		short_options[idx++] = long_options[i].val;
		if (long_options[i].has_arg == required_argument)
			short_options[idx++] = ':';
	}
	while (1) {
		int option_index = 0;

		short_options[idx] = 0;
		ch = getopt_long(argc, argv, short_options,
				 long_options, &option_index);
		if (ch == -1)
			break;

		options[(int)ch] = 1;
		switch (ch) {
		case OptHelp:
			usage();
			return 0;
		case OptSetDevice:
			video_device = optarg;
			if (video_device[0] >= '0' && video_device[0] <= '9' && strlen(video_device) <= 3) {
				static char newdev[20];

				sprintf(newdev, "/dev/video%s", video_device);
				video_device = newdev;
			}
			break;
		case OptSetRadioDevice:
			radio_device = optarg;
			if (radio_device[0] >= '0' && radio_device[0] <= '9' && strlen(radio_device) <= 3) {
				static char newdev[20];

				sprintf(newdev, "/dev/radio%s", radio_device);
				radio_device = newdev;
			}
			break;
		case OptSetVbiDevice:
			vbi_device = optarg;
			if (vbi_device[0] >= '0' && vbi_device[0] <= '9' && strlen(vbi_device) <= 3) {
				static char newdev[20];

				sprintf(newdev, "/dev/vbi%s", vbi_device);
				vbi_device = newdev;
			}
			break;
		case OptNoWarnings:
			show_warnings = false;
			break;
		case OptVerbose:
			show_info = true;
			break;
		case ':':
			fprintf(stderr, "Option `%s' requires a value\n",
				argv[optind]);
			usage();
			return 1;
		case '?':
			fprintf(stderr, "Unknown argument `%s'\n",
				argv[optind]);
			usage();
			return 1;
		}
	}
	if (optind < argc) {
		printf("unknown arguments: ");
		while (optind < argc)
			printf("%s ", argv[optind++]);
		printf("\n");
		usage();
		return 1;
	}
	wrapper = options[OptUseWrapper];

	struct utsname uts;
	int v1, v2, v3;

	uname(&uts);
	sscanf(uts.release, "%d.%d.%d", &v1, &v2, &v3);
	if (v1 == 2 && v2 == 6)
		kernel_version = v3;

	if (!video_device && !radio_device && !vbi_device)
		video_device = "/dev/video0";

	if (video_device && (video_node.fd = test_open(video_device, O_RDWR)) < 0) {
		fprintf(stderr, "Failed to open %s: %s\n", video_device,
			strerror(errno));
		exit(1);
	}

	if (radio_device && (radio_node.fd = test_open(radio_device, O_RDWR)) < 0) {
		fprintf(stderr, "Failed to open %s: %s\n", radio_device,
			strerror(errno));
		exit(1);
	}

	if (vbi_device && (vbi_node.fd = test_open(vbi_device, O_RDWR)) < 0) {
		fprintf(stderr, "Failed to open %s: %s\n", vbi_device,
			strerror(errno));
		exit(1);
	}

	if (video_node.fd >= 0) {
		node.fd = video_node.fd;
		device = video_device;
		node.is_video = true;
	} else if (radio_node.fd >= 0) {
		node.fd = radio_node.fd;
		device = radio_device;
		node.is_radio = true;
		printf("is radio\n");
	} else if (vbi_node.fd >= 0) {
		node.fd = vbi_node.fd;
		device = vbi_device;
		node.is_vbi = true;
	}
	node.device = device;

	doioctl(&node, VIDIOC_QUERYCAP, &vcap);
	if (vcap.capabilities & V4L2_CAP_DEVICE_CAPS)
		node.caps = vcap.device_caps;
	else
		node.caps = vcap.capabilities;
	if (node.caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
			 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_SLICED_VBI_CAPTURE |
			 V4L2_CAP_RDS_CAPTURE | V4L2_CAP_RADIO | V4L2_CAP_TUNER))
		node.has_inputs = true;
	if (node.caps & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VBI_OUTPUT |
			 V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_SLICED_VBI_OUTPUT |
			 V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR))
		node.has_outputs = true;
	if (node.caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
			 V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE |
			 V4L2_CAP_VIDEO_M2M | V4L2_CAP_SLICED_VBI_CAPTURE |
			 V4L2_CAP_RDS_CAPTURE))
		node.can_capture = true;
	if (node.caps & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VBI_OUTPUT |
			 V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE |
			 V4L2_CAP_VIDEO_M2M | V4L2_CAP_SLICED_VBI_OUTPUT |
			 V4L2_CAP_RDS_OUTPUT))
		node.can_output = true;

	/* Information Opts */

	if (kernel_version)
		printf("Running on 2.6.%d\n\n", kernel_version);

	printf("Driver Info:\n");
	printf("\tDriver name   : %s\n", vcap.driver);
	printf("\tCard type     : %s\n", vcap.card);
	printf("\tBus info      : %s\n", vcap.bus_info);
	printf("\tDriver version: %d.%d.%d\n",
			vcap.version >> 16,
			(vcap.version >> 8) & 0xff,
			vcap.version & 0xff);
	printf("\tCapabilities  : 0x%08X\n", vcap.capabilities);
	printf("%s", cap2s(vcap.capabilities).c_str());
	if (vcap.capabilities & V4L2_CAP_DEVICE_CAPS) {
		printf("\tDevice Caps   : 0x%08X\n", vcap.device_caps);
		printf("%s", cap2s(vcap.device_caps).c_str());
	}

	printf("\nCompliance test for device %s (%susing libv4l2):\n\n",
			device, wrapper ? "" : "not ");

	/* Required ioctls */

	printf("Required ioctls:\n");
	printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&node)));
	printf("\n");

	/* Multiple opens */

	printf("Allow for multiple opens:\n");
	if (video_device) {
		video_node2 = node;
		printf("\ttest second video open: %s\n",
				ok((video_node2.fd = test_open(video_device, O_RDWR)) < 0));
		if (video_node2.fd >= 0) {
			printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&video_node2)));
			printf("\ttest VIDIOC_G/S_PRIORITY: %s\n",
					ok(testPrio(&node, &video_node2)));
			node.node2 = &video_node2;
		}
	}
	if (radio_device) {
		radio_node2 = node;
		printf("\ttest second radio open: %s\n",
				ok((radio_node2.fd = test_open(radio_device, O_RDWR)) < 0));
		if (radio_node2.fd >= 0) {
			printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&radio_node2)));
			printf("\ttest VIDIOC_G/S_PRIORITY: %s\n",
					ok(testPrio(&node, &radio_node2)));
			node.node2 = &video_node2;
		}
	}
	if (vbi_device) {
		vbi_node2 = node;
		printf("\ttest second vbi open: %s\n",
				ok((vbi_node2.fd = test_open(vbi_device, O_RDWR)) < 0));
		if (vbi_node2.fd >= 0) {
			printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(&vbi_node2)));
			printf("\ttest VIDIOC_G/S_PRIORITY: %s\n",
					ok(testPrio(&node, &vbi_node2)));
			node.node2 = &video_node2;
		}
	}
	printf("\n");

	/* Debug ioctls */

	printf("Debug ioctls:\n");
	printf("\ttest VIDIOC_DBG_G/S_REGISTER: %s\n", ok(testRegister(&node)));
	printf("\ttest VIDIOC_LOG_STATUS: %s\n", ok(testLogStatus(&node)));
	printf("\n");

	/* Input ioctls */

	printf("Input ioctls:\n");
	printf("\ttest VIDIOC_G/S_TUNER: %s\n", ok(testTuner(&node)));
	printf("\ttest VIDIOC_G/S_FREQUENCY: %s\n", ok(testTunerFreq(&node)));
	printf("\ttest VIDIOC_S_HW_FREQ_SEEK: %s\n", ok(testTunerHwSeek(&node)));
	printf("\ttest VIDIOC_ENUMAUDIO: %s\n", ok(testEnumInputAudio(&node)));
	printf("\ttest VIDIOC_G/S/ENUMINPUT: %s\n", ok(testInput(&node)));
	printf("\ttest VIDIOC_G/S_AUDIO: %s\n", ok(testInputAudio(&node)));
	printf("\tInputs: %d Audio Inputs: %d Tuners: %d\n",
			node.inputs, node.audio_inputs, node.tuners);
	printf("\n");

	/* Output ioctls */

	printf("Output ioctls:\n");
	printf("\ttest VIDIOC_G/S_MODULATOR: %s\n", ok(testModulator(&node)));
	printf("\ttest VIDIOC_G/S_FREQUENCY: %s\n", ok(testModulatorFreq(&node)));
	printf("\ttest VIDIOC_ENUMAUDOUT: %s\n", ok(testEnumOutputAudio(&node)));
	printf("\ttest VIDIOC_G/S/ENUMOUTPUT: %s\n", ok(testOutput(&node)));
	printf("\ttest VIDIOC_G/S_AUDOUT: %s\n", ok(testOutputAudio(&node)));
	printf("\tOutputs: %d Audio Outputs: %d Modulators: %d\n",
			node.outputs, node.audio_outputs, node.modulators);
	printf("\n");

	/* Control ioctls */

	printf("Control ioctls:\n");
	printf("\ttest VIDIOC_QUERYCTRL/MENU: %s\n", ok(testQueryControls(&node)));
	printf("\ttest VIDIOC_G/S_CTRL: %s\n", ok(testSimpleControls(&node)));
	printf("\ttest VIDIOC_G/S/TRY_EXT_CTRLS: %s\n", ok(testExtendedControls(&node)));
	printf("\ttest VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: %s\n", ok(testControlEvents(&node)));
	printf("\ttest VIDIOC_G/S_JPEGCOMP: %s\n", ok(testJpegComp(&node)));
	printf("\tStandard Controls: %d Private Controls: %d\n",
			node.std_controls, node.priv_controls);
	printf("\n");

	/* I/O configuration ioctls */

	printf("Input/Output configuration ioctls:\n");
	printf("\ttest VIDIOC_ENUM/G/S/QUERY_STD: %s\n", ok(testStd(&node)));
	printf("\ttest VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: %s\n", ok(testTimings(&node)));
	printf("\ttest VIDIOC_DV_TIMINGS_CAP: %s\n", ok(testTimingsCap(&node)));
	printf("\n");

	/* Format ioctls */

	printf("Format ioctls:\n");
	printf("\ttest VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: %s\n", ok(testEnumFormats(&node)));
	printf("\ttest VIDIOC_G/S_PARM: %s\n", ok(testParm(&node)));
	printf("\ttest VIDIOC_G_FBUF: %s\n", ok(testFBuf(&node)));
	printf("\ttest VIDIOC_G_FMT: %s\n", ok(testGetFormats(&node)));
	printf("\ttest VIDIOC_TRY_FMT: %s\n", ok(testTryFormats(&node)));
	printf("\ttest VIDIOC_S_FMT: %s\n", ok(testSetFormats(&node)));
	printf("\ttest VIDIOC_G_SLICED_VBI_CAP: %s\n", ok(testSlicedVBICap(&node)));
	printf("\n");

	/* Codec ioctls */

	printf("Codec ioctls:\n");
	printf("\ttest VIDIOC_(TRY_)ENCODER_CMD: %s\n", ok(testEncoder(&node)));
	printf("\ttest VIDIOC_G_ENC_INDEX: %s\n", ok(testEncIndex(&node)));
	printf("\ttest VIDIOC_(TRY_)DECODER_CMD: %s\n", ok(testDecoder(&node)));
	printf("\n");

	/* Buffer ioctls */

	printf("Buffer ioctls:\n");
	printf("\ttest VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: %s\n", ok(testReqBufs(&node)));
	//printf("\ttest read/write: %s\n", ok(testReadWrite(&node)));
	printf("\n");

	/* TODO:

	   VIDIOC_CROPCAP, VIDIOC_G/S_CROP, VIDIOC_G/S_SELECTION
	   VIDIOC_S_FBUF/OVERLAY
	   VIDIOC_QBUF/DQBUF/QUERYBUF/PREPARE_BUFS/EXPBUF
	   VIDIOC_STREAMON/OFF
	   */

	/* Final test report */

	test_close(node.fd);
	if (node.node2)
		test_close(node.node2->fd);
	printf("Total: %d, Succeeded: %d, Failed: %d, Warnings: %d\n",
			tests_total, tests_ok, tests_total - tests_ok, warnings);
	exit(app_result);
}