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

📄 saa7134-core.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * * device driver for philips saa7134 based TV cards * driver core * * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/init.h>#include <linux/list.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/kmod.h>#include <linux/sound.h>#include <linux/interrupt.h>#include <linux/delay.h>#include <linux/mutex.h>#include <linux/dma-mapping.h>#include <linux/pm.h>#include "saa7134-reg.h"#include "saa7134.h"MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards");MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");MODULE_LICENSE("GPL");/* ------------------------------------------------------------------ */static unsigned int irq_debug = 0;module_param(irq_debug, int, 0644);MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");static unsigned int core_debug = 0;module_param(core_debug, int, 0644);MODULE_PARM_DESC(core_debug,"enable debug messages [core]");static unsigned int gpio_tracking = 0;module_param(gpio_tracking, int, 0644);MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");static unsigned int alsa = 0;module_param(alsa, int, 0644);MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]");static unsigned int oss = 0;module_param(oss, int, 0644);MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]");static unsigned int latency = UNSET;module_param(latency, int, 0444);MODULE_PARM_DESC(latency,"pci latency timer");int saa7134_no_overlay=-1;module_param_named(no_overlay, saa7134_no_overlay, int, 0444);MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"		" [some VIA/SIS chipsets are known to have problem with overlay]");static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };static unsigned int vbi_nr[]   = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };static unsigned int tuner[]    = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };static unsigned int card[]     = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };module_param_array(video_nr, int, NULL, 0444);module_param_array(vbi_nr,   int, NULL, 0444);module_param_array(radio_nr, int, NULL, 0444);module_param_array(tuner,    int, NULL, 0444);module_param_array(card,     int, NULL, 0444);MODULE_PARM_DESC(video_nr, "video device number");MODULE_PARM_DESC(vbi_nr,   "vbi device number");MODULE_PARM_DESC(radio_nr, "radio device number");MODULE_PARM_DESC(tuner,    "tuner type");MODULE_PARM_DESC(card,     "card type");static DEFINE_MUTEX(devlist_lock);LIST_HEAD(saa7134_devlist);static LIST_HEAD(mops_list);static unsigned int saa7134_devcount;int (*saa7134_dmasound_init)(struct saa7134_dev *dev);int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);#define dprintk(fmt, arg...)	if (core_debug) \	printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)void saa7134_track_gpio(struct saa7134_dev *dev, char *msg){	unsigned long mode,status;	if (!gpio_tracking)		return;	/* rising SAA7134_GPIO_GPRESCAN reads the status */	saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,0);	saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN);	mode   = saa_readl(SAA7134_GPIO_GPMODE0   >> 2) & 0xfffffff;	status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff;	printk(KERN_DEBUG	       "%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n",	       dev->name, mode, (~mode) & status, mode & status, msg);}void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value){	u32 index, bitval;	index = 1 << bit_no;	switch (value) {	case 0: /* static value */	case 1:	dprintk("setting GPIO%d to static %d\n", bit_no, value);		/* turn sync mode off if necessary */		if (index & 0x00c00000)			saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x00);		if (value)			bitval = index;		else			bitval = 0;		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, index);		saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, index, bitval);		break;	case 3:	/* tristate */		dprintk("setting GPIO%d to tristate\n", bit_no);		saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, index, 0);		break;	}}int saa7134_tuner_callback(void *ptr, int command, int arg){	u8 sync_control;	struct saa7134_dev *dev = ptr;	switch (dev->tuner_type) {	case TUNER_PHILIPS_TDA8290:		switch (command) {		case 0: /* switch LNA gain through GPIO 22*/			saa7134_set_gpio(dev, 22, arg) ;			break;		case 1: /* vsync output at GPIO22. 50 / 60Hz */			dprintk("setting GPIO22 to vsync %d\n", arg);			saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80);			saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03);			if (arg == 1)				sync_control = 11;			else				sync_control = 17;			saa_writeb(SAA7134_VGATE_START, sync_control);			saa_writeb(SAA7134_VGATE_STOP, sync_control + 1);			saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00);			break;		default:			return -EINVAL;		}		break;	default:		return -ENODEV;	}	return 0;}/* ------------------------------------------------------------------ *//* ----------------------------------------------------------- *//* delayed request_module                                      */#if defined(CONFIG_MODULES) && defined(MODULE)static void request_module_async(struct work_struct *work){	struct saa7134_dev* dev = container_of(work, struct saa7134_dev, request_module_wk);	if (card_is_empress(dev))		request_module("saa7134-empress");	if (card_is_dvb(dev))		request_module("saa7134-dvb");	if (alsa)		request_module("saa7134-alsa");	if (oss)		request_module("saa7134-oss");}static void request_submodules(struct saa7134_dev *dev){	INIT_WORK(&dev->request_module_wk, request_module_async);	schedule_work(&dev->request_module_wk);}#else#define request_submodules(dev)#endif /* CONFIG_MODULES *//* ------------------------------------------------------------------ *//* nr of (saa7134-)pages for the given buffer size */static int saa7134_buffer_pages(int size){	size  = PAGE_ALIGN(size);	size += PAGE_SIZE; /* for non-page-aligned buffers */	size /= 4096;	return size;}/* calc max # of buffers from size (must not exceed the 4MB virtual * address space per DMA channel) */int saa7134_buffer_count(unsigned int size, unsigned int count){	unsigned int maxcount;	maxcount = 1024 / saa7134_buffer_pages(size);	if (count > maxcount)		count = maxcount;	return count;}int saa7134_buffer_startpage(struct saa7134_buf *buf){	return saa7134_buffer_pages(buf->vb.bsize) * buf->vb.i;}unsigned long saa7134_buffer_base(struct saa7134_buf *buf){	unsigned long base;	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);	base  = saa7134_buffer_startpage(buf) * 4096;	base += dma->sglist[0].offset;	return base;}/* ------------------------------------------------------------------ */int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt){	__le32       *cpu;	dma_addr_t   dma_addr;	cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);	if (NULL == cpu)		return -ENOMEM;	pt->size = SAA7134_PGTABLE_SIZE;	pt->cpu  = cpu;	pt->dma  = dma_addr;	return 0;}int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,			  struct scatterlist *list, unsigned int length,			  unsigned int startpage){	__le32        *ptr;	unsigned int  i,p;	BUG_ON(NULL == pt || NULL == pt->cpu);	ptr = pt->cpu + startpage;	for (i = 0; i < length; i++, list++)		for (p = 0; p * 4096 < list->length; p++, ptr++)			*ptr = cpu_to_le32(sg_dma_address(list) - list->offset);	return 0;}void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt){	if (NULL == pt->cpu)		return;	pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);	pt->cpu = NULL;}/* ------------------------------------------------------------------ */void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf){	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);	BUG_ON(in_interrupt());	videobuf_waiton(&buf->vb,0,0);	videobuf_dma_unmap(q, dma);	videobuf_dma_free(dma);	buf->vb.state = STATE_NEEDS_INIT;}/* ------------------------------------------------------------------ */int saa7134_buffer_queue(struct saa7134_dev *dev,			 struct saa7134_dmaqueue *q,			 struct saa7134_buf *buf){	struct saa7134_buf *next = NULL;	assert_spin_locked(&dev->slock);	dprintk("buffer_queue %p\n",buf);	if (NULL == q->curr) {		if (!q->need_two) {			q->curr = buf;			buf->activate(dev,buf,NULL);		} else if (list_empty(&q->queue)) {			list_add_tail(&buf->vb.queue,&q->queue);			buf->vb.state = STATE_QUEUED;		} else {			next = list_entry(q->queue.next,struct saa7134_buf,					  vb.queue);			q->curr = buf;			buf->activate(dev,buf,next);		}	} else {		list_add_tail(&buf->vb.queue,&q->queue);		buf->vb.state = STATE_QUEUED;	}	return 0;}void saa7134_buffer_finish(struct saa7134_dev *dev,			   struct saa7134_dmaqueue *q,			   unsigned int state){	assert_spin_locked(&dev->slock);	dprintk("buffer_finish %p\n",q->curr);	/* finish current buffer */	q->curr->vb.state = state;	do_gettimeofday(&q->curr->vb.ts);	wake_up(&q->curr->vb.done);	q->curr = NULL;}void saa7134_buffer_next(struct saa7134_dev *dev,			 struct saa7134_dmaqueue *q){	struct saa7134_buf *buf,*next = NULL;	assert_spin_locked(&dev->slock);	BUG_ON(NULL != q->curr);	if (!list_empty(&q->queue)) {		/* activate next one from queue */		buf = list_entry(q->queue.next,struct saa7134_buf,vb.queue);		dprintk("buffer_next %p [prev=%p/next=%p]\n",			buf,q->queue.prev,q->queue.next);		list_del(&buf->vb.queue);		if (!list_empty(&q->queue))			next = list_entry(q->queue.next,struct saa7134_buf,					  vb.queue);		q->curr = buf;		buf->activate(dev,buf,next);		dprintk("buffer_next #2 prev=%p/next=%p\n",			q->queue.prev,q->queue.next);	} else {		/* nothing to do -- just stop DMA */		dprintk("buffer_next %p\n",NULL);		saa7134_set_dmabits(dev);		del_timer(&q->timeout);	}}void saa7134_buffer_timeout(unsigned long data){	struct saa7134_dmaqueue *q = (struct saa7134_dmaqueue*)data;	struct saa7134_dev *dev = q->dev;	unsigned long flags;	spin_lock_irqsave(&dev->slock,flags);	/* try to reset the hardware (SWRST) */	saa_writeb(SAA7134_REGION_ENABLE, 0x00);	saa_writeb(SAA7134_REGION_ENABLE, 0x80);	saa_writeb(SAA7134_REGION_ENABLE, 0x00);	/* flag current buffer as failed,	   try to start over with the next one. */	if (q->curr) {		dprintk("timeout on %p\n",q->curr);		saa7134_buffer_finish(dev,q,STATE_ERROR);	}	saa7134_buffer_next(dev,q);	spin_unlock_irqrestore(&dev->slock,flags);}/* resends a current buffer in queue after resume */int saa7134_buffer_requeue(struct saa7134_dev *dev,			 struct saa7134_dmaqueue *q){	struct saa7134_buf *buf, *next;	assert_spin_locked(&dev->slock);	buf  = q->curr;	next = buf;	dprintk("buffer_requeue\n");	if (!buf)		return 0;	dprintk("buffer_requeue : resending active buffers \n");	if (!list_empty(&q->queue))		next = list_entry(q->queue.next, struct saa7134_buf,					  vb.queue);	buf->activate(dev, buf, next);	return 0;}/* ------------------------------------------------------------------ */int saa7134_set_dmabits(struct saa7134_dev *dev){	u32 split, task=0, ctrl=0, irq=0;	enum v4l2_field cap = V4L2_FIELD_ANY;	enum v4l2_field ov  = V4L2_FIELD_ANY;	assert_spin_locked(&dev->slock);	if (dev->insuspend)		return 0;	/* video capture -- dma 0 + video task A */	if (dev->video_q.curr) {		task |= 0x01;		ctrl |= SAA7134_MAIN_CTRL_TE0;		irq  |= SAA7134_IRQ1_INTE_RA0_1 |			SAA7134_IRQ1_INTE_RA0_0;		cap = dev->video_q.curr->vb.field;	}	/* video capture -- dma 1+2 (planar modes) */	if (dev->video_q.curr &&	    dev->video_q.curr->fmt->planar) {		ctrl |= SAA7134_MAIN_CTRL_TE4 |

⌨️ 快捷键说明

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