static int standby_resume_wakeup(struct node *node, unsigned me, unsigned la, bool interactive) { if (!node->remote[la].in_standby) return NOTAPPLICABLE; int ret; if (is_tv(la, node->remote[la].prim_type)) ret = wakeup_tv(node, me, la); else ret = wakeup_source(node, me, la); if (ret) return ret; unsigned unresponsive_time = 0; announce("Device is woken up"); fail_on_test(!poll_stable_power_status(node, me, la, CEC_OP_POWER_STATUS_ON, unresponsive_time)); fail_on_test(interactive && !question("Is the device in On state?")); if (unresponsive_time > 0) warn("The device went correctly out of standby, but became unresponsive for %d s during the transition.\n", unresponsive_time); return 0; }
int testReadWrite(struct node *node) { bool can_rw = node->caps & V4L2_CAP_READWRITE; int fd_flags = fcntl(node->fd, F_GETFL); char buf = 0; int ret; fcntl(node->fd, F_SETFL, fd_flags | O_NONBLOCK); if (node->can_capture) ret = read(node->fd, &buf, 1); else ret = write(node->fd, &buf, 1); // Note: RDS can only return multiples of 3, so we accept // both 0 and 1 as return code. if (can_rw) fail_on_test((ret < 0 && errno != EAGAIN) || ret > 1); else fail_on_test(ret < 0 && errno != EINVAL); if (!can_rw) goto rw_exit; reopen(node); fcntl(node->fd, F_SETFL, fd_flags | O_NONBLOCK); /* check that the close cleared the busy flag */ if (node->can_capture) ret = read(node->fd, &buf, 1); else ret = write(node->fd, &buf, 1); fail_on_test((ret < 0 && errno != EAGAIN) || ret > 1); rw_exit: reopen(node); return 0; }
static int standby_resume_standby_toggle(struct node *node, unsigned me, unsigned la, bool interactive) { if (!node->remote[la].in_standby) return NOTAPPLICABLE; struct cec_msg msg = {}; unsigned unresponsive_time = 0; __u8 new_status; node->remote[la].in_standby = false; /* Send Standby again to test that it is not acting like a toggle */ announce("Sending Standby message."); cec_msg_init(&msg, me, la); cec_msg_standby(&msg); int res = doioctl(node, CEC_TRANSMIT, &msg); fail_on_test(res && res != ENONET); fail_on_test(cec_msg_status_is_abort(&msg)); fail_on_test(wait_changing_power_status(node, me, la, new_status, unresponsive_time)); fail_on_test(new_status != CEC_OP_POWER_STATUS_STANDBY); fail_on_test(interactive && !question("Is the device still in standby?")); node->remote[la].in_standby = true; if (unresponsive_time > 0) warn("The device went correctly into standby, but became unresponsive for %d s during the transition.\n", unresponsive_time); return 0; }
static int standby_resume_standby(struct node *node, unsigned me, unsigned la, bool interactive) { if (!node->remote[la].has_power_status) return NOTAPPLICABLE; struct cec_msg msg = {}; unsigned unresponsive_time = 0; fail_on_test(!util_interactive_ensure_power_state(node, me, la, interactive, CEC_OP_POWER_STATUS_ON)); announce("Sending Standby message."); cec_msg_init(&msg, me, la); cec_msg_standby(&msg); fail_on_test(!transmit_timeout(node, &msg)); fail_on_test(cec_msg_status_is_abort(&msg)); fail_on_test(!poll_stable_power_status(node, me, la, CEC_OP_POWER_STATUS_STANDBY, unresponsive_time)); fail_on_test(interactive && !question("Is the device in standby?")); node->remote[la].in_standby = true; if (unresponsive_time > 0) warn("The device went correctly into standby, but became unresponsive for %d s during the transition.\n", unresponsive_time); return 0; }
static int testParmType(struct node *node, unsigned type) { struct v4l2_streamparm parm; int ret; memset(&parm, 0, sizeof(parm)); parm.type = type; ret = doioctl(node, VIDIOC_G_PARM, &parm); if (ret == ENOTTY) return ret; if (ret == EINVAL) return ENOTTY; if (ret) return fail("expected EINVAL, but got %d when getting parms for buftype %d\n", ret, type); fail_on_test(parm.type != type); ret = testParmStruct(node, parm); if (ret) return ret; memset(&parm, 0, sizeof(parm)); parm.type = type; ret = doioctl(node, VIDIOC_S_PARM, &parm); if (ret == ENOTTY) return 0; if (ret) return fail("got error %d when setting parms for buftype %d\n", ret, type); fail_on_test(parm.type != type); return testParmStruct(node, parm); }
int testRegister(struct node *node) { struct v4l2_dbg_register reg; struct v4l2_dbg_chip_ident chip; int ret; int uid = getuid(); reg.match.type = V4L2_CHIP_MATCH_HOST; reg.match.addr = 0; reg.reg = 0; ret = doioctl(node, VIDIOC_DBG_G_REGISTER, ®); if (ret == ENOTTY) return ret; // Not allowed to call VIDIOC_DBG_G_REGISTER unless root fail_on_test(uid && ret != EPERM); fail_on_test(uid == 0 && ret); chip.match.type = V4L2_CHIP_MATCH_HOST; chip.match.addr = 0; fail_on_test(doioctl(node, VIDIOC_DBG_G_CHIP_IDENT, &chip)); if (uid) { // Don't test S_REGISTER as root, don't want to risk // messing with registers in the compliance test. reg.reg = reg.val = 0; ret = doioctl(node, VIDIOC_DBG_S_REGISTER, ®); fail_on_test(ret != ENOTTY && ret != EINVAL && ret != EPERM); } return 0; }
static int standby_resume_active_source_nowake(struct node *node, unsigned me, unsigned la, bool interactive) { if (!node->remote[la].in_standby) return NOTAPPLICABLE; struct cec_msg msg = {}; unsigned unresponsive_time = 0; __u8 new_status; node->remote[la].in_standby = false; /* In CEC 2.0 it is specified that a device shall not go out of standby if an Active Source message is received. */ announce("Sending Active Source message."); cec_msg_init(&msg, me, la); cec_msg_active_source(&msg, node->phys_addr); int res = doioctl(node, CEC_TRANSMIT, &msg); fail_on_test(res && res != ENONET); fail_on_test(wait_changing_power_status(node, me, la, new_status, unresponsive_time)); fail_on_test_v2_warn(node->remote[la].cec_version, new_status != CEC_OP_POWER_STATUS_STANDBY); node->remote[la].in_standby = true; if (unresponsive_time > 0) warn("The device stayed correctly in standby, but became unresponsive for %d s.\n", unresponsive_time); return 0; }
int testReadWrite(struct node *node) { bool can_rw = node->caps & V4L2_CAP_READWRITE; char buf = 0; int ret; if (node->can_capture) ret = read(node->fd, &buf, 1); else ret = write(node->fd, &buf, 1); // Note: RDS can only return multiples of 3, so we accept // both 0 and 1 as return code. if (can_rw) fail_on_test(ret != 0 && ret != 1); else fail_on_test(ret < 0 && errno != EINVAL); if (!can_rw) return 0; reopen(node); /* check that the close cleared the busy flag */ if (node->can_capture) ret = read(node->fd, &buf, 1); else ret = write(node->fd, &buf, 1); fail_on_test(ret != 0 && ret != 1); reopen(node); return 0; }
static int check_prio(struct node *node, struct node *node2, enum v4l2_priority match) { enum v4l2_priority prio; // Must be able to get priority fail_on_test(doioctl(node, VIDIOC_G_PRIORITY, &prio)); // Must match the expected prio fail_on_test(prio != match); fail_on_test(doioctl(node2, VIDIOC_G_PRIORITY, &prio)); fail_on_test(prio != match); return 0; }
static int wakeup_rc(struct node *node, unsigned me, unsigned la) { struct cec_msg msg = {}; struct cec_op_ui_command rc_press = {}; /* Todo: A release should be sent after this */ cec_msg_init(&msg, me, la); rc_press.ui_cmd = 0x6D; /* Power On Function */ cec_msg_user_control_pressed(&msg, &rc_press); fail_on_test(!transmit_timeout(node, &msg)); fail_on_test(cec_msg_status_is_abort(&msg)); return 0; }
static int testSlicedVBICapType(struct node *node, unsigned type) { struct v4l2_sliced_vbi_cap cap; bool sliced_type = (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE || type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); __u32 service_set = 0; int ret; memset(&cap, 0xff, sizeof(cap)); memset(&cap.reserved, 0, sizeof(cap.reserved)); cap.type = type; ret = doioctl(node, VIDIOC_G_SLICED_VBI_CAP, &cap); if (ret == ENOTTY) { fail_on_test(sliced_type && (node->caps & buftype2cap[type])); return ret; } fail_on_test(check_0(cap.reserved, sizeof(cap.reserved))); fail_on_test(cap.type != type); fail_on_test(ret && ret != EINVAL); fail_on_test(ret && sliced_type && (node->caps & buftype2cap[type])); fail_on_test(!ret && (!sliced_type || !(node->caps & buftype2cap[type]))); if (ret) return 0; for (int f = 0; f < 2; f++) for (int i = 0; i < 24; i++) service_set |= cap.service_lines[f][i]; fail_on_test(cap.service_set != service_set); fail_on_test(cap.service_lines[0][0] || cap.service_lines[1][0]); return 0; }
int testChipIdent(struct node *node) { struct v4l2_dbg_chip_ident chip; int ret; memset(&chip, 0, sizeof(chip)); chip.match.type = V4L2_CHIP_MATCH_HOST; chip.match.addr = 0; ret = doioctl(node, VIDIOC_DBG_G_CHIP_IDENT, &chip); // Must return either 0 (OK) or EINVAL (not supported) if (ret == 0) { struct v4l2_dbg_chip_ident orig; memset(&orig, 0, sizeof(orig)); // set invalid match_type chip.match.type = V4L2_CHIP_MATCH_I2C_ADDR + 1; chip.match.addr = 0xdeadbeef; chip.ident = 0xdeadbeef; chip.revision = 0xdeadbeef; orig = chip; ret = doioctl(node, VIDIOC_DBG_G_CHIP_IDENT, &chip); if (ret != EINVAL) return fail("Invalid match_type accepted\n"); fail_on_test(memcmp(&orig, &chip, sizeof(chip))); return 0; } return ret; }
int testEncIndex(struct node *node) { struct v4l2_enc_idx idx; int ret; memset(&idx, 0xff, sizeof(idx)); ret = doioctl(node, VIDIOC_G_ENC_INDEX, &idx); if (ret == ENOTTY) return ret; if (check_0(idx.reserved, sizeof(idx.reserved))) return fail("idx.reserved not zeroed\n"); fail_on_test(ret); fail_on_test(idx.entries != 0); fail_on_test(idx.entries_cap == 0); return 0; }
static int one_touch_play_view_on_wakeup(struct node *node, unsigned me, unsigned la, bool interactive, __u8 opcode) { fail_on_test(!util_interactive_ensure_power_state(node, me, la, interactive, CEC_OP_POWER_STATUS_STANDBY)); int ret = one_touch_play_view_on(node, me, la, interactive, opcode); if (ret && ret != PRESUMED_OK) return ret; fail_on_test(interactive && !question("Did the TV turn on?")); if (interactive) return 0; else return PRESUMED_OK; }
static int one_touch_play_req_active_source(struct node *node, unsigned me, unsigned la, bool interactive) { struct cec_msg msg = {}; cec_msg_init(&msg, me, la); cec_msg_active_source(&msg, node->phys_addr); fail_on_test(!transmit_timeout(node, &msg)); /* We have now said that we are active source, so receiving a reply to Request Active Source should fail the test. */ cec_msg_init(&msg, me, la); cec_msg_request_active_source(&msg, true); fail_on_test(!transmit_timeout(node, &msg)); fail_on_test(!timed_out(&msg)); return 0; }
int testDecoder(struct node *node) { struct v4l2_decoder_cmd cmd; int ret; memset(&cmd, 0xff, sizeof(cmd)); memset(&cmd.raw, 0, sizeof(cmd.raw)); ret = doioctl(node, VIDIOC_DECODER_CMD, &cmd); if (ret == ENOTTY) return ret; fail_on_test(ret != EINVAL); ret = doioctl(node, VIDIOC_TRY_DECODER_CMD, &cmd); fail_on_test(ret == ENOTTY); fail_on_test(ret != EINVAL); cmd.cmd = V4L2_DEC_CMD_STOP; cmd.flags = V4L2_DEC_CMD_STOP_IMMEDIATELY; ret = doioctl(node, VIDIOC_TRY_DECODER_CMD, &cmd); fail_on_test(ret != 0); ret = doioctl(node, VIDIOC_DECODER_CMD, &cmd); fail_on_test(ret != 0); cmd.cmd = V4L2_DEC_CMD_PAUSE; cmd.flags = 0; ret = doioctl(node, VIDIOC_DECODER_CMD, &cmd); fail_on_test(ret != EPERM && ret != EINVAL); cmd.cmd = V4L2_DEC_CMD_RESUME; ret = doioctl(node, VIDIOC_DECODER_CMD, &cmd); fail_on_test(ret != EPERM && ret != EINVAL); return 0; }
static int testSlicedVBICapType(struct node *node, enum v4l2_buf_type type) { struct v4l2_sliced_vbi_cap cap; bool sliced_type = (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE || type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT); __u32 service_set = 0; int ret; memset(&cap, 0xff, sizeof(cap)); memset(&cap.reserved, 0, sizeof(cap.reserved)); cap.type = type; ret = doioctl(node, VIDIOC_G_SLICED_VBI_CAP, &cap); fail_on_test(check_0(cap.reserved, sizeof(cap.reserved))); fail_on_test(cap.type != type); fail_on_test(ret && ret != EINVAL && sliced_type); if (ret == EINVAL) { fail_on_test(sliced_type && (node->caps & buftype2cap[type])); if (node->caps & (V4L2_CAP_SLICED_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT)) return 0; return -ENOSYS; } if (ret) return fail("expected EINVAL, but got %d when getting sliced VBI caps buftype %d\n", ret, type); fail_on_test(!(node->caps & buftype2cap[type])); for (int f = 0; f < 2; f++) for (int i = 0; i < 24; i++) service_set |= cap.service_lines[f][i]; fail_on_test(cap.service_set != service_set); fail_on_test(cap.service_lines[0][0] || cap.service_lines[1][0]); return 0; }
int testInput(struct node *node) { struct v4l2_input descr; int cur_input = MAGIC; int input; int ret = doioctl(node, VIDIOC_G_INPUT, &cur_input); int i = 0; if (ret == ENOTTY) { descr.index = 0; ret = doioctl(node, VIDIOC_ENUMINPUT, &descr); if (ret != ENOTTY) return fail("G_INPUT not supported, but ENUMINPUT is\n"); cur_input = 0; ret = doioctl(node, VIDIOC_S_INPUT, &cur_input); if (ret != ENOTTY) return fail("G_INPUT not supported, but S_INPUT is\n"); return ENOTTY; } if (ret) return fail("could not get current input\n"); if (cur_input == MAGIC) return fail("VIDIOC_G_INPUT didn't fill in the input\n"); if (node->is_radio) return fail("radio can't have input support\n"); for (;;) { memset(&descr, 0xff, sizeof(descr)); descr.index = i; ret = doioctl(node, VIDIOC_ENUMINPUT, &descr); if (ret == EINVAL) break; if (ret) return fail("could not enumerate input %d\n", i); input = i; if (doioctl(node, VIDIOC_S_INPUT, &input)) return fail("could not set input to %d\n", i); if (input != i) return fail("input set to %d, but becomes %d?!\n", i, input); if (checkInput(node, descr, i)) return fail("invalid attributes for input %d\n", i); node->inputs++; i++; } input = i; if (doioctl(node, VIDIOC_S_INPUT, &input) != EINVAL) return fail("could set input to invalid input %d\n", i); if (doioctl(node, VIDIOC_S_INPUT, &cur_input)) return fail("couldn't set input to the original input %d\n", cur_input); if (node->inputs && !node->has_inputs) return fail("inputs found, but no input capabilities set\n"); if (!node->inputs && node->has_inputs) return fail("no inputs found, but input capabilities set\n"); fail_on_test(node->is_m2m && node->inputs > 1); return 0; }
static int power_status_give(struct node *node, unsigned me, unsigned la, bool interactive) { struct cec_msg msg = { }; cec_msg_init(&msg, me, la); cec_msg_give_device_power_status(&msg, true); fail_on_test(!transmit_timeout(node, &msg)); fail_on_test(timed_out(&msg)); fail_on_test(unrecognized_op(&msg)); if (refused(&msg)) return REFUSED; if (cec_msg_status_is_abort(&msg)) return PRESUMED_OK; __u8 power_status; cec_ops_report_power_status(&msg, &power_status); fail_on_test(power_status >= 4); return 0; }
static int wakeup_source(struct node *node, unsigned me, unsigned la) { struct cec_msg msg = {}; cec_msg_init(&msg, me, la); cec_msg_set_stream_path(&msg, node->remote[la].phys_addr); fail_on_test(!transmit_timeout(node, &msg)); if (!cec_msg_status_is_abort(&msg)) return 0; return wakeup_rc(node, me, la); }
static int checkEnumFreqBands(struct node *node, __u32 tuner, __u32 type, __u32 caps) { unsigned i; __u32 caps_union = 0; for (i = 0; ; i++) { struct v4l2_frequency_band band; int ret; memset(band.reserved, 0, sizeof(band.reserved)); band.tuner = tuner; band.type = type; band.index = i; ret = doioctl(node, VIDIOC_ENUM_FREQ_BANDS, &band); if (ret == EINVAL && i) return 0; if (ret) return fail("couldn't get freq band\n"); caps_union |= band.capability; if ((caps & V4L2_TUNER_CAP_LOW) != (band.capability & V4L2_TUNER_CAP_LOW)) return fail("Inconsistent CAP_LOW usage\n"); fail_on_test(band.rangehigh < band.rangelow); fail_on_test(band.index != i); fail_on_test(band.type != type); fail_on_test(band.tuner != tuner); fail_on_test((band.capability & V4L2_TUNER_CAP_FREQ_BANDS) == 0); check_0(band.reserved, sizeof(band.reserved)); } fail_on_test(caps_union != caps); return 0; }
static int testPrio(struct node *node, struct node *node2) { enum v4l2_priority prio; int err; if (node->is_m2m) { fail_on_test(doioctl(node, VIDIOC_G_PRIORITY, &prio) != ENOTTY); return 0; } err = check_prio(node, node2, V4L2_PRIORITY_DEFAULT); if (err) return err; prio = V4L2_PRIORITY_RECORD; // Must be able to change priority fail_on_test(doioctl(node, VIDIOC_S_PRIORITY, &prio)); // Must match the new prio fail_on_test(check_prio(node, node2, V4L2_PRIORITY_RECORD)); prio = V4L2_PRIORITY_INTERACTIVE; // Going back to interactive on the other node must fail fail_on_test(!doioctl(node2, VIDIOC_S_PRIORITY, &prio)); prio = V4L2_PRIORITY_INTERACTIVE; // Changing it on the first node must work. fail_on_test(doioctl(node, VIDIOC_S_PRIORITY, &prio)); fail_on_test(check_prio(node, node2, V4L2_PRIORITY_INTERACTIVE)); return 0; }
static int testQueryBuf(struct node *node, unsigned type, unsigned count) { struct v4l2_buffer buf; int ret; unsigned i; memset(&buf, 0, sizeof(buf)); buf.type = type; for (i = 0; i < count; i++) { buf.index = i; fail_on_test(doioctl(node, VIDIOC_QUERYBUF, &buf)); fail_on_test(buf.index != i); fail_on_test(buf.type != type); fail_on_test(buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_ERROR)); } buf.index = count; ret = doioctl(node, VIDIOC_QUERYBUF, &buf); fail_on_test(ret != EINVAL); return 0; }
static int one_touch_play_view_on_change(struct node *node, unsigned me, unsigned la, bool interactive, __u8 opcode) { struct cec_msg msg = {}; int ret; fail_on_test(!util_interactive_ensure_power_state(node, me, la, interactive, CEC_OP_POWER_STATUS_ON)); interactive_info(true, "Please switch the TV to another source."); ret = one_touch_play_view_on(node, me, la, interactive, opcode); if (ret && ret != PRESUMED_OK) return ret; cec_msg_init(&msg, me, la); cec_msg_active_source(&msg, node->phys_addr); fail_on_test(!transmit_timeout(node, &msg)); fail_on_test(interactive && !question("Did the TV switch to this source?")); if (interactive) return 0; else return PRESUMED_OK; }
static int power_status_report(struct node *node, unsigned me, unsigned la, bool interactive) { struct cec_msg msg = {}; cec_msg_init(&msg, me, la); cec_msg_report_power_status(&msg, CEC_OP_POWER_STATUS_ON); fail_on_test(!transmit_timeout(node, &msg)); if (unrecognized_op(&msg)) return NOTSUPPORTED; if (refused(&msg)) return REFUSED; return PRESUMED_OK; }
int testOutput(struct node *node) { struct v4l2_output descr; int cur_output = MAGIC; int output; int ret = doioctl(node, VIDIOC_G_OUTPUT, &cur_output); int o = 0; if (ret == ENOTTY) { descr.index = 0; ret = doioctl(node, VIDIOC_ENUMOUTPUT, &descr); if (ret != ENOTTY) return fail("G_OUTPUT not supported, but ENUMOUTPUT is\n"); output = 0; ret = doioctl(node, VIDIOC_S_OUTPUT, &output); if (ret != ENOTTY) return fail("G_OUTPUT not supported, but S_OUTPUT is\n"); } if (ret) return ret; if (cur_output == MAGIC) return fail("VIDIOC_G_OUTPUT didn't fill in the output\n"); for (;;) { memset(&descr, 0xff, sizeof(descr)); descr.index = o; ret = doioctl(node, VIDIOC_ENUMOUTPUT, &descr); if (ret) break; output = o; if (doioctl(node, VIDIOC_S_OUTPUT, &output)) return fail("could not set output to %d\n", o); if (output != o) return fail("output set to %d, but becomes %d?!\n", o, output); if (checkOutput(node, descr, o)) return fail("invalid attributes for output %d\n", o); node->outputs++; o++; } output = o; if (doioctl(node, VIDIOC_S_OUTPUT, &output) != EINVAL) return fail("could set output to invalid output %d\n", o); if (doioctl(node, VIDIOC_S_OUTPUT, &cur_output)) return fail("couldn't set output to the original output %d\n", cur_output); if (node->outputs && !node->has_outputs) return fail("outputs found, but no output capabilities set\n"); if (!node->outputs && node->has_outputs) return fail("no outputs found, but output capabilities set\n"); fail_on_test(node->is_m2m && node->outputs > 1); return 0; }
static int checkTimingsCap(struct node *node, bool has_timings) { struct v4l2_dv_timings_cap timingscap; int ret; memset(&timingscap, 0xff, sizeof(timingscap)); ret = doioctl(node, VIDIOC_DV_TIMINGS_CAP, &timingscap); if (ret && has_timings) return fail("TIMINGS cap set, but could not get timings caps\n"); if (!ret && !has_timings) return fail("TIMINGS cap not set, but could still get timings caps\n"); if (ret && !has_timings) return 0; if (check_0(timingscap.reserved, sizeof(timingscap.reserved))) return fail("reserved not zeroed\n"); fail_on_test(timingscap.type != V4L2_DV_BT_656_1120); if (check_0(timingscap.bt.reserved, sizeof(timingscap.bt.reserved))) return fail("reserved not zeroed\n"); fail_on_test(timingscap.bt.min_width > timingscap.bt.max_width); fail_on_test(timingscap.bt.min_height > timingscap.bt.max_height); fail_on_test(timingscap.bt.min_pixelclock > timingscap.bt.max_pixelclock); return 0; }
static int one_touch_play_view_on(struct node *node, unsigned me, unsigned la, bool interactive, __u8 opcode) { struct cec_msg msg = {}; cec_msg_init(&msg, me, la); if (opcode == CEC_MSG_IMAGE_VIEW_ON) cec_msg_image_view_on(&msg); else if (opcode == CEC_MSG_TEXT_VIEW_ON) cec_msg_text_view_on(&msg); fail_on_test(!transmit_timeout(node, &msg)); fail_on_test(is_tv(la, node->remote[la].prim_type) && unrecognized_op(&msg)); if (refused(&msg)) return REFUSED; if (cec_msg_status_is_abort(&msg)) return PRESUMED_OK; if (opcode == CEC_MSG_IMAGE_VIEW_ON) node->remote[la].has_image_view_on = true; else if (opcode == CEC_MSG_TEXT_VIEW_ON) node->remote[la].has_text_view_on = true; return 0; }
static int wakeup_tv(struct node *node, unsigned me, unsigned la) { struct cec_msg msg = {}; cec_msg_init(&msg, me, la); cec_msg_image_view_on(&msg); msg.timeout = 2000; int res = doioctl(node, CEC_TRANSMIT, &msg); if (res == ENONET && la == CEC_LOG_ADDR_TV) { msg.msg[0] = (CEC_LOG_ADDR_UNREGISTERED << 4) | la; res = doioctl(node, CEC_TRANSMIT, &msg); } fail_on_test(res || !(msg.tx_status & CEC_TX_STATUS_OK)); if (!cec_msg_status_is_abort(&msg)) return 0; cec_msg_init(&msg, me, la); cec_msg_text_view_on(&msg); fail_on_test(!transmit_timeout(node, &msg)); if (!cec_msg_status_is_abort(&msg)) return 0; return wakeup_rc(node, me, la); }
static int checkModulator(struct node *node, const struct v4l2_modulator &mod, unsigned m) { bool tv = !node->is_radio; if (mod.index != m) return fail("invalid index\n"); if (check_ustring(mod.name, sizeof(mod.name))) return fail("invalid name\n"); if (check_0(mod.reserved, sizeof(mod.reserved))) return fail("non-zero reserved fields\n"); if (tv) return fail("currently only radio modulators are supported\n"); if (!(mod.capability & V4L2_TUNER_CAP_LOW)) return fail("V4L2_TUNER_CAP_LOW was not set for a radio modulator\n"); if (mod.capability & (V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2)) return fail("TV capabilities for radio modulator?\n"); fail_on_test(!(mod.capability & V4L2_TUNER_CAP_FREQ_BANDS)); if (mod.rangelow >= mod.rangehigh) return fail("rangelow >= rangehigh\n"); if (mod.rangelow == 0 || mod.rangehigh == 0xffffffff) return fail("invalid rangelow or rangehigh\n"); if (!(mod.capability & V4L2_TUNER_CAP_STEREO) && (mod.txsubchans & V4L2_TUNER_SUB_STEREO)) return fail("stereo subchan, but no stereo caps?\n"); if (!(mod.capability & V4L2_TUNER_CAP_LANG1) && (mod.txsubchans & V4L2_TUNER_SUB_LANG1)) return fail("lang1 subchan, but no lang1 caps?\n"); if (!(mod.capability & V4L2_TUNER_CAP_LANG2) && (mod.txsubchans & V4L2_TUNER_SUB_LANG2)) return fail("lang2 subchan, but no lang2 caps?\n"); if (!(mod.capability & V4L2_TUNER_CAP_RDS) && (mod.txsubchans & V4L2_TUNER_SUB_RDS)) return fail("RDS subchan, but no RDS caps?\n"); bool have_rds = mod.capability & V4L2_TUNER_CAP_RDS; bool have_rds_method = mod.capability & (V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_RDS_CONTROLS); if (have_rds ^ have_rds_method) return fail("V4L2_TUNER_CAP_RDS is set, but not V4L2_TUNER_CAP_RDS_* or vice versa\n"); if ((mod.capability & V4L2_TUNER_CAP_RDS_BLOCK_IO) && !(node->caps & V4L2_CAP_READWRITE)) return fail("V4L2_TUNER_CAP_RDS_BLOCK_IO is set, but not V4L2_CAP_READWRITE\n"); if (!(mod.capability & V4L2_TUNER_CAP_RDS_BLOCK_IO) && (node->caps & V4L2_CAP_READWRITE)) return fail("V4L2_TUNER_CAP_RDS_BLOCK_IO is not set, but V4L2_CAP_READWRITE is\n"); return checkEnumFreqBands(node, mod.index, V4L2_TUNER_RADIO, mod.capability); }