blob: 4ea3776b39fba2a4c46abb0f7c238887184d01ed [file] [log] [blame]
Sri Deevie0d3baf2009-03-03 14:37:50 -03001/*
2 DVB device driver for cx231xx
3
4 Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
Sri Deevib9255172009-03-04 17:49:01 -03005 Based on em28xx driver
Sri Deevie0d3baf2009-03-03 14:37:50 -03006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Sri Deevie0d3baf2009-03-03 14:37:50 -030024#include <linux/usb.h>
25
26#include "cx231xx.h"
27#include <media/v4l2-common.h>
28#include <media/videobuf-vmalloc.h>
29
30#include "xc5000.h"
31#include "dvb_dummy_fe.h"
32
Sri Deevie0d3baf2009-03-03 14:37:50 -030033MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
34MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
35MODULE_LICENSE("GPL");
36
37static unsigned int debug;
38module_param(debug, int, 0644);
39MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
40
41DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
42
43#define dprintk(level, fmt, arg...) do { \
44if (debug >= level) \
45 printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
46} while (0)
47
48#define CX231XX_DVB_NUM_BUFS 5
49#define CX231XX_DVB_MAX_PACKETSIZE 564
50#define CX231XX_DVB_MAX_PACKETS 64
51
52struct cx231xx_dvb {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -030053 struct dvb_frontend *frontend;
Sri Deevie0d3baf2009-03-03 14:37:50 -030054
55 /* feed count management */
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -030056 struct mutex lock;
57 int nfeeds;
Sri Deevie0d3baf2009-03-03 14:37:50 -030058
59 /* general boilerplate stuff */
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -030060 struct dvb_adapter adapter;
61 struct dvb_demux demux;
62 struct dmxdev dmxdev;
63 struct dmx_frontend fe_hw;
64 struct dmx_frontend fe_mem;
65 struct dvb_net net;
Sri Deevie0d3baf2009-03-03 14:37:50 -030066};
67
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -030068static inline void print_err_status(struct cx231xx *dev, int packet, int status)
Sri Deevie0d3baf2009-03-03 14:37:50 -030069{
70 char *errmsg = "Unknown";
71
72 switch (status) {
73 case -ENOENT:
74 errmsg = "unlinked synchronuously";
75 break;
76 case -ECONNRESET:
77 errmsg = "unlinked asynchronuously";
78 break;
79 case -ENOSR:
80 errmsg = "Buffer error (overrun)";
81 break;
82 case -EPIPE:
83 errmsg = "Stalled (device not responding)";
84 break;
85 case -EOVERFLOW:
86 errmsg = "Babble (bad cable?)";
87 break;
88 case -EPROTO:
89 errmsg = "Bit-stuff error (bad cable?)";
90 break;
91 case -EILSEQ:
92 errmsg = "CRC/Timeout (could be anything)";
93 break;
94 case -ETIME:
95 errmsg = "Device does not respond";
96 break;
97 }
98 if (packet < 0) {
99 dprintk(1, "URB status %d [%s].\n", status, errmsg);
100 } else {
101 dprintk(1, "URB packet %d, status %d [%s].\n",
102 packet, status, errmsg);
103 }
104}
105
106static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb)
107{
108 int i;
109
110 if (!dev)
111 return 0;
112
113 if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
114 return 0;
115
116 if (urb->status < 0) {
117 print_err_status(dev, -1, urb->status);
118 if (urb->status == -ENOENT)
119 return 0;
120 }
121
122 for (i = 0; i < urb->number_of_packets; i++) {
123 int status = urb->iso_frame_desc[i].status;
124
125 if (status < 0) {
126 print_err_status(dev, i, status);
127 if (urb->iso_frame_desc[i].status != -EPROTO)
128 continue;
129 }
130
131 dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
132 urb->iso_frame_desc[i].offset,
133 urb->iso_frame_desc[i].actual_length);
134 }
135
136 return 0;
137}
138
139static int start_streaming(struct cx231xx_dvb *dvb)
140{
141 int rc;
142 struct cx231xx *dev = dvb->adapter.priv;
143
144 usb_set_interface(dev->udev, 0, 1);
145 rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
146 if (rc < 0)
147 return rc;
148
149 return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300150 CX231XX_DVB_NUM_BUFS,
151 CX231XX_DVB_MAX_PACKETSIZE, dvb_isoc_copy);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300152}
153
154static int stop_streaming(struct cx231xx_dvb *dvb)
155{
156 struct cx231xx *dev = dvb->adapter.priv;
157
158 cx231xx_uninit_isoc(dev);
159
160 cx231xx_set_mode(dev, CX231XX_SUSPEND);
161
162 return 0;
163}
164
165static int start_feed(struct dvb_demux_feed *feed)
166{
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300167 struct dvb_demux *demux = feed->demux;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300168 struct cx231xx_dvb *dvb = demux->priv;
169 int rc, ret;
170
171 if (!demux->dmx.frontend)
172 return -EINVAL;
173
174 mutex_lock(&dvb->lock);
175 dvb->nfeeds++;
176 rc = dvb->nfeeds;
177
178 if (dvb->nfeeds == 1) {
179 ret = start_streaming(dvb);
180 if (ret < 0)
181 rc = ret;
182 }
183
184 mutex_unlock(&dvb->lock);
185 return rc;
186}
187
188static int stop_feed(struct dvb_demux_feed *feed)
189{
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300190 struct dvb_demux *demux = feed->demux;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300191 struct cx231xx_dvb *dvb = demux->priv;
192 int err = 0;
193
194 mutex_lock(&dvb->lock);
195 dvb->nfeeds--;
196
197 if (0 == dvb->nfeeds)
198 err = stop_streaming(dvb);
199
200 mutex_unlock(&dvb->lock);
201 return err;
202}
203
Sri Deevie0d3baf2009-03-03 14:37:50 -0300204/* ------------------------------------------------------------------ */
205static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
206{
207 struct cx231xx *dev = fe->dvb->priv;
208
209 if (acquire)
210 return cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
211 else
212 return cx231xx_set_mode(dev, CX231XX_SUSPEND);
213}
214
215/* ------------------------------------------------------------------ */
216
Sri Deevie0d3baf2009-03-03 14:37:50 -0300217static struct xc5000_config cnxt_rde250_tunerconfig = {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300218 .i2c_address = 0x61,
219 .if_khz = 5380,
Sri Deevie0d3baf2009-03-03 14:37:50 -0300220};
221
Sri Deevie0d3baf2009-03-03 14:37:50 -0300222/* ------------------------------------------------------------------ */
223#if 0
224static int attach_xc5000(u8 addr, struct cx231xx *dev)
225{
226
227 struct dvb_frontend *fe;
228 struct xc5000_config cfg;
229
230 memset(&cfg, 0, sizeof(cfg));
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300231 cfg.i2c_adap = &dev->i2c_bus[1].i2c_adap;
232 cfg.i2c_addr = addr;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300233
234 if (!dev->dvb->frontend) {
235 printk(KERN_ERR "%s/2: dvb frontend not attached. "
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300236 "Can't attach xc5000\n", dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300237 return -EINVAL;
238 }
239
240 fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
241 if (!fe) {
242 printk(KERN_ERR "%s/2: xc5000 attach failed\n", dev->name);
243 dvb_frontend_detach(dev->dvb->frontend);
244 dev->dvb->frontend = NULL;
245 return -EINVAL;
246 }
247
248 printk(KERN_INFO "%s/2: xc5000 attached\n", dev->name);
249
250 return 0;
251}
252#endif
253
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300254int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
Sri Deevie0d3baf2009-03-03 14:37:50 -0300255{
256 int status = 0;
257
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300258 if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
Sri Deevie0d3baf2009-03-03 14:37:50 -0300259
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300260 struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300261
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300262 if (dops->set_analog_params != NULL) {
263 struct analog_parameters params;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300264
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300265 params.frequency = freq;
266 params.std = dev->norm;
267 params.mode = 0; /* 0- Air; 1 - cable */
268 /*params.audmode = ; */
Sri Deevie0d3baf2009-03-03 14:37:50 -0300269
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300270 /* Set the analog parameters to set the frequency */
271 cx231xx_info("Setting Frequency for XC5000\n");
272 dops->set_analog_params(dev->dvb->frontend, &params);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300273 }
274
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300275 }
276
Sri Deevie0d3baf2009-03-03 14:37:50 -0300277 return status;
278}
279
280int cx231xx_reset_analog_tuner(struct cx231xx *dev)
281{
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300282 int status = 0;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300283
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300284 if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
Sri Deevie0d3baf2009-03-03 14:37:50 -0300285
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300286 struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300287
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300288 if (dops->init != NULL && !dev->xc_fw_load_done) {
Sri Deevie0d3baf2009-03-03 14:37:50 -0300289
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300290 cx231xx_info("Reloading firmware for XC5000\n");
291 status = dops->init(dev->dvb->frontend);
292 if (status == 0) {
293 dev->xc_fw_load_done = 1;
294 cx231xx_info
295 ("XC5000 firmware download completed\n");
296 } else {
297 dev->xc_fw_load_done = 0;
298 cx231xx_info
299 ("XC5000 firmware download failed !!!\n");
Sri Deevie0d3baf2009-03-03 14:37:50 -0300300 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300301 }
302
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300303 }
304
Sri Deevie0d3baf2009-03-03 14:37:50 -0300305 return status;
306}
307
Sri Deevie0d3baf2009-03-03 14:37:50 -0300308/* ------------------------------------------------------------------ */
309
310static int register_dvb(struct cx231xx_dvb *dvb,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300311 struct module *module,
312 struct cx231xx *dev, struct device *device)
Sri Deevie0d3baf2009-03-03 14:37:50 -0300313{
314 int result;
315
316 mutex_init(&dvb->lock);
317
318 /* register adapter */
319 result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
320 adapter_nr);
321 if (result < 0) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300322 printk(KERN_WARNING
323 "%s: dvb_register_adapter failed (errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300324 dev->name, result);
325 goto fail_adapter;
326 }
327
328 /* Ensure all frontends negotiate bus access */
329 dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
330
331 dvb->adapter.priv = dev;
332
333 /* register frontend */
334 result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
335 if (result < 0) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300336 printk(KERN_WARNING
337 "%s: dvb_register_frontend failed (errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300338 dev->name, result);
339 goto fail_frontend;
340 }
341
342 /* register demux stuff */
343 dvb->demux.dmx.capabilities =
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300344 DMX_TS_FILTERING | DMX_SECTION_FILTERING |
345 DMX_MEMORY_BASED_FILTERING;
346 dvb->demux.priv = dvb;
347 dvb->demux.filternum = 256;
348 dvb->demux.feednum = 256;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300349 dvb->demux.start_feed = start_feed;
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300350 dvb->demux.stop_feed = stop_feed;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300351
352 result = dvb_dmx_init(&dvb->demux);
353 if (result < 0) {
354 printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
355 dev->name, result);
356 goto fail_dmx;
357 }
358
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300359 dvb->dmxdev.filternum = 256;
360 dvb->dmxdev.demux = &dvb->demux.dmx;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300361 dvb->dmxdev.capabilities = 0;
362 result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
363 if (result < 0) {
364 printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
365 dev->name, result);
366 goto fail_dmxdev;
367 }
368
369 dvb->fe_hw.source = DMX_FRONTEND_0;
370 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
371 if (result < 0) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300372 printk(KERN_WARNING
373 "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300374 dev->name, result);
375 goto fail_fe_hw;
376 }
377
378 dvb->fe_mem.source = DMX_MEMORY_FE;
379 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
380 if (result < 0) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300381 printk(KERN_WARNING
382 "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300383 dev->name, result);
384 goto fail_fe_mem;
385 }
386
387 result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
388 if (result < 0) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300389 printk(KERN_WARNING
390 "%s: connect_frontend failed (errno = %d)\n", dev->name,
391 result);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300392 goto fail_fe_conn;
393 }
394
395 /* register network adapter */
396 dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
397 return 0;
398
Sri Deevib9255172009-03-04 17:49:01 -0300399fail_fe_conn:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300400 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
Sri Deevib9255172009-03-04 17:49:01 -0300401fail_fe_mem:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300402 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
Sri Deevib9255172009-03-04 17:49:01 -0300403fail_fe_hw:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300404 dvb_dmxdev_release(&dvb->dmxdev);
Sri Deevib9255172009-03-04 17:49:01 -0300405fail_dmxdev:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300406 dvb_dmx_release(&dvb->demux);
Sri Deevib9255172009-03-04 17:49:01 -0300407fail_dmx:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300408 dvb_unregister_frontend(dvb->frontend);
Sri Deevib9255172009-03-04 17:49:01 -0300409fail_frontend:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300410 dvb_frontend_detach(dvb->frontend);
411 dvb_unregister_adapter(&dvb->adapter);
Sri Deevib9255172009-03-04 17:49:01 -0300412fail_adapter:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300413 return result;
414}
415
416static void unregister_dvb(struct cx231xx_dvb *dvb)
417{
418 dvb_net_release(&dvb->net);
419 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
420 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
421 dvb_dmxdev_release(&dvb->dmxdev);
422 dvb_dmx_release(&dvb->demux);
423 dvb_unregister_frontend(dvb->frontend);
424 dvb_frontend_detach(dvb->frontend);
425 dvb_unregister_adapter(&dvb->adapter);
426}
427
Sri Deevie0d3baf2009-03-03 14:37:50 -0300428static int dvb_init(struct cx231xx *dev)
429{
430 int result = 0;
431 struct cx231xx_dvb *dvb;
432
433 if (!dev->board.has_dvb) {
434 /* This device does not support the extension */
435 return 0;
436 }
437
438 dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL);
439
440 if (dvb == NULL) {
441 printk(KERN_INFO "cx231xx_dvb: memory allocation failed\n");
442 return -ENOMEM;
443 }
444 dev->dvb = dvb;
445 dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq;
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300446 dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300447
448 cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
449 /* init frontend */
450 switch (dev->model) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300451 case CX231XX_BOARD_CNXT_RDE_250:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300452
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300453 /* dev->dvb->frontend = dvb_attach(s5h1411_attach,
454 &dvico_s5h1411_config,
455 &dev->i2c_bus[1].i2c_adap); */
456 dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300457
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300458 if (dev->dvb->frontend == NULL) {
459 printk(DRIVER_NAME
460 ": Failed to attach dummy front end\n");
461 result = -EINVAL;
462 goto out_free;
463 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300464
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300465 /* define general-purpose callback pointer */
466 dvb->frontend->callback = cx231xx_tuner_callback;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300467
Márton Némethd5abcc72010-01-16 13:21:59 -0300468 if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300469 &dev->i2c_bus[1].i2c_adap,
Márton Némethd5abcc72010-01-16 13:21:59 -0300470 &cnxt_rde250_tunerconfig)) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300471 result = -EINVAL;
472 goto out_free;
473 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300474
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300475 break;
476 case CX231XX_BOARD_CNXT_RDU_250:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300477
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300478 dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300479
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300480 if (dev->dvb->frontend == NULL) {
481 printk(DRIVER_NAME
482 ": Failed to attach dummy front end\n");
483 result = -EINVAL;
484 goto out_free;
485 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300486
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300487 /* define general-purpose callback pointer */
488 dvb->frontend->callback = cx231xx_tuner_callback;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300489
Márton Némethd5abcc72010-01-16 13:21:59 -0300490 if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300491 &dev->i2c_bus[1].i2c_adap,
Márton Némethd5abcc72010-01-16 13:21:59 -0300492 &cnxt_rde250_tunerconfig)) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300493 result = -EINVAL;
494 goto out_free;
495 }
496 break;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300497
498 default:
499 printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300500 " isn't supported yet\n", dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300501 break;
502 }
503 if (NULL == dvb->frontend) {
504 printk(KERN_ERR
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300505 "%s/2: frontend initialization failed\n", dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300506 result = -EINVAL;
507 goto out_free;
508 }
509
Sri Deevie0d3baf2009-03-03 14:37:50 -0300510 /* register everything */
511 result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
512
513 if (result < 0)
514 goto out_free;
515
516 cx231xx_set_mode(dev, CX231XX_SUSPEND);
517 printk(KERN_INFO "Successfully loaded cx231xx-dvb\n");
518 return 0;
519
Sri Deevib9255172009-03-04 17:49:01 -0300520out_free:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300521 cx231xx_set_mode(dev, CX231XX_SUSPEND);
522 kfree(dvb);
523 dev->dvb = NULL;
524 return result;
525}
526
527static int dvb_fini(struct cx231xx *dev)
528{
529 if (!dev->board.has_dvb) {
530 /* This device does not support the extension */
531 return 0;
532 }
533
534 if (dev->dvb) {
535 unregister_dvb(dev->dvb);
536 dev->dvb = NULL;
537 }
538
539 return 0;
540}
541
542static struct cx231xx_ops dvb_ops = {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300543 .id = CX231XX_DVB,
Sri Deevie0d3baf2009-03-03 14:37:50 -0300544 .name = "Cx231xx dvb Extension",
545 .init = dvb_init,
546 .fini = dvb_fini,
547};
548
549static int __init cx231xx_dvb_register(void)
550{
551 return cx231xx_register_extension(&dvb_ops);
552}
553
554static void __exit cx231xx_dvb_unregister(void)
555{
556 cx231xx_unregister_extension(&dvb_ops);
557}
558
559module_init(cx231xx_dvb_register);
560module_exit(cx231xx_dvb_unregister);