drivers/media/pci/bt8xx/bttv-vbi.c

Source file repositories/reference/linux-study-clean/drivers/media/pci/bt8xx/bttv-vbi.c

File Facts

System
Linux kernel
Corpus path
drivers/media/pci/bt8xx/bttv-vbi.c
Extension
.c
Size
10432 bytes
Lines
378
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

while (!list_empty(&btv->vcapture)) {
			buf = list_entry(btv->vcapture.next,
					 struct bttv_buffer, list);
			list_del(&buf->list);
			buf->vbuf.sequence = (btv->field_count >> 1) + seqnr++;
			vb2_buffer_done(&buf->vbuf.vb2_buf,
					VB2_BUF_STATE_QUEUED);
		}
		return -EBUSY;
	}
	if (!vb2_is_streaming(&btv->capq)) {
		init_irqreg(btv);
		btv->field_count = 0;
	}
	return 0;
}

static void stop_streaming_vbi(struct vb2_queue *q)
{
	struct bttv *btv = vb2_get_drv_priv(q);
	unsigned long flags;

	vb2_wait_for_all_buffers(q);
	spin_lock_irqsave(&btv->s_lock, flags);
	free_btres_lock(btv, RESOURCE_VBI);
	if (!vb2_is_streaming(&btv->capq)) {
		/* stop field counter */
		btand(~BT848_INT_VSYNC, BT848_INT_MASK);
	}
	spin_unlock_irqrestore(&btv->s_lock, flags);
}

const struct vb2_ops bttv_vbi_qops = {
	.queue_setup    = queue_setup_vbi,
	.buf_queue      = buf_queue_vbi,
	.buf_prepare    = buf_prepare_vbi,
	.buf_cleanup	= buf_cleanup_vbi,
	.start_streaming = start_streaming_vbi,
	.stop_streaming = stop_streaming_vbi,
};

/* ----------------------------------------------------------------------- */

static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm,
			__s32 crop_start)
{
	__s32 min_start, max_start, max_end, f2_offset;
	unsigned int i;

	/* For compatibility with earlier driver versions we must pretend
	   the VBI and video capture window may overlap. In reality RISC
	   magic aborts VBI capturing at the first line of video capturing,
	   leaving the rest of the buffer unchanged, usually all zero.
	   VBI capturing must always start before video capturing. >> 1
	   because cropping counts field lines times two. */
	min_start = tvnorm->vbistart[0];
	max_start = (crop_start >> 1) - 1;
	max_end = (tvnorm->cropcap.bounds.top
		   + tvnorm->cropcap.bounds.height) >> 1;

	if (min_start > max_start)
		return -EBUSY;

	WARN_ON(max_start >= max_end);

	f->sampling_rate    = tvnorm->Fsc;
	f->samples_per_line = VBI_BPL;
	f->sample_format    = V4L2_PIX_FMT_GREY;
	f->offset           = VBI_OFFSET;

	f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0];

	for (i = 0; i < 2; ++i) {
		if (0 == f->count[i]) {
			/* No data from this field. We leave f->start[i]
			   alone because VIDIOCSVBIFMT is w/o and EINVALs
			   when a driver does not support exactly the
			   requested parameters. */
		} else {
			s64 start, count;

			start = clamp(f->start[i], min_start, max_start);
			/* s64 to prevent overflow. */
			count = (s64) f->start[i] + f->count[i] - start;
			f->start[i] = start;
			f->count[i] = clamp(count, (s64) 1,
					    max_end - start);
		}

		min_start += f2_offset;

Annotation

Implementation Notes