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

📄 bttv-driver.c

📁 一个2.4.21版本的嵌入式linux内核
💻 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-2003 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 <linux/types.h>#include <linux/wrapper.h>#include <linux/interrupt.h>#include <linux/kmod.h>#include <linux/vmalloc.h>#include <linux/init.h>#include <linux/pagemap.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))/* fwd decl */static void bt848_set_risc_jmps(struct bttv *btv, int state);static void make_vbitab(struct bttv *btv);static void bt848_set_winsize(struct bttv *btv);unsigned 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 gpint = 1;static unsigned int irq_debug = 0;static unsigned int gbuffers = 4;static unsigned int gbufsize = BTTV_MAX_FBUF;static unsigned int combfilter = 0;static unsigned int lumafilter = 0;static unsigned int automute = 1;static unsigned int chroma_agc = 0;static unsigned int adc_crush = 1;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-" __stringify(BTTV_MAX) "i");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(gpint,"i");MODULE_PARM(combfilter,"i");MODULE_PARM(lumafilter,"i");MODULE_PARM(automute,"i");MODULE_PARM_DESC(automute,"mute audio on bad/missing video signal, default is 1 (yes)");MODULE_PARM(chroma_agc,"i");MODULE_PARM_DESC(chroma_agc,"enables the AGC of chroma signal, default is 0 (no)");MODULE_PARM(adc_crush,"i");MODULE_PARM_DESC(adc_crush,"enables the luminance ADC crush, default is 1 (yes)");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 *//*******************************/static inline unsigned long kvirt_to_bus(unsigned long adr) {        unsigned long kva;	kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));	kva |= adr & (PAGE_SIZE-1); /* restore the offset */   	return virt_to_bus((void *)kva);}/* 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 kva;	kva = (unsigned long)page_address(vmalloc_to_page((void *)adr));	kva |= adr & (PAGE_SIZE-1); /* restore the offset */	return __pa(kva);}static void * rvmalloc(signed long size){	struct page *page;	void * mem;	unsigned long adr;	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 = vmalloc_to_page((void *)adr);			mem_map_reserve(page);			adr+=PAGE_SIZE;			size-=PAGE_SIZE;		}	}	return mem;}static void rvfree(void * mem, signed long size){	struct page *page;        unsigned long adr;        	if (mem) {	        adr=(unsigned long) mem;		while (size > 0) {			page = vmalloc_to_page((void *)adr);			mem_map_unreserve(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){	if (bttv_tvcards[btv->type].gpiomask)		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;	if (bttv_tvcards[btv->type].gpiomask)		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 (!in_interrupt())		bttv_call_i2c_clients(btv,AUDC_SET_INPUT,&(mode));}static 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 void set_pll(struct bttv *btv){        int i;        if (!btv->pll.pll_crystal)                return;	if (btv->pll.pll_ofreq == btv->pll.pll_current) {		dprintk("bttv%d: PLL: no change required\n",btv->nr);                return;        }        if (btv->pll.pll_ifreq == btv->pll.pll_ofreq) {                /* no PLL needed */                if (btv->pll.pll_current == 0)                        return;		vprintk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n",			btv->nr,btv->pll.pll_ifreq);                btwrite(0x00,BT848_TGCTRL);                btwrite(0x00,BT848_PLL_XCI);                btv->pll.pll_current = 0;                return;        }	vprintk(KERN_INFO "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);        for (i=0; i<10; i++) {		/*  Let other people run while the PLL stabilizes */		vprintk(".");		current->state = TASK_INTERRUPTIBLE;		schedule_timeout(HZ/10);		                if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) {			btwrite(0,BT848_DSTATUS);                } else {                        btwrite(0x08,BT848_TGCTRL);                        btv->pll.pll_current = btv->pll.pll_ofreq;			vprintk(" ok\n");                        return;                }        }        btv->pll.pll_current = -1;	vprintk("failed\n");        return;}static void bt848_muxsel(struct bttv *btv, unsigned int input){	dprintk("bttv%d: bt848_muxsel %d\n",btv->nr,input);	if (bttv_tvcards[btv->type].muxsel[input] < 0) {		dprintk("bttv%d: digital ccir muxsel\n", btv->nr);		btv->channel = input;		return;	}        /* needed by RemoteVideo MX */	if (bttv_tvcards[btv->type].gpiomask2)		btaor(bttv_tvcards[btv->type].gpiomask2,		      ~bttv_tvcards[btv->type].gpiomask2,		      BT848_GPIO_OUT_EN);#if 0	/* This seems to get rid of some synchronization problems */	btand(~(3<<5), BT848_IFORM);	mdelay(10);#endif	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]&3)<<5, ~(3<<5), BT848_IFORM);	audio(btv, (input!=bttv_tvcards[btv->type].tuner) ?              AUDIO_EXTERN : AUDIO_TUNER);	if (bttv_tvcards[btv->type].gpiomask2)		btaor(bttv_tvcards[btv->type].muxsel[input]>>4,		      ~bttv_tvcards[btv->type].gpiomask2,		      BT848_GPIO_DATA);	/* card specific hook */	if (bttv_tvcards[btv->type].muxsel_hook)		bttv_tvcards[btv->type].muxsel_hook(btv, input);	if (bttv_gpio)		bttv_gpio_tracking(btv,"muxsel");	btv->channel=input;}/* special timing tables from conexant... */static u8 SRAM_Table[][60] ={	/* PAL digital input over GPIO[7:0] */	{		45, // 45 bytes following		0x36,0x11,0x01,0x00,0x90,0x02,0x05,0x10,0x04,0x16,		0x12,0x05,0x11,0x00,0x04,0x12,0xC0,0x00,0x31,0x00,		0x06,0x51,0x08,0x03,0x89,0x08,0x07,0xC0,0x44,0x00,		0x81,0x01,0x01,0xA9,0x0D,0x02,0x02,0x50,0x03,0x37,		0x37,0x00,0xAF,0x21,0x00	},	/* NTSC digital input over GPIO[7:0] */	{		51, // 51 bytes following		0x0C,0xC0,0x00,0x00,0x90,0x02,0x03,0x10,0x03,0x06,		0x10,0x04,0x12,0x12,0x05,0x02,0x13,0x04,0x19,0x00,		0x04,0x39,0x00,0x06,0x59,0x08,0x03,0x83,0x08,0x07,		0x03,0x50,0x00,0xC0,0x40,0x00,0x86,0x01,0x01,0xA6,		0x0D,0x02,0x03,0x11,0x01,0x05,0x37,0x00,0xAC,0x21,		0x00,	},	// TGB_NTSC392 // quartzsight	// This table has been modified to be used for Fusion Rev D	{		0x2A, // size of table = 42		0x06, 0x08, 0x04, 0x0a, 0xc0, 0x00, 0x18, 0x08, 0x03, 0x24,		0x08, 0x07, 0x02, 0x90, 0x02, 0x08, 0x10, 0x04, 0x0c, 0x10,		0x05, 0x2c, 0x11, 0x04, 0x55, 0x48, 0x00, 0x05, 0x50, 0x00,		0xbf, 0x0c, 0x02, 0x2f, 0x3d, 0x00, 0x2f, 0x3f, 0x00, 0xc3,		0x20, 0x00	}};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;	int sram; /* index into SRAM_Table */};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 */	{		.Fsc            = 35468950,		.swidth         = 924,		.sheight        = 576,		.totalwidth     = 1135,		.adelay         = 0x7f,		.bdelay         = 0x72, 		.iform          = (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1),		.scaledtwidth   = 1135,		.hdelayx1       = 186,		.hactivex1      = 924,#ifdef VIDEODAT_HACK		.vdelay         = VBI_MAXLINES*2,#else		.vdelay         = 0x20,#endif		.vbipack        = 255,		.sram           = 0,	},{                /* NTSC */		.Fsc            = 28636363,		.swidth         = 768,		.sheight        = 480,		.totalwidth     = 910,

⌨️ 快捷键说明

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