1 // SPDX-License-Identifier: GPL-2.0-only
3 * vivid-radio-tx.c - radio transmitter support functions.
5 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
8 #include <linux/errno.h>
9 #include <linux/kernel.h>
10 #include <linux/sched/signal.h>
11 #include <linux/delay.h>
12 #include <linux/videodev2.h>
13 #include <linux/v4l2-dv-timings.h>
14 #include <media/v4l2-common.h>
15 #include <media/v4l2-event.h>
16 #include <media/v4l2-dv-timings.h>
18 #include "vivid-core.h"
19 #include "vivid-ctrls.h"
20 #include "vivid-radio-common.h"
21 #include "vivid-radio-tx.h"
23 ssize_t
vivid_radio_tx_write(struct file
*file
, const char __user
*buf
,
24 size_t size
, loff_t
*offset
)
26 struct vivid_dev
*dev
= video_drvdata(file
);
27 struct v4l2_rds_data
*data
= dev
->rds_gen
.data
;
32 if (dev
->radio_tx_rds_controls
)
35 if (size
< sizeof(*data
))
37 size
= sizeof(*data
) * (size
/ sizeof(*data
));
39 if (mutex_lock_interruptible(&dev
->mutex
))
41 if (dev
->radio_tx_rds_owner
&&
42 file
->private_data
!= dev
->radio_tx_rds_owner
) {
43 mutex_unlock(&dev
->mutex
);
46 dev
->radio_tx_rds_owner
= file
->private_data
;
49 timestamp
= ktime_sub(ktime_get(), dev
->radio_rds_init_time
);
50 blk
= ktime_divns(timestamp
, VIVID_RDS_NSEC_PER_BLK
);
51 if (blk
- VIVID_RDS_GEN_BLOCKS
>= dev
->radio_tx_rds_last_block
)
52 dev
->radio_tx_rds_last_block
= blk
- VIVID_RDS_GEN_BLOCKS
+ 1;
55 * No data is available if there hasn't been time to get new data,
56 * or if the RDS receiver has been disabled, or if we use the data
57 * from the RDS transmitter and that RDS transmitter has been disabled,
58 * or if the signal quality is too weak.
60 if (blk
== dev
->radio_tx_rds_last_block
||
61 !(dev
->radio_tx_subchans
& V4L2_TUNER_SUB_RDS
)) {
62 mutex_unlock(&dev
->mutex
);
63 if (file
->f_flags
& O_NONBLOCK
)
65 if (msleep_interruptible(20) && signal_pending(current
))
67 if (mutex_lock_interruptible(&dev
->mutex
))
72 for (i
= 0; i
< size
&& blk
> dev
->radio_tx_rds_last_block
;
73 dev
->radio_tx_rds_last_block
++) {
74 unsigned data_blk
= dev
->radio_tx_rds_last_block
% VIVID_RDS_GEN_BLOCKS
;
75 struct v4l2_rds_data rds
;
77 if (copy_from_user(&rds
, buf
+ i
, sizeof(rds
))) {
82 if (!dev
->radio_rds_loop
)
84 if ((rds
.block
& V4L2_RDS_BLOCK_MSK
) == V4L2_RDS_BLOCK_INVALID
||
85 (rds
.block
& V4L2_RDS_BLOCK_ERROR
))
87 rds
.block
&= V4L2_RDS_BLOCK_MSK
;
90 mutex_unlock(&dev
->mutex
);
94 __poll_t
vivid_radio_tx_poll(struct file
*file
, struct poll_table_struct
*wait
)
96 return EPOLLOUT
| EPOLLWRNORM
| v4l2_ctrl_poll(file
, wait
);
99 int vidioc_g_modulator(struct file
*file
, void *fh
, struct v4l2_modulator
*a
)
101 struct vivid_dev
*dev
= video_drvdata(file
);
106 strscpy(a
->name
, "AM/FM/SW Transmitter", sizeof(a
->name
));
107 a
->capability
= V4L2_TUNER_CAP_LOW
| V4L2_TUNER_CAP_STEREO
|
108 V4L2_TUNER_CAP_FREQ_BANDS
| V4L2_TUNER_CAP_RDS
|
109 (dev
->radio_tx_rds_controls
?
110 V4L2_TUNER_CAP_RDS_CONTROLS
:
111 V4L2_TUNER_CAP_RDS_BLOCK_IO
);
112 a
->rangelow
= AM_FREQ_RANGE_LOW
;
113 a
->rangehigh
= FM_FREQ_RANGE_HIGH
;
114 a
->txsubchans
= dev
->radio_tx_subchans
;
118 int vidioc_s_modulator(struct file
*file
, void *fh
, const struct v4l2_modulator
*a
)
120 struct vivid_dev
*dev
= video_drvdata(file
);
124 if (a
->txsubchans
& ~0x13)
126 dev
->radio_tx_subchans
= a
->txsubchans
;