📄 bttv.c
字号:
} else v.mode = VIDEO_SOUND_MONO; 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; if(v.flags&VIDEO_AUDIO_MUTE) audio(btv, AUDIO_MUTE); /* One audio source per tuner */ /* if(v.audio!=0) */ /* ADSTech TV card has more than one */ if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) return -EINVAL; bt848_muxsel(btv,v.audio); if(!(v.flags&VIDEO_AUDIO_MUTE)) audio(btv, AUDIO_UNMUTE); if (btv->audio_chip == TDA9850) { unsigned char con3 = 0; if (v.mode & VIDEO_SOUND_LANG1) con3 = 0x80; /* sap */ if (v.mode & VIDEO_SOUND_STEREO) con3 = 0x40; /* stereo */ I2CWrite(&(btv->i2c), I2C_TDA9850, TDA9850_CON3, con3, 1); } if (btv->have_msp3400) { i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, MSP_SET_VOLUME,&(v.volume)); i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, MSP_SET_BASS,&(v.bass)); i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, MSP_SET_TREBLE,&(v.treble)); i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, MSP_SET_STEREO,&(v.mode)); } btv->audio_dev=v; return 0; } case VIDIOCSYNC: if(copy_from_user((void *)&i,arg,sizeof(int))) return -EFAULT;/* if(i>1 || i<0) return -EINVAL;*/ switch (btv->frame_stat[i]) { case GBUFFER_UNUSED: return -EINVAL; case GBUFFER_GRABBING: while(btv->frame_stat[i]==GBUFFER_GRABBING) { interruptible_sleep_on(&btv->capq); if(signal_pending(current)) return -EINTR; } /* fall */ case GBUFFER_DONE: btv->frame_stat[i] = GBUFFER_UNUSED; break; } return 0; case BTTV_WRITEE:#if LINUX_VERSION_CODE >= 0x020100 if(!capable(CAP_SYS_ADMIN))#else if(!suser())#endif return -EPERM; if(copy_from_user((void *) eedata, (void *) arg, 256)) return -EFAULT; writeee(&(btv->i2c), eedata); return 0; case BTTV_READEE:#if LINUX_VERSION_CODE >= 0x020100 if(!capable(CAP_SYS_ADMIN))#else if(!suser())#endif return -EPERM; readee(&(btv->i2c), eedata); if(copy_to_user((void *) arg, (void *) eedata, 256)) return -EFAULT; break; 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 LINUX_VERSION_CODE >= 0x020100 if(!capable(CAP_SYS_ADMIN))#else if(!suser())#endif return -EPERM; if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) return -EFAULT; btv->pll.pll_ifreq = p.pll_ifreq; btv->pll.pll_ofreq = p.pll_ofreq; btv->pll.pll_crystal = p.pll_crystal; break; } case VIDIOCMCAPTURE: { struct video_mmap vm; if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) return -EFAULT; if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING) return -EBUSY; return vgrab(btv, &vm); } case VIDIOCGMBUF: { struct video_mbuf vm; memset(&vm, 0 , sizeof(vm)); vm.size=BTTV_MAX_FBUF*2; vm.frames=2; vm.offsets[0]=0; vm.offsets[1]=BTTV_MAX_FBUF; 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; if(btv->have_msp3400) { i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, MSP_GET_UNIT, &vu.audio); } vu.teletext=VIDEO_NO_UNIT; if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) return -EFAULT; return 0; } case BTTV_BURST_ON: { tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2; tvnorms[0].hdelayx1=186-BURSTOFFSET; return 0; } case BTTV_BURST_OFF: { tvnorms[0].scaledtwidth=1135; tvnorms[0].hdelayx1=186; return 0; } case BTTV_VERSION: { return BTTV_VERSION_CODE; } case BTTV_PICNR: { /* return picture;*/ return 0; } default: return -ENOIOCTLCMD; } return 0;}static int bttv_init_done(struct video_device *dev){ return 0;}/* * This maps the vmalloced and reserved fbuffer to user space. * * FIXME: * - PAGE_READONLY should suffice!? * - remap_page_range is kind of inefficient for page by page remapping. * But e.g. pte_alloc() does not work in modules ... :-( */ static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size){ struct bttv *btv=(struct bttv *)dev; unsigned long start=(unsigned long) adr; unsigned long page,pos; if (size>2*BTTV_MAX_FBUF) return -EINVAL; if (!btv->fbuffer) { if(fbuffer_alloc(btv)) return -EINVAL; } pos=(unsigned long) btv->fbuffer; while (size > 0) { page = kvirt_to_phys(pos); if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; start+=PAGE_SIZE; pos+=PAGE_SIZE; size-=PAGE_SIZE; } return 0;}static struct video_device bttv_template={ "UNSET", VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT, VID_HARDWARE_BT848, bttv_open, bttv_close, bttv_read, bttv_write,#if LINUX_VERSION_CODE >= 0x020100 NULL, /* poll */#endif bttv_ioctl, bttv_mmap, bttv_init_done, NULL, 0, -1};static long vbi_read(struct video_device *v, char *buf, unsigned long count, int nonblock){ struct bttv *btv=(struct bttv *)(v-2); int q,todo; todo=count; while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) { if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) return -EFAULT; todo-=q; buf+=q; cli(); if (todo && q==VBIBUF_SIZE-btv->vbip) { if(nonblock) { sti(); if(count==todo) return -EWOULDBLOCK; return count-todo; } 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;}#if LINUX_VERSION_CODE >= 0x020100static unsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait){ struct bttv *btv=(struct bttv *)(dev-2); unsigned int mask = 0; poll_wait(file, &btv->vbiq, wait); if (btv->vbip < VBIBUF_SIZE) mask |= (POLLIN | POLLRDNORM); return mask;}#endifstatic int vbi_open(struct video_device *dev, int flags){ struct bttv *btv=(struct bttv *)(dev-2); btv->vbip=VBIBUF_SIZE; btv->cap|=0x0c; bt848_set_risc_jmps(btv); MOD_INC_USE_COUNT; return 0; }static void vbi_close(struct video_device *dev){ struct bttv *btv=(struct bttv *)(dev-2); btv->cap&=~0x0c; bt848_set_risc_jmps(btv); MOD_DEC_USE_COUNT; }static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg){ return -EINVAL;}static struct video_device vbi_template={ "bttv vbi", VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, VID_HARDWARE_BT848, vbi_open, vbi_close, vbi_read, bttv_write,#if LINUX_VERSION_CODE >= 0x020100 vbi_poll,#endif vbi_ioctl, NULL, /* no mmap yet */ bttv_init_done, NULL, 0, -1};static int radio_open(struct video_device *dev, int flags){ struct bttv *btv = (struct bttv *)(dev-1); if (btv->user) return -EBUSY; btv->user++; set_freq(btv,400*16); btv->radio = 1; bt848_muxsel(btv,0); audio(btv, AUDIO_UNMUTE); MOD_INC_USE_COUNT; return 0; }static void radio_close(struct video_device *dev){ struct bttv *btv=(struct bttv *)(dev-1); btv->user--; btv->radio = 0; /*audio(btv, AUDIO_MUTE);*/ MOD_DEC_USE_COUNT; }static long radio_read(struct video_device *v, char *buf, unsigned long count, int nonblock){ return -EINVAL;}static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg){ struct bttv *btv=(struct bttv *)(dev-1); switch (cmd) { case VIDIOCGCAP: { struct video_capability v; strcpy(v.name,btv->video_dev.name); v.type = VID_TYPE_TUNER; v.channels = 1; v.audios = 1; /* No we don't do pictures */ v.maxwidth = 0; v.maxheight = 0; v.minwidth = 0; v.minheight = 0; if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; return 0; break; } 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, "Radio"); v.rangelow=(int)(87.5*16); v.rangehigh=(int)(108*16); v.flags= 0; /* XXX */ v.mode = 0; /* XXX */ if(copy_to_user(arg,&v,sizeof(v))) return -EFAULT; return 0; } case VIDIOCSTUNER: { struct video_tuner v; if(copy_from_user(&v, arg, sizeof(v))) return -EFAULT; /* Only channel 0 has a tuner */ if(v.tuner!=0 || btv->channel) return -EINVAL; /* XXX anything to do ??? */ return 0; } case VIDIOCGFREQ: case VIDIOCSFREQ: case VIDIOCGAUDIO: case VIDIOCSAUDIO: bttv_ioctl((struct video_device *)btv,cmd,arg); break; default: return -ENOIOCTLCMD; } return 0;}static struct video_device radio_template={ "bttv radio", VID_TYPE_TUNER, VID_HARDWARE_BT848, radio_open, radio_close, radio_read, /* just returns -EINVAL */ bttv_write, /* just returns -EINVAL */#if LINUX_VERSION_CODE >= 0x020100 NULL, /* no poll */#endif radio_ioctl, NULL, /* no mmap */ bttv_init_done, /* just returns 0 */ NULL, 0, -1};struct vidbases { unsigned short vendor, device; char *name; uint badr;};static struct vidbases vbs[] = { { PCI_VENDOR_ID_ALLIANCE, PCI_DEVICE_ID_ALLIANCE_AT3D, "Alliance AT3D", PCI_BASE_ADDRESS_0}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215CT222, "ATI MACH64 CT", PCI_BASE_ADDRESS_0}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_210888GX, "ATI MACH64 Winturbo", PCI_BASE_ADDRESS_0}, { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_215GT, "ATI MACH64 GT", PCI_BASE_ADDRESS_0}, { PCI_VENDOR_ID_CIRRUS, 0, "Cirrus Logic", PCI_BASE_ADDRESS_0}, { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, "DEC DC21030", PCI_BASE_ADDRESS_0}, { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, "Matrox Millennium", PCI_BASE_ADDRESS_1}, { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2, "Matrox Millennium II", PCI_BASE_ADDRESS_0}, { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL_2_AGP, "Matrox Millennium II AGP", PCI_BASE_ADDRESS_0}, { PCI_VEN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -