aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/saa7164/saa7164-dvb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/saa7164/saa7164-dvb.c')
-rw-r--r--drivers/media/video/saa7164/saa7164-dvb.c578
1 files changed, 578 insertions, 0 deletions
diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c
new file mode 100644
index 000000000000..f21520f5979e
--- /dev/null
+++ b/drivers/media/video/saa7164/saa7164-dvb.c
@@ -0,0 +1,578 @@
1/*
2 * Driver for the NXP SAA7164 PCIe bridge
3 *
4 * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
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 *
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 "saa7164.h"
23
24#include "tda10048.h"
25#include "tda18271.h"
26#include "s5h1411.h"
27
28#define DRIVER_NAME "saa7164"
29
30DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
31
32/* addr is in the card struct, get it from there */
33static struct tda10048_config hauppauge_hvr2200_1_config = {
34 .demod_address = 0x10 >> 1,
35 .output_mode = TDA10048_SERIAL_OUTPUT,
36 .fwbulkwritelen = TDA10048_BULKWRITE_200,
37 .inversion = TDA10048_INVERSION_ON
38};
39static struct tda10048_config hauppauge_hvr2200_2_config = {
40 .demod_address = 0x12 >> 1,
41 .output_mode = TDA10048_SERIAL_OUTPUT,
42 .fwbulkwritelen = TDA10048_BULKWRITE_200,
43 .inversion = TDA10048_INVERSION_ON
44};
45
46static struct tda18271_std_map hauppauge_tda18271_std_map = {
47 .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 3,
48 .if_lvl = 6, .rfagc_top = 0x37 },
49 .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0,
50 .if_lvl = 6, .rfagc_top = 0x37 },
51};
52
53static struct tda18271_config hauppauge_hvr22x0_tuner_config = {
54 .std_map = &hauppauge_tda18271_std_map,
55 .gate = TDA18271_GATE_ANALOG,
56};
57
58static struct s5h1411_config hauppauge_s5h1411_config = {
59 .output_mode = S5H1411_SERIAL_OUTPUT,
60 .gpio = S5H1411_GPIO_ON,
61 .qam_if = S5H1411_IF_4000,
62 .vsb_if = S5H1411_IF_3250,
63 .inversion = S5H1411_INVERSION_ON,
64 .status_mode = S5H1411_DEMODLOCKING,
65 .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
66};
67
68static int saa7164_dvb_stop_tsport(struct saa7164_tsport *port)
69{
70 struct saa7164_dev *dev = port->dev;
71 int ret;
72
73 ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
74 if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
75 printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
76 __func__, ret);
77 ret = -EIO;
78 } else {
79 dprintk(DBGLVL_DVB, "%s() Stopped\n", __func__);
80 ret = 0;
81 }
82
83 return ret;
84}
85
86static int saa7164_dvb_acquire_tsport(struct saa7164_tsport *port)
87{
88 struct saa7164_dev *dev = port->dev;
89 int ret;
90
91 ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
92 if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
93 printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
94 __func__, ret);
95 ret = -EIO;
96 } else {
97 dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__);
98 ret = 0;
99 }
100
101 return ret;
102}
103
104static int saa7164_dvb_pause_tsport(struct saa7164_tsport *port)
105{
106 struct saa7164_dev *dev = port->dev;
107 int ret;
108
109 ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
110 if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
111 printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
112 __func__, ret);
113 ret = -EIO;
114 } else {
115 dprintk(DBGLVL_DVB, "%s() Paused\n", __func__);
116 ret = 0;
117 }
118
119 return ret;
120}
121
122/* Firmware is very windows centric, meaning you have to transition
123 * the part through AVStream / KS Windows stages, forwards or backwards.
124 * States are: stopped, acquired (h/w), paused, started.
125 */
126static int saa7164_dvb_stop_streaming(struct saa7164_tsport *port)
127{
128 struct saa7164_dev *dev = port->dev;
129 int ret;
130
131 dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
132
133 ret = saa7164_dvb_pause_tsport(port);
134 ret = saa7164_dvb_acquire_tsport(port);
135 ret = saa7164_dvb_stop_tsport(port);
136
137 return ret;
138}
139
140static int saa7164_dvb_cfg_tsport(struct saa7164_tsport *port)
141{
142 tmHWStreamParameters_t *params = &port->hw_streamingparams;
143 struct saa7164_dev *dev = port->dev;
144 struct saa7164_buffer *buf;
145 struct list_head *c, *n;
146 int i = 0;
147
148 dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
149
150 saa7164_writel(port->pitch, params->pitch);
151 saa7164_writel(port->bufsize, params->pitch * params->numberoflines);
152
153 dprintk(DBGLVL_DVB, " configured:\n");
154 dprintk(DBGLVL_DVB, " lmmio 0x%llx\n", (u64)dev->lmmio);
155 dprintk(DBGLVL_DVB, " bufcounter 0x%x = 0x%x\n", port->bufcounter,
156 saa7164_readl(port->bufcounter));
157
158 dprintk(DBGLVL_DVB, " pitch 0x%x = %d\n", port->pitch,
159 saa7164_readl(port->pitch));
160
161 dprintk(DBGLVL_DVB, " bufsize 0x%x = %d\n", port->bufsize,
162 saa7164_readl(port->bufsize));
163
164 dprintk(DBGLVL_DVB, " buffercount = %d\n", port->hwcfg.buffercount);
165 dprintk(DBGLVL_DVB, " bufoffset = 0x%x\n", port->bufoffset);
166 dprintk(DBGLVL_DVB, " bufptr32h = 0x%x\n", port->bufptr32h);
167 dprintk(DBGLVL_DVB, " bufptr32l = 0x%x\n", port->bufptr32l);
168
169 /* Poke the buffers and offsets into PCI space */
170 mutex_lock(&port->dmaqueue_lock);
171 list_for_each_safe(c, n, &port->dmaqueue.list) {
172 buf = list_entry(c, struct saa7164_buffer, list);
173
174 /* TODO: Review this in light of 32v64 assignments */
175 saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
176 saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i),
177 buf->pt_dma);
178 saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0);
179
180 dprintk(DBGLVL_DVB,
181 " buf[%d] offset 0x%lx (0x%x) "
182 "buf 0x%lx/%lx (0x%x/%x)\n",
183 i,
184 port->bufoffset + (i * sizeof(u32)),
185 saa7164_readl(port->bufoffset + (sizeof(u32) * i)),
186 port->bufptr32h + ((sizeof(u32) * 2) * i),
187 port->bufptr32l + ((sizeof(u32) * 2) * i),
188 saa7164_readl(port->bufptr32h + ((sizeof(u32) * i)
189 * 2)),
190 saa7164_readl(port->bufptr32l + ((sizeof(u32) * i)
191 * 2)));
192
193 if (i++ > port->hwcfg.buffercount)
194 BUG();
195
196 }
197 mutex_unlock(&port->dmaqueue_lock);
198
199 return 0;
200}
201
202static int saa7164_dvb_start_tsport(struct saa7164_tsport *port)
203{
204 struct saa7164_dev *dev = port->dev;
205 int ret = 0, result;
206
207 dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
208
209 saa7164_dvb_cfg_tsport(port);
210
211 /* Acquire the hardware */
212 result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
213 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
214 printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
215 __func__, result);
216
217 /* Stop the hardware, regardless */
218 result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
219 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
220 printk(KERN_ERR "%s() acquire/forced stop transition "
221 "failed, res = 0x%x\n", __func__, result);
222 }
223 ret = -EIO;
224 goto out;
225 } else
226 dprintk(DBGLVL_DVB, "%s() Acquired\n", __func__);
227
228 /* Pause the hardware */
229 result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
230 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
231 printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
232 __func__, result);
233
234 /* Stop the hardware, regardless */
235 result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
236 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
237 printk(KERN_ERR "%s() pause/forced stop transition "
238 "failed, res = 0x%x\n", __func__, result);
239 }
240
241 ret = -EIO;
242 goto out;
243 } else
244 dprintk(DBGLVL_DVB, "%s() Paused\n", __func__);
245
246 /* Start the hardware */
247 result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
248 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
249 printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
250 __func__, result);
251
252 /* Stop the hardware, regardless */
253 result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
254 if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
255 printk(KERN_ERR "%s() run/forced stop transition "
256 "failed, res = 0x%x\n", __func__, result);
257 }
258
259 ret = -EIO;
260 } else
261 dprintk(DBGLVL_DVB, "%s() Running\n", __func__);
262
263out:
264 return ret;
265}
266
267static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed)
268{
269 struct dvb_demux *demux = feed->demux;
270 struct saa7164_tsport *port = (struct saa7164_tsport *) demux->priv;
271 struct saa7164_dvb *dvb = &port->dvb;
272 struct saa7164_dev *dev = port->dev;
273 int ret = 0;
274
275 dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
276
277 if (!demux->dmx.frontend)
278 return -EINVAL;
279
280 if (dvb) {
281 mutex_lock(&dvb->lock);
282 if (dvb->feeding++ == 0) {
283 /* Start transport */
284 ret = saa7164_dvb_start_tsport(port);
285 }
286 mutex_unlock(&dvb->lock);
287 dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n",
288 __func__, port->nr, dvb->feeding);
289 }
290
291 return ret;
292}
293
294static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed)
295{
296 struct dvb_demux *demux = feed->demux;
297 struct saa7164_tsport *port = (struct saa7164_tsport *) demux->priv;
298 struct saa7164_dvb *dvb = &port->dvb;
299 struct saa7164_dev *dev = port->dev;
300 int ret = 0;
301
302 dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
303
304 if (dvb) {
305 mutex_lock(&dvb->lock);
306 if (--dvb->feeding == 0) {
307 /* Stop transport */
308 ret = saa7164_dvb_stop_streaming(port);
309 }
310 mutex_unlock(&dvb->lock);
311 dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n",
312 __func__, port->nr, dvb->feeding);
313 }
314
315 return ret;
316}
317
318static int dvb_register(struct saa7164_tsport *port)
319{
320 struct saa7164_dvb *dvb = &port->dvb;
321 struct saa7164_dev *dev = port->dev;
322 struct saa7164_buffer *buf;
323 int result, i;
324
325 dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
326
327 /* Sanity check that the PCI configuration space is active */
328 if (port->hwcfg.BARLocation == 0) {
329 result = -ENOMEM;
330 printk(KERN_ERR "%s: dvb_register_adapter failed "
331 "(errno = %d), NO PCI configuration\n",
332 DRIVER_NAME, result);
333 goto fail_adapter;
334 }
335
336 /* Init and establish defaults */
337 port->hw_streamingparams.bitspersample = 8;
338 port->hw_streamingparams.samplesperline = 188;
339 port->hw_streamingparams.numberoflines =
340 (SAA7164_TS_NUMBER_OF_LINES * 188) / 188;
341
342 port->hw_streamingparams.pitch = 188;
343 port->hw_streamingparams.linethreshold = 0;
344 port->hw_streamingparams.pagetablelistvirt = 0;
345 port->hw_streamingparams.pagetablelistphys = 0;
346 port->hw_streamingparams.numpagetables = 2 +
347 ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE);
348
349 port->hw_streamingparams.numpagetableentries = port->hwcfg.buffercount;
350
351 /* Allocate the PCI resources */
352 for (i = 0; i < port->hwcfg.buffercount; i++) {
353 buf = saa7164_buffer_alloc(port,
354 port->hw_streamingparams.numberoflines *
355 port->hw_streamingparams.pitch);
356
357 if (!buf) {
358 result = -ENOMEM;
359 printk(KERN_ERR "%s: dvb_register_adapter failed "
360 "(errno = %d), unable to allocate buffers\n",
361 DRIVER_NAME, result);
362 goto fail_adapter;
363 }
364 buf->nr = i;
365
366 mutex_lock(&port->dmaqueue_lock);
367 list_add_tail(&buf->list, &port->dmaqueue.list);
368 mutex_unlock(&port->dmaqueue_lock);
369 }
370
371 /* register adapter */
372 result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
373 &dev->pci->dev, adapter_nr);
374 if (result < 0) {
375 printk(KERN_ERR "%s: dvb_register_adapter failed "
376 "(errno = %d)\n", DRIVER_NAME, result);
377 goto fail_adapter;
378 }
379 dvb->adapter.priv = port;
380
381 /* register frontend */
382 result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
383 if (result < 0) {
384 printk(KERN_ERR "%s: dvb_register_frontend failed "
385 "(errno = %d)\n", DRIVER_NAME, result);
386 goto fail_frontend;
387 }
388
389 /* register demux stuff */
390 dvb->demux.dmx.capabilities =
391 DMX_TS_FILTERING | DMX_SECTION_FILTERING |
392 DMX_MEMORY_BASED_FILTERING;
393 dvb->demux.priv = port;
394 dvb->demux.filternum = 256;
395 dvb->demux.feednum = 256;
396 dvb->demux.start_feed = saa7164_dvb_start_feed;
397 dvb->demux.stop_feed = saa7164_dvb_stop_feed;
398 result = dvb_dmx_init(&dvb->demux);
399 if (result < 0) {
400 printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
401 DRIVER_NAME, result);
402 goto fail_dmx;
403 }
404
405 dvb->dmxdev.filternum = 256;
406 dvb->dmxdev.demux = &dvb->demux.dmx;
407 dvb->dmxdev.capabilities = 0;
408 result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
409 if (result < 0) {
410 printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
411 DRIVER_NAME, result);
412 goto fail_dmxdev;
413 }
414
415 dvb->fe_hw.source = DMX_FRONTEND_0;
416 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
417 if (result < 0) {
418 printk(KERN_ERR "%s: add_frontend failed "
419 "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
420 goto fail_fe_hw;
421 }
422
423 dvb->fe_mem.source = DMX_MEMORY_FE;
424 result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
425 if (result < 0) {
426 printk(KERN_ERR "%s: add_frontend failed "
427 "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
428 goto fail_fe_mem;
429 }
430
431 result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
432 if (result < 0) {
433 printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
434 DRIVER_NAME, result);
435 goto fail_fe_conn;
436 }
437
438 /* register network adapter */
439 dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
440 return 0;
441
442fail_fe_conn:
443 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
444fail_fe_mem:
445 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
446fail_fe_hw:
447 dvb_dmxdev_release(&dvb->dmxdev);
448fail_dmxdev:
449 dvb_dmx_release(&dvb->demux);
450fail_dmx:
451 dvb_unregister_frontend(dvb->frontend);
452fail_frontend:
453 dvb_frontend_detach(dvb->frontend);
454 dvb_unregister_adapter(&dvb->adapter);
455fail_adapter:
456 return result;
457}
458
459int saa7164_dvb_unregister(struct saa7164_tsport *port)
460{
461 struct saa7164_dvb *dvb = &port->dvb;
462 struct saa7164_dev *dev = port->dev;
463 struct saa7164_buffer *b;
464 struct list_head *c, *n;
465
466 dprintk(DBGLVL_DVB, "%s()\n", __func__);
467
468 /* Remove any allocated buffers */
469 mutex_lock(&port->dmaqueue_lock);
470 list_for_each_safe(c, n, &port->dmaqueue.list) {
471 b = list_entry(c, struct saa7164_buffer, list);
472 list_del(c);
473 saa7164_buffer_dealloc(port, b);
474 }
475 mutex_unlock(&port->dmaqueue_lock);
476
477 if (dvb->frontend == NULL)
478 return 0;
479
480 dvb_net_release(&dvb->net);
481 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
482 dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
483 dvb_dmxdev_release(&dvb->dmxdev);
484 dvb_dmx_release(&dvb->demux);
485 dvb_unregister_frontend(dvb->frontend);
486 dvb_frontend_detach(dvb->frontend);
487 dvb_unregister_adapter(&dvb->adapter);
488 return 0;
489}
490
491/* All the DVB attach calls go here, this function get's modified
492 * for each new card.
493 */
494int saa7164_dvb_register(struct saa7164_tsport *port)
495{
496 struct saa7164_dev *dev = port->dev;
497 struct saa7164_dvb *dvb = &port->dvb;
498 struct saa7164_i2c *i2c_bus = NULL;
499 int ret;
500
501 dprintk(DBGLVL_DVB, "%s()\n", __func__);
502
503 /* init frontend */
504 switch (dev->board) {
505 case SAA7164_BOARD_HAUPPAUGE_HVR2200:
506 case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
507 case SAA7164_BOARD_HAUPPAUGE_HVR2200_3:
508 switch (port->nr) {
509 case 0:
510 i2c_bus = &dev->i2c_bus[1];
511
512 port->dvb.frontend = dvb_attach(tda10048_attach,
513 &hauppauge_hvr2200_1_config,
514 &i2c_bus->i2c_adap);
515
516 if (port->dvb.frontend != NULL) {
517 dvb_attach(tda18271_attach, port->dvb.frontend,
518 0xc0 >> 1, &i2c_bus->i2c_adap,
519 &hauppauge_hvr22x0_tuner_config);
520 }
521
522 break;
523 case 1:
524 i2c_bus = &dev->i2c_bus[2];
525
526 port->dvb.frontend = dvb_attach(tda10048_attach,
527 &hauppauge_hvr2200_2_config,
528 &i2c_bus->i2c_adap);
529
530 if (port->dvb.frontend != NULL) {
531 dvb_attach(tda18271_attach, port->dvb.frontend,
532 0xc0 >> 1, &i2c_bus->i2c_adap,
533 &hauppauge_hvr22x0_tuner_config);
534 }
535
536 break;
537 }
538 break;
539 case SAA7164_BOARD_HAUPPAUGE_HVR2250:
540 case SAA7164_BOARD_HAUPPAUGE_HVR2250_2:
541 i2c_bus = &dev->i2c_bus[port->nr + 1];
542
543 port->dvb.frontend = dvb_attach(s5h1411_attach,
544 &hauppauge_s5h1411_config,
545 &i2c_bus->i2c_adap);
546
547 if (port->dvb.frontend != NULL) {
548 /* TODO: addr is in the card struct */
549 dvb_attach(tda18271_attach, port->dvb.frontend,
550 0xc0 >> 1, &i2c_bus->i2c_adap,
551 &hauppauge_hvr22x0_tuner_config);
552 }
553
554 break;
555 default:
556 printk(KERN_ERR "%s: The frontend isn't supported\n",
557 dev->name);
558 break;
559 }
560 if (NULL == dvb->frontend) {
561 printk(KERN_ERR "%s() Frontend initialization failed\n",
562 __func__);
563 return -1;
564 }
565
566 /* Put the analog decoder in standby to keep it quiet */
567
568 /* register everything */
569 ret = dvb_register(port);
570 if (ret < 0) {
571 if (dvb->frontend->ops.release)
572 dvb->frontend->ops.release(dvb->frontend);
573 return ret;
574 }
575
576 return 0;
577}
578