brintos

brintos / linux-shallow public Read only

0
0
Text · 19.2 KiB · 040489e Raw
726 lines · c
1#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt2 3#include <media/drv-intf/saa7146_vv.h>4#include <media/v4l2-event.h>5#include <media/v4l2-ctrls.h>6#include <linux/module.h>7#include <linux/kernel.h>8 9/* format descriptions for capture and preview */10static struct saa7146_format formats[] = {11	{12		.pixelformat	= V4L2_PIX_FMT_RGB332,13		.trans		= RGB08_COMPOSED,14		.depth		= 8,15		.flags		= 0,16	}, {17		.pixelformat	= V4L2_PIX_FMT_RGB565,18		.trans		= RGB16_COMPOSED,19		.depth		= 16,20		.flags		= 0,21	}, {22		.pixelformat	= V4L2_PIX_FMT_BGR24,23		.trans		= RGB24_COMPOSED,24		.depth		= 24,25		.flags		= 0,26	}, {27		.pixelformat	= V4L2_PIX_FMT_BGR32,28		.trans		= RGB32_COMPOSED,29		.depth		= 32,30		.flags		= 0,31	}, {32		.pixelformat	= V4L2_PIX_FMT_RGB32,33		.trans		= RGB32_COMPOSED,34		.depth		= 32,35		.flags		= 0,36		.swap		= 0x2,37	}, {38		.pixelformat	= V4L2_PIX_FMT_GREY,39		.trans		= Y8,40		.depth		= 8,41		.flags		= 0,42	}, {43		.pixelformat	= V4L2_PIX_FMT_YUV422P,44		.trans		= YUV422_DECOMPOSED,45		.depth		= 16,46		.flags		= FORMAT_IS_PLANAR,47	}, {48		.pixelformat	= V4L2_PIX_FMT_YVU420,49		.trans		= YUV420_DECOMPOSED,50		.depth		= 12,51		.flags		= FORMAT_BYTE_SWAP|FORMAT_IS_PLANAR,52	}, {53		.pixelformat	= V4L2_PIX_FMT_YUV420,54		.trans		= YUV420_DECOMPOSED,55		.depth		= 12,56		.flags		= FORMAT_IS_PLANAR,57	}, {58		.pixelformat	= V4L2_PIX_FMT_UYVY,59		.trans		= YUV422_COMPOSED,60		.depth		= 16,61		.flags		= 0,62	}63};64 65/* unfortunately, the saa7146 contains a bug which prevents it from doing on-the-fly byte swaps.66   due to this, it's impossible to provide additional *packed* formats, which are simply byte swapped67   (like V4L2_PIX_FMT_YUYV) ... 8-( */68 69struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc)70{71	int i;72 73	for (i = 0; i < ARRAY_SIZE(formats); i++) {74		if (formats[i].pixelformat == fourcc) {75			return formats+i;76		}77	}78 79	DEB_D("unknown pixelformat:'%4.4s'\n", (char *)&fourcc);80	return NULL;81}82 83/********************************************************************************/84/* common pagetable functions */85 86static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)87{88	struct saa7146_vv *vv = dev->vv_data;89	struct pci_dev *pci = dev->pci;90	struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0);91	struct scatterlist *list = sgt->sgl;92	int length = sgt->nents;93	struct v4l2_pix_format *pix = &vv->video_fmt;94	struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pix->pixelformat);95 96	DEB_EE("dev:%p, buf:%p, sg_len:%d\n", dev, buf, length);97 98	if( 0 != IS_PLANAR(sfmt->trans)) {99		struct saa7146_pgtable *pt1 = &buf->pt[0];100		struct saa7146_pgtable *pt2 = &buf->pt[1];101		struct saa7146_pgtable *pt3 = &buf->pt[2];102		struct sg_dma_page_iter dma_iter;103		__le32  *ptr1, *ptr2, *ptr3;104		__le32 fill;105 106		int size = pix->width * pix->height;107		int i, m1, m2, m3, o1, o2;108 109		switch( sfmt->depth ) {110			case 12: {111				/* create some offsets inside the page table */112				m1 = ((size + PAGE_SIZE) / PAGE_SIZE) - 1;113				m2 = ((size + (size / 4) + PAGE_SIZE) / PAGE_SIZE) - 1;114				m3 = ((size + (size / 2) + PAGE_SIZE) / PAGE_SIZE) - 1;115				o1 = size % PAGE_SIZE;116				o2 = (size + (size / 4)) % PAGE_SIZE;117				DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",118					size, m1, m2, m3, o1, o2);119				break;120			}121			case 16: {122				/* create some offsets inside the page table */123				m1 = ((size + PAGE_SIZE) / PAGE_SIZE) - 1;124				m2 = ((size + (size / 2) + PAGE_SIZE) / PAGE_SIZE) - 1;125				m3 = ((2 * size + PAGE_SIZE) / PAGE_SIZE) - 1;126				o1 = size % PAGE_SIZE;127				o2 = (size + (size / 2)) % PAGE_SIZE;128				DEB_CAP("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",129					size, m1, m2, m3, o1, o2);130				break;131			}132			default: {133				return -1;134			}135		}136 137		ptr1 = pt1->cpu;138		ptr2 = pt2->cpu;139		ptr3 = pt3->cpu;140 141		for_each_sg_dma_page(list, &dma_iter, length, 0)142			*ptr1++ = cpu_to_le32(sg_page_iter_dma_address(&dma_iter) - list->offset);143 144		/* if we have a user buffer, the first page may not be145		   aligned to a page boundary. */146		pt1->offset = sgt->sgl->offset;147		pt2->offset = pt1->offset + o1;148		pt3->offset = pt1->offset + o2;149 150		/* create video-dma2 page table */151		ptr1 = pt1->cpu;152		for (i = m1; i <= m2; i++, ptr2++)153			*ptr2 = ptr1[i];154		fill = *(ptr2 - 1);155		for (; i < 1024; i++, ptr2++)156			*ptr2 = fill;157		/* create video-dma3 page table */158		ptr1 = pt1->cpu;159		for (i = m2; i <= m3; i++, ptr3++)160			*ptr3 = ptr1[i];161		fill = *(ptr3 - 1);162		for (; i < 1024; i++, ptr3++)163			*ptr3 = fill;164		/* finally: finish up video-dma1 page table */165		ptr1 = pt1->cpu + m1;166		fill = pt1->cpu[m1];167		for (i = m1; i < 1024; i++, ptr1++)168			*ptr1 = fill;169	} else {170		struct saa7146_pgtable *pt = &buf->pt[0];171 172		return saa7146_pgtable_build_single(pci, pt, list, length);173	}174 175	return 0;176}177 178 179/********************************************************************************/180/* file operations */181 182static int video_begin(struct saa7146_dev *dev)183{184	struct saa7146_vv *vv = dev->vv_data;185	struct saa7146_format *fmt = NULL;186	unsigned int resource;187	int ret = 0;188 189	DEB_EE("dev:%p\n", dev);190 191	fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);192	/* we need to have a valid format set here */193	if (!fmt)194		return -EINVAL;195 196	if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {197		resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;198	} else {199		resource = RESOURCE_DMA1_HPS;200	}201 202	ret = saa7146_res_get(dev, resource);203	if (0 == ret) {204		DEB_S("cannot get capture resource %d\n", resource);205		return -EBUSY;206	}207 208	/* clear out beginning of streaming bit (rps register 0)*/209	saa7146_write(dev, MC2, MASK_27 );210 211	/* enable rps0 irqs */212	SAA7146_IER_ENABLE(dev, MASK_27);213 214	return 0;215}216 217static void video_end(struct saa7146_dev *dev)218{219	struct saa7146_vv *vv = dev->vv_data;220	struct saa7146_format *fmt = NULL;221	unsigned long flags;222	unsigned int resource;223	u32 dmas = 0;224	DEB_EE("dev:%p\n", dev);225 226	fmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);227	/* we need to have a valid format set here */228	if (!fmt)229		return;230 231	if (0 != (fmt->flags & FORMAT_IS_PLANAR)) {232		resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS;233		dmas = MASK_22 | MASK_21 | MASK_20;234	} else {235		resource = RESOURCE_DMA1_HPS;236		dmas = MASK_22;237	}238	spin_lock_irqsave(&dev->slock,flags);239 240	/* disable rps0  */241	saa7146_write(dev, MC1, MASK_28);242 243	/* disable rps0 irqs */244	SAA7146_IER_DISABLE(dev, MASK_27);245 246	/* shut down all used video dma transfers */247	saa7146_write(dev, MC1, dmas);248 249	spin_unlock_irqrestore(&dev->slock, flags);250 251	saa7146_res_free(dev, resource);252}253 254static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)255{256	struct saa7146_dev *dev = video_drvdata(file);257 258	strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver));259	strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card));260	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |261			    V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |262			    V4L2_CAP_DEVICE_CAPS;263	cap->capabilities |= dev->ext_vv_data->capabilities;264	return 0;265}266 267static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)268{269	if (f->index >= ARRAY_SIZE(formats))270		return -EINVAL;271	f->pixelformat = formats[f->index].pixelformat;272	return 0;273}274 275int saa7146_s_ctrl(struct v4l2_ctrl *ctrl)276{277	struct saa7146_dev *dev = container_of(ctrl->handler,278				struct saa7146_dev, ctrl_handler);279	struct saa7146_vv *vv = dev->vv_data;280	u32 val;281 282	switch (ctrl->id) {283	case V4L2_CID_BRIGHTNESS:284		val = saa7146_read(dev, BCS_CTRL);285		val &= 0x00ffffff;286		val |= (ctrl->val << 24);287		saa7146_write(dev, BCS_CTRL, val);288		saa7146_write(dev, MC2, MASK_22 | MASK_06);289		break;290 291	case V4L2_CID_CONTRAST:292		val = saa7146_read(dev, BCS_CTRL);293		val &= 0xff00ffff;294		val |= (ctrl->val << 16);295		saa7146_write(dev, BCS_CTRL, val);296		saa7146_write(dev, MC2, MASK_22 | MASK_06);297		break;298 299	case V4L2_CID_SATURATION:300		val = saa7146_read(dev, BCS_CTRL);301		val &= 0xffffff00;302		val |= (ctrl->val << 0);303		saa7146_write(dev, BCS_CTRL, val);304		saa7146_write(dev, MC2, MASK_22 | MASK_06);305		break;306 307	case V4L2_CID_HFLIP:308		/* fixme: we can support changing VFLIP and HFLIP here... */309		if (vb2_is_busy(&vv->video_dmaq.q))310			return -EBUSY;311		vv->hflip = ctrl->val;312		break;313 314	case V4L2_CID_VFLIP:315		if (vb2_is_busy(&vv->video_dmaq.q))316			return -EBUSY;317		vv->vflip = ctrl->val;318		break;319 320	default:321		return -EINVAL;322	}323	return 0;324}325 326static int vidioc_g_parm(struct file *file, void *fh,327		struct v4l2_streamparm *parm)328{329	struct saa7146_dev *dev = video_drvdata(file);330	struct saa7146_vv *vv = dev->vv_data;331 332	if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)333		return -EINVAL;334	parm->parm.capture.readbuffers = 1;335	v4l2_video_std_frame_period(vv->standard->id,336				    &parm->parm.capture.timeperframe);337	return 0;338}339 340static int vidioc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)341{342	struct saa7146_dev *dev = video_drvdata(file);343	struct saa7146_vv *vv = dev->vv_data;344 345	f->fmt.pix = vv->video_fmt;346	return 0;347}348 349static int vidioc_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f)350{351	struct saa7146_dev *dev = video_drvdata(file);352	struct saa7146_vv *vv = dev->vv_data;353 354	f->fmt.vbi = vv->vbi_fmt;355	return 0;356}357 358static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)359{360	struct saa7146_dev *dev = video_drvdata(file);361	struct saa7146_vv *vv = dev->vv_data;362	struct saa7146_format *fmt;363	enum v4l2_field field;364	int maxw, maxh;365	int calc_bpl;366 367	DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh);368 369	fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);370	if (NULL == fmt)371		return -EINVAL;372 373	field = f->fmt.pix.field;374	maxw  = vv->standard->h_max_out;375	maxh  = vv->standard->v_max_out;376 377	if (V4L2_FIELD_ANY == field) {378		field = (f->fmt.pix.height > maxh / 2)379			? V4L2_FIELD_INTERLACED380			: V4L2_FIELD_BOTTOM;381	}382	switch (field) {383	case V4L2_FIELD_ALTERNATE:384	case V4L2_FIELD_TOP:385	case V4L2_FIELD_BOTTOM:386		maxh = maxh / 2;387		break;388	default:389		field = V4L2_FIELD_INTERLACED;390		break;391	}392 393	f->fmt.pix.field = field;394	f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;395	if (f->fmt.pix.width < 48)396		f->fmt.pix.width = 48;397	if (f->fmt.pix.height < 32)398		f->fmt.pix.height = 32;399	if (f->fmt.pix.width > maxw)400		f->fmt.pix.width = maxw;401	if (f->fmt.pix.height > maxh)402		f->fmt.pix.height = maxh;403 404	calc_bpl = (f->fmt.pix.width * fmt->depth) / 8;405 406	if (f->fmt.pix.bytesperline < calc_bpl)407		f->fmt.pix.bytesperline = calc_bpl;408 409	if (f->fmt.pix.bytesperline > (2 * PAGE_SIZE * fmt->depth) / 8) /* arbitrary constraint */410		f->fmt.pix.bytesperline = calc_bpl;411 412	f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height;413	DEB_D("w:%d, h:%d, bytesperline:%d, sizeimage:%d\n",414	      f->fmt.pix.width, f->fmt.pix.height,415	      f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);416 417	return 0;418}419 420static int vidioc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)421{422	struct saa7146_dev *dev = video_drvdata(file);423	struct saa7146_vv *vv = dev->vv_data;424	int err;425 426	DEB_EE("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p\n", dev);427	if (vb2_is_busy(&vv->video_dmaq.q)) {428		DEB_EE("streaming capture is active\n");429		return -EBUSY;430	}431	err = vidioc_try_fmt_vid_cap(file, fh, f);432	if (0 != err)433		return err;434	switch (f->fmt.pix.field) {435	case V4L2_FIELD_ALTERNATE:436		vv->last_field = V4L2_FIELD_TOP;437		break;438	default:439		vv->last_field = V4L2_FIELD_INTERLACED;440		break;441	}442	vv->video_fmt = f->fmt.pix;443	DEB_EE("set to pixelformat '%4.4s'\n",444	       (char *)&vv->video_fmt.pixelformat);445	return 0;446}447 448static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)449{450	struct saa7146_dev *dev = video_drvdata(file);451	struct saa7146_vv *vv = dev->vv_data;452 453	*norm = vv->standard->id;454	return 0;455}456 457static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id)458{459	struct saa7146_dev *dev = video_drvdata(file);460	struct saa7146_vv *vv = dev->vv_data;461	int found = 0;462	int i;463 464	DEB_EE("VIDIOC_S_STD\n");465 466	for (i = 0; i < dev->ext_vv_data->num_stds; i++)467		if (id & dev->ext_vv_data->stds[i].id)468			break;469 470	if (i != dev->ext_vv_data->num_stds &&471	    vv->standard == &dev->ext_vv_data->stds[i])472		return 0;473 474	if (vb2_is_busy(&vv->video_dmaq.q) || vb2_is_busy(&vv->vbi_dmaq.q)) {475		DEB_D("cannot change video standard while streaming capture is active\n");476		return -EBUSY;477	}478 479	if (i != dev->ext_vv_data->num_stds) {480		vv->standard = &dev->ext_vv_data->stds[i];481		if (NULL != dev->ext_vv_data->std_callback)482			dev->ext_vv_data->std_callback(dev, vv->standard);483		found = 1;484	}485 486	if (!found) {487		DEB_EE("VIDIOC_S_STD: standard not found\n");488		return -EINVAL;489	}490 491	DEB_EE("VIDIOC_S_STD: set to standard to '%s'\n", vv->standard->name);492	return 0;493}494 495const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {496	.vidioc_querycap             = vidioc_querycap,497	.vidioc_enum_fmt_vid_cap     = vidioc_enum_fmt_vid_cap,498	.vidioc_g_fmt_vid_cap        = vidioc_g_fmt_vid_cap,499	.vidioc_try_fmt_vid_cap      = vidioc_try_fmt_vid_cap,500	.vidioc_s_fmt_vid_cap        = vidioc_s_fmt_vid_cap,501	.vidioc_g_std                = vidioc_g_std,502	.vidioc_s_std                = vidioc_s_std,503	.vidioc_g_parm		     = vidioc_g_parm,504	.vidioc_reqbufs		     = vb2_ioctl_reqbufs,505	.vidioc_create_bufs	     = vb2_ioctl_create_bufs,506	.vidioc_querybuf	     = vb2_ioctl_querybuf,507	.vidioc_qbuf		     = vb2_ioctl_qbuf,508	.vidioc_dqbuf		     = vb2_ioctl_dqbuf,509	.vidioc_streamon	     = vb2_ioctl_streamon,510	.vidioc_streamoff	     = vb2_ioctl_streamoff,511	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,512	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,513};514 515const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops = {516	.vidioc_querycap             = vidioc_querycap,517	.vidioc_g_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,518	.vidioc_try_fmt_vbi_cap      = vidioc_g_fmt_vbi_cap,519	.vidioc_s_fmt_vbi_cap        = vidioc_g_fmt_vbi_cap,520	.vidioc_g_std                = vidioc_g_std,521	.vidioc_s_std                = vidioc_s_std,522	.vidioc_g_parm		     = vidioc_g_parm,523	.vidioc_reqbufs		     = vb2_ioctl_reqbufs,524	.vidioc_create_bufs	     = vb2_ioctl_create_bufs,525	.vidioc_querybuf	     = vb2_ioctl_querybuf,526	.vidioc_qbuf		     = vb2_ioctl_qbuf,527	.vidioc_dqbuf		     = vb2_ioctl_dqbuf,528	.vidioc_streamon	     = vb2_ioctl_streamon,529	.vidioc_streamoff	     = vb2_ioctl_streamoff,530	.vidioc_subscribe_event      = v4l2_ctrl_subscribe_event,531	.vidioc_unsubscribe_event    = v4l2_event_unsubscribe,532};533 534/*********************************************************************************/535/* buffer handling functions                                                  */536 537static int buffer_activate (struct saa7146_dev *dev,538		     struct saa7146_buf *buf,539		     struct saa7146_buf *next)540{541	struct saa7146_vv *vv = dev->vv_data;542 543	saa7146_set_capture(dev,buf,next);544 545	mod_timer(&vv->video_dmaq.timeout, jiffies+BUFFER_TIMEOUT);546	return 0;547}548 549static void release_all_pagetables(struct saa7146_dev *dev, struct saa7146_buf *buf)550{551	saa7146_pgtable_free(dev->pci, &buf->pt[0]);552	saa7146_pgtable_free(dev->pci, &buf->pt[1]);553	saa7146_pgtable_free(dev->pci, &buf->pt[2]);554}555 556static int queue_setup(struct vb2_queue *q,557		       unsigned int *num_buffers, unsigned int *num_planes,558		       unsigned int sizes[], struct device *alloc_devs[])559{560	struct saa7146_dev *dev = vb2_get_drv_priv(q);561	unsigned int size = dev->vv_data->video_fmt.sizeimage;562 563	if (*num_planes)564		return sizes[0] < size ? -EINVAL : 0;565	*num_planes = 1;566	sizes[0] = size;567 568	return 0;569}570 571static void buf_queue(struct vb2_buffer *vb)572{573	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);574	struct vb2_queue *vq = vb->vb2_queue;575	struct saa7146_dev *dev = vb2_get_drv_priv(vq);576	struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);577	unsigned long flags;578 579	spin_lock_irqsave(&dev->slock, flags);580 581	saa7146_buffer_queue(dev, &dev->vv_data->video_dmaq, buf);582	spin_unlock_irqrestore(&dev->slock, flags);583}584 585static int buf_init(struct vb2_buffer *vb)586{587	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);588	struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);589	struct vb2_queue *vq = vb->vb2_queue;590	struct saa7146_dev *dev = vb2_get_drv_priv(vq);591	struct saa7146_vv *vv = dev->vv_data;592	struct saa7146_format *sfmt;593	int ret;594 595	buf->activate = buffer_activate;596	sfmt = saa7146_format_by_fourcc(dev, vv->video_fmt.pixelformat);597 598	if (IS_PLANAR(sfmt->trans)) {599		saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);600		saa7146_pgtable_alloc(dev->pci, &buf->pt[1]);601		saa7146_pgtable_alloc(dev->pci, &buf->pt[2]);602	} else {603		saa7146_pgtable_alloc(dev->pci, &buf->pt[0]);604	}605 606	ret = saa7146_pgtable_build(dev, buf);607	if (ret)608		release_all_pagetables(dev, buf);609	return ret;610}611 612static int buf_prepare(struct vb2_buffer *vb)613{614	struct vb2_queue *vq = vb->vb2_queue;615	struct saa7146_dev *dev = vb2_get_drv_priv(vq);616	struct saa7146_vv *vv = dev->vv_data;617	unsigned int size = vv->video_fmt.sizeimage;618 619	if (vb2_plane_size(vb, 0) < size)620		return -EINVAL;621	vb2_set_plane_payload(vb, 0, size);622	return 0;623}624 625static void buf_cleanup(struct vb2_buffer *vb)626{627	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);628	struct saa7146_buf *buf = container_of(vbuf, struct saa7146_buf, vb);629	struct vb2_queue *vq = vb->vb2_queue;630	struct saa7146_dev *dev = vb2_get_drv_priv(vq);631 632	release_all_pagetables(dev, buf);633}634 635static void return_buffers(struct vb2_queue *q, int state)636{637	struct saa7146_dev *dev = vb2_get_drv_priv(q);638	struct saa7146_dmaqueue *dq = &dev->vv_data->video_dmaq;639	struct saa7146_buf *buf;640 641	if (dq->curr) {642		buf = dq->curr;643		dq->curr = NULL;644		vb2_buffer_done(&buf->vb.vb2_buf, state);645	}646	while (!list_empty(&dq->queue)) {647		buf = list_entry(dq->queue.next, struct saa7146_buf, list);648		list_del(&buf->list);649		vb2_buffer_done(&buf->vb.vb2_buf, state);650	}651}652 653static int start_streaming(struct vb2_queue *q, unsigned int count)654{655	struct saa7146_dev *dev = vb2_get_drv_priv(q);656	int ret;657 658	if (!vb2_is_streaming(&dev->vv_data->video_dmaq.q))659		dev->vv_data->seqnr = 0;660	ret = video_begin(dev);661	if (ret)662		return_buffers(q, VB2_BUF_STATE_QUEUED);663	return ret;664}665 666static void stop_streaming(struct vb2_queue *q)667{668	struct saa7146_dev *dev = vb2_get_drv_priv(q);669	struct saa7146_dmaqueue *dq = &dev->vv_data->video_dmaq;670 671	del_timer(&dq->timeout);672	video_end(dev);673	return_buffers(q, VB2_BUF_STATE_ERROR);674}675 676const struct vb2_ops video_qops = {677	.queue_setup	= queue_setup,678	.buf_queue	= buf_queue,679	.buf_init	= buf_init,680	.buf_prepare	= buf_prepare,681	.buf_cleanup	= buf_cleanup,682	.start_streaming = start_streaming,683	.stop_streaming = stop_streaming,684	.wait_prepare	= vb2_ops_wait_prepare,685	.wait_finish	= vb2_ops_wait_finish,686};687 688/********************************************************************************/689/* file operations */690 691static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)692{693	INIT_LIST_HEAD(&vv->video_dmaq.queue);694 695	timer_setup(&vv->video_dmaq.timeout, saa7146_buffer_timeout, 0);696	vv->video_dmaq.dev              = dev;697 698	/* set some default values */699	vv->standard = &dev->ext_vv_data->stds[0];700 701	/* FIXME: what's this? */702	vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A;703	vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A;704}705 706static void video_irq_done(struct saa7146_dev *dev, unsigned long st)707{708	struct saa7146_vv *vv = dev->vv_data;709	struct saa7146_dmaqueue *q = &vv->video_dmaq;710 711	spin_lock(&dev->slock);712	DEB_CAP("called\n");713 714	/* only finish the buffer if we have one... */715	if (q->curr)716		saa7146_buffer_finish(dev, q, VB2_BUF_STATE_DONE);717	saa7146_buffer_next(dev,q,0);718 719	spin_unlock(&dev->slock);720}721 722const struct saa7146_use_ops saa7146_video_uops = {723	.init = video_init,724	.irq_done = video_irq_done,725};726