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