summaryrefslogtreecommitdiff
path: root/linux/drivers/media/dvb
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/dvb')
-rw-r--r--linux/drivers/media/dvb/ttpci-budget/budget-core.c78
-rw-r--r--linux/drivers/media/dvb/ttpci-budget/budget.h8
2 files changed, 69 insertions, 17 deletions
diff --git a/linux/drivers/media/dvb/ttpci-budget/budget-core.c b/linux/drivers/media/dvb/ttpci-budget/budget-core.c
index 90b4d4227..d7ce45356 100644
--- a/linux/drivers/media/dvb/ttpci-budget/budget-core.c
+++ b/linux/drivers/media/dvb/ttpci-budget/budget-core.c
@@ -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 --git a/linux/drivers/media/dvb/ttpci-budget/budget.h b/linux/drivers/media/dvb/ttpci-budget/budget.h
index 7df52e804..0a0a5b16b 100644
--- a/linux/drivers/media/dvb/ttpci-budget/budget.h
+++ b/linux/drivers/media/dvb/ttpci-budget/budget.h
@@ -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;
@@ -68,6 +68,10 @@ static struct saa7146_pci_extension_data x_var = { \
#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
#define BUDGET_KNC1 2