diff options
author | Florian Schirmer <devnull@localhost> | 2003-01-21 18:59:21 +0000 |
---|---|---|
committer | Florian Schirmer <devnull@localhost> | 2003-01-21 18:59:21 +0000 |
commit | 67c2cb401fed80bd2d5a2225d447785e7cc65408 (patch) | |
tree | 5ce01177af00963374857f62ce395979f5630ec7 /linux/drivers/media/dvb/bt8xx | |
parent | e9064d09febdcd05bc998f46cb5138cd5bca6bf7 (diff) | |
download | mediapointer-dvb-s2-67c2cb401fed80bd2d5a2225d447785e7cc65408.tar.gz mediapointer-dvb-s2-67c2cb401fed80bd2d5a2225d447785e7cc65408.tar.bz2 |
Add Bt8xx interface files (stolen from PCTV driver)
Diffstat (limited to 'linux/drivers/media/dvb/bt8xx')
-rw-r--r-- | linux/drivers/media/dvb/bt8xx/bt848.h | 358 | ||||
-rw-r--r-- | linux/drivers/media/dvb/bt8xx/bt878.c | 603 | ||||
-rw-r--r-- | linux/drivers/media/dvb/bt8xx/bt878.h | 109 |
3 files changed, 1070 insertions, 0 deletions
diff --git a/linux/drivers/media/dvb/bt8xx/bt848.h b/linux/drivers/media/dvb/bt8xx/bt848.h new file mode 100644 index 000000000..7015fd825 --- /dev/null +++ b/linux/drivers/media/dvb/bt8xx/bt848.h @@ -0,0 +1,358 @@ +/* + bt848.h - Bt848 register offsets + + Copyright (C) 1996,97,98 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 +#ifndef PCI_DEVICE_ID_BT849 +#define PCI_DEVICE_ID_BT849 0x351 +#endif +#ifndef PCI_DEVICE_ID_BT878 +#define PCI_DEVICE_ID_BT878 0x36e +#endif +#ifndef PCI_DEVICE_ID_BT879 +#define PCI_DEVICE_ID_BT879 0x36f +#endif + + +/* 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_PLOCK (1<<2) +#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_NTSC_J 2 +#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_PAL_NC 7 +#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_SCLOOP_PEAK (1<<7) +#define BT848_SCLOOP_HFILT_MINP (1<<3) +#define BT848_SCLOOP_HFILT_MEDP (2<<3) +#define BT848_SCLOOP_HFILT_MAXP (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) + + + +/* Bt848A and higher only !! */ +#define BT848_TGLB 0x080 +#define BT848_TGCTRL 0x084 +#define BT848_FCAP 0x0E8 +#define BT848_PLL_F_LO 0x0F0 +#define BT848_PLL_F_HI 0x0F4 + +#define BT848_PLL_XCI 0x0F8 +#define BT848_PLL_X (1<<7) +#define BT848_PLL_C (1<<6) + +#define BT848_DVSIF 0x0FC + +/* Bt878 register */ + +#define BT878_DEVCTRL 0x40 +#define BT878_EN_TBFX 0x02 +#define BT878_EN_VSFX 0x04 + +#endif diff --git a/linux/drivers/media/dvb/bt8xx/bt878.c b/linux/drivers/media/dvb/bt8xx/bt878.c new file mode 100644 index 000000000..8ade22161 --- /dev/null +++ b/linux/drivers/media/dvb/bt8xx/bt878.c @@ -0,0 +1,603 @@ +/* + * bt878.c: part of the driver for the Pinnacle PCTV Sat DVB PCI card + * + * Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> + * + * large parts based on the bttv driver + * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + * & Marcus Metzler (mocm@thp.uni-koeln.de) + * (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + */ + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <asm/io.h> +#include <linux/ioport.h> +#include <asm/pgtable.h> +#include <asm/page.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 "bt878.h" + +/**************************************/ +/* Miscellaneous utility definitions */ +/**************************************/ + +unsigned int bt878_verbose = 1; +unsigned int bt878_debug = 0; +MODULE_PARM(bt878_verbose,"i"); +MODULE_PARM_DESC(bt878_verbose,"verbose startup messages, default is 1 (yes)"); +MODULE_PARM(bt878_debug,"i"); +MODULE_PARM_DESC(bt878_debug,"debug messages, default is 0 (no)"); + +int bt878_num; +struct bt878 bt878[BT878_MAX]; + +EXPORT_SYMBOL(bt878_num); +EXPORT_SYMBOL(bt878); + +#if defined(__powerpc__) /* big-endian */ +extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) +{ + __asm__ __volatile__ ("stwbrx %1,0,%2" : \ + "=m" (*addr) : "r" (val), "r" (addr)); + __asm__ __volatile__ ("eieio" : : : "memory"); +} +#define btwrite(dat,adr) io_st_le32((unsigned *)(bt->bt878_mem+(adr)),(dat)) +#define btread(adr) ld_le32((unsigned *)(bt->bt878_mem+(adr))) +#else +#define btwrite(dat,adr) writel((dat), (char *) (bt->bt878_mem+(adr))) +#define btread(adr) readl(bt->bt878_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) + +#if defined(dprintk) +#undef dprintk +#endif +#define dprintk if(bt878_debug) printk + +/*******************************/ +/* Memory management functions */ +/*******************************/ + +#define MDEBUG(x) do { } while(0) /* Debug memory management */ + +/* All taken from [DaveM] from the bttv driver + * I will not pretend that I understand this, but + * it seems to work. + * + * The code used to assume that the kernel vmalloc mappings + * existed in the page tables of every process, this is simply + * not guarenteed. We now use pgd_offset_k which is the + * defined way to get at the kernel page tables. + */ + +/* Given PGD from the address space's page table, return the kernel + * virtual mapping of the physical memory mapped at ADR. + */ +static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +{ + unsigned long ret = 0UL; + pmd_t *pmd; + pte_t *ptep, pte; + + if (!pgd_none(*pgd)) { + pmd = pmd_offset(pgd, adr); + if (!pmd_none(*pmd)) { + ptep = pte_offset(pmd, adr); + pte = *ptep; + if(pte_present(pte)) { + ret = (unsigned long) page_address(pte_page(pte)); + ret |= (adr & (PAGE_SIZE - 1)); + + } + } + } + MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long uvirt_to_bus(unsigned long adr) +{ + unsigned long kva, ret; + + kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +static inline unsigned long kvirt_to_bus(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = virt_to_bus((void *)kva); + MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); + return ret; +} + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long va, kva, ret; + + va = VMALLOC_VMADDR(adr); + kva = uvirt_to_kva(pgd_offset_k(va), va); + ret = __pa(kva); + MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); + return ret; +} + +static void * rvmalloc(signed long size) +{ + void * mem; + unsigned long adr, page; + + mem=vmalloc_32(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_reserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, signed long size) +{ + unsigned long adr, page; + + if (mem) + { + adr=(unsigned long) mem; + while (size > 0) + { + page = kvirt_to_pa(adr); + mem_map_unreserve(virt_to_page(__va(page))); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + +/*****************************/ +/* Buffer setup function(s) */ +/*****************************/ + +int bt878_get_buffers(struct bt878 *bt, int bpl, int lpf, int nbufs, int sync) +{ + /* try to allocate nbufs buffers, 2<=nbufs<=16. Each buffer is + a "frame" bpl bytes wide and lpf lines high. + The buffers will be contiguous in kernel virtual space, but + will consist of discontinuous physical pages. + Set up a DMA program to read all these buffers in sequence, + and generate an interrupt at the start of each buffer. + if sync==1, insert a sync RISC op at the start of each buffer, + else don't. + */ + + unsigned long *pc, *pc2; + unsigned char *bp; + int i, j, size, rest; + unsigned long op; + + dprintk("bt878 debug: bt878_get_buffers(%p, bpl=0x%x, lpf=0x%x, n=0x%x\n",bt,bpl,lpf,nbufs); + if(nbufs<2||nbufs>16) return -EINVAL; + if(bpl<0||bpl>4095) return -EINVAL; + if(lpf*nbufs<0||lpf*nbufs>255) return -EINVAL; + if(!bt) return -ENXIO; + + /* stop a possibly running DMA operation */ + btand(~0x0f,BT878_AGPIO_DMA_CTL); + i=btread(BT878_AGPIO_DMA_CTL); + + if(bt->buffer) {rvfree(bt->buffer,bt->allocbufsize); bt->buffer=0; } + if(bt->riscprog) {rvfree(bt->riscprog,PAGE_SIZE); bt->riscprog=0;} + + bt->framesize=bpl*lpf; + bt->buffersize=bt->framesize*nbufs; + bt->allocbufsize=(bpl*lpf*nbufs); + if(bt->allocbufsize&~PAGE_MASK) + bt->allocbufsize=(bt->allocbufsize&PAGE_MASK)+PAGE_SIZE; + dprintk("bt878 debug: allocating 0x%x bytes (min was 0x%x)\n",bt->allocbufsize,(bpl*lpf*nbufs)); + if(!(bt->buffer=rvmalloc(bt->allocbufsize))) { + return -ENOMEM; + } + if(!(bt->riscprog=rvmalloc(PAGE_SIZE))) { + goto fail1; + } + + dprintk("bt878 debug: buffer=%p, riscprog=%p\n",bt->buffer,bt->riscprog); + /* ok. We have the memory for the buffers. Let us set up the DMA prog */ + pc=bt->riscprog; + bp=bt->buffer; + /* sync operation at the beginning of the program */ + *pc++=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC| + BT848_FIFO_STATUS_FM1|(0xf<<20)); + *pc++=0; + for(i=0;i<nbufs;i++) { + for(j=0;j<lpf;j++) { + size=bpl; + rest=PAGE_SIZE-((unsigned int)bp&(~PAGE_MASK)); + if(rest<size) size=rest; + op=BT848_RISC_WRITE|((~i)&0x0f)<<20|(i&0x0f)<<16|size + |BT848_RISC_SOL; + if(j==0) op|=BT848_RISC_IRQ; + if(size==bpl) op|=BT848_RISC_EOL; + *pc++=cpu_to_le32(op); + *pc++=cpu_to_le32(kvirt_to_bus((unsigned long)bp)); + bp+=size; + if(size<bpl) { + size=bpl-size; + op=BT848_RISC_WRITE|((~i)&0x0f)<<20|(i&0x0f)<<16|size + |BT848_RISC_EOL; + *pc++=cpu_to_le32(op); + *pc++=cpu_to_le32(kvirt_to_bus((unsigned long)bp)); + bp+=size; + if((pc-(unsigned long *)bt->riscprog)*sizeof(long)>PAGE_SIZE) goto fail2; + } + } + if(sync) { + *pc++=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC| + BT848_FIFO_STATUS_FM1); + *pc++=0; + } + } + *pc++=cpu_to_le32(BT848_RISC_JUMP); + *pc++=cpu_to_le32(kvirt_to_bus((unsigned long)bt->riscprog)); + + btwrite(cpu_to_le32(bpl|((lpf*nbufs)<<16)),BT878_APACK_LEN); + btwrite(cpu_to_le32(kvirt_to_bus((unsigned long)bt->riscprog)),BT878_ARISC_START); + + if(bt878_debug) { + for(pc2=bt->riscprog;pc2<pc;pc2++) printk("riscprog[%3.3x]=%8.8lx\n", + (pc2-(unsigned long *)(bt->riscprog)),*pc2); + } + + bt->nbuffers=nbufs; + + return 0; + +fail2: + if(bt->riscprog) {rvfree(bt->riscprog,PAGE_SIZE); bt->riscprog=0;} +fail1: + if(bt->buffer) {rvfree(bt->buffer,bt->allocbufsize); bt->buffer=0; bt->allocbufsize=0;} + return -ENOMEM; +} + +EXPORT_SYMBOL(bt878_get_buffers); + +/*****************************/ +/* Start/Stop grabbing funcs */ +/*****************************/ + +void bt878_start(struct bt878 *bt, u32 controlreg) +{ + if(!bt->buffer||!bt->riscprog) bt878_get_buffers(bt,0x400,1,4,0); + /* this call to bt878_get_buffers ought to succeed... */ + dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n",controlreg); + controlreg&=~0x1f; + controlreg|=0x1b; + btwrite(cpu_to_le32(kvirt_to_bus((unsigned long)bt->riscprog)), + BT878_ARISC_START); + if(bt->tasklet) tasklet_enable(bt->tasklet); + btwrite(0x000ff800,BT878_AINT_MASK); + btwrite(controlreg,BT878_AGPIO_DMA_CTL); +} + +void bt878_stop(struct bt878 *bt) +{ + u32 stat; + int i=0; + + btwrite(0,BT878_AINT_MASK); + btand(~0x1f,BT878_AGPIO_DMA_CTL); + dprintk("bt878 debug: bt878_stop\n"); + do { + stat=btread(BT878_AINT_STAT); + if(!(stat&BT878_ARISC_EN)) break; + i++; + } while(i<500); + if(bt->tasklet) tasklet_disable(bt->tasklet); + dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n",bt->nr,i,stat); +} + +EXPORT_SYMBOL(bt878_start); +EXPORT_SYMBOL(bt878_stop); + +/*****************************/ +/* Interrupt service routine */ +/*****************************/ + +static void bt878_irq(int irq, void *dev_id, struct pt_regs * regs) +{ + u32 stat,astat,mask; + int count; + struct bt878 *bt; + + bt=(struct bt878 *)dev_id; + + count=0; + while(1) { + stat=btread(BT878_AINT_STAT); + mask=btread(BT878_AINT_MASK); + if(!(astat=(stat&mask))) return; /* this interrupt is not for me */ +/* dprintk("bt878(%d) debug: irq count %d, stat 0x%8.8x, mask 0x%8.8x\n",bt->nr,count,stat,mask); */ + btwrite(astat,BT878_AINT_STAT); /* try to clear interupt condition */ + + + if(astat&(BT878_ASCERR|BT878_AOCERR)) { + if(bt878_verbose) { + printk("bt878(%d): irq%s%s risc_pc=%08x\n", + bt->nr, + (astat&BT878_ASCERR)?" SCERR":"", + (astat&BT878_AOCERR)?" OCERR":"", + btread(BT878_ARISC_PC)); + } + } + if(astat&(BT878_APABORT|BT878_ARIPERR|BT878_APPERR)) { + if(bt878_verbose) { + printk("bt878(%d): irq%s%s%s risc_pc=%08x\n", + bt->nr, + (astat&BT878_APABORT)?" PABORT":"", + (astat&BT878_ARIPERR)?" RIPERR":"", + (astat&BT878_APPERR)?" PPERR":"", + btread(BT878_ARISC_PC)); + } + } + if(astat&(BT878_AFDSR|BT878_AFTRGT|BT878_AFBUS)) { + if(bt878_verbose) { + printk("bt878(%d): irq%s%s%s risc_pc=%08x\n", + bt->nr, + (astat&BT878_AFDSR)?" FDSR":"", + (astat&BT878_AFTRGT)?" FTRGT":"", + (astat&BT878_AFBUS)?" FBUS":"", + btread(BT878_ARISC_PC)); + } + } + if(astat&BT878_ARISCI) { + spin_lock(&bt->s_lock); + bt->writebuf=(stat&BT878_ARISCS)>>28; + spin_unlock(&bt->s_lock); + wake_up_interruptible(&bt->readq); + if(bt->tasklet) tasklet_schedule(bt->tasklet); + return; + } + count++; + if(count>20) { + btwrite(0,BT878_AINT_MASK); + printk(KERN_ERR + "bt878(%d): IRQ lockup, cleared int mask\n", bt->nr); + break; + } + } +} + +/***********************/ +/* PCI device handling */ +/***********************/ + +static int __devinit bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) +{ + int result; + unsigned char lat; + struct bt878 *bt; +#if defined(__powerpc__) + unsigned int cmd; +#endif + + printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", bt878_num); + + bt=&bt878[bt878_num]; + bt->dev=dev; + bt->nr = bt878_num; + init_waitqueue_head(&bt->readq); + bt->s_lock = SPIN_LOCK_UNLOCKED; + bt->shutdown=0; + + bt->id=dev->device; + bt->irq=dev->irq; + bt->bt878_adr=pci_resource_start(dev,0); + if (pci_enable_device(dev)) + return -EIO; + if (!request_mem_region(pci_resource_start(dev,0), + pci_resource_len(dev,0), + "bt878")) { + return -EBUSY; + } + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &bt->revision); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); + printk(KERN_INFO "bt878(%d): Bt%x (rev %d) at %02x:%02x.%x, ", + bt878_num,bt->id, bt->revision, dev->bus->number, + PCI_SLOT(dev->devfn),PCI_FUNC(dev->devfn)); + printk("irq: %d, latency: %d, memory: 0x%lx\n", + bt->irq, lat, bt->bt878_adr); + + +#if defined(__powerpc__) + /* on OpenFirmware machines (PowerMac at least), PCI memory cycle */ + /* response on cards with no firmware is not enabled by OF */ + pci_read_config_dword(dev, PCI_COMMAND, &cmd); + cmd = (cmd | PCI_COMMAND_MEMORY ); + pci_write_config_dword(dev, PCI_COMMAND, cmd); +#endif + +#ifdef __sparc__ + bt->bt878_mem=(unsigned char *)bt->bt878_adr; +#else + bt->bt878_mem=ioremap(bt->bt878_adr, 0x1000); +#endif + + /* clear interrupt mask */ + btwrite(0, BT848_INT_MASK); + + result = request_irq(bt->irq, bt878_irq, + SA_SHIRQ | SA_INTERRUPT,"bt878",(void *)bt); + if (result==-EINVAL) + { + printk(KERN_ERR "bt878(%d): Bad irq number or handler\n", + bt878_num); + goto fail1; + } + if (result==-EBUSY) + { + printk(KERN_ERR "bt878(%d): IRQ %d busy, change your PnP config in BIOS\n",bt878_num,bt->irq); + goto fail1; + } + if (result < 0) + goto fail1; + + pci_set_master(dev); + pci_set_drvdata(dev,bt); + +/* if(init_bt878(btv) < 0) { + bt878_remove(dev); + return -EIO; + } +*/ + bt->nbuffers=bt->allocbufsize=0; + bt->buffer=bt->riscprog=0; + + btwrite(0,BT878_AINT_MASK); + + bt878_num++; + + return 0; + +/* fail2: + free_irq(bt->irq,bt); +*/ fail1: + release_mem_region(pci_resource_start(bt->dev,0), + pci_resource_len(bt->dev,0)); + return result; +} + +static void __devexit bt878_remove(struct pci_dev *pci_dev) +{ + u8 command; + struct bt878 *bt = pci_get_drvdata(pci_dev); + + if (bt878_verbose) + printk("bt878(%d): unloading\n",bt->nr); + + /* turn off all capturing, DMA and IRQs */ + btand(~15, BT878_AGPIO_DMA_CTL); + + /* first disable interrupts before unmapping the memory! */ + btwrite(0, BT878_AINT_MASK); + btwrite(~0x0UL,BT878_AINT_STAT); + + /* disable PCI bus-mastering */ + pci_read_config_byte(bt->dev, PCI_COMMAND, &command); + /* Should this be &=~ ?? */ + command&=~PCI_COMMAND_MASTER; + pci_write_config_byte(bt->dev, PCI_COMMAND, command); + + free_irq(bt->irq,bt); + printk(KERN_DEBUG "bt878_mem: 0x%p.\n", bt->bt878_mem); + if (bt->bt878_mem) + iounmap(bt->bt878_mem); + + release_mem_region(pci_resource_start(bt->dev,0), + pci_resource_len(bt->dev,0)); + /* wake up any waiting processes + because shutdown flag is set, no new processes (in this queue) + are expected + */ + bt->shutdown=1; + + if(bt->buffer) {rvfree(bt->buffer,bt->allocbufsize); bt->buffer=0;} + if(bt->riscprog) {rvfree(bt->riscprog,PAGE_SIZE); bt->riscprog=0;} + + pci_set_drvdata(pci_dev, NULL); + return; +} + +static struct pci_device_id bt878_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BROOKTREE_878, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, bt878_pci_tbl); + +static struct pci_driver bt878_pci_driver = { + name: "bt878", + id_table: bt878_pci_tbl, + probe: bt878_probe, + remove: bt878_remove, +}; + +/*******************************/ +/* Module management functions */ +/*******************************/ + +int bt878_init_module(void) +{ + bt878_num = 0; + + printk(KERN_INFO "bt878: AUDIO driver version %d.%d.%d loaded\n", + (BT878_VERSION_CODE >> 16) & 0xff, + (BT878_VERSION_CODE >> 8) & 0xff, + BT878_VERSION_CODE & 0xff); +/* + bt878_check_chipset(); +*/ + return pci_module_init(&bt878_pci_driver); +} + +void bt878_cleanup_module(void) +{ + pci_unregister_driver(&bt878_pci_driver); + return; +} + +module_init(bt878_init_module); +module_exit(bt878_cleanup_module); + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/linux/drivers/media/dvb/bt8xx/bt878.h b/linux/drivers/media/dvb/bt8xx/bt878.h new file mode 100644 index 000000000..adbb74145 --- /dev/null +++ b/linux/drivers/media/dvb/bt8xx/bt878.h @@ -0,0 +1,109 @@ +/* + bt878.h - Bt878 audio module (register offsets) + + Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.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 _BT878_H_ +#define _BT878_H_ + +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include "bt848.h" + +#define BT878_VERSION_CODE 0x000000 + +#define BT878_AINT_STAT 0x100 +#define BT878_ARISCS (0xf<<28) +#define BT878_ARISC_EN (1<<27) +#define BT878_ASCERR (1<<19) +#define BT878_AOCERR (1<<18) +#define BT878_APABORT (1<<17) +#define BT878_ARIPERR (1<<16) +#define BT878_APPERR (1<<15) +#define BT878_AFDSR (1<<14) +#define BT878_AFTRGT (1<<13) +#define BT878_AFBUS (1<<12) +#define BT878_ARISCI (1<<11) +#define BT878_AOFLOW (1<<3) + +#define BT878_AINT_MASK 0x104 + +#define BT878_AGPIO_DMA_CTL 0x10c +#define BT878_A_GAIN (0xf<<28) +#define BT878_A_G2X (1<<27) +#define BT878_A_PWRDN (1<<26) +#define BT878_A_SEL (3<<24) +#define BT878_DA_SCE (1<<23) +#define BT878_DA_LRI (1<<22) +#define BT878_DA_MLB (1<<21) +#define BT878_DA_LRD (0x1f<<16) +#define BT878_DA_DPM (1<<15) +#define BT878_DA_SBR (1<<14) +#define BT878_DA_ES2 (1<<13) +#define BT878_DA_LMT (1<<12) +#define BT878_DA_SDR (0xf<<8) +#define BT878_DA_IOM (3<<6) +#define BT878_DA_APP (1<<5) +#define BT878_ACAP_EN (1<<4) +#define BT878_PKTP (3<<2) +#define BT878_RISC_EN (1<<1) +#define BT878_FIFO_EN 1 + +#define BT878_APACK_LEN 0x110 +#define BT878_AFP_LEN (0xff<<16) +#define BT878_ALP_LEN 0xfff + +#define BT878_ARISC_START 0x114 + +#define BT878_ARISC_PC 0x120 + +#define BT878_MAX 4 +extern int bt878_num; +extern struct bt878 bt878[BT878_MAX]; + +struct bt878 { + spinlock_t s_lock; + unsigned int nr; + struct pci_dev *dev; + unsigned int id; + unsigned char revision; + unsigned int irq; + unsigned long bt878_adr; + unsigned char *bt878_mem; + int nbuffers; + int buffersize; + int framesize; + int allocbufsize; + void *buffer; + void *riscprog; + + int writebuf; + int readbuf; + int readptr; + + wait_queue_head_t readq; + struct tasklet_struct *tasklet; + int shutdown; + }; + +int bt878_get_buffers(struct bt878 *bt, int bpl, int lpf, int nbufs, int sync); +void bt878_start(struct bt878 *bt, u32 controlreg); +void bt878_stop(struct bt878 *bt); +#endif |