diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-05 06:47:02 +0000 |
commit | 99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch) | |
tree | 3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /drivers/char | |
parent | e73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff) |
Merge with Linux 2.3.38.
Diffstat (limited to 'drivers/char')
56 files changed, 5098 insertions, 2978 deletions
diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 6417d954c..7d2d0c8e7 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -62,6 +62,8 @@ if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate 'Support for user-space parallel port device drivers' CONFIG_PPDEV $CONFIG_PARPORT fi +source drivers/i2c/Config.in + mainmenu_option next_comment comment 'Mice' tristate 'Bus Mouse Support' CONFIG_BUSMOUSE @@ -127,7 +129,7 @@ comment 'Video For Linux' tristate 'Video For Linux' CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_DEV" != "n" ]; then dep_tristate ' I2C on parallel port' CONFIG_I2C_PARPORT $CONFIG_PARPORT - comment 'Radio/Video Adapters' + comment 'Radio Adapters' dep_tristate ' ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV dep_tristate ' AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_RTRACK" = "y" ]; then @@ -141,37 +143,15 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then if [ "$CONFIG_RADIO_AZTECH" = "y" ]; then hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350 fi - if [ "$CONFIG_PCI" != "n" ]; then - dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV - fi dep_tristate ' GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c fi - dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV - if [ "$CONFIG_PMAC" = "y" ]; then - dep_tristate ' PlanB Video-In on PowerMac' CONFIG_VIDEO_PLANB $CONFIG_VIDEO_DEV - fi - if [ "$CONFIG_PARPORT" != "n" ]; then - dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT - fi - fi - dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV dep_tristate ' SF16FMI Radio' CONFIG_RADIO_SF16FMI $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_SF16FMI" = "y" ]; then hex ' SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284 fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - if [ "$CONFIG_SGI" = "y" ]; then - dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV - fi - fi - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV - fi dep_tristate ' TerraTec ActiveRadio ISA Standalone' CONFIG_RADIO_TERRATEC $CONFIG_VIDEO_DEV if [ "$CONFIG_RADIO_TERRATEC" = "y" ]; then hex ' Terratec i/o port (normally 0x590)' CONFIG_RADIO_TERRATEC_PORT 590 @@ -194,9 +174,25 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then hex ' ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c fi - dep_tristate ' Zoran ZR36057/36060 support' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI + comment 'Video Adapters' + dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI + dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV + if [ "$CONFIG_PARPORT" != "n" ]; then + dep_tristate ' Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' QuickCam Colour Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT + fi + fi + dep_tristate ' SAA5249 Teletext processor' CONFIG_VIDEO_SAA5249 $CONFIG_VIDEO_DEV + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_SGI" = "y" ]; then + dep_tristate ' SGI Vino Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_VINO $CONFIG_VIDEO_DEV $CONFIG_SGI + fi + dep_tristate ' Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)' CONFIG_VIDEO_STRADIS $CONFIG_VIDEO_DEV $CONFIG_PCI + fi + dep_tristate ' Zoran ZR36057/36060 Video For Linux' CONFIG_VIDEO_ZORAN $CONFIG_VIDEO_DEV $CONFIG_PCI dep_tristate ' Include support for Iomega Buz' CONFIG_VIDEO_BUZ $CONFIG_VIDEO_ZORAN - dep_tristate ' Zoran ZR36120/36125 support' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI + dep_tristate ' Zoran ZR36120/36125 Video For Linux' CONFIG_VIDEO_ZR36120 $CONFIG_VIDEO_DEV $CONFIG_PCI fi endmenu @@ -227,12 +223,12 @@ fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate '/dev/agpgart (AGP Support) (EXPERIMENTAL)' CONFIG_AGP if [ "$CONFIG_AGP" != "n" ]; then - bool ' Intel 440LX/BX/GX support' CONFIG_AGP_INTEL - bool ' Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810 - bool ' VIA VP3/MVP3/Apollo Pro support' CONFIG_AGP_VIA - bool ' AMD Irongate support' CONFIG_AGP_AMD - bool ' Generic SiS support' CONFIG_AGP_SIS - bool ' ALI M1541 support' CONFIG_AGP_ALI + bool ' Intel 440LX/BX/GX support' CONFIG_AGP_INTEL + bool ' Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810 + bool ' VIA VP3/MVP3/Apollo Pro support' CONFIG_AGP_VIA + bool ' AMD Irongate support' CONFIG_AGP_AMD + bool ' Generic SiS support' CONFIG_AGP_SIS + bool ' ALI M1541 support' CONFIG_AGP_ALI fi fi endmenu diff --git a/drivers/char/Makefile b/drivers/char/Makefile index d423692dc..42611313f 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -23,56 +23,69 @@ M_OBJS := O_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o raw.o OX_OBJS := pty.o misc.o +KEYMAP =defkeymap.o +KEYBD =pc_keyb.o +CONSOLE =console.o +SERIAL =serial.o + +ifeq ($(ARCH),m68k) + KEYMAP = + KEYBD = +endif + +ifeq ($(ARCH),arm) + KEYMAP = + KEYBD = + CONSOLE = + SERIAL = +endif + +ifeq ($(CONFIG_DECSTATION),y) + KEYBD = + SERIAL = +endif + +ifeq ($(CONFIG_BAGET_MIPS),y) + KEYBD = + SERIAL = +endif + +ifneq ($(CONFIG_SUN_SERIAL),) + SERIAL = +endif + ifdef CONFIG_VT O_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o -OX_OBJS += console.o selection.o +OX_OBJS += $(CONSOLE) selection.o endif ifeq ($(CONFIG_SERIAL),y) - ifeq ($(CONFIG_SUN_SERIAL),) - ifeq ($(CONFIG_SGI_SERIAL),) - ifeq ($(CONFIG_DECSTATION),) - ifeq ($(CONFIG_BAGET_MIPS),) - OX_OBJS += serial.o - endif - endif - endif - endif +OX_OBJS += $(SERIAL) else ifeq ($(CONFIG_SERIAL),m) - ifeq ($(CONFIG_SUN_SERIAL),) - ifeq ($(CONFIG_SGI_SERIAL),) - ifeq ($(CONFIG_DECSTATION),) - ifeq ($(CONFIG_BAGET_MIPS),) - MX_OBJS += serial.o - endif - endif - endif - endif + MX_OBJS += $(SERIAL) endif endif -ifndef CONFIG_SUN_KEYBOARD -ifndef CONFIG_DECSTATION -ifndef CONFIG_BAGET_MIPS -ifdef CONFIG_VT -OX_OBJS += keyboard.o +ifeq ($(CONFIG_SERIAL_21285),y) +O_OBJS += serial_21285.o endif - ifneq ($(ARCH),m68k) - O_OBJS += pc_keyb.o defkeymap.o - endif + +ifndef CONFIG_SUN_KEYBOARD + ifdef CONFIG_VT + OX_OBJS += keyboard.o + O_OBJS += $(KEYMAP) $(KEYBD) + endif else -ifdef CONFIG_PCI -O_OBJS += defkeymap.o -OX_OBJS += keyboard.o -endif + ifdef CONFIG_PCI + OX_OBJS += keyboard.o + O_OBJS += $(KEYMAP) + endif endif ifdef CONFIG_MAGIC_SYSRQ OX_OBJS += sysrq.o endif -endif -endif ifeq ($(CONFIG_ATARI_DSP56K),y) O_OBJS += dsp56k.o @@ -376,12 +389,12 @@ else endif ifeq ($(CONFIG_VIDEO_BT848),y) -O_OBJS += bttv.o msp3400.o +O_OBJS += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o L_I2C=y L_TUNERS=y else ifeq ($(CONFIG_VIDEO_BT848),m) - M_OBJS += bttv.o msp3400.o + M_OBJS += bttv.o msp3400.o tda8425.o tda9855.o tea6300.o M_I2C=y M_TUNERS=y endif @@ -630,10 +643,10 @@ endif # set when a framegrabber implements i2c support ifeq ($(L_I2C),y) -OX_OBJS += i2c.o +OX_OBJS += i2c-old.o else ifeq ($(M_I2C),y) - MX_OBJS += i2c.o + MX_OBJS += i2c-old.o endif endif diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 39a0e3672..d20869b0e 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -6,9 +6,12 @@ O_TARGET := agp.o ifeq ($(CONFIG_AGP),y) - O_OBJS += agpgart.o + O_OBJS += agpgart_fe.o + OX_OBJS += agpgart_be.o else ifeq ($(CONFIG_AGP), m) + MI_OBJS += agpgart_fe.o + MIX_OBJS += agpgart_be.o M_OBJS += agpgart.o endif endif diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 70c013b7d..538aa5fd4 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -134,13 +134,13 @@ struct agp_bridge_data { #endif }; -#define OUTREG32(mmap, addr, val) *(volatile u32 *)(mmap + (addr)) = (val) -#define OUTREG16(mmap, addr, val) *(volatile u16 *)(mmap + (addr)) = (val) -#define OUTREG8 (mmap, addr, val) *(volatile u8 *) (mmap + (addr)) = (val) +#define OUTREG32(mmap, addr, val) __raw_writel((val), (mmap)+(addr)) +#define OUTREG16(mmap, addr, val) __raw_writew((val), (mmap)+(addr)) +#define OUTREG8 (mmap, addr, val) __raw_writeb((val), (mmap)+(addr)) -#define INREG32(mmap, addr) *(volatile u32 *)(mmap + (addr)) -#define INREG16(mmap, addr) *(volatile u16 *)(mmap + (addr)) -#define INREG8 (mmap, addr) *(volatile u8 *) (mmap + (addr)) +#define INREG32(mmap, addr) __raw_readl((mmap)+(addr)) +#define INREG16(mmap, addr) __raw_readw((mmap)+(addr)) +#define INREG8 (mmap, addr) __raw_readb((mmap)+(addr)) #define CACHE_FLUSH agp_bridge.cache_flush #define A_SIZE_8(x) ((aper_size_info_8 *) x) diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c index eeb21921c..27413489a 100644 --- a/drivers/char/agp/agpgart_be.c +++ b/drivers/char/agp/agpgart_be.c @@ -23,7 +23,6 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#define EXPORT_SYMTAB #include <linux/config.h> #include <linux/version.h> #include <linux/module.h> @@ -62,6 +61,26 @@ static void flush_cache(void); static struct agp_bridge_data agp_bridge; static int agp_try_unsupported __initdata = 0; + + +static inline void flush_cache(void) +{ +#if defined(__i386__) + asm volatile ("wbinvd":::"memory"); +#elif defined(__alpha__) + /* ??? I wonder if we'll really need to flush caches, or if the + core logic can manage to keep the system coherent. The ARM + speaks only of using `cflush' to get things in memory in + preparation for power failure. + + If we do need to call `cflush', we'll need a target page, + as we can only flush one page at a time. */ + mb(); +#else +#error "Please define flush_cache." +#endif +} + #ifdef __SMP__ static atomic_t cpus_waiting; @@ -87,12 +106,6 @@ static void smp_flush_cache(void) #define global_cache_flush flush_cache #endif /* __SMP__ */ -static void flush_cache(void) -{ - asm volatile ("wbinvd":::"memory"); -} - - int agp_backend_acquire(void) { atomic_inc(&agp_bridge.agp_in_use); @@ -1356,6 +1369,7 @@ static int amd_irongate_fetch_size(void) static int amd_irongate_configure(void) { aper_size_info_32 *current_size; + unsigned long addr; u32 temp; u16 enable_reg; @@ -1389,8 +1403,16 @@ static int amd_irongate_configure(void) /* Get the address for the gart region */ pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp); - temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); - agp_bridge.gart_bus_addr = temp; + addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); +#ifdef __alpha__ + /* ??? Presumably what is wanted is the bus address as seen + from the CPU side, since it appears that this value is + exported to userland via an ioctl. The terminology below + is confused, mixing `physical address' with `bus address', + as x86 folk are wont to do. */ + addr = virt_to_phys(ioremap(addr, 0)); +#endif + agp_bridge.gart_bus_addr = addr; return 0; } @@ -1894,13 +1916,10 @@ static struct agp_max_table maxes_table[9] = static int agp_find_max(void) { - int memory; - float t; - int index; - int result; + long memory, t, index, result; - memory = virt_to_phys(high_memory) / 0x100000; - index = 0; + memory = virt_to_phys(high_memory) >> 20; + index = 1; while ((memory > maxes_table[index].mem) && (index < 8)) { @@ -1914,8 +1933,8 @@ static int agp_find_max(void) (t * (maxes_table[index].agp - maxes_table[index - 1].agp)); printk(KERN_INFO "agpgart: Maximum main memory to use " - "for agp memory: %dM\n", result); - result = (result * 0x100000) / 4096; + "for agp memory: %ldM\n", result); + result = result << (20 - PAGE_SHIFT); return result; } diff --git a/drivers/char/agp/agpgart_fe.c b/drivers/char/agp/agpgart_fe.c index 54ad294e7..e098b4bab 100644 --- a/drivers/char/agp/agpgart_fe.c +++ b/drivers/char/agp/agpgart_fe.c @@ -1094,5 +1094,6 @@ int agp_frontend_initialize(void) void agp_frontend_cleanup(void) { + misc_deregister(&agp_miscdev); return; } diff --git a/drivers/char/audiochip.h b/drivers/char/audiochip.h new file mode 100644 index 000000000..23d1b1259 --- /dev/null +++ b/drivers/char/audiochip.h @@ -0,0 +1,60 @@ +#ifndef AUDIOCHIP_H +#define AUDIOCHIP_H + +/* ---------------------------------------------------------------------- */ + +#define MIN(a,b) (((a)>(b))?(b):(a)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +/* v4l device was opened in Radio mode */ +#define AUDC_SET_RADIO _IO('m',2) +/* select from TV,radio,extern,MUTE */ +#define AUDC_SET_INPUT _IOW('m',17,int) + +/* all the stuff below is obsolete and just here for reference. I'll + * remove it once the driver is tested and works fine. + * + * Instead creating alot of tiny API's for all kinds of different + * chips, we'll just pass throuth the v4l ioctl structs (v4l2 not + * yet...). It is a bit less flexible, but most/all used i2c chips + * make sense in v4l context only. So I think that's acceptable... + */ + +#if 0 + +/* TODO (if it is ever [to be] accessible in the V4L[2] spec): + * maybe fade? (back/front) + * notes: + * NEWCHANNEL and SWITCH_MUTE are here because the MSP3400 has a special + * routine to go through when it tunes in to a new channel before turning + * back on the sound. + * Either SET_RADIO, NEWCHANNEL, and SWITCH_MUTE or SET_INPUT need to be + * implemented (MSP3400 uses SET_RADIO to select inputs, and SWITCH_MUTE for + * channel-change mute -- TEA6300 et al use SET_AUDIO to select input [TV, + * radio, external, or MUTE]). If both methods are implemented, you get a + * cookie for doing such a good job! :) + */ + +#define AUDC_SET_TVNORM _IOW('m',1,int) /* TV mode + PAL/SECAM/NTSC */ +#define AUDC_NEWCHANNEL _IO('m',3) /* indicate new chan - off mute */ + +#define AUDC_GET_VOLUME_LEFT _IOR('m',4,__u16) +#define AUDC_GET_VOLUME_RIGHT _IOR('m',5,__u16) +#define AUDC_SET_VOLUME_LEFT _IOW('m',6,__u16) +#define AUDC_SET_VOLUME_RIGHT _IOW('m',7,__u16) + +#define AUDC_GET_STEREO _IOR('m',8,__u16) +#define AUDC_SET_STEREO _IOW('m',9,__u16) + +#define AUDC_GET_DC _IOR('m',10,__u16)/* ??? */ + +#define AUDC_GET_BASS _IOR('m',11,__u16) +#define AUDC_SET_BASS _IOW('m',12,__u16) +#define AUDC_GET_TREBLE _IOR('m',13,__u16) +#define AUDC_SET_TREBLE _IOW('m',14,__u16) + +#define AUDC_GET_UNIT _IOR('m',15,int) /* ??? - unimplemented in MSP3400 */ +#define AUDC_SWITCH_MUTE _IO('m',16) /* turn on mute */ +#endif + +#endif /* AUDIOCHIP_H */ diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index b02bbe766..379a7b929 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -1,9 +1,9 @@ - -/* +/* bttv - Bt848 frame grabber driver Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) & Marcus Metzler (mocm@thp.uni-koeln.de) + (c) 1999 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 @@ -21,7 +21,6 @@ */ #include <linux/module.h> -#include <linux/version.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/fs.h> @@ -41,43 +40,55 @@ #include <linux/types.h> #include <linux/wrapper.h> #include <linux/interrupt.h> - -#include <asm/uaccess.h> +#include <linux/version.h> +#include <linux/kmod.h> #include <linux/vmalloc.h> -#include <linux/videodev.h> #include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include <linux/videodev.h> + + #include "bttv.h" #include "tuner.h" -#define DEBUG(x) /* Debug driver */ -#define IDEBUG(x) /* Debug interrupt handler */ +#define DEBUG(x) /* Debug driver */ +#define IDEBUG(x) /* Debug interrupt handler */ +#define MIN(a,b) (((a)>(b))?(b):(a)) +#define MAX(a,b) (((a)>(b))?(a):(b)) /* Anybody who uses more than four? */ #define BTTV_MAX 4 - static void bt848_set_risc_jmps(struct bttv *btv); -static unsigned int vidmem=0; /* manually set video mem address */ -static int triton1=0; -#ifndef USE_PLL -/* 0=no pll, 1=28MHz, 2=34MHz */ -#define USE_PLL 0 -#endif -#ifndef CARD_DEFAULT -/* card type (see bttv.h) 0=autodetect */ -#define CARD_DEFAULT 0 -#endif +static int bttv_num; /* number of Bt848s in use */ +static struct bttv bttvs[BTTV_MAX]; -static unsigned long remap[BTTV_MAX]; /* remap Bt848 */ + +/* insmod args */ +MODULE_PARM(triton1,"i"); +MODULE_PARM(remap,"1-4i"); +MODULE_PARM(radio,"1-4i"); +MODULE_PARM(card,"1-4i"); +MODULE_PARM(pll,"1-4i"); +MODULE_PARM(bigendian,"i"); +MODULE_PARM(fieldnr,"i"); +MODULE_PARM(autoload,"i"); + +#if defined(__sparc__) || defined(__powerpc__) +static unsigned int bigendian=1; +#else +static unsigned int bigendian=0; +#endif +static int triton1=0; +static unsigned long remap[BTTV_MAX]; static unsigned int radio[BTTV_MAX]; -static unsigned int card[BTTV_MAX] = { CARD_DEFAULT, CARD_DEFAULT, - CARD_DEFAULT, CARD_DEFAULT }; -static unsigned int pll[BTTV_MAX] = { USE_PLL, USE_PLL, USE_PLL, USE_PLL }; +static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 }; +static unsigned int pll[BTTV_MAX] = { 0, 0, 0, 0}; +static unsigned int fieldnr = 0; +static unsigned int autoload = 1; -static int bttv_num; /* number of Bt848s in use */ -static struct bttv bttvs[BTTV_MAX]; #define I2C_TIMING (0x7<<4) #define I2C_DELAY 10 @@ -86,9 +97,9 @@ static struct bttv bttvs[BTTV_MAX]; { btwrite((CTRL<<1)|(DATA), BT848_I2C); udelay(I2C_DELAY); } #define I2C_GET() (btread(BT848_I2C)&1) -#define EEPROM_WRITE_DELAY 20000 #define BURSTOFFSET 76 + /*******************************/ /* Memory management functions */ /*******************************/ @@ -121,9 +132,8 @@ static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) if (!pmd_none(*pmd)) { ptep = pte_offset(pmd, adr); pte = *ptep; - /* Note; page_address will panic for us if the page is high */ if(pte_present(pte)) - ret = page_address(pte_page(pte))|(adr&(PAGE_SIZE-1)); + ret = (page_address(pte_page(pte))|(adr&(PAGE_SIZE-1))); } } MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); @@ -205,12 +215,6 @@ static void rvfree(void * mem, unsigned long size) } } -MODULE_PARM(vidmem,"i"); -MODULE_PARM(triton1,"i"); -MODULE_PARM(remap,"1-4i"); -MODULE_PARM(radio,"1-4i"); -MODULE_PARM(card,"1-4i"); -MODULE_PARM(pll,"1-4i"); /* @@ -223,7 +227,7 @@ MODULE_PARM(pll,"1-4i"); static int fbuffer_alloc(struct bttv *btv) { if(!btv->fbuffer) - btv->fbuffer=(unsigned char *) rvmalloc(2*BTTV_MAX_FBUF); + btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF); else printk(KERN_ERR "bttv%d: Double alloc of fbuffer!\n", btv->nr); @@ -236,194 +240,212 @@ static int fbuffer_alloc(struct bttv *btv) /* ----------------------------------------------------------------------- */ /* I2C functions */ -/* software I2C functions */ - -static void i2c_setlines(struct i2c_bus *bus,int ctrl,int data) +static void bttv_bit_setscl(void *data, int state) { - struct bttv *btv = (struct bttv*)bus->data; - btwrite((ctrl<<1)|data, BT848_I2C); - btread(BT848_I2C); /* flush buffers */ - udelay(I2C_DELAY); + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x02; + else + btv->i2c_state &= ~0x02; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); } -static int i2c_getdataline(struct i2c_bus *bus) +static void bttv_bit_setsda(void *data, int state) { - struct bttv *btv = (struct bttv*)bus->data; - return btread(BT848_I2C)&1; + struct bttv *btv = (struct bttv*)data; + + if (state) + btv->i2c_state |= 0x01; + else + btv->i2c_state &= ~0x01; + btwrite(btv->i2c_state, BT848_I2C); + btread(BT848_I2C); } -/* hardware I2C functions */ +static int bttv_bit_getscl(void *data) +{ + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x02 ? 1 : 0; + return state; +} -/* read I2C */ -static int I2CRead(struct i2c_bus *bus, unsigned char addr) +static int bttv_bit_getsda(void *data) { - u32 i; - u32 stat; - struct bttv *btv = (struct bttv*)bus->data; - - /* clear status bit ; BT848_INT_RACK is ro */ - btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); - - btwrite(((addr & 0xff) << 24) | btv->i2c_command, BT848_I2C); - - /* - * Timeout for I2CRead is 1 second (this should be enough, really!) - */ - for (i=1000; i; i--) - { - stat=btread(BT848_INT_STAT); - if (stat & BT848_INT_I2CDONE) - break; - mdelay(1); - } - - if (!i) - { - printk(KERN_DEBUG "bttv%d: I2CRead timeout\n", - btv->nr); - return -1; - } - if (!(stat & BT848_INT_RACK)) - return -2; - - i=(btread(BT848_I2C)>>8)&0xff; - return i; + struct bttv *btv = (struct bttv*)data; + int state; + + state = btread(BT848_I2C) & 0x01; + return state; } -/* set both to write both bytes, reset it to write only b1 */ +static void bttv_inc_use(struct i2c_adapter *adap) +{ + MOD_INC_USE_COUNT; +} -static int I2CWrite(struct i2c_bus *bus, unsigned char addr, unsigned char b1, - unsigned char b2, int both) +static void bttv_dec_use(struct i2c_adapter *adap) { - u32 i; - u32 data; - u32 stat; - struct bttv *btv = (struct bttv*)bus->data; - - /* clear status bit; BT848_INT_RACK is ro */ - btwrite(BT848_INT_I2CDONE, BT848_INT_STAT); - - data=((addr & 0xff) << 24) | ((b1 & 0xff) << 16) | btv->i2c_command; - if (both) - { - data|=((b2 & 0xff) << 8); - data|=BT848_I2C_W3B; - } - - btwrite(data, BT848_I2C); + MOD_DEC_USE_COUNT; +} - for (i=0x1000; i; i--) - { - stat=btread(BT848_INT_STAT); - if (stat & BT848_INT_I2CDONE) - break; - mdelay(1); - } - - if (!i) - { - printk(KERN_DEBUG "bttv%d: I2CWrite timeout\n", - btv->nr); - return -1; +static void call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg) +{ + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (NULL == btv->i2c_clients[i]) + continue; + if (NULL == btv->i2c_clients[i]->driver->command) + continue; + btv->i2c_clients[i]->driver->command( + btv->i2c_clients[i],cmd,arg); } - if (!(stat & BT848_INT_RACK)) - return -2; - - return 0; } -/* read EEPROM */ -static void readee(struct i2c_bus *bus, unsigned char *eedata) +static int attach_inform(struct i2c_client *client) { - int i, k; - - if (I2CWrite(bus, 0xa0, 0, -1, 0)<0) - { - printk(KERN_WARNING "bttv: readee error\n"); - return; - } - - for (i=0; i<256; i++) - { - k=I2CRead(bus, 0xa1); - if (k<0) - { - printk(KERN_WARNING "bttv: readee error\n"); + struct bttv *btv = (struct bttv*)client->adapter->data; + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (btv->i2c_clients[i] == NULL || + btv->i2c_clients[i]->driver->id == client->driver->id) { + btv->i2c_clients[i] = client; break; } - eedata[i]=k; } + if (btv->tuner_type != -1) + call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + printk("bttv%d: i2c attach [%s]\n",btv->nr,client->name); + return 0; } -/* write EEPROM */ -static void writeee(struct i2c_bus *bus, unsigned char *eedata) +static int detach_inform(struct i2c_client *client) { + struct bttv *btv = (struct bttv*)client->adapter->data; int i; - - for (i=0; i<256; i++) - { - if (I2CWrite(bus, 0xa0, i, eedata[i], 1)<0) - { - printk(KERN_WARNING "bttv: writeee error (%d)\n", i); + + printk("bttv%d: i2c detach [%s]\n",btv->nr,client->name); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (NULL != btv->i2c_clients[i] && + btv->i2c_clients[i]->driver->id == client->driver->id) { + btv->i2c_clients[i] = NULL; break; } - udelay(EEPROM_WRITE_DELAY); } + return 0; } -static void attach_inform(struct i2c_bus *bus, int id) +static struct i2c_algo_bit_data i2c_algo_template = { + NULL, + bttv_bit_setsda, + bttv_bit_setscl, + bttv_bit_getsda, + bttv_bit_getscl, + 10, 10, 100, +}; + +static struct i2c_adapter i2c_adap_template = { + "bt848", + I2C_HW_B_BT848, + NULL, + NULL, + bttv_inc_use, + bttv_dec_use, + attach_inform, + detach_inform, + NULL, +}; + +static struct i2c_client i2c_client_template = { + "bttv internal", + -1, + 0, + 0, + NULL, + NULL +}; + +static int init_bttv_i2c(struct bttv *btv) { - struct bttv *btv = (struct bttv*)bus->data; - - switch (id) - { - case I2C_DRIVERID_MSP3400: - btv->have_msp3400 = 1; - break; - case I2C_DRIVERID_TUNER: - btv->have_tuner = 1; - if (btv->tuner_type != -1) - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_TUNER, - TUNER_SET_TYPE,&btv->tuner_type); - break; - } + /* i2c bit_adapter */ + memcpy(&btv->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter)); + memcpy(&btv->i2c_algo, &i2c_algo_template, sizeof(struct i2c_algo_bit_data)); + memcpy(&btv->i2c_client, &i2c_client_template, sizeof(struct i2c_client)); + + sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name), + " #%d", btv->nr); + btv->i2c_algo.data = btv; + btv->i2c_adap.data = btv; + btv->i2c_adap.algo_data = &btv->i2c_algo; + btv->i2c_client.adapter = &btv->i2c_adap; + + bttv_bit_setscl(btv,1); + bttv_bit_setsda(btv,1); + + return i2c_bit_add_bus(&btv->i2c_adap); } -static void detach_inform(struct i2c_bus *bus, int id) +/* read I2C */ +static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for) { - struct bttv *btv = (struct bttv*)bus->data; + unsigned char buffer = 0; - switch (id) - { - case I2C_DRIVERID_MSP3400: - btv->have_msp3400 = 0; - break; - case I2C_DRIVERID_TUNER: - btv->have_tuner = 0; - break; + if (NULL != probe_for) + printk(KERN_INFO "bttv%d: i2c: checking for %s @ 0x%02x... ", + btv->nr,probe_for,addr); + btv->i2c_client.addr = addr >> 1; + if (1 != i2c_master_recv(&btv->i2c_client, &buffer, 1)) { + if (NULL != probe_for) + printk("not found\n"); + else + printk(KERN_WARNING "bttv%d: i2c read 0x%x: error\n", + btv->nr,addr); + return -1; } + if (NULL != probe_for) + printk("found\n"); + return buffer; } -static struct i2c_bus bttv_i2c_bus_template = +/* write I2C */ +static int I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1, + unsigned char b2, int both) { - "bt848", - I2C_BUSID_BT848, - NULL, + unsigned char buffer[2]; + int bytes = both ? 2 : 1; + + btv->i2c_client.addr = addr >> 1; + buffer[0] = b1; + buffer[1] = b2; + if (bytes != i2c_master_send(&btv->i2c_client, buffer, bytes)) + return -1; + return 0; +} + +/* read EEPROM */ +static void readee(struct bttv *btv, unsigned char *eedata) +{ + int i; + + if (I2CWrite(btv, 0xa0, 0, -1, 0)<0) { + printk(KERN_WARNING "bttv: readee error\n"); + return; + } + btv->i2c_client.addr = 0xa0 >> 1; + for (i=0; i<256; i+=16) { + if (16 != i2c_master_recv(&btv->i2c_client,eedata+i,16)) { + printk(KERN_WARNING "bttv: readee error\n"); + break; + } + } +} -#if LINUX_VERSION_CODE >= 0x020100 - SPIN_LOCK_UNLOCKED, -#endif - attach_inform, - detach_inform, - - i2c_setlines, - i2c_getdataline, - I2CRead, - I2CWrite, -}; - /* ----------------------------------------------------------------------- */ /* some hauppauge specific stuff */ @@ -439,7 +461,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "External" }, { TUNER_ABSENT, "Unspecified" }, { TUNER_ABSENT, "Philips FI1216" }, - { TUNER_ABSENT, "Philips FI1216MF" }, + { TUNER_PHILIPS_SECAM, "Philips FI1216MF" }, { TUNER_PHILIPS_NTSC, "Philips FI1236" }, { TUNER_ABSENT, "Philips FI1246" }, { TUNER_ABSENT, "Philips FI1256" }, @@ -462,11 +484,9 @@ hauppauge_tuner[] = }; static void -hauppauge_eeprom(struct i2c_bus *bus) +hauppauge_eeprom(struct bttv *btv) { - struct bttv *btv = (struct bttv*)bus->data; - - readee(bus, eeprom_data); + readee(btv, eeprom_data); if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER)) { btv->tuner_type = hauppauge_tuner[eeprom_data[9]].id; @@ -488,78 +508,219 @@ hauppauge_msp_reset(struct bttv *btv) /* btaor(0, ~32, BT848_GPIO_OUT_EN); */ } -/* ----------------------------------------------------------------------- */ +/* Imagenation L-Model PXC200 Framegrabber */ +/* This is basically the same procedure as + * used by Alessandro Rubini in his pxc200 + * driver, but using BTTV functions */ +static void init_PXC200(struct bttv *btv) +{ + int tmp; + + /* Initialise GPIO-connevted stuff */ + btwrite(1<<13,BT848_GPIO_OUT_EN); /* Reset pin only */ + btwrite(0,BT848_GPIO_DATA); + udelay(3); + btwrite(1<<13,BT848_GPIO_DATA); + /* GPIO inputs are pulled up, so no need to drive + * reset pin any longer */ + btwrite(0,BT848_GPIO_OUT_EN); + + + /* Initialise MAX517 DAC */ + printk(KERN_INFO "Setting DAC reference voltage level ...\n"); + I2CWrite(btv,0x5E,0,0x80,1); + + /* Initialise 12C508 PIC */ + /* The I2CWrite and I2CRead commmands are actually to the + * same chips - but the R/W bit is included in the address + * argument so the numbers are different */ + + printk(KERN_INFO "Initialising 12C508 PIC chip ...\n"); + + tmp=I2CWrite(btv,0x1E,0x08,0,1); + printk(KERN_INFO "I2C Write(0x08) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x09,0,1); + printk(KERN_INFO "I2C Write(0x09) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x0a,0,1); + printk(KERN_INFO "I2C Write(0x0a) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x0b,0,1); + printk(KERN_INFO "I2C Write(0x0b) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x0c,0,1); + printk(KERN_INFO "I2C Write(0x0c) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x0d,0,1); + printk(KERN_INFO "I2C Write(0x0d) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x01,0,1); + printk(KERN_INFO "I2C Write(0x01) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x02,0,1); + printk(KERN_INFO "I2C Write(0x02) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x03,0,1); + printk(KERN_INFO "I2C Write(0x03) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x04,0,1); + printk(KERN_INFO "I2C Write(0x04) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x05,0,1); + printk(KERN_INFO "I2C Write(0x05) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x06,0,1); + printk(KERN_INFO "I2C Write(0x06) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + tmp=I2CWrite(btv,0x1E,0x00,0,1); + printk(KERN_INFO "I2C Write(0x00) = %i\nI2C Read () = %x\n\n",tmp,I2CRead(btv,0x1F,NULL)); + + printk(KERN_INFO "PXC200 Initialised.\n"); +} + +/* ----------------------------------------------------------------------- */ struct tvcard { + char *name; int video_inputs; int audio_inputs; int tuner; int svhs; u32 gpiomask; u32 muxsel[8]; - u32 audiomux[6]; /* Tuner, Radio, internal, external, mute, stereo */ - u32 gpiomask2; /* GPIO MUX mask */ + u32 audiomux[6]; /* Tuner, Radio, external, internal, mute, stereo */ + u32 gpiomask2; /* GPIO MUX mask */ + + /* look for these i2c audio chips */ + int msp34xx:1; + int tda8425:1; + int tda9840:1; + int tda985x:1; + int tea63xx:1; }; static struct tvcard tvcards[] = { - /* default */ - { 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}}, - /* MIRO */ - { 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10}}, - /* Hauppauge */ - { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, - /* STB */ - { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1}}, - /* Intel??? */ - { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, - /* Diamond DTV2000 */ - { 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3}}, - /* AVerMedia TVPhone */ - { 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0}}, - /* Matrix Vision MV-Delta */ - { 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0}}, - /* Fly Video II */ - { 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, - {0, 0xc00, 0x800, 0x400, 0xc00, 0}}, - /* TurboTV */ - { 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0}}, - /* Newer Hauppauge (bt878) */ - { 3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4}}, - /* MIRO PCTV pro */ - { 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10}}, - /* ADS Technologies Channel Surfer TV (and maybe TV+FM) */ - { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, - /* AVerMedia TVCapture 98 */ - { 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0}, 0}, - /* Aimslab VHX */ - { 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4}}, - /* Zoltrix TV-Max */ - { 3, 1, 0, 2, 0x00000f, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0x8}}, - /* Pixelview PlayTV (bt878) */ - { 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }}, - /* "Leadtek WinView 601", */ - { 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}}, - /* AVEC Intercapture */ - { 3, 2, 0, 2, 0, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0}}, - /* LifeView FlyKit w/o Tuner */ - { 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}}, - /* CEI Raffles Card */ - { 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0}}, - /* Lucky Star Image World ConferenceTV */ - {3, 1, 0, 2, 16777215, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4}}, - /* Phoebe Tv Master + FM */ - { 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0}}, - /* Modular Technology MM205 PCTV, bt878 */ - { 2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 }}, - /* Magic TView CPH061 (bt878) */ - { 3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0, 0, 0, 0}}, + /* 0x00 */ + { "unknown", + 3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0, + 1,1,1,1,0 }, + { "MIRO PCTV", + 4, 1, 0, 2,15, { 2, 3, 1, 1}, { 2, 0, 0, 0,10},0, + 1,1,1,1,0 }, + { "Hauppauge old", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,0,1,0 }, + { "STB", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 0, 2, 3, 1},0, + 0,1,1,1,1 }, + + { "Intel", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0 }, + { "Diamond DTV2000", + 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 0, 1, 0, 1, 3},0, + 1,1,1,1,0 }, + { "AVerMedia TVPhone", + 3, 1, 0, 3,15, { 2, 3, 1, 1}, {12, 0,11,11, 0},0, + 1,1,1,1,0 }, + { "MATRIX-Vision MV-Delta", + 5, 1, -1, 3, 0, { 2, 3, 1, 0, 0},{0 }, 0, + 1,1,1,1,0 }, + + /* 0x08 */ + { "Fly Video II", + 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1}, + { 0, 0xc00, 0x800, 0x400, 0xc00, 0},0, + 1,1,1,1,0 }, + { "TurboTV", + 3, 1, 0, 2, 3, { 2, 3, 1, 1}, { 1, 1, 2, 3, 0},0, + 1,1,1,1,0 }, + { "Hauppauge new (bt878)", + 3, 1, 0, 2, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,0,1,0 }, + { "MIRO PCTV pro", + 3, 1, 0, 2, 65551, { 2, 3, 1, 1}, {1,65537, 0, 0,10},0, + 1,1,1,1,0 }, + + { "ADS Technologies Channel Surfer TV", + 3, 1, 2, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0 }, + { "AVerMedia TVCapture 98", + 3, 4, 0, 2, 15, { 2, 3, 1, 1}, { 13, 14, 11, 7, 0, 0},0, + 1,1,1,1,0 }, + { "Aimslab VHX", + 3, 1, 0, 2, 7, { 2, 3, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0 }, + { "Zoltrix TV-Max", + 3, 1, 0, 2,15, { 2, 3, 1, 1}, {0 , 0, 1 , 0, 10},0, + 1,1,1,1,0 }, + + /* 0x10 */ + { "Pixelview PlayTV (bt878)", + 3, 1, 0, 2, 0x01e000, { 2, 0, 1, 1}, + { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0, + 1,1,1,1,0 }, + { "Leadtek WinView 601", + 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, + { 0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007},0, + 1,1,1,1,0 }, + { "AVEC Intercapture", + 3, 2, 0, 2, 0, {2, 3, 1, 1}, {1, 0, 0, 0, 0},0, + 1,1,1,1,0 }, + { "LifeView FlyKit w/o Tuner", + 3, 1, -1, -1, 0x8dff00, { 2, 3, 1, 1}, { 0 },0, + 0,0,0,0,0 }, + + { "CEI Raffles Card", + 3, 3, 0, 2, 0, {2, 3, 1, 1}, {0, 0, 0, 0 ,0},0, + 1,1,1,1,0 }, + { "Lucky Star Image World ConferenceTV", + 3, 1, 0, 2, 16777215, { 2, 3, 1, 1}, { 131072, 1, 1638400, 3, 4},0, + 1,1,1,1,0 }, + { "Phoebe Tv Master + FM", + 3, 1, 0, 2, 0xc00, { 2, 3, 1, 1},{0, 1, 0x800, 0x400, 0xc00, 0},0, + 1,1,1,1,0 }, + { "Modular Technology MM205 PCTV, bt878", + 2, 1, 0, -1, 7, { 2, 3 }, { 0, 0, 0, 0, 0 },0, + 1,1,1,1,0 }, + + /* 0x18 */ + { "Magic TView CPH061 (bt878)", + 3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0, 0, 0, 0},0, + 1,1,1,1,0 }, + { "Terratec/Vobis TV-Boostar", + 3, 1, 0, 2, 16777215 , { 2, 3, 1, 1}, { 131072, 1, 1638400, 3,4},0, + 1,1,1,1,0 }, + { "Newer Hauppauge WinCam (bt878)", + 4, 1, 0, 3, 7, { 2, 0, 1, 1}, { 0, 1, 2, 3, 4},0, + 1,1,1,1,0 }, + { "MAXI TV Video PCI2", + 3, 1, 0, 2, 0xffff, { 2, 3, 1, 1}, { 0, 1, 2, 3, 0xc00},0, + 1,1,1,1,0 }, + + { "Terratec TerraTV+", + 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, + { 0x20000, 0x30000, 0x00000, 0x10000, 0x40000},0, + 1,1,1,1,0 }, + { "Imagenation PXC200", + 5, 1, -1, 4, 0, { 2, 3, 1, 0, 0}, { 0 }, 0, + 1,1,1,1,0 }, + { "FlyVideo 98", + 3, 1, 0, 2, 0x8dff00, {2, 3, 1, 1}, + { 0, 0x8dff00, 0x800, 0x400, 0x8dff00, 0 },0, + 1,1,1,1,0 }, + { "iProTV", + 3, 1, 0, 2, 1, { 2, 3, 1, 1}, { 1, 0, 0, 0, 0 },0, + 1,1,1,1,0 }, + + /* 0x20 */ + { "Intel Create and Share PCI", + 4, 1, 0, 2, 7, { 2, 3, 1, 1}, { 4, 4, 4, 4, 4},0, + 1,1,1,1,0 }, + { "Askey/Typhoon/Anubis Magic TView", + 3, 1, 0, 2, 0xe00, { 2, 0, 1, 1}, {0x400, 0x400, 0x400, 0x400, 0},0, + 1,1,1,1,0 }, + { "Terratec TerraTValue", + 3, 1, 0, 2, 0x70000, { 2, 3, 1, 1}, { 0x500, 0, 0x300, 0x900, 0x900},0, + 1,1,1,1,0 }, }; -#define TVCARDS (sizeof(tvcards)/sizeof(tvcard)) +#define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard)) -static void audio(struct bttv *btv, int mode) +/* ----------------------------------------------------------------------- */ + +static void audio(struct bttv *btv, int mode, int no_irq_context) { btaor(tvcards[btv->type].gpiomask, ~tvcards[btv->type].gpiomask, BT848_GPIO_OUT_EN); @@ -585,17 +746,14 @@ static void audio(struct bttv *btv, int mode) break; } /* if audio mute or not in H-lock, turn audio off */ - if ((btv->audio&AUDIO_MUTE) -#if 0 - || - (!btv->radio && !(btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC)) -#endif - ) + if ((btv->audio&AUDIO_MUTE)) mode=AUDIO_OFF; - if ((mode == 0) && (btv->radio)) - mode = 1; + if ((mode == AUDIO_TUNER) && (btv->radio)) + mode = AUDIO_RADIO; btaor(tvcards[btv->type].audiomux[mode], ~tvcards[btv->type].gpiomask, BT848_GPIO_DATA); + if (no_irq_context) + call_i2c_clients(btv,AUDC_SET_INPUT,&(mode)); } @@ -697,7 +855,7 @@ static int set_pll(struct bttv *btv) } while(time_before(jiffies,tv)); - for (i=0; i<10; i++) + for (i=0; i<100; i++) { if ((btread(BT848_DSTATUS)&BT848_DSTATUS_PLOCK)) btwrite(0,BT848_DSTATUS); @@ -738,20 +896,12 @@ static void bt848_muxsel(struct bttv *btv, unsigned int input) } btaor((tvcards[btv->type].muxsel[input&7]&3)<<5, ~(3<<5), BT848_IFORM); audio(btv, (input!=tvcards[btv->type].tuner) ? - AUDIO_EXTERN : AUDIO_TUNER); + AUDIO_EXTERN : AUDIO_TUNER, 1); btaor(tvcards[btv->type].muxsel[input]>>4, ~tvcards[btv->type].gpiomask2, BT848_GPIO_DATA); } -/* - * 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. - */ - + struct tvnorm { u32 Fsc; @@ -768,29 +918,14 @@ static struct tvnorm tvnorms[] = { /* PAL-BDGHI */ /* max. active video is actually 922, but 924 is divisible by 4 and 3! */ /* actually, max active PAL with HSCALE=0 is 948, NTSC is 768 - nil */ -#ifdef VIDEODAT { 35468950, 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), 1135, 186, 924, 0x20, 255}, -#else - { 35468950, - 924, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - 1135, 186, 924, 0x20, 255}, -#endif -/* - { 35468950, - 768, 576, 1135, 0x7f, 0x72, (BT848_IFORM_PAL_BDGHI|BT848_IFORM_XT1), - 944, 186, 922, 0x20, 255}, -*/ + /* NTSC */ { 28636363, 768, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), 910, 128, 910, 0x1a, 144}, -/* - { 28636363, - 640, 480, 910, 0x68, 0x5d, (BT848_IFORM_NTSC|BT848_IFORM_XT0), - 780, 122, 754, 0x1a, 144}, -*/ #if 0 /* SECAM EAST */ { 35468950, @@ -889,8 +1024,10 @@ static int make_rawrisctab(struct bttv *btv, unsigned int *ro, unsigned long bpl=1024; /* bytes per line */ unsigned long vadr=(unsigned long) vbuf; - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); /* In PAL 650 blocks of 256 DWORDs are sampled, but only if VDELAY is 2 and without separate VBI grabbing. @@ -913,7 +1050,6 @@ static int make_rawrisctab(struct bttv *btv, unsigned int *ro, return 0; } - static int make_prisctab(struct bttv *btv, unsigned int *ro, unsigned int *re, unsigned int *vbuf, unsigned short width, @@ -962,8 +1098,10 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, cradr=cbadr+csize; inter = (height>btv->win.cropheight/2) ? 1 : 0; - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(ro++)=0; - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); + *(ro++)=0; + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM3); + *(re++)=0; for (line=0; line < (height<<(1^inter)); line++) { @@ -1005,7 +1143,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro, vadr+=bl; if((rcmd&(15<<28))==BT848_RISC_WRITE123) { - *((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr)); + *((*rp)++)=(kvirt_to_bus(cbadr)); cbadr+=blcb; *((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr)); cradr+=blcr; @@ -1045,8 +1183,10 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro, inter = (height>btv->win.cropheight/2) ? 1 : 0; bpl=width*fmtbppx2[palette2fmt[palette]&0xf]/2; - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); for (line=0; line < (height<<(1^inter)); line++) { @@ -1059,7 +1199,7 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro, if (bpl<=bl) { *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_SOL| - BT848_RISC_EOL|bpl); + BT848_RISC_EOL|bpl); *((*rp)++)=cpu_to_le32(kvirt_to_bus(vadr)); vadr+=bpl; } @@ -1156,18 +1296,28 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) unsigned long adr; unsigned char *clipmap, cbit, lastbit, outofmem; + if (btv->win.use_yuv) { + /* yuv-to-offscreen (BT848_COLOR_FMT_YUY2) */ + bpp = 2; + bpl = btv->win.win2.pitch; + adr = btv->win.vidadr + btv->win.win2.start; + } else { + bpp=btv->win.bpp; + if (bpp==15) /* handle 15bpp as 16bpp in calculations */ + bpp++; + bpl=btv->win.bpl; + adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; + } inter=(btv->win.interlace&1)^1; - bpp=btv->win.bpp; - if (bpp==15) /* handle 15bpp as 16bpp in calculations */ - bpp++; - bpl=btv->win.bpl; - ro=btv->risc_odd; - re=btv->risc_even; - if((width=btv->win.width)>1023) + width=btv->win.width; + height=btv->win.height; + if(width > 1023) width = 1023; /* sanity check */ - if((height=btv->win.height)>625) + if(height > 625) height = 625; /* sanity check */ - adr=btv->win.vidadr+btv->win.x*bpp+btv->win.y*bpl; + ro=btv->risc_odd; + re=btv->risc_even; + if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) { /* can't clip, don't generate any risc code */ *(ro++)=cpu_to_le32(BT848_RISC_JUMP); @@ -1186,17 +1336,21 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) /* clip against viewing window AND screen so we do not have to rely on the user program */ - clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ? - (btv->win.swidth-btv->win.x) : width, 0, 1024, 768); - clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? - (btv->win.sheight-btv->win.y) : height,1024,768); - if (btv->win.x<0) - clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); - if (btv->win.y<0) - clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); + if (!btv->win.use_yuv) { + clip_draw_rectangle(clipmap,(btv->win.x+width>btv->win.swidth) ? + (btv->win.swidth-btv->win.x) : width, 0, 1024, 768); + clip_draw_rectangle(clipmap,0,(btv->win.y+height>btv->win.sheight) ? + (btv->win.sheight-btv->win.y) : height,1024,768); + if (btv->win.x<0) + clip_draw_rectangle(clipmap, 0, 0, -(btv->win.x), 768); + if (btv->win.y<0) + clip_draw_rectangle(clipmap, 0, 0, 1024, -(btv->win.y)); + } - *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(ro++)=0; - *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); *(re++)=0; + *(ro++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(ro++)=cpu_to_le32(0); + *(re++)=cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1); + *(re++)=cpu_to_le32(0); /* translate bitmap to risc code */ for (line=outofmem=0; line < (height<<inter) && !outofmem; line++) @@ -1216,8 +1370,9 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) if (!lastbit) { *((*rp)++)=cpu_to_le32(BT848_RISC_WRITE|flags|len); *((*rp)++)=cpu_to_le32(adr + bpp * sx); - } else + } else { *((*rp)++)=cpu_to_le32(BT848_RISC_SKIP|flags|len); + } lastbit=cbit; sx += dx; dx = 1; @@ -1230,6 +1385,7 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) if ((!inter)||(line&1)) adr+=bpl; } + vfree(clipmap); /* outofmem flag relies on the following code to discard extra data */ *(ro++)=cpu_to_le32(BT848_RISC_JUMP); @@ -1238,6 +1394,15 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr) *(re++)=cpu_to_le32(btv->bus_vbi_odd); } +/* + * 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. + */ + /* set geometry for even/odd frames just if you are wondering: handling of even and odd frames will be separated, e.g. for grabbing @@ -1266,7 +1431,8 @@ static inline void bt848_set_eogeo(struct bttv *btv, int odd, u8 vtc, } -static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt, int pllset) +static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, + u16 fmt, int no_irq_context) { u16 vscale, hscale; u32 xsf, sr; @@ -1279,7 +1445,7 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt, int if (!width || !height) return; - + save_flags(flags); cli(); @@ -1288,17 +1454,6 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt, int btv->win.cropheight=tvn->sheight; btv->win.cropwidth=tvn->swidth; -/* - if (btv->win.cropwidth>tvn->cropwidth) - btv->win.cropwidth=tvn->cropwidth; - if (btv->win.cropheight>tvn->cropheight) - btv->win.cropheight=tvn->cropheight; - - if (width>btv->win.cropwidth) - width=btv->win.cropwidth; - if (height>btv->win.cropheight) - height=btv->win.cropheight; -*/ btwrite(tvn->adelay, BT848_ADELAY); btwrite(tvn->bdelay, BT848_BDELAY); btaor(tvn->iform,~(BT848_IFORM_NORM|BT848_IFORM_XTBOTH), BT848_IFORM); @@ -1306,27 +1461,28 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt, int btwrite(1, BT848_VBI_PACK_DEL); btv->pll.pll_ofreq = tvn->Fsc; - if(pllset) - set_pll(btv); + if (no_irq_context) + set_pll(btv); btwrite(fmt, BT848_COLOR_FMT); -#ifdef __sparc__ - if(fmt == BT848_COLOR_FMT_RGB32 || - fmt == BT848_COLOR_FMT_RGB24) { - btwrite((BT848_COLOR_CTL_GAMMA | - BT848_COLOR_CTL_WSWAP_ODD | - BT848_COLOR_CTL_WSWAP_EVEN | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN), - BT848_COLOR_CTL); - } else if(fmt == BT848_COLOR_FMT_RGB16 || - fmt == BT848_COLOR_FMT_RGB15) { + if (bigendian && + fmt == BT848_COLOR_FMT_RGB32) { btwrite((BT848_COLOR_CTL_GAMMA | - BT848_COLOR_CTL_BSWAP_ODD | - BT848_COLOR_CTL_BSWAP_EVEN), - BT848_COLOR_CTL); - } -#endif + BT848_COLOR_CTL_WSWAP_ODD | + BT848_COLOR_CTL_WSWAP_EVEN | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN), + BT848_COLOR_CTL); + } else if (bigendian && + (fmt == BT848_COLOR_FMT_RGB16 || + fmt == BT848_COLOR_FMT_RGB15)) { + btwrite((BT848_COLOR_CTL_GAMMA | + BT848_COLOR_CTL_BSWAP_ODD | + BT848_COLOR_CTL_BSWAP_EVEN), + BT848_COLOR_CTL); + } else { + btwrite(0x10, BT848_COLOR_CTL); + } hactive=width; vtc=0; @@ -1350,18 +1506,18 @@ static void bt848_set_geo(struct bttv *btv, u16 width, u16 height, u16 fmt, int crop=((hactive>>8)&0x03)|((hdelay>>6)&0x0c)| ((vactive>>4)&0x30)|((vdelay>>2)&0xc0); vscale|= btv->win.interlace ? (BT848_VSCALE_INT<<8) : 0; - + bt848_set_eogeo(btv, 0, vtc, hscale, vscale, hactive, vactive, hdelay, vdelay, crop); bt848_set_eogeo(btv, 1, vtc, hscale, vscale, hactive, vactive, hdelay, vdelay, crop); - + restore_flags(flags); } int bpp2fmt[4] = { - BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, + BT848_COLOR_FMT_RGB8, BT848_COLOR_FMT_RGB16, BT848_COLOR_FMT_RGB24, BT848_COLOR_FMT_RGB32 }; @@ -1369,9 +1525,14 @@ static void bt848_set_winsize(struct bttv *btv) { unsigned short format; - btv->win.color_fmt = format = - (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : - bpp2fmt[(btv->win.bpp-1)&3]; + if (btv->win.use_yuv) { + /* yuv-to-offscreen */ + format = BT848_COLOR_FMT_YUY2; + } else { + format = (btv->win.depth==15) ? BT848_COLOR_FMT_RGB15 : + bpp2fmt[(btv->win.bpp-1)&3]; + } + btv->win.color_fmt = format; /* RGB8 seems to be a 9x5x5 GRB color cube starting at * color 16. Why the h... can't they even mention this in the @@ -1385,45 +1546,39 @@ static void bt848_set_winsize(struct bttv *btv) else btor(BT848_CAP_CTL_DITH_FRAME, BT848_CAP_CTL); - bt848_set_geo(btv, btv->win.width, btv->win.height, format, 1); + bt848_set_geo(btv, btv->win.width, btv->win.height, format,1); } /* * Set TSA5522 synthesizer frequency in 1/16 Mhz steps */ +#if 0 static void set_freq(struct bttv *btv, unsigned short freq) { + int naudio; int fixme = freq; /* XXX */ - + /* int oldAudio = btv->audio; */ + /* mute */ - if (btv->have_msp3400) - i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, - MSP_SWITCH_MUTE,0); - - /* switch channel */ - if (btv->have_tuner) { - if (btv->radio) { - i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER, - TUNER_SET_RADIOFREQ,&fixme); - } else { - i2c_control_device(&(btv->i2c), I2C_DRIVERID_TUNER, - TUNER_SET_TVFREQ,&fixme); - } - } + AUDIO(AUDC_SWITCH_MUTE,0); - if (btv->have_msp3400) { - if (btv->radio) { - i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, - MSP_SET_RADIO,0); - } else { - i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, - MSP_SET_TVNORM,&(btv->win.norm)); - i2c_control_device(&(btv->i2c),I2C_DRIVERID_MSP3400, - MSP_NEWCHANNEL,0); - } + /* tune */ + if (btv->radio) { + TUNER(TUNER_SET_RADIOFREQ,&fixme); + } else { + TUNER(TUNER_SET_TVFREQ,&fixme); + } + + if (btv->radio) { + AUDIO(AUDC_SET_RADIO,0); + } else { + AUDIO(AUDC_SET_TVNORM,&(btv->win.norm)); + AUDIO(AUDC_NEWCHANNEL,0); } } +#endif + /* * Grab into virtual memory. @@ -1447,7 +1602,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp) * No grabbing past the end of the buffer! */ - if(mp->frame>1 || mp->frame <0) + if(mp->frame>(MAX_GBUFFERS-1) || mp->frame <0) return -EINVAL; if(mp->height <0 || mp->width <0) @@ -1485,6 +1640,7 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp) re=ro+2048; make_vrisctab(btv, ro, re, vbuf, mp->width, mp->height, mp->format); /* bt848_set_risc_jmps(btv); */ + cli(); btv->frame_stat[mp->frame] = GBUFFER_GRABBING; if (btv->grabbing) { btv->gfmt_next=palette2fmt[mp->format]; @@ -1508,12 +1664,14 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp) } btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ); } + sti(); btor(3, BT848_CAP_CTL); btor(3, BT848_GPIO_DMA_CTL); /* interruptible_sleep_on(&btv->capq); */ return 0; } + static long bttv_write(struct video_device *v, const char *buf, unsigned long count, int nonblock) { return -EINVAL; @@ -1523,6 +1681,7 @@ static long bttv_read(struct video_device *v, char *buf, unsigned long count, in { struct bttv *btv= (struct bttv *)v; int q,todo; + /* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */ todo=count; while (todo && todo>(q=VBIBUF_SIZE-btv->vbip)) @@ -1569,18 +1728,17 @@ static long bttv_read(struct video_device *v, char *buf, unsigned long count, in static int bttv_open(struct video_device *dev, int flags) { struct bttv *btv = (struct bttv *)dev; - int i, ret; - + int i,ret; + ret = -EBUSY; - down(&btv->lock); - if (btv->user) + if (btv->user) goto out_unlock; - - btv->fbuffer= (unsigned char *) rvmalloc(2*BTTV_MAX_FBUF); + + btv->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS*BTTV_MAX_FBUF); ret = -ENOMEM; - if (!btv->fbuffer) + if (!btv->fbuffer) goto out_unlock; - audio(btv, AUDIO_UNMUTE); + btv->grabbing = 0; btv->grab = 0; btv->lastgrab = 0; @@ -1588,9 +1746,9 @@ static int bttv_open(struct video_device *dev, int flags) btv->frame_stat[i] = GBUFFER_UNUSED; btv->user++; - up(&btv->lock); + up(&btv->lock); MOD_INC_USE_COUNT; - return 0; + return 0; out_unlock: up(&btv->lock); @@ -1601,9 +1759,8 @@ static void bttv_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)dev; - down(&btv->lock); + down(&btv->lock); btv->user--; - audio(btv, AUDIO_INTERN); btv->cap&=~3; bt848_set_risc_jmps(btv); @@ -1621,15 +1778,16 @@ static void bttv_close(struct video_device *dev) * be sure its safe to free the buffer. We wait 5-6 fields * which is more than sufficient to be sure. */ - + current->state = TASK_UNINTERRUPTIBLE; schedule_timeout(HZ/10); /* Wait 1/10th of a second */ /* * We have allowed it to drain. */ + if(btv->fbuffer) - rvfree((void *) btv->fbuffer, 2*BTTV_MAX_FBUF); + rvfree((void *) btv->fbuffer, MAX_GBUFFERS*BTTV_MAX_FBUF); btv->fbuffer=0; up(&btv->lock); MOD_DEC_USE_COUNT; @@ -1680,6 +1838,7 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data) btaor(datahi, ~1, BT848_O_CONTROL); } + /* * ioctl routine */ @@ -1687,619 +1846,599 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data) static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { - unsigned char eedata[256]; struct bttv *btv=(struct bttv *)dev; int i; - - 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 = tvcards[btv->type].video_inputs; - b.audios = tvcards[btv->type].audio_inputs; - b.maxwidth = tvnorms[btv->win.norm].swidth; - b.maxheight = tvnorms[btv->win.norm].sheight; - 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; - v.norm = btv->win.norm; - if (v.channel>=tvcards[btv->type].video_inputs) - return -EINVAL; - if(v.channel==tvcards[btv->type].tuner) - { - strcpy(v.name,"Television"); - v.flags|=VIDEO_VC_TUNER; - v.type=VIDEO_TYPE_TV; - v.tuners=1; - } - else if(v.channel==tvcards[btv->type].svhs) - strcpy(v.name,"S-Video"); - else - sprintf(v.name,"Composite%d",v.channel); - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - /* - * Each channel has 1 tuner - */ - case VIDIOCSCHAN: + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name,btv->video_dev.name); + b.type = VID_TYPE_CAPTURE| + ((tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | + VID_TYPE_OVERLAY| + VID_TYPE_CLIPPING| + VID_TYPE_FRAMERAM| + VID_TYPE_SCALES; + b.channels = tvcards[btv->type].video_inputs; + b.audios = tvcards[btv->type].audio_inputs; + b.maxwidth = tvnorms[btv->win.norm].swidth; + b.maxheight = tvnorms[btv->win.norm].sheight; + 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; + v.norm = btv->win.norm; + if (v.channel>=tvcards[btv->type].video_inputs) + return -EINVAL; + if(v.channel==tvcards[btv->type].tuner) { - struct video_channel v; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - - if (v.channel>tvcards[btv->type].video_inputs) - return -EINVAL; - if(v.norm!=VIDEO_MODE_PAL&&v.norm!=VIDEO_MODE_NTSC - &&v.norm!=VIDEO_MODE_SECAM) - return -EOPNOTSUPP; - down(&btv->lock); - bt848_muxsel(btv, v.channel); + strcpy(v.name,"Television"); + v.flags|=VIDEO_VC_TUNER; + v.type=VIDEO_TYPE_TV; + v.tuners=1; + } + else if(v.channel==tvcards[btv->type].svhs) + strcpy(v.name,"S-Video"); + else + sprintf(v.name,"Composite%d",v.channel); + + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* + * Each channel has 1 tuner + */ + case VIDIOCSCHAN: + { + struct video_channel v; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + + if (v.channel>tvcards[btv->type].video_inputs) + return -EINVAL; + if (v.norm > (sizeof(tvnorms)/sizeof(*tvnorms))) + return -EOPNOTSUPP; + + call_i2c_clients(btv,cmd,&v); + down(&btv->lock); + bt848_muxsel(btv, v.channel); + btv->channel=v.channel; + if (btv->win.norm != v.norm) { btv->win.norm = v.norm; - make_vbitab(btv); + make_vbitab(btv); bt848_set_winsize(btv); - btv->channel=v.channel; - up(&btv->lock); - return 0; } - case VIDIOCGTUNER: - { - struct video_tuner v; - if(copy_from_user(&v,arg,sizeof(v))!=0) - return -EFAULT; - if(v.tuner||btv->channel) /* Only tuner 0 */ - return -EINVAL; - strcpy(v.name, "Television"); - v.rangelow=0; - v.rangehigh=0xFFFFFFFF; - v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; - if (btv->audio_chip == TDA9840) { - v.flags |= VIDEO_AUDIO_VOLUME; - v.mode = VIDEO_SOUND_MONO|VIDEO_SOUND_STEREO; - v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; - } - if (btv->audio_chip == TDA9850) { - unsigned char ALR1; - ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1); - if (ALR1 & 32) - v.flags |= VIDEO_TUNER_STEREO_ON; - } - v.mode = btv->win.norm; - v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } - /* We have but one tuner */ - case VIDIOCSTUNER: - { - struct video_tuner v; - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - /* Only one channel has a tuner */ - if(v.tuner!=tvcards[btv->type].tuner) - return -EINVAL; + up(&btv->lock); + return 0; + } + case VIDIOCGTUNER: + { + struct video_tuner v; + if(copy_from_user(&v,arg,sizeof(v))!=0) + return -EFAULT; + if(v.tuner||btv->channel) /* Only tuner 0 */ + return -EINVAL; + strcpy(v.name, "Television"); + v.rangelow=0; + v.rangehigh=0xFFFFFFFF; + v.flags=VIDEO_TUNER_PAL|VIDEO_TUNER_NTSC|VIDEO_TUNER_SECAM; + v.mode = btv->win.norm; + v.signal = (btread(BT848_DSTATUS)&BT848_DSTATUS_HLOC) ? 0xFFFF : 0; + call_i2c_clients(btv,cmd,&v); + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + /* We have but one tuner */ + case VIDIOCSTUNER: + { + struct video_tuner v; + if(copy_from_user(&v, arg, sizeof(v))) + return -EFAULT; + /* Only one channel has a tuner */ + if(v.tuner!=tvcards[btv->type].tuner) + return -EINVAL; - if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC - &&v.mode!=VIDEO_MODE_SECAM) - return -EOPNOTSUPP; - btv->win.norm = v.mode; - down(&btv->lock); - bt848_set_winsize(btv); - up(&btv->lock); - return 0; + if(v.mode!=VIDEO_MODE_PAL&&v.mode!=VIDEO_MODE_NTSC + &&v.mode!=VIDEO_MODE_SECAM) + return -EOPNOTSUPP; + call_i2c_clients(btv,cmd,&v); + if (btv->win.norm != v.mode) { + btv->win.norm = v.mode; + down(&btv->lock); + make_vbitab(btv); + bt848_set_winsize(btv); + up(&btv->lock); } - case VIDIOCGPICT: - { - struct video_picture p=btv->picture; - if(btv->win.depth==8) - p.palette=VIDEO_PALETTE_HI240; - if(btv->win.depth==15) - p.palette=VIDEO_PALETTE_RGB555; - if(btv->win.depth==16) - p.palette=VIDEO_PALETTE_RGB565; - if(btv->win.depth==24) - p.palette=VIDEO_PALETTE_RGB24; - if(btv->win.depth==32) - p.palette=VIDEO_PALETTE_RGB32; + return 0; + } + case VIDIOCGPICT: + { + struct video_picture p=btv->picture; + if(btv->win.depth==8) + p.palette=VIDEO_PALETTE_HI240; + if(btv->win.depth==15) + p.palette=VIDEO_PALETTE_RGB555; + if(btv->win.depth==16) + p.palette=VIDEO_PALETTE_RGB565; + if(btv->win.depth==24) + p.palette=VIDEO_PALETTE_RGB24; + if(btv->win.depth==32) + p.palette=VIDEO_PALETTE_RGB32; - if(copy_to_user(arg, &p, sizeof(p))) - return -EFAULT; - return 0; - } - case VIDIOCSPICT: + 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; + down(&btv->lock); + /* 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; + up(&btv->lock); + return 0; + } + case VIDIOCSWIN: + { + struct video_window vw; + struct video_clip *vcp = NULL; + int on; + + if(copy_from_user(&vw,arg,sizeof(vw))) + return -EFAULT; + + if(vw.flags || vw.width < 16 || vw.height < 16) { - struct video_picture p; - int format; - if(copy_from_user(&p, arg,sizeof(p))) - return -EFAULT; - down(&btv->lock); - /* 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; - - /* set palette if bpp matches */ - if (p.palette < sizeof(palette2fmt)/sizeof(int)) { - format = palette2fmt[p.palette]; - if (fmtbppx2[format&0x0f]/2 == btv->win.bpp) - btv->win.color_fmt = format; - } + down(&btv->lock); + bt848_cap(btv,0); up(&btv->lock); - return 0; + return -EINVAL; + } + if (btv->win.bpp < 4) + { /* adjust and align writes */ + vw.x = (vw.x + 3) & ~3; + vw.width &= ~3; } - case VIDIOCSWIN: - { - struct video_window vw; - struct video_clip *vcp = NULL; - int on; + down(&btv->lock); + btv->win.use_yuv=0; + btv->win.x=vw.x; + btv->win.y=vw.y; + btv->win.width=vw.width; + btv->win.height=vw.height; + + on=(btv->cap&3); - if(copy_from_user(&vw,arg,sizeof(vw))) + bt848_cap(btv,0); + bt848_set_winsize(btv); + up(&btv->lock); + + /* + * Do any clips. + */ + if(vw.clipcount<0) { + if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) + return -ENOMEM; + if(copy_from_user(vcp, vw.clips, + VIDEO_CLIPMAP_SIZE)) { + vfree(vcp); return -EFAULT; - - if(vw.flags || vw.width < 16 || vw.height < 16) - { - down(&btv->lock); - bt848_cap(btv,0); - up(&btv->lock); - return -EINVAL; - } - if (btv->win.bpp < 4) - { /* 32-bit align start and adjust width */ - int i = vw.x; - vw.x = (vw.x + 3) & ~3; - i = vw.x - i; - vw.width -= i; } - - down(&btv->lock); - 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); - - bt848_cap(btv,0); - bt848_set_winsize(btv); - - up(&btv->lock); - - /* - * Do any clips. - */ - if(vw.clipcount<0) { - if((vcp=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) - return -ENOMEM; - if(copy_from_user(vcp, vw.clips, - VIDEO_CLIPMAP_SIZE)) { - vfree(vcp); - return -EFAULT; - } - } else if (vw.clipcount) { - if((vcp=vmalloc(sizeof(struct video_clip)* + } else if (vw.clipcount) { + if((vcp=vmalloc(sizeof(struct video_clip)* (vw.clipcount))) == NULL) - return -ENOMEM; - if(copy_from_user(vcp,vw.clips, - sizeof(struct video_clip)* - vw.clipcount)) { - vfree(vcp); - return -EFAULT; - } - } - down(&btv->lock); - make_clip_tab(btv, vcp, vw.clipcount); - if (vw.clipcount != 0) + return -ENOMEM; + if(copy_from_user(vcp,vw.clips, + sizeof(struct video_clip)* + vw.clipcount)) { vfree(vcp); - if(on && btv->win.vidadr!=0) - bt848_cap(btv,1); - up(&btv->lock); - 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(v!=0 && (btv->win.vidadr==0 || btv->win.width==0 - || btv->win.height==0)) - return -EINVAL; - - down(&btv->lock); - if(v==0) - bt848_cap(btv,0); - else - bt848_cap(btv,1); - up(&btv->lock); + down(&btv->lock); + make_clip_tab(btv, vcp, vw.clipcount); + if (vw.clipcount != 0) + vfree(vcp); + if(on && btv->win.vidadr!=0) + bt848_cap(btv,1); + up(&btv->lock); + return 0; + } + case VIDIOCSWIN2: + { + /* experimental -- right now it handles unclipped yuv data only */ + struct video_window2 vo; + __u32 fbsize; + int on; + + if(copy_from_user(&vo,arg,sizeof(vo))) + return -EFAULT; - 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.depth; - v.bytesperline=btv->win.bpl; - if(copy_to_user(arg, &v,sizeof(v))) - return -EFAULT; - return 0; + fbsize = btv->win.sheight * btv->win.bpl; + if (vo.start + vo.pitch*vo.height > fbsize) + return -EINVAL; + if (vo.palette != VIDEO_PALETTE_YUV422) + return -EINVAL; + + down(&btv->lock); + btv->win.use_yuv=1; + memcpy(&btv->win.win2,&vo,sizeof(vo)); + btv->win.width=vo.width; + btv->win.height=vo.height; + + on=(btv->cap&3); + bt848_cap(btv,0); + bt848_set_winsize(btv); + make_clip_tab(btv, NULL, 0); + if(on && btv->win.vidadr!=0) + bt848_cap(btv,1); + up(&btv->lock); + 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) + return -EINVAL; + if (0 == btv->win.use_yuv && (btv->win.width==0 || btv->win.height==0)) + return -EINVAL; + down(&btv->lock); + if(v==0) + bt848_cap(btv,0); + else + bt848_cap(btv,1); + up(&btv->lock); + 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.depth; + v.bytesperline=btv->win.bpl; + if(copy_to_user(arg, &v,sizeof(v))) + return -EFAULT; + return 0; - } - case VIDIOCSFBUF: - { - struct video_buffer v; -#if LINUX_VERSION_CODE >= 0x020100 - if(!capable(CAP_SYS_ADMIN) - && !capable(CAP_SYS_RAWIO)) -#else - if(!suser()) -#endif - return -EPERM; - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - if(v.depth!=8 && v.depth!=15 && v.depth!=16 && - v.depth!=24 && v.depth!=32 && v.width > 16 && - v.height > 16 && v.bytesperline > 16) - return -EINVAL; - down(&btv->lock); - if (v.base) - btv->win.vidadr=(unsigned long)v.base; - btv->win.sheight=v.height; - btv->win.swidth=v.width; - btv->win.bpp=((v.depth+7)&0x38)/8; - btv->win.depth=v.depth; - btv->win.bpl=v.bytesperline; + } + case VIDIOCSFBUF: + { + struct video_buffer v; + if(!capable(CAP_SYS_ADMIN) && + !capable(CAP_SYS_RAWIO)) + return -EPERM; + if(copy_from_user(&v, arg,sizeof(v))) + return -EFAULT; + if(v.depth!=8 && v.depth!=15 && v.depth!=16 && + v.depth!=24 && v.depth!=32 && v.width > 16 && + v.height > 16 && v.bytesperline > 16) + return -EINVAL; + down(&btv->lock); + if (v.base) + btv->win.vidadr=(unsigned long)v.base; + btv->win.sheight=v.height; + btv->win.swidth=v.width; + btv->win.bpp=((v.depth+7)&0x38)/8; + btv->win.depth=v.depth; + 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_winsize(btv); - up(&btv->lock); - 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; - } + 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_winsize(btv); + up(&btv->lock); + 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; + call_i2c_clients(btv,cmd,&v); + return 0; + } - case VIDIOCGAUDIO: - { - struct video_audio v; - v=btv->audio_dev; - v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); - v.flags|=VIDEO_AUDIO_MUTABLE; - strcpy(v.name,"TV"); - if (btv->audio_chip == TDA9850) { - unsigned char ALR1; - ALR1 = I2CRead(&(btv->i2c), I2C_TDA9850|1); - v.mode = VIDEO_SOUND_MONO; - v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0; - v.mode |= (ALR1 & 64) ? VIDEO_SOUND_LANG1:0; - } - if (btv->have_msp3400) - { - v.flags|=VIDEO_AUDIO_VOLUME | - VIDEO_AUDIO_BASS | - VIDEO_AUDIO_TREBLE; - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_GET_VOLUME,&(v.volume)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_GET_BASS,&(v.bass)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_GET_TREBLE,&(v.treble)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_GET_STEREO,&(v.mode)); - } - else v.mode = VIDEO_SOUND_MONO; - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; + case VIDIOCGAUDIO: + { + struct video_audio v; + + v=btv->audio_dev; + v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE); + v.flags|=VIDEO_AUDIO_MUTABLE; + strcpy(v.name,"TV"); + + v.mode = VIDEO_SOUND_MONO; + call_i2c_clients(btv,cmd,&v); + + if (btv->type == BTTV_TERRATV) { + v.mode = VIDEO_SOUND_MONO; + v.mode |= VIDEO_SOUND_STEREO; + v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; + + } else if (btv->audio_chip == TDA9840) { + /* begin of Horrible Hack <grin@tolna.net> */ + v.flags|=VIDEO_AUDIO_VOLUME; + v.mode = VIDEO_SOUND_MONO; + v.mode |= VIDEO_SOUND_STEREO; + v.mode |= VIDEO_SOUND_LANG1|VIDEO_SOUND_LANG2; + v.volume = 32768; /* fixme */ + v.step = 4096; } - case VIDIOCSAUDIO: - { - struct video_audio v; - if(copy_from_user(&v,arg, sizeof(v))) - return -EFAULT; - down(&btv->lock); - if(v.flags&VIDEO_AUDIO_MUTE) - audio(btv, AUDIO_MUTE); - /* One audio source per tuner */ - /* if(v.audio!=0) */ - /* ADSTech TV card has more than one */ - if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) - { - up(&btv->lock); - return -EINVAL; - } - bt848_muxsel(btv,v.audio); - if(!(v.flags&VIDEO_AUDIO_MUTE)) - audio(btv, AUDIO_UNMUTE); - if (btv->audio_chip == TDA9850) { - unsigned char con3 = 0; - if (v.mode & VIDEO_SOUND_LANG1) - con3 = 0x80; /* sap */ - if (v.mode & VIDEO_SOUND_STEREO) - con3 = 0x40; /* stereo */ - I2CWrite(&(btv->i2c), I2C_TDA9850, - TDA9850_CON3, con3, 1); - } - - /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ - if (btv->type == BTTV_WINVIEW_601) { - int bits_out, loops, vol, data; - - /* 32 levels logarithmic */ - vol = 32 - ((v.volume>>11)); - /* units */ - bits_out = (PT2254_DBS_IN_2>>(vol%5)); - /* tens */ - bits_out |= (PT2254_DBS_IN_10>>(vol/5)); - bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; - data = btread(BT848_GPIO_DATA); - data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| - WINVIEW_PT2254_STROBE); - for (loops = 17; loops >= 0 ; loops--) { - if (bits_out & (1<<loops)) - data |= WINVIEW_PT2254_DATA; - else - data &= ~WINVIEW_PT2254_DATA; - btwrite(data, BT848_GPIO_DATA); - udelay(5); - data |= WINVIEW_PT2254_CLK; - btwrite(data, BT848_GPIO_DATA); - udelay(5); - data &= ~WINVIEW_PT2254_CLK; - btwrite(data, BT848_GPIO_DATA); - } - data |= WINVIEW_PT2254_STROBE; - data &= ~WINVIEW_PT2254_DATA; - btwrite(data, BT848_GPIO_DATA); - udelay(10); - data &= ~WINVIEW_PT2254_STROBE; - btwrite(data, BT848_GPIO_DATA); - } - /* TEA 6320 Audio Support by Michael Wrighton - mgw1@cec.wustl.edu */ - if (btv->audio_chip == TEA6320) - { - int vol; - vol = v.volume >> 11; - if (!(v.flags&VIDEO_AUDIO_MUTE)) - I2CWrite(&(btv->i2c), I2C_TEA6320, - TEA6320_S, TEA6320_S_SB,1); /* at least Raffles card uses input B */ - else - I2CWrite(&(btv->i2c), I2C_TEA6320, - TEA6320_S, TEA6320_S_GMU,1); - I2CWrite(&(btv->i2c), I2C_TEA6320, - TEA6320_V, vol, 1); - } - if (btv->have_msp3400) - { - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_SET_VOLUME,&(v.volume)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_SET_BASS,&(v.bass)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_SET_TREBLE,&(v.treble)); - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_MSP3400, - MSP_SET_STEREO,&(v.mode)); - } - btv->audio_dev=v; + +#if 0 +#warning this should be handled by tda9855.c + else if (btv->audio_chip == TDA9850) { + unsigned char ALR1; + v.flags|=VIDEO_AUDIO_VOLUME; + ALR1 = I2CRead(btv, I2C_TDA9850|1); + v.mode = VIDEO_SOUND_MONO; + v.mode |= (ALR1 & 32) ? VIDEO_SOUND_STEREO:0; + v.mode |= (ALR1 & 32) ? VIDEO_SOUND_LANG1:0; + v.volume = 32768; /* fixme */ + v.step = 4096; + } +#endif + if(copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + return 0; + } + case VIDIOCSAUDIO: + { + struct video_audio v; + + if(copy_from_user(&v,arg, sizeof(v))) + return -EFAULT; + down(&btv->lock); + if(v.flags&VIDEO_AUDIO_MUTE) + audio(btv, AUDIO_MUTE, 1); + /* One audio source per tuner -- huh? <GA> */ + if(v.audio<0 || v.audio >= tvcards[btv->type].audio_inputs) { up(&btv->lock); - return 0; + return -EINVAL; } + /* bt848_muxsel(btv,v.audio); */ + if(!(v.flags&VIDEO_AUDIO_MUTE)) + audio(btv, AUDIO_UNMUTE, 1); - case VIDIOCSYNC: - if(copy_from_user((void *)&i,arg,sizeof(int))) - return -EFAULT; -/* if(i>1 || i<0) - return -EINVAL; -*/ - switch (btv->frame_stat[i]) { - case GBUFFER_UNUSED: - return -EINVAL; - case GBUFFER_GRABBING: - while(btv->frame_stat[i]==GBUFFER_GRABBING) { - interruptible_sleep_on(&btv->capq); - if(signal_pending(current)) - return -EINTR; - } - /* fall */ - case GBUFFER_DONE: - btv->frame_stat[i] = GBUFFER_UNUSED; - break; - } - return 0; + up(&btv->lock); + call_i2c_clients(btv,cmd,&v); + down(&btv->lock); + + if (btv->type == BTTV_TERRATV) { + unsigned int con = 0; + btor(0x180000, BT848_GPIO_OUT_EN); + if (v.mode & VIDEO_SOUND_LANG2) + con = 0x080000; + if (v.mode & VIDEO_SOUND_STEREO) + con = 0x180000; + btaor(con, ~0x180000, BT848_GPIO_DATA); + + } else if (btv->type == BTTV_WINVIEW_601) { + /* PT2254A programming Jon Tombs, jon@gte.esi.us.es */ + int bits_out, loops, vol, data; + + /* 32 levels logarithmic */ + vol = 32 - ((v.volume>>11)); + /* units */ + bits_out = (PT2254_DBS_IN_2>>(vol%5)); + /* tens */ + bits_out |= (PT2254_DBS_IN_10>>(vol/5)); + bits_out |= PT2254_L_CHANEL | PT2254_R_CHANEL; + data = btread(BT848_GPIO_DATA); + data &= ~(WINVIEW_PT2254_CLK| WINVIEW_PT2254_DATA| + WINVIEW_PT2254_STROBE); + for (loops = 17; loops >= 0 ; loops--) { + if (bits_out & (1<<loops)) + data |= WINVIEW_PT2254_DATA; + else + data &= ~WINVIEW_PT2254_DATA; + btwrite(data, BT848_GPIO_DATA); + udelay(5); + data |= WINVIEW_PT2254_CLK; + btwrite(data, BT848_GPIO_DATA); + udelay(5); + data &= ~WINVIEW_PT2254_CLK; + btwrite(data, BT848_GPIO_DATA); + } + data |= WINVIEW_PT2254_STROBE; + data &= ~WINVIEW_PT2254_DATA; + btwrite(data, BT848_GPIO_DATA); + udelay(10); + data &= ~WINVIEW_PT2254_STROBE; + btwrite(data, BT848_GPIO_DATA); - case BTTV_WRITEE: - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - if(copy_from_user((void *) eedata, (void *) arg, 256)) - return -EFAULT; - down(&btv->lock); - writeee(&(btv->i2c), eedata); - up(&btv->lock); - return 0; +#if 0 +#warning this should be handled by tda9855.c + } else if (btv->audio_chip == TDA9850) { + unsigned char con3 = 0; + if (v.mode & VIDEO_SOUND_LANG1) + con3 = 0x80; /* sap */ + if (v.mode & VIDEO_SOUND_STEREO) + con3 = 0x40; /* stereo */ + I2CWrite(btv, I2C_TDA9850, + TDA9850_CON3, con3, 1); + if (v.flags & VIDEO_AUDIO_VOLUME) + I2CWrite(btv, I2C_TDA9850, + TDA9850_CON4, + (v.volume>>12) & 15, 1); +#endif + } + btv->audio_dev=v; + up(&btv->lock); + return 0; + } - case BTTV_READEE: - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - down(&btv->lock); - readee(&(btv->i2c), eedata); - up(&btv->lock); - if(copy_to_user((void *) arg, (void *) eedata, 256)) - return -EFAULT; + case VIDIOCSYNC: + if(copy_from_user((void *)&i,arg,sizeof(int))) + return -EFAULT; + switch (btv->frame_stat[i]) { + case GBUFFER_UNUSED: + return -EINVAL; + case GBUFFER_GRABBING: + while(btv->frame_stat[i]==GBUFFER_GRABBING) { + interruptible_sleep_on(&btv->capq); + if(signal_pending(current)) + return -EINTR; + } + /* fall */ + case GBUFFER_DONE: + btv->frame_stat[i] = GBUFFER_UNUSED; break; + } + return 0; - case BTTV_FIELDNR: - if(copy_to_user((void *) arg, (void *) &btv->last_field, - sizeof(btv->last_field))) - return -EFAULT; - break; + case BTTV_FIELDNR: + if(copy_to_user((void *) arg, (void *) &btv->last_field, + sizeof(btv->last_field))) + return -EFAULT; + break; - case BTTV_PLLSET: { - struct bttv_pll_info p; - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) - return -EFAULT; - down(&btv->lock); - btv->pll.pll_ifreq = p.pll_ifreq; - btv->pll.pll_ofreq = p.pll_ofreq; - btv->pll.pll_crystal = p.pll_crystal; - up(&btv->lock); - break; - } - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - int v; - if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) - return -EFAULT; - if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING) - return -EBUSY; - down(&btv->lock); - v=vgrab(btv, &vm); - up(&btv->lock); - return v; - } + case BTTV_PLLSET: { + struct bttv_pll_info p; + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + if(copy_from_user(&p , (void *) arg, sizeof(btv->pll))) + return -EFAULT; + down(&btv->lock); + btv->pll.pll_ifreq = p.pll_ifreq; + btv->pll.pll_ofreq = p.pll_ofreq; + btv->pll.pll_crystal = p.pll_crystal; + up(&btv->lock); + + break; + } + + case VIDIOCMCAPTURE: + { + struct video_mmap vm; + int ret; + if(copy_from_user((void *) &vm, (void *) arg, sizeof(vm))) + return -EFAULT; + if (btv->frame_stat[vm.frame] == GBUFFER_GRABBING) + return -EBUSY; + down(&btv->lock); + ret = vgrab(btv, &vm); + up(&btv->lock); + return ret; + } - case VIDIOCGMBUF: - { - struct video_mbuf vm; - memset(&vm, 0 , sizeof(vm)); - vm.size=BTTV_MAX_FBUF*2; - vm.frames=2; - vm.offsets[0]=0; - vm.offsets[1]=BTTV_MAX_FBUF; - if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) - return -EFAULT; - return 0; - } + case VIDIOCGMBUF: + { + struct video_mbuf vm; + memset(&vm, 0 , sizeof(vm)); + vm.size=BTTV_MAX_FBUF*MAX_GBUFFERS; + vm.frames=MAX_GBUFFERS; + vm.offsets[0]=0; + vm.offsets[1]=BTTV_MAX_FBUF; + if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) + return -EFAULT; + return 0; + } - case VIDIOCGUNIT: - { - struct video_unit vu; - vu.video=btv->video_dev.minor; - vu.vbi=btv->vbi_dev.minor; - if(btv->radio_dev.minor!=-1) - vu.radio=btv->radio_dev.minor; - else - vu.radio=VIDEO_NO_UNIT; - vu.audio=VIDEO_NO_UNIT; - if(btv->have_msp3400) - { - i2c_control_device(&(btv->i2c), I2C_DRIVERID_MSP3400, - MSP_GET_UNIT, &vu.audio); - } - vu.teletext=VIDEO_NO_UNIT; - if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) - return -EFAULT; - return 0; - } + case VIDIOCGUNIT: + { + struct video_unit vu; + vu.video=btv->video_dev.minor; + vu.vbi=btv->vbi_dev.minor; + if(btv->radio_dev.minor!=-1) + vu.radio=btv->radio_dev.minor; + else + vu.radio=VIDEO_NO_UNIT; + vu.audio=VIDEO_NO_UNIT; +#if 0 + AUDIO(AUDC_GET_UNIT, &vu.audio); +#endif + vu.teletext=VIDEO_NO_UNIT; + if(copy_to_user((void *)arg, (void *)&vu, sizeof(vu))) + return -EFAULT; + return 0; + } - case BTTV_BURST_ON: - { - tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2; - tvnorms[0].hdelayx1=186-BURSTOFFSET; - return 0; - } + case BTTV_BURST_ON: + { + tvnorms[0].scaledtwidth=1135-BURSTOFFSET-2; + tvnorms[0].hdelayx1=186-BURSTOFFSET; + tvnorms[2].scaledtwidth=1135-BURSTOFFSET-2; + tvnorms[2].hdelayx1=186-BURSTOFFSET; + return 0; + } - case BTTV_BURST_OFF: - { - tvnorms[0].scaledtwidth=1135; - tvnorms[0].hdelayx1=186; - return 0; - } + case BTTV_BURST_OFF: + { + tvnorms[0].scaledtwidth=1135; + tvnorms[0].hdelayx1=186; + tvnorms[2].scaledtwidth=1135; + tvnorms[2].hdelayx1=186; + return 0; + } - case BTTV_VERSION: - { - return BTTV_VERSION_CODE; - } + case BTTV_VERSION: + { + return BTTV_VERSION_CODE; + } - case BTTV_PICNR: - { - /* return picture;*/ - return 0; - } + case BTTV_PICNR: + { + /* return picture;*/ + return 0; + } - default: - return -ENOIOCTLCMD; + default: + return -ENOIOCTLCMD; } return 0; } @@ -2317,43 +2456,42 @@ static int bttv_init_done(struct video_device *dev) * - remap_page_range is kind of inefficient for page by page remapping. * But e.g. pte_alloc() does not work in modules ... :-( */ - + static int do_bttv_mmap(struct bttv *btv, const char *adr, unsigned long size) { unsigned long start=(unsigned long) adr; - unsigned long page,pos; + unsigned long page,pos; - if (size>2*BTTV_MAX_FBUF) - return -EINVAL; - if (!btv->fbuffer) - { - if(fbuffer_alloc(btv)) - return -EINVAL; - } - pos=(unsigned long) btv->fbuffer; - while (size > 0) - { - page = kvirt_to_pa(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start+=PAGE_SIZE; - pos+=PAGE_SIZE; - size-=PAGE_SIZE; - } - return 0; + if (size>2*BTTV_MAX_FBUF) + return -EINVAL; + if (!btv->fbuffer) { + if(fbuffer_alloc(btv)) + return -EINVAL; + } + pos=(unsigned long) btv->fbuffer; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start+=PAGE_SIZE; + pos+=PAGE_SIZE; + size-=PAGE_SIZE; + } + return 0; } static int bttv_mmap(struct video_device *dev, const char *adr, unsigned long size) { - struct bttv *btv=(struct bttv *)dev; - int r; - - down(&btv->lock); - r=do_bttv_mmap(btv, adr, size); - up(&btv->lock); - return r; + struct bttv *btv=(struct bttv *)dev; + int r; + + down(&btv->lock); + r=do_bttv_mmap(btv, adr, size); + up(&btv->lock); + return r; } + static struct video_device bttv_template= { "UNSET", @@ -2363,9 +2501,7 @@ static struct video_device bttv_template= bttv_close, bttv_read, bttv_write, -#if LINUX_VERSION_CODE >= 0x020100 - NULL, /* poll */ -#endif + NULL, bttv_ioctl, bttv_mmap, bttv_init_done, @@ -2437,7 +2573,7 @@ static int vbi_open(struct video_device *dev, int flags) { struct bttv *btv=(struct bttv *)(dev-2); - down(&btv->lock); + down(&btv->lock); btv->vbip=VBIBUF_SIZE; btv->cap|=0x0c; bt848_set_risc_jmps(btv); @@ -2451,7 +2587,7 @@ static void vbi_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)(dev-2); - down(&btv->lock); + down(&btv->lock); btv->cap&=~0x0c; bt848_set_risc_jmps(btv); up(&btv->lock); @@ -2459,10 +2595,36 @@ static void vbi_close(struct video_device *dev) MOD_DEC_USE_COUNT; } - static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) { - return -EINVAL; + struct bttv *btv=(struct bttv *)dev; + + switch (cmd) { + case VIDIOCGCAP: + { + struct video_capability b; + strcpy(b.name,btv->vbi_dev.name); + b.type = ((tvcards[btv->type].tuner != -1) ? VID_TYPE_TUNER : 0) | + VID_TYPE_TELETEXT; + b.channels = 0; + b.audios = 0; + b.maxwidth = 0; + b.maxheight = 0; + b.minwidth = 0; + b.minheight = 0; + if(copy_to_user(arg,&b,sizeof(b))) + return -EFAULT; + return 0; + } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + return bttv_ioctl((struct video_device *)btv,cmd,arg); + case BTTV_VBISIZE: + /* make alevt happy :-) */ + return VBIBUF_SIZE; + default: + return -EINVAL; + } } static struct video_device vbi_template= @@ -2474,9 +2636,7 @@ static struct video_device vbi_template= vbi_close, vbi_read, bttv_write, -#if LINUX_VERSION_CODE >= 0x020100 vbi_poll, -#endif vbi_ioctl, NULL, /* no mmap yet */ bttv_init_done, @@ -2490,17 +2650,16 @@ static int radio_open(struct video_device *dev, int flags) { struct bttv *btv = (struct bttv *)(dev-1); - down(&btv->lock); + down(&btv->lock); if (btv->user) goto busy_unlock; btv->user++; - - set_freq(btv,400*16); + btv->radio = 1; + call_i2c_clients(btv,AUDC_SET_RADIO,&btv->tuner_type); bt848_muxsel(btv,0); - audio(btv, AUDIO_UNMUTE); up(&btv->lock); - + MOD_INC_USE_COUNT; return 0; @@ -2512,11 +2671,10 @@ static int radio_open(struct video_device *dev, int flags) static void radio_close(struct video_device *dev) { struct bttv *btv=(struct bttv *)(dev-1); - + down(&btv->lock); btv->user--; btv->radio = 0; - /*audio(btv, AUDIO_MUTE);*/ up(&btv->lock); MOD_DEC_USE_COUNT; } @@ -2595,9 +2753,7 @@ static struct video_device radio_template= radio_close, radio_read, /* just returns -EINVAL */ bttv_write, /* just returns -EINVAL */ -#if LINUX_VERSION_CODE >= 0x020100 NULL, /* no poll */ -#endif radio_ioctl, NULL, /* no mmap */ bttv_init_done, /* just returns 0 */ @@ -2607,7 +2763,6 @@ static struct video_device radio_template= }; - #define TRITON_PCON 0x50 #define TRITON_BUS_CONCURRENCY (1<<0) #define TRITON_STREAMING (1<<1) @@ -2623,79 +2778,69 @@ static void handle_chipset(void) if (triton1) triton1=BT848_INT_ETBF; - - if(pci_pci_problems&PCIPCI_FAIL) - { - printk(KERN_WARNING "bttv: This configuration is known to have PCI to PCI DMA problems\n"); - printk(KERN_WARNING "bttv: You may not be able to use overlay mode.\n"); - } - - while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, dev))) + while ((dev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, dev))) { - unsigned char b; - pci_read_config_byte(dev, 0x53, &b); - DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); - DEBUG(printk("bufcon=0x%02x\n",b)); - } + /* Beware the SiS 85C496 my friend - rev 49 don't work with a bttv */ + printk(KERN_WARNING "BT848 and SIS 85C496 chipset don't always work together.\n"); + } + + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82441, dev))) + { + unsigned char b; + pci_read_config_byte(dev, 0x53, &b); + DEBUG(printk(KERN_INFO "bttv: Host bridge: 82441FX Natoma, ")); + DEBUG(printk("bufcon=0x%02x\n",b)); + } while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) { -/* unsigned char b; - unsigned char bo;*/ - printk(KERN_INFO "bttv: Host bridge 82437FX Triton PIIX\n"); triton1=BT848_INT_ETBF; } } -static void init_tea6300(struct i2c_bus *bus) -{ - I2CWrite(bus, I2C_TEA6300, TEA6300_VL, 0x35, 1); /* volume left 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6300_VR, 0x35, 1); /* volume right 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6300_BA, 0x07, 1); /* bass 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6300_TR, 0x07, 1); /* treble 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6300_FA, 0x0f, 1); /* fader off */ - I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */ -} - -static void init_tea6320(struct i2c_bus *bus) +#if 0 +#warning please use tda8425.c instead +static void init_tda8425(struct bttv *btv) { - I2CWrite(bus, I2C_TEA6300, TEA6320_V, 0x28, 1); /* master volume */ - I2CWrite(bus, I2C_TEA6300, TEA6320_FFL, 0x28, 1); /* volume left 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_FFR, 0x28, 1); /* volume right 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_FRL, 0x28, 1); /* volume rear left 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_FRR, 0x28, 1); /* volume rear right 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_BA, 0x11, 1); /* bass 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_TR, 0x11, 1); /* treble 0dB */ - I2CWrite(bus, I2C_TEA6300, TEA6320_S, TEA6320_S_GMU, 1); /* mute off input A */ + I2CWrite(btv, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */ + I2CWrite(btv, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */ + I2CWrite(btv, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB */ + I2CWrite(btv, I2C_TDA8425, TDA8425_TR, 0xF6, 1); /* treble 0dB */ + I2CWrite(btv, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off */ } +#endif -static void init_tda8425(struct i2c_bus *bus) +/* can tda9855.c handle this too maybe? */ +static void init_tda9840(struct bttv *btv) { - I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */ - I2CWrite(bus, I2C_TDA8425, TDA8425_VR, 0xFC, 1); /* volume right 0dB */ - I2CWrite(bus, I2C_TDA8425, TDA8425_BA, 0xF6, 1); /* bass 0dB */ - I2CWrite(bus, I2C_TDA8425, TDA8425_TR, 0xF6, 1); /* treble 0dB */ - I2CWrite(bus, I2C_TDA8425, TDA8425_S1, 0xCE, 1); /* mute off */ + /* Horrible Hack */ + I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1); /* sound mode switching */ + /* 00 - mute + 10 - mono / averaged stereo + 2a - stereo + 12 - dual A + 1a - dual AB + 16 - dual BA + 1e - dual B + 7a - external */ } -static void init_tda9840(struct i2c_bus *bus) -{ - I2CWrite(bus, I2C_TDA9840, TDA9840_SW, 0x2A, 1); /* Sound mode switching */ -} -static void init_tda9850(struct i2c_bus *bus) +#if 0 +#warning this should be handled by tda9855.c +static void init_tda9850(struct bttv *btv) { - I2CWrite(bus, I2C_TDA9850, TDA9850_CON1, 0x08, 1); /* noise threshold st */ - I2CWrite(bus, I2C_TDA9850, TDA9850_CON2, 0x08, 1); /* noise threshold sap */ - I2CWrite(bus, I2C_TDA9850, TDA9850_CON3, 0x40, 1); /* stereo mode */ - I2CWrite(bus, I2C_TDA9850, TDA9850_CON4, 0x07, 1); /* 0 dB input gain?*/ - I2CWrite(bus, I2C_TDA9850, TDA9850_ALI1, 0x10, 1); /* wideband alignment? */ - I2CWrite(bus, I2C_TDA9850, TDA9850_ALI2, 0x10, 1); /* spectral alignment? */ - I2CWrite(bus, I2C_TDA9850, TDA9850_ALI3, 0x03, 1); + I2CWrite(btv, I2C_TDA9850, TDA9850_CON1, 0x08, 1); /* noise threshold st */ + I2CWrite(btv, I2C_TDA9850, TDA9850_CON2, 0x08, 1); /* noise threshold sap */ + I2CWrite(btv, I2C_TDA9850, TDA9850_CON3, 0x40, 1); /* stereo mode */ + I2CWrite(btv, I2C_TDA9850, TDA9850_CON4, 0x07, 1); /* 0 dB input gain?*/ + I2CWrite(btv, I2C_TDA9850, TDA9850_ALI1, 0x10, 1); /* wideband alignment? */ + I2CWrite(btv, I2C_TDA9850, TDA9850_ALI2, 0x10, 1); /* spectral alignment? */ + I2CWrite(btv, I2C_TDA9850, TDA9850_ALI3, 0x03, 1); } - - +#endif /* Figure out card and tuner type */ @@ -2707,180 +2852,119 @@ static void idcard(int i) DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", i, btread(BT848_GPIO_DATA))); /* Default the card to the user-selected one. */ - btv->type=card[i]; - btv->tuner_type=-1; /* use default tuner type */ + if (card[i] >= 0 && card[i] < TVCARDS) + btv->type=card[i]; /* If we were asked to auto-detect, then do so! Right now this will only recognize Miro, Hauppauge or STB */ if (btv->type == BTTV_UNKNOWN) { - if (I2CRead(&(btv->i2c), I2C_HAUPEE)>=0) + if (I2CRead(btv, I2C_HAUPEE, "eeprom")>=0) { if(btv->id>849) btv->type=BTTV_HAUPPAUGE878; else btv->type=BTTV_HAUPPAUGE; - } else if (I2CRead(&(btv->i2c), I2C_STBEE)>=0) { + } else if (I2CRead(btv, I2C_STBEE, "eeprom")>=0) { btv->type=BTTV_STB; + +#if 0 /* bad idea: 0xc0 is used for the tuner on _many_ boards */ + } else if (I2CRead(btv, I2C_VHX)>=0) { + btv->type=BTTV_VHX; +#endif + } else { - if (I2CRead(&(btv->i2c), 0x80)>=0) /* check for msp34xx */ + if (I2CRead(btv, 0x80, "msp3400")>=0) /* check for msp34xx */ btv->type = BTTV_MIROPRO; else - btv->type=BTTV_MIRO; + btv->type = BTTV_MIRO; } } - /* board specific initialisations */ - - switch(btv->type) - { - case BTTV_MIRO: - case BTTV_MIROPRO: - /* auto detect tuner for MIRO cards */ - btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; - break; - - case BTTV_HAUPPAUGE: - case BTTV_HAUPPAUGE878: - hauppauge_msp_reset(btv); - hauppauge_eeprom(&(btv->i2c)); - if (btv->type == BTTV_HAUPPAUGE878) { - /* all bt878 hauppauge boards use this ... */ - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - } - break; - - case BTTV_CONFERENCETV: - btv->tuner_type = 1; - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - break; - - case BTTV_PIXVIEWPLAYTV: - case BTTV_AVERMEDIA98: - case BTTV_MODTEC_205: - case BTTV_MAGICTVIEW061: - btv->pll.pll_ifreq=28636363; - btv->pll.pll_crystal=BT848_IFORM_XT0; - break; + /* print which board we have found */ + printk(KERN_INFO "bttv%d: model: ",btv->nr); - } - - if (btv->have_tuner && btv->tuner_type != -1) - i2c_control_device(&(btv->i2c), - I2C_DRIVERID_TUNER, - TUNER_SET_TYPE,&btv->tuner_type); + sprintf(btv->video_dev.name,"BT%d",btv->id); + if (btv->id==848 && btv->revision==0x12) + strcat(btv->video_dev.name,"A"); + strcat(btv->video_dev.name,"("); + strcat(btv->video_dev.name, tvcards[btv->type].name); + strcat(btv->video_dev.name,")"); + printk("%s\n",btv->video_dev.name); - - if (I2CRead(&(btv->i2c), I2C_TDA9840) >=0) - { - btv->audio_chip = TDA9840; - printk(KERN_INFO "bttv%d: audio chip: TDA9840\n", btv->nr); + /* board specific initialisations */ + if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) { + /* auto detect tuner for MIRO cards */ + btv->tuner_type=((btread(BT848_GPIO_DATA)>>10)-1)&7; } - - if (I2CRead(&(btv->i2c), I2C_TDA9850) >=0) - { - btv->audio_chip = TDA9850; - printk(KERN_INFO "bttv%d: audio chip: TDA9850\n",btv->nr); + if (btv->type == BTTV_HAUPPAUGE || btv->type == BTTV_HAUPPAUGE878) { + hauppauge_msp_reset(btv); + hauppauge_eeprom(btv); } - - if (I2CRead(&(btv->i2c), I2C_TDA8425) >=0) - { - btv->audio_chip = TDA8425; - printk(KERN_INFO "bttv%d: audio chip: TDA8425\n",btv->nr); + if (btv->type == BTTV_MAXI) { + /* PHILIPS FI1216MK2 tuner (PAL/SECAM) */ + btv->tuner_type=TUNER_PHILIPS_SECAM; + } + + if (btv->type == BTTV_PXC200) + init_PXC200(btv); + + if (btv->type == BTTV_CONFERENCETV) + btv->tuner_type = 1; + + if (btv->type == BTTV_HAUPPAUGE878 || + btv->type == BTTV_CONFERENCETV || + btv->type == BTTV_PIXVIEWPLAYTV || + btv->type == BTTV_AVERMEDIA98) { + btv->pll.pll_ifreq=28636363; + btv->pll.pll_crystal=BT848_IFORM_XT0; } - - switch(btv->audio_chip) - { - case TDA9850: - init_tda9850(&(btv->i2c)); - break; - case TDA9840: - init_tda9840(&(btv->i2c)); - break; - case TDA8425: - init_tda8425(&(btv->i2c)); - break; + + if (btv->tuner_type != -1) + call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); + + /* try to detect audio/fader chips */ + if (tvcards[btv->type].msp34xx && + I2CRead(btv, I2C_MSP3400, "MSP34xx") >=0) { + if (autoload) + request_module("msp3400"); + } + + if (tvcards[btv->type].tda8425 && + I2CRead(btv, I2C_TDA8425, "TDA8425") >=0) { + if (autoload) + request_module("tda8425"); } - - if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0) - { - if(btv->type==BTTV_AVEC_INTERCAP || btv->type==BTTV_CEI_RAFFLES) - { - printk(KERN_INFO "bttv%d: fader chip: TEA6320\n",btv->nr); - btv->audio_chip = TEA6320; - init_tea6320(&(btv->i2c)); - } else { - printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr); - btv->audio_chip = TEA6300; - init_tea6300(&(btv->i2c)); - } - } else - printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr); - printk(KERN_INFO "bttv%d: model: ",btv->nr); + if (tvcards[btv->type].tda9840 && + I2CRead(btv, I2C_TDA9840, "TDA9840") >=0) { + init_tda9840(btv); + btv->audio_chip = TDA9840; + /* move this to a module too? */ + init_tda9840(btv); + } - sprintf(btv->video_dev.name,"BT%d",btv->id); - switch (btv->type) - { - case BTTV_MIRO: - case BTTV_MIROPRO: - strcat(btv->video_dev.name, - (btv->type == BTTV_MIRO) ? "(Miro)" : "(Miro pro)"); - break; - case BTTV_HAUPPAUGE: - strcat(btv->video_dev.name,"(Hauppauge old)"); - break; - case BTTV_HAUPPAUGE878: - strcat(btv->video_dev.name,"(Hauppauge new)"); - break; - case BTTV_STB: - strcat(btv->video_dev.name,"(STB)"); - break; - case BTTV_INTEL: - strcat(btv->video_dev.name,"(Intel)"); - break; - case BTTV_DIAMOND: - strcat(btv->video_dev.name,"(Diamond)"); - break; - case BTTV_AVERMEDIA: - strcat(btv->video_dev.name,"(AVerMedia)"); - break; - case BTTV_MATRIX_VISION: - strcat(btv->video_dev.name,"(MATRIX-Vision)"); - break; - case BTTV_AVERMEDIA98: - strcat(btv->video_dev.name,"(AVerMedia TVCapture 98)"); - break; - case BTTV_VHX: - strcpy(btv->video_dev.name,"(Aimslab-VHX)"); - break; - case BTTV_WINVIEW_601: - strcpy(btv->video_dev.name,"(Leadtek WinView 601)"); - break; - case BTTV_AVEC_INTERCAP: - strcpy(btv->video_dev.name,"(AVEC Intercapture)"); - break; - case BTTV_CEI_RAFFLES: - strcpy(btv->video_dev.name,"(CEI Raffles Card)"); - break; - case BTTV_CONFERENCETV: - strcpy(btv->video_dev.name,"(Image World ConferenceTV)"); - break; - case BTTV_PHOEBE_TVMAS: - strcpy(btv->video_dev.name,"(Phoebe TV Master)"); - break; - case BTTV_MODTEC_205: - strcpy(btv->video_dev.name,"(Modtec MM205)"); - break; + if (tvcards[btv->type].tda985x && + I2CRead(btv, I2C_TDA9850, "TDA985x") >=0) { + if (autoload) + request_module("tda9855"); + } + + if (tvcards[btv->type].tea63xx && + I2CRead(btv, I2C_TEA6300, "TEA63xx") >= 0) { + if (autoload) + request_module("tea6300"); + } + + if (tvcards[btv->type].tuner != -1) { + if (autoload) + request_module("tuner"); } - printk("%s\n",btv->video_dev.name); - audio(btv, AUDIO_INTERN); -} + audio(btv, AUDIO_MUTE, 1); +} static void bt848_set_risc_jmps(struct bttv *btv) @@ -2888,18 +2972,19 @@ static void bt848_set_risc_jmps(struct bttv *btv) int flags=btv->cap; /* Sync to start of odd field */ - btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRE); - btv->risc_jmp[1]=0; + btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC + |BT848_FIFO_STATUS_VRE); + btv->risc_jmp[1]=cpu_to_le32(0); /* Jump to odd vbi sub */ - btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0x5<<20)); + btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20)); if (flags&8) btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd)); else btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4)); /* Jump to odd sub */ - btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0x6<<20)); + btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20)); if (flags&2) btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_odd)); else @@ -2907,8 +2992,9 @@ static void bt848_set_risc_jmps(struct bttv *btv) /* Sync to start of even field */ - btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC|BT848_FIFO_STATUS_VRO); - btv->risc_jmp[7]=0; + btv->risc_jmp[6]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC + |BT848_FIFO_STATUS_VRO); + btv->risc_jmp[7]=cpu_to_le32(0); /* Jump to even vbi sub */ btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP); @@ -2927,7 +3013,7 @@ static void bt848_set_risc_jmps(struct bttv *btv) btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp)); - /* enable capturing */ + /* enable cpaturing and DMA */ btaor(flags, ~0x0f, BT848_CAP_CTL); if (flags&0x0f) bt848_dma(btv, 3); @@ -2935,13 +3021,52 @@ static void bt848_set_risc_jmps(struct bttv *btv) bt848_dma(btv, 0); } +static int +init_video_dev(struct bttv *btv) +{ + int num = btv - bttvs; + + memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); + memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); + memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template)); + + idcard(num); + + if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0) + return -1; + if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) + { + video_unregister_device(&btv->video_dev); + return -1; + } + if (radio[num]) + { + if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) + { + video_unregister_device(&btv->vbi_dev); + video_unregister_device(&btv->video_dev); + return -1; + } + } + return 1; +} + static int init_bt848(int i) { struct bttv *btv = &bttvs[i]; btv->user=0; - - init_MUTEX(&btv->lock); + init_MUTEX(&btv->lock); + +#if 0 + /* dump current state of the gpio registers before changing them, + * might help to make a new card work */ + printk("bttv%d: gpio: out_enable=0x%x, data=0x%x, in=0x%x\n", + i, + btread(BT848_GPIO_OUT_EN), + btread(BT848_GPIO_DATA), + btread(BT848_GPIO_REG_INP)); +#endif /* reset the bt848 */ btwrite(0, BT848_SRESET); @@ -2964,6 +3089,7 @@ static int init_bt848(int i) btv->win.bpl=1024*btv->win.bpp; btv->win.swidth=1024; btv->win.sheight=768; + btv->win.vidadr=0; btv->cap=0; btv->gmode=0; @@ -2977,17 +3103,10 @@ static int init_bt848(int i) btv->grab=0; btv->lastgrab=0; btv->field=btv->last_field=0; - /* cevans - prevents panic if initialization bails due to memory - * alloc failures! - */ - btv->video_dev.minor = -1; - btv->vbi_dev.minor = -1; - btv->radio_dev.minor = -1; /* i2c */ - memcpy(&(btv->i2c),&bttv_i2c_bus_template,sizeof(struct i2c_bus)); - sprintf(btv->i2c.name,"bt848-%d",i); - btv->i2c.data = btv; + btv->tuner_type=-1; + init_bttv_i2c(btv); if (!(btv->risc_odd=(unsigned int *) kmalloc(RISCMEM_LEN/2, GFP_KERNEL))) return -1; @@ -3017,14 +3136,14 @@ static int init_bt848(int i) bt848_set_winsize(btv); /* btwrite(0, BT848_TDEC); */ - btwrite(0x10, BT848_COLOR_CTL); + btwrite(0x10, BT848_COLOR_CTL); btwrite(0x00, BT848_CAP_CTL); btwrite(0xac, BT848_GPIO_DMA_CTL); /* select direct input */ btwrite(0x00, BT848_GPIO_REG_INP); - btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_PAL_BDGHI, + btwrite(BT848_IFORM_MUX1 | BT848_IFORM_XTAUTO | BT848_IFORM_AUTO, BT848_IFORM); btwrite(0xd8, BT848_CONTRAST_LO); @@ -3053,7 +3172,7 @@ static int init_bt848(int i) btwrite(btv->triton1| /*BT848_INT_PABORT|BT848_INT_RIPERR|BT848_INT_PPERR| BT848_INT_FDSR|BT848_INT_FTRGT|BT848_INT_FBUS|*/ - BT848_INT_VSYNC| + (fieldnr ? BT848_INT_VSYNC : 0)| BT848_INT_SCERR| BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| BT848_INT_FMTCHG|BT848_INT_HLOCK, @@ -3065,30 +3184,7 @@ static int init_bt848(int i) /* * Now add the template and register the device unit. */ - - memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template)); - memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template)); - memcpy(&btv->radio_dev,&radio_template,sizeof(radio_template)); - - idcard(i); - - if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER)<0) - return -1; - if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI)<0) - { - video_unregister_device(&btv->video_dev); - return -1; - } - if (radio[i]) - { - if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO)<0) - { - video_unregister_device(&btv->vbi_dev); - video_unregister_device(&btv->video_dev); - return -1; - } - } - i2c_register_bus(&btv->i2c); + init_video_dev(btv); return 0; } @@ -3110,7 +3206,8 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) if (!astat) return; btwrite(astat,BT848_INT_STAT); - IDEBUG(printk ("bttv%d: astat %08x stat %08x\n", btv->nr, astat, stat)); + IDEBUG(printk ("bttv%d: astat %08x\n", btv->nr, astat)); + IDEBUG(printk ("bttv%d: stat %08x\n", btv->nr, stat)); /* get device status bits */ dstat=btread(BT848_DSTATUS); @@ -3133,7 +3230,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) if (astat&BT848_INT_SCERR) { IDEBUG(printk ("bttv%d: IRQ_SCERR\n", btv->nr)); bt848_dma(btv, 0); - bt848_dma(btv, 3); + bt848_dma(btv, 1); wake_up_interruptible(&btv->vbiq); wake_up_interruptible(&btv->capq); @@ -3154,7 +3251,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) /* captured full frame */ if (stat&(2<<28)) { - wake_up_interruptible(&btv->capq); + /*wake_up_interruptible(&btv->capq);*/ btv->last_field=btv->field; btv->grab++; btv->frame_stat[btv->grf] = GBUFFER_DONE; @@ -3170,14 +3267,14 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) btv->risc_jmp[11]=cpu_to_le32(btv->gre); bt848_set_geo(btv, btv->gwidth, btv->gheight, - btv->gfmt, 0); + btv->gfmt,0); } else { bt848_set_risc_jmps(btv); btand(~BT848_VSCALE_COMB, BT848_E_VSCALE_HI); btand(~BT848_VSCALE_COMB, BT848_O_VSCALE_HI); bt848_set_geo(btv, btv->win.width, btv->win.height, - btv->win.color_fmt, 0); + btv->win.color_fmt,0); } wake_up_interruptible(&btv->capq); break; @@ -3188,7 +3285,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) btv->risc_jmp[11]=cpu_to_le32(btv->gre); btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP); bt848_set_geo(btv, btv->gwidth, btv->gheight, - btv->gfmt, 0); + btv->gfmt,0); } } if (astat&BT848_INT_OCERR) @@ -3222,13 +3319,14 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs) if (astat&BT848_INT_HLOCK) { if ((dstat&BT848_DSTATUS_HLOC) || (btv->radio)) - audio(btv, AUDIO_ON); + audio(btv, AUDIO_ON,0); else - audio(btv, AUDIO_OFF); + audio(btv, AUDIO_OFF,0); } if (astat&BT848_INT_I2CDONE) { + IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr)); } count++; @@ -3255,6 +3353,9 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) int result; unsigned char command; struct bttv *btv; +#if defined(__powerpc__) + unsigned int cmd; +#endif btv=&bttvs[bttv_num]; btv->dev=dev; @@ -3278,6 +3379,7 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) else btv->i2c_command=(I2C_TIMING | BT848_I2C_SCL | BT848_I2C_SDA); + btv->bt848_adr&=PCI_BASE_ADDRESS_MEM_MASK; pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision); printk(KERN_INFO "bttv%d: Brooktree Bt%d (rev %d) ", bttv_num,btv->id, btv->revision); @@ -3285,6 +3387,14 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) printk("irq: %d, ",btv->irq); printk("memory: 0x%lx.\n", btv->bt848_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 + btv->pll.pll_crystal = 0; btv->pll.pll_ifreq = 0; btv->pll.pll_ofreq = 0; @@ -3306,8 +3416,12 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) break; } } - - btv->bt848_mem = ioremap(btv->bt848_adr, 0x1000); + +#ifdef __sparc__ + btv->bt848_mem=(unsigned char *)btv->bt848_adr; +#else + btv->bt848_mem=ioremap(btv->bt848_adr, 0x1000); +#endif /* clear interrupt mask */ btwrite(0, BT848_INT_MASK); @@ -3351,13 +3465,12 @@ int configure_bt848(struct pci_dev *dev, int bttv_num) static int find_bt848(void) { - struct pci_dev *dev = pci_devices; + struct pci_dev *dev; int result=0; bttv_num=0; - while (dev) - { + pci_for_each_dev(dev) { if (dev->vendor == PCI_VENDOR_ID_BROOKTREE) if ((dev->device == PCI_DEVICE_ID_BT848)|| (dev->device == PCI_DEVICE_ID_BT849)|| @@ -3366,7 +3479,6 @@ static int find_bt848(void) result=configure_bt848(dev,bttv_num++); if (result) return result; - dev = dev->next; } if(bttv_num) printk(KERN_INFO "bttv: %d Bt8xx card(s) found.\n", bttv_num); @@ -3393,10 +3505,9 @@ static void release_bttv(void) btwrite(0x0, BT848_GPIO_OUT_EN); /* unregister i2c_bus */ - i2c_unregister_bus((&btv->i2c)); + i2c_bit_del_bus(&btv->i2c_adap); /* disable PCI bus-mastering */ - pci_read_config_byte(btv->dev, PCI_COMMAND, &command); /* Should this be &=~ ?? */ command&=~PCI_COMMAND_MASTER; @@ -3436,19 +3547,15 @@ static void release_bttv(void) } #ifdef MODULE - -EXPORT_NO_SYMBOLS; - int init_module(void) -{ #else int init_bttv_cards(struct video_init *unused) -{ #endif +{ int i; handle_chipset(); - if (find_bt848()<0) + if (find_bt848()<=0) return -EIO; /* initialize Bt848s */ @@ -3465,7 +3572,6 @@ int init_bttv_cards(struct video_init *unused) } - #ifdef MODULE void cleanup_module(void) @@ -3477,14 +3583,6 @@ void cleanup_module(void) /* * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 + * c-basic-offset: 8 * End: */ diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h index f6ad6a97e..b4b0caaa0 100644 --- a/drivers/char/bttv.h +++ b/drivers/char/bttv.h @@ -21,15 +21,34 @@ #ifndef _BTTV_H_ #define _BTTV_H_ -#define BTTV_VERSION_CODE 0x000523 +#define BTTV_VERSION_CODE 0x00070b #include <linux/types.h> #include <linux/wait.h> -#include <linux/i2c.h> -#include "msp3400.h" +#include "audiochip.h" #include "bt848.h" -#include <linux/videodev.h> + + +/* experimental, interface might change */ +#ifndef VIDIOCSWIN2 +#define VIDIOCSWIN2 _IOW('v',28,struct video_window2) +struct video_window2 +{ + __u16 palette; /* Palette (aka video format) in use */ + __u32 start; /* start address, relative to video_buffer.base */ + __u32 pitch; + __u32 width; + __u32 height; + __u32 flags; + + struct video_clip *clips; + int clipcount; +}; +#endif + + +#define WAIT_QUEUE wait_queue_head_t #ifndef O_NONCAP #define O_NONCAP O_TRUNC @@ -37,10 +56,10 @@ #define MAX_GBUFFERS 2 #define RISCMEM_LEN (32744*2) -#define VBIBUF_SIZE 65536 +#define VBI_MAXLINES 16 +#define VBIBUF_SIZE (2048*VBI_MAXLINES*2) -/* maximum needed buffer size for extended VBI frame mode capturing */ -#define BTTV_MAX_FBUF 0x190000 +#define BTTV_MAX_FBUF 0x208000 #ifdef __KERNEL__ @@ -58,6 +77,9 @@ struct bttv_window int interlace; int color_fmt; ushort depth; + + int use_yuv; + struct video_window2 win2; }; struct bttv_pll_info { @@ -67,16 +89,9 @@ struct bttv_pll_info { unsigned int pll_current; /* Currently programmed ofreq */ }; -/* Per-open data for handling multiple opens on one device */ -struct device_open -{ - int isopen; - int noncapturing; - struct bttv *dev; -}; -#define MAX_OPENS 3 +#define I2C_CLIENTS_MAX 8 -struct bttv +struct bttv { struct video_device video_dev; struct video_device radio_dev; @@ -84,28 +99,26 @@ struct bttv struct video_picture picture; /* Current picture params */ struct video_audio audio_dev; /* Current audio params */ - struct semaphore lock; + struct semaphore lock; int user; int capuser; - struct device_open open_data[MAX_OPENS]; - - struct i2c_bus i2c; - int have_msp3400; - int have_tuner; + + /* i2c */ + struct i2c_adapter i2c_adap; + struct i2c_algo_bit_data i2c_algo; + struct i2c_client i2c_client; + int i2c_state; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; + int tuner_type; int channel; unsigned int nr; unsigned short id; -#if LINUX_VERSION_CODE < 0x020100 - unsigned char bus; /* PCI bus the Bt848 is on */ - unsigned char devfn; -#else struct pci_dev *dev; -#endif - unsigned int irq; /* IRQ used by Bt848 card */ + unsigned int irq; /* IRQ used by Bt848 card */ unsigned char revision; - unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ + unsigned long bt848_adr; /* bus address of IO mem returned by PCI BIOS */ unsigned char *bt848_mem; /* pointer to mapped IO memory */ unsigned long busriscmem; u32 *riscmem; @@ -114,8 +127,7 @@ struct bttv struct bttv_window win; int type; /* card type */ int audio; /* audio mode */ - int audio_chip; - int fader_chip; + int audio_chip; /* set to one of the chips supported by bttv.c */ int radio; u32 *risc_jmp; @@ -123,10 +135,10 @@ struct bttv u32 *vbi_even; u32 bus_vbi_even; u32 bus_vbi_odd; - wait_queue_head_t vbiq; - wait_queue_head_t capq; - wait_queue_head_t capqo; - wait_queue_head_t capqe; + WAIT_QUEUE vbiq; + WAIT_QUEUE capq; + WAIT_QUEUE capqo; + WAIT_QUEUE capqe; int vbip; u32 *risc_odd; @@ -170,6 +182,17 @@ struct bttv /*The following should be done in more portable way. It depends on define of _ALPHA_BTTV in the Makefile.*/ +#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 *)(btv->bt848_mem+(adr)),(dat)) +#define btread(adr) ld_le32((unsigned *)(btv->bt848_mem+(adr))) +#else #ifdef _ALPHA_BTTV #define btwrite(dat,adr) writel((dat),(char *) (btv->bt848_adr+(adr))) #define btread(adr) readl(btv->bt848_adr+(adr)) @@ -177,6 +200,7 @@ struct bttv #define btwrite(dat,adr) writel((dat), (char *) (btv->bt848_mem+(adr))) #define btread(adr) readl(btv->bt848_mem+(adr)) #endif +#endif #define btand(dat,adr) btwrite((dat) & btread(adr), adr) #define btor(dat,adr) btwrite((dat) | btread(adr), adr) @@ -192,7 +216,7 @@ struct bttv #define BTTV_BURST_OFF _IOR('v' , BASE_VIDIOCPRIVATE+5, int) #define BTTV_VERSION _IOR('v' , BASE_VIDIOCPRIVATE+6, int) #define BTTV_PICNR _IOR('v' , BASE_VIDIOCPRIVATE+7, int) - +#define BTTV_VBISIZE _IOR('v' , BASE_VIDIOCPRIVATE+8, int) #define BTTV_UNKNOWN 0x00 #define BTTV_MIRO 0x01 @@ -220,6 +244,37 @@ struct bttv #define BTTV_MODTEC_205 0x17 #define BTTV_MAGICTVIEW061 0x18 +#define BTTV_MAXI 0x1b +#define BTTV_TERRATV 0x1c +#define BTTV_PXC200 0x1d + +#if 0 +#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 BTTV_AVERMEDIA 0x06 +#define BTTV_MATRIX_VISION 0x07 +#define BTTV_FLYVIDEO 0x08 +#define BTTV_TURBOTV 0x09 +#define BTTV_HAUPPAUGE878 0x0a +#define BTTV_MIROPRO 0x0b +#define BTTV_TVBOOSTAR 0x0c +#define BTTV_WINCAM 0x0d +#define BTTV_MAXI 0x0e +#define BTTV_VHX 0x10 +#define BTTV_PXC200 0x11 +#define BTTV_AVERMEDIA98 0x12 +#define BTTV_FLYVIDEO98 0x13 + +#define BTTV_PIXVIEWPLAYTV 0x17 +#define BTTV_WINVIEW_601 0x18 +#define BTTV_CONFERENCETV 0x1c +#endif + + #define AUDIO_TUNER 0x00 #define AUDIO_RADIO 0x01 #define AUDIO_EXTERN 0x02 @@ -230,25 +285,25 @@ struct bttv #define AUDIO_UNMUTE 0x81 #define TDA9850 0x01 -#define TDA8425 0x02 -#define TDA9840 0x03 +#define TDA9840 0x02 +#define TDA8425 0x03 #define TEA6300 0x04 -#define TEA6320 0x05 #define I2C_TSA5522 0xc2 -#define I2C_TDA9840 0x84 +#define I2C_TDA9840 0x84 #define I2C_TDA9850 0xb6 #define I2C_TDA8425 0x82 #define I2C_HAUPEE 0xa0 #define I2C_STBEE 0xae -#define I2C_VHX 0xc0 -#define I2C_TEA6300 0x80 /* same as TEA6320 */ -#define I2C_TEA6320 0x80 +#define I2C_VHX 0xc0 +#define I2C_MSP3400 0x80 +#define I2C_TEA6300 0x80 +#define I2C_DPL3518 0x84 -#define TDA9840_SW 0x00 -#define TDA9840_LVADJ 0x02 -#define TDA9840_STADJ 0x03 -#define TDA9840_TEST 0x04 +#define TDA9840_SW 0x00 +#define TDA9840_LVADJ 0x02 +#define TDA9840_STADJ 0x03 +#define TDA9840_TEST 0x04 #define TDA9850_CON1 0x04 #define TDA9850_CON2 0x05 @@ -263,7 +318,7 @@ struct bttv #define TDA8425_BA 0x02 #define TDA8425_TR 0x03 #define TDA8425_S1 0x08 - + #define TEA6300_VL 0x00 /* volume control left */ #define TEA6300_VR 0x01 /* volume control right */ #define TEA6300_BA 0x02 /* bass control */ @@ -271,22 +326,6 @@ struct bttv #define TEA6300_FA 0x04 /* fader control */ #define TEA6300_SW 0x05 /* mute and source switch */ - -#define TEA6320_V 0x00 -#define TEA6320_FFR 0x01 /* volume front right */ -#define TEA6320_FFL 0x02 /* volume front left */ -#define TEA6320_FRR 0x03 /* volume rear right */ -#define TEA6320_FRL 0x04 /* volume rear left */ -#define TEA6320_BA 0x05 /* bass */ -#define TEA6320_TR 0x06 /* treble */ -#define TEA6320_S 0x07 /* switch register */ - /* values for those registers: */ -#define TEA6320_S_SA 0x01 /* stereo A input */ -#define TEA6320_S_SB 0x07 /* stereo B -- databook wrong? this works */ -#define TEA6320_S_SC 0x04 /* stereo C */ -#define TEA6320_S_GMU 0x80 /* general mute */ - - #define PT2254_L_CHANEL 0x10 #define PT2254_R_CHANEL 0x08 #define PT2254_DBS_IN_2 0x400 diff --git a/drivers/char/buz.c b/drivers/char/buz.c index de688ae0b..4c4e44621 100644 --- a/drivers/char/buz.c +++ b/drivers/char/buz.c @@ -54,7 +54,7 @@ #include <linux/version.h> #include <asm/uaccess.h> -#include <linux/i2c.h> +#include <linux/i2c-old.h> #include "buz.h" #include <linux/video_decoder.h> #include <linux/video_encoder.h> @@ -3166,8 +3166,6 @@ static int zr36057_init(int i) mdelay(10); zr36060_reset(zr); mdelay(10); - zr36060_sleep(zr, 1); - mdelay(10); /* display codec revision */ if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { @@ -3204,8 +3202,6 @@ static int zr36057_init(int i) udelay(3000); zr36060_reset(zr); udelay(3000); - zr36060_sleep(zr, 1); - udelay(3000); /* display codec revision */ if ((rev=zr36060_read_8(zr, 0x022)) == 0x33) { @@ -3213,8 +3209,8 @@ static int zr36057_init(int i) zr->name, zr36060_read_8(zr, 0x023)); } else { printk(KERN_ERR "%s: Zoran ZR36060 not found (rev=%d)\n", zr->name, rev); -// kfree((void *) zr->stat_com); -// return -1; + kfree((void *) zr->stat_com); + return -1; } break; } diff --git a/drivers/char/console.c b/drivers/char/console.c index 2a58a72ec..090f1066c 100644 --- a/drivers/char/console.c +++ b/drivers/char/console.c @@ -91,9 +91,6 @@ #include <linux/config.h> #include <linux/version.h> #include <linux/tqueue.h> -#ifdef CONFIG_APM -#include <linux/apm_bios.h> -#endif #include <linux/bootmem.h> #include <linux/acpi.h> @@ -190,6 +187,12 @@ DECLARE_TASK_QUEUE(con_task_queue); static int scrollback_delta = 0; /* + * Hook so that the power management routines can (un)blank + * the console on our behalf. + */ +int (*console_blank_hook)(int) = NULL; + +/* * Low-Level Functions */ @@ -2551,10 +2554,8 @@ void do_blank_screen(int entering_gfx) if (i) set_origin(currcons); -#ifdef CONFIG_APM - if (apm_display_blank()) + if (console_blank_hook && console_blank_hook(1)) return; -#endif if (vesa_blank_mode) sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1); } @@ -2578,9 +2579,8 @@ void unblank_screen(void) currcons = fg_console; console_blanked = 0; -#ifdef CONFIG_APM - apm_display_unblank(); -#endif + if (console_blank_hook) + console_blank_hook(0); if (sw->con_blank(vc_cons[currcons].d, 0)) /* Low-level driver cannot restore -> do it ourselves */ update_screen(fg_console); diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile index e33418fd4..ff70792d7 100644 --- a/drivers/char/drm/Makefile +++ b/drivers/char/drm/Makefile @@ -10,7 +10,6 @@ # parent makes.. # -L_TARGET := libdrm.a O_TARGET := drm.o L_OBJS := init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ @@ -19,25 +18,33 @@ L_OBJS := init.o memory.o proc.o auth.o context.o drawable.o bufs.o \ M_OBJS := ifeq ($(CONFIG_DRM_GAMMA),y) - O_OBJS += gamma.o + OX_OBJS += gamma_drv.o + O_OBJS += gamma_dma.o else ifeq ($(CONFIG_DRM_GAMMA),m) + MIX_OBJS += gamma_drv.o + MI_OBJS += gamma_dma.o M_OBJS += gamma.o endif endif ifeq ($(CONFIG_DRM_TDFX),y) - O_OBJS += tdfx.o + OX_OBJS += tdfx_drv.o + O_OBJS += tdfx_context.o else ifeq ($(CONFIG_DRM_TDFX),m) + MIX_OBJS += tdfx_drv.o + MI_OBJS += tdfx_context.o M_OBJS += tdfx.o endif endif +O_OBJS += $(L_OBJS) + include $(TOPDIR)/Rules.make -gamma.o: gamma_drv.o gamma_dma.o $(L_TARGET) - $(LD) $(LD_RFLAG) -r -o $@ gamma_drv.o gamma_dma.o -L. -ldrm +gamma.o : gamma_drv.o gamma_dma.o $(L_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ gamma_drv.o gamma_dma.o $(L_OBJS) -tdfx.o: tdfx_drv.o tdfx_context.o $(L_TARGET) - $(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o -L. -ldrm +tdfx.o: tdfx_drv.o tdfx_context.o $(L_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o $(L_OBJS) diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c index 2a966cab1..028772f26 100644 --- a/drivers/char/drm/gamma_drv.c +++ b/drivers/char/drm/gamma_drv.c @@ -29,7 +29,6 @@ * */ -#define EXPORT_SYMTAB #include <linux/config.h> #include "drmP.h" #include "gamma_drv.h" @@ -122,7 +121,7 @@ void cleanup_module(void) #ifndef MODULE /* gamma_setup is called by the kernel to parse command-line options passed * via the boot-loader (e.g., LILO). It calls the insmod option routine, - * drm_parse_drm. + * drm_parse_options. * * This is not currently supported, since it requires changes to * linux/init/main.c. */ diff --git a/drivers/char/drm/init.c b/drivers/char/drm/init.c index e6b78395c..f416a99af 100644 --- a/drivers/char/drm/init.c +++ b/drivers/char/drm/init.c @@ -35,7 +35,7 @@ int drm_flags = 0; /* drm_parse_option parses a single option. See description for - drm_parse_drm for details. */ + drm_parse_options for details. */ static void drm_parse_option(char *s) { diff --git a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c index c5913a08e..f56e2af95 100644 --- a/drivers/char/drm/tdfx_drv.c +++ b/drivers/char/drm/tdfx_drv.c @@ -29,7 +29,6 @@ * */ -#define EXPORT_SYMTAB #include <linux/config.h> #include "drmP.h" #include "tdfx_drv.h" @@ -89,7 +88,9 @@ static drm_ioctl_desc_t tdfx_ioctls[] = { }; #define TDFX_IOCTL_COUNT DRM_ARRAY_SIZE(tdfx_ioctls) +#ifdef MODULE static char *tdfx = NULL; +#endif MODULE_AUTHOR("Precision Insight, Inc., Cedar Park, Texas."); MODULE_DESCRIPTION("tdfx"); @@ -587,10 +588,11 @@ int tdfx_unlock(struct inode *inode, struct file *filp, unsigned int cmd, module_init(tdfx_init); module_exit(tdfx_cleanup); +#ifndef MODULE /* * tdfx_setup is called by the kernel to parse command-line options passed * via the boot-loader (e.g., LILO). It calls the insmod option routine, - * drm_parse_drm. + * drm_parse_options. */ static int __init tdfx_options(char *str) { @@ -599,3 +601,4 @@ static int __init tdfx_options(char *str) } __setup("tdfx=", tdfx_options); +#endif diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index bce9c6e02..ea44e568d 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -513,8 +513,6 @@ static struct file_operations dsp56k_fops = { dsp56k_release, NULL, /* no special dsp56k_fsync */ NULL, /* no special dsp56k_fasync */ - NULL, /* no special dsp56k_check_media_change */ - NULL /* no special dsp56k_revalidate */ }; diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index 688604227..8b241bde4 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -115,8 +115,6 @@ static struct file_operations dtlk_fops = dtlk_release, NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ NULL /* lock */ }; diff --git a/drivers/char/h8.c b/drivers/char/h8.c index a0cc714c5..8e33b7d51 100644 --- a/drivers/char/h8.c +++ b/drivers/char/h8.c @@ -109,18 +109,7 @@ static int h8_monitor_timer_active = 0; static char driver_version[] = "X0.0";/* no spaces */ static struct file_operations h8_fops = { - NULL, /* lseek */ - NULL, - NULL, /* write */ - NULL, /* readdir */ - NULL, - NULL, - NULL, /* mmap */ - NULL, - NULL, /* flush */ - NULL, - NULL, /* fsync */ - NULL /* fasync */ + /* twelve lines of crap^WNULLs were here */ }; static struct miscdevice h8_device = { diff --git a/drivers/char/i2c.c b/drivers/char/i2c-old.c index 452583f86..bd9750fc3 100644 --- a/drivers/char/i2c.c +++ b/drivers/char/i2c-old.c @@ -15,7 +15,7 @@ #include <linux/locks.h> #include <linux/sched.h> #include <linux/malloc.h> -#include <linux/i2c.h> +#include <linux/i2c-old.h> #define REGPRINT(x) if (verbose) (x) #define I2C_DEBUG(x) if (i2c_debug) (x) diff --git a/drivers/char/i2c-parport.c b/drivers/char/i2c-parport.c index a8f83ce8e..8304a6ab5 100644 --- a/drivers/char/i2c-parport.c +++ b/drivers/char/i2c-parport.c @@ -20,7 +20,7 @@ #include <linux/parport.h> #include <linux/module.h> #include <linux/delay.h> -#include <linux/i2c.h> +#include <linux/i2c-old.h> #include <linux/init.h> #include <linux/spinlock.h> diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 4f25001fb..c5f31d1eb 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -195,12 +195,6 @@ ip2_ipl = { ip2_ipl_ioctl, NULL, ip2_ipl_open, - NULL, - NULL, - NULL, - NULL, - NULL, - /* NULL, NULL 2.2 */ }; static long irq_counter = 0; diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 6d2b5ed83..e8b32f8f3 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -121,8 +121,6 @@ static struct file_operations ISILoad_fops = { ISILoad_release, NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ }; struct miscdevice isiloader_device = { diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 57f3d7199..f4ab04a4d 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -789,8 +789,6 @@ static struct file_operations stli_fsiomem = { stli_memclose, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ NULL /* lock */ }; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index d42b0f39b..281ac186e 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -662,11 +662,30 @@ static void lp_console_write (struct console *co, const char *s, parport_negotiate (port, IEEE1284_MODE_COMPAT); do { - /* Write the data. */ - written = parport_write (port, s, count); - if (written > 0) { - s += written; - count -= written; + /* Write the data, converting LF->CRLF as we go. */ + ssize_t canwrite = count; + char *line = strchr (s, '\n'); + if (line) + canwrite = line - s; + + written = parport_write (port, s, canwrite); + if (written <= 0) + continue; + + s += written; + count -= written; + if (line) { + const char *crlf = "\r\n"; + int i = 2; + + /* Dodge the original '\n', and put '\r\n' instead. */ + s++; + count--; + while (i) { + written = parport_write (port, crlf, i); + if (written > 0) + i -= written, crlf += written; + } } } while (count > 0 && (CONSOLE_LP_STRICT || written > 0)); @@ -679,7 +698,7 @@ static kdev_t lp_console_device (struct console *c) } static struct console lpcons = { - "lp", + "lp0", lp_console_write, NULL, lp_console_device, diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 01e955a26..9e9955501 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -15,7 +15,6 @@ #include <linux/random.h> #include <linux/init.h> #include <linux/joystick.h> -#include <linux/i2c.h> #include <linux/raw.h> #include <linux/capability.h> @@ -23,6 +22,12 @@ #include <asm/io.h> #include <asm/pgalloc.h> +#ifdef CONFIG_VIDEO_BT848 +extern int i2c_init(void); +#endif +#ifdef CONFIG_I2C +extern int i2c_init_all(void); +#endif #ifdef CONFIG_SOUND void soundcore_init(void); #ifdef CONFIG_SOUND_OSS @@ -56,6 +61,9 @@ extern void adbdev_init(void); #ifdef CONFIG_USB extern void usb_init(void); #endif +#ifdef CONFIG_PHONE +extern void telephony_init(void); +#endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) @@ -622,6 +630,9 @@ int __init chr_dev_init(void) #ifdef CONFIG_USB usb_init(); #endif +#ifdef CONFIG_I2C + i2c_init_all(); +#endif #if defined (CONFIG_FB) fbmem_init(); #endif @@ -676,5 +687,8 @@ int __init chr_dev_init(void) #ifdef CONFIG_VIDEO_DEV videodev_init(); #endif +#ifdef CONFIG_PHONE + telephony_init(); +#endif return 0; } diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c index 73fd16541..48709907c 100644 --- a/drivers/char/msp3400.c +++ b/drivers/char/msp3400.c @@ -34,7 +34,6 @@ */ #include <linux/module.h> -#include <linux/version.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/string.h> @@ -42,6 +41,10 @@ #include <linux/delay.h> #include <linux/errno.h> #include <linux/malloc.h> +#include <linux/i2c.h> +#include <linux/videodev.h> +#include <asm/semaphore.h> + #ifdef __SMP__ #include <asm/pgtable.h> #include <linux/smp_lock.h> @@ -51,27 +54,43 @@ #define __KERNEL_SYSCALLS__ #include <linux/unistd.h> -#include <linux/i2c.h> -#include <linux/videodev.h> - -#include "msp3400.h" +#include "audiochip.h" + +#define WAIT_QUEUE wait_queue_head_t /* sound mixer stuff */ #include <linux/config.h> - -#if LINUX_VERSION_CODE > 0x020140 /* need modular sound driver */ -# if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) -# define REGISTER_MIXER 1 -# endif +#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) +# define REGISTER_MIXER 1 #endif +/* Addresses to scan */ +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {0x40,0x44,I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; -static int debug = 0; /* insmod parameter */ +/* insmod parameters */ +static int debug = 0; /* debug output */ +static int once = 0; /* no continous stereo monitoring */ +static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), + the autoscan seems work well only with FM... */ +static int simple = -1; /* use short programming (>= msp3410 only) */ +static int dolby = 0; +static int mixer = -1; struct msp3400c { - struct i2c_bus *bus; - + int simple; int nicam; int mode; int norm; @@ -84,36 +103,34 @@ struct msp3400c { /* thread */ struct task_struct *thread; - wait_queue_head_t wq; + WAIT_QUEUE wq; + struct semaphore *notify; int active,restart,rmmod; int watch_stereo; struct timer_list wake_stereo; + + /* mixer */ + int mixer_modcnt; + int mixer_num; }; +#define MSP3400_MAX 4 +static struct i2c_client *msps[MSP3400_MAX]; + #define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ /* ---------------------------------------------------------------------- */ #define dprintk if (debug) printk -#if LINUX_VERSION_CODE < 0x020100 -/* 2.0.x */ -#define signal_pending(current) (current->signal & ~current->blocked) -#define sigfillset(set) -#define mdelay(x) udelay(1000*x) -#else +MODULE_PARM(once,"i"); MODULE_PARM(debug,"i"); -#endif - -#if LINUX_VERSION_CODE < 0x02017f -void schedule_timeout(int j) -{ - current->timeout = jiffies + j; - schedule(); -} -#endif +MODULE_PARM(simple,"i"); +MODULE_PARM(amsound,"i"); +MODULE_PARM(dolby,"i"); +MODULE_PARM(mixer,"i"); /* ---------------------------------------------------------------------- */ @@ -124,103 +141,78 @@ void schedule_timeout(int j) /* ----------------------------------------------------------------------- */ /* functions for talking to the MSP3400C Sound processor */ -static int msp3400c_reset(struct i2c_bus *bus) +static int msp3400c_reset(struct i2c_client *client) { - int ret = 0; - - mdelay(2); - i2c_start(bus); - i2c_sendbyte(bus, I2C_MSP3400C,2000); - i2c_sendbyte(bus, 0x00,0); - i2c_sendbyte(bus, 0x80,0); - i2c_sendbyte(bus, 0x00,0); - i2c_stop(bus); - mdelay(2); - i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || - 0 != i2c_sendbyte(bus, 0x00,0) || - 0 != i2c_sendbyte(bus, 0x00,0) || - 0 != i2c_sendbyte(bus, 0x00,0)) { - ret = -1; + static char reset_off[3] = { 0x00, 0x80, 0x00 }; + static char reset_on[3] = { 0x00, 0x00, 0x00 }; + + i2c_master_send(client,reset_off,3); /* XXX ignore errors here */ + if (3 != i2c_master_send(client,reset_on, 3)) { printk(KERN_ERR "msp3400: chip reset failed, penguin on i2c bus?\n"); + return -1; } - i2c_stop(bus); - mdelay(2); - return ret; + return 0; } static int -msp3400c_read(struct i2c_bus *bus, int dev, int addr) +msp3400c_read(struct i2c_client *client, int dev, int addr) { - int err,ret; - short val=0; + int err; + + unsigned char write[3]; + unsigned char read[2]; + struct i2c_msg msgs[2] = { + { client->addr, 0, 3, write }, + { client->addr, I2C_M_RD, 2, read } + }; + write[0] = dev+1; + write[1] = addr >> 8; + write[2] = addr & 0xff; for (err = 0; err < 3;) { - ret = 0; - i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || - 0 != i2c_sendbyte(bus, dev+1, 0) || - 0 != i2c_sendbyte(bus, addr >> 8, 0) || - 0 != i2c_sendbyte(bus, addr & 0xff, 0)) { - ret = -1; - } else { - i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C+1,2000)) { - ret = -1; - } else { - val |= (int)i2c_readbyte(bus,0) << 8; - val |= (int)i2c_readbyte(bus,1); - } - } - i2c_stop(bus); - if (0 == ret) + if (2 == i2c_transfer(client->adapter,msgs,2)) break; - - /* some I/O error */ err++; printk(KERN_WARNING "msp34xx: I/O error #%d (read 0x%02x/0x%02x)\n", err, dev, addr); current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/10); } - if (-1 == ret) { + if (3 == err) { printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); - msp3400c_reset(bus); + msp3400c_reset(client); + return -1; } - return val; + return read[0] << 8 | read[1]; } static int -msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val) +msp3400c_write(struct i2c_client *client, int dev, int addr, int val) { - int ret,err; - + int err; + unsigned char buffer[5]; + + buffer[0] = dev; + buffer[1] = addr >> 8; + buffer[2] = addr & 0xff; + buffer[3] = val >> 8; + buffer[4] = val & 0xff; + for (err = 0; err < 3;) { - ret = 0; - i2c_start(bus); - if (0 != i2c_sendbyte(bus, I2C_MSP3400C,2000) || - 0 != i2c_sendbyte(bus, dev, 0) || - 0 != i2c_sendbyte(bus, addr >> 8, 0) || - 0 != i2c_sendbyte(bus, addr & 0xff, 0) || - 0 != i2c_sendbyte(bus, val >> 8, 0) || - 0 != i2c_sendbyte(bus, val & 0xff, 0)) - ret = -1; - i2c_stop(bus); - if (0 == ret) + if (5 == i2c_master_send(client, buffer, 5)) break; - - /* some I/O error */ err++; printk(KERN_WARNING "msp34xx: I/O error #%d (write 0x%02x/0x%02x)\n", err, dev, addr); current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/10); } - if (-1 == ret) { + if (3 == err) { printk(KERN_WARNING "msp34xx: giving up, reseting chip. Sound will go off, sorry folks :-|\n"); - msp3400c_reset(bus); + msp3400c_reset(client); + return -1; } - return ret; + return 0; } /* ------------------------------------------------------------------------ */ @@ -235,6 +227,8 @@ msp3400c_write(struct i2c_bus *bus, int dev, int addr, int val) #define MSP_MODE_FM_SAT 4 #define MSP_MODE_FM_NICAM1 5 #define MSP_MODE_FM_NICAM2 6 +#define MSP_MODE_AM_NICAM 7 +#define MSP_MODE_BTSC 8 static struct MSP_INIT_DATA_DEM { int fir1[6]; @@ -271,15 +265,20 @@ static struct MSP_INIT_DATA_DEM { MSP_CARRIER(6.5), MSP_CARRIER(6.5), 0x00c6, 0x0480, 0x0000, 0x3000}, - /* NICAM B/G, D/K */ + /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ { { -2, -8, -10, 10, 50, 86 }, { 3, 18, 27, 48, 66, 72 }, MSP_CARRIER(5.5), MSP_CARRIER(5.5), 0x00d0, 0x0040, 0x0120, 0x3000}, - /* NICAM I */ + /* NICAM/FM -- I (6.0/6.552) */ { { 2, 4, -6, -4, 40, 94 }, { 3, 18, 27, 48, 66, 72 }, MSP_CARRIER(6.0), MSP_CARRIER(6.0), 0x00d0, 0x0040, 0x0120, 0x3000}, + + /* NICAM/AM -- L (6.5/5.85) */ + { { -2, -8, -10, 10, 50, 86 }, { -4, -12, -9, 23, 79, 126 }, + MSP_CARRIER(6.5), MSP_CARRIER(6.5), + 0x00c6, 0x0140, 0x0120, 0x7000}, }; struct CARRIER_DETECT { @@ -315,16 +314,16 @@ static struct CARRIER_DETECT carrier_detect_65[] = { /* ------------------------------------------------------------------------ */ -static void msp3400c_setcarrier(struct i2c_bus *bus, int cdo1, int cdo2) +static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) { - msp3400c_write(bus,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); - msp3400c_write(bus,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); - msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); - msp3400c_write(bus,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); - msp3400c_write(bus,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0093, cdo1 & 0xfff); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x009b, cdo1 >> 12); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x00a3, cdo2 & 0xfff); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x00ab, cdo2 >> 12); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ } -static void msp3400c_setvolume(struct i2c_bus *bus, int left, int right) +static void msp3400c_setvolume(struct i2c_client *client, int left, int right) { int vol,val,balance; @@ -334,94 +333,106 @@ static void msp3400c_setvolume(struct i2c_bus *bus, int left, int right) if (vol > 0) balance = ((right-left) * 127) / vol; - dprintk("msp3400: setvolume: %d:%d 0x%02x 0x%02x\n", + dprintk("msp34xx: setvolume: %d:%d 0x%02x 0x%02x\n", left,right,val>>8,balance); - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones */ /* scart - on/off only */ - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0); - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0001, balance << 8); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0007, val ? 0x4000 : 0); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0001, balance << 8); } -static void msp3400c_setbass(struct i2c_bus *bus, int bass) +static void msp3400c_setbass(struct i2c_client *client, int bass) { int val = ((bass-32768) * 0x60 / 65535) << 8; - dprintk("msp3400: setbass: %d 0x%02x\n",bass, val>>8); - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */ + dprintk("msp34xx: setbass: %d 0x%02x\n",bass, val>>8); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */ } -static void msp3400c_settreble(struct i2c_bus *bus, int treble) +static void msp3400c_settreble(struct i2c_client *client, int treble) { int val = ((treble-32768) * 0x60 / 65535) << 8; - dprintk("msp3400: settreble: %d 0x%02x\n",treble, val>>8); - msp3400c_write(bus,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */ + dprintk("msp34xx: settreble: %d 0x%02x\n",treble, val>>8); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */ } -static void msp3400c_setmode(struct msp3400c *msp, int type) +static void msp3400c_setmode(struct i2c_client *client, int type) { + struct msp3400c *msp = client->data; int i; dprintk("msp3400: setmode: %d\n",type); msp->mode = type; msp->stereo = VIDEO_SOUND_MONO; - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x00bb, /* ad_cv */ msp_init_data[type].ad_cv); for (i = 5; i >= 0; i--) /* fir 1 */ - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0001, + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0001, msp_init_data[type].fir1[i]); - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0040); - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, 0x0000); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0004); /* fir 2 */ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0040); + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, 0x0000); for (i = 5; i >= 0; i--) - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0005, + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0005, msp_init_data[type].fir2[i]); - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0083, /* MODE_REG */ msp_init_data[type].mode_reg); - msp3400c_setcarrier(msp->bus, msp_init_data[type].cdo1, + msp3400c_setcarrier(client, msp_init_data[type].cdo1, msp_init_data[type].cdo2); - msp3400c_write(msp->bus,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ - - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008, - msp_init_data[type].dfp_src); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009, - msp_init_data[type].dfp_src); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a, + msp3400c_write(client,I2C_MSP3400C_DEM, 0x0056, 0); /*LOAD_REG_1/2*/ + + if (dolby) { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, + 0x0520); /* I2S1 */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, + 0x0620); /* I2S2 */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b, + msp_init_data[type].dfp_src); + } else { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008, + msp_init_data[type].dfp_src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009, + msp_init_data[type].dfp_src); + } + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a, msp_init_data[type].dfp_src); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, msp_init_data[type].dfp_matrix); if (msp->nicam) { - /* msp3410 needs some more initialization */ - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0010, 0x3000); + /* nicam prescale */ + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x3000); } } -static void msp3400c_setstereo(struct msp3400c *msp, int mode) +/* turn on/off nicam + stereo */ +static void msp3400c_setstereo(struct i2c_client *client, int mode) { + struct msp3400c *msp = client->data; int nicam=0; /* channel source: FM/AM or nicam */ int src=0; - + /* switch demodulator */ switch (msp->mode) { case MSP_MODE_FM_TERRA: dprintk("msp3400: FM setstereo: %d\n",mode); - msp3400c_setcarrier(msp->bus,msp->second,msp->main); + msp3400c_setcarrier(client,msp->second,msp->main); switch (mode) { case VIDEO_SOUND_STEREO: - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3001); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3001); break; case VIDEO_SOUND_MONO: case VIDEO_SOUND_LANG1: case VIDEO_SOUND_LANG2: - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000e, 0x3000); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e, 0x3000); break; } break; @@ -429,29 +440,33 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) dprintk("msp3400: SAT setstereo: %d\n",mode); switch (mode) { case VIDEO_SOUND_MONO: - msp3400c_setcarrier(msp->bus, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); + msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); break; case VIDEO_SOUND_STEREO: - msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); + msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); break; case VIDEO_SOUND_LANG1: - msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); break; case VIDEO_SOUND_LANG2: - msp3400c_setcarrier(msp->bus, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); break; } break; case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: + case MSP_MODE_AM_NICAM: dprintk("msp3400: NICAM setstereo: %d\n",mode); - msp->stereo = mode; - msp3400c_setcarrier(msp->bus,msp->second,msp->main); + msp3400c_setcarrier(client,msp->second,msp->main); if (msp->nicam_on) nicam=0x0100; break; + case MSP_MODE_BTSC: + dprintk("msp3400: BTSC setstereo: %d\n",mode); + nicam=0x0300; + break; default: - /* can't do stereo - abort here */ + dprintk("msp3400: mono setstereo\n"); return; } @@ -459,8 +474,8 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) switch (mode) { case VIDEO_SOUND_STEREO: src = 0x0020 | nicam; -#if 0 - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0005,0x4000); +#if 0 + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000); #endif break; case VIDEO_SOUND_MONO: @@ -471,9 +486,16 @@ static void msp3400c_setstereo(struct msp3400c *msp, int mode) src = 0x0010 | nicam; break; } - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0008,src); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0009,src); - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x000a,src); + if (dolby) { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src); + } else { + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src); + } } static void @@ -488,7 +510,10 @@ msp3400c_print_mode(struct msp3400c *msp) } if (msp->mode == MSP_MODE_FM_NICAM1 || msp->mode == MSP_MODE_FM_NICAM2) - printk("msp3400: NICAM carrier : %d.%03d MHz\n", + printk("msp3400: NICAM/FM carrier : %d.%03d MHz\n", + msp->second/910000,(msp->second/910)%1000); + if (msp->mode == MSP_MODE_AM_NICAM) + printk("msp3400: NICAM/AM carrier : %d.%03d MHz\n", msp->second/910000,(msp->second/910)%1000); if (msp->mode == MSP_MODE_FM_TERRA && msp->main != msp->second) { @@ -513,8 +538,9 @@ struct REGISTER_DUMP d1[] = { }; static int -autodetect_stereo(struct msp3400c *msp) +autodetect_stereo(struct i2c_client *client) { + struct msp3400c *msp = client->data; int val; int newstereo = msp->stereo; int newnicam = msp->nicam_on; @@ -522,7 +548,9 @@ autodetect_stereo(struct msp3400c *msp) switch (msp->mode) { case MSP_MODE_FM_TERRA: - val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x18); + val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18); + if (val > 32768) + val -= 65536; dprintk("msp3400: stereo detect register: %d\n",val); if (val > 4096) { @@ -536,7 +564,8 @@ autodetect_stereo(struct msp3400c *msp) break; case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: - val = msp3400c_read(msp->bus, I2C_MSP3400C_DEM, 0x23); + case MSP_MODE_AM_NICAM: + val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23); dprintk("msp3400: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1); if (val & 1) { @@ -564,6 +593,16 @@ autodetect_stereo(struct msp3400c *msp) newnicam=1; } else { newnicam=0; +#if 0 /* fixme: quick & dirty for testing */ + if (msp->main == MSP_CARRIER(6.5)) { + /* This is a french mono channel => AM */ + printk("msp3400: switching to AM mono\n"); + msp3400c_setstereo(msp, VIDEO_SOUND_MONO); + msp->second = msp->main; + msp3400c_setmode(msp, MSP_MODE_AM_DETECT); + msp3400c_setcarrier(client, msp->second, msp->main); + } +#endif newstereo = VIDEO_SOUND_MONO; } break; @@ -596,20 +635,20 @@ static void msp3400c_stereo_wake(unsigned long data) } /* stereo/multilang monitoring */ -static void watch_stereo(struct msp3400c *msp) +static void watch_stereo(struct i2c_client *client) { - LOCK_FLAGS; + struct msp3400c *msp = client->data; - LOCK_I2C_BUS(msp->bus); - if (autodetect_stereo(msp)) { + if (autodetect_stereo(client)) { if (msp->stereo & VIDEO_SOUND_STEREO) - msp3400c_setstereo(msp,VIDEO_SOUND_STEREO); + msp3400c_setstereo(client,VIDEO_SOUND_STEREO); else if (msp->stereo & VIDEO_SOUND_LANG1) - msp3400c_setstereo(msp,VIDEO_SOUND_LANG1); + msp3400c_setstereo(client,VIDEO_SOUND_LANG1); else - msp3400c_setstereo(msp,VIDEO_SOUND_MONO); + msp3400c_setstereo(client,VIDEO_SOUND_MONO); } - UNLOCK_I2C_BUS(msp->bus); + if (once) + msp->watch_stereo = 0; if (msp->watch_stereo) { del_timer(&msp->wake_stereo); msp->wake_stereo.expires = jiffies + 5*HZ; @@ -619,11 +658,11 @@ static void watch_stereo(struct msp3400c *msp) static int msp3400c_thread(void *data) { - struct msp3400c *msp = data; + struct i2c_client *client = data; + struct msp3400c *msp = client->data; struct CARRIER_DETECT *cd; int count, max1,max2,val1,val2, val,this; - LOCK_FLAGS; #ifdef __SMP__ lock_kernel(); @@ -663,15 +702,14 @@ static int msp3400c_thread(void *data) msp->active = 1; if (msp->watch_stereo) { - watch_stereo(msp); + watch_stereo(client); msp->active = 0; continue; } restart: - LOCK_I2C_BUS(msp->bus); - msp3400c_setvolume(msp->bus, 0, 0); - msp3400c_setmode(msp, MSP_MODE_AM_DETECT /* +1 */ ); + msp3400c_setvolume(client, 0, 0); + msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); val1 = val2 = 0; max1 = max2 = -1; del_timer(&msp->wake_stereo); @@ -680,8 +718,7 @@ static int msp3400c_thread(void *data) /* carrier detect pass #1 -- main carrier */ cd = carrier_detect_main; count = CARRIER_COUNT(carrier_detect_main); for (this = 0; this < count; this++) { - msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/25); @@ -692,12 +729,17 @@ static int msp3400c_thread(void *data) goto restart; } - LOCK_I2C_BUS(msp->bus); - val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b); + val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); if (val1 < val) val1 = val, max1 = this; dprintk("msp3400: carrier1 val: %5d / %s\n", val,cd[this].name); } + + if (amsound) { + /* autodetect does'nt work well with AM ... */ + max1 = 3; + dprintk("msp3400: AM sound override\n"); + } /* carrier detect pass #2 -- second (stereo) carrier */ switch (max1) { @@ -714,8 +756,7 @@ static int msp3400c_thread(void *data) break; } for (this = 0; this < count; this++) { - msp3400c_setcarrier(msp->bus, cd[this].cdo,cd[this].cdo); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/25); @@ -726,8 +767,7 @@ static int msp3400c_thread(void *data) goto restart; } - LOCK_I2C_BUS(msp->bus); - val = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b); + val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b); if (val2 < val) val2 = val, max2 = this; dprintk("msp3400: carrier2 val: %5d / %s\n", val,cd[this].name); @@ -740,16 +780,16 @@ static int msp3400c_thread(void *data) if (max2 == 0) { /* B/G FM-stereo */ msp->second = carrier_detect_55[max2].cdo; - msp3400c_setmode(msp, MSP_MODE_FM_TERRA); + msp3400c_setmode(client, MSP_MODE_FM_TERRA); msp->nicam_on = 0; - msp3400c_setstereo(msp, VIDEO_SOUND_MONO); + msp3400c_setstereo(client, VIDEO_SOUND_MONO); msp->watch_stereo = 1; } else if (max2 == 1 && msp->nicam) { /* B/G NICAM */ msp->second = carrier_detect_55[max2].cdo; - msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); + msp3400c_setmode(client, MSP_MODE_FM_NICAM1); msp->nicam_on = 1; - msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp3400c_setcarrier(client, msp->second, msp->main); msp->watch_stereo = 1; } else { goto no_second; @@ -758,25 +798,33 @@ static int msp3400c_thread(void *data) case 2: /* 6.0 */ /* PAL I NICAM */ msp->second = MSP_CARRIER(6.552); - msp3400c_setmode(msp, MSP_MODE_FM_NICAM2); + msp3400c_setmode(client, MSP_MODE_FM_NICAM2); msp->nicam_on = 1; - msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp3400c_setcarrier(client, msp->second, msp->main); msp->watch_stereo = 1; break; case 3: /* 6.5 */ if (max2 == 1 || max2 == 2) { /* D/K FM-stereo */ msp->second = carrier_detect_65[max2].cdo; - msp3400c_setmode(msp, MSP_MODE_FM_TERRA); + msp3400c_setmode(client, MSP_MODE_FM_TERRA); msp->nicam_on = 0; - msp3400c_setstereo(msp, VIDEO_SOUND_MONO); + msp3400c_setstereo(client, VIDEO_SOUND_MONO); + msp->watch_stereo = 1; + } else if (max2 == 0 && msp->nicam && + msp->norm == VIDEO_MODE_SECAM) { + /* L NICAM */ + msp->second = carrier_detect_65[max2].cdo; + msp3400c_setmode(client, MSP_MODE_AM_NICAM); + msp->nicam_on = 1; + msp3400c_setcarrier(client, msp->second, msp->main); msp->watch_stereo = 1; } else if (max2 == 0 && msp->nicam) { /* D/K NICAM */ msp->second = carrier_detect_65[max2].cdo; - msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); + msp3400c_setmode(client, MSP_MODE_FM_NICAM1); msp->nicam_on = 1; - msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp3400c_setcarrier(client, msp->second, msp->main); msp->watch_stereo = 1; } else { goto no_second; @@ -786,17 +834,16 @@ static int msp3400c_thread(void *data) default: no_second: msp->second = carrier_detect_main[max1].cdo; - msp3400c_setmode(msp, MSP_MODE_FM_TERRA); + msp3400c_setmode(client, MSP_MODE_FM_TERRA); msp->nicam_on = 0; - msp3400c_setcarrier(msp->bus, msp->second, msp->main); + msp3400c_setcarrier(client, msp->second, msp->main); msp->stereo = VIDEO_SOUND_MONO; - msp3400c_setstereo(msp, VIDEO_SOUND_MONO); + msp3400c_setstereo(client, VIDEO_SOUND_MONO); break; } /* unmute */ - msp3400c_setvolume(msp->bus, msp->left, msp->right); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setvolume(client, msp->left, msp->right); if (msp->watch_stereo) { del_timer(&msp->wake_stereo); @@ -820,85 +867,208 @@ done: return 0; } -#if 0 /* not finished yet */ +/* ----------------------------------------------------------------------- */ +/* this one uses the automatic sound standard detection of newer */ +/* msp34xx chip versions */ +static struct MODES { + int retval; + int main, second; + char *name; +} modelist[] = { + { 0x0000, 0, 0, "ERROR" }, + { 0x0001, 0, 0, "autodetect start" }, + { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, + { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, + { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, + { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, + { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, + { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, + { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, + { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, + { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, + { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, + { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, + { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, + { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, + { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, + { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, + { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, + { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, + { -1, 0, 0, NULL }, /* EOF */ +}; + static int msp3410d_thread(void *data) { - unsigned long flags; - struct msp3400c *msp = data; - DECLARE_MUTEX_LOCKED(sem); - int i, val; - - /* lock_kernel(); */ + struct i2c_client *client = data; + struct msp3400c *msp = client->data; + int mode,val,i,std; + +#ifdef __SMP__ + lock_kernel(); +#endif exit_mm(current); current->session = 1; current->pgrp = 1; sigfillset(¤t->blocked); current->fs->umask = 0; - strcpy(current->comm,"msp3410 (nicam)"); + strcpy(current->comm,"msp3410 [auto]"); - msp->wait = &sem; msp->thread = current; - /* unlock_kernel(); */ +#ifdef __SMP__ + unlock_kernel(); +#endif - dprintk("msp3410: thread: start\n"); + printk("msp3410: daemon started\n"); if(msp->notify != NULL) up(msp->notify); for (;;) { if (msp->rmmod) goto done; - dprintk("msp3410: thread: sleep\n"); - down_interruptible(&sem); - dprintk("msp3410: thread: wakeup\n"); - if (msp->rmmod) + if (debug > 1) + printk("msp3410: thread: sleep\n"); + interruptible_sleep_on(&msp->wq); + if (debug > 1) + printk("msp3410: thread: wakeup\n"); + if (msp->rmmod || signal_pending(current)) goto done; - + if (VIDEO_MODE_RADIO == msp->norm) continue; /* nothing to do */ msp->active = 1; - restart: - LOCK_I2C_BUS(msp->bus); - /* mute */ - msp3400c_setvolume(msp->bus, 0); - /* quick & dirty hack: - get the audio proccessor into some useful state */ - msp3400c_setmode(msp, MSP_MODE_FM_NICAM1); - /* kick autodetect */ - msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x20, 0x01); - msp3400c_write(msp->bus, I2C_MSP3400C_DFP, 0x21, 0x01); - UNLOCK_I2C_BUS(msp->bus); - - /* wait 1 sec */ - __set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ); - if (signal_pending(current)) - goto done; - if (msp->restart) { - msp->restart = 0; - goto restart; + if (msp->watch_stereo) { +#if 1 /* dump status register */ + val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200); + printk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n", + val, + (val & 0x0002) ? "no" : "yes", + (val & 0x0004) ? "no" : "yes", + (val & 0x0040) ? "stereo" : "mono", + (val & 0x0080) ? ", nicam 2nd mono" : "", + (val & 0x0100) ? ", bilingual/SAP" : ""); + msp->watch_stereo = 0; +#else + watch_stereo(msp); +#endif + msp->active = 0; + continue; } - LOCK_I2C_BUS(msp->bus); - /* debug register dump */ - for (i = 0; i < sizeof(d1)/sizeof(struct REGISTER_DUMP); i++) { - val = msp3400c_read(msp->bus,I2C_MSP3400C_DEM,d1[i].addr); - printk(KERN_DEBUG "msp3400: %s = 0x%x\n",d1[i].name,val); - } + restart: + del_timer(&msp->wake_stereo); + msp->watch_stereo = 0; + + /* put into sane state (and mute) */ + msp3400c_reset(client); + + /* start autodetect */ + switch (msp->norm) { + case VIDEO_MODE_PAL: + mode = 0x1003; + std = 1; + break; + case VIDEO_MODE_NTSC: /* BTSC */ + mode = 0x2003; + std = 0x0020; + break; + case VIDEO_MODE_SECAM: + default: + mode = 0x0003; + std = 1; + break; + } + msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, mode); + msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, std); + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); + msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); + if (debug) { + int i; + for (i = 0; modelist[i].name != NULL; i++) + if (modelist[i].retval == std) + break; + printk("msp3410: setting mode: %s (0x%04x)\n", + modelist[i].name ? modelist[i].name : "unknown",std); + } + + if (std != 1) { + /* programmed some specific mode */ + val = std; + } else { + /* triggered autodetect */ + for (;;) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/10); + if (signal_pending(current)) + goto done; + if (msp->restart) { + msp->restart = 0; + goto restart; + } + + /* check results */ + val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e); + if (val < 0x07ff) + break; + dprintk("msp3410: detection still in progress\n"); + } + } + for (i = 0; modelist[i].name != NULL; i++) + if (modelist[i].retval == val) + break; + if (debug) + printk("msp3410: current mode: %s (0x%04x)\n", + modelist[i].name ? modelist[i].name : "unknown", + val); + msp->main = modelist[i].main; + msp->second = modelist[i].second; + + /* set prescale / stereo */ + switch (val) { + case 0x0009: + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x7c03); /* AM */ + msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* NICAM */ + break; + case 0x0020: /* BTSC */ + /* just turn on stereo */ + msp->mode = MSP_MODE_BTSC; + msp->stereo = VIDEO_SOUND_STEREO; + msp->watch_stereo = 1; + msp3400c_setstereo(client,VIDEO_SOUND_STEREO); + /* set prescale */ + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ + break; + case 0x0003: + msp->mode = MSP_MODE_FM_TERRA; + msp->stereo = VIDEO_SOUND_MONO; + msp->watch_stereo = 1; + /* fall */ + default: + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM */ + msp3400c_write(client, I2C_MSP3400C_DFP, 0x10, 0x5a00); /* NICAM */ + break; + } + /* unmute */ - msp3400c_setvolume(msp->bus, msp->volume); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setbass(client, msp->bass); + msp3400c_settreble(client, msp->treble); + msp3400c_setvolume(client, msp->left, msp->right); + + if (msp->watch_stereo) { + del_timer(&msp->wake_stereo); + msp->wake_stereo.expires = jiffies + HZ; + add_timer(&msp->wake_stereo); + } msp->active = 0; } done: dprintk("msp3410: thread: exit\n"); - msp->wait = NULL; msp->active = 0; msp->thread = NULL; @@ -906,23 +1076,17 @@ done: up(msp->notify); return 0; } -#endif /* ----------------------------------------------------------------------- */ /* mixer stuff -- with the modular sound driver in 2.1.x we can easily */ /* register the msp3400 as mixer device */ -#ifdef REGISTER_MIXER +#ifdef REGISTER_MIXER #include <linux/sound.h> #include <linux/soundcard.h> #include <asm/uaccess.h> -static struct msp3400c *mspmix = NULL; /* ugly hack, should do something more sensible */ -static int mixer_num; -static int mixer_modcnt = 0; -static DECLARE_MUTEX(mixer_sem); - static int mix_to_v4l(int i) { int r; @@ -957,14 +1121,22 @@ static int v4l_to_mix2(int l, int r) static int msp3400c_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { + struct i2c_client *client; + struct msp3400c *msp; int ret,val = 0; - LOCK_FLAGS; + client = file->private_data; + if (!client) + return -ENODEV; + msp = client->data; + if (!msp) + return -ENODEV; + if (cmd == SOUND_MIXER_INFO) { mixer_info info; strncpy(info.id, "MSP3400", sizeof(info.id)); strncpy(info.name, "MSP 3400", sizeof(info.name)); - info.modify_counter = mixer_modcnt; + info.modify_counter = msp->mixer_modcnt; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; @@ -984,12 +1156,6 @@ msp3400c_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u if (get_user(val, (int *)arg)) return -EFAULT; - down(&mixer_sem); - if (!mspmix) { - up(&mixer_sem); - return -ENODEV; - } - switch (cmd) { case MIXER_READ(SOUND_MIXER_RECMASK): case MIXER_READ(SOUND_MIXER_CAPS): @@ -1006,44 +1172,36 @@ msp3400c_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u break; case MIXER_WRITE(SOUND_MIXER_VOLUME): - mspmix->left = mix_to_v4l(val); - mspmix->right = mix_to_v4l(val >> 8); - LOCK_I2C_BUS(mspmix->bus); - msp3400c_setvolume(mspmix->bus,mspmix->left,mspmix->right); - UNLOCK_I2C_BUS(mspmix->bus); - mixer_modcnt++; + msp->left = mix_to_v4l(val); + msp->right = mix_to_v4l(val >> 8); + msp3400c_setvolume(client,msp->left,msp->right); + msp->mixer_modcnt++; /* fall */ case MIXER_READ(SOUND_MIXER_VOLUME): - ret = v4l_to_mix2(mspmix->left, mspmix->right); + ret = v4l_to_mix2(msp->left, msp->right); break; case MIXER_WRITE(SOUND_MIXER_BASS): - mspmix->bass = mix_to_v4l(val); - LOCK_I2C_BUS(mspmix->bus); - msp3400c_setbass(mspmix->bus,mspmix->bass); - UNLOCK_I2C_BUS(mspmix->bus); - mixer_modcnt++; + msp->bass = mix_to_v4l(val); + msp3400c_setbass(client,msp->bass); + msp->mixer_modcnt++; /* fall */ case MIXER_READ(SOUND_MIXER_BASS): - ret = v4l_to_mix(mspmix->bass); + ret = v4l_to_mix(msp->bass); break; case MIXER_WRITE(SOUND_MIXER_TREBLE): - mspmix->treble = mix_to_v4l(val); - LOCK_I2C_BUS(mspmix->bus); - msp3400c_settreble(mspmix->bus,mspmix->treble); - UNLOCK_I2C_BUS(mspmix->bus); - mixer_modcnt++; + msp->treble = mix_to_v4l(val); + msp3400c_settreble(client,msp->treble); + msp->mixer_modcnt++; /* fall */ case MIXER_READ(SOUND_MIXER_TREBLE): - ret = v4l_to_mix(mspmix->treble); + ret = v4l_to_mix(msp->treble); break; default: - up(&mixer_sem); return -EINVAL; } - up(&mixer_sem); if (put_user(ret, (int *)arg)) return -EFAULT; return 0; @@ -1052,6 +1210,21 @@ msp3400c_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u static int msp3400c_mixer_open(struct inode *inode, struct file *file) { + int minor = MINOR(inode->i_rdev); + struct msp3400c *msp; + int i; + + /* search for the right one... */ + for (i = 0; i < MSP3400_MAX; i++) { + msp = msps[i]->data; + if (msp->mixer_num == minor) { + file->private_data = msps[i]; + break; + } + } + if (MSP3400_MAX == i) + return -ENODEV; + MOD_INC_USE_COUNT; return 0; } @@ -1069,7 +1242,7 @@ msp3400c_mixer_llseek(struct file *file, loff_t offset, int origin) return -ESPIPE; } -static /*const*/ struct file_operations msp3400c_mixer_fops = { +static struct file_operations msp3400c_mixer_fops = { msp3400c_mixer_llseek, NULL, /* read */ NULL, /* write */ @@ -1082,8 +1255,6 @@ static /*const*/ struct file_operations msp3400c_mixer_fops = { msp3400c_mixer_release, NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ NULL, /* lock */ }; @@ -1091,36 +1262,72 @@ static /*const*/ struct file_operations msp3400c_mixer_fops = { /* ----------------------------------------------------------------------- */ -static int msp3400c_attach(struct i2c_device *device) +static int msp_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind); +static int msp_detach(struct i2c_client *client); +static int msp_probe(struct i2c_adapter *adap); +static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg); + +static struct i2c_driver driver = { + "i2c msp3400 driver", + I2C_DRIVERID_MSP3400, + I2C_DF_NOTIFY, + msp_probe, + msp_detach, + msp_command, +}; + +static struct i2c_client client_template = +{ + "unset", + -1, + 0, + 0, + NULL, + &driver +}; + +static int msp_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) { DECLARE_MUTEX_LOCKED(sem); struct msp3400c *msp; - int rev1,rev2; - LOCK_FLAGS; + struct i2c_client *c; + int rev1,rev2,i; - device->data = msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL); - if (NULL == msp) + client_template.adapter = adap; + client_template.addr = addr; + + if (-1 == msp3400c_reset(&client_template)) { + dprintk("msp3400: no chip found\n"); + return -1; + } + + if (NULL == (c = kmalloc(sizeof(struct i2c_client),GFP_KERNEL))) + return -ENOMEM; + memcpy(c,&client_template,sizeof(struct i2c_client)); + if (NULL == (msp = kmalloc(sizeof(struct msp3400c),GFP_KERNEL))) { + kfree(c); return -ENOMEM; + } + memset(msp,0,sizeof(struct msp3400c)); - msp->bus = device->bus; msp->left = 65535; msp->right = 65535; msp->bass = 32768; msp->treble = 32768; + c->data = msp; init_waitqueue_head(&msp->wq); - LOCK_I2C_BUS(msp->bus); - if (-1 == msp3400c_reset(msp->bus)) { - UNLOCK_I2C_BUS(msp->bus); + if (-1 == msp3400c_reset(c)) { kfree(msp); dprintk("msp3400: no chip found\n"); return -1; } - rev1 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1e); - rev2 = msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1f); + rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e); + rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f); if (0 == rev1 && 0 == rev2) { - UNLOCK_I2C_BUS(msp->bus); kfree(msp); printk("msp3400: error while reading chip version\n"); return -1; @@ -1128,48 +1335,67 @@ static int msp3400c_attach(struct i2c_device *device) #if 0 /* this will turn on a 1kHz beep - might be useful for debugging... */ - msp3400c_write(msp->bus,I2C_MSP3400C_DFP, 0x0014, 0x1040); + msp3400c_write(client,I2C_MSP3400C_DFP, 0x0014, 0x1040); #endif - UNLOCK_I2C_BUS(msp->bus); - sprintf(device->name,"MSP34%02d%c-%c%d", + sprintf(c->name,"MSP34%02d%c-%c%d", (rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f); msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0; + if (simple == -1) { + /* default mode */ + msp->simple = 0; + } else { + /* use insmod option */ + msp->simple = simple; + } + /* timer for stereo checking */ msp->wake_stereo.function = msp3400c_stereo_wake; msp->wake_stereo.data = (unsigned long)msp; + /* hello world :-) */ + printk(KERN_INFO "msp3400: init: chip=%s",c->name); + if (msp->nicam) + printk(", has NICAM support"); + printk("\n"); + /* startup control thread */ MOD_INC_USE_COUNT; msp->notify = &sem; - kernel_thread(msp3400c_thread, (void *)msp, 0); + kernel_thread(msp->simple ? msp3410d_thread : msp3400c_thread, + (void *)c, 0); down(&sem); msp->notify = NULL; wake_up_interruptible(&msp->wq); - printk(KERN_INFO "msp3400: init: chip=%s",device->name); - if (msp->nicam) - printk(", has NICAM support"); #ifdef REGISTER_MIXER - down(&mixer_sem); - mspmix = msp; - up(&mixer_sem); + if ((msp->mixer_num = register_sound_mixer(&msp3400c_mixer_fops,mixer)) < 0) + printk(KERN_ERR "msp3400c: cannot allocate mixer device\n"); #endif - printk("\n"); + + /* update our own array */ + for (i = 0; i < MSP3400_MAX; i++) { + if (NULL == msps[i]) { + msps[i] = c; + break; + } + } + + /* done */ + i2c_attach_client(c); return 0; } -static int msp3400c_detach(struct i2c_device *device) +static int msp_detach(struct i2c_client *client) { DECLARE_MUTEX_LOCKED(sem); - struct msp3400c *msp = (struct msp3400c*)device->data; - LOCK_FLAGS; - + struct msp3400c *msp = (struct msp3400c*)client->data; + int i; + #ifdef REGISTER_MIXER - down(&mixer_sem); - mspmix = NULL; - up(&mixer_sem); + if (msp->mixer_num >= 0) + unregister_sound_mixer(msp->mixer_num); #endif /* shutdown control thread */ @@ -1182,47 +1408,143 @@ static int msp3400c_detach(struct i2c_device *device) down(&sem); msp->notify = NULL; } - - LOCK_I2C_BUS(msp->bus); - msp3400c_reset(msp->bus); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_reset(client); + /* update our own array */ + for (i = 0; i < MSP3400_MAX; i++) { + if (client == msps[i]) { + msps[i] = NULL; + break; + } + } + + i2c_detach_client(client); kfree(msp); + kfree(client); MOD_DEC_USE_COUNT; return 0; } -static int msp3400c_command(struct i2c_device *device, - unsigned int cmd, void *arg) +static int msp_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, msp_attach); + return 0; +} + +static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg) { - struct msp3400c *msp = (struct msp3400c*)device->data; + struct msp3400c *msp = (struct msp3400c*)client->data; +#if 0 int *iarg = (int*)arg; __u16 *sarg = arg; - LOCK_FLAGS; +#endif switch (cmd) { - case MSP_SET_RADIO: + + case AUDC_SET_RADIO: msp->norm = VIDEO_MODE_RADIO; msp->watch_stereo=0; del_timer(&msp->wake_stereo); - LOCK_I2C_BUS(msp->bus); - msp3400c_setmode(msp,MSP_MODE_FM_RADIO); - msp3400c_setcarrier(msp->bus, MSP_CARRIER(10.7),MSP_CARRIER(10.7)); - msp3400c_setvolume(msp->bus,msp->left, msp->right); - UNLOCK_I2C_BUS(msp->bus); + if (msp->simple) { + msp3400c_reset(client); + msp3400c_write(client, I2C_MSP3400C_DEM, 0x30, 0x0003); /* automatic */ + msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, 0x0040); /* FM Radio */ + msp3400c_write(client, I2C_MSP3400C_DFP, 0x0e, 0x2403); /* FM prescale */ + msp3400c_setbass(client, msp->bass); + msp3400c_settreble(client, msp->treble); + msp3400c_setvolume(client, msp->left, msp->right); + } else { + msp3400c_setmode(client,MSP_MODE_FM_RADIO); + msp3400c_setcarrier(client, MSP_CARRIER(10.7),MSP_CARRIER(10.7)); + msp3400c_setvolume(client,msp->left, msp->right); + } + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + va->volume=MAX(msp->left,msp->right); + va->balance=(32768*MIN(msp->left,msp->right))/ + (va->volume ? va->volume : 1); + va->balance=(msp->left<msp->right)? + (65535-va->balance) : va->balance; + va->bass = msp->bass; + va->treble = msp->treble; + + if (msp->simple) { + /* fixme */ + } else { + autodetect_stereo(client); + va->mode = msp->stereo; + } + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + msp->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + msp->right = (MIN(va->balance,32768) * + va->volume) / 32768; + msp->bass = va->bass; + msp->treble = va->treble; + msp3400c_setvolume(client,msp->left, msp->right); + msp3400c_setbass(client,msp->bass); + msp3400c_settreble(client,msp->treble); + + if (msp->simple) { + /* fixme */ + } else if (va->mode != 0) { + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + msp->stereo = va->mode; + msp3400c_setstereo(client,va->mode); + } break; - case MSP_SET_TVNORM: + } + case VIDIOCSCHAN: + { + struct video_channel *vc = arg; + + msp->norm = vc->norm; + break; + } + case VIDIOCSFREQ: + { + /* new channel -- kick audio carrier scan */ + msp3400c_setvolume(client,0,0); + msp->watch_stereo=0; + del_timer(&msp->wake_stereo); + if (msp->active) + msp->restart = 1; + wake_up_interruptible(&msp->wq); + break; + } + + /* --- v4l2 ioctls --- */ + /* NOT YET */ + +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_SET_TVNORM: msp->norm = *iarg; break; - case MSP_SWITCH_MUTE: + case AUDC_SWITCH_MUTE: /* channels switching step one -- mute */ msp->watch_stereo=0; del_timer(&msp->wake_stereo); - LOCK_I2C_BUS(msp->bus); - msp3400c_setvolume(msp->bus,0,0); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setvolume(client,0,0); break; - case MSP_NEWCHANNEL: + case AUDC_NEWCHANNEL: /* channels switching step two -- trigger sound carrier scan */ msp->watch_stereo=0; del_timer(&msp->wake_stereo); @@ -1231,96 +1553,85 @@ static int msp3400c_command(struct i2c_device *device, wake_up_interruptible(&msp->wq); break; - case MSP_GET_VOLUME: - *sarg = (msp->left > msp->right) ? msp->left : msp->right; + case AUDC_GET_VOLUME_LEFT: + *sarg = msp->left; break; - case MSP_SET_VOLUME: - msp->left = msp->right = *sarg; - LOCK_I2C_BUS(msp->bus); - msp3400c_setvolume(msp->bus,msp->left, msp->right); - UNLOCK_I2C_BUS(msp->bus); + case AUDC_GET_VOLUME_RIGHT: + *sarg = msp->right; + break; + case AUDC_SET_VOLUME_LEFT: + msp->left = *sarg; + msp3400c_setvolume(client,msp->left, msp->right); + break; + case AUDC_SET_VOLUME_RIGHT: + msp->right = *sarg; + msp3400c_setvolume(client,msp->left, msp->right); break; - case MSP_GET_BASS: + case AUDC_GET_BASS: *sarg = msp->bass; break; - case MSP_SET_BASS: + case AUDC_SET_BASS: msp->bass = *sarg; - LOCK_I2C_BUS(msp->bus); - msp3400c_setbass(msp->bus,msp->bass); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_setbass(client,msp->bass); break; - case MSP_GET_TREBLE: + case AUDC_GET_TREBLE: *sarg = msp->treble; break; - case MSP_SET_TREBLE: + case AUDC_SET_TREBLE: msp->treble = *sarg; - LOCK_I2C_BUS(msp->bus); - msp3400c_settreble(msp->bus,msp->treble); - UNLOCK_I2C_BUS(msp->bus); + msp3400c_settreble(client,msp->treble); break; - case MSP_GET_STEREO: - *sarg = msp->stereo; + case AUDC_GET_STEREO: + if (msp->simple) { + *sarg = 0; /* fixme */ + } else { + autodetect_stereo(client); + *sarg = msp->stereo; + } break; - case MSP_SET_STEREO: + case AUDC_SET_STEREO: + if (msp->simple) + break; /* fixme */ if (*sarg) { msp->watch_stereo=0; del_timer(&msp->wake_stereo); - LOCK_I2C_BUS(msp->bus); - msp3400c_setstereo(msp,*sarg); - UNLOCK_I2C_BUS(msp->bus); + msp->stereo = *sarg; + msp3400c_setstereo(client,*sarg); } break; - case MSP_GET_DC: - LOCK_I2C_BUS(msp->bus); - *sarg = ((int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1b) + - (int)msp3400c_read(msp->bus, I2C_MSP3400C_DFP, 0x1c)); - UNLOCK_I2C_BUS(msp->bus); + case AUDC_GET_DC: + if (msp->simple) + break; /* fixme */ + *sarg = ((int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b) + + (int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1c)); break; - +#endif default: - return -EINVAL; + /* nothing */ } return 0; } /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_msp = { - "msp3400", /* name */ - I2C_DRIVERID_MSP3400, /* ID */ - I2C_MSP3400C, I2C_MSP3400C, /* addr range */ - - msp3400c_attach, - msp3400c_detach, - msp3400c_command -}; - #ifdef MODULE int init_module(void) #else - int msp3400c_init(void) +int msp3400c_init(void) #endif { - i2c_register_driver(&i2c_driver_msp); -#ifdef REGISTER_MIXER - if ((mixer_num = register_sound_mixer(&msp3400c_mixer_fops, -1)) < 0) - printk(KERN_ERR "msp3400c: cannot allocate mixer device\n"); -#endif + i2c_add_driver(&driver); return 0; } #ifdef MODULE void cleanup_module(void) { - i2c_unregister_driver(&i2c_driver_msp); -#ifdef REGISTER_MIXER - if (mixer_num >= 0) - unregister_sound_mixer(mixer_num); -#endif + i2c_del_driver(&driver); } #endif @@ -1331,3 +1642,4 @@ void cleanup_module(void) * c-basic-offset: 8 * End: */ + diff --git a/drivers/char/msp3400.h b/drivers/char/msp3400.h deleted file mode 100644 index 7f0ba30e5..000000000 --- a/drivers/char/msp3400.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef MSP3400_H -#define MSP3400_H - -/* ---------------------------------------------------------------------- */ - -#define MSP_SET_TVNORM _IOW('m',1,int) /* TV mode + PAL/SECAM/NTSC */ -#define MSP_SET_RADIO _IO('m',2) /* Radio mode */ -#define MSP_NEWCHANNEL _IO('m',3) /* indicate new channel */ - -#define MSP_GET_VOLUME _IOR('m',4,__u16) -#define MSP_SET_VOLUME _IOW('m',5,__u16) - -#define MSP_GET_STEREO _IOR('m',6,__u16) -#define MSP_SET_STEREO _IOW('m',7,__u16) - -#define MSP_GET_DC _IOW('m',8,__u16) - -#define MSP_GET_BASS _IOR('m', 9,__u16) -#define MSP_SET_BASS _IOW('m',10,__u16) -#define MSP_GET_TREBLE _IOR('m',11,__u16) -#define MSP_SET_TREBLE _IOW('m',12,__u16) - -#define MSP_GET_UNIT _IOR('m',13,int) -#define MSP_SWITCH_MUTE _IO('m',14) -#endif /* MSP3400_H */ diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index b4f50243e..710c5fca9 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -9,7 +9,7 @@ * Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au> * * Original release 01/11/99 - * ==FILEDATE 19990901== + * ==FILEDATE 19991217== * * This code is released under the GNU General Public License (GPL) * @@ -78,7 +78,7 @@ */ #define HDLC_MAGIC 0x239e -#define HDLC_VERSION "1.11" +#define HDLC_VERSION "1.13" #include <linux/version.h> #include <linux/config.h> @@ -171,6 +171,7 @@ do { \ #if LINUX_VERSION_CODE < VERSION(2,1,0) #define __init typedef int spinlock_t; +#define spin_lock_init(a) #define spin_lock_irqsave(a,b) {save_flags((b));cli();} #define spin_unlock_irqrestore(a,b) {restore_flags((b));} #define spin_lock(a) @@ -659,8 +660,11 @@ static void n_hdlc_tty_receive(struct tty_struct *tty, /* wake up any blocked reads and perform async signalling */ wake_up_interruptible (&n_hdlc->read_wait); if (n_hdlc->tty->fasync != NULL) +#if LINUX_VERSION_CODE < VERSION(2,3,0) + kill_fasync (n_hdlc->tty->fasync, SIGIO); +#else kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN); - +#endif } /* end of n_hdlc_tty_receive() */ /* n_hdlc_tty_read() @@ -1072,7 +1076,7 @@ static struct n_hdlc *n_hdlc_alloc (void) void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list) { memset(list,0,sizeof(N_HDLC_BUF_LIST)); - + spin_lock_init(&list->spinlock); } /* end of n_hdlc_buf_list_init() */ /* n_hdlc_buf_put() diff --git a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c index 88e29e5b9..6b5c3a803 100644 --- a/drivers/char/pc110pad.c +++ b/drivers/char/pc110pad.c @@ -639,8 +639,6 @@ static struct file_operations pad_fops = { close_pad, NULL, /* fsync */ fasync_pad, - NULL, /* check_media_change */ - NULL, /* revalidate */ NULL /* lock */ }; diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c index 0841df811..5287ec93d 100644 --- a/drivers/char/pc_keyb.c +++ b/drivers/char/pc_keyb.c @@ -412,6 +412,15 @@ static inline void handle_mouse_event(unsigned char scancode) #endif } +static inline void handle_keyboard_event(unsigned char scancode) +{ +#ifdef CONFIG_VT + if (do_acknowledge(scancode)) + handle_scancode(scancode, !(scancode & 0x80)); +#endif + mark_bh(KEYBOARD_BH); +} + /* * This reads the keyboard status port, and does the * appropriate action. @@ -428,20 +437,18 @@ static unsigned char handle_kbd_event(void) unsigned char scancode; scancode = kbd_read_input(); - if (status & KBD_STAT_MOUSE_OBF) { - handle_mouse_event(scancode); - } else { -#ifdef CONFIG_VT - if (do_acknowledge(scancode)) - handle_scancode(scancode, !(scancode & 0x80)); -#endif - mark_bh(KEYBOARD_BH); + + /* Ignore error bytes */ + if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR))) { + if (status & KBD_STAT_MOUSE_OBF) + handle_mouse_event(scancode); + else + handle_keyboard_event(scancode); } status = kbd_read_status(); - if(!work--) - { + if (!--work) { printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", status); break; @@ -739,6 +746,10 @@ static int __init detect_auxiliary_port(void) int loops = 10; int retval = 0; + /* Check if the BIOS detected a device on the auxiliary port. */ + if (aux_device_present == 0xaa) + return 1; + spin_lock_irqsave(&kbd_controller_lock, flags); /* Put the value 0x5A in the output buffer using the "Write diff --git a/drivers/char/pcmcia/Config.in b/drivers/char/pcmcia/Config.in index 88545b788..7a32e5d55 100644 --- a/drivers/char/pcmcia/Config.in +++ b/drivers/char/pcmcia/Config.in @@ -5,22 +5,19 @@ mainmenu_option next_comment comment 'PCMCIA character device support' -if [ "$CONFIG_SERIAL" = "y" ]; then - dep_tristate ' PCMCIA serial device support' \ - CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA - if [ "$CONFIG_CARDBUS" = "y" ]; then - dep_tristate ' CardBus serial device support' \ - CONFIG_PCMCIA_SERIAL_CB $CONFIG_PCMCIA +if [ "$CONFIG_SERIAL" = "n" -o "$CONFIG_PCMCIA" = "n" ]; then + define_bool CONFIG_PCMCIA_SERIAL n +else + if [ "$CONFIG_SERIAL" = "m" -o "$CONFIG_PCMCIA" = "m" ]; then + define_bool CONFIG_PCMCIA_SERIAL m + else + define_bool CONFIG_PCMCIA_SERIAL y fi fi -if [ "$CONFIG_SERIAL" = "m" ]; then - dep_tristate ' PCMCIA serial device support' \ - CONFIG_PCMCIA_SERIAL_CS m - if [ "$CONFIG_CARDBUS" = "y" ]; then - dep_tristate ' CardBus serial device support' \ - CONFIG_PCMCIA_SERIAL_CB m - fi +dep_tristate ' PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA_SERIAL +if [ "$CONFIG_CARDBUS" = "y" ]; then + dep_tristate ' CardBus serial device support' CONFIG_PCMCIA_SERIAL_CB $CONFIG_PCMCIA_SERIAL fi if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" -o \ diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c index fa69f138f..10d059278 100644 --- a/drivers/char/pcwd.c +++ b/drivers/char/pcwd.c @@ -582,8 +582,6 @@ static struct file_operations pcwd_fops = { pcwd_close, /* Release */ NULL, /* Fsync */ NULL, /* Fasync */ - NULL, /* CheckMediaChange */ - NULL, /* Revalidate */ NULL, /* Lock */ }; diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 71bb3a18c..858b9a1e0 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -50,7 +50,7 @@ #include <linux/ctype.h> #include <linux/poll.h> #include <asm/uaccess.h> -#include "ppdev.h" +#include <linux/ppdev.h> #define PP_VERSION "ppdev: user-space parallel port driver" #define CHRDEV "ppdev" diff --git a/drivers/char/ppdev.h b/drivers/char/ppdev.h deleted file mode 100644 index f466f11e6..000000000 --- a/drivers/char/ppdev.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * linux/drivers/char/ppdev.h - * - * User-space parallel port device driver (header file). - * - * Copyright (C) 1998-9 Tim Waugh <tim@cyberelk.demon.co.uk> - * - * 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. - * - * Added PPGETTIME/PPSETTIME, Fred Barnes, 1999 - */ - -#define PP_MAJOR 99 - -#define PP_IOCTL 'p' - -/* Set mode for read/write (e.g. IEEE1284_MODE_EPP) */ -#define PPSETMODE _IOW(PP_IOCTL, 0x80, int) - -/* Read status */ -#define PPRSTATUS _IOR(PP_IOCTL, 0x81, unsigned char) -#define PPWSTATUS OBSOLETE__IOW(PP_IOCTL, 0x82, unsigned char) - -/* Read/write control */ -#define PPRCONTROL _IOR(PP_IOCTL, 0x83, unsigned char) -#define PPWCONTROL _IOW(PP_IOCTL, 0x84, unsigned char) - -struct ppdev_frob_struct { - unsigned char mask; - unsigned char val; -}; -#define PPFCONTROL _IOW(PP_IOCTL, 0x8e, struct ppdev_frob_struct) - -/* Read/write data */ -#define PPRDATA _IOR(PP_IOCTL, 0x85, unsigned char) -#define PPWDATA _IOW(PP_IOCTL, 0x86, unsigned char) - -/* Read/write econtrol (not used) */ -#define PPRECONTROL OBSOLETE__IOR(PP_IOCTL, 0x87, unsigned char) -#define PPWECONTROL OBSOLETE__IOW(PP_IOCTL, 0x88, unsigned char) - -/* Read/write FIFO (not used) */ -#define PPRFIFO OBSOLETE__IOR(PP_IOCTL, 0x89, unsigned char) -#define PPWFIFO OBSOLETE__IOW(PP_IOCTL, 0x8a, unsigned char) - -/* Claim the port to start using it */ -#define PPCLAIM _IO(PP_IOCTL, 0x8b) - -/* Release the port when you aren't using it */ -#define PPRELEASE _IO(PP_IOCTL, 0x8c) - -/* Yield the port (release it if another driver is waiting, - * then reclaim) */ -#define PPYIELD _IO(PP_IOCTL, 0x8d) - -/* Register device exclusively (must be before PPCLAIM). */ -#define PPEXCL _IO(PP_IOCTL, 0x8f) - -/* Data line direction: non-zero for input mode. */ -#define PPDATADIR _IOW(PP_IOCTL, 0x90, int) - -/* Negotiate a particular IEEE 1284 mode. */ -#define PPNEGOT _IOW(PP_IOCTL, 0x91, int) - -/* Set control lines when an interrupt occurs. */ -#define PPWCTLONIRQ _IOW(PP_IOCTL, 0x92, unsigned char) - -/* Clear (and return) interrupt count. */ -#define PPCLRIRQ _IOR(PP_IOCTL, 0x93, int) - -/* Set the IEEE 1284 phase that we're in (e.g. IEEE1284_PH_FWD_IDLE) */ -#define PPSETPHASE _IOW(PP_IOCTL, 0x94, int) - -/* Set and get port timeout (struct timeval's) */ -#define PPGETTIME _IOR(PP_IOCTL, 0x95, struct timeval) -#define PPSETTIME _IOW(PP_IOCTL, 0x96, struct timeval) - - diff --git a/drivers/char/random.c b/drivers/char/random.c index d97304a13..31fe71317 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1936,7 +1936,7 @@ static __u32 halfMD4Transform (__u32 const buf[4], __u32 const in[8]) /* Alternative: return sum of all words? */ } -#if 0 /* May be needed for IPv6 */ +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]) { @@ -2001,6 +2001,59 @@ static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]) #define REKEY_INTERVAL 300 #define HASH_BITS 24 +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +__u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr, + __u16 sport, __u16 dport) +{ + static __u32 rekey_time = 0; + static __u32 count = 0; + static __u32 secret[12]; + struct timeval tv; + __u32 seq; + + /* The procedure is the same as for IPv4, but addresses are longer. */ + + do_gettimeofday(&tv); /* We need the usecs below... */ + + if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) { + rekey_time = tv.tv_sec; + /* First five words are overwritten below. */ + get_random_bytes(&secret[5], sizeof(secret)-5*4); + count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS; + } + + memcpy(secret, saddr, 16); + secret[4]=(sport << 16) + dport; + + seq = (twothirdsMD4Transform(daddr, secret) & + ((1<<HASH_BITS)-1)) + count; + + seq += tv.tv_usec + tv.tv_sec*1000000; + return seq; +} + +__u32 secure_ipv6_id(__u32 *daddr) +{ + static time_t rekey_time = 0; + static __u32 secret[12]; + time_t t; + + /* + * Pick a random secret every REKEY_INTERVAL seconds. + */ + t = CURRENT_TIME; + if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) { + rekey_time = t; + /* First word is overwritten below. */ + get_random_bytes(secret, sizeof(secret)); + } + + return twothirdsMD4Transform(daddr, secret); +} + +#endif + + __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport) { @@ -2054,6 +2107,38 @@ __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, return seq; } +/* The code below is shamelessly stolen from secure_tcp_sequence_number(). + * All blames to Andrey V. Savochkin <saw@msu.ru>. + */ +__u32 secure_ip_id(__u32 daddr) +{ + static time_t rekey_time = 0; + static __u32 secret[12]; + time_t t; + + /* + * Pick a random secret every REKEY_INTERVAL seconds. + */ + t = CURRENT_TIME; + if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) { + rekey_time = t; + /* First word is overwritten below. */ + get_random_bytes(secret+1, sizeof(secret)-4); + } + + /* + * Pick a unique starting offset for each IP destination. + * Note that the words are placed into the first words to be + * mixed in with the halfMD4. This is because the starting + * vector is also a random secret (at secret+8), and further + * hashing fixed data into it isn't going to improve anything, + * so we should get started with the variable data. + */ + secret[0]=daddr; + + return halfMD4Transform(secret+8, secret); +} + #ifdef CONFIG_SYN_COOKIES /* * Secure SYN cookie computation. This is the algorithm worked out by diff --git a/drivers/char/raw.c b/drivers/char/raw.c index 365c5bd38..a0b2d89c6 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -18,13 +18,11 @@ #define dprintk(x...) -static kdev_t raw_device_bindings[256] = {}; +static struct block_device *raw_device_bindings[256] = {}; static int raw_device_inuse[256] = {}; static int raw_device_sector_size[256] = {}; static int raw_device_sector_bits[256] = {}; -extern struct file_operations * get_blkfops(unsigned int major); - static ssize_t rw_raw_dev(int rw, struct file *, char *, size_t, loff_t *); ssize_t raw_read(struct file *, char *, size_t, loff_t *); @@ -62,64 +60,11 @@ static struct file_operations raw_ctl_fops = { NULL /* fsync */ }; - - void __init raw_init(void) { register_chrdev(RAW_MAJOR, "raw", &raw_fops); } - -/* - * The raw IO open and release code needs to fake appropriate - * open/release calls to the underlying block devices. - */ - -static int bdev_open(kdev_t dev, int mode) -{ - int err = 0; - struct file dummy_file = {}; - struct dentry dummy_dentry = {}; - struct inode * inode = get_empty_inode(); - - if (!inode) - return -ENOMEM; - - dummy_file.f_op = get_blkfops(MAJOR(dev)); - if (!dummy_file.f_op) { - err = -ENODEV; - goto done; - } - - if (dummy_file.f_op->open) { - inode->i_rdev = dev; - dummy_dentry.d_inode = inode; - dummy_file.f_dentry = &dummy_dentry; - dummy_file.f_mode = mode; - err = dummy_file.f_op->open(inode, &dummy_file); - } - - done: - iput(inode); - return err; -} - -static int bdev_close(kdev_t dev) -{ - int err; - struct inode * inode = get_empty_inode(); - - if (!inode) - return -ENOMEM; - - inode->i_rdev = dev; - err = blkdev_release(inode); - iput(inode); - return err; -} - - - /* * Open/close code for raw IO. */ @@ -127,7 +72,8 @@ static int bdev_close(kdev_t dev) int raw_open(struct inode *inode, struct file *filp) { int minor; - kdev_t bdev; + struct block_device * bdev; + kdev_t rdev; /* it should eventually go away */ int err; int sector_size; int sector_bits; @@ -150,10 +96,11 @@ int raw_open(struct inode *inode, struct file *filp) */ bdev = raw_device_bindings[minor]; - if (bdev == NODEV) + if (!bdev) return -ENODEV; - err = bdev_open(bdev, filp->f_mode); + rdev = to_kdev_t(bdev->bd_dev); + err = blkdev_get(bdev, filp->f_mode, 0, BDEV_RAW); if (err) return err; @@ -171,15 +118,15 @@ int raw_open(struct inode *inode, struct file *filp) */ sector_size = 512; - if (lookup_vfsmnt(bdev) != NULL) { - if (blksize_size[MAJOR(bdev)]) - sector_size = blksize_size[MAJOR(bdev)][MINOR(bdev)]; + if (lookup_vfsmnt(rdev) != NULL) { + if (blksize_size[MAJOR(rdev)]) + sector_size = blksize_size[MAJOR(rdev)][MINOR(rdev)]; } else { - if (hardsect_size[MAJOR(bdev)]) - sector_size = hardsect_size[MAJOR(bdev)][MINOR(bdev)]; + if (hardsect_size[MAJOR(rdev)]) + sector_size = hardsect_size[MAJOR(rdev)][MINOR(rdev)]; } - set_blocksize(bdev, sector_size); + set_blocksize(rdev, sector_size); raw_device_sector_size[minor] = sector_size; for (sector_bits = 0; !(sector_size & 1); ) @@ -192,11 +139,11 @@ int raw_open(struct inode *inode, struct file *filp) int raw_release(struct inode *inode, struct file *filp) { int minor; - kdev_t bdev; + struct block_device *bdev; minor = MINOR(inode->i_rdev); bdev = raw_device_bindings[minor]; - bdev_close(bdev); + blkdev_put(bdev, BDEV_RAW); raw_device_inuse[minor]--; return 0; } @@ -261,11 +208,14 @@ int raw_ctl_ioctl(struct inode *inode, err = -EBUSY; break; } + if (raw_device_bindings[minor]) + bdput(raw_device_bindings[minor]); raw_device_bindings[minor] = - MKDEV(rq.block_major, rq.block_minor); + bdget(kdev_t_to_nr(MKDEV(rq.block_major, rq.block_minor))); } else { - rq.block_major = MAJOR(raw_device_bindings[minor]); - rq.block_minor = MINOR(raw_device_bindings[minor]); + kdev_t dev=to_kdev_t(raw_device_bindings[minor]->bd_dev); + rq.block_major = MAJOR(dev); + rq.block_minor = MINOR(dev); err = copy_to_user((void *) arg, &rq, sizeof(rq)); } break; @@ -317,7 +267,7 @@ ssize_t rw_raw_dev(int rw, struct file *filp, char *buf, */ minor = MINOR(filp->f_dentry->d_inode->i_rdev); - dev = raw_device_bindings[minor]; + dev = to_kdev_t(raw_device_bindings[minor]->bd_dev); sector_size = raw_device_sector_size[minor]; sector_bits = raw_device_sector_bits[minor]; sector_mask = sector_size- 1; diff --git a/drivers/char/saa5249.c b/drivers/char/saa5249.c index aab98908a..58c6f7b83 100644 --- a/drivers/char/saa5249.c +++ b/drivers/char/saa5249.c @@ -50,7 +50,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <stdarg.h> -#include <linux/i2c.h> +#include <linux/i2c-old.h> #include <linux/videotext.h> #include <linux/videodev.h> diff --git a/drivers/char/saa7110.c b/drivers/char/saa7110.c index 6a0402f67..6146b84b9 100644 --- a/drivers/char/saa7110.c +++ b/drivers/char/saa7110.c @@ -25,11 +25,11 @@ #include <asm/io.h> #include <asm/uaccess.h> -#include <linux/i2c.h> +#include <linux/i2c-old.h> #include <linux/videodev.h> #include "linux/video_decoder.h" -#define DEBUG(x...) x /* remove when no long debugging */ +#define DEBUG(x...) /* remove when no long debugging */ #define SAA7110_MAX_INPUT 9 /* 6 CVBS, 3 SVHS */ #define SAA7110_MAX_OUTPUT 0 /* its a decoder only */ @@ -224,7 +224,7 @@ static const unsigned char initseq[] = { else { saa7110_write(decoder,0x21,0x16); saa7110_write(decoder,0x0D,0x04); - printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder)); + DEBUG(printk(KERN_INFO "%s_attach: chip version %x\n", device->name, saa7110_read(decoder))); saa7110_write(decoder,0x0D,0x06); } diff --git a/drivers/char/saa7111.c b/drivers/char/saa7111.c index 1c14027b3..1eeeca352 100644 --- a/drivers/char/saa7111.c +++ b/drivers/char/saa7111.c @@ -40,7 +40,7 @@ #include <linux/version.h> #include <asm/uaccess.h> -#include <linux/i2c.h> +#include <linux/i2c-old.h> #include <linux/video_decoder.h> #define DEBUG(x) /* Debug driver */ @@ -70,7 +70,6 @@ struct saa7111 { static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned char data) { int ack; - unsigned long flags; LOCK_I2C_BUS(dev->bus); i2c_start(dev->bus); @@ -85,9 +84,8 @@ static int saa7111_write(struct saa7111 *dev, unsigned char subaddr, unsigned ch static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, unsigned int len) { - int ack; + int ack = 0; unsigned subaddr; - unsigned long flags; while (len > 1) { LOCK_I2C_BUS(dev->bus); @@ -110,7 +108,6 @@ static int saa7111_write_block(struct saa7111 *dev, unsigned const char *data, u static int saa7111_read(struct saa7111 *dev, unsigned char subaddr) { int data; - unsigned long flags; LOCK_I2C_BUS(dev->bus); i2c_start(dev->bus); diff --git a/drivers/char/saa7185.c b/drivers/char/saa7185.c index c42b29c37..c30e6353b 100644 --- a/drivers/char/saa7185.c +++ b/drivers/char/saa7185.c @@ -40,7 +40,7 @@ #include <linux/version.h> #include <asm/uaccess.h> -#include <linux/i2c.h> +#include <linux/i2c-old.h> #include <linux/video_encoder.h> #define DEBUG(x) x /* Debug driver */ @@ -69,7 +69,6 @@ struct saa7185 { static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned char data) { int ack; - unsigned long flags; LOCK_I2C_BUS(dev->bus); @@ -85,9 +84,8 @@ static int saa7185_write(struct saa7185 *dev, unsigned char subaddr, unsigned ch static int saa7185_write_block(struct saa7185 *dev, unsigned const char *data, unsigned int len) { - int ack; + int ack = 0; unsigned subaddr; - unsigned long flags; while (len > 1) { LOCK_I2C_BUS(dev->bus); diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 58a9867e4..c5e2787d5 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -76,6 +76,7 @@ static char *serial_revdate = "1999-11-17"; #include <linux/config.h> #include <linux/version.h> +#include <linux/sysrq.h> #undef SERIAL_PARANOIA_CHECK #define CONFIG_SERIAL_NOPAUSE_IO @@ -3989,7 +3990,6 @@ static struct pci_board pci_boards[] = { */ static void probe_serial_pci(void) { - u16 subvendor, subdevice; int k, line; struct pci_dev *dev = NULL; struct pci_board *board; @@ -4001,18 +4001,7 @@ static void probe_serial_pci(void) printk(KERN_DEBUG "Entered probe_serial_pci()\n"); #endif - if (!pcibios_present()) { -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n"); -#endif - return; - } - - for(dev=pci_devices; dev; dev=dev->next) { - pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, - &subvendor); - pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subdevice); - + pci_for_each_dev(dev) { for (board = pci_boards; board->vendor; board++) { if (board->vendor != (unsigned short) PCI_ANY_ID && dev->vendor != board->vendor) @@ -4021,10 +4010,10 @@ static void probe_serial_pci(void) dev->device != board->device) continue; if (board->subvendor != (unsigned short) PCI_ANY_ID && - subvendor != board->subvendor) + dev->subsystem_vendor != board->subvendor) continue; if (board->subdevice != (unsigned short) PCI_ANY_ID && - subdevice != board->subdevice) + dev->subsystem_device != board->subdevice) continue; break; } diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index aac42d44b..e90400b7f 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -755,8 +755,6 @@ static struct file_operations stl_fsiomem = { stl_memclose, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ NULL /* lock */ }; diff --git a/drivers/char/stradis.c b/drivers/char/stradis.c index 6edbf218c..a34c85d1f 100644 --- a/drivers/char/stradis.c +++ b/drivers/char/stradis.c @@ -44,7 +44,7 @@ #include <asm/uaccess.h> #include <linux/vmalloc.h> #include <linux/videodev.h> -#include <linux/i2c.h> +#include <linux/i2c-old.h> #include "saa7146.h" #include "saa7146reg.h" @@ -2243,26 +2243,19 @@ int init_module(void) int init_stradis_cards(struct video_init *unused) { #endif - struct pci_dev *dev = pci_devices; + struct pci_dev *dev = NULL; int result = 0, i; - u32 newcard; saa_num = 0; - while (dev) { - if (dev->vendor == PCI_VENDOR_ID_PHILIPS) - if (dev->device == PCI_DEVICE_ID_PHILIPS_SAA7146) { - pci_read_config_dword(dev, - PCI_SUBSYSTEM_VENDOR_ID, &newcard); - if (!newcard) - printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num); - else - printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num); - result = configure_saa7146(dev, saa_num++); - } + while ((dev = pci_find_device(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, dev))) { + if (!dev->subsystem_vendor_id) + printk(KERN_INFO "stradis%d: rev1 decoder\n", saa_num); + else + printk(KERN_INFO "stradis%d: SDM2xx found\n", saa_num); + result = configure_saa7146(dev, saa_num++); if (result) return result; - dev = dev->next; } if (saa_num) printk(KERN_INFO "stradis: %d card(s) found.\n", saa_num); diff --git a/drivers/char/sx.c b/drivers/char/sx.c index 6ff328783..eacde318e 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -545,8 +545,6 @@ static struct file_operations sx_fw_fops = { sx_fw_release, NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ }; struct miscdevice sx_fw_device = { diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 5feeeef80..0fd794b73 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * ==FILEDATE 19991207== + * ==FILEDATE 19991217== * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -158,6 +158,7 @@ static int baud_table[] = { #define SERIAL_TYPE_NORMAL 1 #define SERIAL_TYPE_CALLOUT 2 typedef int spinlock_t; +#define spin_lock_init(a) #define spin_lock_irqsave(a,b) {save_flags((b));cli();} #define spin_unlock_irqrestore(a,b) {restore_flags((b));} #define spin_lock(a) @@ -925,7 +926,7 @@ MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); #endif static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "1.15"; +static char *driver_version = "1.16"; static struct tty_driver serial_driver, callout_driver; static int serial_refcount; @@ -4456,7 +4457,7 @@ struct mgsl_struct* mgsl_allocate_device() init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->status_event_wait_q); init_waitqueue_head(&info->event_wait_q); - + spin_lock_init(&info->irq_spinlock); memcpy(&info->params,&default_params,sizeof(MGSL_PARAMS)); info->idle_mode = HDLC_TXIDLE_FLAGS; } diff --git a/drivers/char/tda8425.c b/drivers/char/tda8425.c new file mode 100644 index 000000000..87d79b00e --- /dev/null +++ b/drivers/char/tda8425.c @@ -0,0 +1,325 @@ +/* + * for the TDA8425 chip (I don't know which cards have this) + * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF A DIFFERENT + * CHIP IS AT ADDRESS 0x82 (it relies on i2c to make sure that there is a + * device acknowledging that address) + * + * Copyright (c) 1998 Greg Alexander <galexand@acm.org> + * This code is placed under the terms of the GNU General Public License + * Code liberally copied from msp3400.c, which is by Gerd Knorr + * + * All of this should work, though it would be nice to eventually support + * balance (different left,right values). Also, the chip seems (?) to have + * two stereo inputs, so if someone has this card, could they tell me if the + * second one can be used for anything (i.e., does it have an external input + * that you can't hear even if you set input to composite?) + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/malloc.h> +#include <linux/videodev.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +#include "bttv.h" +#include "audiochip.h" + +/* Addresses to scan */ +#define I2C_TDA8425 0x82 +static unsigned short normal_i2c[] = { + I2C_TDA8425 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +MODULE_PARM(debug,"i"); +static int debug = 0; /* insmod parameter */ +#define dprintk if (debug) printk + + +struct tda8425 { + int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ + int stereo; + __u16 left,right; + __u16 bass,treble; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + + +#define TDA8425_VL 0x00 /* volume left */ +#define TDA8425_VR 0x01 /* volume right */ +#define TDA8425_BA 0x02 /* bass */ +#define TDA8425_TR 0x03 /* treble */ +#define TDA8425_S1 0x08 /* switch functions */ + /* values for those registers: */ +#define TDA8425_S1_OFF 0xEE /* audio off (mute on) */ +#define TDA8425_S1_ON 0xCE /* audio on (mute off) - "linear stereo" mode */ + + +/* ******************************** * + * functions for talking to TDA8425 * + * ******************************** */ + +static int tda8425_write(struct i2c_client *client, int addr, int val) +{ + unsigned char buffer[2]; + + buffer[0] = addr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda8425: I/O error, trying (write %d 0x%x)\n", + addr, val); + return -1; + } + return 0; +} + +static void tda8425_set(struct i2c_client *client) +{ + struct tda8425 *tda = client->data; + + /* mode is ignored today */ + dprintk(KERN_DEBUG "tda8425_set(%04x,%04x,%04x,%04x)\n",tda->left>>10,tda->right>>10,tda->bass>>12,tda->treble>>12); + tda8425_write(client, TDA8425_VL, tda->left>>10 |0xC0); + tda8425_write(client, TDA8425_VR, tda->right>>10 |0xC0); + tda8425_write(client, TDA8425_BA, tda->bass>>12 |0xF0); + tda8425_write(client, TDA8425_TR, tda->treble>>12|0xF0); +} + +static void tda8425_init(struct i2c_client *client) +{ + struct tda8425 *tda = client->data; + + tda->left=tda->right =61440; /* 0dB */ + tda->bass=tda->treble=24576; /* 0dB */ + tda->mode=AUDIO_OFF; + tda->stereo=1; + /* left=right=0x27<<10, bass=treble=0x07<<12 */ + tda8425_write(client, TDA8425_S1, TDA8425_S1_OFF); /* mute */ + tda8425_set(client); +} + +static void tda8425_audio(struct i2c_client *client, int mode) +{ + struct tda8425 *tda = client->data; + + /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ + dprintk(KERN_DEBUG "tda8425_audio:%d (T,R,E,I,O)\n",mode); + tda->mode=mode; + tda8425_write(client, TDA8425_S1, + (mode==AUDIO_OFF)?TDA8425_S1_OFF:TDA8425_S1_ON); + /* this is the function we'll need to change if it turns out the + * input-selecting capabilities should be used. */ +} + + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda8425_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda8425 *tda; + struct i2c_client *client; + + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = tda = kmalloc(sizeof *tda,GFP_KERNEL); + if (!tda) + return -ENOMEM; + memset(tda,0,sizeof *tda); + tda8425_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA8425"); + printk(KERN_INFO "tda8425: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda8425_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda8425_attach); + return 0; +} + + +static int tda8425_detach(struct i2c_client *client) +{ + struct tda8425 *tda = client->data; + + tda8425_init(client); + i2c_detach_client(client); + + kfree(tda); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda8425_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda8425 *tda = client->data; + __u16 *sarg = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + tda8425_audio(client,AUDIO_RADIO); + break; + case AUDC_SET_INPUT: + tda8425_audio(client,*sarg); + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + va->volume=MAX(tda->left,tda->right); + va->balance=(32768*MIN(tda->left,tda->right))/ + (va->volume ? va->volume : 1); + va->balance=(tda->left<tda->right)? + (65535-va->balance) : va->balance; + va->bass = tda->bass; + va->treble = tda->treble; + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + tda->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + tda->right = (MIN(va->balance,32768) * + va->volume) / 32768; + tda->bass = va->bass; + tda->treble = va->treble; + tda8425_set(client); + break; + } + +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_GET_VOLUME_LEFT: + *sarg = tda->left; + break; + case AUDC_GET_VOLUME_RIGHT: + *sarg = tda->right; + break; + case AUDC_SET_VOLUME_LEFT: + tda->left = *sarg; + tda8425_set(client); + break; + case AUDC_SET_VOLUME_RIGHT: + tda->right = *sarg; + tda8425_set(client); + break; + + case AUDC_GET_BASS: + *sarg = tda->bass; + break; + case AUDC_SET_BASS: + tda->bass = *sarg; + tda8425_set(client); + break; + + case AUDC_GET_TREBLE: + *sarg = tda->treble; + break; + case AUDC_SET_TREBLE: + tda->treble = *sarg; + tda8425_set(client); + break; + + case AUDC_GET_STEREO: + *sarg = tda->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO; + break; + case AUDC_SET_STEREO: + tda->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1; + /* TODO: make this write to the TDA9850? */ + break; + +/* case AUDC_SWITCH_MUTE: someday, maybe -- not a lot of point to + case AUDC_NEWCHANNEL: it and it would require preserving state + case AUDC_GET_DC: huh?? (not used by bttv.c) +*/ +#endif + default: + /* nothing */ + } + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda8424 driver", + I2C_DRIVERID_TDA8425, + I2C_DF_NOTIFY, + tda8425_probe, + tda8425_detach, + tda8425_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda8425_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/char/tda9855.c b/drivers/char/tda9855.c new file mode 100644 index 000000000..ed676087f --- /dev/null +++ b/drivers/char/tda9855.c @@ -0,0 +1,456 @@ +/* + * For the TDA9855 chip (afaik, only the Diamond DTV2000 has this) + * This driver will not complain if used with a TDA9850 or any + * other i2c device with the same address. + * + * Copyright (c) 1999 Steve VanDeBogart (vandebo@uclink.berkeley.edu) + * This code is placed under the terms of the GNU General Public License + * Based on tda8425.c by Greg Alexander (c) 1998 + * + * TODO: + * Fix channel change bug - sound goes out when changeing channels, mute + * and unmote to fix. + * Fine tune sound + * Get rest of capabilities into video_audio struct... + * + * Revision: 0.1 + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/malloc.h> +#include <linux/videodev.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +#include "bttv.h" +#include "audiochip.h" + + +MODULE_PARM(debug,"i"); +static int debug = 0; /* insmod parameter */ + +/* Addresses to scan */ +#define I2C_TDA9855_L 0xb4 +#define I2C_TDA9855_H 0xb6 +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = { + I2C_TDA9855_L >> 1, + I2C_TDA9855_H >> 1, + I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + +struct tda9855 { + int addr; + int rvol, lvol; + int bass, treble, sub; + int c1, c2, c3; + int a1, a2, a3; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + + +#define dprintk if (debug) printk + + /* subaddresses */ +#define TDA9855_VR 0x00 /* Volume, right */ +#define TDA9855_VL 0x01 /* Volume, left */ +#define TDA9855_BA 0x02 /* Bass */ +#define TDA9855_TR 0x03 /* Treble */ +#define TDA9855_SW 0x04 /* Subwoofer - not connected on DTV2000 */ +#define TDA9855_C1 0x05 /* Control 1 */ +#define TDA9855_C2 0x06 /* Control 2 */ +#define TDA9855_C3 0x07 /* Control 3 */ +#define TDA9855_A1 0x08 /* Alignmnet 1*/ +#define TDA9855_A2 0x09 /* Alignmnet 2*/ +#define TDA9855_A3 0x0a /* Alignmnet 3*/ + /* Masks for bits in subaddresses */ +/* VR */ /* VL */ +/* lower 7 bits control gain from -71dB (0x28) to 16dB (0x7f) + * in 1dB steps - mute is 0x27 */ + +/* BA */ +/* lower 5 bits control bass gain from -12dB (0x06) to 16.5dB (0x19) + * in .5dB steps - 0 is 0x0E */ + +/* TR */ +/* 4 bits << 1 control treble gain from -12dB (0x3) to 12dB (0xb) + * in 3dB steps - 0 is 0x7 */ + +/* SW */ +/* 4 bits << 2 control subwoofer/surraound gain from -14db (0x1) to 14db (0xf) + * in 3dB steps - mute is 0x0 */ + +/* C1 */ +#define TDA9855_MUTE 1<<7 /* GMU, Mute at outputs */ +#define TDA9855_AVL 1<<6 /* AVL, Automatic Volume Level */ +#define TDA9855_LOUD 1<<5 /* Loudness, 1==off */ +#define TDA9855_SUR 1<<3 /* Surround / Subwoofer 1==.5(L-R) 0==.5(L+R) */ + /* Bits 0 to 3 select various combinations + * of line in and line out, only the + * interesting ones are defined */ +#define TDA9855_EXT 1<<2 /* Selects inputs LIR and LIL. Pins 41 & 12 */ +#define TDA9855_INT 0 /* Selects inputs LOR and LOL. (internal) */ + +/* C2 */ +#define TDA9855_SAP 3<<6 /* Selects SAP output, mute if not received */ +#define TDA9855_STEREO 1<<6 /* Selects Stereo ouput, mono if not received */ +#define TDA9855_MONO 0 /* Forces Mono output */ +#define TDA9855_TZCM 1<<5 /* If set, don't mute till zero crossing */ +#define TDA9855_VZCM 1<<4 /* If set, don't change volume till zero crossing*/ +#define TDA9855_LMU 1<<3 /* Mute at LOR and LOL */ +#define TDA9855_LINEAR 0 /* Linear Stereo */ +#define TDA9855_PSEUDO 1 /* Pseudo Stereo */ +#define TDA9855_SPAT_30 2 /* Spatial Stereo, 30% anti-phase crosstalk */ +#define TDA9855_SPAT_50 3 /* Spatial Stereo, 52% anti-phase crosstalk */ +#define TDA9855_E_MONO 7 /* Forced mono - mono select elseware, so useless*/ + +/* C3 */ +/* lower 4 bits control input gain from -3.5dB (0x0) to 4dB (0xF) + * in .5dB steps - 0 is 0x7 */ + +/* A1 and A2 (read/write) */ +/* lower 5 bites are wideband and spectral expander alignment + * from 0x00 to 0x1f - nominal at 0x0f and 0x10 (read/write) */ +#define TDA9855_STP 1<<5 /* Stereo Pilot/detect (read-only) */ +#define TDA9855_SAPP 1<<6 /* SAP Pilot/detect (read-only) */ +#define TDA9855_STS 1<<7 /* Stereo trigger 1= <35mV 0= <30mV (write-only)*/ + +/* A3 */ +/* lower 3 bits control timing current for alignment: -30% (0x0), -20% (0x1), + * -10% (0x2), nominal (0x3), +10% (0x6), +20% (0x5), +30% (0x4) */ +/* 2 bits << 5 control AVL attack time: 420ohm (0x0), 730ohm (0x2), + * 1200ohm (0x1), 2100ohm (0x3) */ +#define TDA9855_ADJ 1<<7 /* Stereo adjust on/off (wideband and spectral) */ + + +/* Begin code */ + +static int tda9855_write(struct i2c_client *client, int subaddr, int val) +{ + unsigned char buffer[2]; + + buffer[0] = subaddr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tda9855: I/O error, trying (write %d 0x%x)\n", + subaddr, val); + return -1; + } + return 0; +} + +static int tda9855_read(struct i2c_client *client) +{ + unsigned char buffer; + + if (1 != i2c_master_recv(client,&buffer,1)) { + printk(KERN_WARNING "tda9855: I/O error, trying (read)\n"); + return -1; + } + return buffer; +} + +static int tda9855_set(struct i2c_client *client) +{ + struct tda9855 *t = client->data; + unsigned char buf[16]; + + dprintk(KERN_INFO "tda9855_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",t->rvol,t->lvol,t->bass,t->treble,t->sub, + t->c1,t->c2,t->c3,t->a1,t->a2,t->a3); + buf[0] = TDA9855_VR; + buf[1] = t->rvol; + buf[2] = t->lvol; + buf[3] = t->bass; + buf[4] = t->treble; + buf[5] = t->sub; + buf[6] = t->c1; + buf[7] = t->c2; + buf[8] = t->c3; + buf[9] = t->a1; + buf[10] = t->a2; + buf[11] = t->a3; + if (12 != i2c_master_send(client,buf,12)) { + printk(KERN_WARNING "tda9855: I/O error, trying tda9855_set\n"); + return -1; + } + return 0; +} + +static void tda9855_init(struct i2c_client *client) +{ + struct tda9855 *t = client->data; + + t->rvol=0x6f; /* 0dB */ + t->lvol=0x6f; /* 0dB */ + t->bass=0x0e; /* 0dB */ + t->treble=(0x07 << 1); /* 0dB */ + t->sub=0x8 << 2; /* 0dB */ + t->c1=TDA9855_MUTE | TDA9855_AVL | TDA9855_LOUD | TDA9855_INT; + /* Set Mute, AVL, Loudness off, Internal sound */ + t->c2=TDA9855_STEREO | TDA9855_LINEAR; /* Set Stereo liner mode */ + t->c3=0x07; /* 0dB input gain */ + t->a1=0x10; /* Select nominal wideband expander */ + t->a2=0x10; /* Select nominal spectral expander and 30mV trigger */ + t->a3=0x3; /* Set: nominal timinig current, 420ohm AVL attack */ + tda9855_write(client, TDA9855_C1, TDA9855_MUTE); /* mute */ + tda9855_set(client); +} + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tda9855_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tda9855 *t; + struct i2c_client *client; + + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = t = kmalloc(sizeof *t,GFP_KERNEL); + if (!t) + return -ENOMEM; + memset(t,0,sizeof *t); + tda9855_init(client); + MOD_INC_USE_COUNT; + strcpy(client->name,"TDA9855"); + printk(KERN_INFO "tda9855: init\n"); + + i2c_attach_client(client); + return 0; +} + +static int tda9855_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tda9855_attach); + return 0; +} + +static int tda9855_detach(struct i2c_client *client) +{ + struct tda9855 *t = client->data; + + tda9855_init(client); + i2c_detach_client(client); + + kfree(t); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int tda9855_command(struct i2c_client *client, + unsigned int cmd, void *arg) +{ + struct tda9855 *t = client->data; +#if 0 + __u16 *sarg = arg; +#endif + + switch (cmd) { + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + int left,right; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + + /* min is 0x27 max is 0x7f, vstep is 2e8 */ + left = (t->lvol-0x27)*0x2e8; + right = (t->rvol-0x27)*0x2e8; + va->volume=MAX(left,right); + va->balance=(32768*MIN(left,right))/ + (va->volume ? va->volume : 1); + va->balance=(left<right)? + (65535-va->balance) : va->balance; + va->bass = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */ + va->treble = ((t->treble>>1)-0x3)*0x1c71; + + va->mode = ((TDA9855_STP | TDA9855_SAPP) & + tda9855_read(client)) >> 4; + if (0 == va->mode) + va->mode = VIDEO_SOUND_MONO; + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + int left,right; + + left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + right = (MIN(va->balance,32768) * + va->volume) / 32768; + t->lvol = left/0x2e8+0x27; + t->rvol = right/0x2e8+0x27; + t->bass = va->bass/0xccc+0x6; + t->treble = (va->treble/0x1c71+0x3)<<1; + tda9855_write(client,TDA9855_VL,t->lvol); + tda9855_write(client,TDA9855_VR,t->rvol); + tda9855_write(client,TDA9855_BA, t->bass); + tda9855_write(client,TDA9855_TR,t->treble); + + switch (va->mode) { + case VIDEO_SOUND_MONO: + t->c2= TDA9855_MONO | (t->c2 & 0x3f); + break; + case VIDEO_SOUND_STEREO: + t->c2= TDA9855_STEREO | (t->c2 & 0x3f); + break; + case VIDEO_SOUND_LANG2: + t->c2= TDA9855_SAP | (t->c2 & 0x3f); + break; + } + tda9855_write(client,TDA9855_C2,t->c2); + break; + } + +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_GET_VOLUME_LEFT: + *sarg = (t->lvol-0x27)*0x2e8; /* min is 0x27 max is 0x7f, vstep is 2e8 */ + break; + case AUDC_GET_VOLUME_RIGHT: + *sarg = (t->rvol-0x27)*0x2e8; + break; + case AUDC_SET_VOLUME_LEFT: + t->lvol = *sarg/0x2e8+0x27; + break; + case AUDC_SET_VOLUME_RIGHT: + t->rvol = *sarg/0x2e8+0x27; + break; + case AUDC_GET_BASS: + *sarg = (t->bass-0x6)*0xccc; /* min 0x6 max is 0x19 */ + break; + case AUDC_SET_BASS: + t->bass = *sarg/0xccc+0x6; + tda9855_write(client,TDA9855_BA, t->bass); + break; + case AUDC_GET_TREBLE: + *sarg = ((t->treble>>1)-0x3)*0x1c71; + break; + case AUDC_SET_TREBLE: + t->treble = (*sarg/0x1c71+0x3)<<1; + tda9855_write(client,TDA9855_TR,t->treble); + break; + case AUDC_GET_STEREO: + *sarg = ((TDA9855_STP | TDA9855_SAPP) & + tda9855_read(client)) >> 4; + if(*sarg==0) *sarg=VIDEO_SOUND_MONO; + break; + case AUDC_SET_STEREO: + if(*sarg==VIDEO_SOUND_MONO) + t->c2= TDA9855_MONO | (t->c2 & 0x3f); + /* Mask out the sap and stereo bits and set mono */ + else if(*sarg==VIDEO_SOUND_STEREO) + t->c2= TDA9855_STEREO | (t->c2 & 0x3f); + /* Mask out the sap and stereo bits and set stereo */ + else if(*sarg==VIDEO_SOUND_LANG2) + t->c2= TDA9855_SAP | (t->c2 & 0x3f); + /* Mask out the sap and stereo bits and set sap */ + tda9855_write(client,TDA9855_C2,t->c2); + break; + case AUDC_SET_INPUT: + dprintk(KERN_INFO "tda9855: SET_INPUT with 0x%04x\n",*sarg); + if((*sarg & (AUDIO_MUTE | AUDIO_OFF))!=0) + t->c1|=TDA9855_MUTE; + else + t->c1= t->c1 & 0x7f; /* won't work --> (~TDA9855_MUTE); */ + if((*sarg & AUDIO_INTERN) == AUDIO_INTERN) + t->c1=(t->c1 & ~0x7) | TDA9855_INT; /* 0x7 is a mask for the int/ext */ + if((*sarg & AUDIO_EXTERN) == AUDIO_EXTERN) + t->c1=(t->c1 & ~0x7) | TDA9855_EXT; /* 0x7 is a mask for the int/ext */ + tda9855_write(client,TDA9855_C1,t->c1); + break; + case AUDC_SWITCH_MUTE: + if((t->c1 & ~TDA9855_MUTE) == 0) + t->c1|=TDA9855_MUTE; + else + t->c1&=~TDA9855_MUTE; + tda9855_write(client,TDA9855_C1,t->c1); + break; + +/* TDA9855 unsupported: */ +/* case AUDC_NEWCHANNEL: + case AUDC_SET_RADIO: + case AUDC_GET_DC: +*/ +#endif + default: + /* nothing */ + } + return 0; +} + + +static struct i2c_driver driver = { + "i2c tda9855 driver", + I2C_DRIVERID_TDA9855, + I2C_DF_NOTIFY, + tda9855_probe, + tda9855_detach, + tda9855_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tda9855_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_add_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/char/tea6300.c b/drivers/char/tea6300.c new file mode 100644 index 000000000..5449ae0a5 --- /dev/null +++ b/drivers/char/tea6300.c @@ -0,0 +1,344 @@ +/* + * for the TEA6300 chip (only found on Gateway STB TV/FM cards tho the best + * of my knowledge) + * WARNING: THIS DRIVER WILL LOAD WITHOUT COMPLAINTS EVEN IF THE WRONG + * CHIP (i.e., an MSP3400) IS ON I2C ADDRESS 0x80 (it relies on i2c to + * make sure that there is a device acknowledging that address). This + * is a potential problem because the MSP3400 is very popular and does + * use this address! You have been warned! + * + * Copyright (c) 1998 Greg Alexander <galexand@acm.org> + * This code is placed under the terms of the GNU General Public License + * Code liberally copied from msp3400.c, which is by Gerd Knorr + * + * All of this should work, though it would be nice to eventually support + * balance (different left,right values) and, if someone ever finds a card + * with the support (or if you're careful with a soldering iron), fade + * (front/back). + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/malloc.h> +#include <linux/videodev.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +#include "bttv.h" +#include "audiochip.h" + + +/* Addresses to scan */ +#define I2C_TEA6300 0x80 +static unsigned short normal_i2c[] = { + I2C_TEA6300 >> 1, + I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + + +MODULE_PARM(debug,"i"); +static int debug = 0; /* insmod parameter */ + +#define dprintk if (debug) printk + + +struct tea6300 { + int mode; /* set to AUDIO_{OFF,TUNER,RADIO,EXTERN} */ + int stereo; + __u16 left,right; + __u16 bass,treble; +}; + +static struct i2c_driver driver; +static struct i2c_client client_template; + +#define TEA6300_VL 0x00 /* volume left */ +#define TEA6300_VR 0x01 /* volume right */ +#define TEA6300_BA 0x02 /* bass */ +#define TEA6300_TR 0x03 /* treble */ +#define TEA6300_FA 0x04 /* fader control */ +#define TEA6300_S 0x05 /* switch register */ + /* values for those registers: */ +#define TEA6300_S_SA 0x01 /* stereo A input */ +#define TEA6300_S_SB 0x02 /* stereo B */ +#define TEA6300_S_SC 0x04 /* stereo C */ +#define TEA6300_S_GMU 0x80 /* general mute */ + + +/* ******************************** * + * functions for talking to TEA6300 * + * ******************************** */ + +static int tea6300_write(struct i2c_client *client, int addr, int val) +{ + unsigned char buffer[2]; + + buffer[0] = addr; + buffer[1] = val; + if (2 != i2c_master_send(client,buffer,2)) { + printk(KERN_WARNING "tea6300: I/O error, trying (write %d 0x%x)\n", + addr, val); + return -1; + } + return 0; +} + +static void tea6300_set(struct i2c_client *client) +{ + struct tea6300 *tea = client->data; + + /* mode is ignored today */ + dprintk(KERN_DEBUG "tea6300_set(%04x,%04x,%04x,%04x)\n",tea->left>>10,tea->right>>10,tea->bass>>12,tea->treble>>12); + tea6300_write(client, TEA6300_VL, tea->left>>10 ); + tea6300_write(client, TEA6300_VR, tea->right>>10 ); + tea6300_write(client, TEA6300_BA, tea->bass>>12 ); + tea6300_write(client, TEA6300_TR, tea->treble>>12); +} + +static void tea6300_init(struct i2c_client *client) +{ + struct tea6300 *tea = client->data; + + tea->left=tea->right =49152; /* -10dB (loud enough, but not beyond + normal line levels - so as to avoid + clipping */ + tea->bass=tea->treble=28672; /* 0dB */ + tea->mode=AUDIO_OFF; + tea->stereo=1; + /* left=right=0x27<<10, bass=treble=0x07<<12 */ + tea6300_write(client, TEA6300_FA, 0x3f ); /* fader off */ + tea6300_write(client, TEA6300_S , TEA6300_S_GMU); /* mute */ + tea6300_set(client); +} + +static void tea6300_audio(struct i2c_client *client, int mode) +{ + struct tea6300 *tea = client->data; + + /* valid for AUDIO_TUNER, RADIO, EXTERN, OFF */ + dprintk(KERN_DEBUG "tea6300_audio:%d (T,R,E,I,O)\n",mode); + tea->mode=mode; + if (mode==AUDIO_OFF) { /* just mute it */ + tea6300_write(client, TEA6300_S, TEA6300_S_GMU); + return; + } + switch(mode) { + case AUDIO_TUNER: + tea6300_write(client, TEA6300_S, TEA6300_S_SA); + break; + case AUDIO_RADIO: + tea6300_write(client, TEA6300_S, TEA6300_S_SB); + break; + case AUDIO_EXTERN: + tea6300_write(client, TEA6300_S, TEA6300_S_SC); + break; + } +} + + +/* *********************** * + * i2c interface functions * + * *********************** */ + +static int tea6300_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) +{ + struct tea6300 *tea; + struct i2c_client *client; + + client = kmalloc(sizeof *client,GFP_KERNEL); + if (!client) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->adapter = adap; + client->addr = addr; + + client->data = tea = kmalloc(sizeof *tea,GFP_KERNEL); + if (!tea) + return -ENOMEM; + memset(tea,0,sizeof *tea); + tea6300_init(client); + + MOD_INC_USE_COUNT; + strcpy(client->name,"TEA6300T"); + printk(KERN_INFO "tea6300: initialized\n"); + + i2c_attach_client(client); + return 0; +} + +static int tea6300_probe(struct i2c_adapter *adap) +{ + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tea6300_attach); + return 0; +} + +static int tea6300_detach(struct i2c_client *client) +{ + struct tea6300 *tea = client->data; + + tea6300_init(client); + i2c_detach_client(client); + + kfree(tea); + kfree(client); + MOD_DEC_USE_COUNT; + return 0; +} + +static int +tea6300_command(struct i2c_client *client, unsigned int cmd, void *arg) +{ + struct tea6300 *tea = client->data; + __u16 *sarg = arg; + + switch (cmd) { + case AUDC_SET_RADIO: + tea6300_audio(client,AUDIO_RADIO); + break; + case AUDC_SET_INPUT: + tea6300_audio(client,*sarg); + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCGAUDIO: + { + struct video_audio *va = arg; + + va->flags |= VIDEO_AUDIO_VOLUME | + VIDEO_AUDIO_BASS | + VIDEO_AUDIO_TREBLE; + va->volume=MAX(tea->left,tea->right); + va->balance=(32768*MIN(tea->left,tea->right))/ + (va->volume ? va->volume : 1); + va->balance=(tea->left<tea->right)? + (65535-va->balance) : va->balance; + va->bass = tea->bass; + va->treble = tea->treble; + break; + } + case VIDIOCSAUDIO: + { + struct video_audio *va = arg; + + tea->left = (MIN(65536 - va->balance,32768) * + va->volume) / 32768; + tea->right = (MIN(va->balance,32768) * + va->volume) / 32768; + tea->bass = va->bass; + tea->treble = va->treble; + tea6300_set(client); + break; + } +#if 0 + /* --- old, obsolete interface --- */ + case AUDC_GET_VOLUME_LEFT: + *sarg = tea->left; + break; + case AUDC_GET_VOLUME_RIGHT: + *sarg = tea->right; + break; + case AUDC_SET_VOLUME_LEFT: + tea->left = *sarg; + tea6300_set(client); + break; + case AUDC_SET_VOLUME_RIGHT: + tea->right = *sarg; + tea6300_set(client); + break; + + case AUDC_GET_BASS: + *sarg = tea->bass; + break; + case AUDC_SET_BASS: + tea->bass = *sarg; + tea6300_set(client); + break; + + case AUDC_GET_TREBLE: + *sarg = tea->treble; + break; + case AUDC_SET_TREBLE: + tea->treble = *sarg; + tea6300_set(client); + break; + + case AUDC_GET_STEREO: + *sarg = tea->stereo?VIDEO_SOUND_STEREO:VIDEO_SOUND_MONO; + break; + case AUDC_SET_STEREO: + tea->stereo=(*sarg==VIDEO_SOUND_MONO)?0:1; + /* TODO: make this write to the TDA9850? */ + break; + +/* case AUDC_SWITCH_MUTE: someday, maybe -- not a lot of point to + case AUDC_NEWCHANNEL: it and it would require preserving state + case AUDC_GET_DC: huh?? (not used by bttv.c) +*/ +#endif + default: + /* nothing */ + } + return 0; +} + +static struct i2c_driver driver = { + "i2c tea6300 driver", + I2C_DRIVERID_TEA6300, + I2C_DF_NOTIFY, + tea6300_probe, + tea6300_detach, + tea6300_command, +}; + +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver +}; + +#ifdef MODULE +int init_module(void) +#else +int tea6300_init(void) +#endif +{ + i2c_add_driver(&driver); + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + i2c_del_driver(&driver); +} +#endif + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c index 53b90d071..e433faecc 100644 --- a/drivers/char/tpqic02.c +++ b/drivers/char/tpqic02.c @@ -2777,8 +2777,6 @@ static struct file_operations qic02_tape_fops = { qic02_tape_release, /* release */ NULL, /* fsync */ NULL, /* fasync */ - NULL, /* check_media_change */ - NULL /* revalidate */ }; diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c index 01bfdea06..99dc750ee 100644 --- a/drivers/char/tuner.c +++ b/drivers/char/tuner.c @@ -6,44 +6,53 @@ #include <linux/delay.h> #include <linux/errno.h> #include <linux/malloc.h> -#include <linux/version.h> - +#include <linux/poll.h> #include <linux/i2c.h> +#include <linux/types.h> #include <linux/videodev.h> #include "tuner.h" +/* Addresses to scan */ +static unsigned short normal_i2c[] = {I2C_CLIENT_END}; +static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END}; +static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static unsigned short force[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; +static struct i2c_client_address_data addr_data = { + normal_i2c, normal_i2c_range, + probe, probe_range, + ignore, ignore_range, + force +}; + static int debug = 0; /* insmod parameter */ -static int type = -1; /* tuner type */ +static int type = -1; /* insmod parameter */ + +static int addr = 0; +static int this_adap; #define dprintk if (debug) printk -#if LINUX_VERSION_CODE > 0x020100 MODULE_PARM(debug,"i"); MODULE_PARM(type,"i"); -#endif +MODULE_PARM(addr,"i"); -#if LINUX_VERSION_CODE < 0x02017f -void schedule_timeout(int j) +struct tuner { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + j; - schedule(); -} -#endif - -struct tuner -{ - struct i2c_bus *bus; /* where is our chip */ - int addr; - int type; /* chip type */ int freq; /* keep track of the current settings */ - int radio; + int std; + int radio; int mode; /* PAL(0)/SECAM(1) mode (PHILIPS_SECAM only) */ }; +static struct i2c_driver driver; +static struct i2c_client client_template; + /* ---------------------------------------------------------------------- */ struct tunertype @@ -58,13 +67,12 @@ struct tunertype unsigned char VHF_H; unsigned char UHF; unsigned char config; - unsigned char I2C; unsigned short IFPCoff; - unsigned char mode; /* mode change value (tested PHILIPS_SECAM only) */ /* 0x01 -> ??? no change ??? */ /* 0x02 -> PAL BDGHI / SECAM L */ /* 0x04 -> ??? PAL others / SECAM others ??? */ + int capability; }; /* @@ -73,42 +81,47 @@ struct tunertype * "no float in kernel" rule. */ static struct tunertype tuners[] = { - {"Temic PAL", TEMIC, PAL, - 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,623}, - {"Philips PAL_I", Philips, PAL_I, - 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc0,623}, - {"Philips NTSC", Philips, NTSC, - 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,0xc0,732}, - {"Philips SECAM", Philips, SECAM, - 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,0xc0,623,0x02}, - {"NoTuner", NoTuner, NOTUNER, - 0 ,0 ,0x00,0x00,0x00,0x00,0x00,000}, - {"Philips PAL", Philips, PAL, - 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,0xc0,623}, - {"Temic NTSC", TEMIC, NTSC, - 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,0xc2,732}, - {"TEMIC PAL_I", TEMIC, PAL_I, - // 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623}, - 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,0xc2,623}, - {"Temic 4036 FY5 NTSC", TEMIC, NTSC, - 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732}, - {"Alps TSBH1",TEMIC,NTSC, - 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732}, - {"Alps TSBE1",TEMIC,PAL, - 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732}, - {"Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modtec MM205 */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,0xc0,632}, - {"Alps TSBE5", Alps, PAL,/* untested - data sheet guess. Only IF differs. */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,0xc0,622}, - {"Alps TSBC5", Alps, PAL,/* untested - data sheet guess. Only IF differs. */ - 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,0xc0,608}, + { "Temic PAL", TEMIC, PAL, + 16*140.25,16*463.25,0x02,0x04,0x01,0x8e,623}, + { "Philips PAL_I", Philips, PAL_I, + 16*140.25,16*463.25,0xa0,0x90,0x30,0x8e,623}, + { "Philips NTSC", Philips, NTSC, + 16*157.25,16*451.25,0xA0,0x90,0x30,0x8e,732}, + { "Philips SECAM", Philips, SECAM, + 16*168.25,16*447.25,0xA7,0x97,0x37,0x8e,623,0x02}, + { "NoTuner", NoTuner, NOTUNER, + 0,0,0x00,0x00,0x00,0x00,0x00,000}, + { "Philips PAL", Philips, PAL, + 16*168.25,16*447.25,0xA0,0x90,0x30,0x8e,623}, + { "Temic NTSC", TEMIC, NTSC, + 16*157.25,16*463.25,0x02,0x04,0x01,0x8e,732}, + { "Temic PAL_I", TEMIC, PAL_I, + // 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}, + 16*170.00,16*450.00,0x02,0x04,0x01,0x8e,623}, + { "Temic 4036 FY5 NTSC", TEMIC, NTSC, + 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,732}, + { "Alps HSBH1", TEMIC, NTSC, + 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, + { "Alps TSBE1",TEMIC,PAL, + 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,732}, + { "Alps TSBB5", Alps, PAL_I, /* tested (UK UHF) with Modtec MM205 */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,632}, + { "Alps TSBE5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,622}, + { "Alps TSBC5", Alps, PAL, /* untested - data sheet guess. Only IF differs. */ + 16*133.25,16*351.25,0x01,0x02,0x08,0x8e,608}, }; +#define TUNERS (sizeof(tuners)/sizeof(struct tunertype)) /* ---------------------------------------------------------------------- */ -static int tuner_getstatus (struct tuner *t) +static int tuner_getstatus(struct i2c_client *c) { - return i2c_read(t->bus,t->addr+1); + unsigned char byte; + + if (1 != i2c_master_recv(c,&byte,1)) + return 0; + return byte; } #define TUNER_POR 0x80 @@ -116,22 +129,31 @@ static int tuner_getstatus (struct tuner *t) #define TUNER_MODE 0x38 #define TUNER_AFC 0x07 -static int tuner_islocked (struct tuner *t) +static int tuner_islocked (struct i2c_client *c) { - return (tuner_getstatus (t) & TUNER_FL); + return (tuner_getstatus (c) & TUNER_FL); } -static int tuner_afcstatus (struct tuner *t) +static int tuner_afcstatus (struct i2c_client *c) { - return (tuner_getstatus (t) & TUNER_AFC) - 2; + return (tuner_getstatus (c) & TUNER_AFC) - 2; } -static void set_tv_freq(struct tuner *t, int freq) +#if 0 /* unused */ +static int tuner_mode (struct i2c_client *c) +{ + return (tuner_getstatus (c) & TUNER_MODE) >> 3; +} +#endif + +static void set_tv_freq(struct i2c_client *c, int freq) { u8 config; u16 div; struct tunertype *tun; - LOCK_FLAGS; + struct tuner *t = c->data; + unsigned char buffer[4]; + int rc; if (t->type == -1) { printk("tuner: tuner type not set\n"); @@ -146,53 +168,58 @@ static void set_tv_freq(struct tuner *t, int freq) else config = tun->UHF; - if (t->type == TUNER_PHILIPS_SECAM && t->mode) +#if 1 // Fix colorstandard mode change + if (t->type == TUNER_PHILIPS_SECAM + /*&& t->std == V4L2_STANDARD_DDD*/ ) config |= tun->mode; else config &= ~tun->mode; +#else + config &= ~tun->mode; +#endif div=freq + tun->IFPCoff; - div&=0x7fff; - LOCK_I2C_BUS(t->bus); + /* + * Philips FI1216MK2 remark from specification : + * for channel selection involving band switching, and to ensure + * smooth tuning to the desired channel without causing + * unnecessary charge pump action, it is recommended to consider + * the difference between wanted channel frequency and the + * current channel frequency. Unnecessary charge pump action + * will result in very low tuning voltage which may drive the + * oscillator to extreme conditions. + */ + /* + * Progfou: specification says to send config data before + * frequency in case (wanted frequency < current frequency). + */ + if (t->type == TUNER_PHILIPS_SECAM && freq < t->freq) { - /* - * Philips FI1216MK2 remark from specification : - * for channel selection involving band switching, and to ensure - * smooth tuning to the desired channel without causing - * unnecessary charge pump action, it is recommended to consider - * the difference between wanted channel frequency and the - * current channel frequency. Unnecessary charge pump action - * will result in very low tuning voltage which may drive the - * oscillator to extreme conditions. - */ - /* - * Progfou: specification says to send config data before - * frequency in case (wanted frequency < current frequency). - */ - if (i2c_write(t->bus, t->addr, tun->config, config, 1)) { - printk("tuner: i2c i/o error #1\n"); - } else { - if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) - printk("tuner: i2c i/o error #2\n"); - } + buffer[0] = tun->config; + buffer[1] = config; + buffer[2] = (div>>8) & 0x7f; + buffer[3] = div & 0xff; } else { - if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) { - printk("tuner: i2c i/o error #1\n"); - } else { - if (i2c_write(t->bus, t->addr, tun->config, config, 1)) - printk("tuner: i2c i/o error #2\n"); - } + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = tun->config; + buffer[3] = config; } - UNLOCK_I2C_BUS(t->bus); + + if (4 != (rc = i2c_master_send(c,buffer,4))) + printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); + } -static void set_radio_freq(struct tuner *t, int freq) +static void set_radio_freq(struct i2c_client *c, int freq) { u8 config; u16 div; struct tunertype *tun; - LOCK_FLAGS; + struct tuner *t = (struct tuner*)c->data; + unsigned char buffer[4]; + int rc; if (t->type == -1) { printk("tuner: tuner type not set\n"); @@ -204,128 +231,193 @@ static void set_radio_freq(struct tuner *t, int freq) div=freq + (int)(16*10.7); div&=0x7fff; - LOCK_I2C_BUS(t->bus); - if (i2c_write(t->bus, t->addr, (div>>8)&0x7f, div&0xff, 1)<0) { - printk("tuner: i2c i/o error #1\n"); - } else { - if (i2c_write(t->bus, t->addr, tun->config, config, 1)) - printk("tuner: i2c i/o error #2\n"); - } + buffer[0] = (div>>8) & 0x7f; + buffer[1] = div & 0xff; + buffer[2] = tun->config; + buffer[3] = config; + if (4 != (rc = i2c_master_send(c,buffer,4))) + printk("tuner: i2c i/o error: rc == %d (should be 4)\n",rc); + if (debug) { - UNLOCK_I2C_BUS(t->bus); current->state = TASK_INTERRUPTIBLE; schedule_timeout(HZ/10); - LOCK_I2C_BUS(t->bus); - if (tuner_islocked (t)) + if (tuner_islocked (c)) printk ("tuner: PLL locked\n"); else printk ("tuner: PLL not locked\n"); - printk ("tuner: AFC: %d\n", tuner_afcstatus (t)); + printk ("tuner: AFC: %d\n", tuner_afcstatus (c)); } - UNLOCK_I2C_BUS(t->bus); } - /* ---------------------------------------------------------------------- */ -static int tuner_attach(struct i2c_device *device) + +static int tuner_attach(struct i2c_adapter *adap, int addr, + unsigned short flags, int kind) { struct tuner *t; + struct i2c_client *client; - /* - * For now we only try and attach these tuners to the BT848 - * or ZORAN bus. This same module will however work different - * species of card using these chips. Just change the constraints - * (i2c doesn't have a totally clash free 'address' space) - */ - - if(device->bus->id!=I2C_BUSID_BT848 && - device->bus->id!=I2C_BUSID_ZORAN) - return -EINVAL; - - device->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL); - if (NULL == t) - return -ENOMEM; - memset(t,0,sizeof(struct tuner)); - strcpy(device->name,"tuner"); - t->bus = device->bus; - t->addr = device->addr; - t->type = type; - dprintk("tuner: type is %d (%s)\n",t->type, - (t->type == -1 ) ? "autodetect" : tuners[t->type].name); + if (this_adap > 0) + return -1; + this_adap++; + client_template.adapter = adap; + client_template.addr = addr; + + printk("tuner: chip found @ 0x%x\n",addr); + + if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) + return -ENOMEM; + memcpy(client,&client_template,sizeof(struct i2c_client)); + client->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL); + if (NULL == t) { + kfree(client); + return -ENOMEM; + } + memset(t,0,sizeof(struct tuner)); + if (type >= 0 && type < TUNERS) { + t->type = type; + strncpy(client->name, tuners[t->type].name, sizeof(client->name)); + } else { + t->type = -1; + } + i2c_attach_client(client); MOD_INC_USE_COUNT; + + return 0; +} + +static int tuner_probe(struct i2c_adapter *adap) +{ + if (0 != addr) { + normal_i2c_range[0] = addr; + normal_i2c_range[1] = addr; + } + this_adap = 0; + if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848)) + return i2c_probe(adap, &addr_data, tuner_attach); return 0; } -static int tuner_detach(struct i2c_device *device) +static int tuner_detach(struct i2c_client *client) { - struct tuner *t = (struct tuner*)device->data; + struct tuner *t = (struct tuner*)client->data; + + i2c_detach_client(client); kfree(t); + kfree(client); MOD_DEC_USE_COUNT; return 0; } -static int tuner_command(struct i2c_device *device, - unsigned int cmd, void *arg) +static int +tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct tuner *t = (struct tuner*)device->data; - int *iarg = (int*)arg; + struct tuner *t = (struct tuner*)client->data; + int *iarg = (int*)arg; +#if 0 + __u16 *sarg = (__u16*)arg; +#endif - switch (cmd) + switch (cmd) { + + /* --- configuration --- */ + case TUNER_SET_TYPE: + if (t->type != -1) + return 0; + if (*iarg < 0 || *iarg >= TUNERS) + return 0; + t->type = *iarg; + dprintk("tuner: type set to %d (%s)\n", + t->type,tuners[t->type].name); + strncpy(client->name, tuners[t->type].name, sizeof(client->name)); + break; + + /* --- v4l ioctls --- */ + /* take care: bttv does userspace copying, we'll get a + kernel pointer here... */ + case VIDIOCSCHAN: { - case TUNER_SET_TYPE: - if (t->type != -1) - return 0; - t->type = *iarg; - dprintk("tuner: type set to %d (%s)\n", - t->type,tuners[t->type].name); - break; - - case TUNER_SET_TVFREQ: - dprintk("tuner: tv freq set to %d.%02d\n", - (*iarg)/16,(*iarg)%16*100/16); - set_tv_freq(t,*iarg); - t->radio = 0; - t->freq = *iarg; - break; - - case TUNER_SET_RADIOFREQ: + struct video_channel *vc = arg; + + if (t->type == TUNER_PHILIPS_SECAM) { + t->mode = (vc->norm == VIDEO_MODE_SECAM) ? 1 : 0; + set_tv_freq(client,t->freq); + } + return 0; + } + case VIDIOCSFREQ: + { + unsigned long *v = arg; + + t->freq = *v; + if (t->radio) { dprintk("tuner: radio freq set to %d.%02d\n", (*iarg)/16,(*iarg)%16*100/16); - set_radio_freq(t,*iarg); - t->radio = 1; - t->freq = *iarg; - break; - - case TUNER_SET_MODE: - if (t->type != TUNER_PHILIPS_SECAM) { - dprintk("tuner: trying to change mode for other than TUNER_PHILIPS_SECAM\n"); - } else { - dprintk("tuner: mode set to %d\n", *iarg); - t->mode = *iarg; - set_tv_freq(t,t->freq); - } - break; - - default: - return -EINVAL; + set_radio_freq(client,t->freq); + } else { + dprintk("tuner: tv freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_tv_freq(client,t->freq); + } + return 0; + } +#if 0 + /* --- old, obsolete interface --- */ + case TUNER_SET_TVFREQ: + dprintk("tuner: tv freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_tv_freq(client,*iarg); + t->radio = 0; + t->freq = *iarg; + break; + + case TUNER_SET_RADIOFREQ: + dprintk("tuner: radio freq set to %d.%02d\n", + (*iarg)/16,(*iarg)%16*100/16); + set_radio_freq(client,*iarg); + t->radio = 1; + t->freq = *iarg; + break; + case TUNER_SET_MODE: + if (t->type != TUNER_PHILIPS_SECAM) { + dprintk("tuner: trying to change mode for other than TUNER_PHILIPS_SECAM\n"); + } else { + int mode=(*sarg==VIDEO_MODE_SECAM)?1:0; + dprintk("tuner: mode set to %d\n", *sarg); + t->mode = mode; + set_tv_freq(client,t->freq); + } + break; +#endif + default: + /* nothing */ } + return 0; } /* ----------------------------------------------------------------------- */ -struct i2c_driver i2c_driver_tuner = -{ - "tuner", /* name */ - I2C_DRIVERID_TUNER, /* ID */ - 0xc0, 0xce, /* addr range */ +static struct i2c_driver driver = { + "i2c TV tuner driver", + I2C_DRIVERID_TUNER, + I2C_DF_NOTIFY, + tuner_probe, + tuner_detach, + tuner_command, +}; - tuner_attach, - tuner_detach, - tuner_command +static struct i2c_client client_template = +{ + "(unset)", /* name */ + -1, + 0, + 0, + NULL, + &driver }; EXPORT_NO_SYMBOLS; @@ -336,14 +428,14 @@ int init_module(void) int i2c_tuner_init(void) #endif { - i2c_register_driver(&i2c_driver_tuner); + i2c_add_driver(&driver); return 0; } #ifdef MODULE void cleanup_module(void) { - i2c_unregister_driver(&i2c_driver_tuner); + i2c_del_driver(&driver); } #endif diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c index ab41407bf..05f2eeeea 100644 --- a/drivers/char/videodev.c +++ b/drivers/char/videodev.c @@ -54,9 +54,6 @@ extern int init_planbs(struct video_init *); #ifdef CONFIG_VIDEO_ZORAN extern int init_zoran_cards(struct video_init *); #endif -#ifdef CONFIG_VIDEO_ZR36120 -extern int init_zr36120_cards(struct video_init *); -#endif static struct video_init video_init_list[]={ #ifdef CONFIG_VIDEO_BT848 @@ -75,9 +72,6 @@ static struct video_init video_init_list[]={ #ifdef CONFIG_VIDEO_ZORAN {"zoran", init_zoran_cards}, #endif -#ifdef CONFIG_VIDEO_ZR36120 - {"zr36120", init_zr36120_cards}, -#endif {"end", NULL} }; diff --git a/drivers/char/zr36120.c b/drivers/char/zr36120.c index aea50c955..692824133 100644 --- a/drivers/char/zr36120.c +++ b/drivers/char/zr36120.c @@ -18,9 +18,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/config.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/init.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/kernel.h> @@ -34,16 +34,19 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <linux/sched.h> +#include <linux/video_decoder.h> #include <asm/segment.h> #include <linux/version.h> #include <asm/uaccess.h> -#include "linux/video_decoder.h" #include "tuner.h" #include "zr36120.h" #include "zr36120_mem.h" +/* mark an required function argument unused - lintism */ +#define UNUSED(x) (void)(x) + /* sensible default */ #ifndef CARDTYPE #define CARDTYPE 0 @@ -52,9 +55,7 @@ /* Anybody who uses more than four? */ #define ZORAN_MAX 4 -static ulong irq1 = 0; - - unsigned int triton1=0; /* triton1 chipset? */ +static unsigned int triton1=0; /* triton1 chipset? */ static unsigned int cardtype[ZORAN_MAX]={ [ 0 ... ZORAN_MAX-1 ] = CARDTYPE }; MODULE_AUTHOR("Pauline Middelink <middelin@polyware.nl>"); @@ -99,15 +100,21 @@ static struct tvcard tvcards[] = { #undef F #define NRTVCARDS (sizeof(tvcards)/sizeof(tvcards[0])) -static struct { const char name[8]; int mode; int bpp; } palette2fmt[] = { +#ifdef __sparc__ +#define ENDIANESS 0 +#else +#define ENDIANESS ZORAN_VFEC_LE +#endif + +static struct { const char name[8]; uint mode; uint bpp; } palette2fmt[] = { /* n/a */ { "n/a", 0, 0 }, /* GREY */ { "GRAY", 0, 0 }, /* HI240 */ { "HI240", 0, 0 }, -/* RGB565 */ { "RGB565", ZORAN_VFEC_RGB_RGB565|ZORAN_VFEC_LE, 2 }, -/* RGB24 */ { "RGB24", ZORAN_VFEC_RGB_RGB888|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24, 3 }, -/* RGB32 */ { "RGB32", ZORAN_VFEC_RGB_RGB888|ZORAN_VFEC_LE, 4 }, -/* RGB555 */ { "RGB555", ZORAN_VFEC_RGB_RGB555|ZORAN_VFEC_LE, 2 }, -/* YUV422 */ { "YUV422", ZORAN_VFEC_RGB_YUV422|ZORAN_VFEC_LE, 3 }, +/* RGB565 */ { "RGB565", ZORAN_VFEC_RGB_RGB565|ENDIANESS, 2 }, +/* RGB24 */ { "RGB24", ZORAN_VFEC_RGB_RGB888|ENDIANESS|ZORAN_VFEC_PACK24, 3 }, +/* RGB32 */ { "RGB32", ZORAN_VFEC_RGB_RGB888|ENDIANESS, 4 }, +/* RGB555 */ { "RGB555", ZORAN_VFEC_RGB_RGB555|ENDIANESS, 2 }, +/* YUV422 */ { "YUV422", ZORAN_VFEC_RGB_YUV422|ENDIANESS, 2 }, /* YUYV */ { "YUYV", 0, 0 }, /* UYVY */ { "UYVY", 0, 0 }, /* YUV420 */ { "YUV420", 0, 0 }, @@ -116,23 +123,24 @@ static struct { const char name[8]; int mode; int bpp; } palette2fmt[] = { /* YUV422P */ { "YUV422P", 0, 0 }, /* YUV411P */ { "YUV411P", 0, 0 }}; #define NRPALETTES (sizeof(palette2fmt)/sizeof(palette2fmt[0])) +#undef ENDIANESS /* ----------------------------------------------------------------------- */ -/* ZORAN chipset detector */ -/* shamelessly stolen from bttv.c */ +/* ZORAN chipset detector */ +/* shamelessly stolen from bttv.c */ /* Reason for beeing here: we need to detect if we are running on a */ /* Triton based chipset, and if so, enable a certain bit */ /* ----------------------------------------------------------------------- */ - -void handle_chipset(void) +static +void __init handle_chipset(void) { struct pci_dev *dev = NULL; - + /* Just in case some nut set this to something dangerous */ if (triton1) triton1 = ZORAN_VDC_TRICOM; - - while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) + + while ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, dev))) { printk(KERN_INFO "zoran: Host bridge 82437FX Triton PIIX\n"); triton1 = ZORAN_VDC_TRICOM; @@ -148,15 +156,15 @@ static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i); static void zoran_dump(struct zoran *ztv) { - char str[1024]; + char str[256]; char *p=str; /* shut up, gcc! */ int i; for (i=0; i<0x60; i+=4) { if ((i % 16) == 0) { - if (i) printk(/*KERN_DEBUG*/ "%s\n",str); + if (i) printk("%s\n",str); p = str; - p+= sprintf(str, " %04x: ",i); + p+= sprintf(str, KERN_DEBUG " %04x: ",i); } p += sprintf(p, "%08x ",zrread(i)); } @@ -165,114 +173,110 @@ void zoran_dump(struct zoran *ztv) static void reap_states(struct zoran* ztv) { - irq1++; /* debugging... */ + /* count frames */ + ztv->fieldnr++; /* - * GRABBING? + * Are we busy at all? + * This depends on if there is a workqueue AND the + * videotransfer is enabled on the chip... */ - if ( test_bit(STATE_GRAB, &ztv->state) ) { - int i; + if (ztv->workqueue && (zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN)) + { + struct vidinfo* newitem; + + /* did we get a complete frame? */ + if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB) + return; - /* are we already grabbing? */ - if (test_bit(STATE_GRAB, &ztv->prevstate)) { +DEBUG(printk(CARD_DEBUG "completed %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue)); - /* did we get a complete grab? */ - if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB) - goto out; + /* we are done with this buffer, tell everyone */ + ztv->workqueue->status = FBUFFER_DONE; + ztv->workqueue->fieldnr = ztv->fieldnr; + /* not good, here for BTTV_FIELDNR reasons */ + ztv->lastfieldnr = ztv->fieldnr; - /* we are done with this buffer, tell everyone */ - ztv->grabinfo[ztv->lastframe].status = FBUFFER_DONE; + switch (ztv->workqueue->kindof) { + case FBUFFER_GRAB: wake_up_interruptible(&ztv->grabq); + break; + case FBUFFER_VBI: + wake_up_interruptible(&ztv->vbiq); + break; + default: + printk(CARD_INFO "somebody killed the workqueue (kindof=%d)!\n",CARD,ztv->workqueue->kindof); } - /* locate a new frame to grab */ - for (i=0; i<ZORAN_MAX_FBUFFERS; i++) - if (ztv->grabinfo[i].status == FBUFFER_GRABBING) { - - /* there is a buffer more to be grabbed... */ - ztv->lastframe = i; - -DEBUG(printk(KERN_DEBUG "irq(%ld): starting grab(%d)\n",irq1,i)); - - /* loadup the frame settings */ - read_lock(&ztv->lock); - zoran_set_geo(ztv,&ztv->grabinfo[i]); - read_unlock(&ztv->lock); - - zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); - zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR); - zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); - zror(ZORAN_VDC_VIDEN,ZORAN_VDC); - - /* start single-shot grab */ - zror(ZORAN_VSTR_GRAB, ZORAN_VSTR); - goto out; - } - -DEBUG(printk(KERN_DEBUG "irq(%ld): nothing more to grab\n",irq1)); - - /* turn grabbing off the next time around */ - clear_bit(STATE_GRAB, &ztv->state); - - /* force re-init of Read or Overlay settings */ - clear_bit(STATE_READ, &ztv->prevstate); - clear_bit(STATE_OVERLAY, &ztv->prevstate); + /* item completed, skip to next item in queue */ + write_lock(&ztv->lock); + newitem = ztv->workqueue->next; + ztv->workqueue->next = 0; /* mark completed */ + ztv->workqueue = newitem; + write_unlock(&ztv->lock); } /* - * READING? + * ok, so it seems we have nothing in progress right now. + * Lets see if we can find some work. */ - if ( test_bit(STATE_READ, &ztv->state) ) { - /* are we already reading? */ - if (!test_bit(STATE_READ, &ztv->prevstate)) { + if (ztv->workqueue) + { + struct vidinfo* newitem; +again: -DEBUG(printk(KERN_DEBUG "irq(%ld): starting read\n",irq1)); +DEBUG(printk(CARD_DEBUG "starting %s at %p\n",CARD,ztv->workqueue->kindof==FBUFFER_GRAB?"grab":"read",ztv->workqueue)); - read_lock(&ztv->lock); - zoran_set_geo(ztv,&ztv->readinfo); - read_unlock(&ztv->lock); + /* loadup the frame settings */ + read_lock(&ztv->lock); + zoran_set_geo(ztv,ztv->workqueue); + read_unlock(&ztv->lock); - zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); + switch (ztv->workqueue->kindof) { + case FBUFFER_GRAB: + case FBUFFER_VBI: zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR); zror(ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); zror(ZORAN_VDC_VIDEN,ZORAN_VDC); /* start single-shot grab */ zror(ZORAN_VSTR_GRAB, ZORAN_VSTR); - goto out; + break; + default: + printk(CARD_INFO "what is this doing on the queue? (kindof=%d)\n",CARD,ztv->workqueue->kindof); + write_lock(&ztv->lock); + newitem = ztv->workqueue->next; + ztv->workqueue->next = 0; + ztv->workqueue = newitem; + write_unlock(&ztv->lock); + if (newitem) + goto again; /* yeah, sure.. */ } - - /* did we get a complete grab? */ - if (zrread(ZORAN_VSTR) & ZORAN_VSTR_GRAB) - goto out; - -DEBUG(printk(KERN_DEBUG "irq(%ld): nothing more to read\n",irq1)); - - /* turn reading off the next time around */ - clear_bit(STATE_READ, &ztv->state); - /* force re-init of Overlay settings */ - clear_bit(STATE_OVERLAY, &ztv->prevstate); - - /* we are done, tell everyone */ - wake_up_interruptible(&ztv->readq); + /* bye for now */ + return; } +DEBUG(printk(CARD_DEBUG "nothing in queue\n",CARD)); /* - * OVERLAYING? + * What? Even the workqueue is empty? Am i really here + * for nothing? Did i come all that way to... do nothing? */ - if ( test_bit(STATE_OVERLAY, &ztv->state) ) { - /* are we already overlaying? */ - if (!test_bit(STATE_OVERLAY, &ztv->prevstate)) { -DEBUG(printk(KERN_DEBUG "irq(%ld): starting overlay\n",irq1)); + /* do we need to overlay? */ + if (test_bit(STATE_OVERLAY, &ztv->state)) + { + /* are we already overlaying? */ + if (!(zrread(ZORAN_OCR) & ZORAN_OCR_OVLEN) || + !(zrread(ZORAN_VDC) & ZORAN_VDC_VIDEN)) + { +DEBUG(printk(CARD_DEBUG "starting overlay\n",CARD)); read_lock(&ztv->lock); zoran_set_geo(ztv,&ztv->overinfo); read_unlock(&ztv->lock); - zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); - zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); zror(ZORAN_OCR_OVLEN, ZORAN_OCR); + zrand(~ZORAN_VSTR_SNAPSHOT,ZORAN_VSTR); zror(ZORAN_VDC_VIDEN,ZORAN_VDC); } @@ -280,18 +284,43 @@ DEBUG(printk(KERN_DEBUG "irq(%ld): starting overlay\n",irq1)); * leave overlaying on, but turn interrupts off. */ zrand(~ZORAN_ICR_EN,ZORAN_ICR); - goto out; + return; + } + + /* do we have any VBI idle time processing? */ + if (test_bit(STATE_VBI, &ztv->state)) + { + struct vidinfo* item; + struct vidinfo* lastitem; + + /* protect the workqueue */ + write_lock(&ztv->lock); + lastitem = ztv->workqueue; + if (lastitem) + while (lastitem->next) lastitem = lastitem->next; + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + if (item->next == 0 && item->status == FBUFFER_FREE) + { +DEBUG(printk(CARD_DEBUG "%p added to queue\n",CARD,item)); + item->status = FBUFFER_BUSY; + if (!lastitem) + ztv->workqueue = item; + else + lastitem->next = item; + lastitem = item; + } + write_unlock(&ztv->lock); + if (ztv->workqueue) + goto again; /* hey, _i_ graduated :) */ } /* - * THEN WE MUST BE IDLING + * Then we must be realy IDLE */ -DEBUG(printk(KERN_DEBUG "irq(%ld): turning off\n",irq1)); +DEBUG(printk(CARD_DEBUG "turning off\n",CARD)); /* nothing further to do, disable DMA and further IRQs */ zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); zrand(~ZORAN_ICR_EN,ZORAN_ICR); -out: - ztv->prevstate = ztv->state; } static @@ -301,6 +330,7 @@ void zoran_irq(int irq, void *dev_id, struct pt_regs * regs) int count = 0; struct zoran *ztv = (struct zoran *)dev_id; + UNUSED(irq); UNUSED(regs); for (;;) { /* get/clear interrupt status bits */ stat=zrread(ZORAN_ISR); @@ -308,117 +338,35 @@ void zoran_irq(int irq, void *dev_id, struct pt_regs * regs) if (!estat) return; zrwrite(estat,ZORAN_ISR); - IDEBUG(printk(KERN_DEBUG "%s: estat %08x\n",CARD,estat)); - IDEBUG(printk(KERN_DEBUG "%s: stat %08x\n",CARD,stat)); + IDEBUG(printk(CARD_DEBUG "estat %08x\n",CARD,estat)); + IDEBUG(printk(CARD_DEBUG " stat %08x\n",CARD,stat)); if (estat & ZORAN_ISR_CODE) { - IDEBUG(printk(KERN_DEBUG "%s: CodReplIRQ\n",CARD)); + IDEBUG(printk(CARD_DEBUG "CodReplIRQ\n",CARD)); } if (estat & ZORAN_ISR_GIRQ0) { - IDEBUG(printk(KERN_DEBUG "%s: GIRQ0\n",CARD)); + IDEBUG(printk(CARD_DEBUG "GIRQ0\n",CARD)); if (!ztv->card->usegirq1) reap_states(ztv); } if (estat & ZORAN_ISR_GIRQ1) { - IDEBUG(printk(KERN_DEBUG "%s: GIRQ1\n",CARD)); + IDEBUG(printk(CARD_DEBUG "GIRQ1\n",CARD)); if (ztv->card->usegirq1) reap_states(ztv); } count++; if (count > 10) - printk(KERN_ERR "%s: irq loop %d (%x)\n",CARD,count,estat); + printk(CARD_ERR "irq loop %d (%x)\n",CARD,count,estat); if (count > 20) { zrwrite(0, ZORAN_ICR); - printk(KERN_ERR "%s: IRQ lockup, cleared int mask\n",CARD); - } - } -} - -/* - * Scan for a Zoran chip, request the irq and map the io memory - */ -static int find_zoran(void) -{ - unsigned char command, latency; - int result; - struct zoran *ztv; - struct pci_dev *dev; - int zoran_num=0; - - if (!pcibios_present()) - { - DEBUG(printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n")); - return 0; - } - - for (dev = pci_devices; dev != NULL; dev = dev->next) - { - if (dev->vendor != PCI_VENDOR_ID_ZORAN) - continue; - if (dev->device != PCI_DEVICE_ID_ZORAN_36120) - continue; - - /* Ok, ZR36120 found! */ - ztv=&zorans[zoran_num]; - ztv->dev=dev; - ztv->id=dev->device; - ztv->zoran_mem=NULL; - - ztv->zoran_adr = ztv->dev->resource[0].start; - pci_read_config_byte(ztv->dev, PCI_CLASS_REVISION, - &ztv->revision); - printk(KERN_INFO "zoran: Zoran %x (rev %d) ", - ztv->id, ztv->revision); - printk("bus: %d, devfn: %d, ", - ztv->dev->bus->number, ztv->dev->devfn); - printk("irq: %d, ",ztv->dev->irq); - printk("memory: 0x%08x.\n", ztv->zoran_adr); - - ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000); - DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem)); - - result = request_irq(ztv->dev->irq, zoran_irq, - SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv); - if (result==-EINVAL) - { - printk(KERN_ERR "zoran: Bad irq number or handler\n"); - return -EINVAL; - } - if (result==-EBUSY) - { - printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",ztv->dev->irq); - return result; + printk(CARD_ERR "IRQ lockup, cleared int mask\n",CARD); } - if (result < 0) - return result; - - /* Enable bus-mastering */ - pci_read_config_byte(ztv->dev, PCI_COMMAND, &command); - command|=PCI_COMMAND_MASTER|PCI_COMMAND_MEMORY; - pci_write_config_byte(ztv->dev, PCI_COMMAND, command); - pci_read_config_byte(ztv->dev, PCI_COMMAND, &command); - if (!(command&PCI_COMMAND_MASTER)) - { - printk(KERN_ERR "zoran: PCI bus-mastering could not be enabled\n"); - return -1; - } - pci_read_config_byte(ztv->dev, PCI_LATENCY_TIMER, &latency); - if (!latency) - { - latency=32; - pci_write_config_byte(ztv->dev, PCI_LATENCY_TIMER, latency); - DEBUG(printk(KERN_INFO "zoran: latency set to %d\n",latency)); - } - zoran_num++; } - if(zoran_num) - printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num); - return zoran_num; } static @@ -444,31 +392,25 @@ int zoran_muxsel(struct zoran* ztv, int channel, int norm) static void zoran_cap(struct zoran* ztv, int on) { - DEBUG(printk(KERN_DEBUG " zoran_cap(%d) at %ld, state=%x\n",on,irq1,ztv->state)); +DEBUG(printk(CARD_DEBUG "zoran_cap(%d) state=%x\n",CARD,on,ztv->state)); if (on) { ztv->running = 1; - /* - * Clear the previous state flag. This way the irq - * handler will be forced to re-examine its current - * state from scratch, setting up the registers along - * the way. - */ - clear_bit(STATE_OVERLAY, &ztv->prevstate); + /* - * turn interrupts back on. The DMA will be enabled + * turn interrupts (back) on. The DMA will be enabled * inside the irq handler when it detects a restart. */ - zror(ZORAN_ICR_CODE|ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1,ZORAN_ICR); zror(ZORAN_ICR_EN,ZORAN_ICR); } else { - ztv->running = 0; /* - * turn interrupts and DMA both off + * turn both interrupts and DMA off */ zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); zrand(~ZORAN_ICR_EN,ZORAN_ICR); + + ztv->running = 0; } } @@ -488,23 +430,15 @@ void zoran_built_overlay(struct zoran* ztv, int count, struct video_clip *vcp) { ulong* mtop; int ystep = (ztv->vidXshift + ztv->vidWidth+31)/32; /* next DWORD */ - int mult = ztv->interlace; /* double height? */ int i; - DEBUG(printk(KERN_DEBUG " overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count)); - if (ztv->overinfo.overlay == 0) { - zrand(~ZORAN_OCR_OVLEN, ZORAN_OCR); - return; - } - -for (i=0; i<count; i++) { - struct video_clip *vp = vcp+i; - DEBUG(printk(KERN_DEBUG " %d: clip(%d,%d,%d,%d)\n", - i,vp->x,vp->y,vp->width,vp->height)); -} +DEBUG(printk(KERN_DEBUG " overlay at %p, ystep=%d, clips=%d\n",ztv->overinfo.overlay,ystep,count)); - /* clear entire blob */ -/* memset(ztv->overinfo.overlay, 0, 1024*1024/8); */ + for (i=0; i<count; i++) { + struct video_clip *vp = vcp+i; + UNUSED(vp); +DEBUG(printk(KERN_DEBUG " %d: clip(%d,%d,%d,%d)\n", i,vp->x,vp->y,vp->width,vp->height)); + } /* * activate the visible portion of the screen @@ -535,18 +469,18 @@ for (i=0; i<count; i++) { /* process clipping regions */ for (i=0; i<count; i++) { int h; - if (vcp->x < 0 || vcp->x > ztv->overinfo.w || + if (vcp->x < 0 || (uint)vcp->x > ztv->overinfo.w || vcp->y < 0 || vcp->y > ztv->overinfo.h || - vcp->width < 0 || (vcp->x+vcp->width) > ztv->overinfo.w || + vcp->width < 0 || (uint)(vcp->x+vcp->width) > ztv->overinfo.w || vcp->height < 0 || (vcp->y+vcp->height) > ztv->overinfo.h) { - DEBUG(printk(KERN_DEBUG "%s: illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h)); + DEBUG(printk(CARD_DEBUG "illegal clipzone (%d,%d,%d,%d) not in (0,0,%d,%d), adapting\n",CARD,vcp->x,vcp->y,vcp->width,vcp->height,ztv->overinfo.w,ztv->overinfo.h)); if (vcp->x < 0) vcp->x = 0; - if (vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w; + if ((uint)vcp->x > ztv->overinfo.w) vcp->x = ztv->overinfo.w; if (vcp->y < 0) vcp->y = 0; if (vcp->y > ztv->overinfo.h) vcp->y = ztv->overinfo.h; if (vcp->width < 0) vcp->width = 0; - if (vcp->x+vcp->width > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x; + if ((uint)(vcp->x+vcp->width) > ztv->overinfo.w) vcp->width = ztv->overinfo.w - vcp->x; if (vcp->height < 0) vcp->height = 0; if (vcp->y+vcp->height > ztv->overinfo.h) vcp->height = ztv->overinfo.h - vcp->y; // continue; @@ -568,7 +502,7 @@ for (i=0; i<count; i++) { mtop = ztv->overinfo.overlay; zrwrite(virt_to_bus(mtop), ZORAN_MTOP); zrwrite(virt_to_bus(mtop+ystep), ZORAN_MBOT); - zraor((mult*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR); + zraor((ztv->vidInterlace*ystep)<<0,~ZORAN_OCR_MASKSTRIDE,ZORAN_OCR); } struct tvnorm @@ -591,6 +525,17 @@ static struct tvnorm tvnorms[] = { }; #define TVNORMS (sizeof(tvnorms)/sizeof(tvnorm)) +/* + * Program the chip for a setup as described in the vidinfo struct. + * + * Side-effects: calculates vidXshift, vidInterlace, + * vidHeight, vidWidth which are used in a later stage + * to calculate the overlay mask + * + * This is an internal function, as such it does not check the + * validity of the struct members... Spectaculair crashes will + * follow /very/ quick when you're wrong and the chip right :) + */ static void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) { @@ -598,9 +543,9 @@ void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) int stride; int winWidth, winHeight; int maxWidth, maxHeight, maxXOffset, maxYOffset; - int filter; + long vfec; - DEBUG(printk(KERN_DEBUG " set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, vidadr=%lx, overlay=%p)\n", i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->vidadr,i->overlay)); +DEBUG(printk(CARD_DEBUG "set_geo(rect=(%d,%d,%d,%d), norm=%d, format=%d, bpp=%d, bpl=%d, busadr=%lx, overlay=%p)\n",CARD,i->x,i->y,i->w,i->h,ztv->norm,i->format,i->bpp,i->bpl,i->busadr,i->overlay)); /* * make sure the DMA transfers are inhibited during our @@ -609,10 +554,14 @@ void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) zrand(~ZORAN_VDC_VIDEN,ZORAN_VDC); maxWidth = tvnorms[ztv->norm].Wa; - maxHeight = tvnorms[ztv->norm].Ha; + maxHeight = tvnorms[ztv->norm].Ha/2; maxXOffset = tvnorms[ztv->norm].HStart; maxYOffset = tvnorms[ztv->norm].VStart; + /* setup vfec register (keep ExtFl,TopField and VCLKPol settings) */ + vfec = (zrread(ZORAN_VFEC) & (ZORAN_VFEC_EXTFL|ZORAN_VFEC_TOPFIELD|ZORAN_VFEC_VCLKPOL)) | + (palette2fmt[i->format].mode & (ZORAN_VFEC_RGB|ZORAN_VFEC_ERRDIF|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24)); + /* * Set top, bottom ptrs. Since these must be DWORD aligned, * possible adjust the x and the width of the window. @@ -621,7 +570,9 @@ void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) */ ztv->vidXshift = 0; winWidth = i->w; - top = i->vidadr + i->x*i->bpp + i->y*i->bpl; + if (winWidth < 0) + winWidth = -winWidth; + top = i->busadr + i->x*i->bpp + i->y*i->bpl; if (top & 3) { ztv->vidXshift = (top & 3) / i->bpp; winWidth += ztv->vidXshift; @@ -644,30 +595,30 @@ void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) * next line is DWORD aligned too (as required by spec). */ if ((winWidth*i->bpp) & 3) { - DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3)); +DEBUG(printk(KERN_DEBUG " window-width enlarged by %d pixels\n",(winWidth*i->bpp) & 3)); winWidth += (winWidth*i->bpp) & 3; } /* determine the DispMode and stride */ - if (i->h <= maxHeight/2) { - /* single frame suffices for this height */ - zror(ZORAN_VFEC_DISPMOD, ZORAN_VFEC); - ztv->interlace = 0; - winHeight = i->h; - if (winHeight < 0) /* can happen for read's! */ - winHeight = -winHeight; + if (i->h >= 0 && i->h <= maxHeight) { + /* single frame grab suffices for this height. */ + vfec |= ZORAN_VFEC_DISPMOD; + ztv->vidInterlace = 0; stride = i->bpl - (winWidth*i->bpp); + winHeight = i->h; } else { /* interleaving needed for this height */ - zrand(~ZORAN_VFEC_DISPMOD, ZORAN_VFEC); - ztv->interlace = 1; - winHeight = i->h/2; + ztv->vidInterlace = 1; stride = i->bpl*2 - (winWidth*i->bpp); + winHeight = i->h/2; } + if (winHeight < 0) /* can happen for VBI! */ + winHeight = -winHeight; + /* safety net, sometimes bpl is too short??? */ if (stride<0) { - DEBUG(printk(KERN_DEBUG "%s: WARNING stride = %d\n",CARD,stride)); +DEBUG(printk(CARD_DEBUG "WARNING stride = %d\n",CARD,stride)); stride = 0; } @@ -677,86 +628,117 @@ void zoran_set_geo(struct zoran* ztv, struct vidinfo* i) /* remember vidWidth, vidHeight for overlay calculations */ ztv->vidWidth = winWidth; ztv->vidHeight = winHeight; -DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx, winWidth=%d, winHeight=%d, maxWidth=%d, maxHeight=%d, stride=%d\n",top,bot,winWidth,winHeight,maxWidth,maxHeight,stride)); - - /* determine scales and crops */ - if (1) { - int Wa, X, We, HorDcm, hcrop1, hcrop2, Hstart, Hend; - -A: Wa = maxWidth; - X = (winWidth*64+Wa-1)/Wa; - We = winWidth*64/X; - HorDcm = 64-X; - hcrop1 = 2*(Wa-We)/4; - hcrop2 = Wa-We-hcrop1; - Hstart = maxXOffset + hcrop1; - Hend = maxXOffset + Wa-1-hcrop2; +DEBUG(printk(KERN_DEBUG " top=%08lx, bottom=%08lx\n",top,bot)); +DEBUG(printk(KERN_DEBUG " winWidth=%d, winHeight=%d\n",winWidth,winHeight)); +DEBUG(printk(KERN_DEBUG " maxWidth=%d, maxHeight=%d\n",maxWidth,maxHeight)); +DEBUG(printk(KERN_DEBUG " stride=%d\n",stride)); + /* + * determine horizontal scales and crops + */ + if (i->w < 0) { + int Hstart = 1; + int Hend = Hstart + winWidth; +DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Hstart, Hend)); + zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); + } + else { + int Wa = maxWidth; + int X = (winWidth*64+Wa-1)/Wa; + int We = winWidth*64/X; + int HorDcm = 64-X; + int hcrop1 = 2*(Wa-We)/4; /* * BUGFIX: Juha Nurmela <junki@qn-lpr2-165.quicknet.inet.fi> * found the solution to the color phase shift. * See ChangeLog for the full explanation) */ - if (!(Hstart & 1)) { -DEBUG(printk(KERN_DEBUG " correcting horizontal start/end by one\n")); - winWidth--; - goto A; - } + int Hstart = (maxXOffset + hcrop1) | 1; + int Hend = Hstart + We - 1; DEBUG(printk(KERN_DEBUG " X: scale=%d, start=%d, end=%d\n", HorDcm, Hstart, Hend)); zraor((Hstart<<10)|(Hend<<0),~(ZORAN_VFEH_HSTART|ZORAN_VFEH_HEND),ZORAN_VFEH); - zraor((HorDcm<<14),~ZORAN_VFEC_HORDCM, ZORAN_VFEC); - - filter = ZORAN_VFEC_HFILTER_1; - if (HorDcm >= 48) - filter = ZORAN_VFEC_HFILTER_5; /* 5 tap filter */ - else if (HorDcm >= 32) - filter = ZORAN_VFEC_HFILTER_4; /* 4 tap filter */ - else if (HorDcm >= 16) - filter = ZORAN_VFEC_HFILTER_3; /* 3 tap filter */ - zraor(filter, ~ZORAN_VFEC_HFILTER, ZORAN_VFEC); + vfec |= HorDcm<<14; + + if (HorDcm<16) + vfec |= ZORAN_VFEC_HFILTER_1; /* no filter */ + else if (HorDcm<32) + vfec |= ZORAN_VFEC_HFILTER_3; /* 3 tap filter */ + else if (HorDcm<48) + vfec |= ZORAN_VFEC_HFILTER_4; /* 4 tap filter */ + else vfec |= ZORAN_VFEC_HFILTER_5; /* 5 tap filter */ } - /* when height is negative, we want to read from line 0 */ + + /* + * Determine vertical scales and crops + * + * when height is negative, we want to read starting at line 0 + * One day someone might need access to these lines... + */ if (i->h < 0) { int Vstart = 0; int Vend = Vstart + winHeight; - int VerDcm = 0; -DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend)); +DEBUG(printk(KERN_DEBUG " Y: scale=0, start=%d, end=%d\n", Vstart, Vend)); zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); - zraor((VerDcm<<8),~ZORAN_VFEC_VERDCM, ZORAN_VFEC); } else { - int Ha = maxHeight/2; + int Ha = maxHeight; int Y = (winHeight*64+Ha-1)/Ha; int He = winHeight*64/Y; int VerDcm = 64-Y; int vcrop1 = 2*(Ha-He)/4; - int vcrop2 = Ha-He-vcrop1; int Vstart = maxYOffset + vcrop1; - int Vend = maxYOffset + Ha-1-vcrop2; + int Vend = Vstart + He - 1; DEBUG(printk(KERN_DEBUG " Y: scale=%d, start=%d, end=%d\n", VerDcm, Vstart, Vend)); zraor((Vstart<<10)|(Vend<<0),~(ZORAN_VFEV_VSTART|ZORAN_VFEV_VEND),ZORAN_VFEV); - zraor((VerDcm<<8),~ZORAN_VFEC_VERDCM, ZORAN_VFEC); + vfec |= VerDcm<<8; } DEBUG(printk(KERN_DEBUG " F: format=%d(=%s)\n",i->format,palette2fmt[i->format].name)); + /* setup the requested format */ - zraor(palette2fmt[i->format].mode, ~(ZORAN_VFEC_RGB|ZORAN_VFEC_LE|ZORAN_VFEC_PACK24), ZORAN_VFEC); + zrwrite(vfec, ZORAN_VFEC); } -#if LINUX_VERSION_CODE >= 0x020100 static -unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait) +void zoran_common_open(struct zoran* ztv, int flags) { - struct zoran *ztv = (struct zoran *)dev; + UNUSED(flags); + + /* already opened? */ + if (ztv->users++ != 0) + return; - poll_wait(file, &ztv->readq, wait); + /* unmute audio */ + /* /what/ audio? */ - return (POLLIN | POLLRDNORM); + ztv->state = 0; + + /* setup the encoder to the initial values */ + ztv->picture.colour=254<<7; + ztv->picture.brightness=128<<8; + ztv->picture.hue=128<<8; + ztv->picture.contrast=216<<7; + i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture); + + /* default to the composite input since my camera is there */ + zoran_muxsel(ztv, 0, VIDEO_MODE_PAL); +} + +static +void zoran_common_close(struct zoran* ztv) +{ + if (--ztv->users != 0) + return; + + /* mute audio */ + /* /what/ audio? */ + + /* stop the chip */ + zoran_cap(ztv, 0); } -#endif /* * Open a zoran card. Right now the flags are just a hack @@ -764,60 +746,46 @@ unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table static int zoran_open(struct video_device *dev, int flags) { struct zoran *ztv = (struct zoran*)dev; - int i; - - DEBUG(printk(KERN_DEBUG "%s: open(dev,%d)\n",CARD,flags)); - - switch (flags) { - case 0: - /* already active? */ - if (ztv->user) - return -EBUSY; - ztv->user++; - - /* unmute audio */ - /* /what/ audio? */ - -/****************************************** - We really should be doing lazy allocing... - ******************************************/ - /* allocate a frame buffer */ - if (!ztv->fbuffer) - ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE); - if (!ztv->fbuffer) { - /* could not get a buffer, bail out */ - ztv->user--; - return -ENOBUFS; - } - /* at this time we _always_ have a framebuffer */ - memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE); - - if (!ztv->overinfo.overlay) - ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL); - if (!ztv->overinfo.overlay) { - /* could not get an overlay buffer, bail out */ - ztv->user--; - bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE); - return -ENOBUFS; - } - /* at this time we _always_ have a overlay */ + struct vidinfo* item; + char* pos; + + DEBUG(printk(CARD_DEBUG "open(dev,%d)\n",CARD,flags)); + + /********************************************* + * We really should be doing lazy allocing... + *********************************************/ + /* allocate a frame buffer */ + if (!ztv->fbuffer) + ztv->fbuffer = bmalloc(ZORAN_MAX_FBUFSIZE); + if (!ztv->fbuffer) { + /* could not get a buffer, bail out */ + return -ENOBUFS; + } + /* at this time we _always_ have a framebuffer */ + memset(ztv->fbuffer,0,ZORAN_MAX_FBUFSIZE); + + if (!ztv->overinfo.overlay) + ztv->overinfo.overlay = (void*)kmalloc(1024*1024/8, GFP_KERNEL); + if (!ztv->overinfo.overlay) { + /* could not get an overlay buffer, bail out */ + bfree(ztv->fbuffer, ZORAN_MAX_FBUFSIZE); + return -ENOBUFS; + } + /* at this time we _always_ have a overlay */ - /* clear buffer status */ - for (i=0; i<ZORAN_MAX_FBUFFERS; i++) - ztv->grabinfo[i].status = FBUFFER_UNUSED; - ztv->state = 0; - ztv->prevstate = 0; - ztv->lastframe = -1; + /* clear buffer status, and give them a DMAable address */ + pos = ztv->fbuffer; + for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) + { + item->status = FBUFFER_FREE; + item->memadr = pos; + item->busadr = virt_to_bus(pos); + pos += ZORAN_MAX_FBUFFER; + } - /* setup the encoder to the initial values */ - i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &ztv->picture); + /* do the common part of all open's */ + zoran_common_open(ztv, flags); - /* default to the compisite input since my camera is there */ - zoran_muxsel(ztv, 0, VIDEO_MODE_PAL); - break; - case 1: - break; - } MOD_INC_USE_COUNT; return 0; } @@ -827,14 +795,20 @@ void zoran_close(struct video_device* dev) { struct zoran *ztv = (struct zoran*)dev; - DEBUG(printk(KERN_DEBUG "%s: close(dev)\n",CARD)); + DEBUG(printk(CARD_DEBUG "close(dev)\n",CARD)); - /* we are no longer active, goodbye */ - ztv->user--; + /* driver specific closure */ + clear_bit(STATE_OVERLAY, &ztv->state); - /* mute audio */ - /* stop the chip */ - zoran_cap(ztv, 0); + zoran_common_close(ztv); + + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ /* free the allocated framebuffer */ if (ztv->fbuffer) @@ -847,46 +821,139 @@ void zoran_close(struct video_device* dev) MOD_DEC_USE_COUNT; } -static -long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock) -{ - DEBUG(printk(KERN_DEBUG "zoran_write\n")); - return -EINVAL; -} - +/* + * This read function could be used reentrant in a SMP situation. + * + * This is made possible by the spinlock which is kept till we + * found and marked a buffer for our own use. The lock must + * be released as soon as possible to prevent lock contention. + */ static long zoran_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) { struct zoran *ztv = (struct zoran*)dev; - int max; + unsigned long max; + struct vidinfo* unused = 0; + struct vidinfo* done = 0; - DEBUG(printk(KERN_DEBUG "zoran_read(%p,%ld,%d)\n",buf,count,nonblock)); + DEBUG(printk(CARD_DEBUG "zoran_read(%p,%ld,%d)\n",CARD,buf,count,nonblock)); - /* tell the state machine we want in too */ - write_lock_irq(&ztv->lock); - ztv->readinfo.vidadr = virt_to_bus(phys_to_virt((ulong)ztv->fbuffer)); - set_bit(STATE_READ, &ztv->state); - write_unlock_irq(&ztv->lock); - zoran_cap(ztv, 1); + /* find ourself a free or completed buffer */ + for (;;) { + struct vidinfo* item; + + write_lock_irq(&ztv->lock); + for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) + { + if (!unused && item->status == FBUFFER_FREE) + unused = item; + if (!done && item->status == FBUFFER_DONE) + done = item; + } + if (done || unused) + break; + + /* no more free buffers, wait for them. */ + write_unlock_irq(&ztv->lock); + if (nonblock) + return -EWOULDBLOCK; + interruptible_sleep_on(&ztv->grabq); + if (signal_pending(current)) + return -EINTR; + } - /* wait for data to arrive */ - interruptible_sleep_on(&ztv->readq); + /* Do we have 'ready' data? */ + if (!done) { + /* no? than this will take a while... */ + if (nonblock) { + write_unlock_irq(&ztv->lock); + return -EWOULDBLOCK; + } + + /* mark the unused buffer as wanted */ + unused->status = FBUFFER_BUSY; + unused->w = 320; + unused->h = 240; + unused->format = VIDEO_PALETTE_RGB24; + unused->bpp = palette2fmt[unused->format].bpp; + unused->bpl = unused->w * unused->bpp; + unused->next = 0; + { /* add to tail of queue */ + struct vidinfo* oldframe = ztv->workqueue; + if (!oldframe) ztv->workqueue = unused; + else { + while (oldframe->next) oldframe = oldframe->next; + oldframe->next = unused; + } + } + write_unlock_irq(&ztv->lock); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; + /* tell the state machine we want it filled /NOW/ */ + zoran_cap(ztv, 1); + + /* wait till this buffer gets grabbed */ + while (unused->status == FBUFFER_BUSY) { + interruptible_sleep_on(&ztv->grabq); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; + } + done = unused; + } + else + write_unlock_irq(&ztv->lock); - /* give the user what he requested */ - max = ztv->readinfo.w*ztv->readinfo.bpp - ztv->readinfo.h*ztv->readinfo.bpl; + /* Yes! we got data! */ + max = done->bpl * done->h; if (count > max) count = max; - if (copy_to_user((void*)buf, (void*)ztv->fbuffer, count)) - return -EFAULT; + if (copy_to_user((void*)buf, done->memadr, count)) + count = -EFAULT; + + /* keep the engine running */ + done->status = FBUFFER_FREE; +// zoran_cap(ztv,1); + + /* tell listeners this buffer became free */ + wake_up_interruptible(&ztv->grabq); /* goodbye */ + DEBUG(printk(CARD_DEBUG "zoran_read() returns %lu\n",CARD,count)); return count; } +static +long zoran_write(struct video_device* dev, const char* buf, unsigned long count, int nonblock) +{ + struct zoran *ztv = (struct zoran *)dev; + UNUSED(ztv); UNUSED(dev); UNUSED(buf); UNUSED(count); UNUSED(nonblock); + DEBUG(printk(CARD_DEBUG "zoran_write\n",CARD)); + return -EINVAL; +} + +#if LINUX_VERSION_CODE >= 0x020100 +static +unsigned int zoran_poll(struct video_device *dev, struct file *file, poll_table *wait) +{ + struct zoran *ztv = (struct zoran *)dev; + struct vidinfo* item; + unsigned int mask = 0; + + poll_wait(file, &ztv->grabq, wait); + + for (item=ztv->grabinfo; item!=ztv->grabinfo+ZORAN_MAX_FBUFFERS; item++) + if (item->status == FBUFFER_DONE) + { + mask |= (POLLIN | POLLRDNORM); + break; + } + + DEBUG(printk(CARD_DEBUG "zoran_poll()=%x\n",CARD,mask)); + + return mask; +} +#endif + /* append a new clipregion to the vector of video_clips */ static void new_clip(struct video_window* vw, struct video_clip* vcp, int x, int y, int w, int h) @@ -905,20 +972,9 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) switch (cmd) { case VIDIOCGCAP: - { /* get video capabilities */ + { struct video_capability c; - struct video_decoder_capability dc; - int rv; - DEBUG(printk(KERN_DEBUG "%s: GetCapabilities\n",CARD)); - - /* fetch the capabilites of the decoder */ - dc.flags = 0; - dc.inputs = -1; - dc.outputs = -1; - rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc); - if (rv) - return rv; - DEBUG(printk(KERN_DEBUG "%s: capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs)); + DEBUG(printk(CARD_DEBUG "VIDIOCGCAP\n",CARD)); strcpy(c.name,ztv->video_dev.name); c.type = VID_TYPE_CAPTURE| @@ -926,25 +982,30 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) VID_TYPE_CLIPPING| VID_TYPE_FRAMERAM| VID_TYPE_SCALES; - c.channels = ztv->card->video_inputs; - c.audios = ztv->card->audio_inputs; + if (ztv->have_tuner) + c.type |= VID_TYPE_TUNER; + if (ztv->have_decoder) { + c.channels = ztv->card->video_inputs; + c.audios = ztv->card->audio_inputs; + } else + /* no decoder -> no channels */ + c.channels = c.audios = 0; c.maxwidth = 768; c.maxheight = 576; c.minwidth = 32; c.minheight = 32; if (copy_to_user(arg,&c,sizeof(c))) return -EFAULT; - return 0; + break; } case VIDIOCGCHAN: { struct video_channel v; int mux; - if (copy_from_user(&v, arg,sizeof(v))) return -EFAULT; - DEBUG(printk(KERN_DEBUG "%s: GetChannel(%d)\n",CARD,v.channel)); + DEBUG(printk(CARD_DEBUG "VIDIOCGCHAN(%d)\n",CARD,v.channel)); v.flags=VIDEO_VC_AUDIO #ifdef VIDEO_VC_NORM |VIDEO_VC_NORM @@ -959,8 +1020,8 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) #else v.norm=VIDEO_MODE_PAL; #endif - /* too many inputs? */ - if (v.channel >= ztv->card->video_inputs) + /* too many inputs? no decoder -> no channels */ + if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs) return -EINVAL; /* now determine the name of the channel */ @@ -981,15 +1042,17 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) if (copy_to_user(arg,&v,sizeof(v))) return -EFAULT; - return 0; + break; } case VIDIOCSCHAN: { /* set video channel */ struct video_channel v; if (copy_from_user(&v, arg,sizeof(v))) return -EFAULT; - DEBUG(printk(KERN_DEBUG "%s: SetChannel(%d,%d)\n",CARD,v.channel,v.norm)); - if (v.channel >= ztv->card->video_inputs) + DEBUG(printk(CARD_DEBUG "VIDIOCSCHAN(%d,%d)\n",CARD,v.channel,v.norm)); + + /* too many inputs? no decoder -> no channels */ + if (!ztv->have_decoder || v.channel >= ztv->card->video_inputs) return -EINVAL; if (v.norm != VIDEO_MODE_PAL && @@ -1007,9 +1070,10 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) struct video_tuner v; if (copy_from_user(&v, arg,sizeof(v))) return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCGTUNER(%d)\n",CARD,v.tuner)); - /* Only one tuner for now */ - if (!ztv->have_tuner && v.tuner) + /* Only no or one tuner for now */ + if (!ztv->have_tuner || v.tuner) return -EINVAL; strcpy(v.name,"Television"); @@ -1021,17 +1085,17 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) if (copy_to_user(arg,&v,sizeof(v))) return -EFAULT; - return 0; + break; } - case VIDIOCSTUNER: { struct video_tuner v; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSTUNER(%d,%d)\n",CARD,v.tuner,v.mode)); - /* Only one tuner for now */ - if (!ztv->have_tuner && v.tuner) + /* Only no or one tuner for now */ + if (!ztv->have_tuner || v.tuner) return -EINVAL; /* and it only has certain valid modes */ @@ -1047,7 +1111,7 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) case VIDIOCGPICT: { struct video_picture p = ztv->picture; - DEBUG(printk(KERN_DEBUG "%s: GetPicture\n",CARD)); + DEBUG(printk(CARD_DEBUG "VIDIOCGPICT\n",CARD)); p.depth = ztv->depth; switch (p.depth) { case 8: p.palette=VIDEO_PALETTE_YUV422; @@ -1063,21 +1127,21 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) } if (copy_to_user(arg, &p, sizeof(p))) return -EFAULT; - return 0; + break; } case VIDIOCSPICT: { struct video_picture p; - DEBUG(printk(KERN_DEBUG "%s: SetPicture\n",CARD)); if (copy_from_user(&p, arg,sizeof(p))) return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSPICT(%d,%d,%d,%d,%d,%d,%d)\n",CARD,p.brightness,p.hue,p.colour,p.contrast,p.whiteness,p.depth,p.palette)); /* depth must match with framebuffer */ if (p.depth != ztv->depth) return -EINVAL; /* check if palette matches this bpp */ - if (p.palette<1 || p.palette>NRPALETTES || + if (p.palette>NRPALETTES || palette2fmt[p.palette].bpp != ztv->overinfo.bpp) return -EINVAL; @@ -1088,13 +1152,13 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) /* tell the decoder */ i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_SET_PICTURE, &p); - return 0; + break; } case VIDIOCGWIN: { struct video_window vw; - DEBUG(printk(KERN_DEBUG "%s: GetWindow\n",CARD)); + DEBUG(printk(CARD_DEBUG "VIDIOCGWIN\n",CARD)); read_lock(&ztv->lock); vw.x = ztv->overinfo.x; vw.y = ztv->overinfo.y; @@ -1102,23 +1166,21 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) vw.height = ztv->overinfo.h; vw.chromakey= 0; vw.flags = 0; - if (ztv->interlace) + if (ztv->vidInterlace) vw.flags|=VIDEO_WINDOW_INTERLACE; read_unlock(&ztv->lock); if (copy_to_user(arg,&vw,sizeof(vw))) return -EFAULT; - return 0; + break; } case VIDIOCSWIN: { struct video_window vw; struct video_clip *vcp; int on; - if (copy_from_user(&vw,arg,sizeof(vw))) return -EFAULT; - - DEBUG(printk(KERN_DEBUG "%s: SetWindow(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount)); + DEBUG(printk(CARD_DEBUG "VIDIOCSWIN(%d,%d,%d,%d,%x,%d)\n",CARD,vw.x,vw.y,vw.width,vw.height,vw.flags,vw.clipcount)); if (vw.flags) return -EINVAL; @@ -1139,6 +1201,15 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) if (on) zoran_cap(ztv, 0); + /* + * strange, it seems xawtv sometimes calls us with 0 + * width and/or height. Ignore these values + */ + if (vw.x == 0) + vw.x = ztv->overinfo.x; + if (vw.y == 0) + vw.y = ztv->overinfo.y; + /* by now we are committed to the new data... */ write_lock_irq(&ztv->lock); ztv->overinfo.x = vw.x; @@ -1150,10 +1221,6 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) /* * Impose display clips */ - if (vw.x<0) - new_clip(&vw, vcp, 0, 0, -vw.x, vw.height-1); - if (vw.y<0) - new_clip(&vw, vcp, 0, 0, vw.width-1,-vw.y); if (vw.x+vw.width > ztv->swidth) new_clip(&vw, vcp, ztv->swidth-vw.x, 0, vw.width-1, vw.height-1); if (vw.y+vw.height > ztv->sheight) @@ -1165,36 +1232,38 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) vfree(vcp); /* if we were on, restart the video engine */ - if (on) zoran_cap(ztv, on); - return 0; + if (on) + zoran_cap(ztv, 1); + break; } + case VIDIOCCAPTURE: { int v; get_user_ret(v,(int*)arg, -EFAULT); - DEBUG(printk(KERN_DEBUG "%s: Capture(%d)\n",CARD,v)); + DEBUG(printk(CARD_DEBUG "VIDIOCCAPTURE(%d)\n",CARD,v)); if (v==0) { - zoran_cap(ztv, 0); clear_bit(STATE_OVERLAY, &ztv->state); + zoran_cap(ztv, 1); } else { /* is VIDIOCSFBUF, VIDIOCSWIN done? */ - if (ztv->overinfo.vidadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0) + if (ztv->overinfo.busadr==0 || ztv->overinfo.w==0 || ztv->overinfo.h==0) return -EINVAL; set_bit(STATE_OVERLAY, &ztv->state); zoran_cap(ztv, 1); } - return 0; + break; } case VIDIOCGFBUF: { struct video_buffer v; - DEBUG(printk(KERN_DEBUG "%s: GetFramebuffer\n",CARD)); + DEBUG(printk(CARD_DEBUG "VIDIOCGFBUF\n",CARD)); read_lock(&ztv->lock); - v.base = (void *)ztv->overinfo.vidadr; + v.base = (void *)ztv->overinfo.busadr; v.height = ztv->sheight; v.width = ztv->swidth; v.depth = ztv->depth; @@ -1202,19 +1271,21 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) read_unlock(&ztv->lock); if(copy_to_user(arg, &v,sizeof(v))) return -EFAULT; - return 0; + break; } case VIDIOCSFBUF: { struct video_buffer v; #if LINUX_VERSION_CODE >= 0x020100 - if(!capable(CAP_SYS_ADMIN)) + if(!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_ADMIN)) #else if(!suser()) #endif return -EPERM; if (copy_from_user(&v, arg,sizeof(v))) return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline)); + if (v.depth!=15 && v.depth!=16 && v.depth!=24 && v.depth!=32) return -EINVAL; if (v.bytesperline<1) @@ -1222,48 +1293,50 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) if (ztv->running) return -EBUSY; write_lock_irq(&ztv->lock); - ztv->overinfo.vidadr = (unsigned long)v.base; + ztv->overinfo.busadr = (ulong)v.base; ztv->sheight = v.height; ztv->swidth = v.width; - ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */ ztv->depth = v.depth; /* bits per pixel */ - ztv->overinfo.bpl = v.bytesperline; + ztv->overinfo.bpp = ((v.depth+1)&0x38)/8;/* bytes per pixel */ + ztv->overinfo.bpl = v.bytesperline; /* bytes per line */ write_unlock_irq(&ztv->lock); + break; + } - DEBUG(printk(KERN_DEBUG "%s: SetFrameBuffer(%p,%dx%d, bpp %d, bpl %d)\n",CARD,v.base, v.width,v.height, ztv->overinfo.bpp, ztv->overinfo.bpl)); - return 0; + case VIDIOCKEY: + { + /* Will be handled higher up .. */ + break; } case VIDIOCSYNC: { int i; get_user_ret(i,(int*)arg, -EFAULT); - DEBUG(printk(KERN_DEBUG "%s: VIDEOCSYNC(%d)\n",CARD,i)); + DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d)\n",CARD,i)); if (i<0 || i>ZORAN_MAX_FBUFFERS) return -EINVAL; switch (ztv->grabinfo[i].status) { - case FBUFFER_UNUSED: + case FBUFFER_FREE: return -EINVAL; - case FBUFFER_GRABBING: + case FBUFFER_BUSY: /* wait till this buffer gets grabbed */ - while (ztv->grabinfo[i].status == FBUFFER_GRABBING) { + while (ztv->grabinfo[i].status == FBUFFER_BUSY) { interruptible_sleep_on(&ztv->grabq); /* see if a signal did it */ if (signal_pending(current)) - return -ERESTARTSYS; + return -EINTR; } - /* fall through */ + /* don't fall through; a DONE buffer is not UNUSED */ + break; case FBUFFER_DONE: - ztv->grabinfo[i].status = FBUFFER_UNUSED; + ztv->grabinfo[i].status = FBUFFER_FREE; + /* tell ppl we have a spare buffer */ + wake_up_interruptible(&ztv->grabq); break; } - return 0; - } - - case VIDIOCKEY: - { - /* Will be handled higher up .. */ - return 0; + DEBUG(printk(CARD_DEBUG "VIDEOCSYNC(%d) returns\n",CARD,i)); + break; } case VIDIOCMCAPTURE: @@ -1272,63 +1345,67 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) struct vidinfo* frame; if (copy_from_user(&vm,arg,sizeof(vm))) return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCMCAPTURE(%d,(%d,%d),%d)\n",CARD,vm.frame,vm.width,vm.height,vm.format)); if (vm.frame<0 || vm.frame>ZORAN_MAX_FBUFFERS || vm.width<32 || vm.width>768 || vm.height<32 || vm.height>576 || - vm.format<0 || vm.format>NRPALETTES || + vm.format>NRPALETTES || palette2fmt[vm.format].mode == 0) return -EINVAL; - DEBUG(printk(KERN_DEBUG "%s: Mcapture(%d,(%d,%d),%d=%s)\n",CARD,vm.frame,vm.width,vm.height,vm.format,palette2fmt[vm.format].name)); + /* we are allowed to take over UNUSED and DONE buffers */ frame = &ztv->grabinfo[vm.frame]; - if (frame->status == FBUFFER_GRABBING) + if (frame->status == FBUFFER_BUSY) return -EBUSY; /* setup the other parameters if they are given */ write_lock_irq(&ztv->lock); - if (vm.width) - frame->w = vm.width; - if (vm.height) - frame->h = vm.height; - if (vm.format) - frame->format = vm.format; + frame->w = vm.width; + frame->h = vm.height; + frame->format = vm.format; frame->bpp = palette2fmt[frame->format].bpp; frame->bpl = frame->w*frame->bpp; - frame->vidadr = virt_to_bus(phys_to_virt((ulong)ztv->fbuffer+vm.frame*ZORAN_MAX_FBUFFER)); - frame->status = FBUFFER_GRABBING; - set_bit(STATE_GRAB, &ztv->state); + frame->status = FBUFFER_BUSY; + frame->next = 0; + { /* add to tail of queue */ + struct vidinfo* oldframe = ztv->workqueue; + if (!oldframe) ztv->workqueue = frame; + else { + while (oldframe->next) oldframe = oldframe->next; + oldframe->next = frame; + } + } write_unlock_irq(&ztv->lock); - zoran_cap(ztv, 1); - return 0; + break; } case VIDIOCGMBUF: { struct video_mbuf mb; int i; - DEBUG(printk(KERN_DEBUG "%s: GetMemoryBuffer\n",CARD)); + DEBUG(printk(CARD_DEBUG "VIDIOCGMBUF\n",CARD)); mb.size = ZORAN_MAX_FBUFSIZE; mb.frames = ZORAN_MAX_FBUFFERS; for (i=0; i<ZORAN_MAX_FBUFFERS; i++) mb.offsets[i] = i*ZORAN_MAX_FBUFFER; if(copy_to_user(arg, &mb,sizeof(mb))) return -EFAULT; - return 0; + break; } case VIDIOCGUNIT: { struct video_unit vu; - DEBUG(printk(KERN_DEBUG "%s: GetUnit\n",CARD)); + DEBUG(printk(CARD_DEBUG "VIDIOCGUNIT\n",CARD)); vu.video = ztv->video_dev.minor; - vu.vbi = VIDEO_NO_UNIT; + vu.vbi = ztv->vbi_dev.minor; vu.radio = VIDEO_NO_UNIT; vu.audio = VIDEO_NO_UNIT; vu.teletext = VIDEO_NO_UNIT; if(copy_to_user(arg, &vu,sizeof(vu))) return -EFAULT; - return 0; + break; } case VIDIOCGFREQ: @@ -1336,14 +1413,15 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) unsigned long v = ztv->tuner_freq; if (copy_to_user(arg,&v,sizeof(v))) return -EFAULT; - return 0; + DEBUG(printk(CARD_DEBUG "VIDIOCGFREQ\n",CARD)); + break; } - case VIDIOCSFREQ: { unsigned long v; if (copy_from_user(&v, arg, sizeof(v))) return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSFREQ\n",CARD)); if (ztv->have_tuner) { int fixme = v; @@ -1351,20 +1429,25 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg) return -EAGAIN; } ztv->tuner_freq = v; - return 0; + break; } - case VIDIOCGAUDIO: - case VIDIOCSAUDIO: - case VIDIOCGCAPTURE: - case VIDIOCSCAPTURE: - DEBUG(printk(KERN_DEBUG "%s: unhandled video ioctl(%x)\n",CARD,cmd)); - return -EINVAL; + /* Why isn't this in the API? + * And why doesn't it take a buffer number? + case BTTV_FIELDNR: + { + unsigned long v = ztv->lastfieldnr; + if (copy_to_user(arg,&v,sizeof(v))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "BTTV_FIELDNR\n",CARD)); + break; + } + */ default: - DEBUG(printk(KERN_DEBUG "%s: bad ioctl(%x)\n",CARD,cmd)); + return -ENOIOCTLCMD; } - return -EPERM; + return 0; } static @@ -1374,7 +1457,7 @@ int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size) unsigned long start = (unsigned long)adr; unsigned long pos; - DEBUG(printk(KERN_DEBUG "zoran_mmap(0x%p,%ld)\n",adr,size)); + DEBUG(printk(CARD_DEBUG "zoran_mmap(0x%p,%ld)\n",CARD,adr,size)); /* sanity checks */ if (size > ZORAN_MAX_FBUFSIZE || !ztv->fbuffer) @@ -1383,11 +1466,7 @@ int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size) /* start mapping the whole shabang to user memory */ pos = (unsigned long)ztv->fbuffer; while (size>0) { -#ifdef CONFIG_BIGPHYS_AREA unsigned long page = virt_to_phys((void*)pos); -#else - unsigned long page = kvirt_to_phys(pos); -#endif if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; start += PAGE_SIZE; @@ -1397,7 +1476,7 @@ int zoran_mmap(struct video_device* dev, const char* adr, unsigned long size) return 0; } -static struct video_device zoran_template= +static struct video_device zr36120_template= { "UNSET", VID_TYPE_TUNER|VID_TYPE_CAPTURE|VID_TYPE_OVERLAY, @@ -1419,13 +1498,412 @@ static struct video_device zoran_template= }; static -int init_zoran(int card) +int vbi_open(struct video_device *dev, int flags) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + struct vidinfo* item; + + DEBUG(printk(CARD_DEBUG "vbi_open(dev,%d)\n",CARD,flags)); + + /* + * During VBI device open, we continiously grab VBI-like + * data in the vbi buffer when we have nothing to do. + * Only when there is an explicit request for VBI data + * (read call) we /force/ a read. + */ + + /* allocate buffers */ + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + { + item->status = FBUFFER_FREE; + + /* alloc */ + if (!item->memadr) { + item->memadr = bmalloc(ZORAN_VBI_BUFSIZE); + if (!item->memadr) { + /* could not get a buffer, bail out */ + while (item != ztv->readinfo) { + item--; + bfree(item->memadr, ZORAN_VBI_BUFSIZE); + item->memadr = 0; + item->busadr = 0; + } + return -ENOBUFS; + } + } + + /* determine the DMAable address */ + item->busadr = virt_to_bus(item->memadr); + } + + /* do the common part of all open's */ + zoran_common_open(ztv, flags); + + set_bit(STATE_VBI, &ztv->state); + /* start read-ahead */ + zoran_cap(ztv, 1); + + MOD_INC_USE_COUNT; + return 0; +} + +static +void vbi_close(struct video_device *dev) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + struct vidinfo* item; + + DEBUG(printk(CARD_DEBUG "vbi_close(dev)\n",CARD)); + + /* driver specific closure */ + clear_bit(STATE_VBI, &ztv->state); + + zoran_common_close(ztv); + + /* + * This is sucky but right now I can't find a good way to + * be sure its safe to free the buffer. We wait 5-6 fields + * which is more than sufficient to be sure. + */ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); /* Wait 1/10th of a second */ + + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + { + if (item->memadr) + bfree(item->memadr, ZORAN_VBI_BUFSIZE); + item->memadr = 0; + } + + MOD_DEC_USE_COUNT; +} + +/* + * This read function could be used reentrant in a SMP situation. + * + * This is made possible by the spinlock which is kept till we + * found and marked a buffer for our own use. The lock must + * be released as soon as possible to prevent lock contention. + */ +static +long vbi_read(struct video_device* dev, char* buf, unsigned long count, int nonblock) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + unsigned long max; + struct vidinfo* unused = 0; + struct vidinfo* done = 0; + + DEBUG(printk(CARD_DEBUG "vbi_read(0x%p,%ld,%d)\n",CARD,buf,count,nonblock)); + + /* find ourself a free or completed buffer */ + for (;;) { + struct vidinfo* item; + + write_lock_irq(&ztv->lock); + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) { + if (!unused && item->status == FBUFFER_FREE) + unused = item; + if (!done && item->status == FBUFFER_DONE) + done = item; + } + if (done || unused) + break; + + /* no more free buffers, wait for them. */ + write_unlock_irq(&ztv->lock); + if (nonblock) + return -EWOULDBLOCK; + interruptible_sleep_on(&ztv->vbiq); + if (signal_pending(current)) + return -EINTR; + } + + /* Do we have 'ready' data? */ + if (!done) { + /* no? than this will take a while... */ + if (nonblock) { + write_unlock_irq(&ztv->lock); + return -EWOULDBLOCK; + } + + /* mark the unused buffer as wanted */ + unused->status = FBUFFER_BUSY; + unused->next = 0; + { /* add to tail of queue */ + struct vidinfo* oldframe = ztv->workqueue; + if (!oldframe) ztv->workqueue = unused; + else { + while (oldframe->next) oldframe = oldframe->next; + oldframe->next = unused; + } + } + write_unlock_irq(&ztv->lock); + + /* tell the state machine we want it filled /NOW/ */ + zoran_cap(ztv, 1); + + /* wait till this buffer gets grabbed */ + while (unused->status == FBUFFER_BUSY) { + interruptible_sleep_on(&ztv->vbiq); + /* see if a signal did it */ + if (signal_pending(current)) + return -EINTR; + } + done = unused; + } + else + write_unlock_irq(&ztv->lock); + + /* Yes! we got data! */ + max = done->bpl * -done->h; + if (count > max) + count = max; + + /* check if the user gave us enough room to write the data */ + if (!access_ok(VERIFY_WRITE, buf, count)) { + count = -EFAULT; + goto out; + } + + /* + * Now transform/strip the data from YUV to Y-only + * NB. Assume the Y is in the LSB of the YUV data. + */ + { + unsigned char* optr = buf; + unsigned char* eptr = buf+count; + + /* are we beeing accessed from an old driver? */ + if (count == 2*19*2048) { + /* + * Extreme HACK, old VBI programs expect 2048 points + * of data, and we only got 864 orso. Double each + * datapoint and clear the rest of the line. + * This way we have appear to have a + * sample_frequency of 29.5 Mc. + */ + int x,y; + unsigned char* iptr = done->memadr+1; + for (y=done->h; optr<eptr && y<0; y++) + { + /* copy to doubled data to userland */ + for (x=0; optr+1<eptr && x<-done->w; x++) + { + unsigned char a = iptr[x*2]; + *optr++ = a; + *optr++ = a; + } + /* and clear the rest of the line */ + for (x*=2; optr<eptr && x<done->bpl; x++) + *optr++ = 0; + /* next line */ + iptr += done->bpl; + } + } + else { + /* + * Other (probably newer) programs asked + * us what geometry we are using, and are + * reading the correct size. + */ + int x,y; + unsigned char* iptr = done->memadr+1; + for (y=done->h; optr<eptr && y<0; y++) + { + /* copy to doubled data to userland */ + for (x=0; optr<eptr && x<-done->w; x++) + *optr++ = iptr[x*2]; + /* and clear the rest of the line */ + for (;optr<eptr && x<done->bpl; x++) + *optr++ = 0; + /* next line */ + iptr += done->bpl; + } + } + + /* API compliance: + * place the framenumber (half fieldnr) in the last long + */ + ((ulong*)eptr)[-1] = done->fieldnr/2; + } + + /* keep the engine running */ + done->status = FBUFFER_FREE; + zoran_cap(ztv, 1); + + /* tell listeners this buffer just became free */ + wake_up_interruptible(&ztv->vbiq); + + /* goodbye */ +out: + DEBUG(printk(CARD_DEBUG "vbi_read() returns %lu\n",CARD,count)); + return count; +} + +#if LINUX_VERSION_CODE >= 0x020100 +static +unsigned int vbi_poll(struct video_device *dev, struct file *file, poll_table *wait) +{ + struct zoran *ztv = (struct zoran*)dev->priv; + struct vidinfo* item; + unsigned int mask = 0; + + poll_wait(file, &ztv->vbiq, wait); + + for (item=ztv->readinfo; item!=ztv->readinfo+ZORAN_VBI_BUFFERS; item++) + if (item->status == FBUFFER_DONE) + { + mask |= (POLLIN | POLLRDNORM); + break; + } + + DEBUG(printk(CARD_DEBUG "vbi_poll()=%x\n",CARD,mask)); + + return mask; +} +#endif + +static +int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) +{ + struct zoran* ztv = (struct zoran*)dev->priv; + + switch (cmd) { + case VIDIOCGVBIFMT: + { + struct vbi_format f; + DEBUG(printk(CARD_DEBUG "VIDIOCGVBIINFO\n",CARD)); + f.sampling_rate = 14750000UL; + f.samples_per_line = -ztv->readinfo[0].w; + f.sample_format = VIDEO_PALETTE_RAW; + f.start[0] = f.start[1] = ztv->readinfo[0].y; + f.start[1] += 312; + f.count[0] = f.count[1] = -ztv->readinfo[0].h; + f.flags = VBI_INTERLACED; + if (copy_to_user(arg,&f,sizeof(f))) + return -EFAULT; + break; + } + case VIDIOCSVBIFMT: + { + struct vbi_format f; + int i; + if (copy_from_user(&f, arg,sizeof(f))) + return -EFAULT; + DEBUG(printk(CARD_DEBUG "VIDIOCSVBIINFO(%d,%d,%d,%d,%d,%d,%d,%x)\n",CARD,f.sampling_rate,f.samples_per_line,f.sample_format,f.start[0],f.start[1],f.count[0],f.count[1],f.flags)); + + /* lots of parameters are fixed... (PAL) */ + if (f.sampling_rate != 14750000UL || + f.samples_per_line > 864 || + f.sample_format != VIDEO_PALETTE_RAW || + f.start[0] < 0 || + f.start[0] != f.start[1]-312 || + f.count[0] != f.count[1] || + f.start[0]+f.count[0] >= 288 || + f.flags != VBI_INTERLACED) + return -EINVAL; + + write_lock_irq(&ztv->lock); + ztv->readinfo[0].y = f.start[0]; + ztv->readinfo[0].w = -f.samples_per_line; + ztv->readinfo[0].h = -f.count[0]; + ztv->readinfo[0].bpl = f.samples_per_line*ztv->readinfo[0].bpp; + for (i=1; i<ZORAN_VBI_BUFFERS; i++) + ztv->readinfo[i] = ztv->readinfo[i]; + write_unlock_irq(&ztv->lock); + break; + } + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static struct video_device vbi_template= +{ + "UNSET", + VID_TYPE_CAPTURE|VID_TYPE_TELETEXT, + VID_HARDWARE_ZR36120, + + vbi_open, + vbi_close, + vbi_read, + zoran_write, +#if LINUX_VERSION_CODE >= 0x020100 + vbi_poll, /* poll */ +#endif + vbi_ioctl, + NULL, /* no mmap */ + NULL, /* no initialize */ + NULL, /* priv */ + 0, /* busy */ + -1 /* minor */ +}; + +/* + * Scan for a Zoran chip, request the irq and map the io memory + */ +static +int __init find_zoran(void) +{ + int result; + struct zoran *ztv; + struct pci_dev *dev = NULL; + unsigned char revision; + int zoran_num=0; + + if (!pcibios_present()) + { + printk(KERN_DEBUG "zoran: PCI-BIOS not present or not accessible!\n"); + return 0; + } + + while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev))) + { + /* Ok, a ZR36120/ZR36125 found! */ + ztv = &zorans[zoran_num]; + ztv->dev = dev; + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision); + printk(KERN_INFO "zoran: Zoran %x (rev %d) ", + dev->device, revision); + printk("bus: %d, devfn: %d, irq: %d, ", + dev->bus->number, dev->devfn, dev->irq); + printk("memory: 0x%08lx.\n", ztv->zoran_adr); + + ztv->zoran_mem = ioremap(ztv->zoran_adr, 0x1000); + DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem)); + + result = request_irq(dev->irq, zoran_irq, + SA_SHIRQ|SA_INTERRUPT,"zoran",(void *)ztv); + if (result==-EINVAL) + { + printk(KERN_ERR "zoran: Bad irq number or handler\n"); + return -EINVAL; + } + if (result==-EBUSY) + printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq); + if (result < 0) + return result; + + /* Enable bus-mastering */ + pci_set_master(dev); + + zoran_num++; + } + if(zoran_num) + printk(KERN_INFO "zoran: %d Zoran card(s) found.\n",zoran_num); + return zoran_num; +} + +static +int __init init_zoran(int card) { struct zoran *ztv = &zorans[card]; int i; /* if the given cardtype valid? */ - if (cardtype[card]<0 || cardtype[card]>=NRTVCARDS) { + if (cardtype[card]>=NRTVCARDS) { printk(KERN_INFO "invalid cardtype(%d) detected\n",cardtype[card]); return -1; } @@ -1436,19 +1914,20 @@ int init_zoran(int card) zror(ZORAN_PCI_SOFTRESET,ZORAN_PCI); udelay(10); - /* default setup for max. PAL size in a 1024xXXX hicolor framebuffer */ - - /* framegrabber details */ - ztv->swidth=800; - ztv->sheight=600; - ztv->depth=16; - - /* channel details */ - ztv->norm=0; /* PAL */ - ztv->card=tvcards+cardtype[card]; /* point to the selected card */ + /* zoran chip specific details */ + ztv->card = tvcards+cardtype[card]; /* point to the selected card */ + ztv->norm = 0; /* PAL */ ztv->tuner_freq = 0; - ztv->overinfo.status = FBUFFER_UNUSED; + /* videocard details */ + ztv->swidth = 800; + ztv->sheight = 600; + ztv->depth = 16; + + /* State details */ + ztv->fbuffer = 0; + ztv->overinfo.kindof = FBUFFER_OVERLAY; + ztv->overinfo.status = FBUFFER_FREE; ztv->overinfo.x = 0; ztv->overinfo.y = 0; ztv->overinfo.w = 768; /* 640 */ @@ -1456,40 +1935,37 @@ int init_zoran(int card) ztv->overinfo.format = VIDEO_PALETTE_RGB565; ztv->overinfo.bpp = palette2fmt[ztv->overinfo.format].bpp; ztv->overinfo.bpl = ztv->overinfo.bpp*ztv->swidth; - ztv->overinfo.vidadr = 0; + ztv->overinfo.busadr = 0; + ztv->overinfo.memadr = 0; ztv->overinfo.overlay = 0; - - ztv->readinfo = ztv->overinfo; - ztv->readinfo.w = 768; - ztv->readinfo.h = -22; - ztv->readinfo.format = VIDEO_PALETTE_YUV422; - ztv->readinfo.bpp = palette2fmt[ztv->readinfo.format].bpp; - ztv->readinfo.bpl = ztv->readinfo.w*ztv->readinfo.bpp; - - /* grabbing details */ for (i=0; i<ZORAN_MAX_FBUFFERS; i++) { ztv->grabinfo[i] = ztv->overinfo; - ztv->grabinfo[i].format = VIDEO_PALETTE_RGB24; + ztv->grabinfo[i].kindof = FBUFFER_GRAB; } + init_waitqueue_head(&ztv->grabq); + + /* VBI details */ + ztv->readinfo[0] = ztv->overinfo; + ztv->readinfo[0].kindof = FBUFFER_VBI; + ztv->readinfo[0].w = -864; + ztv->readinfo[0].h = -38; + ztv->readinfo[0].format = VIDEO_PALETTE_YUV422; + ztv->readinfo[0].bpp = palette2fmt[ztv->readinfo[0].format].bpp; + ztv->readinfo[0].bpl = 1024*ztv->readinfo[0].bpp; + for (i=1; i<ZORAN_VBI_BUFFERS; i++) + ztv->readinfo[i] = ztv->readinfo[0]; + init_waitqueue_head(&ztv->vbiq); /* maintenance data */ - ztv->fbuffer = NULL; - ztv->user = 0; ztv->have_decoder = 0; ztv->have_tuner = 0; + ztv->tuner_type = 0; ztv->running = 0; - init_waitqueue_head(&ztv->grabq); - init_waitqueue_head(&ztv->readq); + ztv->users = 0; ztv->lock = RW_LOCK_UNLOCKED; - ztv->state = 0; - ztv->prevstate = 0; - ztv->lastframe = -1; - - /* picture details */ - ztv->picture.colour=254<<7; - ztv->picture.brightness=128<<8; - ztv->picture.hue=128<<8; - ztv->picture.contrast=216<<7; + ztv->workqueue = 0; + ztv->fieldnr = 0; + ztv->lastfieldnr = 0; if (triton1) zrand(~ZORAN_VDC_TRICOM, ZORAN_VDC); @@ -1509,7 +1985,7 @@ int init_zoran(int card) zrwrite(ZORAN_PCI_SOFTRESET|(ztv->card->gpdir<<0),ZORAN_PCI); /* implicit: 3 duration and recovery PCI clocks on guest 0-3 */ zrwrite(ztv->card->gpval<<24,ZORAN_GUEST); - + /* clear interrupt status */ zrwrite(~0, ZORAN_ISR); @@ -1523,29 +1999,37 @@ int init_zoran(int card) /* * Now add the template and register the device unit */ - ztv->video_dev = zoran_template; + ztv->video_dev = zr36120_template; strcpy(ztv->video_dev.name, ztv->i2c.name); + ztv->video_dev.priv = ztv; if (video_register_device(&ztv->video_dev, VFL_TYPE_GRABBER) < 0) return -1; + + ztv->vbi_dev = vbi_template; + strcpy(ztv->vbi_dev.name, ztv->i2c.name); + ztv->vbi_dev.priv = ztv; + if (video_register_device(&ztv->vbi_dev, VFL_TYPE_VBI) < 0) { + video_unregister_device(&ztv->video_dev); + return -1; + } i2c_register_bus(&ztv->i2c); /* set interrupt mask - the PIN enable will be set later */ zrwrite(ZORAN_ICR_GIRQ0|ZORAN_ICR_GIRQ1|ZORAN_ICR_CODE, ZORAN_ICR); - printk(KERN_INFO "%s: installed %s\n",CARD,ztv->card->name); + printk(KERN_INFO "%s: installed %s\n",ztv->i2c.name,ztv->card->name); return 0; } static -void release_zoran(int max) +void __exit release_zoran(int max) { - u8 command; struct zoran *ztv; int i; for (i=0;i<max; i++) { - ztv=&zorans[i]; + ztv = &zorans[i]; /* turn off all capturing, DMA and IRQs */ /* reset the zoran */ @@ -1564,31 +2048,22 @@ void release_zoran(int max) /* unregister i2c_bus */ i2c_unregister_bus((&ztv->i2c)); - /* disable PCI bus-mastering */ - pci_read_config_byte(ztv->dev, PCI_COMMAND, &command); - command&=PCI_COMMAND_MASTER; - pci_write_config_byte(ztv->dev, PCI_COMMAND, command); - /* unmap and free memory */ if (ztv->zoran_mem) iounmap(ztv->zoran_mem); video_unregister_device(&ztv->video_dev); + video_unregister_device(&ztv->vbi_dev); } } -#ifdef MODULE -void cleanup_module(void) +void __exit zr36120_exit(void) { release_zoran(zoran_cards); } -int init_module(void) +int __init zr36120_init(void) { -#else -int init_zr36120_cards(struct video_init *unused) -{ -#endif int card; handle_chipset(); @@ -1607,3 +2082,6 @@ int init_zr36120_cards(struct video_init *unused) } return 0; } + +module_init(zr36120_init); +module_exit(zr36120_exit); diff --git a/drivers/char/zr36120.h b/drivers/char/zr36120.h index 8cfd19064..e500de10d 100644 --- a/drivers/char/zr36120.h +++ b/drivers/char/zr36120.h @@ -26,7 +26,7 @@ #include <linux/types.h> #include <linux/wait.h> -#include <linux/i2c.h> +#include <linux/i2c-old.h> #include <linux/videodev.h> #include <asm/io.h> @@ -43,12 +43,11 @@ extern struct i2c_bus zoran_i2c_bus_template; #define ZORAN_MAX_FBUFFERS 2 -#define ZORAN_MAX_FBUFFER 0x0A2000 -#define ZORAN_MAX_FBUFSIZE (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER) +#define ZORAN_MAX_FBUFFER (768*576*2) +#define ZORAN_MAX_FBUFSIZE (ZORAN_MAX_FBUFFERS*ZORAN_MAX_FBUFFER) -/* external declarations */ -extern unsigned long zoran_alloc_memory(void); -extern void zoran_free_memory(void); +#define ZORAN_VBI_BUFFERS 2 +#define ZORAN_VBI_BUFSIZE (22*1024*2) struct tvcard { char* name; /* name of the cardtype */ @@ -70,76 +69,84 @@ struct tvcard { #define SVHS(x) ((x)|IS_SVHS) struct vidinfo { - int status; -#define FBUFFER_UNUSED 0 -#define FBUFFER_GRABBING 1 -#define FBUFFER_DONE 2 - int x,y; - int w,h; - int bpl; - int bpp; /* should be calculated */ - int format; - ulong vidadr; /* physical video address */ - ulong* overlay; + struct vidinfo* next; /* next active buffer */ + uint kindof; +#define FBUFFER_OVERLAY 0 +#define FBUFFER_GRAB 1 +#define FBUFFER_VBI 2 + uint status; +#define FBUFFER_FREE 0 +#define FBUFFER_BUSY 1 +#define FBUFFER_DONE 2 + ulong fieldnr; /* # of field, not framer! */ + uint x,y; + int w,h; /* w,h can be negative! */ + uint format; /* index in palette2fmt[] */ + uint bpp; /* lookup from palette2fmt[] */ + uint bpl; /* calc: width * bpp */ + ulong busadr; /* bus addr for DMA engine */ + char* memadr; /* kernel addr for making copies */ + ulong* overlay; /* kernel addr of overlay mask */ }; struct zoran { struct video_device video_dev; -#define CARD ztv->video_dev.name - struct i2c_bus i2c; - struct video_picture picture; /* Current picture params */ - struct video_audio audio_dev; /* Current audio params */ +#define CARD_DEBUG KERN_DEBUG "%s(%lu): " +#define CARD_INFO KERN_INFO "%s(%lu): " +#define CARD_ERR KERN_ERR "%s(%lu): " +#define CARD ztv->video_dev.name,ztv->fieldnr /* zoran chip specific details */ - struct pci_dev* dev; /* ptr to PCI device */ - ushort id; /* chip id */ - unsigned char revision; /* chip revision */ - int zoran_adr; /* bus address of IO memory */ - char* zoran_mem; /* pointer to mapped IO memory */ + struct i2c_bus i2c; /* i2c registration data */ + struct pci_dev* dev; /* ptr to PCI device */ + ulong zoran_adr; /* bus address of IO memory */ + char* zoran_mem; /* kernel address of IO memory */ + struct tvcard* card; /* the cardtype */ + uint norm; /* 0=PAL, 1=NTSC, 2=SECAM */ + uint tuner_freq; /* Current freq in kHz */ + struct video_picture picture; /* Current picture params */ /* videocard details */ - int swidth; /* screen width */ - int sheight; /* screen height */ - int depth; /* depth in bits */ - - /* channel details */ - int norm; /* 0=PAL, 1=NTSC, 2=SECAM */ - struct tvcard* card; /* the cardtype */ - int tuner_freq; /* in Hz */ + uint swidth; /* screen width */ + uint sheight; /* screen height */ + uint depth; /* depth in bits */ /* State details */ - struct vidinfo overinfo; /* overlay data */ - struct vidinfo grabinfo[ZORAN_MAX_FBUFFERS]; /* grabbing data */ - struct vidinfo readinfo; /* reading data */ + char* fbuffer; /* framebuffers for mmap */ + struct vidinfo overinfo; /* overlay data */ + struct vidinfo grabinfo[ZORAN_MAX_FBUFFERS]; /* grabbing data*/ + wait_queue_head_t grabq; /* grabbers queue */ + + /* VBI details */ + struct video_device vbi_dev; + struct vidinfo readinfo[2]; /* VBI data - flip buffers */ + wait_queue_head_t vbiq; /* vbi queue */ /* maintenance data */ - char* fbuffer; /* framebuffers for mmap */ - int user; /* # users */ - int have_decoder; /* did we detect a mux? */ - int have_tuner; /* did we detect a tuner? */ - int tuner_type; /* tuner type, when found */ - int running; - wait_queue_head_t grabq; /* waiting capturers */ - wait_queue_head_t readq; /* waiting readers */ + int have_decoder; /* did we detect a mux? */ + int have_tuner; /* did we detect a tuner? */ + int users; /* howmany video/vbi open? */ + int tuner_type; /* tuner type, when found */ + int running; /* are we rolling? */ rwlock_t lock; - int state; /* what is requested of us? */ -#define STATE_READ 0 -#define STATE_GRAB 1 -#define STATE_OVERLAY 2 - int prevstate; - int lastframe; - - int interlace; /* calculated */ + int state; /* what is requested of us? */ +#define STATE_OVERLAY 0 +#define STATE_VBI 1 + struct vidinfo* workqueue; /* buffers to grab, head is active */ + ulong fieldnr; /* #field, ticked every VSYNC */ + ulong lastfieldnr; /* #field, ticked every GRAB */ + + int vidInterlace; /* calculated */ int vidXshift; /* calculated */ - int vidWidth; /* calculated */ - int vidHeight; /* calculated */ + uint vidWidth; /* calculated */ + uint vidHeight; /* calculated */ }; #define zrwrite(dat,adr) writel((dat),(char *) (ztv->zoran_mem+(adr))) #define zrread(adr) readl(ztv->zoran_mem+(adr)) -#if !defined(PDEBUG) || (PDEBUG == 0) +#if PDEBUG == 0 #define zrand(dat,adr) zrwrite((dat) & zrread(adr), adr) #define zror(dat,adr) zrwrite((dat) | zrread(adr), adr) #define zraor(dat,mask,adr) zrwrite( ((dat)&~(mask)) | ((mask)&zrread(adr)), adr) diff --git a/drivers/char/zr36120_i2c.c b/drivers/char/zr36120_i2c.c index 8eb618b14..0de59b9f1 100644 --- a/drivers/char/zr36120_i2c.c +++ b/drivers/char/zr36120_i2c.c @@ -23,9 +23,9 @@ #include <asm/io.h> #include <linux/version.h> +#include <linux/video_decoder.h> #include <asm/uaccess.h> -#include "linux/video_decoder.h" #include "tuner.h" #include "zr36120.h" @@ -59,23 +59,38 @@ static void attach_inform(struct i2c_bus *bus, int id) { struct zoran *ztv = (struct zoran*)bus->data; + struct video_decoder_capability dc; + int rv; switch (id) { case I2C_DRIVERID_VIDEODECODER: - ztv->have_decoder = 1; - DEBUG(printk(KERN_INFO "%s: decoder attached\n",CARD)); + DEBUG(printk(CARD_INFO "decoder attached\n",CARD)); + + /* fetch the capabilites of the decoder */ + rv = i2c_control_device(&ztv->i2c, I2C_DRIVERID_VIDEODECODER, DECODER_GET_CAPABILITIES, &dc); + if (rv) { + DEBUG(printk(CARD_DEBUG "decoder is not V4L aware!\n",CARD)); + break; + } + DEBUG(printk(CARD_DEBUG "capabilities %d %d %d\n",CARD,dc.flags,dc.inputs,dc.outputs)); + + /* Test if the decoder can de VBI transfers */ + if (dc.flags & 16 /*VIDEO_DECODER_VBI*/) + ztv->have_decoder = 2; + else + ztv->have_decoder = 1; break; case I2C_DRIVERID_TUNER: ztv->have_tuner = 1; - DEBUG(printk(KERN_INFO "%s: tuner attached\n",CARD)); + DEBUG(printk(CARD_INFO "tuner attached\n",CARD)); if (ztv->tuner_type >= 0) { if (i2c_control_device(&ztv->i2c,I2C_DRIVERID_TUNER,TUNER_SET_TYPE,&ztv->tuner_type)<0) - DEBUG(printk(KERN_INFO "%s: attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type)); + DEBUG(printk(CARD_INFO "attach_inform; tuner wont be set to type %d\n",CARD,ztv->tuner_type)); } break; default: - DEBUG(printk(KERN_INFO "%s: attach_inform; unknown device id=%d\n",CARD,id)); + DEBUG(printk(CARD_INFO "attach_inform; unknown device id=%d\n",CARD,id)); break; } } @@ -88,14 +103,14 @@ void detach_inform(struct i2c_bus *bus, int id) switch (id) { case I2C_DRIVERID_VIDEODECODER: ztv->have_decoder = 0; - DEBUG(printk(KERN_INFO "%s: decoder detached\n",CARD)); + DEBUG(printk(CARD_INFO "decoder detached\n",CARD)); break; case I2C_DRIVERID_TUNER: ztv->have_tuner = 0; - DEBUG(printk(KERN_INFO "%s: tuner detached\n",CARD)); + DEBUG(printk(CARD_INFO "tuner detached\n",CARD)); break; default: - DEBUG(printk(KERN_INFO "%s: detach_inform; unknown device id=%d\n",CARD,id)); + DEBUG(printk(CARD_INFO "detach_inform; unknown device id=%d\n",CARD,id)); break; } } diff --git a/drivers/char/zr36120_mem.c b/drivers/char/zr36120_mem.c index 0a93ab722..5e81049eb 100644 --- a/drivers/char/zr36120_mem.c +++ b/drivers/char/zr36120_mem.c @@ -22,6 +22,7 @@ #include <linux/mm.h> #include <linux/pci.h> #include <linux/wrapper.h> +#include <linux/slab.h> #include <asm/io.h> #ifdef CONFIG_BIGPHYS_AREA #include <linux/bigphysarea.h> @@ -30,62 +31,21 @@ #include "zr36120.h" #include "zr36120_mem.h" -/* ----------------------------------------------------------------------- */ -/* Memory functions */ -/* shamelessly stolen and adapted from bttv.c */ -/* ----------------------------------------------------------------------- */ +/*******************************/ +/* Memory management functions */ +/*******************************/ -/* - * convert virtual user memory address to physical address - * (virt_to_phys only works for kmalloced kernel memory) - */ -inline unsigned long uvirt_to_phys(unsigned long adr) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *ptep, pte; - - pgd = pgd_offset(current->mm, adr); - if (pgd_none(*pgd)) - return 0; - pmd = pmd_offset(pgd, adr); - if (pmd_none(*pmd)) - return 0; - ptep = pte_offset(pmd, adr/*&(~PGDIR_MASK)*/); - pte = *ptep; - /* Note; page_address will panic for us if the page is high */ - if(pte_present(pte)) - return page_address(pte_page(pte))|(adr&(PAGE_SIZE-1)); - return 0; -} - -/* - * vmalloced address to physical address - */ -inline unsigned long kvirt_to_phys(unsigned long adr) -{ - return uvirt_to_phys(VMALLOC_VMADDR(adr)); -} - -/* - * vmalloced address to bus address - */ -inline unsigned long kvirt_to_bus(unsigned long adr) +inline int __get_order(unsigned long size) { - return virt_to_bus(phys_to_virt(kvirt_to_phys(adr))); -} - -inline int order(unsigned long size) -{ - int ordr = 0; + int order = 0; size = (size+PAGE_SIZE-1)/PAGE_SIZE; while (size) { size /= 2; - ordr++; + order++; } - return ordr; + return order; } - + void* bmalloc(unsigned long size) { void* mem; @@ -96,7 +56,7 @@ void* bmalloc(unsigned long size) * The following function got a lot of memory at boottime, * so we know its always there... */ - mem = (void*)__get_free_pages(GFP_USER,order(size)); + mem = (void*)__get_free_pages(GFP_USER|GFP_DMA,__get_order(size)); #endif if (mem) { unsigned long adr = (unsigned long)mem; @@ -122,7 +82,7 @@ void bfree(void* mem, unsigned long size) #ifdef CONFIG_BIGPHYS_AREA bigphysarea_free_pages(mem); #else - free_pages((unsigned long)mem,order(size)); + free_pages((unsigned long)mem,__get_order(size)); #endif } } diff --git a/drivers/char/zr36120_mem.h b/drivers/char/zr36120_mem.h index 609f0a1a9..aad117acc 100644 --- a/drivers/char/zr36120_mem.h +++ b/drivers/char/zr36120_mem.h @@ -1,17 +1,3 @@ -extern inline unsigned long uvirt_to_phys(unsigned long adr); - -/* vmalloced address to physical address */ -extern inline unsigned long kvirt_to_phys(unsigned long adr) -{ return uvirt_to_phys(VMALLOC_VMADDR(adr)); } - -/* vmalloced address to bus address */ -extern inline unsigned long kvirt_to_bus(unsigned long adr) -{ return virt_to_bus(phys_to_virt(kvirt_to_phys(adr))); } - -/* always vmalloced memory - not always continuous! */ -void* rvmalloc(unsigned long size); -void rvfree(void* mem, unsigned long size); - /* either kmalloc() or bigphysarea() alloced memory - continuous */ void* bmalloc(unsigned long size); void bfree(void* mem, unsigned long size); |