Browse Source

V4L/DVB (8889): dvb-ttpci: Support full-ts hardware modification

Add support for the 'full-ts' hardware modification.

On full-featured cards the data throughput is limited by the hardware
design. The full-ts mod removes this bottleneck, i.e. the card is able
to deliver the complete transport stream of a transponder.

For details see http://www.escape-edv.de/endriss/dvb-full-ts-mod

Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Oliver Endriss 16 năm trước cách đây
mục cha
commit
9e615eac82

+ 88 - 25
drivers/media/dvb/ttpci/av7110.c

@@ -88,6 +88,7 @@ static int budgetpatch;
 static int wss_cfg_4_3 = 0x4008;
 static int wss_cfg_16_9 = 0x0007;
 static int tv_standard;
+static int full_ts;
 
 module_param_named(debug, av7110_debug, int, 0644);
 MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
@@ -106,6 +107,8 @@ module_param(volume, int, 0444);
 MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)");
 module_param(budgetpatch, int, 0444);
 MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)");
+module_param(full_ts, int, 0444);
+MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable");
 module_param(wss_cfg_4_3, int, 0444);
 MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data");
 module_param(wss_cfg_16_9, int, 0444);
@@ -116,6 +119,8 @@ MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC");
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static void restart_feeds(struct av7110 *av7110);
+static int budget_start_feed(struct dvb_demux_feed *feed);
+static int budget_stop_feed(struct dvb_demux_feed *feed);
 
 static int av7110_num;
 
@@ -806,6 +811,9 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
 
 	dprintk(4, "%p\n", av7110);
 
+	if (av7110->full_ts)
+		return 0;
+
 	if (dvbdmxfilter->type == DMX_TYPE_SEC) {
 		if (hw_sections) {
 			buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) |
@@ -854,6 +862,9 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
 
 	dprintk(4, "%p\n", av7110);
 
+	if (av7110->full_ts)
+		return 0;
+
 	handle = dvbdmxfilter->hw_handle;
 	if (handle >= 32) {
 		printk("%s tried to stop invalid filter %04x, filter type = %x\n",
@@ -913,7 +924,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
 				return ret;
 		}
 
-	if ((dvbdmxfeed->ts_type & TS_PACKET)) {
+	if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) {
 		if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000))
 			ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
 		if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000))
@@ -974,7 +985,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
 	if (!demux->dmx.frontend)
 		return -EINVAL;
 
-	if (feed->pid > 0x1fff)
+	if (!av7110->full_ts && feed->pid > 0x1fff)
 		return -EINVAL;
 
 	if (feed->type == DMX_TYPE_TS) {
@@ -1003,7 +1014,12 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
 		}
 	}
 
-	else if (feed->type == DMX_TYPE_SEC) {
+	if (av7110->full_ts) {
+		budget_start_feed(feed);
+		return ret;
+	}
+
+	if (feed->type == DMX_TYPE_SEC) {
 		int i;
 
 		for (i = 0; i < demux->filternum; i++) {
@@ -1050,7 +1066,12 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
 				ret = StopHWFilter(feed->filter);
 	}
 
-	if (!ret && feed->type == DMX_TYPE_SEC) {
+	if (av7110->full_ts) {
+		budget_stop_feed(feed);
+		return ret;
+	}
+
+	if (feed->type == DMX_TYPE_SEC) {
 		for (i = 0; i<demux->filternum; i++) {
 			if (demux->filter[i].state == DMX_STATE_GO &&
 			    demux->filter[i].filter.parent == &feed->feed.sec) {
@@ -1074,6 +1095,7 @@ static void restart_feeds(struct av7110 *av7110)
 	struct dvb_demux *dvbdmx = &av7110->demux;
 	struct dvb_demux_feed *feed;
 	int mode;
+	int feeding;
 	int i, j;
 
 	dprintk(4, "%p\n", av7110);
@@ -1082,6 +1104,8 @@ static void restart_feeds(struct av7110 *av7110)
 	av7110->playing = 0;
 	av7110->rec_mode = 0;
 
+	feeding = av7110->feeding1; /* full_ts mod */
+
 	for (i = 0; i < dvbdmx->feednum; i++) {
 		feed = &dvbdmx->feed[i];
 		if (feed->state == DMX_STATE_GO) {
@@ -1099,6 +1123,8 @@ static void restart_feeds(struct av7110 *av7110)
 		}
 	}
 
+	av7110->feeding1 = feeding; /* full_ts mod */
+
 	if (mode)
 		av7110_av_start_play(av7110, mode);
 }
@@ -1197,8 +1223,9 @@ static int start_ts_capture(struct av7110 *budget)
 
 	if (budget->feeding1)
 		return ++budget->feeding1;
-	memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH);
+	memset(budget->grabbing, 0x00, TS_BUFLEN);
 	budget->ttbp = 0;
+	SAA7146_ISR_CLEAR(budget->dev, MASK_10);  /* VPE */
 	SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
 	saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
 	return ++budget->feeding1;
@@ -1239,12 +1266,8 @@ static void vpeirq(unsigned long data)
 	u8 *mem = (u8 *) (budget->grabbing);
 	u32 olddma = budget->ttbp;
 	u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
+	struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1;
 
-	if (!budgetpatch) {
-		printk("av7110.c: vpeirq() called while budgetpatch disabled!"
-		       " check saa7146 IER register\n");
-		BUG();
-	}
 	/* nearest lower position divisible by 188 */
 	newdma -= newdma % 188;
 
@@ -1268,11 +1291,11 @@ static void vpeirq(unsigned long data)
 
 	if (newdma > olddma)
 		/* no wraparound, dump olddma..newdma */
-		dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188);
+		dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188);
 	else {
 		/* wraparound, dump olddma..buflen and 0..newdma */
-		dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188);
-		dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188);
+		dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
+		dvb_dmx_swfilter_packets(demux, mem, newdma / 188);
 	}
 }
 
@@ -1294,8 +1317,8 @@ static int av7110_register(struct av7110 *av7110)
 	for (i = 0; i < 32; i++)
 		av7110->handle2filter[i] = NULL;
 
-	dvbdemux->filternum = 32;
-	dvbdemux->feednum = 32;
+	dvbdemux->filternum = (av7110->full_ts) ? 256 : 32;
+	dvbdemux->feednum = (av7110->full_ts) ? 256 : 32;
 	dvbdemux->start_feed = av7110_start_feed;
 	dvbdemux->stop_feed = av7110_stop_feed;
 	dvbdemux->write_to_decoder = av7110_write_to_decoder;
@@ -1305,7 +1328,7 @@ static int av7110_register(struct av7110 *av7110)
 	dvb_dmx_init(&av7110->demux);
 	av7110->demux.dmx.get_stc = dvb_get_stc;
 
-	av7110->dmxdev.filternum = 32;
+	av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32;
 	av7110->dmxdev.demux = &dvbdemux->dmx;
 	av7110->dmxdev.capabilities = 0;
 
@@ -1422,7 +1445,6 @@ int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val)
 	return i2c_transfer(&av7110->i2c_adap, &msgs, 1);
 }
 
-#if 0
 u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
 {
 	u8 mm1[] = {0x00};
@@ -1439,7 +1461,6 @@ u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
 
 	return mm2[0];
 }
-#endif
 
 /****************************************************************************
  * INITIALIZATION
@@ -2484,7 +2505,47 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
 			       av7110->dvb_adapter.proposed_mac);
 	ret = -ENOMEM;
 
-	if (budgetpatch) {
+	/* full-ts mod? */
+	if (full_ts)
+		av7110->full_ts = true;
+
+	/* check for full-ts flag in eeprom */
+	if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) {
+		u8 flags = i2c_readreg(av7110, 0xaa, 2);
+		if (flags != 0xff && (flags & 0x01))
+			av7110->full_ts = true;
+	}
+
+	if (av7110->full_ts) {
+		printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n");
+		spin_lock_init(&av7110->feedlock1);
+		av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
+								 &av7110->pt);
+		if (!av7110->grabbing)
+			goto err_i2c_del_3;
+
+		saa7146_write(dev, DD1_STREAM_B, 0x00000000);
+		saa7146_write(dev, MC2, (MASK_10 | MASK_26));
+
+		saa7146_write(dev, DD1_INIT, 0x00000600);
+		saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
+
+		saa7146_write(dev, BRS_CTRL, 0x60000000);
+		saa7146_write(dev, MC2, MASK_08 | MASK_24);
+
+		/* dma3 */
+		saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000));
+		saa7146_write(dev, BASE_ODD3, 0);
+		saa7146_write(dev, BASE_EVEN3, 0);
+		saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT);
+		saa7146_write(dev, PITCH3, TS_WIDTH);
+		saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90);
+		saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
+		saa7146_write(dev, MC2, MASK_04 | MASK_20);
+
+		tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
+
+	} else if (budgetpatch) {
 		spin_lock_init(&av7110->feedlock1);
 		av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
 								 &av7110->pt);
@@ -2710,11 +2771,13 @@ static int __devexit av7110_detach(struct saa7146_dev* saa)
 #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE)
 	av7110_ir_exit(av7110);
 #endif
-	if (budgetpatch) {
-		/* Disable RPS1 */
-		saa7146_write(saa, MC1, MASK_29);
-		/* VSYNC LOW (inactive) */
-		saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+	if (budgetpatch || av7110->full_ts) {
+		if (budgetpatch) {
+			/* Disable RPS1 */
+			saa7146_write(saa, MC1, MASK_29);
+			/* VSYNC LOW (inactive) */
+			saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+		}
 		saa7146_write(saa, MC1, MASK_20);	/* DMA3 off */
 		SAA7146_IER_DISABLE(saa, MASK_10);
 		SAA7146_ISR_CLEAR(saa, MASK_10);
@@ -2794,7 +2857,7 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr)
 		tasklet_schedule(&av7110->gpio_tasklet);
 	}
 
-	if ((*isr & MASK_10) && budgetpatch)
+	if (*isr & MASK_10)
 		tasklet_schedule(&av7110->vpe_tasklet);
 }
 

+ 1 - 0
drivers/media/dvb/ttpci/av7110.h

@@ -192,6 +192,7 @@ struct av7110 {
 	unsigned char           *grabbing;
 	struct saa7146_pgtable  pt;
 	struct tasklet_struct   vpe_tasklet;
+	bool			full_ts;
 
 	int			fe_synced;
 	struct mutex		pid_mutex;

+ 3 - 0
drivers/media/dvb/ttpci/av7110_av.c

@@ -788,6 +788,9 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l
 
 	dprintk(2, "av7110:%p, \n", av7110);
 
+	if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE)
+		return 0;
+
 	switch (feed->pes_type) {
 	case 0:
 		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)