// SPDX-License-Identifier: GPL-2.0-only /* * Linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III * flexcop-pci.c - covers the PCI part including DMA transfers * see flexcop.c for copyright information
*/
#define FC_PCI_INIT 0x01 #define FC_PCI_DMA_INIT 0x02 int init_state;
void __iomem *io_mem;
u32 irq; /* buffersize (at least for DMA1, need to be % 188 == 0,
* this logic is required */ #define FC_DEFAULT_DMA1_BUFSIZE (1280 * 188) #define FC_DEFAULT_DMA2_BUFSIZE (10 * 188) struct flexcop_dma dma[2];
int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */
u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occurred */ int count; int count_prev; int stream_problem;
if (fc_pci->count == fc_pci->count_prev) {
deb_chk("no IRQ since the last check\n"); if (fc_pci->stream_problem++ == 3) { struct dvb_demux_feed *feed;
deb_info("flexcop-pci: stream problem, resetting pid filter\n");
/* When PID filtering is turned on, we use the timer IRQ, because small amounts * of data need to be passed to the user space instantly as well. When PID
* filtering is turned off, we use the page-change-IRQ */ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
{ struct flexcop_pci *fc_pci = dev_id; struct flexcop_device *fc = fc_pci->fc_dev; unsignedlong flags;
flexcop_ibi_value v;
irqreturn_t ret = IRQ_HANDLED;
spin_lock_irqsave(&fc_pci->irq_lock, flags);
v = fc->read_ibi_reg(fc, irq_20c);
/* errors */ if (v.irq_20c.Data_receiver_error)
deb_chk("data receiver error\n"); if (v.irq_20c.Continuity_error_flag)
deb_chk("Continuity error flag is set\n"); if (v.irq_20c.LLC_SNAP_FLAG_set)
deb_chk("LLC_SNAP_FLAG_set is set\n"); if (v.irq_20c.Transport_Error)
deb_chk("Transport error\n");
if ((fc_pci->count % 1000) == 0)
deb_chk("%d valid irq took place so far\n", fc_pci->count);
if (v.irq_20c.DMA1_IRQ_Status == 1) { if (fc_pci->active_dma1_addr == 0)
flexcop_pass_dmx_packets(fc_pci->fc_dev,
fc_pci->dma[0].cpu_addr0,
fc_pci->dma[0].size / 188); else
flexcop_pass_dmx_packets(fc_pci->fc_dev,
fc_pci->dma[0].cpu_addr1,
fc_pci->dma[0].size / 188);
deb_irq("page change to page: %d\n",!fc_pci->active_dma1_addr);
fc_pci->active_dma1_addr = !fc_pci->active_dma1_addr; /* for the timer IRQ we only can use buffer dmx feeding, because we don't have
* complete TS packets when reading from the DMA memory */
} elseif (v.irq_20c.DMA1_Timer_Status == 1) {
dma_addr_t cur_addr =
fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; if (cur_pos > fc_pci->dma[0].size * 2) goto error;
/* buffer end was reached, restarted from the beginning * pass the data from last_cur_pos to the buffer end to the demux
*/ if (cur_pos < fc_pci->last_dma1_cur_pos) {
deb_irq(" end was reached: passing %d bytes ",
(fc_pci->dma[0].size*2 - 1) -
fc_pci->last_dma1_cur_pos);
flexcop_pass_dmx_data(fc_pci->fc_dev,
fc_pci->dma[0].cpu_addr0 +
fc_pci->last_dma1_cur_pos,
(fc_pci->dma[0].size*2) -
fc_pci->last_dma1_cur_pos);
fc_pci->last_dma1_cur_pos = 0;
}
/* in theory every _exit function should be called exactly two times, * here and in the bail-out-part of the _init-function
*/ staticvoid flexcop_pci_remove(struct pci_dev *pdev)
{ struct flexcop_pci *fc_pci = pci_get_drvdata(pdev);
if (irq_chk_intv > 0)
cancel_delayed_work_sync(&fc_pci->irq_check_work);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.