📄 bttv-driver.c
字号:
} 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 (i >= 4 && i <= 8) { memset(&va,0,sizeof(va)); bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); if (btv->audio_hook) btv->audio_hook(btv,&va,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: 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; 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 (i >= 4 && i <= 8) { memset(&va,0,sizeof(va)); bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va); if (btv->audio_hook) btv->audio_hook(btv,&va,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: if (c->value) { va.flags |= VIDEO_AUDIO_MUTE; audio_mux(btv, AUDIO_MUTE); } else { va.flags &= ~VIDEO_AUDIO_MUTE; audio_mux(btv, AUDIO_UNMUTE); } 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; 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; } if (i >= 4 && i <= 8) { bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va); if (btv->audio_hook) btv->audio_hook(btv,&va,1); } 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(btv, old); kfree(old); } dprintk("switch_overlay: done\n"); return retval;}/* ----------------------------------------------------------------------- *//* video4linux (1) interface */static int bttv_prepare_buffer(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; } /* alloc + fill struct bttv_buffer (if changed) */ if (buf->vb.width != width || buf->vb.height != height || buf->vb.field != field || buf->tvnorm != btv->tvnorm || buf->fmt != fmt) { buf->vb.width = width; buf->vb.height = height; buf->vb.field = field; buf->tvnorm = btv->tvnorm; buf->fmt = fmt; redo_dma_risc = 1; } /* alloc risc memory */ if (STATE_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(btv->c.pci,&buf->vb,&btv->fbuf))) goto fail; } if (redo_dma_risc) if (0 != (rc = bttv_buffer_risc(btv,buf))) goto fail; buf->vb.state = STATE_PREPARED; return 0; fail: bttv_dma_free(btv,buf); return rc;}static intbuffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size){ struct bttv_fh *fh = q->priv_data; *size = fh->fmt->depth*fh->width*fh->height >> 3; if (0 == *count) *count = gbuffers; while (*size * *count > gbuffers * gbufsize) (*count)--; return 0;}static intbuffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, enum v4l2_field field){ struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct bttv_fh *fh = q->priv_data; return bttv_prepare_buffer(fh->btv, buf, fh->fmt, fh->width, fh->height, field);}static voidbuffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb){ struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct bttv_fh *fh = q->priv_data; struct bttv *btv = fh->btv; buf->vb.state = STATE_QUEUED; list_add_tail(&buf->vb.queue,&btv->capture); if (!btv->curr.frame_irq) { btv->loop_irq |= 1; bttv_set_dma(btv, 0x03); }}static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb){ struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb); struct bttv_fh *fh = q->priv_data; bttv_dma_free(fh->btv,buf);}static struct videobuf_queue_ops bttv_video_qops = { .buf_setup = buffer_setup, .buf_prepare = buffer_prepare, .buf_queue = buffer_queue, .buf_release = buffer_release,};static const char *v4l1_ioctls[] = { "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE", "GVBIFMT", "SVBIFMT" };#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg){ switch (cmd) { case BTTV_VERSION: return BTTV_VERSION_CODE; /* *** v4l1 *** ************************************************ */ case VIDIOCGFREQ: { unsigned long *freq = arg; *freq = btv->freq; return 0; } case VIDIOCSFREQ: { unsigned long *freq = arg; down(&btv->lock); btv->freq=*freq; bttv_call_i2c_clients(btv,VIDIOCSFREQ,freq); if (btv->has_matchbox && btv->radio_user) tea5757_set_freq(btv,*freq); up(&btv->lock); return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -