/* write string property */
static int si4713_write_econtrol_string(struct si4713_device *sdev,
				struct v4l2_ext_control *control)
{
	struct v4l2_queryctrl vqc;
	int len;
	s32 rval = 0;

	vqc.id = control->id;
	rval = si4713_queryctrl(&sdev->sd, &vqc);
	if (rval < 0)
		goto exit;

	switch (control->id) {
	case V4L2_CID_RDS_TX_PS_NAME: {
		char ps_name[MAX_RDS_PS_NAME + 1];

		len = control->size - 1;
		if (len > MAX_RDS_PS_NAME) {
			rval = -ERANGE;
			goto exit;
		}
		rval = copy_from_user(ps_name, control->string, len);
		if (rval < 0)
			goto exit;
		ps_name[len] = '\0';

		if (strlen(ps_name) % vqc.step) {
			rval = -ERANGE;
			goto exit;
		}

		rval = si4713_set_rds_ps_name(sdev, ps_name);
	}
		break;

	case V4L2_CID_RDS_TX_RADIO_TEXT: {
		char radio_text[MAX_RDS_RADIO_TEXT + 1];

		len = control->size - 1;
		if (len > MAX_RDS_RADIO_TEXT) {
			rval = -ERANGE;
			goto exit;
		}
		rval = copy_from_user(radio_text, control->string, len);
		if (rval < 0)
			goto exit;
		radio_text[len] = '\0';

		if (strlen(radio_text) % vqc.step) {
			rval = -ERANGE;
			goto exit;
		}

		rval = si4713_set_rds_radio_text(sdev, radio_text);
	}
		break;

	default:
		rval = -EINVAL;
		break;
	};

exit:
	return rval;
}
Esempio n. 2
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_setup(struct si4713_device *sdev)
{
	struct v4l2_ext_control ctrl;
	struct v4l2_frequency f;
	struct v4l2_modulator vm;
	struct si4713_device *tmp;
	int rval = 0;

	tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
	if (!tmp)
		return -ENOMEM;

	/* Get a local copy to avoid race */
	mutex_lock(&sdev->mutex);
	memcpy(tmp, sdev, sizeof(*sdev));
	mutex_unlock(&sdev->mutex);

	ctrl.id = V4L2_CID_RDS_TX_PI;
	ctrl.value = tmp->rds_info.pi;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_AUDIO_COMPRESSION_THRESHOLD;
	ctrl.value = tmp->acomp_info.threshold;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_AUDIO_COMPRESSION_GAIN;
	ctrl.value = tmp->acomp_info.gain;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_PILOT_TONE_FREQUENCY;
	ctrl.value = tmp->pilot_info.frequency;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME;
	ctrl.value = tmp->acomp_info.attack_time;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_PILOT_TONE_DEVIATION;
	ctrl.value = tmp->pilot_info.deviation;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_AUDIO_LIMITER_DEVIATION;
	ctrl.value = tmp->limiter_info.deviation;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_RDS_TX_DEVIATION;
	ctrl.value = tmp->rds_info.deviation;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_RDS_TX_PTY;
	ctrl.value = tmp->rds_info.pty;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_AUDIO_LIMITER_ENABLED;
	ctrl.value = tmp->limiter_info.enabled;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_AUDIO_COMPRESSION_ENABLED;
	ctrl.value = tmp->acomp_info.enabled;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_PILOT_TONE_ENABLED;
	ctrl.value = tmp->pilot_info.enabled;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_AUDIO_LIMITER_RELEASE_TIME;
	ctrl.value = tmp->limiter_info.release_time;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME;
	ctrl.value = tmp->acomp_info.release_time;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_TUNE_PREEMPHASIS;
	ctrl.value = tmp->preemphasis;
	rval |= si4713_write_econtrol_integers(sdev, &ctrl);

	ctrl.id = V4L2_CID_RDS_TX_PS_NAME;
	rval |= si4713_set_rds_ps_name(sdev, tmp->rds_info.ps_name);

	ctrl.id = V4L2_CID_RDS_TX_RADIO_TEXT;
	rval |= si4713_set_rds_radio_text(sdev, tmp->rds_info.radio_text);

	/* Device procedure needs to set frequency first */
	f.frequency = tmp->frequency ? tmp->frequency : DEFAULT_FREQUENCY;
	f.frequency = si4713_to_v4l2(f.frequency);
	rval |= si4713_s_frequency(&sdev->sd, &f);

	ctrl.id = V4L2_CID_TUNE_POWER_LEVEL;
	ctrl.value = tmp->power_level;
	rval |= si4713_write_econtrol_tune(sdev, &ctrl);

	ctrl.id = V4L2_CID_TUNE_ANTENNA_CAPACITOR;
	ctrl.value = tmp->antenna_capacitor;
	rval |= si4713_write_econtrol_tune(sdev, &ctrl);

	vm.index = 0;
	if (tmp->stereo)
		vm.txsubchans = V4L2_TUNER_SUB_STEREO;
	else
		vm.txsubchans = V4L2_TUNER_SUB_MONO;
	if (tmp->rds_info.enabled)
		vm.txsubchans |= V4L2_TUNER_SUB_RDS;
	si4713_s_modulator(&sdev->sd, &vm);

	kfree(tmp);

	return rval;
}