drivers/media/common/videobuf2/videobuf2-vmalloc.c

Source file repositories/reference/linux-study-clean/drivers/media/common/videobuf2/videobuf2-vmalloc.c

File Facts

System
Linux kernel
Corpus path
drivers/media/common/videobuf2/videobuf2-vmalloc.c
Extension
.c
Size
10456 bytes
Lines
446
Domain
Driver Families
Bucket
drivers/media
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

struct vb2_vmalloc_buf {
	void				*vaddr;
	struct frame_vector		*vec;
	enum dma_data_direction		dma_dir;
	unsigned long			size;
	refcount_t			refcount;
	struct vb2_vmarea_handler	handler;
	struct dma_buf			*dbuf;
};

static void vb2_vmalloc_put(void *buf_priv);

static void *vb2_vmalloc_alloc(struct vb2_buffer *vb, struct device *dev,
			       unsigned long size)
{
	struct vb2_vmalloc_buf *buf;

	buf = kzalloc_obj(*buf, GFP_KERNEL | vb->vb2_queue->gfp_flags);
	if (!buf)
		return ERR_PTR(-ENOMEM);

	buf->size = size;
	buf->vaddr = vmalloc_user(buf->size);
	if (!buf->vaddr) {
		pr_debug("vmalloc of size %ld failed\n", buf->size);
		kfree(buf);
		return ERR_PTR(-ENOMEM);
	}

	buf->dma_dir = vb->vb2_queue->dma_dir;
	buf->handler.refcount = &buf->refcount;
	buf->handler.put = vb2_vmalloc_put;
	buf->handler.arg = buf;

	refcount_set(&buf->refcount, 1);
	return buf;
}

static void vb2_vmalloc_put(void *buf_priv)
{
	struct vb2_vmalloc_buf *buf = buf_priv;

	if (refcount_dec_and_test(&buf->refcount)) {
		vfree(buf->vaddr);
		kfree(buf);
	}
}

static void *vb2_vmalloc_get_userptr(struct vb2_buffer *vb, struct device *dev,
				     unsigned long vaddr, unsigned long size)
{
	struct vb2_vmalloc_buf *buf;
	struct frame_vector *vec;
	int n_pages, offset, i;
	int ret = -ENOMEM;

	buf = kzalloc_obj(*buf);
	if (!buf)
		return ERR_PTR(-ENOMEM);

	buf->dma_dir = vb->vb2_queue->dma_dir;
	offset = vaddr & ~PAGE_MASK;
	buf->size = size;
	vec = vb2_create_framevec(vaddr, size,
				  buf->dma_dir == DMA_FROM_DEVICE ||
				  buf->dma_dir == DMA_BIDIRECTIONAL);
	if (IS_ERR(vec)) {
		ret = PTR_ERR(vec);
		goto fail_pfnvec_create;
	}
	buf->vec = vec;
	n_pages = frame_vector_count(vec);
	if (frame_vector_to_pages(vec) < 0) {
		unsigned long *nums = frame_vector_pfns(vec);

		/*
		 * We cannot get page pointers for these pfns. Check memory is
		 * physically contiguous and use direct mapping.
		 */
		for (i = 1; i < n_pages; i++)
			if (nums[i-1] + 1 != nums[i])
				goto fail_map;
		buf->vaddr = (__force void *)
			ioremap(__pfn_to_phys(nums[0]), size + offset);
	} else {
		buf->vaddr = vm_map_ram(frame_vector_pages(vec), n_pages, -1);
	}

	if (!buf->vaddr)
		goto fail_map;

Annotation

Implementation Notes