1 /******************************************************************************
2 /
3 / File: Tuner.cpp
4 /
5 / Description: Philips Desktop TV Tuners interface.
6 /
7 / Copyright 2001, Carlos Hasan
8 /
9 *******************************************************************************/
10
11 #include <Debug.h>
12 #include "Tuner.h"
13
14 enum tuner_control_bits {
15 CHANGE_PUMP = 0x40, /* change pump settings */
16 CHANGE_PUMP_FAST = 0x00, /* for fast tuning */
17 CHANGE_PUMP_SLOW = 0x40, /* for moderate speed tuning */
18
19 TEST_MODE = 0x38, /* test mode settings */
20 TEST_MODE_NORMAL = 0x08, /* for normal operation */
21
22 RATIO_SELECT = 0x06, /* ratio select */
23 RATIO_SELECT_FAST = 0x00, /* fast picture search */
24 RATIO_SELECT_SLOW = 0x02, /* slow picture search */
25 RATIO_SELECT_NORMAL = 0x06, /* normal picture search */
26
27 OS_MODE = 0x01, /* PLL disabling */
28 OS_MODE_NORMAL = 0x00, /* for normal operation */
29 OS_MODE_SWITCH = 0x01 /* change pump to high impedance */
30 };
31
32 enum tuner_status_bits {
33 STB_POR = 0x80, /* power on reset */
34 STB_FL = 0x40, /* in-lock flag */
35 STB_INF = 0x38, /* digital information */
36 STB_ADC = 0x07 /* A/D converter */
37 };
38
39 /*****************************************************************************
40 /
41 / Tuner Parameters and Frequencies for TV Antenna and Cable Channels
42 /
43 ******************************************************************************/
44
45 static const int kBandsPerTuner = 5;
46
47 static const struct {
48 tuner_type brand;
49 const char* name;
50 struct {
51 int pll;
52 float minFrequency, maxFrequency;
53 } bands[kBandsPerTuner];
54 } kTunerTable[] = {
55 /* Philips FI1236 NTSC M/N */
56 { C_TUNER_FI1236, "FI1236 NTSC",
57 { { 0xa2, 54.00, 157.25 },
58 { 0x94, 162.00, 451.25 },
59 { 0x34, 451.25, 463.25 },
60 { 0x31, 463.25, 801.25 },
61 { 0x00, 0.00, 0.00 } } },
62
63 /* Philips FI1236J NTSC Japan */
64 { C_TUNER_FI1236J, "FI1236J NTSC Japan",
65 { { 0xa2, 54.00, 157.25 },
66 { 0x94, 162.00, 451.25 },
67 { 0x34, 451.25, 463.25 },
68 { 0x31, 463.25, 801.25 },
69 { 0x00, 0.00, 0.00 } } },
70
71 /* Philips FI1236MK2 NTSC M/N */
72 { C_TUNER_FI1236MK2, "FI1236MK2 NTSC",
73 { { 0xa0, 55.25, 160.00 },
74 { 0x90, 160.00, 454.00 },
75 { 0x30, 454.00, 855.25 },
76 { 0x00, 0.00, 0.00 },
77 { 0x00, 0.00, 0.00 } } },
78
79 /* Philips FI1216 PAL B/G */
80 { C_TUNER_FI1216, "FI1216 PAL",
81 { { 0xa2, 45.00, 140.25 },
82 { 0xa4, 140.25, 168.25 },
83 { 0x94, 168.25, 447.25 },
84 { 0x34, 447.25, 463.25 },
85 { 0x31, 463.25, 855.25 } } },
86
87 /* Philips FI1216MK2 PAL B/G */
88 { C_TUNER_FI1216MK2, "FI1216MK2 PAL",
89 { { 0xa0, 48.25, 170.00 },
90 { 0x90, 170.00, 450.00 },
91 { 0x30, 450.00, 855.25 },
92 { 0x00, 0.00, 0.00 },
93 { 0x00, 0.00, 0.00 } } },
94
95 /* Philips FI1216MF PAL B/G, SECAM L/L' */
96 { C_TUNER_FI1216MF, "FI1216MF PAL/SECAM",
97 { { 0xa1, 45.00, 168.25 },
98 { 0x91, 168.25, 447.25 },
99 { 0x31, 447.25, 855.25 },
100 { 0x00, 0.00, 0.00 },
101 { 0x00, 0.00, 0.00 } } },
102
103 /* Philips FI1246 PAL I */
104 { C_TUNER_FI1246, "FI1246 PAL I",
105 { { 0xa2, 45.00, 140.25 },
106 { 0xa4, 140.25, 168.25 },
107 { 0x94, 168.25, 447.25 },
108 { 0x34, 447.25, 463.25 },
109 { 0x31, 463.25, 855.25 } } },
110
111 /* Philips FI1256 SECAM D/K */
112 { C_TUNER_FI1256, "FI1256 SECAM",
113 { { 0xa0, 48.25, 168.25 },
114 { 0x90, 175.25, 455.25 },
115 { 0x30, 463.25, 863.25 },
116 { 0x00, 0.00, 0.00 },
117 { 0x00, 0.00, 0.00 } } },
118
119 /* Temic FN5AL PAL I/B/G/DK, SECAM DK */
120 { C_TUNER_TEMIC_FN5AL_PAL, "Temic FN5AL PAL",
121 { { 0xa2, 45.00, 140.25 },
122 { 0xa4, 140.25, 168.25 },
123 { 0x94, 168.25, 447.25 },
124 { 0x31, 447.25, 855.25 },
125 { 0x00, 0.00, 0.00 } } },
126
127 /* Temic FN5AL PAL I/B/G/DK, SECAM DK */
128 { C_TUNER_TEMIC_FN5AL_SECAM, "Temic FN5AL SECAM",
129 { { 0xa0, 48.25, 168.25 },
130 { 0x90, 175.25, 455.25 },
131 { 0x30, 463.25, 863.25 },
132 { 0x00, 0.00, 0.00 },
133 { 0x00, 0.00, 0.00 } } } };
134
135 static const int kNumTuners = sizeof(kTunerTable) / sizeof(kTunerTable[0]);
136
137
CTuner(CI2CPort & port)138 CTuner::CTuner(CI2CPort & port)
139 : fPort(port),
140 fType(C_TUNER_NONE),
141 fAddress(0xC6),
142 fDivider(0)
143 {
144 PRINT(("CTuner::CTuner()\n"));
145
146 if( fPort.InitCheck() == B_OK ) {
147 radeon_video_tuner tuner;
148 radeon_video_decoder video;
149 radeon_video_clock clock;
150 int dummy;
151
152 fPort.Radeon().GetMMParameters(tuner, video, clock, dummy, dummy, dummy);
153 switch (tuner) {
154 case C_RADEON_NO_TUNER:
155 fType = C_TUNER_NONE;
156 break;
157 case C_RADEON_FI1236_MK1_NTSC:
158 fType = C_TUNER_FI1236;
159 break;
160 case C_RADEON_FI1236_MK2_NTSC_JAPAN:
161 fType = C_TUNER_FI1236J;
162 break;
163 case C_RADEON_FI1216_MK2_PAL_BG:
164 fType = C_TUNER_FI1216;
165 break;
166 case C_RADEON_FI1246_MK2_PAL_I:
167 fType = C_TUNER_FI1246;
168 break;
169 case C_RADEON_FI1216_MF_MK2_PAL_BG_SECAM_L:
170 fType = C_TUNER_FI1216MF;
171 break;
172 case C_RADEON_FI1236_MK2_NTSC:
173 fType = C_TUNER_FI1236MK2;
174 break;
175 case C_RADEON_FI1256_MK2_SECAM_DK:
176 fType = C_TUNER_FI1256;
177 break;
178 case C_RADEON_FI1216_MK2_PAL_BG_SECAM_L:
179 fType = C_TUNER_FI1216MK2;
180 break;
181 case C_RADEON_TEMIC_FN5AL_PAL_IBGDK_SECAM_DK:
182 fType = C_TUNER_TEMIC_FN5AL_PAL;
183 break;
184 default:
185 fType = C_TUNER_FI1236;
186 break;
187 }
188
189 for (fAddress = 0xc0; fAddress <= 0xc6; fAddress += 0x02) {
190 if (fPort.Probe(fAddress)) {
191 PRINT(("CTuner::CTuner() - TV Tuner found at I2C port 0x%02x\n", fAddress));
192 break;
193 }
194 }
195 }
196 if( InitCheck() != B_OK )
197 PRINT(("CTuner::CTuner() - TV Tuner not found!\n"));
198 }
199
~CTuner()200 CTuner::~CTuner()
201 {
202 PRINT(("CTuner::~CTuner()\n"));
203 }
204
InitCheck() const205 status_t CTuner::InitCheck() const
206 {
207 return (fType != C_TUNER_NONE && fAddress >= 0xc0 && fAddress <= 0xc6) ?
208 B_OK : B_ERROR;
209 }
210
SetFrequency(float frequency,float picture)211 bool CTuner::SetFrequency(float frequency, float picture)
212 {
213 //PRINT(("CTuner::SetFrequency(%g, %g)\n", frequency, picture));
214
215 for (int index = 0; index < kNumTuners; index++) {
216 if (kTunerTable[index].brand == fType) {
217 for (int band = 0; band < kBandsPerTuner; band++) {
218 if (frequency >= kTunerTable[index].bands[band].minFrequency &&
219 frequency <= kTunerTable[index].bands[band].maxFrequency) {
220 SetParameters(
221 (int) (16.0 * (frequency + picture)),
222 CHANGE_PUMP_FAST | RATIO_SELECT_NORMAL |
223 TEST_MODE_NORMAL | OS_MODE_NORMAL,
224 kTunerTable[index].bands[band].pll |
225 ((Status() & STB_INF) >> 3));
226 return true;
227 }
228 }
229 }
230 }
231 return false;
232 }
233
SweepFrequency(float frequency,float picture)234 bool CTuner::SweepFrequency(float frequency, float picture)
235 {
236 PRINT(("CTuner::SweepFrequency(%g, %g)\n", frequency, picture));
237
238 float centerFrequency = frequency;
239
240 /* sweeping down */
241 do {
242 SetFrequency(frequency, picture);
243 for (int timeout = 0; timeout < 10; timeout++) {
244 snooze(20000);
245 if (IsLocked())
246 break;
247 }
248 } while (ADC() == 0 &&
249 (frequency -= 0.5000) > centerFrequency - 3.000);
250
251 /* sweeping up */
252 do {
253 SetFrequency(frequency, picture);
254 for (int timeout = 0; timeout < 10; timeout++) {
255 snooze(20000);
256 if (IsLocked())
257 break;
258 }
259 } while (ADC() != 0 &&
260 (frequency += 0.0625) < centerFrequency + 0.500);
261
262 return (ADC() == 0);
263 }
264
Name() const265 const char * CTuner::Name() const
266 {
267 for (int index = 0; index < kNumTuners; index++) {
268 if (kTunerTable[index].brand == fType)
269 return kTunerTable[index].name;
270 }
271 return 0;
272 }
273
Type() const274 tuner_type CTuner::Type() const
275 {
276 return fType;
277 }
278
HasSignal(void)279 bool CTuner::HasSignal(void)
280 {
281 return (IsLocked() && ADC() <= 2);
282 }
283
Status(void)284 int CTuner::Status(void)
285 {
286 char buffer[1];
287 fPort.Read(fAddress, buffer, sizeof(buffer));
288 return buffer[0] & 0xff;
289 }
290
ADC(void)291 int CTuner::ADC(void)
292 {
293 return Status() & STB_ADC;
294 }
295
IsLocked(void)296 bool CTuner::IsLocked(void)
297 {
298 return (Status() & STB_FL) != 0;
299 }
300
SetParameters(int divider,int control,int band)301 void CTuner::SetParameters(int divider, int control, int band)
302 {
303 char buffer[4];
304
305 if (divider > fDivider) {
306 buffer[0] = (divider >> 8) & 0x7f;
307 buffer[1] = (divider >> 0) & 0xff;
308
309 buffer[2] = (control | 0x80);
310 buffer[3] = (band & 0xff);
311 }
312 else {
313 buffer[0] = (control | 0x80);
314 buffer[1] = (band & 0xff);
315
316 buffer[2] = (divider >> 8) & 0x7f;
317 buffer[3] = (divider >> 0) & 0xff;
318 }
319
320 fDivider = divider;
321
322 fPort.Write(fAddress, buffer, sizeof(buffer));
323 }
324