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

📄 bttv-driver.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 5 页
字号:
/*    bttv - Bt848 frame grabber driver    Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)                           & Marcus Metzler (mocm@thp.uni-koeln.de)    (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.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 <linux/version.h>#include <linux/module.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/slab.h>#include <linux/mm.h>#include <linux/poll.h>#include <linux/pci.h>#include <linux/signal.h>#include <asm/io.h>#include <linux/ioport.h>#include <asm/pgtable.h>#include <asm/page.h>#include <linux/sched.h>#include <asm/segment.h>#include <linux/types.h>#include <linux/wrapper.h>#include <linux/interrupt.h>#include <linux/kmod.h>#include <linux/vmalloc.h>#include <linux/init.h>#include "bttvp.h"#include "tuner.h"#define DEBUG(x)	/* Debug driver */#define MIN(a,b) (((a)>(b))?(b):(a))#define MAX(a,b) (((a)>(b))?(a):(b))static void bt848_set_risc_jmps(struct bttv *btv, int state);int bttv_num;			/* number of Bt848s in use */struct bttv bttvs[BTTV_MAX];/* configuration variables */#if defined(__sparc__) || defined(__powerpc__) || defined(__hppa__)static unsigned int bigendian=1;#elsestatic unsigned int bigendian=0;#endifstatic unsigned int radio[BTTV_MAX];static unsigned int fieldnr = 0;static unsigned int irq_debug = 0;static unsigned int gbuffers = 2;static unsigned int gbufsize = BTTV_MAX_FBUF;static unsigned int combfilter = 0;static unsigned int lumafilter = 0;static int video_nr = -1;static int radio_nr = -1;static int vbi_nr = -1;unsigned int bttv_debug = 0;unsigned int bttv_verbose = 1;unsigned int bttv_gpio = 0;/* insmod options */MODULE_PARM(radio,"1-4i");MODULE_PARM_DESC(radio,"The TV card supports radio, default is 0 (no)");MODULE_PARM(bigendian,"i");MODULE_PARM_DESC(bigendian,"byte order of the framebuffer, default is native endian");MODULE_PARM(fieldnr,"i");MODULE_PARM_DESC(fieldnr,"count fields, default is 0 (no)");MODULE_PARM(bttv_verbose,"i");MODULE_PARM_DESC(bttv_verbose,"verbose startup messages, default is 1 (yes)");MODULE_PARM(bttv_gpio,"i");MODULE_PARM_DESC(bttv_gpio,"log gpio changes, default is 0 (no)");MODULE_PARM(bttv_debug,"i");MODULE_PARM_DESC(bttv_debug,"debug messages, default is 0 (no)");MODULE_PARM(irq_debug,"i");MODULE_PARM_DESC(irq_debug,"irq handler debug messages, default is 0 (no)");MODULE_PARM(gbuffers,"i");MODULE_PARM_DESC(gbuffers,"number of capture buffers, default is 2 (64 max)");MODULE_PARM(gbufsize,"i");MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");MODULE_PARM(combfilter,"i");MODULE_PARM(lumafilter,"i");MODULE_PARM(video_nr,"i");MODULE_PARM(radio_nr,"i");MODULE_PARM(vbi_nr,"i");MODULE_DESCRIPTION("bttv - v4l driver module for bt848/878 based cards");MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");MODULE_LICENSE("GPL");/* kernel args */#ifndef MODULEstatic int __init p_radio(char *str) { return bttv_parse(str,BTTV_MAX,radio); }__setup("bttv.radio=", p_radio);#endif#define I2C_TIMING (0x7<<4)#define I2C_DELAY   10#define I2C_SET(CTRL,DATA) \    { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); }#define I2C_GET()   (btread(BT848_I2C)&1)#define BURSTOFFSET 76#define BTTV_ERRORS 5/*******************************//* Memory management functions *//*******************************/#define MDEBUG(x)	do { } while(0)		/* Debug memory management *//* [DaveM] I've recoded most of this so that: * 1) It's easier to tell what is happening * 2) It's more portable, especially for translating things *    out of vmalloc mapped areas in the kernel. * 3) Less unnecessary translations happen. * * The code used to assume that the kernel vmalloc mappings * existed in the page tables of every process, this is simply * not guarenteed.  We now use pgd_offset_k which is the * defined way to get at the kernel page tables. *//* Given PGD from the address space's page table, return the kernel * virtual mapping of the physical memory mapped at ADR. */static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr){        unsigned long ret = 0UL;	pmd_t *pmd;	pte_t *ptep, pte;  	if (!pgd_none(*pgd)) {                pmd = pmd_offset(pgd, adr);                if (!pmd_none(*pmd)) {                        ptep = pte_offset(pmd, adr);                        pte = *ptep;                        if(pte_present(pte)) {				ret  = (unsigned long) page_address(pte_page(pte));				ret |= (adr & (PAGE_SIZE - 1));							}                }        }        MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret));	return ret;}static inline unsigned long uvirt_to_bus(unsigned long adr) {        unsigned long kva, ret;        kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr);	ret = virt_to_bus((void *)kva);        MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret));        return ret;}static inline unsigned long kvirt_to_bus(unsigned long adr) {        unsigned long va, kva, ret;        va = VMALLOC_VMADDR(adr);        kva = uvirt_to_kva(pgd_offset_k(va), va);	ret = virt_to_bus((void *)kva);        MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret));        return ret;}/* Here we want the physical address of the memory. * This is used when initializing the contents of the * area and marking the pages as reserved. */static inline unsigned long kvirt_to_pa(unsigned long adr) {        unsigned long va, kva, ret;        va = VMALLOC_VMADDR(adr);        kva = uvirt_to_kva(pgd_offset_k(va), va);	ret = __pa(kva);        MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret));        return ret;}static void * rvmalloc(signed long size){	void * mem;	unsigned long adr, page;	mem=vmalloc_32(size);	if (NULL == mem)		printk(KERN_INFO "bttv: vmalloc_32(%ld) failed\n",size);	else {		/* Clear the ram out, no junk to the user */		memset(mem, 0, size);	        adr=(unsigned long) mem;		while (size > 0)                 {	                page = kvirt_to_pa(adr);			mem_map_reserve(virt_to_page(__va(page)));			adr+=PAGE_SIZE;			size-=PAGE_SIZE;		}	}	return mem;}static void rvfree(void * mem, signed long size){        unsigned long adr, page;        	if (mem) 	{	        adr=(unsigned long) mem;		while (size > 0)                 {	                page = kvirt_to_pa(adr);			mem_map_unreserve(virt_to_page(__va(page)));			adr+=PAGE_SIZE;			size-=PAGE_SIZE;		}		vfree(mem);	}}/* *	Create the giant waste of buffer space we need for now *	until we get DMA to user space sorted out (probably 2.3.x) * *	We only create this as and when someone uses mmap */ static int fbuffer_alloc(struct bttv *btv){	if(!btv->fbuffer)		btv->fbuffer=(unsigned char *) rvmalloc(gbuffers*gbufsize);	else		printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n",			btv->nr);	if(!btv->fbuffer)		return -ENOBUFS;	return 0;}/* ----------------------------------------------------------------------- */void bttv_gpio_tracking(struct bttv *btv, char *comment){	unsigned int outbits, data;	outbits = btread(BT848_GPIO_OUT_EN);	data    = btread(BT848_GPIO_DATA);	printk(KERN_DEBUG "bttv%d: gpio: en=%08x, out=%08x in=%08x [%s]\n",	       btv->nr,outbits,data & outbits, data & ~outbits, comment);}static char *audio_modes[] = { "audio: tuner", "audio: radio", "audio: extern",			       "audio: intern", "audio: off" };static void audio(struct bttv *btv, int mode, int no_irq_context){	btaor(bttv_tvcards[btv->type].gpiomask, ~bttv_tvcards[btv->type].gpiomask,              BT848_GPIO_OUT_EN);	switch (mode)	{	        case AUDIO_MUTE:                        btv->audio|=AUDIO_MUTE;			break; 		case AUDIO_UNMUTE:			btv->audio&=~AUDIO_MUTE;			mode=btv->audio;			break;		case AUDIO_OFF:			mode=AUDIO_OFF;			break;		case AUDIO_ON:			mode=btv->audio;			break;		default:			btv->audio&=AUDIO_MUTE;			btv->audio|=mode;			break;	}        /* if audio mute or not in H-lock, turn audio off */	if ((btv->audio&AUDIO_MUTE))	        mode=AUDIO_OFF;        if ((mode == AUDIO_TUNER) && (btv->radio))		mode = AUDIO_RADIO;	btaor(bttv_tvcards[btv->type].audiomux[mode],              ~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA);	if (bttv_gpio)		bttv_gpio_tracking(btv,audio_modes[mode]);	if (no_irq_context)		bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(mode));}extern inline void bt848_dma(struct bttv *btv, uint state){	if (state)		btor(3, BT848_GPIO_DMA_CTL);	else		btand(~3, BT848_GPIO_DMA_CTL);}/* If Bt848a or Bt849, use PLL for PAL/SECAM and crystal for NTSC*//* Frequency = (F_input / PLL_X) * PLL_I.PLL_F/PLL_C    PLL_X = Reference pre-divider (0=1, 1=2)    PLL_C = Post divider (0=6, 1=4)   PLL_I = Integer input    PLL_F = Fractional input       F_input = 28.636363 MHz:    PAL (CLKx2 = 35.46895 MHz): PLL_X = 1, PLL_I = 0x0E, PLL_F = 0xDCF9, PLL_C = 0*/static void set_pll_freq(struct bttv *btv, unsigned int fin, unsigned int fout){        unsigned char fl, fh, fi;                /* prevent overflows */        fin/=4;        fout/=4;        fout*=12;        fi=fout/fin;        fout=(fout%fin)*256;        fh=fout/fin;        fout=(fout%fin)*256;        fl=fout/fin;        /*printk("0x%02x 0x%02x 0x%02x\n", fi, fh, fl);*/        btwrite(fl, BT848_PLL_F_LO);        btwrite(fh, BT848_PLL_F_HI);        btwrite(fi|BT848_PLL_X, BT848_PLL_XCI);}static int set_pll(struct bttv *btv){        int i;	unsigned long tv;        if (!btv->pll.pll_crystal)                return 0;        if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {                /* no PLL needed */                if (btv->pll.pll_current == 0) {                        /* printk ("bttv%d: PLL: is off\n",btv->nr); */                        return 0;                }		if (bttv_verbose)			printk ("bttv%d: PLL: switching off\n",btv->nr);                btwrite(0x00,BT848_TGCTRL);                btwrite(0x00,BT848_PLL_XCI);                btv->pll.pll_current = 0;                return 0;        }        if (btv->pll.pll_ofreq == btv->pll.pll_current) {                /* printk("bttv%d: PLL: no change required\n",btv->nr); */                return 1;        }        if (bttv_verbose)		printk("bttv%d: PLL: %d => %d ... ",btv->nr,		       btv->pll.pll_ifreq, btv->pll.pll_ofreq);	set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq);	/*  Let other people run while the PLL stabilizes */	tv=jiffies+HZ/10;       /* .1 seconds */	do	{		schedule();	}	while(time_before(jiffies,tv));        for (i=0; i<100; i++)         {                if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK))                        btwrite(0,BT848_DSTATUS);                else                {                        btwrite(0x08,BT848_TGCTRL);                        btv->pll.pll_current = btv->pll.pll_ofreq;			if (bttv_verbose)				printk("ok\n");                        return 1;                }                mdelay(10);        }        btv->pll.pll_current = 0;	if (bttv_verbose)		printk("oops\n");        return -1;}static void bt848_muxsel(struct bttv *btv, unsigned int input){#if 0 /* seems no card uses this ... */	btaor(bttv_tvcards[btv->type].gpiomask2,~bttv_tvcards[btv->type].gpiomask2,              BT848_GPIO_OUT_EN);#endif	/* This seems to get rid of some synchronization problems */	btand(~(3<<5), BT848_IFORM);	mdelay(10);         	input %= bttv_tvcards[btv->type].video_inputs;	if (input==bttv_tvcards[btv->type].svhs) 	{		btor(BT848_CONTROL_COMP, BT848_E_CONTROL);		btor(BT848_CONTROL_COMP, BT848_O_CONTROL);	}	else	{		btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);		btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);	}	btaor((bttv_tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM);	audio(btv, (input!=bttv_tvcards[btv->type].tuner) ?               AUDIO_EXTERN : AUDIO_TUNER, 1);#if 0 /* seems no card uses this ... */	btaor(bttv_tvcards[btv->type].muxsel[input]>>4,		~bttv_tvcards[btv->type].gpiomask2, BT848_GPIO_DATA);	if (bttv_gpio)		bttv_gpio_tracking(btv,"muxsel");#endif}struct tvnorm {        u32 Fsc;        u16 swidth, sheight; /* scaled standard width, height */	u16 totalwidth;	u8 adelay, bdelay, iform;	u32 scaledtwidth;	u16 hdelayx1, hactivex1;	u16 vdelay;        u8 vbipack;};static struct tvnorm tvnorms[] = {	/* PAL-BDGHI */        /* max. active video is actually 922, but 924 is divisible by 4 and 3! */ 	/* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */        { 35468950,          924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),          1135, 186, 924,#ifdef VIDEODAT_HACK	  VBI_MAXLINES*2,#else	  0x20,#endif	  255},	/* NTSC */	{ 28636363,          768, 480,  910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0),          910, 128, 910, 0x1a, 144},#if 0	/* SECAM EAST */	{ 35468950,           768, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),	  944, 186, 922, 0x20, 255},#else	/* SECAM L */        { 35468950,          924, 576, 1135, 0x7f, 0xb0, (BT848_IFORM_SECAM|BT848_IFORM_XT1),          1135, 186, 922, 0x20, 255},#endif        /* PAL-NC */

⌨️ 快捷键说明

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