diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/tuner-xc2028-types.h | 99 | ||||
-rw-r--r-- | drivers/media/video/tuner-xc2028.c | 452 | ||||
-rw-r--r-- | drivers/media/video/tuner-xc2028.h | 15 |
3 files changed, 455 insertions, 111 deletions
diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/video/tuner-xc2028-types.h new file mode 100644 index 000000000000..80b19eb1b083 --- /dev/null +++ b/drivers/media/video/tuner-xc2028-types.h | |||
@@ -0,0 +1,99 @@ | |||
1 | /* tuner-xc2028_types | ||
2 | * | ||
3 | * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
4 | * This code is placed under the terms of the GNU General Public License v2 | ||
5 | */ | ||
6 | |||
7 | /* xc3028 firmware types */ | ||
8 | |||
9 | /* BASE firmware should be loaded before any other firmware */ | ||
10 | #define BASE (1<<0) | ||
11 | |||
12 | /* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ | ||
13 | #define F8MHZ (1<<1) | ||
14 | |||
15 | /* Multichannel Television Sound (MTS) | ||
16 | Those firmwares are capable of using xc2038 DSP to decode audio and | ||
17 | produce a baseband audio output on some pins of the chip. | ||
18 | There are MTS firmwares for the most used video standards. It should be | ||
19 | required to use MTS firmwares, depending on the way audio is routed into | ||
20 | the bridge chip | ||
21 | */ | ||
22 | #define MTS (1<<2) | ||
23 | |||
24 | /* FIXME: I have no idea what's the difference between | ||
25 | D2620 and D2633 firmwares | ||
26 | */ | ||
27 | #define D2620 (1<<3) | ||
28 | #define D2633 (1<<4) | ||
29 | |||
30 | /* DTV firmwares for 6, 7 and 8 MHz | ||
31 | DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS | ||
32 | DTV8 - 8MHz - DVB-C/DVB-T | ||
33 | */ | ||
34 | #define DTV6_ATSC (1<<5) | ||
35 | #define DTV6_QAM (1<<6) | ||
36 | #define DTV7 (1<<7) | ||
37 | #define DTV78 (1<<8) | ||
38 | #define DTV8 (1<<9) | ||
39 | |||
40 | /* There's a FM | BASE firmware + FM specific firmware (std=0) */ | ||
41 | #define FM (1<<10) | ||
42 | |||
43 | /* Applies only for FM firmware | ||
44 | Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) | ||
45 | */ | ||
46 | #define INPUT1 (1<<11) | ||
47 | |||
48 | |||
49 | /* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) | ||
50 | and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) | ||
51 | There are variants both with and without NOGD | ||
52 | */ | ||
53 | #define LCD (1<<12) | ||
54 | |||
55 | /* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) | ||
56 | and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) | ||
57 | */ | ||
58 | #define NOGD (1<<13) | ||
59 | |||
60 | /* Old firmwares were broken into init0 and init1 */ | ||
61 | #define INIT1 (1<<14) | ||
62 | |||
63 | /* Newer types to be moved to videodev2.h */ | ||
64 | |||
65 | #define V4L2_STD_SECAM_K3 (0x02000000) | ||
66 | |||
67 | /* Audio types */ | ||
68 | |||
69 | #define V4L2_STD_A2_A (1L<<32) | ||
70 | #define V4L2_STD_A2_B (1L<<33) | ||
71 | #define V4L2_STD_NICAM_A (1L<<34) | ||
72 | #define V4L2_STD_NICAM_B (1L<<35) | ||
73 | #define V4L2_STD_AM (1L<<36) | ||
74 | #define V4L2_STD_BTSC (1L<<37) | ||
75 | #define V4L2_STD__EIAJ (1L<<38) | ||
76 | |||
77 | #define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) | ||
78 | #define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) | ||
79 | |||
80 | /* To preserve backward compatibilty, | ||
81 | (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported | ||
82 | */ | ||
83 | |||
84 | #define V4L2_STD_AUDIO (V4L2_STD_A2 | \ | ||
85 | V4L2_STD_NICAM | \ | ||
86 | V4L2_STD_AM | \ | ||
87 | V4L2_STD_BTSC | \ | ||
88 | V4L2_STD_EIAJ) | ||
89 | |||
90 | /* Used standards with audio restrictions */ | ||
91 | |||
92 | #define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) | ||
93 | #define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) | ||
94 | #define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) | ||
95 | #define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) | ||
96 | #define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) | ||
97 | #define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) | ||
98 | #define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) | ||
99 | #define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) | ||
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index e4c371896de4..7d53d58aafa1 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 | ||
24 | static LIST_HEAD(xc2028_list); | 25 | static LIST_HEAD(xc2028_list); |
25 | 26 | /* struct for storing firmware table */ | |
26 | /* Firmwares used on tm5600/tm6000 + xc2028/xc3028 */ | 27 | struct firmware_description { |
27 | 28 | unsigned int type; | |
28 | /* Generic firmwares */ | 29 | v4l2_std_id id; |
29 | static const char *firmware_INIT0 = "tm_xc3028_MTS_init0.fw"; | 30 | unsigned char *ptr; |
30 | static const char *firmware_8MHZ_INIT0 = "tm_xc3028_8M_MTS_init0.fw"; | 31 | unsigned int size; |
31 | static const char *firmware_INIT1 = "tm_xc3028_68M_MTS_init1.fw"; | 32 | }; |
32 | |||
33 | /* Standard-specific firmwares */ | ||
34 | static const char *firmware_6M = "tm_xc3028_DTV_6M.fw"; | ||
35 | static const char *firmware_7M = "tm_xc3028_DTV_7M.fw"; | ||
36 | static const char *firmware_8M = "tm_xc3028_DTV_8M.fw"; | ||
37 | static const char *firmware_B = "tm_xc3028_B_PAL.fw"; | ||
38 | static const char *firmware_DK = "tm_xc3028_DK_PAL_MTS.fw"; | ||
39 | static const char *firmware_MN = "tm_xc3028_MN_BTSC.fw"; | ||
40 | 33 | ||
41 | struct xc2028_data { | 34 | struct 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 | ||
105 | static int load_firmware (struct dvb_frontend *fe, const char *name) | 108 | static 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 | |||
125 | static 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 | |||
239 | corrupt: | ||
240 | rc=-EINVAL; | ||
241 | tuner_info("Error: firmware file is corrupted!\n"); | ||
242 | |||
243 | err: | ||
244 | tuner_info("Releasing loaded firmware file.\n"); | ||
245 | |||
246 | free_firmware(priv); | ||
247 | |||
248 | done: | ||
249 | release_firmware(fw); | ||
250 | tuner_info("Firmware files loaded.\n"); | ||
251 | |||
252 | return rc; | ||
253 | } | ||
254 | |||
255 | static 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 | |||
291 | found: | ||
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 | ||
187 | err: | 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 | ||
193 | static int check_firmware(struct dvb_frontend *fe, enum tuner_mode new_mode, | 367 | static 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 | ||
663 | static 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 | |||
456 | static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { | 689 | static 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 | ||
diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h index d5a18a37d1c5..f4856f07bd08 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/video/tuner-xc2028.h | |||
@@ -9,13 +9,22 @@ | |||
9 | 9 | ||
10 | #include "dvb_frontend.h" | 10 | #include "dvb_frontend.h" |
11 | 11 | ||
12 | #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" | ||
13 | |||
14 | enum xc2028_firm_type { | ||
15 | XC2028_FIRM_NORMAL, | ||
16 | XC2028_FIRM_MTS, | ||
17 | }; | ||
18 | |||
19 | struct xc2028_ctrl { | ||
20 | enum xc2028_firm_type type; | ||
21 | char *fname; | ||
22 | }; | ||
23 | |||
12 | /* xc2028 commands for callback */ | 24 | /* xc2028 commands for callback */ |
13 | #define XC2028_TUNER_RESET 0 | 25 | #define XC2028_TUNER_RESET 0 |
14 | #define XC2028_RESET_CLK 1 | 26 | #define XC2028_RESET_CLK 1 |
15 | 27 | ||
16 | struct dvb_frontend; | ||
17 | struct i2c_client; | ||
18 | |||
19 | #if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) | 28 | #if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) |
20 | int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, | 29 | int xc2028_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, |
21 | u8 i2c_addr, struct device *dev, void *video_dev, | 30 | u8 i2c_addr, struct device *dev, void *video_dev, |