bttv-driver.c
来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 2,527 行 · 第 1/5 页
C
2,527 行
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; default: return -EINVAL; } if (bttv_ctls[i].category == V4L2_CTRL_CAT_AUDIO) { bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va); if (bttv_tvcards[btv->type].audio_hook) bttv_tvcards[btv->type].audio_hook(btv,&va,1); } return 0;}#endif /* HAVE_V4L2 *//* ----------------------------------------------------------------------- */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->nr,outbits,data & outbits, data & ~outbits, comment);}void bttv_field_count(struct bttv *btv){ int need_count = 0; if (locked_btres(btv,RESOURCE_STREAMING)) need_count++; if (btv->vbi.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){ 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;}#ifdef HAVE_V4L2static const struct bttv_format*format_by_fourcc(int fourcc){ 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;}#endif/* ----------------------------------------------------------------------- *//* 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; if (new) new->vb.state = STATE_DONE; spin_lock_irqsave(&btv->s_lock,flags); old = btv->screen; btv->screen = new; bttv_set_dma(btv, 0x03, 1); spin_unlock_irqrestore(&btv->s_lock,flags); if (NULL == new) free_btres(btv,fh,RESOURCE_OVERLAY); if (NULL != old) bttv_dma_free(btv, old); return retval;}static voidbttv_stop_streaming(struct bttv *btv, struct bttv_fh *fh){ unsigned long flags; int i; /* remove queued buffers from list */ spin_lock_irqsave(&btv->s_lock,flags); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == fh->bufs[i]) continue; if (fh->bufs[i]->vb.state == STATE_QUEUED) { list_del(&fh->bufs[i]->vb.queue); fh->bufs[i]->vb.state = STATE_ERROR; } } spin_unlock_irqrestore(&btv->s_lock,flags); /* free all buffers + clear queue */ for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == fh->bufs[i]) continue; bttv_dma_free(fh->btv,fh->bufs[i]); } INIT_LIST_HEAD(&fh->stream); free_btres(btv,fh,RESOURCE_STREAMING); bttv_field_count(btv);}/* ----------------------------------------------------------------------- *//* video4linux (1) interface */static int bttv_prepare_buffer(struct bttv *btv, struct bttv_buffer *buf, const struct bttv_format *fmt, int width, int height, int 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->tvnorm != btv->tvnorm || buf->fmt != fmt) { buf->vb.width = width; buf->vb.height = height; buf->tvnorm = btv->tvnorm; buf->fmt = fmt; redo_dma_risc = 1; } if (STATE_NEEDS_INIT == buf->vb.state) { field = bttv_buffer_field(btv, field, VBUF_FIELD_EVEN, btv->tvnorm, height); if (field != buf->vb.field) redo_dma_risc = 1; if (redo_dma_risc) bttv_dma_free(btv,buf); } /* alloc risc memory */ if (STATE_NEEDS_INIT == buf->vb.state) { redo_dma_risc = 1; if (0 != (rc = videobuf_iolock(btv->dev,&buf->vb))) 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 voidbttv_queue_buffer(struct bttv *btv, struct bttv_buffer *buf){ unsigned long flags; buf->vb.state = STATE_QUEUED; spin_lock_irqsave(&btv->s_lock,flags); list_add_tail(&buf->vb.queue,&btv->capture); bttv_set_dma(btv, 0x03, 1); spin_unlock_irqrestore(&btv->s_lock,flags);}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 (sizeof(v4l1_ioctls)/sizeof(char*))static const char *v4l2_ioctls[] = { "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT", "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF", "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON", "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD", "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER", "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL", "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43", "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT", "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR", "S_MODULATOR"};#define V4L2_IOCTLS (sizeof(v4l2_ioctls)/sizeof(char*))int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg){ switch (cmd) { case BTTV_VERSION: return BTTV_VERSION_CODE; /* *** v4l1 *** ************************************************ */ case VIDIOCGFREQ:#ifdef HAVE_V4L2 case VIDIOC_G_FREQ:#endif { unsigned long *freq = arg; *freq = btv->freq; return 0; } case VIDIOCSFREQ:#ifdef HAVE_V4L2 case VIDIOC_S_FREQ:#endif { 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; } case VIDIOCGTUNER: { struct video_tuner *v = arg; if (v->tuner) /* Only tuner 0 */ return -EINVAL; strcpy(v->name, "Television"); v->rangelow = 0; v->rangehigh = 0x7FFFFFFF; v->flags = VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; v->mode = btv->tvnorm; v->signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; bttv_call_i2c_clients(btv,cmd,v); return 0; } case VIDIOCSTUNER: { struct video_tuner *v = arg; if (v->tuner) /* Only tuner 0 */ return -EINVAL; if (v->mode >= BTTV_TVNORMS) return -EINVAL; down(&btv->lock); set_tvnorm(btv,v->mode); bttv_call_i2c_clients(btv,cmd,v); up(&btv->lock); return 0; } case VIDIOCGCHAN: { struct video_channel *v = arg; if (v->channel >= bttv_tvcards[btv->type].video_inputs) return -EINVAL; v->tuners=0; v->flags = VIDEO_VC_AUDIO; v->type = VIDEO_TYPE_CAMERA; v->norm = btv->tvnorm; 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); } return 0; } case VIDIOCSCHAN: { struct video_channel *v = arg; if (v->channel < 0 || v->channel >= bttv_tvcards[btv->type].video_inputs) return -EINVAL; if (v->norm >= BTTV_TVNORMS) return -EINVAL; down(&btv->lock); if (v->channel == btv->input && v->norm == btv->tvnorm) { /* nothing to do */ up(&btv->lock); return 0; } btv->tvnorm = v->norm; set_input(btv,v->channel); up(&btv->lock); return 0; } case VIDIOCGAUDIO: { struct video_audio *v = arg; memset(v,0,sizeof(*v)); strcpy(v->name,"Television"); v->flags |= VIDEO_AUDIO_MUTABLE; v->mode = VIDEO_SOUND_MONO; down(&btv->lock); 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); up(&btv->lock); return 0; } case VIDIOCSAUDIO: { struct video_audio *v = arg; if(v->audio < 0 || v->audio >= bttv_tvcards[btv->type].audio_inputs) return -EINVAL; down(&btv->lock); audio_mux(btv, (v->flags&VIDEO_AUDIO_MUTE) ? AUDIO_MUTE : AUDIO_UNMUTE); 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); up(&btv->lock); return 0; }#ifdef HAVE_V4L2 /* *** v4l2 *** ************************************************ */ case VIDIOC_ENUMSTD: { struct v4l2_enumstd *e = arg; if (e->index < 0 || e->index >= BTTV_TVNORMS) return -EINVAL; v4l2_video_std_construct(&e->std, bttv_tvnorms[e->index].v4l2_id, 0); e->inputs = 0x0f; e->outputs = 0x00; return 0; } case VIDIOC_G_STD: { struct v4l2_standard *s = arg; v4l2_video_std_construct(s,bttv_tvnorms[btv->tvnorm].v4l2_id,0); return 0; } case VIDIOC_S_STD: { struct v4l2_standard *s = arg; int i, id = v4l2_video_std_confirm(s); for(i = 0; i < BTTV_TVNORMS; i++) if (id == bttv_tvnorms[i].v4l2_id) break; if (i == BTTV_TVNORMS) return -EINVAL; down(&btv->lock); set_tvnorm(btv,i); i2c_vidiocschan(btv); up(&btv->lock); return 0; } case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; if (i->index >= bttv_tvcards[btv->type].video_inputs) return -EINVAL; i->type = V4L2_INPUT_TYPE_CAMERA; i->capability = 0; i->assoc_audio = 0; if (i->index == bttv_tvcards[btv->type].tuner) { sprintf(i->name, "Television"); i->type = V4L2_INPUT_TYPE_TUNER; i->capability = V4L2_INPUT_CAP_AUDIO; } else if (i->index==bttv_tvcards[btv->type].svhs) { sprintf(i->name, "S-Video"); } else { sprintf(i->name,"Composite%d",i->index); } return 0; } case VIDIOC_G_INPUT: { int *i = arg; *i = btv->input; return 0; } case VIDIOC_S_INPUT: { int *i = arg; if (*i < 0 || *i > bttv_tvcards[btv->type].video_inputs) return -EINVAL; down(&btv->lock); set_input(btv,*i); i2c_vidiocschan(btv); up(&btv->lock); return 0; } case VIDIOC_G_TUNER: {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?