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

📄 cx23885-video.c

📁 trident tm5600的linux驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
	unsigned int height, enum v4l2_field field){	dprintk(1, "%s()\n", __func__);	return 0;}static int cx23885_start_video_dma(struct cx23885_dev *dev,			   struct cx23885_dmaqueue *q,			   struct cx23885_buffer *buf){	dprintk(1, "%s()\n", __func__);	/* setup fifo + format */	cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],				buf->bpl, buf->risc.dma);	cx23885_set_scale(dev, buf->vb.width, buf->vb.height, buf->vb.field);	/* reset counter */	cx_write(VID_A_GPCNT_CTL, 3);	q->count = 1;	/* enable irq */	cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);	cx_set(VID_A_INT_MSK, 0x000011);	/* start dma */	cx_set(DEV_CNTRL2, (1<<5));	cx_set(VID_A_DMA_CTL, 0x11); /* FIFO and RISC enable */	return 0;}#if 0#ifdef CONFIG_PMstatic int cx23885_stop_video_dma(struct cx23885_dev *dev){	dprintk(1, "%s()\n", __func__);	/* stop dma */	cx_clear(VID_A_DMA_CTL, 0x11);	/* disable irqs */	cx_clear(PCI_INT_MSK, 0x000001);	cx_clear(VID_A_INT_MSK, 0x000011);	return 0;}#endif#endifstatic int cx23885_restart_video_queue(struct cx23885_dev *dev,			       struct cx23885_dmaqueue *q){	struct cx23885_buffer *buf, *prev;	struct list_head *item;	dprintk(1, "%s()\n", __func__);	if (!list_empty(&q->active)) {		buf = list_entry(q->active.next, struct cx23885_buffer,			vb.queue);		dprintk(2, "restart_queue [%p/%d]: restart dma\n",			buf, buf->vb.i);		cx23885_start_video_dma(dev, q, buf);		list_for_each(item, &q->active) {			buf = list_entry(item, struct cx23885_buffer,				vb.queue);			buf->count    = q->count++;		}		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);		return 0;	}	prev = NULL;	for (;;) {		if (list_empty(&q->queued))			return 0;		buf = list_entry(q->queued.next, struct cx23885_buffer,			vb.queue);		if (NULL == prev) {			list_move_tail(&buf->vb.queue, &q->active);			cx23885_start_video_dma(dev, q, buf);			buf->vb.state = VIDEOBUF_ACTIVE;			buf->count    = q->count++;			mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);			dprintk(2, "[%p/%d] restart_queue - first active\n",				buf, buf->vb.i);		} else if (prev->vb.width  == buf->vb.width  &&			   prev->vb.height == buf->vb.height &&			   prev->fmt       == buf->fmt) {			list_move_tail(&buf->vb.queue, &q->active);			buf->vb.state = VIDEOBUF_ACTIVE;			buf->count    = q->count++;			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);			prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */			dprintk(2, "[%p/%d] restart_queue - move to active\n",				buf, buf->vb.i);		} else {			return 0;		}		prev = buf;	}}static int buffer_setup(struct videobuf_queue *q, unsigned int *count,	unsigned int *size){	struct cx23885_fh *fh = q->priv_data;	*size = fh->fmt->depth*fh->width*fh->height >> 3;	if (0 == *count)		*count = 32;	while (*size * *count > vid_limit * 1024 * 1024)		(*count)--;	return 0;}static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,	       enum v4l2_field field){	struct cx23885_fh *fh  = q->priv_data;	struct cx23885_dev *dev = fh->dev;	struct cx23885_buffer *buf =		container_of(vb, struct cx23885_buffer, vb);	int rc, init_buffer = 0;	u32 line0_offset, line1_offset;	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);	BUG_ON(NULL == fh->fmt);	if (fh->width  < 48 || fh->width  > norm_maxw(dev->tvnorm) ||	    fh->height < 32 || fh->height > norm_maxh(dev->tvnorm))		return -EINVAL;	buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;	if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)		return -EINVAL;	if (buf->fmt       != fh->fmt    ||	    buf->vb.width  != fh->width  ||	    buf->vb.height != fh->height ||	    buf->vb.field  != field) {		buf->fmt       = fh->fmt;		buf->vb.width  = fh->width;		buf->vb.height = fh->height;		buf->vb.field  = field;		init_buffer = 1;	}	if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {		init_buffer = 1;		rc = videobuf_iolock(q, &buf->vb, NULL);		if (0 != rc)			goto fail;	}	if (init_buffer) {		buf->bpl = buf->vb.width * buf->fmt->depth >> 3;		switch (buf->vb.field) {		case V4L2_FIELD_TOP:			cx23885_risc_buffer(dev->pci, &buf->risc,					 dma->sglist, 0, UNSET,					 buf->bpl, 0, buf->vb.height);			break;		case V4L2_FIELD_BOTTOM:			cx23885_risc_buffer(dev->pci, &buf->risc,					 dma->sglist, UNSET, 0,					 buf->bpl, 0, buf->vb.height);			break;		case V4L2_FIELD_INTERLACED:			if (dev->tvnorm & V4L2_STD_NTSC) {				/* cx25840 transmits NTSC bottom field first */				dprintk(1, "%s() Creating NTSC risc\n",					__func__);				line0_offset = buf->bpl;				line1_offset = 0;			} else {				/* All other formats are top field first */				dprintk(1, "%s() Creating PAL/SECAM risc\n",					__func__);				line0_offset = 0;				line1_offset = buf->bpl;			}			cx23885_risc_buffer(dev->pci, &buf->risc,					dma->sglist, line0_offset,					line1_offset,					buf->bpl, buf->bpl,					buf->vb.height >> 1);			break;		case V4L2_FIELD_SEQ_TB:			cx23885_risc_buffer(dev->pci, &buf->risc,					 dma->sglist,					 0, buf->bpl * (buf->vb.height >> 1),					 buf->bpl, 0,					 buf->vb.height >> 1);			break;		case V4L2_FIELD_SEQ_BT:			cx23885_risc_buffer(dev->pci, &buf->risc,					 dma->sglist,					 buf->bpl * (buf->vb.height >> 1), 0,					 buf->bpl, 0,					 buf->vb.height >> 1);			break;		default:			BUG();		}	}	dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",		buf, buf->vb.i,		fh->width, fh->height, fh->fmt->depth, fh->fmt->name,		(unsigned long)buf->risc.dma);	buf->vb.state = VIDEOBUF_PREPARED;	return 0; fail:	cx23885_free_buffer(q, buf);	return rc;}static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb){	struct cx23885_buffer   *buf = container_of(vb,		struct cx23885_buffer, vb);	struct cx23885_buffer   *prev;	struct cx23885_fh       *fh   = vq->priv_data;	struct cx23885_dev      *dev  = fh->dev;	struct cx23885_dmaqueue *q    = &dev->vidq;	/* add jump to stopper */	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);	buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */	if (!list_empty(&q->queued)) {		list_add_tail(&buf->vb.queue, &q->queued);		buf->vb.state = VIDEOBUF_QUEUED;		dprintk(2, "[%p/%d] buffer_queue - append to queued\n",			buf, buf->vb.i);	} else if (list_empty(&q->active)) {		list_add_tail(&buf->vb.queue, &q->active);		cx23885_start_video_dma(dev, q, buf);		buf->vb.state = VIDEOBUF_ACTIVE;		buf->count    = q->count++;		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);		dprintk(2, "[%p/%d] buffer_queue - first active\n",			buf, buf->vb.i);	} else {		prev = list_entry(q->active.prev, struct cx23885_buffer,			vb.queue);		if (prev->vb.width  == buf->vb.width  &&		    prev->vb.height == buf->vb.height &&		    prev->fmt       == buf->fmt) {			list_add_tail(&buf->vb.queue, &q->active);			buf->vb.state = VIDEOBUF_ACTIVE;			buf->count    = q->count++;			prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);			/* 64 bit bits 63-32 */			prev->risc.jmp[2] = cpu_to_le32(0);			dprintk(2, "[%p/%d] buffer_queue - append to active\n",				buf, buf->vb.i);		} else {			list_add_tail(&buf->vb.queue, &q->queued);			buf->vb.state = VIDEOBUF_QUEUED;			dprintk(2, "[%p/%d] buffer_queue - first queued\n",				buf, buf->vb.i);		}	}}static void buffer_release(struct videobuf_queue *q,	struct videobuf_buffer *vb){	struct cx23885_buffer *buf = container_of(vb,		struct cx23885_buffer, vb);	cx23885_free_buffer(q, buf);}static struct videobuf_queue_ops cx23885_video_qops = {	.buf_setup    = buffer_setup,	.buf_prepare  = buffer_prepare,	.buf_queue    = buffer_queue,	.buf_release  = buffer_release,};static struct videobuf_queue *get_queue(struct cx23885_fh *fh){	switch (fh->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		return &fh->vidq;	case V4L2_BUF_TYPE_VBI_CAPTURE:		return &fh->vbiq;	default:		BUG();		return NULL;	}}static int get_resource(struct cx23885_fh *fh){	switch (fh->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		return RESOURCE_VIDEO;	case V4L2_BUF_TYPE_VBI_CAPTURE:		return RESOURCE_VBI;	default:		BUG();		return 0;	}}static int video_open(struct inode *inode, struct file *file){	int minor = iminor(inode);	struct cx23885_dev *h, *dev = NULL;	struct cx23885_fh *fh;	struct list_head *list;	enum v4l2_buf_type type = 0;	int radio = 0;	lock_kernel();	list_for_each(list, &cx23885_devlist) {		h = list_entry(list, struct cx23885_dev, devlist);		if (h->video_dev->minor == minor) {			dev  = h;			type = V4L2_BUF_TYPE_VIDEO_CAPTURE;		}		if (h->vbi_dev &&		   h->vbi_dev->minor == minor) {			dev  = h;			type = V4L2_BUF_TYPE_VBI_CAPTURE;		}		if (h->radio_dev &&		    h->radio_dev->minor == minor) {			radio = 1;			dev   = h;		}	}	if (NULL == dev) {		unlock_kernel();		return -ENODEV;	}	dprintk(1, "open minor=%d radio=%d type=%s\n",		minor, radio, v4l2_type_names[type]);	/* allocate + initialize per filehandle data */	fh = kzalloc(sizeof(*fh), GFP_KERNEL);	if (NULL == fh) {		unlock_kernel();		return -ENOMEM;	}	file->private_data = fh;	fh->dev      = dev;	fh->radio    = radio;	fh->type     = type;	fh->width    = 320;	fh->height   = 240;	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);	videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops,			    &dev->pci->dev, &dev->slock,			    V4L2_BUF_TYPE_VIDEO_CAPTURE,			    V4L2_FIELD_INTERLACED,			    sizeof(struct cx23885_buffer),			    fh);	dprintk(1, "post videobuf_queue_init()\n");#if 0	if (fh->radio) {		int board = dev->board;		dprintk(1, "video_open: setting radio device\n");		cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3);		cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0);		cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1);		cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2);		dev->tvaudio = WW_FM;		cx23885_set_tvaudio(dev);		cx23885_set_stereo(dev, V4L2_TUNER_MODE_STEREO, 1);		cx23885_call_i2c_clients(&dev->i2c_bus[1],			AUDC_SET_RADIO, NULL);	}#endif	unlock_kernel();	return 0;}static ssize_t video_read(struct file *file, char __user *data,	size_t count, loff_t *ppos){	struct cx23885_fh *fh = file->private_data;	switch (fh->type) {	case V4L2_BUF_TYPE_VIDEO_CAPTURE:		if (res_locked(fh->dev, RESOURCE_VIDEO))			return -EBUSY;		return videobuf_read_one(&fh->vidq, data, count, ppos,					 file->f_flags & O_NONBLOCK);	case V4L2_BUF_TYPE_VBI_CAPTURE:		if (!res_get(fh->dev, fh, RESOURCE_VBI))			return -EBUSY;		return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,					    file->f_flags & O_NONBLOCK);	default:		BUG();		return 0;	}}static unsigned int video_poll(struct file *file,	struct poll_table_struct *wait){	struct cx23885_fh *fh = file->private_data;	struct cx23885_buffer *buf;	if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {		if (!res_get(fh->dev, fh, RESOURCE_VBI))			return POLLERR;		return videobuf_poll_stream(file, &fh->vbiq, wait);	}	if (res_check(fh, RESOURCE_VIDEO)) {		/* streaming capture */		if (list_empty(&fh->vidq.stream))			return POLLERR;		buf = list_entry(fh->vidq.stream.next,			struct cx23885_buffer, vb.stream);	} else {		/* read() capture */		buf = (struct cx23885_buffer *)fh->vidq.read_buf;		if (NULL == buf)			return POLLERR;	}	poll_wait(file, &buf->vb.done, wait);	if (buf->vb.state == VIDEOBUF_DONE ||	    buf->vb.state == VIDEOBUF_ERROR)		return POLLIN|POLLRDNORM;	return 0;}static int video_release(struct inode *inode, struct file *file){	struct cx23885_fh *fh = file->private_data;	struct cx23885_dev *dev = fh->dev;	/* turn off overlay */	if (res_check(fh, RESOURCE_OVERLAY)) {		/* FIXME */		res_free(dev, fh, RESOURCE_OVERLAY);	}	/* stop video capture */	if (res_check(fh, RESOURCE_VIDEO)) {		videobuf_queue_cancel(&fh->vidq);		res_free(dev, fh, RESOURCE_VIDEO);	}	if (fh->vidq.read_buf) {		buffer_release(&fh->vidq, fh->vidq.read_buf);		kfree(fh->vidq.read_buf);	}

⌨️ 快捷键说明

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