Annotation of sys/dev/pci/bktr/bktr_tuner.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: bktr_tuner.c,v 1.6 2007/06/11 08:10:22 robert Exp $ */
2: /* $FreeBSD: src/sys/dev/bktr/bktr_tuner.c,v 1.9 2000/10/19 07:33:28 roger Exp $ */
3:
4: /*
5: * This is part of the Driver for Video Capture Cards (Frame grabbers)
6: * and TV Tuner cards using the Brooktree Bt848, Bt848A, Bt849A, Bt878, Bt879
7: * chipset.
8: * Copyright Roger Hardiman and Amancio Hasty.
9: *
10: * bktr_tuner : This deals with controlling the tuner fitted to TV cards.
11: *
12: */
13:
14: /*
15: * 1. Redistributions of source code must retain the
16: * Copyright (c) 1997 Amancio Hasty, 1999 Roger Hardiman
17: * All rights reserved.
18: *
19: * Redistribution and use in source and binary forms, with or without
20: * modification, are permitted provided that the following conditions
21: * are met:
22: * 1. Redistributions of source code must retain the above copyright
23: * notice, this list of conditions and the following disclaimer.
24: * 2. Redistributions in binary form must reproduce the above copyright
25: * notice, this list of conditions and the following disclaimer in the
26: * documentation and/or other materials provided with the distribution.
27: * 3. All advertising materials mentioning features or use of this software
28: * must display the following acknowledgement:
29: * This product includes software developed by Amancio Hasty and
30: * Roger Hardiman
31: * 4. The name of the author may not be used to endorse or promote products
32: * derived from this software without specific prior written permission.
33: *
34: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
35: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
36: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
38: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
40: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
42: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
43: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44: * POSSIBILITY OF SUCH DAMAGE.
45: */
46:
47:
48:
49: #include <sys/param.h>
50: #include <sys/systm.h>
51: #include <sys/kernel.h>
52: #include <sys/vnode.h>
53: #include <sys/proc.h>
54:
55: #include <dev/ic/bt8xx.h> /* OpenBSD .h file location */
56: #include <dev/pci/bktr/bktr_reg.h>
57: #include <dev/pci/bktr/bktr_tuner.h>
58: #include <dev/pci/bktr/bktr_card.h>
59: #include <dev/pci/bktr/bktr_core.h>
60:
61: #if defined( TUNER_AFC )
62: #define AFC_DELAY 10000 /* 10 millisend delay */
63: #define AFC_BITS 0x07
64: #define AFC_FREQ_MINUS_125 0x00
65: #define AFC_FREQ_MINUS_62 0x01
66: #define AFC_FREQ_CENTERED 0x02
67: #define AFC_FREQ_PLUS_62 0x03
68: #define AFC_FREQ_PLUS_125 0x04
69: #define AFC_MAX_STEP (5 * FREQFACTOR) /* no more than 5 MHz */
70: #endif /* TUNER_AFC */
71:
72:
73: #define TTYPE_XXX 0
74: #define TTYPE_NTSC 1
75: #define TTYPE_NTSC_J 2
76: #define TTYPE_PAL 3
77: #define TTYPE_PAL_M 4
78: #define TTYPE_PAL_N 5
79: #define TTYPE_SECAM 6
80:
81: #define TSA552x_CB_MSB (0x80)
82: #define TSA552x_CB_CP (1<<6) /* set this for fast tuning */
83: #define TSA552x_CB_T2 (1<<5) /* test mode - Normally set to 0 */
84: #define TSA552x_CB_T1 (1<<4) /* test mode - Normally set to 0 */
85: #define TSA552x_CB_T0 (1<<3) /* test mode - Normally set to 1 */
86: #define TSA552x_CB_RSA (1<<2) /* 0 for 31.25 khz, 1 for 62.5 kHz */
87: #define TSA552x_CB_RSB (1<<1) /* 0 for FM 50kHz steps, 1 = Use RSA*/
88: #define TSA552x_CB_OS (1<<0) /* Set to 0 for normal operation */
89:
90: #define TSA552x_RADIO (TSA552x_CB_MSB | \
91: TSA552x_CB_T0)
92:
93: /* raise the charge pump voltage for fast tuning */
94: #define TSA552x_FCONTROL (TSA552x_CB_MSB | \
95: TSA552x_CB_CP | \
96: TSA552x_CB_T0 | \
97: TSA552x_CB_RSA | \
98: TSA552x_CB_RSB)
99:
100: /* lower the charge pump voltage for better residual oscillator FM */
101: #define TSA552x_SCONTROL (TSA552x_CB_MSB | \
102: TSA552x_CB_T0 | \
103: TSA552x_CB_RSA | \
104: TSA552x_CB_RSB)
105:
106: /* The control value for the ALPS TSCH5 Tuner */
107: #define TSCH5_FCONTROL 0x82
108: #define TSCH5_RADIO 0x86
109:
110: /* The control value for the ALPS TSBH1 Tuner */
111: #define TSBH1_FCONTROL 0xce
112:
113:
114: static const struct TUNER tuners[] = {
115: /* XXX FIXME: fill in the band-switch crosspoints */
116: /* NO_TUNER */
117: { "<no>", /* the 'name' */
118: TTYPE_XXX, /* input type */
119: { 0x00, /* control byte for Tuner PLL */
120: 0x00,
121: 0x00,
122: 0x00 },
123: { 0x00, 0x00 }, /* band-switch crosspoints */
124: { 0x00, 0x00, 0x00,0x00} }, /* the band-switch values */
125:
126: /* TEMIC_NTSC */
127: { "Temic NTSC", /* the 'name' */
128: TTYPE_NTSC, /* input type */
129: { TSA552x_SCONTROL, /* control byte for Tuner PLL */
130: TSA552x_SCONTROL,
131: TSA552x_SCONTROL,
132: 0x00 },
133: { 0x00, 0x00}, /* band-switch crosspoints */
134: { 0x02, 0x04, 0x01, 0x00 } }, /* the band-switch values */
135:
136: /* TEMIC_PAL */
137: { "Temic PAL", /* the 'name' */
138: TTYPE_PAL, /* input type */
139: { TSA552x_SCONTROL, /* control byte for Tuner PLL */
140: TSA552x_SCONTROL,
141: TSA552x_SCONTROL,
142: 0x00 },
143: { 0x00, 0x00 }, /* band-switch crosspoints */
144: { 0x02, 0x04, 0x01, 0x00 } }, /* the band-switch values */
145:
146: /* TEMIC_SECAM */
147: { "Temic SECAM", /* the 'name' */
148: TTYPE_SECAM, /* input type */
149: { TSA552x_SCONTROL, /* control byte for Tuner PLL */
150: TSA552x_SCONTROL,
151: TSA552x_SCONTROL,
152: 0x00 },
153: { 0x00, 0x00 }, /* band-switch crosspoints */
154: { 0x02, 0x04, 0x01,0x00 } }, /* the band-switch values */
155:
156: /* PHILIPS_NTSC */
157: { "Philips NTSC", /* the 'name' */
158: TTYPE_NTSC, /* input type */
159: { TSA552x_SCONTROL, /* control byte for Tuner PLL */
160: TSA552x_SCONTROL,
161: TSA552x_SCONTROL,
162: 0x00 },
163: { 0x00, 0x00 }, /* band-switch crosspoints */
164: { 0xa0, 0x90, 0x30, 0x00 } }, /* the band-switch values */
165:
166: /* PHILIPS_PAL */
167: { "Philips PAL", /* the 'name' */
168: TTYPE_PAL, /* input type */
169: { TSA552x_SCONTROL, /* control byte for Tuner PLL */
170: TSA552x_SCONTROL,
171: TSA552x_SCONTROL,
172: 0x00 },
173: { 0x00, 0x00 }, /* band-switch crosspoints */
174: { 0xa0, 0x90, 0x30, 0x00 } }, /* the band-switch values */
175:
176: /* PHILIPS_SECAM */
177: { "Philips SECAM", /* the 'name' */
178: TTYPE_SECAM, /* input type */
179: { TSA552x_SCONTROL, /* control byte for Tuner PLL */
180: TSA552x_SCONTROL,
181: TSA552x_SCONTROL,
182: 0x00 },
183: { 0x00, 0x00 }, /* band-switch crosspoints */
184: { 0xa7, 0x97, 0x37, 0x00 } }, /* the band-switch values */
185:
186: /* TEMIC_PAL I */
187: { "Temic PAL I", /* the 'name' */
188: TTYPE_PAL, /* input type */
189: { TSA552x_SCONTROL, /* control byte for Tuner PLL */
190: TSA552x_SCONTROL,
191: TSA552x_SCONTROL,
192: 0x00 },
193: { 0x00, 0x00 }, /* band-switch crosspoints */
194: { 0x02, 0x04, 0x01,0x00 } }, /* the band-switch values */
195:
196: /* PHILIPS_PALI */
197: { "Philips PAL I", /* the 'name' */
198: TTYPE_PAL, /* input type */
199: { TSA552x_SCONTROL, /* control byte for Tuner PLL */
200: TSA552x_SCONTROL,
201: TSA552x_SCONTROL,
202: 0x00 },
203: { 0x00, 0x00 }, /* band-switch crosspoints */
204: { 0xa0, 0x90, 0x30,0x00 } }, /* the band-switch values */
205:
206: /* PHILIPS_FR1236_NTSC */
207: { "Philips FR1236 NTSC FM", /* the 'name' */
208: TTYPE_NTSC, /* input type */
209: { TSA552x_FCONTROL, /* control byte for Tuner PLL */
210: TSA552x_FCONTROL,
211: TSA552x_FCONTROL,
212: TSA552x_RADIO },
213: { 0x00, 0x00 }, /* band-switch crosspoints */
214: { 0xa0, 0x90, 0x30,0xa4 } }, /* the band-switch values */
215:
216: /* PHILIPS_FR1216_PAL */
217: { "Philips FR1216 PAL FM" , /* the 'name' */
218: TTYPE_PAL, /* input type */
219: { TSA552x_FCONTROL, /* control byte for Tuner PLL */
220: TSA552x_FCONTROL,
221: TSA552x_FCONTROL,
222: TSA552x_RADIO },
223: { 0x00, 0x00 }, /* band-switch crosspoints */
224: { 0xa0, 0x90, 0x30, 0xa4 } }, /* the band-switch values */
225:
226: /* PHILIPS_FR1236_SECAM */
227: { "Philips FR1236 SECAM FM", /* the 'name' */
228: TTYPE_SECAM, /* input type */
229: { TSA552x_FCONTROL, /* control byte for Tuner PLL */
230: TSA552x_FCONTROL,
231: TSA552x_FCONTROL,
232: TSA552x_RADIO },
233: { 0x00, 0x00 }, /* band-switch crosspoints */
234: { 0xa7, 0x97, 0x37, 0xa4 } }, /* the band-switch values */
235:
236: /* ALPS TSCH5 NTSC */
237: { "ALPS TSCH5 NTSC FM", /* the 'name' */
238: TTYPE_NTSC, /* input type */
239: { TSCH5_FCONTROL, /* control byte for Tuner PLL */
240: TSCH5_FCONTROL,
241: TSCH5_FCONTROL,
242: TSCH5_RADIO },
243: { 0x00, 0x00 }, /* band-switch crosspoints */
244: { 0x14, 0x12, 0x11, 0x04 } }, /* the band-switch values */
245:
246: /* ALPS TSBH1 NTSC */
247: { "ALPS TSBH1 NTSC", /* the 'name' */
248: TTYPE_NTSC, /* input type */
249: { TSBH1_FCONTROL, /* control byte for Tuner PLL */
250: TSBH1_FCONTROL,
251: TSBH1_FCONTROL,
252: 0x00 },
253: { 0x00, 0x00 }, /* band-switch crosspoints */
254: { 0x01, 0x02, 0x08, 0x00 } }, /* the band-switch values */
255:
256: /* Tivision TVF5533-MF NTSC */
257: { "Tivision TVF5533-MF NTSC", /* the 'name' */
258: TTYPE_NTSC, /* input 'type' */
259: { TSBH1_FCONTROL, /* ctr byte for Tuner PLL */
260: TSBH1_FCONTROL,
261: TSBH1_FCONTROL,
262: 0x00 },
263: { 0x00, 0x00 }, /* band-switch crosspoints */
264: { 0x01, 0x02, 0x04, 0x00 } }, /* the band-switch values */
265: };
266:
267:
268: /* scaling factor for frequencies expressed as ints */
269: #define FREQFACTOR 16
270:
271: /*
272: * Format:
273: * entry 0: MAX legal channel
274: * entry 1: IF frequency
275: * expressed as fi{mHz} * 16,
276: * eg 45.75mHz == 45.75 * 16 = 732
277: * entry 2: [place holder/future]
278: * entry 3: base of channel record 0
279: * entry 3 + (x*3): base of channel record 'x'
280: * entry LAST: NULL channel entry marking end of records
281: *
282: * Record:
283: * int 0: base channel
284: * int 1: frequency of base channel,
285: * expressed as fb{mHz} * 16,
286: * int 2: offset frequency between channels,
287: * expressed as fo{mHz} * 16,
288: */
289:
290: /*
291: * North American Broadcast Channels:
292: *
293: * 2: 55.25 mHz - 4: 67.25 mHz
294: * 5: 77.25 mHz - 6: 83.25 mHz
295: * 7: 175.25 mHz - 13: 211.25 mHz
296: * 14: 471.25 mHz - 83: 885.25 mHz
297: *
298: * IF freq: 45.75 mHz
299: */
300: #define OFFSET 6.00
301: static const int nabcst[] = {
302: 83, (int)( 45.75 * FREQFACTOR), 0,
303: 14, (int)(471.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
304: 7, (int)(175.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
305: 5, (int)( 77.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
306: 2, (int)( 55.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
307: 0
308: };
309: #undef OFFSET
310:
311: /*
312: * North American Cable Channels, IRC:
313: *
314: * 2: 55.25 mHz - 4: 67.25 mHz
315: * 5: 77.25 mHz - 6: 83.25 mHz
316: * 7: 175.25 mHz - 13: 211.25 mHz
317: * 14: 121.25 mHz - 22: 169.25 mHz
318: * 23: 217.25 mHz - 94: 643.25 mHz
319: * 95: 91.25 mHz - 99: 115.25 mHz
320: *
321: * IF freq: 45.75 mHz
322: */
323: #define OFFSET 6.00
324: static const int irccable[] = {
325: 116, (int)( 45.75 * FREQFACTOR), 0,
326: 100, (int)(649.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
327: 95, (int)( 91.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
328: 23, (int)(217.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
329: 14, (int)(121.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
330: 7, (int)(175.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
331: 5, (int)( 77.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
332: 2, (int)( 55.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
333: 0
334: };
335: #undef OFFSET
336:
337: /*
338: * North American Cable Channels, HRC:
339: *
340: * 2: 54 mHz - 4: 66 mHz
341: * 5: 78 mHz - 6: 84 mHz
342: * 7: 174 mHz - 13: 210 mHz
343: * 14: 120 mHz - 22: 168 mHz
344: * 23: 216 mHz - 94: 642 mHz
345: * 95: 90 mHz - 99: 114 mHz
346: *
347: * IF freq: 45.75 mHz
348: */
349: #define OFFSET 6.00
350: static const int hrccable[] = {
351: 116, (int)( 45.75 * FREQFACTOR), 0,
352: 100, (int)(648.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
353: 95, (int)( 90.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
354: 23, (int)(216.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
355: 14, (int)(120.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
356: 7, (int)(174.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
357: 5, (int)( 78.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
358: 2, (int)( 54.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
359: 0
360: };
361: #undef OFFSET
362:
363: /*
364: * Western European broadcast channels:
365: *
366: * (there are others that appear to vary between countries - rmt)
367: *
368: * here's the table Philips provides:
369: * caution, some of the offsets don't compute...
370: *
371: * 1 4525 700 N21
372: *
373: * 2 4825 700 E2
374: * 3 5525 700 E3
375: * 4 6225 700 E4
376: *
377: * 5 17525 700 E5
378: * 6 18225 700 E6
379: * 7 18925 700 E7
380: * 8 19625 700 E8
381: * 9 20325 700 E9
382: * 10 21025 700 E10
383: * 11 21725 700 E11
384: * 12 22425 700 E12
385: *
386: * 13 5375 700 ITA
387: * 14 6225 700 ITB
388: *
389: * 15 8225 700 ITC
390: *
391: * 16 17525 700 ITD
392: * 17 18325 700 ITE
393: *
394: * 18 19225 700 ITF
395: * 19 20125 700 ITG
396: * 20 21025 700 ITH
397: *
398: * 21 47125 800 E21
399: * 22 47925 800 E22
400: * 23 48725 800 E23
401: * 24 49525 800 E24
402: * 25 50325 800 E25
403: * 26 51125 800 E26
404: * 27 51925 800 E27
405: * 28 52725 800 E28
406: * 29 53525 800 E29
407: * 30 54325 800 E30
408: * 31 55125 800 E31
409: * 32 55925 800 E32
410: * 33 56725 800 E33
411: * 34 57525 800 E34
412: * 35 58325 800 E35
413: * 36 59125 800 E36
414: * 37 59925 800 E37
415: * 38 60725 800 E38
416: * 39 61525 800 E39
417: * 40 62325 800 E40
418: * 41 63125 800 E41
419: * 42 63925 800 E42
420: * 43 64725 800 E43
421: * 44 65525 800 E44
422: * 45 66325 800 E45
423: * 46 67125 800 E46
424: * 47 67925 800 E47
425: * 48 68725 800 E48
426: * 49 69525 800 E49
427: * 50 70325 800 E50
428: * 51 71125 800 E51
429: * 52 71925 800 E52
430: * 53 72725 800 E53
431: * 54 73525 800 E54
432: * 55 74325 800 E55
433: * 56 75125 800 E56
434: * 57 75925 800 E57
435: * 58 76725 800 E58
436: * 59 77525 800 E59
437: * 60 78325 800 E60
438: * 61 79125 800 E61
439: * 62 79925 800 E62
440: * 63 80725 800 E63
441: * 64 81525 800 E64
442: * 65 82325 800 E65
443: * 66 83125 800 E66
444: * 67 83925 800 E67
445: * 68 84725 800 E68
446: * 69 85525 800 E69
447: *
448: * 70 4575 800 IA
449: * 71 5375 800 IB
450: * 72 6175 800 IC
451: *
452: * 74 6925 700 S01
453: * 75 7625 700 S02
454: * 76 8325 700 S03
455: *
456: * 80 10525 700 S1
457: * 81 11225 700 S2
458: * 82 11925 700 S3
459: * 83 12625 700 S4
460: * 84 13325 700 S5
461: * 85 14025 700 S6
462: * 86 14725 700 S7
463: * 87 15425 700 S8
464: * 88 16125 700 S9
465: * 89 16825 700 S10
466: * 90 23125 700 S11
467: * 91 23825 700 S12
468: * 92 24525 700 S13
469: * 93 25225 700 S14
470: * 94 25925 700 S15
471: * 95 26625 700 S16
472: * 96 27325 700 S17
473: * 97 28025 700 S18
474: * 98 28725 700 S19
475: * 99 29425 700 S20
476: *
477: *
478: * Channels S21 - S41 are taken from
479: * http://gemma.apple.com:80/dev/technotes/tn/tn1012.html
480: *
481: * 100 30325 800 S21
482: * 101 31125 800 S22
483: * 102 31925 800 S23
484: * 103 32725 800 S24
485: * 104 33525 800 S25
486: * 105 34325 800 S26
487: * 106 35125 800 S27
488: * 107 35925 800 S28
489: * 108 36725 800 S29
490: * 109 37525 800 S30
491: * 110 38325 800 S31
492: * 111 39125 800 S32
493: * 112 39925 800 S33
494: * 113 40725 800 S34
495: * 114 41525 800 S35
496: * 115 42325 800 S36
497: * 116 43125 800 S37
498: * 117 43925 800 S38
499: * 118 44725 800 S39
500: * 119 45525 800 S40
501: * 120 46325 800 S41
502: *
503: * 121 3890 000 IFFREQ
504: *
505: */
506: static const int weurope[] = {
507: 121, (int)( 38.90 * FREQFACTOR), 0,
508: 100, (int)(303.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
509: 90, (int)(231.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR),
510: 80, (int)(105.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR),
511: 74, (int)( 69.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR),
512: 21, (int)(471.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
513: 17, (int)(183.25 * FREQFACTOR), (int)(9.00 * FREQFACTOR),
514: 16, (int)(175.25 * FREQFACTOR), (int)(9.00 * FREQFACTOR),
515: 15, (int)(82.25 * FREQFACTOR), (int)(8.50 * FREQFACTOR),
516: 13, (int)(53.75 * FREQFACTOR), (int)(8.50 * FREQFACTOR),
517: 5, (int)(175.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR),
518: 2, (int)(48.25 * FREQFACTOR), (int)(7.00 * FREQFACTOR),
519: 0
520: };
521:
522: /*
523: * Japanese Broadcast Channels:
524: *
525: * 1: 91.25MHz - 3: 103.25MHz
526: * 4: 171.25MHz - 7: 189.25MHz
527: * 8: 193.25MHz - 12: 217.25MHz (VHF)
528: * 13: 471.25MHz - 62: 765.25MHz (UHF)
529: *
530: * IF freq: 45.75 mHz
531: * OR
532: * IF freq: 58.75 mHz
533: */
534: #define OFFSET 6.00
535: #define IF_FREQ 45.75
536: static const int jpnbcst[] = {
537: 62, (int)(IF_FREQ * FREQFACTOR), 0,
538: 13, (int)(471.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
539: 8, (int)(193.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
540: 4, (int)(171.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
541: 1, (int)( 91.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
542: 0
543: };
544: #undef IF_FREQ
545: #undef OFFSET
546:
547: /*
548: * Japanese Cable Channels:
549: *
550: * 1: 91.25MHz - 3: 103.25MHz
551: * 4: 171.25MHz - 7: 189.25MHz
552: * 8: 193.25MHz - 12: 217.25MHz
553: * 13: 109.25MHz - 21: 157.25MHz
554: * 22: 165.25MHz
555: * 23: 223.25MHz - 63: 463.25MHz
556: *
557: * IF freq: 45.75 mHz
558: */
559: #define OFFSET 6.00
560: #define IF_FREQ 45.75
561: static const int jpncable[] = {
562: 63, (int)(IF_FREQ * FREQFACTOR), 0,
563: 23, (int)(223.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
564: 22, (int)(165.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
565: 13, (int)(109.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
566: 8, (int)(193.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
567: 4, (int)(171.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
568: 1, (int)( 91.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
569: 0
570: };
571: #undef IF_FREQ
572: #undef OFFSET
573:
574: /*
575: * xUSSR Broadcast Channels:
576: *
577: * 1: 49.75MHz - 2: 59.25MHz
578: * 3: 77.25MHz - 5: 93.25MHz
579: * 6: 175.25MHz - 12: 223.25MHz
580: * 13-20 - not exist
581: * 21: 471.25MHz - 34: 575.25MHz
582: * 35: 583.25MHz - 69: 855.25MHz
583: *
584: * Cable channels
585: *
586: * 70: 111.25MHz - 77: 167.25MHz
587: * 78: 231.25MHz -107: 463.25MHz
588: *
589: * IF freq: 38.90 MHz
590: */
591: #define IF_FREQ 38.90
592: static const int xussr[] = {
593: 107, (int)(IF_FREQ * FREQFACTOR), 0,
594: 78, (int)(231.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
595: 70, (int)(111.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
596: 35, (int)(583.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
597: 21, (int)(471.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
598: 6, (int)(175.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
599: 3, (int)( 77.25 * FREQFACTOR), (int)(8.00 * FREQFACTOR),
600: 1, (int)( 49.75 * FREQFACTOR), (int)(9.50 * FREQFACTOR),
601: 0
602: };
603: #undef IF_FREQ
604:
605: /*
606: * Australian broadcast channels
607: */
608: #define OFFSET 7.00
609: #define IF_FREQ 38.90
610: static const int australia[] = {
611: 83, (int)(IF_FREQ * FREQFACTOR), 0,
612: 28, (int)(527.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
613: 10, (int)(209.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
614: 6, (int)(175.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
615: 4, (int)( 95.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
616: 3, (int)( 86.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
617: 1, (int)( 57.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR),
618: 0
619: };
620: #undef OFFSET
621: #undef IF_FREQ
622:
623: /*
624: * France broadcast channels
625: */
626: #define OFFSET 8.00
627: #define IF_FREQ 38.90
628: static const int france[] = {
629: 69, (int)(IF_FREQ * FREQFACTOR), 0,
630: 21, (int)(471.25 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), /* 21 -> 69 */
631: 5, (int)(176.00 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), /* 5 -> 10 */
632: 4, (int)( 63.75 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), /* 4 */
633: 3, (int)( 60.50 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), /* 3 */
634: 1, (int)( 47.75 * FREQFACTOR), (int)(OFFSET * FREQFACTOR), /* 1 2 */
635: 0
636: };
637: #undef OFFSET
638: #undef IF_FREQ
639:
640: static const struct {
641: const int *ptr;
642: char name[BT848_MAX_CHNLSET_NAME_LEN];
643: } freqTable[] = {
644: {NULL, ""},
645: {nabcst, "nabcst"},
646: {irccable, "cableirc"},
647: {hrccable, "cablehrc"},
648: {weurope, "weurope"},
649: {jpnbcst, "jpnbcst"},
650: {jpncable, "jpncable"},
651: {xussr, "xussr"},
652: {australia, "australia"},
653: {france, "france"},
654:
655: };
656:
657: #define TBL_CHNL freqTable[ bktr->tuner.chnlset ].ptr[ x ]
658: #define TBL_BASE_FREQ freqTable[ bktr->tuner.chnlset ].ptr[ x + 1 ]
659: #define TBL_OFFSET freqTable[ bktr->tuner.chnlset ].ptr[ x + 2 ]
660: static int
661: frequency_lookup( bktr_ptr_t bktr, int channel )
662: {
663: int x;
664:
665: /* check for "> MAX channel" */
666: x = 0;
667: if ( channel > TBL_CHNL )
668: return( -1 );
669:
670: /* search the table for data */
671: for ( x = 3; TBL_CHNL; x += 3 ) {
672: if ( channel >= TBL_CHNL ) {
673: return( TBL_BASE_FREQ +
674: ((channel - TBL_CHNL) * TBL_OFFSET) );
675: }
676: }
677:
678: /* not found, must be below the MIN channel */
679: return( -1 );
680: }
681: #undef TBL_OFFSET
682: #undef TBL_BASE_FREQ
683: #undef TBL_CHNL
684:
685:
686: #define TBL_IF freqTable[ bktr->tuner.chnlset ].ptr[ 1 ]
687:
688:
689: /* Initialise the tuner structures in the bktr_softc */
690: /* This is needed as the tuner details are no longer globally declared */
691:
692: void select_tuner( bktr_ptr_t bktr, int tuner_type ) {
693: if (tuner_type < Bt848_MAX_TUNER) {
694: bktr->card.tuner = &tuners[ tuner_type ];
695: } else {
696: bktr->card.tuner = NULL;
697: }
698: }
699:
700: /*
701: * Tuner Notes:
702: * Programming the tuner properly is quite complicated.
703: * Here are some notes, based on a FM1246 data sheet for a PAL-I tuner.
704: * The tuner (front end) covers 45.75 MHz - 855.25 MHz and an FM band of
705: * 87.5 MHz to 108.0 MHz.
706: *
707: * RF and IF. RF = radio frequencies, it is the transmitted signal.
708: * IF is the Intermediate Frequency (the offset from the base
709: * signal where the video, color, audio and NICAM signals are.
710: *
711: * Eg, Picture at 38.9 MHz, Colour at 34.47 MHz, sound at 32.9 MHz
712: * NICAM at 32.348 MHz.
713: * Strangely enough, there is an IF (intermediate frequency) for
714: * FM Radio which is 10.7 MHz.
715: *
716: * The tuner also works in Bands. Philips bands are
717: * FM radio band 87.50 to 108.00 MHz
718: * Low band 45.75 to 170.00 MHz
719: * Mid band 170.00 to 450.00 MHz
720: * High band 450.00 to 855.25 MHz
721: *
722: *
723: * Now we need to set the PLL on the tuner to the required freuqncy.
724: * It has a programmable divisor.
725: * For TV we want
726: * N = 16 (freq RF(pc) + freq IF(pc)) pc is picture carrier and RF and IF
727: * are in MHz.
728:
729: * For RADIO we want a different equation.
730: * freq IF is 10.70 MHz (so the data sheet tells me)
731: * N = (freq RF + freq IF) / step size
732: * The step size must be set to 50 khz (so the data sheet tells me)
733: * (note this is 50 kHz, the other things are in MHz)
734: * so we end up with N = 20x(freq RF + 10.7)
735: *
736: */
737:
738: #define LOW_BAND 0
739: #define MID_BAND 1
740: #define HIGH_BAND 2
741: #define FM_RADIO_BAND 3
742:
743:
744: /* Check if these are correct for other than Philips PAL */
745: #define STATUSBIT_COLD 0x80
746: #define STATUSBIT_LOCK 0x40
747: #define STATUSBIT_TV 0x20
748: #define STATUSBIT_STEREO 0x10 /* valid if FM (aka not TV) */
749: #define STATUSBIT_ADC 0x07
750:
751: /*
752: * set the frequency of the tuner
753: * If 'type' is TV_FREQUENCY, the frequency is freq MHz*16
754: * If 'type' is FM_RADIO_FREQUENCY, the frequency is freq MHz * 100
755: * (note *16 gives is 4 bits of fraction, eg steps of nnn.0625)
756: *
757: */
758: int
759: tv_freq( bktr_ptr_t bktr, int frequency, int type )
760: {
761: const struct TUNER* tuner;
762: u_char addr;
763: u_char control;
764: u_char band;
765: int N;
766: int band_select = 0;
767: #if defined( TEST_TUNER_AFC )
768: int oldFrequency, afcDelta;
769: #endif
770:
771: tuner = bktr->card.tuner;
772: if ( tuner == NULL )
773: return( -1 );
774:
775: if (type == TV_FREQUENCY) {
776: /*
777: * select the band based on frequency
778: * XXX FIXME: get the cross-over points from the tuner struct
779: */
780: if ( frequency < (160 * FREQFACTOR ) )
781: band_select = LOW_BAND;
782: else if ( frequency < (454 * FREQFACTOR ) )
783: band_select = MID_BAND;
784: else
785: band_select = HIGH_BAND;
786:
787: bktr->tuner.tuner_mode = BT848_TUNER_MODE_TV;
788:
789: #if defined( TEST_TUNER_AFC )
790: if ( bktr->tuner.afc )
791: frequency -= 4;
792: #endif
793: /*
794: * N = 16 * { fRF(pc) + fIF(pc) }
795: * or N = 16* fRF(pc) + 16*fIF(pc) }
796: * where:
797: * pc is picture carrier, fRF & fIF are in MHz
798: *
799: * fortunatly, frequency is passed in as MHz * 16
800: * and the TBL_IF frequency is also stored in MHz * 16
801: */
802: N = frequency + TBL_IF;
803:
804: /* set the address of the PLL */
805: addr = bktr->card.tuner_pllAddr;
806: control = tuner->pllControl[ band_select ];
807: band = tuner->bandAddrs[ band_select ];
808:
809: if(!(band && control)) /* Don't try to set un- */
810: return(-1); /* supported modes. */
811:
812: if ( frequency > bktr->tuner.frequency ) {
813: i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff );
814: i2cWrite( bktr, addr, control, band );
815: }
816: else {
817: i2cWrite( bktr, addr, control, band );
818: i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff );
819: }
820:
821: #if defined( TUNER_AFC )
822: if ( bktr->tuner.afc == TRUE ) {
823: #if defined( TEST_TUNER_AFC )
824: oldFrequency = frequency;
825: #endif
826: if ( (N = do_afc( bktr, addr, N )) < 0 ) {
827: /* AFC failed, restore requested frequency */
828: N = frequency + TBL_IF;
829: #if defined( TEST_TUNER_AFC )
830: printf("%s: do_afc: failed to lock\n",
831: bktr_name(bktr));
832: #endif
833: i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff );
834: }
835: else
836: frequency = N - TBL_IF;
837: #if defined( TEST_TUNER_AFC )
838: printf("%s: do_afc: returned freq %d (%d %% %d)\n", bktr_name(bktr), frequency, frequency / 16, frequency % 16);
839: afcDelta = frequency - oldFrequency;
840: printf("%s: changed by: %d clicks (%d mod %d)\n", bktr_name(bktr), afcDelta, afcDelta / 16, afcDelta % 16);
841: #endif
842: }
843: #endif /* TUNER_AFC */
844:
845: bktr->tuner.frequency = frequency;
846: }
847:
848: if ( type == FM_RADIO_FREQUENCY ) {
849: band_select = FM_RADIO_BAND;
850:
851: bktr->tuner.tuner_mode = BT848_TUNER_MODE_RADIO;
852:
853: /*
854: * N = { fRF(pc) + fIF(pc) }/step_size
855: * The step size is 50kHz for FM radio.
856: * (eg after 102.35MHz comes 102.40 MHz)
857: * fIF is 10.7 MHz (as detailed in the specs)
858: *
859: * frequency is passed in as MHz * 100
860: *
861: * So, we have N = (frequency/100 + 10.70) /(50/1000)
862: */
863: N = (frequency + 1070)/5;
864:
865: /* set the address of the PLL */
866: addr = bktr->card.tuner_pllAddr;
867: control = tuner->pllControl[ band_select ];
868: band = tuner->bandAddrs[ band_select ];
869:
870: if(!(band && control)) /* Don't try to set un- */
871: return(-1); /* supported modes. */
872:
873: band |= bktr->tuner.radio_mode; /* tuner.radio_mode is set in
874: * the ioctls RADIO_SETMODE
875: * and RADIO_GETMODE */
876:
877: i2cWrite( bktr, addr, control, band );
878: i2cWrite( bktr, addr, (N>>8) & 0x7f, N & 0xff );
879:
880: bktr->tuner.frequency = (N * 5) - 1070;
881:
882:
883: }
884:
885:
886: return( 0 );
887: }
888:
889:
890:
891: #if defined( TUNER_AFC )
892: /*
893: *
894: */
895: int
896: do_afc( bktr_ptr_t bktr, int addr, int frequency )
897: {
898: int step;
899: int status;
900: int origFrequency;
901:
902: origFrequency = frequency;
903:
904: /* wait for first setting to take effect */
905: tsleep( BKTR_SLEEP, PZERO, "tuning", hz/8 );
906:
907: if ( (status = i2cRead( bktr, addr + 1 )) < 0 )
908: return( -1 );
909:
910: #if defined( TEST_TUNER_AFC )
911: printf( "%s: Original freq: %d, status: 0x%02x\n", bktr_name(bktr), frequency, status );
912: #endif
913: for ( step = 0; step < AFC_MAX_STEP; ++step ) {
914: if ( (status = i2cRead( bktr, addr + 1 )) < 0 )
915: goto fubar;
916: if ( !(status & 0x40) ) {
917: #if defined( TEST_TUNER_AFC )
918: printf( "%s: no lock!\n", bktr_name(bktr) );
919: #endif
920: goto fubar;
921: }
922:
923: switch( status & AFC_BITS ) {
924: case AFC_FREQ_CENTERED:
925: #if defined( TEST_TUNER_AFC )
926: printf( "%s: Centered, freq: %d, status: 0x%02x\n", bktr_name(bktr), frequency, status );
927: #endif
928: return( frequency );
929:
930: case AFC_FREQ_MINUS_125:
931: case AFC_FREQ_MINUS_62:
932: #if defined( TEST_TUNER_AFC )
933: printf( "%s: Low, freq: %d, status: 0x%02x\n", bktr_name(bktr), frequency, status );
934: #endif
935: --frequency;
936: break;
937:
938: case AFC_FREQ_PLUS_62:
939: case AFC_FREQ_PLUS_125:
940: #if defined( TEST_TUNER_AFC )
941: printf( "%s: Hi, freq: %d, status: 0x%02x\n", bktr_name(bktr), frequency, status );
942: #endif
943: ++frequency;
944: break;
945: }
946:
947: i2cWrite( bktr, addr,
948: (frequency>>8) & 0x7f, frequency & 0xff );
949: DELAY( AFC_DELAY );
950: }
951:
952: fubar:
953: i2cWrite( bktr, addr,
954: (origFrequency>>8) & 0x7f, origFrequency & 0xff );
955:
956: return( -1 );
957: }
958: #endif /* TUNER_AFC */
959: #undef TBL_IF
960:
961:
962: /*
963: * Get the Tuner status and signal strength
964: */
965: int get_tuner_status( bktr_ptr_t bktr ) {
966: return i2cRead( bktr, bktr->card.tuner_pllAddr + 1 );
967: }
968:
969: /*
970: * set the channel of the tuner
971: */
972: int
973: tv_channel( bktr_ptr_t bktr, int channel )
974: {
975: int frequency;
976:
977: /* calculate the frequency according to tuner type */
978: if ( (frequency = frequency_lookup( bktr, channel )) < 0 )
979: return( -1 );
980:
981: /* set the new frequency */
982: if ( tv_freq( bktr, frequency, TV_FREQUENCY ) < 0 )
983: return( -1 );
984:
985: /* OK to update records */
986: return( (bktr->tuner.channel = channel) );
987: }
988:
989: /*
990: * get channelset name
991: */
992: int
993: tuner_getchnlset(struct bktr_chnlset *chnlset)
994: {
995: if (( chnlset->index < CHNLSET_MIN ) ||
996: ( chnlset->index > CHNLSET_MAX ))
997: return( EINVAL );
998:
999: memcpy(&chnlset->name, &freqTable[chnlset->index].name,
1000: BT848_MAX_CHNLSET_NAME_LEN);
1001:
1002: chnlset->max_channel=freqTable[chnlset->index].ptr[0];
1003: return( 0 );
1004: }
CVSweb