2 * vivid-radio-common.c - common radio rx/tx support functions.
4 * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6 * This program is free software; you may redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 #include <linux/errno.h>
21 #include <linux/kernel.h>
22 #include <linux/delay.h>
23 #include <linux/videodev2.h>
25 #include "vivid-core.h"
26 #include "vivid-ctrls.h"
27 #include "vivid-radio-common.h"
28 #include "vivid-rds-gen.h"
31 * These functions are shared between the vivid receiver and transmitter
32 * since both use the same frequency bands.
35 const struct v4l2_frequency_band vivid_radio_bands
[TOT_BANDS
] = {
38 .type
= V4L2_TUNER_RADIO
,
40 .capability
= V4L2_TUNER_CAP_LOW
| V4L2_TUNER_CAP_STEREO
|
41 V4L2_TUNER_CAP_FREQ_BANDS
,
42 .rangelow
= FM_FREQ_RANGE_LOW
,
43 .rangehigh
= FM_FREQ_RANGE_HIGH
,
44 .modulation
= V4L2_BAND_MODULATION_FM
,
48 .type
= V4L2_TUNER_RADIO
,
50 .capability
= V4L2_TUNER_CAP_LOW
| V4L2_TUNER_CAP_FREQ_BANDS
,
51 .rangelow
= AM_FREQ_RANGE_LOW
,
52 .rangehigh
= AM_FREQ_RANGE_HIGH
,
53 .modulation
= V4L2_BAND_MODULATION_AM
,
57 .type
= V4L2_TUNER_RADIO
,
59 .capability
= V4L2_TUNER_CAP_LOW
| V4L2_TUNER_CAP_FREQ_BANDS
,
60 .rangelow
= SW_FREQ_RANGE_LOW
,
61 .rangehigh
= SW_FREQ_RANGE_HIGH
,
62 .modulation
= V4L2_BAND_MODULATION_AM
,
67 * Initialize the RDS generator. If we can loop, then the RDS generator
68 * is set up with the values from the RDS TX controls, otherwise it
69 * will fill in standard values using one of two alternates.
71 void vivid_radio_rds_init(struct vivid_dev
*dev
)
73 struct vivid_rds_gen
*rds
= &dev
->rds_gen
;
74 bool alt
= dev
->radio_rx_rds_use_alternates
;
76 /* Do nothing, blocks will be filled by the transmitter */
77 if (dev
->radio_rds_loop
&& !dev
->radio_tx_rds_controls
)
80 if (dev
->radio_rds_loop
) {
81 v4l2_ctrl_lock(dev
->radio_tx_rds_pi
);
82 rds
->picode
= dev
->radio_tx_rds_pi
->cur
.val
;
83 rds
->pty
= dev
->radio_tx_rds_pty
->cur
.val
;
84 rds
->mono_stereo
= dev
->radio_tx_rds_mono_stereo
->cur
.val
;
85 rds
->art_head
= dev
->radio_tx_rds_art_head
->cur
.val
;
86 rds
->compressed
= dev
->radio_tx_rds_compressed
->cur
.val
;
87 rds
->dyn_pty
= dev
->radio_tx_rds_dyn_pty
->cur
.val
;
88 rds
->ta
= dev
->radio_tx_rds_ta
->cur
.val
;
89 rds
->tp
= dev
->radio_tx_rds_tp
->cur
.val
;
90 rds
->ms
= dev
->radio_tx_rds_ms
->cur
.val
;
92 dev
->radio_tx_rds_psname
->p_cur
.p_char
,
94 strlcpy(rds
->radiotext
,
95 dev
->radio_tx_rds_radiotext
->p_cur
.p_char
+ alt
* 64,
96 sizeof(rds
->radiotext
));
97 v4l2_ctrl_unlock(dev
->radio_tx_rds_pi
);
99 vivid_rds_gen_fill(rds
, dev
->radio_rx_freq
, alt
);
101 if (dev
->radio_rx_rds_controls
) {
102 v4l2_ctrl_s_ctrl(dev
->radio_rx_rds_pty
, rds
->pty
);
103 v4l2_ctrl_s_ctrl(dev
->radio_rx_rds_ta
, rds
->ta
);
104 v4l2_ctrl_s_ctrl(dev
->radio_rx_rds_tp
, rds
->tp
);
105 v4l2_ctrl_s_ctrl(dev
->radio_rx_rds_ms
, rds
->ms
);
106 v4l2_ctrl_s_ctrl_string(dev
->radio_rx_rds_psname
, rds
->psname
);
107 v4l2_ctrl_s_ctrl_string(dev
->radio_rx_rds_radiotext
, rds
->radiotext
);
108 if (!dev
->radio_rds_loop
)
109 dev
->radio_rx_rds_use_alternates
= !dev
->radio_rx_rds_use_alternates
;
111 vivid_rds_generate(rds
);
115 * Calculate the emulated signal quality taking into account the frequency
116 * the transmitter is using.
118 static void vivid_radio_calc_sig_qual(struct vivid_dev
*dev
)
122 int sig_qual
, sig_qual_tx
= mod
;
125 * For SW and FM there is a channel every 1000 kHz, for AM there is one
128 if (dev
->radio_rx_freq
<= AM_FREQ_RANGE_HIGH
) {
132 sig_qual
= (dev
->radio_rx_freq
+ delta
) % mod
- delta
;
133 if (dev
->has_radio_tx
)
134 sig_qual_tx
= dev
->radio_rx_freq
- dev
->radio_tx_freq
;
135 if (abs(sig_qual_tx
) <= abs(sig_qual
)) {
136 sig_qual
= sig_qual_tx
;
138 * Zero the internal rds buffer if we are going to loop
141 if (!dev
->radio_rds_loop
&& !dev
->radio_tx_rds_controls
)
142 memset(dev
->rds_gen
.data
, 0,
143 sizeof(dev
->rds_gen
.data
));
144 dev
->radio_rds_loop
= dev
->radio_rx_freq
>= FM_FREQ_RANGE_LOW
;
146 dev
->radio_rds_loop
= false;
148 if (dev
->radio_rx_freq
<= AM_FREQ_RANGE_HIGH
)
150 dev
->radio_rx_sig_qual
= sig_qual
;
153 int vivid_radio_g_frequency(struct file
*file
, const unsigned *pfreq
, struct v4l2_frequency
*vf
)
157 vf
->frequency
= *pfreq
;
161 int vivid_radio_s_frequency(struct file
*file
, unsigned *pfreq
, const struct v4l2_frequency
*vf
)
163 struct vivid_dev
*dev
= video_drvdata(file
);
170 if (vf
->frequency
>= (FM_FREQ_RANGE_LOW
+ SW_FREQ_RANGE_HIGH
) / 2)
172 else if (vf
->frequency
<= (AM_FREQ_RANGE_HIGH
+ SW_FREQ_RANGE_LOW
) / 2)
177 freq
= clamp_t(u32
, vf
->frequency
, vivid_radio_bands
[band
].rangelow
,
178 vivid_radio_bands
[band
].rangehigh
);
182 * For both receiver and transmitter recalculate the signal quality
183 * (since that depends on both frequencies) and re-init the rds
186 vivid_radio_calc_sig_qual(dev
);
187 vivid_radio_rds_init(dev
);