aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/tuner-xc2028.c
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2007-10-24 08:22:08 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-01-25 16:01:05 -0500
commitde3fe21ba2fdc0733ad4e555b95121baeba7fcd5 (patch)
treee3bee94cd7d9460cf15957865990af0e9120e232 /drivers/media/video/tuner-xc2028.c
parent215b95baf969c6f895969f0a4ae0479954fba7cd (diff)
V4L/DVB (6431): Improve firmware format
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/tuner-xc2028.c')
-rw-r--r--drivers/media/video/tuner-xc2028.c452
1 files changed, 344 insertions, 108 deletions
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index e4c371896de..7d53d58aafa 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -15,6 +15,7 @@
15#include <linux/mutex.h> 15#include <linux/mutex.h>
16#include "tuner-i2c.h" 16#include "tuner-i2c.h"
17#include "tuner-xc2028.h" 17#include "tuner-xc2028.h"
18#include "tuner-xc2028-types.h"
18 19
19#include <linux/dvb/frontend.h> 20#include <linux/dvb/frontend.h>
20#include "dvb_frontend.h" 21#include "dvb_frontend.h"
@@ -22,21 +23,13 @@
22#define PREFIX "xc2028 " 23#define PREFIX "xc2028 "
23 24
24static LIST_HEAD(xc2028_list); 25static LIST_HEAD(xc2028_list);
25 26/* struct for storing firmware table */
26/* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */ 27struct firmware_description {
27 28 unsigned int type;
28/* Generic firmwares */ 29 v4l2_std_id id;
29static const char *firmware_INIT0 = "tm_xc3028_MTS_init0.fw"; 30 unsigned char *ptr;
30static const char *firmware_8MHZ_INIT0 = "tm_xc3028_8M_MTS_init0.fw"; 31 unsigned int size;
31static const char *firmware_INIT1 = "tm_xc3028_68M_MTS_init1.fw"; 32};
32
33/* Standard-specific firmwares */
34static const char *firmware_6M = "tm_xc3028_DTV_6M.fw";
35static const char *firmware_7M = "tm_xc3028_DTV_7M.fw";
36static const char *firmware_8M = "tm_xc3028_DTV_8M.fw";
37static const char *firmware_B = "tm_xc3028_B_PAL.fw";
38static const char *firmware_DK = "tm_xc3028_DK_PAL_MTS.fw";
39static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw";
40 33
41struct xc2028_data { 34struct xc2028_data {
42 struct list_head xc2028_list; 35 struct list_head xc2028_list;
@@ -46,7 +39,14 @@ struct xc2028_data {
46 struct device *dev; 39 struct device *dev;
47 void *video_dev; 40 void *video_dev;
48 int count; 41 int count;
49 u32 frequency; 42 __u32 frequency;
43
44 struct firmware_description *firm;
45 int firm_size;
46
47 __u16 version;
48
49 struct xc2028_ctrl ctrl;
50 50
51 v4l2_std_id firm_type; /* video stds supported 51 v4l2_std_id firm_type; /* video stds supported
52 by current firmware */ 52 by current firmware */
@@ -54,6 +54,9 @@ struct xc2028_data {
54 6M, 7M or 8M */ 54 6M, 7M or 8M */
55 int need_load_generic; /* The generic firmware 55 int need_load_generic; /* The generic firmware
56 were loaded? */ 56 were loaded? */
57
58 int max_len; /* Max firmware chunk */
59
57 enum tuner_mode mode; 60 enum tuner_mode mode;
58 struct i2c_client *i2c_client; 61 struct i2c_client *i2c_client;
59 62
@@ -102,92 +105,263 @@ static int xc2028_get_reg(struct xc2028_data *priv, u16 reg)
102 return (buf[1])|(buf[0]<<8); 105 return (buf[1])|(buf[0]<<8);
103} 106}
104 107
105static int load_firmware (struct dvb_frontend *fe, const char *name) 108static void free_firmware (struct xc2028_data *priv)
106{ 109{
107 struct xc2028_data *priv = fe->tuner_priv; 110 int i;
111
112 if (!priv->firm)
113 return;
114
115 for (i=0;i<priv->firm_size;i++) {
116 if (priv->firm[i].ptr)
117 kfree(priv->firm[i].ptr);
118 }
119 kfree(priv->firm);
120
121 priv->firm=NULL;
122 priv->need_load_generic = 1;
123}
124
125static int load_all_firmwares (struct dvb_frontend *fe)
126{
127 struct xc2028_data *priv = fe->tuner_priv;
108 const struct firmware *fw=NULL; 128 const struct firmware *fw=NULL;
109 unsigned char *p, *endp; 129 unsigned char *p, *endp;
110 int len=0, rc=0; 130 int rc=0, n, n_array;
111 static const char firmware_ver[] = "tm6000/xcv v1"; 131 char name[33];
112 132
113 tuner_info("%s called\n", __FUNCTION__); 133 tuner_info("%s called\n", __FUNCTION__);
114 134
115 tuner_info("Loading firmware %s\n", name); 135 tuner_info("Loading firmware %s\n", priv->ctrl.fname);
116 rc = request_firmware(&fw, name, priv->dev); 136 rc = request_firmware(&fw, priv->ctrl.fname, priv->dev);
117 if (rc < 0) { 137 if (rc < 0) {
118 if (rc==-ENOENT) 138 if (rc==-ENOENT)
119 tuner_info("Error: firmware %s not found.\n", name); 139 tuner_info("Error: firmware %s not found.\n",
140 priv->ctrl.fname);
120 else 141 else
121 tuner_info("Error %d while requesting firmware %s \n", rc, name); 142 tuner_info("Error %d while requesting firmware %s \n",
143 rc, priv->ctrl.fname);
122 144
123 return rc; 145 return rc;
124 } 146 }
125 p=fw->data; 147 p=fw->data;
126 endp=p+fw->size; 148 endp=p+fw->size;
127 149
128 if(fw->size==0) { 150 if(fw->size<sizeof(name)-1+2) {
129 tuner_info("Error: firmware size is zero!\n"); 151 tuner_info("Error: firmware size is zero!\n");
130 rc=-EINVAL; 152 rc=-EINVAL;
131 goto err; 153 goto done;
132 } 154 }
133 if (fw->size<sizeof(firmware_ver)-1) { 155
134 /* Firmware is incorrect */ 156 memcpy(name,p,sizeof(name)-1);
135 tuner_info("Error: firmware size is less than header (%d<%d)!\n", 157 name[sizeof(name)-1]=0;
136 (int)fw->size,(int)sizeof(firmware_ver)-1); 158 p+=sizeof(name)-1;
137 rc=-EINVAL; 159
138 goto err; 160 priv->version = le16_to_cpu(*(__u16 *)p);
161 p += 2;
162
163 tuner_info("firmware: %s, ver %d.%d\n", name,
164 priv->version>>8, priv->version&0xff);
165
166 if (p+2>endp)
167 goto corrupt;
168
169 n_array = le16_to_cpu(*(__u16 *)p);
170 p += 2;
171
172 tuner_info("there are %d firmwares at %s\n", n_array, priv->ctrl.fname);
173
174 priv->firm=kzalloc(sizeof(*priv->firm)*n_array,GFP_KERNEL);
175
176 if (!fw) {
177 tuner_info("Not enough memory for loading firmware.\n");
178 rc=-ENOMEM;
179 goto done;
139 } 180 }
140 181
141 if (memcmp(p,firmware_ver,sizeof(firmware_ver)-1)) { 182 priv->firm_size = n_array;
142 /* Firmware is incorrect */ 183 n=-1;
143 tuner_info("Error: firmware is not for tm5600/6000 + Xcv2028/3028!\n"); 184 while (p<endp) {
144 rc=-EINVAL; 185 __u32 type, size;
145 goto err; 186 v4l2_std_id id;
187
188 n++;
189 if (n >= n_array) {
190 tuner_info("Too much firmwares at the file\n");
191 goto corrupt;
192 }
193
194 /* Checks if there's enough bytes to read */
195 if (p+sizeof(type)+sizeof(id)+sizeof(size)>endp) {
196 tuner_info("Lost firmware!\n");
197 goto corrupt;
198 }
199
200 type = le32_to_cpu(*(__u32 *)p);
201 p += sizeof(type);
202
203 id = le64_to_cpu(*(v4l2_std_id *)p);
204 p += sizeof(id);
205
206 size = le32_to_cpu(*(v4l2_std_id *)p);
207 p += sizeof(size);
208
209 if ((!size)||(size+p>endp)) {
210 tuner_info("Firmware type %x, id %lx corrupt\n",
211 type, (unsigned long) id);
212 goto corrupt;
213 }
214
215 priv->firm[n].ptr=kzalloc(size,GFP_KERNEL);
216 if (!priv->firm[n].ptr) {
217 tuner_info("Not enough memory.\n");
218 rc=-ENOMEM;
219 goto err;
220 }
221 tuner_info("Loading firmware type %x, id %lx, size=%d.\n",
222 type, (unsigned long) id, size);
223
224 memcpy(priv->firm[n].ptr, p, size);
225 priv->firm[n].type = type;
226 priv->firm[n].id = id;
227 priv->firm[n].size = size;
228
229 p += size;
230 }
231
232 if (n+1 != priv->firm_size) {
233 tuner_info("Firmware file is incomplete!\n");
234 goto corrupt;
235 }
236
237 goto done;
238
239corrupt:
240 rc=-EINVAL;
241 tuner_info("Error: firmware file is corrupted!\n");
242
243err:
244 tuner_info("Releasing loaded firmware file.\n");
245
246 free_firmware(priv);
247
248done:
249 release_firmware(fw);
250 tuner_info("Firmware files loaded.\n");
251
252 return rc;
253}
254
255static int load_firmware (struct dvb_frontend *fe, unsigned int type,
256 v4l2_std_id *id)
257{
258 struct xc2028_data *priv = fe->tuner_priv;
259 int i, rc;
260 unsigned char *p, *endp, buf[priv->max_len];
261
262 tuner_info("%s called\n", __FUNCTION__);
263
264 if (!priv->firm) {
265 printk (KERN_ERR PREFIX "Error! firmware not loaded\n");
266 return -EINVAL;
267 }
268
269 if ((type == 0) && (*id == 0))
270 *id=V4L2_STD_PAL;
271
272 /* Seek for exact match */
273 for (i=0;i<priv->firm_size;i++) {
274 if ( (type == priv->firm[i].type) &&
275 (*id == priv->firm[i].id))
276 goto found;
277 }
278
279 /* Seek for generic video standard match */
280 for (i=0;i<priv->firm_size;i++) {
281 if ( (type == priv->firm[i].type) && (*id & priv->firm[i].id))
282 goto found;
283 }
284
285 /*FIXME: Would make sense to seek for type "hint" match ? */
286
287 tuner_info ("Can't find firmware for type=%x, id=%lx\n", type,
288 (long int)*id);
289 return -EINVAL;
290
291found:
292 *id = priv->firm[i].id;
293 tuner_info ("Found firmware for type=%x, id=%lx\n", type,
294 (long int)*id);
295
296 p = priv->firm[i].ptr;
297
298 if (!p) {
299 printk(KERN_ERR PREFIX "Firmware pointer were freed!");
300 return -EINVAL;
146 } 301 }
147 p+=sizeof(firmware_ver)-1; 302 endp = p+priv->firm[i].size;
148 303
149 while(p<endp) { 304 while (p<endp) {
150 if ((*p) & 0x80) { 305 __u16 size;
306
307 /* Checks if there's enough bytes to read */
308 if (p+sizeof(size)>endp) {
309 tuner_info("missing bytes\n");
310 return -EINVAL;
311 }
312
313
314 size = le16_to_cpu(*(__u16 *)p);
315 p += sizeof(size);
316
317 if (size == 0xffff)
318 return 0;
319
320 if (!size) {
151 /* Special callback command received */ 321 /* Special callback command received */
152 rc = priv->tuner_callback(priv->video_dev, 322 rc = priv->tuner_callback(priv->video_dev,
153 XC2028_TUNER_RESET, (*p)&0x7f); 323 XC2028_TUNER_RESET, 0);
154 if (rc<0) { 324 if (rc<0) {
155 tuner_info("Error at RESET code %d\n", 325 tuner_info("Error at RESET code %d\n",
156 (*p)&0x7f); 326 (*p)&0x7f);
157 goto err; 327 return -EINVAL;
158 } 328 }
159 p++;
160 continue; 329 continue;
161 } 330 }
162 len=*p; 331
163 p++; 332 /* Checks for a sleep command */
164 if (p+len+1>endp) { 333 if (size & 0x8000) {
165 /* Firmware is incorrect */ 334 msleep (size & 0x7fff);
166 tuner_info("Error: firmware is truncated!\n"); 335 continue;
167 rc=-EINVAL;
168 goto err;
169 }
170 if (len<=0) {
171 tuner_info("Error: firmware file is corrupted!\n");
172 rc=-EINVAL;
173 goto err;
174 } 336 }
175 337
176 i2c_send(rc, priv, p, len); 338 if ((size + p > endp)) {
177 if (rc<0) 339 tuner_info("missing bytes: need %d, have %d\n",
178 goto err; 340 size, (int)(endp-p));
179 p+=len; 341 return -EINVAL;
342 }
180 343
181 if (*p) 344 buf[0] = *p;
182 msleep(*p);
183 p++; 345 p++;
184 } 346 size--;
185 347
348 /* Sends message chunks */
349 while (size>0) {
350 int len = (size<priv->max_len-1)?size:priv->max_len-1;
186 351
187err: 352 memcpy(buf+1, p, len);
188 release_firmware(fw);
189 353
190 return rc; 354 i2c_send(rc, priv, buf, len+1);
355 if (rc<0) {
356 tuner_info("%d returned from send\n",rc);
357 return -EINVAL;
358 }
359
360 p += len;
361 size -= len;
362 }
363 }
364 return -EINVAL;
191} 365}
192 366
193static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, 367static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
@@ -196,11 +370,21 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
196{ 370{
197 struct xc2028_data *priv = fe->tuner_priv; 371 struct xc2028_data *priv = fe->tuner_priv;
198 int rc, version; 372 int rc, version;
199 const char *name; 373 v4l2_std_id std0=0;
200 int change_digital_bandwidth; 374 unsigned int type0=0,type=0;
375 int change_digital_bandwidth;
201 376
202 tuner_info("%s called\n", __FUNCTION__); 377 tuner_info("%s called\n", __FUNCTION__);
203 378
379 if (!priv->firm) {
380 if (!priv->ctrl.fname)
381 return -EINVAL;
382
383 rc=load_all_firmwares(fe);
384 if (rc<0)
385 return rc;
386 }
387
204 tuner_info( "I am in mode %u and I should switch to mode %i\n", 388 tuner_info( "I am in mode %u and I should switch to mode %i\n",
205 priv->mode, new_mode); 389 priv->mode, new_mode);
206 390
@@ -213,23 +397,31 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
213 change_digital_bandwidth = (priv->mode == T_DIGITAL_TV 397 change_digital_bandwidth = (priv->mode == T_DIGITAL_TV
214 && bandwidth != priv->bandwidth) ? 1 : 0; 398 && bandwidth != priv->bandwidth) ? 1 : 0;
215 tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth, 399 tuner_info("old bandwidth %u, new bandwidth %u\n", priv->bandwidth,
216 bandwidth); 400 bandwidth);
217 401
218 if (priv->need_load_generic) { 402 if (priv->need_load_generic) {
219 if (priv->bandwidth==8)
220 name = firmware_8MHZ_INIT0;
221 else
222 name = firmware_INIT0;
223
224 /* Reset is needed before loading firmware */ 403 /* Reset is needed before loading firmware */
225 rc = priv->tuner_callback(priv->video_dev, 404 rc = priv->tuner_callback(priv->video_dev,
226 XC2028_TUNER_RESET, 0); 405 XC2028_TUNER_RESET, 0);
227 if (rc<0) 406 if (rc<0)
228 return rc; 407 return rc;
229 408
230 rc = load_firmware(fe,name); 409 type0=BASE;
231 if (rc<0) 410
411 if (priv->ctrl.type == XC2028_FIRM_MTS)
412 type0 |= MTS;
413
414 if (priv->bandwidth==8)
415 type0 |= F8MHZ;
416
417 /* FIXME: How to load FM and FM|INPUT1 firmwares? */
418
419 rc = load_firmware(fe, type0, &std0);
420 if (rc<0) {
421 tuner_info("Error %d while loading generic firmware\n",
422 rc);
232 return rc; 423 return rc;
424 }
233 425
234 priv->need_load_generic=0; 426 priv->need_load_generic=0;
235 priv->firm_type=0; 427 priv->firm_type=0;
@@ -241,49 +433,53 @@ static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode,
241 tuner_info("I should change bandwidth %u\n", 433 tuner_info("I should change bandwidth %u\n",
242 change_digital_bandwidth); 434 change_digital_bandwidth);
243 435
244 /* FIXME: t->std makes no sense here */
245 if (change_digital_bandwidth) { 436 if (change_digital_bandwidth) {
437
438 /*FIXME: Should allow selecting between D2620 and D2633 */
439 type |= D2620;
440
441 /* FIXME: When should select a DTV78 firmware?
442 */
246 switch(bandwidth) { 443 switch(bandwidth) {
247 case BANDWIDTH_8_MHZ: 444 case BANDWIDTH_8_MHZ:
248 std = V4L2_STD_DTV_8MHZ; 445 type |= DTV8;
249 break; 446 break;
250 447 case BANDWIDTH_7_MHZ:
251 case BANDWIDTH_7_MHZ: 448 type |= DTV7;
252 std = V4L2_STD_DTV_7MHZ;
253 break; 449 break;
254 450 case BANDWIDTH_6_MHZ:
255 case BANDWIDTH_6_MHZ: 451 /* FIXME: Should allow select also ATSC */
256 std = V4L2_STD_DTV_6MHZ; 452 type |= DTV6_QAM;
257 break; 453 break;
258 454
259 default: 455 default:
260 tuner_info("error: bandwidth not supported.\n"); 456 tuner_info("error: bandwidth not supported.\n");
261 }; 457 };
262 priv->bandwidth = bandwidth; 458 priv->bandwidth = bandwidth;
263 } 459 }
264 460
461 /* Load INIT1, if needed */
462 tuner_info("Trying to load init1 firmware\n");
463 type0 = BASE | INIT1 | priv->ctrl.type;
464 if (priv->ctrl.type == XC2028_FIRM_MTS)
465 type0 |= MTS;
466
467 /* FIXME: Should handle errors - if INIT1 found */
468 rc = load_firmware(fe, type0, &std0);
469
470 /* FIXME: Should add support for FM radio
471 */
472
473 if (priv->ctrl.type == XC2028_FIRM_MTS)
474 type |= MTS;
475
476 tuner_info("firmware standard to load: %08lx\n",(unsigned long) std);
265 if (priv->firm_type & std) { 477 if (priv->firm_type & std) {
266 tuner_info("xc3028: no need to load a std-specific firmware.\n"); 478 tuner_info("no need to load a std-specific firmware.\n");
267 return 0; 479 return 0;
268 } 480 }
269 481
270 rc = load_firmware(fe,firmware_INIT1); 482 rc = load_firmware(fe, type, &std);
271
272 if (std & V4L2_STD_MN)
273 name=firmware_MN;
274 else if (std & V4L2_STD_DTV_6MHZ)
275 name=firmware_6M;
276 else if (std & V4L2_STD_DTV_7MHZ)
277 name=firmware_7M;
278 else if (std & V4L2_STD_DTV_8MHZ)
279 name=firmware_8M;
280 else if (std & V4L2_STD_PAL_B)
281 name=firmware_B;
282 else
283 name=firmware_DK;
284
285 tuner_info("loading firmware named %s.\n", name);
286 rc = load_firmware(fe, name);
287 if (rc<0) 483 if (rc<0)
288 return rc; 484 return rc;
289 485
@@ -341,11 +537,11 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */,
341 537
342 tuner_info("%s called\n", __FUNCTION__); 538 tuner_info("%s called\n", __FUNCTION__);
343 539
540 mutex_lock(&priv->lock);
541
344 /* HACK: It seems that specific firmware need to be reloaded 542 /* HACK: It seems that specific firmware need to be reloaded
345 when freq is changed */ 543 when freq is changed */
346 544
347 mutex_lock(&priv->lock);
348
349 priv->firm_type=0; 545 priv->firm_type=0;
350 546
351 /* Reset GPIO 1 */ 547 /* Reset GPIO 1 */
@@ -365,7 +561,13 @@ static int generic_set_tv_freq(struct dvb_frontend *fe, u32 freq /* in Hz */,
365 div = (freq - offset + DIV/2)/DIV; 561 div = (freq - offset + DIV/2)/DIV;
366 562
367 /* CMD= Set frequency */ 563 /* CMD= Set frequency */
368 send_seq(priv, {0x00, 0x02, 0x00, 0x00}); 564
565 if (priv->version<0x0202) {
566 send_seq(priv, {0x00, 0x02, 0x00, 0x00});
567 } else {
568 send_seq(priv, {0x80, 0x02, 0x00, 0x00});
569 }
570
369 rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1); 571 rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
370 if (rc<0) 572 if (rc<0)
371 goto ret; 573 goto ret;
@@ -436,8 +638,13 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
436 638
437 priv->count--; 639 priv->count--;
438 640
439 if (!priv->count) 641 if (!priv->count) {
642 if (priv->ctrl.fname)
643 kfree(priv->ctrl.fname);
644
645 free_firmware(priv);
440 kfree (priv); 646 kfree (priv);
647 }
441 648
442 return 0; 649 return 0;
443} 650}
@@ -453,6 +660,32 @@ static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
453 return 0; 660 return 0;
454} 661}
455 662
663static int xc2028_set_config (struct dvb_frontend *fe, void *priv_cfg)
664{
665 struct xc2028_data *priv = fe->tuner_priv;
666 struct xc2028_ctrl *p = priv_cfg;
667
668 tuner_info("%s called\n", __FUNCTION__);
669
670 priv->ctrl.type = p->type;
671
672 if (p->fname) {
673 if (priv->ctrl.fname)
674 kfree(priv->ctrl.fname);
675
676 priv->ctrl.fname = kmalloc(strlen(p->fname)+1, GFP_KERNEL);
677 if (!priv->ctrl.fname)
678 return -ENOMEM;
679
680 free_firmware(priv);
681 strcpy(priv->ctrl.fname, p->fname);
682 }
683
684 tuner_info("%s OK\n", __FUNCTION__);
685
686 return 0;
687}
688
456static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { 689static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
457 .info = { 690 .info = {
458 .name = "Xceive XC3028", 691 .name = "Xceive XC3028",
@@ -461,6 +694,7 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
461 .frequency_step = 50000, 694 .frequency_step = 50000,
462 }, 695 },
463 696
697 .set_config = xc2028_set_config,
464 .set_analog_params = xc2028_set_tv_freq, 698 .set_analog_params = xc2028_set_tv_freq,
465 .release = xc2028_dvb_release, 699 .release = xc2028_dvb_release,
466 .get_frequency = xc2028_get_frequency, 700 .get_frequency = xc2028_get_frequency,
@@ -513,6 +747,8 @@ int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap,
513 priv->dev = dev; 747 priv->dev = dev;
514 priv->video_dev = video_dev; 748 priv->video_dev = video_dev;
515 priv->tuner_callback = tuner_callback; 749 priv->tuner_callback = tuner_callback;
750 priv->max_len = 13;
751
516 752
517 mutex_init(&priv->lock); 753 mutex_init(&priv->lock);
518 754