📄 saa7146_video.c
字号:
case VIDIOC_TRY_FMT: { struct v4l2_format *f = arg; DEB_EE(("VIDIOC_TRY_FMT\n")); return try_fmt(fh,f); } case VIDIOC_G_STD: { v4l2_std_id *id = arg; DEB_EE(("VIDIOC_G_STD\n")); *id = vv->standard->id; return 0; } /* the saa7146 supfhrts (used in conjunction with the saa7111a for example) PAL / NTSC / SECAM. if your hardware does not (or does more) -- override this function in your extension */ case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; if (e->index < 0 ) return -EINVAL; if( e->index < dev->ext_vv_data->num_stds ) { DEB_EE(("VIDIOC_ENUMSTD: index:%d\n",e->index)); v4l2_video_std_construct(e, dev->ext_vv_data->stds[e->index].id, dev->ext_vv_data->stds[e->index].name); return 0; } return -EINVAL; } case VIDIOC_S_STD: { v4l2_std_id *id = arg; int i; int restart_overlay = 0; int found = 0; struct saa7146_fh *ov_fh = NULL; DEB_EE(("VIDIOC_S_STD\n")); if( 0 != vv->streaming ) { return -EBUSY; } down(&dev->lock); if( vv->ov_data != NULL ) { ov_fh = vv->ov_data->fh; saa7146_stop_preview(ov_fh); restart_overlay = 1; } for(i = 0; i < dev->ext_vv_data->num_stds; i++) if (*id & dev->ext_vv_data->stds[i].id) break; if (i != dev->ext_vv_data->num_stds) { vv->standard = &dev->ext_vv_data->stds[i]; if( NULL != dev->ext_vv_data->std_callback ) dev->ext_vv_data->std_callback(dev, vv->standard); found = 1; } if( 0 != restart_overlay ) { saa7146_start_preview(ov_fh); } up(&dev->lock); if( 0 == found ) { DEB_EE(("VIDIOC_S_STD: standard not found.\n")); return -EINVAL; } DEB_EE(("VIDIOC_S_STD: set to standard to '%s'\n",vv->standard->name)); return 0; } case VIDIOC_OVERLAY:/* FIXME: remove when videodev2.h update is in kernel */#ifdef VIDIOC_OVERLAY_OLD case VIDIOC_OVERLAY_OLD:#endif { int on = *(int *)arg; int err = 0; if( NULL == vv->ov_fmt && on != 0 ) { DEB_D(("VIDIOC_OVERLAY: no framebuffer informations. call S_FBUF first!\n")); return -EAGAIN; } DEB_D(("VIDIOC_OVERLAY on:%d\n",on)); if( 0 != on ) { if( vv->ov_data != NULL ) { if( fh != vv->ov_data->fh) { DEB_D(("overlay already active in another open\n")); return -EAGAIN; } } if (0 == saa7146_res_get(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { DEB_D(("cannot get overlay resources\n")); return -EBUSY; } spin_lock_irqsave(&dev->slock,flags); err = saa7146_start_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); return err; } if( vv->ov_data != NULL ) { if( fh != vv->ov_data->fh) { DEB_D(("overlay is active, but in another open\n")); return -EAGAIN; } } else { DEB_D(("overlay is not active\n")); return 0; } spin_lock_irqsave(&dev->slock,flags); err = saa7146_stop_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); /* free resources */ saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); return err; } case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *req = arg; DEB_D(("VIDIOC_REQBUFS, type:%d\n",req->type)); return videobuf_reqbufs(file,q,req); } case VIDIOC_QUERYBUF: { struct v4l2_buffer *buf = arg; DEB_D(("VIDIOC_QUERYBUF, type:%d, offset:%d\n",buf->type,buf->m.offset)); return videobuf_querybuf(q,buf); } case VIDIOC_QBUF: { struct v4l2_buffer *buf = arg; int ret = 0; ret = videobuf_qbuf(file,q,buf); DEB_D(("VIDIOC_QBUF: ret:%d, index:%d\n",ret,buf->index)); return ret; } case VIDIOC_DQBUF: { struct v4l2_buffer *buf = arg; int ret = 0; ret = videobuf_dqbuf(file,q,buf); DEB_D(("VIDIOC_DQBUF: ret:%d, index:%d\n",ret,buf->index)); return ret; } case VIDIOC_STREAMON: { int *type = arg; DEB_D(("VIDIOC_STREAMON, type:%d\n",*type)); if( fh == vv->streaming ) { DEB_D(("already capturing.\n")); return 0; } err = video_begin(fh); if( 0 != err) { return err; } err = videobuf_streamon(file,q); return err; } case VIDIOC_STREAMOFF: { int *type = arg; DEB_D(("VIDIOC_STREAMOFF, type:%d\n",*type)); if( fh != vv->streaming ) { DEB_D(("this open is not capturing.\n")); return -EINVAL; } err = videobuf_streamoff(file,q); video_end(fh, file); return err; } case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; struct videobuf_queue *q; int i; /* fixme: number of capture buffers and sizes for v4l apps */ int gbuffers = 2; int gbufsize = 768*576*4; DEB_D(("VIDIOCGMBUF \n")); q = &fh->video_q; down(&q->lock); err = videobuf_mmap_setup(file,q,gbuffers,gbufsize, V4L2_MEMORY_MMAP); if (err < 0) { up(&q->lock); return err; } memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = gbuffers; mbuf->size = gbuffers * gbufsize; for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; up(&q->lock); return 0; } default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, saa7146_video_do_ioctl); } return 0;}/*********************************************************************************//* buffer handling functions */static int buffer_activate (struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next){ struct saa7146_vv *vv = dev->vv_data; buf->vb.state = STATE_ACTIVE; saa7146_set_capture(dev,buf,next); mod_timer(&vv->video_q.timeout, jiffies+BUFFER_TIMEOUT); return 0;}static int buffer_prepare(struct file *file, struct videobuf_buffer *vb, enum v4l2_field field){ struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; struct saa7146_buf *buf = (struct saa7146_buf *)vb; int size,err = 0; DEB_CAP(("vbuf:%p\n",vb)); /* sanity checks */ if (fh->video_fmt.width < 48 || fh->video_fmt.height < 32 || fh->video_fmt.width > vv->standard->h_max_out || fh->video_fmt.height > vv->standard->v_max_out) { DEB_D(("w (%d) / h (%d) out of bounds.\n",fh->video_fmt.width,fh->video_fmt.height)); return -EINVAL; } size = fh->video_fmt.sizeimage; if (0 != buf->vb.baddr && buf->vb.bsize < size) { DEB_D(("size mismatch.\n")); return -EINVAL; } DEB_CAP(("buffer_prepare [size=%dx%d,bytes=%d,fields=%s]\n", fh->video_fmt.width,fh->video_fmt.height,size,v4l2_field_names[fh->video_fmt.field])); if (buf->vb.width != fh->video_fmt.width || buf->vb.bytesperline != fh->video_fmt.bytesperline || buf->vb.height != fh->video_fmt.height || buf->vb.size != size || buf->vb.field != field || buf->vb.field != fh->video_fmt.field || buf->fmt != &fh->video_fmt) { saa7146_dma_free(dev,buf); } if (STATE_NEEDS_INIT == buf->vb.state) { struct saa7146_format *sfmt; buf->vb.bytesperline = fh->video_fmt.bytesperline; buf->vb.width = fh->video_fmt.width; buf->vb.height = fh->video_fmt.height; buf->vb.size = size; buf->vb.field = field; buf->fmt = &fh->video_fmt; buf->vb.field = fh->video_fmt.field; sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); if( 0 != IS_PLANAR(sfmt->trans)) { saa7146_pgtable_free(dev->pci, &buf->pt[0]); saa7146_pgtable_free(dev->pci, &buf->pt[1]); saa7146_pgtable_free(dev->pci, &buf->pt[2]); saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); saa7146_pgtable_alloc(dev->pci, &buf->pt[1]); saa7146_pgtable_alloc(dev->pci, &buf->pt[2]); } else { saa7146_pgtable_free(dev->pci, &buf->pt[0]); saa7146_pgtable_alloc(dev->pci, &buf->pt[0]); } err = videobuf_iolock(dev->pci,&buf->vb, &vv->ov_fb); if (err) goto oops; err = saa7146_pgtable_build(dev,buf); if (err) goto oops; } buf->vb.state = STATE_PREPARED; buf->activate = buffer_activate; return 0; oops: DEB_D(("error out.\n")); saa7146_dma_free(dev,buf); return err;}static int buffer_setup(struct file *file, unsigned int *count, unsigned int *size){ struct saa7146_fh *fh = file->private_data; if (0 == *count || *count > MAX_SAA7146_CAPTURE_BUFFERS) *count = MAX_SAA7146_CAPTURE_BUFFERS; *size = fh->video_fmt.sizeimage; /* check if we exceed the "memory" parameter */ if( (*count * *size) > (memory*1048576) ) { *count = (memory*1048576) / *size; } DEB_CAP(("%d buffers, %d bytes each.\n",*count,*size)); return 0;}static void buffer_queue(struct file *file, struct videobuf_buffer *vb){ struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; struct saa7146_buf *buf = (struct saa7146_buf *)vb; DEB_CAP(("vbuf:%p\n",vb)); saa7146_buffer_queue(fh->dev,&vv->video_q,buf);}static void buffer_release(struct file *file, struct videobuf_buffer *vb){ struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; struct saa7146_buf *buf = (struct saa7146_buf *)vb; DEB_CAP(("vbuf:%p\n",vb)); saa7146_dma_free(dev,buf);}static struct videobuf_queue_ops video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release,};/********************************************************************************//* file operations */static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv){ INIT_LIST_HEAD(&vv->video_q.queue); init_timer(&vv->video_q.timeout); vv->video_q.timeout.function = saa7146_buffer_timeout; vv->video_q.timeout.data = (unsigned long)(&vv->video_q); vv->video_q.dev = dev; /* set some default values */ vv->standard = &dev->ext_vv_data->stds[0]; /* FIXME: what's this? */ vv->current_hps_source = SAA7146_HPS_SOURCE_PORT_A; vv->current_hps_sync = SAA7146_HPS_SYNC_PORT_A;}static int video_open(struct saa7146_dev *dev, struct file *file){ struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; struct saa7146_format *sfmt; fh->video_fmt.width = 384; fh->video_fmt.height = 288; fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24; fh->video_fmt.bytesperline = 0; fh->video_fmt.field = V4L2_FIELD_ANY; sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8; videobuf_queue_init(&fh->video_q, &video_qops, dev->pci, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct saa7146_buf)); init_MUTEX(&fh->video_q.lock); return 0;}static void video_close(struct saa7146_dev *dev, struct file *file){ struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data; struct saa7146_vv *vv = dev->vv_data; unsigned long flags; if( 0 != vv->ov_data ) { if( fh == vv->ov_data->fh ) { spin_lock_irqsave(&dev->slock,flags); saa7146_stop_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); saa7146_res_free(fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); } } if( fh == vv->streaming ) { video_end(fh, file); }}static void video_irq_done(struct saa7146_dev *dev, unsigned long st){ struct saa7146_vv *vv = dev->vv_data; struct saa7146_dmaqueue *q = &vv->video_q; spin_lock(&dev->slock); DEB_CAP(("called.\n")); /* only finish the buffer if we have one... */ if( NULL != q->curr ) { saa7146_buffer_finish(dev,q,STATE_DONE); } saa7146_buffer_next(dev,q,0); spin_unlock(&dev->slock);}static ssize_t video_read(struct file *file, char *data, size_t count, loff_t *ppos){ struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; ssize_t ret = 0; int restart_overlay = 0; struct saa7146_fh *ov_fh = NULL; DEB_EE(("called.\n")); /* fixme: should we allow read() captures while streaming capture? */ if( 0 != vv->streaming ) { DEB_S(("already capturing.\n")); return -EBUSY; } /* stop any active overlay */ if( vv->ov_data != NULL ) { ov_fh = vv->ov_data->fh; saa7146_stop_preview(ov_fh); saa7146_res_free(ov_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP); restart_overlay = 1; } ret = video_begin(fh); if( 0 != ret) { goto out; } ret = videobuf_read_one(file,&fh->video_q , data, count, ppos); video_end(fh, file);out: /* restart overlay if it was active before */ if( 0 != restart_overlay ) { if (0 == saa7146_res_get(ov_fh, RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP)) { DEB_D(("cannot get overlay resources again!\n")); BUG(); } saa7146_start_preview(ov_fh); } return ret;}struct saa7146_use_ops saa7146_video_uops = { .init = video_init, .open = video_open, .release = video_close, .irq_done = video_irq_done, .read = video_read,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -