This source file includes following definitions.
- sfr_probe
- sfr_attach
- sfr_find
- sfr_get_info
- sfr_set_info
- sfr_set_freq
- sfr_get_freq
- sfr_set_vol
- sfr_send_volume
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/proc.h>
33 #include <sys/errno.h>
34 #include <sys/ioctl.h>
35 #include <sys/device.h>
36 #include <sys/radioio.h>
37
38 #include <dev/isa/isavar.h>
39 #include <dev/radio_if.h>
40
41 #include <dev/ic/tc921x.h>
42 #include <dev/ic/pt2254a.h>
43
44 #define SF16FMR_BASE_VALID(x) (x == 0x384 || x == 0x284)
45
46 #define SF16FMR_CAPABILITIES 0
47
48 #define SF16FMR_FREQ_DATA 0
49 #define SF16FMR_FREQ_CLOCK 1
50 #define SF16FMR_FREQ_PERIOD 2
51
52 #define SF16FMR_FREQ_STEADY (1 << SF16FMR_FREQ_DATA) | \
53 (1 << SF16FMR_FREQ_CLOCK) | \
54 (1 << SF16FMR_FREQ_PERIOD)
55
56 #define SF16FMR_VOLU_STROBE_ON (1 << 3)
57 #define SF16FMR_VOLU_STROBE_OFF (0 << 3)
58 #define SF16FMR_VOLU_CLOCK_ON (1 << 4)
59 #define SF16FMR_VOLU_CLOCK_OFF (0 << 4)
60 #define SF16FMR_VOLU_DATA_ON (1 << 5)
61 #define SF16FMR_VOLU_DATA_OFF (0 << 5)
62
63 int sfr_probe(struct device *, void *, void *);
64 void sfr_attach(struct device *, struct device * self, void *);
65
66 int sfr_get_info(void *, struct radio_info *);
67 int sfr_set_info(void *, struct radio_info *);
68
69
70 struct radio_hw_if sfr_hw_if = {
71 NULL,
72 NULL,
73 sfr_get_info,
74 sfr_set_info,
75 NULL
76 };
77
78 struct sfr_softc {
79 struct device sc_dev;
80
81 u_int32_t freq;
82 u_int8_t vol;
83 int mute;
84
85 struct tc921x_t c;
86 };
87
88 struct cfattach sfr_ca = {
89 sizeof(struct sfr_softc), sfr_probe, sfr_attach
90 };
91
92 struct cfdriver sfr_cd = {
93 NULL, "sfr", DV_DULL
94 };
95
96 int sfr_find(bus_space_tag_t, bus_space_handle_t);
97 u_int32_t sfr_set_freq(struct tc921x_t *, u_int32_t);
98 u_int32_t sfr_get_freq(struct tc921x_t *);
99 u_int8_t sfr_set_vol(bus_space_tag_t, bus_space_handle_t, u_int8_t, int);
100 void sfr_send_volume(bus_space_tag_t, bus_space_handle_t, u_int32_t);
101
102 int
103 sfr_probe(struct device *parent, void *match, void *aux)
104 {
105 struct isa_attach_args *ia = aux;
106 bus_space_tag_t iot = ia->ia_iot;
107 bus_space_handle_t ioh;
108 int iosize = 1, iobase = ia->ia_iobase;
109
110 if (!SF16FMR_BASE_VALID(iobase)) {
111 printf("sfr: configured iobase 0x%x invalid\n", iobase);
112 return (0);
113 }
114
115 if (bus_space_map(iot, iobase, iosize, 0, &ioh))
116 return (0);
117
118 if (!sfr_find(iot, ioh)) {
119 bus_space_unmap(iot, ioh, iosize);
120 return (0);
121 }
122
123 bus_space_unmap(iot, ioh, iosize);
124 ia->ia_iosize = iosize;
125 return (1);
126 }
127
128 void
129 sfr_attach(struct device *parent, struct device *self, void *aux)
130 {
131 struct sfr_softc *sc = (void *) self;
132 struct isa_attach_args *ia = aux;
133
134 sc->c.iot = ia->ia_iot;
135 sc->mute = 0;
136 sc->vol = 0;
137 sc->freq = MIN_FM_FREQ;
138 sc->c.period = SF16FMR_FREQ_PERIOD;
139 sc->c.clock = SF16FMR_FREQ_CLOCK;
140 sc->c.data = SF16FMR_FREQ_DATA;
141
142
143 if (bus_space_map(sc->c.iot, ia->ia_iobase, ia->ia_iosize,
144 0, &sc->c.ioh)) {
145 printf(": bus_space_map() failed\n");
146 return;
147 }
148
149 printf(": SoundForte RadioLink SF16-FMR\n");
150 sfr_set_freq(&sc->c, sc->freq);
151 sfr_set_vol(sc->c.iot, sc->c.ioh, sc->vol, sc->mute);
152
153 radio_attach_mi(&sfr_hw_if, sc, &sc->sc_dev);
154 }
155
156 int
157 sfr_find(bus_space_tag_t iot, bus_space_handle_t ioh)
158 {
159 struct sfr_softc sc;
160 u_int32_t freq;
161
162 sc.c.iot = iot;
163 sc.c.ioh = ioh;
164 sc.c.offset = 0;
165 sc.c.period = SF16FMR_FREQ_PERIOD;
166 sc.c.clock = SF16FMR_FREQ_CLOCK;
167 sc.c.data = SF16FMR_FREQ_DATA;
168
169
170
171
172
173
174 sc.freq = MIN_FM_FREQ;
175
176 sfr_set_freq(&sc.c, sc.freq);
177
178 freq = sfr_set_freq(&sc.c, sc.freq);
179 if (sc.freq == freq)
180 return 1;
181
182 return 0;
183 }
184
185 int
186 sfr_get_info(void *v, struct radio_info *ri)
187 {
188 struct sfr_softc *sc = v;
189
190 ri->mute = sc->mute;
191 ri->volume = sc->vol;
192 ri->caps = SF16FMR_CAPABILITIES;
193 ri->freq = sc->freq = sfr_get_freq(&sc->c);
194
195
196 ri->stereo = 1;
197 ri->rfreq = 0;
198 ri->lock = 0;
199
200 return (0);
201 }
202
203 int
204 sfr_set_info(void *v, struct radio_info *ri)
205 {
206 struct sfr_softc *sc = v;
207
208 sc->mute = ri->mute ? 1 : 0;
209 sc->vol = ri->volume;
210 sc->freq = sfr_set_freq(&sc->c, ri->freq);
211 sc->vol = sfr_set_vol(sc->c.iot, sc->c.ioh, sc->vol, sc->mute);
212
213 return (0);
214 }
215
216 u_int32_t
217 sfr_set_freq(struct tc921x_t *c, u_int32_t freq) {
218 u_int32_t data = 0ul;
219
220 data |= tc921x_encode_freq(freq);
221 data |= TC921X_D0_REF_FREQ_10_KHZ;
222 data |= TC921X_D0_PULSE_SWALLOW_FM_MODE;
223 data |= TC921X_D0_OSC_7POINT2_MHZ;
224 data |= TC921X_D0_OUT_CONTROL_ON;
225 tc921x_write_addr(c, 0xD0, data);
226
227 data = TC921X_D2_IO_PORT_OUTPUT(4);
228 tc921x_write_addr(c, 0xD2, data);
229
230 return sfr_get_freq(c);
231 }
232
233 u_int32_t
234 sfr_get_freq(struct tc921x_t *c) {
235 return tc921x_decode_freq(tc921x_read_addr(c, 0xD1));
236 }
237
238 u_int8_t
239 sfr_set_vol(bus_space_tag_t iot, bus_space_handle_t ioh, u_int8_t vol, int mute) {
240 u_int32_t v;
241 u_int8_t ret;
242
243 ret = mute ? 0 : vol;
244
245 v = pt2254a_encode_volume(&ret, 255);
246
247 sfr_send_volume(iot, ioh,
248 pt2254a_compose_register(v, v, USE_CHANNEL, USE_CHANNEL));
249
250 return ret;
251 }
252
253 void
254 sfr_send_volume(bus_space_tag_t iot, bus_space_handle_t ioh, u_int32_t vol) {
255 u_int8_t one, zero;
256 int i;
257
258 one = zero = SF16FMR_FREQ_STEADY;
259 one = zero |= SF16FMR_VOLU_STROBE_OFF;
260
261 one |= SF16FMR_VOLU_DATA_ON;
262 zero |= SF16FMR_VOLU_DATA_OFF;
263
264 bus_space_write_1(iot, ioh, 0, SF16FMR_VOLU_STROBE_OFF | SF16FMR_FREQ_STEADY);
265
266 for (i = 0; i < PT2254A_REGISTER_LENGTH; i++) {
267 if (vol & (1 << i)) {
268 bus_space_write_1(iot, ioh, 0,
269 one | SF16FMR_VOLU_CLOCK_OFF);
270 bus_space_write_1(iot, ioh, 0,
271 one | SF16FMR_VOLU_CLOCK_ON);
272 } else {
273 bus_space_write_1(iot, ioh, 0,
274 zero | SF16FMR_VOLU_CLOCK_OFF);
275 bus_space_write_1(iot, ioh, 0,
276 zero | SF16FMR_VOLU_CLOCK_ON);
277 }
278 }
279
280
281 bus_space_write_1(iot, ioh, 0, SF16FMR_VOLU_STROBE_ON | SF16FMR_FREQ_STEADY);
282 bus_space_write_1(iot, ioh, 0, SF16FMR_VOLU_STROBE_OFF | SF16FMR_FREQ_STEADY);
283 }