blob: 130794b971ce54d9e0e2dd3cdb3a3816bc7fc10f [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"
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -030032#include "s5h1432.h"
33#include "tda18271.h"
34#include "s5h1411.h"
Sri Deevie0d3baf2009-03-03 14:37:50 -030035
Sri Deevie0d3baf2009-03-03 14:37:50 -030036MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
37MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
38MODULE_LICENSE("GPL");
39
40static unsigned int debug;
41module_param(debug, int, 0644);
42MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
43
44DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
45
46#define dprintk(level, fmt, arg...) do { \
47if (debug >= level) \
48 printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
49} while (0)
50
51#define CX231XX_DVB_NUM_BUFS 5
52#define CX231XX_DVB_MAX_PACKETSIZE 564
53#define CX231XX_DVB_MAX_PACKETS 64
54
55struct cx231xx_dvb {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -030056 struct dvb_frontend *frontend;
Sri Deevie0d3baf2009-03-03 14:37:50 -030057
58 /* feed count management */
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -030059 struct mutex lock;
60 int nfeeds;
Sri Deevie0d3baf2009-03-03 14:37:50 -030061
62 /* general boilerplate stuff */
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -030063 struct dvb_adapter adapter;
64 struct dvb_demux demux;
65 struct dmxdev dmxdev;
66 struct dmx_frontend fe_hw;
67 struct dmx_frontend fe_mem;
68 struct dvb_net net;
Sri Deevie0d3baf2009-03-03 14:37:50 -030069};
70
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -030071static struct s5h1432_config dvico_s5h1432_config = {
72 .output_mode = S5H1432_SERIAL_OUTPUT,
73 .gpio = S5H1432_GPIO_ON,
74 .qam_if = S5H1432_IF_4000,
75 .vsb_if = S5H1432_IF_4000,
76 .inversion = S5H1432_INVERSION_OFF,
77 .status_mode = S5H1432_DEMODLOCKING,
78 .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
79};
80
81static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = {
82 .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4,
83 .if_lvl = 1, .rfagc_top = 0x37, },
84 .dvbt_7 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
85 .if_lvl = 1, .rfagc_top = 0x37, },
86 .dvbt_8 = { .if_freq = 4000, .agc_mode = 3, .std = 6,
87 .if_lvl = 1, .rfagc_top = 0x37, },
88};
89
90static struct tda18271_config cnxt_rde253s_tunerconfig = {
91 .std_map = &cnxt_rde253s_tda18271_std_map,
92 .gate = TDA18271_GATE_ANALOG,
93};
94
95static struct s5h1411_config tda18271_s5h1411_config = {
96 .output_mode = S5H1411_SERIAL_OUTPUT,
97 .gpio = S5H1411_GPIO_OFF,
98 .vsb_if = S5H1411_IF_3250,
99 .qam_if = S5H1411_IF_4000,
100 .inversion = S5H1411_INVERSION_ON,
101 .status_mode = S5H1411_DEMODLOCKING,
102 .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
103};
104static struct s5h1411_config xc5000_s5h1411_config = {
105 .output_mode = S5H1411_SERIAL_OUTPUT,
106 .gpio = S5H1411_GPIO_OFF,
107 .vsb_if = S5H1411_IF_3250,
108 .qam_if = S5H1411_IF_3250,
109 .inversion = S5H1411_INVERSION_OFF,
110 .status_mode = S5H1411_DEMODLOCKING,
111 .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
112};
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300113static inline void print_err_status(struct cx231xx *dev, int packet, int status)
Sri Deevie0d3baf2009-03-03 14:37:50 -0300114{
115 char *errmsg = "Unknown";
116
117 switch (status) {
118 case -ENOENT:
119 errmsg = "unlinked synchronuously";
120 break;
121 case -ECONNRESET:
122 errmsg = "unlinked asynchronuously";
123 break;
124 case -ENOSR:
125 errmsg = "Buffer error (overrun)";
126 break;
127 case -EPIPE:
128 errmsg = "Stalled (device not responding)";
129 break;
130 case -EOVERFLOW:
131 errmsg = "Babble (bad cable?)";
132 break;
133 case -EPROTO:
134 errmsg = "Bit-stuff error (bad cable?)";
135 break;
136 case -EILSEQ:
137 errmsg = "CRC/Timeout (could be anything)";
138 break;
139 case -ETIME:
140 errmsg = "Device does not respond";
141 break;
142 }
143 if (packet < 0) {
144 dprintk(1, "URB status %d [%s].\n", status, errmsg);
145 } else {
146 dprintk(1, "URB packet %d, status %d [%s].\n",
147 packet, status, errmsg);
148 }
149}
150
151static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb)
152{
153 int i;
154
155 if (!dev)
156 return 0;
157
158 if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
159 return 0;
160
161 if (urb->status < 0) {
162 print_err_status(dev, -1, urb->status);
163 if (urb->status == -ENOENT)
164 return 0;
165 }
166
167 for (i = 0; i < urb->number_of_packets; i++) {
168 int status = urb->iso_frame_desc[i].status;
169
170 if (status < 0) {
171 print_err_status(dev, i, status);
172 if (urb->iso_frame_desc[i].status != -EPROTO)
173 continue;
174 }
175
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300176 dvb_dmx_swfilter(&dev->dvb->demux,
177 urb->transfer_buffer +
178 urb->iso_frame_desc[i].offset,
179 urb->iso_frame_desc[i].actual_length);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300180 }
181
182 return 0;
183}
184
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300185static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb)
186{
187 int i;
188
189 if (!dev)
190 return 0;
191
192 if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
193 return 0;
194
195 if (urb->status < 0) {
196 print_err_status(dev, -1, urb->status);
197 if (urb->status == -ENOENT)
198 return 0;
199 }
200
201 /* Feed the transport payload into the kernel demux */
202 dvb_dmx_swfilter(&dev->dvb->demux,
203 urb->transfer_buffer, urb->actual_length);
204
205 return 0;
206}
207
Sri Deevie0d3baf2009-03-03 14:37:50 -0300208static int start_streaming(struct cx231xx_dvb *dvb)
209{
210 int rc;
211 struct cx231xx *dev = dvb->adapter.priv;
212
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300213 if (dev->USE_ISO) {
214 cx231xx_info("DVB transfer mode is ISO.\n");
215mutex_lock(&dev->i2c_lock);
216 cx231xx_enable_i2c_for_tuner(dev, I2C_1);
217 cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
218 cx231xx_enable_i2c_for_tuner(dev, I2C_3);
219mutex_unlock(&dev->i2c_lock);
220 rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
221 if (rc < 0)
222 return rc;
223 dev->mode_tv = 1;
224 return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS,
225 CX231XX_DVB_NUM_BUFS,
226 dev->ts1_mode.max_pkt_size,
227 dvb_isoc_copy);
228 } else {
229 cx231xx_info("DVB transfer mode is BULK.\n");
230 cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
231 rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
232 if (rc < 0)
233 return rc;
234 dev->mode_tv = 1;
235 return cx231xx_init_bulk(dev, CX231XX_DVB_MAX_PACKETS,
236 CX231XX_DVB_NUM_BUFS,
237 dev->ts1_mode.max_pkt_size,
238 dvb_bulk_copy);
239 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300240
Sri Deevie0d3baf2009-03-03 14:37:50 -0300241}
242
243static int stop_streaming(struct cx231xx_dvb *dvb)
244{
245 struct cx231xx *dev = dvb->adapter.priv;
246
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300247 if (dev->USE_ISO)
248 cx231xx_uninit_isoc(dev);
249 else
250 cx231xx_uninit_bulk(dev);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300251
252 cx231xx_set_mode(dev, CX231XX_SUSPEND);
253
254 return 0;
255}
256
257static int start_feed(struct dvb_demux_feed *feed)
258{
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300259 struct dvb_demux *demux = feed->demux;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300260 struct cx231xx_dvb *dvb = demux->priv;
261 int rc, ret;
262
263 if (!demux->dmx.frontend)
264 return -EINVAL;
265
266 mutex_lock(&dvb->lock);
267 dvb->nfeeds++;
268 rc = dvb->nfeeds;
269
270 if (dvb->nfeeds == 1) {
271 ret = start_streaming(dvb);
272 if (ret < 0)
273 rc = ret;
274 }
275
276 mutex_unlock(&dvb->lock);
277 return rc;
278}
279
280static int stop_feed(struct dvb_demux_feed *feed)
281{
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300282 struct dvb_demux *demux = feed->demux;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300283 struct cx231xx_dvb *dvb = demux->priv;
284 int err = 0;
285
286 mutex_lock(&dvb->lock);
287 dvb->nfeeds--;
288
289 if (0 == dvb->nfeeds)
290 err = stop_streaming(dvb);
291
292 mutex_unlock(&dvb->lock);
293 return err;
294}
295
Sri Deevie0d3baf2009-03-03 14:37:50 -0300296/* ------------------------------------------------------------------ */
297static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
298{
299 struct cx231xx *dev = fe->dvb->priv;
300
301 if (acquire)
302 return cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
303 else
304 return cx231xx_set_mode(dev, CX231XX_SUSPEND);
305}
306
307/* ------------------------------------------------------------------ */
308
Sri Deevie0d3baf2009-03-03 14:37:50 -0300309static struct xc5000_config cnxt_rde250_tunerconfig = {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300310 .i2c_address = 0x61,
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300311 .if_khz = 4000,
312};
313static struct xc5000_config cnxt_rdu250_tunerconfig = {
314 .i2c_address = 0x61,
315 .if_khz = 3250,
Sri Deevie0d3baf2009-03-03 14:37:50 -0300316};
317
Sri Deevie0d3baf2009-03-03 14:37:50 -0300318/* ------------------------------------------------------------------ */
319#if 0
320static int attach_xc5000(u8 addr, struct cx231xx *dev)
321{
322
323 struct dvb_frontend *fe;
324 struct xc5000_config cfg;
325
326 memset(&cfg, 0, sizeof(cfg));
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300327 cfg.i2c_adap = &dev->i2c_bus[1].i2c_adap;
328 cfg.i2c_addr = addr;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300329
330 if (!dev->dvb->frontend) {
331 printk(KERN_ERR "%s/2: dvb frontend not attached. "
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300332 "Can't attach xc5000\n", dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300333 return -EINVAL;
334 }
335
336 fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
337 if (!fe) {
338 printk(KERN_ERR "%s/2: xc5000 attach failed\n", dev->name);
339 dvb_frontend_detach(dev->dvb->frontend);
340 dev->dvb->frontend = NULL;
341 return -EINVAL;
342 }
343
344 printk(KERN_INFO "%s/2: xc5000 attached\n", dev->name);
345
346 return 0;
347}
348#endif
349
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300350int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
Sri Deevie0d3baf2009-03-03 14:37:50 -0300351{
352 int status = 0;
353
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300354 if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
Sri Deevie0d3baf2009-03-03 14:37:50 -0300355
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300356 struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300357
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300358 if (dops->set_analog_params != NULL) {
359 struct analog_parameters params;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300360
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300361 params.frequency = freq;
362 params.std = dev->norm;
363 params.mode = 0; /* 0- Air; 1 - cable */
364 /*params.audmode = ; */
Sri Deevie0d3baf2009-03-03 14:37:50 -0300365
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300366 /* Set the analog parameters to set the frequency */
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300367 dops->set_analog_params(dev->dvb->frontend, &params);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300368 }
369
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300370 }
371
Sri Deevie0d3baf2009-03-03 14:37:50 -0300372 return status;
373}
374
375int cx231xx_reset_analog_tuner(struct cx231xx *dev)
376{
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300377 int status = 0;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300378
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300379 if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
Sri Deevie0d3baf2009-03-03 14:37:50 -0300380
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300381 struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300382
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300383 if (dops->init != NULL && !dev->xc_fw_load_done) {
Sri Deevie0d3baf2009-03-03 14:37:50 -0300384
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300385 cx231xx_info("Reloading firmware for XC5000\n");
386 status = dops->init(dev->dvb->frontend);
387 if (status == 0) {
388 dev->xc_fw_load_done = 1;
389 cx231xx_info
390 ("XC5000 firmware download completed\n");
391 } else {
392 dev->xc_fw_load_done = 0;
393 cx231xx_info
394 ("XC5000 firmware download failed !!!\n");
Sri Deevie0d3baf2009-03-03 14:37:50 -0300395 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300396 }
397
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300398 }
399
Sri Deevie0d3baf2009-03-03 14:37:50 -0300400 return status;
401}
402
Sri Deevie0d3baf2009-03-03 14:37:50 -0300403/* ------------------------------------------------------------------ */
404
405static int register_dvb(struct cx231xx_dvb *dvb,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300406 struct module *module,
407 struct cx231xx *dev, struct device *device)
Sri Deevie0d3baf2009-03-03 14:37:50 -0300408{
409 int result;
410
411 mutex_init(&dvb->lock);
412
413 /* register adapter */
414 result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
415 adapter_nr);
416 if (result < 0) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300417 printk(KERN_WARNING
418 "%s: dvb_register_adapter failed (errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300419 dev->name, result);
420 goto fail_adapter;
421 }
422
423 /* Ensure all frontends negotiate bus access */
424 dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
425
426 dvb->adapter.priv = dev;
427
428 /* register frontend */
429 result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
430 if (result < 0) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300431 printk(KERN_WARNING
432 "%s: dvb_register_frontend failed (errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300433 dev->name, result);
434 goto fail_frontend;
435 }
436
437 /* register demux stuff */
438 dvb->demux.dmx.capabilities =
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300439 DMX_TS_FILTERING | DMX_SECTION_FILTERING |
440 DMX_MEMORY_BASED_FILTERING;
441 dvb->demux.priv = dvb;
442 dvb->demux.filternum = 256;
443 dvb->demux.feednum = 256;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300444 dvb->demux.start_feed = start_feed;
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300445 dvb->demux.stop_feed = stop_feed;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300446
447 result = dvb_dmx_init(&dvb->demux);
448 if (result < 0) {
449 printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
450 dev->name, result);
451 goto fail_dmx;
452 }
453
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300454 dvb->dmxdev.filternum = 256;
455 dvb->dmxdev.demux = &dvb->demux.dmx;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300456 dvb->dmxdev.capabilities = 0;
457 result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
458 if (result < 0) {
459 printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
460 dev->name, result);
461 goto fail_dmxdev;
462 }
463
464 dvb->fe_hw.source = DMX_FRONTEND_0;
465 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
466 if (result < 0) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300467 printk(KERN_WARNING
468 "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300469 dev->name, result);
470 goto fail_fe_hw;
471 }
472
473 dvb->fe_mem.source = DMX_MEMORY_FE;
474 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
475 if (result < 0) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300476 printk(KERN_WARNING
477 "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
Sri Deevie0d3baf2009-03-03 14:37:50 -0300478 dev->name, result);
479 goto fail_fe_mem;
480 }
481
482 result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
483 if (result < 0) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300484 printk(KERN_WARNING
485 "%s: connect_frontend failed (errno = %d)\n", dev->name,
486 result);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300487 goto fail_fe_conn;
488 }
489
490 /* register network adapter */
491 dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
492 return 0;
493
Sri Deevib9255172009-03-04 17:49:01 -0300494fail_fe_conn:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300495 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
Sri Deevib9255172009-03-04 17:49:01 -0300496fail_fe_mem:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300497 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
Sri Deevib9255172009-03-04 17:49:01 -0300498fail_fe_hw:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300499 dvb_dmxdev_release(&dvb->dmxdev);
Sri Deevib9255172009-03-04 17:49:01 -0300500fail_dmxdev:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300501 dvb_dmx_release(&dvb->demux);
Sri Deevib9255172009-03-04 17:49:01 -0300502fail_dmx:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300503 dvb_unregister_frontend(dvb->frontend);
Sri Deevib9255172009-03-04 17:49:01 -0300504fail_frontend:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300505 dvb_frontend_detach(dvb->frontend);
506 dvb_unregister_adapter(&dvb->adapter);
Sri Deevib9255172009-03-04 17:49:01 -0300507fail_adapter:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300508 return result;
509}
510
511static void unregister_dvb(struct cx231xx_dvb *dvb)
512{
513 dvb_net_release(&dvb->net);
514 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
515 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
516 dvb_dmxdev_release(&dvb->dmxdev);
517 dvb_dmx_release(&dvb->demux);
518 dvb_unregister_frontend(dvb->frontend);
519 dvb_frontend_detach(dvb->frontend);
520 dvb_unregister_adapter(&dvb->adapter);
521}
522
Sri Deevie0d3baf2009-03-03 14:37:50 -0300523static int dvb_init(struct cx231xx *dev)
524{
525 int result = 0;
526 struct cx231xx_dvb *dvb;
527
528 if (!dev->board.has_dvb) {
529 /* This device does not support the extension */
530 return 0;
531 }
532
533 dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL);
534
535 if (dvb == NULL) {
536 printk(KERN_INFO "cx231xx_dvb: memory allocation failed\n");
537 return -ENOMEM;
538 }
539 dev->dvb = dvb;
540 dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq;
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300541 dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300542
543 cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300544 cx231xx_demod_reset(dev);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300545 /* init frontend */
546 switch (dev->model) {
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300547 case CX231XX_BOARD_CNXT_CARRAERA:
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300548 case CX231XX_BOARD_CNXT_RDE_250:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300549
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300550 dev->dvb->frontend = dvb_attach(s5h1432_attach,
551 &dvico_s5h1432_config,
552 &dev->i2c_bus[2].i2c_adap);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300553
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300554 if (dev->dvb->frontend == NULL) {
555 printk(DRIVER_NAME
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300556 ": Failed to attach s5h1432 front end\n");
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300557 result = -EINVAL;
558 goto out_free;
559 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300560
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300561 /* define general-purpose callback pointer */
562 dvb->frontend->callback = cx231xx_tuner_callback;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300563
Márton Némethd5abcc72010-01-16 13:21:59 -0300564 if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300565 &dev->i2c_bus[1].i2c_adap,
Márton Némethd5abcc72010-01-16 13:21:59 -0300566 &cnxt_rde250_tunerconfig)) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300567 result = -EINVAL;
568 goto out_free;
569 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300570
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300571 break;
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300572 case CX231XX_BOARD_CNXT_SHELBY:
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300573 case CX231XX_BOARD_CNXT_RDU_250:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300574
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300575 dev->dvb->frontend = dvb_attach(s5h1411_attach,
576 &xc5000_s5h1411_config,
577 &dev->i2c_bus[2].i2c_adap);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300578
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300579 if (dev->dvb->frontend == NULL) {
580 printk(DRIVER_NAME
581 ": Failed to attach dummy front end\n");
582 result = -EINVAL;
583 goto out_free;
584 }
Sri Deevie0d3baf2009-03-03 14:37:50 -0300585
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300586 /* define general-purpose callback pointer */
587 dvb->frontend->callback = cx231xx_tuner_callback;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300588
Márton Némethd5abcc72010-01-16 13:21:59 -0300589 if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300590 &dev->i2c_bus[1].i2c_adap,
Palash Bandyopadhyay64fbf442010-07-06 18:12:25 -0300591 &cnxt_rdu250_tunerconfig)) {
592 result = -EINVAL;
593 goto out_free;
594 }
595 break;
596 case CX231XX_BOARD_CNXT_RDE_253S:
597
598 dev->dvb->frontend = dvb_attach(s5h1432_attach,
599 &dvico_s5h1432_config,
600 &dev->i2c_bus[2].i2c_adap);
601
602 if (dev->dvb->frontend == NULL) {
603 printk(DRIVER_NAME
604 ": Failed to attach s5h1432 front end\n");
605 result = -EINVAL;
606 goto out_free;
607 }
608
609 /* define general-purpose callback pointer */
610 dvb->frontend->callback = cx231xx_tuner_callback;
611
612 if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
613 0x60, &dev->i2c_bus[1].i2c_adap,
614 &cnxt_rde253s_tunerconfig)) {
615 result = -EINVAL;
616 goto out_free;
617 }
618 break;
619 case CX231XX_BOARD_CNXT_RDU_253S:
620
621 dev->dvb->frontend = dvb_attach(s5h1411_attach,
622 &tda18271_s5h1411_config,
623 &dev->i2c_bus[2].i2c_adap);
624
625 if (dev->dvb->frontend == NULL) {
626 printk(DRIVER_NAME
627 ": Failed to attach dummy front end\n");
628 result = -EINVAL;
629 goto out_free;
630 }
631
632 /* define general-purpose callback pointer */
633 dvb->frontend->callback = cx231xx_tuner_callback;
634
635 if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
636 0x60, &dev->i2c_bus[1].i2c_adap,
637 &cnxt_rde253s_tunerconfig)) {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300638 result = -EINVAL;
639 goto out_free;
640 }
641 break;
Sri Deevie0d3baf2009-03-03 14:37:50 -0300642
643 default:
644 printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300645 " isn't supported yet\n", dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300646 break;
647 }
648 if (NULL == dvb->frontend) {
649 printk(KERN_ERR
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300650 "%s/2: frontend initialization failed\n", dev->name);
Sri Deevie0d3baf2009-03-03 14:37:50 -0300651 result = -EINVAL;
652 goto out_free;
653 }
654
Sri Deevie0d3baf2009-03-03 14:37:50 -0300655 /* register everything */
656 result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
657
658 if (result < 0)
659 goto out_free;
660
661 cx231xx_set_mode(dev, CX231XX_SUSPEND);
662 printk(KERN_INFO "Successfully loaded cx231xx-dvb\n");
663 return 0;
664
Sri Deevib9255172009-03-04 17:49:01 -0300665out_free:
Sri Deevie0d3baf2009-03-03 14:37:50 -0300666 cx231xx_set_mode(dev, CX231XX_SUSPEND);
667 kfree(dvb);
668 dev->dvb = NULL;
669 return result;
670}
671
672static int dvb_fini(struct cx231xx *dev)
673{
674 if (!dev->board.has_dvb) {
675 /* This device does not support the extension */
676 return 0;
677 }
678
679 if (dev->dvb) {
680 unregister_dvb(dev->dvb);
681 dev->dvb = NULL;
682 }
683
684 return 0;
685}
686
687static struct cx231xx_ops dvb_ops = {
Mauro Carvalho Chehab84b5dbf2009-03-03 06:14:34 -0300688 .id = CX231XX_DVB,
Sri Deevie0d3baf2009-03-03 14:37:50 -0300689 .name = "Cx231xx dvb Extension",
690 .init = dvb_init,
691 .fini = dvb_fini,
692};
693
694static int __init cx231xx_dvb_register(void)
695{
696 return cx231xx_register_extension(&dvb_ops);
697}
698
699static void __exit cx231xx_dvb_unregister(void)
700{
701 cx231xx_unregister_extension(&dvb_ops);
702}
703
704module_init(cx231xx_dvb_register);
705module_exit(cx231xx_dvb_unregister);