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

📄 bttv.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 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)    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/module.h>#include <linux/version.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/malloc.h>#include <linux/mm.h>#if LINUX_VERSION_CODE >= 0x020100#include <linux/poll.h>#endif#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/version.h>#if LINUX_VERSION_CODE >= 0x020100#include <asm/uaccess.h>#include <linux/vmalloc.h>#else#include <linux/bios32.h>#define mdelay(x) udelay((x)*1000)#define signal_pending(current)  (current->signal & ~current->blocked)#define sigfillset(set)static inline int time_before(unsigned long a, unsigned long b){	return((long)((a) - (b)) < 0L);}static inline unsigned longcopy_to_user(void *to, const void *from, unsigned long n){        memcpy_tofs(to,from,n);	return 0;}static inline unsigned longcopy_from_user(void *to, const void *from, unsigned long n){        memcpy_fromfs(to,from,n);	return 0;}#define ioremap vremap #define iounmap vfree#endif#include <linux/videodev.h>#include <linux/i2c.h>#include "bttv.h"#include "tuner.h"#define DEBUG(x) 		/* Debug driver */	#define IDEBUG(x) 		/* Debug interrupt handler */#if LINUX_VERSION_CODE >= 0x020117MODULE_PARM(vidmem,"i");MODULE_PARM(triton1,"i");MODULE_PARM(remap,"1-4i");MODULE_PARM(radio,"1-4i");MODULE_PARM(card,"1-4i");MODULE_PARM(pll,"1-4i");#endif/* Anybody who uses more than four? */#define BTTV_MAX 4static int find_vga(void);static void bt848_set_risc_jmps(struct bttv *btv);static unsigned int vidmem=0;   /* manually set video mem address */static int triton1=0;#ifndef USE_PLL/* 0=no pll, 1=28MHz, 2=34MHz */#define USE_PLL 0#endif#ifndef CARD_DEFAULT/* card type (see bttv.h) 0=autodetect */#define CARD_DEFAULT 0#endifstatic unsigned int remap[BTTV_MAX];    /* remap Bt848 */static unsigned int radio[BTTV_MAX];static unsigned int card[BTTV_MAX] = { CARD_DEFAULT, CARD_DEFAULT,                                        CARD_DEFAULT, CARD_DEFAULT };static unsigned int pll[BTTV_MAX] = { USE_PLL, USE_PLL, USE_PLL, USE_PLL };static int bttv_num;			/* number of Bt848s in use */static struct bttv bttvs[BTTV_MAX];#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 EEPROM_WRITE_DELAY    20000#define BURSTOFFSET 76/*******************************//* Memory management functions *//*******************************//* convert virtual user memory address to physical address *//* (virt_to_phys only works for kmalloced kernel memory) */static inline unsigned long uvirt_to_phys(unsigned long adr){	pgd_t *pgd;	pmd_t *pmd;	pte_t *ptep, pte;  	pgd = pgd_offset(current->mm, adr);	if (pgd_none(*pgd))		return 0;	pmd = pmd_offset(pgd, adr);	if (pmd_none(*pmd))		return 0;	ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/);	pte = *ptep;	if(pte_present(pte))		return 		  virt_to_phys((void *)(pte_page(pte)|(adr&(PAGE_SIZE-1))));	return 0;}static inline unsigned long uvirt_to_bus(unsigned long adr) {	return virt_to_bus(phys_to_virt(uvirt_to_phys(adr)));}/* convert virtual kernel memory address to physical address *//* (virt_to_phys only works for kmalloced kernel memory) */static inline unsigned long kvirt_to_phys(unsigned long adr) {	return uvirt_to_phys(VMALLOC_VMADDR(adr));}static inline unsigned long kvirt_to_bus(unsigned long adr) {	return uvirt_to_bus(VMALLOC_VMADDR(adr));}static void * rvmalloc(unsigned long size){	void * mem;	unsigned long adr, page;        	mem=vmalloc(size);	if (mem) 	{		memset(mem, 0, size); /* Clear the ram out, no junk to the user */	        adr=(unsigned long) mem;		while (size > 0)                 {	                page = kvirt_to_phys(adr);			mem_map_reserve(MAP_NR(phys_to_virt(page)));			adr+=PAGE_SIZE;			size-=PAGE_SIZE;		}	}	return mem;}static void rvfree(void * mem, unsigned long size){        unsigned long adr, page;        	if (mem) 	{	        adr=(unsigned long) mem;		while (size > 0)                 {	                page = kvirt_to_phys(adr);			mem_map_unreserve(MAP_NR(phys_to_virt(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(2*BTTV_MAX_FBUF);	else		printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n",			btv->nr);	if(!btv->fbuffer)		return -ENOBUFS;	return 0;}/* ----------------------------------------------------------------------- *//* I2C functions                                                           *//* software I2C functions */static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data){        struct bttv *btv = (struct bttv*)bus->data;	btwrite((ctrl<<1)|data, BT848_I2C);	btread(BT848_I2C); /* flush buffers */	udelay(I2C_DELAY);}static int i2c_getdataline(struct i2c_bus *bus){        struct bttv *btv = (struct bttv*)bus->data;	return btread(BT848_I2C)&1;}/* hardware I2C functions *//* read I2C */static int I2CRead(struct i2c_bus *bus, unsigned char addr) {	u32 i;	u32 stat;	struct bttv *btv = (struct bttv*)bus->data;  	/* clear status bit ; BT848_INT_RACK is ro */	btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);  	btwrite(((addr & 0xff) << 24) | btv->i2c_command, BT848_I2C);  	/*	 * Timeout for I2CRead is 1 second (this should be enough, really!)	 */	for (i=1000; i; i--)	{		stat=btread(BT848_INT_STAT);		if (stat & BT848_INT_I2CDONE)                        break;                mdelay(1);	}  	if (!i) 	{		printk(KERN_DEBUG "bttv%d: I2CRead timeout\n",			btv->nr);		return -1;	}	if (!(stat & BT848_INT_RACK))		return -2;  	i=(btread(BT848_I2C)>>8)&0xff;	return i;}/* set both to write both bytes, reset it to write only b1 */static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1,		    unsigned char b2, int both){	u32 i;	u32 data;	u32 stat;	struct bttv *btv = (struct bttv*)bus->data;  	/* clear status bit; BT848_INT_RACK is ro */	btwrite(BT848_INT_I2CDONE, BT848_INT_STAT);  	data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | btv->i2c_command;	if (both)	{		data|=((b2 & 0xff) << 8);		data|=BT848_I2C_W3B;	}  	btwrite(data, BT848_I2C);	for (i=0x1000; i; i--)	{		stat=btread(BT848_INT_STAT);		if (stat & BT848_INT_I2CDONE)			break;                mdelay(1);	}  	if (!i) 	{		printk(KERN_DEBUG "bttv%d: I2CWrite timeout\n",			btv->nr);		return -1;	}	if (!(stat & BT848_INT_RACK))		return -2;  	return 0;}/* read EEPROM */static void readee(struct i2c_bus *bus, unsigned char *eedata){	int i, k;        	if (I2CWrite(bus, 0xa0, 0, -1, 0)<0)	{		printk(KERN_WARNING "bttv: readee error\n");		return;	}        	for (i=0; i<256; i++)	{		k=I2CRead(bus, 0xa1);		if (k<0)		{			printk(KERN_WARNING "bttv: readee error\n");			break;		}		eedata[i]=k;	}}/* write EEPROM */static void writeee(struct i2c_bus *bus, unsigned char *eedata){	int i;  	for (i=0; i<256; i++)	{		if (I2CWrite(bus, 0xa0, i, eedata[i], 1)<0)		{			printk(KERN_WARNING "bttv: writeee error (%d)\n", i);			break;		}		udelay(EEPROM_WRITE_DELAY);	}}void attach_inform(struct i2c_bus *bus, int id){        struct bttv *btv = (struct bttv*)bus->data;        	switch (id)         {        	case I2C_DRIVERID_MSP3400:                	btv->have_msp3400 = 1;			break;        	case I2C_DRIVERID_TUNER:			btv->have_tuner = 1;			if (btv->tuner_type != -1)  				i2c_control_device(&(btv->i2c),                                                    I2C_DRIVERID_TUNER,                                                   TUNER_SET_TYPE,&btv->tuner_type);			break;	}}void detach_inform(struct i2c_bus *bus, int id){        struct bttv *btv = (struct bttv*)bus->data;	switch (id) 	{		case I2C_DRIVERID_MSP3400:		        btv->have_msp3400 = 0;			break;		case I2C_DRIVERID_TUNER:			btv->have_tuner = 0;			break;	}}static struct i2c_bus bttv_i2c_bus_template = {        "bt848",        I2C_BUSID_BT848,	NULL,#if LINUX_VERSION_CODE >= 0x020100	SPIN_LOCK_UNLOCKED,#endif	attach_inform,	detach_inform,		i2c_setlines,	i2c_getdataline,	I2CRead,	I2CWrite,}; /* ----------------------------------------------------------------------- *//* some hauppauge specific stuff                                           */static unsigned char eeprom_data[256];static struct HAUPPAUGE_TUNER {        int  id;        char *name;} hauppauge_tuner[] = {        { TUNER_ABSENT,        "" },        { TUNER_ABSENT,        "External" },        { TUNER_ABSENT,        "Unspecified" },        { TUNER_ABSENT,        "Philips FI1216" },        { TUNER_ABSENT,        "Philips FI1216MF" },        { TUNER_PHILIPS_NTSC,  "Philips FI1236" },        { TUNER_ABSENT,        "Philips FI1246" },        { TUNER_ABSENT,        "Philips FI1256" },        { TUNER_PHILIPS_PAL,   "Philips FI1216 MK2" },        { TUNER_PHILIPS_SECAM, "Philips FI1216MF MK2" },        { TUNER_PHILIPS_NTSC,  "Philips FI1236 MK2" },        { TUNER_PHILIPS_PAL_I, "Philips FI1246 MK2" },        { TUNER_ABSENT,        "Philips FI1256 MK2" },        { TUNER_ABSENT,        "Temic 4032FY5" },        { TUNER_TEMIC_PAL,     "Temic 4002FH5" },        { TUNER_TEMIC_PAL_I,   "Temic 4062FY5" },        { TUNER_ABSENT,        "Philips FR1216 MK2" },        { TUNER_PHILIPS_SECAM, "Philips FR1216MF MK2" },        { TUNER_PHILIPS_NTSC,  "Philips FR1236 MK2" },        { TUNER_PHILIPS_PAL_I, "Philips FR1246 MK2" },        { TUNER_ABSENT,        "Philips FR1256 MK2" },        { TUNER_PHILIPS_PAL,   "Philips FM1216" },        { TUNER_ABSENT,        "Philips FM1216MF" },        { TUNER_PHILIPS_NTSC,  "Philips FM1236" },};static voidhauppauge_eeprom(struct i2c_bus *bus){        struct bttv *btv = (struct bttv*)bus->data;                readee(bus, eeprom_data);        if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER))         {                btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id;                printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr,                       hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type);        }}static voidhauppauge_msp_reset(struct bttv *btv){        /* Reset the MSP on some Hauppauge cards */        /* Thanks to Ky鰏ti M鋖kki (kmalkki@cc.hut.fi)! */        /* Can this hurt cards without one? What about Miros with MSP? */        btaor(32, ~32, BT848_GPIO_OUT_EN);        btaor(0, ~32, BT848_GPIO_DATA);        udelay(2500);        btaor(32, ~32, BT848_GPIO_DATA);        /* btaor(0, ~32, BT848_GPIO_OUT_EN); */}/* ----------------------------------------------------------------------- */struct tvcard{        int video_inputs;        int audio_inputs;        int tuner;        int svhs;

⌨️ 快捷键说明

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