drivers/media/pci/hws/hws_irq.c

Source file repositories/reference/linux-study-clean/drivers/media/pci/hws/hws_irq.c

File Facts

System
Linux kernel
Corpus path
drivers/media/pci/hws/hws_irq.c
Extension
.c
Size
7843 bytes
Lines
270
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

if (v->active) {
			list_add(&buf->list, &v->capture_queue);
			v->queued_count++;
			v->active = NULL;
		}
		spin_unlock_irqrestore(&v->irq_lock, f);
		return -EBUSY;
	}

	/* Also program the DMA address register directly */
	{
		dma_addr_t dma_addr =
		    vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
		hws_program_dma_for_addr(hws, ch, dma_addr);
		iowrite32(lower_32_bits(dma_addr),
			  hws->bar0_base + HWS_REG_DMA_ADDR(ch));
	}

	dev_dbg(&hws->pdev->dev, "arm_next(ch=%u): programmed buffer %p\n", ch,
		buf);
	spin_lock_irqsave(&v->irq_lock, flags);
	hws_prime_next_locked(v);
	spin_unlock_irqrestore(&v->irq_lock, flags);
	return 0;
}

static void hws_video_handle_vdone(struct hws_video *v)
{
	struct hws_pcie_dev *hws = v->parent;
	unsigned int ch = v->channel_index;
	struct hwsvideo_buffer *done;
	unsigned long flags;
	bool promoted = false;

	dev_dbg(&hws->pdev->dev,
		"bh_video(ch=%u): stop=%d cap=%d active=%p\n",
		ch, READ_ONCE(v->stop_requested), READ_ONCE(v->cap_active),
		v->active);

	int ret;

	dev_dbg(&hws->pdev->dev,
		"bh_video(ch=%u): entry stop=%d cap=%d\n", ch,
		v->stop_requested, v->cap_active);
	if (READ_ONCE(hws->suspended))
		return;

	if (READ_ONCE(v->stop_requested) || !READ_ONCE(v->cap_active))
		return;

	spin_lock_irqsave(&v->irq_lock, flags);
	done = v->active;
	if (done && v->next_prepared) {
		v->active = v->next_prepared;
		v->next_prepared = NULL;
		promoted = true;
	}
	spin_unlock_irqrestore(&v->irq_lock, flags);

	/* 1) Complete the buffer the HW just finished (if any) */
	if (done) {
		struct vb2_v4l2_buffer *vb2v = &done->vb;
		size_t expected = v->pix.sizeimage;
		size_t plane_size = vb2_plane_size(&vb2v->vb2_buf, 0);

		if (expected > plane_size) {
			dev_warn_ratelimited(&hws->pdev->dev,
					     "bh_video(ch=%u): sizeimage %zu > plane %zu, dropping seq=%u\n",
					     ch, expected, plane_size,
					     (u32)atomic_read(&v->sequence_number) + 1);
			vb2_buffer_done(&vb2v->vb2_buf, VB2_BUF_STATE_ERROR);
			goto arm_next;
		}
		vb2_set_plane_payload(&vb2v->vb2_buf, 0, expected);

		dma_rmb();	/* device writes visible before userspace sees it */

		vb2v->sequence = (u32)atomic_inc_return(&v->sequence_number);
		vb2v->vb2_buf.timestamp = ktime_get_ns();
		dev_dbg(&hws->pdev->dev,
			"bh_video(ch=%u): DONE buf=%p seq=%u half_seen=%d toggle=%u\n",
			ch, done, vb2v->sequence, v->half_seen,
			v->last_buf_half_toggle);

		if (!promoted)
			v->active = NULL;	/* channel no longer owns this buffer */
		vb2_buffer_done(&vb2v->vb2_buf, VB2_BUF_STATE_DONE);
	}

	if (READ_ONCE(hws->suspended))

Annotation

Implementation Notes