Re: [PATCHv3 10/13] hackrf: add support for transmitter

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

 



Some comments below:

On 07/31/2015 04:10 AM, Antti Palosaari wrote:
> HackRF SDR device has both receiver and transmitter. There is limitation
> that receiver and transmitter cannot be used at the same time
> (half-duplex operation). That patch implements transmitter support to
> existing receiver only driver.
> 
> Cc: Hans Verkuil <hverkuil@xxxxxxxxx>
> Signed-off-by: Antti Palosaari <crope@xxxxxx>
> ---
>  drivers/media/usb/hackrf/hackrf.c | 894 ++++++++++++++++++++++++++------------
>  1 file changed, 627 insertions(+), 267 deletions(-)
> 
> diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
> index 5bd291b..f4b5606 100644
> --- a/drivers/media/usb/hackrf/hackrf.c
> +++ b/drivers/media/usb/hackrf/hackrf.c

<snip>

> @@ -748,15 +925,11 @@ static int hackrf_s_fmt_sdr_cap(struct file *file, void *priv,
>  		struct v4l2_format *f)
>  {
>  	struct hackrf_dev *dev = video_drvdata(file);
> -	struct vb2_queue *q = &dev->vb_queue;
>  	int i;
>  
>  	dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
>  			(char *)&f->fmt.sdr.pixelformat);
>  
> -	if (vb2_is_busy(q))
> -		return -EBUSY;
> -

Why is this removed?

