📄 saa7146_video.c
字号:
/* nothing */; }; switch (c->id) { case V4L2_CID_BRIGHTNESS: { u32 value = saa7146_read(dev, BCS_CTRL); value &= 0x00ffffff; value |= (c->value << 24); saa7146_write(dev, BCS_CTRL, value); saa7146_write(dev, MC2, MASK_22 | MASK_06 ); break; } case V4L2_CID_CONTRAST: { u32 value = saa7146_read(dev, BCS_CTRL); value &= 0xff00ffff; value |= (c->value << 16); saa7146_write(dev, BCS_CTRL, value); saa7146_write(dev, MC2, MASK_22 | MASK_06 ); break; } case V4L2_CID_SATURATION: { u32 value = saa7146_read(dev, BCS_CTRL); value &= 0xffffff00; value |= (c->value << 0); saa7146_write(dev, BCS_CTRL, value); saa7146_write(dev, MC2, MASK_22 | MASK_06 ); break; } case V4L2_CID_HFLIP: /* fixme: we can supfhrt changing VFLIP and HFLIP here... */ if( 0 != vv->streaming ) { DEB_D(("V4L2_CID_HFLIP while active capture.\n")); return -EINVAL; } vv->hflip = c->value; restart_overlay = 1; break; case V4L2_CID_VFLIP: if( 0 != vv->streaming ) { DEB_D(("V4L2_CID_VFLIP while active capture.\n")); return -EINVAL; } vv->vflip = c->value; restart_overlay = 1; break; default: { return -EINVAL; } } if( 0 != restart_overlay ) { if( 0 != vv->ov_data ) { if( fh == vv->ov_data->fh ) { spin_lock_irqsave(&dev->slock,flags); saa7146_stop_preview(fh); saa7146_start_preview(fh); spin_unlock_irqrestore(&dev->slock,flags); } } } return 0;}/********************************************************************************//* common pagetable functions */static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf){ struct pci_dev *pci = dev->pci; struct scatterlist *list = buf->vb.dma.sglist; int length = buf->vb.dma.sglen; struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat); DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length)); if( 0 != IS_PLANAR(sfmt->trans)) { struct saa7146_pgtable *pt1 = &buf->pt[0]; struct saa7146_pgtable *pt2 = &buf->pt[1]; struct saa7146_pgtable *pt3 = &buf->pt[2]; u32 *ptr1, *ptr2, *ptr3; u32 fill; int size = buf->fmt->width*buf->fmt->height; int i,p,m1,m2,m3,o1,o2; switch( sfmt->depth ) { case 12: { /* create some offsets inside the page table */ m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; m2 = ((size+(size/4)+PAGE_SIZE)/PAGE_SIZE)-1; m3 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; o1 = size%PAGE_SIZE; o2 = (size+(size/4))%PAGE_SIZE; DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); break; } case 16: { /* create some offsets inside the page table */ m1 = ((size+PAGE_SIZE)/PAGE_SIZE)-1; m2 = ((size+(size/2)+PAGE_SIZE)/PAGE_SIZE)-1; m3 = ((2*size+PAGE_SIZE)/PAGE_SIZE)-1; o1 = size%PAGE_SIZE; o2 = (size+(size/2))%PAGE_SIZE; DEB_CAP(("size:%d, m1:%d, m2:%d, m3:%d, o1:%d, o2:%d\n",size,m1,m2,m3,o1,o2)); break; } default: { return -1; } } ptr1 = pt1->cpu; ptr2 = pt2->cpu; ptr3 = pt3->cpu; /* walk all pages, copy all page addresses to ptr1 */ for (i = 0; i < length; i++, list++) { for (p = 0; p * 4096 < list->length; p++, ptr1++) { *ptr1 = sg_dma_address(list) - list->offset; } }/* ptr1 = pt1->cpu; for(j=0;j<40;j++) { printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); }*/ /* if we have a user buffer, the first page may not be aligned to a page boundary. */ pt1->offset = buf->vb.dma.sglist->offset; pt2->offset = pt1->offset+o1; pt3->offset = pt1->offset+o2; /* create video-dma2 page table */ ptr1 = pt1->cpu; for(i = m1; i <= m2 ; i++, ptr2++) { *ptr2 = ptr1[i]; } fill = *(ptr2-1); for(;i<1024;i++,ptr2++) { *ptr2 = fill; } /* create video-dma3 page table */ ptr1 = pt1->cpu; for(i = m2; i <= m3; i++,ptr3++) { *ptr3 = ptr1[i]; } fill = *(ptr3-1); for(;i<1024;i++,ptr3++) { *ptr3 = fill; } /* finally: finish up video-dma1 page table */ ptr1 = pt1->cpu+m1; fill = pt1->cpu[m1]; for(i=m1;i<1024;i++,ptr1++) { *ptr1 = fill; }/* ptr1 = pt1->cpu; ptr2 = pt2->cpu; ptr3 = pt3->cpu; for(j=0;j<40;j++) { printk("ptr1 %d: 0x%08x\n",j,ptr1[j]); } for(j=0;j<40;j++) { printk("ptr2 %d: 0x%08x\n",j,ptr2[j]); } for(j=0;j<40;j++) { printk("ptr3 %d: 0x%08x\n",j,ptr3[j]); }*/ } else { struct saa7146_pgtable *pt = &buf->pt[0]; return saa7146_pgtable_build_single(pci, pt, list, length); } return 0;}/********************************************************************************//* file operations */static int video_begin(struct saa7146_fh *fh){ struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; struct saa7146_format *fmt = NULL; unsigned long flags; unsigned int resource; int ret = 0; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); if( fh == vv->streaming ) { DEB_S(("already capturing.\n")); return -EBUSY; } if( vv->streaming != 0 ) { DEB_S(("already capturing, but in another open.\n")); return -EBUSY; } fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); /* we need to have a valid format set here */ BUG_ON(NULL == fmt); if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; } else { resource = RESOURCE_DMA1_HPS; } ret = saa7146_res_get(fh, resource); if (0 == ret) { DEB_S(("cannot get capture resource %d\n",resource)); return -EBUSY; } spin_lock_irqsave(&dev->slock,flags); /* clear out beginning of streaming bit (rps register 0)*/ saa7146_write(dev, MC2, MASK_27 ); /* enable rps0 irqs */ IER_ENABLE(dev, MASK_27); vv->streaming = fh; spin_unlock_irqrestore(&dev->slock,flags); return 0;}static int video_end(struct saa7146_fh *fh, struct file *file){ struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; struct saa7146_format *fmt = NULL; unsigned long flags; unsigned int resource; u32 dmas = 0; DEB_EE(("dev:%p, fh:%p\n",dev,fh)); if( vv->streaming != fh ) { DEB_S(("not capturing.\n")); return -EINVAL; } fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat); /* we need to have a valid format set here */ BUG_ON(NULL == fmt); if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { resource = RESOURCE_DMA1_HPS|RESOURCE_DMA2_CLP|RESOURCE_DMA3_BRS; dmas = MASK_22 | MASK_21 | MASK_20; } else { resource = RESOURCE_DMA1_HPS; dmas = MASK_22; } saa7146_res_free(fh, resource); spin_lock_irqsave(&dev->slock,flags); /* disable rps0 */ saa7146_write(dev, MC1, MASK_28); /* disable rps0 irqs */ IER_DISABLE(dev, MASK_27); /* shut down all used video dma transfers */ saa7146_write(dev, MC1, dmas); vv->streaming = NULL; spin_unlock_irqrestore(&dev->slock, flags); return 0;}/* * This function is _not_ called directly, but from * video_generic_ioctl (and maybe others). userspace * copying is done already, arg is a kernel pointer. */int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; unsigned long flags; int err = 0, result = 0, ee = 0; struct saa7146_use_ops *ops; struct videobuf_queue *q; /* check if extension handles the command */ for(ee = 0; dev->ext_vv_data->ioctls[ee].flags != 0; ee++) { if( cmd == dev->ext_vv_data->ioctls[ee].cmd ) break; } if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_EXCLUSIVE) ) { DEB_D(("extension handles ioctl exclusive.\n")); result = dev->ext_vv_data->ioctl(fh, cmd, arg); return result; } if( 0 != (dev->ext_vv_data->ioctls[ee].flags & SAA7146_BEFORE) ) { DEB_D(("extension handles ioctl before.\n")); result = dev->ext_vv_data->ioctl(fh, cmd, arg); if( -EAGAIN != result ) { return result; } } /* fixme: add handle "after" case (is it still needed?) */ switch (fh->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: { ops = &saa7146_video_uops; q = &fh->video_q; break; } case V4L2_BUF_TYPE_VBI_CAPTURE: { ops = &saa7146_vbi_uops; q = &fh->vbi_q; break; } default: BUG(); return 0; } switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); DEB_EE(("VIDIOC_QUERYCAP\n")); strcpy(cap->driver, "saa7146 v4l2"); strlcpy(cap->card, dev->ext->name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",dev->pci->slot_name); cap->version = SAA7146_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; cap->capabilities |= dev->ext_vv_data->capabilities; return 0; } case VIDIOC_G_FBUF: { struct v4l2_framebuffer *fb = arg; DEB_EE(("VIDIOC_G_FBUF\n")); *fb = vv->ov_fb; fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; return 0; } case VIDIOC_S_FBUF: { struct v4l2_framebuffer *fb = arg; struct saa7146_format *fmt; struct saa7146_fh *ov_fh = NULL; int restart_overlay = 0; DEB_EE(("VIDIOC_S_FBUF\n"));/* if(!capable(CAP_SYS_ADMIN)) { // && !capable(CAP_SYS_RAWIO)) { DEB_D(("VIDIOC_S_FBUF: not CAP_SYS_ADMIN or CAP_SYS_RAWIO.\n")); return -EPERM; }*/ /* check args */ fmt = format_by_fourcc(dev,fb->fmt.pixelformat); if (NULL == fmt) { return -EINVAL; } /* planar formats are not allowed for overlay video, clipping and video dma would clash */ if (0 != (fmt->flags & FORMAT_IS_PLANAR)) { DEB_S(("planar pixelformat '%4.4s' not allowed for overlay\n",(char *)&fmt->pixelformat)); } down(&dev->lock); if( vv->ov_data != NULL ) { ov_fh = vv->ov_data->fh; saa7146_stop_preview(ov_fh); restart_overlay = 1; } /* ok, accept it */ vv->ov_fb = *fb; vv->ov_fmt = fmt; if (0 == vv->ov_fb.fmt.bytesperline) vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width*fmt->depth/8; if( 0 != restart_overlay ) { saa7146_start_preview(ov_fh); } up(&dev->lock); return 0; } case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; int index; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OVERLAY: { index = f->index; if (index < 0 || index >= NUM_FORMATS) { return -EINVAL; } memset(f,0,sizeof(*f)); f->index = index; strlcpy(f->description,formats[index].name,sizeof(f->description)); f->pixelformat = formats[index].pixelformat; break; } default: return -EINVAL; } DEB_EE(("VIDIOC_ENUM_FMT: type:%d, index:%d\n",f->type,f->index)); return 0; } case VIDIOC_QUERYCTRL: { const struct v4l2_queryctrl *ctrl; struct v4l2_queryctrl *c = arg; if ((c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) && (c->id < V4L2_CID_PRIVATE_BASE || c->id >= V4L2_CID_PRIVATE_LASTP1)) return -EINVAL; ctrl = ctrl_by_id(c->id); if( NULL == ctrl ) { return -EINVAL;/* c->flags = V4L2_CTRL_FLAG_DISABLED; return 0;*/ } DEB_EE(("VIDIOC_QUERYCTRL: id:%d\n",c->id)); *c = *ctrl; return 0; } case VIDIOC_G_CTRL: { DEB_EE(("VIDIOC_G_CTRL\n")); return get_control(fh,arg); } case VIDIOC_S_CTRL:/* FIXME: remove when videodev2.h update is in kernel */#ifdef VIDIOC_S_CTRL_OLD case VIDIOC_S_CTRL_OLD:#endif { DEB_EE(("VIDIOC_S_CTRL\n")); down(&dev->lock); err = set_control(fh,arg); up(&dev->lock); return err; } case VIDIOC_G_PARM: { struct v4l2_streamparm *parm = arg; if( parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ) { return -EINVAL; } memset(&parm->parm.capture,0,sizeof(struct v4l2_captureparm)); parm->parm.capture.readbuffers = 1; // fixme: only for PAL! parm->parm.capture.timeperframe.numerator = 1; parm->parm.capture.timeperframe.denominator = 25; return 0; } case VIDIOC_G_FMT: { struct v4l2_format *f = arg; DEB_EE(("VIDIOC_G_FMT\n")); return g_fmt(fh,f); } case VIDIOC_S_FMT: { struct v4l2_format *f = arg; DEB_EE(("VIDIOC_S_FMT\n")); return s_fmt(fh,f); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -