for (i = 0; i < buf->actual_size; i += 188) { if (*(bufcpu + i) != 0x47)
port->sync_errors++;
/* TODO: Query pid lower 8 bits, ignoring upper bits intensionally */
pid = ((*(bufcpu + i + 1) & 0x1f) << 8) | *(bufcpu + i + 2);
cc = *(bufcpu + i + 3) & 0x0f;
if (pid == FIXED_VIDEO_PID) {
a = ((port->last_v_cc + 1) & 0x0f); if (a != cc) {
printk(KERN_ERR "video cc last = %x current = %x i = %d\n",
port->last_v_cc, cc, i);
port->v_cc_errors++;
}
port->last_v_cc = cc;
} else if (pid == FIXED_AUDIO_PID) {
a = ((port->last_a_cc + 1) & 0x0f); if (a != cc) {
printk(KERN_ERR "audio cc last = %x current = %x i = %d\n",
port->last_a_cc, cc, i);
port->a_cc_errors++;
}
port->last_a_cc = cc;
}
}
/* Only report errors if we've been through this function at least * once already and the cached cc values are primed. First time through * always generates errors.
*/ if (port->v_cc_errors && (port->done_first_interrupt > 1))
printk(KERN_ERR "video pid cc, %d errors\n", port->v_cc_errors);
} else
printk(KERN_ERR "encirq no free buffers, increase param encoder_buffers\n");
/* Ensure offset into buffer remains 0, fill buffer * with known bad data. We check for this data at a later point
* in time. */
saa7164_buffer_zero_offsets(port, bufnr);
memset(buf->cpu, 0xff, buf->pci_size); if (crc_checking) { /* Throw yet aanother new checksum on the dma buffer */
buf->crc = crc32(0, buf->cpu, buf->actual_size);
}
/* Find the current write point from the hardware */
wp = saa7164_readl(port->bufcounter);
BUG_ON(wp > (port->hwcfg.buffercount - 1));
/* Find the previous buffer to the current write point */ if (wp == 0)
rp = (port->hwcfg.buffercount - 1); else
rp = wp - 1;
/* Lookup the WP in the buffer list */ /* TODO: turn this into a worker thread */
list_for_each_safe(c, n, &port->dmaqueue.list) {
buf = list_entry(c, struct saa7164_buffer, list);
BUG_ON(i > port->hwcfg.buffercount);
i++;
if (buf->idx == rp) { /* Found the buffer, deal with it */
dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n",
__func__, wp, rp);
saa7164_buffer_deliver(buf); break;
}
u32 intid, intstat[INT_SIZE/4]; int i, handled = 0, bit;
if (dev == NULL) {
printk(KERN_ERR "%s() No device specified\n", __func__);
handled = 0; goto out;
}
porta = &dev->ports[SAA7164_PORT_TS1];
portb = &dev->ports[SAA7164_PORT_TS2];
portc = &dev->ports[SAA7164_PORT_ENC1];
portd = &dev->ports[SAA7164_PORT_ENC2];
porte = &dev->ports[SAA7164_PORT_VBI1];
portf = &dev->ports[SAA7164_PORT_VBI2];
/* Check that the hardware is accessible. If the status bytes are * 0xFF then the device is not accessible, the IRQ belongs * to another driver. * 4 x u32 interrupt registers.
*/ for (i = 0; i < INT_SIZE/4; i++) {
/* TODO: Convert into saa7164_readl() */ /* Read the 4 hardware interrupt registers */
intstat[i] = saa7164_readl(dev->int_status + (i * 4));
if (intstat[i])
handled = 1;
} if (handled == 0) goto out;
/* For each of the HW interrupt registers */ for (i = 0; i < INT_SIZE/4; i++) {
if (intstat[i]) { /* Each function of the board has it's own interruptid. * Find the function that triggered then call * it's handler.
*/ for (bit = 0; bit < 32; bit++) {
if (((intstat[i] >> bit) & 0x00000001) == 0) continue;
/* Calculate the interrupt id (0x00 to 0x7f) */
intid = (i * 32) + bit; if (intid == dev->intfdesc.bInterruptId) { /* A response to an cmd/api call */
schedule_work(&dev->workcmd);
} elseif (intid == porta->hwcfg.interruptid) {
/* Transport path 1 */
saa7164_irq_ts(porta);
} elseif (intid == portb->hwcfg.interruptid) {
/* Transport path 2 */
saa7164_irq_ts(portb);
} elseif (intid == portc->hwcfg.interruptid) {
/* Encoder path 1 */
saa7164_irq_encoder(portc);
} elseif (intid == portd->hwcfg.interruptid) {
/* Encoder path 2 */
saa7164_irq_encoder(portd);
} elseif (intid == porte->hwcfg.interruptid) {
/* VBI path 1 */
saa7164_irq_vbi(porte);
} elseif (intid == portf->hwcfg.interruptid) {
/* VBI path 2 */
saa7164_irq_vbi(portf);
} else { /* Find the function */
dprintk(DBGLVL_IRQ, "%s() unhandled interrupt reg 0x%x bit 0x%x intid = 0x%x\n",
__func__, i, bit, intid);
}
}
/* Ack it */
saa7164_writel(dev->int_ack + (i * 4), intstat[i]);
/* Much of the hardware configuration and PCI registers are configured * dynamically depending on firmware. We have to cache some initial * structures then use these to locate other important structures * from PCI space.
*/ staticvoid saa7164_get_descriptors(struct saa7164_dev *dev)
{
memcpy_fromio(&dev->hwdesc, dev->bmmio, sizeof(struct tmComResHWDescr));
memcpy_fromio(&dev->intfdesc, dev->bmmio + sizeof(struct tmComResHWDescr), sizeof(struct tmComResInterfaceDescr));
memcpy_fromio(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation, sizeof(struct tmComResBusDescr));
if (get_resources(dev) < 0) {
printk(KERN_ERR "CORE %s No more PCIe resources for subsystem: %04x:%04x\n",
dev->name, dev->pci->subsystem_vendor,
dev->pci->subsystem_device);
while (1) {
msleep_interruptible(100); if (kthread_should_stop()) break;
try_to_freeze();
dprintk(DBGLVL_THR, "thread running\n");
/* Dump the firmware debug message to console */ /* Polling this costs us 1-2% of the arm CPU */ /* convert this into a respnde to interrupt 0x7a */
saa7164_api_collect_debug(dev);
/* Monitor CPU load every 1 second */ if ((last_poll_time + 1000 /* ms */) < jiffies_to_msecs(jiffies)) {
saa7164_api_get_load_info(dev, &fwinfo);
last_poll_time = jiffies_to_msecs(jiffies);
}
staticbool saa7164_enable_msi(struct pci_dev *pci_dev, struct saa7164_dev *dev)
{ int err;
if (!enable_msi) {
printk(KERN_WARNING "%s() MSI disabled by module parameter 'enable_msi'"
, __func__); returnfalse;
}
err = pci_enable_msi(pci_dev);
if (err) {
printk(KERN_ERR "%s() Failed to enable MSI interrupt. Falling back to a shared IRQ\n",
__func__); returnfalse;
}
/* no error - so request an msi interrupt */
err = request_irq(pci_dev->irq, saa7164_irq, 0,
dev->name, dev);
if (err) { /* fall back to legacy interrupt */
printk(KERN_ERR "%s() Failed to get an MSI interrupt. Falling back to a shared IRQ\n",
__func__);
pci_disable_msi(pci_dev); returnfalse;
}
pci_set_master(pci_dev); /* TODO */
err = dma_set_mask(&pci_dev->dev, 0xffffffff); if (err) {
printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); goto fail_irq;
}
/* irq bit */ if (saa7164_enable_msi(pci_dev, dev)) {
dev->msi = true;
} else { /* if we have an error (i.e. we don't have an interrupt)
or msi is not enabled - fallback to shared interrupt */
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d\n", dev->name,
pci_dev->irq);
err = -EIO; goto fail_irq;
}
}
pci_set_drvdata(pci_dev, dev);
/* Init the internal command list */ for (i = 0; i < SAA_CMD_MAX_MSG_UNITS; i++) {
dev->cmds[i].seqno = i;
dev->cmds[i].inuse = 0;
mutex_init(&dev->cmds[i].lock);
init_waitqueue_head(&dev->cmds[i].wait);
}
/* We need a deferred interrupt handler for cmd handling */
INIT_WORK(&dev->workcmd, saa7164_work_cmdhandler);
/* Only load the firmware if we know the board */ if (dev->board != SAA7164_BOARD_UNKNOWN) {
err = saa7164_downloadfirmware(dev); if (err < 0) {
printk(KERN_ERR "Failed to boot firmware, no features registered\n"); goto fail_fw;
}
saa7164_get_descriptors(dev);
saa7164_dumpregs(dev, 0);
saa7164_getcurrentfirmwareversion(dev);
saa7164_getfirmwarestatus(dev);
err = saa7164_bus_setup(dev); if (err < 0)
printk(KERN_ERR "Failed to setup the bus, will continue\n");
saa7164_bus_dump(dev);
/* Ping the running firmware via the command bus and get the * firmware version, this checks the bus is running OK.
*/
version = 0; if (saa7164_api_get_fw_version(dev, &version) == SAA_OK)
dprintk(1, "Bus is operating correctly using version %d.%d.%d.%d (0x%x)\n",
(version & 0x0000fc00) >> 10,
(version & 0x000003e0) >> 5,
(version & 0x0000001f),
(version & 0xffff0000) >> 16,
version); else
printk(KERN_ERR "Failed to communicate with the firmware\n");
/* Bring up the I2C buses */
saa7164_i2c_register(&dev->i2c_bus[0]);
saa7164_i2c_register(&dev->i2c_bus[1]);
saa7164_i2c_register(&dev->i2c_bus[2]);
saa7164_gpio_setup(dev);
saa7164_card_setup(dev);
/* Parse the dynamic device configuration, find various * media endpoints (MPEG, WMV, PS, TS) and cache their * configuration details into the driver, so we can * reference them later during simething_register() func, * interrupt handlers, deferred work handlers etc.
*/
saa7164_api_enum_subdevs(dev);
/* Begin to create the video sub-systems and register funcs */ if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) { if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS1]) < 0) {
printk(KERN_ERR "%s() Failed to register dvb adapters on porta\n",
__func__);
}
}
if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) { if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS2]) < 0) {
printk(KERN_ERR"%s() Failed to register dvb adapters on portb\n",
__func__);
}
}
if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) { if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC1]) < 0) {
printk(KERN_ERR"%s() Failed to register mpeg encoder\n",
__func__);
}
}
if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) { if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC2]) < 0) {
printk(KERN_ERR"%s() Failed to register mpeg encoder\n",
__func__);
}
}
if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) { if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI1]) < 0) {
printk(KERN_ERR"%s() Failed to register vbi device\n",
__func__);
}
}
if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) { if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI2]) < 0) {
printk(KERN_ERR"%s() Failed to register vbi device\n",
__func__);
}
}
saa7164_api_set_debug(dev, fw_debug);
if (fw_debug) {
dev->kthread = kthread_run(saa7164_thread_function, dev, "saa7164 debug"); if (IS_ERR(dev->kthread)) {
dev->kthread = NULL;
printk(KERN_ERR "%s() Failed to create debug kernel thread\n",
__func__);
}
}
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.