vserver 1.9.5.x5
[linux-2.6.git] / drivers / media / video / cx88 / cx88-cards.c
1 /*
2  * $Id: cx88-cards.c,v 1.47 2004/11/03 09:04:50 kraxel Exp $
3  *
4  * device driver for Conexant 2388x based TV cards
5  * card-specific stuff.
6  *
7  * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  */
23
24 #include <linux/init.h>
25 #include <linux/module.h>
26 #include <linux/pci.h>
27 #include <linux/delay.h>
28
29 #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
30 # define WITH_DVB 1
31 #endif
32
33 #include "cx88.h"
34 #ifdef WITH_DVB
35 #include "cx22702.h"
36 #endif
37
38 /* ------------------------------------------------------------------ */
39 /* board config info                                                  */
40
41 struct cx88_board cx88_boards[] = {
42         [CX88_BOARD_UNKNOWN] = {
43                 .name           = "UNKNOWN/GENERIC",
44                 .tuner_type     = UNSET,
45                 .input          = {{
46                         .type   = CX88_VMUX_COMPOSITE1,
47                         .vmux   = 0,
48                 },{
49                         .type   = CX88_VMUX_COMPOSITE2,
50                         .vmux   = 1,
51                 },{
52                         .type   = CX88_VMUX_COMPOSITE3,
53                         .vmux   = 2,
54                 },{
55                         .type   = CX88_VMUX_COMPOSITE4,
56                         .vmux   = 3,
57                 }},
58         },
59         [CX88_BOARD_HAUPPAUGE] = {
60                 .name           = "Hauppauge WinTV 34xxx models",
61                 .tuner_type     = UNSET,
62                 .input          = {{
63                         .type   = CX88_VMUX_TELEVISION,
64                         .vmux   = 0,
65                         .gpio0  = 0xff00,  // internal decoder
66                 },{
67                         .type   = CX88_VMUX_DEBUG,
68                         .vmux   = 0,
69                         .gpio0  = 0xff01,  // mono from tuner chip
70                 },{
71                         .type   = CX88_VMUX_COMPOSITE1,
72                         .vmux   = 1,
73                         .gpio0  = 0xff02,
74                 },{
75                         .type   = CX88_VMUX_SVIDEO,
76                         .vmux   = 2,
77                         .gpio0  = 0xff02,
78                 }},
79                 .radio = {
80                         .type   = CX88_RADIO,
81                         .gpio0  = 0xff01,
82                 },
83         },
84         [CX88_BOARD_GDI] = {
85                 .name           = "GDI Black Gold",
86                 .tuner_type     = UNSET,
87                 .input          = {{
88                         .type   = CX88_VMUX_TELEVISION,
89                         .vmux   = 0,
90                 }},
91         },
92         [CX88_BOARD_PIXELVIEW] = {
93                 .name           = "PixelView",
94                 .tuner_type     = UNSET,
95                 .input          = {{
96                         .type   = CX88_VMUX_TELEVISION,
97                         .vmux   = 0,
98                         .gpio0  = 0xff00,  // internal decoder
99                 },{
100                         .type   = CX88_VMUX_COMPOSITE1,
101                         .vmux   = 1,
102                 },{
103                         .type   = CX88_VMUX_SVIDEO,
104                         .vmux   = 2,
105                 }},
106                 .radio = {
107                          .type  = CX88_RADIO,
108                          .gpio0 = 0xff10,
109                  },
110         },
111         [CX88_BOARD_ATI_WONDER_PRO] = {
112                 .name           = "ATI TV Wonder Pro",
113                 .tuner_type     = 44,
114                 .tda9887_conf   = TDA9887_PRESENT | TDA9887_INTERCARRIER,
115                 .input          = {{
116                         .type   = CX88_VMUX_TELEVISION,
117                         .vmux   = 0,
118                         .gpio0  = 0x03ff,
119                 },{
120                         .type   = CX88_VMUX_COMPOSITE1,
121                         .vmux   = 1,
122                         .gpio0  = 0x03fe,
123                 },{
124                         .type   = CX88_VMUX_SVIDEO,
125                         .vmux   = 2,
126                         .gpio0  = 0x03fe,
127                 }},
128         },
129         [CX88_BOARD_WINFAST2000XP] = {
130                 .name           = "Leadtek Winfast 2000XP Expert",
131                 .tuner_type     = 44,
132                 .tda9887_conf   = TDA9887_PRESENT,
133                 .input          = {{
134                         .type   = CX88_VMUX_TELEVISION,
135                         .vmux   = 0,
136                         .gpio0  = 0x00F5e700,
137                         .gpio1  = 0x00003004,
138                         .gpio2  = 0x00F5e700,
139                         .gpio3  = 0x02000000,
140                 },{
141                         .type   = CX88_VMUX_COMPOSITE1,
142                         .vmux   = 1,
143                         .gpio0  = 0x00F5c700,
144                         .gpio1  = 0x00003004,
145                         .gpio2  = 0x00F5c700,
146                         .gpio3  = 0x02000000,
147                 },{
148                         .type   = CX88_VMUX_SVIDEO,
149                         .vmux   = 2,
150                         .gpio0  = 0x00F5c700,
151                         .gpio1  = 0x00003004,
152                         .gpio2  = 0x00F5c700,
153                         .gpio3  = 0x02000000,
154                 }},
155                 .radio = {
156                         .type   = CX88_RADIO,
157                         .gpio0  = 0x00F5d700,
158                         .gpio1  = 0x00003004,
159                         .gpio2  = 0x00F5d700,
160                         .gpio3  = 0x02000000,
161                 },
162         },
163         [CX88_BOARD_AVERTV_303] = {
164                 .name           = "AverTV Studio 303 (M126)",
165                 .tuner_type     = 38,
166                 .tda9887_conf   = TDA9887_PRESENT,
167                 .input          = {{
168                         .type   = CX88_VMUX_TELEVISION,
169                         .vmux   = 0,
170                         .gpio1  = 0x309f,
171                 },{
172                         .type   = CX88_VMUX_COMPOSITE1,
173                         .vmux   = 1,
174                         .gpio1  = 0x305f,
175                 },{
176                         .type   = CX88_VMUX_SVIDEO,
177                         .vmux   = 2,
178                         .gpio1  = 0x305f,
179                 }},
180                 .radio = {
181                         .type   = CX88_RADIO,
182                 },
183         },
184         [CX88_BOARD_MSI_TVANYWHERE_MASTER] = {
185                 // added gpio values thanks to Michal
186                 // values for PAL from DScaler
187                 .name           = "MSI TV-@nywhere Master",
188                 .tuner_type     = 33,
189                 .tda9887_conf   = TDA9887_PRESENT,
190                 .input          = {{
191                         .type   = CX88_VMUX_TELEVISION,
192                         .vmux   = 0,
193                         .gpio0  = 0x000040bf,
194                         .gpio1  = 0x000080c0,
195                         .gpio2  = 0x0000ff40,
196                 },{
197                         .type   = CX88_VMUX_COMPOSITE1,
198                         .vmux   = 1,
199                         .gpio0  = 0x000040bf,
200                         .gpio1  = 0x000080c0,
201                         .gpio2  = 0x0000ff40,
202                 },{
203                         .type   = CX88_VMUX_SVIDEO,
204                         .vmux   = 2,
205                         .gpio0  = 0x000040bf,
206                         .gpio1  = 0x000080c0,
207                         .gpio2  = 0x0000ff40,
208                 }},
209                 .radio = {
210                          .type   = CX88_RADIO,
211                 },
212         },
213         [CX88_BOARD_WINFAST_DV2000] = {
214                 .name           = "Leadtek Winfast DV2000",
215                 .tuner_type     = 38,
216                 .tda9887_conf   = TDA9887_PRESENT,
217                 .input          = {{
218                         .type   = CX88_VMUX_TELEVISION,
219                         .vmux   = 0,
220                 }},
221                 .radio = {
222                         .type   = CX88_RADIO,
223                 },
224         },
225         [CX88_BOARD_LEADTEK_PVR2000] = {
226                 .name           = "Leadtek PVR 2000",
227                 .tuner_type     = 38,
228                 .input          = {{
229                         .type   = CX88_VMUX_TELEVISION,
230                         .vmux   = 0,
231                 },{
232                         .type   = CX88_VMUX_COMPOSITE1,
233                         .vmux   = 1,
234                 },{
235                         .type   = CX88_VMUX_SVIDEO,
236                         .vmux   = 2,
237                 }},
238                 .radio = {
239                         .type   = CX88_RADIO,
240                 },
241                 .blackbird = 1,
242         },
243         [CX88_BOARD_IODATA_GVVCP3PCI] = {
244                 .name           = "IODATA GV-VCP3/PCI",
245                 .tuner_type     = TUNER_ABSENT,
246                 .input          = {{
247                         .type   = CX88_VMUX_COMPOSITE1,
248                         .vmux   = 0,
249                 },{
250                         .type   = CX88_VMUX_COMPOSITE2,
251                         .vmux   = 1,
252                 },{
253                         .type   = CX88_VMUX_SVIDEO,
254                         .vmux   = 2,
255                 }},
256         },
257         [CX88_BOARD_PROLINK_PLAYTVPVR] = {
258                 .name           = "Prolink PlayTV PVR",
259                 .tuner_type     = 43,
260                 .tda9887_conf   = TDA9887_PRESENT,
261                 .input          = {{
262                         .type   = CX88_VMUX_TELEVISION,
263                         .vmux   = 0,
264                         .gpio0  = 0xff00,
265                 },{
266                         .type   = CX88_VMUX_COMPOSITE1,
267                         .vmux   = 1,
268                         .gpio0  = 0xff03,
269                 },{
270                         .type   = CX88_VMUX_SVIDEO,
271                         .vmux   = 2,
272                         .gpio0  = 0xff03,
273                 }},
274                 .radio = {
275                         .type   = CX88_RADIO,
276                         .gpio0  = 0xff00,
277                 },
278         },
279         [CX88_BOARD_ASUS_PVR_416] = {
280                 .name           = "ASUS PVR-416",
281                 .tuner_type     = 43,
282                 .tda9887_conf   = TDA9887_PRESENT,
283                 .input          = {{
284                         .type   = CX88_VMUX_TELEVISION,
285                         .vmux   = 0,
286                         .gpio0  = 0x0000fde6,
287                 },{
288                         .type   = CX88_VMUX_SVIDEO,
289                         .vmux   = 2,
290                         .gpio0  = 0x0000fde6, // 0x0000fda6 L,R RCA audio in?
291                 }},
292                 .radio = {
293                         .type   = CX88_RADIO,
294                         .gpio0  = 0x0000fde2,
295                 },
296                 .blackbird = 1,
297         },
298         [CX88_BOARD_MSI_TVANYWHERE] = {
299                 .name           = "MSI TV-@nywhere",
300                 .tuner_type     = 33,
301                 .tda9887_conf   = TDA9887_PRESENT,
302                 .input          = {{
303                         .type   = CX88_VMUX_TELEVISION,
304                         .vmux   = 0,
305                         .gpio0  = 0x00000fbf,
306                         .gpio2  = 0x0000fc08,
307                 },{
308                         .type   = CX88_VMUX_COMPOSITE1,
309                         .vmux   = 1,
310                         .gpio0  = 0x00000fbf,
311                         .gpio2  = 0x0000fc68,
312                 },{
313                         .type   = CX88_VMUX_SVIDEO,
314                         .vmux   = 2,
315                         .gpio0  = 0x00000fbf,
316                         .gpio2  = 0x0000fc68,
317                 }},
318         },
319         [CX88_BOARD_KWORLD_DVB_T] = {
320                 .name           = "KWorld/VStream XPert DVB-T",
321                 .tuner_type     = TUNER_ABSENT,
322                 .input          = {{
323                         .type   = CX88_VMUX_DVB,
324                         .vmux   = 0,
325                 },{
326                         .type   = CX88_VMUX_COMPOSITE1,
327                         .vmux   = 1,
328                 },{
329                         .type   = CX88_VMUX_SVIDEO,
330                         .vmux   = 2,
331                 }},
332                 .dvb            = 1,
333         },
334         [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
335                 .name           = "DVICO FusionHDTV DVB-T1",
336                 .tuner_type     = TUNER_ABSENT, /* No analog tuner */
337                 .input          = {{
338                         .type   = CX88_VMUX_COMPOSITE1,
339                         .vmux   = 1,
340                         .gpio0  = 0x000027df,
341                  },{
342                         .type   = CX88_VMUX_SVIDEO,
343                         .vmux   = 2,
344                         .gpio0  = 0x000027df,
345                 }},
346                 .dvb            = 1,
347         },
348         [CX88_BOARD_KWORLD_LTV883] = {
349                 .name           = "KWorld LTV883RF",
350                 .tuner_type     = 48,
351                 .input          = {{
352                         .type   = CX88_VMUX_TELEVISION,
353                         .vmux   = 0,
354                         .gpio0  = 0x07f8,
355                 },{
356                         .type   = CX88_VMUX_DEBUG,
357                         .vmux   = 0,
358                         .gpio0  = 0x07f9,  // mono from tuner chip
359                 },{
360                         .type   = CX88_VMUX_COMPOSITE1,
361                         .vmux   = 1,
362                         .gpio0  = 0x000007fa,
363                 },{
364                         .type   = CX88_VMUX_SVIDEO,
365                         .vmux   = 2,
366                         .gpio0  = 0x000007fa,
367                 }},
368                 .radio = {
369                         .type   = CX88_RADIO,
370                         .gpio0  = 0x000007f8,
371                 },
372         },
373         [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD] = {
374                 .name           = "DViCO - FusionHDTV 3 Gold",
375                 .tuner_type     = TUNER_MICROTUNE_4042FI5,
376                 /*
377                    GPIO[0] resets DT3302 DTV receiver
378                     0 - reset asserted
379                     1 - normal operation
380                    GPIO[1] mutes analog audio output connector
381                     0 - enable selected source
382                     1 - mute
383                    GPIO[2] selects source for analog audio output connector
384                     0 - analog audio input connector on tab
385                     1 - analog DAC output from CX23881 chip
386                    GPIO[3] selects RF input connector on tuner module
387                     0 - RF connector labeled CABLE
388                     1 - RF connector labeled ANT
389                 */
390                 .input          = {{
391                         .type   = CX88_VMUX_TELEVISION,
392                         .vmux   = 0,
393                         .gpio0  = 0x0f0d,
394                 },{
395                         .type   = CX88_VMUX_CABLE,
396                         .vmux   = 0,
397                         .gpio0  = 0x0f05,
398                 },{
399                         .type   = CX88_VMUX_COMPOSITE1,
400                         .vmux   = 1,
401                         .gpio0  = 0x0f00,
402                 },{
403                         .type   = CX88_VMUX_SVIDEO,
404                         .vmux   = 2,
405                         .gpio0  = 0x0f00,
406                 }},
407 #if 0
408                 .ts             = {
409                          .type   = CX88_TS,
410                          .gpio0  = 0x00000f01,   /* Hooked to tuner reset bit */
411                  }
412 #endif
413         },
414         [CX88_BOARD_HAUPPAUGE_DVB_T1] = {
415                 .name           = "Hauppauge Nova-T DVB-T",
416                 .tuner_type     = TUNER_ABSENT,
417                 .input          = {{
418                         .type   = CX88_VMUX_DVB,
419                         .vmux   = 0,
420                 }},
421                 .dvb            = 1,
422         },
423         [CX88_BOARD_CONEXANT_DVB_T1] = {
424                 .name           = "Conexant DVB-T reference design",
425                 .tuner_type     = TUNER_ABSENT,
426                 .input          = {{
427                         .type   = CX88_VMUX_DVB,
428                         .vmux   = 0,
429                 }},
430                 .dvb            = 1,
431         },
432         [CX88_BOARD_PROVIDEO_PV259] = {
433                 .name           = "Provideo PV259",
434                 .tuner_type     = TUNER_PHILIPS_FQ1216ME,
435                 .input          = {{
436                         .type   = CX88_VMUX_TELEVISION,
437                         .vmux   = 0,
438                 }},
439                 .blackbird = 1,
440         },
441         [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
442                 .name           = "DVICO FusionHDTV DVB-T Plus",
443                 .tuner_type     = TUNER_ABSENT, /* No analog tuner */
444                 .input          = {{
445                         .type   = CX88_VMUX_COMPOSITE1,
446                         .vmux   = 1,
447                         .gpio0  = 0x000027df,
448                  },{
449                         .type   = CX88_VMUX_SVIDEO,
450                         .vmux   = 2,
451                         .gpio0  = 0x000027df,
452                 }},
453                 .dvb            = 1,
454         },
455 };
456 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
457
458 /* ------------------------------------------------------------------ */
459 /* PCI subsystem IDs                                                  */
460
461 struct cx88_subid cx88_subids[] = {
462         {
463                 .subvendor = 0x0070,
464                 .subdevice = 0x3400,
465                 .card      = CX88_BOARD_HAUPPAUGE,
466         },{
467                 .subvendor = 0x0070,
468                 .subdevice = 0x3401,
469                 .card      = CX88_BOARD_HAUPPAUGE,
470         },{
471                 .subvendor = 0x14c7,
472                 .subdevice = 0x0106,
473                 .card      = CX88_BOARD_GDI,
474         },{
475                 .subvendor = 0x14c7,
476                 .subdevice = 0x0107, /* with mpeg encoder */
477                 .card      = CX88_BOARD_GDI,
478         },{
479                 .subvendor = PCI_VENDOR_ID_ATI,
480                 .subdevice = 0x00f8,
481                 .card      = CX88_BOARD_ATI_WONDER_PRO,
482         },{
483                 .subvendor = 0x107d,
484                 .subdevice = 0x6611,
485                 .card      = CX88_BOARD_WINFAST2000XP,
486         },{
487                 .subvendor = 0x107d,
488                 .subdevice = 0x6613,    /* NTSC */
489                 .card      = CX88_BOARD_WINFAST2000XP,
490         },{
491                 .subvendor = 0x107d,
492                 .subdevice = 0x6620,
493                 .card      = CX88_BOARD_WINFAST_DV2000,
494         },{
495                 .subvendor = 0x107d,
496                 .subdevice = 0x663b,
497                 .card      = CX88_BOARD_LEADTEK_PVR2000,
498         },{
499                 .subvendor = 0x107d,
500                 .subdevice = 0x663C,
501                 .card      = CX88_BOARD_LEADTEK_PVR2000,
502         },{
503                 .subvendor = 0x1461,
504                 .subdevice = 0x000b,
505                 .card      = CX88_BOARD_AVERTV_303,
506         },{
507                 .subvendor = 0x1462,
508                 .subdevice = 0x8606,
509                 .card      = CX88_BOARD_MSI_TVANYWHERE_MASTER,
510         },{
511                 .subvendor = 0x10fc,
512                 .subdevice = 0xd003,
513                 .card      = CX88_BOARD_IODATA_GVVCP3PCI,
514         },{
515                 .subvendor = 0x1043,
516                 .subdevice = 0x4823,  /* with mpeg encoder */
517                 .card      = CX88_BOARD_ASUS_PVR_416,
518         },{
519                 .subvendor = 0x17de,
520                 .subdevice = 0x08a6,
521                 .card      = CX88_BOARD_KWORLD_DVB_T,
522         },{
523                 .subvendor = 0x18ac,
524                 .subdevice = 0xd810,
525                 .card      = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD,
526         },{
527                 .subvendor = 0x18AC,
528                 .subdevice = 0xDB00,
529                 .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1,
530         },{
531                 .subvendor = 0x0070,
532                 .subdevice = 0x9002,
533                 .card      = CX88_BOARD_HAUPPAUGE_DVB_T1,
534         },{
535                 .subvendor = 0x14f1,
536                 .subdevice = 0x0187,
537                 .card      = CX88_BOARD_CONEXANT_DVB_T1,
538         },{
539                 .subvendor = 0x1540,
540                 .subdevice = 0x2580,
541                 .card      = CX88_BOARD_PROVIDEO_PV259,
542         },{
543                 .subvendor = 0x18AC,
544                 .subdevice = 0xDB10,
545                 .card      = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
546         }
547 };
548 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
549
550 /* ----------------------------------------------------------------------- */
551 /* some leadtek specific stuff                                             */
552
553 static void __devinit leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
554 {
555         /* This is just for the Winfast 2000 XP board ATM; I don't have data on
556          * any others.
557          *
558          * Byte 0 is 1 on the NTSC board.
559          */
560
561         if (eeprom_data[4] != 0x7d ||
562             eeprom_data[5] != 0x10 ||
563             eeprom_data[7] != 0x66) {
564                 printk(KERN_WARNING "%s: Leadtek eeprom invalid.\n",
565                        core->name);
566                 return;
567         }
568
569         core->has_radio  = 1;
570         core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38;
571
572         printk(KERN_INFO "%s: Leadtek Winfast 2000 XP config: "
573                "tuner=%d, eeprom[0]=0x%02x\n",
574                core->name, core->tuner_type, eeprom_data[0]);
575 }
576
577
578 /* ----------------------------------------------------------------------- */
579 /* some hauppauge specific stuff                                           */
580
581 static struct {
582         int  id;
583         char *name;
584 } hauppauge_tuner[] __devinitdata = {
585         { TUNER_ABSENT,        "" },
586         { TUNER_ABSENT,        "External" },
587         { TUNER_ABSENT,        "Unspecified" },
588         { TUNER_PHILIPS_PAL,   "Philips FI1216" },
589         { TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
590         { TUNER_PHILIPS_NTSC,  "Philips FI1236" },
591         { TUNER_PHILIPS_PAL_I, "Philips FI1246" },
592         { TUNER_PHILIPS_PAL_DK,"Philips FI1256" },
593         { TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },
594         { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
595         { TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },
596         { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
597         { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" },
598         { TUNER_TEMIC_NTSC,    "Temic 4032FY5" },
599         { TUNER_TEMIC_PAL,     "Temic 4002FH5" },
600         { TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },
601         { TUNER_PHILIPS_PAL,   "Philips FR1216 MK2" },
602         { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
603         { TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },
604         { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
605         { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" },
606         { TUNER_PHILIPS_PAL,   "Philips FM1216" },
607         { TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
608         { TUNER_PHILIPS_NTSC,  "Philips FM1236" },
609         { TUNER_PHILIPS_PAL_I, "Philips FM1246" },
610         { TUNER_PHILIPS_PAL_DK,"Philips FM1256" },
611         { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
612         { TUNER_ABSENT,        "Samsung TCPN9082D" },
613         { TUNER_ABSENT,        "Samsung TCPM9092P" },
614         { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
615         { TUNER_ABSENT,        "Samsung TCPN9085D" },
616         { TUNER_ABSENT,        "Samsung TCPB9085P" },
617         { TUNER_ABSENT,        "Samsung TCPL9091P" },
618         { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
619         { TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
620         { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
621         { TUNER_PHILIPS_NTSC,        "Philips TD1536" },
622         { TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
623         { TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
624         { TUNER_ABSENT,        "Philips FI1256MP" },
625         { TUNER_ABSENT,        "Samsung TCPQ9091P" },
626         { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
627         { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
628         { TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
629         { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
630         { TUNER_ABSENT,        "Philips TD1536D_FH_44"},
631         { TUNER_LG_NTSC_FM,    "LG TPI8NSR01F"},
632         { TUNER_LG_PAL_FM,     "LG TPI8PSB01D"},
633         { TUNER_LG_PAL,        "LG TPI8PSB11D"},
634         { TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
635         { TUNER_LG_PAL_I,      "LG TAPC-I701D"}
636 };
637
638 static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
639 {
640         unsigned int blk2,tuner,radio,model;
641
642         if (eeprom_data[0] != 0x84 || eeprom_data[2] != 0) {
643                 printk(KERN_WARNING "%s: Hauppauge eeprom: invalid\n",
644                        core->name);
645                 return;
646         }
647
648         /* Block 2 starts after len+3 bytes header */
649         blk2 = eeprom_data[1] + 3;
650
651         /* decode + use some config infos */
652         model = eeprom_data[12] << 8 | eeprom_data[11];
653         tuner = eeprom_data[9];
654         radio = eeprom_data[blk2-1] & 0x01;
655
656         if (tuner < ARRAY_SIZE(hauppauge_tuner))
657                 core->tuner_type = hauppauge_tuner[tuner].id;
658         if (radio)
659                 core->has_radio = 1;
660
661         printk(KERN_INFO "%s: hauppauge eeprom: model=%d, "
662                "tuner=%s (%d), radio=%s\n",
663                core->name, model, (tuner < ARRAY_SIZE(hauppauge_tuner)
664                                    ? hauppauge_tuner[tuner].name : "?"),
665                core->tuner_type, radio ? "yes" : "no");
666 }
667
668 #ifdef WITH_DVB
669 static int hauppauge_eeprom_dvb(struct cx88_core *core, u8 *ee)
670 {
671         int model;
672         int tuner;
673         char *tname;
674
675         /* Make sure we support the board model */
676         model = ee[0x1f] << 24 | ee[0x1e] << 16 | ee[0x1d] << 8 | ee[0x1c];
677         switch(model) {
678         case 90002:
679         case 90500:
680         case 90501:
681                 /* known */
682                 break;
683         default:
684                 printk("%s: warning: unknown hauppauge model #%d\n",
685                        core->name, model);
686                 break;
687         }
688
689         /* Make sure we support the tuner */
690         tuner = ee[0x2d];
691         switch(tuner) {
692         case 0x4B:
693                 tname = "Thomson DTT 7595";
694                 core->pll_type = PLLTYPE_DTT7595;
695                 break;
696         case 0x4C:
697                 tname = "Thomson DTT 7592";
698                 core->pll_type = PLLTYPE_DTT7592;
699                 break;
700         default:
701                 printk("%s: error: unknown hauppauge tuner 0x%02x\n",
702                        core->name, tuner);
703                 return -ENODEV;
704         }
705         printk(KERN_INFO "%s: hauppauge eeprom: model=%d, tuner=%s (%d)\n",
706                core->name, model, tname, tuner);
707
708         core->pll_addr = 0x61;
709         core->demod_addr = 0x43;
710 }
711 #endif
712
713 /* ----------------------------------------------------------------------- */
714 /* some GDI (was: Modular Technology) specific stuff                       */
715
716 static struct {
717         int  id;
718         int  fm;
719         char *name;
720 } gdi_tuner[] = {
721         [ 0x01 ] = { .id   = TUNER_ABSENT,
722                      .name = "NTSC_M" },
723         [ 0x02 ] = { .id   = TUNER_ABSENT,
724                      .name = "PAL_B" },
725         [ 0x03 ] = { .id   = TUNER_ABSENT,
726                      .name = "PAL_I" },
727         [ 0x04 ] = { .id   = TUNER_ABSENT,
728                      .name = "PAL_D" },
729         [ 0x05 ] = { .id   = TUNER_ABSENT,
730                      .name = "SECAM" },
731
732         [ 0x10 ] = { .id   = TUNER_ABSENT,
733                      .fm   = 1,
734                      .name = "TEMIC_4049" },
735         [ 0x11 ] = { .id   = TUNER_TEMIC_4136FY5,
736                      .name = "TEMIC_4136" },
737         [ 0x12 ] = { .id   = TUNER_ABSENT,
738                      .name = "TEMIC_4146" },
739
740         [ 0x20 ] = { .id   = TUNER_PHILIPS_FQ1216ME,
741                      .fm   = 1,
742                      .name = "PHILIPS_FQ1216_MK3" },
743         [ 0x21 ] = { .id   = TUNER_ABSENT, .fm = 1,
744                      .name = "PHILIPS_FQ1236_MK3" },
745         [ 0x22 ] = { .id   = TUNER_ABSENT,
746                      .name = "PHILIPS_FI1236_MK3" },
747         [ 0x23 ] = { .id   = TUNER_ABSENT,
748                      .name = "PHILIPS_FI1216_MK3" },
749 };
750
751 static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
752 {
753         char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner))
754                 ? gdi_tuner[eeprom_data[0x0d]].name : NULL;
755
756         printk(KERN_INFO "%s: GDI: tuner=%s\n", core->name,
757                name ? name : "unknown");
758         if (NULL == name)
759                 return;
760         core->tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
761         core->has_radio  = gdi_tuner[eeprom_data[0x0d]].fm;
762 }
763
764 /* ----------------------------------------------------------------------- */
765
766 static int
767 i2c_eeprom(struct i2c_client *c, unsigned char *eedata, int len)
768 {
769         unsigned char buf;
770         int err;
771
772         c->addr = 0xa0 >> 1;
773         buf = 0;
774         if (1 != (err = i2c_master_send(c,&buf,1))) {
775                 printk(KERN_INFO "cx88: Huh, no eeprom present (err=%d)?\n",
776                        err);
777                 return -1;
778         }
779         if (len != (err = i2c_master_recv(c,eedata,len))) {
780                 printk(KERN_WARNING "cx88: i2c eeprom read error (err=%d)\n",
781                        err);
782                 return -1;
783         }
784 #if 0
785         for (i = 0; i < len; i++) {
786                 if (0 == (i % 16))
787                         printk(KERN_INFO "cx88 ee: %02x:",i);
788                 printk(" %02x",eedata[i]);
789                 if (15 == (i % 16))
790                         printk("\n");
791         }
792 #endif
793         return 0;
794 }
795
796 void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
797 {
798         int i;
799
800         if (0 == pci->subsystem_vendor &&
801             0 == pci->subsystem_device) {
802                 printk("%s: Your board has no valid PCI Subsystem ID and thus can't\n"
803                        "%s: be autodetected.  Please pass card=<n> insmod option to\n"
804                        "%s: workaround that.  Redirect complaints to the vendor of\n"
805                        "%s: the TV card.  Best regards,\n"
806                        "%s:         -- tux\n",
807                        core->name,core->name,core->name,core->name,core->name);
808         } else {
809                 printk("%s: Your board isn't known (yet) to the driver.  You can\n"
810                        "%s: try to pick one of the existing card configs via\n"
811                        "%s: card=<n> insmod option.  Updating to the latest\n"
812                        "%s: version might help as well.\n",
813                        core->name,core->name,core->name,core->name);
814         }
815         printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
816                core->name);
817         for (i = 0; i < cx88_bcount; i++)
818                 printk("%s:    card=%d -> %s\n",
819                        core->name, i, cx88_boards[i].name);
820 }
821
822 void cx88_card_setup(struct cx88_core *core)
823 {
824         static u8 eeprom[128];
825
826         switch (core->board) {
827         case CX88_BOARD_HAUPPAUGE:
828                 if (0 == core->i2c_rc)
829                         i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
830                 hauppauge_eeprom(core,eeprom+8);
831                 break;
832         case CX88_BOARD_GDI:
833                 if (0 == core->i2c_rc)
834                         i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
835                 gdi_eeprom(core,eeprom);
836                 break;
837         case CX88_BOARD_WINFAST2000XP:
838                 if (0 == core->i2c_rc)
839                         i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
840                 leadtek_eeprom(core,eeprom);
841                 break;
842         case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
843                 /* Tuner reset is hooked to  the tuner out of reset */
844                 cx_set(MO_GP0_IO, 0x00000101);
845                 cx_clear(MO_GP0_IO, 0x00000001);
846                 msleep(1);
847                 cx_set(MO_GP0_IO, 0x00000101);
848                 break;
849 #ifdef WITH_DVB
850         case CX88_BOARD_HAUPPAUGE_DVB_T1:
851                 if (0 == core->i2c_rc)
852                         i2c_eeprom(&core->i2c_client,eeprom,sizeof(eeprom));
853                 hauppauge_eeprom_dvb(core,eeprom);
854                 break;
855         case CX88_BOARD_CONEXANT_DVB_T1:
856                 core->pll_type   = PLLTYPE_DTT7579;
857                 core->pll_addr   = 0x60;
858                 core->demod_addr = 0x43;
859                 break;
860 #endif
861         }
862         if (cx88_boards[core->board].radio.type == CX88_RADIO)
863                 core->has_radio = 1;
864 }
865
866 /* ------------------------------------------------------------------ */
867
868 EXPORT_SYMBOL(cx88_boards);
869 EXPORT_SYMBOL(cx88_bcount);
870 EXPORT_SYMBOL(cx88_subids);
871 EXPORT_SYMBOL(cx88_idcount);
872 EXPORT_SYMBOL(cx88_card_list);
873 EXPORT_SYMBOL(cx88_card_setup);
874
875 /*
876  * Local variables:
877  * c-basic-offset: 8
878  * End:
879  */