1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/errno.h>
21#include <linux/kernel.h>
22#include <linux/delay.h>
23#include <linux/videodev2.h>
24
25#include "vivid-core.h"
26#include "vivid-ctrls.h"
27#include "vivid-radio-common.h"
28#include "vivid-rds-gen.h"
29
30
31
32
33
34
35const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS] = {
36
37 {
38 .type = V4L2_TUNER_RADIO,
39 .index = 0,
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,
45 },
46
47 {
48 .type = V4L2_TUNER_RADIO,
49 .index = 1,
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,
54 },
55
56 {
57 .type = V4L2_TUNER_RADIO,
58 .index = 2,
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,
63 },
64};
65
66
67
68
69
70
71void vivid_radio_rds_init(struct vivid_dev *dev)
72{
73 struct vivid_rds_gen *rds = &dev->rds_gen;
74 bool alt = dev->radio_rx_rds_use_alternates;
75
76
77 if (dev->radio_rds_loop && !dev->radio_tx_rds_controls)
78 return;
79
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;
91 strlcpy(rds->psname,
92 dev->radio_tx_rds_psname->p_cur.p_char,
93 sizeof(rds->psname));
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);
98 } else {
99 vivid_rds_gen_fill(rds, dev->radio_rx_freq, alt);
100 }
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;
110 }
111 vivid_rds_generate(rds);
112}
113
114
115
116
117
118static void vivid_radio_calc_sig_qual(struct vivid_dev *dev)
119{
120 int mod = 16000;
121 int delta = 800;
122 int sig_qual, sig_qual_tx = mod;
123
124
125
126
127
128 if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) {
129 mod /= 10;
130 delta /= 10;
131 }
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;
137
138
139
140
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;
145 } else {
146 dev->radio_rds_loop = false;
147 }
148 if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH)
149 sig_qual *= 10;
150 dev->radio_rx_sig_qual = sig_qual;
151}
152
153int vivid_radio_g_frequency(struct file *file, const unsigned *pfreq, struct v4l2_frequency *vf)
154{
155 if (vf->tuner != 0)
156 return -EINVAL;
157 vf->frequency = *pfreq;
158 return 0;
159}
160
161int vivid_radio_s_frequency(struct file *file, unsigned *pfreq, const struct v4l2_frequency *vf)
162{
163 struct vivid_dev *dev = video_drvdata(file);
164 unsigned freq;
165 unsigned band;
166
167 if (vf->tuner != 0)
168 return -EINVAL;
169
170 if (vf->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) / 2)
171 band = BAND_FM;
172 else if (vf->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) / 2)
173 band = BAND_AM;
174 else
175 band = BAND_SW;
176
177 freq = clamp_t(u32, vf->frequency, vivid_radio_bands[band].rangelow,
178 vivid_radio_bands[band].rangehigh);
179 *pfreq = freq;
180
181
182
183
184
185
186 vivid_radio_calc_sig_qual(dev);
187 vivid_radio_rds_init(dev);
188 return 0;
189}
190