summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-05 06:47:02 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-05 06:47:02 +0000
commit99a7e12f34b3661a0d1354eef83a0eef4df5e34c (patch)
tree3560aca9ca86792f9ab7bd87861ea143a1b3c7a3 /drivers/char
parente73a04659c0b8cdee4dd40e58630e2cf63afb316 (diff)
Merge with Linux 2.3.38.
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Config.in58
-rw-r--r--drivers/char/Makefile87
-rw-r--r--drivers/char/agp/Makefile5
-rw-r--r--drivers/char/agp/agp.h12
-rw-r--r--drivers/char/agp/agpgart_be.c53
-rw-r--r--drivers/char/agp/agpgart_fe.c1
-rw-r--r--drivers/char/audiochip.h60
-rw-r--r--drivers/char/bttv.c2664
-rw-r--r--drivers/char/bttv.h167
-rw-r--r--drivers/char/buz.c10
-rw-r--r--drivers/char/console.c18
-rw-r--r--drivers/char/drm/Makefile21
-rw-r--r--drivers/char/drm/gamma_drv.c3
-rw-r--r--drivers/char/drm/init.c2
-rw-r--r--drivers/char/drm/tdfx_drv.c7
-rw-r--r--drivers/char/dsp56k.c2
-rw-r--r--drivers/char/dtlk.c2
-rw-r--r--drivers/char/h8.c13
-rw-r--r--drivers/char/i2c-old.c (renamed from drivers/char/i2c.c)2
-rw-r--r--drivers/char/i2c-parport.c2
-rw-r--r--drivers/char/ip2main.c6
-rw-r--r--drivers/char/isicom.c2
-rw-r--r--drivers/char/istallion.c2
-rw-r--r--drivers/char/lp.c31
-rw-r--r--drivers/char/mem.c16
-rw-r--r--drivers/char/msp3400.c1064
-rw-r--r--drivers/char/msp3400.h25
-rw-r--r--drivers/char/n_hdlc.c12
-rw-r--r--drivers/char/pc110pad.c2
-rw-r--r--drivers/char/pc_keyb.c31
-rw-r--r--drivers/char/pcmcia/Config.in23
-rw-r--r--drivers/char/pcwd.c2
-rw-r--r--drivers/char/ppdev.c2
-rw-r--r--drivers/char/ppdev.h81
-rw-r--r--drivers/char/random.c87
-rw-r--r--drivers/char/raw.c92
-rw-r--r--drivers/char/saa5249.c2
-rw-r--r--drivers/char/saa7110.c6
-rw-r--r--drivers/char/saa7111.c7
-rw-r--r--drivers/char/saa7185.c6
-rw-r--r--drivers/char/serial.c19
-rw-r--r--drivers/char/stallion.c2
-rw-r--r--drivers/char/stradis.c23
-rw-r--r--drivers/char/sx.c2
-rw-r--r--drivers/char/synclink.c7
-rw-r--r--drivers/char/tda8425.c325
-rw-r--r--drivers/char/tda9855.c456
-rw-r--r--drivers/char/tea6300.c344
-rw-r--r--drivers/char/tpqic02.c2
-rw-r--r--drivers/char/tuner.c444
-rw-r--r--drivers/char/videodev.c6
-rw-r--r--drivers/char/zr36120.c1530
-rw-r--r--drivers/char/zr36120.h119
-rw-r--r--drivers/char/zr36120_i2c.c33
-rw-r--r--drivers/char/zr36120_mem.c62
-rw-r--r--drivers/char/zr36120_mem.h14
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(&current->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);