📄 zr36120.c
字号:
v.flags |= VIDEO_VC_TUNER; v.tuners = 1; } } else if (mux & IS_SVHS) sprintf(v.name,"S-Video-%d",v.channel); else sprintf(v.name,"CVBS-%d",v.channel); if (copy_to_user(arg,&v,sizeof(v))) return -EFAULT; break; } case VIDIOCSCHAN: { /* set video channel */ struct video_channel v; if (copy_from_user(&v, arg,sizeof(v))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm)); /* too many inputs? no decoder -> no channels */ if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs || v.channel < 0) return -EINVAL; if (v.norm != VIDEO_MODE_PAL && v.norm != VIDEO_MODE_NTSC && v.norm != VIDEO_MODE_SECAM && v.norm != VIDEO_MODE_AUTO) return -EOPNOTSUPP; /* make it happen, nr1! */ return zoran_muxsel(ztv,v.channel,v.norm); } case VIDIOCGTUNER: { struct video_tuner v; if (copy_from_user(&v, arg,sizeof(v))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner)); /* Only no or one tuner for now */ if (!ztv->have_tuner || v.tuner) return -EINVAL; strcpy(v.name,"Television"); v.rangelow = 0; v.rangehigh = ~0; v.flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; v.mode = ztv->norm; v.signal = 0xFFFF; /* unknown */ if (copy_to_user(arg,&v,sizeof(v))) return -EFAULT; break; } case VIDIOCSTUNER: { struct video_tuner v; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode)); /* Only no or one tuner for now */ if (!ztv->have_tuner || v.tuner) return -EINVAL; /* and it only has certain valid modes */ if( v.mode != VIDEO_MODE_PAL && v.mode != VIDEO_MODE_NTSC && v.mode != VIDEO_MODE_SECAM) return -EOPNOTSUPP; /* engage! */ return zoran_muxsel(ztv,v.tuner,v.mode); } case VIDIOCGPICT: { struct video_picture p = ztv->picture; DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD)); p.depth = ztv->depth; switch (p.depth) { case 8: p.palette=VIDEO_PALETTE_YUV422; break; case 15: p.palette=VIDEO_PALETTE_RGB555; break; case 16: p.palette=VIDEO_PALETTE_RGB565; break; case 24: p.palette=VIDEO_PALETTE_RGB24; break; case 32: p.palette=VIDEO_PALETTE_RGB32; break; } if (copy_to_user(arg, &p, sizeof(p))) return -EFAULT; break; } case VIDIOCSPICT: { struct video_picture p; if (copy_from_user(&p, arg,sizeof(p))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette)); /* depth must match with framebuffer */ if (p.depth != ztv->depth) return -EINVAL; /* check if palette matches this bpp */ if (p.palette>NRPALETTES || palette2fmt[p.palette].bpp != ztv->overinfo.bpp) return -EINVAL; write_lock_irq(&ztv->lock); ztv->overinfo.format = p.palette; ztv->picture = p; write_unlock_irq(&ztv->lock); /* tell the decoder */ i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); break; } case VIDIOCGWIN: { struct video_window vw; DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD)); read_lock(&ztv->lock); vw.x = ztv->overinfo.x; vw.y = ztv->overinfo.y; vw.width = ztv->overinfo.w; vw.height = ztv->overinfo.h; vw.chromakey= 0; vw.flags = 0; if (ztv->vidInterlace) vw.flags|=VIDEO_WINDOW_INTERLACE; read_unlock(&ztv->lock); if (copy_to_user(arg,&vw,sizeof(vw))) return -EFAULT; break; } case VIDIOCSWIN: { struct video_window vw; struct video_clip *vcp; int on; if (copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount)); if (vw.flags) return -EINVAL; if (vw.clipcount <0 || vw.clipcount>256) return -EDOM; /* Too many! */ /* * Do any clips. */ vcp = vmalloc(sizeof(struct video_clip)*(vw.clipcount+4)); if (vcp==NULL) return -ENOMEM; if (vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) { vfree(vcp); return -EFAULT; } on = ztv->running; if (on) zoran_cap(ztv, 0); /* * strange, it seems xawtv sometimes calls us with 0 * width and/or height. Ignore these values */ if (vw.x == 0) vw.x = ztv->overinfo.x; if (vw.y == 0) vw.y = ztv->overinfo.y; /* by now we are committed to the new data... */ write_lock_irq(&ztv->lock); ztv->overinfo.x = vw.x; ztv->overinfo.y = vw.y; ztv->overinfo.w = vw.width; ztv->overinfo.h = vw.height; write_unlock_irq(&ztv->lock); /* * Impose display clips */ if (vw.x+vw.width > ztv->swidth) new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1); if (vw.y+vw.height > ztv->sheight) new_clip(&vw, vcp, 0, ztv->sheight-vw.y, vw.width-1, vw.height-1); /* built the requested clipping zones */ zoran_set_geo(ztv, &ztv->overinfo); zoran_built_overlay(ztv, vw.clipcount, vcp); vfree(vcp); /* if we were on, restart the video engine */ if (on) zoran_cap(ztv, 1); break; } case VIDIOCCAPTURE: { int v; if (get_user(v, (int *)arg)) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v)); if (v==0) { clear_bit(STATE_OVERLAY, &ztv->state); zoran_cap(ztv, 1); } else { /* is VIDIOCSFBUF, VIDIOCSWIN done? */ if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0) return -EINVAL; set_bit(STATE_OVERLAY, &ztv->state); zoran_cap(ztv, 1); } break; } case VIDIOCGFBUF: { struct video_buffer v; DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD)); read_lock(&ztv->lock); v.base = (void *)ztv->overinfo.busadr; v.height = ztv->sheight; v.width = ztv->swidth; v.depth = ztv->depth; v.bytesperline = ztv->overinfo.bpl; read_unlock(&ztv->lock); if(copy_to_user(arg, &v,sizeof(v))) return -EFAULT; break; } case VIDIOCSFBUF: { struct video_buffer v; if(!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&v, arg,sizeof(v))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline)); if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32) return -EINVAL; if (v.bytesperline<1) return -EINVAL; if (ztv->running) return -EBUSY; write_lock_irq(&ztv->lock); ztv->overinfo.busadr = (ulong)v.base; ztv->sheight = v.height; ztv->swidth = v.width; ztv->depth = v.depth; /* bits per pixel */ ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */ ztv->overinfo.bpl = v.bytesperline; /* bytes per line */ write_unlock_irq(&ztv->lock); break; } case VIDIOCKEY: { /* Will be handled higher up .. */ break; } case VIDIOCSYNC: { int i; if (get_user(i, (int *) arg)) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i)); if (i<0 || i>ZORAN_MAX_FBUFFERS) return -EINVAL; switch (ztv->grabinfo[i].status) { case FBUFFER_FREE: return -EINVAL; case FBUFFER_BUSY: /* wait till this buffer gets grabbed */ wait_event_interruptible(ztv->grabq, (ztv->grabinfo[i].status != FBUFFER_BUSY)); /* see if a signal did it */ if (signal_pending(current)) return -EINTR; /* don't fall through; a DONE buffer is not UNUSED */ break; case FBUFFER_DONE: ztv->grabinfo[i].status = FBUFFER_FREE; /* tell ppl we have a spare buffer */ wake_up_interruptible(&ztv->grabq); break; } DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i)); break; } case VIDIOCMCAPTURE: { struct video_mmap vm; struct vidinfo* frame; if (copy_from_user(&vm,arg,sizeof(vm))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format)); if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS || vm.width<32 || vm.width>768 || vm.height<32 || vm.height>576 || vm.format>NRPALETTES || palette2fmt[vm.format].mode == 0) return -EINVAL; /* we are allowed to take over UNUSED and DONE buffers */ frame = &ztv->grabinfo[vm.frame]; if (frame->status == FBUFFER_BUSY) return -EBUSY; /* setup the other parameters if they are given */ write_lock_irq(&ztv->lock); frame->w = vm.width; frame->h = vm.height; frame->format = vm.format; frame->bpp = palette2fmt[frame->format].bpp; frame->bpl = frame->w*frame->bpp; frame->status = FBUFFER_BUSY; frame->next = 0; { /* add to tail of queue */ struct vidinfo* oldframe = ztv->workqueue; if (!oldframe) ztv->workqueue = frame; else { while (oldframe->next) oldframe = oldframe->next; oldframe->next = frame; } } write_unlock_irq(&ztv->lock); zoran_cap(ztv, 1); break; } case VIDIOCGMBUF: { struct video_mbuf mb; int i; DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD)); mb.size = ZORAN_MAX_FBUFSIZE; mb.frames = ZORAN_MAX_FBUFFERS; for (i=0; i<ZORAN_MAX_FBUFFERS; i++) mb.offsets[i] = i*ZORAN_MAX_FBUFFER; if(copy_to_user(arg, &mb,sizeof(mb))) return -EFAULT; break; } case VIDIOCGUNIT: { struct video_unit vu; DEBUG(printk(CARD_DEBUG "VIDIOCGUNIT\n",CARD)); vu.video = ztv->video_dev.minor; vu.vbi = ztv->vbi_dev.minor; vu.radio = VIDEO_NO_UNIT; vu.audio = VIDEO_NO_UNIT; vu.teletext = VIDEO_NO_UNIT; if(copy_to_user(arg, &vu,sizeof(vu))) return -EFAULT; break; } case VIDIOCGFREQ: { unsigned long v = ztv->tuner_freq; if (copy_to_user(arg,&v,sizeof(v))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD)); break; } case VIDIOCSFREQ: { unsigned long v; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD)); if (ztv->have_tuner) { int fixme = v; if (i2c_control_device(&(ztv->i2c), I2C_DRIVERID_TUNER, TUNER_SET_TVFREQ, &fixme) < 0) return -EAGAIN; } ztv->tuner_freq = v; break; } /* Why isn't this in the API? * And why doesn't it take a buffer number? case BTTV_FIELDNR: { unsigned long v = ztv->lastfieldnr; if (copy_to_user(arg,&v,sizeof(v))) return -EFAULT; DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD)); break; } */ default: return -ENOIOCTLCMD; } return 0;}staticint zoran_mmap(struct vm_area_struct *vma, struct video_device* dev, const char* adr, unsigned long size){ struct zoran* ztv = (struct zoran*)dev; unsigned long start = (unsigned long)adr; unsigned long pos; DEBUG(printk(CARD_DEBUG "zoran_mmap(0x%p,%ld)\n",CARD,adr,size)); /* sanity checks */ if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer) return -EINVAL; /* start mapping the whole shabang to user memory */ pos = (unsigned long)ztv->fbuffer; while (size>0) { unsigned long pfn = virt_to_phys((void*)pos) >> PAGE_SHIFT; if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; start += PAGE_SIZE; pos += PAGE_SIZE; size -= PAGE_SIZE; } return 0;}static struct video_device zr36120_template={ .owner = THIS_MODULE, .name = "UNSET", .type = VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY, .hardware = VID_HARDWARE_ZR36120, .open = zoran_open, .close = zoran_close, .read = zoran_read, .write = zoran_write, .poll = zoran_poll, .ioctl = zoran_ioctl, .mmap = zoran_mmap, .minor = -1,};staticint vbi_open(struct video_device *dev, int flags){ struct zoran *ztv = dev->priv; struct vidinfo* item; DEBUG(printk(CARD_DEBUG "vbi_open(dev,%d)\n",CARD,flags)); /* * During VBI device open, we continiously grab VBI-like * data in the vbi buffer when we have nothing to do. * Only when there is an explicit request for VBI data * (read call) we /force/ a read. */ /* allocate buffers */ for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) { item->status = FBUFFER_FREE; /* alloc */ if (!item->memadr) { item->memadr = bmalloc(ZORAN_VBI_BUFSIZE); if (!item->memadr) { /* could not get a buffer, bail out */ while (item != ztv->readinfo) { item--; bfree(item->memadr, ZORAN_VBI_BUFSIZE); item->memadr = 0; item->busadr = 0; } return -ENOBUFS; } } /* determine the DMAable address */ item->busadr = virt_to_bus(item->memadr); } /* do the common part of all open's */ zoran_common_open(ztv, flags); set_bit(STATE_VBI, &ztv->state); /* start read-ahead */ zoran_cap(ztv, 1); return 0;}staticvoid vbi_close(struct video_device *dev){ struct zoran *ztv = dev->priv; struct vidinfo* item; DEBUG(printk(CARD_DEBUG "vbi_close(dev)\n",CARD)); /* driver specific closure */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -