bttv-driver.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 2,527 行 · 第 1/5 页

C
2,527
字号
		struct v4l2_tuner *t = arg;		down(&btv->lock);		memset(t,0,sizeof(*t));		t->input = bttv_tvcards[btv->type].tuner;		strcpy(t->name, "Television");		v4l2_video_std_construct(&t->std, bttv_tvnorms[btv->tvnorm].v4l2_id, 0);		t->capability = V4L2_TUNER_CAP_NORM;		t->rangehigh = 0xffffffffUL;		t->rxsubchans = V4L2_TUNER_SUB_MONO;		if (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)			t->signal = 0xffff;		{			/* Hmmm ... */			struct video_audio va;			memset(&va, 0, sizeof(struct video_audio));			bttv_call_i2c_clients(btv, VIDIOCGAUDIO, &va);			if (bttv_tvcards[btv->type].audio_hook)				bttv_tvcards[btv->type].audio_hook(btv,&va,0);			if(va.mode & VIDEO_SOUND_STEREO)				t->rxsubchans |= V4L2_TUNER_SUB_STEREO;			if(va.mode & VIDEO_SOUND_LANG1)				t->rxsubchans |= V4L2_TUNER_SUB_LANG1;			if(va.mode & VIDEO_SOUND_LANG2)				t->rxsubchans |= V4L2_TUNER_SUB_LANG2;		}		/* FIXME: fill capability+audmode */		up(&btv->lock);		return 0;	}	case VIDIOC_S_TUNER: {		struct v4l2_tuner *t = arg;				if(t->input!=bttv_tvcards[btv->type].tuner)			return -EINVAL;		down(&btv->lock);		{			struct video_audio va;			memset(&va, 0, sizeof(struct video_audio));			if (t->audmode == V4L2_TUNER_MODE_MONO)				va.mode = VIDEO_SOUND_MONO;			else if (t->audmode == V4L2_TUNER_MODE_STEREO)				va.mode = VIDEO_SOUND_STEREO;			else if (t->audmode == V4L2_TUNER_MODE_LANG1)				va.mode = VIDEO_SOUND_LANG1;			else if (t->audmode == V4L2_TUNER_MODE_LANG2)				va.mode = VIDEO_SOUND_LANG2;			bttv_call_i2c_clients(btv, VIDIOCSAUDIO, &va);			if (bttv_tvcards[btv->type].audio_hook)				bttv_tvcards[btv->type].audio_hook(btv,&va,1);		}		up(&btv->lock);		return 0;	}#endif /* HAVE_V4L2 */	default:		return -ENOIOCTLCMD;		}	return 0;}static int setup_window(struct bttv_fh *fh, struct bttv *btv,			int x, int y, int width, int height,			struct video_clip *user_clips, int nclips){	struct video_clip *clips = NULL;	int n,size,retval = 0;		if (width  < 48 ||	    height < 32 ||	    width  > bttv_tvnorms[btv->tvnorm].swidth ||	    height > bttv_tvnorms[btv->tvnorm].sheight ||	    NULL == fh->ovfmt)		return -EINVAL;	if (nclips > 2048)		return -EINVAL;	/* copy clips  --  luckily v4l1 + v4l2 are binary	   compatible here ...*/	n = nclips;	size = sizeof(struct video_clip)*(n+4);	clips = kmalloc(size,GFP_KERNEL);	if (NULL == clips)		return -ENOMEM;	if (n > 0) {		if (copy_from_user(clips,user_clips,				   sizeof(struct video_clip)*nclips)) {			kfree(clips);			return -EFAULT;		}	}	/* clip against screen */	if (NULL != btv->fbuf.base)		n = bttv_screen_clips(&btv->fbuf, x, y,				      width, height,				      clips, n);	bttv_sort_clips(clips,nclips);		down(&fh->lock);	if (fh->ov.clips)		kfree(fh->ov.clips);	fh->ov.clips   = clips;	fh->ov.nclips  = nclips;		fh->ov.x       = x;	fh->ov.y       = y;	fh->ov.width   = width;	fh->ov.height  = height;	btv->init.ov.width   = width;	btv->init.ov.height  = height;		/* update overlay if needed */	retval = 0;	if (check_btres(fh, RESOURCE_OVERLAY)) {		struct bttv_buffer *new;				new = videobuf_alloc(sizeof(*new),V4L2_BUF_TYPE_CAPTURE);		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);		retval = bttv_switch_overlay(btv,fh,new);	}	up(&fh->lock);	return retval;}static void release_buffer(struct file *file, struct videobuf_buffer *vb){	struct bttv_buffer *buf = (struct bttv_buffer*)vb;	struct bttv_fh *fh = file->private_data;	bttv_dma_free(fh->btv,buf);}static int bttv_do_ioctl(struct inode *inode, struct file *file,			 unsigned int cmd, void *arg){	struct bttv_fh *fh  = file->private_data;	struct bttv    *btv = fh->btv;	int retval;	if (bttv_debug > 1) {		switch (_IOC_TYPE(cmd)) {		case 'v':			printk("bttv%d: ioctl 0x%x (v4l1, VIDIOC%s)\n",			       btv->nr, cmd, (_IOC_NR(cmd) < V4L1_IOCTLS) ?			       v4l1_ioctls[_IOC_NR(cmd)] : "???");			break;		case 'V':			printk("bttv%d: ioctl 0x%x (v4l2, VIDIOC_%s)\n",			       btv->nr, cmd,  (_IOC_NR(cmd) < V4L2_IOCTLS) ?			       v4l2_ioctls[_IOC_NR(cmd)] : "???");			break;		default:			printk("bttv%d: ioctl 0x%x (???)\n",			       btv->nr, cmd);		}	}	if (btv->errors)		bttv_reinit_bt848(btv);	switch (cmd) {	/* ***  v4l1  *** ************************************************ */	case VIDIOCGCAP:	{                struct video_capability *cap = arg;		memset(cap,0,sizeof(*cap));                strcpy(cap->name,btv->video_dev.name);                cap->type = VID_TYPE_CAPTURE|			VID_TYPE_TUNER|			VID_TYPE_OVERLAY|			VID_TYPE_CLIPPING|                        VID_TYPE_SCALES;                cap->channels  = bttv_tvcards[btv->type].video_inputs;                cap->audios    = bttv_tvcards[btv->type].audio_inputs;                cap->maxwidth  = bttv_tvnorms[btv->tvnorm].swidth;                cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;                cap->minwidth  = 48;                cap->minheight = 32;                return 0;	}	case VIDIOCGPICT:	{		struct video_picture *pic = arg;		memset(pic,0,sizeof(*pic));		pic->brightness = btv->bright;		pic->contrast   = btv->contrast;		pic->hue        = btv->hue;		pic->colour     = btv->saturation;		if (fh->buf.fmt) {			pic->depth   = fh->buf.fmt->depth;			pic->palette = fh->buf.fmt->palette;		}		return 0;	}	case VIDIOCSPICT:	{		struct video_picture *pic = arg;		const struct bttv_format *fmt;				fmt = format_by_palette(pic->palette);		if (NULL == fmt)			return -EINVAL;		down(&fh->lock);		retval = -EINVAL;		if (fmt->depth != pic->depth && !sloppy)			goto fh_unlock_and_return;		fh->ovfmt   = fmt;		fh->buf.fmt = fmt;		btv->init.ovfmt   = fmt;		btv->init.buf.fmt = fmt;		if (bigendian) {			/* dirty hack time:  swap bytes for overlay if the			   display adaptor is big endian (insmod option) */			if (fmt->palette == VIDEO_PALETTE_RGB555 ||			    fmt->palette == VIDEO_PALETTE_RGB565 ||			    fmt->palette == VIDEO_PALETTE_RGB32) {				fh->ovfmt = fmt+1;			}		}		bt848_bright(btv,pic->brightness);		bt848_contrast(btv,pic->contrast);		bt848_hue(btv,pic->hue);		bt848_sat(btv,pic->colour);		up(&fh->lock);                return 0;	}	case VIDIOCGWIN:	{		struct video_window *win = arg;		memset(win,0,sizeof(*win));		win->x      = fh->ov.x;		win->y      = fh->ov.y;		win->width  = fh->ov.width;		win->height = fh->ov.height;		return 0;	}	case VIDIOCSWIN:	{		struct video_window *win = arg;		retval = setup_window(fh,btv,win->x,win->y,				      win->width,win->height,				      win->clips,				      win->clipcount);		if (0 == retval) {			/* on v4l1 this ioctl affects the read() size too */			fh->buf.vb.width  = fh->ov.width;			fh->buf.vb.height = fh->ov.height;			btv->init.buf.vb.width  = fh->ov.width;			btv->init.buf.vb.height = fh->ov.height;		}		return retval;	}	case VIDIOCGFBUF:	{		struct video_buffer *fbuf = arg;		*fbuf = btv->fbuf;		return 0;	}	case VIDIOCSFBUF:	{		struct video_buffer *fbuf = arg;		const struct bttv_format *fmt;		unsigned long end;		if(!capable(CAP_SYS_ADMIN) &&                   !capable(CAP_SYS_RAWIO))                        return -EPERM;		end = (unsigned long)fbuf->base +			fbuf->height * fbuf->bytesperline;		if (0 == find_videomem((unsigned long)fbuf->base,end))			return -EINVAL;		down(&fh->lock);		retval = -EINVAL;		if (sloppy) {			/* also set the default palette -- for backward			   compatibility with older versions */			switch (fbuf->depth) {			case 8:				fmt = format_by_palette(VIDEO_PALETTE_HI240);				break;			case 16:				fmt = format_by_palette(VIDEO_PALETTE_RGB565);				break;			case 24:				fmt = format_by_palette(VIDEO_PALETTE_RGB24);				break;			case 32:				fmt = format_by_palette(VIDEO_PALETTE_RGB32);				break;			case 15:				fbuf->depth = 16;				fmt = format_by_palette(VIDEO_PALETTE_RGB555);				break;			default:				fmt = NULL;				break;			}			if (NULL == fmt)				goto fh_unlock_and_return;			fh->ovfmt   = fmt;			fh->buf.fmt = fmt;			btv->init.ovfmt   = fmt;			btv->init.buf.fmt = fmt;		} else {			if (15 == fbuf->depth)				fbuf->depth = 16;			if (fbuf->depth !=  8 && fbuf->depth != 16 &&			    fbuf->depth != 24 && fbuf->depth != 32)				goto fh_unlock_and_return;		}		btv->fbuf = *fbuf;		up(&fh->lock);		return 0;	}	case VIDIOCCAPTURE:#ifdef HAVE_V4L2	case VIDIOC_PREVIEW:#endif	{		struct bttv_buffer *new;		int *on = arg;		if (*on) {			/* verify args */			if (NULL == btv->fbuf.base)				return -EINVAL;			if (fh->ov.width <48 ||			    fh->ov.height<32 ||			    fh->ov.width >bttv_tvnorms[btv->tvnorm].swidth  ||			    fh->ov.height>bttv_tvnorms[btv->tvnorm].sheight ||			    NULL == fh->ovfmt)				return -EINVAL;		}		if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY))			return -EBUSY;				down(&fh->lock);		if (*on) {			fh->ov.tvnorm = btv->tvnorm;			new = videobuf_alloc(sizeof(*new),					     V4L2_BUF_TYPE_CAPTURE);			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);		} else {			new = NULL;		}		/* switch over */	        retval = bttv_switch_overlay(btv,fh,new);		up(&fh->lock);		return retval;	}	case VIDIOCGMBUF:	{		struct video_mbuf *mbuf = arg;		int i;		if (!mmap)			return -EINVAL;		down(&fh->lock);		retval = videobuf_mmap_setup			(file,(struct videobuf_buffer**)fh->bufs,			 sizeof(struct bttv_buffer),			 gbuffers,gbufsize,V4L2_BUF_TYPE_CAPTURE,			 release_buffer);		if (retval < 0)			goto fh_unlock_and_return;		memset(mbuf,0,sizeof(*mbuf));		mbuf->frames = gbuffers;		mbuf->size   = gbuffers * gbufsize;		for (i = 0; i < gbuffers; i++)			mbuf->offsets[i] = i * gbufsize;		up(&fh->lock);		return 0;	}	case VIDIOCMCAPTURE:	{		struct video_mmap *vm = arg;		struct bttv_buffer *buf;		if (vm->frame >= VIDEO_MAX_FRAME)			return -EINVAL;		down(&fh->lock);		retval = -EINVAL;		buf = fh->bufs[vm->frame];		if (NULL == buf)			goto fh_unlock_and_return;		if (0 == buf->vb.baddr)			goto fh_unlock_and_return;		if (buf->vb.state == STATE_QUEUED ||		    buf->vb.state == STATE_ACTIVE)			goto fh_unlock_and_return;				retval = bttv_prepare_buffer(btv,buf,					     format_by_palette(vm->format),					     vm->width,vm->height,0);		if (0 != retval)			goto fh_unlock_and_return;		bttv_queue_buffer(btv,buf);		up(&fh->lock);		return 0;	}	case VIDIOCSYNC:	{		int *frame = arg;		struct bttv_buffer *buf;		if (*frame >= VIDEO_MAX_FRAME)			return -EINVAL;		down(&fh->lock);		retval = -EINVAL;		buf = fh->bufs[*frame];		if (NULL == buf)			goto fh_unlock_and_return;		retval = videobuf_waiton(&buf->vb,0,1);		if (0 != retval)			goto fh_unlock_and_return;		switch (buf->vb.state) {		case STATE_ERROR:			retval = -EIO;			/* fall through */		case STATE_DONE:			videobuf_dma_pci_sync(btv->dev,&buf->vb.dma);			bttv_dma_free(btv,buf);			break;		default:			retval = -EINVAL;			break;		}		up(&fh->lock);		return retval;	}        case BTTV_VERSION:        case VIDIOCGFREQ:        case VIDIOCSFREQ:        case VIDIOCGTUNER:        case VIDIOCSTUNER:        case VIDIOCGCHAN:        case VIDIOCSCHAN:	case VIDIOCGAUDIO:	case VIDIOCSAUDIO:		return bttv_common_ioctls(btv,cmd,arg);#ifdef HAVE_V4L2	/* ***  v4l2  *** ************************************************ */	case VIDIOC_QUERYCAP:	{		struct v4l2_capability *cap = arg;		if (0 == v4l2)			return -EINVAL;                strcpy(cap->name,btv->video_dev.name);		cap->type = V4L2_TYPE_CAPTURE;		cap->flags = V4L2_FLAG_TUNER | V4L2_FLAG_PREVIEW			| V4L2_FLAG_READ | V4L2_FLAG_SELECT;		if (mmap)			cap->flags |= V4L2_FLAG_STREAMING;		cap->inputs = bttv_tvcards[btv->type].video_inputs;		cap->outputs = 0;		cap->audios = bttv_tvcards[btv->type].audio_inputs;		cap->maxwidth = bttv_tvnorms[btv->tvnorm].swidth;		cap->maxheight = bttv_tvnorms[btv->tvnorm].sheight;		cap->minwidth = 48;		cap->minheight = 32;		cap->maxframerate = 30;		return 0;	}	case VIDIOC_ENUM_PIXFMT:	case VIDIOC_ENUM_FBUFFMT:	{		struct v4l2_fmtdesc *f = arg;		int i, index;		index = -1;		for (i = 0; i < BTTV_FORMATS; i++) {			if (bttv_formats[i].fourcc != -1)				index++;			if (index == f->index)				break;		}		if (BTTV_FORMATS == i)			return -EINVAL;		if (cmd == VIDIOC_ENUM_FBUFFMT &&		    0 == (bttv_formats[i].flags & FORMAT_FLAGS_PACKED))			return -EINVAL;		memset(f,0,sizeof(*f));		f->index = index;		strncpy(f->description,bttv_formats[i].name,31);		f->pixelformat = bttv_formats[i].fourcc;		f->depth = bttv_formats[i].depth;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?