📄 bttv.c
字号:
/* 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 + -