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 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 200 CTuner::~CTuner() 201 { 202 PRINT(("CTuner::~CTuner()\n")); 203 } 204 205 status_t CTuner::InitCheck() const 206 { 207 return (fType != C_TUNER_NONE && fAddress >= 0xc0 && fAddress <= 0xc6) ? 208 B_OK : B_ERROR; 209 } 210 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 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 265 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 274 tuner_type CTuner::Type() const 275 { 276 return fType; 277 } 278 279 bool CTuner::HasSignal(void) 280 { 281 return (IsLocked() && ADC() <= 2); 282 } 283 284 int CTuner::Status(void) 285 { 286 char buffer[1]; 287 fPort.Read(fAddress, buffer, sizeof(buffer)); 288 return buffer[0] & 0xff; 289 } 290 291 int CTuner::ADC(void) 292 { 293 return Status() & STB_ADC; 294 } 295 296 bool CTuner::IsLocked(void) 297 { 298 return (Status() & STB_FL) != 0; 299 } 300 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