Annotation of sys/dev/isa/radiotrack.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: radiotrack.c,v 1.4 2002/08/28 21:20:48 mickey Exp $ */
2: /* $RuOBSD: radiotrack.c,v 1.3 2001/10/18 16:51:36 pva Exp $ */
3:
4: /*
5: * Copyright (c) 2001, 2002 Maxim Tsyplakov <tm@oganer.net>,
6: * Vladimir Popov <jumbo@narod.ru>
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21: * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28: */
29:
30: /* AIMS Lab Radiotrack FM Radio Card device driver */
31:
32: /*
33: * Sanyo LM7000 Direct PLL Frequency Synthesizer
34: */
35:
36: #include <sys/param.h>
37: #include <sys/systm.h>
38: #include <sys/ioctl.h>
39: #include <sys/device.h>
40: #include <sys/radioio.h>
41:
42: #include <machine/bus.h>
43:
44: #include <dev/ic/lm700x.h>
45: #include <dev/isa/isavar.h>
46: #include <dev/isa/rtreg.h>
47: #include <dev/isa/rtvar.h>
48: #include <dev/radio_if.h>
49:
50: void rtattach(struct rt_softc *);
51: int rt_get_info(void *, struct radio_info *);
52: int rt_set_info(void *, struct radio_info *);
53:
54: struct radio_hw_if rt_hw_if = {
55: NULL, /* open */
56: NULL, /* close */
57: rt_get_info,
58: rt_set_info,
59: NULL
60: };
61:
62: struct cfdriver rt_cd = {
63: NULL, "rt", DV_DULL
64: };
65:
66: void rt_set_mute(struct rt_softc *, int);
67: void rt_set_freq(struct rt_softc *, u_int32_t);
68: u_int8_t rt_state(bus_space_tag_t, bus_space_handle_t);
69:
70: void sfi_lm700x_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
71: void rt_lm700x_init(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
72: void rt_lm700x_rset(bus_space_tag_t, bus_space_handle_t, bus_size_t, u_int32_t);
73:
74: u_int8_t rt_conv_vol(u_int8_t);
75: u_int8_t rt_unconv_vol(u_int8_t);
76:
77: void
78: rtattach(struct rt_softc *sc) {
79: sc->sc_freq = MIN_FM_FREQ;
80: sc->sc_mute = 0;
81: sc->sc_vol = 0;
82: sc->sc_rf = LM700X_REF_050;
83: sc->sc_stereo = LM700X_STEREO;
84:
85: sc->lm.wzcl = RT_WREN_ON | RT_CLCK_OFF | RT_DATA_OFF;
86: sc->lm.wzch = RT_WREN_ON | RT_CLCK_ON | RT_DATA_OFF;
87: sc->lm.wocl = RT_WREN_ON | RT_CLCK_OFF | RT_DATA_ON;
88: sc->lm.woch = RT_WREN_ON | RT_CLCK_ON | RT_DATA_ON;
89:
90: switch (sc->sc_ct) {
91: case CARD_RADIOTRACK:
92: sc->lm.initdata = 0;
93: sc->lm.rsetdata = RT_SIGNAL_METER;
94: sc->lm.init = rt_lm700x_init;
95: sc->lm.rset = rt_lm700x_rset;
96: break;
97: case CARD_SF16FMI:
98: sc->lm.initdata = RT_CARD_OFF;
99: sc->lm.rsetdata = RT_CARD_ON;
100: sc->lm.init = sfi_lm700x_init;
101: sc->lm.rset = sfi_lm700x_init;
102: break;
103: }
104:
105: rt_set_freq(sc, sc->sc_freq);
106: rt_set_mute(sc, sc->sc_vol);
107:
108: radio_attach_mi(&rt_hw_if, sc, &sc->sc_dev);
109: }
110:
111: int
112: rt_set_info(void *v, struct radio_info *ri)
113: {
114: struct rt_softc *sc = v;
115:
116: sc->sc_mute = ri->mute ? 1 : 0;
117: sc->sc_rf = lm700x_encode_ref(ri->rfreq);
118:
119: switch (sc->sc_ct) {
120: case CARD_RADIOTRACK:
121: sc->sc_vol = rt_conv_vol(ri->volume);
122: break;
123: case CARD_SF16FMI:
124: sc->sc_vol = ri->volume ? 1 : 0;
125: break;
126: }
127: /*
128: * Though SF16-FMI does not set stereo/mono
129: * it won't hurt to have this
130: */
131: sc->sc_stereo = ri->stereo ? LM700X_STEREO : LM700X_MONO;
132:
133: rt_set_freq(sc, ri->freq);
134: rt_set_mute(sc, sc->sc_vol);
135:
136: return (0);
137: }
138:
139: int
140: rt_get_info(void *v, struct radio_info *ri)
141: {
142: struct rt_softc *sc = v;
143:
144: switch (sc->sc_ct) {
145: case CARD_RADIOTRACK:
146: ri->caps = RTRACK_CAPABILITIES;
147: ri->info = 3 & rt_state(sc->lm.iot, sc->lm.ioh);
148: ri->volume = rt_unconv_vol(sc->sc_vol);
149: break;
150: case CARD_SF16FMI:
151: ri->caps = SF16FMI_CAPABILITIES;
152: ri->volume = sc->sc_vol ? 255 : 0;
153: ri->info = 0; /* UNSUPPORTED */
154: break;
155: default:
156: /* No such card */
157: return (1);
158: }
159:
160: ri->mute = sc->sc_mute;
161: ri->stereo = sc->sc_stereo == LM700X_STEREO ? 0 : 1;
162: ri->rfreq = lm700x_decode_ref(sc->sc_rf);
163: ri->freq = sc->sc_freq;
164:
165: /* UNSUPPORTED */
166: ri->lock = 0;
167:
168: return (0);
169: }
170:
171: /*
172: * Mute the card
173: */
174: void
175: rt_set_mute(struct rt_softc *sc, int vol)
176: {
177: int val;
178:
179: if (sc->sc_ct == CARD_UNKNOWN)
180: return;
181:
182: if (sc->sc_ct == CARD_SF16FMI) {
183: val = vol ? RT_CARD_ON : RT_CARD_OFF;
184: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
185: sc->sc_mute ? RT_CARD_OFF : val);
186: return;
187: }
188:
189: /* CARD_RADIOTRACK */
190: if (sc->sc_mute) {
191: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
192: RT_VOLUME_DOWN | RT_CARD_ON);
193: DELAY(MAX_VOL * RT_VOLUME_DELAY);
194: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
195: RT_VOLUME_STEADY | RT_CARD_ON);
196: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0, RT_CARD_OFF);
197: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0, RT_CARD_OFF);
198: } else {
199: val = sc->sc_vol - vol;
200: if (val < 0) {
201: val *= -1;
202: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
203: RT_VOLUME_DOWN | RT_CARD_ON);
204: } else {
205: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
206: RT_VOLUME_UP | RT_CARD_ON);
207: }
208: DELAY(val * RT_VOLUME_DELAY);
209: bus_space_write_1(sc->lm.iot, sc->lm.ioh, 0,
210: RT_VOLUME_STEADY | RT_CARD_ON);
211: }
212: }
213:
214: void
215: rt_set_freq(struct rt_softc *sc, u_int32_t nfreq)
216: {
217: u_int32_t reg;
218:
219: if (nfreq > MAX_FM_FREQ)
220: nfreq = MAX_FM_FREQ;
221: if (nfreq < MIN_FM_FREQ)
222: nfreq = MIN_FM_FREQ;
223:
224: sc->sc_freq = nfreq;
225:
226: reg = lm700x_encode_freq(nfreq, sc->sc_rf);
227: reg |= sc->sc_stereo | sc->sc_rf | LM700X_DIVIDER_FM;
228:
229: lm700x_hardware_write(&sc->lm, reg, RT_VOLUME_STEADY);
230:
231: rt_set_mute(sc, sc->sc_vol);
232: }
233:
234: /*
235: * Return state of the card - tuned/not tuned, mono/stereo
236: */
237: u_int8_t
238: rt_state(bus_space_tag_t iot, bus_space_handle_t ioh)
239: {
240: u_int8_t ret;
241:
242: bus_space_write_1(iot, ioh, 0,
243: RT_VOLUME_STEADY | RT_SIGNAL_METER | RT_CARD_ON);
244: DELAY(RT_SIGNAL_METER_DELAY);
245: ret = bus_space_read_1(iot, ioh, 0);
246:
247: switch (ret) {
248: case 0xFD:
249: ret = RADIO_INFO_SIGNAL | RADIO_INFO_STEREO;
250: break;
251: case 0xFF:
252: ret = 0;
253: break;
254: default:
255: ret = RADIO_INFO_SIGNAL;
256: break;
257: }
258:
259: return ret;
260: }
261:
262: /*
263: * Convert volume to hardware representation.
264: */
265: u_int8_t
266: rt_conv_vol(u_int8_t vol)
267: {
268: if (vol < VOLUME_RATIO(1))
269: return 0;
270: else if (vol >= VOLUME_RATIO(1) && vol < VOLUME_RATIO(2))
271: return 1;
272: else if (vol >= VOLUME_RATIO(2) && vol < VOLUME_RATIO(3))
273: return 2;
274: else if (vol >= VOLUME_RATIO(3) && vol < VOLUME_RATIO(4))
275: return 3;
276: else
277: return 4;
278: }
279:
280: /*
281: * Convert volume from hardware representation
282: */
283: u_int8_t
284: rt_unconv_vol(u_int8_t vol)
285: {
286: return VOLUME_RATIO(vol);
287: }
288:
289: void
290: sfi_lm700x_init(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
291: u_int32_t data)
292: {
293: bus_space_write_1(iot, ioh, off, data);
294: }
295:
296: void
297: rt_lm700x_init(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
298: u_int32_t data)
299: {
300: /* Do nothing */
301: return;
302: }
303:
304: void
305: rt_lm700x_rset(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
306: u_int32_t data)
307: {
308: DELAY(1000);
309: bus_space_write_1(iot, ioh, off, RT_CARD_OFF | data);
310: DELAY(50000);
311: bus_space_write_1(iot, ioh, off, RT_VOLUME_STEADY | RT_CARD_ON | data);
312: }
CVSweb