>  	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
>  	for (i = 0; i < NUM_FORMATS; i++) {
>  		if (f->fmt.sdr.pixelformat == formats[i].pixelformat) {
> @@ -856,17 +1029,64 @@ static int hackrf_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
>  
>  	if (v->index == 0) {
>  		strlcpy(v->name, "HackRF ADC", sizeof(v->name));
> -		v->type = V4L2_TUNER_ADC;
> +		v->type = V4L2_TUNER_SDR;
>  		v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
> -		v->rangelow  = bands_adc[0].rangelow;
> -		v->rangehigh = bands_adc[0].rangehigh;
> +		v->rangelow  = bands_adc_dac[0].rangelow;
> +		v->rangehigh = bands_adc_dac[0].rangehigh;
>  		ret = 0;
>  	} else if (v->index == 1) {
> -		strlcpy(v->name, "HackRF RF", sizeof(v->name));
> +		strlcpy(v->name, "HackRF RF RX", sizeof(v->name));

This seems unnecessary. You're calling g_tuner, so it is obvious that it is RX.
I'd keep the name as "HackRF RF".

>  		v->type = V4L2_TUNER_RF;
>  		v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
> -		v->rangelow  = bands_rf[0].rangelow;
> -		v->rangehigh = bands_rf[0].rangehigh;
> +		v->rangelow  = bands_rx_tx[0].rangelow;
> +		v->rangehigh = bands_rx_tx[0].rangehigh;
> +		ret = 0;
> +	} else {
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +static int hackrf_s_modulator(struct file *file, void *fh,
> +		       const struct v4l2_modulator *a)
> +{
> +	struct hackrf_dev *dev = video_drvdata(file);
> +	int ret;
> +
> +	dev_dbg(dev->dev, "index=%d\n", a->index);
> +
> +	if (a->index == 0)
> +		ret = 0;
> +	else if (a->index == 1)
> +		ret = 0;
> +	else
> +		ret = -EINVAL;
> +
> +	return ret;

I'd just write:

	return a->index > 1 ? -EINVAL : 0;

More to the point, why implement this at all? At the moment s_modulator is meaningless
since there is nothing to set.

> +}
> +
> +static int hackrf_g_modulator(struct file *file, void *fh,
> +			      struct v4l2_modulator *a)
> +{
> +	struct hackrf_dev *dev = video_drvdata(file);
> +	int ret;
> +
> +	dev_dbg(dev->dev, "index=%d\n", a->index);
> +
> +	if (a->index == 0) {
> +		strlcpy(a->name, "HackRF DAC", sizeof(a->name));
> +		a->type = V4L2_TUNER_SDR;
> +		a->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
> +		a->rangelow  = bands_adc_dac[0].rangelow;
> +		a->rangehigh = bands_adc_dac[0].rangehigh;
> +		ret = 0;
> +	} else if (a->index == 1) {
> +		strlcpy(a->name, "HackRF RF TX", sizeof(a->name));

Same as with g_tuner: I'd drop the "TX" part in the name.

> +		a->type = V4L2_TUNER_RF;
> +		a->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
> +		a->rangelow  = bands_rx_tx[0].rangelow;
> +		a->rangehigh = bands_rx_tx[0].rangehigh;
>  		ret = 0;
>  	} else {
>  		ret = -EINVAL;

<snip>

> @@ -969,6 +1213,11 @@ static const struct v4l2_ioctl_ops hackrf_ioctl_ops = {
>  	.vidioc_enum_fmt_sdr_cap  = hackrf_enum_fmt_sdr_cap,
>  	.vidioc_try_fmt_sdr_cap   = hackrf_try_fmt_sdr_cap,
>  
> +	.vidioc_s_fmt_sdr_out     = hackrf_s_fmt_sdr_cap,
> +	.vidioc_g_fmt_sdr_out     = hackrf_g_fmt_sdr_cap,
> +	.vidioc_enum_fmt_sdr_out  = hackrf_enum_fmt_sdr_cap,
> +	.vidioc_try_fmt_sdr_out   = hackrf_try_fmt_sdr_cap,
> +

Since hackrf_*_fmt_sdr_cap is used for both capture and output I suggest that
those functions are renamed to hackrf_*_fmt_sdr(), dropping the "_cap" part.

>  	.vidioc_reqbufs           = vb2_ioctl_reqbufs,
>  	.vidioc_create_bufs       = vb2_ioctl_create_bufs,
>  	.vidioc_prepare_buf       = vb2_ioctl_prepare_buf,
> @@ -982,6 +1231,9 @@ static const struct v4l2_ioctl_ops hackrf_ioctl_ops = {
>  	.vidioc_s_tuner           = hackrf_s_tuner,
>  	.vidioc_g_tuner           = hackrf_g_tuner,
>  
> +	.vidioc_s_modulator       = hackrf_s_modulator,
> +	.vidioc_g_modulator       = hackrf_g_modulator,
> +
>  	.vidioc_s_frequency       = hackrf_s_frequency,
>  	.vidioc_g_frequency       = hackrf_g_frequency,
>  	.vidioc_enum_freq_bands   = hackrf_enum_freq_bands,
> @@ -996,6 +1248,7 @@ static const struct v4l2_file_operations hackrf_fops = {
>  	.open                     = v4l2_fh_open,
>  	.release                  = vb2_fop_release,
>  	.read                     = vb2_fop_read,
> +	.write                    = vb2_fop_write,
>  	.poll                     = vb2_fop_poll,
>  	.mmap                     = vb2_fop_mmap,
>  	.unlocked_ioctl           = video_ioctl2,

<snip>

> @@ -1089,85 +1393,141 @@ static int hackrf_probe(struct usb_interface *intf,
>  				buf, BUF_SIZE);
>  	if (ret) {
>  		dev_err(dev->dev, "Could not detect board\n");
> -		goto err_free_mem;
> +		goto err_kfree;
>  	}
>  
>  	buf[BUF_SIZE - 1] = '\0';
> -
>  	dev_info(dev->dev, "Board ID: %02x\n", u8tmp);
>  	dev_info(dev->dev, "Firmware version: %s\n", buf);
>  
> -	/* Init videobuf2 queue structure */
> -	dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
> -	dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
> -	dev->vb_queue.drv_priv = dev;
> -	dev->vb_queue.buf_struct_size = sizeof(struct hackrf_frame_buf);
> -	dev->vb_queue.ops = &hackrf_vb2_ops;
> -	dev->vb_queue.mem_ops = &vb2_vmalloc_memops;
> -	dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> -	ret = vb2_queue_init(&dev->vb_queue);
> +	/* Init vb2 queue structure for receiver */
> +	dev->rx_vb2_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
> +	dev->rx_vb2_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;

I suggest that you add VB2_DMABUF here and for tx_vb2_queue.io_modes.

I see no reason to leave that out.

Also add .vidioc_expbuf = vb2_ioctl_expbuf to the ioctl ops.

> +	dev->rx_vb2_queue.ops = &hackrf_vb2_ops;
> +	dev->rx_vb2_queue.mem_ops = &vb2_vmalloc_memops;
> +	dev->rx_vb2_queue.drv_priv = dev;
> +	dev->rx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer);
> +	dev->rx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> +	ret = vb2_queue_init(&dev->rx_vb2_queue);
> +	if (ret) {
> +		dev_err(dev->dev, "Could not initialize rx vb2 queue\n");
> +		goto err_kfree;
> +	}
> +
> +	/* Init vb2 queue structure for transmitter */
> +	dev->tx_vb2_queue.type = V4L2_BUF_TYPE_SDR_OUTPUT;
> +	dev->tx_vb2_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_WRITE;
> +	dev->tx_vb2_queue.ops = &hackrf_vb2_ops;
> +	dev->tx_vb2_queue.mem_ops = &vb2_vmalloc_memops;
> +	dev->tx_vb2_queue.drv_priv = dev;
> +	dev->tx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer);
> +	dev->tx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> +	ret = vb2_queue_init(&dev->tx_vb2_queue);
>  	if (ret) {
> -		dev_err(dev->dev, "Could not initialize vb2 queue\n");
> -		goto err_free_mem;
> +		dev_err(dev->dev, "Could not initialize tx vb2 queue\n");
> +		goto err_kfree;
>  	}
>  
> -	/* Init video_device structure */
> -	dev->vdev = hackrf_template;
> -	dev->vdev.queue = &dev->vb_queue;
> -	dev->vdev.queue->lock = &dev->vb_queue_lock;
> -	video_set_drvdata(&dev->vdev, dev);
> +	/* Register controls for receiver */
> +	v4l2_ctrl_handler_init(&dev->rx_ctrl_handler, 5);
> +	dev->rx_bandwidth_auto = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
> +		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
> +		0, 1, 0, 1);
> +	dev->rx_bandwidth = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
> +		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_BANDWIDTH,
> +		1750000, 28000000, 50000, 1750000);
> +	v4l2_ctrl_auto_cluster(2, &dev->rx_bandwidth_auto, 0, false);
> +	dev->rx_rf_gain = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
> +		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_RF_GAIN, 0, 12, 12, 0);
> +	dev->rx_lna_gain = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
> +		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
> +	dev->rx_if_gain = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
> +		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_IF_GAIN, 0, 62, 2, 0);
> +	if (dev->rx_ctrl_handler.error) {
> +		ret = dev->rx_ctrl_handler.error;
> +		dev_err(dev->dev, "Could not initialize controls\n");
> +		goto err_v4l2_ctrl_handler_free_rx;
> +	}
> +	v4l2_ctrl_handler_setup(&dev->rx_ctrl_handler);
> +
> +	/* Register controls for transmitter */
> +	v4l2_ctrl_handler_init(&dev->tx_ctrl_handler, 4);
> +	dev->tx_bandwidth_auto = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
> +		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
> +		0, 1, 0, 1);
> +	dev->tx_bandwidth = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
> +		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_BANDWIDTH,
> +		1750000, 28000000, 50000, 1750000);
> +	v4l2_ctrl_auto_cluster(2, &dev->tx_bandwidth_auto, 0, false);
> +	dev->tx_lna_gain = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
> +		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_LNA_GAIN, 0, 47, 1, 0);
> +	dev->tx_rf_gain = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
> +		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_RF_GAIN, 0, 15, 15, 0);
> +	if (dev->tx_ctrl_handler.error) {
> +		ret = dev->tx_ctrl_handler.error;
> +		dev_err(dev->dev, "Could not initialize controls\n");
> +		goto err_v4l2_ctrl_handler_free_tx;
> +	}
> +	v4l2_ctrl_handler_setup(&dev->tx_ctrl_handler);
>  
>  	/* Register the v4l2_device structure */
>  	dev->v4l2_dev.release = hackrf_video_release;
>  	ret = v4l2_device_register(&intf->dev, &dev->v4l2_dev);
>  	if (ret) {
>  		dev_err(dev->dev, "Failed to register v4l2-device (%d)\n", ret);
> -		goto err_free_mem;
> +		goto err_v4l2_ctrl_handler_free_tx;
>  	}
>  
> -	/* Register controls */
> -	v4l2_ctrl_handler_init(&dev->hdl, 5);
> -	dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> -			V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
> -	dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> -			V4L2_CID_RF_TUNER_BANDWIDTH,
> -			1750000, 28000000, 50000, 1750000);
> -	v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
> -	dev->rf_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> -			V4L2_CID_RF_TUNER_RF_GAIN, 0, 12, 12, 0);
> -	dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> -			V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
> -	dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> -			V4L2_CID_RF_TUNER_IF_GAIN, 0, 62, 2, 0);
> -	if (dev->hdl.error) {
> -		ret = dev->hdl.error;
> -		dev_err(dev->dev, "Could not initialize controls\n");
> -		goto err_free_controls;
> +	/* Init video_device structure for receiver */
> +	dev->rx_vdev = hackrf_template;
> +	dev->rx_vdev.queue = &dev->rx_vb2_queue;
> +	dev->rx_vdev.queue->lock = &dev->vb_queue_lock;
> +	dev->rx_vdev.v4l2_dev = &dev->v4l2_dev;
> +	dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler;
> +	dev->rx_vdev.lock = &dev->v4l2_lock;
> +	dev->rx_vdev.vfl_dir = VFL_DIR_RX;
> +	video_set_drvdata(&dev->rx_vdev, dev);
> +	ret = video_register_device(&dev->rx_vdev, VFL_TYPE_SDR, -1);
> +	if (ret) {
> +		dev_err(dev->dev,
> +			"Failed to register as video device (%d)\n", ret);
> +		goto err_v4l2_device_unregister;
>  	}
> -
> -	v4l2_ctrl_handler_setup(&dev->hdl);
> -
> -	dev->v4l2_dev.ctrl_handler = &dev->hdl;
> -	dev->vdev.v4l2_dev = &dev->v4l2_dev;
> -	dev->vdev.lock = &dev->v4l2_lock;
> -
> -	ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
> +	dev_info(dev->dev, "Registered as %s\n",
> +		 video_device_node_name(&dev->rx_vdev));
> +
> +	/* Init video_device structure for transmitter */
> +	dev->tx_vdev = hackrf_template;
> +	dev->tx_vdev.queue = &dev->tx_vb2_queue;
> +	dev->tx_vdev.queue->lock = &dev->vb_queue_lock;
> +	dev->tx_vdev.v4l2_dev = &dev->v4l2_dev;
> +	dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler;
> +	dev->tx_vdev.lock = &dev->v4l2_lock;
> +	dev->tx_vdev.vfl_dir = VFL_DIR_TX;
> +	video_set_drvdata(&dev->tx_vdev, dev);
> +	ret = video_register_device(&dev->tx_vdev, VFL_TYPE_SDR, -1);
>  	if (ret) {
> -		dev_err(dev->dev, "Failed to register as video device (%d)\n",
> -				ret);
> -		goto err_unregister_v4l2_dev;
> +		dev_err(dev->dev,
> +			"Failed to register as video device (%d)\n", ret);
> +		goto err_video_unregister_device_rx;
>  	}
>  	dev_info(dev->dev, "Registered as %s\n",
> -			video_device_node_name(&dev->vdev));
> +		 video_device_node_name(&dev->tx_vdev));
> +
>  	dev_notice(dev->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
>  	return 0;
> -
> -err_free_controls:
> -	v4l2_ctrl_handler_free(&dev->hdl);
> -err_unregister_v4l2_dev:
> +err_video_unregister_device_rx:
> +	video_unregister_device(&dev->rx_vdev);
> +err_v4l2_device_unregister:
>  	v4l2_device_unregister(&dev->v4l2_dev);
> -err_free_mem:
> +err_v4l2_ctrl_handler_free_tx:
> +	v4l2_ctrl_handler_free(&dev->tx_ctrl_handler);
> +err_v4l2_ctrl_handler_free_rx:
> +	v4l2_ctrl_handler_free(&dev->rx_ctrl_handler);
> +err_kfree:
>  	kfree(dev);
> +err:
> +	dev_dbg(dev->dev, "failed=%d\n", ret);
>  	return ret;
>  }
>  
> 

Regards,

	Hans
--
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