saa7146_core.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 602 行 · 第 1/2 页

C
602
字号
/*    saa7146.o - driver for generic saa7146-based hardware    Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de>    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 <media/saa7146.h>LIST_HEAD(saa7146_devices);DEFINE_MUTEX(saa7146_devices_lock);static int saa7146_num;unsigned int saa7146_debug;module_param(saa7146_debug, uint, 0644);MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");#if 0 /* keep */static void dump_registers(struct saa7146_dev* dev){	int i = 0;	INFO((" @ %li jiffies:\n",jiffies));	for(i = 0; i <= 0x148; i+=4) {		printk("0x%03x: 0x%08x\n",i,saa7146_read(dev,i));	}}#endif/**************************************************************************** * gpio and debi helper functions ****************************************************************************/void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data){	u32 value = 0;	BUG_ON(port > 3);	value = saa7146_read(dev, GPIO_CTRL);	value &= ~(0xff << (8*port));	value |= (data << (8*port));	saa7146_write(dev, GPIO_CTRL, value);}/* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,				unsigned long us1, unsigned long us2){	unsigned long timeout;	int err;	/* wait for registers to be programmed */	timeout = jiffies + usecs_to_jiffies(us1);	while (1) {		err = time_after(jiffies, timeout);		if (saa7146_read(dev, MC2) & 2)			break;		if (err) {			printk(KERN_ERR "%s: %s timed out while waiting for "					"registers getting programmed\n",					dev->name, __func__);			return -ETIMEDOUT;		}		msleep(1);	}	/* wait for transfer to complete */	timeout = jiffies + usecs_to_jiffies(us2);	while (1) {		err = time_after(jiffies, timeout);		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))			break;		saa7146_read(dev, MC2);		if (err) {			DEB_S(("%s: %s timed out while waiting for transfer "				"completion\n",	dev->name, __func__));			return -ETIMEDOUT;		}		msleep(1);	}	return 0;}static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev,				unsigned long us1, unsigned long us2){	unsigned long loops;	/* wait for registers to be programmed */	loops = us1;	while (1) {		if (saa7146_read(dev, MC2) & 2)			break;		if (!loops--) {			printk(KERN_ERR "%s: %s timed out while waiting for "					"registers getting programmed\n",					dev->name, __func__);			return -ETIMEDOUT;		}		udelay(1);	}	/* wait for transfer to complete */	loops = us2 / 5;	while (1) {		if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))			break;		saa7146_read(dev, MC2);		if (!loops--) {			DEB_S(("%s: %s timed out while waiting for transfer "				"completion\n", dev->name, __func__));			return -ETIMEDOUT;		}		udelay(5);	}	return 0;}int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop){	if (nobusyloop)		return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000);	else		return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000);}/**************************************************************************** * general helper functions ****************************************************************************//* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c   make sure virt has been allocated with vmalloc_32(), otherwise the BUG()   may be triggered on highmem machines */static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages){	struct scatterlist *sglist;	struct page *pg;	int i;	sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);	if (NULL == sglist)		return NULL;	sg_init_table(sglist, nr_pages);	for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {		pg = vmalloc_to_page(virt);		if (NULL == pg)			goto err;		BUG_ON(PageHighMem(pg));		sg_set_page(&sglist[i], pg, PAGE_SIZE, 0);	}	return sglist; err:	kfree(sglist);	return NULL;}/********************************************************************************//* common page table functions */void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt){	int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;	void *mem = vmalloc_32(length);	int slen = 0;	if (NULL == mem)		goto err_null;	if (!(pt->slist = vmalloc_to_sg(mem, pages)))		goto err_free_mem;	if (saa7146_pgtable_alloc(pci, pt))		goto err_free_slist;	pt->nents = pages;	slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE);	if (0 == slen)		goto err_free_pgtable;	if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen))		goto err_unmap_sg;	return mem;err_unmap_sg:	pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);err_free_pgtable:	saa7146_pgtable_free(pci, pt);err_free_slist:	kfree(pt->slist);	pt->slist = NULL;err_free_mem:	vfree(mem);err_null:	return NULL;}void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt){	pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);	saa7146_pgtable_free(pci, pt);	kfree(pt->slist);	pt->slist = NULL;	vfree(mem);}void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt){	if (NULL == pt->cpu)		return;	pci_free_consistent(pci, pt->size, pt->cpu, pt->dma);	pt->cpu = NULL;}int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt){	__le32       *cpu;	dma_addr_t   dma_addr = 0;	cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr);	if (NULL == cpu) {		return -ENOMEM;	}	pt->size = PAGE_SIZE;	pt->cpu  = cpu;	pt->dma  = dma_addr;	return 0;}int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt,	struct scatterlist *list, int sglen  ){	__le32 *ptr, fill;	int nr_pages = 0;	int i,p;	BUG_ON(0 == sglen);	BUG_ON(list->offset > PAGE_SIZE);	/* if we have a user buffer, the first page may not be	   aligned to a page boundary. */	pt->offset = list->offset;	ptr = pt->cpu;	for (i = 0; i < sglen; i++, list++) {/*		printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset);*/		for (p = 0; p * 4096 < list->length; p++, ptr++) {			*ptr = cpu_to_le32(sg_dma_address(list) + p * 4096);			nr_pages++;		}	}	/* safety; fill the page table up with the last valid page */	fill = *(ptr-1);	for(i=nr_pages;i<1024;i++) {		*ptr++ = fill;	}/*	ptr = pt->cpu;	printk("offset: %d\n",pt->offset);	for(i=0;i<5;i++) {		printk("ptr1 %d: 0x%08x\n",i,ptr[i]);	}*/	return 0;}/********************************************************************************//* interrupt handler */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)#elsestatic irqreturn_t interrupt_hw(int irq, void *dev_id)#endif{	struct saa7146_dev *dev = dev_id;	u32 isr;

⌨️ 快捷键说明

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