drivers/media/pci/ivtv/ivtv-yuv.c

Source file repositories/reference/linux-study-clean/drivers/media/pci/ivtv/ivtv-yuv.c

File Facts

System
Linux kernel
Corpus path
drivers/media/pci/ivtv/ivtv-yuv.c
Extension
.c
Size
38534 bytes
Lines
1294
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 (y_pages == y_dma.page_count) {
			IVTV_DEBUG_WARN
				("failed to map uv user pages, returned %d expecting %d\n",
				 uv_pages, uv_dma.page_count);

			if (uv_pages >= 0) {
				unpin_user_pages(&dma->map[y_pages], uv_pages);
				rc = -EFAULT;
			} else {
				rc = uv_pages;
			}
		} else {
			IVTV_DEBUG_WARN
				("failed to map y user pages, returned %d expecting %d\n",
				 y_pages, y_dma.page_count);
		}
		if (y_pages >= 0) {
			unpin_user_pages(dma->map, y_pages);
			/*
			 * Inherit the -EFAULT from rc's
			 * initialization, but allow it to be
			 * overridden by uv_pages above if it was an
			 * actual errno.
			 */
		} else {
			rc = y_pages;
		}
		return rc;
	}

	dma->page_count = y_pages + uv_pages;

	/* Fill & map SG List */
	if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
		IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
		unpin_user_pages(dma->map, dma->page_count);
		dma->page_count = 0;
		return -ENOMEM;
	}
	dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist,
				    dma->page_count, DMA_TO_DEVICE);
	if (!dma->SG_length) {
		IVTV_DEBUG_WARN("%s: DMA map error, SG_length is 0\n", __func__);
		unpin_user_pages(dma->map, dma->page_count);
		dma->page_count = 0;
		return -EINVAL;
	}

	/* Fill SG Array with new values */
	ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);

	/* If we've offset the y plane, ensure top area is blanked */
	if (f->offset_y && yi->blanking_ptr) {
		dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
		dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr);
		dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
		dma->SG_length++;
	}

	/* Tag SG Array with Interrupt Bit */
	dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);

	ivtv_udma_sync_for_device(itv);
	return 0;
}

/* We rely on a table held in the firmware - Quick check. */
int ivtv_yuv_filter_check(struct ivtv *itv)
{
	int i, y, uv;

	for (i = 0, y = 16, uv = 4; i < 16; i++, y += 24, uv += 12) {
		if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + y) != i << 16) ||
		    (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + uv) != i << 16)) {
			IVTV_WARN ("YUV filter table not found in firmware.\n");
			return -1;
		}
	}
	return 0;
}

static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
{
	u32 i, line;

	/* If any filter is -1, then don't update it */
	if (h_filter > -1) {
		if (h_filter > 4)
			h_filter = 4;
		i = IVTV_YUV_HORIZONTAL_FILTER_OFFSET + (h_filter * 384);

Annotation

Implementation Notes