Commit | Line | Data |
---|---|---|
e0d3bafd SD |
1 | /* |
2 | DVB device driver for cx231xx | |
3 | ||
4 | Copyright (C) 2008 <srinivasa.deevi at conexant dot com> | |
b9255176 | 5 | Based on em28xx driver |
e0d3bafd SD |
6 | |
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 | ||
589dadf2 | 22 | #include "cx231xx.h" |
e0d3bafd | 23 | #include <linux/kernel.h> |
5a0e3ad6 | 24 | #include <linux/slab.h> |
e0d3bafd | 25 | |
e0d3bafd SD |
26 | #include <media/v4l2-common.h> |
27 | #include <media/videobuf-vmalloc.h> | |
28 | ||
29 | #include "xc5000.h" | |
64fbf444 PB |
30 | #include "s5h1432.h" |
31 | #include "tda18271.h" | |
32 | #include "s5h1411.h" | |
1a50fdde | 33 | #include "lgdt3305.h" |
dd2e7dd2 | 34 | #include "si2165.h" |
ede676c7 | 35 | #include "mb86a20s.h" |
9e49f7c3 | 36 | #include "si2157.h" |
809abdbf | 37 | #include "lgdt3306a.h" |
e0d3bafd | 38 | |
e0d3bafd SD |
39 | MODULE_DESCRIPTION("driver for cx231xx based DVB cards"); |
40 | MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>"); | |
41 | MODULE_LICENSE("GPL"); | |
42 | ||
43 | static unsigned int debug; | |
44 | module_param(debug, int, 0644); | |
45 | MODULE_PARM_DESC(debug, "enable debug messages [dvb]"); | |
46 | ||
47 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |
48 | ||
e0d3bafd SD |
49 | #define CX231XX_DVB_NUM_BUFS 5 |
50 | #define CX231XX_DVB_MAX_PACKETSIZE 564 | |
51 | #define CX231XX_DVB_MAX_PACKETS 64 | |
52 | ||
53 | struct cx231xx_dvb { | |
84b5dbf3 | 54 | struct dvb_frontend *frontend; |
e0d3bafd SD |
55 | |
56 | /* feed count management */ | |
84b5dbf3 MCC |
57 | struct mutex lock; |
58 | int nfeeds; | |
e0d3bafd SD |
59 | |
60 | /* general boilerplate stuff */ | |
84b5dbf3 MCC |
61 | struct dvb_adapter adapter; |
62 | struct dvb_demux demux; | |
63 | struct dmxdev dmxdev; | |
64 | struct dmx_frontend fe_hw; | |
65 | struct dmx_frontend fe_mem; | |
66 | struct dvb_net net; | |
6d3debaf | 67 | struct i2c_client *i2c_client_tuner; |
e0d3bafd SD |
68 | }; |
69 | ||
64fbf444 PB |
70 | static struct s5h1432_config dvico_s5h1432_config = { |
71 | .output_mode = S5H1432_SERIAL_OUTPUT, | |
72 | .gpio = S5H1432_GPIO_ON, | |
73 | .qam_if = S5H1432_IF_4000, | |
74 | .vsb_if = S5H1432_IF_4000, | |
75 | .inversion = S5H1432_INVERSION_OFF, | |
76 | .status_mode = S5H1432_DEMODLOCKING, | |
77 | .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | |
78 | }; | |
79 | ||
80 | static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = { | |
81 | .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4, | |
82 | .if_lvl = 1, .rfagc_top = 0x37, }, | |
83 | .dvbt_7 = { .if_freq = 4000, .agc_mode = 3, .std = 5, | |
84 | .if_lvl = 1, .rfagc_top = 0x37, }, | |
85 | .dvbt_8 = { .if_freq = 4000, .agc_mode = 3, .std = 6, | |
86 | .if_lvl = 1, .rfagc_top = 0x37, }, | |
87 | }; | |
88 | ||
ede676c7 | 89 | static struct tda18271_std_map mb86a20s_tda18271_config = { |
84c09d72 MCC |
90 | .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4, |
91 | .if_lvl = 0, .rfagc_top = 0x37, }, | |
ede676c7 MCC |
92 | }; |
93 | ||
64fbf444 PB |
94 | static struct tda18271_config cnxt_rde253s_tunerconfig = { |
95 | .std_map = &cnxt_rde253s_tda18271_std_map, | |
96 | .gate = TDA18271_GATE_ANALOG, | |
97 | }; | |
98 | ||
99 | static struct s5h1411_config tda18271_s5h1411_config = { | |
100 | .output_mode = S5H1411_SERIAL_OUTPUT, | |
101 | .gpio = S5H1411_GPIO_OFF, | |
102 | .vsb_if = S5H1411_IF_3250, | |
103 | .qam_if = S5H1411_IF_4000, | |
104 | .inversion = S5H1411_INVERSION_ON, | |
105 | .status_mode = S5H1411_DEMODLOCKING, | |
106 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | |
107 | }; | |
108 | static struct s5h1411_config xc5000_s5h1411_config = { | |
109 | .output_mode = S5H1411_SERIAL_OUTPUT, | |
110 | .gpio = S5H1411_GPIO_OFF, | |
111 | .vsb_if = S5H1411_IF_3250, | |
112 | .qam_if = S5H1411_IF_3250, | |
113 | .inversion = S5H1411_INVERSION_OFF, | |
114 | .status_mode = S5H1411_DEMODLOCKING, | |
115 | .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, | |
116 | }; | |
1a50fdde MK |
117 | |
118 | static struct lgdt3305_config hcw_lgdt3305_config = { | |
119 | .i2c_addr = 0x0e, | |
120 | .mpeg_mode = LGDT3305_MPEG_SERIAL, | |
121 | .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE, | |
122 | .tpvalid_polarity = LGDT3305_TP_VALID_HIGH, | |
123 | .deny_i2c_rptr = 1, | |
124 | .spectral_inversion = 1, | |
125 | .qam_if_khz = 4000, | |
126 | .vsb_if_khz = 3250, | |
127 | }; | |
128 | ||
129 | static struct tda18271_std_map hauppauge_tda18271_std_map = { | |
130 | .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4, | |
131 | .if_lvl = 1, .rfagc_top = 0x58, }, | |
132 | .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5, | |
133 | .if_lvl = 1, .rfagc_top = 0x58, }, | |
134 | }; | |
135 | ||
136 | static struct tda18271_config hcw_tda18271_config = { | |
137 | .std_map = &hauppauge_tda18271_std_map, | |
138 | .gate = TDA18271_GATE_DIGITAL, | |
139 | }; | |
140 | ||
ede676c7 MCC |
141 | static const struct mb86a20s_config pv_mb86a20s_config = { |
142 | .demod_address = 0x10, | |
7572f9c5 | 143 | .is_serial = true, |
ede676c7 MCC |
144 | }; |
145 | ||
146 | static struct tda18271_config pv_tda18271_config = { | |
147 | .std_map = &mb86a20s_tda18271_config, | |
148 | .gate = TDA18271_GATE_DIGITAL, | |
149 | .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, | |
150 | }; | |
151 | ||
dd2e7dd2 MS |
152 | static const struct si2165_config hauppauge_930C_HD_1113xx_si2165_config = { |
153 | .i2c_addr = 0x64, | |
154 | .chip_mode = SI2165_MODE_PLL_XTAL, | |
155 | .ref_freq_Hz = 16000000, | |
156 | }; | |
157 | ||
9e49f7c3 MS |
158 | static const struct si2165_config pctv_quatro_stick_1114xx_si2165_config = { |
159 | .i2c_addr = 0x64, | |
160 | .chip_mode = SI2165_MODE_PLL_EXT, | |
161 | .ref_freq_Hz = 24000000, | |
162 | }; | |
163 | ||
809abdbf OS |
164 | static struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = { |
165 | .i2c_addr = 0x59, | |
166 | .qam_if_khz = 4000, | |
167 | .vsb_if_khz = 3250, | |
168 | .deny_i2c_rptr = 1, | |
169 | .spectral_inversion = 1, | |
170 | .mpeg_mode = LGDT3306A_MPEG_SERIAL, | |
171 | .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, | |
172 | .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH, | |
173 | .xtalMHz = 25, | |
174 | }; | |
175 | ||
84b5dbf3 | 176 | static inline void print_err_status(struct cx231xx *dev, int packet, int status) |
e0d3bafd SD |
177 | { |
178 | char *errmsg = "Unknown"; | |
179 | ||
180 | switch (status) { | |
181 | case -ENOENT: | |
182 | errmsg = "unlinked synchronuously"; | |
183 | break; | |
184 | case -ECONNRESET: | |
185 | errmsg = "unlinked asynchronuously"; | |
186 | break; | |
187 | case -ENOSR: | |
188 | errmsg = "Buffer error (overrun)"; | |
189 | break; | |
190 | case -EPIPE: | |
191 | errmsg = "Stalled (device not responding)"; | |
192 | break; | |
193 | case -EOVERFLOW: | |
194 | errmsg = "Babble (bad cable?)"; | |
195 | break; | |
196 | case -EPROTO: | |
197 | errmsg = "Bit-stuff error (bad cable?)"; | |
198 | break; | |
199 | case -EILSEQ: | |
200 | errmsg = "CRC/Timeout (could be anything)"; | |
201 | break; | |
202 | case -ETIME: | |
203 | errmsg = "Device does not respond"; | |
204 | break; | |
205 | } | |
206 | if (packet < 0) { | |
336fea92 | 207 | dev_dbg(dev->dev, |
3b795d01 | 208 | "URB status %d [%s].\n", status, errmsg); |
e0d3bafd | 209 | } else { |
336fea92 | 210 | dev_dbg(dev->dev, |
3b795d01 | 211 | "URB packet %d, status %d [%s].\n", |
e0d3bafd SD |
212 | packet, status, errmsg); |
213 | } | |
214 | } | |
215 | ||
216 | static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb) | |
217 | { | |
218 | int i; | |
219 | ||
220 | if (!dev) | |
221 | return 0; | |
222 | ||
990862a2 | 223 | if (dev->state & DEV_DISCONNECTED) |
e0d3bafd SD |
224 | return 0; |
225 | ||
226 | if (urb->status < 0) { | |
227 | print_err_status(dev, -1, urb->status); | |
228 | if (urb->status == -ENOENT) | |
229 | return 0; | |
230 | } | |
231 | ||
232 | for (i = 0; i < urb->number_of_packets; i++) { | |
233 | int status = urb->iso_frame_desc[i].status; | |
234 | ||
235 | if (status < 0) { | |
236 | print_err_status(dev, i, status); | |
237 | if (urb->iso_frame_desc[i].status != -EPROTO) | |
238 | continue; | |
239 | } | |
240 | ||
64fbf444 PB |
241 | dvb_dmx_swfilter(&dev->dvb->demux, |
242 | urb->transfer_buffer + | |
243 | urb->iso_frame_desc[i].offset, | |
244 | urb->iso_frame_desc[i].actual_length); | |
e0d3bafd SD |
245 | } |
246 | ||
247 | return 0; | |
248 | } | |
249 | ||
64fbf444 PB |
250 | static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb) |
251 | { | |
64fbf444 PB |
252 | if (!dev) |
253 | return 0; | |
254 | ||
990862a2 | 255 | if (dev->state & DEV_DISCONNECTED) |
64fbf444 PB |
256 | return 0; |
257 | ||
258 | if (urb->status < 0) { | |
259 | print_err_status(dev, -1, urb->status); | |
260 | if (urb->status == -ENOENT) | |
261 | return 0; | |
262 | } | |
263 | ||
264 | /* Feed the transport payload into the kernel demux */ | |
265 | dvb_dmx_swfilter(&dev->dvb->demux, | |
266 | urb->transfer_buffer, urb->actual_length); | |
267 | ||
268 | return 0; | |
269 | } | |
270 | ||
e0d3bafd SD |
271 | static int start_streaming(struct cx231xx_dvb *dvb) |
272 | { | |
273 | int rc; | |
274 | struct cx231xx *dev = dvb->adapter.priv; | |
275 | ||
64fbf444 | 276 | if (dev->USE_ISO) { |
336fea92 | 277 | dev_dbg(dev->dev, "DVB transfer mode is ISO.\n"); |
64fbf444 | 278 | cx231xx_set_alt_setting(dev, INDEX_TS1, 4); |
64fbf444 PB |
279 | rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); |
280 | if (rc < 0) | |
281 | return rc; | |
282 | dev->mode_tv = 1; | |
283 | return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS, | |
284 | CX231XX_DVB_NUM_BUFS, | |
285 | dev->ts1_mode.max_pkt_size, | |
286 | dvb_isoc_copy); | |
287 | } else { | |
336fea92 | 288 | dev_dbg(dev->dev, "DVB transfer mode is BULK.\n"); |
64fbf444 PB |
289 | cx231xx_set_alt_setting(dev, INDEX_TS1, 0); |
290 | rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); | |
291 | if (rc < 0) | |
292 | return rc; | |
293 | dev->mode_tv = 1; | |
294 | return cx231xx_init_bulk(dev, CX231XX_DVB_MAX_PACKETS, | |
295 | CX231XX_DVB_NUM_BUFS, | |
296 | dev->ts1_mode.max_pkt_size, | |
297 | dvb_bulk_copy); | |
298 | } | |
e0d3bafd | 299 | |
e0d3bafd SD |
300 | } |
301 | ||
302 | static int stop_streaming(struct cx231xx_dvb *dvb) | |
303 | { | |
304 | struct cx231xx *dev = dvb->adapter.priv; | |
305 | ||
64fbf444 PB |
306 | if (dev->USE_ISO) |
307 | cx231xx_uninit_isoc(dev); | |
308 | else | |
309 | cx231xx_uninit_bulk(dev); | |
e0d3bafd SD |
310 | |
311 | cx231xx_set_mode(dev, CX231XX_SUSPEND); | |
312 | ||
313 | return 0; | |
314 | } | |
315 | ||
316 | static int start_feed(struct dvb_demux_feed *feed) | |
317 | { | |
84b5dbf3 | 318 | struct dvb_demux *demux = feed->demux; |
e0d3bafd SD |
319 | struct cx231xx_dvb *dvb = demux->priv; |
320 | int rc, ret; | |
321 | ||
322 | if (!demux->dmx.frontend) | |
323 | return -EINVAL; | |
324 | ||
325 | mutex_lock(&dvb->lock); | |
326 | dvb->nfeeds++; | |
327 | rc = dvb->nfeeds; | |
328 | ||
329 | if (dvb->nfeeds == 1) { | |
330 | ret = start_streaming(dvb); | |
331 | if (ret < 0) | |
332 | rc = ret; | |
333 | } | |
334 | ||
335 | mutex_unlock(&dvb->lock); | |
336 | return rc; | |
337 | } | |
338 | ||
339 | static int stop_feed(struct dvb_demux_feed *feed) | |
340 | { | |
84b5dbf3 | 341 | struct dvb_demux *demux = feed->demux; |
e0d3bafd SD |
342 | struct cx231xx_dvb *dvb = demux->priv; |
343 | int err = 0; | |
344 | ||
345 | mutex_lock(&dvb->lock); | |
346 | dvb->nfeeds--; | |
347 | ||
348 | if (0 == dvb->nfeeds) | |
349 | err = stop_streaming(dvb); | |
350 | ||
351 | mutex_unlock(&dvb->lock); | |
352 | return err; | |
353 | } | |
354 | ||
e0d3bafd SD |
355 | /* ------------------------------------------------------------------ */ |
356 | static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) | |
357 | { | |
358 | struct cx231xx *dev = fe->dvb->priv; | |
359 | ||
360 | if (acquire) | |
361 | return cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); | |
362 | else | |
363 | return cx231xx_set_mode(dev, CX231XX_SUSPEND); | |
364 | } | |
365 | ||
366 | /* ------------------------------------------------------------------ */ | |
367 | ||
e0d3bafd | 368 | static struct xc5000_config cnxt_rde250_tunerconfig = { |
84b5dbf3 | 369 | .i2c_address = 0x61, |
64fbf444 PB |
370 | .if_khz = 4000, |
371 | }; | |
372 | static struct xc5000_config cnxt_rdu250_tunerconfig = { | |
373 | .i2c_address = 0x61, | |
374 | .if_khz = 3250, | |
e0d3bafd SD |
375 | }; |
376 | ||
e0d3bafd SD |
377 | /* ------------------------------------------------------------------ */ |
378 | #if 0 | |
379 | static int attach_xc5000(u8 addr, struct cx231xx *dev) | |
380 | { | |
381 | ||
382 | struct dvb_frontend *fe; | |
383 | struct xc5000_config cfg; | |
384 | ||
385 | memset(&cfg, 0, sizeof(cfg)); | |
c3c3f1ae | 386 | cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master); |
84b5dbf3 | 387 | cfg.i2c_addr = addr; |
e0d3bafd SD |
388 | |
389 | if (!dev->dvb->frontend) { | |
336fea92 | 390 | dev_err(dev->dev, "%s/2: dvb frontend not attached. " |
84b5dbf3 | 391 | "Can't attach xc5000\n", dev->name); |
e0d3bafd SD |
392 | return -EINVAL; |
393 | } | |
394 | ||
395 | fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg); | |
396 | if (!fe) { | |
336fea92 | 397 | dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name); |
e0d3bafd SD |
398 | dvb_frontend_detach(dev->dvb->frontend); |
399 | dev->dvb->frontend = NULL; | |
400 | return -EINVAL; | |
401 | } | |
402 | ||
336fea92 | 403 | dev_info(dev->dev, "%s/2: xc5000 attached\n", dev->name); |
e0d3bafd SD |
404 | |
405 | return 0; | |
406 | } | |
407 | #endif | |
408 | ||
84b5dbf3 | 409 | int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) |
e0d3bafd | 410 | { |
84b5dbf3 | 411 | if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { |
e0d3bafd | 412 | |
84b5dbf3 | 413 | struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; |
e0d3bafd | 414 | |
84b5dbf3 MCC |
415 | if (dops->set_analog_params != NULL) { |
416 | struct analog_parameters params; | |
e0d3bafd | 417 | |
84b5dbf3 MCC |
418 | params.frequency = freq; |
419 | params.std = dev->norm; | |
420 | params.mode = 0; /* 0- Air; 1 - cable */ | |
421 | /*params.audmode = ; */ | |
e0d3bafd | 422 | |
84b5dbf3 | 423 | /* Set the analog parameters to set the frequency */ |
84b5dbf3 | 424 | dops->set_analog_params(dev->dvb->frontend, ¶ms); |
e0d3bafd SD |
425 | } |
426 | ||
84b5dbf3 MCC |
427 | } |
428 | ||
ea21f702 | 429 | return 0; |
e0d3bafd SD |
430 | } |
431 | ||
432 | int cx231xx_reset_analog_tuner(struct cx231xx *dev) | |
433 | { | |
84b5dbf3 | 434 | int status = 0; |
e0d3bafd | 435 | |
84b5dbf3 | 436 | if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { |
e0d3bafd | 437 | |
84b5dbf3 | 438 | struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; |
e0d3bafd | 439 | |
84b5dbf3 | 440 | if (dops->init != NULL && !dev->xc_fw_load_done) { |
e0d3bafd | 441 | |
336fea92 | 442 | dev_dbg(dev->dev, |
b7085c08 | 443 | "Reloading firmware for XC5000\n"); |
84b5dbf3 MCC |
444 | status = dops->init(dev->dvb->frontend); |
445 | if (status == 0) { | |
446 | dev->xc_fw_load_done = 1; | |
336fea92 | 447 | dev_dbg(dev->dev, |
b7085c08 | 448 | "XC5000 firmware download completed\n"); |
84b5dbf3 MCC |
449 | } else { |
450 | dev->xc_fw_load_done = 0; | |
336fea92 | 451 | dev_dbg(dev->dev, |
b7085c08 | 452 | "XC5000 firmware download failed !!!\n"); |
e0d3bafd | 453 | } |
e0d3bafd SD |
454 | } |
455 | ||
84b5dbf3 MCC |
456 | } |
457 | ||
e0d3bafd SD |
458 | return status; |
459 | } | |
460 | ||
e0d3bafd SD |
461 | /* ------------------------------------------------------------------ */ |
462 | ||
463 | static int register_dvb(struct cx231xx_dvb *dvb, | |
84b5dbf3 MCC |
464 | struct module *module, |
465 | struct cx231xx *dev, struct device *device) | |
e0d3bafd SD |
466 | { |
467 | int result; | |
468 | ||
469 | mutex_init(&dvb->lock); | |
470 | ||
1d058bdc | 471 | |
e0d3bafd SD |
472 | /* register adapter */ |
473 | result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, | |
474 | adapter_nr); | |
475 | if (result < 0) { | |
336fea92 | 476 | dev_warn(dev->dev, |
84b5dbf3 | 477 | "%s: dvb_register_adapter failed (errno = %d)\n", |
e0d3bafd SD |
478 | dev->name, result); |
479 | goto fail_adapter; | |
480 | } | |
89a2c1d6 | 481 | dvb_register_media_controller(&dvb->adapter, dev->media_dev); |
e0d3bafd SD |
482 | |
483 | /* Ensure all frontends negotiate bus access */ | |
484 | dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; | |
485 | ||
486 | dvb->adapter.priv = dev; | |
487 | ||
488 | /* register frontend */ | |
489 | result = dvb_register_frontend(&dvb->adapter, dvb->frontend); | |
490 | if (result < 0) { | |
336fea92 | 491 | dev_warn(dev->dev, |
84b5dbf3 | 492 | "%s: dvb_register_frontend failed (errno = %d)\n", |
e0d3bafd SD |
493 | dev->name, result); |
494 | goto fail_frontend; | |
495 | } | |
496 | ||
497 | /* register demux stuff */ | |
498 | dvb->demux.dmx.capabilities = | |
84b5dbf3 MCC |
499 | DMX_TS_FILTERING | DMX_SECTION_FILTERING | |
500 | DMX_MEMORY_BASED_FILTERING; | |
501 | dvb->demux.priv = dvb; | |
502 | dvb->demux.filternum = 256; | |
503 | dvb->demux.feednum = 256; | |
e0d3bafd | 504 | dvb->demux.start_feed = start_feed; |
84b5dbf3 | 505 | dvb->demux.stop_feed = stop_feed; |
e0d3bafd SD |
506 | |
507 | result = dvb_dmx_init(&dvb->demux); | |
508 | if (result < 0) { | |
336fea92 | 509 | dev_warn(dev->dev, |
3b795d01 | 510 | "%s: dvb_dmx_init failed (errno = %d)\n", |
e0d3bafd SD |
511 | dev->name, result); |
512 | goto fail_dmx; | |
513 | } | |
514 | ||
84b5dbf3 MCC |
515 | dvb->dmxdev.filternum = 256; |
516 | dvb->dmxdev.demux = &dvb->demux.dmx; | |
e0d3bafd SD |
517 | dvb->dmxdev.capabilities = 0; |
518 | result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); | |
519 | if (result < 0) { | |
336fea92 | 520 | dev_warn(dev->dev, |
3b795d01 MCC |
521 | "%s: dvb_dmxdev_init failed (errno = %d)\n", |
522 | dev->name, result); | |
e0d3bafd SD |
523 | goto fail_dmxdev; |
524 | } | |
525 | ||
526 | dvb->fe_hw.source = DMX_FRONTEND_0; | |
527 | result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); | |
528 | if (result < 0) { | |
336fea92 | 529 | dev_warn(dev->dev, |
84b5dbf3 | 530 | "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", |
e0d3bafd SD |
531 | dev->name, result); |
532 | goto fail_fe_hw; | |
533 | } | |
534 | ||
535 | dvb->fe_mem.source = DMX_MEMORY_FE; | |
536 | result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); | |
537 | if (result < 0) { | |
336fea92 | 538 | dev_warn(dev->dev, |
3b795d01 MCC |
539 | "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", |
540 | dev->name, result); | |
e0d3bafd SD |
541 | goto fail_fe_mem; |
542 | } | |
543 | ||
544 | result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); | |
545 | if (result < 0) { | |
336fea92 | 546 | dev_warn(dev->dev, |
3b795d01 MCC |
547 | "%s: connect_frontend failed (errno = %d)\n", |
548 | dev->name, result); | |
e0d3bafd SD |
549 | goto fail_fe_conn; |
550 | } | |
551 | ||
552 | /* register network adapter */ | |
553 | dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); | |
0230d60e | 554 | result = dvb_create_media_graph(&dvb->adapter, false); |
0d3ab841 MCC |
555 | if (result < 0) |
556 | goto fail_create_graph; | |
480884b6 | 557 | |
e0d3bafd SD |
558 | return 0; |
559 | ||
0d3ab841 MCC |
560 | fail_create_graph: |
561 | dvb_net_release(&dvb->net); | |
b9255176 | 562 | fail_fe_conn: |
e0d3bafd | 563 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); |
b9255176 | 564 | fail_fe_mem: |
e0d3bafd | 565 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); |
b9255176 | 566 | fail_fe_hw: |
e0d3bafd | 567 | dvb_dmxdev_release(&dvb->dmxdev); |
b9255176 | 568 | fail_dmxdev: |
e0d3bafd | 569 | dvb_dmx_release(&dvb->demux); |
b9255176 | 570 | fail_dmx: |
e0d3bafd | 571 | dvb_unregister_frontend(dvb->frontend); |
b9255176 | 572 | fail_frontend: |
e0d3bafd SD |
573 | dvb_frontend_detach(dvb->frontend); |
574 | dvb_unregister_adapter(&dvb->adapter); | |
b9255176 | 575 | fail_adapter: |
e0d3bafd SD |
576 | return result; |
577 | } | |
578 | ||
579 | static void unregister_dvb(struct cx231xx_dvb *dvb) | |
580 | { | |
6d3debaf | 581 | struct i2c_client *client; |
e0d3bafd SD |
582 | dvb_net_release(&dvb->net); |
583 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); | |
584 | dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); | |
585 | dvb_dmxdev_release(&dvb->dmxdev); | |
586 | dvb_dmx_release(&dvb->demux); | |
6d3debaf MS |
587 | client = dvb->i2c_client_tuner; |
588 | /* remove I2C tuner */ | |
589 | if (client) { | |
590 | module_put(client->dev.driver->owner); | |
591 | i2c_unregister_device(client); | |
592 | } | |
e0d3bafd SD |
593 | dvb_unregister_frontend(dvb->frontend); |
594 | dvb_frontend_detach(dvb->frontend); | |
595 | dvb_unregister_adapter(&dvb->adapter); | |
596 | } | |
597 | ||
e0d3bafd SD |
598 | static int dvb_init(struct cx231xx *dev) |
599 | { | |
600 | int result = 0; | |
601 | struct cx231xx_dvb *dvb; | |
c3c3f1ae MS |
602 | struct i2c_adapter *tuner_i2c; |
603 | struct i2c_adapter *demod_i2c; | |
e0d3bafd SD |
604 | |
605 | if (!dev->board.has_dvb) { | |
606 | /* This device does not support the extension */ | |
607 | return 0; | |
608 | } | |
609 | ||
610 | dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL); | |
611 | ||
612 | if (dvb == NULL) { | |
336fea92 | 613 | dev_info(dev->dev, |
3b795d01 | 614 | "cx231xx_dvb: memory allocation failed\n"); |
e0d3bafd SD |
615 | return -ENOMEM; |
616 | } | |
617 | dev->dvb = dvb; | |
618 | dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq; | |
84b5dbf3 | 619 | dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner; |
e0d3bafd | 620 | |
c3c3f1ae MS |
621 | tuner_i2c = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master); |
622 | demod_i2c = cx231xx_get_i2c_adap(dev, dev->board.demod_i2c_master); | |
761f6cf6 | 623 | mutex_lock(&dev->lock); |
e0d3bafd | 624 | cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); |
64fbf444 | 625 | cx231xx_demod_reset(dev); |
e0d3bafd SD |
626 | /* init frontend */ |
627 | switch (dev->model) { | |
64fbf444 | 628 | case CX231XX_BOARD_CNXT_CARRAERA: |
84b5dbf3 MCC |
629 | case CX231XX_BOARD_CNXT_RDE_250: |
630 | ||
64fbf444 PB |
631 | dev->dvb->frontend = dvb_attach(s5h1432_attach, |
632 | &dvico_s5h1432_config, | |
c3c3f1ae | 633 | demod_i2c); |
84b5dbf3 MCC |
634 | |
635 | if (dev->dvb->frontend == NULL) { | |
336fea92 | 636 | dev_err(dev->dev, |
3b795d01 | 637 | "Failed to attach s5h1432 front end\n"); |
84b5dbf3 MCC |
638 | result = -EINVAL; |
639 | goto out_free; | |
640 | } | |
641 | ||
642 | /* define general-purpose callback pointer */ | |
643 | dvb->frontend->callback = cx231xx_tuner_callback; | |
644 | ||
d5abcc78 | 645 | if (!dvb_attach(xc5000_attach, dev->dvb->frontend, |
c3c3f1ae | 646 | tuner_i2c, |
d5abcc78 | 647 | &cnxt_rde250_tunerconfig)) { |
84b5dbf3 MCC |
648 | result = -EINVAL; |
649 | goto out_free; | |
650 | } | |
651 | ||
652 | break; | |
64fbf444 | 653 | case CX231XX_BOARD_CNXT_SHELBY: |
84b5dbf3 MCC |
654 | case CX231XX_BOARD_CNXT_RDU_250: |
655 | ||
64fbf444 PB |
656 | dev->dvb->frontend = dvb_attach(s5h1411_attach, |
657 | &xc5000_s5h1411_config, | |
c3c3f1ae | 658 | demod_i2c); |
84b5dbf3 MCC |
659 | |
660 | if (dev->dvb->frontend == NULL) { | |
336fea92 | 661 | dev_err(dev->dev, |
3b795d01 | 662 | "Failed to attach s5h1411 front end\n"); |
84b5dbf3 MCC |
663 | result = -EINVAL; |
664 | goto out_free; | |
665 | } | |
666 | ||
667 | /* define general-purpose callback pointer */ | |
668 | dvb->frontend->callback = cx231xx_tuner_callback; | |
669 | ||
d5abcc78 | 670 | if (!dvb_attach(xc5000_attach, dev->dvb->frontend, |
c3c3f1ae | 671 | tuner_i2c, |
64fbf444 PB |
672 | &cnxt_rdu250_tunerconfig)) { |
673 | result = -EINVAL; | |
674 | goto out_free; | |
675 | } | |
676 | break; | |
677 | case CX231XX_BOARD_CNXT_RDE_253S: | |
678 | ||
679 | dev->dvb->frontend = dvb_attach(s5h1432_attach, | |
680 | &dvico_s5h1432_config, | |
c3c3f1ae | 681 | demod_i2c); |
64fbf444 PB |
682 | |
683 | if (dev->dvb->frontend == NULL) { | |
336fea92 | 684 | dev_err(dev->dev, |
3b795d01 | 685 | "Failed to attach s5h1432 front end\n"); |
64fbf444 PB |
686 | result = -EINVAL; |
687 | goto out_free; | |
688 | } | |
689 | ||
690 | /* define general-purpose callback pointer */ | |
691 | dvb->frontend->callback = cx231xx_tuner_callback; | |
692 | ||
693 | if (!dvb_attach(tda18271_attach, dev->dvb->frontend, | |
c3c3f1ae | 694 | 0x60, tuner_i2c, |
64fbf444 PB |
695 | &cnxt_rde253s_tunerconfig)) { |
696 | result = -EINVAL; | |
697 | goto out_free; | |
698 | } | |
699 | break; | |
700 | case CX231XX_BOARD_CNXT_RDU_253S: | |
8b1255a2 | 701 | case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID: |
64fbf444 PB |
702 | |
703 | dev->dvb->frontend = dvb_attach(s5h1411_attach, | |
704 | &tda18271_s5h1411_config, | |
c3c3f1ae | 705 | demod_i2c); |
64fbf444 PB |
706 | |
707 | if (dev->dvb->frontend == NULL) { | |
336fea92 | 708 | dev_err(dev->dev, |
3b795d01 | 709 | "Failed to attach s5h1411 front end\n"); |
64fbf444 PB |
710 | result = -EINVAL; |
711 | goto out_free; | |
712 | } | |
713 | ||
714 | /* define general-purpose callback pointer */ | |
715 | dvb->frontend->callback = cx231xx_tuner_callback; | |
716 | ||
717 | if (!dvb_attach(tda18271_attach, dev->dvb->frontend, | |
c3c3f1ae | 718 | 0x60, tuner_i2c, |
64fbf444 | 719 | &cnxt_rde253s_tunerconfig)) { |
84b5dbf3 MCC |
720 | result = -EINVAL; |
721 | goto out_free; | |
722 | } | |
723 | break; | |
1a50fdde MK |
724 | case CX231XX_BOARD_HAUPPAUGE_EXETER: |
725 | ||
336fea92 | 726 | dev_info(dev->dev, |
3b795d01 | 727 | "%s: looking for tuner / demod on i2c bus: %d\n", |
c3c3f1ae | 728 | __func__, i2c_adapter_id(tuner_i2c)); |
1a50fdde MK |
729 | |
730 | dev->dvb->frontend = dvb_attach(lgdt3305_attach, | |
731 | &hcw_lgdt3305_config, | |
599bedb7 | 732 | demod_i2c); |
1a50fdde MK |
733 | |
734 | if (dev->dvb->frontend == NULL) { | |
336fea92 | 735 | dev_err(dev->dev, |
3b795d01 | 736 | "Failed to attach LG3305 front end\n"); |
1a50fdde MK |
737 | result = -EINVAL; |
738 | goto out_free; | |
739 | } | |
740 | ||
741 | /* define general-purpose callback pointer */ | |
742 | dvb->frontend->callback = cx231xx_tuner_callback; | |
743 | ||
744 | dvb_attach(tda18271_attach, dev->dvb->frontend, | |
c3c3f1ae | 745 | 0x60, tuner_i2c, |
1a50fdde MK |
746 | &hcw_tda18271_config); |
747 | break; | |
748 | ||
dd2e7dd2 MS |
749 | case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx: |
750 | ||
751 | dev->dvb->frontend = dvb_attach(si2165_attach, | |
752 | &hauppauge_930C_HD_1113xx_si2165_config, | |
599bedb7 | 753 | demod_i2c |
dd2e7dd2 MS |
754 | ); |
755 | ||
756 | if (dev->dvb->frontend == NULL) { | |
336fea92 | 757 | dev_err(dev->dev, |
3b795d01 | 758 | "Failed to attach SI2165 front end\n"); |
dd2e7dd2 MS |
759 | result = -EINVAL; |
760 | goto out_free; | |
761 | } | |
762 | ||
3f9280a8 | 763 | dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; |
dd2e7dd2 MS |
764 | |
765 | /* define general-purpose callback pointer */ | |
766 | dvb->frontend->callback = cx231xx_tuner_callback; | |
767 | ||
768 | dvb_attach(tda18271_attach, dev->dvb->frontend, | |
769 | 0x60, | |
c3c3f1ae | 770 | tuner_i2c, |
dd2e7dd2 MS |
771 | &hcw_tda18271_config); |
772 | ||
773 | dev->cx231xx_reset_analog_tuner = NULL; | |
774 | break; | |
775 | ||
9e49f7c3 MS |
776 | case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: |
777 | { | |
778 | struct i2c_client *client; | |
779 | struct i2c_board_info info; | |
780 | struct si2157_config si2157_config; | |
781 | ||
782 | memset(&info, 0, sizeof(struct i2c_board_info)); | |
783 | ||
784 | dev->dvb->frontend = dvb_attach(si2165_attach, | |
785 | &pctv_quatro_stick_1114xx_si2165_config, | |
599bedb7 | 786 | demod_i2c |
9e49f7c3 MS |
787 | ); |
788 | ||
789 | if (dev->dvb->frontend == NULL) { | |
336fea92 | 790 | dev_err(dev->dev, |
3b795d01 | 791 | "Failed to attach SI2165 front end\n"); |
9e49f7c3 MS |
792 | result = -EINVAL; |
793 | goto out_free; | |
794 | } | |
795 | ||
3f9280a8 | 796 | dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; |
9e49f7c3 MS |
797 | |
798 | /* define general-purpose callback pointer */ | |
799 | dvb->frontend->callback = cx231xx_tuner_callback; | |
800 | ||
801 | /* attach tuner */ | |
802 | memset(&si2157_config, 0, sizeof(si2157_config)); | |
803 | si2157_config.fe = dev->dvb->frontend; | |
ee3c3e46 | 804 | si2157_config.if_port = 1; |
9e49f7c3 MS |
805 | si2157_config.inversion = true; |
806 | strlcpy(info.type, "si2157", I2C_NAME_SIZE); | |
807 | info.addr = 0x60; | |
808 | info.platform_data = &si2157_config; | |
809 | request_module("si2157"); | |
810 | ||
811 | client = i2c_new_device( | |
c3c3f1ae | 812 | tuner_i2c, |
9e49f7c3 MS |
813 | &info); |
814 | if (client == NULL || client->dev.driver == NULL) { | |
815 | dvb_frontend_detach(dev->dvb->frontend); | |
816 | result = -ENODEV; | |
817 | goto out_free; | |
818 | } | |
819 | ||
820 | if (!try_module_get(client->dev.driver->owner)) { | |
821 | i2c_unregister_device(client); | |
822 | dvb_frontend_detach(dev->dvb->frontend); | |
823 | result = -ENODEV; | |
824 | goto out_free; | |
825 | } | |
826 | ||
827 | dev->cx231xx_reset_analog_tuner = NULL; | |
828 | ||
829 | dev->dvb->i2c_client_tuner = client; | |
830 | break; | |
831 | } | |
809abdbf OS |
832 | case CX231XX_BOARD_HAUPPAUGE_955Q: |
833 | { | |
834 | struct i2c_client *client; | |
835 | struct i2c_board_info info; | |
836 | struct si2157_config si2157_config; | |
837 | ||
838 | memset(&info, 0, sizeof(struct i2c_board_info)); | |
839 | ||
840 | dev->dvb->frontend = dvb_attach(lgdt3306a_attach, | |
841 | &hauppauge_955q_lgdt3306a_config, | |
599bedb7 | 842 | demod_i2c |
809abdbf OS |
843 | ); |
844 | ||
845 | if (dev->dvb->frontend == NULL) { | |
846 | dev_err(dev->dev, | |
847 | "Failed to attach LGDT3306A frontend.\n"); | |
848 | result = -EINVAL; | |
849 | goto out_free; | |
850 | } | |
851 | ||
852 | dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; | |
853 | ||
854 | /* define general-purpose callback pointer */ | |
855 | dvb->frontend->callback = cx231xx_tuner_callback; | |
856 | ||
857 | /* attach tuner */ | |
858 | memset(&si2157_config, 0, sizeof(si2157_config)); | |
859 | si2157_config.fe = dev->dvb->frontend; | |
ee3c3e46 | 860 | si2157_config.if_port = 1; |
809abdbf OS |
861 | si2157_config.inversion = true; |
862 | strlcpy(info.type, "si2157", I2C_NAME_SIZE); | |
863 | info.addr = 0x60; | |
864 | info.platform_data = &si2157_config; | |
865 | request_module("si2157"); | |
866 | ||
867 | client = i2c_new_device( | |
868 | tuner_i2c, | |
869 | &info); | |
870 | if (client == NULL || client->dev.driver == NULL) { | |
871 | dvb_frontend_detach(dev->dvb->frontend); | |
872 | result = -ENODEV; | |
873 | goto out_free; | |
874 | } | |
875 | ||
876 | if (!try_module_get(client->dev.driver->owner)) { | |
877 | i2c_unregister_device(client); | |
878 | dvb_frontend_detach(dev->dvb->frontend); | |
879 | result = -ENODEV; | |
880 | goto out_free; | |
881 | } | |
882 | ||
883 | dev->cx231xx_reset_analog_tuner = NULL; | |
9e49f7c3 | 884 | |
809abdbf OS |
885 | dev->dvb->i2c_client_tuner = client; |
886 | break; | |
887 | } | |
ede676c7 | 888 | case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID: |
eeaaf817 | 889 | case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID: |
ede676c7 | 890 | |
336fea92 | 891 | dev_info(dev->dev, |
3b795d01 MCC |
892 | "%s: looking for demod on i2c bus: %d\n", |
893 | __func__, i2c_adapter_id(tuner_i2c)); | |
ede676c7 MCC |
894 | |
895 | dev->dvb->frontend = dvb_attach(mb86a20s_attach, | |
896 | &pv_mb86a20s_config, | |
c3c3f1ae | 897 | demod_i2c); |
ede676c7 MCC |
898 | |
899 | if (dev->dvb->frontend == NULL) { | |
336fea92 | 900 | dev_err(dev->dev, |
3b795d01 | 901 | "Failed to attach mb86a20s demod\n"); |
ede676c7 MCC |
902 | result = -EINVAL; |
903 | goto out_free; | |
904 | } | |
905 | ||
906 | /* define general-purpose callback pointer */ | |
907 | dvb->frontend->callback = cx231xx_tuner_callback; | |
908 | ||
909 | dvb_attach(tda18271_attach, dev->dvb->frontend, | |
c3c3f1ae | 910 | 0x60, tuner_i2c, |
ede676c7 MCC |
911 | &pv_tda18271_config); |
912 | break; | |
e0d3bafd SD |
913 | |
914 | default: | |
336fea92 | 915 | dev_err(dev->dev, |
3b795d01 MCC |
916 | "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", |
917 | dev->name); | |
e0d3bafd SD |
918 | break; |
919 | } | |
920 | if (NULL == dvb->frontend) { | |
336fea92 | 921 | dev_err(dev->dev, |
84b5dbf3 | 922 | "%s/2: frontend initialization failed\n", dev->name); |
e0d3bafd SD |
923 | result = -EINVAL; |
924 | goto out_free; | |
925 | } | |
926 | ||
e0d3bafd | 927 | /* register everything */ |
336fea92 | 928 | result = register_dvb(dvb, THIS_MODULE, dev, dev->dev); |
e0d3bafd SD |
929 | |
930 | if (result < 0) | |
931 | goto out_free; | |
932 | ||
761f6cf6 | 933 | |
336fea92 | 934 | dev_info(dev->dev, "Successfully loaded cx231xx-dvb\n"); |
e0d3bafd | 935 | |
761f6cf6 | 936 | ret: |
e0d3bafd | 937 | cx231xx_set_mode(dev, CX231XX_SUSPEND); |
761f6cf6 DH |
938 | mutex_unlock(&dev->lock); |
939 | return result; | |
940 | ||
941 | out_free: | |
e0d3bafd SD |
942 | kfree(dvb); |
943 | dev->dvb = NULL; | |
761f6cf6 | 944 | goto ret; |
e0d3bafd SD |
945 | } |
946 | ||
947 | static int dvb_fini(struct cx231xx *dev) | |
948 | { | |
949 | if (!dev->board.has_dvb) { | |
950 | /* This device does not support the extension */ | |
951 | return 0; | |
952 | } | |
953 | ||
954 | if (dev->dvb) { | |
955 | unregister_dvb(dev->dvb); | |
956 | dev->dvb = NULL; | |
957 | } | |
958 | ||
959 | return 0; | |
960 | } | |
961 | ||
962 | static struct cx231xx_ops dvb_ops = { | |
84b5dbf3 | 963 | .id = CX231XX_DVB, |
e0d3bafd SD |
964 | .name = "Cx231xx dvb Extension", |
965 | .init = dvb_init, | |
966 | .fini = dvb_fini, | |
967 | }; | |
968 | ||
969 | static int __init cx231xx_dvb_register(void) | |
970 | { | |
971 | return cx231xx_register_extension(&dvb_ops); | |
972 | } | |
973 | ||
974 | static void __exit cx231xx_dvb_unregister(void) | |
975 | { | |
976 | cx231xx_unregister_extension(&dvb_ops); | |
977 | } | |
978 | ||
979 | module_init(cx231xx_dvb_register); | |
980 | module_exit(cx231xx_dvb_unregister); |