📄 bttv.c
字号:
} interruptible_sleep_on(&btv->vbiq); sti(); if(signal_pending(current)) { if(todo==count) return -EINTR; else return count-todo; } } } if (todo) { if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) return -EFAULT; btv->vbip+=todo; } return count;}/* * Open a bttv card. Right now the flags stuff is just playing */ static int bttv_open(struct video_device *dev, int flags){ struct bttv *btv = (struct bttv *)dev; int users, i; if (btv->user) return -EBUSY; audio(btv, AUDIO_UNMUTE); for (i=users=0; i<bttv_num; i++) users+=bttvs[i].user; if (users==1) find_vga(); btv->fbuffer=NULL; if (!btv->fbuffer) btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF); if (!btv->fbuffer) return -EINVAL; btv->grabbing = 0; btv->grab = 0; btv->lastgrab = 0; for (i = 0; i < MAX_GBUFFERS; i++) btv->frame_stat[i] = GBUFFER_UNUSED; btv->user++; MOD_INC_USE_COUNT; return 0; }static void bttv_close(struct video_device *dev){ struct bttv *btv=(struct bttv *)dev; btv->user--; audio(btv, AUDIO_INTERN); btv->cap&=~3; bt848_set_risc_jmps(btv); /* * A word of warning. At this point the chip * is still capturing because its FIFO hasn't emptied * and the DMA control operations are posted PCI * operations. */ btread(BT848_I2C); /* This fixes the PCI posting delay */ /* * This is sucky but right now I can't find a good way to * be sure its safe to free the buffer. We wait 5-6 fields * which is more than sufficient to be sure. */ current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ/10); /* Wait 1/10th of a second */ /* * We have allowed it to drain. */ if(btv->fbuffer) rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF); btv->fbuffer=0; MOD_DEC_USE_COUNT; }/***********************************//* ioctls and supporting functions *//***********************************/extern inline void bt848_bright(struct bttv *btv, uint bright){ btwrite(bright&0xff, BT848_BRIGHT);}extern inline void bt848_hue(struct bttv *btv, uint hue){ btwrite(hue&0xff, BT848_HUE);}extern inline void bt848_contrast(struct bttv *btv, uint cont){ unsigned int conthi; conthi=(cont>>6)&4; btwrite(cont&0xff, BT848_CONTRAST_LO); btaor(conthi, ~4, BT848_E_CONTROL); btaor(conthi, ~4, BT848_O_CONTROL);}extern inline void bt848_sat_u(struct bttv *btv, unsigned long data){ u32 datahi; datahi=(data>>7)&2; btwrite(data&0xff, BT848_SAT_U_LO); btaor(datahi, ~2, BT848_E_CONTROL); btaor(datahi, ~2, BT848_O_CONTROL);}static inline void bt848_sat_v(struct bttv *btv, unsigned long data){ u32 datahi; datahi=(data>>8)&1; btwrite(data&0xff, BT848_SAT_V_LO); btaor(datahi, ~1, BT848_E_CONTROL); btaor(datahi, ~1, BT848_O_CONTROL);}/* * ioctl routine */ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg){ unsigned char eedata[256]; struct bttv *btv=(struct bttv *)dev; int i; switch (cmd) { case VIDIOCGCAP: { struct video_capability b; strcpy(b.name,btv->video_dev.name); b.type = VID_TYPE_CAPTURE| VID_TYPE_TUNER| VID_TYPE_TELETEXT| VID_TYPE_OVERLAY| VID_TYPE_CLIPPING| VID_TYPE_FRAMERAM| VID_TYPE_SCALES; b.channels = tvcards[btv->type].video_inputs; b.audios = tvcards[btv->type].audio_inputs; b.maxwidth = tvnorms[btv->win.norm].swidth; b.maxheight = tvnorms[btv->win.norm].sheight; b.minwidth = 32; 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>=tvcards[btv->type].video_inputs) return -EINVAL; if(v.channel==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==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>tvcards[btv->type].video_inputs) return -EINVAL; bt848_muxsel(btv, v.channel); if(v.norm!=VIDEO_MODE_PAL&&v.norm!=VIDEO_MODE_NTSC &&v.norm!=VIDEO_MODE_SECAM) return -EOPNOTSUPP; btv->win.norm = v.norm; make_vbitab(btv); bt848_set_winsize(btv); btv->channel=v.channel; return 0; } case VIDIOCGTUNER: { struct video_tuner v; if(copy_from_user(&v,arg,sizeof(v))!=0) return -EFAULT; if(v.tuner||btv->channel) /* Only tuner 0 */ return -EINVAL; strcpy(v.name, "Television"); v.rangelow=0; v.rangehigh=0xFFFFFFFF; v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; if (btv->audio_chip == TDA9840) { v.flags |= VIDEO_AUDIO_VOLUME; v.mode = VIDEO_SOUND_MONO|VIDEO_SOUND_STEREO; v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; } if (btv->audio_chip == TDA9850) { unsigned char ALR1; ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1); if (ALR1 & 32) v.flags |= VIDEO_TUNER_STEREO_ON; } v.mode = btv->win.norm; v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; 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!=tvcards[btv->type].tuner) return -EINVAL; if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC &&v.mode!=VIDEO_MODE_SECAM) return -EOPNOTSUPP; btv->win.norm = v.mode; bt848_set_winsize(btv); return 0; } case VIDIOCGPICT: { struct video_picture p=btv->picture; if(btv->win.depth==8) p.palette=VIDEO_PALETTE_HI240; if(btv->win.depth==15) p.palette=VIDEO_PALETTE_RGB555; if(btv->win.depth==16) p.palette=VIDEO_PALETTE_RGB565; if(btv->win.depth==24) p.palette=VIDEO_PALETTE_RGB24; if(btv->win.depth==32) p.palette=VIDEO_PALETTE_RGB32; if(copy_to_user(arg, &p, sizeof(p))) return -EFAULT; return 0; } case VIDIOCSPICT: { struct video_picture p; int format; if(copy_from_user(&p, arg,sizeof(p))) return -EFAULT; /* 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; /* set palette if bpp matches */ if (p.palette < sizeof(palette2fmt)/sizeof(int)) { format = palette2fmt[p.palette]; if (fmtbppx2[format&0x0f]/2 == btv->win.bpp) btv->win.color_fmt = format; } return 0; } case VIDIOCSWIN: { struct video_window vw; struct video_clip *vcp = NULL; int on; if(copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; if(vw.flags || vw.width < 16 || vw.height < 16) { bt848_cap(btv,0); return -EINVAL; } if (btv->win.bpp < 4) { /* 32-bit align start and adjust width */ int i = vw.x; vw.x = (vw.x + 3) & ~3; i = vw.x - i; vw.width -= i; } btv->win.x=vw.x; btv->win.y=vw.y; btv->win.width=vw.width; btv->win.height=vw.height; if(btv->win.height>btv->win.cropheight/2) btv->win.interlace=1; else btv->win.interlace=0; on=(btv->cap&3); bt848_cap(btv,0); bt848_set_winsize(btv); /* * Do any clips. */ if(vw.clipcount<0) { if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) return -ENOMEM; if(copy_from_user(vcp, vw.clips, VIDEO_CLIPMAP_SIZE)) { vfree(vcp); return -EFAULT; } } else if (vw.clipcount) { if((vcp=vmalloc(sizeof(struct video_clip)* (vw.clipcount))) == NULL) return -ENOMEM; if(copy_from_user(vcp,vw.clips, sizeof(struct video_clip)* vw.clipcount)) { vfree(vcp); return -EFAULT; } } make_clip_tab(btv, vcp, vw.clipcount); if (vw.clipcount != 0) vfree(vcp); if(on && btv->win.vidadr!=0) bt848_cap(btv,1); return 0; } case VIDIOCGWIN: { struct video_window vw; /* Oh for a COBOL move corresponding .. */ vw.x=btv->win.x; vw.y=btv->win.y; vw.width=btv->win.width; vw.height=btv->win.height; vw.chromakey=0; vw.flags=0; 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(v==0) { bt848_cap(btv,0); } else { if(btv->win.vidadr==0 || btv->win.width==0 || btv->win.height==0) return -EINVAL; bt848_cap(btv,1); } 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 LINUX_VERSION_CODE >= 0x020100 if(!capable(CAP_SYS_ADMIN))#else if(!suser())#endif 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; if (v.base) { if ((unsigned long)v.base&1) btv->win.vidadr=(unsigned long)(PAGE_OFFSET|uvirt_to_bus((unsigned long)v.base)); else 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; 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)); bt848_set_winsize(btv); 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; set_freq(btv, btv->win.freq); 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"); if (btv->audio_chip == TDA9850) { unsigned char ALR1; ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1); v.mode = VIDEO_SOUND_MONO; v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0; v.mode |= (ALR1 & 64) ? VIDEO_SOUND_LANG1:0; } if (btv->have_msp3400) { v.flags|=VIDEO_AUDIO_VOLUME | VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE; i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, MSP_GET_VOLUME,&(v.volume)); i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, MSP_GET_BASS,&(v.bass)); i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, MSP_GET_TREBLE,&(v.treble)); i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, MSP_GET_STEREO,&(v.mode));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -