Esempio n. 1
0
/* si4713_s_ctrl - set the value of a control */
static int si4713_s_ctrl(struct v4l2_ctrl *ctrl)
{
	struct si4713_device *sdev =
		container_of(ctrl->handler, struct si4713_device, ctrl_handler);
	u32 val = 0;
	s32 bit = 0, mask = 0;
	u16 property = 0;
	int mul = 0;
	unsigned long *table = NULL;
	int size = 0;
	bool force = false;
	int c;
	int ret = 0;

	if (ctrl->id != V4L2_CID_AUDIO_MUTE)
		return -EINVAL;
	if (ctrl->is_new) {
		if (ctrl->val) {
			ret = si4713_set_mute(sdev, ctrl->val);
			if (!ret)
				ret = si4713_set_power_state(sdev, POWER_DOWN);
			return ret;
		}
		ret = si4713_set_power_state(sdev, POWER_UP);
		if (!ret)
			ret = si4713_set_mute(sdev, ctrl->val);
		if (!ret)
			ret = si4713_setup(sdev);
		if (ret)
			return ret;
		force = true;
	}

	if (!sdev->power_state)
		return 0;

	for (c = 1; !ret && c < ctrl->ncontrols; c++) {
		ctrl = ctrl->cluster[c];

		if (!force && !ctrl->is_new)
			continue;

		switch (ctrl->id) {
		case V4L2_CID_RDS_TX_PS_NAME:
			ret = si4713_set_rds_ps_name(sdev, ctrl->string);
			break;

		case V4L2_CID_RDS_TX_RADIO_TEXT:
			ret = si4713_set_rds_radio_text(sdev, ctrl->string);
			break;

		case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
			/* don't handle this control if we force setting all
			 * controls since in that case it will be handled by
			 * V4L2_CID_TUNE_POWER_LEVEL. */
			if (force)
				break;
			/* fall through */
		case V4L2_CID_TUNE_POWER_LEVEL:
			ret = si4713_tx_tune_power(sdev,
				sdev->tune_pwr_level->val, sdev->tune_ant_cap->val);
			if (!ret) {
				/* Make sure we don't set this twice */
				sdev->tune_ant_cap->is_new = false;
				sdev->tune_pwr_level->is_new = false;
			}
			break;

		default:
			ret = si4713_choose_econtrol_action(sdev, ctrl->id, &bit,
					&mask, &property, &mul, &table, &size);
			if (ret < 0)
				break;

			val = ctrl->val;
			if (mul) {
				val = val / mul;
			} else if (table) {
				ret = usecs_to_dev(val, table, size);
				if (ret < 0)
					break;
				val = ret;
				ret = 0;
			}

			if (mask) {
				ret = si4713_read_property(sdev, property, &val);
				if (ret < 0)
					break;
				val = set_bits(val, ctrl->val, bit, mask);
			}

			ret = si4713_write_property(sdev, property, val);
			if (ret < 0)
				break;
			if (mask)
				val = ctrl->val;
			break;
		}
	}

	return ret;
}
static int si4713_write_econtrol_integers(struct si4713_device *sdev,
					struct v4l2_ext_control *control)
{
	s32 rval;
	u32 *shadow = NULL, val = 0;
	s32 bit = 0, mask = 0;
	u16 property = 0;
	int mul = 0;
	unsigned long *table = NULL;
	int size = 0;

	rval = validate_range(&sdev->sd, control);
	if (rval < 0)
		goto exit;

	rval = si4713_choose_econtrol_action(sdev, control->id, &shadow, &bit,
			&mask, &property, &mul, &table, &size);
	if (rval < 0)
		goto exit;

	val = control->value;
	if (mul) {
		val = control->value / mul;
	} else if (table) {
		rval = usecs_to_dev(control->value, table, size);
		if (rval < 0)
			goto exit;
		val = rval;
		rval = 0;
	}

	mutex_lock(&sdev->mutex);

	if (sdev->power_state) {
		if (mask) {
			rval = si4713_read_property(sdev, property, &val);
			if (rval < 0)
				goto unlock;
			val = set_bits(val, control->value, bit, mask);
		}

		rval = si4713_write_property(sdev, property, val);
		if (rval < 0)
			goto unlock;
		if (mask)
			val = control->value;
	}

	if (mul) {
		*shadow = val * mul;
	} else if (table) {
		rval = dev_to_usecs(val, table, size);
		if (rval < 0)
			goto unlock;
		*shadow = rval;
		rval = 0;
	} else {
		*shadow = val;
	}

unlock:
	mutex_unlock(&sdev->mutex);
exit:
	return rval;
}