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 + -
显示快捷键?