📄 bttv-driver.c
字号:
case VIDIOCGCAP: { struct video_capability b; strcpy(b.name,btv->video_dev.name); b.type = VID_TYPE_CAPTURE| ((bttv_tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | VID_TYPE_OVERLAY| VID_TYPE_CLIPPING| VID_TYPE_FRAMERAM| VID_TYPE_SCALES; b.channels = bttv_tvcards[btv->type].video_inputs; b.audios = bttv_tvcards[btv->type].audio_inputs; b.maxwidth = tvnorms[btv->win.norm].swidth; b.maxheight = tvnorms[btv->win.norm].sheight; b.minwidth = 48; b.minheight = 32; if(copy_to_user(arg,&b,sizeof(b))) return -EFAULT; return 0; } case VIDIOCGCHAN: { struct video_channel v; if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; v.flags=VIDEO_VC_AUDIO; v.tuners=0; v.type=VIDEO_TYPE_CAMERA; v.norm = btv->win.norm; if (v.channel>=bttv_tvcards[btv->type].video_inputs) return -EINVAL; if(v.channel==bttv_tvcards[btv->type].tuner) { strcpy(v.name,"Television"); v.flags|=VIDEO_VC_TUNER; v.type=VIDEO_TYPE_TV; v.tuners=1; } else if(v.channel==bttv_tvcards[btv->type].svhs) strcpy(v.name,"S-Video"); else sprintf(v.name,"Composite%d",v.channel); if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; } /* * Each channel has 1 tuner */ case VIDIOCSCHAN: { struct video_channel v; if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; if (v.channel>bttv_tvcards[btv->type].video_inputs) return -EINVAL; if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms))) return -EOPNOTSUPP; bttv_call_i2c_clients(btv,cmd,&v); down(&btv->lock); bt848_muxsel(btv, v.channel); btv->channel=v.channel; if (btv->win.norm != v.norm) { btv->win.norm = v.norm; make_vbitab(btv); spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_winsize(btv); spin_unlock_irqrestore(&btv->s_lock, irq_flags); } up(&btv->lock); return 0; } case VIDIOCGTUNER: { struct video_tuner v; if(copy_from_user(&v,arg,sizeof(v))!=0) return -EFAULT;#if 0 /* tuner.signal might be of intrest for non-tuner sources too ... */ if(v.tuner||btv->channel) /* Only tuner 0 */ return -EINVAL;#endif strcpy(v.name, "Television"); v.rangelow=0; v.rangehigh=0xFFFFFFFF; v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; v.mode = btv->win.norm; v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; bttv_call_i2c_clients(btv,cmd,&v); if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; } /* We have but one tuner */ case VIDIOCSTUNER: { struct video_tuner v; if(copy_from_user(&v, arg, sizeof(v))) return -EFAULT; /* Only one channel has a tuner */ if(v.tuner!=bttv_tvcards[btv->type].tuner) return -EINVAL; if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC &&v.mode!=VIDEO_MODE_SECAM) return -EOPNOTSUPP; bttv_call_i2c_clients(btv,cmd,&v); if (btv->win.norm != v.mode) { btv->win.norm = v.mode; down(&btv->lock); set_pll(btv); make_vbitab(btv); spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_winsize(btv); spin_unlock_irqrestore(&btv->s_lock, irq_flags); up(&btv->lock); } return 0; } case VIDIOCGPICT: { struct video_picture p=btv->picture; if(copy_to_user(arg, &p, sizeof(p))) return -EFAULT; return 0; } case VIDIOCSPICT: { struct video_picture p; if(copy_from_user(&p, arg,sizeof(p))) return -EFAULT; if (p.palette > PALETTEFMT_MAX) return -EINVAL; down(&btv->lock); /* We want -128 to 127 we get 0-65535 */ bt848_bright(btv, (p.brightness>>8)-128); /* 0-511 for the colour */ bt848_sat_u(btv, p.colour>>7); bt848_sat_v(btv, ((p.colour>>7)*201L)/237); /* -128 to 127 */ bt848_hue(btv, (p.hue>>8)-128); /* 0-511 */ bt848_contrast(btv, p.contrast>>7); btv->picture = p; up(&btv->lock); return 0; } case VIDIOCSWIN: { struct video_window vw; struct video_clip *vcp = NULL; if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; down(&btv->lock); if(vw.flags || vw.width < 16 || vw.height < 16) { spin_lock_irqsave(&btv->s_lock, irq_flags); btv->scr_on = 0; bt848_set_risc_jmps(btv,-1); spin_unlock_irqrestore(&btv->s_lock, irq_flags); up(&btv->lock); return -EINVAL; } if (btv->win.bpp < 4) { /* adjust and align writes */ vw.x = (vw.x + 3) & ~3; vw.width &= ~3; } if (btv->needs_restart) bt848_restart(btv); btv->win.x=vw.x; btv->win.y=vw.y; btv->win.width=vw.width; btv->win.height=vw.height; spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_risc_jmps(btv,0); bt848_set_winsize(btv); spin_unlock_irqrestore(&btv->s_lock, irq_flags); /* * Do any clips. */ if(vw.clipcount<0) { if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { up(&btv->lock); return -ENOMEM; } if(copy_from_user(vcp, vw.clips, VIDEO_CLIPMAP_SIZE)) { up(&btv->lock); vfree(vcp); return -EFAULT; } } else if (vw.clipcount > 2048) { up(&btv->lock); return -EINVAL; } else if (vw.clipcount) { if((vcp=vmalloc(sizeof(struct video_clip)* (vw.clipcount))) == NULL) { up(&btv->lock); return -ENOMEM; } if(copy_from_user(vcp,vw.clips, sizeof(struct video_clip)* vw.clipcount)) { up(&btv->lock); vfree(vcp); return -EFAULT; } } make_clip_tab(btv, vcp, vw.clipcount); if (vw.clipcount != 0) vfree(vcp); spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_risc_jmps(btv,-1); spin_unlock_irqrestore(&btv->s_lock, irq_flags); up(&btv->lock); return 0; } case VIDIOCGWIN: { struct video_window vw; memset(&vw,0,sizeof(vw)); vw.x=btv->win.x; vw.y=btv->win.y; vw.width=btv->win.width; vw.height=btv->win.height; if(btv->win.interlace) vw.flags|=VIDEO_WINDOW_INTERLACE; if(copy_to_user(arg,&vw,sizeof(vw))) return -EFAULT; return 0; } case VIDIOCCAPTURE: { int v; if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; if(btv->win.vidadr == 0) return -EINVAL; if (btv->win.width==0 || btv->win.height==0) return -EINVAL; if (1 == no_overlay) return -EIO; spin_lock_irqsave(&btv->s_lock, irq_flags); if (v == 1 && btv->win.vidadr != 0) btv->scr_on = 1; if (v == 0) btv->scr_on = 0; bt848_set_risc_jmps(btv,-1); spin_unlock_irqrestore(&btv->s_lock, irq_flags); return 0; } case VIDIOCGFBUF: { struct video_buffer v; v.base=(void *)btv->win.vidadr; v.height=btv->win.sheight; v.width=btv->win.swidth; v.depth=btv->win.depth; v.bytesperline=btv->win.bpl; if(copy_to_user(arg, &v,sizeof(v))) return -EFAULT; return 0; } case VIDIOCSFBUF: { struct video_buffer v; if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) return -EPERM; if(copy_from_user(&v, arg,sizeof(v))) return -EFAULT; if(v.depth!=8 && v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32 && v.width > 16 && v.height > 16 && v.bytesperline > 16) return -EINVAL; down(&btv->lock); if (v.base) btv->win.vidadr=(unsigned long)v.base; btv->win.sheight=v.height; btv->win.swidth=v.width; btv->win.bpp=((v.depth+7)&0x38)/8; btv->win.depth=v.depth; btv->win.bpl=v.bytesperline;#if 0 /* was broken for ages and nobody noticed. Looks like we don't need it any more as everybody explicitly sets the palette using VIDIOCSPICT these days */ /* set sefault color format */ switch (v.depth) { case 8: btv->picture.palette = VIDEO_PALETTE_HI240; break; case 15: btv->picture.palette = VIDEO_PALETTE_RGB555; break; case 16: btv->picture.palette = VIDEO_PALETTE_RGB565; break; case 24: btv->picture.palette = VIDEO_PALETTE_RGB24; break; case 32: btv->picture.palette = VIDEO_PALETTE_RGB32; break; }#endif if (bttv_debug) printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", v.base, v.width,v.height, btv->win.bpp, btv->win.bpl); spin_lock_irqsave(&btv->s_lock, irq_flags); bt848_set_winsize(btv); spin_unlock_irqrestore(&btv->s_lock, irq_flags); up(&btv->lock); return 0; } case VIDIOCKEY: { /* Will be handled higher up .. */ return 0; } case VIDIOCGFREQ: { unsigned long v=btv->win.freq; if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; } case VIDIOCSFREQ: { unsigned long v; if(copy_from_user(&v, arg, sizeof(v))) return -EFAULT; btv->win.freq=v; bttv_call_i2c_clients(btv,cmd,&v);#if 1 if (btv->radio && btv->has_matchbox) tea5757_set_freq(btv,v);#endif return 0; } case VIDIOCGAUDIO: { struct video_audio v; v=btv->audio_dev; v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); v.flags|=VIDEO_AUDIO_MUTABLE; strcpy(v.name,"TV"); v.mode = VIDEO_SOUND_MONO; bttv_call_i2c_clients(btv,cmd,&v); /* card specific hooks */ if (bttv_tvcards[btv->type].audio_hook) bttv_tvcards[btv->type].audio_hook(btv,&v,0); if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; } case VIDIOCSAUDIO: { struct video_audio v; if(copy_from_user(&v,arg, sizeof(v))) return -EFAULT; down(&btv->lock); if(v.flags&VIDEO_AUDIO_MUTE) audio(btv, AUDIO_MUTE, 1); /* One audio source per tuner -- huh? <GA> */ if(v.audio<0 || v.audio >= bttv_tvcards[btv->type].audio_inputs) { up(&btv->lock); return -EINVAL; } /* bt848_muxsel(btv,v.audio); */ if(!(v.flags&VIDEO_AUDIO_MUTE)) audio(btv, AUDIO_UNMUTE, 1); bttv_call_i2c_clients(btv,cmd,&v); /* card specific hooks */ if (bttv_tvcards[btv->type].audio_hook) bttv_tvcards[btv->type].audio_hook(btv,&v,1); btv->audio_dev=v; up(&btv->lock); return 0; } case VIDIOCSYNC: { DECLARE_WAITQUEUE(wait, current); if(copy_from_user((void *)&i,arg,sizeof(int))) return -EFAULT; if (i < 0 || i >= gbuffers) return -EINVAL; switch (btv->gbuf[i].stat) { case GBUFFER_UNUSED: ret = -EINVAL; break; case GBUFFER_GRABBING: add_wait_queue(&btv->capq, &wait); current->state = TASK_INTERRUPTIBLE; while(btv->gbuf[i].stat==GBUFFER_GRABBING) { if (bttv_debug) printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i); schedule(); if(signal_pending(current)) { remove_wait_queue(&btv->capq, &wait); current->state = TASK_RUNNING; return -EINTR; } } remove_wait_queue(&btv->capq, &wait); current->state = TASK_RUNNING; /* fall throuth */ case GBUFFER_DONE: case GBUFFER_ERROR: ret = (btv->gbuf[i].stat == GBUFFER_ERROR) ? -EIO : 0; if (bttv_debug) printk("bttv%d: cap sync: buffer %d, retval %d\n",btv->nr,i,ret); btv->gbuf[i].stat = GBUFFER_UNUSED; } if (btv->needs_restart) { down(&btv->lock); bt848_restart(btv); up(&btv->lock); } return ret; } case BTTV_FIELDNR: if(copy_to_user((void *) arg, (void *) &btv->last_field, sizeof(btv->last_field))) return -EFAULT; break; case BTTV_PLLSET: { struct bttv_pll_info p; if(!capable(CAP_SYS_ADMIN)) return -EPERM; if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) return -EFAULT; down(&btv->lock); btv->pll.pll_ifreq = p.pll_ifreq; btv->pll.pll_ofreq = p.pll_ofreq; btv->pll.pll_crystal = p.pll_crystal; up(&btv->lock); break; } case VIDIOCMCAPTURE: { struct video_mmap vm; int ret; if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) return -EFAULT; down(&btv->lock); ret = vgrab(btv, &vm); up(&btv->lock); return ret; } case VIDIOCGMBUF: { struct video_mbuf vm; memset(&vm, 0 , sizeof(vm)); vm.size=gbufsize*gbuffers; vm.frames=gbuffers; for (i = 0; i < gbuffers; i++) vm.offsets[i]=i*gbufsize; if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) return -EFAULT; return 0; } case VIDIOCGUNIT: { struct video_unit vu; vu.video=btv->video_dev.minor; vu.vbi=btv->vbi_dev.minor; if(btv->radio_dev.minor!=-1) vu.radio=btv->radio_dev.minor; else vu.radio=VIDEO_NO_UNIT; vu.audio=VIDEO_NO_UNIT; vu.teletext=VIDEO_NO_UNIT; if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) return -EFAULT; return 0; } case BTTV_BURST_ON: { burst(1); return 0; } case BTTV_BURST_OFF: { burst(0); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -