Mailing List archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[linux-dvb] Re: new. perfect fidbirq() improved



HI again,

This is by far my best fidbirq() for dvb-kernel. 

CPU and PCI can be heavy loaded and not properly configured,
VSYNC trigger timing can be inaccurate.
Two DVB cards can share the same interrupt,
Sometimes even whole interrupt can be lost.

Still mplayer will play everything perfect, without
a single glitch or screen artefact.

Best regards, Emard

diff -pur orig/dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget-core.c dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget-core.c
--- orig/dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget-core.c	Fri Jan 24 13:28:45 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget-core.c	Sun Feb  2 18:28:20 2003
@@ -105,32 +105,80 @@ TTBStart(struct budget_s *budget)
         return ++budget->feeding;
 }
 
+/* TS_PACKETS is minumum number of accumulated 188-byte packets 
+** (TS_SIZE=188) that is considered 'complete' and can
+** be delivered to the sw_demux in one 'quantum'.
+** TS_QUANTUM is size in bytes of TS_PACKETS
+** TS_MAX_PACKETS is number of TS_PACKETS in one DMA window
+** TS_BUFLEN is 1024*188
+*/
 static
 void fidbirq (unsigned long data)
 {
 	struct budget_s *budget = (struct budget_s*) data;
 	u8 *mem=(u8 *)(budget->grabbing);
-	int num=512;
-	int field=0x80 & saa7146_read(budget->dev, PSR);
+	u8 oldtsf = budget->tsf;
+	u8 newtsf = 0x80 & saa7146_read(budget->dev, PSR);
+	u16 oldpkt = budget->ttbp;
+	u16 newpkt = saa7146_read(budget->dev, PCI_VDP3)/TS_QUANTUM; /* PCI_VDP3 = 0..TS_BUFLEN-1 */
+	u8 *olddma = mem + oldpkt*TS_QUANTUM; /* rounded to first complete packet */
 
 	DEB_EE(("budget: %p\n",budget));
+	
+	/* Zero-Packet-Loss fidbirq by EMARD */
 
-	if (field) {
-		if (field==budget->tsf)
-			num=1024;
-		else
-			mem+=TS_BUFLEN/2;
-	} else {
-		if (field==budget->tsf) {
-			if (budget->feeding && mem[TS_BUFLEN/2]==0x47)
-				dvb_dmx_swfilter_packets(&budget->demux, 
-				    mem+TS_BUFLEN/2, 512 );
+	budget->ttbp = newpkt;
+	budget->tsf = newtsf;
+	
+	/* exit immediately when the card is not set for feeding
+	** or when values are out of expected boundaries
+	*/
+	if(budget->feeding == 0 ||
+		oldpkt >= TS_MAX_PACKETS || newpkt >= TS_MAX_PACKETS)
+		return;
+
+	/* use heuristic methods for recovering from lost interrupt
+	*/
+	if(oldtsf == newtsf)
+	{
+		/* interrupt is probably lost, some data can't be
+		** retrieved because of DMA overwriting, but let's 
+		** try to save what is left of good data in the DMA
+		** window.
+		*/
+		if(newpkt != oldpkt)
+		{	/* DMA is probably in progress right now,
+			** overwriting data. Shift oldpkt 1 packets
+			** forward from newpkt as a gap for racing with 
+			** ongoing DMA transfer. Consider TS_MAX_PACKETS-1 packets
+			** are still valid in DMA window.
+			*/
+			oldpkt = (newpkt + 1) % TS_MAX_PACKETS;
+			olddma = mem + oldpkt*TS_QUANTUM;
+			/* from now on, proceed as usual */
 		}
 	}
 
-	budget->tsf=field;
-	if (budget->feeding && mem[0]==0x47)
-		dvb_dmx_swfilter_packets(&budget->demux, mem, num);
+	if(oldpkt < newpkt)
+	{	/* no wraparound - dump linear data
+		** from olddma to newdma
+		*/
+		if(*olddma == 0x47)
+			dvb_dmx_swfilter_packets(&budget->demux, olddma,
+				TS_PACKETS*(newpkt-oldpkt));
+	}
+	else
+	{ 	/* wraparound - dump in two chunks,
+		** from olddma to end of DMA window
+		** and from begin of DMA window to newdma
+		*/
+		if(*olddma == 0x47)
+			dvb_dmx_swfilter_packets(&budget->demux, olddma,
+				TS_PACKETS*(TS_MAX_PACKETS - oldpkt));
+		if(*mem == 0x47 && newpkt > 0)
+			dvb_dmx_swfilter_packets(&budget->demux, mem,
+				TS_PACKETS*newpkt);
+	}			
 }
 
 inline static void 
diff -pur orig/dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget.h dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget.h
--- orig/dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget.h	Thu Jan 23 20:00:03 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget.h	Sun Feb  2 18:28:11 2003
@@ -46,8 +46,8 @@ struct budget_s {
         int                     fe_synced; 
         struct semaphore        pid_mutex;
 
-        int tsf;
-        u32 ttbp;
+        u8 tsf;
+        u16 ttbp;
         int feeding;
 
         int registered;
@@ -67,6 +67,10 @@ static struct saa7146_pci_extension_data
 #define TS_WIDTH  (4*188)
 #define TS_HEIGHT (1024/4)
 #define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
+
+#define TS_PACKETS	1
+#define TS_QUANTUM	(TS_PACKETS*TS_SIZE)
+#define TS_MAX_PACKETS	(TS_BUFLEN/TS_QUANTUM)
 
 #define BUDGET_TT		   0
 #define BUDGET_TT_HW_DISEQC	   1
diff -pur orig/dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget-core.c dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget-core.c
--- orig/dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget-core.c	Thu Jan 23 20:00:03 2003
+++ dvb-kernel/linux/drivers/media/dvb/ttpci-budget/budget-core.c	Sun Feb  2 00:51:08 2003
@@ -432,6 +432,8 @@ int budget_attach (struct saa7146_dev* d
 **              which seems that can be done perfectly without this :-)).
 */                                                      
                 cnt = 0;                                // Setup RPS1 "program" (p35)
+                // Wait reset Source Line Counter Threshold                     (p36)
+                dev->rps1[cnt++]=cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS);
                 // Wait Source Line Counter Threshold                           (p36)
                 dev->rps1[cnt++]=cpu_to_le32(CMD_PAUSE | EVT_HS);
                 // Set GPIO3=1                                                  (p42)
@@ -446,8 +448,6 @@ int budget_attach (struct saa7146_dev* d
                 dev->rps1[cnt++]=cpu_to_le32(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
                 dev->rps1[cnt++]=cpu_to_le32(GPIO3_MSK);
                 dev->rps1[cnt++]=cpu_to_le32(SAA7146_GPIO_OUTLO<<24);
-                // Wait reset Source Line Counter Threshold                     (p36)
-                dev->rps1[cnt++]=cpu_to_le32(CMD_PAUSE | RPS_INV | EVT_HS);
                 // Jump to begin of RPS program                                 (p37)
                 dev->rps1[cnt++]=cpu_to_le32(CMD_JUMP);
                 dev->rps1[cnt++]=cpu_to_le32(virt_to_bus(&dev->rps1[0]));

Home | Main Index | Thread Index