📄 bttv-driver.c
字号:
} c = btv->i2c_tvaudio_client; if (c) { struct v4l2_routing route; route.input = input; route.output = 0; c->driver->command(c, VIDIOC_INT_S_AUDIO_ROUTING, &route); } return 0;}static inline intaudio_mute(struct bttv *btv, int mute){ return audio_mux(btv, btv->audio, mute);}static inline intaudio_input(struct bttv *btv, int input){ return audio_mux(btv, input, btv->mute);}static voidi2c_vidiocschan(struct bttv *btv){ v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id; bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std); if (btv->c.type == BTTV_BOARD_VOODOOTV_FM) bttv_tda9880_setnorm(btv,btv->tvnorm);}static intset_tvnorm(struct bttv *btv, unsigned int norm){ const struct bttv_tvnorm *tvnorm; if (norm < 0 || norm >= BTTV_TVNORMS) return -EINVAL; btv->tvnorm = norm; tvnorm = &bttv_tvnorms[norm]; btwrite(tvnorm->adelay, BT848_ADELAY); btwrite(tvnorm->bdelay, BT848_BDELAY); btaor(tvnorm->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); btwrite(tvnorm->vbipack, BT848_VBI_PACK_SIZE); btwrite(1, BT848_VBI_PACK_DEL); bt848A_set_timing(btv); switch (btv->c.type) { case BTTV_BOARD_VOODOOTV_FM: bttv_tda9880_setnorm(btv,norm); break;#if 0 case BTTV_BOARD_OSPREY540: osprey_540_set_norm(btv,norm); break;#endif } return 0;}static voidset_input(struct bttv *btv, unsigned int input){ unsigned long flags; btv->input = input; if (irq_iswitch) { spin_lock_irqsave(&btv->s_lock,flags); if (btv->curr.frame_irq) { /* active capture -> delayed input switch */ btv->new_input = input; } else { video_mux(btv,input); } spin_unlock_irqrestore(&btv->s_lock,flags); } else { video_mux(btv,input); } audio_input(btv,(input == bttv_tvcards[btv->c.type].tuner ? TVAUDIO_INPUT_TUNER : TVAUDIO_INPUT_EXTERN)); set_tvnorm(btv,btv->tvnorm); i2c_vidiocschan(btv);}static void init_irqreg(struct bttv *btv){ /* clear status */ btwrite(0xfffffUL, BT848_INT_STAT); if (bttv_tvcards[btv->c.type].no_video) { /* i2c only */ btwrite(BT848_INT_I2CDONE, BT848_INT_MASK); } else { /* full video */ btwrite((btv->triton1) | (btv->gpioirq ? BT848_INT_GPINT : 0) | BT848_INT_SCERR | (fdsr ? BT848_INT_FDSR : 0) | BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| BT848_INT_FMTCHG|BT848_INT_HLOCK| BT848_INT_I2CDONE, BT848_INT_MASK); }}static void init_bt848(struct bttv *btv){ int val; if (bttv_tvcards[btv->c.type].no_video) { /* very basic init only */ init_irqreg(btv); return; } btwrite(0x00, BT848_CAP_CTL); btwrite(BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL); btwrite(BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM); /* set planar and packed mode trigger points and */ /* set rising edge of inverted GPINTR pin as irq trigger */ btwrite(BT848_GPIO_DMA_CTL_PKTP_32| BT848_GPIO_DMA_CTL_PLTP1_16| BT848_GPIO_DMA_CTL_PLTP23_16| BT848_GPIO_DMA_CTL_GPINTC| BT848_GPIO_DMA_CTL_GPINTI, BT848_GPIO_DMA_CTL); val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; btwrite(val, BT848_E_SCLOOP); btwrite(val, BT848_O_SCLOOP); btwrite(0x20, BT848_E_VSCALE_HI); btwrite(0x20, BT848_O_VSCALE_HI); btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), BT848_ADC); btwrite(whitecrush_upper, BT848_WC_UP); btwrite(whitecrush_lower, BT848_WC_DOWN); if (btv->opt_lumafilter) { btwrite(0, BT848_E_CONTROL); btwrite(0, BT848_O_CONTROL); } else { btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); } bt848_bright(btv, btv->bright); bt848_hue(btv, btv->hue); bt848_contrast(btv, btv->contrast); bt848_sat(btv, btv->saturation); /* interrupt */ init_irqreg(btv);}static void bttv_reinit_bt848(struct bttv *btv){ unsigned long flags; if (bttv_verbose) printk(KERN_INFO "bttv%d: reset, reinitialize\n",btv->c.nr); spin_lock_irqsave(&btv->s_lock,flags); btv->errors=0; bttv_set_dma(btv,0); spin_unlock_irqrestore(&btv->s_lock,flags); init_bt848(btv); btv->pll.pll_current = -1; set_input(btv,btv->input);}static int get_control(struct bttv *btv, struct v4l2_control *c){ struct video_audio va; int i; for (i = 0; i < BTTV_CTLS; i++) if (bttv_ctls[i].id == c->id) break; if (i == BTTV_CTLS) return -EINVAL; if (btv->audio_hook && i >= 4 && i <= 8) { memset(&va,0,sizeof(va)); btv->audio_hook(btv,&va,0); switch (c->id) { case V4L2_CID_AUDIO_MUTE: c->value = (VIDEO_AUDIO_MUTE & va.flags) ? 1 : 0; break; case V4L2_CID_AUDIO_VOLUME: c->value = va.volume; break; case V4L2_CID_AUDIO_BALANCE: c->value = va.balance; break; case V4L2_CID_AUDIO_BASS: c->value = va.bass; break; case V4L2_CID_AUDIO_TREBLE: c->value = va.treble; break; } return 0; } switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = btv->bright; break; case V4L2_CID_HUE: c->value = btv->hue; break; case V4L2_CID_CONTRAST: c->value = btv->contrast; break; case V4L2_CID_SATURATION: c->value = btv->saturation; break; case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_VOLUME: case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: bttv_call_i2c_clients(btv,VIDIOC_G_CTRL,c); break; case V4L2_CID_PRIVATE_CHROMA_AGC: c->value = btv->opt_chroma_agc; break; case V4L2_CID_PRIVATE_COMBFILTER: c->value = btv->opt_combfilter; break; case V4L2_CID_PRIVATE_LUMAFILTER: c->value = btv->opt_lumafilter; break; case V4L2_CID_PRIVATE_AUTOMUTE: c->value = btv->opt_automute; break; case V4L2_CID_PRIVATE_AGC_CRUSH: c->value = btv->opt_adc_crush; break; case V4L2_CID_PRIVATE_VCR_HACK: c->value = btv->opt_vcr_hack; break; case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: c->value = btv->opt_whitecrush_upper; break; case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: c->value = btv->opt_whitecrush_lower; break; case V4L2_CID_PRIVATE_UV_RATIO: c->value = btv->opt_uv_ratio; break; case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: c->value = btv->opt_full_luma_range; break; case V4L2_CID_PRIVATE_CORING: c->value = btv->opt_coring; break; default: return -EINVAL; } return 0;}static int set_control(struct bttv *btv, struct v4l2_control *c){ struct video_audio va; int i,val; for (i = 0; i < BTTV_CTLS; i++) if (bttv_ctls[i].id == c->id) break; if (i == BTTV_CTLS) return -EINVAL; if (btv->audio_hook && i >= 4 && i <= 8) { memset(&va,0,sizeof(va)); btv->audio_hook(btv,&va,0); switch (c->id) { case V4L2_CID_AUDIO_MUTE: if (c->value) { va.flags |= VIDEO_AUDIO_MUTE; audio_mute(btv, 1); } else { va.flags &= ~VIDEO_AUDIO_MUTE; audio_mute(btv, 0); } break; case V4L2_CID_AUDIO_VOLUME: va.volume = c->value; break; case V4L2_CID_AUDIO_BALANCE: va.balance = c->value; break; case V4L2_CID_AUDIO_BASS: va.bass = c->value; break; case V4L2_CID_AUDIO_TREBLE: va.treble = c->value; break; } btv->audio_hook(btv,&va,1); return 0; } switch (c->id) { case V4L2_CID_BRIGHTNESS: bt848_bright(btv,c->value); break; case V4L2_CID_HUE: bt848_hue(btv,c->value); break; case V4L2_CID_CONTRAST: bt848_contrast(btv,c->value); break; case V4L2_CID_SATURATION: bt848_sat(btv,c->value); break; case V4L2_CID_AUDIO_MUTE: audio_mute(btv, c->value); /* fall through */ case V4L2_CID_AUDIO_VOLUME: case V4L2_CID_AUDIO_BALANCE: case V4L2_CID_AUDIO_BASS: case V4L2_CID_AUDIO_TREBLE: bttv_call_i2c_clients(btv,VIDIOC_S_CTRL,c); break; case V4L2_CID_PRIVATE_CHROMA_AGC: btv->opt_chroma_agc = c->value; val = btv->opt_chroma_agc ? BT848_SCLOOP_CAGC : 0; btwrite(val, BT848_E_SCLOOP); btwrite(val, BT848_O_SCLOOP); break; case V4L2_CID_PRIVATE_COMBFILTER: btv->opt_combfilter = c->value; break; case V4L2_CID_PRIVATE_LUMAFILTER: btv->opt_lumafilter = c->value; if (btv->opt_lumafilter) { btand(~BT848_CONTROL_LDEC, BT848_E_CONTROL); btand(~BT848_CONTROL_LDEC, BT848_O_CONTROL); } else { btor(BT848_CONTROL_LDEC, BT848_E_CONTROL); btor(BT848_CONTROL_LDEC, BT848_O_CONTROL); } break; case V4L2_CID_PRIVATE_AUTOMUTE: btv->opt_automute = c->value; break; case V4L2_CID_PRIVATE_AGC_CRUSH: btv->opt_adc_crush = c->value; btwrite(BT848_ADC_RESERVED | (btv->opt_adc_crush ? BT848_ADC_CRUSH : 0), BT848_ADC); break; case V4L2_CID_PRIVATE_VCR_HACK: btv->opt_vcr_hack = c->value; break; case V4L2_CID_PRIVATE_WHITECRUSH_UPPER: btv->opt_whitecrush_upper = c->value; btwrite(c->value, BT848_WC_UP); break; case V4L2_CID_PRIVATE_WHITECRUSH_LOWER: btv->opt_whitecrush_lower = c->value; btwrite(c->value, BT848_WC_DOWN); break; case V4L2_CID_PRIVATE_UV_RATIO: btv->opt_uv_ratio = c->value; bt848_sat(btv, btv->saturation); break; case V4L2_CID_PRIVATE_FULL_LUMA_RANGE: btv->opt_full_luma_range = c->value; btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM); break; case V4L2_CID_PRIVATE_CORING: btv->opt_coring = c->value; btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM); break; default: return -EINVAL; } return 0;}/* ----------------------------------------------------------------------- */void bttv_gpio_tracking(struct bttv *btv, char *comment){ unsigned int outbits, data; outbits = btread(BT848_GPIO_OUT_EN); data = btread(BT848_GPIO_DATA); printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n", btv->c.nr,outbits,data & outbits, data & ~outbits, comment);}static void bttv_field_count(struct bttv *btv){ int need_count = 0; if (btv->users) need_count++; if (need_count) { /* start field counter */ btor(BT848_INT_VSYNC,BT848_INT_MASK); } else { /* stop field counter */ btand(~BT848_INT_VSYNC,BT848_INT_MASK); btv->field_count = 0; }}static const struct bttv_format*format_by_palette(int palette){ unsigned int i; for (i = 0; i < BTTV_FORMATS; i++) { if (-1 == bttv_formats[i].palette) continue; if (bttv_formats[i].palette == palette) return bttv_formats+i; } return NULL;}static const struct bttv_format*format_by_fourcc(int fourcc){ unsigned int i; for (i = 0; i < BTTV_FORMATS; i++) { if (-1 == bttv_formats[i].fourcc) continue; if (bttv_formats[i].fourcc == fourcc) return bttv_formats+i; } return NULL;}/* ----------------------------------------------------------------------- *//* misc helpers */static intbttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, struct bttv_buffer *new){ struct bttv_buffer *old; unsigned long flags; int retval = 0; dprintk("switch_overlay: enter [new=%p]\n",new); if (new) new->vb.state = STATE_DONE; spin_lock_irqsave(&btv->s_lock,flags); old = btv->screen; btv->screen = new; btv->loop_irq |= 1; bttv_set_dma(btv, 0x03); spin_unlock_irqrestore(&btv->s_lock,flags); if (NULL == new) free_btres(btv,fh,RESOURCE_OVERLAY); if (NULL != old) { dprintk("switch_overlay: old=%p state is %d\n",old,old->vb.state); bttv_dma_free(&fh->cap,btv, old); kfree(old); } dprintk("switch_overlay: done\n"); return retval;}/* ----------------------------------------------------------------------- *//* video4linux (1) interface */static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf, const struct bttv_format *fmt, unsigned int width, unsigned int height, enum v4l2_field field){ int redo_dma_risc = 0; int rc; /* check settings */ if (NULL == fmt) return -EINVAL; if (fmt->btformat == BT848_COLOR_FMT_RAW) { width = RAW_BPL; height = RAW_LINES*2; if (width*height > buf->vb.bsize) return -EINVAL; buf->vb.size = buf->vb.bsize; } else { if (width < 48 || height < 32 || width > bttv_tvnorms[btv->tvnorm].swidth || height > bttv_tvnorms[btv->tvnorm].sheight) return -EINVAL; buf->vb.size = (width * height * fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) return -EINVAL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -