Re: [PATCH v5 4/5] V4L2: WL1273 FM Radio: Controls for the FM radio.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Friday 16 July 2010 12:27:46 Matti J. Aaltonen wrote:
> This file implements V4L2 controls for using the Texas Instruments
> WL1273 FM Radio.
> 
> Signed-off-by: Matti J. Aaltonen <matti.j.aaltonen@xxxxxxxxx>

<snip>

> +
> +static unsigned int wl1273_fm_fops_poll(struct file *file,
> +					struct poll_table_struct *pts)
> +{
> +	struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
> +	struct wl1273_core *core = radio->core;
> +	unsigned int rd_index, wr_index;
> +
> +	if (radio->owner && radio->owner != file)
> +		return -EBUSY;
> +
> +	radio->owner = file;
> +	poll_wait(file, &core->read_queue, pts);
> +
> +	rd_index = core->rd_index;
> +	wr_index = core->wr_index;
> +	if (rd_index != wr_index)
> +		return POLLIN | POLLOUT | POLLRDNORM;

You also need to add POLLWRNORM.

I wonder if this code is correct. Doesn't this depend on whether the device
is in receive or transmit mode? So either poll returns POLLIN|POLLRDNORM or
POLLOUT|POLLWRNORM. Or am I missing something?

> +
> +	return 0;
> +}

<snip>

> +#define WL1273_RDS_NOT_SYNCHRONIZED 0
> +#define WL1273_RDS_SYNCHRONIZED 1
> +
> +static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv,
> +				    struct v4l2_tuner *tuner)
> +{
> +	struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
> +	struct wl1273_core *core = radio->core;
> +	u16 val;
> +	int r;
> +
> +	dev_dbg(radio->dev, "%s\n", __func__);
> +
> +	if (tuner->index > 0)
> +		return -EINVAL;
> +
> +	strcpy(tuner->name, WL1273_FM_DRIVER_NAME);

strlcpy

> +	tuner->type = V4L2_TUNER_RADIO;
> +
> +	tuner->rangelow	=
> +		WL1273_FREQ(core->bands[core->band].bottom_frequency);
> +	tuner->rangehigh =
> +		WL1273_FREQ(core->bands[core->band].top_frequency);
> +
> +	tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;

You can't detect whether mono or stereo is received? Does the alsa codec always
receive two channel audio? How does it handle mono vs stereo?

> +	tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS;

Shouldn't CAP_STEREO be added?

> +
> +	if (core->mode != WL1273_MODE_RX)
> +		return 0;
> +
> +	if (mutex_lock_interruptible(&core->lock))
> +		return -EINTR;
> +
> +	r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &val);
> +	if (r)
> +		goto out;
> +
> +	tuner->signal = (s16) val;
> +	dev_dbg(radio->dev, "Signal: %d\n", tuner->signal);
> +
> +	tuner->afc = 0;
> +
> +	r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
> +	if (r)
> +		goto out;
> +
> +	if (val == WL1273_RDS_SYNCHRONIZED)
> +		tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;

tuner->audmode isn't filled!

> +out:
> +	mutex_unlock(&core->lock);
> +
> +	return r;
> +}
> +
> +static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv,
> +				    struct v4l2_tuner *tuner)
> +{
> +	struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
> +	struct wl1273_core *core = radio->core;
> +	int r = 0;
> +
> +	dev_dbg(radio->dev, "%s\n", __func__);
> +	dev_dbg(radio->dev, "tuner->index: %d\n", tuner->index);
> +	dev_dbg(radio->dev, "tuner->name: %s\n", tuner->name);
> +	dev_dbg(radio->dev, "tuner->capability: 0x%04x\n", tuner->capability);
> +	dev_dbg(radio->dev, "tuner->rxsubchans: 0x%04x\n", tuner->rxsubchans);
> +	dev_dbg(radio->dev, "tuner->rangelow: %d\n", tuner->rangelow);
> +	dev_dbg(radio->dev, "tuner->rangehigh: %d\n", tuner->rangehigh);
> +
> +	if (tuner->index > 0)
> +		return -EINVAL;
> +
> +	if (mutex_lock_interruptible(&core->lock))
> +		return -EINTR;
> +
> +	r = wl1273_fm_set_mode(core, WL1273_MODE_RX);
> +	if (r)
> +		goto out;
> +
> +	if (tuner->rxsubchans & V4L2_TUNER_SUB_RDS)
> +		r = wl1273_fm_set_rds(core, WL1273_RDS_ON);
> +	else
> +		r = wl1273_fm_set_rds(core, WL1273_RDS_OFF);
> +
> +	if (r)
> +		dev_warn(radio->dev, "%s: RDS fails: %d\n", __func__, r);
> +
> +	if (tuner->audmode == V4L2_TUNER_MODE_MONO)
> +		r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
> +					WL1273_RX_MONO);
> +	else
> +		r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
> +					WL1273_RX_STEREO);
> +	if (r < 0)
> +		dev_warn(radio->dev, WL1273_FM_DRIVER_NAME
> +			 ": set tuner mode failed with %d\n", r);
> +out:
> +	mutex_unlock(&core->lock);
> +
> +	return r;
> +}
> +
> +static int wl1273_fm_vidioc_g_frequency(struct file *file, void *priv,
> +					struct v4l2_frequency *freq)
> +{
> +	struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
> +	struct wl1273_core *core = radio->core;
> +
> +	dev_dbg(radio->dev, "%s\n", __func__);
> +
> +	if (mutex_lock_interruptible(&core->lock))
> +		return -EINTR;
> +
> +	freq->type = V4L2_TUNER_RADIO;
> +	freq->frequency = WL1273_FREQ(wl1273_fm_get_freq(core));
> +
> +	mutex_unlock(&core->lock);
> +
> +	return 0;
> +}
> +
> +static int wl1273_fm_vidioc_s_frequency(struct file *file, void *priv,
> +					struct v4l2_frequency *freq)
> +{
> +	struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
> +	struct wl1273_core *core = radio->core;
> +	int r;
> +
> +	dev_dbg(radio->dev, "%s: %d\n", __func__, freq->frequency);
> +
> +	if (freq->type != V4L2_TUNER_RADIO) {
> +		dev_dbg(radio->dev,
> +			"freq->type != V4L2_TUNER_RADIO: %d\n", freq->type);
> +		return -EINVAL;
> +	}
> +
> +	if (mutex_lock_interruptible(&core->lock))
> +		return -EINTR;
> +
> +	if (core->mode == WL1273_MODE_RX) {
> +		dev_dbg(radio->dev, "freq: %d\n", freq->frequency);
> +
> +		r = wl1273_fm_set_rx_freq(core,
> +					  WL1273_INV_FREQ(freq->frequency));
> +		if (r)
> +			dev_warn(radio->dev, WL1273_FM_DRIVER_NAME
> +				 ": set frequency failed with %d\n", r);
> +	} else {
> +		r = wl1273_fm_set_tx_freq(core,
> +					  WL1273_INV_FREQ(freq->frequency));
> +		if (r)
> +			dev_warn(radio->dev, WL1273_FM_DRIVER_NAME
> +				 ": set frequency failed with %d\n", r);
> +	}
> +
> +	mutex_unlock(&core->lock);
> +
> +	dev_dbg(radio->dev, "wl1273_vidioc_s_frequency: DONE\n");
> +	return r;
> +}
> +
> +#define WL1273_DEFAULT_SEEK_LEVEL	7
> +
> +static int wl1273_fm_vidioc_s_hw_freq_seek(struct file *file, void *priv,
> +					   struct v4l2_hw_freq_seek *seek)
> +{
> +	struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
> +	struct wl1273_core *core = radio->core;
> +	int r;
> +
> +	dev_dbg(radio->dev, "%s\n", __func__);
> +
> +	if (seek->tuner != 0 || seek->type != V4L2_TUNER_RADIO)
> +		return -EINVAL;
> +
> +	if (mutex_lock_interruptible(&core->lock))
> +		return -EINTR;
> +
> +	r = wl1273_fm_set_mode(core, WL1273_MODE_RX);
> +	if (r)
> +		goto out;
> +
> +	r = wl1273_fm_tx_set_spacing(core, seek->spacing);
> +	if (r)
> +		dev_warn(radio->dev, "HW seek failed: %d\n", r);
> +
> +	r = wl1273_fm_set_seek(core, seek->wrap_around, seek->seek_upward,
> +			       WL1273_DEFAULT_SEEK_LEVEL);
> +	if (r)
> +		dev_warn(radio->dev, "HW seek failed: %d\n", r);
> +
> +	mutex_unlock(&core->lock);
> + out:
> +	return r;
> +}
> +
> +static int wl1273_fm_vidioc_s_modulator(struct file *file, void *priv,
> +					struct v4l2_modulator *modulator)
> +{
> +	struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
> +	struct wl1273_core *core = radio->core;
> +	int r = 0;
> +
> +	dev_dbg(radio->dev, "%s\n", __func__);
> +
> +	if (modulator->index > 0)
> +		return -EINVAL;
> +
> +	if (mutex_lock_interruptible(&core->lock))
> +		return -EINTR;
> +
> +	r = wl1273_fm_set_mode(core, WL1273_MODE_TX);
> +	if (r)
> +		goto out;
> +
> +	if (modulator->txsubchans & V4L2_TUNER_SUB_RDS)
> +		r = wl1273_fm_set_rds(core, WL1273_RDS_ON);
> +	else
> +		r = wl1273_fm_set_rds(core, WL1273_RDS_OFF);

There is no support for SUB_MONO or SUB_STEREO?

> +
> +out:
> +	mutex_unlock(&core->lock);
> +
> +	return r;
> +}
> +
> +static int wl1273_fm_vidioc_g_modulator(struct file *file, void *priv,
> +					struct v4l2_modulator *modulator)
> +{
> +	struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
> +	struct wl1273_core *core = radio->core;
> +
> +	dev_dbg(radio->dev, "%s\n", __func__);
> +
> +	if (mutex_lock_interruptible(&core->lock))
> +		return -EINTR;
> +
> +	strcpy(modulator->name, WL1273_FM_DRIVER_NAME);
> +
> +	modulator->rangelow =
> +		WL1273_FREQ(core->bands[core->band].bottom_frequency);
> +	modulator->rangehigh =
> +		WL1273_FREQ(core->bands[core->band].top_frequency);
> +
> +	modulator->capability = V4L2_TUNER_CAP_RDS;

Shouldn't CAP_LOW and CAP_STEREO be added here?

> +
> +	if (core->rds_on)
> +		modulator->txsubchans |= V4L2_TUNER_SUB_RDS;
> +	else
> +		modulator->txsubchans &= ~V4L2_TUNER_SUB_RDS;

The SUB_MONO/SUB_STEREO flags aren't handled here.

> +
> +	mutex_unlock(&core->lock);
> +
> +	return 0;
> +}
> +

The g/s_tuner and g/s_modulator functions are always hard to get right. Lots of
tricky flags and settings...

Regards,

	Hans

-- 
Hans Verkuil - video4linux developer - sponsored by TANDBERG, part of Cisco
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux