diff options
Diffstat (limited to 'linux/drivers/media/dvb')
-rw-r--r-- | linux/drivers/media/dvb/ttpci-budget/budget-core.c | 78 | ||||
-rw-r--r-- | linux/drivers/media/dvb/ttpci-budget/budget.h | 8 |
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 |