[PATCH] V4L: Miscellaneous fixes
[linux-2.6.git] / drivers / media / video / tveeprom.c
1 /*
2  * tveeprom - eeprom decoder for tvcard configuration eeproms
3  *
4  * Data and decoding routines shamelessly borrowed from bttv-cards.c
5  * eeprom access routine shamelessly borrowed from bttv-if.c
6  * which are:
7
8     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
9                            & Marcus Metzler (mocm@thp.uni-koeln.de)
10     (c) 1999-2001 Gerd Knorr <kraxel@goldbach.in-berlin.de>
11
12  * Adjustments to fit a more general model and all bugs:
13
14         Copyright (C) 2003 John Klar <linpvr at projectplasma.com>
15
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29  */
30
31
32 #include <linux/module.h>
33 #include <linux/moduleparam.h>
34 #include <linux/errno.h>
35 #include <linux/kernel.h>
36 #include <linux/init.h>
37 #include <linux/types.h>
38 #include <linux/videodev.h>
39 #include <linux/i2c.h>
40
41 #include <media/tuner.h>
42 #include <media/tveeprom.h>
43
44 MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver");
45 MODULE_AUTHOR("John Klar");
46 MODULE_LICENSE("GPL");
47
48 static int debug = 0;
49 module_param(debug, int, 0644);
50 MODULE_PARM_DESC(debug, "Debug level (0-2)");
51
52 #define STRM(array,i) (i < sizeof(array)/sizeof(char*) ? array[i] : "unknown")
53
54 #define dprintk(num, args...) \
55         do { \
56                 if (debug >= num) \
57                         printk(KERN_INFO "tveeprom: " args); \
58         } while (0)
59
60 #define TVEEPROM_KERN_ERR(args...) printk(KERN_ERR "tveeprom: " args);
61 #define TVEEPROM_KERN_INFO(args...) printk(KERN_INFO "tveeprom: " args);
62
63 /* ----------------------------------------------------------------------- */
64 /* some hauppauge specific stuff                                           */
65
66 static struct HAUPPAUGE_TUNER_FMT
67 {
68         int     id;
69         char *name;
70 }
71 hauppauge_tuner_fmt[] =
72 {
73         { 0x00000000, "unknown1" },
74         { 0x00000000, "unknown2" },
75         { 0x00000007, "PAL(B/G)" },
76         { 0x00001000, "NTSC(M)" },
77         { 0x00000010, "PAL(I)" },
78         { 0x00400000, "SECAM(L/L´)" },
79         { 0x00000e00, "PAL(D/K)" },
80         { 0x03000000, "ATSC Digital" },
81 };
82
83 /* This is the full list of possible tuners. Many thanks to Hauppauge for
84    supplying this information. Note that many tuners where only used for
85    testing and never made it to the outside world. So you will only see
86    a subset in actual produced cards. */
87 static struct HAUPPAUGE_TUNER
88 {
89         int  id;
90         char *name;
91 }
92 hauppauge_tuner[] =
93 {
94         /* 0-9 */
95         { TUNER_ABSENT,        "None" },
96         { TUNER_ABSENT,        "External" },
97         { TUNER_ABSENT,        "Unspecified" },
98         { TUNER_PHILIPS_PAL,   "Philips FI1216" },
99         { TUNER_PHILIPS_SECAM, "Philips FI1216MF" },
100         { TUNER_PHILIPS_NTSC,  "Philips FI1236" },
101         { TUNER_PHILIPS_PAL_I, "Philips FI1246" },
102         { TUNER_PHILIPS_PAL_DK,"Philips FI1256" },
103         { TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },
104         { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },
105         /* 10-19 */
106         { TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },
107         { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },
108         { TUNER_PHILIPS_PAL_DK,"Philips FI1256 MK2" },
109         { TUNER_TEMIC_NTSC,    "Temic 4032FY5" },
110         { TUNER_TEMIC_PAL,     "Temic 4002FH5" },
111         { TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },
112         { TUNER_PHILIPS_PAL,   "Philips FR1216 MK2" },
113         { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },
114         { TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },
115         { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },
116         /* 20-29 */
117         { TUNER_PHILIPS_PAL_DK,"Philips FR1256 MK2" },
118         { TUNER_PHILIPS_PAL,   "Philips FM1216" },
119         { TUNER_PHILIPS_SECAM, "Philips FM1216MF" },
120         { TUNER_PHILIPS_NTSC,  "Philips FM1236" },
121         { TUNER_PHILIPS_PAL_I, "Philips FM1246" },
122         { TUNER_PHILIPS_PAL_DK,"Philips FM1256" },
123         { TUNER_TEMIC_4036FY5_NTSC, "Temic 4036FY5" },
124         { TUNER_ABSENT,        "Samsung TCPN9082D" },
125         { TUNER_ABSENT,        "Samsung TCPM9092P" },
126         { TUNER_TEMIC_4006FH5_PAL, "Temic 4006FH5" },
127         /* 30-39 */
128         { TUNER_ABSENT,        "Samsung TCPN9085D" },
129         { TUNER_ABSENT,        "Samsung TCPB9085P" },
130         { TUNER_ABSENT,        "Samsung TCPL9091P" },
131         { TUNER_TEMIC_4039FR5_NTSC, "Temic 4039FR5" },
132         { TUNER_PHILIPS_FQ1216ME,   "Philips FQ1216 ME" },
133         { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
134         { TUNER_PHILIPS_NTSC,        "Philips TD1536" },
135         { TUNER_PHILIPS_NTSC,        "Philips TD1536D" },
136         { TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
137         { TUNER_ABSENT,        "Philips FI1256MP" },
138         /* 40-49 */
139         { TUNER_ABSENT,        "Samsung TCPQ9091P" },
140         { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
141         { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
142         { TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
143         { TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
144         { TUNER_ABSENT,        "Philips TD1536D FH 44"},
145         { TUNER_LG_NTSC_FM,    "LG TP18NSR01F"},
146         { TUNER_LG_PAL_FM,     "LG TP18PSB01D"},
147         { TUNER_LG_PAL,        "LG TP18PSB11D"},
148         { TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
149         /* 50-59 */
150         { TUNER_LG_PAL_I,      "LG TAPC-I701D"},
151         { TUNER_ABSENT,        "Temic 4042FI5"},
152         { TUNER_MICROTUNE_4049FM5, "Microtune 4049 FM5"},
153         { TUNER_ABSENT,        "LG TPI8NSR11F"},
154         { TUNER_ABSENT,        "Microtune 4049 FM5 Alt I2C"},
155         { TUNER_ABSENT,        "Philips FQ1216ME MK3"},
156         { TUNER_ABSENT,        "Philips FI1236 MK3"},
157         { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216 ME MK3"},
158         { TUNER_ABSENT,        "Philips FM1236 MK3"},
159         { TUNER_ABSENT,        "Philips FM1216MP MK3"},
160         /* 60-69 */
161         { TUNER_ABSENT,        "LG S001D MK3"},
162         { TUNER_ABSENT,        "LG M001D MK3"},
163         { TUNER_ABSENT,        "LG S701D MK3"},
164         { TUNER_ABSENT,        "LG M701D MK3"},
165         { TUNER_ABSENT,        "Temic 4146FM5"},
166         { TUNER_ABSENT,        "Temic 4136FY5"},
167         { TUNER_ABSENT,        "Temic 4106FH5"},
168         { TUNER_ABSENT,        "Philips FQ1216LMP MK3"},
169         { TUNER_LG_NTSC_TAPE,  "LG TAPE H001F MK3"},
170         { TUNER_ABSENT,        "LG TAPE H701F MK3"},
171         /* 70-79 */
172         { TUNER_ABSENT,        "LG TALN H200T"},
173         { TUNER_ABSENT,        "LG TALN H250T"},
174         { TUNER_ABSENT,        "LG TALN M200T"},
175         { TUNER_ABSENT,        "LG TALN Z200T"},
176         { TUNER_ABSENT,        "LG TALN S200T"},
177         { TUNER_ABSENT,        "Thompson DTT7595"},
178         { TUNER_ABSENT,        "Thompson DTT7592"},
179         { TUNER_ABSENT,        "Silicon TDA8275C1 8290"},
180         { TUNER_ABSENT,        "Silicon TDA8275C1 8290 FM"},
181         { TUNER_ABSENT,        "Thompson DTT757"},
182         /* 80-89 */
183         { TUNER_ABSENT,        "Philips FQ1216LME MK3"},
184         { TUNER_ABSENT,        "LG TAPC G701D"},
185         { TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
186         { TUNER_ABSENT,        "TCL 2002MB 3"},
187         { TUNER_ABSENT,        "TCL 2002MI 3"},
188         { TUNER_TCL_2002N,     "TCL 2002N 6A"},
189         { TUNER_ABSENT,        "Philips FQ1236 MK3"},
190         { TUNER_ABSENT,        "Samsung TCPN 2121P30A"},
191         { TUNER_ABSENT,        "Samsung TCPE 4121P30A"},
192         { TUNER_PHILIPS_FM1216ME_MK3, "TCL MFPE05 2"},
193         /* 90-99 */
194         { TUNER_ABSENT,        "LG TALN H202T"},
195         { TUNER_PHILIPS_FQ1216AME_MK4, "Philips FQ1216AME MK4"},
196         { TUNER_PHILIPS_FQ1236A_MK4, "Philips FQ1236A MK4"},
197         { TUNER_ABSENT,        "Philips FQ1286A MK4"},
198         { TUNER_ABSENT,        "Philips FQ1216ME MK5"},
199         { TUNER_ABSENT,        "Philips FQ1236 MK5"},
200         { TUNER_ABSENT,        "Unspecified"},
201         { TUNER_LG_PAL_TAPE,   "LG PAL (TAPE Series)"},
202 };
203
204 static char *sndtype[] = {
205         "None", "TEA6300", "TEA6320", "TDA9850", "MSP3400C", "MSP3410D",
206         "MSP3415", "MSP3430", "MSP3438", "CS5331", "MSP3435", "MSP3440",
207         "MSP3445", "MSP3411", "MSP3416", "MSP3425",
208
209         "Type 0x10","Type 0x11","Type 0x12","Type 0x13",
210         "Type 0x14","Type 0x15","Type 0x16","Type 0x17",
211         "Type 0x18","MSP4418","Type 0x1a","MSP4448",
212         "Type 0x1c","Type 0x1d","Type 0x1e","Type 0x1f",
213 };
214
215 static int hasRadioTuner(int tunerType)
216 {
217         switch (tunerType) {
218                 case 18: //PNPEnv_TUNER_FR1236_MK2:
219                 case 23: //PNPEnv_TUNER_FM1236:
220                 case 38: //PNPEnv_TUNER_FMR1236:
221                 case 16: //PNPEnv_TUNER_FR1216_MK2:
222                 case 19: //PNPEnv_TUNER_FR1246_MK2:
223                 case 21: //PNPEnv_TUNER_FM1216:
224                 case 24: //PNPEnv_TUNER_FM1246:
225                 case 17: //PNPEnv_TUNER_FR1216MF_MK2:
226                 case 22: //PNPEnv_TUNER_FM1216MF:
227                 case 20: //PNPEnv_TUNER_FR1256_MK2:
228                 case 25: //PNPEnv_TUNER_FM1256:
229                 case 33: //PNPEnv_TUNER_4039FR5:
230                 case 42: //PNPEnv_TUNER_4009FR5:
231                 case 52: //PNPEnv_TUNER_4049FM5:
232                 case 54: //PNPEnv_TUNER_4049FM5_AltI2C:
233                 case 44: //PNPEnv_TUNER_4009FN5:
234                 case 31: //PNPEnv_TUNER_TCPB9085P:
235                 case 30: //PNPEnv_TUNER_TCPN9085D:
236                 case 46: //PNPEnv_TUNER_TP18NSR01F:
237                 case 47: //PNPEnv_TUNER_TP18PSB01D:
238                 case 49: //PNPEnv_TUNER_TAPC_I001D:
239                 case 60: //PNPEnv_TUNER_TAPE_S001D_MK3:
240                 case 57: //PNPEnv_TUNER_FM1216ME_MK3:
241                 case 59: //PNPEnv_TUNER_FM1216MP_MK3:
242                 case 58: //PNPEnv_TUNER_FM1236_MK3:
243                 case 68: //PNPEnv_TUNER_TAPE_H001F_MK3:
244                 case 61: //PNPEnv_TUNER_TAPE_M001D_MK3:
245                 case 78: //PNPEnv_TUNER_TDA8275C1_8290_FM:
246                 case 89: //PNPEnv_TUNER_TCL_MFPE05_2:
247                 case 92: //PNPEnv_TUNER_PHILIPS_FQ1236A_MK4:
248                     return 1;
249         }
250         return 0;
251 }
252
253 void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data)
254 {
255         /* ----------------------------------------------
256         ** The hauppauge eeprom format is tagged
257         **
258         ** if packet[0] == 0x84, then packet[0..1] == length
259         ** else length = packet[0] & 3f;
260         ** if packet[0] & f8 == f8, then EOD and packet[1] == checksum
261         **
262         ** In our (ivtv) case we're interested in the following:
263         ** tuner type: tag [00].05 or [0a].01 (index into hauppauge_tuner)
264         ** tuner fmts: tag [00].04 or [0a].00 (bitmask index into hauppauge_tuner_fmt)
265         ** radio:      tag [00].{last} or [0e].00  (bitmask.  bit2=FM)
266         ** audio proc: tag [02].01 or [05].00 (lower nibble indexes lut?)
267
268         ** Fun info:
269         ** model:      tag [00].07-08 or [06].00-01
270         ** revision:   tag [00].09-0b or [06].04-06
271         ** serial#:    tag [01].05-07 or [04].04-06
272
273         ** # of inputs/outputs ???
274         */
275
276         int i, j, len, done, beenhere, tag, tuner = 0, t_format = 0;
277         char *t_name = NULL, *t_fmt_name = NULL;
278
279         dprintk(1, "%s\n",__FUNCTION__);
280         tvee->revision = done = len = beenhere = 0;
281         for (i = 0; !done && i < 256; i += len) {
282                 dprintk(2, "processing pos = %02x (%02x, %02x)\n",
283                         i, eeprom_data[i], eeprom_data[i + 1]);
284
285                 if (eeprom_data[i] == 0x84) {
286                         len = eeprom_data[i + 1] + (eeprom_data[i + 2] << 8);
287                         i+=3;
288                 } else if ((eeprom_data[i] & 0xf0) == 0x70) {
289                         if ((eeprom_data[i] & 0x08)) {
290                                 /* verify checksum! */
291                                 done = 1;
292                                 break;
293                         }
294                         len = eeprom_data[i] & 0x07;
295                         ++i;
296                 } else {
297                         TVEEPROM_KERN_ERR("Encountered bad packet header [%02x]. "
298                                    "Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]);
299                         return;
300                 }
301
302                 dprintk(1, "%3d [%02x] ", len, eeprom_data[i]);
303                 for(j = 1; j < len; j++) {
304                         dprintk(1, "%02x ", eeprom_data[i + j]);
305                 }
306                 dprintk(1, "\n");
307
308                 /* process by tag */
309                 tag = eeprom_data[i];
310                 switch (tag) {
311                 case 0x00:
312                         tuner = eeprom_data[i+6];
313                         t_format = eeprom_data[i+5];
314                         tvee->has_radio = eeprom_data[i+len-1];
315                         tvee->model =
316                                 eeprom_data[i+8] +
317                                 (eeprom_data[i+9] << 8);
318                         tvee->revision = eeprom_data[i+10] +
319                                 (eeprom_data[i+11] << 8) +
320                                 (eeprom_data[i+12] << 16);
321                         break;
322                 case 0x01:
323                         tvee->serial_number =
324                                 eeprom_data[i+6] +
325                                 (eeprom_data[i+7] << 8) +
326                                 (eeprom_data[i+8] << 16);
327                         break;
328                 case 0x02:
329                         tvee->audio_processor = eeprom_data[i+2] & 0x0f;
330                         break;
331                 case 0x04:
332                         tvee->serial_number =
333                                 eeprom_data[i+5] +
334                                 (eeprom_data[i+6] << 8) +
335                                 (eeprom_data[i+7] << 16);
336                         break;
337                 case 0x05:
338                         tvee->audio_processor = eeprom_data[i+1] & 0x0f;
339                         break;
340                 case 0x06:
341                         tvee->model =
342                                 eeprom_data[i+1] +
343                                 (eeprom_data[i+2] << 8);
344                         tvee->revision = eeprom_data[i+5] +
345                                 (eeprom_data[i+6] << 8) +
346                                 (eeprom_data[i+7] << 16);
347                         break;
348                 case 0x0a:
349                         if(beenhere == 0) {
350                                 tuner = eeprom_data[i+2];
351                                 t_format = eeprom_data[i+1];
352                                 beenhere = 1;
353                                 break;
354                         } else {
355                                 break;
356                         }
357                 case 0x0e:
358                         tvee->has_radio = eeprom_data[i+1];
359                         break;
360                 default:
361                         dprintk(1, "Not sure what to do with tag [%02x]\n", tag);
362                         /* dump the rest of the packet? */
363                 }
364
365         }
366
367         if (!done) {
368                 TVEEPROM_KERN_ERR("Ran out of data!\n");
369                 return;
370         }
371
372         if (tvee->revision != 0) {
373                 tvee->rev_str[0] = 32 + ((tvee->revision >> 18) & 0x3f);
374                 tvee->rev_str[1] = 32 + ((tvee->revision >> 12) & 0x3f);
375                 tvee->rev_str[2] = 32 + ((tvee->revision >>  6) & 0x3f);
376                 tvee->rev_str[3] = 32 + ( tvee->revision        & 0x3f);
377                 tvee->rev_str[4] = 0;
378         }
379
380         if (hasRadioTuner(tuner) && !tvee->has_radio) {
381             TVEEPROM_KERN_INFO("The eeprom says no radio is present, but the tuner type\n");
382             TVEEPROM_KERN_INFO("indicates otherwise. I will assume that radio is present.\n");
383             tvee->has_radio = 1;
384         }
385
386         if (tuner < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) {
387                 tvee->tuner_type = hauppauge_tuner[tuner].id;
388                 t_name = hauppauge_tuner[tuner].name;
389         } else {
390                 t_name = "<unknown>";
391         }
392
393         tvee->tuner_formats = 0;
394         t_fmt_name = "<none>";
395         for (i = 0; i < 8; i++) {
396                 if (t_format & (1<<i)) {
397                         tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
398                         /* yuck */
399                         t_fmt_name = hauppauge_tuner_fmt[i].name;
400                 }
401         }
402
403
404         TVEEPROM_KERN_INFO("Hauppauge: model = %d, rev = %s, serial# = %d\n",
405                    tvee->model,
406                    tvee->rev_str,
407                    tvee->serial_number);
408         TVEEPROM_KERN_INFO("tuner = %s (idx = %d, type = %d)\n",
409                    t_name,
410                    tuner,
411                    tvee->tuner_type);
412         TVEEPROM_KERN_INFO("tuner fmt = %s (eeprom = 0x%02x, v4l2 = 0x%08x)\n",
413                    t_fmt_name,
414                    t_format,
415                    tvee->tuner_formats);
416
417         TVEEPROM_KERN_INFO("audio_processor = %s (type = %d)\n",
418                    STRM(sndtype,tvee->audio_processor),
419                    tvee->audio_processor);
420
421 }
422 EXPORT_SYMBOL(tveeprom_hauppauge_analog);
423
424 /* ----------------------------------------------------------------------- */
425 /* generic helper functions                                                */
426
427 int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
428 {
429         unsigned char buf;
430         int err;
431
432         dprintk(1, "%s\n",__FUNCTION__);
433         buf = 0;
434         if (1 != (err = i2c_master_send(c,&buf,1))) {
435                 printk(KERN_INFO "tveeprom(%s): Huh, no eeprom present (err=%d)?\n",
436                        c->name,err);
437                 return -1;
438         }
439         if (len != (err = i2c_master_recv(c,eedata,len))) {
440                 printk(KERN_WARNING "tveeprom(%s): i2c eeprom read error (err=%d)\n",
441                        c->name,err);
442                 return -1;
443         }
444         return 0;
445 }
446 EXPORT_SYMBOL(tveeprom_read);
447
448 #if 0
449 int tveeprom_dump(unsigned char *eedata, int len)
450 {
451         int i;
452
453         dprintk(1, "%s\n",__FUNCTION__);
454         for (i = 0; i < len; i++) {
455                 if (0 == (i % 16))
456                         printk(KERN_INFO "tveeprom: %02x:",i);
457                 printk(" %02x",eedata[i]);
458                 if (15 == (i % 16))
459                         printk("\n");
460         }
461         return 0;
462 }
463 EXPORT_SYMBOL(tveeprom_dump);
464 #endif  /*  0  */
465
466 /* ----------------------------------------------------------------------- */
467 /* needed for ivtv.sf.net at the moment.  Should go away in the long       */
468 /* run, just call the exported tveeprom_* directly, there is no point in   */
469 /* using the indirect way via i2c_driver->command()                        */
470
471 #ifndef I2C_DRIVERID_TVEEPROM
472 # define I2C_DRIVERID_TVEEPROM I2C_DRIVERID_EXP2
473 #endif
474
475 static unsigned short normal_i2c[] = {
476         0xa0 >> 1,
477         I2C_CLIENT_END,
478 };
479
480 I2C_CLIENT_INSMOD;
481
482 static struct i2c_driver i2c_driver_tveeprom;
483
484 static int
485 tveeprom_command(struct i2c_client *client,
486                  unsigned int       cmd,
487                  void              *arg)
488 {
489         struct tveeprom eeprom;
490         u32 *eeprom_props = arg;
491         u8 *buf;
492
493         switch (cmd) {
494         case 0:
495                 buf = kmalloc(256,GFP_KERNEL);
496                 memset(buf,0,256);
497                 tveeprom_read(client,buf,256);
498                 tveeprom_hauppauge_analog(&eeprom,buf);
499                 kfree(buf);
500                 eeprom_props[0] = eeprom.tuner_type;
501                 eeprom_props[1] = eeprom.tuner_formats;
502                 eeprom_props[2] = eeprom.model;
503                 eeprom_props[3] = eeprom.revision;
504                 break;
505         default:
506                 return -EINVAL;
507         }
508         return 0;
509 }
510
511 static int
512 tveeprom_detect_client(struct i2c_adapter *adapter,
513                        int                 address,
514                        int                 kind)
515 {
516         struct i2c_client *client;
517
518         dprintk(1,"%s: id 0x%x @ 0x%x\n",__FUNCTION__,
519                adapter->id, address << 1);
520         client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
521         if (NULL == client)
522                 return -ENOMEM;
523         memset(client, 0, sizeof(struct i2c_client));
524         client->addr = address;
525         client->adapter = adapter;
526         client->driver = &i2c_driver_tveeprom;
527         client->flags = I2C_CLIENT_ALLOW_USE;
528         snprintf(client->name, sizeof(client->name), "tveeprom");
529         i2c_attach_client(client);
530         return 0;
531 }
532
533 static int
534 tveeprom_attach_adapter (struct i2c_adapter *adapter)
535 {
536         dprintk(1,"%s: id 0x%x\n",__FUNCTION__,adapter->id);
537         if (adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848))
538                 return 0;
539         return i2c_probe(adapter, &addr_data, tveeprom_detect_client);
540 }
541
542 static int
543 tveeprom_detach_client (struct i2c_client *client)
544 {
545         int err;
546
547         err = i2c_detach_client(client);
548         if (err < 0)
549                 return err;
550         kfree(client);
551         return 0;
552 }
553
554 static struct i2c_driver i2c_driver_tveeprom = {
555         .owner          = THIS_MODULE,
556         .name           = "tveeprom",
557         .id             = I2C_DRIVERID_TVEEPROM,
558         .flags          = I2C_DF_NOTIFY,
559         .attach_adapter = tveeprom_attach_adapter,
560         .detach_client  = tveeprom_detach_client,
561         .command        = tveeprom_command,
562 };
563
564 static int __init tveeprom_init(void)
565 {
566         return i2c_add_driver(&i2c_driver_tveeprom);
567 }
568
569 static void __exit tveeprom_exit(void)
570 {
571         i2c_del_driver(&i2c_driver_tveeprom);
572 }
573
574 module_init(tveeprom_init);
575 module_exit(tveeprom_exit);
576
577 /*
578  * Local variables:
579  * c-basic-offset: 8
580  * End:
581  */