⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 saa7134-video.c

📁 该代码是天敏电视卡天敏大师4的核心芯片在linux下面的驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	h_start = dev->crop_current.left;	v_start = dev->crop_current.top/2;	h_stop  = (dev->crop_current.left + dev->crop_current.width -1);	v_stop  = (dev->crop_current.top + dev->crop_current.height -1)/2;		saa_writeb(SAA7134_VIDEO_H_START1(task), h_start &  0xff);	saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8);	saa_writeb(SAA7134_VIDEO_H_STOP1(task),  h_stop  &  0xff);	saa_writeb(SAA7134_VIDEO_H_STOP2(task),  h_stop  >> 8);	saa_writeb(SAA7134_VIDEO_V_START1(task), v_start &  0xff);	saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8);	saa_writeb(SAA7134_VIDEO_V_STOP1(task),  v_stop  &  0xff);	saa_writeb(SAA7134_VIDEO_V_STOP2(task),  v_stop  >> 8);	prescale = dev->crop_defrect.width / width;	if (0 == prescale)		prescale = 1;	xscale = 1024 * dev->crop_defrect.width / prescale / width;	yscale = 512 * div * dev->crop_defrect.height / height;       	dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale);	set_h_prescale(dev,task,prescale);	saa_writeb(SAA7134_H_SCALE_INC1(task),      xscale &  0xff);	saa_writeb(SAA7134_H_SCALE_INC2(task),      xscale >> 8);	set_v_scale(dev,task,yscale);		saa_writeb(SAA7134_VIDEO_PIXELS1(task),     width  & 0xff);	saa_writeb(SAA7134_VIDEO_PIXELS2(task),     width  >> 8);	saa_writeb(SAA7134_VIDEO_LINES1(task),      height/div & 0xff);	saa_writeb(SAA7134_VIDEO_LINES2(task),      height/div >> 8);	/* deinterlace y offsets */	y_odd  = dev->ctl_y_odd;	y_even = dev->ctl_y_even;	saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd);	saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even);	saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd);	saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even);}/* ------------------------------------------------------------------ */struct cliplist {	__u16 position;	__u8  enable;	__u8  disable;};static void sort_cliplist(struct cliplist *cl, int entries){	struct cliplist swap;	int i,j,n;		for (i = entries-2; i >= 0; i--) {		for (n = 0, j = 0; j <= i; j++) {			if (cl[j].position > cl[j+1].position) {				swap = cl[j];				cl[j] = cl[j+1];				cl[j+1] = swap;				n++;			}		}		if (0 == n)			break;	}}static void set_cliplist(struct saa7134_dev *dev, int reg,			struct cliplist *cl, int entries, char *name){	__u8 winbits = 0;	int i;	for (i = 0; i < entries; i++) {		winbits |= cl[i].enable;		winbits &= ~cl[i].disable;		if (i < 15 && cl[i].position == cl[i+1].position)			continue;		saa_writeb(reg + 0, winbits);		saa_writeb(reg + 2, cl[i].position & 0xff);		saa_writeb(reg + 3, cl[i].position >> 8);		dprintk("clip: %s winbits=%02x pos=%d\n",			name,winbits,cl[i].position);		reg += 8;	}	for (; reg < 0x400; reg += 8) {		saa_writeb(reg+ 0, 0);		saa_writeb(reg + 1, 0);		saa_writeb(reg + 2, 0);		saa_writeb(reg + 3, 0);	}}static int clip_range(int val){	if (val < 0)		val = 0;	return val;}static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips,			  int nclips, int interlace){	struct cliplist col[16], row[16];	int cols, rows, i;	int div = interlace ? 2 : 1;	memset(col,0,sizeof(col)); cols = 0;	memset(row,0,sizeof(row)); rows = 0;	for (i = 0; i < nclips && i < 8; i++) {		col[cols].position = clip_range(clips[i].c.left);		col[cols].enable   = (1 << i);		cols++;		col[cols].position = clip_range(clips[i].c.left+clips[i].c.width);		col[cols].disable  = (1 << i);		cols++;		row[rows].position = clip_range(clips[i].c.top / div);		row[rows].enable   = (1 << i);		rows++;		row[rows].position = clip_range((clips[i].c.top + clips[i].c.height)						/ div);		row[rows].disable  = (1 << i);		rows++;	}	sort_cliplist(col,cols);	sort_cliplist(row,rows);	set_cliplist(dev,0x380,col,cols,"cols");	set_cliplist(dev,0x384,row,rows,"rows");	return 0;}static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win){	enum v4l2_field field;	int maxw, maxh;	if (NULL == dev->ovbuf.base)		return -EINVAL;	if (NULL == dev->ovfmt)		return -EINVAL;	if (win->w.width < 48 || win->w.height <  32)		return -EINVAL;	if (win->clipcount > 2048)		return -EINVAL;	field = win->field;	maxw  = dev->crop_current.width;	maxh  = dev->crop_current.height;	if (V4L2_FIELD_ANY == field) {                field = (win->w.height > maxh/2)                        ? V4L2_FIELD_INTERLACED                        : V4L2_FIELD_TOP;        }        switch (field) {        case V4L2_FIELD_TOP:        case V4L2_FIELD_BOTTOM:                maxh = maxh / 2;                break;        case V4L2_FIELD_INTERLACED:                break;        default:                return -EINVAL;        }	win->field = field;	if (win->w.width > maxw)		win->w.width = maxw;	if (win->w.height > maxh)		win->w.height = maxh;	return 0;}static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh){	unsigned long base,control,bpl;	int err;	err = verify_preview(dev,&fh->win);	if (0 != err)		return err;	dev->ovfield = fh->win.field;	dprintk("start_preview %dx%d+%d+%d %s field=%s\n",		fh->win.w.width,fh->win.w.height,		fh->win.w.left,fh->win.w.top,		dev->ovfmt->name,v4l2_field_names[dev->ovfield]);	/* setup window + clipping */	set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height,		 V4L2_FIELD_HAS_BOTH(dev->ovfield));	setup_clipping(dev,fh->clips,fh->nclips,		       V4L2_FIELD_HAS_BOTH(dev->ovfield));	if (dev->ovfmt->yuv)		saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03);	else		saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x01);	saa_writeb(SAA7134_OFMT_VIDEO_B, dev->ovfmt->pm | 0x20);	/* dma: setup channel 1 (= Video Task B) */	base  = (unsigned long)dev->ovbuf.base;	base += dev->ovbuf.fmt.bytesperline * fh->win.w.top;	base += dev->ovfmt->depth/8         * fh->win.w.left;	bpl   = dev->ovbuf.fmt.bytesperline;	control = SAA7134_RS_CONTROL_BURST_16;	if (dev->ovfmt->bswap)		control |= SAA7134_RS_CONTROL_BSWAP;	if (dev->ovfmt->wswap)		control |= SAA7134_RS_CONTROL_WSWAP;	if (V4L2_FIELD_HAS_BOTH(dev->ovfield)) {		saa_writel(SAA7134_RS_BA1(1),base);		saa_writel(SAA7134_RS_BA2(1),base+bpl);		saa_writel(SAA7134_RS_PITCH(1),bpl*2);		saa_writel(SAA7134_RS_CONTROL(1),control);	} else {		saa_writel(SAA7134_RS_BA1(1),base);		saa_writel(SAA7134_RS_BA2(1),base);		saa_writel(SAA7134_RS_PITCH(1),bpl);		saa_writel(SAA7134_RS_CONTROL(1),control);	}	/* start dma */	dev->ovenable = 1;	saa7134_set_dmabits(dev);	return 0;}static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh){	dev->ovenable = 0;	saa7134_set_dmabits(dev);	return 0;}/* ------------------------------------------------------------------ */static int buffer_activate(struct saa7134_dev *dev,			   struct saa7134_buf *buf,			   struct saa7134_buf *next){	unsigned long base,control,bpl;	unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */	dprintk("buffer_activate buf=%p\n",buf);	buf->vb.state = STATE_ACTIVE;	buf->top_seen = 0;		set_size(dev,TASK_A,buf->vb.width,buf->vb.height,		 V4L2_FIELD_HAS_BOTH(buf->vb.field));	if (buf->fmt->yuv)		saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03);	else		saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01);	saa_writeb(SAA7134_OFMT_VIDEO_A, buf->fmt->pm);	/* DMA: setup channel 0 (= Video Task A0) */	base  = saa7134_buffer_base(buf);	if (buf->fmt->planar)		bpl = buf->vb.width;	else		bpl = (buf->vb.width * buf->fmt->depth) / 8;	control = SAA7134_RS_CONTROL_BURST_16 |		SAA7134_RS_CONTROL_ME |		(buf->pt->dma >> 12);	if (buf->fmt->bswap)		control |= SAA7134_RS_CONTROL_BSWAP;	if (buf->fmt->wswap)		control |= SAA7134_RS_CONTROL_WSWAP;	if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {		/* interlaced */		saa_writel(SAA7134_RS_BA1(0),base);		saa_writel(SAA7134_RS_BA2(0),base+bpl);		saa_writel(SAA7134_RS_PITCH(0),bpl*2);	} else {		/* non-interlaced */		saa_writel(SAA7134_RS_BA1(0),base);		saa_writel(SAA7134_RS_BA2(0),base);		saa_writel(SAA7134_RS_PITCH(0),bpl);	}	saa_writel(SAA7134_RS_CONTROL(0),control);	if (buf->fmt->planar) {		/* DMA: setup channel 4+5 (= planar task A) */		bpl_uv   = bpl >> buf->fmt->hshift;		lines_uv = buf->vb.height >> buf->fmt->vshift;		base2    = base + bpl * buf->vb.height;		base3    = base2 + bpl_uv * lines_uv;		if (buf->fmt->uvswap)			tmp = base2, base2 = base3, base3 = tmp;		dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n",			bpl_uv,lines_uv,base2,base3);		if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {			/* interlaced */			saa_writel(SAA7134_RS_BA1(4),base2);			saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv);			saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2);			saa_writel(SAA7134_RS_BA1(5),base3);			saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv);			saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2);		} else {			/* non-interlaced */			saa_writel(SAA7134_RS_BA1(4),base2);			saa_writel(SAA7134_RS_BA2(4),base2);			saa_writel(SAA7134_RS_PITCH(4),bpl_uv);			saa_writel(SAA7134_RS_BA1(5),base3);			saa_writel(SAA7134_RS_BA2(5),base3);			saa_writel(SAA7134_RS_PITCH(5),bpl_uv);		}		saa_writel(SAA7134_RS_CONTROL(4),control);		saa_writel(SAA7134_RS_CONTROL(5),control);	}	/* start DMA */	saa7134_set_dmabits(dev);	mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT);	return 0;}static int buffer_prepare(struct file *file, struct videobuf_buffer *vb,			  enum v4l2_field field){	struct saa7134_fh *fh = file->private_data;	struct saa7134_dev *dev = fh->dev;	struct saa7134_buf *buf = (struct saa7134_buf *)vb;	unsigned int size;	int err;		/* sanity checks */	if (NULL == fh->fmt)		return -EINVAL;	if (fh->width  < 48 ||	    fh->height < 32 ||	    fh->width  > dev->crop_current.width ||	    fh->height > dev->crop_current.height)		return -EINVAL;	size = (fh->width * fh->height * fh->fmt->depth) >> 3;	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)		return -EINVAL;	dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n",		vb->i,fh->width,fh->height,size,v4l2_field_names[field],		fh->fmt->name);	if (buf->vb.width  != fh->width  ||	    buf->vb.height != fh->height ||	    buf->vb.size   != size       ||	    buf->vb.field  != field      ||	    buf->fmt       != fh->fmt) {		saa7134_dma_free(dev,buf);	}	if (STATE_NEEDS_INIT == buf->vb.state) {		buf->vb.width  = fh->width;		buf->vb.height = fh->height;		buf->vb.size   = size;		buf->vb.field  = field;		buf->fmt       = fh->fmt;		buf->pt        = &fh->pt_cap;		err = videobuf_iolock(dev->pci,&buf->vb,&dev->ovbuf);		if (err)			goto oops;		err = saa7134_pgtable_build(dev->pci,buf->pt,					    buf->vb.dma.sglist,					    buf->vb.dma.sglen,					    saa7134_buffer_startpage(buf));		if (err)			goto oops;	}	buf->vb.state = STATE_PREPARED;	buf->activate = buffer_activate;	return 0; oops:	saa7134_dma_free(dev,buf);	return err;}static intbuffer_setup(struct file *file, unsigned int *count, unsigned int *size){	struct saa7134_fh *fh = file->private_data;	*size = fh->fmt->depth * fh->width * fh->height >> 3;	if (0 == *count)		*count = gbuffers;	*count = saa7134_buffer_count(*size,*count);	return 0;}static void buffer_queue(struct file *file, struct videobuf_buffer *vb){	struct saa7134_fh *fh = file->private_data;	struct saa7134_buf *buf = (struct saa7134_buf *)vb;		saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf);}static void buffer_release(struct file *file, struct videobuf_buffer *vb){	struct saa7134_fh *fh = file->private_data;	struct saa7134_buf *buf = (struct saa7134_buf *)vb;		saa7134_dma_free(fh->dev,buf);}static struct videobuf_queue_ops video_qops = {	.buf_setup    = buffer_setup,	.buf_prepare  = buffer_prepare,	.buf_queue    = buffer_queue,	.buf_release  = buffer_release,};/* ------------------------------------------------------------------ */static int get_control(struct saa7134_dev *dev, struct v4l2_control *c){	const struct v4l2_queryctrl* ctrl;	ctrl = ctrl_by_id(c->id);	if (NULL == ctrl)		return -EINVAL;	switch (c->id) {	case V4L2_CID_BRIGHTNESS:		c->value = dev->ctl_bright;		break;	case V4L2_CID_HUE:		c->value = dev->ctl_hue;		break;	case V4L2_CID_CONTRAST:		c->value = dev->ctl_contrast;		break;	case V4L2_CID_SATURATION:		c->value = dev->ctl_saturation;		break;	case V4L2_CID_AUDIO_MUTE:		c->value = dev->ctl_mute;		break;	case V4L2_CID_AUDIO_VOLUME:		c->value = dev->ctl_volume;		break;	case V4L2_CID_PRIVATE_INVERT:		c->value = dev->ctl_invert;		break;	case V4L2_CID_VFLIP:		c->value = dev->ctl_mirror;		break;	case V4L2_CID_PRIVATE_Y_EVEN:		c->value = dev->ctl_y_even;		break;	case V4L2_CID_PRIVATE_Y_ODD:		c->value = dev->ctl_y_odd;		break;	default:		return -EINVAL;	}	return 0;}static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,		       struct v4l2_control *c){	const struct v4l2_queryctrl* ctrl;	unsigned long flags;	int restart_overlay = 0;	ctrl = ctrl_by_id(c->id);	if (NULL == ctrl)		return -EINVAL;	dprintk("set_control name=%s val=%d\n",ctrl->name,c->value);	switch (ctrl->type) {	case V4L2_CTRL_TYPE_BOOLEAN:	case V4L2_CTRL_TYPE_MENU:	case V4L2_CTRL_TYPE_INTEGER:		if (c->value < ctrl->minimum)			c->value = ctrl->minimum;		if (c->value > ctrl->maximum)			c->value = ctrl->maximum;		break;	default:		/* nothing */;	};	switch (c->id) {	case V4L2_CID_BRIGHTNESS:		dev->ctl_bright = c->value;		saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright);		break;	case V4L2_CID_HUE:		dev->ctl_hue = c->value;		saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue);		break;	case V4L2_CID_CONTRAST:		dev->ctl_contrast = c->value;		saa_writeb(SAA7134_DEC_LUMA_CONTRAST,			   dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);		break;	case V4L2_CID_SATURATION:		dev->ctl_saturation = c->value;		saa_writeb(SAA7134_DEC_CHROMA_SATURATION,			   dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);		break;	case V4L2_CID_AUDIO_MUTE:		dev->ctl_mute = c->value;		saa7134_tvaudio_setmute(dev);		break;	case V4L2_CID_AUDIO_VOLUME:		dev->ctl_volume = c->value;		saa7134_tvaudio_setvolume(dev,dev->ctl_volume);		break;	case V4L2_CID_PRIVATE_INVERT:		dev->ctl_invert = c->value;		saa_writeb(SAA7134_DEC_LUMA_CONTRAST,			   dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);		saa_writeb(SAA7134_DEC_CHROMA_SATURATION,			   dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);		break;	case V4L2_CID_VFLIP:		dev->ctl_mirror = c->value;		restart_overlay = 1;		break;	case V4L2_CID_PRIVATE_Y_EVEN:		dev->ctl_y_even = c->value;		restart_overlay = 1;		break;	case V4L2_CID_PRIVATE_Y_ODD:		dev->ctl_y_odd = c->value;		restart_overlay = 1;		break;	default:		return -EINVAL;	}	if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) {		spin_lock_irqsave(&dev->slock,flags);		stop_preview(dev,fh);		start_preview(dev,fh);		spin_unlock_irqrestore(&dev->slock,flags);	}	return 0;}/* ------------------------------------------------------------------ */static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh){	struct videobuf_queue* q = NULL;		switch (fh->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		q = &fh->cap;		break;	case V4L2_BUF_TYPE_VBI_CAPTURE:		q = &fh->vbi;		break;	default:		BUG();	}	return q;}static int saa7134_resource(struct saa7134_fh *fh){	int res = 0;		switch (fh->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		res = RESOURCE_VIDEO;		break;	case V4L2_BUF_TYPE_VBI_CAPTURE:		res = RESOURCE_VBI;		break;	default:		BUG();	}	return res;}static int video_open(struct inode *inode, struct file *file){	int minor = iminor(inode);	struct saa7134_dev *h,*dev = NULL;	struct saa7134_fh *fh;	struct list_head *list;

⌨️ 快捷键说明

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