drivers/media/pci/solo6x10/solo6x10-p2m.c

Source file repositories/reference/linux-study-clean/drivers/media/pci/solo6x10/solo6x10-p2m.c

File Facts

System
Linux kernel
Corpus path
drivers/media/pci/solo6x10/solo6x10-p2m.c
Extension
.c
Size
8316 bytes
Lines
318
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

else if (time_left == 0) {
		solo_dev->p2m_timeouts++;
		ret = -EAGAIN;
	}

	solo_reg_write(solo_dev, SOLO_P2M_CONTROL(p2m_id), 0);

	/* Don't write here for the no_desc_mode case, because config is 0.
	 * We can't test no_desc_mode again, it might race. */
	if (desc_cnt > 1 && solo_dev->type != SOLO_DEV_6110 && config)
		solo_reg_write(solo_dev, SOLO_P2M_CONFIG(p2m_id), config);

	mutex_unlock(&p2m_dev->mutex);

	return ret;
}

void solo_p2m_fill_desc(struct solo_p2m_desc *desc, int wr,
			dma_addr_t dma_addr, u32 ext_addr, u32 size,
			int repeat, u32 ext_size)
{
	WARN_ON_ONCE(dma_addr & 0x03);
	WARN_ON_ONCE(!size);

	desc->cfg = SOLO_P2M_COPY_SIZE(size >> 2);
	desc->ctrl = SOLO_P2M_BURST_SIZE(SOLO_P2M_BURST_256) |
		(wr ? SOLO_P2M_WRITE : 0) | SOLO_P2M_TRANS_ON;

	if (repeat) {
		desc->cfg |= SOLO_P2M_EXT_INC(ext_size >> 2);
		desc->ctrl |=  SOLO_P2M_PCI_INC(size >> 2) |
			 SOLO_P2M_REPEAT(repeat);
	}

	desc->dma_addr = dma_addr;
	desc->ext_addr = ext_addr;
}

int solo_p2m_dma_t(struct solo_dev *solo_dev, int wr,
		   dma_addr_t dma_addr, u32 ext_addr, u32 size,
		   int repeat, u32 ext_size)
{
	struct solo_p2m_desc desc[2];

	solo_p2m_fill_desc(&desc[1], wr, dma_addr, ext_addr, size, repeat,
			   ext_size);

	/* No need for desc_dma since we know it is a single-shot */
	return solo_p2m_dma_desc(solo_dev, desc, 0, 1);
}

void solo_p2m_isr(struct solo_dev *solo_dev, int id)
{
	struct solo_p2m_dev *p2m_dev = &solo_dev->p2m_dev[id];
	struct solo_p2m_desc *desc;

	if (p2m_dev->desc_count <= p2m_dev->desc_idx) {
		complete(&p2m_dev->completion);
		return;
	}

	/* Setup next descriptor */
	p2m_dev->desc_idx++;
	desc = &p2m_dev->descs[p2m_dev->desc_idx];

	solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), 0);
	solo_reg_write(solo_dev, SOLO_P2M_TAR_ADR(id), desc->dma_addr);
	solo_reg_write(solo_dev, SOLO_P2M_EXT_ADR(id), desc->ext_addr);
	solo_reg_write(solo_dev, SOLO_P2M_EXT_CFG(id), desc->cfg);
	solo_reg_write(solo_dev, SOLO_P2M_CONTROL(id), desc->ctrl);
}

void solo_p2m_error_isr(struct solo_dev *solo_dev)
{
	unsigned int err = solo_reg_read(solo_dev, SOLO_PCI_ERR);
	struct solo_p2m_dev *p2m_dev;
	int i;

	if (!(err & (SOLO_PCI_ERR_P2M | SOLO_PCI_ERR_P2M_DESC)))
		return;

	for (i = 0; i < SOLO_NR_P2M; i++) {
		p2m_dev = &solo_dev->p2m_dev[i];
		p2m_dev->error = 1;
		solo_reg_write(solo_dev, SOLO_P2M_CONTROL(i), 0);
		complete(&p2m_dev->completion);
	}
}

void solo_p2m_exit(struct solo_dev *solo_dev)

Annotation

Implementation Notes