diff --unified --recursive --new-file --exclude-from exclude linux.videovan/drivers/char/Config.in linux/drivers/char/Config.in --- linux.videovan/drivers/char/Config.in Thu Sep 11 21:14:00 1997 +++ linux/drivers/char/Config.in Sun Oct 19 18:12:23 1997 @@ -107,6 +107,8 @@ if [ "$CONFIG_PPC" = "y" ]; then bool 'Tadpole ANA H8 Support' CONFIG_H8 fi +tristate 'Video For Linux' CONFIG_VIDEO_DEV +dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV tristate '/dev/nvram support' CONFIG_NVRAM tristate 'PC joystick support' CONFIG_JOYSTICK endmenu diff --unified --recursive --new-file --exclude-from exclude linux.videovan/drivers/char/Makefile linux/drivers/char/Makefile --- linux.videovan/drivers/char/Makefile Sun Sep 7 00:18:58 1997 +++ linux/drivers/char/Makefile Sun Oct 19 20:03:37 1997 @@ -281,6 +281,22 @@ endif endif +ifeq ($(CONFIG_VIDEO_DEV),y) +LX_OBJS += videodev.o +else + ifeq ($(CONFIG_VIDEO_DEV),m) + MX_OBJS += videodev.o + endif +endif + +ifeq ($(CONFIG_VIDEO_BT848),y) +L_OBJS += bttv.o +else + ifeq ($(CONFIG_VIDEO_BT848),m) + M_OBJS += bttv.o + endif +endif + ifeq ($(CONFIG_QIC02_TAPE),y) L_OBJS += tpqic02.o else diff --unified --recursive --new-file --exclude-from exclude linux.videovan/drivers/char/bt848.h linux/drivers/char/bt848.h --- linux.videovan/drivers/char/bt848.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/bt848.h Sun Oct 19 20:05:14 1997 @@ -0,0 +1,319 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97 Ralph Metzler (rjkm@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. +*/ + +#ifndef _BT848_H_ +#define _BT848_H_ + +#ifndef PCI_VENDOR_ID_BROOKTREE +#define PCI_VENDOR_ID_BROOKTREE 0x109e +#endif +#ifndef PCI_DEVICE_ID_BT848 +#define PCI_DEVICE_ID_BT848 0x350 +#endif + +#define RISCMEM_LEN 131040 + +/* Brooktree 848 registers */ + +#define BT848_DSTATUS 0x000 +#define BT848_DSTATUS_PRES (1<<7) +#define BT848_DSTATUS_HLOC (1<<6) +#define BT848_DSTATUS_FIELD (1<<5) +#define BT848_DSTATUS_NUML (1<<4) +#define BT848_DSTATUS_CSEL (1<<3) +#define BT848_DSTATUS_LOF (1<<1) +#define BT848_DSTATUS_COF (1<<0) + +#define BT848_IFORM 0x004 +#define BT848_IFORM_HACTIVE (1<<7) +#define BT848_IFORM_MUXSEL (3<<5) +#define BT848_IFORM_MUX0 (2<<5) +#define BT848_IFORM_MUX1 (3<<5) +#define BT848_IFORM_MUX2 (1<<5) +#define BT848_IFORM_XTSEL (3<<3) +#define BT848_IFORM_XT0 (1<<3) +#define BT848_IFORM_XT1 (2<<3) +#define BT848_IFORM_XTAUTO (3<<3) +#define BT848_IFORM_XTBOTH (3<<3) +#define BT848_IFORM_NTSC 1 +#define BT848_IFORM_PAL_BDGHI 3 +#define BT848_IFORM_PAL_M 4 +#define BT848_IFORM_PAL_N 5 +#define BT848_IFORM_SECAM 6 +#define BT848_IFORM_AUTO 0 +#define BT848_IFORM_NORM 7 + +#define BT848_TDEC 0x008 +#define BT848_TDEC_DEC_FIELD (1<<7) +#define BT848_TDEC_FLDALIGN (1<<6) +#define BT848_TDEC_DEC_RAT (0x1f) + +#define BT848_E_CROP 0x00C +#define BT848_O_CROP 0x08C + +#define BT848_E_VDELAY_LO 0x010 +#define BT848_O_VDELAY_LO 0x090 + +#define BT848_E_VACTIVE_LO 0x014 +#define BT848_O_VACTIVE_LO 0x094 + +#define BT848_E_HDELAY_LO 0x018 +#define BT848_O_HDELAY_LO 0x098 + +#define BT848_E_HACTIVE_LO 0x01C +#define BT848_O_HACTIVE_LO 0x09C + +#define BT848_E_HSCALE_HI 0x020 +#define BT848_O_HSCALE_HI 0x0A0 + +#define BT848_E_HSCALE_LO 0x024 +#define BT848_O_HSCALE_LO 0x0A4 + +#define BT848_BRIGHT 0x028 + +#define BT848_E_CONTROL 0x02C +#define BT848_O_CONTROL 0x0AC +#define BT848_CONTROL_LNOTCH (1<<7) +#define BT848_CONTROL_COMP (1<<6) +#define BT848_CONTROL_LDEC (1<<5) +#define BT848_CONTROL_CBSENSE (1<<4) +#define BT848_CONTROL_CON_MSB (1<<2) +#define BT848_CONTROL_SAT_U_MSB (1<<1) +#define BT848_CONTROL_SAT_V_MSB (1<<0) + +#define BT848_CONTRAST_LO 0x030 +#define BT848_SAT_U_LO 0x034 +#define BT848_SAT_V_LO 0x038 +#define BT848_HUE 0x03C + +#define BT848_E_SCLOOP 0x040 +#define BT848_O_SCLOOP 0x0C0 +#define BT848_SCLOOP_CAGC (1<<6) +#define BT848_SCLOOP_CKILL (1<<5) +#define BT848_SCLOOP_HFILT_AUTO (0<<3) +#define BT848_SCLOOP_HFILT_CIF (1<<3) +#define BT848_SCLOOP_HFILT_QCIF (2<<3) +#define BT848_SCLOOP_HFILT_ICON (3<<3) + +#define BT848_OFORM 0x048 +#define BT848_OFORM_RANGE (1<<7) +#define BT848_OFORM_CORE0 (0<<5) +#define BT848_OFORM_CORE8 (1<<5) +#define BT848_OFORM_CORE16 (2<<5) +#define BT848_OFORM_CORE32 (3<<5) + +#define BT848_E_VSCALE_HI 0x04C +#define BT848_O_VSCALE_HI 0x0CC +#define BT848_VSCALE_YCOMB (1<<7) +#define BT848_VSCALE_COMB (1<<6) +#define BT848_VSCALE_INT (1<<5) +#define BT848_VSCALE_HI 15 + +#define BT848_E_VSCALE_LO 0x050 +#define BT848_O_VSCALE_LO 0x0D0 +#define BT848_TEST 0x054 +#define BT848_ADELAY 0x060 +#define BT848_BDELAY 0x064 + +#define BT848_ADC 0x068 +#define BT848_ADC_RESERVED (2<<6) +#define BT848_ADC_SYNC_T (1<<5) +#define BT848_ADC_AGC_EN (1<<4) +#define BT848_ADC_CLK_SLEEP (1<<3) +#define BT848_ADC_Y_SLEEP (1<<2) +#define BT848_ADC_C_SLEEP (1<<1) +#define BT848_ADC_CRUSH (1<<0) + +#define BT848_E_VTC 0x06C +#define BT848_O_VTC 0x0EC +#define BT848_VTC_HSFMT (1<<7) +#define BT848_VTC_VFILT_2TAP 0 +#define BT848_VTC_VFILT_3TAP 1 +#define BT848_VTC_VFILT_4TAP 2 +#define BT848_VTC_VFILT_5TAP 3 + +#define BT848_SRESET 0x07C + +#define BT848_COLOR_FMT 0x0D4 +#define BT848_COLOR_FMT_O_RGB32 (0<<4) +#define BT848_COLOR_FMT_O_RGB24 (1<<4) +#define BT848_COLOR_FMT_O_RGB16 (2<<4) +#define BT848_COLOR_FMT_O_RGB15 (3<<4) +#define BT848_COLOR_FMT_O_YUY2 (4<<4) +#define BT848_COLOR_FMT_O_BtYUV (5<<4) +#define BT848_COLOR_FMT_O_Y8 (6<<4) +#define BT848_COLOR_FMT_O_RGB8 (7<<4) +#define BT848_COLOR_FMT_O_YCrCb422 (8<<4) +#define BT848_COLOR_FMT_O_YCrCb411 (9<<4) +#define BT848_COLOR_FMT_O_RAW (14<<4) +#define BT848_COLOR_FMT_E_RGB32 0 +#define BT848_COLOR_FMT_E_RGB24 1 +#define BT848_COLOR_FMT_E_RGB16 2 +#define BT848_COLOR_FMT_E_RGB15 3 +#define BT848_COLOR_FMT_E_YUY2 4 +#define BT848_COLOR_FMT_E_BtYUV 5 +#define BT848_COLOR_FMT_E_Y8 6 +#define BT848_COLOR_FMT_E_RGB8 7 +#define BT848_COLOR_FMT_E_YCrCb422 8 +#define BT848_COLOR_FMT_E_YCrCb411 9 +#define BT848_COLOR_FMT_E_RAW 14 + +#define BT848_COLOR_FMT_RGB32 0x00 +#define BT848_COLOR_FMT_RGB24 0x11 +#define BT848_COLOR_FMT_RGB16 0x22 +#define BT848_COLOR_FMT_RGB15 0x33 +#define BT848_COLOR_FMT_YUY2 0x44 +#define BT848_COLOR_FMT_BtYUV 0x55 +#define BT848_COLOR_FMT_Y8 0x66 +#define BT848_COLOR_FMT_RGB8 0x77 +#define BT848_COLOR_FMT_YCrCb422 0x88 +#define BT848_COLOR_FMT_YCrCb411 0x99 +#define BT848_COLOR_FMT_RAW 0xee + +#define BT848_COLOR_CTL 0x0D8 +#define BT848_COLOR_CTL_EXT_FRMRATE (1<<7) +#define BT848_COLOR_CTL_COLOR_BARS (1<<6) +#define BT848_COLOR_CTL_RGB_DED (1<<5) +#define BT848_COLOR_CTL_GAMMA (1<<4) +#define BT848_COLOR_CTL_WSWAP_ODD (1<<3) +#define BT848_COLOR_CTL_WSWAP_EVEN (1<<2) +#define BT848_COLOR_CTL_BSWAP_ODD (1<<1) +#define BT848_COLOR_CTL_BSWAP_EVEN (1<<0) + +#define BT848_CAP_CTL 0x0DC +#define BT848_CAP_CTL_DITH_FRAME (1<<4) +#define BT848_CAP_CTL_CAPTURE_VBI_ODD (1<<3) +#define BT848_CAP_CTL_CAPTURE_VBI_EVEN (1<<2) +#define BT848_CAP_CTL_CAPTURE_ODD (1<<1) +#define BT848_CAP_CTL_CAPTURE_EVEN (1<<0) + +#define BT848_VBI_PACK_SIZE 0x0E0 + +#define BT848_VBI_PACK_DEL 0x0E4 +#define BT848_VBI_PACK_DEL_VBI_HDELAY 0xfc +#define BT848_VBI_PACK_DEL_EXT_FRAME 2 +#define BT848_VBI_PACK_DEL_VBI_PKT_HI 1 + +#define BT848_INT_STAT 0x100 +#define BT848_INT_MASK 0x104 + +#define BT848_INT_ETBF (1<<23) + +#define BT848_INT_RISCS (0xf<<28) +#define BT848_INT_RISC_EN (1<<27) +#define BT848_INT_RACK (1<<25) +#define BT848_INT_FIELD (1<<24) +#define BT848_INT_SCERR (1<<19) +#define BT848_INT_OCERR (1<<18) +#define BT848_INT_PABORT (1<<17) +#define BT848_INT_RIPERR (1<<16) +#define BT848_INT_PPERR (1<<15) +#define BT848_INT_FDSR (1<<14) +#define BT848_INT_FTRGT (1<<13) +#define BT848_INT_FBUS (1<<12) +#define BT848_INT_RISCI (1<<11) +#define BT848_INT_GPINT (1<<9) +#define BT848_INT_I2CDONE (1<<8) +#define BT848_INT_VPRES (1<<5) +#define BT848_INT_HLOCK (1<<4) +#define BT848_INT_OFLOW (1<<3) +#define BT848_INT_HSYNC (1<<2) +#define BT848_INT_VSYNC (1<<1) +#define BT848_INT_FMTCHG (1<<0) + + +#define BT848_GPIO_DMA_CTL 0x10C +#define BT848_GPIO_DMA_CTL_GPINTC (1<<15) +#define BT848_GPIO_DMA_CTL_GPINTI (1<<14) +#define BT848_GPIO_DMA_CTL_GPWEC (1<<13) +#define BT848_GPIO_DMA_CTL_GPIOMODE (3<<11) +#define BT848_GPIO_DMA_CTL_GPCLKMODE (1<<10) +#define BT848_GPIO_DMA_CTL_PLTP23_4 (0<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_8 (1<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_16 (2<<6) +#define BT848_GPIO_DMA_CTL_PLTP23_32 (3<<6) +#define BT848_GPIO_DMA_CTL_PLTP1_4 (0<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_8 (1<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_16 (2<<4) +#define BT848_GPIO_DMA_CTL_PLTP1_32 (3<<4) +#define BT848_GPIO_DMA_CTL_PKTP_4 (0<<2) +#define BT848_GPIO_DMA_CTL_PKTP_8 (1<<2) +#define BT848_GPIO_DMA_CTL_PKTP_16 (2<<2) +#define BT848_GPIO_DMA_CTL_PKTP_32 (3<<2) +#define BT848_GPIO_DMA_CTL_RISC_ENABLE (1<<1) +#define BT848_GPIO_DMA_CTL_FIFO_ENABLE (1<<0) + +#define BT848_I2C 0x110 +#define BT848_I2C_DIV (0xf<<4) +#define BT848_I2C_SYNC (1<<3) +#define BT848_I2C_W3B (1<<2) +#define BT848_I2C_SCL (1<<1) +#define BT848_I2C_SDA (1<<0) + + +#define BT848_RISC_STRT_ADD 0x114 +#define BT848_GPIO_OUT_EN 0x118 +#define BT848_GPIO_REG_INP 0x11C +#define BT848_RISC_COUNT 0x120 +#define BT848_GPIO_DATA 0x200 + + +/* Bt848 RISC commands */ + +/* only for the SYNC RISC command */ +#define BT848_FIFO_STATUS_FM1 0x06 +#define BT848_FIFO_STATUS_FM3 0x0e +#define BT848_FIFO_STATUS_SOL 0x02 +#define BT848_FIFO_STATUS_EOL4 0x01 +#define BT848_FIFO_STATUS_EOL3 0x0d +#define BT848_FIFO_STATUS_EOL2 0x09 +#define BT848_FIFO_STATUS_EOL1 0x05 +#define BT848_FIFO_STATUS_VRE 0x04 +#define BT848_FIFO_STATUS_VRO 0x0c +#define BT848_FIFO_STATUS_PXV 0x00 + +#define BT848_RISC_RESYNC (1<<15) + +/* WRITE and SKIP */ +/* disable which bytes of each DWORD */ +#define BT848_RISC_BYTE0 (1<<12) +#define BT848_RISC_BYTE1 (1<<13) +#define BT848_RISC_BYTE2 (1<<14) +#define BT848_RISC_BYTE3 (1<<15) +#define BT848_RISC_BYTE_ALL (0x0f<<12) +#define BT848_RISC_BYTE_NONE 0 +/* cause RISCI */ +#define BT848_RISC_IRQ (1<<24) +/* RISC command is last one in this line */ +#define BT848_RISC_EOL (1<<26) +/* RISC command is first one in this line */ +#define BT848_RISC_SOL (1<<27) + +#define BT848_RISC_WRITE (0x01<<28) +#define BT848_RISC_SKIP (0x02<<28) +#define BT848_RISC_WRITEC (0x05<<28) +#define BT848_RISC_JUMP (0x07<<28) +#define BT848_RISC_SYNC (0x08<<28) + +#define BT848_RISC_WRITE123 (0x09<<28) +#define BT848_RISC_SKIP123 (0x0a<<28) +#define BT848_RISC_WRITE1S23 (0x0b<<28) + +#endif diff --unified --recursive --new-file --exclude-from exclude linux.videovan/drivers/char/bttv.c linux/drivers/char/bttv.c --- linux.videovan/drivers/char/bttv.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/bttv.c Mon Oct 20 00:13:52 1997 @@ -0,0 +1,1997 @@ +/* + bttv - Bt848 frame grabber driver + + Copyright (C) 1996,97 Ralph Metzler (rjkm@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. + + Modified to put the RISC code writer in the kernel and to fit a + common (and I hope safe) kernel interface. When we have an X extension + all will now be really sweet. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "bttv.h" +#include "tuner.h" + +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ + +static unsigned int remap=0; +static unsigned int vidmem=0; +static unsigned int tuner=0; /* Default tuner */ + +static int find_vga(void); +static void bt848_set_risc_jmps(struct bttv *btv); + +/* Anybody who uses more than four? */ +#define BTTV_MAX 4 + +static int bttv_num; +static struct bttv bttvs[BTTV_MAX]; + +#define I2C_TIMING (0x7<<4) +#define I2C_COMMAND (I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA) + +#define AUDIO_MUTE_DELAY 10000 +#define FREQ_CHANGE_DELAY 20000 +#define EEPROM_WRITE_DELAY 20000 + + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +/* convert virtual user memory address to physical address */ +/* (virt_to_phys only works for kmalloced kernel memory) */ + +static inline ulong uvirt_to_phys(ulong adr) +{ + pgd_t *pgd; + pmd_t *pmd; + pte_t *ptep, pte; + +/* printk("adr: 0x%08x\n",adr);*/ + pgd = pgd_offset(current->mm, adr); +/* printk("pgd: 0x%08x\n",pgd);*/ + if (pgd_none(*pgd)) + return 0; + pmd = pmd_offset(pgd, adr); +/* printk("pmd: 0x%08x\n",pmd); */ + if (pmd_none(*pmd)) + return 0; + ptep = pte_offset(pmd, adr&(~PGDIR_MASK)); + pte = *ptep; + if(pte_present(pte)) + return (pte_page(pte)|(adr&(PAGE_SIZE-1))); + return 0; +} + +/* convert virtual kernel memory address to physical address */ +/* (virt_to_phys only works for kmalloced kernel memory) */ + +static inline ulong kvirt_to_phys(ulong adr) +{ + return uvirt_to_phys(VMALLOC_VMADDR(adr)); +} + +static inline ulong kvirt_to_bus(ulong adr) +{ + return virt_to_bus(phys_to_virt(kvirt_to_phys(adr))); +} + + +/*****************/ +/* I2C functions */ +/*****************/ + +static int I2CRead(struct bttv *btv, int addr) +{ + u32 i; + u32 stat; + + /* clear status bit ; BT848_INT_RACK is ro */ + btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); + + btwrite(((addr & 0xff) << 24) | I2C_COMMAND, BT848_I2C); + + for (i=0x7fffffff; i; i--) + { + stat=btread(BT848_INT_STAT); + if (stat & BT848_INT_I2CDONE) + break; + } + + if (!i) + 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 bttv *btv, unchar addr, unchar b1, + unchar b2, int both) +{ + u32 i; + u32 data; + u32 stat; + + /* clear status bit; BT848_INT_RACK is ro */ + btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); + + data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | I2C_COMMAND; + if (both) + { + data|=((b2 & 0xff) << 8); + data|=BT848_I2C_W3B; + } + + btwrite(data, BT848_I2C); + + for (i=0x7fffffff; i; i--) + { + stat=btread(BT848_INT_STAT); + if (stat & BT848_INT_I2CDONE) + break; + } + + if (!i) + return -1; + if (!(stat & BT848_INT_RACK)) + return -2; + + return 0; +} + +static void readee(struct bttv *btv, unchar *eedata) +{ + int i, k; + + if (I2CWrite(btv, 0xa0, 0, -1, 0)<0) + { + printk(KERN_WARNING "bttv: readee error\n"); + return; + } + + for (i=0; i<256; i++) + { + k=I2CRead(btv, 0xa1); + if (k<0) + { + printk(KERN_WARNING "bttv: readee error\n"); + break; + } + eedata[i]=k; + } +} + +static void writeee(struct bttv *btv, unchar *eedata) +{ + int i; + + for (i=0; i<256; i++) + { + if (I2CWrite(btv, 0xa0, i, eedata[i], 1)<0) + { + printk(KERN_WARNING "bttv: writeee error (%d)\n", i); + break; + } + udelay(EEPROM_WRITE_DELAY); + } +} + +/* + * Tuner, internal, external and mute + */ + +static unchar audiomuxs[][4] = +{ + { 0x00, 0x00, 0x00, 0x00}, /* unknown */ + { 0x02, 0x00, 0x00, 0x0a}, /* MIRO */ + { 0x00, 0x02, 0x03, 0x04}, /* Hauppauge */ + { 0x04, 0x02, 0x03, 0x01}, /* STB */ + { 0x01, 0x02, 0x03, 0x04}, /* Intel??? */ + { 0x01, 0x02, 0x03, 0x04}, /* Diamond DTV2000??? */ +}; + +static void audio(struct bttv *btv, int mode) +{ + btwrite(0x0f, BT848_GPIO_OUT_EN); + btwrite(0x00, BT848_GPIO_REG_INP); + + switch (mode) + { + 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 ((btv->audio&AUDIO_MUTE) || !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)) + mode=AUDIO_OFF; + btaor(audiomuxs[btv->type][mode] , ~0x0f, BT848_GPIO_DATA); +} + + +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); +} + + +static void bt848_cap(struct bttv *btv, uint state) +{ + if (state) + { + btv->cap|=3; + bt848_set_risc_jmps(btv); + } + else + { + btv->cap&=~3; + bt848_set_risc_jmps(btv); + } +} + +static void bt848_muxsel(struct bttv *btv, uint input) +{ + input&=3; + + /* This seems to get rid of some synchronization problems */ + btand(~(3<<5), BT848_IFORM); + udelay(10000); + + if (input==3) + { + 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); + } + if (input==2) + input=3; + btaor(((input+2)&3)<<5, ~(3<<5), BT848_IFORM); + audio(btv, input ? AUDIO_EXTERN : AUDIO_TUNER); +} + + +#define VBIBUF_SIZE 65536 + +static void make_vbitab(struct bttv *btv) +{ + int i; + dword *po=(dword *) btv->vbi_odd; + dword *pe=(dword *) btv->vbi_even; + + DEBUG(printk(KERN_DEBUG "vbiodd: 0x%08x\n",(int)btv->vbi_odd)); + DEBUG(printk(KERN_DEBUG "vbievn: 0x%08x\n",(int)btv->vbi_even)); + DEBUG(printk(KERN_DEBUG "po: 0x%08x\n",(int)po)); + DEBUG(printk(KERN_DEBUG "pe: 0x%08x\n",(int)pe)); + + *(po++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(po++)=0; + for (i=0; i<16; i++) + { + *(po++)=BT848_RISC_WRITE|2044|BT848_RISC_EOL|BT848_RISC_SOL|(13<<20); + *(po++)=kvirt_to_bus((ulong)btv->vbibuf+i*2048); + } + *(po++)=BT848_RISC_JUMP; + *(po++)=virt_to_bus(btv->risc_jmp+4); + + *(pe++)=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; *(pe++)=0; + for (i=16; i<32; i++) + { + *(pe++)=BT848_RISC_WRITE|2044|BT848_RISC_EOL|BT848_RISC_SOL; + *(pe++)=kvirt_to_bus((ulong)btv->vbibuf+i*2048); + } + *(pe++)=BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16); + *(pe++)=virt_to_bus(btv->risc_jmp+10); +} + +/* + * Set the registers for the size we have specified. Don't bother + * trying to understand this without the BT848 manual in front of + * you [AC]. + * + * PS: The manual is free for download in .pdf format from + * www.brooktree.com - nicely done those folks. + */ + +static void bt848_set_size(struct bttv *btv) +{ + u16 vscale, hscale; + u32 xsf, sr; + u16 hdelay, vdelay; + u16 hactive, vactive; + u16 inter; + u8 crop; + + /* + * No window , no try... + */ + + if (!btv->win.width) + return; + if (!btv->win.height) + return; + + inter=(btv->win.interlace&1)^1; + + switch (btv->win.bpp) + { + /* + * RGB8 seems to be a 9x5x5 GRB color cube starting at color 16 + * Why the h... can't they even mention this in the datasheet??? + */ + case 1: + btwrite(BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT); + btand(~0x10, BT848_CAP_CTL); // Dithering looks much better in this mode + break; + case 2: + btwrite(BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT); + btor(0x10, BT848_CAP_CTL); + break; + case 3: + btwrite(BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT); + btor(0x10, BT848_CAP_CTL); + break; + case 4: + btwrite(BT848_COLOR_FMT_RGB32, BT848_COLOR_FMT); + btor(0x10, BT848_CAP_CTL); + break; + } + + /* + * Set things up according to the final picture width. + */ + + hactive=btv->win.width; + if (hactive < 193) + { + btwrite (2, BT848_E_VTC); + btwrite (2, BT848_O_VTC); + } + else if (hactive < 385) + { + btwrite (1, BT848_E_VTC); + btwrite (1, BT848_O_VTC); + } + else + { + btwrite (0, BT848_E_VTC); + btwrite (0, BT848_O_VTC); + } + + /* + * Ok are we doing Never The Same Color or PAL ? + */ + + if (btv->win.norm==1) + { + btv->win.cropwidth=640; + btv->win.cropheight=480; + btwrite(0x68, BT848_ADELAY); + btwrite(0x5d, BT848_BDELAY); + btaor(BT848_IFORM_NTSC, ~7, BT848_IFORM); + btaor(BT848_IFORM_XT0, ~0x18, BT848_IFORM); + xsf = (btv->win.width*365625UL)/300000UL; + hscale = ((910UL*4096UL)/xsf-4096); + vdelay=btv->win.cropy+0x16; + hdelay=((hactive*135)/754+btv->win.cropx)&0x3fe; + } + else + { + btv->win.cropwidth=768; + btv->win.cropheight=576; + if (btv->win.norm==0) + { + btwrite(0x7f, BT848_ADELAY); + btwrite(0x72, BT848_BDELAY); + btaor(BT848_IFORM_PAL_BDGHI, ~BT848_IFORM_NORM, BT848_IFORM); + } + else + { + btwrite(0x7f, BT848_ADELAY); + btwrite(0x00, BT848_BDELAY); + btaor(BT848_IFORM_SECAM, ~BT848_IFORM_NORM, BT848_IFORM); + } + btaor(BT848_IFORM_XT1, ~0x18, BT848_IFORM); + xsf = (btv->win.width*36875UL)/30000UL; + hscale = ((1135UL*4096UL)/xsf-4096); + vdelay=btv->win.cropy+0x20; + hdelay=((hactive*186)/922+btv->win.cropx)&0x3fe; + } + sr=((btv->win.cropheight>>inter)*512)/btv->win.height-512; + vscale=(0x10000UL-sr)&0x1fff; + vactive=btv->win.cropheight; + +#if 0 + printk("bttv: hscale=0x%04x, ",hscale); + printk("bttv: vscale=0x%04x\n",vscale); + + printk("bttv: hdelay =0x%04x\n",hdelay); + printk("bttv: hactive=0x%04x\n",hactive); + printk("bttv: vdelay =0x%04x\n",vdelay); + printk("bttv: vactive=0x%04x\n",vactive); +#endif + + /* + * Interlace is set elsewhere according to the final image + * size we desire + */ + + if (btv->win.interlace) + { + btor(BT848_VSCALE_INT, BT848_E_VSCALE_HI); + btor(BT848_VSCALE_INT, BT848_O_VSCALE_HI); + } + else + { + btand(~BT848_VSCALE_INT, BT848_E_VSCALE_HI); + btand(~BT848_VSCALE_INT, BT848_O_VSCALE_HI); + } + + /* + * Load her up + */ + + btwrite(hscale>>8, BT848_E_HSCALE_HI); + btwrite(hscale>>8, BT848_O_HSCALE_HI); + btwrite(hscale&0xff, BT848_E_HSCALE_LO); + btwrite(hscale&0xff, BT848_O_HSCALE_LO); + + btwrite((vscale>>8)|(btread(BT848_E_VSCALE_HI)&0xe0), BT848_E_VSCALE_HI); + btwrite((vscale>>8)|(btread(BT848_O_VSCALE_HI)&0xe0), BT848_O_VSCALE_HI); + btwrite(vscale&0xff, BT848_E_VSCALE_LO); + btwrite(vscale&0xff, BT848_O_VSCALE_LO); + + btwrite(hactive&0xff, BT848_E_HACTIVE_LO); + btwrite(hactive&0xff, BT848_O_HACTIVE_LO); + btwrite(hdelay&0xff, BT848_E_HDELAY_LO); + btwrite(hdelay&0xff, BT848_O_HDELAY_LO); + + btwrite(vactive&0xff, BT848_E_VACTIVE_LO); + btwrite(vactive&0xff, BT848_O_VACTIVE_LO); + btwrite(vdelay&0xff, BT848_E_VDELAY_LO); + btwrite(vdelay&0xff, BT848_O_VDELAY_LO); + + crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| + ((vactive>>4)&0x30)|((vdelay>>2)&0xc0); + btwrite(crop, BT848_E_CROP); + btwrite(crop, BT848_O_CROP); +} + + +/* + * The floats in the tuner struct are computed at compile time + * by gcc and cast back to integers. Thus we don't violate the + * "no float in kernel" rule. + */ + +static struct tunertype tuners[] = { + {"Temic PAL", TEMIC, PAL, + 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2}, + {"Philips PAL_I", Philips, PAL_I, + 16*140.25,16*463.25,0x00,0x00,0x00,0x00,0x00}, + {"Philips NTSC", Philips, NTSC, + 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0}, + {"Philips SECAM", Philips, SECAM, + 16*168.25,16*447.25,0xA3,0x93,0x33,0x8e,0xc0}, + {"NoTuner", NoTuner, NOTUNER, + 0 ,0 ,0x00,0x00,0x00,0x00,0x00}, + {"Philips PAL", Philips, PAL, + 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0}, + {"Temic NTSC", TEMIC, NTSC, + 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2}, + {"TEMIC PAL_I", TEMIC, PAL_I, + 0 ,0 ,0x00,0x00,0x00,0x00,0xc2}, +}; + +/* + * Set TSA5522 synthesizer frequency in 1/16 Mhz steps + */ + +static void set_freq(struct bttv *btv, ushort freq) +{ + u8 config; + u16 div; + struct tunertype *tun=&tuners[btv->tuner]; + int oldAudio = btv->audio; + + audio(btv, AUDIO_MUTE); + udelay(AUDIO_MUTE_DELAY); + if (freq < tun->thresh1) + config = tun->VHF_L; + else if (freq < tun->thresh2) + config = tun->VHF_H; + else + config = tun->UHF; + + div=freq+623; /* div=((freq+16*38.9));*/ + + div&=0x7fff; + if (I2CWrite(btv, btv->tuneradr, (div>>8)&0x7f, div&0xff, 1)<0) + return; + I2CWrite(btv, btv->tuneradr, tun->config, config, 1); + if (!(oldAudio & AUDIO_MUTE)) + { + udelay(FREQ_CHANGE_DELAY); + audio(btv, AUDIO_UNMUTE); + } +} + +static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock) +{ + return -EINVAL; +} + +static long bttv_read(struct video_device *v, char *buf, unsigned long count, int nonblock) +{ + struct bttv *btv= (struct bttv *)v; + int q,todo; + + todo=count; + while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q)) + return -EFAULT; + todo-=q; + buf+=q; + +/* btv->vbip=0; */ + cli(); + if (todo && q==VBIBUF_SIZE-btv->vbip) + { + if(nonblock) + { + sti(); + if(count==todo) + return -EWOULDBLOCK; + return count-todo; + } + interruptible_sleep_on(&btv->vbiq); + sti(); + if(current->signal & ~current->blocked) + { + if(todo==count) + return -EINTR; + else + return count-todo; + } + } + } + if (todo) + { + if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, todo)) + return -EFAULT; + btv->vbip+=todo; + } + return count; +} + +/* + * Open a bttv card. Right now the flags stuff is just playing + */ + +static int bttv_open(struct video_device *dev, int flags) +{ + struct bttv *btv = (struct bttv *)dev; + int users, i; + + switch (flags) + { + case 0: + if (btv->user) + return -EBUSY; + btv->user++; + audio(btv, AUDIO_UNMUTE); + for (i=users=0; ivbip=VBIBUF_SIZE; + btv->cap|=0x0c; + bt848_set_risc_jmps(btv); + break; + } + MOD_INC_USE_COUNT; + return 0; +} + +static void bttv_close(struct video_device *dev) +{ + struct bttv *btv=(struct bttv *)dev; + + btv->user--; + audio(btv, AUDIO_MUTE); + btv->cap&=~3; +#if 0 /* FIXME */ + if(minor&0x20) + { + btv->cap&=~0x0c; + } +#endif + bt848_set_risc_jmps(btv); + + MOD_DEC_USE_COUNT; +} + +/***********************************/ +/* ioctls and supporting functions */ +/***********************************/ + +extern inline void bt848_bright(struct bttv *btv, uint bright) +{ + btwrite(bright&0xff, BT848_BRIGHT); +} + +extern inline void bt848_hue(struct bttv *btv, uint hue) +{ + btwrite(hue&0xff, BT848_HUE); +} + +extern inline void bt848_contrast(struct bttv *btv, uint cont) +{ + unsigned int conthi; + + conthi=(cont>>6)&4; + btwrite(cont&0xff, BT848_CONTRAST_LO); + btaor(conthi, ~4, BT848_E_CONTROL); + btaor(conthi, ~4, BT848_O_CONTROL); +} + +extern inline void bt848_sat_u(struct bttv *btv, ulong data) +{ + u32 datahi; + + datahi=(data>>7)&2; + btwrite(data&0xff, BT848_SAT_U_LO); + btaor(datahi, ~2, BT848_E_CONTROL); + btaor(datahi, ~2, BT848_O_CONTROL); +} + +static inline void bt848_sat_v(struct bttv *btv, ulong data) +{ + u32 datahi; + + datahi=(data>>8)&1; + btwrite(data&0xff, BT848_SAT_V_LO); + btaor(datahi, ~1, BT848_E_CONTROL); + btaor(datahi, ~1, BT848_O_CONTROL); +} + +/* + * Cliprect -> risc table. + * + * FIXME: This is generating wrong code when we have some kinds of + * rectangle lists. I don't currently understand why. + */ + +static void write_risc_data(struct bttv *btv, struct video_clip *vp, int count) +{ + int i; + u32 yy, y, x, dx, ox; + u32 *rmem, *rmem2; + struct video_clip first, *cur, *cur2, *nx, first2, *prev, *nx2; + u32 *rp, rpo=0, rpe=0, p, bpsl; + u32 *rpp; + u32 mask; + int interlace; + int depth; + + rmem=(u32 *)btv->risc_odd; + rmem2=(u32 *)btv->risc_even; + depth=btv->win.bpp; + + /* create y-sorted list */ + + first.next=NULL; + for (i=0; inext) && (vp[i].y > cur->next->y)) + cur=nx; + cur->next=&(vp[i]); + vp[i].next=nx; + } + first2.next=NULL; + + rmem[rpo++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; rmem[rpo++]=0; + + rmem2[rpe++]=BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1; rmem2[rpe++]=0; + + + /* + * 32bit depth frame buffers need extra flags setting + */ + + if (depth==4) + mask=BT848_RISC_BYTE3; + else + mask=0; + + bpsl=btv->win.width*btv->win.bpp; + p=btv->win.vidadr+btv->win.x*btv->win.bpp+ + btv->win.y*btv->win.bpl; + + interlace=btv->win.interlace; + + /* + * Loop through all lines + */ + + for (yy=0; yy<(btv->win.height<<(1^interlace)); yy++) + { + y=yy>>(1^interlace); + + /* + * Even or odd frame generation. We have to + * write the RISC instructions to the right stream. + */ + + if(!(y&1)) + { + rp=&rpo; + rpp=rmem; + } + else + { + rp=&rpe; + rpp=rmem2; + } + + + /* + * first2 is the header of a list of "active" rectangles. We add + * rectangles as we hit their top and remove them as they fall off + * the bottom + */ + + /* remove rects with y2 > y */ + if ((cur=first2.next)) + { + prev=&first2; + do + { + if (cur->y+cur->height < y) + prev->next=cur->next; + else + prev=cur; + } + while ((cur=cur->next)); + } + + /* add rect to second (x-sorted) list if rect.y == y */ + if ((cur=first.next)) + { + while ((cur) && (cur->y == y)) + { + first.next=cur->next; + cur2=&first2; + while ((nx2=cur2->next) && (cur->x > cur2->next->x)) + cur2=nx2; + cur2->next=cur; + cur->next=nx2; + cur=first.next; + } + } + + + /* + * Begin writing the RISC script + */ + + dx=x=0; + + /* + * Starting at x position 0 on a new scan line + * write to location p, don't yet write the number + * of pixels for the instruction + */ + + rpp[(*rp)++]=BT848_RISC_WRITE|BT848_RISC_SOL; + rpp[(*rp)++]=p; + + /* + * For each rectangle we have in the "active" list - sorted left to + * right.. + */ + + for (cur2=first2.next; cur2; cur2=cur2->next) + { + /* + * If we are to the left of the first drawing area + */ + + if (x+dx < cur2->x) + { + /* Bytes pending ? */ + if (dx) + { + /* For a delta away from the start we need to write a SKIP */ + if (x) + rpp[(*rp)++]=BT848_RISC_SKIP|(dx*depth); + else + /* Rewrite the start of line WRITE to a SKIP */ + rpp[(*rp)-2]|=BT848_RISC_BYTE_ALL|(dx*depth); + /* Move X to the next point (drawing start) */ + x=x+dx; + } + /* Ok how far are we from the start of the next rectangle ? */ + dx=cur2->x-x; + /* dx is now the size of data to write */ + + /* If this isnt the left edge generate a "write continue" */ + if (x) + rpp[(*rp)++]=BT848_RISC_WRITEC|(dx*depth)|mask; + else + /* Fill in the byte count on the initial WRITE */ + rpp[(*rp)-2]|=(dx*depth)|mask; + /* Move to the start of the rectangle */ + x=cur2->x; + /* x is our left dx is byte size of hole */ + dx=cur2->width+1; + } + else + /* Already in a clip zone.. set dx */ + if (x+dx < cur2->x+cur2->width) + dx=cur2->x+cur2->width-x+1; + } + /* now treat the rest of the line */ + ox=x; + if (dx) + { + /* Complete the SKIP to eat to the end of the gap */ + if (x) + rpp[(*rp)++]=BT848_RISC_SKIP|(dx*depth); + else + /* Rewrite to SKIP start to this point */ + rpp[(*rp)-2]|=BT848_RISC_BYTE_ALL|(dx*depth); + x=x+dx; + } + + /* + * Not at the right hand edge ? + */ + + if ((dx=btv->win.width-x)!=0) + { + /* Write to edge of display */ + if (x) + rpp[(*rp)++]=BT848_RISC_WRITEC|(dx*depth)|BT848_RISC_EOL|mask; + else + /* Entire frame is a write - patch first order */ + rpp[(*rp)-2]|=(dx*depth)|BT848_RISC_EOL|mask; + } + else + { + /* End of line if needed */ + if (ox) + rpp[(*rp)-1]|=BT848_RISC_EOL|mask; + else + { + /* Skip the line : write a SKIP + start/end of line marks */ + (*rp)--; + rpp[(*rp)-1]=BT848_RISC_SKIP|(btv->win.width*depth)| + BT848_RISC_EOL|BT848_RISC_SOL; + } + } + /* + * Move the video render pointer on a line + */ + if (interlace||(y&1)) + p+=btv->win.bpl; + } + + /* + * Attach the interframe jumps + */ + + rmem[rpo++]=BT848_RISC_JUMP; + rmem[rpo++]=btv->bus_vbi_even; + + rmem2[rpe++]=BT848_RISC_JUMP; + rmem2[rpe++]=btv->bus_vbi_odd; +} + +/* + * Helper for adding clips. + */ + +static void new_risc_clip(struct video_window *vw, struct video_clip *vcp, int x, int y, int w, int h) +{ + vcp[vw->clipcount].x=x; + vcp[vw->clipcount].y=y; + vcp[vw->clipcount].width=w; + vcp[vw->clipcount].height=h; + vw->clipcount++; +} + +/* + * ioctl routine + */ + +static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + unsigned char eedata[256]; +/* unsigned long data;*/ +/* static ushort creg;*/ + struct bttv *btv=(struct bttv *)dev; + static int lastchan=0; + + switch (cmd) + { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name,btv->video_dev.name); + b.type = VID_TYPE_CAPTURE| + VID_TYPE_TUNER| + VID_TYPE_TELETEXT| + VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING| + VID_TYPE_FRAMERAM| + VID_TYPE_SCALES; + b.channels = 4; /* tv , input, svhs */ + b.audios = 4; /* tv, input, svhs */ + b.maxwidth = 768; + b.maxheight = 576; + b.minwidth = 32; + b.minheight = 32; + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + v.flags=VIDEO_VC_AUDIO; + v.tuners=0; + v.type=VIDEO_TYPE_CAMERA; + switch(v.channel) + { + case 0: + strcpy(v.name,"Television"); + v.flags|=VIDEO_VC_TUNER; + v.type=VIDEO_TYPE_TV; + v.tuners=1; + break; + case 1: + strcpy(v.name,"Composite1"); + break; + case 2: + strcpy(v.name,"Composite2"); + break; + case 3: + strcpy(v.name,"SVHS"); + break; + default: + return -EINVAL; + } + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* + * Each channel has 1 tuner + */ + case VIDIOCSCHAN: + { + int v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + bt848_muxsel(btv, v); + lastchan=v; + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v,arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner||lastchan) /* Only tuner 0 */ + return -EINVAL; + strcpy(v.name, "Television"); + v.rangelow=0; + v.rangehigh=0xFFFFFFFF; + v.flags|=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC; + v.mode = btv->win.norm; + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* We have but tuner 0 */ + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + /* Only channel 0 has a tuner */ + if(v.tuner!=0 || lastchan) + return -EINVAL; + if(v.mode!=VIDEO_MODE_PAL||v.mode!=VIDEO_MODE_NTSC) + return -EOPNOTSUPP; + btv->win.norm = v.mode; + bt848_set_size(btv); + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p=btv->picture; + if(copy_to_user(arg, &p, sizeof(p))) + return -EFAULT; + return 0; + } + case VIDIOCSPICT: + { + struct video_picture p; + if(copy_from_user(&p, arg,sizeof(p))) + return -EFAULT; + /* We want -128 to 127 we get 0-65535 */ + bt848_bright(btv, (p.brightness>>8)-128); + /* 0-511 for the colour */ + bt848_sat_u(btv, p.colour>>7); + bt848_sat_v(btv, ((p.colour>>7)*201L)/237); + /* -128 to 127 */ + bt848_hue(btv, (p.hue>>8)-128); + /* 0-511 */ + bt848_contrast(btv, p.contrast>>7); + btv->picture=p; + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip *vcp; + int on; + + if(copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + + if(vw.flags) + return -EINVAL; + + btv->win.x=vw.x; + btv->win.y=vw.y; + btv->win.width=vw.width; + btv->win.height=vw.height; + + if(btv->win.height>btv->win.cropheight/2) + btv->win.interlace=1; + else + btv->win.interlace=0; + + on=(btv->cap&3)?1:0; + + bt848_cap(btv,0); + bt848_set_size(btv); + + if(vw.clipcount>256) + return -EDOM; /* Too many! */ + + /* + * Do any clips. + */ + + vcp=vmalloc(sizeof(struct video_clip)*(vw.clipcount+4)); + if(vcp==NULL) + return -ENOMEM; + if(vw.clipcount && copy_from_user(vcp,vw.clips,sizeof(struct video_clip)*vw.clipcount)) + return -EFAULT; + /* + * Impose display clips + */ + if(btv->win.x<0) + new_risc_clip(&vw, vcp, 0, 0, -btv->win.x, btv->win.height-1); + if(btv->win.y<0) + new_risc_clip(&vw, vcp, 0, 0, btv->win.width-1,-btv->win.y); + if(btv->win.x+btv->win.width> btv->win.swidth) + new_risc_clip(&vw, vcp, btv->win.swidth-btv->win.x, 0, btv->win.width-1, btv->win.height-1); + if(btv->win.y+btv->win.height > btv->win.sheight) + new_risc_clip(&vw, vcp, 0, btv->win.sheight-btv->win.y, btv->win.width-1, btv->win.height-1); + /* + * Question: Do we need to walk the clip list + * and saw off any clips outside the window + * frame or will write_risc_tab do the right + * thing ? + */ + write_risc_data(btv,vcp, vw.clipcount); + vfree(vcp); + if(on) + bt848_cap(btv,1); + return 0; + } + case VIDIOCGWIN: + { + struct video_window vw; + /* Oh for a COBOL move corresponding .. */ + vw.x=btv->win.x; + vw.y=btv->win.y; + vw.width=btv->win.width; + vw.height=btv->win.height; + vw.chromakey=0; + vw.flags=0; + if(btv->win.interlace) + vw.flags|=VIDEO_WINDOW_INTERLACE; + if(copy_to_user(arg,&vw,sizeof(vw))) + return -EFAULT; + return 0; + } + case VIDIOCCAPTURE: + { + int v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(btv->win.vidadr==0 || btv->win.width==0 || btv->win.height==0) + return -EINVAL; + if(v==0) + { + bt848_cap(btv,0); + } + else + { + bt848_cap(btv,1); + } + return 0; + } + case VIDIOCGFBUF: + { + struct video_buffer v; + v.base=(void *)btv->win.vidadr; + v.height=btv->win.sheight; + v.width=btv->win.swidth; + v.depth=btv->win.bpp*8; + v.bytesperline=btv->win.bpl; + if(copy_to_user(arg, &v,sizeof(v))) + return -EFAULT; + return 0; + + } + case VIDIOCSFBUF: + { + struct video_buffer v; + if(!suser()) + return -EPERM; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(v.depth!=8 && v.depth!=16 && v.depth!=24 && v.depth!=32) + return -EINVAL; + btv->win.vidadr=(int)v.base; + btv->win.sheight=v.height; + btv->win.swidth=v.width; + btv->win.bpp=v.depth/8; + btv->win.bpl=v.bytesperline; + + DEBUG(printk("Display at %p is %d by %d, bytedepth %d, bpl %d\n", + v.base, v.width,v.height, btv->win.bpp, btv->win.bpl)); + bt848_set_size(btv); + return 0; + } + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + return 0; + } + case VIDIOCGFREQ: + { + unsigned long v=btv->win.freq; + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSFREQ: + { + unsigned long v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + btv->win.freq=v; + set_freq(btv, btv->win.freq); + return 0; + } + + case VIDIOCGAUDIO: + { + struct video_audio vp; + vp=btv->audio_dev; + vp.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); + vp.flags|=VIDEO_AUDIO_MUTABLE; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + if(copy_from_user(&v,arg, sizeof(v))) + return -EFAULT; + if(v.flags&VIDEO_AUDIO_MUTE) + audio(btv, AUDIO_MUTE); + if(v.audio<0||v.audio>2) + return -EINVAL; + bt848_muxsel(btv,v.audio); + if(!(v.flags&VIDEO_AUDIO_MUTE)) + audio(btv, AUDIO_UNMUTE); + btv->audio_dev=v; + return 0; + } + + case BTTV_WRITEEE: + if(copy_from_user((void *) eedata, (void *) arg, 256)) + return -EFAULT; + writeee(btv, eedata); + break; + + case BTTV_READEE: + readee(btv, eedata); + if(copy_to_user((void *) arg, (void *) eedata, 256)) + return -EFAULT; + break; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static int bttv_init_done(struct video_device *dev) +{ + return 0; +} + +static struct video_device bttv_template= +{ + "UNSET", + VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY|VID_TYPE_TELETEXT, + VID_HARDWARE_BT848, + bttv_open, + bttv_close, + bttv_read, + bttv_write, + bttv_ioctl, + NULL, /* no mmap yet */ + bttv_init_done, + NULL, + 0, + 0 +}; + +struct vidbases +{ + ushort vendor, device; + char *name; + uint badr; +}; + +static struct vidbases vbs[] = { + { PCI_VENDOR_ID_TSENG, 0, "TSENG", PCI_BASE_ADDRESS_0}, + { PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_MIL, + "Matrox Millennium", PCI_BASE_ADDRESS_1}, + { PCI_VENDOR_ID_MATROX, 0x051a, "Matrox Mystique", PCI_BASE_ADDRESS_1}, + { PCI_VENDOR_ID_S3, 0, "S3", PCI_BASE_ADDRESS_0}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_210888GX, + "ATI MACH64 Winturbo", PCI_BASE_ADDRESS_0}, + { PCI_VENDOR_ID_CIRRUS, 0, "Cirrus Logic", PCI_BASE_ADDRESS_0}, + { PCI_VENDOR_ID_N9, PCI_DEVICE_ID_N9_I128, + "Number Nine Imagine 128", PCI_BASE_ADDRESS_0}, + { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TGA, + "DEC DC21030", PCI_BASE_ADDRESS_0}, +}; + + +/* DEC TGA offsets stolen from XFree-3.2 */ + +static uint dec_offsets[4] = { + 0x200000, + 0x804000, + 0, + 0x1004000 +}; + +#define NR_CARDS (sizeof(vbs)/sizeof(struct vidbases)) + +/* Scan for PCI display adapter + if more than one card is present the last one is used for now */ + +static int find_vga(void) +{ + unsigned int devfn, class, vendev; + ushort vendor, device, badr; + int found=0, bus=0, i, tga_type; + unsigned int vidadr=0; + + + for (devfn = 0; devfn < 0xff; devfn++) + { + if (PCI_FUNC(devfn) != 0) + continue; + pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &vendev); + if (vendev == 0xffffffff || vendev == 0x00000000) + continue; + pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &device); + pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class); + class = class >> 16; +/* if (class == PCI_CLASS_DISPLAY_VGA) {*/ + if ((class>>8) == PCI_BASE_CLASS_DISPLAY || + /* Number 9 GXE64Pro needs this */ + class == PCI_CLASS_NOT_DEFINED_VGA) + { + badr=0; + printk(KERN_INFO "bttv: PCI display adapter: "); + for (i=0; i> 12) & 0x0f; + if (tga_type != 0 && tga_type != 1 && tga_type != 3) + { + printk(KERN_ERR "bttv: TGA type (0x%x) unrecognized!\n", tga_type); + found--; + } + vidadr+=dec_offsets[tga_type]; + } + + DEBUG(printk(KERN_DEBUG "bttv: memory @ 0x%08x, ", vidadr)); + DEBUG(printk(KERN_DEBUG "devfn: 0x%04x.\n", devfn)); + found++; + } + } + + if (vidmem) + { + vidadr=vidmem<<20; + printk(KERN_INFO "bttv: Video memory override: 0x%08x\n", vidadr); + found=1; + } + for (i=0; i switch it off */ + if(!(b & TRITON_BUS_CONCURRENCY)) + { + printk(KERN_WARNING "bttv: 82437FX: disabling bus concurrency\n"); + b |= TRITON_BUS_CONCURRENCY; + } + + /* still freezes on other boards -> switch off even more */ + if(b & TRITON_PEER_CONCURRENCY) + { + printk(KERN_WARNING "bttv: 82437FX: disabling peer concurrency\n"); + b &= ~TRITON_PEER_CONCURRENCY; + } + if(!(b & TRITON_STREAMING)) + { + printk(KERN_WARNING "bttv: 82437FX: disabling streaming\n"); + b |= TRITON_STREAMING; + } + + if (b!=bo) + { + pcibios_write_config_byte(bus, devfn, TRITON_PCON, b); + printk(KERN_DEBUG "bttv: 82437FX: PCON changed to: 0x%x\n",b); + } + } + } +} + +static void init_tda9850(struct bttv *btv) +{ + I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0, 1); +} + +/* Figure out card and tuner type */ + +static void idcard(struct bttv *btv) +{ + int i; + + btwrite(0, BT848_GPIO_OUT_EN); + DEBUG(printk(KERN_DEBUG "bttv: GPIO: 0x%08x\n", btread(BT848_GPIO_DATA))); + + btv->type=BTTV_MIRO; + btv->tuner=tuner; + + if (I2CRead(btv, I2C_HAUPEE)>=0) + btv->type=BTTV_HAUPPAUGE; + else if (I2CRead(btv, I2C_STBEE)>=0) + btv->type=BTTV_STB; + + for (i=0xc0; i<0xd0; i+=2) + { + if (I2CRead(btv, i)>=0) + { + btv->tuneradr=i; + break; + } + } + + btv->dbx = I2CRead(btv, I2C_TDA9850) ? 0 : 1; + + if (btv->dbx) + init_tda9850(btv); + + /* How do I detect the tuner type for other cards but Miro ??? */ + printk(KERN_INFO "bttv: model: "); + switch (btv->type) + { + case BTTV_MIRO: + btv->tuner=((btread(BT848_GPIO_DATA)>>10)-1)&7; + printk("MIRO"); + strcpy(btv->video_dev.name,"BT848(Miro)"); + break; + case BTTV_HAUPPAUGE: + printk("HAUPPAUGE"); + strcpy(btv->video_dev.name,"BT848(Hauppauge)"); + break; + case BTTV_STB: + printk("STB"); + strcpy(btv->video_dev.name,"BT848(STB)"); + break; + case BTTV_INTEL: + printk("Intel"); + strcpy(btv->video_dev.name,"BT848(Intel)"); + break; + case BTTV_DIAMOND: + printk("Diamond"); + strcpy(btv->video_dev.name,"BT848(Diamond)"); + break; + } + printk(" (%s @ 0x%02x)\n", tuners[btv->tuner].name, btv->tuneradr); + audio(btv, AUDIO_MUTE); +} + + +static void bt848_set_risc_jmps(struct bttv *btv) +{ + int flags=btv->cap; + + btv->risc_jmp[0]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE; + btv->risc_jmp[1]=0; + + btv->risc_jmp[2]=BT848_RISC_JUMP; + if (flags&8) + btv->risc_jmp[3]=virt_to_bus(btv->vbi_odd); + else + btv->risc_jmp[3]=virt_to_bus(btv->risc_jmp+4); + + btv->risc_jmp[4]=BT848_RISC_JUMP; + if (flags&2) + btv->risc_jmp[5]=virt_to_bus(btv->risc_odd); + else + btv->risc_jmp[5]=virt_to_bus(btv->risc_jmp+6); + + btv->risc_jmp[6]=BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO; + btv->risc_jmp[7]=0; + + btv->risc_jmp[8]=BT848_RISC_JUMP; + if (flags&4) + btv->risc_jmp[9]=virt_to_bus(btv->vbi_even); + else + btv->risc_jmp[9]=virt_to_bus(btv->risc_jmp+10); + + btv->risc_jmp[10]=BT848_RISC_JUMP; + if (flags&1) + btv->risc_jmp[11]=virt_to_bus(btv->risc_even); + else + btv->risc_jmp[11]=virt_to_bus(btv->risc_jmp); + + btaor(flags, ~0x0f, BT848_CAP_CTL); + if (flags&0x0f) + bt848_dma(btv, 3); + else + bt848_dma(btv, 0); +} + + +static int init_bt848(struct bttv *btv) +{ + /* reset the bt848 */ + btwrite(0,BT848_SRESET); + btv->user=0; + + DEBUG(printk(KERN_DEBUG "bttv: bt848_mem: 0x%08x\n",(unsigned int) btv->bt848_mem)); + + /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ + + btv->win.norm=0; /* change this to 1 for NTSC, 2 for SECAM */ + btv->win.interlace=1; + btv->win.x=0; + btv->win.y=0; + btv->win.width=768; /* 640 */ + btv->win.height=576; /* 480 */ + btv->win.cropwidth=768; /* 640 */ + btv->win.cropheight=576; /* 480 */ + btv->win.cropx=0; + btv->win.cropy=0; + btv->win.bpp=2; + btv->win.bpl=1024*btv->win.bpp; + btv->win.swidth=1024; + btv->win.sheight=768; + btv->cap=0; + + if (!(btv->risc_odd=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + return -1; + if (!(btv->risc_even=(dword *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) + return -1; + if (!(btv->risc_jmp =(dword *) kmalloc(1024, GFP_KERNEL))) + return -1; + btv->vbi_odd=btv->risc_jmp+12; + btv->vbi_even=btv->vbi_odd+256; + btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp); + btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6); + + btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD); + btv->vbibuf=(unchar *) vmalloc(VBIBUF_SIZE); + if (!btv->vbibuf) + return -1; + + bt848_muxsel(btv, 1); + bt848_set_size(btv); + +/* btwrite(0, BT848_TDEC); */ + btwrite(0x10, BT848_COLOR_CTL); + btwrite(0x00, BT848_CAP_CTL); + + btwrite(0x0ff, BT848_VBI_PACK_SIZE); + btwrite(1, BT848_VBI_PACK_DEL); + + btwrite(0xfc, BT848_GPIO_DMA_CTL); + btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI, + BT848_IFORM); + + bt848_bright(btv, 0x10); + btwrite(0xd8, BT848_CONTRAST_LO); + + btwrite(0x60, BT848_E_VSCALE_HI); + btwrite(0x60, BT848_O_VSCALE_HI); + btwrite(/*BT848_ADC_SYNC_T|*/ + BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC); + + btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL); + btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL); + btwrite(0x00, BT848_E_SCLOOP); + btwrite(0x00, BT848_O_SCLOOP); + + btwrite(0xffffffUL,BT848_INT_STAT); +/* BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR|BT848_INT_FDSR| + BT848_INT_FTRGT|BT848_INT_FBUS|*/ + btwrite(BT848_INT_ETBF| + BT848_INT_SCERR| + BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| + BT848_INT_FMTCHG|BT848_INT_HLOCK, + BT848_INT_MASK); + +/* make_risctab(btv); */ + make_vbitab(btv); + bt848_set_risc_jmps(btv); + + /* + * Now add the template and register the device unit. + */ + + memcpy(&btv->video_dev,&bttv_template,sizeof(bttv_template)); + idcard(btv); + if(video_register_device(&btv->video_dev)<0) + return -1; + return 0; +} + + +static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + u32 stat,astat; + u32 dstat; + int count; + struct bttv *btv; + + btv=(struct bttv *)dev_id; + count=0; + while (1) + { + /* get/clear interrupt status bits */ + stat=btread(BT848_INT_STAT); + astat=stat&btread(BT848_INT_MASK); + if (!astat) + return; + btwrite(astat,BT848_INT_STAT); + IDEBUG(printk ("bttv: astat %08x\n",astat)); + IDEBUG(printk ("bttv: stat %08x\n",stat)); + + /* get device status bits */ + dstat=btread(BT848_DSTATUS); + + if (astat&BT848_INT_FMTCHG) + { + IDEBUG(printk ("bttv: IRQ_FMTCHG\n")); +/* btv->win.norm&=(dstat&BT848_DSTATUS_NUML) ? (~1) : (~0); */ + } + if (astat&BT848_INT_VPRES) + { + IDEBUG(printk ("bttv: IRQ_VPRES\n")); + } + if (astat&BT848_INT_VSYNC) + { + IDEBUG(printk ("bttv: IRQ_VSYNC\n")); + } + if (astat&BT848_INT_SCERR) { + IDEBUG(printk ("bttv: IRQ_SCERR\n")); + bt848_dma(btv, 0); + bt848_dma(btv, 1); + wake_up_interruptible(&btv->vbiq); + wake_up_interruptible(&btv->capq); + } + if (astat&BT848_INT_RISCI) + { + IDEBUG(printk ("bttv: IRQ_RISCI\n")); + /* printk ("bttv: IRQ_RISCI%d\n",stat>>28); */ + if (stat&(1<<28)) + { + btv->vbip=0; + wake_up_interruptible(&btv->vbiq); + } + if (stat&(2<<28)) + { + bt848_set_risc_jmps(btv); + wake_up_interruptible(&btv->capq); + break; + } + } + if (astat&BT848_INT_OCERR) + { + IDEBUG(printk ("bttv: IRQ_OCERR\n")); + } + if (astat&BT848_INT_PABORT) + { + IDEBUG(printk ("bttv: IRQ_PABORT\n")); + } + if (astat&BT848_INT_RIPERR) + { + IDEBUG(printk ("bttv: IRQ_RIPERR\n")); + } + if (astat&BT848_INT_PPERR) + { + IDEBUG(printk ("bttv: IRQ_PPERR\n")); + } + if (astat&BT848_INT_FDSR) + { + IDEBUG(printk ("bttv: IRQ_FDSR\n")); + } + if (astat&BT848_INT_FTRGT) + { + IDEBUG(printk ("bttv: IRQ_FTRGT\n")); + } + if (astat&BT848_INT_FBUS) + { + IDEBUG(printk ("bttv: IRQ_FBUS\n")); + } + if (astat&BT848_INT_HLOCK) + { + if (dstat&BT848_DSTATUS_HLOC) + audio(btv, AUDIO_ON); + else + audio(btv, AUDIO_OFF); + } + + if (astat&BT848_INT_I2CDONE) + { + } + + count++; + if (count > 10) + printk (KERN_WARNING "bttv: irq loop %d\n", count); + if (count > 20) + { + btwrite(0, BT848_INT_MASK); + printk(KERN_ERR "bttv: IRQ lockup, cleared int mask\n"); + } + } +} + + +/* + * Scan for a Bt848 card, request the irq and map the io memory + */ + +static int find_bt848(void) +{ + short pci_index; + unsigned char command, latency; + int result; + unsigned char bus, devfn; + struct bttv *btv; + + bttv_num=0; + + if (!pcibios_present()) + { + DEBUG(printk(KERN_DEBUG "bttv: PCI-BIOS not present or not accessable!\n")); + return 0; + } + + for (pci_index = 0; + !pcibios_find_device(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848, + pci_index, &bus, &devfn); + ++pci_index) + { + btv=&bttvs[bttv_num]; + btv->bus=bus; + btv->devfn=devfn; + btv->bt848_mem=NULL; + btv->vbibuf=NULL; + btv->risc_jmp=NULL; + btv->vbi_odd=NULL; + btv->vbi_even=NULL; + btv->vbiq=NULL; + btv->capq=NULL; + btv->vbip=VBIBUF_SIZE; + + pcibios_read_config_byte(btv->bus, btv->devfn, + PCI_INTERRUPT_LINE, &btv->irq); + pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0, + &btv->bt848_adr); + + if (remap&&(!bttv_num)) + { + remap<<=20; + remap&=PCI_BASE_ADDRESS_MEM_MASK; + printk(KERN_INFO "Remapping to : 0x%08x.\n", remap); + remap|=btv->bt848_adr&(~PCI_BASE_ADDRESS_MEM_MASK); + pcibios_write_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0, + remap); + pcibios_read_config_dword(btv->bus, btv->devfn, PCI_BASE_ADDRESS_0, + &btv->bt848_adr); + } + + btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK; + pcibios_read_config_byte(btv->bus, btv->devfn, PCI_CLASS_REVISION, + &btv->revision); + printk(KERN_INFO "bttv: Brooktree Bt848 (rev %d) ",btv->revision); + printk("bus: %d, devfn: %d, ", + btv->bus, btv->devfn); + printk("irq: %d, ",btv->irq); + printk("memory: 0x%08x.\n", btv->bt848_adr); + + btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); + + result = request_irq(btv->irq, bttv_irq, + SA_SHIRQ | SA_INTERRUPT,"bttv",(void *)btv); + if (result==-EINVAL) + { + printk(KERN_ERR "bttv: Bad irq number or handler\n"); + return -EINVAL; + } + if (result==-EBUSY) + { + printk(KERN_ERR "bttv: IRQ %d busy, change your PnP config in BIOS\n",btv->irq); + return result; + } + if (result < 0) + return result; + + /* Enable bus-mastering */ + pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command); + command|=PCI_COMMAND_MASTER; + pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command); + pcibios_read_config_byte(btv->bus, btv->devfn, PCI_COMMAND, &command); + if (!(command&PCI_COMMAND_MASTER)) + { + printk(KERN_ERR "bttv: PCI bus-mastering could not be enabled\n"); + return -1; + } + pcibios_read_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER, + &latency); + if (!latency) + { + latency=32; + pcibios_write_config_byte(btv->bus, btv->devfn, PCI_LATENCY_TIMER, + latency); + } + DEBUG(printk(KERN_DEBUG "bttv: latency: %02x\n", latency)); + bttv_num++; + } + if(bttv_num) + printk(KERN_INFO "bttv: %d Bt848 card(s) found.\n", bttv_num); + return bttv_num; +} + +static void release_bttv(void) +{ + u8 command; + int i; + struct bttv *btv; + + for (i=0;ibus, btv->devfn, PCI_COMMAND, &command); + command|=PCI_COMMAND_MASTER; + pcibios_write_config_byte(btv->bus, btv->devfn, PCI_COMMAND, command); + + /* unmap and free memory */ + if (btv->risc_odd) + kfree((void *) btv->risc_odd); + + if (btv->risc_even) + kfree((void *) btv->risc_even); + + DEBUG(printk(KERN_DEBUG "free: risc_jmp: 0x%08x.\n", btv->risc_jmp)); + if (btv->risc_jmp) + kfree((void *) btv->risc_jmp); + + DEBUG(printk(KERN_DEBUG "bt848_vbibuf: 0x%08x.\n", btv->vbibuf)); + if (btv->vbibuf) + vfree((void *) btv->vbibuf); + free_irq(btv->irq,btv); + DEBUG(printk(KERN_DEBUG "bt848_mem: 0x%08x.\n", btv->bt848_mem)); + if (btv->bt848_mem) + iounmap(btv->bt848_mem); + video_unregister_device(&btv->video_dev); + } +} + + +#ifdef MODULE + +int init_module(void) +{ +#else +int init_bttv_cards(struct video_init *unused) +{ +#endif + int i; + + handle_chipset(); + if (find_bt848()<0) + return -EIO; + + for (i=0; i +#include + +#include "bt848.h" + +typedef unsigned int dword; + +struct riscprog { + uint length; + dword *busadr; + dword *prog; +}; + +/* values that can be set by user programs */ + +struct bttv_window { + int x, y; + ushort width, height; + ushort bpp, bpl; + ushort swidth, sheight; + short cropx, cropy; + ushort cropwidth, cropheight; + int vidadr; + ushort freq; + int norm; + int interlace; + int color_fmt; +}; + +/* private data that can only be read (or set indirectly) by user program */ + +struct bttv { + struct video_device video_dev; + struct video_picture picture; /* Current picture params */ + struct video_audio audio_dev; /* Current audio params */ + u_char bus; /* PCI bus the Bt848 is on */ + u_char devfn; + u_char revision; + u_char irq; /* IRQ used by Bt848 card */ + uint bt848_adr; /* bus address of IO mem returned by PCI BIOS */ + u_char *bt848_mem; /* pointer to mapped IO memory */ + ulong busriscmem; + dword *riscmem; + + u_char *vbibuf; + struct bttv_window win; + int type; /* card type */ + int audio; /* audio mode */ + int user; + int tuner; + int tuneradr; + int dbx; + + dword *risc_jmp; + dword *vbi_odd; + dword *vbi_even; + dword bus_vbi_even; + dword bus_vbi_odd; + struct wait_queue *vbiq; + struct wait_queue *capq; + int vbip; + + dword *risc_odd; + dword *risc_even; + int cap; +}; + +/*The following should be done in more portable way. It depends on define + of _ALPHA_BTTV in the Makefile.*/ +#ifdef _ALPHA_BTTV +#define btwrite(dat,adr) writel((dat),(char *) (btv->bt848_adr+(adr))) +#define btread(adr) readl(btv->bt848_adr+(adr)) +#else +#define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr))) +#define btread(adr) readl(btv->bt848_mem+(adr)) +#endif + +#define btand(dat,adr) btwrite((dat) & btread(adr), adr) +#define btor(dat,adr) btwrite((dat) | btread(adr), adr) +#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) + +/* bttv ioctls */ +#define BTTV_WRITE_BTREG 0x00 +#define BTTV_READ_BTREG 0x01 +#define BTTV_SET_BTREG 0x02 +#define BTTV_SETRISC 0x03 +#define BTTV_SETWTW 0x04 +#define BTTV_GETWTW 0x05 +#define BTTV_DMA 0x06 +#define BTTV_CAP_OFF 0x07 +#define BTTV_CAP_ON 0x08 +#define BTTV_GETBTTV 0x09 +#define BTTV_SETFREQ 0x0a +#define BTTV_SETCHAN 0x0b +#define BTTV_INPUT 0x0c +#define BTTV_READEE 0x0d +#define BTTV_WRITEEE 0x0e +#define BTTV_BRIGHT 0x0f +#define BTTV_HUE 0x10 +#define BTTV_COLOR 0x11 +#define BTTV_CONTRAST 0x12 +#define BTTV_SET_FFREQ 0x13 +#define BTTV_MUTE 0x14 + +#define BTTV_GRAB 0x20 +#define BTTV_TESTM 0x20 + + +#define BTTV_UNKNOWN 0x00 +#define BTTV_MIRO 0x01 +#define BTTV_HAUPPAUGE 0x02 +#define BTTV_STB 0x03 +#define BTTV_INTEL 0x04 +#define BTTV_DIAMOND 0x05 + +#define AUDIO_TUNER 0x00 +#define AUDIO_EXTERN 0x01 +#define AUDIO_INTERN 0x02 +#define AUDIO_OFF 0x03 +#define AUDIO_ON 0x04 +#define AUDIO_MUTE 0x80 +#define AUDIO_UNMUTE 0x81 + +#define I2C_TSA5522 0xc2 +#define I2C_TDA9850 0xb6 +#define I2C_HAUPEE 0xa0 +#define I2C_STBEE 0xae + +#define TDA9850_CON1 0x04 +#define TDA9850_CON2 0x05 +#define TDA9850_CON3 0x06 +#define TDA9850_CON4 0x07 +#define TDA9850_ALI1 0x08 +#define TDA9850_ALI2 0x09 +#define TDA9850_ALI3 0x0a + +#endif diff --unified --recursive --new-file --exclude-from exclude linux.videovan/drivers/char/tuner.h linux/drivers/char/tuner.h --- linux.videovan/drivers/char/tuner.h Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/tuner.h Sun Oct 19 18:15:39 1997 @@ -0,0 +1,59 @@ +/* + tuner.h - definition for different tuners + + Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de) + minor modifications by Ralph Metzler (rjkm@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. +*/ + +#ifndef _TUNER_H +#define _TUNER_H + +#define TUNER_TEMIC_PAL 0 /* Miro Gpio Coding -1 */ +#define TUNER_PHILIPS_PAL_I 1 +#define TUNER_PHILIPS_NTSC 2 +#define TUNER_PHILIPS_SECAM 3 +#define TUNER_ABSENT 4 +#define TUNER_PHILIPS_PAL 5 +#define TUNER_TEMIC_NTSC 6 +#define TUNER_TEMIC_PAL_I 7 + +#define NOTUNER 0 +#define PAL 1 +#define PAL_I 2 +#define NTSC 3 +#define SECAM 4 + +#define NoTuner 0 +#define Philips 1 +#define TEMIC 2 +#define Sony 3 + +struct tunertype { + char *name; + unchar Vendor; + unchar Type; + + ushort thresh1; /* frequency Range for UHF,VHF-L, VHF_H */ + ushort thresh2; + unchar VHF_L; + unchar VHF_H; + unchar UHF; + unchar config; + unchar I2C; +}; +#endif + diff --unified --recursive --new-file --exclude-from exclude linux.videovan/drivers/char/videodev.c linux/drivers/char/videodev.c --- linux.videovan/drivers/char/videodev.c Thu Jan 1 01:00:00 1970 +++ linux/drivers/char/videodev.c Sun Oct 19 18:33:58 1997 @@ -0,0 +1,257 @@ +/* + * Video capture interface for Linux + * + * A generic video device interface for the LINUX operating system + * using a set of device structures/vectors for low level operations. + * + * 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. + * + * Author: Alan Cox, + * + * Fixes: + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#define VIDEO_NUM_DEVICES 256 + +/* + * Active devices + */ + +static struct video_device *video_device[VIDEO_NUM_DEVICES]; + +/* + * Initialiser list + */ + +struct video_init +{ + char *name; + int (*init)(struct video_init *); +}; + +extern int init_bttv_cards(struct video_init *); + +static struct video_init video_init_list[]={ +#ifdef CONFIG_VIDEO_BT848 + {"bttv", init_bttv_cards}, +#endif + {"end", NULL} +}; + + +/* + * Read will do some smarts later on. Buffer pin etc. + */ + +static long video_read(struct inode *inode, struct file *file, + char *buf, unsigned long count) +{ + int err; + struct video_device *vfl=video_device[MINOR(inode->i_rdev)]; + return vfl->read(vfl, buf, count, file->f_flags&O_NONBLOCK); +} + +/* + * Write for now does nothing. No reason it shouldnt do overlay setting + * for some boards I guess.. + */ + +static long video_write(struct inode *inode, struct file *file, + const char *buf, unsigned long count) +{ + int err; + struct video_device *vfl=video_device[MINOR(inode->i_rdev)]; + return vfl->write(vfl, buf, count, file->f_flags&O_NONBLOCK); +} + +/* + * Open a video device. + */ + +static int video_open(struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR(inode->i_rdev); + int err; + struct video_device *vfl; + + if(minor>=VIDEO_NUM_DEVICES) + return -ENODEV; + + vfl=video_device[minor]; + if(vfl==NULL) + return -ENODEV; + if(vfl->busy) + return -EBUSY; + vfl->busy=1; /* In case vfl->open sleeps */ + + if(vfl->open) + { + err=vfl->open(vfl,0); /* Tell the device it is open */ + if(err) + { + vfl->busy=0; + return err; + } + } + return 0; +} + +/* + * Last close of a video for Linux device + */ + +static int video_release(struct inode *inode, struct file *file) +{ + struct video_device *vfl=video_device[MINOR(inode->i_rdev)]; + if(vfl->close) + vfl->close(vfl); + vfl->busy=0; + return 0; +} + +/* + * Question: Should we be able to capture and then seek around the + * image ? + */ + +static long long video_lseek(struct file * file, + long long offset, int origin) +{ + return -ESPIPE; +} + + +static int video_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct video_device *vfl=video_device[MINOR(inode->i_rdev)]; + int err=vfl->ioctl(vfl, cmd, (void *)arg); + + if(err!=-ENOIOCTLCMD) + return err; + + switch(cmd) + { + default: + return -EINVAL; + } +} + +/* + * We need to do MMAP support + */ + +/* + * Video For Linux device drivers request registration here. + */ + +int video_register_device(struct video_device *vfd) +{ + int i=0; + int base=0; + int err; + + for(i=base;iminor=i; + /* The init call may sleep so we book the slot out + then call */ + MOD_INC_USE_COUNT; + err=vfd->initialize(vfd); + if(err<0) + { + video_device[i]=NULL; + MOD_DEC_USE_COUNT; + return err; + } + return 0; + } + } + return -ENFILE; +} + +/* + * Unregister an unused video for linux device + */ + +void video_unregister_device(struct video_device *vfd) +{ + if(video_device[vfd->minor]!=vfd) + panic("vfd: bad unregister"); + video_device[vfd->minor]=NULL; + MOD_DEC_USE_COUNT; +} + + +static struct file_operations video_fops= +{ + video_lseek, + video_read, + video_write, + NULL, /* readdir */ + NULL, /* poll */ + video_ioctl, + NULL, /* mmap */ + video_open, + video_release +}; + +/* + * Initialise video for linux + */ + +int videodev_init(void) +{ + struct video_init *vfli = video_init_list; + + printk(KERN_INFO "Linux video capture interface: v0.01 ALPHA\n"); + if(register_chrdev(VIDEO_MAJOR,"video_capture", &video_fops)) + { + printk("video_dev: unable to get major %d\n", VIDEO_MAJOR); + return -EIO; + } + + /* + * Init kernel installed video drivers + */ + + while(vfli->init!=NULL) + { + vfli->init(vfli); + vfli++; + } + return 0; +} + + +int init_module(void) +{ + return videodev_init(); +} + +void cleanup_module(void) +{ + unregister_chrdev(VIDEO_MAJOR, "video_capture"); +} + +EXPORT_SYMBOL(video_register_device); +EXPORT_SYMBOL(video_unregister_device); diff --unified --recursive --new-file --exclude-from exclude linux.videovan/include/linux/videodev.h linux/include/linux/videodev.h --- linux.videovan/include/linux/videodev.h Thu Jan 1 01:00:00 1970 +++ linux/include/linux/videodev.h Sun Oct 19 23:18:06 1997 @@ -0,0 +1,160 @@ +#ifndef __LINUX_VIDEODEV_H +#define __LINUX_VIDEODEV_H + +#ifdef __KERNEL__ + +struct video_device +{ + char name[32]; + int type; + int hardware; + + int (*open)(struct video_device *, int mode); + void (*close)(struct video_device *); + long (*read)(struct video_device *, char *, unsigned long, int noblock); + /* Do we need a write method ? */ + long (*write)(struct video_device *, const char *, unsigned long, int noblock); + int (*ioctl)(struct video_device *, unsigned int , void *); + int (*mmap)(struct video_device *, const char *, unsigned long); + int (*initialize)(struct video_device *); + void *private; + int busy; + int minor; +}; + +extern int videodev_init(void); +#define VIDEO_MAJOR 81 +extern int video_register_device(struct video_device *); +extern void video_unregister_device(struct video_device *); +#endif + + +#define VID_TYPE_CAPTURE 1 /* Can capture */ +#define VID_TYPE_TUNER 2 /* Can tune */ +#define VID_TYPE_TELETEXT 4 /* Does teletext */ +#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ +#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ +#define VID_TYPE_CLIPPING 32 /* Can clip */ +#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ +#define VID_TYPE_SCALES 128 /* Scalable */ + + +struct video_capability +{ + char name[32]; + int type; + int channels; /* Num channels */ + int audios; /* Num audio devices */ + int maxwidth; /* Supported width */ + int maxheight; /* And height */ + int minwidth; /* Supported width */ + int minheight; /* And height */ +}; + + +struct video_channel +{ + int channel; + char name[32]; + int tuners; + __u32 flags; +#define VIDEO_VC_TUNER 1 /* Channel has a tuner */ +#define VIDEO_VC_AUDIO 2 /* Channel has audio */ + __u16 type; +#define VIDEO_TYPE_TV 1 +#define VIDEO_TYPE_CAMERA 2 +}; + +struct video_tuner +{ + int tuner; + char name[32]; + ulong rangelow, rangehigh; /* Tuner range */ + __u32 flags; +#define VIDEO_TUNER_PAL 1 +#define VIDEO_TUNER_NTSC 2 +#define VIDEO_TUNER_SECAM 4 + __u16 mode; /* PAL/NTSC/SECAM/OTHER */ +#define VIDEO_MODE_PAL 0 +#define VIDEO_MODE_NTSC 1 +#define VIDEO_MODE_SCAM 2 +}; + +struct video_picture +{ + __u16 brightness; + __u16 hue; + __u16 colour; + __u16 contrast; + __u16 whiteness; /* Black and white only */ + __u16 depth; /* Capture depth */ +}; + +struct video_audio +{ + int audio; /* Audio channel */ + __u16 volume; /* If settable */ + __u16 bass, treble; + __u32 flags; +#define VIDEO_AUDIO_MUTE 1 +#define VIDEO_AUDIO_MUTABLE 2 +#define VIDEO_AUDIO_VOLUME 4 +#define VIDEO_AUDIO_BASS 8 +#define VIDEO_AUDIO_TREBLE 16 +}; + +struct video_clip +{ + __s32 x,y; + __s32 width, height; + struct video_clip *next; /* For user use/driver use only */ +}; + +struct video_window +{ + __u32 x,y; + __u32 width,height; + __u32 chromakey; + __u32 flags; + struct video_clip *clips; /* Set only */ + int clipcount; +#define VIDEO_WINDOW_INTERLACE 1 +}; + +struct video_buffer +{ + void *base; + int height,width; + int depth; + int bytesperline; +}; + + +struct video_key +{ + __u8 key[8]; + __u32 flags; +}; + +#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ +#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ +#define VIDIOCSCHAN _IOW('v',3,int) /* Set channel */ +#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ +#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ +#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ +#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ +#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ +#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Set the video overlay window */ +#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ +#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ +#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ +#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ +#define VIDIOCGFREQ _IOR('v',15, unsigned long) /* Set tuner */ +#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ +#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ +#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ + + +#define VID_HARDWARE_BT848 1 + +#endif .