diff options
Diffstat (limited to 'drivers/media/dvb/bt8xx/dvb-bt8xx.c')
-rw-r--r-- | drivers/media/dvb/bt8xx/dvb-bt8xx.c | 970 |
1 files changed, 970 insertions, 0 deletions
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c new file mode 100644 index 00000000000..521d6910498 --- /dev/null +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c | |||
@@ -0,0 +1,970 @@ | |||
1 | /* | ||
2 | * Bt8xx based DVB adapter driver | ||
3 | * | ||
4 | * Copyright (C) 2002,2003 Florian Schirmer <jolt@tuxbox.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/bitops.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/i2c.h> | ||
30 | |||
31 | #include "dmxdev.h" | ||
32 | #include "dvbdev.h" | ||
33 | #include "dvb_demux.h" | ||
34 | #include "dvb_frontend.h" | ||
35 | #include "dvb-bt8xx.h" | ||
36 | #include "bt878.h" | ||
37 | |||
38 | static int debug; | ||
39 | |||
40 | module_param(debug, int, 0644); | ||
41 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
42 | |||
43 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
44 | |||
45 | #define dprintk( args... ) \ | ||
46 | do { \ | ||
47 | if (debug) printk(KERN_DEBUG args); \ | ||
48 | } while (0) | ||
49 | |||
50 | #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ | ||
51 | |||
52 | static void dvb_bt8xx_task(unsigned long data) | ||
53 | { | ||
54 | struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data; | ||
55 | |||
56 | //printk("%d ", card->bt->finished_block); | ||
57 | |||
58 | while (card->bt->last_block != card->bt->finished_block) { | ||
59 | (card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) | ||
60 | (&card->demux, | ||
61 | &card->bt->buf_cpu[card->bt->last_block * | ||
62 | card->bt->block_bytes], | ||
63 | card->bt->block_bytes); | ||
64 | card->bt->last_block = (card->bt->last_block + 1) % | ||
65 | card->bt->block_count; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
70 | { | ||
71 | struct dvb_demux*dvbdmx = dvbdmxfeed->demux; | ||
72 | struct dvb_bt8xx_card *card = dvbdmx->priv; | ||
73 | int rc; | ||
74 | |||
75 | dprintk("dvb_bt8xx: start_feed\n"); | ||
76 | |||
77 | if (!dvbdmx->dmx.frontend) | ||
78 | return -EINVAL; | ||
79 | |||
80 | mutex_lock(&card->lock); | ||
81 | card->nfeeds++; | ||
82 | rc = card->nfeeds; | ||
83 | if (card->nfeeds == 1) | ||
84 | bt878_start(card->bt, card->gpio_mode, | ||
85 | card->op_sync_orin, card->irq_err_ignore); | ||
86 | mutex_unlock(&card->lock); | ||
87 | return rc; | ||
88 | } | ||
89 | |||
90 | static int dvb_bt8xx_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | ||
91 | { | ||
92 | struct dvb_demux *dvbdmx = dvbdmxfeed->demux; | ||
93 | struct dvb_bt8xx_card *card = dvbdmx->priv; | ||
94 | |||
95 | dprintk("dvb_bt8xx: stop_feed\n"); | ||
96 | |||
97 | if (!dvbdmx->dmx.frontend) | ||
98 | return -EINVAL; | ||
99 | |||
100 | mutex_lock(&card->lock); | ||
101 | card->nfeeds--; | ||
102 | if (card->nfeeds == 0) | ||
103 | bt878_stop(card->bt); | ||
104 | mutex_unlock(&card->lock); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int is_pci_slot_eq(struct pci_dev* adev, struct pci_dev* bdev) | ||
110 | { | ||
111 | if ((adev->subsystem_vendor == bdev->subsystem_vendor) && | ||
112 | (adev->subsystem_device == bdev->subsystem_device) && | ||
113 | (adev->bus->number == bdev->bus->number) && | ||
114 | (PCI_SLOT(adev->devfn) == PCI_SLOT(bdev->devfn))) | ||
115 | return 1; | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static struct bt878 __devinit *dvb_bt8xx_878_match(unsigned int bttv_nr, struct pci_dev* bttv_pci_dev) | ||
120 | { | ||
121 | unsigned int card_nr; | ||
122 | |||
123 | /* Hmm, n squared. Hope n is small */ | ||
124 | for (card_nr = 0; card_nr < bt878_num; card_nr++) | ||
125 | if (is_pci_slot_eq(bt878[card_nr].dev, bttv_pci_dev)) | ||
126 | return &bt878[card_nr]; | ||
127 | return NULL; | ||
128 | } | ||
129 | |||
130 | static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) | ||
131 | { | ||
132 | static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 }; | ||
133 | static u8 mt352_reset [] = { 0x50, 0x80 }; | ||
134 | static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; | ||
135 | static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 }; | ||
136 | static u8 mt352_gpp_ctl_cfg [] = { 0x8C, 0x33 }; | ||
137 | static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; | ||
138 | |||
139 | mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); | ||
140 | udelay(2000); | ||
141 | mt352_write(fe, mt352_reset, sizeof(mt352_reset)); | ||
142 | mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); | ||
143 | |||
144 | mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); | ||
145 | mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); | ||
146 | mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) | ||
152 | { | ||
153 | u32 div; | ||
154 | unsigned char bs = 0; | ||
155 | unsigned char cp = 0; | ||
156 | |||
157 | if (buf_len < 5) | ||
158 | return -EINVAL; | ||
159 | |||
160 | div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; | ||
161 | |||
162 | if (params->frequency < 542000000) | ||
163 | cp = 0xb4; | ||
164 | else if (params->frequency < 771000000) | ||
165 | cp = 0xbc; | ||
166 | else | ||
167 | cp = 0xf4; | ||
168 | |||
169 | if (params->frequency == 0) | ||
170 | bs = 0x03; | ||
171 | else if (params->frequency < 443250000) | ||
172 | bs = 0x02; | ||
173 | else | ||
174 | bs = 0x08; | ||
175 | |||
176 | pllbuf[0] = 0x60; | ||
177 | pllbuf[1] = div >> 8; | ||
178 | pllbuf[2] = div & 0xff; | ||
179 | pllbuf[3] = cp; | ||
180 | pllbuf[4] = bs; | ||
181 | |||
182 | return 5; | ||
183 | } | ||
184 | |||
185 | static struct mt352_config thomson_dtt7579_config = { | ||
186 | .demod_address = 0x0f, | ||
187 | .demod_init = thomson_dtt7579_demod_init, | ||
188 | }; | ||
189 | |||
190 | static struct zl10353_config thomson_dtt7579_zl10353_config = { | ||
191 | .demod_address = 0x0f, | ||
192 | }; | ||
193 | |||
194 | static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) | ||
195 | { | ||
196 | u32 freq = params->frequency; | ||
197 | |||
198 | int i, a, n, pump; | ||
199 | u32 band, pll; | ||
200 | |||
201 | u32 osci[]={950000,1019000,1075000,1178000,1296000,1432000, | ||
202 | 1576000,1718000,1856000,2036000,2150000}; | ||
203 | u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,0x00101000, | ||
204 | 0x00102000,0x00104000,0x00108000,0x00110000, | ||
205 | 0x00120000,0x00140000}; | ||
206 | |||
207 | #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */ | ||
208 | printk("cx24108 debug: entering SetTunerFreq, freq=%d\n",freq); | ||
209 | |||
210 | /* This is really the bit driving the tuner chip cx24108 */ | ||
211 | |||
212 | if (freq<950000) | ||
213 | freq = 950000; /* kHz */ | ||
214 | else if (freq>2150000) | ||
215 | freq = 2150000; /* satellite IF is 950..2150MHz */ | ||
216 | |||
217 | /* decide which VCO to use for the input frequency */ | ||
218 | for(i = 1; (i < ARRAY_SIZE(osci) - 1) && (osci[i] < freq); i++); | ||
219 | printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq); | ||
220 | band=bandsel[i]; | ||
221 | /* the gain values must be set by SetSymbolrate */ | ||
222 | /* compute the pll divider needed, from Conexant data sheet, | ||
223 | resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4, | ||
224 | depending on the divider bit. It is set to /4 on the 2 lowest | ||
225 | bands */ | ||
226 | n=((i<=2?2:1)*freq*10L)/(XTAL/100); | ||
227 | a=n%32; n/=32; if(a==0) n--; | ||
228 | pump=(freq<(osci[i-1]+osci[i])/2); | ||
229 | pll=0xf8000000| | ||
230 | ((pump?1:2)<<(14+11))| | ||
231 | ((n&0x1ff)<<(5+11))| | ||
232 | ((a&0x1f)<<11); | ||
233 | /* everything is shifted left 11 bits to left-align the bits in the | ||
234 | 32bit word. Output to the tuner goes MSB-aligned, after all */ | ||
235 | printk("cx24108 debug: pump=%d, n=%d, a=%d\n",pump,n,a); | ||
236 | cx24110_pll_write(fe,band); | ||
237 | /* set vga and vca to their widest-band settings, as a precaution. | ||
238 | SetSymbolrate might not be called to set this up */ | ||
239 | cx24110_pll_write(fe,0x500c0000); | ||
240 | cx24110_pll_write(fe,0x83f1f800); | ||
241 | cx24110_pll_write(fe,pll); | ||
242 | //writereg(client,0x56,0x7f); | ||
243 | |||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int pinnsat_tuner_init(struct dvb_frontend* fe) | ||
248 | { | ||
249 | struct dvb_bt8xx_card *card = fe->dvb->priv; | ||
250 | |||
251 | bttv_gpio_enable(card->bttv_nr, 1, 1); /* output */ | ||
252 | bttv_write_gpio(card->bttv_nr, 1, 1); /* relay on */ | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int pinnsat_tuner_sleep(struct dvb_frontend* fe) | ||
258 | { | ||
259 | struct dvb_bt8xx_card *card = fe->dvb->priv; | ||
260 | |||
261 | bttv_write_gpio(card->bttv_nr, 1, 0); /* relay off */ | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static struct cx24110_config pctvsat_config = { | ||
267 | .demod_address = 0x55, | ||
268 | }; | ||
269 | |||
270 | static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) | ||
271 | { | ||
272 | struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; | ||
273 | u8 cfg, cpump, band_select; | ||
274 | u8 data[4]; | ||
275 | u32 div; | ||
276 | struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; | ||
277 | |||
278 | div = (36000000 + params->frequency + 83333) / 166666; | ||
279 | cfg = 0x88; | ||
280 | |||
281 | if (params->frequency < 175000000) | ||
282 | cpump = 2; | ||
283 | else if (params->frequency < 390000000) | ||
284 | cpump = 1; | ||
285 | else if (params->frequency < 470000000) | ||
286 | cpump = 2; | ||
287 | else if (params->frequency < 750000000) | ||
288 | cpump = 2; | ||
289 | else | ||
290 | cpump = 3; | ||
291 | |||
292 | if (params->frequency < 175000000) | ||
293 | band_select = 0x0e; | ||
294 | else if (params->frequency < 470000000) | ||
295 | band_select = 0x05; | ||
296 | else | ||
297 | band_select = 0x03; | ||
298 | |||
299 | data[0] = (div >> 8) & 0x7f; | ||
300 | data[1] = div & 0xff; | ||
301 | data[2] = ((div >> 10) & 0x60) | cfg; | ||
302 | data[3] = (cpump << 6) | band_select; | ||
303 | |||
304 | if (fe->ops.i2c_gate_ctrl) | ||
305 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
306 | i2c_transfer(card->i2c_adapter, &msg, 1); | ||
307 | return (div * 166666 - 36000000); | ||
308 | } | ||
309 | |||
310 | static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) | ||
311 | { | ||
312 | struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; | ||
313 | |||
314 | return request_firmware(fw, name, &bt->bt->dev->dev); | ||
315 | } | ||
316 | |||
317 | static struct sp887x_config microtune_mt7202dtf_config = { | ||
318 | .demod_address = 0x70, | ||
319 | .request_firmware = microtune_mt7202dtf_request_firmware, | ||
320 | }; | ||
321 | |||
322 | static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) | ||
323 | { | ||
324 | static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; | ||
325 | static u8 mt352_reset [] = { 0x50, 0x80 }; | ||
326 | static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; | ||
327 | static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, | ||
328 | 0x00, 0xFF, 0x00, 0x40, 0x40 }; | ||
329 | static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; | ||
330 | static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; | ||
331 | |||
332 | mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); | ||
333 | udelay(2000); | ||
334 | mt352_write(fe, mt352_reset, sizeof(mt352_reset)); | ||
335 | mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); | ||
336 | |||
337 | mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); | ||
338 | udelay(2000); | ||
339 | mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra)); | ||
340 | mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) | ||
346 | { | ||
347 | u32 div; | ||
348 | unsigned char bs = 0; | ||
349 | unsigned char cp = 0; | ||
350 | |||
351 | if (buf_len < 5) return -EINVAL; | ||
352 | |||
353 | div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; | ||
354 | |||
355 | if (params->frequency < 150000000) | ||
356 | cp = 0xB4; | ||
357 | else if (params->frequency < 173000000) | ||
358 | cp = 0xBC; | ||
359 | else if (params->frequency < 250000000) | ||
360 | cp = 0xB4; | ||
361 | else if (params->frequency < 400000000) | ||
362 | cp = 0xBC; | ||
363 | else if (params->frequency < 420000000) | ||
364 | cp = 0xF4; | ||
365 | else if (params->frequency < 470000000) | ||
366 | cp = 0xFC; | ||
367 | else if (params->frequency < 600000000) | ||
368 | cp = 0xBC; | ||
369 | else if (params->frequency < 730000000) | ||
370 | cp = 0xF4; | ||
371 | else | ||
372 | cp = 0xFC; | ||
373 | |||
374 | if (params->frequency < 150000000) | ||
375 | bs = 0x01; | ||
376 | else if (params->frequency < 173000000) | ||
377 | bs = 0x01; | ||
378 | else if (params->frequency < 250000000) | ||
379 | bs = 0x02; | ||
380 | else if (params->frequency < 400000000) | ||
381 | bs = 0x02; | ||
382 | else if (params->frequency < 420000000) | ||
383 | bs = 0x02; | ||
384 | else if (params->frequency < 470000000) | ||
385 | bs = 0x02; | ||
386 | else if (params->frequency < 600000000) | ||
387 | bs = 0x08; | ||
388 | else if (params->frequency < 730000000) | ||
389 | bs = 0x08; | ||
390 | else | ||
391 | bs = 0x08; | ||
392 | |||
393 | pllbuf[0] = 0x61; | ||
394 | pllbuf[1] = div >> 8; | ||
395 | pllbuf[2] = div & 0xff; | ||
396 | pllbuf[3] = cp; | ||
397 | pllbuf[4] = bs; | ||
398 | |||
399 | return 5; | ||
400 | } | ||
401 | |||
402 | static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { | ||
403 | .demod_address = 0x0f, | ||
404 | .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, | ||
405 | }; | ||
406 | |||
407 | static struct dst_config dst_config = { | ||
408 | .demod_address = 0x55, | ||
409 | }; | ||
410 | |||
411 | static int or51211_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) | ||
412 | { | ||
413 | struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; | ||
414 | |||
415 | return request_firmware(fw, name, &bt->bt->dev->dev); | ||
416 | } | ||
417 | |||
418 | static void or51211_setmode(struct dvb_frontend * fe, int mode) | ||
419 | { | ||
420 | struct dvb_bt8xx_card *bt = fe->dvb->priv; | ||
421 | bttv_write_gpio(bt->bttv_nr, 0x0002, mode); /* Reset */ | ||
422 | msleep(20); | ||
423 | } | ||
424 | |||
425 | static void or51211_reset(struct dvb_frontend * fe) | ||
426 | { | ||
427 | struct dvb_bt8xx_card *bt = fe->dvb->priv; | ||
428 | |||
429 | /* RESET DEVICE | ||
430 | * reset is controlled by GPIO-0 | ||
431 | * when set to 0 causes reset and when to 1 for normal op | ||
432 | * must remain reset for 128 clock cycles on a 50Mhz clock | ||
433 | * also PRM1 PRM2 & PRM4 are controlled by GPIO-1,GPIO-2 & GPIO-4 | ||
434 | * We assume that the reset has be held low long enough or we | ||
435 | * have been reset by a power on. When the driver is unloaded | ||
436 | * reset set to 0 so if reloaded we have been reset. | ||
437 | */ | ||
438 | /* reset & PRM1,2&4 are outputs */ | ||
439 | int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F); | ||
440 | if (ret != 0) | ||
441 | printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret); | ||
442 | bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */ | ||
443 | msleep(20); | ||
444 | /* Now set for normal operation */ | ||
445 | bttv_write_gpio(bt->bttv_nr, 0x0001F, 0x0001); | ||
446 | /* wait for operation to begin */ | ||
447 | msleep(500); | ||
448 | } | ||
449 | |||
450 | static void or51211_sleep(struct dvb_frontend * fe) | ||
451 | { | ||
452 | struct dvb_bt8xx_card *bt = fe->dvb->priv; | ||
453 | bttv_write_gpio(bt->bttv_nr, 0x0001, 0x0000); | ||
454 | } | ||
455 | |||
456 | static struct or51211_config or51211_config = { | ||
457 | .demod_address = 0x15, | ||
458 | .request_firmware = or51211_request_firmware, | ||
459 | .setmode = or51211_setmode, | ||
460 | .reset = or51211_reset, | ||
461 | .sleep = or51211_sleep, | ||
462 | }; | ||
463 | |||
464 | static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) | ||
465 | { | ||
466 | struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; | ||
467 | u8 buf[4]; | ||
468 | u32 div; | ||
469 | struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) }; | ||
470 | |||
471 | div = (params->frequency + 36166667) / 166667; | ||
472 | |||
473 | buf[0] = (div >> 8) & 0x7F; | ||
474 | buf[1] = div & 0xFF; | ||
475 | buf[2] = 0x85; | ||
476 | if ((params->frequency >= 47000000) && (params->frequency < 153000000)) | ||
477 | buf[3] = 0x01; | ||
478 | else if ((params->frequency >= 153000000) && (params->frequency < 430000000)) | ||
479 | buf[3] = 0x02; | ||
480 | else if ((params->frequency >= 430000000) && (params->frequency < 824000000)) | ||
481 | buf[3] = 0x0C; | ||
482 | else if ((params->frequency >= 824000000) && (params->frequency < 863000000)) | ||
483 | buf[3] = 0x8C; | ||
484 | else | ||
485 | return -EINVAL; | ||
486 | |||
487 | if (fe->ops.i2c_gate_ctrl) | ||
488 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
489 | i2c_transfer(card->i2c_adapter, &msg, 1); | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static struct nxt6000_config vp3021_alps_tded4_config = { | ||
494 | .demod_address = 0x0a, | ||
495 | .clock_inversion = 1, | ||
496 | }; | ||
497 | |||
498 | static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) | ||
499 | { | ||
500 | static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; | ||
501 | static u8 mt352_reset [] = { 0x50, 0x80 }; | ||
502 | static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; | ||
503 | static u8 mt352_agc_cfg [] = { 0x67, 0x20, 0xa0 }; | ||
504 | static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; | ||
505 | |||
506 | mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); | ||
507 | udelay(2000); | ||
508 | mt352_write(fe, mt352_reset, sizeof(mt352_reset)); | ||
509 | mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); | ||
510 | mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); | ||
511 | mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) | ||
517 | { | ||
518 | u32 div; | ||
519 | struct dvb_ofdm_parameters *op = ¶ms->u.ofdm; | ||
520 | |||
521 | if (buf_len < 5) | ||
522 | return -EINVAL; | ||
523 | |||
524 | div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; | ||
525 | |||
526 | pllbuf[0] = 0x61; | ||
527 | pllbuf[1] = (div >> 8) & 0x7F; | ||
528 | pllbuf[2] = div & 0xFF; | ||
529 | pllbuf[3] = 0x85; | ||
530 | |||
531 | dprintk("frequency %u, div %u\n", params->frequency, div); | ||
532 | |||
533 | if (params->frequency < 470000000) | ||
534 | pllbuf[4] = 0x02; | ||
535 | else if (params->frequency > 823000000) | ||
536 | pllbuf[4] = 0x88; | ||
537 | else | ||
538 | pllbuf[4] = 0x08; | ||
539 | |||
540 | if (op->bandwidth == 8) | ||
541 | pllbuf[4] |= 0x04; | ||
542 | |||
543 | return 5; | ||
544 | } | ||
545 | |||
546 | static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) | ||
547 | { | ||
548 | /* | ||
549 | * Reset the frontend, must be called before trying | ||
550 | * to initialise the MT352 or mt352_attach | ||
551 | * will fail. Same goes for the nxt6000 frontend. | ||
552 | * | ||
553 | */ | ||
554 | |||
555 | int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08); | ||
556 | if (ret != 0) | ||
557 | printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret); | ||
558 | |||
559 | /* Pulse the reset line */ | ||
560 | bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ | ||
561 | bttv_write_gpio(bt->bttv_nr, 0x08, 0x00); /* Low */ | ||
562 | msleep(100); | ||
563 | |||
564 | bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ | ||
565 | } | ||
566 | |||
567 | static struct mt352_config digitv_alps_tded4_config = { | ||
568 | .demod_address = 0x0a, | ||
569 | .demod_init = digitv_alps_tded4_demod_init, | ||
570 | }; | ||
571 | |||
572 | static struct lgdt330x_config tdvs_tua6034_config = { | ||
573 | .demod_address = 0x0e, | ||
574 | .demod_chip = LGDT3303, | ||
575 | .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ | ||
576 | }; | ||
577 | |||
578 | static void lgdt330x_reset(struct dvb_bt8xx_card *bt) | ||
579 | { | ||
580 | /* Set pin 27 of the lgdt3303 chip high to reset the frontend */ | ||
581 | |||
582 | /* Pulse the reset line */ | ||
583 | bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ | ||
584 | bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000000); /* Low */ | ||
585 | msleep(100); | ||
586 | |||
587 | bttv_write_gpio(bt->bttv_nr, 0x00e00007, 0x00000001); /* High */ | ||
588 | msleep(100); | ||
589 | } | ||
590 | |||
591 | static void frontend_init(struct dvb_bt8xx_card *card, u32 type) | ||
592 | { | ||
593 | struct dst_state* state = NULL; | ||
594 | |||
595 | switch(type) { | ||
596 | case BTTV_BOARD_DVICO_DVBT_LITE: | ||
597 | card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter); | ||
598 | |||
599 | if (card->fe == NULL) | ||
600 | card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config, | ||
601 | card->i2c_adapter); | ||
602 | |||
603 | if (card->fe != NULL) { | ||
604 | card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs; | ||
605 | card->fe->ops.info.frequency_min = 174000000; | ||
606 | card->fe->ops.info.frequency_max = 862000000; | ||
607 | } | ||
608 | break; | ||
609 | |||
610 | case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: | ||
611 | lgdt330x_reset(card); | ||
612 | card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter); | ||
613 | if (card->fe != NULL) { | ||
614 | dvb_attach(simple_tuner_attach, card->fe, | ||
615 | card->i2c_adapter, 0x61, | ||
616 | TUNER_LG_TDVS_H06XF); | ||
617 | dprintk ("dvb_bt8xx: lgdt330x detected\n"); | ||
618 | } | ||
619 | break; | ||
620 | |||
621 | case BTTV_BOARD_NEBULA_DIGITV: | ||
622 | /* | ||
623 | * It is possible to determine the correct frontend using the I2C bus (see the Nebula SDK); | ||
624 | * this would be a cleaner solution than trying each frontend in turn. | ||
625 | */ | ||
626 | |||
627 | /* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */ | ||
628 | digitv_alps_tded4_reset(card); | ||
629 | card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter); | ||
630 | if (card->fe != NULL) { | ||
631 | card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params; | ||
632 | dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); | ||
633 | break; | ||
634 | } | ||
635 | |||
636 | /* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */ | ||
637 | digitv_alps_tded4_reset(card); | ||
638 | card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter); | ||
639 | |||
640 | if (card->fe != NULL) { | ||
641 | card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs; | ||
642 | dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); | ||
643 | } | ||
644 | break; | ||
645 | |||
646 | case BTTV_BOARD_AVDVBT_761: | ||
647 | card->fe = dvb_attach(sp887x_attach, µtune_mt7202dtf_config, card->i2c_adapter); | ||
648 | if (card->fe) { | ||
649 | card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params; | ||
650 | } | ||
651 | break; | ||
652 | |||
653 | case BTTV_BOARD_AVDVBT_771: | ||
654 | card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); | ||
655 | if (card->fe != NULL) { | ||
656 | card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs; | ||
657 | card->fe->ops.info.frequency_min = 174000000; | ||
658 | card->fe->ops.info.frequency_max = 862000000; | ||
659 | } | ||
660 | break; | ||
661 | |||
662 | case BTTV_BOARD_TWINHAN_DST: | ||
663 | /* DST is not a frontend driver !!! */ | ||
664 | state = kmalloc(sizeof (struct dst_state), GFP_KERNEL); | ||
665 | if (!state) { | ||
666 | printk("dvb_bt8xx: No memory\n"); | ||
667 | break; | ||
668 | } | ||
669 | /* Setup the Card */ | ||
670 | state->config = &dst_config; | ||
671 | state->i2c = card->i2c_adapter; | ||
672 | state->bt = card->bt; | ||
673 | state->dst_ca = NULL; | ||
674 | /* DST is not a frontend, attaching the ASIC */ | ||
675 | if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) { | ||
676 | printk("%s: Could not find a Twinhan DST.\n", __func__); | ||
677 | break; | ||
678 | } | ||
679 | /* Attach other DST peripherals if any */ | ||
680 | /* Conditional Access device */ | ||
681 | card->fe = &state->frontend; | ||
682 | if (state->dst_hw_cap & DST_TYPE_HAS_CA) | ||
683 | dvb_attach(dst_ca_attach, state, &card->dvb_adapter); | ||
684 | break; | ||
685 | |||
686 | case BTTV_BOARD_PINNACLESAT: | ||
687 | card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter); | ||
688 | if (card->fe) { | ||
689 | card->fe->ops.tuner_ops.init = pinnsat_tuner_init; | ||
690 | card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep; | ||
691 | card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params; | ||
692 | } | ||
693 | break; | ||
694 | |||
695 | case BTTV_BOARD_PC_HDTV: | ||
696 | card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter); | ||
697 | if (card->fe != NULL) | ||
698 | dvb_attach(simple_tuner_attach, card->fe, | ||
699 | card->i2c_adapter, 0x61, | ||
700 | TUNER_PHILIPS_FCV1236D); | ||
701 | break; | ||
702 | } | ||
703 | |||
704 | if (card->fe == NULL) | ||
705 | printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", | ||
706 | card->bt->dev->vendor, | ||
707 | card->bt->dev->device, | ||
708 | card->bt->dev->subsystem_vendor, | ||
709 | card->bt->dev->subsystem_device); | ||
710 | else | ||
711 | if (dvb_register_frontend(&card->dvb_adapter, card->fe)) { | ||
712 | printk("dvb-bt8xx: Frontend registration failed!\n"); | ||
713 | dvb_frontend_detach(card->fe); | ||
714 | card->fe = NULL; | ||
715 | } | ||
716 | } | ||
717 | |||
718 | static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) | ||
719 | { | ||
720 | int result; | ||
721 | |||
722 | result = dvb_register_adapter(&card->dvb_adapter, card->card_name, | ||
723 | THIS_MODULE, &card->bt->dev->dev, | ||
724 | adapter_nr); | ||
725 | if (result < 0) { | ||
726 | printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result); | ||
727 | return result; | ||
728 | } | ||
729 | card->dvb_adapter.priv = card; | ||
730 | |||
731 | card->bt->adapter = card->i2c_adapter; | ||
732 | |||
733 | memset(&card->demux, 0, sizeof(struct dvb_demux)); | ||
734 | |||
735 | card->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING; | ||
736 | |||
737 | card->demux.priv = card; | ||
738 | card->demux.filternum = 256; | ||
739 | card->demux.feednum = 256; | ||
740 | card->demux.start_feed = dvb_bt8xx_start_feed; | ||
741 | card->demux.stop_feed = dvb_bt8xx_stop_feed; | ||
742 | card->demux.write_to_decoder = NULL; | ||
743 | |||
744 | if ((result = dvb_dmx_init(&card->demux)) < 0) { | ||
745 | printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); | ||
746 | |||
747 | dvb_unregister_adapter(&card->dvb_adapter); | ||
748 | return result; | ||
749 | } | ||
750 | |||
751 | card->dmxdev.filternum = 256; | ||
752 | card->dmxdev.demux = &card->demux.dmx; | ||
753 | card->dmxdev.capabilities = 0; | ||
754 | |||
755 | if ((result = dvb_dmxdev_init(&card->dmxdev, &card->dvb_adapter)) < 0) { | ||
756 | printk("dvb_bt8xx: dvb_dmxdev_init failed (errno = %d)\n", result); | ||
757 | |||
758 | dvb_dmx_release(&card->demux); | ||
759 | dvb_unregister_adapter(&card->dvb_adapter); | ||
760 | return result; | ||
761 | } | ||
762 | |||
763 | card->fe_hw.source = DMX_FRONTEND_0; | ||
764 | |||
765 | if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_hw)) < 0) { | ||
766 | printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); | ||
767 | |||
768 | dvb_dmxdev_release(&card->dmxdev); | ||
769 | dvb_dmx_release(&card->demux); | ||
770 | dvb_unregister_adapter(&card->dvb_adapter); | ||
771 | return result; | ||
772 | } | ||
773 | |||
774 | card->fe_mem.source = DMX_MEMORY_FE; | ||
775 | |||
776 | if ((result = card->demux.dmx.add_frontend(&card->demux.dmx, &card->fe_mem)) < 0) { | ||
777 | printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); | ||
778 | |||
779 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); | ||
780 | dvb_dmxdev_release(&card->dmxdev); | ||
781 | dvb_dmx_release(&card->demux); | ||
782 | dvb_unregister_adapter(&card->dvb_adapter); | ||
783 | return result; | ||
784 | } | ||
785 | |||
786 | if ((result = card->demux.dmx.connect_frontend(&card->demux.dmx, &card->fe_hw)) < 0) { | ||
787 | printk("dvb_bt8xx: dvb_dmx_init failed (errno = %d)\n", result); | ||
788 | |||
789 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); | ||
790 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); | ||
791 | dvb_dmxdev_release(&card->dmxdev); | ||
792 | dvb_dmx_release(&card->demux); | ||
793 | dvb_unregister_adapter(&card->dvb_adapter); | ||
794 | return result; | ||
795 | } | ||
796 | |||
797 | dvb_net_init(&card->dvb_adapter, &card->dvbnet, &card->demux.dmx); | ||
798 | |||
799 | tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); | ||
800 | |||
801 | frontend_init(card, type); | ||
802 | |||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | static int __devinit dvb_bt8xx_probe(struct bttv_sub_device *sub) | ||
807 | { | ||
808 | struct dvb_bt8xx_card *card; | ||
809 | struct pci_dev* bttv_pci_dev; | ||
810 | int ret; | ||
811 | |||
812 | if (!(card = kzalloc(sizeof(struct dvb_bt8xx_card), GFP_KERNEL))) | ||
813 | return -ENOMEM; | ||
814 | |||
815 | mutex_init(&card->lock); | ||
816 | card->bttv_nr = sub->core->nr; | ||
817 | strlcpy(card->card_name, sub->core->v4l2_dev.name, sizeof(card->card_name)); | ||
818 | card->i2c_adapter = &sub->core->i2c_adap; | ||
819 | |||
820 | switch(sub->core->type) { | ||
821 | case BTTV_BOARD_PINNACLESAT: | ||
822 | card->gpio_mode = 0x0400c060; | ||
823 | /* should be: BT878_A_GAIN=0,BT878_A_PWRDN,BT878_DA_DPM,BT878_DA_SBR, | ||
824 | BT878_DA_IOM=1,BT878_DA_APP to enable serial highspeed mode. */ | ||
825 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
826 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
827 | break; | ||
828 | |||
829 | case BTTV_BOARD_DVICO_DVBT_LITE: | ||
830 | card->gpio_mode = 0x0400C060; | ||
831 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
832 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
833 | /* 26, 15, 14, 6, 5 | ||
834 | * A_PWRDN DA_DPM DA_SBR DA_IOM_DA | ||
835 | * DA_APP(parallel) */ | ||
836 | break; | ||
837 | |||
838 | case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: | ||
839 | card->gpio_mode = 0x0400c060; | ||
840 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
841 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
842 | break; | ||
843 | |||
844 | case BTTV_BOARD_NEBULA_DIGITV: | ||
845 | case BTTV_BOARD_AVDVBT_761: | ||
846 | card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); | ||
847 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
848 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
849 | /* A_PWRDN DA_SBR DA_APP (high speed serial) */ | ||
850 | break; | ||
851 | |||
852 | case BTTV_BOARD_AVDVBT_771: //case 0x07711461: | ||
853 | card->gpio_mode = 0x0400402B; | ||
854 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
855 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
856 | /* A_PWRDN DA_SBR DA_APP[0] PKTP=10 RISC_ENABLE FIFO_ENABLE*/ | ||
857 | break; | ||
858 | |||
859 | case BTTV_BOARD_TWINHAN_DST: | ||
860 | card->gpio_mode = 0x2204f2c; | ||
861 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
862 | card->irq_err_ignore = BT878_APABORT | BT878_ARIPERR | | ||
863 | BT878_APPERR | BT878_AFBUS; | ||
864 | /* 25,21,14,11,10,9,8,3,2 then | ||
865 | * 0x33 = 5,4,1,0 | ||
866 | * A_SEL=SML, DA_MLB, DA_SBR, | ||
867 | * DA_SDR=f, fifo trigger = 32 DWORDS | ||
868 | * IOM = 0 == audio A/D | ||
869 | * DPM = 0 == digital audio mode | ||
870 | * == async data parallel port | ||
871 | * then 0x33 (13 is set by start_capture) | ||
872 | * DA_APP = async data parallel port, | ||
873 | * ACAP_EN = 1, | ||
874 | * RISC+FIFO ENABLE */ | ||
875 | break; | ||
876 | |||
877 | case BTTV_BOARD_PC_HDTV: | ||
878 | card->gpio_mode = 0x0100EC7B; | ||
879 | card->op_sync_orin = BT878_RISC_SYNC_MASK; | ||
880 | card->irq_err_ignore = BT878_AFBUS | BT878_AFDSR; | ||
881 | break; | ||
882 | |||
883 | default: | ||
884 | printk(KERN_WARNING "dvb_bt8xx: Unknown bttv card type: %d.\n", | ||
885 | sub->core->type); | ||
886 | kfree(card); | ||
887 | return -ENODEV; | ||
888 | } | ||
889 | |||
890 | dprintk("dvb_bt8xx: identified card%d as %s\n", card->bttv_nr, card->card_name); | ||
891 | |||
892 | if (!(bttv_pci_dev = bttv_get_pcidev(card->bttv_nr))) { | ||
893 | printk("dvb_bt8xx: no pci device for card %d\n", card->bttv_nr); | ||
894 | kfree(card); | ||
895 | return -ENODEV; | ||
896 | } | ||
897 | |||
898 | if (!(card->bt = dvb_bt8xx_878_match(card->bttv_nr, bttv_pci_dev))) { | ||
899 | printk("dvb_bt8xx: unable to determine DMA core of card %d,\n", | ||
900 | card->bttv_nr); | ||
901 | printk("dvb_bt8xx: if you have the ALSA bt87x audio driver " | ||
902 | "installed, try removing it.\n"); | ||
903 | |||
904 | kfree(card); | ||
905 | return -ENODEV; | ||
906 | } | ||
907 | |||
908 | mutex_init(&card->bt->gpio_lock); | ||
909 | card->bt->bttv_nr = sub->core->nr; | ||
910 | |||
911 | if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) { | ||
912 | kfree(card); | ||
913 | return ret; | ||
914 | } | ||
915 | |||
916 | dev_set_drvdata(&sub->dev, card); | ||
917 | return 0; | ||
918 | } | ||
919 | |||
920 | static void dvb_bt8xx_remove(struct bttv_sub_device *sub) | ||
921 | { | ||
922 | struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev); | ||
923 | |||
924 | dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); | ||
925 | |||
926 | bt878_stop(card->bt); | ||
927 | tasklet_kill(&card->bt->tasklet); | ||
928 | dvb_net_release(&card->dvbnet); | ||
929 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); | ||
930 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); | ||
931 | dvb_dmxdev_release(&card->dmxdev); | ||
932 | dvb_dmx_release(&card->demux); | ||
933 | if (card->fe) { | ||
934 | dvb_unregister_frontend(card->fe); | ||
935 | dvb_frontend_detach(card->fe); | ||
936 | } | ||
937 | dvb_unregister_adapter(&card->dvb_adapter); | ||
938 | |||
939 | kfree(card); | ||
940 | } | ||
941 | |||
942 | static struct bttv_sub_driver driver = { | ||
943 | .drv = { | ||
944 | .name = "dvb-bt8xx", | ||
945 | }, | ||
946 | .probe = dvb_bt8xx_probe, | ||
947 | .remove = dvb_bt8xx_remove, | ||
948 | /* FIXME: | ||
949 | * .shutdown = dvb_bt8xx_shutdown, | ||
950 | * .suspend = dvb_bt8xx_suspend, | ||
951 | * .resume = dvb_bt8xx_resume, | ||
952 | */ | ||
953 | }; | ||
954 | |||
955 | static int __init dvb_bt8xx_init(void) | ||
956 | { | ||
957 | return bttv_sub_register(&driver, "dvb"); | ||
958 | } | ||
959 | |||
960 | static void __exit dvb_bt8xx_exit(void) | ||
961 | { | ||
962 | bttv_sub_unregister(&driver); | ||
963 | } | ||
964 | |||
965 | module_init(dvb_bt8xx_init); | ||
966 | module_exit(dvb_bt8xx_exit); | ||
967 | |||
968 | MODULE_DESCRIPTION("Bt8xx based DVB adapter driver"); | ||
969 | MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>"); | ||
970 | MODULE_LICENSE("GPL"); | ||